blob: 74a43b818d0e0401616dcc5ace7af52bcf53c726 [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
143struct mxc_nand_host {
144 struct mtd_info mtd;
145 struct nand_chip nand;
Sascha Hauer34f6e152008-09-02 17:16:59 +0200146 struct device *dev;
147
Sascha Hauerc6de7e12009-10-05 11:14:35 +0200148 void *spare0;
149 void *main_area0;
Sascha Hauerc6de7e12009-10-05 11:14:35 +0200150
151 void __iomem *base;
Sascha Hauer34f6e152008-09-02 17:16:59 +0200152 void __iomem *regs;
Sascha Hauer71ec5152010-08-06 15:53:11 +0200153 void __iomem *regs_axi;
154 void __iomem *regs_ip;
Sascha Hauer34f6e152008-09-02 17:16:59 +0200155 int status_request;
Sascha Hauer34f6e152008-09-02 17:16:59 +0200156 struct clk *clk;
157 int clk_act;
158 int irq;
Sascha Hauer94f77e52010-08-06 15:53:09 +0200159 int eccsize;
Baruch Siachd178e3e2011-03-14 09:01:56 +0200160 int active_cs;
Sascha Hauer34f6e152008-09-02 17:16:59 +0200161
Sascha Hauer63f14742010-10-18 10:16:26 +0200162 struct completion op_completion;
Sascha Hauerf8f96082009-06-04 17:12:26 +0200163
164 uint8_t *data_buf;
165 unsigned int buf_start;
166 int spare_len;
Sascha Hauer5f973042010-08-06 15:53:06 +0200167
168 void (*preset)(struct mtd_info *);
169 void (*send_cmd)(struct mxc_nand_host *, uint16_t, int);
170 void (*send_addr)(struct mxc_nand_host *, uint16_t, int);
171 void (*send_page)(struct mtd_info *, unsigned int);
172 void (*send_read_id)(struct mxc_nand_host *);
173 uint16_t (*get_dev_status)(struct mxc_nand_host *);
Sascha Hauer7aaf28a2010-08-06 15:53:07 +0200174 int (*check_int)(struct mxc_nand_host *);
Sascha Hauer63f14742010-10-18 10:16:26 +0200175 void (*irq_control)(struct mxc_nand_host *, int);
Sascha Hauer34f6e152008-09-02 17:16:59 +0200176};
177
Sascha Hauer34f6e152008-09-02 17:16:59 +0200178/* OOB placement block for use with hardware ecc generation */
Sascha Hauer94671142009-10-05 12:14:21 +0200179static struct nand_ecclayout nandv1_hw_eccoob_smallpage = {
Sascha Hauer34f6e152008-09-02 17:16:59 +0200180 .eccbytes = 5,
181 .eccpos = {6, 7, 8, 9, 10},
Sascha Hauer8c1fd892009-10-21 10:22:01 +0200182 .oobfree = {{0, 5}, {12, 4}, }
Sascha Hauer34f6e152008-09-02 17:16:59 +0200183};
184
Sascha Hauer94671142009-10-05 12:14:21 +0200185static struct nand_ecclayout nandv1_hw_eccoob_largepage = {
Vladimir Barinovbd3fd622009-05-25 13:06:17 +0400186 .eccbytes = 20,
187 .eccpos = {6, 7, 8, 9, 10, 22, 23, 24, 25, 26,
188 38, 39, 40, 41, 42, 54, 55, 56, 57, 58},
189 .oobfree = {{2, 4}, {11, 10}, {27, 10}, {43, 10}, {59, 5}, }
Sascha Hauer34f6e152008-09-02 17:16:59 +0200190};
191
Sascha Hauer94671142009-10-05 12:14:21 +0200192/* OOB description for 512 byte pages with 16 byte OOB */
193static struct nand_ecclayout nandv2_hw_eccoob_smallpage = {
194 .eccbytes = 1 * 9,
195 .eccpos = {
196 7, 8, 9, 10, 11, 12, 13, 14, 15
197 },
198 .oobfree = {
199 {.offset = 0, .length = 5}
200 }
201};
202
203/* OOB description for 2048 byte pages with 64 byte OOB */
204static struct nand_ecclayout nandv2_hw_eccoob_largepage = {
205 .eccbytes = 4 * 9,
206 .eccpos = {
207 7, 8, 9, 10, 11, 12, 13, 14, 15,
208 23, 24, 25, 26, 27, 28, 29, 30, 31,
209 39, 40, 41, 42, 43, 44, 45, 46, 47,
210 55, 56, 57, 58, 59, 60, 61, 62, 63
211 },
212 .oobfree = {
213 {.offset = 2, .length = 4},
214 {.offset = 16, .length = 7},
215 {.offset = 32, .length = 7},
216 {.offset = 48, .length = 7}
217 }
218};
219
Baruch Siach2c1c5f12011-03-09 16:12:20 +0200220/* OOB description for 4096 byte pages with 128 byte OOB */
221static struct nand_ecclayout nandv2_hw_eccoob_4k = {
222 .eccbytes = 8 * 9,
223 .eccpos = {
224 7, 8, 9, 10, 11, 12, 13, 14, 15,
225 23, 24, 25, 26, 27, 28, 29, 30, 31,
226 39, 40, 41, 42, 43, 44, 45, 46, 47,
227 55, 56, 57, 58, 59, 60, 61, 62, 63,
228 71, 72, 73, 74, 75, 76, 77, 78, 79,
229 87, 88, 89, 90, 91, 92, 93, 94, 95,
230 103, 104, 105, 106, 107, 108, 109, 110, 111,
231 119, 120, 121, 122, 123, 124, 125, 126, 127,
232 },
233 .oobfree = {
234 {.offset = 2, .length = 4},
235 {.offset = 16, .length = 7},
236 {.offset = 32, .length = 7},
237 {.offset = 48, .length = 7},
238 {.offset = 64, .length = 7},
239 {.offset = 80, .length = 7},
240 {.offset = 96, .length = 7},
241 {.offset = 112, .length = 7},
242 }
243};
244
Sascha Hauer34f6e152008-09-02 17:16:59 +0200245static const char *part_probes[] = { "RedBoot", "cmdlinepart", NULL };
Sascha Hauer34f6e152008-09-02 17:16:59 +0200246
247static irqreturn_t mxc_nfc_irq(int irq, void *dev_id)
248{
249 struct mxc_nand_host *host = dev_id;
250
Sascha Hauer63f14742010-10-18 10:16:26 +0200251 if (!host->check_int(host))
252 return IRQ_NONE;
Sascha Hauer34f6e152008-09-02 17:16:59 +0200253
Sascha Hauer63f14742010-10-18 10:16:26 +0200254 host->irq_control(host, 0);
255
256 complete(&host->op_completion);
Sascha Hauer34f6e152008-09-02 17:16:59 +0200257
258 return IRQ_HANDLED;
259}
260
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
Sascha Hauer63f14742010-10-18 10:16:26 +0200283 if (!cpu_is_mx21())
284 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 +0200289/*
290 * It has been observed that the i.MX21 cannot read the CONFIG2:INT bit
291 * if interrupts are masked (CONFIG1:INT_MSK is set). To handle this, the
292 * driver can enable/disable the irq line rather than simply masking the
293 * interrupts.
294 */
295static void irq_control_mx21(struct mxc_nand_host *host, int activate)
296{
297 if (activate)
298 enable_irq(host->irq);
299 else
300 disable_irq_nosync(host->irq);
301}
302
303static void irq_control_v1_v2(struct mxc_nand_host *host, int activate)
304{
305 uint16_t tmp;
306
307 tmp = readw(NFC_V1_V2_CONFIG1);
308
309 if (activate)
310 tmp &= ~NFC_V1_V2_CONFIG1_INT_MSK;
311 else
312 tmp |= NFC_V1_V2_CONFIG1_INT_MSK;
313
314 writew(tmp, NFC_V1_V2_CONFIG1);
315}
316
317static void irq_control_v3(struct mxc_nand_host *host, int activate)
318{
319 uint32_t tmp;
320
321 tmp = readl(NFC_V3_CONFIG2);
322
323 if (activate)
324 tmp &= ~NFC_V3_CONFIG2_INT_MSK;
325 else
326 tmp |= NFC_V3_CONFIG2_INT_MSK;
327
328 writel(tmp, NFC_V3_CONFIG2);
329}
330
Sascha Hauer34f6e152008-09-02 17:16:59 +0200331/* This function polls the NANDFC to wait for the basic operation to
332 * complete by checking the INT bit of config2 register.
333 */
Sascha Hauerc110eaf2009-10-21 16:01:02 +0200334static void wait_op_done(struct mxc_nand_host *host, int useirq)
Sascha Hauer34f6e152008-09-02 17:16:59 +0200335{
Ivo Claryssea47bfd22010-04-08 16:16:51 +0200336 int max_retries = 8000;
Sascha Hauer34f6e152008-09-02 17:16:59 +0200337
338 if (useirq) {
Sascha Hauer7aaf28a2010-08-06 15:53:07 +0200339 if (!host->check_int(host)) {
Sascha Hauer63f14742010-10-18 10:16:26 +0200340 INIT_COMPLETION(host->op_completion);
341 host->irq_control(host, 1);
342 wait_for_completion(&host->op_completion);
Sascha Hauer34f6e152008-09-02 17:16:59 +0200343 }
344 } else {
345 while (max_retries-- > 0) {
Sascha Hauer7aaf28a2010-08-06 15:53:07 +0200346 if (host->check_int(host))
Sascha Hauer34f6e152008-09-02 17:16:59 +0200347 break;
Sascha Hauer7aaf28a2010-08-06 15:53:07 +0200348
Sascha Hauer34f6e152008-09-02 17:16:59 +0200349 udelay(1);
350 }
Roel Kluin43950a62009-06-04 16:24:59 +0200351 if (max_retries < 0)
Brian Norris0a32a102011-07-19 10:06:10 -0700352 pr_debug("%s: INT not set\n", __func__);
Sascha Hauer34f6e152008-09-02 17:16:59 +0200353 }
354}
355
Sascha Hauer71ec5152010-08-06 15:53:11 +0200356static void send_cmd_v3(struct mxc_nand_host *host, uint16_t cmd, int useirq)
357{
358 /* fill command */
359 writel(cmd, NFC_V3_FLASH_CMD);
360
361 /* send out command */
362 writel(NFC_CMD, NFC_V3_LAUNCH);
363
364 /* Wait for operation to complete */
365 wait_op_done(host, useirq);
366}
367
Sascha Hauer34f6e152008-09-02 17:16:59 +0200368/* This function issues the specified command to the NAND device and
369 * waits for completion. */
Sascha Hauer5f973042010-08-06 15:53:06 +0200370static void send_cmd_v1_v2(struct mxc_nand_host *host, uint16_t cmd, int useirq)
Sascha Hauer34f6e152008-09-02 17:16:59 +0200371{
Brian Norris289c0522011-07-19 10:06:09 -0700372 pr_debug("send_cmd(host, 0x%x, %d)\n", cmd, useirq);
Sascha Hauer34f6e152008-09-02 17:16:59 +0200373
Sascha Hauer1bc99182010-08-06 15:53:08 +0200374 writew(cmd, NFC_V1_V2_FLASH_CMD);
375 writew(NFC_CMD, NFC_V1_V2_CONFIG2);
Sascha Hauer34f6e152008-09-02 17:16:59 +0200376
Ivo Claryssea47bfd22010-04-08 16:16:51 +0200377 if (cpu_is_mx21() && (cmd == NAND_CMD_RESET)) {
378 int max_retries = 100;
379 /* Reset completion is indicated by NFC_CONFIG2 */
380 /* being set to 0 */
381 while (max_retries-- > 0) {
Sascha Hauer1bc99182010-08-06 15:53:08 +0200382 if (readw(NFC_V1_V2_CONFIG2) == 0) {
Ivo Claryssea47bfd22010-04-08 16:16:51 +0200383 break;
384 }
385 udelay(1);
386 }
387 if (max_retries < 0)
Brian Norris0a32a102011-07-19 10:06:10 -0700388 pr_debug("%s: RESET failed\n", __func__);
Ivo Claryssea47bfd22010-04-08 16:16:51 +0200389 } else {
390 /* Wait for operation to complete */
391 wait_op_done(host, useirq);
392 }
Sascha Hauer34f6e152008-09-02 17:16:59 +0200393}
394
Sascha Hauer71ec5152010-08-06 15:53:11 +0200395static void send_addr_v3(struct mxc_nand_host *host, uint16_t addr, int islast)
396{
397 /* fill address */
398 writel(addr, NFC_V3_FLASH_ADDR0);
399
400 /* send out address */
401 writel(NFC_ADDR, NFC_V3_LAUNCH);
402
403 wait_op_done(host, 0);
404}
405
Sascha Hauer34f6e152008-09-02 17:16:59 +0200406/* This function sends an address (or partial address) to the
407 * NAND device. The address is used to select the source/destination for
408 * a NAND command. */
Sascha Hauer5f973042010-08-06 15:53:06 +0200409static void send_addr_v1_v2(struct mxc_nand_host *host, uint16_t addr, int islast)
Sascha Hauer34f6e152008-09-02 17:16:59 +0200410{
Brian Norris289c0522011-07-19 10:06:09 -0700411 pr_debug("send_addr(host, 0x%x %d)\n", addr, islast);
Sascha Hauer34f6e152008-09-02 17:16:59 +0200412
Sascha Hauer1bc99182010-08-06 15:53:08 +0200413 writew(addr, NFC_V1_V2_FLASH_ADDR);
414 writew(NFC_ADDR, NFC_V1_V2_CONFIG2);
Sascha Hauer34f6e152008-09-02 17:16:59 +0200415
416 /* Wait for operation to complete */
Sascha Hauerc110eaf2009-10-21 16:01:02 +0200417 wait_op_done(host, islast);
Sascha Hauer34f6e152008-09-02 17:16:59 +0200418}
419
Sascha Hauer71ec5152010-08-06 15:53:11 +0200420static void send_page_v3(struct mtd_info *mtd, unsigned int ops)
421{
422 struct nand_chip *nand_chip = mtd->priv;
423 struct mxc_nand_host *host = nand_chip->priv;
424 uint32_t tmp;
425
426 tmp = readl(NFC_V3_CONFIG1);
427 tmp &= ~(7 << 4);
428 writel(tmp, NFC_V3_CONFIG1);
429
430 /* transfer data from NFC ram to nand */
431 writel(ops, NFC_V3_LAUNCH);
432
433 wait_op_done(host, false);
434}
435
Sascha Hauer5f973042010-08-06 15:53:06 +0200436static void send_page_v1_v2(struct mtd_info *mtd, unsigned int ops)
Sascha Hauer34f6e152008-09-02 17:16:59 +0200437{
Sascha Hauer2d69c7f2009-10-05 11:24:02 +0200438 struct nand_chip *nand_chip = mtd->priv;
439 struct mxc_nand_host *host = nand_chip->priv;
Sascha Hauerc5d23f12009-06-04 17:25:53 +0200440 int bufs, i;
Sascha Hauer34f6e152008-09-02 17:16:59 +0200441
Sascha Hauer94671142009-10-05 12:14:21 +0200442 if (nfc_is_v1() && mtd->writesize > 512)
Sascha Hauerc5d23f12009-06-04 17:25:53 +0200443 bufs = 4;
444 else
445 bufs = 1;
Sascha Hauer34f6e152008-09-02 17:16:59 +0200446
Sascha Hauerc5d23f12009-06-04 17:25:53 +0200447 for (i = 0; i < bufs; i++) {
448
449 /* NANDFC buffer 0 is used for page read/write */
Baruch Siachd178e3e2011-03-14 09:01:56 +0200450 writew((host->active_cs << 4) | i, NFC_V1_V2_BUF_ADDR);
Sascha Hauerc5d23f12009-06-04 17:25:53 +0200451
Sascha Hauer1bc99182010-08-06 15:53:08 +0200452 writew(ops, NFC_V1_V2_CONFIG2);
Sascha Hauerc5d23f12009-06-04 17:25:53 +0200453
454 /* Wait for operation to complete */
Sascha Hauerc110eaf2009-10-21 16:01:02 +0200455 wait_op_done(host, true);
Sascha Hauer34f6e152008-09-02 17:16:59 +0200456 }
Sascha Hauer34f6e152008-09-02 17:16:59 +0200457}
458
Sascha Hauer71ec5152010-08-06 15:53:11 +0200459static void send_read_id_v3(struct mxc_nand_host *host)
460{
461 /* Read ID into main buffer */
462 writel(NFC_ID, NFC_V3_LAUNCH);
463
464 wait_op_done(host, true);
465
466 memcpy(host->data_buf, host->main_area0, 16);
467}
468
Sascha Hauer34f6e152008-09-02 17:16:59 +0200469/* Request the NANDFC to perform a read of the NAND device ID. */
Sascha Hauer5f973042010-08-06 15:53:06 +0200470static void send_read_id_v1_v2(struct mxc_nand_host *host)
Sascha Hauer34f6e152008-09-02 17:16:59 +0200471{
472 struct nand_chip *this = &host->nand;
Sascha Hauer34f6e152008-09-02 17:16:59 +0200473
474 /* NANDFC buffer 0 is used for device ID output */
Baruch Siachd178e3e2011-03-14 09:01:56 +0200475 writew(host->active_cs << 4, NFC_V1_V2_BUF_ADDR);
Sascha Hauer34f6e152008-09-02 17:16:59 +0200476
Sascha Hauer1bc99182010-08-06 15:53:08 +0200477 writew(NFC_ID, NFC_V1_V2_CONFIG2);
Sascha Hauer34f6e152008-09-02 17:16:59 +0200478
479 /* Wait for operation to complete */
Sascha Hauerc110eaf2009-10-21 16:01:02 +0200480 wait_op_done(host, true);
Sascha Hauer34f6e152008-09-02 17:16:59 +0200481
Sascha Hauerc6de7e12009-10-05 11:14:35 +0200482 memcpy(host->data_buf, host->main_area0, 16);
John Ognessf7b66e52010-06-18 18:59:47 +0200483
484 if (this->options & NAND_BUSWIDTH_16) {
485 /* compress the ID info */
486 host->data_buf[1] = host->data_buf[2];
487 host->data_buf[2] = host->data_buf[4];
488 host->data_buf[3] = host->data_buf[6];
489 host->data_buf[4] = host->data_buf[8];
490 host->data_buf[5] = host->data_buf[10];
491 }
Sascha Hauer34f6e152008-09-02 17:16:59 +0200492}
493
Sascha Hauer71ec5152010-08-06 15:53:11 +0200494static uint16_t get_dev_status_v3(struct mxc_nand_host *host)
Sascha Hauer34f6e152008-09-02 17:16:59 +0200495{
Sascha Hauer71ec5152010-08-06 15:53:11 +0200496 writew(NFC_STATUS, NFC_V3_LAUNCH);
Sascha Hauerc110eaf2009-10-21 16:01:02 +0200497 wait_op_done(host, true);
Sascha Hauer34f6e152008-09-02 17:16:59 +0200498
Sascha Hauer71ec5152010-08-06 15:53:11 +0200499 return readl(NFC_V3_CONFIG1) >> 16;
500}
501
Sascha Hauer34f6e152008-09-02 17:16:59 +0200502/* This function requests the NANDFC to perform a read of the
503 * NAND device status and returns the current status. */
Sascha Hauer5f973042010-08-06 15:53:06 +0200504static uint16_t get_dev_status_v1_v2(struct mxc_nand_host *host)
Sascha Hauer34f6e152008-09-02 17:16:59 +0200505{
Sascha Hauerc29c6072010-08-06 15:53:05 +0200506 void __iomem *main_buf = host->main_area0;
Sascha Hauer34f6e152008-09-02 17:16:59 +0200507 uint32_t store;
508 uint16_t ret;
Sascha Hauer34f6e152008-09-02 17:16:59 +0200509
Baruch Siachd178e3e2011-03-14 09:01:56 +0200510 writew(host->active_cs << 4, NFC_V1_V2_BUF_ADDR);
Sascha Hauerc29c6072010-08-06 15:53:05 +0200511
512 /*
513 * The device status is stored in main_area0. To
514 * prevent corruption of the buffer save the value
515 * and restore it afterwards.
516 */
Sascha Hauer34f6e152008-09-02 17:16:59 +0200517 store = readl(main_buf);
Sascha Hauer34f6e152008-09-02 17:16:59 +0200518
Sascha Hauer1bc99182010-08-06 15:53:08 +0200519 writew(NFC_STATUS, NFC_V1_V2_CONFIG2);
Sascha Hauer34f6e152008-09-02 17:16:59 +0200520 wait_op_done(host, true);
521
Sascha Hauer34f6e152008-09-02 17:16:59 +0200522 ret = readw(main_buf);
Sascha Hauerc29c6072010-08-06 15:53:05 +0200523
Sascha Hauer34f6e152008-09-02 17:16:59 +0200524 writel(store, main_buf);
525
526 return ret;
527}
528
529/* This functions is used by upper layer to checks if device is ready */
530static int mxc_nand_dev_ready(struct mtd_info *mtd)
531{
532 /*
533 * NFC handles R/B internally. Therefore, this function
534 * always returns status as ready.
535 */
536 return 1;
537}
538
539static void mxc_nand_enable_hwecc(struct mtd_info *mtd, int mode)
540{
541 /*
542 * If HW ECC is enabled, we turn it on during init. There is
543 * no need to enable again here.
544 */
545}
546
Sascha Hauer94f77e52010-08-06 15:53:09 +0200547static int mxc_nand_correct_data_v1(struct mtd_info *mtd, u_char *dat,
Sascha Hauer34f6e152008-09-02 17:16:59 +0200548 u_char *read_ecc, u_char *calc_ecc)
549{
550 struct nand_chip *nand_chip = mtd->priv;
551 struct mxc_nand_host *host = nand_chip->priv;
552
553 /*
554 * 1-Bit errors are automatically corrected in HW. No need for
555 * additional correction. 2-Bit errors cannot be corrected by
556 * HW ECC, so we need to return failure
557 */
Sascha Hauer1bc99182010-08-06 15:53:08 +0200558 uint16_t ecc_status = readw(NFC_V1_V2_ECC_STATUS_RESULT);
Sascha Hauer34f6e152008-09-02 17:16:59 +0200559
560 if (((ecc_status & 0x3) == 2) || ((ecc_status >> 2) == 2)) {
Brian Norris289c0522011-07-19 10:06:09 -0700561 pr_debug("MXC_NAND: HWECC uncorrectable 2-bit ECC error\n");
Sascha Hauer34f6e152008-09-02 17:16:59 +0200562 return -1;
563 }
564
565 return 0;
566}
567
Sascha Hauer94f77e52010-08-06 15:53:09 +0200568static int mxc_nand_correct_data_v2_v3(struct mtd_info *mtd, u_char *dat,
569 u_char *read_ecc, u_char *calc_ecc)
570{
571 struct nand_chip *nand_chip = mtd->priv;
572 struct mxc_nand_host *host = nand_chip->priv;
573 u32 ecc_stat, err;
574 int no_subpages = 1;
575 int ret = 0;
576 u8 ecc_bit_mask, err_limit;
577
578 ecc_bit_mask = (host->eccsize == 4) ? 0x7 : 0xf;
579 err_limit = (host->eccsize == 4) ? 0x4 : 0x8;
580
581 no_subpages = mtd->writesize >> 9;
582
Sascha Hauer71ec5152010-08-06 15:53:11 +0200583 if (nfc_is_v21())
584 ecc_stat = readl(NFC_V1_V2_ECC_STATUS_RESULT);
585 else
586 ecc_stat = readl(NFC_V3_ECC_STATUS_RESULT);
Sascha Hauer94f77e52010-08-06 15:53:09 +0200587
588 do {
589 err = ecc_stat & ecc_bit_mask;
590 if (err > err_limit) {
591 printk(KERN_WARNING "UnCorrectable RS-ECC Error\n");
592 return -1;
593 } else {
594 ret += err;
595 }
596 ecc_stat >>= 4;
597 } while (--no_subpages);
598
599 mtd->ecc_stats.corrected += ret;
600 pr_debug("%d Symbol Correctable RS-ECC Error\n", ret);
601
602 return ret;
603}
604
Sascha Hauer34f6e152008-09-02 17:16:59 +0200605static int mxc_nand_calculate_ecc(struct mtd_info *mtd, const u_char *dat,
606 u_char *ecc_code)
607{
608 return 0;
609}
610
611static u_char mxc_nand_read_byte(struct mtd_info *mtd)
612{
613 struct nand_chip *nand_chip = mtd->priv;
614 struct mxc_nand_host *host = nand_chip->priv;
Sascha Hauerf8f96082009-06-04 17:12:26 +0200615 uint8_t ret;
Sascha Hauer34f6e152008-09-02 17:16:59 +0200616
617 /* Check for status request */
618 if (host->status_request)
Sascha Hauer5f973042010-08-06 15:53:06 +0200619 return host->get_dev_status(host) & 0xFF;
Sascha Hauer34f6e152008-09-02 17:16:59 +0200620
Sascha Hauerf8f96082009-06-04 17:12:26 +0200621 ret = *(uint8_t *)(host->data_buf + host->buf_start);
622 host->buf_start++;
Sascha Hauer34f6e152008-09-02 17:16:59 +0200623
624 return ret;
625}
626
627static uint16_t mxc_nand_read_word(struct mtd_info *mtd)
628{
629 struct nand_chip *nand_chip = mtd->priv;
630 struct mxc_nand_host *host = nand_chip->priv;
Sascha Hauerf8f96082009-06-04 17:12:26 +0200631 uint16_t ret;
Sascha Hauer34f6e152008-09-02 17:16:59 +0200632
Sascha Hauerf8f96082009-06-04 17:12:26 +0200633 ret = *(uint16_t *)(host->data_buf + host->buf_start);
634 host->buf_start += 2;
Sascha Hauer34f6e152008-09-02 17:16:59 +0200635
636 return ret;
637}
638
639/* Write data of length len to buffer buf. The data to be
640 * written on NAND Flash is first copied to RAMbuffer. After the Data Input
641 * Operation by the NFC, the data is written to NAND Flash */
642static void mxc_nand_write_buf(struct mtd_info *mtd,
643 const u_char *buf, int len)
644{
645 struct nand_chip *nand_chip = mtd->priv;
646 struct mxc_nand_host *host = nand_chip->priv;
Sascha Hauerf8f96082009-06-04 17:12:26 +0200647 u16 col = host->buf_start;
648 int n = mtd->oobsize + mtd->writesize - col;
Sascha Hauer34f6e152008-09-02 17:16:59 +0200649
Sascha Hauerf8f96082009-06-04 17:12:26 +0200650 n = min(n, len);
Sascha Hauer34f6e152008-09-02 17:16:59 +0200651
Sascha Hauerf8f96082009-06-04 17:12:26 +0200652 memcpy(host->data_buf + col, buf, n);
Sascha Hauer34f6e152008-09-02 17:16:59 +0200653
Sascha Hauerf8f96082009-06-04 17:12:26 +0200654 host->buf_start += n;
Sascha Hauer34f6e152008-09-02 17:16:59 +0200655}
656
657/* Read the data buffer from the NAND Flash. To read the data from NAND
658 * Flash first the data output cycle is initiated by the NFC, which copies
659 * the data to RAMbuffer. This data of length len is then copied to buffer buf.
660 */
661static void mxc_nand_read_buf(struct mtd_info *mtd, u_char *buf, int len)
662{
663 struct nand_chip *nand_chip = mtd->priv;
664 struct mxc_nand_host *host = nand_chip->priv;
Sascha Hauerf8f96082009-06-04 17:12:26 +0200665 u16 col = host->buf_start;
666 int n = mtd->oobsize + mtd->writesize - col;
Sascha Hauer34f6e152008-09-02 17:16:59 +0200667
Sascha Hauerf8f96082009-06-04 17:12:26 +0200668 n = min(n, len);
Sascha Hauer34f6e152008-09-02 17:16:59 +0200669
Baruch Siach5d9d9932011-03-02 16:47:55 +0200670 memcpy(buf, host->data_buf + col, n);
Sascha Hauer34f6e152008-09-02 17:16:59 +0200671
Baruch Siach5d9d9932011-03-02 16:47:55 +0200672 host->buf_start += n;
Sascha Hauer34f6e152008-09-02 17:16:59 +0200673}
674
675/* Used by the upper layer to verify the data in NAND Flash
676 * with the data in the buf. */
677static int mxc_nand_verify_buf(struct mtd_info *mtd,
678 const u_char *buf, int len)
679{
680 return -EFAULT;
681}
682
683/* This function is used by upper layer for select and
684 * deselect of the NAND chip */
685static void mxc_nand_select_chip(struct mtd_info *mtd, int chip)
686{
687 struct nand_chip *nand_chip = mtd->priv;
688 struct mxc_nand_host *host = nand_chip->priv;
689
Baruch Siachd178e3e2011-03-14 09:01:56 +0200690 if (chip == -1) {
Sascha Hauer34f6e152008-09-02 17:16:59 +0200691 /* Disable the NFC clock */
692 if (host->clk_act) {
693 clk_disable(host->clk);
694 host->clk_act = 0;
695 }
Baruch Siachd178e3e2011-03-14 09:01:56 +0200696 return;
697 }
Sascha Hauer34f6e152008-09-02 17:16:59 +0200698
Baruch Siachd178e3e2011-03-14 09:01:56 +0200699 if (!host->clk_act) {
700 /* Enable the NFC clock */
701 clk_enable(host->clk);
702 host->clk_act = 1;
703 }
704
705 if (nfc_is_v21()) {
706 host->active_cs = chip;
707 writew(host->active_cs << 4, NFC_V1_V2_BUF_ADDR);
Sascha Hauer34f6e152008-09-02 17:16:59 +0200708 }
709}
710
Sascha Hauerf8f96082009-06-04 17:12:26 +0200711/*
712 * Function to transfer data to/from spare area.
713 */
714static void copy_spare(struct mtd_info *mtd, bool bfrom)
715{
716 struct nand_chip *this = mtd->priv;
717 struct mxc_nand_host *host = this->priv;
718 u16 i, j;
719 u16 n = mtd->writesize >> 9;
720 u8 *d = host->data_buf + mtd->writesize;
Sascha Hauerc6de7e12009-10-05 11:14:35 +0200721 u8 *s = host->spare0;
Sascha Hauerf8f96082009-06-04 17:12:26 +0200722 u16 t = host->spare_len;
723
724 j = (mtd->oobsize / n >> 1) << 1;
725
726 if (bfrom) {
727 for (i = 0; i < n - 1; i++)
728 memcpy(d + i * j, s + i * t, j);
729
730 /* the last section */
731 memcpy(d + i * j, s + i * t, mtd->oobsize - i * j);
732 } else {
733 for (i = 0; i < n - 1; i++)
734 memcpy(&s[i * t], &d[i * j], j);
735
736 /* the last section */
737 memcpy(&s[i * t], &d[i * j], mtd->oobsize - i * j);
738 }
739}
740
Sascha Hauera3e65b62009-06-02 11:47:59 +0200741static void mxc_do_addr_cycle(struct mtd_info *mtd, int column, int page_addr)
Sascha Hauer34f6e152008-09-02 17:16:59 +0200742{
743 struct nand_chip *nand_chip = mtd->priv;
744 struct mxc_nand_host *host = nand_chip->priv;
Sascha Hauer34f6e152008-09-02 17:16:59 +0200745
746 /* Write out column address, if necessary */
747 if (column != -1) {
748 /*
749 * MXC NANDFC can only perform full page+spare or
750 * spare-only read/write. When the upper layers
Gilles Espinasse177b2412011-01-09 08:59:49 +0100751 * perform a read/write buf operation, the saved column
752 * address is used to index into the full page.
Sascha Hauer34f6e152008-09-02 17:16:59 +0200753 */
Sascha Hauer5f973042010-08-06 15:53:06 +0200754 host->send_addr(host, 0, page_addr == -1);
Sascha Hauer2d69c7f2009-10-05 11:24:02 +0200755 if (mtd->writesize > 512)
Sascha Hauer34f6e152008-09-02 17:16:59 +0200756 /* another col addr cycle for 2k page */
Sascha Hauer5f973042010-08-06 15:53:06 +0200757 host->send_addr(host, 0, false);
Sascha Hauer34f6e152008-09-02 17:16:59 +0200758 }
759
760 /* Write out page address, if necessary */
761 if (page_addr != -1) {
762 /* paddr_0 - p_addr_7 */
Sascha Hauer5f973042010-08-06 15:53:06 +0200763 host->send_addr(host, (page_addr & 0xff), false);
Sascha Hauer34f6e152008-09-02 17:16:59 +0200764
Sascha Hauer2d69c7f2009-10-05 11:24:02 +0200765 if (mtd->writesize > 512) {
Vladimir Barinovbd3fd622009-05-25 13:06:17 +0400766 if (mtd->size >= 0x10000000) {
767 /* paddr_8 - paddr_15 */
Sascha Hauer5f973042010-08-06 15:53:06 +0200768 host->send_addr(host, (page_addr >> 8) & 0xff, false);
769 host->send_addr(host, (page_addr >> 16) & 0xff, true);
Vladimir Barinovbd3fd622009-05-25 13:06:17 +0400770 } else
771 /* paddr_8 - paddr_15 */
Sascha Hauer5f973042010-08-06 15:53:06 +0200772 host->send_addr(host, (page_addr >> 8) & 0xff, true);
Sascha Hauer34f6e152008-09-02 17:16:59 +0200773 } else {
774 /* One more address cycle for higher density devices */
775 if (mtd->size >= 0x4000000) {
776 /* paddr_8 - paddr_15 */
Sascha Hauer5f973042010-08-06 15:53:06 +0200777 host->send_addr(host, (page_addr >> 8) & 0xff, false);
778 host->send_addr(host, (page_addr >> 16) & 0xff, true);
Sascha Hauer34f6e152008-09-02 17:16:59 +0200779 } else
780 /* paddr_8 - paddr_15 */
Sascha Hauer5f973042010-08-06 15:53:06 +0200781 host->send_addr(host, (page_addr >> 8) & 0xff, true);
Sascha Hauer34f6e152008-09-02 17:16:59 +0200782 }
783 }
Sascha Hauera3e65b62009-06-02 11:47:59 +0200784}
Sascha Hauer34f6e152008-09-02 17:16:59 +0200785
Sascha Hauer6e85dfd2010-08-06 15:53:10 +0200786/*
787 * v2 and v3 type controllers can do 4bit or 8bit ecc depending
788 * on how much oob the nand chip has. For 8bit ecc we need at least
789 * 26 bytes of oob data per 512 byte block.
790 */
791static int get_eccsize(struct mtd_info *mtd)
792{
793 int oobbytes_per_512 = 0;
794
795 oobbytes_per_512 = mtd->oobsize * 512 / mtd->writesize;
796
797 if (oobbytes_per_512 < 26)
798 return 4;
799 else
800 return 8;
801}
802
Sascha Hauer5f973042010-08-06 15:53:06 +0200803static void preset_v1_v2(struct mtd_info *mtd)
Ivo Claryssed4840182010-04-08 16:14:44 +0200804{
805 struct nand_chip *nand_chip = mtd->priv;
806 struct mxc_nand_host *host = nand_chip->priv;
Sascha Hauerb8db2f52010-08-09 15:04:19 +0200807 uint16_t config1 = 0;
Ivo Claryssed4840182010-04-08 16:14:44 +0200808
Sascha Hauerb8db2f52010-08-09 15:04:19 +0200809 if (nand_chip->ecc.mode == NAND_ECC_HW)
810 config1 |= NFC_V1_V2_CONFIG1_ECC_EN;
811
812 if (nfc_is_v21())
813 config1 |= NFC_V2_CONFIG1_FP_INT;
814
815 if (!cpu_is_mx21())
816 config1 |= NFC_V1_V2_CONFIG1_INT_MSK;
Sascha Hauer6e85dfd2010-08-06 15:53:10 +0200817
818 if (nfc_is_v21() && mtd->writesize) {
Sascha Hauerb8db2f52010-08-09 15:04:19 +0200819 uint16_t pages_per_block = mtd->erasesize / mtd->writesize;
820
Sascha Hauer6e85dfd2010-08-06 15:53:10 +0200821 host->eccsize = get_eccsize(mtd);
822 if (host->eccsize == 4)
Sascha Hauerb8db2f52010-08-09 15:04:19 +0200823 config1 |= NFC_V2_CONFIG1_ECC_MODE_4;
824
825 config1 |= NFC_V2_CONFIG1_PPB(ffs(pages_per_block) - 6);
Sascha Hauer6e85dfd2010-08-06 15:53:10 +0200826 } else {
827 host->eccsize = 1;
828 }
829
Sascha Hauerb8db2f52010-08-09 15:04:19 +0200830 writew(config1, NFC_V1_V2_CONFIG1);
Ivo Claryssed4840182010-04-08 16:14:44 +0200831 /* preset operation */
832
833 /* Unlock the internal RAM Buffer */
Sascha Hauer1bc99182010-08-06 15:53:08 +0200834 writew(0x2, NFC_V1_V2_CONFIG);
Ivo Claryssed4840182010-04-08 16:14:44 +0200835
836 /* Blocks to be unlocked */
837 if (nfc_is_v21()) {
Baruch Siachd178e3e2011-03-14 09:01:56 +0200838 writew(0x0, NFC_V21_UNLOCKSTART_BLKADDR0);
839 writew(0x0, NFC_V21_UNLOCKSTART_BLKADDR1);
840 writew(0x0, NFC_V21_UNLOCKSTART_BLKADDR2);
841 writew(0x0, NFC_V21_UNLOCKSTART_BLKADDR3);
842 writew(0xffff, NFC_V21_UNLOCKEND_BLKADDR0);
843 writew(0xffff, NFC_V21_UNLOCKEND_BLKADDR1);
844 writew(0xffff, NFC_V21_UNLOCKEND_BLKADDR2);
845 writew(0xffff, NFC_V21_UNLOCKEND_BLKADDR3);
Ivo Claryssed4840182010-04-08 16:14:44 +0200846 } else if (nfc_is_v1()) {
Sascha Hauer1bc99182010-08-06 15:53:08 +0200847 writew(0x0, NFC_V1_UNLOCKSTART_BLKADDR);
Wolfram Stering5172ac12011-09-23 13:53:44 +0200848 writew(0xffff, NFC_V1_UNLOCKEND_BLKADDR);
Ivo Claryssed4840182010-04-08 16:14:44 +0200849 } else
850 BUG();
851
852 /* Unlock Block Command for given address range */
Sascha Hauer1bc99182010-08-06 15:53:08 +0200853 writew(0x4, NFC_V1_V2_WRPROT);
Ivo Claryssed4840182010-04-08 16:14:44 +0200854}
855
Sascha Hauer71ec5152010-08-06 15:53:11 +0200856static void preset_v3(struct mtd_info *mtd)
857{
858 struct nand_chip *chip = mtd->priv;
859 struct mxc_nand_host *host = chip->priv;
860 uint32_t config2, config3;
861 int i, addr_phases;
862
863 writel(NFC_V3_CONFIG1_RBA(0), NFC_V3_CONFIG1);
864 writel(NFC_V3_IPC_CREQ, NFC_V3_IPC);
865
866 /* Unlock the internal RAM Buffer */
867 writel(NFC_V3_WRPROT_BLS_UNLOCK | NFC_V3_WRPROT_UNLOCK,
868 NFC_V3_WRPROT);
869
870 /* Blocks to be unlocked */
871 for (i = 0; i < NAND_MAX_CHIPS; i++)
872 writel(0x0 | (0xffff << 16),
873 NFC_V3_WRPROT_UNLOCK_BLK_ADD0 + (i << 2));
874
875 writel(0, NFC_V3_IPC);
876
877 config2 = NFC_V3_CONFIG2_ONE_CYCLE |
878 NFC_V3_CONFIG2_2CMD_PHASES |
879 NFC_V3_CONFIG2_SPAS(mtd->oobsize >> 1) |
880 NFC_V3_CONFIG2_ST_CMD(0x70) |
Sascha Hauer63f14742010-10-18 10:16:26 +0200881 NFC_V3_CONFIG2_INT_MSK |
Sascha Hauer71ec5152010-08-06 15:53:11 +0200882 NFC_V3_CONFIG2_NUM_ADDR_PHASE0;
883
884 if (chip->ecc.mode == NAND_ECC_HW)
885 config2 |= NFC_V3_CONFIG2_ECC_EN;
886
887 addr_phases = fls(chip->pagemask) >> 3;
888
889 if (mtd->writesize == 2048) {
890 config2 |= NFC_V3_CONFIG2_PS_2048;
891 config2 |= NFC_V3_CONFIG2_NUM_ADDR_PHASE1(addr_phases);
892 } else if (mtd->writesize == 4096) {
893 config2 |= NFC_V3_CONFIG2_PS_4096;
894 config2 |= NFC_V3_CONFIG2_NUM_ADDR_PHASE1(addr_phases);
895 } else {
896 config2 |= NFC_V3_CONFIG2_PS_512;
897 config2 |= NFC_V3_CONFIG2_NUM_ADDR_PHASE1(addr_phases - 1);
898 }
899
900 if (mtd->writesize) {
901 config2 |= NFC_V3_CONFIG2_PPB(ffs(mtd->erasesize / mtd->writesize) - 6);
902 host->eccsize = get_eccsize(mtd);
903 if (host->eccsize == 8)
904 config2 |= NFC_V3_CONFIG2_ECC_MODE_8;
905 }
906
907 writel(config2, NFC_V3_CONFIG2);
908
909 config3 = NFC_V3_CONFIG3_NUM_OF_DEVICES(0) |
910 NFC_V3_CONFIG3_NO_SDMA |
911 NFC_V3_CONFIG3_RBB_MODE |
912 NFC_V3_CONFIG3_SBB(6) | /* Reset default */
913 NFC_V3_CONFIG3_ADD_OP(0);
914
915 if (!(chip->options & NAND_BUSWIDTH_16))
916 config3 |= NFC_V3_CONFIG3_FW8;
917
918 writel(config3, NFC_V3_CONFIG3);
919
920 writel(0, NFC_V3_DELAY_LINE);
Sascha Hauer34f6e152008-09-02 17:16:59 +0200921}
922
Sascha Hauer34f6e152008-09-02 17:16:59 +0200923/* Used by the upper layer to write command to NAND Flash for
924 * different operations to be carried out on NAND Flash */
925static void mxc_nand_command(struct mtd_info *mtd, unsigned command,
926 int column, int page_addr)
927{
928 struct nand_chip *nand_chip = mtd->priv;
929 struct mxc_nand_host *host = nand_chip->priv;
Sascha Hauer34f6e152008-09-02 17:16:59 +0200930
Brian Norris289c0522011-07-19 10:06:09 -0700931 pr_debug("mxc_nand_command (cmd = 0x%x, col = 0x%x, page = 0x%x)\n",
Sascha Hauer34f6e152008-09-02 17:16:59 +0200932 command, column, page_addr);
933
934 /* Reset command state information */
935 host->status_request = false;
936
937 /* Command pre-processing step */
Sascha Hauer34f6e152008-09-02 17:16:59 +0200938 switch (command) {
Ivo Claryssed4840182010-04-08 16:14:44 +0200939 case NAND_CMD_RESET:
Sascha Hauer5f973042010-08-06 15:53:06 +0200940 host->preset(mtd);
941 host->send_cmd(host, command, false);
Ivo Claryssed4840182010-04-08 16:14:44 +0200942 break;
Sascha Hauer34f6e152008-09-02 17:16:59 +0200943
Sascha Hauer34f6e152008-09-02 17:16:59 +0200944 case NAND_CMD_STATUS:
Sascha Hauerf8f96082009-06-04 17:12:26 +0200945 host->buf_start = 0;
Sascha Hauer34f6e152008-09-02 17:16:59 +0200946 host->status_request = true;
Sascha Hauer89121a62009-06-04 17:18:01 +0200947
Sascha Hauer5f973042010-08-06 15:53:06 +0200948 host->send_cmd(host, command, true);
Sascha Hauer89121a62009-06-04 17:18:01 +0200949 mxc_do_addr_cycle(mtd, column, page_addr);
Sascha Hauer34f6e152008-09-02 17:16:59 +0200950 break;
951
Sascha Hauer34f6e152008-09-02 17:16:59 +0200952 case NAND_CMD_READ0:
Sascha Hauer34f6e152008-09-02 17:16:59 +0200953 case NAND_CMD_READOOB:
Sascha Hauer89121a62009-06-04 17:18:01 +0200954 if (command == NAND_CMD_READ0)
955 host->buf_start = column;
956 else
957 host->buf_start = column + mtd->writesize;
Sascha Hauerf8f96082009-06-04 17:12:26 +0200958
Sascha Hauer5ea32022010-04-27 15:24:01 +0200959 command = NAND_CMD_READ0; /* only READ0 is valid */
Sascha Hauer89121a62009-06-04 17:18:01 +0200960
Sascha Hauer5f973042010-08-06 15:53:06 +0200961 host->send_cmd(host, command, false);
Sascha Hauer89121a62009-06-04 17:18:01 +0200962 mxc_do_addr_cycle(mtd, column, page_addr);
963
Sascha Hauer2d69c7f2009-10-05 11:24:02 +0200964 if (mtd->writesize > 512)
Sascha Hauer5f973042010-08-06 15:53:06 +0200965 host->send_cmd(host, NAND_CMD_READSTART, true);
Sascha Hauerc5d23f12009-06-04 17:25:53 +0200966
Sascha Hauer5f973042010-08-06 15:53:06 +0200967 host->send_page(mtd, NFC_OUTPUT);
Sascha Hauer89121a62009-06-04 17:18:01 +0200968
Sascha Hauerc6de7e12009-10-05 11:14:35 +0200969 memcpy(host->data_buf, host->main_area0, mtd->writesize);
Sascha Hauer89121a62009-06-04 17:18:01 +0200970 copy_spare(mtd, true);
Sascha Hauer34f6e152008-09-02 17:16:59 +0200971 break;
972
Sascha Hauer34f6e152008-09-02 17:16:59 +0200973 case NAND_CMD_SEQIN:
Sascha Hauer5ea32022010-04-27 15:24:01 +0200974 if (column >= mtd->writesize)
975 /* call ourself to read a page */
976 mxc_nand_command(mtd, NAND_CMD_READ0, 0, page_addr);
Sascha Hauer34f6e152008-09-02 17:16:59 +0200977
Sascha Hauer5ea32022010-04-27 15:24:01 +0200978 host->buf_start = column;
Sascha Hauer89121a62009-06-04 17:18:01 +0200979
Sascha Hauer5f973042010-08-06 15:53:06 +0200980 host->send_cmd(host, command, false);
Sascha Hauer89121a62009-06-04 17:18:01 +0200981 mxc_do_addr_cycle(mtd, column, page_addr);
Sascha Hauer34f6e152008-09-02 17:16:59 +0200982 break;
983
984 case NAND_CMD_PAGEPROG:
Sascha Hauerc6de7e12009-10-05 11:14:35 +0200985 memcpy(host->main_area0, host->data_buf, mtd->writesize);
Sascha Hauerf8f96082009-06-04 17:12:26 +0200986 copy_spare(mtd, false);
Sascha Hauer5f973042010-08-06 15:53:06 +0200987 host->send_page(mtd, NFC_INPUT);
988 host->send_cmd(host, command, true);
Sascha Hauer89121a62009-06-04 17:18:01 +0200989 mxc_do_addr_cycle(mtd, column, page_addr);
Sascha Hauer34f6e152008-09-02 17:16:59 +0200990 break;
991
Sascha Hauer34f6e152008-09-02 17:16:59 +0200992 case NAND_CMD_READID:
Sascha Hauer5f973042010-08-06 15:53:06 +0200993 host->send_cmd(host, command, true);
Sascha Hauer89121a62009-06-04 17:18:01 +0200994 mxc_do_addr_cycle(mtd, column, page_addr);
Sascha Hauer5f973042010-08-06 15:53:06 +0200995 host->send_read_id(host);
Sascha Hauer94671142009-10-05 12:14:21 +0200996 host->buf_start = column;
Sascha Hauer34f6e152008-09-02 17:16:59 +0200997 break;
998
Sascha Hauer89121a62009-06-04 17:18:01 +0200999 case NAND_CMD_ERASE1:
Sascha Hauer34f6e152008-09-02 17:16:59 +02001000 case NAND_CMD_ERASE2:
Sascha Hauer5f973042010-08-06 15:53:06 +02001001 host->send_cmd(host, command, false);
Sascha Hauer89121a62009-06-04 17:18:01 +02001002 mxc_do_addr_cycle(mtd, column, page_addr);
1003
Sascha Hauer34f6e152008-09-02 17:16:59 +02001004 break;
1005 }
1006}
1007
Sascha Hauerf1372052009-10-21 14:25:27 +02001008/*
1009 * The generic flash bbt decriptors overlap with our ecc
1010 * hardware, so define some i.MX specific ones.
1011 */
1012static uint8_t bbt_pattern[] = { 'B', 'b', 't', '0' };
1013static uint8_t mirror_pattern[] = { '1', 't', 'b', 'B' };
1014
1015static struct nand_bbt_descr bbt_main_descr = {
1016 .options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE
1017 | NAND_BBT_2BIT | NAND_BBT_VERSION | NAND_BBT_PERCHIP,
1018 .offs = 0,
1019 .len = 4,
1020 .veroffs = 4,
1021 .maxblocks = 4,
1022 .pattern = bbt_pattern,
1023};
1024
1025static struct nand_bbt_descr bbt_mirror_descr = {
1026 .options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE
1027 | NAND_BBT_2BIT | NAND_BBT_VERSION | NAND_BBT_PERCHIP,
1028 .offs = 0,
1029 .len = 4,
1030 .veroffs = 4,
1031 .maxblocks = 4,
1032 .pattern = mirror_pattern,
1033};
1034
Sascha Hauer34f6e152008-09-02 17:16:59 +02001035static int __init mxcnd_probe(struct platform_device *pdev)
1036{
1037 struct nand_chip *this;
1038 struct mtd_info *mtd;
1039 struct mxc_nand_platform_data *pdata = pdev->dev.platform_data;
1040 struct mxc_nand_host *host;
1041 struct resource *res;
Dmitry Eremin-Solenikovd4ed8f12011-06-02 18:00:43 +04001042 int err = 0;
Sascha Hauer94671142009-10-05 12:14:21 +02001043 struct nand_ecclayout *oob_smallpage, *oob_largepage;
Sascha Hauer34f6e152008-09-02 17:16:59 +02001044
1045 /* Allocate memory for MTD device structure and private data */
Sascha Hauerf8f96082009-06-04 17:12:26 +02001046 host = kzalloc(sizeof(struct mxc_nand_host) + NAND_MAX_PAGESIZE +
1047 NAND_MAX_OOBSIZE, GFP_KERNEL);
Sascha Hauer34f6e152008-09-02 17:16:59 +02001048 if (!host)
1049 return -ENOMEM;
1050
Sascha Hauerf8f96082009-06-04 17:12:26 +02001051 host->data_buf = (uint8_t *)(host + 1);
Sascha Hauerf8f96082009-06-04 17:12:26 +02001052
Sascha Hauer34f6e152008-09-02 17:16:59 +02001053 host->dev = &pdev->dev;
1054 /* structures must be linked */
1055 this = &host->nand;
1056 mtd = &host->mtd;
1057 mtd->priv = this;
1058 mtd->owner = THIS_MODULE;
David Brownell87f39f02009-03-26 00:42:50 -07001059 mtd->dev.parent = &pdev->dev;
Sascha Hauer1fbff0a2009-10-21 16:06:27 +02001060 mtd->name = DRIVER_NAME;
Sascha Hauer34f6e152008-09-02 17:16:59 +02001061
1062 /* 50 us command delay time */
1063 this->chip_delay = 5;
1064
1065 this->priv = host;
1066 this->dev_ready = mxc_nand_dev_ready;
1067 this->cmdfunc = mxc_nand_command;
1068 this->select_chip = mxc_nand_select_chip;
1069 this->read_byte = mxc_nand_read_byte;
1070 this->read_word = mxc_nand_read_word;
1071 this->write_buf = mxc_nand_write_buf;
1072 this->read_buf = mxc_nand_read_buf;
1073 this->verify_buf = mxc_nand_verify_buf;
1074
Sascha Hauere65fb002009-02-16 14:29:10 +01001075 host->clk = clk_get(&pdev->dev, "nfc");
Vladimir Barinov8541c112009-04-23 15:47:22 +04001076 if (IS_ERR(host->clk)) {
1077 err = PTR_ERR(host->clk);
Sascha Hauer34f6e152008-09-02 17:16:59 +02001078 goto eclk;
Vladimir Barinov8541c112009-04-23 15:47:22 +04001079 }
Sascha Hauer34f6e152008-09-02 17:16:59 +02001080
1081 clk_enable(host->clk);
1082 host->clk_act = 1;
1083
1084 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
1085 if (!res) {
1086 err = -ENODEV;
1087 goto eres;
1088 }
1089
Sascha Hauerc6de7e12009-10-05 11:14:35 +02001090 host->base = ioremap(res->start, resource_size(res));
1091 if (!host->base) {
Vladimir Barinov8541c112009-04-23 15:47:22 +04001092 err = -ENOMEM;
Sascha Hauer34f6e152008-09-02 17:16:59 +02001093 goto eres;
1094 }
1095
Sascha Hauerc6de7e12009-10-05 11:14:35 +02001096 host->main_area0 = host->base;
Sascha Hauer94671142009-10-05 12:14:21 +02001097
Sascha Hauer5f973042010-08-06 15:53:06 +02001098 if (nfc_is_v1() || nfc_is_v21()) {
1099 host->preset = preset_v1_v2;
1100 host->send_cmd = send_cmd_v1_v2;
1101 host->send_addr = send_addr_v1_v2;
1102 host->send_page = send_page_v1_v2;
1103 host->send_read_id = send_read_id_v1_v2;
1104 host->get_dev_status = get_dev_status_v1_v2;
Sascha Hauer7aaf28a2010-08-06 15:53:07 +02001105 host->check_int = check_int_v1_v2;
Sascha Hauer63f14742010-10-18 10:16:26 +02001106 if (cpu_is_mx21())
1107 host->irq_control = irq_control_mx21;
1108 else
1109 host->irq_control = irq_control_v1_v2;
Sascha Hauer5f973042010-08-06 15:53:06 +02001110 }
Sascha Hauer94671142009-10-05 12:14:21 +02001111
1112 if (nfc_is_v21()) {
Sascha Hauer938cf992010-08-06 15:53:04 +02001113 host->regs = host->base + 0x1e00;
Sascha Hauer94671142009-10-05 12:14:21 +02001114 host->spare0 = host->base + 0x1000;
1115 host->spare_len = 64;
1116 oob_smallpage = &nandv2_hw_eccoob_smallpage;
1117 oob_largepage = &nandv2_hw_eccoob_largepage;
Ivo Claryssed4840182010-04-08 16:14:44 +02001118 this->ecc.bytes = 9;
Sascha Hauer94671142009-10-05 12:14:21 +02001119 } else if (nfc_is_v1()) {
Sascha Hauer938cf992010-08-06 15:53:04 +02001120 host->regs = host->base + 0xe00;
Sascha Hauer94671142009-10-05 12:14:21 +02001121 host->spare0 = host->base + 0x800;
1122 host->spare_len = 16;
1123 oob_smallpage = &nandv1_hw_eccoob_smallpage;
1124 oob_largepage = &nandv1_hw_eccoob_largepage;
Sascha Hauer94671142009-10-05 12:14:21 +02001125 this->ecc.bytes = 3;
Sascha Hauer71ec5152010-08-06 15:53:11 +02001126 host->eccsize = 1;
1127 } else if (nfc_is_v3_2()) {
1128 res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
1129 if (!res) {
1130 err = -ENODEV;
1131 goto eirq;
1132 }
1133 host->regs_ip = ioremap(res->start, resource_size(res));
1134 if (!host->regs_ip) {
1135 err = -ENOMEM;
1136 goto eirq;
1137 }
1138 host->regs_axi = host->base + 0x1e00;
1139 host->spare0 = host->base + 0x1000;
1140 host->spare_len = 64;
1141 host->preset = preset_v3;
1142 host->send_cmd = send_cmd_v3;
1143 host->send_addr = send_addr_v3;
1144 host->send_page = send_page_v3;
1145 host->send_read_id = send_read_id_v3;
1146 host->check_int = check_int_v3;
1147 host->get_dev_status = get_dev_status_v3;
Sascha Hauer63f14742010-10-18 10:16:26 +02001148 host->irq_control = irq_control_v3;
Sascha Hauer71ec5152010-08-06 15:53:11 +02001149 oob_smallpage = &nandv2_hw_eccoob_smallpage;
1150 oob_largepage = &nandv2_hw_eccoob_largepage;
Sascha Hauer94671142009-10-05 12:14:21 +02001151 } else
1152 BUG();
Sascha Hauer34f6e152008-09-02 17:16:59 +02001153
Sascha Hauer13e1add2009-10-21 10:39:05 +02001154 this->ecc.size = 512;
Sascha Hauer94671142009-10-05 12:14:21 +02001155 this->ecc.layout = oob_smallpage;
Sascha Hauer13e1add2009-10-21 10:39:05 +02001156
1157 if (pdata->hw_ecc) {
1158 this->ecc.calculate = mxc_nand_calculate_ecc;
1159 this->ecc.hwctl = mxc_nand_enable_hwecc;
Sascha Hauer94f77e52010-08-06 15:53:09 +02001160 if (nfc_is_v1())
1161 this->ecc.correct = mxc_nand_correct_data_v1;
1162 else
1163 this->ecc.correct = mxc_nand_correct_data_v2_v3;
Sascha Hauer13e1add2009-10-21 10:39:05 +02001164 this->ecc.mode = NAND_ECC_HW;
Sascha Hauer13e1add2009-10-21 10:39:05 +02001165 } else {
1166 this->ecc.mode = NAND_ECC_SOFT;
Sascha Hauer34f6e152008-09-02 17:16:59 +02001167 }
1168
Sascha Hauer34f6e152008-09-02 17:16:59 +02001169 /* NAND bus width determines access funtions used by upper layer */
Sascha Hauer13e1add2009-10-21 10:39:05 +02001170 if (pdata->width == 2)
Sascha Hauer34f6e152008-09-02 17:16:59 +02001171 this->options |= NAND_BUSWIDTH_16;
Sascha Hauer13e1add2009-10-21 10:39:05 +02001172
Sascha Hauerf1372052009-10-21 14:25:27 +02001173 if (pdata->flash_bbt) {
1174 this->bbt_td = &bbt_main_descr;
1175 this->bbt_md = &bbt_mirror_descr;
1176 /* update flash based bbt */
Brian Norrisbb9ebd42011-05-31 16:31:23 -07001177 this->bbt_options |= NAND_BBT_USE_FLASH;
Sascha Hauer34f6e152008-09-02 17:16:59 +02001178 }
1179
Sascha Hauer63f14742010-10-18 10:16:26 +02001180 init_completion(&host->op_completion);
Ivo Claryssed4840182010-04-08 16:14:44 +02001181
1182 host->irq = platform_get_irq(pdev, 0);
1183
Sascha Hauer63f14742010-10-18 10:16:26 +02001184 /*
1185 * mask the interrupt. For i.MX21 explicitely call
1186 * irq_control_v1_v2 to use the mask bit. We can't call
1187 * disable_irq_nosync() for an interrupt we do not own yet.
1188 */
1189 if (cpu_is_mx21())
1190 irq_control_v1_v2(host, 0);
1191 else
1192 host->irq_control(host, 0);
1193
Ivo Claryssea47bfd22010-04-08 16:16:51 +02001194 err = request_irq(host->irq, mxc_nfc_irq, IRQF_DISABLED, DRIVER_NAME, host);
Ivo Claryssed4840182010-04-08 16:14:44 +02001195 if (err)
1196 goto eirq;
1197
Sascha Hauer63f14742010-10-18 10:16:26 +02001198 host->irq_control(host, 0);
1199
1200 /*
1201 * Now that the interrupt is disabled make sure the interrupt
1202 * mask bit is cleared on i.MX21. Otherwise we can't read
1203 * the interrupt status bit on this machine.
1204 */
1205 if (cpu_is_mx21())
1206 irq_control_v1_v2(host, 1);
1207
Vladimir Barinovbd3fd622009-05-25 13:06:17 +04001208 /* first scan to find the device and get the page size */
Baruch Siachd178e3e2011-03-14 09:01:56 +02001209 if (nand_scan_ident(mtd, nfc_is_v21() ? 4 : 1, NULL)) {
Vladimir Barinovbd3fd622009-05-25 13:06:17 +04001210 err = -ENXIO;
1211 goto escan;
1212 }
Sascha Hauer34f6e152008-09-02 17:16:59 +02001213
Sascha Hauer6e85dfd2010-08-06 15:53:10 +02001214 /* Call preset again, with correct writesize this time */
1215 host->preset(mtd);
1216
Sascha Hauer2d69c7f2009-10-05 11:24:02 +02001217 if (mtd->writesize == 2048)
Sascha Hauer94671142009-10-05 12:14:21 +02001218 this->ecc.layout = oob_largepage;
Baruch Siach2c1c5f12011-03-09 16:12:20 +02001219 if (nfc_is_v21() && mtd->writesize == 4096)
1220 this->ecc.layout = &nandv2_hw_eccoob_4k;
Vladimir Barinovbd3fd622009-05-25 13:06:17 +04001221
1222 /* second phase scan */
1223 if (nand_scan_tail(mtd)) {
Sascha Hauer34f6e152008-09-02 17:16:59 +02001224 err = -ENXIO;
1225 goto escan;
1226 }
1227
1228 /* Register the partitions */
Dmitry Eremin-Solenikovd4ed8f12011-06-02 18:00:43 +04001229 mtd_device_parse_register(mtd, part_probes, 0,
1230 pdata->parts, pdata->nr_parts);
Sascha Hauer34f6e152008-09-02 17:16:59 +02001231
1232 platform_set_drvdata(pdev, host);
1233
1234 return 0;
1235
1236escan:
Magnus Liljab258fd82009-05-08 21:57:47 +02001237 free_irq(host->irq, host);
Sascha Hauer34f6e152008-09-02 17:16:59 +02001238eirq:
Sascha Hauer71ec5152010-08-06 15:53:11 +02001239 if (host->regs_ip)
1240 iounmap(host->regs_ip);
Sascha Hauerc6de7e12009-10-05 11:14:35 +02001241 iounmap(host->base);
Sascha Hauer34f6e152008-09-02 17:16:59 +02001242eres:
1243 clk_put(host->clk);
1244eclk:
1245 kfree(host);
1246
1247 return err;
1248}
1249
Uwe Kleine-König51eeb872009-12-07 09:44:05 +00001250static int __devexit mxcnd_remove(struct platform_device *pdev)
Sascha Hauer34f6e152008-09-02 17:16:59 +02001251{
1252 struct mxc_nand_host *host = platform_get_drvdata(pdev);
1253
1254 clk_put(host->clk);
1255
1256 platform_set_drvdata(pdev, NULL);
1257
1258 nand_release(&host->mtd);
Magnus Liljab258fd82009-05-08 21:57:47 +02001259 free_irq(host->irq, host);
Sascha Hauer71ec5152010-08-06 15:53:11 +02001260 if (host->regs_ip)
1261 iounmap(host->regs_ip);
Sascha Hauerc6de7e12009-10-05 11:14:35 +02001262 iounmap(host->base);
Sascha Hauer34f6e152008-09-02 17:16:59 +02001263 kfree(host);
1264
1265 return 0;
1266}
1267
Sascha Hauer34f6e152008-09-02 17:16:59 +02001268static struct platform_driver mxcnd_driver = {
1269 .driver = {
1270 .name = DRIVER_NAME,
Eric Bénard04dd0d32010-06-17 20:59:04 +02001271 },
Uwe Kleine-Königdaa0f152009-11-24 22:07:08 +01001272 .remove = __devexit_p(mxcnd_remove),
Sascha Hauer34f6e152008-09-02 17:16:59 +02001273};
1274
1275static int __init mxc_nd_init(void)
1276{
Vladimir Barinov8541c112009-04-23 15:47:22 +04001277 return platform_driver_probe(&mxcnd_driver, mxcnd_probe);
Sascha Hauer34f6e152008-09-02 17:16:59 +02001278}
1279
1280static void __exit mxc_nd_cleanup(void)
1281{
1282 /* Unregister the device structure */
1283 platform_driver_unregister(&mxcnd_driver);
1284}
1285
1286module_init(mxc_nd_init);
1287module_exit(mxc_nd_cleanup);
1288
1289MODULE_AUTHOR("Freescale Semiconductor, Inc.");
1290MODULE_DESCRIPTION("MXC NAND MTD driver");
1291MODULE_LICENSE("GPL");