blob: f5fd25461a09965c1f3e4bd6fe24b2639bb99fbd [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 Hauer94671142009-10-05 12:14:21 +020042
Sascha Hauer34f6e152008-09-02 17:16:59 +020043/* Addresses for NFC registers */
Sascha Hauer1bc99182010-08-06 15:53:08 +020044#define NFC_V1_V2_BUF_SIZE (host->regs + 0x00)
45#define NFC_V1_V2_BUF_ADDR (host->regs + 0x04)
46#define NFC_V1_V2_FLASH_ADDR (host->regs + 0x06)
47#define NFC_V1_V2_FLASH_CMD (host->regs + 0x08)
48#define NFC_V1_V2_CONFIG (host->regs + 0x0a)
49#define NFC_V1_V2_ECC_STATUS_RESULT (host->regs + 0x0c)
50#define NFC_V1_V2_RSLTMAIN_AREA (host->regs + 0x0e)
51#define NFC_V1_V2_RSLTSPARE_AREA (host->regs + 0x10)
52#define NFC_V1_V2_WRPROT (host->regs + 0x12)
53#define NFC_V1_UNLOCKSTART_BLKADDR (host->regs + 0x14)
54#define NFC_V1_UNLOCKEND_BLKADDR (host->regs + 0x16)
55#define NFC_V21_UNLOCKSTART_BLKADDR (host->regs + 0x20)
56#define NFC_V21_UNLOCKEND_BLKADDR (host->regs + 0x22)
57#define NFC_V1_V2_NF_WRPRST (host->regs + 0x18)
58#define NFC_V1_V2_CONFIG1 (host->regs + 0x1a)
59#define NFC_V1_V2_CONFIG2 (host->regs + 0x1c)
Sascha Hauer34f6e152008-09-02 17:16:59 +020060
Sascha Hauer1bc99182010-08-06 15:53:08 +020061#define NFC_V1_V2_CONFIG1_SP_EN (1 << 2)
62#define NFC_V1_V2_CONFIG1_ECC_EN (1 << 3)
63#define NFC_V1_V2_CONFIG1_INT_MSK (1 << 4)
64#define NFC_V1_V2_CONFIG1_BIG (1 << 5)
65#define NFC_V1_V2_CONFIG1_RST (1 << 6)
66#define NFC_V1_V2_CONFIG1_CE (1 << 7)
67#define NFC_V1_V2_CONFIG1_ONE_CYCLE (1 << 8)
Sascha Hauer34f6e152008-09-02 17:16:59 +020068
Sascha Hauer1bc99182010-08-06 15:53:08 +020069#define NFC_V1_V2_CONFIG2_INT (1 << 15)
Sascha Hauer34f6e152008-09-02 17:16:59 +020070
Sascha Hauer1bc99182010-08-06 15:53:08 +020071/*
72 * Operation modes for the NFC. Valid for v1, v2 and v3
73 * type controllers.
74 */
75#define NFC_CMD (1 << 0)
76#define NFC_ADDR (1 << 1)
77#define NFC_INPUT (1 << 2)
78#define NFC_OUTPUT (1 << 3)
79#define NFC_ID (1 << 4)
80#define NFC_STATUS (1 << 5)
Sascha Hauer34f6e152008-09-02 17:16:59 +020081
82struct mxc_nand_host {
83 struct mtd_info mtd;
84 struct nand_chip nand;
85 struct mtd_partition *parts;
86 struct device *dev;
87
Sascha Hauerc6de7e12009-10-05 11:14:35 +020088 void *spare0;
89 void *main_area0;
Sascha Hauerc6de7e12009-10-05 11:14:35 +020090
91 void __iomem *base;
Sascha Hauer34f6e152008-09-02 17:16:59 +020092 void __iomem *regs;
Sascha Hauer34f6e152008-09-02 17:16:59 +020093 int status_request;
Sascha Hauer34f6e152008-09-02 17:16:59 +020094 struct clk *clk;
95 int clk_act;
96 int irq;
Sascha Hauer94f77e52010-08-06 15:53:09 +020097 int eccsize;
Sascha Hauer34f6e152008-09-02 17:16:59 +020098
99 wait_queue_head_t irq_waitq;
Sascha Hauerf8f96082009-06-04 17:12:26 +0200100
101 uint8_t *data_buf;
102 unsigned int buf_start;
103 int spare_len;
Sascha Hauer5f973042010-08-06 15:53:06 +0200104
105 void (*preset)(struct mtd_info *);
106 void (*send_cmd)(struct mxc_nand_host *, uint16_t, int);
107 void (*send_addr)(struct mxc_nand_host *, uint16_t, int);
108 void (*send_page)(struct mtd_info *, unsigned int);
109 void (*send_read_id)(struct mxc_nand_host *);
110 uint16_t (*get_dev_status)(struct mxc_nand_host *);
Sascha Hauer7aaf28a2010-08-06 15:53:07 +0200111 int (*check_int)(struct mxc_nand_host *);
Sascha Hauer34f6e152008-09-02 17:16:59 +0200112};
113
Sascha Hauer34f6e152008-09-02 17:16:59 +0200114/* OOB placement block for use with hardware ecc generation */
Sascha Hauer94671142009-10-05 12:14:21 +0200115static struct nand_ecclayout nandv1_hw_eccoob_smallpage = {
Sascha Hauer34f6e152008-09-02 17:16:59 +0200116 .eccbytes = 5,
117 .eccpos = {6, 7, 8, 9, 10},
Sascha Hauer8c1fd892009-10-21 10:22:01 +0200118 .oobfree = {{0, 5}, {12, 4}, }
Sascha Hauer34f6e152008-09-02 17:16:59 +0200119};
120
Sascha Hauer94671142009-10-05 12:14:21 +0200121static struct nand_ecclayout nandv1_hw_eccoob_largepage = {
Vladimir Barinovbd3fd622009-05-25 13:06:17 +0400122 .eccbytes = 20,
123 .eccpos = {6, 7, 8, 9, 10, 22, 23, 24, 25, 26,
124 38, 39, 40, 41, 42, 54, 55, 56, 57, 58},
125 .oobfree = {{2, 4}, {11, 10}, {27, 10}, {43, 10}, {59, 5}, }
Sascha Hauer34f6e152008-09-02 17:16:59 +0200126};
127
Sascha Hauer94671142009-10-05 12:14:21 +0200128/* OOB description for 512 byte pages with 16 byte OOB */
129static struct nand_ecclayout nandv2_hw_eccoob_smallpage = {
130 .eccbytes = 1 * 9,
131 .eccpos = {
132 7, 8, 9, 10, 11, 12, 13, 14, 15
133 },
134 .oobfree = {
135 {.offset = 0, .length = 5}
136 }
137};
138
139/* OOB description for 2048 byte pages with 64 byte OOB */
140static struct nand_ecclayout nandv2_hw_eccoob_largepage = {
141 .eccbytes = 4 * 9,
142 .eccpos = {
143 7, 8, 9, 10, 11, 12, 13, 14, 15,
144 23, 24, 25, 26, 27, 28, 29, 30, 31,
145 39, 40, 41, 42, 43, 44, 45, 46, 47,
146 55, 56, 57, 58, 59, 60, 61, 62, 63
147 },
148 .oobfree = {
149 {.offset = 2, .length = 4},
150 {.offset = 16, .length = 7},
151 {.offset = 32, .length = 7},
152 {.offset = 48, .length = 7}
153 }
154};
155
Sascha Hauer34f6e152008-09-02 17:16:59 +0200156#ifdef CONFIG_MTD_PARTITIONS
157static const char *part_probes[] = { "RedBoot", "cmdlinepart", NULL };
158#endif
159
160static irqreturn_t mxc_nfc_irq(int irq, void *dev_id)
161{
162 struct mxc_nand_host *host = dev_id;
163
Ivo Claryssea47bfd22010-04-08 16:16:51 +0200164 disable_irq_nosync(irq);
Sascha Hauer34f6e152008-09-02 17:16:59 +0200165
166 wake_up(&host->irq_waitq);
167
168 return IRQ_HANDLED;
169}
170
Sascha Hauer7aaf28a2010-08-06 15:53:07 +0200171static int check_int_v1_v2(struct mxc_nand_host *host)
172{
173 uint32_t tmp;
174
Sascha Hauer1bc99182010-08-06 15:53:08 +0200175 tmp = readw(NFC_V1_V2_CONFIG2);
176 if (!(tmp & NFC_V1_V2_CONFIG2_INT))
Sascha Hauer7aaf28a2010-08-06 15:53:07 +0200177 return 0;
178
Sascha Hauer1bc99182010-08-06 15:53:08 +0200179 writew(tmp & ~NFC_V1_V2_CONFIG2_INT, NFC_V1_V2_CONFIG2);
Sascha Hauer7aaf28a2010-08-06 15:53:07 +0200180
181 return 1;
182}
183
Sascha Hauer34f6e152008-09-02 17:16:59 +0200184/* This function polls the NANDFC to wait for the basic operation to
185 * complete by checking the INT bit of config2 register.
186 */
Sascha Hauerc110eaf2009-10-21 16:01:02 +0200187static void wait_op_done(struct mxc_nand_host *host, int useirq)
Sascha Hauer34f6e152008-09-02 17:16:59 +0200188{
Ivo Claryssea47bfd22010-04-08 16:16:51 +0200189 int max_retries = 8000;
Sascha Hauer34f6e152008-09-02 17:16:59 +0200190
191 if (useirq) {
Sascha Hauer7aaf28a2010-08-06 15:53:07 +0200192 if (!host->check_int(host)) {
Sascha Hauer34f6e152008-09-02 17:16:59 +0200193
Ivo Claryssea47bfd22010-04-08 16:16:51 +0200194 enable_irq(host->irq);
Sascha Hauer34f6e152008-09-02 17:16:59 +0200195
Sascha Hauer7aaf28a2010-08-06 15:53:07 +0200196 wait_event(host->irq_waitq, host->check_int(host));
Sascha Hauer34f6e152008-09-02 17:16:59 +0200197 }
198 } else {
199 while (max_retries-- > 0) {
Sascha Hauer7aaf28a2010-08-06 15:53:07 +0200200 if (host->check_int(host))
Sascha Hauer34f6e152008-09-02 17:16:59 +0200201 break;
Sascha Hauer7aaf28a2010-08-06 15:53:07 +0200202
Sascha Hauer34f6e152008-09-02 17:16:59 +0200203 udelay(1);
204 }
Roel Kluin43950a62009-06-04 16:24:59 +0200205 if (max_retries < 0)
Sascha Hauer62465492009-06-04 15:57:20 +0200206 DEBUG(MTD_DEBUG_LEVEL0, "%s: INT not set\n",
207 __func__);
Sascha Hauer34f6e152008-09-02 17:16:59 +0200208 }
209}
210
211/* This function issues the specified command to the NAND device and
212 * waits for completion. */
Sascha Hauer5f973042010-08-06 15:53:06 +0200213static void send_cmd_v1_v2(struct mxc_nand_host *host, uint16_t cmd, int useirq)
Sascha Hauer34f6e152008-09-02 17:16:59 +0200214{
215 DEBUG(MTD_DEBUG_LEVEL3, "send_cmd(host, 0x%x, %d)\n", cmd, useirq);
216
Sascha Hauer1bc99182010-08-06 15:53:08 +0200217 writew(cmd, NFC_V1_V2_FLASH_CMD);
218 writew(NFC_CMD, NFC_V1_V2_CONFIG2);
Sascha Hauer34f6e152008-09-02 17:16:59 +0200219
Ivo Claryssea47bfd22010-04-08 16:16:51 +0200220 if (cpu_is_mx21() && (cmd == NAND_CMD_RESET)) {
221 int max_retries = 100;
222 /* Reset completion is indicated by NFC_CONFIG2 */
223 /* being set to 0 */
224 while (max_retries-- > 0) {
Sascha Hauer1bc99182010-08-06 15:53:08 +0200225 if (readw(NFC_V1_V2_CONFIG2) == 0) {
Ivo Claryssea47bfd22010-04-08 16:16:51 +0200226 break;
227 }
228 udelay(1);
229 }
230 if (max_retries < 0)
231 DEBUG(MTD_DEBUG_LEVEL0, "%s: RESET failed\n",
232 __func__);
233 } else {
234 /* Wait for operation to complete */
235 wait_op_done(host, useirq);
236 }
Sascha Hauer34f6e152008-09-02 17:16:59 +0200237}
238
239/* This function sends an address (or partial address) to the
240 * NAND device. The address is used to select the source/destination for
241 * a NAND command. */
Sascha Hauer5f973042010-08-06 15:53:06 +0200242static void send_addr_v1_v2(struct mxc_nand_host *host, uint16_t addr, int islast)
Sascha Hauer34f6e152008-09-02 17:16:59 +0200243{
244 DEBUG(MTD_DEBUG_LEVEL3, "send_addr(host, 0x%x %d)\n", addr, islast);
245
Sascha Hauer1bc99182010-08-06 15:53:08 +0200246 writew(addr, NFC_V1_V2_FLASH_ADDR);
247 writew(NFC_ADDR, NFC_V1_V2_CONFIG2);
Sascha Hauer34f6e152008-09-02 17:16:59 +0200248
249 /* Wait for operation to complete */
Sascha Hauerc110eaf2009-10-21 16:01:02 +0200250 wait_op_done(host, islast);
Sascha Hauer34f6e152008-09-02 17:16:59 +0200251}
252
Sascha Hauer5f973042010-08-06 15:53:06 +0200253static void send_page_v1_v2(struct mtd_info *mtd, unsigned int ops)
Sascha Hauer34f6e152008-09-02 17:16:59 +0200254{
Sascha Hauer2d69c7f2009-10-05 11:24:02 +0200255 struct nand_chip *nand_chip = mtd->priv;
256 struct mxc_nand_host *host = nand_chip->priv;
Sascha Hauerc5d23f12009-06-04 17:25:53 +0200257 int bufs, i;
Sascha Hauer34f6e152008-09-02 17:16:59 +0200258
Sascha Hauer94671142009-10-05 12:14:21 +0200259 if (nfc_is_v1() && mtd->writesize > 512)
Sascha Hauerc5d23f12009-06-04 17:25:53 +0200260 bufs = 4;
261 else
262 bufs = 1;
Sascha Hauer34f6e152008-09-02 17:16:59 +0200263
Sascha Hauerc5d23f12009-06-04 17:25:53 +0200264 for (i = 0; i < bufs; i++) {
265
266 /* NANDFC buffer 0 is used for page read/write */
Sascha Hauer1bc99182010-08-06 15:53:08 +0200267 writew(i, NFC_V1_V2_BUF_ADDR);
Sascha Hauerc5d23f12009-06-04 17:25:53 +0200268
Sascha Hauer1bc99182010-08-06 15:53:08 +0200269 writew(ops, NFC_V1_V2_CONFIG2);
Sascha Hauerc5d23f12009-06-04 17:25:53 +0200270
271 /* Wait for operation to complete */
Sascha Hauerc110eaf2009-10-21 16:01:02 +0200272 wait_op_done(host, true);
Sascha Hauer34f6e152008-09-02 17:16:59 +0200273 }
Sascha Hauer34f6e152008-09-02 17:16:59 +0200274}
275
276/* Request the NANDFC to perform a read of the NAND device ID. */
Sascha Hauer5f973042010-08-06 15:53:06 +0200277static void send_read_id_v1_v2(struct mxc_nand_host *host)
Sascha Hauer34f6e152008-09-02 17:16:59 +0200278{
279 struct nand_chip *this = &host->nand;
Sascha Hauer34f6e152008-09-02 17:16:59 +0200280
281 /* NANDFC buffer 0 is used for device ID output */
Sascha Hauer1bc99182010-08-06 15:53:08 +0200282 writew(0x0, NFC_V1_V2_BUF_ADDR);
Sascha Hauer34f6e152008-09-02 17:16:59 +0200283
Sascha Hauer1bc99182010-08-06 15:53:08 +0200284 writew(NFC_ID, NFC_V1_V2_CONFIG2);
Sascha Hauer34f6e152008-09-02 17:16:59 +0200285
286 /* Wait for operation to complete */
Sascha Hauerc110eaf2009-10-21 16:01:02 +0200287 wait_op_done(host, true);
Sascha Hauer34f6e152008-09-02 17:16:59 +0200288
289 if (this->options & NAND_BUSWIDTH_16) {
Sascha Hauerc6de7e12009-10-05 11:14:35 +0200290 void __iomem *main_buf = host->main_area0;
Sascha Hauer34f6e152008-09-02 17:16:59 +0200291 /* compress the ID info */
292 writeb(readb(main_buf + 2), main_buf + 1);
293 writeb(readb(main_buf + 4), main_buf + 2);
294 writeb(readb(main_buf + 6), main_buf + 3);
295 writeb(readb(main_buf + 8), main_buf + 4);
296 writeb(readb(main_buf + 10), main_buf + 5);
297 }
Sascha Hauerc6de7e12009-10-05 11:14:35 +0200298 memcpy(host->data_buf, host->main_area0, 16);
Sascha Hauer34f6e152008-09-02 17:16:59 +0200299}
300
301/* This function requests the NANDFC to perform a read of the
302 * NAND device status and returns the current status. */
Sascha Hauer5f973042010-08-06 15:53:06 +0200303static uint16_t get_dev_status_v1_v2(struct mxc_nand_host *host)
Sascha Hauer34f6e152008-09-02 17:16:59 +0200304{
Sascha Hauerc29c6072010-08-06 15:53:05 +0200305 void __iomem *main_buf = host->main_area0;
Sascha Hauer34f6e152008-09-02 17:16:59 +0200306 uint32_t store;
Sascha Hauerf06368f2009-10-05 17:18:42 +0200307 uint16_t ret;
Sascha Hauer34f6e152008-09-02 17:16:59 +0200308
Sascha Hauerc29c6072010-08-06 15:53:05 +0200309 writew(0x0, NFC_V1_V2_BUF_ADDR);
310
311 /*
312 * The device status is stored in main_area0. To
313 * prevent corruption of the buffer save the value
314 * and restore it afterwards.
315 */
Sascha Hauer34f6e152008-09-02 17:16:59 +0200316 store = readl(main_buf);
Sascha Hauer34f6e152008-09-02 17:16:59 +0200317
Sascha Hauer1bc99182010-08-06 15:53:08 +0200318 writew(NFC_STATUS, NFC_V1_V2_CONFIG2);
Sascha Hauerc110eaf2009-10-21 16:01:02 +0200319 wait_op_done(host, true);
Sascha Hauer34f6e152008-09-02 17:16:59 +0200320
Sascha Hauer34f6e152008-09-02 17:16:59 +0200321 ret = readw(main_buf);
Sascha Hauerc29c6072010-08-06 15:53:05 +0200322
Sascha Hauer34f6e152008-09-02 17:16:59 +0200323 writel(store, main_buf);
324
325 return ret;
326}
327
328/* This functions is used by upper layer to checks if device is ready */
329static int mxc_nand_dev_ready(struct mtd_info *mtd)
330{
331 /*
332 * NFC handles R/B internally. Therefore, this function
333 * always returns status as ready.
334 */
335 return 1;
336}
337
338static void mxc_nand_enable_hwecc(struct mtd_info *mtd, int mode)
339{
340 /*
341 * If HW ECC is enabled, we turn it on during init. There is
342 * no need to enable again here.
343 */
344}
345
Sascha Hauer94f77e52010-08-06 15:53:09 +0200346static int mxc_nand_correct_data_v1(struct mtd_info *mtd, u_char *dat,
Sascha Hauer34f6e152008-09-02 17:16:59 +0200347 u_char *read_ecc, u_char *calc_ecc)
348{
349 struct nand_chip *nand_chip = mtd->priv;
350 struct mxc_nand_host *host = nand_chip->priv;
351
352 /*
353 * 1-Bit errors are automatically corrected in HW. No need for
354 * additional correction. 2-Bit errors cannot be corrected by
355 * HW ECC, so we need to return failure
356 */
Sascha Hauer1bc99182010-08-06 15:53:08 +0200357 uint16_t ecc_status = readw(NFC_V1_V2_ECC_STATUS_RESULT);
Sascha Hauer34f6e152008-09-02 17:16:59 +0200358
359 if (((ecc_status & 0x3) == 2) || ((ecc_status >> 2) == 2)) {
360 DEBUG(MTD_DEBUG_LEVEL0,
361 "MXC_NAND: HWECC uncorrectable 2-bit ECC error\n");
362 return -1;
363 }
364
365 return 0;
366}
367
Sascha Hauer94f77e52010-08-06 15:53:09 +0200368static int mxc_nand_correct_data_v2_v3(struct mtd_info *mtd, u_char *dat,
369 u_char *read_ecc, u_char *calc_ecc)
370{
371 struct nand_chip *nand_chip = mtd->priv;
372 struct mxc_nand_host *host = nand_chip->priv;
373 u32 ecc_stat, err;
374 int no_subpages = 1;
375 int ret = 0;
376 u8 ecc_bit_mask, err_limit;
377
378 ecc_bit_mask = (host->eccsize == 4) ? 0x7 : 0xf;
379 err_limit = (host->eccsize == 4) ? 0x4 : 0x8;
380
381 no_subpages = mtd->writesize >> 9;
382
383 ecc_stat = readl(NFC_V1_V2_ECC_STATUS_RESULT);
384
385 do {
386 err = ecc_stat & ecc_bit_mask;
387 if (err > err_limit) {
388 printk(KERN_WARNING "UnCorrectable RS-ECC Error\n");
389 return -1;
390 } else {
391 ret += err;
392 }
393 ecc_stat >>= 4;
394 } while (--no_subpages);
395
396 mtd->ecc_stats.corrected += ret;
397 pr_debug("%d Symbol Correctable RS-ECC Error\n", ret);
398
399 return ret;
400}
401
Sascha Hauer34f6e152008-09-02 17:16:59 +0200402static int mxc_nand_calculate_ecc(struct mtd_info *mtd, const u_char *dat,
403 u_char *ecc_code)
404{
405 return 0;
406}
407
408static u_char mxc_nand_read_byte(struct mtd_info *mtd)
409{
410 struct nand_chip *nand_chip = mtd->priv;
411 struct mxc_nand_host *host = nand_chip->priv;
Sascha Hauerf8f96082009-06-04 17:12:26 +0200412 uint8_t ret;
Sascha Hauer34f6e152008-09-02 17:16:59 +0200413
414 /* Check for status request */
415 if (host->status_request)
Sascha Hauer5f973042010-08-06 15:53:06 +0200416 return host->get_dev_status(host) & 0xFF;
Sascha Hauer34f6e152008-09-02 17:16:59 +0200417
Sascha Hauerf8f96082009-06-04 17:12:26 +0200418 ret = *(uint8_t *)(host->data_buf + host->buf_start);
419 host->buf_start++;
Sascha Hauer34f6e152008-09-02 17:16:59 +0200420
421 return ret;
422}
423
424static uint16_t mxc_nand_read_word(struct mtd_info *mtd)
425{
426 struct nand_chip *nand_chip = mtd->priv;
427 struct mxc_nand_host *host = nand_chip->priv;
Sascha Hauerf8f96082009-06-04 17:12:26 +0200428 uint16_t ret;
Sascha Hauer34f6e152008-09-02 17:16:59 +0200429
Sascha Hauerf8f96082009-06-04 17:12:26 +0200430 ret = *(uint16_t *)(host->data_buf + host->buf_start);
431 host->buf_start += 2;
Sascha Hauer34f6e152008-09-02 17:16:59 +0200432
433 return ret;
434}
435
436/* Write data of length len to buffer buf. The data to be
437 * written on NAND Flash is first copied to RAMbuffer. After the Data Input
438 * Operation by the NFC, the data is written to NAND Flash */
439static void mxc_nand_write_buf(struct mtd_info *mtd,
440 const u_char *buf, int len)
441{
442 struct nand_chip *nand_chip = mtd->priv;
443 struct mxc_nand_host *host = nand_chip->priv;
Sascha Hauerf8f96082009-06-04 17:12:26 +0200444 u16 col = host->buf_start;
445 int n = mtd->oobsize + mtd->writesize - col;
Sascha Hauer34f6e152008-09-02 17:16:59 +0200446
Sascha Hauerf8f96082009-06-04 17:12:26 +0200447 n = min(n, len);
Sascha Hauer34f6e152008-09-02 17:16:59 +0200448
Sascha Hauerf8f96082009-06-04 17:12:26 +0200449 memcpy(host->data_buf + col, buf, n);
Sascha Hauer34f6e152008-09-02 17:16:59 +0200450
Sascha Hauerf8f96082009-06-04 17:12:26 +0200451 host->buf_start += n;
Sascha Hauer34f6e152008-09-02 17:16:59 +0200452}
453
454/* Read the data buffer from the NAND Flash. To read the data from NAND
455 * Flash first the data output cycle is initiated by the NFC, which copies
456 * the data to RAMbuffer. This data of length len is then copied to buffer buf.
457 */
458static void mxc_nand_read_buf(struct mtd_info *mtd, u_char *buf, int len)
459{
460 struct nand_chip *nand_chip = mtd->priv;
461 struct mxc_nand_host *host = nand_chip->priv;
Sascha Hauerf8f96082009-06-04 17:12:26 +0200462 u16 col = host->buf_start;
463 int n = mtd->oobsize + mtd->writesize - col;
Sascha Hauer34f6e152008-09-02 17:16:59 +0200464
Sascha Hauerf8f96082009-06-04 17:12:26 +0200465 n = min(n, len);
Sascha Hauer34f6e152008-09-02 17:16:59 +0200466
Sascha Hauerf8f96082009-06-04 17:12:26 +0200467 memcpy(buf, host->data_buf + col, len);
Sascha Hauer34f6e152008-09-02 17:16:59 +0200468
Sascha Hauerf8f96082009-06-04 17:12:26 +0200469 host->buf_start += len;
Sascha Hauer34f6e152008-09-02 17:16:59 +0200470}
471
472/* Used by the upper layer to verify the data in NAND Flash
473 * with the data in the buf. */
474static int mxc_nand_verify_buf(struct mtd_info *mtd,
475 const u_char *buf, int len)
476{
477 return -EFAULT;
478}
479
480/* This function is used by upper layer for select and
481 * deselect of the NAND chip */
482static void mxc_nand_select_chip(struct mtd_info *mtd, int chip)
483{
484 struct nand_chip *nand_chip = mtd->priv;
485 struct mxc_nand_host *host = nand_chip->priv;
486
Sascha Hauer34f6e152008-09-02 17:16:59 +0200487 switch (chip) {
488 case -1:
489 /* Disable the NFC clock */
490 if (host->clk_act) {
491 clk_disable(host->clk);
492 host->clk_act = 0;
493 }
494 break;
495 case 0:
496 /* Enable the NFC clock */
497 if (!host->clk_act) {
498 clk_enable(host->clk);
499 host->clk_act = 1;
500 }
501 break;
502
503 default:
504 break;
505 }
506}
507
Sascha Hauerf8f96082009-06-04 17:12:26 +0200508/*
509 * Function to transfer data to/from spare area.
510 */
511static void copy_spare(struct mtd_info *mtd, bool bfrom)
512{
513 struct nand_chip *this = mtd->priv;
514 struct mxc_nand_host *host = this->priv;
515 u16 i, j;
516 u16 n = mtd->writesize >> 9;
517 u8 *d = host->data_buf + mtd->writesize;
Sascha Hauerc6de7e12009-10-05 11:14:35 +0200518 u8 *s = host->spare0;
Sascha Hauerf8f96082009-06-04 17:12:26 +0200519 u16 t = host->spare_len;
520
521 j = (mtd->oobsize / n >> 1) << 1;
522
523 if (bfrom) {
524 for (i = 0; i < n - 1; i++)
525 memcpy(d + i * j, s + i * t, j);
526
527 /* the last section */
528 memcpy(d + i * j, s + i * t, mtd->oobsize - i * j);
529 } else {
530 for (i = 0; i < n - 1; i++)
531 memcpy(&s[i * t], &d[i * j], j);
532
533 /* the last section */
534 memcpy(&s[i * t], &d[i * j], mtd->oobsize - i * j);
535 }
536}
537
Sascha Hauera3e65b62009-06-02 11:47:59 +0200538static void mxc_do_addr_cycle(struct mtd_info *mtd, int column, int page_addr)
Sascha Hauer34f6e152008-09-02 17:16:59 +0200539{
540 struct nand_chip *nand_chip = mtd->priv;
541 struct mxc_nand_host *host = nand_chip->priv;
Sascha Hauer34f6e152008-09-02 17:16:59 +0200542
543 /* Write out column address, if necessary */
544 if (column != -1) {
545 /*
546 * MXC NANDFC can only perform full page+spare or
547 * spare-only read/write. When the upper layers
548 * layers perform a read/write buf operation,
Daniel Mack3ad2f3f2010-02-03 08:01:28 +0800549 * we will used the saved column address to index into
Sascha Hauer34f6e152008-09-02 17:16:59 +0200550 * the full page.
551 */
Sascha Hauer5f973042010-08-06 15:53:06 +0200552 host->send_addr(host, 0, page_addr == -1);
Sascha Hauer2d69c7f2009-10-05 11:24:02 +0200553 if (mtd->writesize > 512)
Sascha Hauer34f6e152008-09-02 17:16:59 +0200554 /* another col addr cycle for 2k page */
Sascha Hauer5f973042010-08-06 15:53:06 +0200555 host->send_addr(host, 0, false);
Sascha Hauer34f6e152008-09-02 17:16:59 +0200556 }
557
558 /* Write out page address, if necessary */
559 if (page_addr != -1) {
560 /* paddr_0 - p_addr_7 */
Sascha Hauer5f973042010-08-06 15:53:06 +0200561 host->send_addr(host, (page_addr & 0xff), false);
Sascha Hauer34f6e152008-09-02 17:16:59 +0200562
Sascha Hauer2d69c7f2009-10-05 11:24:02 +0200563 if (mtd->writesize > 512) {
Vladimir Barinovbd3fd622009-05-25 13:06:17 +0400564 if (mtd->size >= 0x10000000) {
565 /* paddr_8 - paddr_15 */
Sascha Hauer5f973042010-08-06 15:53:06 +0200566 host->send_addr(host, (page_addr >> 8) & 0xff, false);
567 host->send_addr(host, (page_addr >> 16) & 0xff, true);
Vladimir Barinovbd3fd622009-05-25 13:06:17 +0400568 } else
569 /* paddr_8 - paddr_15 */
Sascha Hauer5f973042010-08-06 15:53:06 +0200570 host->send_addr(host, (page_addr >> 8) & 0xff, true);
Sascha Hauer34f6e152008-09-02 17:16:59 +0200571 } else {
572 /* One more address cycle for higher density devices */
573 if (mtd->size >= 0x4000000) {
574 /* paddr_8 - paddr_15 */
Sascha Hauer5f973042010-08-06 15:53:06 +0200575 host->send_addr(host, (page_addr >> 8) & 0xff, false);
576 host->send_addr(host, (page_addr >> 16) & 0xff, true);
Sascha Hauer34f6e152008-09-02 17:16:59 +0200577 } else
578 /* paddr_8 - paddr_15 */
Sascha Hauer5f973042010-08-06 15:53:06 +0200579 host->send_addr(host, (page_addr >> 8) & 0xff, true);
Sascha Hauer34f6e152008-09-02 17:16:59 +0200580 }
581 }
Sascha Hauera3e65b62009-06-02 11:47:59 +0200582}
Sascha Hauer34f6e152008-09-02 17:16:59 +0200583
Sascha Hauer5f973042010-08-06 15:53:06 +0200584static void preset_v1_v2(struct mtd_info *mtd)
Ivo Claryssed4840182010-04-08 16:14:44 +0200585{
586 struct nand_chip *nand_chip = mtd->priv;
587 struct mxc_nand_host *host = nand_chip->priv;
588 uint16_t tmp;
589
Ivo Claryssea47bfd22010-04-08 16:16:51 +0200590 /* enable interrupt, disable spare enable */
Sascha Hauer1bc99182010-08-06 15:53:08 +0200591 tmp = readw(NFC_V1_V2_CONFIG1);
592 tmp &= ~NFC_V1_V2_CONFIG1_INT_MSK;
593 tmp &= ~NFC_V1_V2_CONFIG1_SP_EN;
Ivo Claryssed4840182010-04-08 16:14:44 +0200594 if (nand_chip->ecc.mode == NAND_ECC_HW) {
Sascha Hauer1bc99182010-08-06 15:53:08 +0200595 tmp |= NFC_V1_V2_CONFIG1_ECC_EN;
Ivo Claryssed4840182010-04-08 16:14:44 +0200596 } else {
Sascha Hauer1bc99182010-08-06 15:53:08 +0200597 tmp &= ~NFC_V1_V2_CONFIG1_ECC_EN;
Ivo Claryssed4840182010-04-08 16:14:44 +0200598 }
Sascha Hauer1bc99182010-08-06 15:53:08 +0200599 writew(tmp, NFC_V1_V2_CONFIG1);
Ivo Claryssed4840182010-04-08 16:14:44 +0200600 /* preset operation */
601
602 /* Unlock the internal RAM Buffer */
Sascha Hauer1bc99182010-08-06 15:53:08 +0200603 writew(0x2, NFC_V1_V2_CONFIG);
Ivo Claryssed4840182010-04-08 16:14:44 +0200604
605 /* Blocks to be unlocked */
606 if (nfc_is_v21()) {
Sascha Hauer1bc99182010-08-06 15:53:08 +0200607 writew(0x0, NFC_V21_UNLOCKSTART_BLKADDR);
608 writew(0xffff, NFC_V21_UNLOCKEND_BLKADDR);
Ivo Claryssed4840182010-04-08 16:14:44 +0200609 } else if (nfc_is_v1()) {
Sascha Hauer1bc99182010-08-06 15:53:08 +0200610 writew(0x0, NFC_V1_UNLOCKSTART_BLKADDR);
611 writew(0x4000, NFC_V1_UNLOCKEND_BLKADDR);
Ivo Claryssed4840182010-04-08 16:14:44 +0200612 } else
613 BUG();
614
615 /* Unlock Block Command for given address range */
Sascha Hauer1bc99182010-08-06 15:53:08 +0200616 writew(0x4, NFC_V1_V2_WRPROT);
Ivo Claryssed4840182010-04-08 16:14:44 +0200617}
618
Sascha Hauer34f6e152008-09-02 17:16:59 +0200619/* Used by the upper layer to write command to NAND Flash for
620 * different operations to be carried out on NAND Flash */
621static void mxc_nand_command(struct mtd_info *mtd, unsigned command,
622 int column, int page_addr)
623{
624 struct nand_chip *nand_chip = mtd->priv;
625 struct mxc_nand_host *host = nand_chip->priv;
Sascha Hauer34f6e152008-09-02 17:16:59 +0200626
627 DEBUG(MTD_DEBUG_LEVEL3,
628 "mxc_nand_command (cmd = 0x%x, col = 0x%x, page = 0x%x)\n",
629 command, column, page_addr);
630
631 /* Reset command state information */
632 host->status_request = false;
633
634 /* Command pre-processing step */
Sascha Hauer34f6e152008-09-02 17:16:59 +0200635 switch (command) {
Ivo Claryssed4840182010-04-08 16:14:44 +0200636 case NAND_CMD_RESET:
Sascha Hauer5f973042010-08-06 15:53:06 +0200637 host->preset(mtd);
638 host->send_cmd(host, command, false);
Ivo Claryssed4840182010-04-08 16:14:44 +0200639 break;
Sascha Hauer34f6e152008-09-02 17:16:59 +0200640
Sascha Hauer34f6e152008-09-02 17:16:59 +0200641 case NAND_CMD_STATUS:
Sascha Hauerf8f96082009-06-04 17:12:26 +0200642 host->buf_start = 0;
Sascha Hauer34f6e152008-09-02 17:16:59 +0200643 host->status_request = true;
Sascha Hauer89121a62009-06-04 17:18:01 +0200644
Sascha Hauer5f973042010-08-06 15:53:06 +0200645 host->send_cmd(host, command, true);
Sascha Hauer89121a62009-06-04 17:18:01 +0200646 mxc_do_addr_cycle(mtd, column, page_addr);
Sascha Hauer34f6e152008-09-02 17:16:59 +0200647 break;
648
Sascha Hauer34f6e152008-09-02 17:16:59 +0200649 case NAND_CMD_READ0:
Sascha Hauer34f6e152008-09-02 17:16:59 +0200650 case NAND_CMD_READOOB:
Sascha Hauer89121a62009-06-04 17:18:01 +0200651 if (command == NAND_CMD_READ0)
652 host->buf_start = column;
653 else
654 host->buf_start = column + mtd->writesize;
Sascha Hauerf8f96082009-06-04 17:12:26 +0200655
Sascha Hauer6c499392010-05-28 10:02:17 +0200656 command = NAND_CMD_READ0; /* only READ0 is valid */
Sascha Hauer89121a62009-06-04 17:18:01 +0200657
Sascha Hauer5f973042010-08-06 15:53:06 +0200658 host->send_cmd(host, command, false);
Sascha Hauer89121a62009-06-04 17:18:01 +0200659 mxc_do_addr_cycle(mtd, column, page_addr);
660
Sascha Hauer2d69c7f2009-10-05 11:24:02 +0200661 if (mtd->writesize > 512)
Sascha Hauer5f973042010-08-06 15:53:06 +0200662 host->send_cmd(host, NAND_CMD_READSTART, true);
Sascha Hauerc5d23f12009-06-04 17:25:53 +0200663
Sascha Hauer5f973042010-08-06 15:53:06 +0200664 host->send_page(mtd, NFC_OUTPUT);
Sascha Hauer89121a62009-06-04 17:18:01 +0200665
Sascha Hauerc6de7e12009-10-05 11:14:35 +0200666 memcpy(host->data_buf, host->main_area0, mtd->writesize);
Sascha Hauer89121a62009-06-04 17:18:01 +0200667 copy_spare(mtd, true);
Sascha Hauer34f6e152008-09-02 17:16:59 +0200668 break;
669
Sascha Hauer34f6e152008-09-02 17:16:59 +0200670 case NAND_CMD_SEQIN:
Sascha Hauer6c499392010-05-28 10:02:17 +0200671 if (column >= mtd->writesize)
672 /* call ourself to read a page */
673 mxc_nand_command(mtd, NAND_CMD_READ0, 0, page_addr);
Sascha Hauer34f6e152008-09-02 17:16:59 +0200674
Sascha Hauer6c499392010-05-28 10:02:17 +0200675 host->buf_start = column;
Sascha Hauer89121a62009-06-04 17:18:01 +0200676
Sascha Hauer5f973042010-08-06 15:53:06 +0200677 host->send_cmd(host, command, false);
Sascha Hauer89121a62009-06-04 17:18:01 +0200678 mxc_do_addr_cycle(mtd, column, page_addr);
Sascha Hauer34f6e152008-09-02 17:16:59 +0200679 break;
680
681 case NAND_CMD_PAGEPROG:
Sascha Hauerc6de7e12009-10-05 11:14:35 +0200682 memcpy(host->main_area0, host->data_buf, mtd->writesize);
Sascha Hauerf8f96082009-06-04 17:12:26 +0200683 copy_spare(mtd, false);
Sascha Hauer5f973042010-08-06 15:53:06 +0200684 host->send_page(mtd, NFC_INPUT);
685 host->send_cmd(host, command, true);
Sascha Hauer89121a62009-06-04 17:18:01 +0200686 mxc_do_addr_cycle(mtd, column, page_addr);
Sascha Hauer34f6e152008-09-02 17:16:59 +0200687 break;
688
Sascha Hauer34f6e152008-09-02 17:16:59 +0200689 case NAND_CMD_READID:
Sascha Hauer5f973042010-08-06 15:53:06 +0200690 host->send_cmd(host, command, true);
Sascha Hauer89121a62009-06-04 17:18:01 +0200691 mxc_do_addr_cycle(mtd, column, page_addr);
Sascha Hauer5f973042010-08-06 15:53:06 +0200692 host->send_read_id(host);
Sascha Hauer94671142009-10-05 12:14:21 +0200693 host->buf_start = column;
Sascha Hauer34f6e152008-09-02 17:16:59 +0200694 break;
695
Sascha Hauer89121a62009-06-04 17:18:01 +0200696 case NAND_CMD_ERASE1:
Sascha Hauer34f6e152008-09-02 17:16:59 +0200697 case NAND_CMD_ERASE2:
Sascha Hauer5f973042010-08-06 15:53:06 +0200698 host->send_cmd(host, command, false);
Sascha Hauer89121a62009-06-04 17:18:01 +0200699 mxc_do_addr_cycle(mtd, column, page_addr);
700
Sascha Hauer34f6e152008-09-02 17:16:59 +0200701 break;
702 }
703}
704
Sascha Hauerf1372052009-10-21 14:25:27 +0200705/*
706 * The generic flash bbt decriptors overlap with our ecc
707 * hardware, so define some i.MX specific ones.
708 */
709static uint8_t bbt_pattern[] = { 'B', 'b', 't', '0' };
710static uint8_t mirror_pattern[] = { '1', 't', 'b', 'B' };
711
712static struct nand_bbt_descr bbt_main_descr = {
713 .options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE
714 | NAND_BBT_2BIT | NAND_BBT_VERSION | NAND_BBT_PERCHIP,
715 .offs = 0,
716 .len = 4,
717 .veroffs = 4,
718 .maxblocks = 4,
719 .pattern = bbt_pattern,
720};
721
722static struct nand_bbt_descr bbt_mirror_descr = {
723 .options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE
724 | NAND_BBT_2BIT | NAND_BBT_VERSION | NAND_BBT_PERCHIP,
725 .offs = 0,
726 .len = 4,
727 .veroffs = 4,
728 .maxblocks = 4,
729 .pattern = mirror_pattern,
730};
731
Sascha Hauer34f6e152008-09-02 17:16:59 +0200732static int __init mxcnd_probe(struct platform_device *pdev)
733{
734 struct nand_chip *this;
735 struct mtd_info *mtd;
736 struct mxc_nand_platform_data *pdata = pdev->dev.platform_data;
737 struct mxc_nand_host *host;
738 struct resource *res;
Sascha Hauer34f6e152008-09-02 17:16:59 +0200739 int err = 0, nr_parts = 0;
Sascha Hauer94671142009-10-05 12:14:21 +0200740 struct nand_ecclayout *oob_smallpage, *oob_largepage;
Sascha Hauer34f6e152008-09-02 17:16:59 +0200741
742 /* Allocate memory for MTD device structure and private data */
Sascha Hauerf8f96082009-06-04 17:12:26 +0200743 host = kzalloc(sizeof(struct mxc_nand_host) + NAND_MAX_PAGESIZE +
744 NAND_MAX_OOBSIZE, GFP_KERNEL);
Sascha Hauer34f6e152008-09-02 17:16:59 +0200745 if (!host)
746 return -ENOMEM;
747
Sascha Hauerf8f96082009-06-04 17:12:26 +0200748 host->data_buf = (uint8_t *)(host + 1);
Sascha Hauerf8f96082009-06-04 17:12:26 +0200749
Sascha Hauer34f6e152008-09-02 17:16:59 +0200750 host->dev = &pdev->dev;
751 /* structures must be linked */
752 this = &host->nand;
753 mtd = &host->mtd;
754 mtd->priv = this;
755 mtd->owner = THIS_MODULE;
David Brownell87f39f02009-03-26 00:42:50 -0700756 mtd->dev.parent = &pdev->dev;
Sascha Hauer1fbff0a2009-10-21 16:06:27 +0200757 mtd->name = DRIVER_NAME;
Sascha Hauer34f6e152008-09-02 17:16:59 +0200758
759 /* 50 us command delay time */
760 this->chip_delay = 5;
761
762 this->priv = host;
763 this->dev_ready = mxc_nand_dev_ready;
764 this->cmdfunc = mxc_nand_command;
765 this->select_chip = mxc_nand_select_chip;
766 this->read_byte = mxc_nand_read_byte;
767 this->read_word = mxc_nand_read_word;
768 this->write_buf = mxc_nand_write_buf;
769 this->read_buf = mxc_nand_read_buf;
770 this->verify_buf = mxc_nand_verify_buf;
771
Sascha Hauere65fb002009-02-16 14:29:10 +0100772 host->clk = clk_get(&pdev->dev, "nfc");
Vladimir Barinov8541c112009-04-23 15:47:22 +0400773 if (IS_ERR(host->clk)) {
774 err = PTR_ERR(host->clk);
Sascha Hauer34f6e152008-09-02 17:16:59 +0200775 goto eclk;
Vladimir Barinov8541c112009-04-23 15:47:22 +0400776 }
Sascha Hauer34f6e152008-09-02 17:16:59 +0200777
778 clk_enable(host->clk);
779 host->clk_act = 1;
780
781 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
782 if (!res) {
783 err = -ENODEV;
784 goto eres;
785 }
786
Sascha Hauerc6de7e12009-10-05 11:14:35 +0200787 host->base = ioremap(res->start, resource_size(res));
788 if (!host->base) {
Vladimir Barinov8541c112009-04-23 15:47:22 +0400789 err = -ENOMEM;
Sascha Hauer34f6e152008-09-02 17:16:59 +0200790 goto eres;
791 }
792
Sascha Hauerc6de7e12009-10-05 11:14:35 +0200793 host->main_area0 = host->base;
Sascha Hauer94671142009-10-05 12:14:21 +0200794
Sascha Hauer5f973042010-08-06 15:53:06 +0200795 if (nfc_is_v1() || nfc_is_v21()) {
796 host->preset = preset_v1_v2;
797 host->send_cmd = send_cmd_v1_v2;
798 host->send_addr = send_addr_v1_v2;
799 host->send_page = send_page_v1_v2;
800 host->send_read_id = send_read_id_v1_v2;
801 host->get_dev_status = get_dev_status_v1_v2;
Sascha Hauer7aaf28a2010-08-06 15:53:07 +0200802 host->check_int = check_int_v1_v2;
Sascha Hauer5f973042010-08-06 15:53:06 +0200803 }
804
Sascha Hauer94671142009-10-05 12:14:21 +0200805 if (nfc_is_v21()) {
Sascha Hauer938cf992010-08-06 15:53:04 +0200806 host->regs = host->base + 0x1e00;
Sascha Hauer94671142009-10-05 12:14:21 +0200807 host->spare0 = host->base + 0x1000;
808 host->spare_len = 64;
809 oob_smallpage = &nandv2_hw_eccoob_smallpage;
810 oob_largepage = &nandv2_hw_eccoob_largepage;
Ivo Claryssed4840182010-04-08 16:14:44 +0200811 this->ecc.bytes = 9;
Sascha Hauer94671142009-10-05 12:14:21 +0200812 } else if (nfc_is_v1()) {
Sascha Hauer938cf992010-08-06 15:53:04 +0200813 host->regs = host->base + 0xe00;
Sascha Hauer94671142009-10-05 12:14:21 +0200814 host->spare0 = host->base + 0x800;
815 host->spare_len = 16;
816 oob_smallpage = &nandv1_hw_eccoob_smallpage;
817 oob_largepage = &nandv1_hw_eccoob_largepage;
Sascha Hauer94671142009-10-05 12:14:21 +0200818 this->ecc.bytes = 3;
819 } else
820 BUG();
Sascha Hauer34f6e152008-09-02 17:16:59 +0200821
Sascha Hauer13e1add2009-10-21 10:39:05 +0200822 this->ecc.size = 512;
Sascha Hauer94671142009-10-05 12:14:21 +0200823 this->ecc.layout = oob_smallpage;
Sascha Hauer13e1add2009-10-21 10:39:05 +0200824
825 if (pdata->hw_ecc) {
826 this->ecc.calculate = mxc_nand_calculate_ecc;
827 this->ecc.hwctl = mxc_nand_enable_hwecc;
Sascha Hauer94f77e52010-08-06 15:53:09 +0200828 if (nfc_is_v1())
829 this->ecc.correct = mxc_nand_correct_data_v1;
830 else
831 this->ecc.correct = mxc_nand_correct_data_v2_v3;
Sascha Hauer13e1add2009-10-21 10:39:05 +0200832 this->ecc.mode = NAND_ECC_HW;
Sascha Hauer13e1add2009-10-21 10:39:05 +0200833 } else {
834 this->ecc.mode = NAND_ECC_SOFT;
Sascha Hauer34f6e152008-09-02 17:16:59 +0200835 }
836
Sascha Hauer34f6e152008-09-02 17:16:59 +0200837 /* NAND bus width determines access funtions used by upper layer */
Sascha Hauer13e1add2009-10-21 10:39:05 +0200838 if (pdata->width == 2)
Sascha Hauer34f6e152008-09-02 17:16:59 +0200839 this->options |= NAND_BUSWIDTH_16;
Sascha Hauer13e1add2009-10-21 10:39:05 +0200840
Sascha Hauerf1372052009-10-21 14:25:27 +0200841 if (pdata->flash_bbt) {
842 this->bbt_td = &bbt_main_descr;
843 this->bbt_md = &bbt_mirror_descr;
844 /* update flash based bbt */
845 this->options |= NAND_USE_FLASH_BBT;
Sascha Hauer34f6e152008-09-02 17:16:59 +0200846 }
847
Ivo Claryssed4840182010-04-08 16:14:44 +0200848 init_waitqueue_head(&host->irq_waitq);
849
850 host->irq = platform_get_irq(pdev, 0);
851
Ivo Claryssea47bfd22010-04-08 16:16:51 +0200852 err = request_irq(host->irq, mxc_nfc_irq, IRQF_DISABLED, DRIVER_NAME, host);
Ivo Claryssed4840182010-04-08 16:14:44 +0200853 if (err)
854 goto eirq;
855
Vladimir Barinovbd3fd622009-05-25 13:06:17 +0400856 /* first scan to find the device and get the page size */
David Woodhouse5e81e882010-02-26 18:32:56 +0000857 if (nand_scan_ident(mtd, 1, NULL)) {
Vladimir Barinovbd3fd622009-05-25 13:06:17 +0400858 err = -ENXIO;
859 goto escan;
860 }
Sascha Hauer34f6e152008-09-02 17:16:59 +0200861
Sascha Hauer2d69c7f2009-10-05 11:24:02 +0200862 if (mtd->writesize == 2048)
Sascha Hauer94671142009-10-05 12:14:21 +0200863 this->ecc.layout = oob_largepage;
Vladimir Barinovbd3fd622009-05-25 13:06:17 +0400864
865 /* second phase scan */
866 if (nand_scan_tail(mtd)) {
Sascha Hauer34f6e152008-09-02 17:16:59 +0200867 err = -ENXIO;
868 goto escan;
869 }
870
871 /* Register the partitions */
872#ifdef CONFIG_MTD_PARTITIONS
873 nr_parts =
874 parse_mtd_partitions(mtd, part_probes, &host->parts, 0);
875 if (nr_parts > 0)
876 add_mtd_partitions(mtd, host->parts, nr_parts);
877 else
878#endif
879 {
880 pr_info("Registering %s as whole device\n", mtd->name);
881 add_mtd_device(mtd);
882 }
883
884 platform_set_drvdata(pdev, host);
885
886 return 0;
887
888escan:
Magnus Liljab258fd82009-05-08 21:57:47 +0200889 free_irq(host->irq, host);
Sascha Hauer34f6e152008-09-02 17:16:59 +0200890eirq:
Sascha Hauerc6de7e12009-10-05 11:14:35 +0200891 iounmap(host->base);
Sascha Hauer34f6e152008-09-02 17:16:59 +0200892eres:
893 clk_put(host->clk);
894eclk:
895 kfree(host);
896
897 return err;
898}
899
Uwe Kleine-König51eeb872009-12-07 09:44:05 +0000900static int __devexit mxcnd_remove(struct platform_device *pdev)
Sascha Hauer34f6e152008-09-02 17:16:59 +0200901{
902 struct mxc_nand_host *host = platform_get_drvdata(pdev);
903
904 clk_put(host->clk);
905
906 platform_set_drvdata(pdev, NULL);
907
908 nand_release(&host->mtd);
Magnus Liljab258fd82009-05-08 21:57:47 +0200909 free_irq(host->irq, host);
Sascha Hauerc6de7e12009-10-05 11:14:35 +0200910 iounmap(host->base);
Sascha Hauer34f6e152008-09-02 17:16:59 +0200911 kfree(host);
912
913 return 0;
914}
915
Sascha Hauer34f6e152008-09-02 17:16:59 +0200916static struct platform_driver mxcnd_driver = {
917 .driver = {
918 .name = DRIVER_NAME,
Eric Bénard04dd0d32010-06-17 20:59:04 +0200919 },
Uwe Kleine-Königdaa0f152009-11-24 22:07:08 +0100920 .remove = __devexit_p(mxcnd_remove),
Sascha Hauer34f6e152008-09-02 17:16:59 +0200921};
922
923static int __init mxc_nd_init(void)
924{
Vladimir Barinov8541c112009-04-23 15:47:22 +0400925 return platform_driver_probe(&mxcnd_driver, mxcnd_probe);
Sascha Hauer34f6e152008-09-02 17:16:59 +0200926}
927
928static void __exit mxc_nd_cleanup(void)
929{
930 /* Unregister the device structure */
931 platform_driver_unregister(&mxcnd_driver);
932}
933
934module_init(mxc_nd_init);
935module_exit(mxc_nd_cleanup);
936
937MODULE_AUTHOR("Freescale Semiconductor, Inc.");
938MODULE_DESCRIPTION("MXC NAND MTD driver");
939MODULE_LICENSE("GPL");