blob: b2828e84d24377fdbf2be2d9af3d2492ee7feea2 [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>
33
34#include <asm/mach/flash.h>
35#include <mach/mxc_nand.h>
Sascha Hauer94671142009-10-05 12:14:21 +020036#include <mach/hardware.h>
Sascha Hauer34f6e152008-09-02 17:16:59 +020037
38#define DRIVER_NAME "mxc_nand"
39
Sascha Hauer94671142009-10-05 12:14:21 +020040#define nfc_is_v21() (cpu_is_mx25() || cpu_is_mx35())
Ivo Claryssea47bfd22010-04-08 16:16:51 +020041#define nfc_is_v1() (cpu_is_mx31() || cpu_is_mx27() || cpu_is_mx21())
Sascha Hauer71ec5152010-08-06 15:53:11 +020042#define nfc_is_v3_2() cpu_is_mx51()
43#define nfc_is_v3() nfc_is_v3_2()
Sascha Hauer94671142009-10-05 12:14:21 +020044
Sascha Hauer34f6e152008-09-02 17:16:59 +020045/* Addresses for NFC registers */
Sascha Hauer1bc99182010-08-06 15:53:08 +020046#define NFC_V1_V2_BUF_SIZE (host->regs + 0x00)
47#define NFC_V1_V2_BUF_ADDR (host->regs + 0x04)
48#define NFC_V1_V2_FLASH_ADDR (host->regs + 0x06)
49#define NFC_V1_V2_FLASH_CMD (host->regs + 0x08)
50#define NFC_V1_V2_CONFIG (host->regs + 0x0a)
51#define NFC_V1_V2_ECC_STATUS_RESULT (host->regs + 0x0c)
52#define NFC_V1_V2_RSLTMAIN_AREA (host->regs + 0x0e)
53#define NFC_V1_V2_RSLTSPARE_AREA (host->regs + 0x10)
54#define NFC_V1_V2_WRPROT (host->regs + 0x12)
55#define NFC_V1_UNLOCKSTART_BLKADDR (host->regs + 0x14)
56#define NFC_V1_UNLOCKEND_BLKADDR (host->regs + 0x16)
57#define NFC_V21_UNLOCKSTART_BLKADDR (host->regs + 0x20)
58#define NFC_V21_UNLOCKEND_BLKADDR (host->regs + 0x22)
59#define NFC_V1_V2_NF_WRPRST (host->regs + 0x18)
60#define NFC_V1_V2_CONFIG1 (host->regs + 0x1a)
61#define NFC_V1_V2_CONFIG2 (host->regs + 0x1c)
Sascha Hauer34f6e152008-09-02 17:16:59 +020062
Sascha Hauer6e85dfd2010-08-06 15:53:10 +020063#define NFC_V2_CONFIG1_ECC_MODE_4 (1 << 0)
Sascha Hauer1bc99182010-08-06 15:53:08 +020064#define NFC_V1_V2_CONFIG1_SP_EN (1 << 2)
65#define NFC_V1_V2_CONFIG1_ECC_EN (1 << 3)
66#define NFC_V1_V2_CONFIG1_INT_MSK (1 << 4)
67#define NFC_V1_V2_CONFIG1_BIG (1 << 5)
68#define NFC_V1_V2_CONFIG1_RST (1 << 6)
69#define NFC_V1_V2_CONFIG1_CE (1 << 7)
Sascha Hauerb8db2f52010-08-09 15:04:19 +020070#define NFC_V2_CONFIG1_ONE_CYCLE (1 << 8)
71#define NFC_V2_CONFIG1_PPB(x) (((x) & 0x3) << 9)
72#define NFC_V2_CONFIG1_FP_INT (1 << 11)
Sascha Hauer34f6e152008-09-02 17:16:59 +020073
Sascha Hauer1bc99182010-08-06 15:53:08 +020074#define NFC_V1_V2_CONFIG2_INT (1 << 15)
Sascha Hauer34f6e152008-09-02 17:16:59 +020075
Sascha Hauer1bc99182010-08-06 15:53:08 +020076/*
77 * Operation modes for the NFC. Valid for v1, v2 and v3
78 * type controllers.
79 */
80#define NFC_CMD (1 << 0)
81#define NFC_ADDR (1 << 1)
82#define NFC_INPUT (1 << 2)
83#define NFC_OUTPUT (1 << 3)
84#define NFC_ID (1 << 4)
85#define NFC_STATUS (1 << 5)
Sascha Hauer34f6e152008-09-02 17:16:59 +020086
Sascha Hauer71ec5152010-08-06 15:53:11 +020087#define NFC_V3_FLASH_CMD (host->regs_axi + 0x00)
88#define NFC_V3_FLASH_ADDR0 (host->regs_axi + 0x04)
Sascha Hauer34f6e152008-09-02 17:16:59 +020089
Sascha Hauer71ec5152010-08-06 15:53:11 +020090#define NFC_V3_CONFIG1 (host->regs_axi + 0x34)
91#define NFC_V3_CONFIG1_SP_EN (1 << 0)
92#define NFC_V3_CONFIG1_RBA(x) (((x) & 0x7 ) << 4)
Sascha Hauer34f6e152008-09-02 17:16:59 +020093
Sascha Hauer71ec5152010-08-06 15:53:11 +020094#define NFC_V3_ECC_STATUS_RESULT (host->regs_axi + 0x38)
Sascha Hauer34f6e152008-09-02 17:16:59 +020095
Sascha Hauer71ec5152010-08-06 15:53:11 +020096#define NFC_V3_LAUNCH (host->regs_axi + 0x40)
Sascha Hauer34f6e152008-09-02 17:16:59 +020097
Sascha Hauer71ec5152010-08-06 15:53:11 +020098#define NFC_V3_WRPROT (host->regs_ip + 0x0)
99#define NFC_V3_WRPROT_LOCK_TIGHT (1 << 0)
100#define NFC_V3_WRPROT_LOCK (1 << 1)
101#define NFC_V3_WRPROT_UNLOCK (1 << 2)
102#define NFC_V3_WRPROT_BLS_UNLOCK (2 << 6)
103
104#define NFC_V3_WRPROT_UNLOCK_BLK_ADD0 (host->regs_ip + 0x04)
105
106#define NFC_V3_CONFIG2 (host->regs_ip + 0x24)
107#define NFC_V3_CONFIG2_PS_512 (0 << 0)
108#define NFC_V3_CONFIG2_PS_2048 (1 << 0)
109#define NFC_V3_CONFIG2_PS_4096 (2 << 0)
110#define NFC_V3_CONFIG2_ONE_CYCLE (1 << 2)
111#define NFC_V3_CONFIG2_ECC_EN (1 << 3)
112#define NFC_V3_CONFIG2_2CMD_PHASES (1 << 4)
113#define NFC_V3_CONFIG2_NUM_ADDR_PHASE0 (1 << 5)
114#define NFC_V3_CONFIG2_ECC_MODE_8 (1 << 6)
115#define NFC_V3_CONFIG2_PPB(x) (((x) & 0x3) << 7)
116#define NFC_V3_CONFIG2_NUM_ADDR_PHASE1(x) (((x) & 0x3) << 12)
117#define NFC_V3_CONFIG2_INT_MSK (1 << 15)
118#define NFC_V3_CONFIG2_ST_CMD(x) (((x) & 0xff) << 24)
119#define NFC_V3_CONFIG2_SPAS(x) (((x) & 0xff) << 16)
120
121#define NFC_V3_CONFIG3 (host->regs_ip + 0x28)
122#define NFC_V3_CONFIG3_ADD_OP(x) (((x) & 0x3) << 0)
123#define NFC_V3_CONFIG3_FW8 (1 << 3)
124#define NFC_V3_CONFIG3_SBB(x) (((x) & 0x7) << 8)
125#define NFC_V3_CONFIG3_NUM_OF_DEVICES(x) (((x) & 0x7) << 12)
126#define NFC_V3_CONFIG3_RBB_MODE (1 << 15)
127#define NFC_V3_CONFIG3_NO_SDMA (1 << 20)
128
129#define NFC_V3_IPC (host->regs_ip + 0x2C)
130#define NFC_V3_IPC_CREQ (1 << 0)
131#define NFC_V3_IPC_INT (1 << 31)
132
133#define NFC_V3_DELAY_LINE (host->regs_ip + 0x34)
Sascha Hauer34f6e152008-09-02 17:16:59 +0200134
135struct mxc_nand_host {
136 struct mtd_info mtd;
137 struct nand_chip nand;
138 struct mtd_partition *parts;
139 struct device *dev;
140
Sascha Hauerc6de7e12009-10-05 11:14:35 +0200141 void *spare0;
142 void *main_area0;
Sascha Hauerc6de7e12009-10-05 11:14:35 +0200143
144 void __iomem *base;
Sascha Hauer34f6e152008-09-02 17:16:59 +0200145 void __iomem *regs;
Sascha Hauer71ec5152010-08-06 15:53:11 +0200146 void __iomem *regs_axi;
147 void __iomem *regs_ip;
Sascha Hauer34f6e152008-09-02 17:16:59 +0200148 int status_request;
Sascha Hauer34f6e152008-09-02 17:16:59 +0200149 struct clk *clk;
150 int clk_act;
151 int irq;
Sascha Hauer94f77e52010-08-06 15:53:09 +0200152 int eccsize;
Sascha Hauer34f6e152008-09-02 17:16:59 +0200153
154 wait_queue_head_t irq_waitq;
Sascha Hauerf8f96082009-06-04 17:12:26 +0200155
156 uint8_t *data_buf;
157 unsigned int buf_start;
158 int spare_len;
Sascha Hauer5f973042010-08-06 15:53:06 +0200159
160 void (*preset)(struct mtd_info *);
161 void (*send_cmd)(struct mxc_nand_host *, uint16_t, int);
162 void (*send_addr)(struct mxc_nand_host *, uint16_t, int);
163 void (*send_page)(struct mtd_info *, unsigned int);
164 void (*send_read_id)(struct mxc_nand_host *);
165 uint16_t (*get_dev_status)(struct mxc_nand_host *);
Sascha Hauer7aaf28a2010-08-06 15:53:07 +0200166 int (*check_int)(struct mxc_nand_host *);
Sascha Hauer34f6e152008-09-02 17:16:59 +0200167};
168
Sascha Hauer34f6e152008-09-02 17:16:59 +0200169/* OOB placement block for use with hardware ecc generation */
Sascha Hauer94671142009-10-05 12:14:21 +0200170static struct nand_ecclayout nandv1_hw_eccoob_smallpage = {
Sascha Hauer34f6e152008-09-02 17:16:59 +0200171 .eccbytes = 5,
172 .eccpos = {6, 7, 8, 9, 10},
Sascha Hauer8c1fd892009-10-21 10:22:01 +0200173 .oobfree = {{0, 5}, {12, 4}, }
Sascha Hauer34f6e152008-09-02 17:16:59 +0200174};
175
Sascha Hauer94671142009-10-05 12:14:21 +0200176static struct nand_ecclayout nandv1_hw_eccoob_largepage = {
Vladimir Barinovbd3fd622009-05-25 13:06:17 +0400177 .eccbytes = 20,
178 .eccpos = {6, 7, 8, 9, 10, 22, 23, 24, 25, 26,
179 38, 39, 40, 41, 42, 54, 55, 56, 57, 58},
180 .oobfree = {{2, 4}, {11, 10}, {27, 10}, {43, 10}, {59, 5}, }
Sascha Hauer34f6e152008-09-02 17:16:59 +0200181};
182
Sascha Hauer94671142009-10-05 12:14:21 +0200183/* OOB description for 512 byte pages with 16 byte OOB */
184static struct nand_ecclayout nandv2_hw_eccoob_smallpage = {
185 .eccbytes = 1 * 9,
186 .eccpos = {
187 7, 8, 9, 10, 11, 12, 13, 14, 15
188 },
189 .oobfree = {
190 {.offset = 0, .length = 5}
191 }
192};
193
194/* OOB description for 2048 byte pages with 64 byte OOB */
195static struct nand_ecclayout nandv2_hw_eccoob_largepage = {
196 .eccbytes = 4 * 9,
197 .eccpos = {
198 7, 8, 9, 10, 11, 12, 13, 14, 15,
199 23, 24, 25, 26, 27, 28, 29, 30, 31,
200 39, 40, 41, 42, 43, 44, 45, 46, 47,
201 55, 56, 57, 58, 59, 60, 61, 62, 63
202 },
203 .oobfree = {
204 {.offset = 2, .length = 4},
205 {.offset = 16, .length = 7},
206 {.offset = 32, .length = 7},
207 {.offset = 48, .length = 7}
208 }
209};
210
Sascha Hauer34f6e152008-09-02 17:16:59 +0200211#ifdef CONFIG_MTD_PARTITIONS
212static const char *part_probes[] = { "RedBoot", "cmdlinepart", NULL };
213#endif
214
215static irqreturn_t mxc_nfc_irq(int irq, void *dev_id)
216{
217 struct mxc_nand_host *host = dev_id;
218
Ivo Claryssea47bfd22010-04-08 16:16:51 +0200219 disable_irq_nosync(irq);
Sascha Hauer34f6e152008-09-02 17:16:59 +0200220
221 wake_up(&host->irq_waitq);
222
223 return IRQ_HANDLED;
224}
225
Sascha Hauer71ec5152010-08-06 15:53:11 +0200226static int check_int_v3(struct mxc_nand_host *host)
227{
228 uint32_t tmp;
229
230 tmp = readl(NFC_V3_IPC);
231 if (!(tmp & NFC_V3_IPC_INT))
232 return 0;
233
234 tmp &= ~NFC_V3_IPC_INT;
235 writel(tmp, NFC_V3_IPC);
236
237 return 1;
238}
239
Sascha Hauer7aaf28a2010-08-06 15:53:07 +0200240static int check_int_v1_v2(struct mxc_nand_host *host)
241{
242 uint32_t tmp;
243
Sascha Hauer1bc99182010-08-06 15:53:08 +0200244 tmp = readw(NFC_V1_V2_CONFIG2);
245 if (!(tmp & NFC_V1_V2_CONFIG2_INT))
Sascha Hauer7aaf28a2010-08-06 15:53:07 +0200246 return 0;
247
Sascha Hauer1bc99182010-08-06 15:53:08 +0200248 writew(tmp & ~NFC_V1_V2_CONFIG2_INT, NFC_V1_V2_CONFIG2);
Sascha Hauer7aaf28a2010-08-06 15:53:07 +0200249
250 return 1;
251}
252
Sascha Hauer34f6e152008-09-02 17:16:59 +0200253/* This function polls the NANDFC to wait for the basic operation to
254 * complete by checking the INT bit of config2 register.
255 */
Sascha Hauerc110eaf2009-10-21 16:01:02 +0200256static void wait_op_done(struct mxc_nand_host *host, int useirq)
Sascha Hauer34f6e152008-09-02 17:16:59 +0200257{
Ivo Claryssea47bfd22010-04-08 16:16:51 +0200258 int max_retries = 8000;
Sascha Hauer34f6e152008-09-02 17:16:59 +0200259
260 if (useirq) {
Sascha Hauer7aaf28a2010-08-06 15:53:07 +0200261 if (!host->check_int(host)) {
Sascha Hauer34f6e152008-09-02 17:16:59 +0200262
Ivo Claryssea47bfd22010-04-08 16:16:51 +0200263 enable_irq(host->irq);
Sascha Hauer34f6e152008-09-02 17:16:59 +0200264
Sascha Hauer7aaf28a2010-08-06 15:53:07 +0200265 wait_event(host->irq_waitq, host->check_int(host));
Sascha Hauer34f6e152008-09-02 17:16:59 +0200266 }
267 } else {
268 while (max_retries-- > 0) {
Sascha Hauer7aaf28a2010-08-06 15:53:07 +0200269 if (host->check_int(host))
Sascha Hauer34f6e152008-09-02 17:16:59 +0200270 break;
Sascha Hauer7aaf28a2010-08-06 15:53:07 +0200271
Sascha Hauer34f6e152008-09-02 17:16:59 +0200272 udelay(1);
273 }
Roel Kluin43950a62009-06-04 16:24:59 +0200274 if (max_retries < 0)
Sascha Hauer62465492009-06-04 15:57:20 +0200275 DEBUG(MTD_DEBUG_LEVEL0, "%s: INT not set\n",
276 __func__);
Sascha Hauer34f6e152008-09-02 17:16:59 +0200277 }
278}
279
Sascha Hauer71ec5152010-08-06 15:53:11 +0200280static void send_cmd_v3(struct mxc_nand_host *host, uint16_t cmd, int useirq)
281{
282 /* fill command */
283 writel(cmd, NFC_V3_FLASH_CMD);
284
285 /* send out command */
286 writel(NFC_CMD, NFC_V3_LAUNCH);
287
288 /* Wait for operation to complete */
289 wait_op_done(host, useirq);
290}
291
Sascha Hauer34f6e152008-09-02 17:16:59 +0200292/* This function issues the specified command to the NAND device and
293 * waits for completion. */
Sascha Hauer5f973042010-08-06 15:53:06 +0200294static void send_cmd_v1_v2(struct mxc_nand_host *host, uint16_t cmd, int useirq)
Sascha Hauer34f6e152008-09-02 17:16:59 +0200295{
296 DEBUG(MTD_DEBUG_LEVEL3, "send_cmd(host, 0x%x, %d)\n", cmd, useirq);
297
Sascha Hauer1bc99182010-08-06 15:53:08 +0200298 writew(cmd, NFC_V1_V2_FLASH_CMD);
299 writew(NFC_CMD, NFC_V1_V2_CONFIG2);
Sascha Hauer34f6e152008-09-02 17:16:59 +0200300
Ivo Claryssea47bfd22010-04-08 16:16:51 +0200301 if (cpu_is_mx21() && (cmd == NAND_CMD_RESET)) {
302 int max_retries = 100;
303 /* Reset completion is indicated by NFC_CONFIG2 */
304 /* being set to 0 */
305 while (max_retries-- > 0) {
Sascha Hauer1bc99182010-08-06 15:53:08 +0200306 if (readw(NFC_V1_V2_CONFIG2) == 0) {
Ivo Claryssea47bfd22010-04-08 16:16:51 +0200307 break;
308 }
309 udelay(1);
310 }
311 if (max_retries < 0)
312 DEBUG(MTD_DEBUG_LEVEL0, "%s: RESET failed\n",
313 __func__);
314 } else {
315 /* Wait for operation to complete */
316 wait_op_done(host, useirq);
317 }
Sascha Hauer34f6e152008-09-02 17:16:59 +0200318}
319
Sascha Hauer71ec5152010-08-06 15:53:11 +0200320static void send_addr_v3(struct mxc_nand_host *host, uint16_t addr, int islast)
321{
322 /* fill address */
323 writel(addr, NFC_V3_FLASH_ADDR0);
324
325 /* send out address */
326 writel(NFC_ADDR, NFC_V3_LAUNCH);
327
328 wait_op_done(host, 0);
329}
330
Sascha Hauer34f6e152008-09-02 17:16:59 +0200331/* This function sends an address (or partial address) to the
332 * NAND device. The address is used to select the source/destination for
333 * a NAND command. */
Sascha Hauer5f973042010-08-06 15:53:06 +0200334static void send_addr_v1_v2(struct mxc_nand_host *host, uint16_t addr, int islast)
Sascha Hauer34f6e152008-09-02 17:16:59 +0200335{
336 DEBUG(MTD_DEBUG_LEVEL3, "send_addr(host, 0x%x %d)\n", addr, islast);
337
Sascha Hauer1bc99182010-08-06 15:53:08 +0200338 writew(addr, NFC_V1_V2_FLASH_ADDR);
339 writew(NFC_ADDR, NFC_V1_V2_CONFIG2);
Sascha Hauer34f6e152008-09-02 17:16:59 +0200340
341 /* Wait for operation to complete */
Sascha Hauerc110eaf2009-10-21 16:01:02 +0200342 wait_op_done(host, islast);
Sascha Hauer34f6e152008-09-02 17:16:59 +0200343}
344
Sascha Hauer71ec5152010-08-06 15:53:11 +0200345static void send_page_v3(struct mtd_info *mtd, unsigned int ops)
346{
347 struct nand_chip *nand_chip = mtd->priv;
348 struct mxc_nand_host *host = nand_chip->priv;
349 uint32_t tmp;
350
351 tmp = readl(NFC_V3_CONFIG1);
352 tmp &= ~(7 << 4);
353 writel(tmp, NFC_V3_CONFIG1);
354
355 /* transfer data from NFC ram to nand */
356 writel(ops, NFC_V3_LAUNCH);
357
358 wait_op_done(host, false);
359}
360
Sascha Hauer5f973042010-08-06 15:53:06 +0200361static void send_page_v1_v2(struct mtd_info *mtd, unsigned int ops)
Sascha Hauer34f6e152008-09-02 17:16:59 +0200362{
Sascha Hauer2d69c7f2009-10-05 11:24:02 +0200363 struct nand_chip *nand_chip = mtd->priv;
364 struct mxc_nand_host *host = nand_chip->priv;
Sascha Hauerc5d23f12009-06-04 17:25:53 +0200365 int bufs, i;
Sascha Hauer34f6e152008-09-02 17:16:59 +0200366
Sascha Hauer94671142009-10-05 12:14:21 +0200367 if (nfc_is_v1() && mtd->writesize > 512)
Sascha Hauerc5d23f12009-06-04 17:25:53 +0200368 bufs = 4;
369 else
370 bufs = 1;
Sascha Hauer34f6e152008-09-02 17:16:59 +0200371
Sascha Hauerc5d23f12009-06-04 17:25:53 +0200372 for (i = 0; i < bufs; i++) {
373
374 /* NANDFC buffer 0 is used for page read/write */
Sascha Hauer1bc99182010-08-06 15:53:08 +0200375 writew(i, NFC_V1_V2_BUF_ADDR);
Sascha Hauerc5d23f12009-06-04 17:25:53 +0200376
Sascha Hauer1bc99182010-08-06 15:53:08 +0200377 writew(ops, NFC_V1_V2_CONFIG2);
Sascha Hauerc5d23f12009-06-04 17:25:53 +0200378
379 /* Wait for operation to complete */
Sascha Hauerc110eaf2009-10-21 16:01:02 +0200380 wait_op_done(host, true);
Sascha Hauer34f6e152008-09-02 17:16:59 +0200381 }
Sascha Hauer34f6e152008-09-02 17:16:59 +0200382}
383
Sascha Hauer71ec5152010-08-06 15:53:11 +0200384static void send_read_id_v3(struct mxc_nand_host *host)
385{
386 /* Read ID into main buffer */
387 writel(NFC_ID, NFC_V3_LAUNCH);
388
389 wait_op_done(host, true);
390
391 memcpy(host->data_buf, host->main_area0, 16);
392}
393
Sascha Hauer34f6e152008-09-02 17:16:59 +0200394/* Request the NANDFC to perform a read of the NAND device ID. */
Sascha Hauer5f973042010-08-06 15:53:06 +0200395static void send_read_id_v1_v2(struct mxc_nand_host *host)
Sascha Hauer34f6e152008-09-02 17:16:59 +0200396{
397 struct nand_chip *this = &host->nand;
Sascha Hauer34f6e152008-09-02 17:16:59 +0200398
399 /* NANDFC buffer 0 is used for device ID output */
Sascha Hauer1bc99182010-08-06 15:53:08 +0200400 writew(0x0, NFC_V1_V2_BUF_ADDR);
Sascha Hauer34f6e152008-09-02 17:16:59 +0200401
Sascha Hauer1bc99182010-08-06 15:53:08 +0200402 writew(NFC_ID, NFC_V1_V2_CONFIG2);
Sascha Hauer34f6e152008-09-02 17:16:59 +0200403
404 /* Wait for operation to complete */
Sascha Hauerc110eaf2009-10-21 16:01:02 +0200405 wait_op_done(host, true);
Sascha Hauer34f6e152008-09-02 17:16:59 +0200406
Sascha Hauerc6de7e12009-10-05 11:14:35 +0200407 memcpy(host->data_buf, host->main_area0, 16);
John Ognessf7b66e52010-06-18 18:59:47 +0200408
409 if (this->options & NAND_BUSWIDTH_16) {
410 /* compress the ID info */
411 host->data_buf[1] = host->data_buf[2];
412 host->data_buf[2] = host->data_buf[4];
413 host->data_buf[3] = host->data_buf[6];
414 host->data_buf[4] = host->data_buf[8];
415 host->data_buf[5] = host->data_buf[10];
416 }
Sascha Hauer34f6e152008-09-02 17:16:59 +0200417}
418
Sascha Hauer71ec5152010-08-06 15:53:11 +0200419static uint16_t get_dev_status_v3(struct mxc_nand_host *host)
Sascha Hauer34f6e152008-09-02 17:16:59 +0200420{
Sascha Hauer71ec5152010-08-06 15:53:11 +0200421 writew(NFC_STATUS, NFC_V3_LAUNCH);
Sascha Hauerc110eaf2009-10-21 16:01:02 +0200422 wait_op_done(host, true);
Sascha Hauer34f6e152008-09-02 17:16:59 +0200423
Sascha Hauer71ec5152010-08-06 15:53:11 +0200424 return readl(NFC_V3_CONFIG1) >> 16;
425}
426
Sascha Hauer34f6e152008-09-02 17:16:59 +0200427/* This function requests the NANDFC to perform a read of the
428 * NAND device status and returns the current status. */
Sascha Hauer5f973042010-08-06 15:53:06 +0200429static uint16_t get_dev_status_v1_v2(struct mxc_nand_host *host)
Sascha Hauer34f6e152008-09-02 17:16:59 +0200430{
Sascha Hauerc29c6072010-08-06 15:53:05 +0200431 void __iomem *main_buf = host->main_area0;
Sascha Hauer34f6e152008-09-02 17:16:59 +0200432 uint32_t store;
433 uint16_t ret;
Sascha Hauer34f6e152008-09-02 17:16:59 +0200434
Sascha Hauerc29c6072010-08-06 15:53:05 +0200435 writew(0x0, NFC_V1_V2_BUF_ADDR);
436
437 /*
438 * The device status is stored in main_area0. To
439 * prevent corruption of the buffer save the value
440 * and restore it afterwards.
441 */
Sascha Hauer34f6e152008-09-02 17:16:59 +0200442 store = readl(main_buf);
Sascha Hauer34f6e152008-09-02 17:16:59 +0200443
Sascha Hauer1bc99182010-08-06 15:53:08 +0200444 writew(NFC_STATUS, NFC_V1_V2_CONFIG2);
Sascha Hauer34f6e152008-09-02 17:16:59 +0200445 wait_op_done(host, true);
446
Sascha Hauer34f6e152008-09-02 17:16:59 +0200447 ret = readw(main_buf);
Sascha Hauerc29c6072010-08-06 15:53:05 +0200448
Sascha Hauer34f6e152008-09-02 17:16:59 +0200449 writel(store, main_buf);
450
451 return ret;
452}
453
454/* This functions is used by upper layer to checks if device is ready */
455static int mxc_nand_dev_ready(struct mtd_info *mtd)
456{
457 /*
458 * NFC handles R/B internally. Therefore, this function
459 * always returns status as ready.
460 */
461 return 1;
462}
463
464static void mxc_nand_enable_hwecc(struct mtd_info *mtd, int mode)
465{
466 /*
467 * If HW ECC is enabled, we turn it on during init. There is
468 * no need to enable again here.
469 */
470}
471
Sascha Hauer94f77e52010-08-06 15:53:09 +0200472static int mxc_nand_correct_data_v1(struct mtd_info *mtd, u_char *dat,
Sascha Hauer34f6e152008-09-02 17:16:59 +0200473 u_char *read_ecc, u_char *calc_ecc)
474{
475 struct nand_chip *nand_chip = mtd->priv;
476 struct mxc_nand_host *host = nand_chip->priv;
477
478 /*
479 * 1-Bit errors are automatically corrected in HW. No need for
480 * additional correction. 2-Bit errors cannot be corrected by
481 * HW ECC, so we need to return failure
482 */
Sascha Hauer1bc99182010-08-06 15:53:08 +0200483 uint16_t ecc_status = readw(NFC_V1_V2_ECC_STATUS_RESULT);
Sascha Hauer34f6e152008-09-02 17:16:59 +0200484
485 if (((ecc_status & 0x3) == 2) || ((ecc_status >> 2) == 2)) {
486 DEBUG(MTD_DEBUG_LEVEL0,
487 "MXC_NAND: HWECC uncorrectable 2-bit ECC error\n");
488 return -1;
489 }
490
491 return 0;
492}
493
Sascha Hauer94f77e52010-08-06 15:53:09 +0200494static int mxc_nand_correct_data_v2_v3(struct mtd_info *mtd, u_char *dat,
495 u_char *read_ecc, u_char *calc_ecc)
496{
497 struct nand_chip *nand_chip = mtd->priv;
498 struct mxc_nand_host *host = nand_chip->priv;
499 u32 ecc_stat, err;
500 int no_subpages = 1;
501 int ret = 0;
502 u8 ecc_bit_mask, err_limit;
503
504 ecc_bit_mask = (host->eccsize == 4) ? 0x7 : 0xf;
505 err_limit = (host->eccsize == 4) ? 0x4 : 0x8;
506
507 no_subpages = mtd->writesize >> 9;
508
Sascha Hauer71ec5152010-08-06 15:53:11 +0200509 if (nfc_is_v21())
510 ecc_stat = readl(NFC_V1_V2_ECC_STATUS_RESULT);
511 else
512 ecc_stat = readl(NFC_V3_ECC_STATUS_RESULT);
Sascha Hauer94f77e52010-08-06 15:53:09 +0200513
514 do {
515 err = ecc_stat & ecc_bit_mask;
516 if (err > err_limit) {
517 printk(KERN_WARNING "UnCorrectable RS-ECC Error\n");
518 return -1;
519 } else {
520 ret += err;
521 }
522 ecc_stat >>= 4;
523 } while (--no_subpages);
524
525 mtd->ecc_stats.corrected += ret;
526 pr_debug("%d Symbol Correctable RS-ECC Error\n", ret);
527
528 return ret;
529}
530
Sascha Hauer34f6e152008-09-02 17:16:59 +0200531static int mxc_nand_calculate_ecc(struct mtd_info *mtd, const u_char *dat,
532 u_char *ecc_code)
533{
534 return 0;
535}
536
537static u_char mxc_nand_read_byte(struct mtd_info *mtd)
538{
539 struct nand_chip *nand_chip = mtd->priv;
540 struct mxc_nand_host *host = nand_chip->priv;
Sascha Hauerf8f96082009-06-04 17:12:26 +0200541 uint8_t ret;
Sascha Hauer34f6e152008-09-02 17:16:59 +0200542
543 /* Check for status request */
544 if (host->status_request)
Sascha Hauer5f973042010-08-06 15:53:06 +0200545 return host->get_dev_status(host) & 0xFF;
Sascha Hauer34f6e152008-09-02 17:16:59 +0200546
Sascha Hauerf8f96082009-06-04 17:12:26 +0200547 ret = *(uint8_t *)(host->data_buf + host->buf_start);
548 host->buf_start++;
Sascha Hauer34f6e152008-09-02 17:16:59 +0200549
550 return ret;
551}
552
553static uint16_t mxc_nand_read_word(struct mtd_info *mtd)
554{
555 struct nand_chip *nand_chip = mtd->priv;
556 struct mxc_nand_host *host = nand_chip->priv;
Sascha Hauerf8f96082009-06-04 17:12:26 +0200557 uint16_t ret;
Sascha Hauer34f6e152008-09-02 17:16:59 +0200558
Sascha Hauerf8f96082009-06-04 17:12:26 +0200559 ret = *(uint16_t *)(host->data_buf + host->buf_start);
560 host->buf_start += 2;
Sascha Hauer34f6e152008-09-02 17:16:59 +0200561
562 return ret;
563}
564
565/* Write data of length len to buffer buf. The data to be
566 * written on NAND Flash is first copied to RAMbuffer. After the Data Input
567 * Operation by the NFC, the data is written to NAND Flash */
568static void mxc_nand_write_buf(struct mtd_info *mtd,
569 const u_char *buf, int len)
570{
571 struct nand_chip *nand_chip = mtd->priv;
572 struct mxc_nand_host *host = nand_chip->priv;
Sascha Hauerf8f96082009-06-04 17:12:26 +0200573 u16 col = host->buf_start;
574 int n = mtd->oobsize + mtd->writesize - col;
Sascha Hauer34f6e152008-09-02 17:16:59 +0200575
Sascha Hauerf8f96082009-06-04 17:12:26 +0200576 n = min(n, len);
Sascha Hauer34f6e152008-09-02 17:16:59 +0200577
Sascha Hauerf8f96082009-06-04 17:12:26 +0200578 memcpy(host->data_buf + col, buf, n);
Sascha Hauer34f6e152008-09-02 17:16:59 +0200579
Sascha Hauerf8f96082009-06-04 17:12:26 +0200580 host->buf_start += n;
Sascha Hauer34f6e152008-09-02 17:16:59 +0200581}
582
583/* Read the data buffer from the NAND Flash. To read the data from NAND
584 * Flash first the data output cycle is initiated by the NFC, which copies
585 * the data to RAMbuffer. This data of length len is then copied to buffer buf.
586 */
587static void mxc_nand_read_buf(struct mtd_info *mtd, u_char *buf, int len)
588{
589 struct nand_chip *nand_chip = mtd->priv;
590 struct mxc_nand_host *host = nand_chip->priv;
Sascha Hauerf8f96082009-06-04 17:12:26 +0200591 u16 col = host->buf_start;
592 int n = mtd->oobsize + mtd->writesize - col;
Sascha Hauer34f6e152008-09-02 17:16:59 +0200593
Sascha Hauerf8f96082009-06-04 17:12:26 +0200594 n = min(n, len);
Sascha Hauer34f6e152008-09-02 17:16:59 +0200595
Sascha Hauerf8f96082009-06-04 17:12:26 +0200596 memcpy(buf, host->data_buf + col, len);
Sascha Hauer34f6e152008-09-02 17:16:59 +0200597
Sascha Hauerf8f96082009-06-04 17:12:26 +0200598 host->buf_start += len;
Sascha Hauer34f6e152008-09-02 17:16:59 +0200599}
600
601/* Used by the upper layer to verify the data in NAND Flash
602 * with the data in the buf. */
603static int mxc_nand_verify_buf(struct mtd_info *mtd,
604 const u_char *buf, int len)
605{
606 return -EFAULT;
607}
608
609/* This function is used by upper layer for select and
610 * deselect of the NAND chip */
611static void mxc_nand_select_chip(struct mtd_info *mtd, int chip)
612{
613 struct nand_chip *nand_chip = mtd->priv;
614 struct mxc_nand_host *host = nand_chip->priv;
615
Sascha Hauer34f6e152008-09-02 17:16:59 +0200616 switch (chip) {
617 case -1:
618 /* Disable the NFC clock */
619 if (host->clk_act) {
620 clk_disable(host->clk);
621 host->clk_act = 0;
622 }
623 break;
624 case 0:
625 /* Enable the NFC clock */
626 if (!host->clk_act) {
627 clk_enable(host->clk);
628 host->clk_act = 1;
629 }
630 break;
631
632 default:
633 break;
634 }
635}
636
Sascha Hauerf8f96082009-06-04 17:12:26 +0200637/*
638 * Function to transfer data to/from spare area.
639 */
640static void copy_spare(struct mtd_info *mtd, bool bfrom)
641{
642 struct nand_chip *this = mtd->priv;
643 struct mxc_nand_host *host = this->priv;
644 u16 i, j;
645 u16 n = mtd->writesize >> 9;
646 u8 *d = host->data_buf + mtd->writesize;
Sascha Hauerc6de7e12009-10-05 11:14:35 +0200647 u8 *s = host->spare0;
Sascha Hauerf8f96082009-06-04 17:12:26 +0200648 u16 t = host->spare_len;
649
650 j = (mtd->oobsize / n >> 1) << 1;
651
652 if (bfrom) {
653 for (i = 0; i < n - 1; i++)
654 memcpy(d + i * j, s + i * t, j);
655
656 /* the last section */
657 memcpy(d + i * j, s + i * t, mtd->oobsize - i * j);
658 } else {
659 for (i = 0; i < n - 1; i++)
660 memcpy(&s[i * t], &d[i * j], j);
661
662 /* the last section */
663 memcpy(&s[i * t], &d[i * j], mtd->oobsize - i * j);
664 }
665}
666
Sascha Hauera3e65b62009-06-02 11:47:59 +0200667static void mxc_do_addr_cycle(struct mtd_info *mtd, int column, int page_addr)
Sascha Hauer34f6e152008-09-02 17:16:59 +0200668{
669 struct nand_chip *nand_chip = mtd->priv;
670 struct mxc_nand_host *host = nand_chip->priv;
Sascha Hauer34f6e152008-09-02 17:16:59 +0200671
672 /* Write out column address, if necessary */
673 if (column != -1) {
674 /*
675 * MXC NANDFC can only perform full page+spare or
676 * spare-only read/write. When the upper layers
677 * layers perform a read/write buf operation,
Daniel Mack3ad2f3f2010-02-03 08:01:28 +0800678 * we will used the saved column address to index into
Sascha Hauer34f6e152008-09-02 17:16:59 +0200679 * the full page.
680 */
Sascha Hauer5f973042010-08-06 15:53:06 +0200681 host->send_addr(host, 0, page_addr == -1);
Sascha Hauer2d69c7f2009-10-05 11:24:02 +0200682 if (mtd->writesize > 512)
Sascha Hauer34f6e152008-09-02 17:16:59 +0200683 /* another col addr cycle for 2k page */
Sascha Hauer5f973042010-08-06 15:53:06 +0200684 host->send_addr(host, 0, false);
Sascha Hauer34f6e152008-09-02 17:16:59 +0200685 }
686
687 /* Write out page address, if necessary */
688 if (page_addr != -1) {
689 /* paddr_0 - p_addr_7 */
Sascha Hauer5f973042010-08-06 15:53:06 +0200690 host->send_addr(host, (page_addr & 0xff), false);
Sascha Hauer34f6e152008-09-02 17:16:59 +0200691
Sascha Hauer2d69c7f2009-10-05 11:24:02 +0200692 if (mtd->writesize > 512) {
Vladimir Barinovbd3fd622009-05-25 13:06:17 +0400693 if (mtd->size >= 0x10000000) {
694 /* paddr_8 - paddr_15 */
Sascha Hauer5f973042010-08-06 15:53:06 +0200695 host->send_addr(host, (page_addr >> 8) & 0xff, false);
696 host->send_addr(host, (page_addr >> 16) & 0xff, true);
Vladimir Barinovbd3fd622009-05-25 13:06:17 +0400697 } else
698 /* paddr_8 - paddr_15 */
Sascha Hauer5f973042010-08-06 15:53:06 +0200699 host->send_addr(host, (page_addr >> 8) & 0xff, true);
Sascha Hauer34f6e152008-09-02 17:16:59 +0200700 } else {
701 /* One more address cycle for higher density devices */
702 if (mtd->size >= 0x4000000) {
703 /* paddr_8 - paddr_15 */
Sascha Hauer5f973042010-08-06 15:53:06 +0200704 host->send_addr(host, (page_addr >> 8) & 0xff, false);
705 host->send_addr(host, (page_addr >> 16) & 0xff, true);
Sascha Hauer34f6e152008-09-02 17:16:59 +0200706 } else
707 /* paddr_8 - paddr_15 */
Sascha Hauer5f973042010-08-06 15:53:06 +0200708 host->send_addr(host, (page_addr >> 8) & 0xff, true);
Sascha Hauer34f6e152008-09-02 17:16:59 +0200709 }
710 }
Sascha Hauera3e65b62009-06-02 11:47:59 +0200711}
Sascha Hauer34f6e152008-09-02 17:16:59 +0200712
Sascha Hauer6e85dfd2010-08-06 15:53:10 +0200713/*
714 * v2 and v3 type controllers can do 4bit or 8bit ecc depending
715 * on how much oob the nand chip has. For 8bit ecc we need at least
716 * 26 bytes of oob data per 512 byte block.
717 */
718static int get_eccsize(struct mtd_info *mtd)
719{
720 int oobbytes_per_512 = 0;
721
722 oobbytes_per_512 = mtd->oobsize * 512 / mtd->writesize;
723
724 if (oobbytes_per_512 < 26)
725 return 4;
726 else
727 return 8;
728}
729
Sascha Hauer5f973042010-08-06 15:53:06 +0200730static void preset_v1_v2(struct mtd_info *mtd)
Ivo Claryssed4840182010-04-08 16:14:44 +0200731{
732 struct nand_chip *nand_chip = mtd->priv;
733 struct mxc_nand_host *host = nand_chip->priv;
Sascha Hauerb8db2f52010-08-09 15:04:19 +0200734 uint16_t config1 = 0;
Ivo Claryssed4840182010-04-08 16:14:44 +0200735
Sascha Hauerb8db2f52010-08-09 15:04:19 +0200736 if (nand_chip->ecc.mode == NAND_ECC_HW)
737 config1 |= NFC_V1_V2_CONFIG1_ECC_EN;
738
739 if (nfc_is_v21())
740 config1 |= NFC_V2_CONFIG1_FP_INT;
741
742 if (!cpu_is_mx21())
743 config1 |= NFC_V1_V2_CONFIG1_INT_MSK;
Sascha Hauer6e85dfd2010-08-06 15:53:10 +0200744
745 if (nfc_is_v21() && mtd->writesize) {
Sascha Hauerb8db2f52010-08-09 15:04:19 +0200746 uint16_t pages_per_block = mtd->erasesize / mtd->writesize;
747
Sascha Hauer6e85dfd2010-08-06 15:53:10 +0200748 host->eccsize = get_eccsize(mtd);
749 if (host->eccsize == 4)
Sascha Hauerb8db2f52010-08-09 15:04:19 +0200750 config1 |= NFC_V2_CONFIG1_ECC_MODE_4;
751
752 config1 |= NFC_V2_CONFIG1_PPB(ffs(pages_per_block) - 6);
Sascha Hauer6e85dfd2010-08-06 15:53:10 +0200753 } else {
754 host->eccsize = 1;
755 }
756
Sascha Hauerb8db2f52010-08-09 15:04:19 +0200757 writew(config1, NFC_V1_V2_CONFIG1);
Ivo Claryssed4840182010-04-08 16:14:44 +0200758 /* preset operation */
759
760 /* Unlock the internal RAM Buffer */
Sascha Hauer1bc99182010-08-06 15:53:08 +0200761 writew(0x2, NFC_V1_V2_CONFIG);
Ivo Claryssed4840182010-04-08 16:14:44 +0200762
763 /* Blocks to be unlocked */
764 if (nfc_is_v21()) {
Sascha Hauer1bc99182010-08-06 15:53:08 +0200765 writew(0x0, NFC_V21_UNLOCKSTART_BLKADDR);
766 writew(0xffff, NFC_V21_UNLOCKEND_BLKADDR);
Ivo Claryssed4840182010-04-08 16:14:44 +0200767 } else if (nfc_is_v1()) {
Sascha Hauer1bc99182010-08-06 15:53:08 +0200768 writew(0x0, NFC_V1_UNLOCKSTART_BLKADDR);
769 writew(0x4000, NFC_V1_UNLOCKEND_BLKADDR);
Ivo Claryssed4840182010-04-08 16:14:44 +0200770 } else
771 BUG();
772
773 /* Unlock Block Command for given address range */
Sascha Hauer1bc99182010-08-06 15:53:08 +0200774 writew(0x4, NFC_V1_V2_WRPROT);
Ivo Claryssed4840182010-04-08 16:14:44 +0200775}
776
Sascha Hauer71ec5152010-08-06 15:53:11 +0200777static void preset_v3(struct mtd_info *mtd)
778{
779 struct nand_chip *chip = mtd->priv;
780 struct mxc_nand_host *host = chip->priv;
781 uint32_t config2, config3;
782 int i, addr_phases;
783
784 writel(NFC_V3_CONFIG1_RBA(0), NFC_V3_CONFIG1);
785 writel(NFC_V3_IPC_CREQ, NFC_V3_IPC);
786
787 /* Unlock the internal RAM Buffer */
788 writel(NFC_V3_WRPROT_BLS_UNLOCK | NFC_V3_WRPROT_UNLOCK,
789 NFC_V3_WRPROT);
790
791 /* Blocks to be unlocked */
792 for (i = 0; i < NAND_MAX_CHIPS; i++)
793 writel(0x0 | (0xffff << 16),
794 NFC_V3_WRPROT_UNLOCK_BLK_ADD0 + (i << 2));
795
796 writel(0, NFC_V3_IPC);
797
798 config2 = NFC_V3_CONFIG2_ONE_CYCLE |
799 NFC_V3_CONFIG2_2CMD_PHASES |
800 NFC_V3_CONFIG2_SPAS(mtd->oobsize >> 1) |
801 NFC_V3_CONFIG2_ST_CMD(0x70) |
802 NFC_V3_CONFIG2_NUM_ADDR_PHASE0;
803
804 if (chip->ecc.mode == NAND_ECC_HW)
805 config2 |= NFC_V3_CONFIG2_ECC_EN;
806
807 addr_phases = fls(chip->pagemask) >> 3;
808
809 if (mtd->writesize == 2048) {
810 config2 |= NFC_V3_CONFIG2_PS_2048;
811 config2 |= NFC_V3_CONFIG2_NUM_ADDR_PHASE1(addr_phases);
812 } else if (mtd->writesize == 4096) {
813 config2 |= NFC_V3_CONFIG2_PS_4096;
814 config2 |= NFC_V3_CONFIG2_NUM_ADDR_PHASE1(addr_phases);
815 } else {
816 config2 |= NFC_V3_CONFIG2_PS_512;
817 config2 |= NFC_V3_CONFIG2_NUM_ADDR_PHASE1(addr_phases - 1);
818 }
819
820 if (mtd->writesize) {
821 config2 |= NFC_V3_CONFIG2_PPB(ffs(mtd->erasesize / mtd->writesize) - 6);
822 host->eccsize = get_eccsize(mtd);
823 if (host->eccsize == 8)
824 config2 |= NFC_V3_CONFIG2_ECC_MODE_8;
825 }
826
827 writel(config2, NFC_V3_CONFIG2);
828
829 config3 = NFC_V3_CONFIG3_NUM_OF_DEVICES(0) |
830 NFC_V3_CONFIG3_NO_SDMA |
831 NFC_V3_CONFIG3_RBB_MODE |
832 NFC_V3_CONFIG3_SBB(6) | /* Reset default */
833 NFC_V3_CONFIG3_ADD_OP(0);
834
835 if (!(chip->options & NAND_BUSWIDTH_16))
836 config3 |= NFC_V3_CONFIG3_FW8;
837
838 writel(config3, NFC_V3_CONFIG3);
839
840 writel(0, NFC_V3_DELAY_LINE);
Sascha Hauer34f6e152008-09-02 17:16:59 +0200841}
842
Sascha Hauer34f6e152008-09-02 17:16:59 +0200843/* Used by the upper layer to write command to NAND Flash for
844 * different operations to be carried out on NAND Flash */
845static void mxc_nand_command(struct mtd_info *mtd, unsigned command,
846 int column, int page_addr)
847{
848 struct nand_chip *nand_chip = mtd->priv;
849 struct mxc_nand_host *host = nand_chip->priv;
Sascha Hauer34f6e152008-09-02 17:16:59 +0200850
851 DEBUG(MTD_DEBUG_LEVEL3,
852 "mxc_nand_command (cmd = 0x%x, col = 0x%x, page = 0x%x)\n",
853 command, column, page_addr);
854
855 /* Reset command state information */
856 host->status_request = false;
857
858 /* Command pre-processing step */
Sascha Hauer34f6e152008-09-02 17:16:59 +0200859 switch (command) {
Ivo Claryssed4840182010-04-08 16:14:44 +0200860 case NAND_CMD_RESET:
Sascha Hauer5f973042010-08-06 15:53:06 +0200861 host->preset(mtd);
862 host->send_cmd(host, command, false);
Ivo Claryssed4840182010-04-08 16:14:44 +0200863 break;
Sascha Hauer34f6e152008-09-02 17:16:59 +0200864
Sascha Hauer34f6e152008-09-02 17:16:59 +0200865 case NAND_CMD_STATUS:
Sascha Hauerf8f96082009-06-04 17:12:26 +0200866 host->buf_start = 0;
Sascha Hauer34f6e152008-09-02 17:16:59 +0200867 host->status_request = true;
Sascha Hauer89121a62009-06-04 17:18:01 +0200868
Sascha Hauer5f973042010-08-06 15:53:06 +0200869 host->send_cmd(host, command, true);
Sascha Hauer89121a62009-06-04 17:18:01 +0200870 mxc_do_addr_cycle(mtd, column, page_addr);
Sascha Hauer34f6e152008-09-02 17:16:59 +0200871 break;
872
Sascha Hauer34f6e152008-09-02 17:16:59 +0200873 case NAND_CMD_READ0:
Sascha Hauer34f6e152008-09-02 17:16:59 +0200874 case NAND_CMD_READOOB:
Sascha Hauer89121a62009-06-04 17:18:01 +0200875 if (command == NAND_CMD_READ0)
876 host->buf_start = column;
877 else
878 host->buf_start = column + mtd->writesize;
Sascha Hauerf8f96082009-06-04 17:12:26 +0200879
Sascha Hauer5ea32022010-04-27 15:24:01 +0200880 command = NAND_CMD_READ0; /* only READ0 is valid */
Sascha Hauer89121a62009-06-04 17:18:01 +0200881
Sascha Hauer5f973042010-08-06 15:53:06 +0200882 host->send_cmd(host, command, false);
Sascha Hauer89121a62009-06-04 17:18:01 +0200883 mxc_do_addr_cycle(mtd, column, page_addr);
884
Sascha Hauer2d69c7f2009-10-05 11:24:02 +0200885 if (mtd->writesize > 512)
Sascha Hauer5f973042010-08-06 15:53:06 +0200886 host->send_cmd(host, NAND_CMD_READSTART, true);
Sascha Hauerc5d23f12009-06-04 17:25:53 +0200887
Sascha Hauer5f973042010-08-06 15:53:06 +0200888 host->send_page(mtd, NFC_OUTPUT);
Sascha Hauer89121a62009-06-04 17:18:01 +0200889
Sascha Hauerc6de7e12009-10-05 11:14:35 +0200890 memcpy(host->data_buf, host->main_area0, mtd->writesize);
Sascha Hauer89121a62009-06-04 17:18:01 +0200891 copy_spare(mtd, true);
Sascha Hauer34f6e152008-09-02 17:16:59 +0200892 break;
893
Sascha Hauer34f6e152008-09-02 17:16:59 +0200894 case NAND_CMD_SEQIN:
Sascha Hauer5ea32022010-04-27 15:24:01 +0200895 if (column >= mtd->writesize)
896 /* call ourself to read a page */
897 mxc_nand_command(mtd, NAND_CMD_READ0, 0, page_addr);
Sascha Hauer34f6e152008-09-02 17:16:59 +0200898
Sascha Hauer5ea32022010-04-27 15:24:01 +0200899 host->buf_start = column;
Sascha Hauer89121a62009-06-04 17:18:01 +0200900
Sascha Hauer5f973042010-08-06 15:53:06 +0200901 host->send_cmd(host, command, false);
Sascha Hauer89121a62009-06-04 17:18:01 +0200902 mxc_do_addr_cycle(mtd, column, page_addr);
Sascha Hauer34f6e152008-09-02 17:16:59 +0200903 break;
904
905 case NAND_CMD_PAGEPROG:
Sascha Hauerc6de7e12009-10-05 11:14:35 +0200906 memcpy(host->main_area0, host->data_buf, mtd->writesize);
Sascha Hauerf8f96082009-06-04 17:12:26 +0200907 copy_spare(mtd, false);
Sascha Hauer5f973042010-08-06 15:53:06 +0200908 host->send_page(mtd, NFC_INPUT);
909 host->send_cmd(host, command, true);
Sascha Hauer89121a62009-06-04 17:18:01 +0200910 mxc_do_addr_cycle(mtd, column, page_addr);
Sascha Hauer34f6e152008-09-02 17:16:59 +0200911 break;
912
Sascha Hauer34f6e152008-09-02 17:16:59 +0200913 case NAND_CMD_READID:
Sascha Hauer5f973042010-08-06 15:53:06 +0200914 host->send_cmd(host, command, true);
Sascha Hauer89121a62009-06-04 17:18:01 +0200915 mxc_do_addr_cycle(mtd, column, page_addr);
Sascha Hauer5f973042010-08-06 15:53:06 +0200916 host->send_read_id(host);
Sascha Hauer94671142009-10-05 12:14:21 +0200917 host->buf_start = column;
Sascha Hauer34f6e152008-09-02 17:16:59 +0200918 break;
919
Sascha Hauer89121a62009-06-04 17:18:01 +0200920 case NAND_CMD_ERASE1:
Sascha Hauer34f6e152008-09-02 17:16:59 +0200921 case NAND_CMD_ERASE2:
Sascha Hauer5f973042010-08-06 15:53:06 +0200922 host->send_cmd(host, command, false);
Sascha Hauer89121a62009-06-04 17:18:01 +0200923 mxc_do_addr_cycle(mtd, column, page_addr);
924
Sascha Hauer34f6e152008-09-02 17:16:59 +0200925 break;
926 }
927}
928
Sascha Hauerf1372052009-10-21 14:25:27 +0200929/*
930 * The generic flash bbt decriptors overlap with our ecc
931 * hardware, so define some i.MX specific ones.
932 */
933static uint8_t bbt_pattern[] = { 'B', 'b', 't', '0' };
934static uint8_t mirror_pattern[] = { '1', 't', 'b', 'B' };
935
936static struct nand_bbt_descr bbt_main_descr = {
937 .options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE
938 | NAND_BBT_2BIT | NAND_BBT_VERSION | NAND_BBT_PERCHIP,
939 .offs = 0,
940 .len = 4,
941 .veroffs = 4,
942 .maxblocks = 4,
943 .pattern = bbt_pattern,
944};
945
946static struct nand_bbt_descr bbt_mirror_descr = {
947 .options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE
948 | NAND_BBT_2BIT | NAND_BBT_VERSION | NAND_BBT_PERCHIP,
949 .offs = 0,
950 .len = 4,
951 .veroffs = 4,
952 .maxblocks = 4,
953 .pattern = mirror_pattern,
954};
955
Sascha Hauer34f6e152008-09-02 17:16:59 +0200956static int __init mxcnd_probe(struct platform_device *pdev)
957{
958 struct nand_chip *this;
959 struct mtd_info *mtd;
960 struct mxc_nand_platform_data *pdata = pdev->dev.platform_data;
961 struct mxc_nand_host *host;
962 struct resource *res;
Sascha Hauer34f6e152008-09-02 17:16:59 +0200963 int err = 0, nr_parts = 0;
Sascha Hauer94671142009-10-05 12:14:21 +0200964 struct nand_ecclayout *oob_smallpage, *oob_largepage;
Sascha Hauer34f6e152008-09-02 17:16:59 +0200965
966 /* Allocate memory for MTD device structure and private data */
Sascha Hauerf8f96082009-06-04 17:12:26 +0200967 host = kzalloc(sizeof(struct mxc_nand_host) + NAND_MAX_PAGESIZE +
968 NAND_MAX_OOBSIZE, GFP_KERNEL);
Sascha Hauer34f6e152008-09-02 17:16:59 +0200969 if (!host)
970 return -ENOMEM;
971
Sascha Hauerf8f96082009-06-04 17:12:26 +0200972 host->data_buf = (uint8_t *)(host + 1);
Sascha Hauerf8f96082009-06-04 17:12:26 +0200973
Sascha Hauer34f6e152008-09-02 17:16:59 +0200974 host->dev = &pdev->dev;
975 /* structures must be linked */
976 this = &host->nand;
977 mtd = &host->mtd;
978 mtd->priv = this;
979 mtd->owner = THIS_MODULE;
David Brownell87f39f02009-03-26 00:42:50 -0700980 mtd->dev.parent = &pdev->dev;
Sascha Hauer1fbff0a2009-10-21 16:06:27 +0200981 mtd->name = DRIVER_NAME;
Sascha Hauer34f6e152008-09-02 17:16:59 +0200982
983 /* 50 us command delay time */
984 this->chip_delay = 5;
985
986 this->priv = host;
987 this->dev_ready = mxc_nand_dev_ready;
988 this->cmdfunc = mxc_nand_command;
989 this->select_chip = mxc_nand_select_chip;
990 this->read_byte = mxc_nand_read_byte;
991 this->read_word = mxc_nand_read_word;
992 this->write_buf = mxc_nand_write_buf;
993 this->read_buf = mxc_nand_read_buf;
994 this->verify_buf = mxc_nand_verify_buf;
995
Sascha Hauere65fb002009-02-16 14:29:10 +0100996 host->clk = clk_get(&pdev->dev, "nfc");
Vladimir Barinov8541c112009-04-23 15:47:22 +0400997 if (IS_ERR(host->clk)) {
998 err = PTR_ERR(host->clk);
Sascha Hauer34f6e152008-09-02 17:16:59 +0200999 goto eclk;
Vladimir Barinov8541c112009-04-23 15:47:22 +04001000 }
Sascha Hauer34f6e152008-09-02 17:16:59 +02001001
1002 clk_enable(host->clk);
1003 host->clk_act = 1;
1004
1005 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
1006 if (!res) {
1007 err = -ENODEV;
1008 goto eres;
1009 }
1010
Sascha Hauerc6de7e12009-10-05 11:14:35 +02001011 host->base = ioremap(res->start, resource_size(res));
1012 if (!host->base) {
Vladimir Barinov8541c112009-04-23 15:47:22 +04001013 err = -ENOMEM;
Sascha Hauer34f6e152008-09-02 17:16:59 +02001014 goto eres;
1015 }
1016
Sascha Hauerc6de7e12009-10-05 11:14:35 +02001017 host->main_area0 = host->base;
Sascha Hauer94671142009-10-05 12:14:21 +02001018
Sascha Hauer5f973042010-08-06 15:53:06 +02001019 if (nfc_is_v1() || nfc_is_v21()) {
1020 host->preset = preset_v1_v2;
1021 host->send_cmd = send_cmd_v1_v2;
1022 host->send_addr = send_addr_v1_v2;
1023 host->send_page = send_page_v1_v2;
1024 host->send_read_id = send_read_id_v1_v2;
1025 host->get_dev_status = get_dev_status_v1_v2;
Sascha Hauer7aaf28a2010-08-06 15:53:07 +02001026 host->check_int = check_int_v1_v2;
Sascha Hauer5f973042010-08-06 15:53:06 +02001027 }
Sascha Hauer94671142009-10-05 12:14:21 +02001028
1029 if (nfc_is_v21()) {
Sascha Hauer938cf992010-08-06 15:53:04 +02001030 host->regs = host->base + 0x1e00;
Sascha Hauer94671142009-10-05 12:14:21 +02001031 host->spare0 = host->base + 0x1000;
1032 host->spare_len = 64;
1033 oob_smallpage = &nandv2_hw_eccoob_smallpage;
1034 oob_largepage = &nandv2_hw_eccoob_largepage;
Ivo Claryssed4840182010-04-08 16:14:44 +02001035 this->ecc.bytes = 9;
Sascha Hauer94671142009-10-05 12:14:21 +02001036 } else if (nfc_is_v1()) {
Sascha Hauer938cf992010-08-06 15:53:04 +02001037 host->regs = host->base + 0xe00;
Sascha Hauer94671142009-10-05 12:14:21 +02001038 host->spare0 = host->base + 0x800;
1039 host->spare_len = 16;
1040 oob_smallpage = &nandv1_hw_eccoob_smallpage;
1041 oob_largepage = &nandv1_hw_eccoob_largepage;
Sascha Hauer94671142009-10-05 12:14:21 +02001042 this->ecc.bytes = 3;
Sascha Hauer71ec5152010-08-06 15:53:11 +02001043 host->eccsize = 1;
1044 } else if (nfc_is_v3_2()) {
1045 res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
1046 if (!res) {
1047 err = -ENODEV;
1048 goto eirq;
1049 }
1050 host->regs_ip = ioremap(res->start, resource_size(res));
1051 if (!host->regs_ip) {
1052 err = -ENOMEM;
1053 goto eirq;
1054 }
1055 host->regs_axi = host->base + 0x1e00;
1056 host->spare0 = host->base + 0x1000;
1057 host->spare_len = 64;
1058 host->preset = preset_v3;
1059 host->send_cmd = send_cmd_v3;
1060 host->send_addr = send_addr_v3;
1061 host->send_page = send_page_v3;
1062 host->send_read_id = send_read_id_v3;
1063 host->check_int = check_int_v3;
1064 host->get_dev_status = get_dev_status_v3;
1065 oob_smallpage = &nandv2_hw_eccoob_smallpage;
1066 oob_largepage = &nandv2_hw_eccoob_largepage;
Sascha Hauer94671142009-10-05 12:14:21 +02001067 } else
1068 BUG();
Sascha Hauer34f6e152008-09-02 17:16:59 +02001069
Sascha Hauer13e1add2009-10-21 10:39:05 +02001070 this->ecc.size = 512;
Sascha Hauer94671142009-10-05 12:14:21 +02001071 this->ecc.layout = oob_smallpage;
Sascha Hauer13e1add2009-10-21 10:39:05 +02001072
1073 if (pdata->hw_ecc) {
1074 this->ecc.calculate = mxc_nand_calculate_ecc;
1075 this->ecc.hwctl = mxc_nand_enable_hwecc;
Sascha Hauer94f77e52010-08-06 15:53:09 +02001076 if (nfc_is_v1())
1077 this->ecc.correct = mxc_nand_correct_data_v1;
1078 else
1079 this->ecc.correct = mxc_nand_correct_data_v2_v3;
Sascha Hauer13e1add2009-10-21 10:39:05 +02001080 this->ecc.mode = NAND_ECC_HW;
Sascha Hauer13e1add2009-10-21 10:39:05 +02001081 } else {
1082 this->ecc.mode = NAND_ECC_SOFT;
Sascha Hauer34f6e152008-09-02 17:16:59 +02001083 }
1084
Sascha Hauer34f6e152008-09-02 17:16:59 +02001085 /* NAND bus width determines access funtions used by upper layer */
Sascha Hauer13e1add2009-10-21 10:39:05 +02001086 if (pdata->width == 2)
Sascha Hauer34f6e152008-09-02 17:16:59 +02001087 this->options |= NAND_BUSWIDTH_16;
Sascha Hauer13e1add2009-10-21 10:39:05 +02001088
Sascha Hauerf1372052009-10-21 14:25:27 +02001089 if (pdata->flash_bbt) {
1090 this->bbt_td = &bbt_main_descr;
1091 this->bbt_md = &bbt_mirror_descr;
1092 /* update flash based bbt */
1093 this->options |= NAND_USE_FLASH_BBT;
Sascha Hauer34f6e152008-09-02 17:16:59 +02001094 }
1095
Ivo Claryssed4840182010-04-08 16:14:44 +02001096 init_waitqueue_head(&host->irq_waitq);
1097
1098 host->irq = platform_get_irq(pdev, 0);
1099
Ivo Claryssea47bfd22010-04-08 16:16:51 +02001100 err = request_irq(host->irq, mxc_nfc_irq, IRQF_DISABLED, DRIVER_NAME, host);
Ivo Claryssed4840182010-04-08 16:14:44 +02001101 if (err)
1102 goto eirq;
1103
Vladimir Barinovbd3fd622009-05-25 13:06:17 +04001104 /* first scan to find the device and get the page size */
David Woodhouse5e81e882010-02-26 18:32:56 +00001105 if (nand_scan_ident(mtd, 1, NULL)) {
Vladimir Barinovbd3fd622009-05-25 13:06:17 +04001106 err = -ENXIO;
1107 goto escan;
1108 }
Sascha Hauer34f6e152008-09-02 17:16:59 +02001109
Sascha Hauer6e85dfd2010-08-06 15:53:10 +02001110 /* Call preset again, with correct writesize this time */
1111 host->preset(mtd);
1112
Sascha Hauer2d69c7f2009-10-05 11:24:02 +02001113 if (mtd->writesize == 2048)
Sascha Hauer94671142009-10-05 12:14:21 +02001114 this->ecc.layout = oob_largepage;
Vladimir Barinovbd3fd622009-05-25 13:06:17 +04001115
1116 /* second phase scan */
1117 if (nand_scan_tail(mtd)) {
Sascha Hauer34f6e152008-09-02 17:16:59 +02001118 err = -ENXIO;
1119 goto escan;
1120 }
1121
1122 /* Register the partitions */
1123#ifdef CONFIG_MTD_PARTITIONS
1124 nr_parts =
1125 parse_mtd_partitions(mtd, part_probes, &host->parts, 0);
1126 if (nr_parts > 0)
1127 add_mtd_partitions(mtd, host->parts, nr_parts);
Baruch Siachcce02462010-05-31 08:49:40 +03001128 else if (pdata->parts)
1129 add_mtd_partitions(mtd, pdata->parts, pdata->nr_parts);
Sascha Hauer34f6e152008-09-02 17:16:59 +02001130 else
1131#endif
1132 {
1133 pr_info("Registering %s as whole device\n", mtd->name);
1134 add_mtd_device(mtd);
1135 }
1136
1137 platform_set_drvdata(pdev, host);
1138
1139 return 0;
1140
1141escan:
Magnus Liljab258fd82009-05-08 21:57:47 +02001142 free_irq(host->irq, host);
Sascha Hauer34f6e152008-09-02 17:16:59 +02001143eirq:
Sascha Hauer71ec5152010-08-06 15:53:11 +02001144 if (host->regs_ip)
1145 iounmap(host->regs_ip);
Sascha Hauerc6de7e12009-10-05 11:14:35 +02001146 iounmap(host->base);
Sascha Hauer34f6e152008-09-02 17:16:59 +02001147eres:
1148 clk_put(host->clk);
1149eclk:
1150 kfree(host);
1151
1152 return err;
1153}
1154
Uwe Kleine-König51eeb872009-12-07 09:44:05 +00001155static int __devexit mxcnd_remove(struct platform_device *pdev)
Sascha Hauer34f6e152008-09-02 17:16:59 +02001156{
1157 struct mxc_nand_host *host = platform_get_drvdata(pdev);
1158
1159 clk_put(host->clk);
1160
1161 platform_set_drvdata(pdev, NULL);
1162
1163 nand_release(&host->mtd);
Magnus Liljab258fd82009-05-08 21:57:47 +02001164 free_irq(host->irq, host);
Sascha Hauer71ec5152010-08-06 15:53:11 +02001165 if (host->regs_ip)
1166 iounmap(host->regs_ip);
Sascha Hauerc6de7e12009-10-05 11:14:35 +02001167 iounmap(host->base);
Sascha Hauer34f6e152008-09-02 17:16:59 +02001168 kfree(host);
1169
1170 return 0;
1171}
1172
Sascha Hauer34f6e152008-09-02 17:16:59 +02001173static struct platform_driver mxcnd_driver = {
1174 .driver = {
1175 .name = DRIVER_NAME,
Eric Bénard04dd0d32010-06-17 20:59:04 +02001176 },
Uwe Kleine-Königdaa0f152009-11-24 22:07:08 +01001177 .remove = __devexit_p(mxcnd_remove),
Sascha Hauer34f6e152008-09-02 17:16:59 +02001178};
1179
1180static int __init mxc_nd_init(void)
1181{
Vladimir Barinov8541c112009-04-23 15:47:22 +04001182 return platform_driver_probe(&mxcnd_driver, mxcnd_probe);
Sascha Hauer34f6e152008-09-02 17:16:59 +02001183}
1184
1185static void __exit mxc_nd_cleanup(void)
1186{
1187 /* Unregister the device structure */
1188 platform_driver_unregister(&mxcnd_driver);
1189}
1190
1191module_init(mxc_nd_init);
1192module_exit(mxc_nd_cleanup);
1193
1194MODULE_AUTHOR("Freescale Semiconductor, Inc.");
1195MODULE_DESCRIPTION("MXC NAND MTD driver");
1196MODULE_LICENSE("GPL");