blob: fbd94f00e0ab382d85adc0ee86725627ad73154b [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>
Sascha Hauer34f6e152008-09-02 17:16:59 +020035
36#include <asm/mach/flash.h>
37#include <mach/mxc_nand.h>
Sascha Hauer94671142009-10-05 12:14:21 +020038#include <mach/hardware.h>
Sascha Hauer34f6e152008-09-02 17:16:59 +020039
40#define DRIVER_NAME "mxc_nand"
41
Sascha Hauer94671142009-10-05 12:14:21 +020042#define nfc_is_v21() (cpu_is_mx25() || cpu_is_mx35())
Ivo Claryssea47bfd22010-04-08 16:16:51 +020043#define nfc_is_v1() (cpu_is_mx31() || cpu_is_mx27() || cpu_is_mx21())
Jason Liuc97926d2011-08-22 14:13:17 +080044#define nfc_is_v3_2() (cpu_is_mx51() || cpu_is_mx53())
Sascha Hauer71ec5152010-08-06 15:53:11 +020045#define nfc_is_v3() nfc_is_v3_2()
Sascha Hauer94671142009-10-05 12:14:21 +020046
Sascha Hauer34f6e152008-09-02 17:16:59 +020047/* Addresses for NFC registers */
Sascha Hauer1bc99182010-08-06 15:53:08 +020048#define NFC_V1_V2_BUF_SIZE (host->regs + 0x00)
49#define NFC_V1_V2_BUF_ADDR (host->regs + 0x04)
50#define NFC_V1_V2_FLASH_ADDR (host->regs + 0x06)
51#define NFC_V1_V2_FLASH_CMD (host->regs + 0x08)
52#define NFC_V1_V2_CONFIG (host->regs + 0x0a)
53#define NFC_V1_V2_ECC_STATUS_RESULT (host->regs + 0x0c)
54#define NFC_V1_V2_RSLTMAIN_AREA (host->regs + 0x0e)
55#define NFC_V1_V2_RSLTSPARE_AREA (host->regs + 0x10)
56#define NFC_V1_V2_WRPROT (host->regs + 0x12)
57#define NFC_V1_UNLOCKSTART_BLKADDR (host->regs + 0x14)
58#define NFC_V1_UNLOCKEND_BLKADDR (host->regs + 0x16)
Baruch Siachd178e3e2011-03-14 09:01:56 +020059#define NFC_V21_UNLOCKSTART_BLKADDR0 (host->regs + 0x20)
60#define NFC_V21_UNLOCKSTART_BLKADDR1 (host->regs + 0x24)
61#define NFC_V21_UNLOCKSTART_BLKADDR2 (host->regs + 0x28)
62#define NFC_V21_UNLOCKSTART_BLKADDR3 (host->regs + 0x2c)
63#define NFC_V21_UNLOCKEND_BLKADDR0 (host->regs + 0x22)
64#define NFC_V21_UNLOCKEND_BLKADDR1 (host->regs + 0x26)
65#define NFC_V21_UNLOCKEND_BLKADDR2 (host->regs + 0x2a)
66#define NFC_V21_UNLOCKEND_BLKADDR3 (host->regs + 0x2e)
Sascha Hauer1bc99182010-08-06 15:53:08 +020067#define NFC_V1_V2_NF_WRPRST (host->regs + 0x18)
68#define NFC_V1_V2_CONFIG1 (host->regs + 0x1a)
69#define NFC_V1_V2_CONFIG2 (host->regs + 0x1c)
Sascha Hauer34f6e152008-09-02 17:16:59 +020070
Sascha Hauer6e85dfd2010-08-06 15:53:10 +020071#define NFC_V2_CONFIG1_ECC_MODE_4 (1 << 0)
Sascha Hauer1bc99182010-08-06 15:53:08 +020072#define NFC_V1_V2_CONFIG1_SP_EN (1 << 2)
73#define NFC_V1_V2_CONFIG1_ECC_EN (1 << 3)
74#define NFC_V1_V2_CONFIG1_INT_MSK (1 << 4)
75#define NFC_V1_V2_CONFIG1_BIG (1 << 5)
76#define NFC_V1_V2_CONFIG1_RST (1 << 6)
77#define NFC_V1_V2_CONFIG1_CE (1 << 7)
Sascha Hauerb8db2f52010-08-09 15:04:19 +020078#define NFC_V2_CONFIG1_ONE_CYCLE (1 << 8)
79#define NFC_V2_CONFIG1_PPB(x) (((x) & 0x3) << 9)
80#define NFC_V2_CONFIG1_FP_INT (1 << 11)
Sascha Hauer34f6e152008-09-02 17:16:59 +020081
Sascha Hauer1bc99182010-08-06 15:53:08 +020082#define NFC_V1_V2_CONFIG2_INT (1 << 15)
Sascha Hauer34f6e152008-09-02 17:16:59 +020083
Sascha Hauer1bc99182010-08-06 15:53:08 +020084/*
85 * Operation modes for the NFC. Valid for v1, v2 and v3
86 * type controllers.
87 */
88#define NFC_CMD (1 << 0)
89#define NFC_ADDR (1 << 1)
90#define NFC_INPUT (1 << 2)
91#define NFC_OUTPUT (1 << 3)
92#define NFC_ID (1 << 4)
93#define NFC_STATUS (1 << 5)
Sascha Hauer34f6e152008-09-02 17:16:59 +020094
Sascha Hauer71ec5152010-08-06 15:53:11 +020095#define NFC_V3_FLASH_CMD (host->regs_axi + 0x00)
96#define NFC_V3_FLASH_ADDR0 (host->regs_axi + 0x04)
Sascha Hauer34f6e152008-09-02 17:16:59 +020097
Sascha Hauer71ec5152010-08-06 15:53:11 +020098#define NFC_V3_CONFIG1 (host->regs_axi + 0x34)
99#define NFC_V3_CONFIG1_SP_EN (1 << 0)
100#define NFC_V3_CONFIG1_RBA(x) (((x) & 0x7 ) << 4)
Sascha Hauer34f6e152008-09-02 17:16:59 +0200101
Sascha Hauer71ec5152010-08-06 15:53:11 +0200102#define NFC_V3_ECC_STATUS_RESULT (host->regs_axi + 0x38)
Sascha Hauer34f6e152008-09-02 17:16:59 +0200103
Sascha Hauer71ec5152010-08-06 15:53:11 +0200104#define NFC_V3_LAUNCH (host->regs_axi + 0x40)
Sascha Hauer34f6e152008-09-02 17:16:59 +0200105
Sascha Hauer71ec5152010-08-06 15:53:11 +0200106#define NFC_V3_WRPROT (host->regs_ip + 0x0)
107#define NFC_V3_WRPROT_LOCK_TIGHT (1 << 0)
108#define NFC_V3_WRPROT_LOCK (1 << 1)
109#define NFC_V3_WRPROT_UNLOCK (1 << 2)
110#define NFC_V3_WRPROT_BLS_UNLOCK (2 << 6)
111
112#define NFC_V3_WRPROT_UNLOCK_BLK_ADD0 (host->regs_ip + 0x04)
113
114#define NFC_V3_CONFIG2 (host->regs_ip + 0x24)
115#define NFC_V3_CONFIG2_PS_512 (0 << 0)
116#define NFC_V3_CONFIG2_PS_2048 (1 << 0)
117#define NFC_V3_CONFIG2_PS_4096 (2 << 0)
118#define NFC_V3_CONFIG2_ONE_CYCLE (1 << 2)
119#define NFC_V3_CONFIG2_ECC_EN (1 << 3)
120#define NFC_V3_CONFIG2_2CMD_PHASES (1 << 4)
121#define NFC_V3_CONFIG2_NUM_ADDR_PHASE0 (1 << 5)
122#define NFC_V3_CONFIG2_ECC_MODE_8 (1 << 6)
123#define NFC_V3_CONFIG2_PPB(x) (((x) & 0x3) << 7)
124#define NFC_V3_CONFIG2_NUM_ADDR_PHASE1(x) (((x) & 0x3) << 12)
125#define NFC_V3_CONFIG2_INT_MSK (1 << 15)
126#define NFC_V3_CONFIG2_ST_CMD(x) (((x) & 0xff) << 24)
127#define NFC_V3_CONFIG2_SPAS(x) (((x) & 0xff) << 16)
128
129#define NFC_V3_CONFIG3 (host->regs_ip + 0x28)
130#define NFC_V3_CONFIG3_ADD_OP(x) (((x) & 0x3) << 0)
131#define NFC_V3_CONFIG3_FW8 (1 << 3)
132#define NFC_V3_CONFIG3_SBB(x) (((x) & 0x7) << 8)
133#define NFC_V3_CONFIG3_NUM_OF_DEVICES(x) (((x) & 0x7) << 12)
134#define NFC_V3_CONFIG3_RBB_MODE (1 << 15)
135#define NFC_V3_CONFIG3_NO_SDMA (1 << 20)
136
137#define NFC_V3_IPC (host->regs_ip + 0x2C)
138#define NFC_V3_IPC_CREQ (1 << 0)
139#define NFC_V3_IPC_INT (1 << 31)
140
141#define NFC_V3_DELAY_LINE (host->regs_ip + 0x34)
Sascha Hauer34f6e152008-09-02 17:16:59 +0200142
Uwe Kleine-Könige4303b22012-04-23 11:23:35 +0200143struct mxc_nand_host;
144
145struct mxc_nand_devtype_data {
146 void (*preset)(struct mtd_info *);
147 void (*send_cmd)(struct mxc_nand_host *, uint16_t, int);
148 void (*send_addr)(struct mxc_nand_host *, uint16_t, int);
149 void (*send_page)(struct mtd_info *, unsigned int);
150 void (*send_read_id)(struct mxc_nand_host *);
151 uint16_t (*get_dev_status)(struct mxc_nand_host *);
152 int (*check_int)(struct mxc_nand_host *);
153 void (*irq_control)(struct mxc_nand_host *, int);
Uwe Kleine-König6d38af22012-04-23 11:23:36 +0200154 u32 (*get_ecc_status)(struct mxc_nand_host *);
Uwe Kleine-Könige4303b22012-04-23 11:23:35 +0200155};
156
Sascha Hauer34f6e152008-09-02 17:16:59 +0200157struct mxc_nand_host {
158 struct mtd_info mtd;
159 struct nand_chip nand;
Sascha Hauer34f6e152008-09-02 17:16:59 +0200160 struct device *dev;
161
Sascha Hauerc6de7e12009-10-05 11:14:35 +0200162 void *spare0;
163 void *main_area0;
Sascha Hauerc6de7e12009-10-05 11:14:35 +0200164
165 void __iomem *base;
Sascha Hauer34f6e152008-09-02 17:16:59 +0200166 void __iomem *regs;
Sascha Hauer71ec5152010-08-06 15:53:11 +0200167 void __iomem *regs_axi;
168 void __iomem *regs_ip;
Sascha Hauer34f6e152008-09-02 17:16:59 +0200169 int status_request;
Sascha Hauer34f6e152008-09-02 17:16:59 +0200170 struct clk *clk;
171 int clk_act;
172 int irq;
Sascha Hauer94f77e52010-08-06 15:53:09 +0200173 int eccsize;
Baruch Siachd178e3e2011-03-14 09:01:56 +0200174 int active_cs;
Sascha Hauer34f6e152008-09-02 17:16:59 +0200175
Sascha Hauer63f14742010-10-18 10:16:26 +0200176 struct completion op_completion;
Sascha Hauerf8f96082009-06-04 17:12:26 +0200177
178 uint8_t *data_buf;
179 unsigned int buf_start;
180 int spare_len;
Sascha Hauer5f973042010-08-06 15:53:06 +0200181
Uwe Kleine-Könige4303b22012-04-23 11:23:35 +0200182 const struct mxc_nand_devtype_data *devtype_data;
Uwe Kleine-König85569582012-04-23 11:23:34 +0200183
184 /*
185 * On i.MX21 the CONFIG2:INT bit cannot be read if interrupts are masked
186 * (CONFIG1:INT_MSK is set). To handle this the driver uses
187 * enable_irq/disable_irq_nosync instead of CONFIG1:INT_MSK
188 */
189 int irqpending_quirk;
Sascha Hauer34f6e152008-09-02 17:16:59 +0200190};
191
Sascha Hauer34f6e152008-09-02 17:16:59 +0200192/* OOB placement block for use with hardware ecc generation */
Sascha Hauer94671142009-10-05 12:14:21 +0200193static struct nand_ecclayout nandv1_hw_eccoob_smallpage = {
Sascha Hauer34f6e152008-09-02 17:16:59 +0200194 .eccbytes = 5,
195 .eccpos = {6, 7, 8, 9, 10},
Sascha Hauer8c1fd892009-10-21 10:22:01 +0200196 .oobfree = {{0, 5}, {12, 4}, }
Sascha Hauer34f6e152008-09-02 17:16:59 +0200197};
198
Sascha Hauer94671142009-10-05 12:14:21 +0200199static struct nand_ecclayout nandv1_hw_eccoob_largepage = {
Vladimir Barinovbd3fd622009-05-25 13:06:17 +0400200 .eccbytes = 20,
201 .eccpos = {6, 7, 8, 9, 10, 22, 23, 24, 25, 26,
202 38, 39, 40, 41, 42, 54, 55, 56, 57, 58},
203 .oobfree = {{2, 4}, {11, 10}, {27, 10}, {43, 10}, {59, 5}, }
Sascha Hauer34f6e152008-09-02 17:16:59 +0200204};
205
Sascha Hauer94671142009-10-05 12:14:21 +0200206/* OOB description for 512 byte pages with 16 byte OOB */
207static struct nand_ecclayout nandv2_hw_eccoob_smallpage = {
208 .eccbytes = 1 * 9,
209 .eccpos = {
210 7, 8, 9, 10, 11, 12, 13, 14, 15
211 },
212 .oobfree = {
213 {.offset = 0, .length = 5}
214 }
215};
216
217/* OOB description for 2048 byte pages with 64 byte OOB */
218static struct nand_ecclayout nandv2_hw_eccoob_largepage = {
219 .eccbytes = 4 * 9,
220 .eccpos = {
221 7, 8, 9, 10, 11, 12, 13, 14, 15,
222 23, 24, 25, 26, 27, 28, 29, 30, 31,
223 39, 40, 41, 42, 43, 44, 45, 46, 47,
224 55, 56, 57, 58, 59, 60, 61, 62, 63
225 },
226 .oobfree = {
227 {.offset = 2, .length = 4},
228 {.offset = 16, .length = 7},
229 {.offset = 32, .length = 7},
230 {.offset = 48, .length = 7}
231 }
232};
233
Baruch Siach2c1c5f12011-03-09 16:12:20 +0200234/* OOB description for 4096 byte pages with 128 byte OOB */
235static struct nand_ecclayout nandv2_hw_eccoob_4k = {
236 .eccbytes = 8 * 9,
237 .eccpos = {
238 7, 8, 9, 10, 11, 12, 13, 14, 15,
239 23, 24, 25, 26, 27, 28, 29, 30, 31,
240 39, 40, 41, 42, 43, 44, 45, 46, 47,
241 55, 56, 57, 58, 59, 60, 61, 62, 63,
242 71, 72, 73, 74, 75, 76, 77, 78, 79,
243 87, 88, 89, 90, 91, 92, 93, 94, 95,
244 103, 104, 105, 106, 107, 108, 109, 110, 111,
245 119, 120, 121, 122, 123, 124, 125, 126, 127,
246 },
247 .oobfree = {
248 {.offset = 2, .length = 4},
249 {.offset = 16, .length = 7},
250 {.offset = 32, .length = 7},
251 {.offset = 48, .length = 7},
252 {.offset = 64, .length = 7},
253 {.offset = 80, .length = 7},
254 {.offset = 96, .length = 7},
255 {.offset = 112, .length = 7},
256 }
257};
258
Sascha Hauer34f6e152008-09-02 17:16:59 +0200259static const char *part_probes[] = { "RedBoot", "cmdlinepart", NULL };
Sascha Hauer34f6e152008-09-02 17:16:59 +0200260
Sascha Hauer71ec5152010-08-06 15:53:11 +0200261static int check_int_v3(struct mxc_nand_host *host)
262{
263 uint32_t tmp;
264
265 tmp = readl(NFC_V3_IPC);
266 if (!(tmp & NFC_V3_IPC_INT))
267 return 0;
268
269 tmp &= ~NFC_V3_IPC_INT;
270 writel(tmp, NFC_V3_IPC);
271
272 return 1;
273}
274
Sascha Hauer7aaf28a2010-08-06 15:53:07 +0200275static int check_int_v1_v2(struct mxc_nand_host *host)
276{
277 uint32_t tmp;
278
Sascha Hauer1bc99182010-08-06 15:53:08 +0200279 tmp = readw(NFC_V1_V2_CONFIG2);
280 if (!(tmp & NFC_V1_V2_CONFIG2_INT))
Sascha Hauer7aaf28a2010-08-06 15:53:07 +0200281 return 0;
282
Uwe Kleine-König85569582012-04-23 11:23:34 +0200283 if (!host->irqpending_quirk)
Sascha Hauer63f14742010-10-18 10:16:26 +0200284 writew(tmp & ~NFC_V1_V2_CONFIG2_INT, NFC_V1_V2_CONFIG2);
Sascha Hauer7aaf28a2010-08-06 15:53:07 +0200285
286 return 1;
287}
288
Sascha Hauer63f14742010-10-18 10:16:26 +0200289static void irq_control_v1_v2(struct mxc_nand_host *host, int activate)
290{
291 uint16_t tmp;
292
293 tmp = readw(NFC_V1_V2_CONFIG1);
294
295 if (activate)
296 tmp &= ~NFC_V1_V2_CONFIG1_INT_MSK;
297 else
298 tmp |= NFC_V1_V2_CONFIG1_INT_MSK;
299
300 writew(tmp, NFC_V1_V2_CONFIG1);
301}
302
303static void irq_control_v3(struct mxc_nand_host *host, int activate)
304{
305 uint32_t tmp;
306
307 tmp = readl(NFC_V3_CONFIG2);
308
309 if (activate)
310 tmp &= ~NFC_V3_CONFIG2_INT_MSK;
311 else
312 tmp |= NFC_V3_CONFIG2_INT_MSK;
313
314 writel(tmp, NFC_V3_CONFIG2);
315}
316
Uwe Kleine-König85569582012-04-23 11:23:34 +0200317static void irq_control(struct mxc_nand_host *host, int activate)
318{
319 if (host->irqpending_quirk) {
320 if (activate)
321 enable_irq(host->irq);
322 else
323 disable_irq_nosync(host->irq);
324 } else {
Uwe Kleine-Könige4303b22012-04-23 11:23:35 +0200325 host->devtype_data->irq_control(host, activate);
Uwe Kleine-König85569582012-04-23 11:23:34 +0200326 }
327}
328
Uwe Kleine-König6d38af22012-04-23 11:23:36 +0200329static u32 get_ecc_status_v1(struct mxc_nand_host *host)
330{
331 return readw(NFC_V1_V2_ECC_STATUS_RESULT);
332}
333
334static u32 get_ecc_status_v2(struct mxc_nand_host *host)
335{
336 return readl(NFC_V1_V2_ECC_STATUS_RESULT);
337}
338
339static u32 get_ecc_status_v3(struct mxc_nand_host *host)
340{
341 return readl(NFC_V3_ECC_STATUS_RESULT);
342}
343
Uwe Kleine-König85569582012-04-23 11:23:34 +0200344static irqreturn_t mxc_nfc_irq(int irq, void *dev_id)
345{
346 struct mxc_nand_host *host = dev_id;
347
Uwe Kleine-Könige4303b22012-04-23 11:23:35 +0200348 if (!host->devtype_data->check_int(host))
Uwe Kleine-König85569582012-04-23 11:23:34 +0200349 return IRQ_NONE;
350
351 irq_control(host, 0);
352
353 complete(&host->op_completion);
354
355 return IRQ_HANDLED;
356}
357
Sascha Hauer34f6e152008-09-02 17:16:59 +0200358/* This function polls the NANDFC to wait for the basic operation to
359 * complete by checking the INT bit of config2 register.
360 */
Sascha Hauerc110eaf2009-10-21 16:01:02 +0200361static void wait_op_done(struct mxc_nand_host *host, int useirq)
Sascha Hauer34f6e152008-09-02 17:16:59 +0200362{
Ivo Claryssea47bfd22010-04-08 16:16:51 +0200363 int max_retries = 8000;
Sascha Hauer34f6e152008-09-02 17:16:59 +0200364
365 if (useirq) {
Uwe Kleine-Könige4303b22012-04-23 11:23:35 +0200366 if (!host->devtype_data->check_int(host)) {
Sascha Hauer63f14742010-10-18 10:16:26 +0200367 INIT_COMPLETION(host->op_completion);
Uwe Kleine-König85569582012-04-23 11:23:34 +0200368 irq_control(host, 1);
Sascha Hauer63f14742010-10-18 10:16:26 +0200369 wait_for_completion(&host->op_completion);
Sascha Hauer34f6e152008-09-02 17:16:59 +0200370 }
371 } else {
372 while (max_retries-- > 0) {
Uwe Kleine-Könige4303b22012-04-23 11:23:35 +0200373 if (host->devtype_data->check_int(host))
Sascha Hauer34f6e152008-09-02 17:16:59 +0200374 break;
Sascha Hauer7aaf28a2010-08-06 15:53:07 +0200375
Sascha Hauer34f6e152008-09-02 17:16:59 +0200376 udelay(1);
377 }
Roel Kluin43950a62009-06-04 16:24:59 +0200378 if (max_retries < 0)
Brian Norris0a32a102011-07-19 10:06:10 -0700379 pr_debug("%s: INT not set\n", __func__);
Sascha Hauer34f6e152008-09-02 17:16:59 +0200380 }
381}
382
Sascha Hauer71ec5152010-08-06 15:53:11 +0200383static void send_cmd_v3(struct mxc_nand_host *host, uint16_t cmd, int useirq)
384{
385 /* fill command */
386 writel(cmd, NFC_V3_FLASH_CMD);
387
388 /* send out command */
389 writel(NFC_CMD, NFC_V3_LAUNCH);
390
391 /* Wait for operation to complete */
392 wait_op_done(host, useirq);
393}
394
Sascha Hauer34f6e152008-09-02 17:16:59 +0200395/* This function issues the specified command to the NAND device and
396 * waits for completion. */
Sascha Hauer5f973042010-08-06 15:53:06 +0200397static void send_cmd_v1_v2(struct mxc_nand_host *host, uint16_t cmd, int useirq)
Sascha Hauer34f6e152008-09-02 17:16:59 +0200398{
Brian Norris289c0522011-07-19 10:06:09 -0700399 pr_debug("send_cmd(host, 0x%x, %d)\n", cmd, useirq);
Sascha Hauer34f6e152008-09-02 17:16:59 +0200400
Sascha Hauer1bc99182010-08-06 15:53:08 +0200401 writew(cmd, NFC_V1_V2_FLASH_CMD);
402 writew(NFC_CMD, NFC_V1_V2_CONFIG2);
Sascha Hauer34f6e152008-09-02 17:16:59 +0200403
Uwe Kleine-König85569582012-04-23 11:23:34 +0200404 if (host->irqpending_quirk && (cmd == NAND_CMD_RESET)) {
Ivo Claryssea47bfd22010-04-08 16:16:51 +0200405 int max_retries = 100;
406 /* Reset completion is indicated by NFC_CONFIG2 */
407 /* being set to 0 */
408 while (max_retries-- > 0) {
Sascha Hauer1bc99182010-08-06 15:53:08 +0200409 if (readw(NFC_V1_V2_CONFIG2) == 0) {
Ivo Claryssea47bfd22010-04-08 16:16:51 +0200410 break;
411 }
412 udelay(1);
413 }
414 if (max_retries < 0)
Brian Norris0a32a102011-07-19 10:06:10 -0700415 pr_debug("%s: RESET failed\n", __func__);
Ivo Claryssea47bfd22010-04-08 16:16:51 +0200416 } else {
417 /* Wait for operation to complete */
418 wait_op_done(host, useirq);
419 }
Sascha Hauer34f6e152008-09-02 17:16:59 +0200420}
421
Sascha Hauer71ec5152010-08-06 15:53:11 +0200422static void send_addr_v3(struct mxc_nand_host *host, uint16_t addr, int islast)
423{
424 /* fill address */
425 writel(addr, NFC_V3_FLASH_ADDR0);
426
427 /* send out address */
428 writel(NFC_ADDR, NFC_V3_LAUNCH);
429
430 wait_op_done(host, 0);
431}
432
Sascha Hauer34f6e152008-09-02 17:16:59 +0200433/* This function sends an address (or partial address) to the
434 * NAND device. The address is used to select the source/destination for
435 * a NAND command. */
Sascha Hauer5f973042010-08-06 15:53:06 +0200436static void send_addr_v1_v2(struct mxc_nand_host *host, uint16_t addr, int islast)
Sascha Hauer34f6e152008-09-02 17:16:59 +0200437{
Brian Norris289c0522011-07-19 10:06:09 -0700438 pr_debug("send_addr(host, 0x%x %d)\n", addr, islast);
Sascha Hauer34f6e152008-09-02 17:16:59 +0200439
Sascha Hauer1bc99182010-08-06 15:53:08 +0200440 writew(addr, NFC_V1_V2_FLASH_ADDR);
441 writew(NFC_ADDR, NFC_V1_V2_CONFIG2);
Sascha Hauer34f6e152008-09-02 17:16:59 +0200442
443 /* Wait for operation to complete */
Sascha Hauerc110eaf2009-10-21 16:01:02 +0200444 wait_op_done(host, islast);
Sascha Hauer34f6e152008-09-02 17:16:59 +0200445}
446
Sascha Hauer71ec5152010-08-06 15:53:11 +0200447static void send_page_v3(struct mtd_info *mtd, unsigned int ops)
448{
449 struct nand_chip *nand_chip = mtd->priv;
450 struct mxc_nand_host *host = nand_chip->priv;
451 uint32_t tmp;
452
453 tmp = readl(NFC_V3_CONFIG1);
454 tmp &= ~(7 << 4);
455 writel(tmp, NFC_V3_CONFIG1);
456
457 /* transfer data from NFC ram to nand */
458 writel(ops, NFC_V3_LAUNCH);
459
460 wait_op_done(host, false);
461}
462
Uwe Kleine-König6d38af22012-04-23 11:23:36 +0200463static void send_page_v2(struct mtd_info *mtd, unsigned int ops)
464{
465 struct nand_chip *nand_chip = mtd->priv;
466 struct mxc_nand_host *host = nand_chip->priv;
467
468 /* NANDFC buffer 0 is used for page read/write */
469 writew(host->active_cs << 4, NFC_V1_V2_BUF_ADDR);
470
471 writew(ops, NFC_V1_V2_CONFIG2);
472
473 /* Wait for operation to complete */
474 wait_op_done(host, true);
475}
476
477static void send_page_v1(struct mtd_info *mtd, unsigned int ops)
Sascha Hauer34f6e152008-09-02 17:16:59 +0200478{
Sascha Hauer2d69c7f2009-10-05 11:24:02 +0200479 struct nand_chip *nand_chip = mtd->priv;
480 struct mxc_nand_host *host = nand_chip->priv;
Sascha Hauerc5d23f12009-06-04 17:25:53 +0200481 int bufs, i;
Sascha Hauer34f6e152008-09-02 17:16:59 +0200482
Uwe Kleine-König6d38af22012-04-23 11:23:36 +0200483 if (mtd->writesize > 512)
Sascha Hauerc5d23f12009-06-04 17:25:53 +0200484 bufs = 4;
485 else
486 bufs = 1;
Sascha Hauer34f6e152008-09-02 17:16:59 +0200487
Sascha Hauerc5d23f12009-06-04 17:25:53 +0200488 for (i = 0; i < bufs; i++) {
489
490 /* NANDFC buffer 0 is used for page read/write */
Baruch Siachd178e3e2011-03-14 09:01:56 +0200491 writew((host->active_cs << 4) | i, NFC_V1_V2_BUF_ADDR);
Sascha Hauerc5d23f12009-06-04 17:25:53 +0200492
Sascha Hauer1bc99182010-08-06 15:53:08 +0200493 writew(ops, NFC_V1_V2_CONFIG2);
Sascha Hauerc5d23f12009-06-04 17:25:53 +0200494
495 /* Wait for operation to complete */
Sascha Hauerc110eaf2009-10-21 16:01:02 +0200496 wait_op_done(host, true);
Sascha Hauer34f6e152008-09-02 17:16:59 +0200497 }
Sascha Hauer34f6e152008-09-02 17:16:59 +0200498}
499
Sascha Hauer71ec5152010-08-06 15:53:11 +0200500static void send_read_id_v3(struct mxc_nand_host *host)
501{
502 /* Read ID into main buffer */
503 writel(NFC_ID, NFC_V3_LAUNCH);
504
505 wait_op_done(host, true);
506
507 memcpy(host->data_buf, host->main_area0, 16);
508}
509
Sascha Hauer34f6e152008-09-02 17:16:59 +0200510/* Request the NANDFC to perform a read of the NAND device ID. */
Sascha Hauer5f973042010-08-06 15:53:06 +0200511static void send_read_id_v1_v2(struct mxc_nand_host *host)
Sascha Hauer34f6e152008-09-02 17:16:59 +0200512{
513 struct nand_chip *this = &host->nand;
Sascha Hauer34f6e152008-09-02 17:16:59 +0200514
515 /* NANDFC buffer 0 is used for device ID output */
Baruch Siachd178e3e2011-03-14 09:01:56 +0200516 writew(host->active_cs << 4, NFC_V1_V2_BUF_ADDR);
Sascha Hauer34f6e152008-09-02 17:16:59 +0200517
Sascha Hauer1bc99182010-08-06 15:53:08 +0200518 writew(NFC_ID, NFC_V1_V2_CONFIG2);
Sascha Hauer34f6e152008-09-02 17:16:59 +0200519
520 /* Wait for operation to complete */
Sascha Hauerc110eaf2009-10-21 16:01:02 +0200521 wait_op_done(host, true);
Sascha Hauer34f6e152008-09-02 17:16:59 +0200522
Sascha Hauerc6de7e12009-10-05 11:14:35 +0200523 memcpy(host->data_buf, host->main_area0, 16);
John Ognessf7b66e52010-06-18 18:59:47 +0200524
525 if (this->options & NAND_BUSWIDTH_16) {
526 /* compress the ID info */
527 host->data_buf[1] = host->data_buf[2];
528 host->data_buf[2] = host->data_buf[4];
529 host->data_buf[3] = host->data_buf[6];
530 host->data_buf[4] = host->data_buf[8];
531 host->data_buf[5] = host->data_buf[10];
532 }
Sascha Hauer34f6e152008-09-02 17:16:59 +0200533}
534
Sascha Hauer71ec5152010-08-06 15:53:11 +0200535static uint16_t get_dev_status_v3(struct mxc_nand_host *host)
Sascha Hauer34f6e152008-09-02 17:16:59 +0200536{
Sascha Hauer71ec5152010-08-06 15:53:11 +0200537 writew(NFC_STATUS, NFC_V3_LAUNCH);
Sascha Hauerc110eaf2009-10-21 16:01:02 +0200538 wait_op_done(host, true);
Sascha Hauer34f6e152008-09-02 17:16:59 +0200539
Sascha Hauer71ec5152010-08-06 15:53:11 +0200540 return readl(NFC_V3_CONFIG1) >> 16;
541}
542
Sascha Hauer34f6e152008-09-02 17:16:59 +0200543/* This function requests the NANDFC to perform a read of the
544 * NAND device status and returns the current status. */
Sascha Hauer5f973042010-08-06 15:53:06 +0200545static uint16_t get_dev_status_v1_v2(struct mxc_nand_host *host)
Sascha Hauer34f6e152008-09-02 17:16:59 +0200546{
Sascha Hauerc29c6072010-08-06 15:53:05 +0200547 void __iomem *main_buf = host->main_area0;
Sascha Hauer34f6e152008-09-02 17:16:59 +0200548 uint32_t store;
549 uint16_t ret;
Sascha Hauer34f6e152008-09-02 17:16:59 +0200550
Baruch Siachd178e3e2011-03-14 09:01:56 +0200551 writew(host->active_cs << 4, NFC_V1_V2_BUF_ADDR);
Sascha Hauerc29c6072010-08-06 15:53:05 +0200552
553 /*
554 * The device status is stored in main_area0. To
555 * prevent corruption of the buffer save the value
556 * and restore it afterwards.
557 */
Sascha Hauer34f6e152008-09-02 17:16:59 +0200558 store = readl(main_buf);
Sascha Hauer34f6e152008-09-02 17:16:59 +0200559
Sascha Hauer1bc99182010-08-06 15:53:08 +0200560 writew(NFC_STATUS, NFC_V1_V2_CONFIG2);
Sascha Hauer34f6e152008-09-02 17:16:59 +0200561 wait_op_done(host, true);
562
Sascha Hauer34f6e152008-09-02 17:16:59 +0200563 ret = readw(main_buf);
Sascha Hauerc29c6072010-08-06 15:53:05 +0200564
Sascha Hauer34f6e152008-09-02 17:16:59 +0200565 writel(store, main_buf);
566
567 return ret;
568}
569
570/* This functions is used by upper layer to checks if device is ready */
571static int mxc_nand_dev_ready(struct mtd_info *mtd)
572{
573 /*
574 * NFC handles R/B internally. Therefore, this function
575 * always returns status as ready.
576 */
577 return 1;
578}
579
580static void mxc_nand_enable_hwecc(struct mtd_info *mtd, int mode)
581{
582 /*
583 * If HW ECC is enabled, we turn it on during init. There is
584 * no need to enable again here.
585 */
586}
587
Sascha Hauer94f77e52010-08-06 15:53:09 +0200588static int mxc_nand_correct_data_v1(struct mtd_info *mtd, u_char *dat,
Sascha Hauer34f6e152008-09-02 17:16:59 +0200589 u_char *read_ecc, u_char *calc_ecc)
590{
591 struct nand_chip *nand_chip = mtd->priv;
592 struct mxc_nand_host *host = nand_chip->priv;
593
594 /*
595 * 1-Bit errors are automatically corrected in HW. No need for
596 * additional correction. 2-Bit errors cannot be corrected by
597 * HW ECC, so we need to return failure
598 */
Uwe Kleine-König6d38af22012-04-23 11:23:36 +0200599 uint16_t ecc_status = get_ecc_status_v1(host);
Sascha Hauer34f6e152008-09-02 17:16:59 +0200600
601 if (((ecc_status & 0x3) == 2) || ((ecc_status >> 2) == 2)) {
Brian Norris289c0522011-07-19 10:06:09 -0700602 pr_debug("MXC_NAND: HWECC uncorrectable 2-bit ECC error\n");
Sascha Hauer34f6e152008-09-02 17:16:59 +0200603 return -1;
604 }
605
606 return 0;
607}
608
Sascha Hauer94f77e52010-08-06 15:53:09 +0200609static int mxc_nand_correct_data_v2_v3(struct mtd_info *mtd, u_char *dat,
610 u_char *read_ecc, u_char *calc_ecc)
611{
612 struct nand_chip *nand_chip = mtd->priv;
613 struct mxc_nand_host *host = nand_chip->priv;
614 u32 ecc_stat, err;
615 int no_subpages = 1;
616 int ret = 0;
617 u8 ecc_bit_mask, err_limit;
618
619 ecc_bit_mask = (host->eccsize == 4) ? 0x7 : 0xf;
620 err_limit = (host->eccsize == 4) ? 0x4 : 0x8;
621
622 no_subpages = mtd->writesize >> 9;
623
Uwe Kleine-König6d38af22012-04-23 11:23:36 +0200624 ecc_stat = host->devtype_data->get_ecc_status(host);
Sascha Hauer94f77e52010-08-06 15:53:09 +0200625
626 do {
627 err = ecc_stat & ecc_bit_mask;
628 if (err > err_limit) {
629 printk(KERN_WARNING "UnCorrectable RS-ECC Error\n");
630 return -1;
631 } else {
632 ret += err;
633 }
634 ecc_stat >>= 4;
635 } while (--no_subpages);
636
637 mtd->ecc_stats.corrected += ret;
638 pr_debug("%d Symbol Correctable RS-ECC Error\n", ret);
639
640 return ret;
641}
642
Sascha Hauer34f6e152008-09-02 17:16:59 +0200643static int mxc_nand_calculate_ecc(struct mtd_info *mtd, const u_char *dat,
644 u_char *ecc_code)
645{
646 return 0;
647}
648
649static u_char mxc_nand_read_byte(struct mtd_info *mtd)
650{
651 struct nand_chip *nand_chip = mtd->priv;
652 struct mxc_nand_host *host = nand_chip->priv;
Sascha Hauerf8f96082009-06-04 17:12:26 +0200653 uint8_t ret;
Sascha Hauer34f6e152008-09-02 17:16:59 +0200654
655 /* Check for status request */
656 if (host->status_request)
Uwe Kleine-Könige4303b22012-04-23 11:23:35 +0200657 return host->devtype_data->get_dev_status(host) & 0xFF;
Sascha Hauer34f6e152008-09-02 17:16:59 +0200658
Sascha Hauerf8f96082009-06-04 17:12:26 +0200659 ret = *(uint8_t *)(host->data_buf + host->buf_start);
660 host->buf_start++;
Sascha Hauer34f6e152008-09-02 17:16:59 +0200661
662 return ret;
663}
664
665static uint16_t mxc_nand_read_word(struct mtd_info *mtd)
666{
667 struct nand_chip *nand_chip = mtd->priv;
668 struct mxc_nand_host *host = nand_chip->priv;
Sascha Hauerf8f96082009-06-04 17:12:26 +0200669 uint16_t ret;
Sascha Hauer34f6e152008-09-02 17:16:59 +0200670
Sascha Hauerf8f96082009-06-04 17:12:26 +0200671 ret = *(uint16_t *)(host->data_buf + host->buf_start);
672 host->buf_start += 2;
Sascha Hauer34f6e152008-09-02 17:16:59 +0200673
674 return ret;
675}
676
677/* Write data of length len to buffer buf. The data to be
678 * written on NAND Flash is first copied to RAMbuffer. After the Data Input
679 * Operation by the NFC, the data is written to NAND Flash */
680static void mxc_nand_write_buf(struct mtd_info *mtd,
681 const u_char *buf, int len)
682{
683 struct nand_chip *nand_chip = mtd->priv;
684 struct mxc_nand_host *host = nand_chip->priv;
Sascha Hauerf8f96082009-06-04 17:12:26 +0200685 u16 col = host->buf_start;
686 int n = mtd->oobsize + mtd->writesize - col;
Sascha Hauer34f6e152008-09-02 17:16:59 +0200687
Sascha Hauerf8f96082009-06-04 17:12:26 +0200688 n = min(n, len);
Sascha Hauer34f6e152008-09-02 17:16:59 +0200689
Sascha Hauerf8f96082009-06-04 17:12:26 +0200690 memcpy(host->data_buf + col, buf, n);
Sascha Hauer34f6e152008-09-02 17:16:59 +0200691
Sascha Hauerf8f96082009-06-04 17:12:26 +0200692 host->buf_start += n;
Sascha Hauer34f6e152008-09-02 17:16:59 +0200693}
694
695/* Read the data buffer from the NAND Flash. To read the data from NAND
696 * Flash first the data output cycle is initiated by the NFC, which copies
697 * the data to RAMbuffer. This data of length len is then copied to buffer buf.
698 */
699static void mxc_nand_read_buf(struct mtd_info *mtd, u_char *buf, int len)
700{
701 struct nand_chip *nand_chip = mtd->priv;
702 struct mxc_nand_host *host = nand_chip->priv;
Sascha Hauerf8f96082009-06-04 17:12:26 +0200703 u16 col = host->buf_start;
704 int n = mtd->oobsize + mtd->writesize - col;
Sascha Hauer34f6e152008-09-02 17:16:59 +0200705
Sascha Hauerf8f96082009-06-04 17:12:26 +0200706 n = min(n, len);
Sascha Hauer34f6e152008-09-02 17:16:59 +0200707
Baruch Siach5d9d9932011-03-02 16:47:55 +0200708 memcpy(buf, host->data_buf + col, n);
Sascha Hauer34f6e152008-09-02 17:16:59 +0200709
Baruch Siach5d9d9932011-03-02 16:47:55 +0200710 host->buf_start += n;
Sascha Hauer34f6e152008-09-02 17:16:59 +0200711}
712
713/* Used by the upper layer to verify the data in NAND Flash
714 * with the data in the buf. */
715static int mxc_nand_verify_buf(struct mtd_info *mtd,
716 const u_char *buf, int len)
717{
718 return -EFAULT;
719}
720
721/* This function is used by upper layer for select and
722 * deselect of the NAND chip */
723static void mxc_nand_select_chip(struct mtd_info *mtd, int chip)
724{
725 struct nand_chip *nand_chip = mtd->priv;
726 struct mxc_nand_host *host = nand_chip->priv;
727
Baruch Siachd178e3e2011-03-14 09:01:56 +0200728 if (chip == -1) {
Sascha Hauer34f6e152008-09-02 17:16:59 +0200729 /* Disable the NFC clock */
730 if (host->clk_act) {
731 clk_disable(host->clk);
732 host->clk_act = 0;
733 }
Baruch Siachd178e3e2011-03-14 09:01:56 +0200734 return;
735 }
Sascha Hauer34f6e152008-09-02 17:16:59 +0200736
Baruch Siachd178e3e2011-03-14 09:01:56 +0200737 if (!host->clk_act) {
738 /* Enable the NFC clock */
739 clk_enable(host->clk);
740 host->clk_act = 1;
741 }
742
743 if (nfc_is_v21()) {
744 host->active_cs = chip;
745 writew(host->active_cs << 4, NFC_V1_V2_BUF_ADDR);
Sascha Hauer34f6e152008-09-02 17:16:59 +0200746 }
747}
748
Sascha Hauerf8f96082009-06-04 17:12:26 +0200749/*
750 * Function to transfer data to/from spare area.
751 */
752static void copy_spare(struct mtd_info *mtd, bool bfrom)
753{
754 struct nand_chip *this = mtd->priv;
755 struct mxc_nand_host *host = this->priv;
756 u16 i, j;
757 u16 n = mtd->writesize >> 9;
758 u8 *d = host->data_buf + mtd->writesize;
Sascha Hauerc6de7e12009-10-05 11:14:35 +0200759 u8 *s = host->spare0;
Sascha Hauerf8f96082009-06-04 17:12:26 +0200760 u16 t = host->spare_len;
761
762 j = (mtd->oobsize / n >> 1) << 1;
763
764 if (bfrom) {
765 for (i = 0; i < n - 1; i++)
766 memcpy(d + i * j, s + i * t, j);
767
768 /* the last section */
769 memcpy(d + i * j, s + i * t, mtd->oobsize - i * j);
770 } else {
771 for (i = 0; i < n - 1; i++)
772 memcpy(&s[i * t], &d[i * j], j);
773
774 /* the last section */
775 memcpy(&s[i * t], &d[i * j], mtd->oobsize - i * j);
776 }
777}
778
Sascha Hauera3e65b62009-06-02 11:47:59 +0200779static void mxc_do_addr_cycle(struct mtd_info *mtd, int column, int page_addr)
Sascha Hauer34f6e152008-09-02 17:16:59 +0200780{
781 struct nand_chip *nand_chip = mtd->priv;
782 struct mxc_nand_host *host = nand_chip->priv;
Sascha Hauer34f6e152008-09-02 17:16:59 +0200783
784 /* Write out column address, if necessary */
785 if (column != -1) {
786 /*
787 * MXC NANDFC can only perform full page+spare or
788 * spare-only read/write. When the upper layers
Gilles Espinasse177b2412011-01-09 08:59:49 +0100789 * perform a read/write buf operation, the saved column
790 * address is used to index into the full page.
Sascha Hauer34f6e152008-09-02 17:16:59 +0200791 */
Uwe Kleine-Könige4303b22012-04-23 11:23:35 +0200792 host->devtype_data->send_addr(host, 0, page_addr == -1);
Sascha Hauer2d69c7f2009-10-05 11:24:02 +0200793 if (mtd->writesize > 512)
Sascha Hauer34f6e152008-09-02 17:16:59 +0200794 /* another col addr cycle for 2k page */
Uwe Kleine-Könige4303b22012-04-23 11:23:35 +0200795 host->devtype_data->send_addr(host, 0, false);
Sascha Hauer34f6e152008-09-02 17:16:59 +0200796 }
797
798 /* Write out page address, if necessary */
799 if (page_addr != -1) {
800 /* paddr_0 - p_addr_7 */
Uwe Kleine-Könige4303b22012-04-23 11:23:35 +0200801 host->devtype_data->send_addr(host, (page_addr & 0xff), false);
Sascha Hauer34f6e152008-09-02 17:16:59 +0200802
Sascha Hauer2d69c7f2009-10-05 11:24:02 +0200803 if (mtd->writesize > 512) {
Vladimir Barinovbd3fd622009-05-25 13:06:17 +0400804 if (mtd->size >= 0x10000000) {
805 /* paddr_8 - paddr_15 */
Uwe Kleine-Könige4303b22012-04-23 11:23:35 +0200806 host->devtype_data->send_addr(host,
807 (page_addr >> 8) & 0xff,
808 false);
809 host->devtype_data->send_addr(host,
810 (page_addr >> 16) & 0xff,
811 true);
Vladimir Barinovbd3fd622009-05-25 13:06:17 +0400812 } else
813 /* paddr_8 - paddr_15 */
Uwe Kleine-Könige4303b22012-04-23 11:23:35 +0200814 host->devtype_data->send_addr(host,
815 (page_addr >> 8) & 0xff, true);
Sascha Hauer34f6e152008-09-02 17:16:59 +0200816 } else {
817 /* One more address cycle for higher density devices */
818 if (mtd->size >= 0x4000000) {
819 /* paddr_8 - paddr_15 */
Uwe Kleine-Könige4303b22012-04-23 11:23:35 +0200820 host->devtype_data->send_addr(host,
821 (page_addr >> 8) & 0xff,
822 false);
823 host->devtype_data->send_addr(host,
824 (page_addr >> 16) & 0xff,
825 true);
Sascha Hauer34f6e152008-09-02 17:16:59 +0200826 } else
827 /* paddr_8 - paddr_15 */
Uwe Kleine-Könige4303b22012-04-23 11:23:35 +0200828 host->devtype_data->send_addr(host,
829 (page_addr >> 8) & 0xff, true);
Sascha Hauer34f6e152008-09-02 17:16:59 +0200830 }
831 }
Sascha Hauera3e65b62009-06-02 11:47:59 +0200832}
Sascha Hauer34f6e152008-09-02 17:16:59 +0200833
Sascha Hauer6e85dfd2010-08-06 15:53:10 +0200834/*
835 * v2 and v3 type controllers can do 4bit or 8bit ecc depending
836 * on how much oob the nand chip has. For 8bit ecc we need at least
837 * 26 bytes of oob data per 512 byte block.
838 */
839static int get_eccsize(struct mtd_info *mtd)
840{
841 int oobbytes_per_512 = 0;
842
843 oobbytes_per_512 = mtd->oobsize * 512 / mtd->writesize;
844
845 if (oobbytes_per_512 < 26)
846 return 4;
847 else
848 return 8;
849}
850
Uwe Kleine-König6d38af22012-04-23 11:23:36 +0200851static void preset_v1(struct mtd_info *mtd)
Ivo Claryssed4840182010-04-08 16:14:44 +0200852{
853 struct nand_chip *nand_chip = mtd->priv;
854 struct mxc_nand_host *host = nand_chip->priv;
Sascha Hauerb8db2f52010-08-09 15:04:19 +0200855 uint16_t config1 = 0;
Ivo Claryssed4840182010-04-08 16:14:44 +0200856
Sascha Hauerb8db2f52010-08-09 15:04:19 +0200857 if (nand_chip->ecc.mode == NAND_ECC_HW)
858 config1 |= NFC_V1_V2_CONFIG1_ECC_EN;
859
Uwe Kleine-König6d38af22012-04-23 11:23:36 +0200860 if (!host->irqpending_quirk)
861 config1 |= NFC_V1_V2_CONFIG1_INT_MSK;
862
863 host->eccsize = 1;
864
865 writew(config1, NFC_V1_V2_CONFIG1);
866 /* preset operation */
867
868 /* Unlock the internal RAM Buffer */
869 writew(0x2, NFC_V1_V2_CONFIG);
870
871 /* Blocks to be unlocked */
872 writew(0x0, NFC_V1_UNLOCKSTART_BLKADDR);
873 writew(0xffff, NFC_V1_UNLOCKEND_BLKADDR);
874
875 /* Unlock Block Command for given address range */
876 writew(0x4, NFC_V1_V2_WRPROT);
877}
878
879static void preset_v2(struct mtd_info *mtd)
880{
881 struct nand_chip *nand_chip = mtd->priv;
882 struct mxc_nand_host *host = nand_chip->priv;
883 uint16_t config1 = 0;
884
885 if (nand_chip->ecc.mode == NAND_ECC_HW)
886 config1 |= NFC_V1_V2_CONFIG1_ECC_EN;
887
888 config1 |= NFC_V2_CONFIG1_FP_INT;
Sascha Hauerb8db2f52010-08-09 15:04:19 +0200889
Uwe Kleine-König85569582012-04-23 11:23:34 +0200890 if (!host->irqpending_quirk)
Sascha Hauerb8db2f52010-08-09 15:04:19 +0200891 config1 |= NFC_V1_V2_CONFIG1_INT_MSK;
Sascha Hauer6e85dfd2010-08-06 15:53:10 +0200892
Uwe Kleine-König6d38af22012-04-23 11:23:36 +0200893 if (mtd->writesize) {
Sascha Hauerb8db2f52010-08-09 15:04:19 +0200894 uint16_t pages_per_block = mtd->erasesize / mtd->writesize;
895
Sascha Hauer6e85dfd2010-08-06 15:53:10 +0200896 host->eccsize = get_eccsize(mtd);
897 if (host->eccsize == 4)
Sascha Hauerb8db2f52010-08-09 15:04:19 +0200898 config1 |= NFC_V2_CONFIG1_ECC_MODE_4;
899
900 config1 |= NFC_V2_CONFIG1_PPB(ffs(pages_per_block) - 6);
Sascha Hauer6e85dfd2010-08-06 15:53:10 +0200901 } else {
902 host->eccsize = 1;
903 }
904
Sascha Hauerb8db2f52010-08-09 15:04:19 +0200905 writew(config1, NFC_V1_V2_CONFIG1);
Ivo Claryssed4840182010-04-08 16:14:44 +0200906 /* preset operation */
907
908 /* Unlock the internal RAM Buffer */
Sascha Hauer1bc99182010-08-06 15:53:08 +0200909 writew(0x2, NFC_V1_V2_CONFIG);
Ivo Claryssed4840182010-04-08 16:14:44 +0200910
911 /* Blocks to be unlocked */
Uwe Kleine-König6d38af22012-04-23 11:23:36 +0200912 writew(0x0, NFC_V21_UNLOCKSTART_BLKADDR0);
913 writew(0x0, NFC_V21_UNLOCKSTART_BLKADDR1);
914 writew(0x0, NFC_V21_UNLOCKSTART_BLKADDR2);
915 writew(0x0, NFC_V21_UNLOCKSTART_BLKADDR3);
916 writew(0xffff, NFC_V21_UNLOCKEND_BLKADDR0);
917 writew(0xffff, NFC_V21_UNLOCKEND_BLKADDR1);
918 writew(0xffff, NFC_V21_UNLOCKEND_BLKADDR2);
919 writew(0xffff, NFC_V21_UNLOCKEND_BLKADDR3);
Ivo Claryssed4840182010-04-08 16:14:44 +0200920
921 /* Unlock Block Command for given address range */
Sascha Hauer1bc99182010-08-06 15:53:08 +0200922 writew(0x4, NFC_V1_V2_WRPROT);
Ivo Claryssed4840182010-04-08 16:14:44 +0200923}
924
Sascha Hauer71ec5152010-08-06 15:53:11 +0200925static void preset_v3(struct mtd_info *mtd)
926{
927 struct nand_chip *chip = mtd->priv;
928 struct mxc_nand_host *host = chip->priv;
929 uint32_t config2, config3;
930 int i, addr_phases;
931
932 writel(NFC_V3_CONFIG1_RBA(0), NFC_V3_CONFIG1);
933 writel(NFC_V3_IPC_CREQ, NFC_V3_IPC);
934
935 /* Unlock the internal RAM Buffer */
936 writel(NFC_V3_WRPROT_BLS_UNLOCK | NFC_V3_WRPROT_UNLOCK,
937 NFC_V3_WRPROT);
938
939 /* Blocks to be unlocked */
940 for (i = 0; i < NAND_MAX_CHIPS; i++)
941 writel(0x0 | (0xffff << 16),
942 NFC_V3_WRPROT_UNLOCK_BLK_ADD0 + (i << 2));
943
944 writel(0, NFC_V3_IPC);
945
946 config2 = NFC_V3_CONFIG2_ONE_CYCLE |
947 NFC_V3_CONFIG2_2CMD_PHASES |
948 NFC_V3_CONFIG2_SPAS(mtd->oobsize >> 1) |
949 NFC_V3_CONFIG2_ST_CMD(0x70) |
Sascha Hauer63f14742010-10-18 10:16:26 +0200950 NFC_V3_CONFIG2_INT_MSK |
Sascha Hauer71ec5152010-08-06 15:53:11 +0200951 NFC_V3_CONFIG2_NUM_ADDR_PHASE0;
952
953 if (chip->ecc.mode == NAND_ECC_HW)
954 config2 |= NFC_V3_CONFIG2_ECC_EN;
955
956 addr_phases = fls(chip->pagemask) >> 3;
957
958 if (mtd->writesize == 2048) {
959 config2 |= NFC_V3_CONFIG2_PS_2048;
960 config2 |= NFC_V3_CONFIG2_NUM_ADDR_PHASE1(addr_phases);
961 } else if (mtd->writesize == 4096) {
962 config2 |= NFC_V3_CONFIG2_PS_4096;
963 config2 |= NFC_V3_CONFIG2_NUM_ADDR_PHASE1(addr_phases);
964 } else {
965 config2 |= NFC_V3_CONFIG2_PS_512;
966 config2 |= NFC_V3_CONFIG2_NUM_ADDR_PHASE1(addr_phases - 1);
967 }
968
969 if (mtd->writesize) {
970 config2 |= NFC_V3_CONFIG2_PPB(ffs(mtd->erasesize / mtd->writesize) - 6);
971 host->eccsize = get_eccsize(mtd);
972 if (host->eccsize == 8)
973 config2 |= NFC_V3_CONFIG2_ECC_MODE_8;
974 }
975
976 writel(config2, NFC_V3_CONFIG2);
977
978 config3 = NFC_V3_CONFIG3_NUM_OF_DEVICES(0) |
979 NFC_V3_CONFIG3_NO_SDMA |
980 NFC_V3_CONFIG3_RBB_MODE |
981 NFC_V3_CONFIG3_SBB(6) | /* Reset default */
982 NFC_V3_CONFIG3_ADD_OP(0);
983
984 if (!(chip->options & NAND_BUSWIDTH_16))
985 config3 |= NFC_V3_CONFIG3_FW8;
986
987 writel(config3, NFC_V3_CONFIG3);
988
989 writel(0, NFC_V3_DELAY_LINE);
Sascha Hauer34f6e152008-09-02 17:16:59 +0200990}
991
Sascha Hauer34f6e152008-09-02 17:16:59 +0200992/* Used by the upper layer to write command to NAND Flash for
993 * different operations to be carried out on NAND Flash */
994static void mxc_nand_command(struct mtd_info *mtd, unsigned command,
995 int column, int page_addr)
996{
997 struct nand_chip *nand_chip = mtd->priv;
998 struct mxc_nand_host *host = nand_chip->priv;
Sascha Hauer34f6e152008-09-02 17:16:59 +0200999
Brian Norris289c0522011-07-19 10:06:09 -07001000 pr_debug("mxc_nand_command (cmd = 0x%x, col = 0x%x, page = 0x%x)\n",
Sascha Hauer34f6e152008-09-02 17:16:59 +02001001 command, column, page_addr);
1002
1003 /* Reset command state information */
1004 host->status_request = false;
1005
1006 /* Command pre-processing step */
Sascha Hauer34f6e152008-09-02 17:16:59 +02001007 switch (command) {
Ivo Claryssed4840182010-04-08 16:14:44 +02001008 case NAND_CMD_RESET:
Uwe Kleine-Könige4303b22012-04-23 11:23:35 +02001009 host->devtype_data->preset(mtd);
1010 host->devtype_data->send_cmd(host, command, false);
Ivo Claryssed4840182010-04-08 16:14:44 +02001011 break;
Sascha Hauer34f6e152008-09-02 17:16:59 +02001012
Sascha Hauer34f6e152008-09-02 17:16:59 +02001013 case NAND_CMD_STATUS:
Sascha Hauerf8f96082009-06-04 17:12:26 +02001014 host->buf_start = 0;
Sascha Hauer34f6e152008-09-02 17:16:59 +02001015 host->status_request = true;
Sascha Hauer89121a62009-06-04 17:18:01 +02001016
Uwe Kleine-Könige4303b22012-04-23 11:23:35 +02001017 host->devtype_data->send_cmd(host, command, true);
Sascha Hauer89121a62009-06-04 17:18:01 +02001018 mxc_do_addr_cycle(mtd, column, page_addr);
Sascha Hauer34f6e152008-09-02 17:16:59 +02001019 break;
1020
Sascha Hauer34f6e152008-09-02 17:16:59 +02001021 case NAND_CMD_READ0:
Sascha Hauer34f6e152008-09-02 17:16:59 +02001022 case NAND_CMD_READOOB:
Sascha Hauer89121a62009-06-04 17:18:01 +02001023 if (command == NAND_CMD_READ0)
1024 host->buf_start = column;
1025 else
1026 host->buf_start = column + mtd->writesize;
Sascha Hauerf8f96082009-06-04 17:12:26 +02001027
Sascha Hauer5ea32022010-04-27 15:24:01 +02001028 command = NAND_CMD_READ0; /* only READ0 is valid */
Sascha Hauer89121a62009-06-04 17:18:01 +02001029
Uwe Kleine-Könige4303b22012-04-23 11:23:35 +02001030 host->devtype_data->send_cmd(host, command, false);
Sascha Hauer89121a62009-06-04 17:18:01 +02001031 mxc_do_addr_cycle(mtd, column, page_addr);
1032
Sascha Hauer2d69c7f2009-10-05 11:24:02 +02001033 if (mtd->writesize > 512)
Uwe Kleine-Könige4303b22012-04-23 11:23:35 +02001034 host->devtype_data->send_cmd(host,
1035 NAND_CMD_READSTART, true);
Sascha Hauerc5d23f12009-06-04 17:25:53 +02001036
Uwe Kleine-Könige4303b22012-04-23 11:23:35 +02001037 host->devtype_data->send_page(mtd, NFC_OUTPUT);
Sascha Hauer89121a62009-06-04 17:18:01 +02001038
Sascha Hauerc6de7e12009-10-05 11:14:35 +02001039 memcpy(host->data_buf, host->main_area0, mtd->writesize);
Sascha Hauer89121a62009-06-04 17:18:01 +02001040 copy_spare(mtd, true);
Sascha Hauer34f6e152008-09-02 17:16:59 +02001041 break;
1042
Sascha Hauer34f6e152008-09-02 17:16:59 +02001043 case NAND_CMD_SEQIN:
Sascha Hauer5ea32022010-04-27 15:24:01 +02001044 if (column >= mtd->writesize)
1045 /* call ourself to read a page */
1046 mxc_nand_command(mtd, NAND_CMD_READ0, 0, page_addr);
Sascha Hauer34f6e152008-09-02 17:16:59 +02001047
Sascha Hauer5ea32022010-04-27 15:24:01 +02001048 host->buf_start = column;
Sascha Hauer89121a62009-06-04 17:18:01 +02001049
Uwe Kleine-Könige4303b22012-04-23 11:23:35 +02001050 host->devtype_data->send_cmd(host, command, false);
Sascha Hauer89121a62009-06-04 17:18:01 +02001051 mxc_do_addr_cycle(mtd, column, page_addr);
Sascha Hauer34f6e152008-09-02 17:16:59 +02001052 break;
1053
1054 case NAND_CMD_PAGEPROG:
Sascha Hauerc6de7e12009-10-05 11:14:35 +02001055 memcpy(host->main_area0, host->data_buf, mtd->writesize);
Sascha Hauerf8f96082009-06-04 17:12:26 +02001056 copy_spare(mtd, false);
Uwe Kleine-Könige4303b22012-04-23 11:23:35 +02001057 host->devtype_data->send_page(mtd, NFC_INPUT);
1058 host->devtype_data->send_cmd(host, command, true);
Sascha Hauer89121a62009-06-04 17:18:01 +02001059 mxc_do_addr_cycle(mtd, column, page_addr);
Sascha Hauer34f6e152008-09-02 17:16:59 +02001060 break;
1061
Sascha Hauer34f6e152008-09-02 17:16:59 +02001062 case NAND_CMD_READID:
Uwe Kleine-Könige4303b22012-04-23 11:23:35 +02001063 host->devtype_data->send_cmd(host, command, true);
Sascha Hauer89121a62009-06-04 17:18:01 +02001064 mxc_do_addr_cycle(mtd, column, page_addr);
Uwe Kleine-Könige4303b22012-04-23 11:23:35 +02001065 host->devtype_data->send_read_id(host);
Sascha Hauer94671142009-10-05 12:14:21 +02001066 host->buf_start = column;
Sascha Hauer34f6e152008-09-02 17:16:59 +02001067 break;
1068
Sascha Hauer89121a62009-06-04 17:18:01 +02001069 case NAND_CMD_ERASE1:
Sascha Hauer34f6e152008-09-02 17:16:59 +02001070 case NAND_CMD_ERASE2:
Uwe Kleine-Könige4303b22012-04-23 11:23:35 +02001071 host->devtype_data->send_cmd(host, command, false);
Sascha Hauer89121a62009-06-04 17:18:01 +02001072 mxc_do_addr_cycle(mtd, column, page_addr);
1073
Sascha Hauer34f6e152008-09-02 17:16:59 +02001074 break;
1075 }
1076}
1077
Sascha Hauerf1372052009-10-21 14:25:27 +02001078/*
1079 * The generic flash bbt decriptors overlap with our ecc
1080 * hardware, so define some i.MX specific ones.
1081 */
1082static uint8_t bbt_pattern[] = { 'B', 'b', 't', '0' };
1083static uint8_t mirror_pattern[] = { '1', 't', 'b', 'B' };
1084
1085static struct nand_bbt_descr bbt_main_descr = {
1086 .options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE
1087 | NAND_BBT_2BIT | NAND_BBT_VERSION | NAND_BBT_PERCHIP,
1088 .offs = 0,
1089 .len = 4,
1090 .veroffs = 4,
1091 .maxblocks = 4,
1092 .pattern = bbt_pattern,
1093};
1094
1095static struct nand_bbt_descr bbt_mirror_descr = {
1096 .options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE
1097 | NAND_BBT_2BIT | NAND_BBT_VERSION | NAND_BBT_PERCHIP,
1098 .offs = 0,
1099 .len = 4,
1100 .veroffs = 4,
1101 .maxblocks = 4,
1102 .pattern = mirror_pattern,
1103};
1104
Uwe Kleine-Könige4303b22012-04-23 11:23:35 +02001105/* v1: i.MX21, i.MX27, i.MX31 */
1106static const struct mxc_nand_devtype_data imx21_nand_devtype_data = {
Uwe Kleine-König6d38af22012-04-23 11:23:36 +02001107 .preset = preset_v1,
Uwe Kleine-Könige4303b22012-04-23 11:23:35 +02001108 .send_cmd = send_cmd_v1_v2,
1109 .send_addr = send_addr_v1_v2,
Uwe Kleine-König6d38af22012-04-23 11:23:36 +02001110 .send_page = send_page_v1,
Uwe Kleine-Könige4303b22012-04-23 11:23:35 +02001111 .send_read_id = send_read_id_v1_v2,
1112 .get_dev_status = get_dev_status_v1_v2,
1113 .check_int = check_int_v1_v2,
1114 .irq_control = irq_control_v1_v2,
Uwe Kleine-König6d38af22012-04-23 11:23:36 +02001115 .get_ecc_status = get_ecc_status_v1,
Uwe Kleine-Könige4303b22012-04-23 11:23:35 +02001116};
1117
1118/* v21: i.MX25, i.MX35 */
1119static const struct mxc_nand_devtype_data imx25_nand_devtype_data = {
Uwe Kleine-König6d38af22012-04-23 11:23:36 +02001120 .preset = preset_v2,
Uwe Kleine-Könige4303b22012-04-23 11:23:35 +02001121 .send_cmd = send_cmd_v1_v2,
1122 .send_addr = send_addr_v1_v2,
Uwe Kleine-König6d38af22012-04-23 11:23:36 +02001123 .send_page = send_page_v2,
Uwe Kleine-Könige4303b22012-04-23 11:23:35 +02001124 .send_read_id = send_read_id_v1_v2,
1125 .get_dev_status = get_dev_status_v1_v2,
1126 .check_int = check_int_v1_v2,
1127 .irq_control = irq_control_v1_v2,
Uwe Kleine-König6d38af22012-04-23 11:23:36 +02001128 .get_ecc_status = get_ecc_status_v2,
Uwe Kleine-Könige4303b22012-04-23 11:23:35 +02001129};
1130
1131/* v3: i.MX51, i.MX53 */
1132static const struct mxc_nand_devtype_data imx51_nand_devtype_data = {
1133 .preset = preset_v3,
1134 .send_cmd = send_cmd_v3,
1135 .send_addr = send_addr_v3,
1136 .send_page = send_page_v3,
1137 .send_read_id = send_read_id_v3,
1138 .get_dev_status = get_dev_status_v3,
1139 .check_int = check_int_v3,
1140 .irq_control = irq_control_v3,
Uwe Kleine-König6d38af22012-04-23 11:23:36 +02001141 .get_ecc_status = get_ecc_status_v3,
Uwe Kleine-Könige4303b22012-04-23 11:23:35 +02001142};
1143
Sascha Hauer34f6e152008-09-02 17:16:59 +02001144static int __init mxcnd_probe(struct platform_device *pdev)
1145{
1146 struct nand_chip *this;
1147 struct mtd_info *mtd;
1148 struct mxc_nand_platform_data *pdata = pdev->dev.platform_data;
1149 struct mxc_nand_host *host;
1150 struct resource *res;
Dmitry Eremin-Solenikovd4ed8f12011-06-02 18:00:43 +04001151 int err = 0;
Sascha Hauer94671142009-10-05 12:14:21 +02001152 struct nand_ecclayout *oob_smallpage, *oob_largepage;
Sascha Hauer34f6e152008-09-02 17:16:59 +02001153
1154 /* Allocate memory for MTD device structure and private data */
Sascha Hauerf8f96082009-06-04 17:12:26 +02001155 host = kzalloc(sizeof(struct mxc_nand_host) + NAND_MAX_PAGESIZE +
1156 NAND_MAX_OOBSIZE, GFP_KERNEL);
Sascha Hauer34f6e152008-09-02 17:16:59 +02001157 if (!host)
1158 return -ENOMEM;
1159
Sascha Hauerf8f96082009-06-04 17:12:26 +02001160 host->data_buf = (uint8_t *)(host + 1);
Sascha Hauerf8f96082009-06-04 17:12:26 +02001161
Sascha Hauer34f6e152008-09-02 17:16:59 +02001162 host->dev = &pdev->dev;
1163 /* structures must be linked */
1164 this = &host->nand;
1165 mtd = &host->mtd;
1166 mtd->priv = this;
1167 mtd->owner = THIS_MODULE;
David Brownell87f39f02009-03-26 00:42:50 -07001168 mtd->dev.parent = &pdev->dev;
Sascha Hauer1fbff0a2009-10-21 16:06:27 +02001169 mtd->name = DRIVER_NAME;
Sascha Hauer34f6e152008-09-02 17:16:59 +02001170
1171 /* 50 us command delay time */
1172 this->chip_delay = 5;
1173
1174 this->priv = host;
1175 this->dev_ready = mxc_nand_dev_ready;
1176 this->cmdfunc = mxc_nand_command;
1177 this->select_chip = mxc_nand_select_chip;
1178 this->read_byte = mxc_nand_read_byte;
1179 this->read_word = mxc_nand_read_word;
1180 this->write_buf = mxc_nand_write_buf;
1181 this->read_buf = mxc_nand_read_buf;
1182 this->verify_buf = mxc_nand_verify_buf;
1183
Sascha Hauere65fb002009-02-16 14:29:10 +01001184 host->clk = clk_get(&pdev->dev, "nfc");
Vladimir Barinov8541c112009-04-23 15:47:22 +04001185 if (IS_ERR(host->clk)) {
1186 err = PTR_ERR(host->clk);
Sascha Hauer34f6e152008-09-02 17:16:59 +02001187 goto eclk;
Vladimir Barinov8541c112009-04-23 15:47:22 +04001188 }
Sascha Hauer34f6e152008-09-02 17:16:59 +02001189
1190 clk_enable(host->clk);
1191 host->clk_act = 1;
1192
1193 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
1194 if (!res) {
1195 err = -ENODEV;
1196 goto eres;
1197 }
1198
Sascha Hauerc6de7e12009-10-05 11:14:35 +02001199 host->base = ioremap(res->start, resource_size(res));
1200 if (!host->base) {
Vladimir Barinov8541c112009-04-23 15:47:22 +04001201 err = -ENOMEM;
Sascha Hauer34f6e152008-09-02 17:16:59 +02001202 goto eres;
1203 }
1204
Sascha Hauerc6de7e12009-10-05 11:14:35 +02001205 host->main_area0 = host->base;
Sascha Hauer94671142009-10-05 12:14:21 +02001206
Uwe Kleine-Könige4303b22012-04-23 11:23:35 +02001207 if (nfc_is_v1()) {
1208 host->devtype_data = &imx21_nand_devtype_data;
Sascha Hauer63f14742010-10-18 10:16:26 +02001209 if (cpu_is_mx21())
Uwe Kleine-König85569582012-04-23 11:23:34 +02001210 host->irqpending_quirk = 1;
Sascha Hauer938cf992010-08-06 15:53:04 +02001211 host->regs = host->base + 0xe00;
Sascha Hauer94671142009-10-05 12:14:21 +02001212 host->spare0 = host->base + 0x800;
1213 host->spare_len = 16;
1214 oob_smallpage = &nandv1_hw_eccoob_smallpage;
1215 oob_largepage = &nandv1_hw_eccoob_largepage;
Sascha Hauer94671142009-10-05 12:14:21 +02001216 this->ecc.bytes = 3;
Sascha Hauer71ec5152010-08-06 15:53:11 +02001217 host->eccsize = 1;
Uwe Kleine-Könige4303b22012-04-23 11:23:35 +02001218 } else if (nfc_is_v21()) {
1219 host->devtype_data = &imx25_nand_devtype_data;
1220 host->regs = host->base + 0x1e00;
1221 host->spare0 = host->base + 0x1000;
1222 host->spare_len = 64;
1223 oob_smallpage = &nandv2_hw_eccoob_smallpage;
1224 oob_largepage = &nandv2_hw_eccoob_largepage;
1225 this->ecc.bytes = 9;
Sascha Hauer71ec5152010-08-06 15:53:11 +02001226 } else if (nfc_is_v3_2()) {
Uwe Kleine-Könige4303b22012-04-23 11:23:35 +02001227 host->devtype_data = &imx51_nand_devtype_data;
Sascha Hauer71ec5152010-08-06 15:53:11 +02001228 res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
1229 if (!res) {
1230 err = -ENODEV;
1231 goto eirq;
1232 }
1233 host->regs_ip = ioremap(res->start, resource_size(res));
1234 if (!host->regs_ip) {
1235 err = -ENOMEM;
1236 goto eirq;
1237 }
1238 host->regs_axi = host->base + 0x1e00;
1239 host->spare0 = host->base + 0x1000;
1240 host->spare_len = 64;
Sascha Hauer71ec5152010-08-06 15:53:11 +02001241 oob_smallpage = &nandv2_hw_eccoob_smallpage;
1242 oob_largepage = &nandv2_hw_eccoob_largepage;
Sascha Hauer94671142009-10-05 12:14:21 +02001243 } else
1244 BUG();
Sascha Hauer34f6e152008-09-02 17:16:59 +02001245
Sascha Hauer13e1add2009-10-21 10:39:05 +02001246 this->ecc.size = 512;
Sascha Hauer94671142009-10-05 12:14:21 +02001247 this->ecc.layout = oob_smallpage;
Sascha Hauer13e1add2009-10-21 10:39:05 +02001248
1249 if (pdata->hw_ecc) {
1250 this->ecc.calculate = mxc_nand_calculate_ecc;
1251 this->ecc.hwctl = mxc_nand_enable_hwecc;
Sascha Hauer94f77e52010-08-06 15:53:09 +02001252 if (nfc_is_v1())
1253 this->ecc.correct = mxc_nand_correct_data_v1;
1254 else
1255 this->ecc.correct = mxc_nand_correct_data_v2_v3;
Sascha Hauer13e1add2009-10-21 10:39:05 +02001256 this->ecc.mode = NAND_ECC_HW;
Sascha Hauer13e1add2009-10-21 10:39:05 +02001257 } else {
1258 this->ecc.mode = NAND_ECC_SOFT;
Sascha Hauer34f6e152008-09-02 17:16:59 +02001259 }
1260
Sascha Hauer34f6e152008-09-02 17:16:59 +02001261 /* NAND bus width determines access funtions used by upper layer */
Sascha Hauer13e1add2009-10-21 10:39:05 +02001262 if (pdata->width == 2)
Sascha Hauer34f6e152008-09-02 17:16:59 +02001263 this->options |= NAND_BUSWIDTH_16;
Sascha Hauer13e1add2009-10-21 10:39:05 +02001264
Sascha Hauerf1372052009-10-21 14:25:27 +02001265 if (pdata->flash_bbt) {
1266 this->bbt_td = &bbt_main_descr;
1267 this->bbt_md = &bbt_mirror_descr;
1268 /* update flash based bbt */
Brian Norrisbb9ebd42011-05-31 16:31:23 -07001269 this->bbt_options |= NAND_BBT_USE_FLASH;
Sascha Hauer34f6e152008-09-02 17:16:59 +02001270 }
1271
Sascha Hauer63f14742010-10-18 10:16:26 +02001272 init_completion(&host->op_completion);
Ivo Claryssed4840182010-04-08 16:14:44 +02001273
1274 host->irq = platform_get_irq(pdev, 0);
1275
Sascha Hauer63f14742010-10-18 10:16:26 +02001276 /*
Uwe Kleine-Könige4303b22012-04-23 11:23:35 +02001277 * Use host->devtype_data->irq_control() here instead of irq_control()
1278 * because we must not disable_irq_nosync without having requested the
1279 * irq.
Sascha Hauer63f14742010-10-18 10:16:26 +02001280 */
Uwe Kleine-Könige4303b22012-04-23 11:23:35 +02001281 host->devtype_data->irq_control(host, 0);
Sascha Hauer63f14742010-10-18 10:16:26 +02001282
Ivo Claryssea47bfd22010-04-08 16:16:51 +02001283 err = request_irq(host->irq, mxc_nfc_irq, IRQF_DISABLED, DRIVER_NAME, host);
Ivo Claryssed4840182010-04-08 16:14:44 +02001284 if (err)
1285 goto eirq;
1286
Sascha Hauer63f14742010-10-18 10:16:26 +02001287 /*
Uwe Kleine-König85569582012-04-23 11:23:34 +02001288 * Now that we "own" the interrupt make sure the interrupt mask bit is
1289 * cleared on i.MX21. Otherwise we can't read the interrupt status bit
1290 * on this machine.
Sascha Hauer63f14742010-10-18 10:16:26 +02001291 */
Uwe Kleine-König85569582012-04-23 11:23:34 +02001292 if (host->irqpending_quirk) {
1293 disable_irq_nosync(host->irq);
Uwe Kleine-Könige4303b22012-04-23 11:23:35 +02001294 host->devtype_data->irq_control(host, 1);
Uwe Kleine-König85569582012-04-23 11:23:34 +02001295 }
Sascha Hauer63f14742010-10-18 10:16:26 +02001296
Vladimir Barinovbd3fd622009-05-25 13:06:17 +04001297 /* first scan to find the device and get the page size */
Baruch Siachd178e3e2011-03-14 09:01:56 +02001298 if (nand_scan_ident(mtd, nfc_is_v21() ? 4 : 1, NULL)) {
Vladimir Barinovbd3fd622009-05-25 13:06:17 +04001299 err = -ENXIO;
1300 goto escan;
1301 }
Sascha Hauer34f6e152008-09-02 17:16:59 +02001302
Sascha Hauer6e85dfd2010-08-06 15:53:10 +02001303 /* Call preset again, with correct writesize this time */
Uwe Kleine-Könige4303b22012-04-23 11:23:35 +02001304 host->devtype_data->preset(mtd);
Sascha Hauer6e85dfd2010-08-06 15:53:10 +02001305
Sascha Hauer2d69c7f2009-10-05 11:24:02 +02001306 if (mtd->writesize == 2048)
Sascha Hauer94671142009-10-05 12:14:21 +02001307 this->ecc.layout = oob_largepage;
Baruch Siach2c1c5f12011-03-09 16:12:20 +02001308 if (nfc_is_v21() && mtd->writesize == 4096)
1309 this->ecc.layout = &nandv2_hw_eccoob_4k;
Vladimir Barinovbd3fd622009-05-25 13:06:17 +04001310
1311 /* second phase scan */
1312 if (nand_scan_tail(mtd)) {
Sascha Hauer34f6e152008-09-02 17:16:59 +02001313 err = -ENXIO;
1314 goto escan;
1315 }
1316
Mike Dunn6a918ba2012-03-11 14:21:11 -07001317 if (this->ecc.mode == NAND_ECC_HW) {
1318 if (nfc_is_v1())
1319 this->ecc.strength = 1;
1320 else
1321 this->ecc.strength = (host->eccsize == 4) ? 4 : 8;
1322 }
1323
Sascha Hauer34f6e152008-09-02 17:16:59 +02001324 /* Register the partitions */
Artem Bityutskiy42d7fbe2012-03-09 19:24:26 +02001325 mtd_device_parse_register(mtd, part_probes, NULL, pdata->parts,
1326 pdata->nr_parts);
Sascha Hauer34f6e152008-09-02 17:16:59 +02001327
1328 platform_set_drvdata(pdev, host);
1329
1330 return 0;
1331
1332escan:
Magnus Liljab258fd82009-05-08 21:57:47 +02001333 free_irq(host->irq, host);
Sascha Hauer34f6e152008-09-02 17:16:59 +02001334eirq:
Sascha Hauer71ec5152010-08-06 15:53:11 +02001335 if (host->regs_ip)
1336 iounmap(host->regs_ip);
Sascha Hauerc6de7e12009-10-05 11:14:35 +02001337 iounmap(host->base);
Sascha Hauer34f6e152008-09-02 17:16:59 +02001338eres:
1339 clk_put(host->clk);
1340eclk:
1341 kfree(host);
1342
1343 return err;
1344}
1345
Uwe Kleine-König51eeb872009-12-07 09:44:05 +00001346static int __devexit mxcnd_remove(struct platform_device *pdev)
Sascha Hauer34f6e152008-09-02 17:16:59 +02001347{
1348 struct mxc_nand_host *host = platform_get_drvdata(pdev);
1349
1350 clk_put(host->clk);
1351
1352 platform_set_drvdata(pdev, NULL);
1353
1354 nand_release(&host->mtd);
Magnus Liljab258fd82009-05-08 21:57:47 +02001355 free_irq(host->irq, host);
Sascha Hauer71ec5152010-08-06 15:53:11 +02001356 if (host->regs_ip)
1357 iounmap(host->regs_ip);
Sascha Hauerc6de7e12009-10-05 11:14:35 +02001358 iounmap(host->base);
Sascha Hauer34f6e152008-09-02 17:16:59 +02001359 kfree(host);
1360
1361 return 0;
1362}
1363
Sascha Hauer34f6e152008-09-02 17:16:59 +02001364static struct platform_driver mxcnd_driver = {
1365 .driver = {
1366 .name = DRIVER_NAME,
Uwe Kleine-König8d1fd162012-04-23 11:23:33 +02001367 .owner = THIS_MODULE,
Eric Bénard04dd0d32010-06-17 20:59:04 +02001368 },
Uwe Kleine-Königdaa0f152009-11-24 22:07:08 +01001369 .remove = __devexit_p(mxcnd_remove),
Sascha Hauer34f6e152008-09-02 17:16:59 +02001370};
1371
1372static int __init mxc_nd_init(void)
1373{
Vladimir Barinov8541c112009-04-23 15:47:22 +04001374 return platform_driver_probe(&mxcnd_driver, mxcnd_probe);
Sascha Hauer34f6e152008-09-02 17:16:59 +02001375}
1376
1377static void __exit mxc_nd_cleanup(void)
1378{
1379 /* Unregister the device structure */
1380 platform_driver_unregister(&mxcnd_driver);
1381}
1382
1383module_init(mxc_nd_init);
1384module_exit(mxc_nd_cleanup);
1385
1386MODULE_AUTHOR("Freescale Semiconductor, Inc.");
1387MODULE_DESCRIPTION("MXC NAND MTD driver");
1388MODULE_LICENSE("GPL");