blob: 022dcdc256fb68932634242ccff9d86d37dfcb74 [file] [log] [blame]
Sascha Hauer34f6e152008-09-02 17:16:59 +02001/*
2 * Copyright 2004-2007 Freescale Semiconductor, Inc. All Rights Reserved.
3 * Copyright 2008 Sascha Hauer, kernel@pengutronix.de
4 *
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License
7 * as published by the Free Software Foundation; either version 2
8 * of the License, or (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
17 * MA 02110-1301, USA.
18 */
19
20#include <linux/delay.h>
21#include <linux/slab.h>
22#include <linux/init.h>
23#include <linux/module.h>
24#include <linux/mtd/mtd.h>
25#include <linux/mtd/nand.h>
26#include <linux/mtd/partitions.h>
27#include <linux/interrupt.h>
28#include <linux/device.h>
29#include <linux/platform_device.h>
30#include <linux/clk.h>
31#include <linux/err.h>
32#include <linux/io.h>
Sascha Hauer63f14742010-10-18 10:16:26 +020033#include <linux/irq.h>
34#include <linux/completion.h>
Uwe Kleine-König64363562012-04-23 11:23:41 +020035#include <linux/of_device.h>
36#include <linux/of_mtd.h>
Sascha Hauer34f6e152008-09-02 17:16:59 +020037
38#include <asm/mach/flash.h>
Arnd Bergmann82906b12012-08-24 15:14:29 +020039#include <linux/platform_data/mtd-mxc_nand.h>
Sascha Hauer34f6e152008-09-02 17:16:59 +020040
41#define DRIVER_NAME "mxc_nand"
42
43/* Addresses for NFC registers */
Sascha Hauer1bc99182010-08-06 15:53:08 +020044#define NFC_V1_V2_BUF_SIZE (host->regs + 0x00)
45#define NFC_V1_V2_BUF_ADDR (host->regs + 0x04)
46#define NFC_V1_V2_FLASH_ADDR (host->regs + 0x06)
47#define NFC_V1_V2_FLASH_CMD (host->regs + 0x08)
48#define NFC_V1_V2_CONFIG (host->regs + 0x0a)
49#define NFC_V1_V2_ECC_STATUS_RESULT (host->regs + 0x0c)
50#define NFC_V1_V2_RSLTMAIN_AREA (host->regs + 0x0e)
51#define NFC_V1_V2_RSLTSPARE_AREA (host->regs + 0x10)
52#define NFC_V1_V2_WRPROT (host->regs + 0x12)
53#define NFC_V1_UNLOCKSTART_BLKADDR (host->regs + 0x14)
54#define NFC_V1_UNLOCKEND_BLKADDR (host->regs + 0x16)
Baruch Siachd178e3e2011-03-14 09:01:56 +020055#define NFC_V21_UNLOCKSTART_BLKADDR0 (host->regs + 0x20)
56#define NFC_V21_UNLOCKSTART_BLKADDR1 (host->regs + 0x24)
57#define NFC_V21_UNLOCKSTART_BLKADDR2 (host->regs + 0x28)
58#define NFC_V21_UNLOCKSTART_BLKADDR3 (host->regs + 0x2c)
59#define NFC_V21_UNLOCKEND_BLKADDR0 (host->regs + 0x22)
60#define NFC_V21_UNLOCKEND_BLKADDR1 (host->regs + 0x26)
61#define NFC_V21_UNLOCKEND_BLKADDR2 (host->regs + 0x2a)
62#define NFC_V21_UNLOCKEND_BLKADDR3 (host->regs + 0x2e)
Sascha Hauer1bc99182010-08-06 15:53:08 +020063#define NFC_V1_V2_NF_WRPRST (host->regs + 0x18)
64#define NFC_V1_V2_CONFIG1 (host->regs + 0x1a)
65#define NFC_V1_V2_CONFIG2 (host->regs + 0x1c)
Sascha Hauer34f6e152008-09-02 17:16:59 +020066
Sascha Hauer6e85dfd2010-08-06 15:53:10 +020067#define NFC_V2_CONFIG1_ECC_MODE_4 (1 << 0)
Sascha Hauer1bc99182010-08-06 15:53:08 +020068#define NFC_V1_V2_CONFIG1_SP_EN (1 << 2)
69#define NFC_V1_V2_CONFIG1_ECC_EN (1 << 3)
70#define NFC_V1_V2_CONFIG1_INT_MSK (1 << 4)
71#define NFC_V1_V2_CONFIG1_BIG (1 << 5)
72#define NFC_V1_V2_CONFIG1_RST (1 << 6)
73#define NFC_V1_V2_CONFIG1_CE (1 << 7)
Sascha Hauerb8db2f52010-08-09 15:04:19 +020074#define NFC_V2_CONFIG1_ONE_CYCLE (1 << 8)
75#define NFC_V2_CONFIG1_PPB(x) (((x) & 0x3) << 9)
76#define NFC_V2_CONFIG1_FP_INT (1 << 11)
Sascha Hauer34f6e152008-09-02 17:16:59 +020077
Sascha Hauer1bc99182010-08-06 15:53:08 +020078#define NFC_V1_V2_CONFIG2_INT (1 << 15)
Sascha Hauer34f6e152008-09-02 17:16:59 +020079
Sascha Hauer1bc99182010-08-06 15:53:08 +020080/*
81 * Operation modes for the NFC. Valid for v1, v2 and v3
82 * type controllers.
83 */
84#define NFC_CMD (1 << 0)
85#define NFC_ADDR (1 << 1)
86#define NFC_INPUT (1 << 2)
87#define NFC_OUTPUT (1 << 3)
88#define NFC_ID (1 << 4)
89#define NFC_STATUS (1 << 5)
Sascha Hauer34f6e152008-09-02 17:16:59 +020090
Sascha Hauer71ec5152010-08-06 15:53:11 +020091#define NFC_V3_FLASH_CMD (host->regs_axi + 0x00)
92#define NFC_V3_FLASH_ADDR0 (host->regs_axi + 0x04)
Sascha Hauer34f6e152008-09-02 17:16:59 +020093
Sascha Hauer71ec5152010-08-06 15:53:11 +020094#define NFC_V3_CONFIG1 (host->regs_axi + 0x34)
95#define NFC_V3_CONFIG1_SP_EN (1 << 0)
96#define NFC_V3_CONFIG1_RBA(x) (((x) & 0x7 ) << 4)
Sascha Hauer34f6e152008-09-02 17:16:59 +020097
Sascha Hauer71ec5152010-08-06 15:53:11 +020098#define NFC_V3_ECC_STATUS_RESULT (host->regs_axi + 0x38)
Sascha Hauer34f6e152008-09-02 17:16:59 +020099
Sascha Hauer71ec5152010-08-06 15:53:11 +0200100#define NFC_V3_LAUNCH (host->regs_axi + 0x40)
Sascha Hauer34f6e152008-09-02 17:16:59 +0200101
Sascha Hauer71ec5152010-08-06 15:53:11 +0200102#define NFC_V3_WRPROT (host->regs_ip + 0x0)
103#define NFC_V3_WRPROT_LOCK_TIGHT (1 << 0)
104#define NFC_V3_WRPROT_LOCK (1 << 1)
105#define NFC_V3_WRPROT_UNLOCK (1 << 2)
106#define NFC_V3_WRPROT_BLS_UNLOCK (2 << 6)
107
108#define NFC_V3_WRPROT_UNLOCK_BLK_ADD0 (host->regs_ip + 0x04)
109
110#define NFC_V3_CONFIG2 (host->regs_ip + 0x24)
111#define NFC_V3_CONFIG2_PS_512 (0 << 0)
112#define NFC_V3_CONFIG2_PS_2048 (1 << 0)
113#define NFC_V3_CONFIG2_PS_4096 (2 << 0)
114#define NFC_V3_CONFIG2_ONE_CYCLE (1 << 2)
115#define NFC_V3_CONFIG2_ECC_EN (1 << 3)
116#define NFC_V3_CONFIG2_2CMD_PHASES (1 << 4)
117#define NFC_V3_CONFIG2_NUM_ADDR_PHASE0 (1 << 5)
118#define NFC_V3_CONFIG2_ECC_MODE_8 (1 << 6)
Sascha Hauer71718a8e2012-06-06 12:33:15 +0200119#define NFC_V3_CONFIG2_PPB(x, shift) (((x) & 0x3) << shift)
Sascha Hauer71ec5152010-08-06 15:53:11 +0200120#define NFC_V3_CONFIG2_NUM_ADDR_PHASE1(x) (((x) & 0x3) << 12)
121#define NFC_V3_CONFIG2_INT_MSK (1 << 15)
122#define NFC_V3_CONFIG2_ST_CMD(x) (((x) & 0xff) << 24)
123#define NFC_V3_CONFIG2_SPAS(x) (((x) & 0xff) << 16)
124
125#define NFC_V3_CONFIG3 (host->regs_ip + 0x28)
126#define NFC_V3_CONFIG3_ADD_OP(x) (((x) & 0x3) << 0)
127#define NFC_V3_CONFIG3_FW8 (1 << 3)
128#define NFC_V3_CONFIG3_SBB(x) (((x) & 0x7) << 8)
129#define NFC_V3_CONFIG3_NUM_OF_DEVICES(x) (((x) & 0x7) << 12)
130#define NFC_V3_CONFIG3_RBB_MODE (1 << 15)
131#define NFC_V3_CONFIG3_NO_SDMA (1 << 20)
132
133#define NFC_V3_IPC (host->regs_ip + 0x2C)
134#define NFC_V3_IPC_CREQ (1 << 0)
135#define NFC_V3_IPC_INT (1 << 31)
136
137#define NFC_V3_DELAY_LINE (host->regs_ip + 0x34)
Sascha Hauer34f6e152008-09-02 17:16:59 +0200138
Uwe Kleine-Könige4303b22012-04-23 11:23:35 +0200139struct mxc_nand_host;
140
141struct mxc_nand_devtype_data {
142 void (*preset)(struct mtd_info *);
143 void (*send_cmd)(struct mxc_nand_host *, uint16_t, int);
144 void (*send_addr)(struct mxc_nand_host *, uint16_t, int);
145 void (*send_page)(struct mtd_info *, unsigned int);
146 void (*send_read_id)(struct mxc_nand_host *);
147 uint16_t (*get_dev_status)(struct mxc_nand_host *);
148 int (*check_int)(struct mxc_nand_host *);
149 void (*irq_control)(struct mxc_nand_host *, int);
Uwe Kleine-König6d38af22012-04-23 11:23:36 +0200150 u32 (*get_ecc_status)(struct mxc_nand_host *);
Uwe Kleine-König6dcdf992012-04-23 11:23:37 +0200151 struct nand_ecclayout *ecclayout_512, *ecclayout_2k, *ecclayout_4k;
Uwe Kleine-König5e05a2d62012-04-23 11:23:38 +0200152 void (*select_chip)(struct mtd_info *mtd, int chip);
Uwe Kleine-König69d023b2012-04-23 11:23:39 +0200153 int (*correct_data)(struct mtd_info *mtd, u_char *dat,
154 u_char *read_ecc, u_char *calc_ecc);
Uwe Kleine-Königf48d0f92012-04-23 11:23:40 +0200155
156 /*
157 * On i.MX21 the CONFIG2:INT bit cannot be read if interrupts are masked
158 * (CONFIG1:INT_MSK is set). To handle this the driver uses
159 * enable_irq/disable_irq_nosync instead of CONFIG1:INT_MSK
160 */
161 int irqpending_quirk;
162 int needs_ip;
163
164 size_t regs_offset;
165 size_t spare0_offset;
166 size_t axi_offset;
167
168 int spare_len;
169 int eccbytes;
170 int eccsize;
Sascha Hauer71718a8e2012-06-06 12:33:15 +0200171 int ppb_shift;
Uwe Kleine-Könige4303b22012-04-23 11:23:35 +0200172};
173
Sascha Hauer34f6e152008-09-02 17:16:59 +0200174struct mxc_nand_host {
175 struct mtd_info mtd;
176 struct nand_chip nand;
Sascha Hauer34f6e152008-09-02 17:16:59 +0200177 struct device *dev;
178
Uwe Kleine-König4b6f05e2012-04-24 10:05:22 +0200179 void __iomem *spare0;
180 void __iomem *main_area0;
Sascha Hauerc6de7e12009-10-05 11:14:35 +0200181
182 void __iomem *base;
Sascha Hauer34f6e152008-09-02 17:16:59 +0200183 void __iomem *regs;
Sascha Hauer71ec5152010-08-06 15:53:11 +0200184 void __iomem *regs_axi;
185 void __iomem *regs_ip;
Sascha Hauer34f6e152008-09-02 17:16:59 +0200186 int status_request;
Sascha Hauer34f6e152008-09-02 17:16:59 +0200187 struct clk *clk;
188 int clk_act;
189 int irq;
Sascha Hauer94f77e52010-08-06 15:53:09 +0200190 int eccsize;
Baruch Siachd178e3e2011-03-14 09:01:56 +0200191 int active_cs;
Sascha Hauer34f6e152008-09-02 17:16:59 +0200192
Sascha Hauer63f14742010-10-18 10:16:26 +0200193 struct completion op_completion;
Sascha Hauerf8f96082009-06-04 17:12:26 +0200194
195 uint8_t *data_buf;
196 unsigned int buf_start;
Sascha Hauer5f973042010-08-06 15:53:06 +0200197
Uwe Kleine-Könige4303b22012-04-23 11:23:35 +0200198 const struct mxc_nand_devtype_data *devtype_data;
Uwe Kleine-König64363562012-04-23 11:23:41 +0200199 struct mxc_nand_platform_data pdata;
Sascha Hauer34f6e152008-09-02 17:16:59 +0200200};
201
Sascha Hauer34f6e152008-09-02 17:16:59 +0200202/* OOB placement block for use with hardware ecc generation */
Sascha Hauer94671142009-10-05 12:14:21 +0200203static struct nand_ecclayout nandv1_hw_eccoob_smallpage = {
Sascha Hauer34f6e152008-09-02 17:16:59 +0200204 .eccbytes = 5,
205 .eccpos = {6, 7, 8, 9, 10},
Sascha Hauer8c1fd892009-10-21 10:22:01 +0200206 .oobfree = {{0, 5}, {12, 4}, }
Sascha Hauer34f6e152008-09-02 17:16:59 +0200207};
208
Sascha Hauer94671142009-10-05 12:14:21 +0200209static struct nand_ecclayout nandv1_hw_eccoob_largepage = {
Vladimir Barinovbd3fd622009-05-25 13:06:17 +0400210 .eccbytes = 20,
211 .eccpos = {6, 7, 8, 9, 10, 22, 23, 24, 25, 26,
212 38, 39, 40, 41, 42, 54, 55, 56, 57, 58},
213 .oobfree = {{2, 4}, {11, 10}, {27, 10}, {43, 10}, {59, 5}, }
Sascha Hauer34f6e152008-09-02 17:16:59 +0200214};
215
Sascha Hauer94671142009-10-05 12:14:21 +0200216/* OOB description for 512 byte pages with 16 byte OOB */
217static struct nand_ecclayout nandv2_hw_eccoob_smallpage = {
218 .eccbytes = 1 * 9,
219 .eccpos = {
220 7, 8, 9, 10, 11, 12, 13, 14, 15
221 },
222 .oobfree = {
223 {.offset = 0, .length = 5}
224 }
225};
226
227/* OOB description for 2048 byte pages with 64 byte OOB */
228static struct nand_ecclayout nandv2_hw_eccoob_largepage = {
229 .eccbytes = 4 * 9,
230 .eccpos = {
231 7, 8, 9, 10, 11, 12, 13, 14, 15,
232 23, 24, 25, 26, 27, 28, 29, 30, 31,
233 39, 40, 41, 42, 43, 44, 45, 46, 47,
234 55, 56, 57, 58, 59, 60, 61, 62, 63
235 },
236 .oobfree = {
237 {.offset = 2, .length = 4},
238 {.offset = 16, .length = 7},
239 {.offset = 32, .length = 7},
240 {.offset = 48, .length = 7}
241 }
242};
243
Baruch Siach2c1c5f12011-03-09 16:12:20 +0200244/* OOB description for 4096 byte pages with 128 byte OOB */
245static struct nand_ecclayout nandv2_hw_eccoob_4k = {
246 .eccbytes = 8 * 9,
247 .eccpos = {
248 7, 8, 9, 10, 11, 12, 13, 14, 15,
249 23, 24, 25, 26, 27, 28, 29, 30, 31,
250 39, 40, 41, 42, 43, 44, 45, 46, 47,
251 55, 56, 57, 58, 59, 60, 61, 62, 63,
252 71, 72, 73, 74, 75, 76, 77, 78, 79,
253 87, 88, 89, 90, 91, 92, 93, 94, 95,
254 103, 104, 105, 106, 107, 108, 109, 110, 111,
255 119, 120, 121, 122, 123, 124, 125, 126, 127,
256 },
257 .oobfree = {
258 {.offset = 2, .length = 4},
259 {.offset = 16, .length = 7},
260 {.offset = 32, .length = 7},
261 {.offset = 48, .length = 7},
262 {.offset = 64, .length = 7},
263 {.offset = 80, .length = 7},
264 {.offset = 96, .length = 7},
265 {.offset = 112, .length = 7},
266 }
267};
268
Uwe Kleine-König64363562012-04-23 11:23:41 +0200269static const char *part_probes[] = { "RedBoot", "cmdlinepart", "ofpart", NULL };
Sascha Hauer34f6e152008-09-02 17:16:59 +0200270
Sascha Hauer096bcc22012-05-29 10:16:09 +0200271static void memcpy32_fromio(void *trg, const void __iomem *src, size_t size)
272{
273 int i;
274 u32 *t = trg;
275 const __iomem u32 *s = src;
276
277 for (i = 0; i < (size >> 2); i++)
278 *t++ = __raw_readl(s++);
279}
280
281static void memcpy32_toio(void __iomem *trg, const void *src, int size)
282{
283 int i;
284 u32 __iomem *t = trg;
285 const u32 *s = src;
286
287 for (i = 0; i < (size >> 2); i++)
288 __raw_writel(*s++, t++);
289}
290
Sascha Hauer71ec5152010-08-06 15:53:11 +0200291static int check_int_v3(struct mxc_nand_host *host)
292{
293 uint32_t tmp;
294
295 tmp = readl(NFC_V3_IPC);
296 if (!(tmp & NFC_V3_IPC_INT))
297 return 0;
298
299 tmp &= ~NFC_V3_IPC_INT;
300 writel(tmp, NFC_V3_IPC);
301
302 return 1;
303}
304
Sascha Hauer7aaf28a2010-08-06 15:53:07 +0200305static int check_int_v1_v2(struct mxc_nand_host *host)
306{
307 uint32_t tmp;
308
Sascha Hauer1bc99182010-08-06 15:53:08 +0200309 tmp = readw(NFC_V1_V2_CONFIG2);
310 if (!(tmp & NFC_V1_V2_CONFIG2_INT))
Sascha Hauer7aaf28a2010-08-06 15:53:07 +0200311 return 0;
312
Uwe Kleine-Königf48d0f92012-04-23 11:23:40 +0200313 if (!host->devtype_data->irqpending_quirk)
Sascha Hauer63f14742010-10-18 10:16:26 +0200314 writew(tmp & ~NFC_V1_V2_CONFIG2_INT, NFC_V1_V2_CONFIG2);
Sascha Hauer7aaf28a2010-08-06 15:53:07 +0200315
316 return 1;
317}
318
Sascha Hauer63f14742010-10-18 10:16:26 +0200319static void irq_control_v1_v2(struct mxc_nand_host *host, int activate)
320{
321 uint16_t tmp;
322
323 tmp = readw(NFC_V1_V2_CONFIG1);
324
325 if (activate)
326 tmp &= ~NFC_V1_V2_CONFIG1_INT_MSK;
327 else
328 tmp |= NFC_V1_V2_CONFIG1_INT_MSK;
329
330 writew(tmp, NFC_V1_V2_CONFIG1);
331}
332
333static void irq_control_v3(struct mxc_nand_host *host, int activate)
334{
335 uint32_t tmp;
336
337 tmp = readl(NFC_V3_CONFIG2);
338
339 if (activate)
340 tmp &= ~NFC_V3_CONFIG2_INT_MSK;
341 else
342 tmp |= NFC_V3_CONFIG2_INT_MSK;
343
344 writel(tmp, NFC_V3_CONFIG2);
345}
346
Uwe Kleine-König85569582012-04-23 11:23:34 +0200347static void irq_control(struct mxc_nand_host *host, int activate)
348{
Uwe Kleine-Königf48d0f92012-04-23 11:23:40 +0200349 if (host->devtype_data->irqpending_quirk) {
Uwe Kleine-König85569582012-04-23 11:23:34 +0200350 if (activate)
351 enable_irq(host->irq);
352 else
353 disable_irq_nosync(host->irq);
354 } else {
Uwe Kleine-Könige4303b22012-04-23 11:23:35 +0200355 host->devtype_data->irq_control(host, activate);
Uwe Kleine-König85569582012-04-23 11:23:34 +0200356 }
357}
358
Uwe Kleine-König6d38af22012-04-23 11:23:36 +0200359static u32 get_ecc_status_v1(struct mxc_nand_host *host)
360{
361 return readw(NFC_V1_V2_ECC_STATUS_RESULT);
362}
363
364static u32 get_ecc_status_v2(struct mxc_nand_host *host)
365{
366 return readl(NFC_V1_V2_ECC_STATUS_RESULT);
367}
368
369static u32 get_ecc_status_v3(struct mxc_nand_host *host)
370{
371 return readl(NFC_V3_ECC_STATUS_RESULT);
372}
373
Uwe Kleine-König85569582012-04-23 11:23:34 +0200374static irqreturn_t mxc_nfc_irq(int irq, void *dev_id)
375{
376 struct mxc_nand_host *host = dev_id;
377
Uwe Kleine-Könige4303b22012-04-23 11:23:35 +0200378 if (!host->devtype_data->check_int(host))
Uwe Kleine-König85569582012-04-23 11:23:34 +0200379 return IRQ_NONE;
380
381 irq_control(host, 0);
382
383 complete(&host->op_completion);
384
385 return IRQ_HANDLED;
386}
387
Sascha Hauer34f6e152008-09-02 17:16:59 +0200388/* This function polls the NANDFC to wait for the basic operation to
389 * complete by checking the INT bit of config2 register.
390 */
Sascha Hauerc110eaf2009-10-21 16:01:02 +0200391static void wait_op_done(struct mxc_nand_host *host, int useirq)
Sascha Hauer34f6e152008-09-02 17:16:59 +0200392{
Ivo Claryssea47bfd22010-04-08 16:16:51 +0200393 int max_retries = 8000;
Sascha Hauer34f6e152008-09-02 17:16:59 +0200394
395 if (useirq) {
Uwe Kleine-Könige4303b22012-04-23 11:23:35 +0200396 if (!host->devtype_data->check_int(host)) {
Sascha Hauer63f14742010-10-18 10:16:26 +0200397 INIT_COMPLETION(host->op_completion);
Uwe Kleine-König85569582012-04-23 11:23:34 +0200398 irq_control(host, 1);
Sascha Hauer63f14742010-10-18 10:16:26 +0200399 wait_for_completion(&host->op_completion);
Sascha Hauer34f6e152008-09-02 17:16:59 +0200400 }
401 } else {
402 while (max_retries-- > 0) {
Uwe Kleine-Könige4303b22012-04-23 11:23:35 +0200403 if (host->devtype_data->check_int(host))
Sascha Hauer34f6e152008-09-02 17:16:59 +0200404 break;
Sascha Hauer7aaf28a2010-08-06 15:53:07 +0200405
Sascha Hauer34f6e152008-09-02 17:16:59 +0200406 udelay(1);
407 }
Roel Kluin43950a62009-06-04 16:24:59 +0200408 if (max_retries < 0)
Brian Norris0a32a102011-07-19 10:06:10 -0700409 pr_debug("%s: INT not set\n", __func__);
Sascha Hauer34f6e152008-09-02 17:16:59 +0200410 }
411}
412
Sascha Hauer71ec5152010-08-06 15:53:11 +0200413static void send_cmd_v3(struct mxc_nand_host *host, uint16_t cmd, int useirq)
414{
415 /* fill command */
416 writel(cmd, NFC_V3_FLASH_CMD);
417
418 /* send out command */
419 writel(NFC_CMD, NFC_V3_LAUNCH);
420
421 /* Wait for operation to complete */
422 wait_op_done(host, useirq);
423}
424
Sascha Hauer34f6e152008-09-02 17:16:59 +0200425/* This function issues the specified command to the NAND device and
426 * waits for completion. */
Sascha Hauer5f973042010-08-06 15:53:06 +0200427static void send_cmd_v1_v2(struct mxc_nand_host *host, uint16_t cmd, int useirq)
Sascha Hauer34f6e152008-09-02 17:16:59 +0200428{
Brian Norris289c0522011-07-19 10:06:09 -0700429 pr_debug("send_cmd(host, 0x%x, %d)\n", cmd, useirq);
Sascha Hauer34f6e152008-09-02 17:16:59 +0200430
Sascha Hauer1bc99182010-08-06 15:53:08 +0200431 writew(cmd, NFC_V1_V2_FLASH_CMD);
432 writew(NFC_CMD, NFC_V1_V2_CONFIG2);
Sascha Hauer34f6e152008-09-02 17:16:59 +0200433
Uwe Kleine-Königf48d0f92012-04-23 11:23:40 +0200434 if (host->devtype_data->irqpending_quirk && (cmd == NAND_CMD_RESET)) {
Ivo Claryssea47bfd22010-04-08 16:16:51 +0200435 int max_retries = 100;
436 /* Reset completion is indicated by NFC_CONFIG2 */
437 /* being set to 0 */
438 while (max_retries-- > 0) {
Sascha Hauer1bc99182010-08-06 15:53:08 +0200439 if (readw(NFC_V1_V2_CONFIG2) == 0) {
Ivo Claryssea47bfd22010-04-08 16:16:51 +0200440 break;
441 }
442 udelay(1);
443 }
444 if (max_retries < 0)
Brian Norris0a32a102011-07-19 10:06:10 -0700445 pr_debug("%s: RESET failed\n", __func__);
Ivo Claryssea47bfd22010-04-08 16:16:51 +0200446 } else {
447 /* Wait for operation to complete */
448 wait_op_done(host, useirq);
449 }
Sascha Hauer34f6e152008-09-02 17:16:59 +0200450}
451
Sascha Hauer71ec5152010-08-06 15:53:11 +0200452static void send_addr_v3(struct mxc_nand_host *host, uint16_t addr, int islast)
453{
454 /* fill address */
455 writel(addr, NFC_V3_FLASH_ADDR0);
456
457 /* send out address */
458 writel(NFC_ADDR, NFC_V3_LAUNCH);
459
460 wait_op_done(host, 0);
461}
462
Sascha Hauer34f6e152008-09-02 17:16:59 +0200463/* This function sends an address (or partial address) to the
464 * NAND device. The address is used to select the source/destination for
465 * a NAND command. */
Sascha Hauer5f973042010-08-06 15:53:06 +0200466static void send_addr_v1_v2(struct mxc_nand_host *host, uint16_t addr, int islast)
Sascha Hauer34f6e152008-09-02 17:16:59 +0200467{
Brian Norris289c0522011-07-19 10:06:09 -0700468 pr_debug("send_addr(host, 0x%x %d)\n", addr, islast);
Sascha Hauer34f6e152008-09-02 17:16:59 +0200469
Sascha Hauer1bc99182010-08-06 15:53:08 +0200470 writew(addr, NFC_V1_V2_FLASH_ADDR);
471 writew(NFC_ADDR, NFC_V1_V2_CONFIG2);
Sascha Hauer34f6e152008-09-02 17:16:59 +0200472
473 /* Wait for operation to complete */
Sascha Hauerc110eaf2009-10-21 16:01:02 +0200474 wait_op_done(host, islast);
Sascha Hauer34f6e152008-09-02 17:16:59 +0200475}
476
Sascha Hauer71ec5152010-08-06 15:53:11 +0200477static void send_page_v3(struct mtd_info *mtd, unsigned int ops)
478{
479 struct nand_chip *nand_chip = mtd->priv;
480 struct mxc_nand_host *host = nand_chip->priv;
481 uint32_t tmp;
482
483 tmp = readl(NFC_V3_CONFIG1);
484 tmp &= ~(7 << 4);
485 writel(tmp, NFC_V3_CONFIG1);
486
487 /* transfer data from NFC ram to nand */
488 writel(ops, NFC_V3_LAUNCH);
489
490 wait_op_done(host, false);
491}
492
Uwe Kleine-König6d38af22012-04-23 11:23:36 +0200493static void send_page_v2(struct mtd_info *mtd, unsigned int ops)
494{
495 struct nand_chip *nand_chip = mtd->priv;
496 struct mxc_nand_host *host = nand_chip->priv;
497
498 /* NANDFC buffer 0 is used for page read/write */
499 writew(host->active_cs << 4, NFC_V1_V2_BUF_ADDR);
500
501 writew(ops, NFC_V1_V2_CONFIG2);
502
503 /* Wait for operation to complete */
504 wait_op_done(host, true);
505}
506
507static void send_page_v1(struct mtd_info *mtd, unsigned int ops)
Sascha Hauer34f6e152008-09-02 17:16:59 +0200508{
Sascha Hauer2d69c7f2009-10-05 11:24:02 +0200509 struct nand_chip *nand_chip = mtd->priv;
510 struct mxc_nand_host *host = nand_chip->priv;
Sascha Hauerc5d23f12009-06-04 17:25:53 +0200511 int bufs, i;
Sascha Hauer34f6e152008-09-02 17:16:59 +0200512
Uwe Kleine-König6d38af22012-04-23 11:23:36 +0200513 if (mtd->writesize > 512)
Sascha Hauerc5d23f12009-06-04 17:25:53 +0200514 bufs = 4;
515 else
516 bufs = 1;
Sascha Hauer34f6e152008-09-02 17:16:59 +0200517
Sascha Hauerc5d23f12009-06-04 17:25:53 +0200518 for (i = 0; i < bufs; i++) {
519
520 /* NANDFC buffer 0 is used for page read/write */
Baruch Siachd178e3e2011-03-14 09:01:56 +0200521 writew((host->active_cs << 4) | i, NFC_V1_V2_BUF_ADDR);
Sascha Hauerc5d23f12009-06-04 17:25:53 +0200522
Sascha Hauer1bc99182010-08-06 15:53:08 +0200523 writew(ops, NFC_V1_V2_CONFIG2);
Sascha Hauerc5d23f12009-06-04 17:25:53 +0200524
525 /* Wait for operation to complete */
Sascha Hauerc110eaf2009-10-21 16:01:02 +0200526 wait_op_done(host, true);
Sascha Hauer34f6e152008-09-02 17:16:59 +0200527 }
Sascha Hauer34f6e152008-09-02 17:16:59 +0200528}
529
Sascha Hauer71ec5152010-08-06 15:53:11 +0200530static void send_read_id_v3(struct mxc_nand_host *host)
531{
532 /* Read ID into main buffer */
533 writel(NFC_ID, NFC_V3_LAUNCH);
534
535 wait_op_done(host, true);
536
Sascha Hauer096bcc22012-05-29 10:16:09 +0200537 memcpy32_fromio(host->data_buf, host->main_area0, 16);
Sascha Hauer71ec5152010-08-06 15:53:11 +0200538}
539
Sascha Hauer34f6e152008-09-02 17:16:59 +0200540/* Request the NANDFC to perform a read of the NAND device ID. */
Sascha Hauer5f973042010-08-06 15:53:06 +0200541static void send_read_id_v1_v2(struct mxc_nand_host *host)
Sascha Hauer34f6e152008-09-02 17:16:59 +0200542{
543 struct nand_chip *this = &host->nand;
Sascha Hauer34f6e152008-09-02 17:16:59 +0200544
545 /* NANDFC buffer 0 is used for device ID output */
Baruch Siachd178e3e2011-03-14 09:01:56 +0200546 writew(host->active_cs << 4, NFC_V1_V2_BUF_ADDR);
Sascha Hauer34f6e152008-09-02 17:16:59 +0200547
Sascha Hauer1bc99182010-08-06 15:53:08 +0200548 writew(NFC_ID, NFC_V1_V2_CONFIG2);
Sascha Hauer34f6e152008-09-02 17:16:59 +0200549
550 /* Wait for operation to complete */
Sascha Hauerc110eaf2009-10-21 16:01:02 +0200551 wait_op_done(host, true);
Sascha Hauer34f6e152008-09-02 17:16:59 +0200552
Sascha Hauer096bcc22012-05-29 10:16:09 +0200553 memcpy32_fromio(host->data_buf, host->main_area0, 16);
John Ognessf7b66e52010-06-18 18:59:47 +0200554
555 if (this->options & NAND_BUSWIDTH_16) {
556 /* compress the ID info */
557 host->data_buf[1] = host->data_buf[2];
558 host->data_buf[2] = host->data_buf[4];
559 host->data_buf[3] = host->data_buf[6];
560 host->data_buf[4] = host->data_buf[8];
561 host->data_buf[5] = host->data_buf[10];
562 }
Sascha Hauer34f6e152008-09-02 17:16:59 +0200563}
564
Sascha Hauer71ec5152010-08-06 15:53:11 +0200565static uint16_t get_dev_status_v3(struct mxc_nand_host *host)
Sascha Hauer34f6e152008-09-02 17:16:59 +0200566{
Sascha Hauer71ec5152010-08-06 15:53:11 +0200567 writew(NFC_STATUS, NFC_V3_LAUNCH);
Sascha Hauerc110eaf2009-10-21 16:01:02 +0200568 wait_op_done(host, true);
Sascha Hauer34f6e152008-09-02 17:16:59 +0200569
Sascha Hauer71ec5152010-08-06 15:53:11 +0200570 return readl(NFC_V3_CONFIG1) >> 16;
571}
572
Sascha Hauer34f6e152008-09-02 17:16:59 +0200573/* This function requests the NANDFC to perform a read of the
574 * NAND device status and returns the current status. */
Sascha Hauer5f973042010-08-06 15:53:06 +0200575static uint16_t get_dev_status_v1_v2(struct mxc_nand_host *host)
Sascha Hauer34f6e152008-09-02 17:16:59 +0200576{
Sascha Hauerc29c6072010-08-06 15:53:05 +0200577 void __iomem *main_buf = host->main_area0;
Sascha Hauer34f6e152008-09-02 17:16:59 +0200578 uint32_t store;
579 uint16_t ret;
Sascha Hauer34f6e152008-09-02 17:16:59 +0200580
Baruch Siachd178e3e2011-03-14 09:01:56 +0200581 writew(host->active_cs << 4, NFC_V1_V2_BUF_ADDR);
Sascha Hauerc29c6072010-08-06 15:53:05 +0200582
583 /*
584 * The device status is stored in main_area0. To
585 * prevent corruption of the buffer save the value
586 * and restore it afterwards.
587 */
Sascha Hauer34f6e152008-09-02 17:16:59 +0200588 store = readl(main_buf);
Sascha Hauer34f6e152008-09-02 17:16:59 +0200589
Sascha Hauer1bc99182010-08-06 15:53:08 +0200590 writew(NFC_STATUS, NFC_V1_V2_CONFIG2);
Sascha Hauer34f6e152008-09-02 17:16:59 +0200591 wait_op_done(host, true);
592
Sascha Hauer34f6e152008-09-02 17:16:59 +0200593 ret = readw(main_buf);
Sascha Hauerc29c6072010-08-06 15:53:05 +0200594
Sascha Hauer34f6e152008-09-02 17:16:59 +0200595 writel(store, main_buf);
596
597 return ret;
598}
599
600/* This functions is used by upper layer to checks if device is ready */
601static int mxc_nand_dev_ready(struct mtd_info *mtd)
602{
603 /*
604 * NFC handles R/B internally. Therefore, this function
605 * always returns status as ready.
606 */
607 return 1;
608}
609
610static void mxc_nand_enable_hwecc(struct mtd_info *mtd, int mode)
611{
612 /*
613 * If HW ECC is enabled, we turn it on during init. There is
614 * no need to enable again here.
615 */
616}
617
Sascha Hauer94f77e52010-08-06 15:53:09 +0200618static int mxc_nand_correct_data_v1(struct mtd_info *mtd, u_char *dat,
Sascha Hauer34f6e152008-09-02 17:16:59 +0200619 u_char *read_ecc, u_char *calc_ecc)
620{
621 struct nand_chip *nand_chip = mtd->priv;
622 struct mxc_nand_host *host = nand_chip->priv;
623
624 /*
625 * 1-Bit errors are automatically corrected in HW. No need for
626 * additional correction. 2-Bit errors cannot be corrected by
627 * HW ECC, so we need to return failure
628 */
Uwe Kleine-König6d38af22012-04-23 11:23:36 +0200629 uint16_t ecc_status = get_ecc_status_v1(host);
Sascha Hauer34f6e152008-09-02 17:16:59 +0200630
631 if (((ecc_status & 0x3) == 2) || ((ecc_status >> 2) == 2)) {
Brian Norris289c0522011-07-19 10:06:09 -0700632 pr_debug("MXC_NAND: HWECC uncorrectable 2-bit ECC error\n");
Sascha Hauer34f6e152008-09-02 17:16:59 +0200633 return -1;
634 }
635
636 return 0;
637}
638
Sascha Hauer94f77e52010-08-06 15:53:09 +0200639static int mxc_nand_correct_data_v2_v3(struct mtd_info *mtd, u_char *dat,
640 u_char *read_ecc, u_char *calc_ecc)
641{
642 struct nand_chip *nand_chip = mtd->priv;
643 struct mxc_nand_host *host = nand_chip->priv;
644 u32 ecc_stat, err;
645 int no_subpages = 1;
646 int ret = 0;
647 u8 ecc_bit_mask, err_limit;
648
649 ecc_bit_mask = (host->eccsize == 4) ? 0x7 : 0xf;
650 err_limit = (host->eccsize == 4) ? 0x4 : 0x8;
651
652 no_subpages = mtd->writesize >> 9;
653
Uwe Kleine-König6d38af22012-04-23 11:23:36 +0200654 ecc_stat = host->devtype_data->get_ecc_status(host);
Sascha Hauer94f77e52010-08-06 15:53:09 +0200655
656 do {
657 err = ecc_stat & ecc_bit_mask;
658 if (err > err_limit) {
659 printk(KERN_WARNING "UnCorrectable RS-ECC Error\n");
660 return -1;
661 } else {
662 ret += err;
663 }
664 ecc_stat >>= 4;
665 } while (--no_subpages);
666
667 mtd->ecc_stats.corrected += ret;
668 pr_debug("%d Symbol Correctable RS-ECC Error\n", ret);
669
670 return ret;
671}
672
Sascha Hauer34f6e152008-09-02 17:16:59 +0200673static int mxc_nand_calculate_ecc(struct mtd_info *mtd, const u_char *dat,
674 u_char *ecc_code)
675{
676 return 0;
677}
678
679static u_char mxc_nand_read_byte(struct mtd_info *mtd)
680{
681 struct nand_chip *nand_chip = mtd->priv;
682 struct mxc_nand_host *host = nand_chip->priv;
Sascha Hauerf8f96082009-06-04 17:12:26 +0200683 uint8_t ret;
Sascha Hauer34f6e152008-09-02 17:16:59 +0200684
685 /* Check for status request */
686 if (host->status_request)
Uwe Kleine-Könige4303b22012-04-23 11:23:35 +0200687 return host->devtype_data->get_dev_status(host) & 0xFF;
Sascha Hauer34f6e152008-09-02 17:16:59 +0200688
Sascha Hauerf8f96082009-06-04 17:12:26 +0200689 ret = *(uint8_t *)(host->data_buf + host->buf_start);
690 host->buf_start++;
Sascha Hauer34f6e152008-09-02 17:16:59 +0200691
692 return ret;
693}
694
695static uint16_t mxc_nand_read_word(struct mtd_info *mtd)
696{
697 struct nand_chip *nand_chip = mtd->priv;
698 struct mxc_nand_host *host = nand_chip->priv;
Sascha Hauerf8f96082009-06-04 17:12:26 +0200699 uint16_t ret;
Sascha Hauer34f6e152008-09-02 17:16:59 +0200700
Sascha Hauerf8f96082009-06-04 17:12:26 +0200701 ret = *(uint16_t *)(host->data_buf + host->buf_start);
702 host->buf_start += 2;
Sascha Hauer34f6e152008-09-02 17:16:59 +0200703
704 return ret;
705}
706
707/* Write data of length len to buffer buf. The data to be
708 * written on NAND Flash is first copied to RAMbuffer. After the Data Input
709 * Operation by the NFC, the data is written to NAND Flash */
710static void mxc_nand_write_buf(struct mtd_info *mtd,
711 const u_char *buf, int len)
712{
713 struct nand_chip *nand_chip = mtd->priv;
714 struct mxc_nand_host *host = nand_chip->priv;
Sascha Hauerf8f96082009-06-04 17:12:26 +0200715 u16 col = host->buf_start;
716 int n = mtd->oobsize + mtd->writesize - col;
Sascha Hauer34f6e152008-09-02 17:16:59 +0200717
Sascha Hauerf8f96082009-06-04 17:12:26 +0200718 n = min(n, len);
Sascha Hauer34f6e152008-09-02 17:16:59 +0200719
Sascha Hauerf8f96082009-06-04 17:12:26 +0200720 memcpy(host->data_buf + col, buf, n);
Sascha Hauer34f6e152008-09-02 17:16:59 +0200721
Sascha Hauerf8f96082009-06-04 17:12:26 +0200722 host->buf_start += n;
Sascha Hauer34f6e152008-09-02 17:16:59 +0200723}
724
725/* Read the data buffer from the NAND Flash. To read the data from NAND
726 * Flash first the data output cycle is initiated by the NFC, which copies
727 * the data to RAMbuffer. This data of length len is then copied to buffer buf.
728 */
729static void mxc_nand_read_buf(struct mtd_info *mtd, u_char *buf, int len)
730{
731 struct nand_chip *nand_chip = mtd->priv;
732 struct mxc_nand_host *host = nand_chip->priv;
Sascha Hauerf8f96082009-06-04 17:12:26 +0200733 u16 col = host->buf_start;
734 int n = mtd->oobsize + mtd->writesize - col;
Sascha Hauer34f6e152008-09-02 17:16:59 +0200735
Sascha Hauerf8f96082009-06-04 17:12:26 +0200736 n = min(n, len);
Sascha Hauer34f6e152008-09-02 17:16:59 +0200737
Baruch Siach5d9d9932011-03-02 16:47:55 +0200738 memcpy(buf, host->data_buf + col, n);
Sascha Hauer34f6e152008-09-02 17:16:59 +0200739
Baruch Siach5d9d9932011-03-02 16:47:55 +0200740 host->buf_start += n;
Sascha Hauer34f6e152008-09-02 17:16:59 +0200741}
742
Sascha Hauer34f6e152008-09-02 17:16:59 +0200743/* This function is used by upper layer for select and
744 * deselect of the NAND chip */
Uwe Kleine-König5e05a2d62012-04-23 11:23:38 +0200745static void mxc_nand_select_chip_v1_v3(struct mtd_info *mtd, int chip)
Sascha Hauer34f6e152008-09-02 17:16:59 +0200746{
747 struct nand_chip *nand_chip = mtd->priv;
748 struct mxc_nand_host *host = nand_chip->priv;
749
Baruch Siachd178e3e2011-03-14 09:01:56 +0200750 if (chip == -1) {
Sascha Hauer34f6e152008-09-02 17:16:59 +0200751 /* Disable the NFC clock */
752 if (host->clk_act) {
Sascha Hauer97c32132012-03-07 20:56:35 +0100753 clk_disable_unprepare(host->clk);
Sascha Hauer34f6e152008-09-02 17:16:59 +0200754 host->clk_act = 0;
755 }
Baruch Siachd178e3e2011-03-14 09:01:56 +0200756 return;
757 }
Sascha Hauer34f6e152008-09-02 17:16:59 +0200758
Baruch Siachd178e3e2011-03-14 09:01:56 +0200759 if (!host->clk_act) {
760 /* Enable the NFC clock */
Sascha Hauer97c32132012-03-07 20:56:35 +0100761 clk_prepare_enable(host->clk);
Baruch Siachd178e3e2011-03-14 09:01:56 +0200762 host->clk_act = 1;
763 }
Uwe Kleine-König5e05a2d62012-04-23 11:23:38 +0200764}
Baruch Siachd178e3e2011-03-14 09:01:56 +0200765
Uwe Kleine-König5e05a2d62012-04-23 11:23:38 +0200766static void mxc_nand_select_chip_v2(struct mtd_info *mtd, int chip)
Sascha Hauer34f6e152008-09-02 17:16:59 +0200767{
768 struct nand_chip *nand_chip = mtd->priv;
769 struct mxc_nand_host *host = nand_chip->priv;
770
771 if (chip == -1) {
772 /* Disable the NFC clock */
773 if (host->clk_act) {
Fabio Estevam3d059692012-05-25 20:14:50 -0300774 clk_disable_unprepare(host->clk);
Sascha Hauer34f6e152008-09-02 17:16:59 +0200775 host->clk_act = 0;
776 }
777 return;
Sascha Hauer34f6e152008-09-02 17:16:59 +0200778 }
Sascha Hauer34f6e152008-09-02 17:16:59 +0200779
780 if (!host->clk_act) {
781 /* Enable the NFC clock */
Fabio Estevam3d059692012-05-25 20:14:50 -0300782 clk_prepare_enable(host->clk);
Sascha Hauer34f6e152008-09-02 17:16:59 +0200783 host->clk_act = 1;
784 }
785
Uwe Kleine-König5e05a2d62012-04-23 11:23:38 +0200786 host->active_cs = chip;
787 writew(host->active_cs << 4, NFC_V1_V2_BUF_ADDR);
Sascha Hauer34f6e152008-09-02 17:16:59 +0200788}
789
Sascha Hauerf8f96082009-06-04 17:12:26 +0200790/*
791 * Function to transfer data to/from spare area.
792 */
793static void copy_spare(struct mtd_info *mtd, bool bfrom)
794{
795 struct nand_chip *this = mtd->priv;
796 struct mxc_nand_host *host = this->priv;
797 u16 i, j;
798 u16 n = mtd->writesize >> 9;
799 u8 *d = host->data_buf + mtd->writesize;
Uwe Kleine-König4b6f05e2012-04-24 10:05:22 +0200800 u8 __iomem *s = host->spare0;
Uwe Kleine-Königf48d0f92012-04-23 11:23:40 +0200801 u16 t = host->devtype_data->spare_len;
Sascha Hauerf8f96082009-06-04 17:12:26 +0200802
803 j = (mtd->oobsize / n >> 1) << 1;
804
805 if (bfrom) {
806 for (i = 0; i < n - 1; i++)
Sascha Hauer096bcc22012-05-29 10:16:09 +0200807 memcpy32_fromio(d + i * j, s + i * t, j);
Sascha Hauerf8f96082009-06-04 17:12:26 +0200808
809 /* the last section */
Sascha Hauer096bcc22012-05-29 10:16:09 +0200810 memcpy32_fromio(d + i * j, s + i * t, mtd->oobsize - i * j);
Sascha Hauerf8f96082009-06-04 17:12:26 +0200811 } else {
812 for (i = 0; i < n - 1; i++)
Sascha Hauer096bcc22012-05-29 10:16:09 +0200813 memcpy32_toio(&s[i * t], &d[i * j], j);
Sascha Hauerf8f96082009-06-04 17:12:26 +0200814
815 /* the last section */
Sascha Hauer096bcc22012-05-29 10:16:09 +0200816 memcpy32_toio(&s[i * t], &d[i * j], mtd->oobsize - i * j);
Sascha Hauerf8f96082009-06-04 17:12:26 +0200817 }
818}
819
Sascha Hauera3e65b62009-06-02 11:47:59 +0200820static void mxc_do_addr_cycle(struct mtd_info *mtd, int column, int page_addr)
Sascha Hauer34f6e152008-09-02 17:16:59 +0200821{
822 struct nand_chip *nand_chip = mtd->priv;
823 struct mxc_nand_host *host = nand_chip->priv;
Sascha Hauer34f6e152008-09-02 17:16:59 +0200824
825 /* Write out column address, if necessary */
826 if (column != -1) {
827 /*
828 * MXC NANDFC can only perform full page+spare or
829 * spare-only read/write. When the upper layers
Gilles Espinasse177b2412011-01-09 08:59:49 +0100830 * perform a read/write buf operation, the saved column
831 * address is used to index into the full page.
Sascha Hauer34f6e152008-09-02 17:16:59 +0200832 */
Uwe Kleine-Könige4303b22012-04-23 11:23:35 +0200833 host->devtype_data->send_addr(host, 0, page_addr == -1);
Sascha Hauer2d69c7f2009-10-05 11:24:02 +0200834 if (mtd->writesize > 512)
Sascha Hauer34f6e152008-09-02 17:16:59 +0200835 /* another col addr cycle for 2k page */
Uwe Kleine-Könige4303b22012-04-23 11:23:35 +0200836 host->devtype_data->send_addr(host, 0, false);
Sascha Hauer34f6e152008-09-02 17:16:59 +0200837 }
838
839 /* Write out page address, if necessary */
840 if (page_addr != -1) {
841 /* paddr_0 - p_addr_7 */
Uwe Kleine-Könige4303b22012-04-23 11:23:35 +0200842 host->devtype_data->send_addr(host, (page_addr & 0xff), false);
Sascha Hauer34f6e152008-09-02 17:16:59 +0200843
Sascha Hauer2d69c7f2009-10-05 11:24:02 +0200844 if (mtd->writesize > 512) {
Vladimir Barinovbd3fd622009-05-25 13:06:17 +0400845 if (mtd->size >= 0x10000000) {
846 /* paddr_8 - paddr_15 */
Uwe Kleine-Könige4303b22012-04-23 11:23:35 +0200847 host->devtype_data->send_addr(host,
848 (page_addr >> 8) & 0xff,
849 false);
850 host->devtype_data->send_addr(host,
851 (page_addr >> 16) & 0xff,
852 true);
Vladimir Barinovbd3fd622009-05-25 13:06:17 +0400853 } else
854 /* paddr_8 - paddr_15 */
Uwe Kleine-Könige4303b22012-04-23 11:23:35 +0200855 host->devtype_data->send_addr(host,
856 (page_addr >> 8) & 0xff, true);
Sascha Hauer34f6e152008-09-02 17:16:59 +0200857 } else {
858 /* One more address cycle for higher density devices */
859 if (mtd->size >= 0x4000000) {
860 /* paddr_8 - paddr_15 */
Uwe Kleine-Könige4303b22012-04-23 11:23:35 +0200861 host->devtype_data->send_addr(host,
862 (page_addr >> 8) & 0xff,
863 false);
864 host->devtype_data->send_addr(host,
865 (page_addr >> 16) & 0xff,
866 true);
Sascha Hauer34f6e152008-09-02 17:16:59 +0200867 } else
868 /* paddr_8 - paddr_15 */
Uwe Kleine-Könige4303b22012-04-23 11:23:35 +0200869 host->devtype_data->send_addr(host,
870 (page_addr >> 8) & 0xff, true);
Sascha Hauer34f6e152008-09-02 17:16:59 +0200871 }
872 }
Sascha Hauera3e65b62009-06-02 11:47:59 +0200873}
Sascha Hauer34f6e152008-09-02 17:16:59 +0200874
Sascha Hauer6e85dfd2010-08-06 15:53:10 +0200875/*
876 * v2 and v3 type controllers can do 4bit or 8bit ecc depending
877 * on how much oob the nand chip has. For 8bit ecc we need at least
878 * 26 bytes of oob data per 512 byte block.
879 */
880static int get_eccsize(struct mtd_info *mtd)
881{
882 int oobbytes_per_512 = 0;
883
884 oobbytes_per_512 = mtd->oobsize * 512 / mtd->writesize;
885
886 if (oobbytes_per_512 < 26)
887 return 4;
888 else
889 return 8;
890}
891
Uwe Kleine-König6d38af22012-04-23 11:23:36 +0200892static void preset_v1(struct mtd_info *mtd)
Ivo Claryssed4840182010-04-08 16:14:44 +0200893{
894 struct nand_chip *nand_chip = mtd->priv;
895 struct mxc_nand_host *host = nand_chip->priv;
Sascha Hauerb8db2f52010-08-09 15:04:19 +0200896 uint16_t config1 = 0;
Ivo Claryssed4840182010-04-08 16:14:44 +0200897
Sascha Hauerb8db2f52010-08-09 15:04:19 +0200898 if (nand_chip->ecc.mode == NAND_ECC_HW)
899 config1 |= NFC_V1_V2_CONFIG1_ECC_EN;
900
Uwe Kleine-Königf48d0f92012-04-23 11:23:40 +0200901 if (!host->devtype_data->irqpending_quirk)
Sascha Hauerb8db2f52010-08-09 15:04:19 +0200902 config1 |= NFC_V1_V2_CONFIG1_INT_MSK;
Sascha Hauer6e85dfd2010-08-06 15:53:10 +0200903
Uwe Kleine-König6d38af22012-04-23 11:23:36 +0200904 host->eccsize = 1;
905
906 writew(config1, NFC_V1_V2_CONFIG1);
907 /* preset operation */
908
909 /* Unlock the internal RAM Buffer */
910 writew(0x2, NFC_V1_V2_CONFIG);
911
912 /* Blocks to be unlocked */
913 writew(0x0, NFC_V1_UNLOCKSTART_BLKADDR);
914 writew(0xffff, NFC_V1_UNLOCKEND_BLKADDR);
915
916 /* Unlock Block Command for given address range */
917 writew(0x4, NFC_V1_V2_WRPROT);
918}
919
920static void preset_v2(struct mtd_info *mtd)
921{
922 struct nand_chip *nand_chip = mtd->priv;
923 struct mxc_nand_host *host = nand_chip->priv;
924 uint16_t config1 = 0;
925
926 if (nand_chip->ecc.mode == NAND_ECC_HW)
927 config1 |= NFC_V1_V2_CONFIG1_ECC_EN;
928
929 config1 |= NFC_V2_CONFIG1_FP_INT;
Ivo Claryssed4840182010-04-08 16:14:44 +0200930
Uwe Kleine-Königf48d0f92012-04-23 11:23:40 +0200931 if (!host->devtype_data->irqpending_quirk)
Ivo Claryssed4840182010-04-08 16:14:44 +0200932 config1 |= NFC_V1_V2_CONFIG1_INT_MSK;
Sascha Hauer6e85dfd2010-08-06 15:53:10 +0200933
Uwe Kleine-König6d38af22012-04-23 11:23:36 +0200934 if (mtd->writesize) {
Sascha Hauerb8db2f52010-08-09 15:04:19 +0200935 uint16_t pages_per_block = mtd->erasesize / mtd->writesize;
936
Sascha Hauer6e85dfd2010-08-06 15:53:10 +0200937 host->eccsize = get_eccsize(mtd);
938 if (host->eccsize == 4)
Sascha Hauerb8db2f52010-08-09 15:04:19 +0200939 config1 |= NFC_V2_CONFIG1_ECC_MODE_4;
940
941 config1 |= NFC_V2_CONFIG1_PPB(ffs(pages_per_block) - 6);
Sascha Hauer6e85dfd2010-08-06 15:53:10 +0200942 } else {
943 host->eccsize = 1;
944 }
945
Sascha Hauerb8db2f52010-08-09 15:04:19 +0200946 writew(config1, NFC_V1_V2_CONFIG1);
Ivo Claryssed4840182010-04-08 16:14:44 +0200947 /* preset operation */
948
949 /* Unlock the internal RAM Buffer */
Sascha Hauer1bc99182010-08-06 15:53:08 +0200950 writew(0x2, NFC_V1_V2_CONFIG);
Ivo Claryssed4840182010-04-08 16:14:44 +0200951
952 /* Blocks to be unlocked */
Uwe Kleine-König6d38af22012-04-23 11:23:36 +0200953 writew(0x0, NFC_V21_UNLOCKSTART_BLKADDR0);
954 writew(0x0, NFC_V21_UNLOCKSTART_BLKADDR1);
955 writew(0x0, NFC_V21_UNLOCKSTART_BLKADDR2);
956 writew(0x0, NFC_V21_UNLOCKSTART_BLKADDR3);
957 writew(0xffff, NFC_V21_UNLOCKEND_BLKADDR0);
958 writew(0xffff, NFC_V21_UNLOCKEND_BLKADDR1);
959 writew(0xffff, NFC_V21_UNLOCKEND_BLKADDR2);
960 writew(0xffff, NFC_V21_UNLOCKEND_BLKADDR3);
Ivo Claryssed4840182010-04-08 16:14:44 +0200961
962 /* Unlock Block Command for given address range */
Sascha Hauer1bc99182010-08-06 15:53:08 +0200963 writew(0x4, NFC_V1_V2_WRPROT);
Ivo Claryssed4840182010-04-08 16:14:44 +0200964}
965
Sascha Hauer71ec5152010-08-06 15:53:11 +0200966static void preset_v3(struct mtd_info *mtd)
967{
968 struct nand_chip *chip = mtd->priv;
969 struct mxc_nand_host *host = chip->priv;
970 uint32_t config2, config3;
971 int i, addr_phases;
972
973 writel(NFC_V3_CONFIG1_RBA(0), NFC_V3_CONFIG1);
974 writel(NFC_V3_IPC_CREQ, NFC_V3_IPC);
975
976 /* Unlock the internal RAM Buffer */
977 writel(NFC_V3_WRPROT_BLS_UNLOCK | NFC_V3_WRPROT_UNLOCK,
978 NFC_V3_WRPROT);
979
980 /* Blocks to be unlocked */
981 for (i = 0; i < NAND_MAX_CHIPS; i++)
982 writel(0x0 | (0xffff << 16),
983 NFC_V3_WRPROT_UNLOCK_BLK_ADD0 + (i << 2));
984
985 writel(0, NFC_V3_IPC);
986
987 config2 = NFC_V3_CONFIG2_ONE_CYCLE |
988 NFC_V3_CONFIG2_2CMD_PHASES |
989 NFC_V3_CONFIG2_SPAS(mtd->oobsize >> 1) |
990 NFC_V3_CONFIG2_ST_CMD(0x70) |
Sascha Hauer63f14742010-10-18 10:16:26 +0200991 NFC_V3_CONFIG2_INT_MSK |
Sascha Hauer71ec5152010-08-06 15:53:11 +0200992 NFC_V3_CONFIG2_NUM_ADDR_PHASE0;
993
994 if (chip->ecc.mode == NAND_ECC_HW)
995 config2 |= NFC_V3_CONFIG2_ECC_EN;
996
997 addr_phases = fls(chip->pagemask) >> 3;
998
999 if (mtd->writesize == 2048) {
1000 config2 |= NFC_V3_CONFIG2_PS_2048;
1001 config2 |= NFC_V3_CONFIG2_NUM_ADDR_PHASE1(addr_phases);
1002 } else if (mtd->writesize == 4096) {
1003 config2 |= NFC_V3_CONFIG2_PS_4096;
1004 config2 |= NFC_V3_CONFIG2_NUM_ADDR_PHASE1(addr_phases);
1005 } else {
1006 config2 |= NFC_V3_CONFIG2_PS_512;
1007 config2 |= NFC_V3_CONFIG2_NUM_ADDR_PHASE1(addr_phases - 1);
1008 }
1009
1010 if (mtd->writesize) {
Sascha Hauer71718a8e2012-06-06 12:33:15 +02001011 config2 |= NFC_V3_CONFIG2_PPB(
1012 ffs(mtd->erasesize / mtd->writesize) - 6,
1013 host->devtype_data->ppb_shift);
Sascha Hauer71ec5152010-08-06 15:53:11 +02001014 host->eccsize = get_eccsize(mtd);
1015 if (host->eccsize == 8)
1016 config2 |= NFC_V3_CONFIG2_ECC_MODE_8;
1017 }
1018
1019 writel(config2, NFC_V3_CONFIG2);
1020
1021 config3 = NFC_V3_CONFIG3_NUM_OF_DEVICES(0) |
1022 NFC_V3_CONFIG3_NO_SDMA |
1023 NFC_V3_CONFIG3_RBB_MODE |
1024 NFC_V3_CONFIG3_SBB(6) | /* Reset default */
1025 NFC_V3_CONFIG3_ADD_OP(0);
1026
1027 if (!(chip->options & NAND_BUSWIDTH_16))
1028 config3 |= NFC_V3_CONFIG3_FW8;
1029
1030 writel(config3, NFC_V3_CONFIG3);
1031
1032 writel(0, NFC_V3_DELAY_LINE);
Sascha Hauer34f6e152008-09-02 17:16:59 +02001033}
1034
Sascha Hauer34f6e152008-09-02 17:16:59 +02001035/* Used by the upper layer to write command to NAND Flash for
1036 * different operations to be carried out on NAND Flash */
1037static void mxc_nand_command(struct mtd_info *mtd, unsigned command,
1038 int column, int page_addr)
1039{
1040 struct nand_chip *nand_chip = mtd->priv;
1041 struct mxc_nand_host *host = nand_chip->priv;
Sascha Hauer34f6e152008-09-02 17:16:59 +02001042
Brian Norris289c0522011-07-19 10:06:09 -07001043 pr_debug("mxc_nand_command (cmd = 0x%x, col = 0x%x, page = 0x%x)\n",
Sascha Hauer34f6e152008-09-02 17:16:59 +02001044 command, column, page_addr);
1045
1046 /* Reset command state information */
1047 host->status_request = false;
1048
1049 /* Command pre-processing step */
Sascha Hauer34f6e152008-09-02 17:16:59 +02001050 switch (command) {
Ivo Claryssed4840182010-04-08 16:14:44 +02001051 case NAND_CMD_RESET:
Uwe Kleine-Könige4303b22012-04-23 11:23:35 +02001052 host->devtype_data->preset(mtd);
1053 host->devtype_data->send_cmd(host, command, false);
Ivo Claryssed4840182010-04-08 16:14:44 +02001054 break;
Sascha Hauer34f6e152008-09-02 17:16:59 +02001055
Sascha Hauer34f6e152008-09-02 17:16:59 +02001056 case NAND_CMD_STATUS:
Sascha Hauerf8f96082009-06-04 17:12:26 +02001057 host->buf_start = 0;
Sascha Hauer34f6e152008-09-02 17:16:59 +02001058 host->status_request = true;
Sascha Hauer89121a62009-06-04 17:18:01 +02001059
Uwe Kleine-Könige4303b22012-04-23 11:23:35 +02001060 host->devtype_data->send_cmd(host, command, true);
Sascha Hauer89121a62009-06-04 17:18:01 +02001061 mxc_do_addr_cycle(mtd, column, page_addr);
Sascha Hauer34f6e152008-09-02 17:16:59 +02001062 break;
1063
Sascha Hauer34f6e152008-09-02 17:16:59 +02001064 case NAND_CMD_READ0:
Sascha Hauer34f6e152008-09-02 17:16:59 +02001065 case NAND_CMD_READOOB:
Sascha Hauer89121a62009-06-04 17:18:01 +02001066 if (command == NAND_CMD_READ0)
1067 host->buf_start = column;
1068 else
1069 host->buf_start = column + mtd->writesize;
Sascha Hauerf8f96082009-06-04 17:12:26 +02001070
Sascha Hauer5ea32022010-04-27 15:24:01 +02001071 command = NAND_CMD_READ0; /* only READ0 is valid */
Sascha Hauer89121a62009-06-04 17:18:01 +02001072
Uwe Kleine-Könige4303b22012-04-23 11:23:35 +02001073 host->devtype_data->send_cmd(host, command, false);
Sascha Hauer89121a62009-06-04 17:18:01 +02001074 mxc_do_addr_cycle(mtd, column, page_addr);
1075
Sascha Hauer2d69c7f2009-10-05 11:24:02 +02001076 if (mtd->writesize > 512)
Uwe Kleine-Könige4303b22012-04-23 11:23:35 +02001077 host->devtype_data->send_cmd(host,
1078 NAND_CMD_READSTART, true);
Sascha Hauerc5d23f12009-06-04 17:25:53 +02001079
Uwe Kleine-Könige4303b22012-04-23 11:23:35 +02001080 host->devtype_data->send_page(mtd, NFC_OUTPUT);
Sascha Hauer89121a62009-06-04 17:18:01 +02001081
Sascha Hauer096bcc22012-05-29 10:16:09 +02001082 memcpy32_fromio(host->data_buf, host->main_area0,
1083 mtd->writesize);
Sascha Hauer89121a62009-06-04 17:18:01 +02001084 copy_spare(mtd, true);
Sascha Hauer34f6e152008-09-02 17:16:59 +02001085 break;
1086
Sascha Hauer34f6e152008-09-02 17:16:59 +02001087 case NAND_CMD_SEQIN:
Sascha Hauer5ea32022010-04-27 15:24:01 +02001088 if (column >= mtd->writesize)
1089 /* call ourself to read a page */
1090 mxc_nand_command(mtd, NAND_CMD_READ0, 0, page_addr);
Sascha Hauer34f6e152008-09-02 17:16:59 +02001091
Sascha Hauer5ea32022010-04-27 15:24:01 +02001092 host->buf_start = column;
Sascha Hauer89121a62009-06-04 17:18:01 +02001093
Uwe Kleine-Könige4303b22012-04-23 11:23:35 +02001094 host->devtype_data->send_cmd(host, command, false);
Sascha Hauer89121a62009-06-04 17:18:01 +02001095 mxc_do_addr_cycle(mtd, column, page_addr);
Sascha Hauer34f6e152008-09-02 17:16:59 +02001096 break;
1097
1098 case NAND_CMD_PAGEPROG:
Sascha Hauer096bcc22012-05-29 10:16:09 +02001099 memcpy32_toio(host->main_area0, host->data_buf, mtd->writesize);
Sascha Hauerf8f96082009-06-04 17:12:26 +02001100 copy_spare(mtd, false);
Uwe Kleine-Könige4303b22012-04-23 11:23:35 +02001101 host->devtype_data->send_page(mtd, NFC_INPUT);
1102 host->devtype_data->send_cmd(host, command, true);
Sascha Hauer89121a62009-06-04 17:18:01 +02001103 mxc_do_addr_cycle(mtd, column, page_addr);
Sascha Hauer34f6e152008-09-02 17:16:59 +02001104 break;
1105
Sascha Hauer34f6e152008-09-02 17:16:59 +02001106 case NAND_CMD_READID:
Uwe Kleine-Könige4303b22012-04-23 11:23:35 +02001107 host->devtype_data->send_cmd(host, command, true);
Sascha Hauer89121a62009-06-04 17:18:01 +02001108 mxc_do_addr_cycle(mtd, column, page_addr);
Uwe Kleine-Könige4303b22012-04-23 11:23:35 +02001109 host->devtype_data->send_read_id(host);
Sascha Hauer94671142009-10-05 12:14:21 +02001110 host->buf_start = column;
Sascha Hauer34f6e152008-09-02 17:16:59 +02001111 break;
1112
Sascha Hauer89121a62009-06-04 17:18:01 +02001113 case NAND_CMD_ERASE1:
Sascha Hauer34f6e152008-09-02 17:16:59 +02001114 case NAND_CMD_ERASE2:
Uwe Kleine-Könige4303b22012-04-23 11:23:35 +02001115 host->devtype_data->send_cmd(host, command, false);
Sascha Hauer89121a62009-06-04 17:18:01 +02001116 mxc_do_addr_cycle(mtd, column, page_addr);
1117
Sascha Hauer34f6e152008-09-02 17:16:59 +02001118 break;
1119 }
1120}
1121
Sascha Hauerf1372052009-10-21 14:25:27 +02001122/*
1123 * The generic flash bbt decriptors overlap with our ecc
1124 * hardware, so define some i.MX specific ones.
1125 */
1126static uint8_t bbt_pattern[] = { 'B', 'b', 't', '0' };
1127static uint8_t mirror_pattern[] = { '1', 't', 'b', 'B' };
1128
1129static struct nand_bbt_descr bbt_main_descr = {
1130 .options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE
1131 | NAND_BBT_2BIT | NAND_BBT_VERSION | NAND_BBT_PERCHIP,
1132 .offs = 0,
1133 .len = 4,
1134 .veroffs = 4,
1135 .maxblocks = 4,
1136 .pattern = bbt_pattern,
1137};
1138
1139static struct nand_bbt_descr bbt_mirror_descr = {
1140 .options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE
1141 | NAND_BBT_2BIT | NAND_BBT_VERSION | NAND_BBT_PERCHIP,
1142 .offs = 0,
1143 .len = 4,
1144 .veroffs = 4,
1145 .maxblocks = 4,
1146 .pattern = mirror_pattern,
1147};
1148
Uwe Kleine-Königf48d0f92012-04-23 11:23:40 +02001149/* v1 + irqpending_quirk: i.MX21 */
Uwe Kleine-Könige4303b22012-04-23 11:23:35 +02001150static const struct mxc_nand_devtype_data imx21_nand_devtype_data = {
Uwe Kleine-König6d38af22012-04-23 11:23:36 +02001151 .preset = preset_v1,
Uwe Kleine-Könige4303b22012-04-23 11:23:35 +02001152 .send_cmd = send_cmd_v1_v2,
1153 .send_addr = send_addr_v1_v2,
Uwe Kleine-König6d38af22012-04-23 11:23:36 +02001154 .send_page = send_page_v1,
Uwe Kleine-Könige4303b22012-04-23 11:23:35 +02001155 .send_read_id = send_read_id_v1_v2,
1156 .get_dev_status = get_dev_status_v1_v2,
1157 .check_int = check_int_v1_v2,
1158 .irq_control = irq_control_v1_v2,
Uwe Kleine-König6d38af22012-04-23 11:23:36 +02001159 .get_ecc_status = get_ecc_status_v1,
Uwe Kleine-König6dcdf992012-04-23 11:23:37 +02001160 .ecclayout_512 = &nandv1_hw_eccoob_smallpage,
1161 .ecclayout_2k = &nandv1_hw_eccoob_largepage,
1162 .ecclayout_4k = &nandv1_hw_eccoob_smallpage, /* XXX: needs fix */
Uwe Kleine-König5e05a2d62012-04-23 11:23:38 +02001163 .select_chip = mxc_nand_select_chip_v1_v3,
Uwe Kleine-König69d023b2012-04-23 11:23:39 +02001164 .correct_data = mxc_nand_correct_data_v1,
Uwe Kleine-Königf48d0f92012-04-23 11:23:40 +02001165 .irqpending_quirk = 1,
1166 .needs_ip = 0,
1167 .regs_offset = 0xe00,
1168 .spare0_offset = 0x800,
1169 .spare_len = 16,
1170 .eccbytes = 3,
1171 .eccsize = 1,
1172};
1173
1174/* v1 + !irqpending_quirk: i.MX27, i.MX31 */
1175static const struct mxc_nand_devtype_data imx27_nand_devtype_data = {
1176 .preset = preset_v1,
1177 .send_cmd = send_cmd_v1_v2,
1178 .send_addr = send_addr_v1_v2,
1179 .send_page = send_page_v1,
1180 .send_read_id = send_read_id_v1_v2,
1181 .get_dev_status = get_dev_status_v1_v2,
1182 .check_int = check_int_v1_v2,
1183 .irq_control = irq_control_v1_v2,
1184 .get_ecc_status = get_ecc_status_v1,
1185 .ecclayout_512 = &nandv1_hw_eccoob_smallpage,
1186 .ecclayout_2k = &nandv1_hw_eccoob_largepage,
1187 .ecclayout_4k = &nandv1_hw_eccoob_smallpage, /* XXX: needs fix */
1188 .select_chip = mxc_nand_select_chip_v1_v3,
1189 .correct_data = mxc_nand_correct_data_v1,
1190 .irqpending_quirk = 0,
1191 .needs_ip = 0,
1192 .regs_offset = 0xe00,
1193 .spare0_offset = 0x800,
1194 .axi_offset = 0,
1195 .spare_len = 16,
1196 .eccbytes = 3,
1197 .eccsize = 1,
Uwe Kleine-Könige4303b22012-04-23 11:23:35 +02001198};
1199
1200/* v21: i.MX25, i.MX35 */
1201static const struct mxc_nand_devtype_data imx25_nand_devtype_data = {
Uwe Kleine-König6d38af22012-04-23 11:23:36 +02001202 .preset = preset_v2,
Uwe Kleine-Könige4303b22012-04-23 11:23:35 +02001203 .send_cmd = send_cmd_v1_v2,
1204 .send_addr = send_addr_v1_v2,
Uwe Kleine-König6d38af22012-04-23 11:23:36 +02001205 .send_page = send_page_v2,
Uwe Kleine-Könige4303b22012-04-23 11:23:35 +02001206 .send_read_id = send_read_id_v1_v2,
1207 .get_dev_status = get_dev_status_v1_v2,
1208 .check_int = check_int_v1_v2,
1209 .irq_control = irq_control_v1_v2,
Uwe Kleine-König6d38af22012-04-23 11:23:36 +02001210 .get_ecc_status = get_ecc_status_v2,
Uwe Kleine-König6dcdf992012-04-23 11:23:37 +02001211 .ecclayout_512 = &nandv2_hw_eccoob_smallpage,
1212 .ecclayout_2k = &nandv2_hw_eccoob_largepage,
1213 .ecclayout_4k = &nandv2_hw_eccoob_4k,
Uwe Kleine-König5e05a2d62012-04-23 11:23:38 +02001214 .select_chip = mxc_nand_select_chip_v2,
Uwe Kleine-König69d023b2012-04-23 11:23:39 +02001215 .correct_data = mxc_nand_correct_data_v2_v3,
Uwe Kleine-Königf48d0f92012-04-23 11:23:40 +02001216 .irqpending_quirk = 0,
1217 .needs_ip = 0,
1218 .regs_offset = 0x1e00,
1219 .spare0_offset = 0x1000,
1220 .axi_offset = 0,
1221 .spare_len = 64,
1222 .eccbytes = 9,
1223 .eccsize = 0,
Uwe Kleine-Könige4303b22012-04-23 11:23:35 +02001224};
1225
Sascha Hauer71718a8e2012-06-06 12:33:15 +02001226/* v3.2a: i.MX51 */
Uwe Kleine-Könige4303b22012-04-23 11:23:35 +02001227static const struct mxc_nand_devtype_data imx51_nand_devtype_data = {
1228 .preset = preset_v3,
1229 .send_cmd = send_cmd_v3,
1230 .send_addr = send_addr_v3,
1231 .send_page = send_page_v3,
1232 .send_read_id = send_read_id_v3,
1233 .get_dev_status = get_dev_status_v3,
1234 .check_int = check_int_v3,
1235 .irq_control = irq_control_v3,
Uwe Kleine-König6d38af22012-04-23 11:23:36 +02001236 .get_ecc_status = get_ecc_status_v3,
Uwe Kleine-König6dcdf992012-04-23 11:23:37 +02001237 .ecclayout_512 = &nandv2_hw_eccoob_smallpage,
1238 .ecclayout_2k = &nandv2_hw_eccoob_largepage,
1239 .ecclayout_4k = &nandv2_hw_eccoob_smallpage, /* XXX: needs fix */
Uwe Kleine-König5e05a2d62012-04-23 11:23:38 +02001240 .select_chip = mxc_nand_select_chip_v1_v3,
Uwe Kleine-König69d023b2012-04-23 11:23:39 +02001241 .correct_data = mxc_nand_correct_data_v2_v3,
Uwe Kleine-Königf48d0f92012-04-23 11:23:40 +02001242 .irqpending_quirk = 0,
1243 .needs_ip = 1,
1244 .regs_offset = 0,
1245 .spare0_offset = 0x1000,
1246 .axi_offset = 0x1e00,
1247 .spare_len = 64,
1248 .eccbytes = 0,
1249 .eccsize = 0,
Sascha Hauer71718a8e2012-06-06 12:33:15 +02001250 .ppb_shift = 7,
1251};
1252
1253/* v3.2b: i.MX53 */
1254static const struct mxc_nand_devtype_data imx53_nand_devtype_data = {
1255 .preset = preset_v3,
1256 .send_cmd = send_cmd_v3,
1257 .send_addr = send_addr_v3,
1258 .send_page = send_page_v3,
1259 .send_read_id = send_read_id_v3,
1260 .get_dev_status = get_dev_status_v3,
1261 .check_int = check_int_v3,
1262 .irq_control = irq_control_v3,
1263 .get_ecc_status = get_ecc_status_v3,
1264 .ecclayout_512 = &nandv2_hw_eccoob_smallpage,
1265 .ecclayout_2k = &nandv2_hw_eccoob_largepage,
1266 .ecclayout_4k = &nandv2_hw_eccoob_smallpage, /* XXX: needs fix */
1267 .select_chip = mxc_nand_select_chip_v1_v3,
1268 .correct_data = mxc_nand_correct_data_v2_v3,
1269 .irqpending_quirk = 0,
1270 .needs_ip = 1,
1271 .regs_offset = 0,
1272 .spare0_offset = 0x1000,
1273 .axi_offset = 0x1e00,
1274 .spare_len = 64,
1275 .eccbytes = 0,
1276 .eccsize = 0,
1277 .ppb_shift = 8,
Uwe Kleine-Könige4303b22012-04-23 11:23:35 +02001278};
1279
Shawn Guo4d624352012-09-15 13:34:09 +08001280static inline int is_imx21_nfc(struct mxc_nand_host *host)
1281{
1282 return host->devtype_data == &imx21_nand_devtype_data;
1283}
1284
1285static inline int is_imx27_nfc(struct mxc_nand_host *host)
1286{
1287 return host->devtype_data == &imx27_nand_devtype_data;
1288}
1289
1290static inline int is_imx25_nfc(struct mxc_nand_host *host)
1291{
1292 return host->devtype_data == &imx25_nand_devtype_data;
1293}
1294
1295static inline int is_imx51_nfc(struct mxc_nand_host *host)
1296{
1297 return host->devtype_data == &imx51_nand_devtype_data;
1298}
1299
1300static inline int is_imx53_nfc(struct mxc_nand_host *host)
1301{
1302 return host->devtype_data == &imx53_nand_devtype_data;
1303}
1304
1305static struct platform_device_id mxcnd_devtype[] = {
1306 {
1307 .name = "imx21-nand",
1308 .driver_data = (kernel_ulong_t) &imx21_nand_devtype_data,
1309 }, {
1310 .name = "imx27-nand",
1311 .driver_data = (kernel_ulong_t) &imx27_nand_devtype_data,
1312 }, {
1313 .name = "imx25-nand",
1314 .driver_data = (kernel_ulong_t) &imx25_nand_devtype_data,
1315 }, {
1316 .name = "imx51-nand",
1317 .driver_data = (kernel_ulong_t) &imx51_nand_devtype_data,
1318 }, {
1319 .name = "imx53-nand",
1320 .driver_data = (kernel_ulong_t) &imx53_nand_devtype_data,
1321 }, {
1322 /* sentinel */
1323 }
1324};
1325MODULE_DEVICE_TABLE(platform, mxcnd_devtype);
1326
Uwe Kleine-König64363562012-04-23 11:23:41 +02001327#ifdef CONFIG_OF_MTD
1328static const struct of_device_id mxcnd_dt_ids[] = {
1329 {
1330 .compatible = "fsl,imx21-nand",
1331 .data = &imx21_nand_devtype_data,
1332 }, {
1333 .compatible = "fsl,imx27-nand",
1334 .data = &imx27_nand_devtype_data,
1335 }, {
1336 .compatible = "fsl,imx25-nand",
1337 .data = &imx25_nand_devtype_data,
1338 }, {
1339 .compatible = "fsl,imx51-nand",
1340 .data = &imx51_nand_devtype_data,
Sascha Hauer71718a8e2012-06-06 12:33:15 +02001341 }, {
1342 .compatible = "fsl,imx53-nand",
1343 .data = &imx53_nand_devtype_data,
Uwe Kleine-König64363562012-04-23 11:23:41 +02001344 },
1345 { /* sentinel */ }
1346};
1347
1348static int __init mxcnd_probe_dt(struct mxc_nand_host *host)
1349{
1350 struct device_node *np = host->dev->of_node;
1351 struct mxc_nand_platform_data *pdata = &host->pdata;
1352 const struct of_device_id *of_id =
1353 of_match_device(mxcnd_dt_ids, host->dev);
1354 int buswidth;
1355
1356 if (!np)
1357 return 1;
1358
1359 if (of_get_nand_ecc_mode(np) >= 0)
1360 pdata->hw_ecc = 1;
1361
1362 pdata->flash_bbt = of_get_nand_on_flash_bbt(np);
1363
1364 buswidth = of_get_nand_bus_width(np);
1365 if (buswidth < 0)
1366 return buswidth;
1367
1368 pdata->width = buswidth / 8;
1369
1370 host->devtype_data = of_id->data;
1371
1372 return 0;
1373}
1374#else
1375static int __init mxcnd_probe_dt(struct mxc_nand_host *host)
1376{
1377 return 1;
1378}
1379#endif
1380
Fabio Estevamddf16d62012-09-05 11:35:25 -03001381static int __devinit mxcnd_probe(struct platform_device *pdev)
Sascha Hauer34f6e152008-09-02 17:16:59 +02001382{
1383 struct nand_chip *this;
1384 struct mtd_info *mtd;
Sascha Hauer34f6e152008-09-02 17:16:59 +02001385 struct mxc_nand_host *host;
1386 struct resource *res;
Dmitry Eremin-Solenikovd4ed8f12011-06-02 18:00:43 +04001387 int err = 0;
Sascha Hauer34f6e152008-09-02 17:16:59 +02001388
1389 /* Allocate memory for MTD device structure and private data */
Sascha Hauere4a09cb2012-06-06 12:33:13 +02001390 host = devm_kzalloc(&pdev->dev, sizeof(struct mxc_nand_host) +
1391 NAND_MAX_PAGESIZE + NAND_MAX_OOBSIZE, GFP_KERNEL);
Sascha Hauer34f6e152008-09-02 17:16:59 +02001392 if (!host)
1393 return -ENOMEM;
1394
Sascha Hauerf8f96082009-06-04 17:12:26 +02001395 host->data_buf = (uint8_t *)(host + 1);
Sascha Hauerf8f96082009-06-04 17:12:26 +02001396
Sascha Hauer34f6e152008-09-02 17:16:59 +02001397 host->dev = &pdev->dev;
1398 /* structures must be linked */
1399 this = &host->nand;
1400 mtd = &host->mtd;
1401 mtd->priv = this;
1402 mtd->owner = THIS_MODULE;
David Brownell87f39f02009-03-26 00:42:50 -07001403 mtd->dev.parent = &pdev->dev;
Sascha Hauer1fbff0a2009-10-21 16:06:27 +02001404 mtd->name = DRIVER_NAME;
Sascha Hauer34f6e152008-09-02 17:16:59 +02001405
1406 /* 50 us command delay time */
1407 this->chip_delay = 5;
1408
1409 this->priv = host;
1410 this->dev_ready = mxc_nand_dev_ready;
1411 this->cmdfunc = mxc_nand_command;
Sascha Hauer34f6e152008-09-02 17:16:59 +02001412 this->read_byte = mxc_nand_read_byte;
1413 this->read_word = mxc_nand_read_word;
1414 this->write_buf = mxc_nand_write_buf;
1415 this->read_buf = mxc_nand_read_buf;
Sascha Hauer34f6e152008-09-02 17:16:59 +02001416
Fabio Estevam24b82d32012-09-05 11:52:27 -03001417 host->clk = devm_clk_get(&pdev->dev, NULL);
Sascha Hauere4a09cb2012-06-06 12:33:13 +02001418 if (IS_ERR(host->clk))
1419 return PTR_ERR(host->clk);
Sascha Hauer34f6e152008-09-02 17:16:59 +02001420
Sascha Hauer71885b62012-06-06 12:33:14 +02001421 err = mxcnd_probe_dt(host);
Shawn Guo4d624352012-09-15 13:34:09 +08001422 if (err > 0) {
1423 struct mxc_nand_platform_data *pdata = pdev->dev.platform_data;
1424 if (pdata) {
1425 host->pdata = *pdata;
1426 host->devtype_data = (struct mxc_nand_devtype_data *)
1427 pdev->id_entry->driver_data;
1428 } else {
1429 err = -ENODEV;
1430 }
1431 }
Sascha Hauer71885b62012-06-06 12:33:14 +02001432 if (err < 0)
1433 return err;
1434
1435 if (host->devtype_data->needs_ip) {
1436 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
1437 if (!res)
1438 return -ENODEV;
1439 host->regs_ip = devm_request_and_ioremap(&pdev->dev, res);
1440 if (!host->regs_ip)
1441 return -ENOMEM;
1442
1443 res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
1444 } else {
1445 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
1446 }
1447
Sascha Hauere4a09cb2012-06-06 12:33:13 +02001448 if (!res)
1449 return -ENODEV;
Sascha Hauer34f6e152008-09-02 17:16:59 +02001450
Sascha Hauere4a09cb2012-06-06 12:33:13 +02001451 host->base = devm_request_and_ioremap(&pdev->dev, res);
1452 if (!host->base)
1453 return -ENOMEM;
Sascha Hauer34f6e152008-09-02 17:16:59 +02001454
Sascha Hauerc6de7e12009-10-05 11:14:35 +02001455 host->main_area0 = host->base;
Sascha Hauer94671142009-10-05 12:14:21 +02001456
Uwe Kleine-Königf48d0f92012-04-23 11:23:40 +02001457 if (host->devtype_data->regs_offset)
1458 host->regs = host->base + host->devtype_data->regs_offset;
1459 host->spare0 = host->base + host->devtype_data->spare0_offset;
1460 if (host->devtype_data->axi_offset)
1461 host->regs_axi = host->base + host->devtype_data->axi_offset;
1462
1463 this->ecc.bytes = host->devtype_data->eccbytes;
1464 host->eccsize = host->devtype_data->eccsize;
1465
1466 this->select_chip = host->devtype_data->select_chip;
1467 this->ecc.size = 512;
1468 this->ecc.layout = host->devtype_data->ecclayout_512;
1469
Uwe Kleine-König64363562012-04-23 11:23:41 +02001470 if (host->pdata.hw_ecc) {
Sascha Hauer13e1add2009-10-21 10:39:05 +02001471 this->ecc.calculate = mxc_nand_calculate_ecc;
1472 this->ecc.hwctl = mxc_nand_enable_hwecc;
Uwe Kleine-König69d023b2012-04-23 11:23:39 +02001473 this->ecc.correct = host->devtype_data->correct_data;
Sascha Hauer13e1add2009-10-21 10:39:05 +02001474 this->ecc.mode = NAND_ECC_HW;
Sascha Hauer13e1add2009-10-21 10:39:05 +02001475 } else {
1476 this->ecc.mode = NAND_ECC_SOFT;
Sascha Hauer34f6e152008-09-02 17:16:59 +02001477 }
1478
Uwe Kleine-König64363562012-04-23 11:23:41 +02001479 /* NAND bus width determines access functions used by upper layer */
1480 if (host->pdata.width == 2)
Sascha Hauer34f6e152008-09-02 17:16:59 +02001481 this->options |= NAND_BUSWIDTH_16;
Sascha Hauer13e1add2009-10-21 10:39:05 +02001482
Uwe Kleine-König64363562012-04-23 11:23:41 +02001483 if (host->pdata.flash_bbt) {
Sascha Hauerf1372052009-10-21 14:25:27 +02001484 this->bbt_td = &bbt_main_descr;
1485 this->bbt_md = &bbt_mirror_descr;
1486 /* update flash based bbt */
Brian Norrisbb9ebd42011-05-31 16:31:23 -07001487 this->bbt_options |= NAND_BBT_USE_FLASH;
Sascha Hauer34f6e152008-09-02 17:16:59 +02001488 }
1489
Sascha Hauer63f14742010-10-18 10:16:26 +02001490 init_completion(&host->op_completion);
Ivo Claryssed4840182010-04-08 16:14:44 +02001491
1492 host->irq = platform_get_irq(pdev, 0);
1493
Sascha Hauer63f14742010-10-18 10:16:26 +02001494 /*
Uwe Kleine-Könige4303b22012-04-23 11:23:35 +02001495 * Use host->devtype_data->irq_control() here instead of irq_control()
1496 * because we must not disable_irq_nosync without having requested the
1497 * irq.
Sascha Hauer63f14742010-10-18 10:16:26 +02001498 */
Uwe Kleine-Könige4303b22012-04-23 11:23:35 +02001499 host->devtype_data->irq_control(host, 0);
Sascha Hauer63f14742010-10-18 10:16:26 +02001500
Sascha Hauere4a09cb2012-06-06 12:33:13 +02001501 err = devm_request_irq(&pdev->dev, host->irq, mxc_nfc_irq,
1502 IRQF_DISABLED, DRIVER_NAME, host);
Ivo Claryssed4840182010-04-08 16:14:44 +02001503 if (err)
Sascha Hauere4a09cb2012-06-06 12:33:13 +02001504 return err;
1505
1506 clk_prepare_enable(host->clk);
1507 host->clk_act = 1;
Ivo Claryssed4840182010-04-08 16:14:44 +02001508
Sascha Hauer63f14742010-10-18 10:16:26 +02001509 /*
Uwe Kleine-König85569582012-04-23 11:23:34 +02001510 * Now that we "own" the interrupt make sure the interrupt mask bit is
1511 * cleared on i.MX21. Otherwise we can't read the interrupt status bit
1512 * on this machine.
Sascha Hauer63f14742010-10-18 10:16:26 +02001513 */
Uwe Kleine-Königf48d0f92012-04-23 11:23:40 +02001514 if (host->devtype_data->irqpending_quirk) {
Uwe Kleine-König85569582012-04-23 11:23:34 +02001515 disable_irq_nosync(host->irq);
Uwe Kleine-Könige4303b22012-04-23 11:23:35 +02001516 host->devtype_data->irq_control(host, 1);
Uwe Kleine-König85569582012-04-23 11:23:34 +02001517 }
Sascha Hauer63f14742010-10-18 10:16:26 +02001518
Vladimir Barinovbd3fd622009-05-25 13:06:17 +04001519 /* first scan to find the device and get the page size */
Shawn Guo4d624352012-09-15 13:34:09 +08001520 if (nand_scan_ident(mtd, is_imx25_nfc(host) ? 4 : 1, NULL)) {
Vladimir Barinovbd3fd622009-05-25 13:06:17 +04001521 err = -ENXIO;
1522 goto escan;
1523 }
Sascha Hauer34f6e152008-09-02 17:16:59 +02001524
Sascha Hauer6e85dfd2010-08-06 15:53:10 +02001525 /* Call preset again, with correct writesize this time */
Uwe Kleine-Könige4303b22012-04-23 11:23:35 +02001526 host->devtype_data->preset(mtd);
Sascha Hauer6e85dfd2010-08-06 15:53:10 +02001527
Sascha Hauer2d69c7f2009-10-05 11:24:02 +02001528 if (mtd->writesize == 2048)
Uwe Kleine-König6dcdf992012-04-23 11:23:37 +02001529 this->ecc.layout = host->devtype_data->ecclayout_2k;
1530 else if (mtd->writesize == 4096)
1531 this->ecc.layout = host->devtype_data->ecclayout_4k;
Sascha Hauer34f6e152008-09-02 17:16:59 +02001532
Mike Dunn6a918ba2012-03-11 14:21:11 -07001533 if (this->ecc.mode == NAND_ECC_HW) {
Shawn Guo4d624352012-09-15 13:34:09 +08001534 if (is_imx21_nfc(host) || is_imx27_nfc(host))
Mike Dunn6a918ba2012-03-11 14:21:11 -07001535 this->ecc.strength = 1;
1536 else
1537 this->ecc.strength = (host->eccsize == 4) ? 4 : 8;
1538 }
1539
Sascha Hauer4a43faf2012-05-25 16:22:42 +02001540 /* second phase scan */
1541 if (nand_scan_tail(mtd)) {
1542 err = -ENXIO;
1543 goto escan;
1544 }
1545
Sascha Hauer34f6e152008-09-02 17:16:59 +02001546 /* Register the partitions */
Uwe Kleine-König64363562012-04-23 11:23:41 +02001547 mtd_device_parse_register(mtd, part_probes,
1548 &(struct mtd_part_parser_data){
1549 .of_node = pdev->dev.of_node,
1550 },
1551 host->pdata.parts,
1552 host->pdata.nr_parts);
Sascha Hauer34f6e152008-09-02 17:16:59 +02001553
1554 platform_set_drvdata(pdev, host);
1555
1556 return 0;
1557
1558escan:
Sascha Hauere4a09cb2012-06-06 12:33:13 +02001559 clk_disable_unprepare(host->clk);
Sascha Hauer34f6e152008-09-02 17:16:59 +02001560
1561 return err;
1562}
1563
Uwe Kleine-König51eeb872009-12-07 09:44:05 +00001564static int __devexit mxcnd_remove(struct platform_device *pdev)
Sascha Hauer34f6e152008-09-02 17:16:59 +02001565{
1566 struct mxc_nand_host *host = platform_get_drvdata(pdev);
1567
Sascha Hauer34f6e152008-09-02 17:16:59 +02001568 platform_set_drvdata(pdev, NULL);
1569
1570 nand_release(&host->mtd);
Sascha Hauer34f6e152008-09-02 17:16:59 +02001571
1572 return 0;
1573}
1574
Sascha Hauer34f6e152008-09-02 17:16:59 +02001575static struct platform_driver mxcnd_driver = {
1576 .driver = {
1577 .name = DRIVER_NAME,
Uwe Kleine-König8d1fd162012-04-23 11:23:33 +02001578 .owner = THIS_MODULE,
Uwe Kleine-König64363562012-04-23 11:23:41 +02001579 .of_match_table = of_match_ptr(mxcnd_dt_ids),
Eric Bénard04dd0d32010-06-17 20:59:04 +02001580 },
Shawn Guo4d624352012-09-15 13:34:09 +08001581 .id_table = mxcnd_devtype,
Fabio Estevamddf16d62012-09-05 11:35:25 -03001582 .probe = mxcnd_probe,
Uwe Kleine-Königdaa0f152009-11-24 22:07:08 +01001583 .remove = __devexit_p(mxcnd_remove),
Sascha Hauer34f6e152008-09-02 17:16:59 +02001584};
Fabio Estevamddf16d62012-09-05 11:35:25 -03001585module_platform_driver(mxcnd_driver);
Sascha Hauer34f6e152008-09-02 17:16:59 +02001586
1587MODULE_AUTHOR("Freescale Semiconductor, Inc.");
1588MODULE_DESCRIPTION("MXC NAND MTD driver");
1589MODULE_LICENSE("GPL");