blob: 0afe5904a3372076f3e9b5cc4f9cf6a0e9c95a9e [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>
Sachin Kamatd367e372013-10-18 16:16:35 +053035#include <linux/of.h>
Uwe Kleine-König64363562012-04-23 11:23:41 +020036#include <linux/of_device.h>
37#include <linux/of_mtd.h>
Sascha Hauer34f6e152008-09-02 17:16:59 +020038
39#include <asm/mach/flash.h>
Arnd Bergmann82906b12012-08-24 15:14:29 +020040#include <linux/platform_data/mtd-mxc_nand.h>
Sascha Hauer34f6e152008-09-02 17:16:59 +020041
42#define DRIVER_NAME "mxc_nand"
43
44/* Addresses for NFC registers */
Sascha Hauer1bc99182010-08-06 15:53:08 +020045#define NFC_V1_V2_BUF_SIZE (host->regs + 0x00)
46#define NFC_V1_V2_BUF_ADDR (host->regs + 0x04)
47#define NFC_V1_V2_FLASH_ADDR (host->regs + 0x06)
48#define NFC_V1_V2_FLASH_CMD (host->regs + 0x08)
49#define NFC_V1_V2_CONFIG (host->regs + 0x0a)
50#define NFC_V1_V2_ECC_STATUS_RESULT (host->regs + 0x0c)
51#define NFC_V1_V2_RSLTMAIN_AREA (host->regs + 0x0e)
52#define NFC_V1_V2_RSLTSPARE_AREA (host->regs + 0x10)
53#define NFC_V1_V2_WRPROT (host->regs + 0x12)
54#define NFC_V1_UNLOCKSTART_BLKADDR (host->regs + 0x14)
55#define NFC_V1_UNLOCKEND_BLKADDR (host->regs + 0x16)
Baruch Siachd178e3e2011-03-14 09:01:56 +020056#define NFC_V21_UNLOCKSTART_BLKADDR0 (host->regs + 0x20)
57#define NFC_V21_UNLOCKSTART_BLKADDR1 (host->regs + 0x24)
58#define NFC_V21_UNLOCKSTART_BLKADDR2 (host->regs + 0x28)
59#define NFC_V21_UNLOCKSTART_BLKADDR3 (host->regs + 0x2c)
60#define NFC_V21_UNLOCKEND_BLKADDR0 (host->regs + 0x22)
61#define NFC_V21_UNLOCKEND_BLKADDR1 (host->regs + 0x26)
62#define NFC_V21_UNLOCKEND_BLKADDR2 (host->regs + 0x2a)
63#define NFC_V21_UNLOCKEND_BLKADDR3 (host->regs + 0x2e)
Sascha Hauer1bc99182010-08-06 15:53:08 +020064#define NFC_V1_V2_NF_WRPRST (host->regs + 0x18)
65#define NFC_V1_V2_CONFIG1 (host->regs + 0x1a)
66#define NFC_V1_V2_CONFIG2 (host->regs + 0x1c)
Sascha Hauer34f6e152008-09-02 17:16:59 +020067
Sascha Hauer6e85dfd2010-08-06 15:53:10 +020068#define NFC_V2_CONFIG1_ECC_MODE_4 (1 << 0)
Sascha Hauer1bc99182010-08-06 15:53:08 +020069#define NFC_V1_V2_CONFIG1_SP_EN (1 << 2)
70#define NFC_V1_V2_CONFIG1_ECC_EN (1 << 3)
71#define NFC_V1_V2_CONFIG1_INT_MSK (1 << 4)
72#define NFC_V1_V2_CONFIG1_BIG (1 << 5)
73#define NFC_V1_V2_CONFIG1_RST (1 << 6)
74#define NFC_V1_V2_CONFIG1_CE (1 << 7)
Sascha Hauerb8db2f52010-08-09 15:04:19 +020075#define NFC_V2_CONFIG1_ONE_CYCLE (1 << 8)
76#define NFC_V2_CONFIG1_PPB(x) (((x) & 0x3) << 9)
77#define NFC_V2_CONFIG1_FP_INT (1 << 11)
Sascha Hauer34f6e152008-09-02 17:16:59 +020078
Sascha Hauer1bc99182010-08-06 15:53:08 +020079#define NFC_V1_V2_CONFIG2_INT (1 << 15)
Sascha Hauer34f6e152008-09-02 17:16:59 +020080
Sascha Hauer1bc99182010-08-06 15:53:08 +020081/*
82 * Operation modes for the NFC. Valid for v1, v2 and v3
83 * type controllers.
84 */
85#define NFC_CMD (1 << 0)
86#define NFC_ADDR (1 << 1)
87#define NFC_INPUT (1 << 2)
88#define NFC_OUTPUT (1 << 3)
89#define NFC_ID (1 << 4)
90#define NFC_STATUS (1 << 5)
Sascha Hauer34f6e152008-09-02 17:16:59 +020091
Sascha Hauer71ec5152010-08-06 15:53:11 +020092#define NFC_V3_FLASH_CMD (host->regs_axi + 0x00)
93#define NFC_V3_FLASH_ADDR0 (host->regs_axi + 0x04)
Sascha Hauer34f6e152008-09-02 17:16:59 +020094
Sascha Hauer71ec5152010-08-06 15:53:11 +020095#define NFC_V3_CONFIG1 (host->regs_axi + 0x34)
96#define NFC_V3_CONFIG1_SP_EN (1 << 0)
97#define NFC_V3_CONFIG1_RBA(x) (((x) & 0x7 ) << 4)
Sascha Hauer34f6e152008-09-02 17:16:59 +020098
Sascha Hauer71ec5152010-08-06 15:53:11 +020099#define NFC_V3_ECC_STATUS_RESULT (host->regs_axi + 0x38)
Sascha Hauer34f6e152008-09-02 17:16:59 +0200100
Sascha Hauer71ec5152010-08-06 15:53:11 +0200101#define NFC_V3_LAUNCH (host->regs_axi + 0x40)
Sascha Hauer34f6e152008-09-02 17:16:59 +0200102
Sascha Hauer71ec5152010-08-06 15:53:11 +0200103#define NFC_V3_WRPROT (host->regs_ip + 0x0)
104#define NFC_V3_WRPROT_LOCK_TIGHT (1 << 0)
105#define NFC_V3_WRPROT_LOCK (1 << 1)
106#define NFC_V3_WRPROT_UNLOCK (1 << 2)
107#define NFC_V3_WRPROT_BLS_UNLOCK (2 << 6)
108
109#define NFC_V3_WRPROT_UNLOCK_BLK_ADD0 (host->regs_ip + 0x04)
110
111#define NFC_V3_CONFIG2 (host->regs_ip + 0x24)
112#define NFC_V3_CONFIG2_PS_512 (0 << 0)
113#define NFC_V3_CONFIG2_PS_2048 (1 << 0)
114#define NFC_V3_CONFIG2_PS_4096 (2 << 0)
115#define NFC_V3_CONFIG2_ONE_CYCLE (1 << 2)
116#define NFC_V3_CONFIG2_ECC_EN (1 << 3)
117#define NFC_V3_CONFIG2_2CMD_PHASES (1 << 4)
118#define NFC_V3_CONFIG2_NUM_ADDR_PHASE0 (1 << 5)
119#define NFC_V3_CONFIG2_ECC_MODE_8 (1 << 6)
Sascha Hauer71718a8e2012-06-06 12:33:15 +0200120#define NFC_V3_CONFIG2_PPB(x, shift) (((x) & 0x3) << shift)
Sascha Hauer71ec5152010-08-06 15:53:11 +0200121#define NFC_V3_CONFIG2_NUM_ADDR_PHASE1(x) (((x) & 0x3) << 12)
122#define NFC_V3_CONFIG2_INT_MSK (1 << 15)
123#define NFC_V3_CONFIG2_ST_CMD(x) (((x) & 0xff) << 24)
124#define NFC_V3_CONFIG2_SPAS(x) (((x) & 0xff) << 16)
125
126#define NFC_V3_CONFIG3 (host->regs_ip + 0x28)
127#define NFC_V3_CONFIG3_ADD_OP(x) (((x) & 0x3) << 0)
128#define NFC_V3_CONFIG3_FW8 (1 << 3)
129#define NFC_V3_CONFIG3_SBB(x) (((x) & 0x7) << 8)
130#define NFC_V3_CONFIG3_NUM_OF_DEVICES(x) (((x) & 0x7) << 12)
131#define NFC_V3_CONFIG3_RBB_MODE (1 << 15)
132#define NFC_V3_CONFIG3_NO_SDMA (1 << 20)
133
134#define NFC_V3_IPC (host->regs_ip + 0x2C)
135#define NFC_V3_IPC_CREQ (1 << 0)
136#define NFC_V3_IPC_INT (1 << 31)
137
138#define NFC_V3_DELAY_LINE (host->regs_ip + 0x34)
Sascha Hauer34f6e152008-09-02 17:16:59 +0200139
Uwe Kleine-Könige4303b22012-04-23 11:23:35 +0200140struct mxc_nand_host;
141
142struct mxc_nand_devtype_data {
143 void (*preset)(struct mtd_info *);
144 void (*send_cmd)(struct mxc_nand_host *, uint16_t, int);
145 void (*send_addr)(struct mxc_nand_host *, uint16_t, int);
146 void (*send_page)(struct mtd_info *, unsigned int);
147 void (*send_read_id)(struct mxc_nand_host *);
148 uint16_t (*get_dev_status)(struct mxc_nand_host *);
149 int (*check_int)(struct mxc_nand_host *);
150 void (*irq_control)(struct mxc_nand_host *, int);
Uwe Kleine-König6d38af22012-04-23 11:23:36 +0200151 u32 (*get_ecc_status)(struct mxc_nand_host *);
Uwe Kleine-König6dcdf992012-04-23 11:23:37 +0200152 struct nand_ecclayout *ecclayout_512, *ecclayout_2k, *ecclayout_4k;
Uwe Kleine-König5e05a2d2012-04-23 11:23:38 +0200153 void (*select_chip)(struct mtd_info *mtd, int chip);
Uwe Kleine-König69d023b2012-04-23 11:23:39 +0200154 int (*correct_data)(struct mtd_info *mtd, u_char *dat,
155 u_char *read_ecc, u_char *calc_ecc);
Uwe Kleine-Königf48d0f92012-04-23 11:23:40 +0200156
157 /*
158 * On i.MX21 the CONFIG2:INT bit cannot be read if interrupts are masked
159 * (CONFIG1:INT_MSK is set). To handle this the driver uses
160 * enable_irq/disable_irq_nosync instead of CONFIG1:INT_MSK
161 */
162 int irqpending_quirk;
163 int needs_ip;
164
165 size_t regs_offset;
166 size_t spare0_offset;
167 size_t axi_offset;
168
169 int spare_len;
170 int eccbytes;
171 int eccsize;
Sascha Hauer71718a8e2012-06-06 12:33:15 +0200172 int ppb_shift;
Uwe Kleine-Könige4303b22012-04-23 11:23:35 +0200173};
174
Sascha Hauer34f6e152008-09-02 17:16:59 +0200175struct mxc_nand_host {
176 struct mtd_info mtd;
177 struct nand_chip nand;
Sascha Hauer34f6e152008-09-02 17:16:59 +0200178 struct device *dev;
179
Uwe Kleine-König4b6f05e2012-04-24 10:05:22 +0200180 void __iomem *spare0;
181 void __iomem *main_area0;
Sascha Hauerc6de7e12009-10-05 11:14:35 +0200182
183 void __iomem *base;
Sascha Hauer34f6e152008-09-02 17:16:59 +0200184 void __iomem *regs;
Sascha Hauer71ec5152010-08-06 15:53:11 +0200185 void __iomem *regs_axi;
186 void __iomem *regs_ip;
Sascha Hauer34f6e152008-09-02 17:16:59 +0200187 int status_request;
Sascha Hauer34f6e152008-09-02 17:16:59 +0200188 struct clk *clk;
189 int clk_act;
190 int irq;
Sascha Hauer94f77e52010-08-06 15:53:09 +0200191 int eccsize;
Baruch Siachd178e3e2011-03-14 09:01:56 +0200192 int active_cs;
Sascha Hauer34f6e152008-09-02 17:16:59 +0200193
Sascha Hauer63f14742010-10-18 10:16:26 +0200194 struct completion op_completion;
Sascha Hauerf8f96082009-06-04 17:12:26 +0200195
196 uint8_t *data_buf;
197 unsigned int buf_start;
Sascha Hauer5f973042010-08-06 15:53:06 +0200198
Uwe Kleine-Könige4303b22012-04-23 11:23:35 +0200199 const struct mxc_nand_devtype_data *devtype_data;
Uwe Kleine-König64363562012-04-23 11:23:41 +0200200 struct mxc_nand_platform_data pdata;
Sascha Hauer34f6e152008-09-02 17:16:59 +0200201};
202
Sascha Hauer34f6e152008-09-02 17:16:59 +0200203/* OOB placement block for use with hardware ecc generation */
Sascha Hauer94671142009-10-05 12:14:21 +0200204static struct nand_ecclayout nandv1_hw_eccoob_smallpage = {
Sascha Hauer34f6e152008-09-02 17:16:59 +0200205 .eccbytes = 5,
206 .eccpos = {6, 7, 8, 9, 10},
Sascha Hauer8c1fd892009-10-21 10:22:01 +0200207 .oobfree = {{0, 5}, {12, 4}, }
Sascha Hauer34f6e152008-09-02 17:16:59 +0200208};
209
Sascha Hauer94671142009-10-05 12:14:21 +0200210static struct nand_ecclayout nandv1_hw_eccoob_largepage = {
Vladimir Barinovbd3fd622009-05-25 13:06:17 +0400211 .eccbytes = 20,
212 .eccpos = {6, 7, 8, 9, 10, 22, 23, 24, 25, 26,
213 38, 39, 40, 41, 42, 54, 55, 56, 57, 58},
214 .oobfree = {{2, 4}, {11, 10}, {27, 10}, {43, 10}, {59, 5}, }
Sascha Hauer34f6e152008-09-02 17:16:59 +0200215};
216
Sascha Hauer94671142009-10-05 12:14:21 +0200217/* OOB description for 512 byte pages with 16 byte OOB */
218static struct nand_ecclayout nandv2_hw_eccoob_smallpage = {
219 .eccbytes = 1 * 9,
220 .eccpos = {
221 7, 8, 9, 10, 11, 12, 13, 14, 15
222 },
223 .oobfree = {
224 {.offset = 0, .length = 5}
225 }
226};
227
228/* OOB description for 2048 byte pages with 64 byte OOB */
229static struct nand_ecclayout nandv2_hw_eccoob_largepage = {
230 .eccbytes = 4 * 9,
231 .eccpos = {
232 7, 8, 9, 10, 11, 12, 13, 14, 15,
233 23, 24, 25, 26, 27, 28, 29, 30, 31,
234 39, 40, 41, 42, 43, 44, 45, 46, 47,
235 55, 56, 57, 58, 59, 60, 61, 62, 63
236 },
237 .oobfree = {
238 {.offset = 2, .length = 4},
239 {.offset = 16, .length = 7},
240 {.offset = 32, .length = 7},
241 {.offset = 48, .length = 7}
242 }
243};
244
Baruch Siach2c1c5f12011-03-09 16:12:20 +0200245/* OOB description for 4096 byte pages with 128 byte OOB */
246static struct nand_ecclayout nandv2_hw_eccoob_4k = {
247 .eccbytes = 8 * 9,
248 .eccpos = {
249 7, 8, 9, 10, 11, 12, 13, 14, 15,
250 23, 24, 25, 26, 27, 28, 29, 30, 31,
251 39, 40, 41, 42, 43, 44, 45, 46, 47,
252 55, 56, 57, 58, 59, 60, 61, 62, 63,
253 71, 72, 73, 74, 75, 76, 77, 78, 79,
254 87, 88, 89, 90, 91, 92, 93, 94, 95,
255 103, 104, 105, 106, 107, 108, 109, 110, 111,
256 119, 120, 121, 122, 123, 124, 125, 126, 127,
257 },
258 .oobfree = {
259 {.offset = 2, .length = 4},
260 {.offset = 16, .length = 7},
261 {.offset = 32, .length = 7},
262 {.offset = 48, .length = 7},
263 {.offset = 64, .length = 7},
264 {.offset = 80, .length = 7},
265 {.offset = 96, .length = 7},
266 {.offset = 112, .length = 7},
267 }
268};
269
Jingoo Hanb2ac0372013-08-07 16:18:52 +0900270static const char * const part_probes[] = {
Lothar Waßmann740bb0c2012-12-06 08:42:28 +0100271 "cmdlinepart", "RedBoot", "ofpart", NULL };
Sascha Hauer34f6e152008-09-02 17:16:59 +0200272
Sascha Hauer096bcc22012-05-29 10:16:09 +0200273static void memcpy32_fromio(void *trg, const void __iomem *src, size_t size)
274{
275 int i;
276 u32 *t = trg;
277 const __iomem u32 *s = src;
278
279 for (i = 0; i < (size >> 2); i++)
280 *t++ = __raw_readl(s++);
281}
282
Koul, Vinod33a87a12014-10-20 21:36:13 +0530283static inline void memcpy32_toio(void __iomem *trg, const void *src, int size)
Sascha Hauer096bcc22012-05-29 10:16:09 +0200284{
Koul, Vinod33a87a12014-10-20 21:36:13 +0530285 /* __iowrite32_copy use 32bit size values so divide by 4 */
286 __iowrite32_copy(trg, src, size / 4);
Sascha Hauer096bcc22012-05-29 10:16:09 +0200287}
288
Sascha Hauer71ec5152010-08-06 15:53:11 +0200289static int check_int_v3(struct mxc_nand_host *host)
290{
291 uint32_t tmp;
292
293 tmp = readl(NFC_V3_IPC);
294 if (!(tmp & NFC_V3_IPC_INT))
295 return 0;
296
297 tmp &= ~NFC_V3_IPC_INT;
298 writel(tmp, NFC_V3_IPC);
299
300 return 1;
301}
302
Sascha Hauer7aaf28a2010-08-06 15:53:07 +0200303static int check_int_v1_v2(struct mxc_nand_host *host)
304{
305 uint32_t tmp;
306
Sascha Hauer1bc99182010-08-06 15:53:08 +0200307 tmp = readw(NFC_V1_V2_CONFIG2);
308 if (!(tmp & NFC_V1_V2_CONFIG2_INT))
Sascha Hauer7aaf28a2010-08-06 15:53:07 +0200309 return 0;
310
Uwe Kleine-Königf48d0f92012-04-23 11:23:40 +0200311 if (!host->devtype_data->irqpending_quirk)
Sascha Hauer63f14742010-10-18 10:16:26 +0200312 writew(tmp & ~NFC_V1_V2_CONFIG2_INT, NFC_V1_V2_CONFIG2);
Sascha Hauer7aaf28a2010-08-06 15:53:07 +0200313
314 return 1;
315}
316
Sascha Hauer63f14742010-10-18 10:16:26 +0200317static void irq_control_v1_v2(struct mxc_nand_host *host, int activate)
318{
319 uint16_t tmp;
320
321 tmp = readw(NFC_V1_V2_CONFIG1);
322
323 if (activate)
324 tmp &= ~NFC_V1_V2_CONFIG1_INT_MSK;
325 else
326 tmp |= NFC_V1_V2_CONFIG1_INT_MSK;
327
328 writew(tmp, NFC_V1_V2_CONFIG1);
329}
330
331static void irq_control_v3(struct mxc_nand_host *host, int activate)
332{
333 uint32_t tmp;
334
335 tmp = readl(NFC_V3_CONFIG2);
336
337 if (activate)
338 tmp &= ~NFC_V3_CONFIG2_INT_MSK;
339 else
340 tmp |= NFC_V3_CONFIG2_INT_MSK;
341
342 writel(tmp, NFC_V3_CONFIG2);
343}
344
Uwe Kleine-König85569582012-04-23 11:23:34 +0200345static void irq_control(struct mxc_nand_host *host, int activate)
346{
Uwe Kleine-Königf48d0f92012-04-23 11:23:40 +0200347 if (host->devtype_data->irqpending_quirk) {
Uwe Kleine-König85569582012-04-23 11:23:34 +0200348 if (activate)
349 enable_irq(host->irq);
350 else
351 disable_irq_nosync(host->irq);
352 } else {
Uwe Kleine-Könige4303b22012-04-23 11:23:35 +0200353 host->devtype_data->irq_control(host, activate);
Uwe Kleine-König85569582012-04-23 11:23:34 +0200354 }
355}
356
Uwe Kleine-König6d38af22012-04-23 11:23:36 +0200357static u32 get_ecc_status_v1(struct mxc_nand_host *host)
358{
359 return readw(NFC_V1_V2_ECC_STATUS_RESULT);
360}
361
362static u32 get_ecc_status_v2(struct mxc_nand_host *host)
363{
364 return readl(NFC_V1_V2_ECC_STATUS_RESULT);
365}
366
367static u32 get_ecc_status_v3(struct mxc_nand_host *host)
368{
369 return readl(NFC_V3_ECC_STATUS_RESULT);
370}
371
Uwe Kleine-König85569582012-04-23 11:23:34 +0200372static irqreturn_t mxc_nfc_irq(int irq, void *dev_id)
373{
374 struct mxc_nand_host *host = dev_id;
375
Uwe Kleine-Könige4303b22012-04-23 11:23:35 +0200376 if (!host->devtype_data->check_int(host))
Uwe Kleine-König85569582012-04-23 11:23:34 +0200377 return IRQ_NONE;
378
379 irq_control(host, 0);
380
381 complete(&host->op_completion);
382
383 return IRQ_HANDLED;
384}
385
Sascha Hauer34f6e152008-09-02 17:16:59 +0200386/* This function polls the NANDFC to wait for the basic operation to
387 * complete by checking the INT bit of config2 register.
388 */
Uwe Kleine-Könige35d1d82015-02-10 19:59:55 +0100389static int wait_op_done(struct mxc_nand_host *host, int useirq)
Sascha Hauer34f6e152008-09-02 17:16:59 +0200390{
Uwe Kleine-Könige35d1d82015-02-10 19:59:55 +0100391 int ret = 0;
392
393 /*
394 * If operation is already complete, don't bother to setup an irq or a
395 * loop.
396 */
397 if (host->devtype_data->check_int(host))
398 return 0;
Sascha Hauer34f6e152008-09-02 17:16:59 +0200399
400 if (useirq) {
Uwe Kleine-Könige35d1d82015-02-10 19:59:55 +0100401 unsigned long timeout;
402
403 reinit_completion(&host->op_completion);
404
405 irq_control(host, 1);
406
407 timeout = wait_for_completion_timeout(&host->op_completion, HZ);
408 if (!timeout && !host->devtype_data->check_int(host)) {
409 dev_dbg(host->dev, "timeout waiting for irq\n");
410 ret = -ETIMEDOUT;
Sascha Hauer34f6e152008-09-02 17:16:59 +0200411 }
412 } else {
Uwe Kleine-Könige35d1d82015-02-10 19:59:55 +0100413 int max_retries = 8000;
414 int done;
415
416 do {
417 udelay(1);
418
419 done = host->devtype_data->check_int(host);
420 if (done)
Sascha Hauer34f6e152008-09-02 17:16:59 +0200421 break;
Sascha Hauer7aaf28a2010-08-06 15:53:07 +0200422
Uwe Kleine-Könige35d1d82015-02-10 19:59:55 +0100423 } while (--max_retries);
424
425 if (!done) {
426 dev_dbg(host->dev, "timeout polling for completion\n");
427 ret = -ETIMEDOUT;
Sascha Hauer34f6e152008-09-02 17:16:59 +0200428 }
Sascha Hauer34f6e152008-09-02 17:16:59 +0200429 }
Uwe Kleine-Könige35d1d82015-02-10 19:59:55 +0100430
431 WARN_ONCE(ret < 0, "timeout! useirq=%d\n", useirq);
432
433 return ret;
Sascha Hauer34f6e152008-09-02 17:16:59 +0200434}
435
Sascha Hauer71ec5152010-08-06 15:53:11 +0200436static void send_cmd_v3(struct mxc_nand_host *host, uint16_t cmd, int useirq)
437{
438 /* fill command */
439 writel(cmd, NFC_V3_FLASH_CMD);
440
441 /* send out command */
442 writel(NFC_CMD, NFC_V3_LAUNCH);
443
444 /* Wait for operation to complete */
445 wait_op_done(host, useirq);
446}
447
Sascha Hauer34f6e152008-09-02 17:16:59 +0200448/* This function issues the specified command to the NAND device and
449 * waits for completion. */
Sascha Hauer5f973042010-08-06 15:53:06 +0200450static void send_cmd_v1_v2(struct mxc_nand_host *host, uint16_t cmd, int useirq)
Sascha Hauer34f6e152008-09-02 17:16:59 +0200451{
Brian Norris289c0522011-07-19 10:06:09 -0700452 pr_debug("send_cmd(host, 0x%x, %d)\n", cmd, useirq);
Sascha Hauer34f6e152008-09-02 17:16:59 +0200453
Sascha Hauer1bc99182010-08-06 15:53:08 +0200454 writew(cmd, NFC_V1_V2_FLASH_CMD);
455 writew(NFC_CMD, NFC_V1_V2_CONFIG2);
Sascha Hauer34f6e152008-09-02 17:16:59 +0200456
Uwe Kleine-Königf48d0f92012-04-23 11:23:40 +0200457 if (host->devtype_data->irqpending_quirk && (cmd == NAND_CMD_RESET)) {
Ivo Claryssea47bfd22010-04-08 16:16:51 +0200458 int max_retries = 100;
459 /* Reset completion is indicated by NFC_CONFIG2 */
460 /* being set to 0 */
461 while (max_retries-- > 0) {
Sascha Hauer1bc99182010-08-06 15:53:08 +0200462 if (readw(NFC_V1_V2_CONFIG2) == 0) {
Ivo Claryssea47bfd22010-04-08 16:16:51 +0200463 break;
464 }
465 udelay(1);
466 }
467 if (max_retries < 0)
Brian Norris0a32a102011-07-19 10:06:10 -0700468 pr_debug("%s: RESET failed\n", __func__);
Ivo Claryssea47bfd22010-04-08 16:16:51 +0200469 } else {
470 /* Wait for operation to complete */
471 wait_op_done(host, useirq);
472 }
Sascha Hauer34f6e152008-09-02 17:16:59 +0200473}
474
Sascha Hauer71ec5152010-08-06 15:53:11 +0200475static void send_addr_v3(struct mxc_nand_host *host, uint16_t addr, int islast)
476{
477 /* fill address */
478 writel(addr, NFC_V3_FLASH_ADDR0);
479
480 /* send out address */
481 writel(NFC_ADDR, NFC_V3_LAUNCH);
482
483 wait_op_done(host, 0);
484}
485
Sascha Hauer34f6e152008-09-02 17:16:59 +0200486/* This function sends an address (or partial address) to the
487 * NAND device. The address is used to select the source/destination for
488 * a NAND command. */
Sascha Hauer5f973042010-08-06 15:53:06 +0200489static void send_addr_v1_v2(struct mxc_nand_host *host, uint16_t addr, int islast)
Sascha Hauer34f6e152008-09-02 17:16:59 +0200490{
Brian Norris289c0522011-07-19 10:06:09 -0700491 pr_debug("send_addr(host, 0x%x %d)\n", addr, islast);
Sascha Hauer34f6e152008-09-02 17:16:59 +0200492
Sascha Hauer1bc99182010-08-06 15:53:08 +0200493 writew(addr, NFC_V1_V2_FLASH_ADDR);
494 writew(NFC_ADDR, NFC_V1_V2_CONFIG2);
Sascha Hauer34f6e152008-09-02 17:16:59 +0200495
496 /* Wait for operation to complete */
Sascha Hauerc110eaf2009-10-21 16:01:02 +0200497 wait_op_done(host, islast);
Sascha Hauer34f6e152008-09-02 17:16:59 +0200498}
499
Sascha Hauer71ec5152010-08-06 15:53:11 +0200500static void send_page_v3(struct mtd_info *mtd, unsigned int ops)
501{
502 struct nand_chip *nand_chip = mtd->priv;
503 struct mxc_nand_host *host = nand_chip->priv;
504 uint32_t tmp;
505
506 tmp = readl(NFC_V3_CONFIG1);
507 tmp &= ~(7 << 4);
508 writel(tmp, NFC_V3_CONFIG1);
509
510 /* transfer data from NFC ram to nand */
511 writel(ops, NFC_V3_LAUNCH);
512
513 wait_op_done(host, false);
514}
515
Uwe Kleine-König6d38af22012-04-23 11:23:36 +0200516static void send_page_v2(struct mtd_info *mtd, unsigned int ops)
517{
518 struct nand_chip *nand_chip = mtd->priv;
519 struct mxc_nand_host *host = nand_chip->priv;
520
521 /* NANDFC buffer 0 is used for page read/write */
522 writew(host->active_cs << 4, NFC_V1_V2_BUF_ADDR);
523
524 writew(ops, NFC_V1_V2_CONFIG2);
525
526 /* Wait for operation to complete */
527 wait_op_done(host, true);
528}
529
530static void send_page_v1(struct mtd_info *mtd, unsigned int ops)
Sascha Hauer34f6e152008-09-02 17:16:59 +0200531{
Sascha Hauer2d69c7f2009-10-05 11:24:02 +0200532 struct nand_chip *nand_chip = mtd->priv;
533 struct mxc_nand_host *host = nand_chip->priv;
Sascha Hauerc5d23f12009-06-04 17:25:53 +0200534 int bufs, i;
Sascha Hauer34f6e152008-09-02 17:16:59 +0200535
Uwe Kleine-König6d38af22012-04-23 11:23:36 +0200536 if (mtd->writesize > 512)
Sascha Hauerc5d23f12009-06-04 17:25:53 +0200537 bufs = 4;
538 else
539 bufs = 1;
Sascha Hauer34f6e152008-09-02 17:16:59 +0200540
Sascha Hauerc5d23f12009-06-04 17:25:53 +0200541 for (i = 0; i < bufs; i++) {
542
543 /* NANDFC buffer 0 is used for page read/write */
Baruch Siachd178e3e2011-03-14 09:01:56 +0200544 writew((host->active_cs << 4) | i, NFC_V1_V2_BUF_ADDR);
Sascha Hauerc5d23f12009-06-04 17:25:53 +0200545
Sascha Hauer1bc99182010-08-06 15:53:08 +0200546 writew(ops, NFC_V1_V2_CONFIG2);
Sascha Hauerc5d23f12009-06-04 17:25:53 +0200547
548 /* Wait for operation to complete */
Sascha Hauerc110eaf2009-10-21 16:01:02 +0200549 wait_op_done(host, true);
Sascha Hauer34f6e152008-09-02 17:16:59 +0200550 }
Sascha Hauer34f6e152008-09-02 17:16:59 +0200551}
552
Sascha Hauer71ec5152010-08-06 15:53:11 +0200553static void send_read_id_v3(struct mxc_nand_host *host)
554{
555 /* Read ID into main buffer */
556 writel(NFC_ID, NFC_V3_LAUNCH);
557
558 wait_op_done(host, true);
559
Sascha Hauer096bcc22012-05-29 10:16:09 +0200560 memcpy32_fromio(host->data_buf, host->main_area0, 16);
Sascha Hauer71ec5152010-08-06 15:53:11 +0200561}
562
Sascha Hauer34f6e152008-09-02 17:16:59 +0200563/* Request the NANDFC to perform a read of the NAND device ID. */
Sascha Hauer5f973042010-08-06 15:53:06 +0200564static void send_read_id_v1_v2(struct mxc_nand_host *host)
Sascha Hauer34f6e152008-09-02 17:16:59 +0200565{
Sascha Hauer34f6e152008-09-02 17:16:59 +0200566 /* NANDFC buffer 0 is used for device ID output */
Baruch Siachd178e3e2011-03-14 09:01:56 +0200567 writew(host->active_cs << 4, NFC_V1_V2_BUF_ADDR);
Sascha Hauer34f6e152008-09-02 17:16:59 +0200568
Sascha Hauer1bc99182010-08-06 15:53:08 +0200569 writew(NFC_ID, NFC_V1_V2_CONFIG2);
Sascha Hauer34f6e152008-09-02 17:16:59 +0200570
571 /* Wait for operation to complete */
Sascha Hauerc110eaf2009-10-21 16:01:02 +0200572 wait_op_done(host, true);
Sascha Hauer34f6e152008-09-02 17:16:59 +0200573
Sascha Hauer096bcc22012-05-29 10:16:09 +0200574 memcpy32_fromio(host->data_buf, host->main_area0, 16);
Sascha Hauer34f6e152008-09-02 17:16:59 +0200575}
576
Sascha Hauer71ec5152010-08-06 15:53:11 +0200577static uint16_t get_dev_status_v3(struct mxc_nand_host *host)
Sascha Hauer34f6e152008-09-02 17:16:59 +0200578{
Sascha Hauer71ec5152010-08-06 15:53:11 +0200579 writew(NFC_STATUS, NFC_V3_LAUNCH);
Sascha Hauerc110eaf2009-10-21 16:01:02 +0200580 wait_op_done(host, true);
Sascha Hauer34f6e152008-09-02 17:16:59 +0200581
Sascha Hauer71ec5152010-08-06 15:53:11 +0200582 return readl(NFC_V3_CONFIG1) >> 16;
583}
584
Sascha Hauer34f6e152008-09-02 17:16:59 +0200585/* This function requests the NANDFC to perform a read of the
586 * NAND device status and returns the current status. */
Sascha Hauer5f973042010-08-06 15:53:06 +0200587static uint16_t get_dev_status_v1_v2(struct mxc_nand_host *host)
Sascha Hauer34f6e152008-09-02 17:16:59 +0200588{
Sascha Hauerc29c6072010-08-06 15:53:05 +0200589 void __iomem *main_buf = host->main_area0;
Sascha Hauer34f6e152008-09-02 17:16:59 +0200590 uint32_t store;
591 uint16_t ret;
Sascha Hauer34f6e152008-09-02 17:16:59 +0200592
Baruch Siachd178e3e2011-03-14 09:01:56 +0200593 writew(host->active_cs << 4, NFC_V1_V2_BUF_ADDR);
Sascha Hauerc29c6072010-08-06 15:53:05 +0200594
595 /*
596 * The device status is stored in main_area0. To
597 * prevent corruption of the buffer save the value
598 * and restore it afterwards.
599 */
Sascha Hauer34f6e152008-09-02 17:16:59 +0200600 store = readl(main_buf);
Sascha Hauer34f6e152008-09-02 17:16:59 +0200601
Sascha Hauer1bc99182010-08-06 15:53:08 +0200602 writew(NFC_STATUS, NFC_V1_V2_CONFIG2);
Sascha Hauer34f6e152008-09-02 17:16:59 +0200603 wait_op_done(host, true);
604
Sascha Hauer34f6e152008-09-02 17:16:59 +0200605 ret = readw(main_buf);
Sascha Hauerc29c6072010-08-06 15:53:05 +0200606
Sascha Hauer34f6e152008-09-02 17:16:59 +0200607 writel(store, main_buf);
608
609 return ret;
610}
611
612/* This functions is used by upper layer to checks if device is ready */
613static int mxc_nand_dev_ready(struct mtd_info *mtd)
614{
615 /*
616 * NFC handles R/B internally. Therefore, this function
617 * always returns status as ready.
618 */
619 return 1;
620}
621
622static void mxc_nand_enable_hwecc(struct mtd_info *mtd, int mode)
623{
624 /*
625 * If HW ECC is enabled, we turn it on during init. There is
626 * no need to enable again here.
627 */
628}
629
Sascha Hauer94f77e52010-08-06 15:53:09 +0200630static int mxc_nand_correct_data_v1(struct mtd_info *mtd, u_char *dat,
Sascha Hauer34f6e152008-09-02 17:16:59 +0200631 u_char *read_ecc, u_char *calc_ecc)
632{
633 struct nand_chip *nand_chip = mtd->priv;
634 struct mxc_nand_host *host = nand_chip->priv;
635
636 /*
637 * 1-Bit errors are automatically corrected in HW. No need for
638 * additional correction. 2-Bit errors cannot be corrected by
639 * HW ECC, so we need to return failure
640 */
Uwe Kleine-König6d38af22012-04-23 11:23:36 +0200641 uint16_t ecc_status = get_ecc_status_v1(host);
Sascha Hauer34f6e152008-09-02 17:16:59 +0200642
643 if (((ecc_status & 0x3) == 2) || ((ecc_status >> 2) == 2)) {
Brian Norris289c0522011-07-19 10:06:09 -0700644 pr_debug("MXC_NAND: HWECC uncorrectable 2-bit ECC error\n");
Sascha Hauer34f6e152008-09-02 17:16:59 +0200645 return -1;
646 }
647
648 return 0;
649}
650
Sascha Hauer94f77e52010-08-06 15:53:09 +0200651static int mxc_nand_correct_data_v2_v3(struct mtd_info *mtd, u_char *dat,
652 u_char *read_ecc, u_char *calc_ecc)
653{
654 struct nand_chip *nand_chip = mtd->priv;
655 struct mxc_nand_host *host = nand_chip->priv;
656 u32 ecc_stat, err;
657 int no_subpages = 1;
658 int ret = 0;
659 u8 ecc_bit_mask, err_limit;
660
661 ecc_bit_mask = (host->eccsize == 4) ? 0x7 : 0xf;
662 err_limit = (host->eccsize == 4) ? 0x4 : 0x8;
663
664 no_subpages = mtd->writesize >> 9;
665
Uwe Kleine-König6d38af22012-04-23 11:23:36 +0200666 ecc_stat = host->devtype_data->get_ecc_status(host);
Sascha Hauer94f77e52010-08-06 15:53:09 +0200667
668 do {
669 err = ecc_stat & ecc_bit_mask;
670 if (err > err_limit) {
671 printk(KERN_WARNING "UnCorrectable RS-ECC Error\n");
672 return -1;
673 } else {
674 ret += err;
675 }
676 ecc_stat >>= 4;
677 } while (--no_subpages);
678
Sascha Hauer94f77e52010-08-06 15:53:09 +0200679 pr_debug("%d Symbol Correctable RS-ECC Error\n", ret);
680
681 return ret;
682}
683
Sascha Hauer34f6e152008-09-02 17:16:59 +0200684static int mxc_nand_calculate_ecc(struct mtd_info *mtd, const u_char *dat,
685 u_char *ecc_code)
686{
687 return 0;
688}
689
690static u_char mxc_nand_read_byte(struct mtd_info *mtd)
691{
692 struct nand_chip *nand_chip = mtd->priv;
693 struct mxc_nand_host *host = nand_chip->priv;
Sascha Hauerf8f96082009-06-04 17:12:26 +0200694 uint8_t ret;
Sascha Hauer34f6e152008-09-02 17:16:59 +0200695
696 /* Check for status request */
697 if (host->status_request)
Uwe Kleine-Könige4303b22012-04-23 11:23:35 +0200698 return host->devtype_data->get_dev_status(host) & 0xFF;
Sascha Hauer34f6e152008-09-02 17:16:59 +0200699
Uwe Kleine-König3f410692015-02-10 19:59:57 +0100700 if (nand_chip->options & NAND_BUSWIDTH_16) {
701 /* only take the lower byte of each word */
702 ret = *(uint16_t *)(host->data_buf + host->buf_start);
Sascha Hauer34f6e152008-09-02 17:16:59 +0200703
Uwe Kleine-König3f410692015-02-10 19:59:57 +0100704 host->buf_start += 2;
705 } else {
706 ret = *(uint8_t *)(host->data_buf + host->buf_start);
707 host->buf_start++;
708 }
709
710 pr_debug("%s: ret=0x%hhx (start=%u)\n", __func__, ret, host->buf_start);
Sascha Hauer34f6e152008-09-02 17:16:59 +0200711 return ret;
712}
713
714static uint16_t mxc_nand_read_word(struct mtd_info *mtd)
715{
716 struct nand_chip *nand_chip = mtd->priv;
717 struct mxc_nand_host *host = nand_chip->priv;
Sascha Hauerf8f96082009-06-04 17:12:26 +0200718 uint16_t ret;
Sascha Hauer34f6e152008-09-02 17:16:59 +0200719
Sascha Hauerf8f96082009-06-04 17:12:26 +0200720 ret = *(uint16_t *)(host->data_buf + host->buf_start);
721 host->buf_start += 2;
Sascha Hauer34f6e152008-09-02 17:16:59 +0200722
723 return ret;
724}
725
726/* Write data of length len to buffer buf. The data to be
727 * written on NAND Flash is first copied to RAMbuffer. After the Data Input
728 * Operation by the NFC, the data is written to NAND Flash */
729static void mxc_nand_write_buf(struct mtd_info *mtd,
730 const u_char *buf, int len)
731{
732 struct nand_chip *nand_chip = mtd->priv;
733 struct mxc_nand_host *host = nand_chip->priv;
Sascha Hauerf8f96082009-06-04 17:12:26 +0200734 u16 col = host->buf_start;
735 int n = mtd->oobsize + mtd->writesize - col;
Sascha Hauer34f6e152008-09-02 17:16:59 +0200736
Sascha Hauerf8f96082009-06-04 17:12:26 +0200737 n = min(n, len);
Sascha Hauer34f6e152008-09-02 17:16:59 +0200738
Sascha Hauerf8f96082009-06-04 17:12:26 +0200739 memcpy(host->data_buf + col, buf, n);
Sascha Hauer34f6e152008-09-02 17:16:59 +0200740
Sascha Hauerf8f96082009-06-04 17:12:26 +0200741 host->buf_start += n;
Sascha Hauer34f6e152008-09-02 17:16:59 +0200742}
743
744/* Read the data buffer from the NAND Flash. To read the data from NAND
745 * Flash first the data output cycle is initiated by the NFC, which copies
746 * the data to RAMbuffer. This data of length len is then copied to buffer buf.
747 */
748static void mxc_nand_read_buf(struct mtd_info *mtd, u_char *buf, int len)
749{
750 struct nand_chip *nand_chip = mtd->priv;
751 struct mxc_nand_host *host = nand_chip->priv;
Sascha Hauerf8f96082009-06-04 17:12:26 +0200752 u16 col = host->buf_start;
753 int n = mtd->oobsize + mtd->writesize - col;
Sascha Hauer34f6e152008-09-02 17:16:59 +0200754
Sascha Hauerf8f96082009-06-04 17:12:26 +0200755 n = min(n, len);
Sascha Hauer34f6e152008-09-02 17:16:59 +0200756
Baruch Siach5d9d9932011-03-02 16:47:55 +0200757 memcpy(buf, host->data_buf + col, n);
Sascha Hauer34f6e152008-09-02 17:16:59 +0200758
Baruch Siach5d9d9932011-03-02 16:47:55 +0200759 host->buf_start += n;
Sascha Hauer34f6e152008-09-02 17:16:59 +0200760}
761
Sascha Hauer34f6e152008-09-02 17:16:59 +0200762/* This function is used by upper layer for select and
763 * deselect of the NAND chip */
Uwe Kleine-König5e05a2d2012-04-23 11:23:38 +0200764static void mxc_nand_select_chip_v1_v3(struct mtd_info *mtd, int chip)
Sascha Hauer34f6e152008-09-02 17:16:59 +0200765{
766 struct nand_chip *nand_chip = mtd->priv;
767 struct mxc_nand_host *host = nand_chip->priv;
768
Baruch Siachd178e3e2011-03-14 09:01:56 +0200769 if (chip == -1) {
Sascha Hauer34f6e152008-09-02 17:16:59 +0200770 /* Disable the NFC clock */
771 if (host->clk_act) {
Sascha Hauer97c32132012-03-07 20:56:35 +0100772 clk_disable_unprepare(host->clk);
Sascha Hauer34f6e152008-09-02 17:16:59 +0200773 host->clk_act = 0;
774 }
Baruch Siachd178e3e2011-03-14 09:01:56 +0200775 return;
776 }
Sascha Hauer34f6e152008-09-02 17:16:59 +0200777
Baruch Siachd178e3e2011-03-14 09:01:56 +0200778 if (!host->clk_act) {
779 /* Enable the NFC clock */
Sascha Hauer97c32132012-03-07 20:56:35 +0100780 clk_prepare_enable(host->clk);
Baruch Siachd178e3e2011-03-14 09:01:56 +0200781 host->clk_act = 1;
782 }
Uwe Kleine-König5e05a2d2012-04-23 11:23:38 +0200783}
Baruch Siachd178e3e2011-03-14 09:01:56 +0200784
Uwe Kleine-König5e05a2d2012-04-23 11:23:38 +0200785static void mxc_nand_select_chip_v2(struct mtd_info *mtd, int chip)
Sascha Hauer34f6e152008-09-02 17:16:59 +0200786{
787 struct nand_chip *nand_chip = mtd->priv;
788 struct mxc_nand_host *host = nand_chip->priv;
789
790 if (chip == -1) {
791 /* Disable the NFC clock */
792 if (host->clk_act) {
Fabio Estevam3d059692012-05-25 20:14:50 -0300793 clk_disable_unprepare(host->clk);
Sascha Hauer34f6e152008-09-02 17:16:59 +0200794 host->clk_act = 0;
795 }
796 return;
Sascha Hauer34f6e152008-09-02 17:16:59 +0200797 }
Sascha Hauer34f6e152008-09-02 17:16:59 +0200798
799 if (!host->clk_act) {
800 /* Enable the NFC clock */
Fabio Estevam3d059692012-05-25 20:14:50 -0300801 clk_prepare_enable(host->clk);
Sascha Hauer34f6e152008-09-02 17:16:59 +0200802 host->clk_act = 1;
803 }
804
Uwe Kleine-König5e05a2d2012-04-23 11:23:38 +0200805 host->active_cs = chip;
806 writew(host->active_cs << 4, NFC_V1_V2_BUF_ADDR);
Sascha Hauer34f6e152008-09-02 17:16:59 +0200807}
808
Sascha Hauerf8f96082009-06-04 17:12:26 +0200809/*
810 * Function to transfer data to/from spare area.
811 */
812static void copy_spare(struct mtd_info *mtd, bool bfrom)
813{
814 struct nand_chip *this = mtd->priv;
815 struct mxc_nand_host *host = this->priv;
816 u16 i, j;
817 u16 n = mtd->writesize >> 9;
818 u8 *d = host->data_buf + mtd->writesize;
Uwe Kleine-König4b6f05e2012-04-24 10:05:22 +0200819 u8 __iomem *s = host->spare0;
Uwe Kleine-Königf48d0f92012-04-23 11:23:40 +0200820 u16 t = host->devtype_data->spare_len;
Sascha Hauerf8f96082009-06-04 17:12:26 +0200821
822 j = (mtd->oobsize / n >> 1) << 1;
823
824 if (bfrom) {
825 for (i = 0; i < n - 1; i++)
Sascha Hauer096bcc22012-05-29 10:16:09 +0200826 memcpy32_fromio(d + i * j, s + i * t, j);
Sascha Hauerf8f96082009-06-04 17:12:26 +0200827
828 /* the last section */
Sascha Hauer096bcc22012-05-29 10:16:09 +0200829 memcpy32_fromio(d + i * j, s + i * t, mtd->oobsize - i * j);
Sascha Hauerf8f96082009-06-04 17:12:26 +0200830 } else {
831 for (i = 0; i < n - 1; i++)
Sascha Hauer096bcc22012-05-29 10:16:09 +0200832 memcpy32_toio(&s[i * t], &d[i * j], j);
Sascha Hauerf8f96082009-06-04 17:12:26 +0200833
834 /* the last section */
Sascha Hauer096bcc22012-05-29 10:16:09 +0200835 memcpy32_toio(&s[i * t], &d[i * j], mtd->oobsize - i * j);
Sascha Hauerf8f96082009-06-04 17:12:26 +0200836 }
837}
838
Uwe Kleine-Königc4ca3992015-02-10 19:59:58 +0100839/*
840 * MXC NANDFC can only perform full page+spare or spare-only read/write. When
841 * the upper layers perform a read/write buf operation, the saved column address
842 * is used to index into the full page. So usually this function is called with
843 * column == 0 (unless no column cycle is needed indicated by column == -1)
844 */
Sascha Hauera3e65b62009-06-02 11:47:59 +0200845static void mxc_do_addr_cycle(struct mtd_info *mtd, int column, int page_addr)
Sascha Hauer34f6e152008-09-02 17:16:59 +0200846{
847 struct nand_chip *nand_chip = mtd->priv;
848 struct mxc_nand_host *host = nand_chip->priv;
Sascha Hauer34f6e152008-09-02 17:16:59 +0200849
850 /* Write out column address, if necessary */
851 if (column != -1) {
Uwe Kleine-Königc4ca3992015-02-10 19:59:58 +0100852 host->devtype_data->send_addr(host, column & 0xff,
853 page_addr == -1);
Sascha Hauer2d69c7f2009-10-05 11:24:02 +0200854 if (mtd->writesize > 512)
Sascha Hauer34f6e152008-09-02 17:16:59 +0200855 /* another col addr cycle for 2k page */
Uwe Kleine-Königc4ca3992015-02-10 19:59:58 +0100856 host->devtype_data->send_addr(host,
857 (column >> 8) & 0xff,
858 false);
Sascha Hauer34f6e152008-09-02 17:16:59 +0200859 }
860
861 /* Write out page address, if necessary */
862 if (page_addr != -1) {
863 /* paddr_0 - p_addr_7 */
Uwe Kleine-Könige4303b22012-04-23 11:23:35 +0200864 host->devtype_data->send_addr(host, (page_addr & 0xff), false);
Sascha Hauer34f6e152008-09-02 17:16:59 +0200865
Sascha Hauer2d69c7f2009-10-05 11:24:02 +0200866 if (mtd->writesize > 512) {
Vladimir Barinovbd3fd622009-05-25 13:06:17 +0400867 if (mtd->size >= 0x10000000) {
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,
871 false);
872 host->devtype_data->send_addr(host,
873 (page_addr >> 16) & 0xff,
874 true);
Vladimir Barinovbd3fd622009-05-25 13:06:17 +0400875 } else
876 /* paddr_8 - paddr_15 */
Uwe Kleine-Könige4303b22012-04-23 11:23:35 +0200877 host->devtype_data->send_addr(host,
878 (page_addr >> 8) & 0xff, true);
Sascha Hauer34f6e152008-09-02 17:16:59 +0200879 } else {
880 /* One more address cycle for higher density devices */
881 if (mtd->size >= 0x4000000) {
882 /* paddr_8 - paddr_15 */
Uwe Kleine-Könige4303b22012-04-23 11:23:35 +0200883 host->devtype_data->send_addr(host,
884 (page_addr >> 8) & 0xff,
885 false);
886 host->devtype_data->send_addr(host,
887 (page_addr >> 16) & 0xff,
888 true);
Sascha Hauer34f6e152008-09-02 17:16:59 +0200889 } else
890 /* paddr_8 - paddr_15 */
Uwe Kleine-Könige4303b22012-04-23 11:23:35 +0200891 host->devtype_data->send_addr(host,
892 (page_addr >> 8) & 0xff, true);
Sascha Hauer34f6e152008-09-02 17:16:59 +0200893 }
894 }
Sascha Hauera3e65b62009-06-02 11:47:59 +0200895}
Sascha Hauer34f6e152008-09-02 17:16:59 +0200896
Sascha Hauer6e85dfd2010-08-06 15:53:10 +0200897/*
898 * v2 and v3 type controllers can do 4bit or 8bit ecc depending
899 * on how much oob the nand chip has. For 8bit ecc we need at least
900 * 26 bytes of oob data per 512 byte block.
901 */
902static int get_eccsize(struct mtd_info *mtd)
903{
904 int oobbytes_per_512 = 0;
905
906 oobbytes_per_512 = mtd->oobsize * 512 / mtd->writesize;
907
908 if (oobbytes_per_512 < 26)
909 return 4;
910 else
911 return 8;
912}
913
Uwe Kleine-König6d38af22012-04-23 11:23:36 +0200914static void preset_v1(struct mtd_info *mtd)
Ivo Claryssed4840182010-04-08 16:14:44 +0200915{
916 struct nand_chip *nand_chip = mtd->priv;
917 struct mxc_nand_host *host = nand_chip->priv;
Sascha Hauerb8db2f52010-08-09 15:04:19 +0200918 uint16_t config1 = 0;
Ivo Claryssed4840182010-04-08 16:14:44 +0200919
Uwe Kleine-König1f42adc2015-02-10 19:59:56 +0100920 if (nand_chip->ecc.mode == NAND_ECC_HW && mtd->writesize)
Sascha Hauerb8db2f52010-08-09 15:04:19 +0200921 config1 |= NFC_V1_V2_CONFIG1_ECC_EN;
922
Uwe Kleine-Königf48d0f92012-04-23 11:23:40 +0200923 if (!host->devtype_data->irqpending_quirk)
Sascha Hauerb8db2f52010-08-09 15:04:19 +0200924 config1 |= NFC_V1_V2_CONFIG1_INT_MSK;
Sascha Hauer6e85dfd2010-08-06 15:53:10 +0200925
Uwe Kleine-König6d38af22012-04-23 11:23:36 +0200926 host->eccsize = 1;
927
928 writew(config1, NFC_V1_V2_CONFIG1);
929 /* preset operation */
930
931 /* Unlock the internal RAM Buffer */
932 writew(0x2, NFC_V1_V2_CONFIG);
933
934 /* Blocks to be unlocked */
935 writew(0x0, NFC_V1_UNLOCKSTART_BLKADDR);
936 writew(0xffff, NFC_V1_UNLOCKEND_BLKADDR);
937
938 /* Unlock Block Command for given address range */
939 writew(0x4, NFC_V1_V2_WRPROT);
940}
941
942static void preset_v2(struct mtd_info *mtd)
943{
944 struct nand_chip *nand_chip = mtd->priv;
945 struct mxc_nand_host *host = nand_chip->priv;
946 uint16_t config1 = 0;
947
Uwe Kleine-König6d38af22012-04-23 11:23:36 +0200948 config1 |= NFC_V2_CONFIG1_FP_INT;
Ivo Claryssed4840182010-04-08 16:14:44 +0200949
Uwe Kleine-Königf48d0f92012-04-23 11:23:40 +0200950 if (!host->devtype_data->irqpending_quirk)
Ivo Claryssed4840182010-04-08 16:14:44 +0200951 config1 |= NFC_V1_V2_CONFIG1_INT_MSK;
Sascha Hauer6e85dfd2010-08-06 15:53:10 +0200952
Uwe Kleine-König6d38af22012-04-23 11:23:36 +0200953 if (mtd->writesize) {
Sascha Hauerb8db2f52010-08-09 15:04:19 +0200954 uint16_t pages_per_block = mtd->erasesize / mtd->writesize;
955
Uwe Kleine-König1f42adc2015-02-10 19:59:56 +0100956 if (nand_chip->ecc.mode == NAND_ECC_HW)
957 config1 |= NFC_V1_V2_CONFIG1_ECC_EN;
958
Sascha Hauer6e85dfd2010-08-06 15:53:10 +0200959 host->eccsize = get_eccsize(mtd);
960 if (host->eccsize == 4)
Sascha Hauerb8db2f52010-08-09 15:04:19 +0200961 config1 |= NFC_V2_CONFIG1_ECC_MODE_4;
962
963 config1 |= NFC_V2_CONFIG1_PPB(ffs(pages_per_block) - 6);
Sascha Hauer6e85dfd2010-08-06 15:53:10 +0200964 } else {
965 host->eccsize = 1;
966 }
967
Sascha Hauerb8db2f52010-08-09 15:04:19 +0200968 writew(config1, NFC_V1_V2_CONFIG1);
Ivo Claryssed4840182010-04-08 16:14:44 +0200969 /* preset operation */
970
971 /* Unlock the internal RAM Buffer */
Sascha Hauer1bc99182010-08-06 15:53:08 +0200972 writew(0x2, NFC_V1_V2_CONFIG);
Ivo Claryssed4840182010-04-08 16:14:44 +0200973
974 /* Blocks to be unlocked */
Uwe Kleine-König6d38af22012-04-23 11:23:36 +0200975 writew(0x0, NFC_V21_UNLOCKSTART_BLKADDR0);
976 writew(0x0, NFC_V21_UNLOCKSTART_BLKADDR1);
977 writew(0x0, NFC_V21_UNLOCKSTART_BLKADDR2);
978 writew(0x0, NFC_V21_UNLOCKSTART_BLKADDR3);
979 writew(0xffff, NFC_V21_UNLOCKEND_BLKADDR0);
980 writew(0xffff, NFC_V21_UNLOCKEND_BLKADDR1);
981 writew(0xffff, NFC_V21_UNLOCKEND_BLKADDR2);
982 writew(0xffff, NFC_V21_UNLOCKEND_BLKADDR3);
Ivo Claryssed4840182010-04-08 16:14:44 +0200983
984 /* Unlock Block Command for given address range */
Sascha Hauer1bc99182010-08-06 15:53:08 +0200985 writew(0x4, NFC_V1_V2_WRPROT);
Ivo Claryssed4840182010-04-08 16:14:44 +0200986}
987
Sascha Hauer71ec5152010-08-06 15:53:11 +0200988static void preset_v3(struct mtd_info *mtd)
989{
990 struct nand_chip *chip = mtd->priv;
991 struct mxc_nand_host *host = chip->priv;
992 uint32_t config2, config3;
993 int i, addr_phases;
994
995 writel(NFC_V3_CONFIG1_RBA(0), NFC_V3_CONFIG1);
996 writel(NFC_V3_IPC_CREQ, NFC_V3_IPC);
997
998 /* Unlock the internal RAM Buffer */
999 writel(NFC_V3_WRPROT_BLS_UNLOCK | NFC_V3_WRPROT_UNLOCK,
1000 NFC_V3_WRPROT);
1001
1002 /* Blocks to be unlocked */
1003 for (i = 0; i < NAND_MAX_CHIPS; i++)
1004 writel(0x0 | (0xffff << 16),
1005 NFC_V3_WRPROT_UNLOCK_BLK_ADD0 + (i << 2));
1006
1007 writel(0, NFC_V3_IPC);
1008
1009 config2 = NFC_V3_CONFIG2_ONE_CYCLE |
1010 NFC_V3_CONFIG2_2CMD_PHASES |
1011 NFC_V3_CONFIG2_SPAS(mtd->oobsize >> 1) |
1012 NFC_V3_CONFIG2_ST_CMD(0x70) |
Sascha Hauer63f14742010-10-18 10:16:26 +02001013 NFC_V3_CONFIG2_INT_MSK |
Sascha Hauer71ec5152010-08-06 15:53:11 +02001014 NFC_V3_CONFIG2_NUM_ADDR_PHASE0;
1015
Sascha Hauer71ec5152010-08-06 15:53:11 +02001016 addr_phases = fls(chip->pagemask) >> 3;
1017
1018 if (mtd->writesize == 2048) {
1019 config2 |= NFC_V3_CONFIG2_PS_2048;
1020 config2 |= NFC_V3_CONFIG2_NUM_ADDR_PHASE1(addr_phases);
1021 } else if (mtd->writesize == 4096) {
1022 config2 |= NFC_V3_CONFIG2_PS_4096;
1023 config2 |= NFC_V3_CONFIG2_NUM_ADDR_PHASE1(addr_phases);
1024 } else {
1025 config2 |= NFC_V3_CONFIG2_PS_512;
1026 config2 |= NFC_V3_CONFIG2_NUM_ADDR_PHASE1(addr_phases - 1);
1027 }
1028
1029 if (mtd->writesize) {
Uwe Kleine-König1f42adc2015-02-10 19:59:56 +01001030 if (chip->ecc.mode == NAND_ECC_HW)
1031 config2 |= NFC_V3_CONFIG2_ECC_EN;
1032
Sascha Hauer71718a8e2012-06-06 12:33:15 +02001033 config2 |= NFC_V3_CONFIG2_PPB(
1034 ffs(mtd->erasesize / mtd->writesize) - 6,
1035 host->devtype_data->ppb_shift);
Sascha Hauer71ec5152010-08-06 15:53:11 +02001036 host->eccsize = get_eccsize(mtd);
1037 if (host->eccsize == 8)
1038 config2 |= NFC_V3_CONFIG2_ECC_MODE_8;
1039 }
1040
1041 writel(config2, NFC_V3_CONFIG2);
1042
1043 config3 = NFC_V3_CONFIG3_NUM_OF_DEVICES(0) |
1044 NFC_V3_CONFIG3_NO_SDMA |
1045 NFC_V3_CONFIG3_RBB_MODE |
1046 NFC_V3_CONFIG3_SBB(6) | /* Reset default */
1047 NFC_V3_CONFIG3_ADD_OP(0);
1048
1049 if (!(chip->options & NAND_BUSWIDTH_16))
1050 config3 |= NFC_V3_CONFIG3_FW8;
1051
1052 writel(config3, NFC_V3_CONFIG3);
1053
1054 writel(0, NFC_V3_DELAY_LINE);
Sascha Hauer34f6e152008-09-02 17:16:59 +02001055}
1056
Sascha Hauer34f6e152008-09-02 17:16:59 +02001057/* Used by the upper layer to write command to NAND Flash for
1058 * different operations to be carried out on NAND Flash */
1059static void mxc_nand_command(struct mtd_info *mtd, unsigned command,
1060 int column, int page_addr)
1061{
1062 struct nand_chip *nand_chip = mtd->priv;
1063 struct mxc_nand_host *host = nand_chip->priv;
Sascha Hauer34f6e152008-09-02 17:16:59 +02001064
Brian Norris289c0522011-07-19 10:06:09 -07001065 pr_debug("mxc_nand_command (cmd = 0x%x, col = 0x%x, page = 0x%x)\n",
Sascha Hauer34f6e152008-09-02 17:16:59 +02001066 command, column, page_addr);
1067
1068 /* Reset command state information */
1069 host->status_request = false;
1070
1071 /* Command pre-processing step */
Sascha Hauer34f6e152008-09-02 17:16:59 +02001072 switch (command) {
Ivo Claryssed4840182010-04-08 16:14:44 +02001073 case NAND_CMD_RESET:
Uwe Kleine-Könige4303b22012-04-23 11:23:35 +02001074 host->devtype_data->preset(mtd);
1075 host->devtype_data->send_cmd(host, command, false);
Ivo Claryssed4840182010-04-08 16:14:44 +02001076 break;
Sascha Hauer34f6e152008-09-02 17:16:59 +02001077
Sascha Hauer34f6e152008-09-02 17:16:59 +02001078 case NAND_CMD_STATUS:
Sascha Hauerf8f96082009-06-04 17:12:26 +02001079 host->buf_start = 0;
Sascha Hauer34f6e152008-09-02 17:16:59 +02001080 host->status_request = true;
Sascha Hauer89121a62009-06-04 17:18:01 +02001081
Uwe Kleine-Könige4303b22012-04-23 11:23:35 +02001082 host->devtype_data->send_cmd(host, command, true);
Uwe Kleine-Königc4ca3992015-02-10 19:59:58 +01001083 WARN_ONCE(column != -1 || page_addr != -1,
1084 "Unexpected column/row value (cmd=%u, col=%d, row=%d)\n",
1085 command, column, page_addr);
Sascha Hauer89121a62009-06-04 17:18:01 +02001086 mxc_do_addr_cycle(mtd, column, page_addr);
Sascha Hauer34f6e152008-09-02 17:16:59 +02001087 break;
1088
Sascha Hauer34f6e152008-09-02 17:16:59 +02001089 case NAND_CMD_READ0:
Sascha Hauer34f6e152008-09-02 17:16:59 +02001090 case NAND_CMD_READOOB:
Sascha Hauer89121a62009-06-04 17:18:01 +02001091 if (command == NAND_CMD_READ0)
1092 host->buf_start = column;
1093 else
1094 host->buf_start = column + mtd->writesize;
Sascha Hauerf8f96082009-06-04 17:12:26 +02001095
Sascha Hauer5ea32022010-04-27 15:24:01 +02001096 command = NAND_CMD_READ0; /* only READ0 is valid */
Sascha Hauer89121a62009-06-04 17:18:01 +02001097
Uwe Kleine-Könige4303b22012-04-23 11:23:35 +02001098 host->devtype_data->send_cmd(host, command, false);
Uwe Kleine-Königc4ca3992015-02-10 19:59:58 +01001099 WARN_ONCE(column < 0,
1100 "Unexpected column/row value (cmd=%u, col=%d, row=%d)\n",
1101 command, column, page_addr);
1102 mxc_do_addr_cycle(mtd, 0, page_addr);
Sascha Hauer89121a62009-06-04 17:18:01 +02001103
Sascha Hauer2d69c7f2009-10-05 11:24:02 +02001104 if (mtd->writesize > 512)
Uwe Kleine-Könige4303b22012-04-23 11:23:35 +02001105 host->devtype_data->send_cmd(host,
1106 NAND_CMD_READSTART, true);
Sascha Hauerc5d23f12009-06-04 17:25:53 +02001107
Uwe Kleine-Könige4303b22012-04-23 11:23:35 +02001108 host->devtype_data->send_page(mtd, NFC_OUTPUT);
Sascha Hauer89121a62009-06-04 17:18:01 +02001109
Sascha Hauer096bcc22012-05-29 10:16:09 +02001110 memcpy32_fromio(host->data_buf, host->main_area0,
1111 mtd->writesize);
Sascha Hauer89121a62009-06-04 17:18:01 +02001112 copy_spare(mtd, true);
Sascha Hauer34f6e152008-09-02 17:16:59 +02001113 break;
1114
Sascha Hauer34f6e152008-09-02 17:16:59 +02001115 case NAND_CMD_SEQIN:
Sascha Hauer5ea32022010-04-27 15:24:01 +02001116 if (column >= mtd->writesize)
1117 /* call ourself to read a page */
1118 mxc_nand_command(mtd, NAND_CMD_READ0, 0, page_addr);
Sascha Hauer34f6e152008-09-02 17:16:59 +02001119
Sascha Hauer5ea32022010-04-27 15:24:01 +02001120 host->buf_start = column;
Sascha Hauer89121a62009-06-04 17:18:01 +02001121
Uwe Kleine-Könige4303b22012-04-23 11:23:35 +02001122 host->devtype_data->send_cmd(host, command, false);
Uwe Kleine-Königc4ca3992015-02-10 19:59:58 +01001123 WARN_ONCE(column < -1,
1124 "Unexpected column/row value (cmd=%u, col=%d, row=%d)\n",
1125 command, column, page_addr);
1126 mxc_do_addr_cycle(mtd, 0, page_addr);
Sascha Hauer34f6e152008-09-02 17:16:59 +02001127 break;
1128
1129 case NAND_CMD_PAGEPROG:
Sascha Hauer096bcc22012-05-29 10:16:09 +02001130 memcpy32_toio(host->main_area0, host->data_buf, mtd->writesize);
Sascha Hauerf8f96082009-06-04 17:12:26 +02001131 copy_spare(mtd, false);
Uwe Kleine-Könige4303b22012-04-23 11:23:35 +02001132 host->devtype_data->send_page(mtd, NFC_INPUT);
1133 host->devtype_data->send_cmd(host, command, true);
Uwe Kleine-Königc4ca3992015-02-10 19:59:58 +01001134 WARN_ONCE(column != -1 || page_addr != -1,
1135 "Unexpected column/row value (cmd=%u, col=%d, row=%d)\n",
1136 command, column, page_addr);
Sascha Hauer89121a62009-06-04 17:18:01 +02001137 mxc_do_addr_cycle(mtd, column, page_addr);
Sascha Hauer34f6e152008-09-02 17:16:59 +02001138 break;
1139
Sascha Hauer34f6e152008-09-02 17:16:59 +02001140 case NAND_CMD_READID:
Uwe Kleine-Könige4303b22012-04-23 11:23:35 +02001141 host->devtype_data->send_cmd(host, command, true);
Sascha Hauer89121a62009-06-04 17:18:01 +02001142 mxc_do_addr_cycle(mtd, column, page_addr);
Uwe Kleine-Könige4303b22012-04-23 11:23:35 +02001143 host->devtype_data->send_read_id(host);
Uwe Kleine-Königc4ca3992015-02-10 19:59:58 +01001144 host->buf_start = 0;
Sascha Hauer34f6e152008-09-02 17:16:59 +02001145 break;
1146
Sascha Hauer89121a62009-06-04 17:18:01 +02001147 case NAND_CMD_ERASE1:
Sascha Hauer34f6e152008-09-02 17:16:59 +02001148 case NAND_CMD_ERASE2:
Uwe Kleine-Könige4303b22012-04-23 11:23:35 +02001149 host->devtype_data->send_cmd(host, command, false);
Uwe Kleine-Königc4ca3992015-02-10 19:59:58 +01001150 WARN_ONCE(column != -1,
1151 "Unexpected column value (cmd=%u, col=%d)\n",
1152 command, column);
Sascha Hauer89121a62009-06-04 17:18:01 +02001153 mxc_do_addr_cycle(mtd, column, page_addr);
1154
Sascha Hauer34f6e152008-09-02 17:16:59 +02001155 break;
1156 }
1157}
1158
Sascha Hauerf1372052009-10-21 14:25:27 +02001159/*
1160 * The generic flash bbt decriptors overlap with our ecc
1161 * hardware, so define some i.MX specific ones.
1162 */
1163static uint8_t bbt_pattern[] = { 'B', 'b', 't', '0' };
1164static uint8_t mirror_pattern[] = { '1', 't', 'b', 'B' };
1165
1166static struct nand_bbt_descr bbt_main_descr = {
1167 .options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE
1168 | NAND_BBT_2BIT | NAND_BBT_VERSION | NAND_BBT_PERCHIP,
1169 .offs = 0,
1170 .len = 4,
1171 .veroffs = 4,
1172 .maxblocks = 4,
1173 .pattern = bbt_pattern,
1174};
1175
1176static struct nand_bbt_descr bbt_mirror_descr = {
1177 .options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE
1178 | NAND_BBT_2BIT | NAND_BBT_VERSION | NAND_BBT_PERCHIP,
1179 .offs = 0,
1180 .len = 4,
1181 .veroffs = 4,
1182 .maxblocks = 4,
1183 .pattern = mirror_pattern,
1184};
1185
Uwe Kleine-Königf48d0f92012-04-23 11:23:40 +02001186/* v1 + irqpending_quirk: i.MX21 */
Uwe Kleine-Könige4303b22012-04-23 11:23:35 +02001187static const struct mxc_nand_devtype_data imx21_nand_devtype_data = {
Uwe Kleine-König6d38af22012-04-23 11:23:36 +02001188 .preset = preset_v1,
Uwe Kleine-Könige4303b22012-04-23 11:23:35 +02001189 .send_cmd = send_cmd_v1_v2,
1190 .send_addr = send_addr_v1_v2,
Uwe Kleine-König6d38af22012-04-23 11:23:36 +02001191 .send_page = send_page_v1,
Uwe Kleine-Könige4303b22012-04-23 11:23:35 +02001192 .send_read_id = send_read_id_v1_v2,
1193 .get_dev_status = get_dev_status_v1_v2,
1194 .check_int = check_int_v1_v2,
1195 .irq_control = irq_control_v1_v2,
Uwe Kleine-König6d38af22012-04-23 11:23:36 +02001196 .get_ecc_status = get_ecc_status_v1,
Uwe Kleine-König6dcdf992012-04-23 11:23:37 +02001197 .ecclayout_512 = &nandv1_hw_eccoob_smallpage,
1198 .ecclayout_2k = &nandv1_hw_eccoob_largepage,
1199 .ecclayout_4k = &nandv1_hw_eccoob_smallpage, /* XXX: needs fix */
Uwe Kleine-König5e05a2d2012-04-23 11:23:38 +02001200 .select_chip = mxc_nand_select_chip_v1_v3,
Uwe Kleine-König69d023b2012-04-23 11:23:39 +02001201 .correct_data = mxc_nand_correct_data_v1,
Uwe Kleine-Königf48d0f92012-04-23 11:23:40 +02001202 .irqpending_quirk = 1,
1203 .needs_ip = 0,
1204 .regs_offset = 0xe00,
1205 .spare0_offset = 0x800,
1206 .spare_len = 16,
1207 .eccbytes = 3,
1208 .eccsize = 1,
1209};
1210
1211/* v1 + !irqpending_quirk: i.MX27, i.MX31 */
1212static const struct mxc_nand_devtype_data imx27_nand_devtype_data = {
1213 .preset = preset_v1,
1214 .send_cmd = send_cmd_v1_v2,
1215 .send_addr = send_addr_v1_v2,
1216 .send_page = send_page_v1,
1217 .send_read_id = send_read_id_v1_v2,
1218 .get_dev_status = get_dev_status_v1_v2,
1219 .check_int = check_int_v1_v2,
1220 .irq_control = irq_control_v1_v2,
1221 .get_ecc_status = get_ecc_status_v1,
1222 .ecclayout_512 = &nandv1_hw_eccoob_smallpage,
1223 .ecclayout_2k = &nandv1_hw_eccoob_largepage,
1224 .ecclayout_4k = &nandv1_hw_eccoob_smallpage, /* XXX: needs fix */
1225 .select_chip = mxc_nand_select_chip_v1_v3,
1226 .correct_data = mxc_nand_correct_data_v1,
1227 .irqpending_quirk = 0,
1228 .needs_ip = 0,
1229 .regs_offset = 0xe00,
1230 .spare0_offset = 0x800,
1231 .axi_offset = 0,
1232 .spare_len = 16,
1233 .eccbytes = 3,
1234 .eccsize = 1,
Uwe Kleine-Könige4303b22012-04-23 11:23:35 +02001235};
1236
1237/* v21: i.MX25, i.MX35 */
1238static const struct mxc_nand_devtype_data imx25_nand_devtype_data = {
Uwe Kleine-König6d38af22012-04-23 11:23:36 +02001239 .preset = preset_v2,
Uwe Kleine-Könige4303b22012-04-23 11:23:35 +02001240 .send_cmd = send_cmd_v1_v2,
1241 .send_addr = send_addr_v1_v2,
Uwe Kleine-König6d38af22012-04-23 11:23:36 +02001242 .send_page = send_page_v2,
Uwe Kleine-Könige4303b22012-04-23 11:23:35 +02001243 .send_read_id = send_read_id_v1_v2,
1244 .get_dev_status = get_dev_status_v1_v2,
1245 .check_int = check_int_v1_v2,
1246 .irq_control = irq_control_v1_v2,
Uwe Kleine-König6d38af22012-04-23 11:23:36 +02001247 .get_ecc_status = get_ecc_status_v2,
Uwe Kleine-König6dcdf992012-04-23 11:23:37 +02001248 .ecclayout_512 = &nandv2_hw_eccoob_smallpage,
1249 .ecclayout_2k = &nandv2_hw_eccoob_largepage,
1250 .ecclayout_4k = &nandv2_hw_eccoob_4k,
Uwe Kleine-König5e05a2d2012-04-23 11:23:38 +02001251 .select_chip = mxc_nand_select_chip_v2,
Uwe Kleine-König69d023b2012-04-23 11:23:39 +02001252 .correct_data = mxc_nand_correct_data_v2_v3,
Uwe Kleine-Königf48d0f92012-04-23 11:23:40 +02001253 .irqpending_quirk = 0,
1254 .needs_ip = 0,
1255 .regs_offset = 0x1e00,
1256 .spare0_offset = 0x1000,
1257 .axi_offset = 0,
1258 .spare_len = 64,
1259 .eccbytes = 9,
1260 .eccsize = 0,
Uwe Kleine-Könige4303b22012-04-23 11:23:35 +02001261};
1262
Sascha Hauer71718a8e2012-06-06 12:33:15 +02001263/* v3.2a: i.MX51 */
Uwe Kleine-Könige4303b22012-04-23 11:23:35 +02001264static const struct mxc_nand_devtype_data imx51_nand_devtype_data = {
1265 .preset = preset_v3,
1266 .send_cmd = send_cmd_v3,
1267 .send_addr = send_addr_v3,
1268 .send_page = send_page_v3,
1269 .send_read_id = send_read_id_v3,
1270 .get_dev_status = get_dev_status_v3,
1271 .check_int = check_int_v3,
1272 .irq_control = irq_control_v3,
Uwe Kleine-König6d38af22012-04-23 11:23:36 +02001273 .get_ecc_status = get_ecc_status_v3,
Uwe Kleine-König6dcdf992012-04-23 11:23:37 +02001274 .ecclayout_512 = &nandv2_hw_eccoob_smallpage,
1275 .ecclayout_2k = &nandv2_hw_eccoob_largepage,
1276 .ecclayout_4k = &nandv2_hw_eccoob_smallpage, /* XXX: needs fix */
Uwe Kleine-König5e05a2d2012-04-23 11:23:38 +02001277 .select_chip = mxc_nand_select_chip_v1_v3,
Uwe Kleine-König69d023b2012-04-23 11:23:39 +02001278 .correct_data = mxc_nand_correct_data_v2_v3,
Uwe Kleine-Königf48d0f92012-04-23 11:23:40 +02001279 .irqpending_quirk = 0,
1280 .needs_ip = 1,
1281 .regs_offset = 0,
1282 .spare0_offset = 0x1000,
1283 .axi_offset = 0x1e00,
1284 .spare_len = 64,
1285 .eccbytes = 0,
1286 .eccsize = 0,
Sascha Hauer71718a8e2012-06-06 12:33:15 +02001287 .ppb_shift = 7,
1288};
1289
1290/* v3.2b: i.MX53 */
1291static const struct mxc_nand_devtype_data imx53_nand_devtype_data = {
1292 .preset = preset_v3,
1293 .send_cmd = send_cmd_v3,
1294 .send_addr = send_addr_v3,
1295 .send_page = send_page_v3,
1296 .send_read_id = send_read_id_v3,
1297 .get_dev_status = get_dev_status_v3,
1298 .check_int = check_int_v3,
1299 .irq_control = irq_control_v3,
1300 .get_ecc_status = get_ecc_status_v3,
1301 .ecclayout_512 = &nandv2_hw_eccoob_smallpage,
1302 .ecclayout_2k = &nandv2_hw_eccoob_largepage,
1303 .ecclayout_4k = &nandv2_hw_eccoob_smallpage, /* XXX: needs fix */
1304 .select_chip = mxc_nand_select_chip_v1_v3,
1305 .correct_data = mxc_nand_correct_data_v2_v3,
1306 .irqpending_quirk = 0,
1307 .needs_ip = 1,
1308 .regs_offset = 0,
1309 .spare0_offset = 0x1000,
1310 .axi_offset = 0x1e00,
1311 .spare_len = 64,
1312 .eccbytes = 0,
1313 .eccsize = 0,
1314 .ppb_shift = 8,
Uwe Kleine-Könige4303b22012-04-23 11:23:35 +02001315};
1316
Shawn Guo4d624352012-09-15 13:34:09 +08001317static inline int is_imx21_nfc(struct mxc_nand_host *host)
1318{
1319 return host->devtype_data == &imx21_nand_devtype_data;
1320}
1321
1322static inline int is_imx27_nfc(struct mxc_nand_host *host)
1323{
1324 return host->devtype_data == &imx27_nand_devtype_data;
1325}
1326
1327static inline int is_imx25_nfc(struct mxc_nand_host *host)
1328{
1329 return host->devtype_data == &imx25_nand_devtype_data;
1330}
1331
1332static inline int is_imx51_nfc(struct mxc_nand_host *host)
1333{
1334 return host->devtype_data == &imx51_nand_devtype_data;
1335}
1336
1337static inline int is_imx53_nfc(struct mxc_nand_host *host)
1338{
1339 return host->devtype_data == &imx53_nand_devtype_data;
1340}
1341
1342static struct platform_device_id mxcnd_devtype[] = {
1343 {
1344 .name = "imx21-nand",
1345 .driver_data = (kernel_ulong_t) &imx21_nand_devtype_data,
1346 }, {
1347 .name = "imx27-nand",
1348 .driver_data = (kernel_ulong_t) &imx27_nand_devtype_data,
1349 }, {
1350 .name = "imx25-nand",
1351 .driver_data = (kernel_ulong_t) &imx25_nand_devtype_data,
1352 }, {
1353 .name = "imx51-nand",
1354 .driver_data = (kernel_ulong_t) &imx51_nand_devtype_data,
1355 }, {
1356 .name = "imx53-nand",
1357 .driver_data = (kernel_ulong_t) &imx53_nand_devtype_data,
1358 }, {
1359 /* sentinel */
1360 }
1361};
1362MODULE_DEVICE_TABLE(platform, mxcnd_devtype);
1363
Uwe Kleine-König64363562012-04-23 11:23:41 +02001364#ifdef CONFIG_OF_MTD
1365static const struct of_device_id mxcnd_dt_ids[] = {
1366 {
1367 .compatible = "fsl,imx21-nand",
1368 .data = &imx21_nand_devtype_data,
1369 }, {
1370 .compatible = "fsl,imx27-nand",
1371 .data = &imx27_nand_devtype_data,
1372 }, {
1373 .compatible = "fsl,imx25-nand",
1374 .data = &imx25_nand_devtype_data,
1375 }, {
1376 .compatible = "fsl,imx51-nand",
1377 .data = &imx51_nand_devtype_data,
Sascha Hauer71718a8e2012-06-06 12:33:15 +02001378 }, {
1379 .compatible = "fsl,imx53-nand",
1380 .data = &imx53_nand_devtype_data,
Uwe Kleine-König64363562012-04-23 11:23:41 +02001381 },
1382 { /* sentinel */ }
1383};
1384
1385static int __init mxcnd_probe_dt(struct mxc_nand_host *host)
1386{
1387 struct device_node *np = host->dev->of_node;
1388 struct mxc_nand_platform_data *pdata = &host->pdata;
1389 const struct of_device_id *of_id =
1390 of_match_device(mxcnd_dt_ids, host->dev);
1391 int buswidth;
1392
1393 if (!np)
1394 return 1;
1395
1396 if (of_get_nand_ecc_mode(np) >= 0)
1397 pdata->hw_ecc = 1;
1398
1399 pdata->flash_bbt = of_get_nand_on_flash_bbt(np);
1400
1401 buswidth = of_get_nand_bus_width(np);
1402 if (buswidth < 0)
1403 return buswidth;
1404
1405 pdata->width = buswidth / 8;
1406
1407 host->devtype_data = of_id->data;
1408
1409 return 0;
1410}
1411#else
1412static int __init mxcnd_probe_dt(struct mxc_nand_host *host)
1413{
1414 return 1;
1415}
1416#endif
1417
Bill Pemberton06f25512012-11-19 13:23:07 -05001418static int mxcnd_probe(struct platform_device *pdev)
Sascha Hauer34f6e152008-09-02 17:16:59 +02001419{
1420 struct nand_chip *this;
1421 struct mtd_info *mtd;
Sascha Hauer34f6e152008-09-02 17:16:59 +02001422 struct mxc_nand_host *host;
1423 struct resource *res;
Dmitry Eremin-Solenikovd4ed8f12011-06-02 18:00:43 +04001424 int err = 0;
Sascha Hauer34f6e152008-09-02 17:16:59 +02001425
1426 /* Allocate memory for MTD device structure and private data */
Huang Shijiea5900552013-12-21 00:02:27 +08001427 host = devm_kzalloc(&pdev->dev, sizeof(struct mxc_nand_host),
1428 GFP_KERNEL);
Sascha Hauer34f6e152008-09-02 17:16:59 +02001429 if (!host)
1430 return -ENOMEM;
1431
Huang Shijiea5900552013-12-21 00:02:27 +08001432 /* allocate a temporary buffer for the nand_scan_ident() */
1433 host->data_buf = devm_kzalloc(&pdev->dev, PAGE_SIZE, GFP_KERNEL);
1434 if (!host->data_buf)
1435 return -ENOMEM;
Sascha Hauerf8f96082009-06-04 17:12:26 +02001436
Sascha Hauer34f6e152008-09-02 17:16:59 +02001437 host->dev = &pdev->dev;
1438 /* structures must be linked */
1439 this = &host->nand;
1440 mtd = &host->mtd;
1441 mtd->priv = this;
1442 mtd->owner = THIS_MODULE;
David Brownell87f39f02009-03-26 00:42:50 -07001443 mtd->dev.parent = &pdev->dev;
Sascha Hauer1fbff0a2009-10-21 16:06:27 +02001444 mtd->name = DRIVER_NAME;
Sascha Hauer34f6e152008-09-02 17:16:59 +02001445
1446 /* 50 us command delay time */
1447 this->chip_delay = 5;
1448
1449 this->priv = host;
1450 this->dev_ready = mxc_nand_dev_ready;
1451 this->cmdfunc = mxc_nand_command;
Sascha Hauer34f6e152008-09-02 17:16:59 +02001452 this->read_byte = mxc_nand_read_byte;
1453 this->read_word = mxc_nand_read_word;
1454 this->write_buf = mxc_nand_write_buf;
1455 this->read_buf = mxc_nand_read_buf;
Sascha Hauer34f6e152008-09-02 17:16:59 +02001456
Fabio Estevam24b82d32012-09-05 11:52:27 -03001457 host->clk = devm_clk_get(&pdev->dev, NULL);
Sascha Hauere4a09cb2012-06-06 12:33:13 +02001458 if (IS_ERR(host->clk))
1459 return PTR_ERR(host->clk);
Sascha Hauer34f6e152008-09-02 17:16:59 +02001460
Sascha Hauer71885b62012-06-06 12:33:14 +02001461 err = mxcnd_probe_dt(host);
Shawn Guo4d624352012-09-15 13:34:09 +08001462 if (err > 0) {
Jingoo Han453810b2013-07-30 17:18:33 +09001463 struct mxc_nand_platform_data *pdata =
1464 dev_get_platdata(&pdev->dev);
Shawn Guo4d624352012-09-15 13:34:09 +08001465 if (pdata) {
1466 host->pdata = *pdata;
1467 host->devtype_data = (struct mxc_nand_devtype_data *)
1468 pdev->id_entry->driver_data;
1469 } else {
1470 err = -ENODEV;
1471 }
1472 }
Sascha Hauer71885b62012-06-06 12:33:14 +02001473 if (err < 0)
1474 return err;
1475
1476 if (host->devtype_data->needs_ip) {
1477 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
Thierry Redingb0de7742013-01-21 11:09:12 +01001478 host->regs_ip = devm_ioremap_resource(&pdev->dev, res);
1479 if (IS_ERR(host->regs_ip))
1480 return PTR_ERR(host->regs_ip);
Sascha Hauer71885b62012-06-06 12:33:14 +02001481
1482 res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
1483 } else {
1484 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
1485 }
1486
Thierry Redingb0de7742013-01-21 11:09:12 +01001487 host->base = devm_ioremap_resource(&pdev->dev, res);
1488 if (IS_ERR(host->base))
1489 return PTR_ERR(host->base);
Sascha Hauer34f6e152008-09-02 17:16:59 +02001490
Sascha Hauerc6de7e12009-10-05 11:14:35 +02001491 host->main_area0 = host->base;
Sascha Hauer94671142009-10-05 12:14:21 +02001492
Uwe Kleine-Königf48d0f92012-04-23 11:23:40 +02001493 if (host->devtype_data->regs_offset)
1494 host->regs = host->base + host->devtype_data->regs_offset;
1495 host->spare0 = host->base + host->devtype_data->spare0_offset;
1496 if (host->devtype_data->axi_offset)
1497 host->regs_axi = host->base + host->devtype_data->axi_offset;
1498
1499 this->ecc.bytes = host->devtype_data->eccbytes;
1500 host->eccsize = host->devtype_data->eccsize;
1501
1502 this->select_chip = host->devtype_data->select_chip;
1503 this->ecc.size = 512;
1504 this->ecc.layout = host->devtype_data->ecclayout_512;
1505
Uwe Kleine-König64363562012-04-23 11:23:41 +02001506 if (host->pdata.hw_ecc) {
Sascha Hauer13e1add2009-10-21 10:39:05 +02001507 this->ecc.calculate = mxc_nand_calculate_ecc;
1508 this->ecc.hwctl = mxc_nand_enable_hwecc;
Uwe Kleine-König69d023b2012-04-23 11:23:39 +02001509 this->ecc.correct = host->devtype_data->correct_data;
Sascha Hauer13e1add2009-10-21 10:39:05 +02001510 this->ecc.mode = NAND_ECC_HW;
Sascha Hauer13e1add2009-10-21 10:39:05 +02001511 } else {
1512 this->ecc.mode = NAND_ECC_SOFT;
Sascha Hauer34f6e152008-09-02 17:16:59 +02001513 }
1514
Uwe Kleine-König64363562012-04-23 11:23:41 +02001515 /* NAND bus width determines access functions used by upper layer */
1516 if (host->pdata.width == 2)
Sascha Hauer34f6e152008-09-02 17:16:59 +02001517 this->options |= NAND_BUSWIDTH_16;
Sascha Hauer13e1add2009-10-21 10:39:05 +02001518
Uwe Kleine-König64363562012-04-23 11:23:41 +02001519 if (host->pdata.flash_bbt) {
Sascha Hauerf1372052009-10-21 14:25:27 +02001520 this->bbt_td = &bbt_main_descr;
1521 this->bbt_md = &bbt_mirror_descr;
1522 /* update flash based bbt */
Brian Norrisbb9ebd42011-05-31 16:31:23 -07001523 this->bbt_options |= NAND_BBT_USE_FLASH;
Sascha Hauer34f6e152008-09-02 17:16:59 +02001524 }
1525
Sascha Hauer63f14742010-10-18 10:16:26 +02001526 init_completion(&host->op_completion);
Ivo Claryssed4840182010-04-08 16:14:44 +02001527
1528 host->irq = platform_get_irq(pdev, 0);
Fabio Estevam26fbf482014-02-14 01:09:34 -02001529 if (host->irq < 0)
1530 return host->irq;
Ivo Claryssed4840182010-04-08 16:14:44 +02001531
Sascha Hauer63f14742010-10-18 10:16:26 +02001532 /*
Uwe Kleine-Könige4303b22012-04-23 11:23:35 +02001533 * Use host->devtype_data->irq_control() here instead of irq_control()
1534 * because we must not disable_irq_nosync without having requested the
1535 * irq.
Sascha Hauer63f14742010-10-18 10:16:26 +02001536 */
Uwe Kleine-Könige4303b22012-04-23 11:23:35 +02001537 host->devtype_data->irq_control(host, 0);
Sascha Hauer63f14742010-10-18 10:16:26 +02001538
Sascha Hauere4a09cb2012-06-06 12:33:13 +02001539 err = devm_request_irq(&pdev->dev, host->irq, mxc_nfc_irq,
Michael Opdenackerb1eb2342013-10-13 08:21:32 +02001540 0, DRIVER_NAME, host);
Ivo Claryssed4840182010-04-08 16:14:44 +02001541 if (err)
Sascha Hauere4a09cb2012-06-06 12:33:13 +02001542 return err;
1543
Fabio Estevamdcedf622013-12-02 00:50:02 -02001544 err = clk_prepare_enable(host->clk);
1545 if (err)
1546 return err;
Sascha Hauere4a09cb2012-06-06 12:33:13 +02001547 host->clk_act = 1;
Ivo Claryssed4840182010-04-08 16:14:44 +02001548
Sascha Hauer63f14742010-10-18 10:16:26 +02001549 /*
Uwe Kleine-König85569582012-04-23 11:23:34 +02001550 * Now that we "own" the interrupt make sure the interrupt mask bit is
1551 * cleared on i.MX21. Otherwise we can't read the interrupt status bit
1552 * on this machine.
Sascha Hauer63f14742010-10-18 10:16:26 +02001553 */
Uwe Kleine-Königf48d0f92012-04-23 11:23:40 +02001554 if (host->devtype_data->irqpending_quirk) {
Uwe Kleine-König85569582012-04-23 11:23:34 +02001555 disable_irq_nosync(host->irq);
Uwe Kleine-Könige4303b22012-04-23 11:23:35 +02001556 host->devtype_data->irq_control(host, 1);
Uwe Kleine-König85569582012-04-23 11:23:34 +02001557 }
Sascha Hauer63f14742010-10-18 10:16:26 +02001558
Vladimir Barinovbd3fd622009-05-25 13:06:17 +04001559 /* first scan to find the device and get the page size */
Shawn Guo4d624352012-09-15 13:34:09 +08001560 if (nand_scan_ident(mtd, is_imx25_nfc(host) ? 4 : 1, NULL)) {
Vladimir Barinovbd3fd622009-05-25 13:06:17 +04001561 err = -ENXIO;
1562 goto escan;
1563 }
Sascha Hauer34f6e152008-09-02 17:16:59 +02001564
Huang Shijiea5900552013-12-21 00:02:27 +08001565 /* allocate the right size buffer now */
1566 devm_kfree(&pdev->dev, (void *)host->data_buf);
1567 host->data_buf = devm_kzalloc(&pdev->dev, mtd->writesize + mtd->oobsize,
1568 GFP_KERNEL);
1569 if (!host->data_buf) {
1570 err = -ENOMEM;
1571 goto escan;
1572 }
1573
Sascha Hauer6e85dfd2010-08-06 15:53:10 +02001574 /* Call preset again, with correct writesize this time */
Uwe Kleine-Könige4303b22012-04-23 11:23:35 +02001575 host->devtype_data->preset(mtd);
Sascha Hauer6e85dfd2010-08-06 15:53:10 +02001576
Sascha Hauer2d69c7f2009-10-05 11:24:02 +02001577 if (mtd->writesize == 2048)
Uwe Kleine-König6dcdf992012-04-23 11:23:37 +02001578 this->ecc.layout = host->devtype_data->ecclayout_2k;
1579 else if (mtd->writesize == 4096)
1580 this->ecc.layout = host->devtype_data->ecclayout_4k;
Sascha Hauer34f6e152008-09-02 17:16:59 +02001581
Mike Dunn6a918ba2012-03-11 14:21:11 -07001582 if (this->ecc.mode == NAND_ECC_HW) {
Shawn Guo4d624352012-09-15 13:34:09 +08001583 if (is_imx21_nfc(host) || is_imx27_nfc(host))
Mike Dunn6a918ba2012-03-11 14:21:11 -07001584 this->ecc.strength = 1;
1585 else
1586 this->ecc.strength = (host->eccsize == 4) ? 4 : 8;
1587 }
1588
Sascha Hauer4a43faf2012-05-25 16:22:42 +02001589 /* second phase scan */
1590 if (nand_scan_tail(mtd)) {
1591 err = -ENXIO;
1592 goto escan;
1593 }
1594
Sascha Hauer34f6e152008-09-02 17:16:59 +02001595 /* Register the partitions */
Uwe Kleine-König64363562012-04-23 11:23:41 +02001596 mtd_device_parse_register(mtd, part_probes,
1597 &(struct mtd_part_parser_data){
1598 .of_node = pdev->dev.of_node,
1599 },
1600 host->pdata.parts,
1601 host->pdata.nr_parts);
Sascha Hauer34f6e152008-09-02 17:16:59 +02001602
1603 platform_set_drvdata(pdev, host);
1604
1605 return 0;
1606
1607escan:
Lothar Waßmannc10d8ee2012-12-06 08:42:27 +01001608 if (host->clk_act)
1609 clk_disable_unprepare(host->clk);
Sascha Hauer34f6e152008-09-02 17:16:59 +02001610
1611 return err;
1612}
1613
Bill Pemberton810b7e02012-11-19 13:26:04 -05001614static int mxcnd_remove(struct platform_device *pdev)
Sascha Hauer34f6e152008-09-02 17:16:59 +02001615{
1616 struct mxc_nand_host *host = platform_get_drvdata(pdev);
1617
Sascha Hauer34f6e152008-09-02 17:16:59 +02001618 nand_release(&host->mtd);
Wei Yongjun8bfd4f72013-12-17 11:35:35 +08001619 if (host->clk_act)
1620 clk_disable_unprepare(host->clk);
Sascha Hauer34f6e152008-09-02 17:16:59 +02001621
1622 return 0;
1623}
1624
Sascha Hauer34f6e152008-09-02 17:16:59 +02001625static struct platform_driver mxcnd_driver = {
1626 .driver = {
1627 .name = DRIVER_NAME,
Uwe Kleine-König64363562012-04-23 11:23:41 +02001628 .of_match_table = of_match_ptr(mxcnd_dt_ids),
Eric Bénard04dd0d32010-06-17 20:59:04 +02001629 },
Shawn Guo4d624352012-09-15 13:34:09 +08001630 .id_table = mxcnd_devtype,
Fabio Estevamddf16d62012-09-05 11:35:25 -03001631 .probe = mxcnd_probe,
Bill Pemberton5153b882012-11-19 13:21:24 -05001632 .remove = mxcnd_remove,
Sascha Hauer34f6e152008-09-02 17:16:59 +02001633};
Fabio Estevamddf16d62012-09-05 11:35:25 -03001634module_platform_driver(mxcnd_driver);
Sascha Hauer34f6e152008-09-02 17:16:59 +02001635
1636MODULE_AUTHOR("Freescale Semiconductor, Inc.");
1637MODULE_DESCRIPTION("MXC NAND MTD driver");
1638MODULE_LICENSE("GPL");