diff options
author | David Woodhouse <David.Woodhouse@intel.com> | 2009-11-30 07:35:02 -0500 |
---|---|---|
committer | David Woodhouse <David.Woodhouse@intel.com> | 2009-11-30 07:35:02 -0500 |
commit | 96178769652ba886d4dfe770e770456689cbb559 (patch) | |
tree | b405f45d4ba9ca6ab90d41f055adb57e08fe7376 /drivers/mtd | |
parent | 2e386e4bac90554887e73d6f342e845185b33fc3 (diff) | |
parent | 1fbff0a6e975a986032881f139b806c23680f823 (diff) |
Merge branch 'mxc-nand' of git://git.pengutronix.de/git/imx/linux-2.6
Diffstat (limited to 'drivers/mtd')
-rw-r--r-- | drivers/mtd/nand/mxc_nand.c | 773 |
1 files changed, 298 insertions, 475 deletions
diff --git a/drivers/mtd/nand/mxc_nand.c b/drivers/mtd/nand/mxc_nand.c index 4bc43eb6c604..f7366e99fe1e 100644 --- a/drivers/mtd/nand/mxc_nand.c +++ b/drivers/mtd/nand/mxc_nand.c | |||
@@ -33,9 +33,13 @@ | |||
33 | 33 | ||
34 | #include <asm/mach/flash.h> | 34 | #include <asm/mach/flash.h> |
35 | #include <mach/mxc_nand.h> | 35 | #include <mach/mxc_nand.h> |
36 | #include <mach/hardware.h> | ||
36 | 37 | ||
37 | #define DRIVER_NAME "mxc_nand" | 38 | #define DRIVER_NAME "mxc_nand" |
38 | 39 | ||
40 | #define nfc_is_v21() (cpu_is_mx25() || cpu_is_mx35()) | ||
41 | #define nfc_is_v1() (cpu_is_mx31() || cpu_is_mx27()) | ||
42 | |||
39 | /* Addresses for NFC registers */ | 43 | /* Addresses for NFC registers */ |
40 | #define NFC_BUF_SIZE 0xE00 | 44 | #define NFC_BUF_SIZE 0xE00 |
41 | #define NFC_BUF_ADDR 0xE04 | 45 | #define NFC_BUF_ADDR 0xE04 |
@@ -46,24 +50,14 @@ | |||
46 | #define NFC_RSLTMAIN_AREA 0xE0E | 50 | #define NFC_RSLTMAIN_AREA 0xE0E |
47 | #define NFC_RSLTSPARE_AREA 0xE10 | 51 | #define NFC_RSLTSPARE_AREA 0xE10 |
48 | #define NFC_WRPROT 0xE12 | 52 | #define NFC_WRPROT 0xE12 |
49 | #define NFC_UNLOCKSTART_BLKADDR 0xE14 | 53 | #define NFC_V1_UNLOCKSTART_BLKADDR 0xe14 |
50 | #define NFC_UNLOCKEND_BLKADDR 0xE16 | 54 | #define NFC_V1_UNLOCKEND_BLKADDR 0xe16 |
55 | #define NFC_V21_UNLOCKSTART_BLKADDR 0xe20 | ||
56 | #define NFC_V21_UNLOCKEND_BLKADDR 0xe22 | ||
51 | #define NFC_NF_WRPRST 0xE18 | 57 | #define NFC_NF_WRPRST 0xE18 |
52 | #define NFC_CONFIG1 0xE1A | 58 | #define NFC_CONFIG1 0xE1A |
53 | #define NFC_CONFIG2 0xE1C | 59 | #define NFC_CONFIG2 0xE1C |
54 | 60 | ||
55 | /* Addresses for NFC RAM BUFFER Main area 0 */ | ||
56 | #define MAIN_AREA0 0x000 | ||
57 | #define MAIN_AREA1 0x200 | ||
58 | #define MAIN_AREA2 0x400 | ||
59 | #define MAIN_AREA3 0x600 | ||
60 | |||
61 | /* Addresses for NFC SPARE BUFFER Spare area 0 */ | ||
62 | #define SPARE_AREA0 0x800 | ||
63 | #define SPARE_AREA1 0x810 | ||
64 | #define SPARE_AREA2 0x820 | ||
65 | #define SPARE_AREA3 0x830 | ||
66 | |||
67 | /* Set INT to 0, FCMD to 1, rest to 0 in NFC_CONFIG2 Register | 61 | /* Set INT to 0, FCMD to 1, rest to 0 in NFC_CONFIG2 Register |
68 | * for Command operation */ | 62 | * for Command operation */ |
69 | #define NFC_CMD 0x1 | 63 | #define NFC_CMD 0x1 |
@@ -106,48 +100,66 @@ struct mxc_nand_host { | |||
106 | struct mtd_partition *parts; | 100 | struct mtd_partition *parts; |
107 | struct device *dev; | 101 | struct device *dev; |
108 | 102 | ||
103 | void *spare0; | ||
104 | void *main_area0; | ||
105 | void *main_area1; | ||
106 | |||
107 | void __iomem *base; | ||
109 | void __iomem *regs; | 108 | void __iomem *regs; |
110 | int spare_only; | ||
111 | int status_request; | 109 | int status_request; |
112 | int pagesize_2k; | ||
113 | uint16_t col_addr; | ||
114 | struct clk *clk; | 110 | struct clk *clk; |
115 | int clk_act; | 111 | int clk_act; |
116 | int irq; | 112 | int irq; |
117 | 113 | ||
118 | wait_queue_head_t irq_waitq; | 114 | wait_queue_head_t irq_waitq; |
119 | }; | ||
120 | |||
121 | /* Define delays in microsec for NAND device operations */ | ||
122 | #define TROP_US_DELAY 2000 | ||
123 | /* Macros to get byte and bit positions of ECC */ | ||
124 | #define COLPOS(x) ((x) >> 3) | ||
125 | #define BITPOS(x) ((x) & 0xf) | ||
126 | 115 | ||
127 | /* Define single bit Error positions in Main & Spare area */ | 116 | uint8_t *data_buf; |
128 | #define MAIN_SINGLEBIT_ERROR 0x4 | 117 | unsigned int buf_start; |
129 | #define SPARE_SINGLEBIT_ERROR 0x1 | 118 | int spare_len; |
130 | |||
131 | /* OOB placement block for use with hardware ecc generation */ | ||
132 | static struct nand_ecclayout nand_hw_eccoob_8 = { | ||
133 | .eccbytes = 5, | ||
134 | .eccpos = {6, 7, 8, 9, 10}, | ||
135 | .oobfree = {{0, 5}, {11, 5}, } | ||
136 | }; | 119 | }; |
137 | 120 | ||
138 | static struct nand_ecclayout nand_hw_eccoob_16 = { | 121 | /* OOB placement block for use with hardware ecc generation */ |
122 | static struct nand_ecclayout nandv1_hw_eccoob_smallpage = { | ||
139 | .eccbytes = 5, | 123 | .eccbytes = 5, |
140 | .eccpos = {6, 7, 8, 9, 10}, | 124 | .eccpos = {6, 7, 8, 9, 10}, |
141 | .oobfree = {{0, 5}, {11, 5}, } | 125 | .oobfree = {{0, 5}, {12, 4}, } |
142 | }; | 126 | }; |
143 | 127 | ||
144 | static struct nand_ecclayout nand_hw_eccoob_64 = { | 128 | static struct nand_ecclayout nandv1_hw_eccoob_largepage = { |
145 | .eccbytes = 20, | 129 | .eccbytes = 20, |
146 | .eccpos = {6, 7, 8, 9, 10, 22, 23, 24, 25, 26, | 130 | .eccpos = {6, 7, 8, 9, 10, 22, 23, 24, 25, 26, |
147 | 38, 39, 40, 41, 42, 54, 55, 56, 57, 58}, | 131 | 38, 39, 40, 41, 42, 54, 55, 56, 57, 58}, |
148 | .oobfree = {{2, 4}, {11, 10}, {27, 10}, {43, 10}, {59, 5}, } | 132 | .oobfree = {{2, 4}, {11, 10}, {27, 10}, {43, 10}, {59, 5}, } |
149 | }; | 133 | }; |
150 | 134 | ||
135 | /* OOB description for 512 byte pages with 16 byte OOB */ | ||
136 | static struct nand_ecclayout nandv2_hw_eccoob_smallpage = { | ||
137 | .eccbytes = 1 * 9, | ||
138 | .eccpos = { | ||
139 | 7, 8, 9, 10, 11, 12, 13, 14, 15 | ||
140 | }, | ||
141 | .oobfree = { | ||
142 | {.offset = 0, .length = 5} | ||
143 | } | ||
144 | }; | ||
145 | |||
146 | /* OOB description for 2048 byte pages with 64 byte OOB */ | ||
147 | static struct nand_ecclayout nandv2_hw_eccoob_largepage = { | ||
148 | .eccbytes = 4 * 9, | ||
149 | .eccpos = { | ||
150 | 7, 8, 9, 10, 11, 12, 13, 14, 15, | ||
151 | 23, 24, 25, 26, 27, 28, 29, 30, 31, | ||
152 | 39, 40, 41, 42, 43, 44, 45, 46, 47, | ||
153 | 55, 56, 57, 58, 59, 60, 61, 62, 63 | ||
154 | }, | ||
155 | .oobfree = { | ||
156 | {.offset = 2, .length = 4}, | ||
157 | {.offset = 16, .length = 7}, | ||
158 | {.offset = 32, .length = 7}, | ||
159 | {.offset = 48, .length = 7} | ||
160 | } | ||
161 | }; | ||
162 | |||
151 | #ifdef CONFIG_MTD_PARTITIONS | 163 | #ifdef CONFIG_MTD_PARTITIONS |
152 | static const char *part_probes[] = { "RedBoot", "cmdlinepart", NULL }; | 164 | static const char *part_probes[] = { "RedBoot", "cmdlinepart", NULL }; |
153 | #endif | 165 | #endif |
@@ -170,10 +182,10 @@ static irqreturn_t mxc_nfc_irq(int irq, void *dev_id) | |||
170 | /* This function polls the NANDFC to wait for the basic operation to | 182 | /* This function polls the NANDFC to wait for the basic operation to |
171 | * complete by checking the INT bit of config2 register. | 183 | * complete by checking the INT bit of config2 register. |
172 | */ | 184 | */ |
173 | static void wait_op_done(struct mxc_nand_host *host, int max_retries, | 185 | static void wait_op_done(struct mxc_nand_host *host, int useirq) |
174 | uint16_t param, int useirq) | ||
175 | { | 186 | { |
176 | uint32_t tmp; | 187 | uint32_t tmp; |
188 | int max_retries = 2000; | ||
177 | 189 | ||
178 | if (useirq) { | 190 | if (useirq) { |
179 | if ((readw(host->regs + NFC_CONFIG2) & NFC_INT) == 0) { | 191 | if ((readw(host->regs + NFC_CONFIG2) & NFC_INT) == 0) { |
@@ -200,8 +212,8 @@ static void wait_op_done(struct mxc_nand_host *host, int max_retries, | |||
200 | udelay(1); | 212 | udelay(1); |
201 | } | 213 | } |
202 | if (max_retries < 0) | 214 | if (max_retries < 0) |
203 | DEBUG(MTD_DEBUG_LEVEL0, "%s(%d): INT not set\n", | 215 | DEBUG(MTD_DEBUG_LEVEL0, "%s: INT not set\n", |
204 | __func__, param); | 216 | __func__); |
205 | } | 217 | } |
206 | } | 218 | } |
207 | 219 | ||
@@ -215,7 +227,7 @@ static void send_cmd(struct mxc_nand_host *host, uint16_t cmd, int useirq) | |||
215 | writew(NFC_CMD, host->regs + NFC_CONFIG2); | 227 | writew(NFC_CMD, host->regs + NFC_CONFIG2); |
216 | 228 | ||
217 | /* Wait for operation to complete */ | 229 | /* Wait for operation to complete */ |
218 | wait_op_done(host, TROP_US_DELAY, cmd, useirq); | 230 | wait_op_done(host, useirq); |
219 | } | 231 | } |
220 | 232 | ||
221 | /* This function sends an address (or partial address) to the | 233 | /* This function sends an address (or partial address) to the |
@@ -229,82 +241,47 @@ static void send_addr(struct mxc_nand_host *host, uint16_t addr, int islast) | |||
229 | writew(NFC_ADDR, host->regs + NFC_CONFIG2); | 241 | writew(NFC_ADDR, host->regs + NFC_CONFIG2); |
230 | 242 | ||
231 | /* Wait for operation to complete */ | 243 | /* Wait for operation to complete */ |
232 | wait_op_done(host, TROP_US_DELAY, addr, islast); | 244 | wait_op_done(host, islast); |
233 | } | 245 | } |
234 | 246 | ||
235 | /* This function requests the NANDFC to initate the transfer | 247 | static void send_page(struct mtd_info *mtd, unsigned int ops) |
236 | * of data currently in the NANDFC RAM buffer to the NAND device. */ | ||
237 | static void send_prog_page(struct mxc_nand_host *host, uint8_t buf_id, | ||
238 | int spare_only) | ||
239 | { | 248 | { |
240 | DEBUG(MTD_DEBUG_LEVEL3, "send_prog_page (%d)\n", spare_only); | 249 | struct nand_chip *nand_chip = mtd->priv; |
241 | 250 | struct mxc_nand_host *host = nand_chip->priv; | |
242 | /* NANDFC buffer 0 is used for page read/write */ | 251 | int bufs, i; |
243 | writew(buf_id, host->regs + NFC_BUF_ADDR); | ||
244 | |||
245 | /* Configure spare or page+spare access */ | ||
246 | if (!host->pagesize_2k) { | ||
247 | uint16_t config1 = readw(host->regs + NFC_CONFIG1); | ||
248 | if (spare_only) | ||
249 | config1 |= NFC_SP_EN; | ||
250 | else | ||
251 | config1 &= ~(NFC_SP_EN); | ||
252 | writew(config1, host->regs + NFC_CONFIG1); | ||
253 | } | ||
254 | 252 | ||
255 | writew(NFC_INPUT, host->regs + NFC_CONFIG2); | 253 | if (nfc_is_v1() && mtd->writesize > 512) |
254 | bufs = 4; | ||
255 | else | ||
256 | bufs = 1; | ||
256 | 257 | ||
257 | /* Wait for operation to complete */ | 258 | for (i = 0; i < bufs; i++) { |
258 | wait_op_done(host, TROP_US_DELAY, spare_only, true); | ||
259 | } | ||
260 | 259 | ||
261 | /* Requests NANDFC to initated the transfer of data from the | 260 | /* NANDFC buffer 0 is used for page read/write */ |
262 | * NAND device into in the NANDFC ram buffer. */ | 261 | writew(i, host->regs + NFC_BUF_ADDR); |
263 | static void send_read_page(struct mxc_nand_host *host, uint8_t buf_id, | ||
264 | int spare_only) | ||
265 | { | ||
266 | DEBUG(MTD_DEBUG_LEVEL3, "send_read_page (%d)\n", spare_only); | ||
267 | 262 | ||
268 | /* NANDFC buffer 0 is used for page read/write */ | 263 | writew(ops, host->regs + NFC_CONFIG2); |
269 | writew(buf_id, host->regs + NFC_BUF_ADDR); | ||
270 | 264 | ||
271 | /* Configure spare or page+spare access */ | 265 | /* Wait for operation to complete */ |
272 | if (!host->pagesize_2k) { | 266 | wait_op_done(host, true); |
273 | uint32_t config1 = readw(host->regs + NFC_CONFIG1); | ||
274 | if (spare_only) | ||
275 | config1 |= NFC_SP_EN; | ||
276 | else | ||
277 | config1 &= ~NFC_SP_EN; | ||
278 | writew(config1, host->regs + NFC_CONFIG1); | ||
279 | } | 267 | } |
280 | |||
281 | writew(NFC_OUTPUT, host->regs + NFC_CONFIG2); | ||
282 | |||
283 | /* Wait for operation to complete */ | ||
284 | wait_op_done(host, TROP_US_DELAY, spare_only, true); | ||
285 | } | 268 | } |
286 | 269 | ||
287 | /* Request the NANDFC to perform a read of the NAND device ID. */ | 270 | /* Request the NANDFC to perform a read of the NAND device ID. */ |
288 | static void send_read_id(struct mxc_nand_host *host) | 271 | static void send_read_id(struct mxc_nand_host *host) |
289 | { | 272 | { |
290 | struct nand_chip *this = &host->nand; | 273 | struct nand_chip *this = &host->nand; |
291 | uint16_t tmp; | ||
292 | 274 | ||
293 | /* NANDFC buffer 0 is used for device ID output */ | 275 | /* NANDFC buffer 0 is used for device ID output */ |
294 | writew(0x0, host->regs + NFC_BUF_ADDR); | 276 | writew(0x0, host->regs + NFC_BUF_ADDR); |
295 | 277 | ||
296 | /* Read ID into main buffer */ | ||
297 | tmp = readw(host->regs + NFC_CONFIG1); | ||
298 | tmp &= ~NFC_SP_EN; | ||
299 | writew(tmp, host->regs + NFC_CONFIG1); | ||
300 | |||
301 | writew(NFC_ID, host->regs + NFC_CONFIG2); | 278 | writew(NFC_ID, host->regs + NFC_CONFIG2); |
302 | 279 | ||
303 | /* Wait for operation to complete */ | 280 | /* Wait for operation to complete */ |
304 | wait_op_done(host, TROP_US_DELAY, 0, true); | 281 | wait_op_done(host, true); |
305 | 282 | ||
306 | if (this->options & NAND_BUSWIDTH_16) { | 283 | if (this->options & NAND_BUSWIDTH_16) { |
307 | void __iomem *main_buf = host->regs + MAIN_AREA0; | 284 | void __iomem *main_buf = host->main_area0; |
308 | /* compress the ID info */ | 285 | /* compress the ID info */ |
309 | writeb(readb(main_buf + 2), main_buf + 1); | 286 | writeb(readb(main_buf + 2), main_buf + 1); |
310 | writeb(readb(main_buf + 4), main_buf + 2); | 287 | writeb(readb(main_buf + 4), main_buf + 2); |
@@ -312,15 +289,16 @@ static void send_read_id(struct mxc_nand_host *host) | |||
312 | writeb(readb(main_buf + 8), main_buf + 4); | 289 | writeb(readb(main_buf + 8), main_buf + 4); |
313 | writeb(readb(main_buf + 10), main_buf + 5); | 290 | writeb(readb(main_buf + 10), main_buf + 5); |
314 | } | 291 | } |
292 | memcpy(host->data_buf, host->main_area0, 16); | ||
315 | } | 293 | } |
316 | 294 | ||
317 | /* This function requests the NANDFC to perform a read of the | 295 | /* This function requests the NANDFC to perform a read of the |
318 | * NAND device status and returns the current status. */ | 296 | * NAND device status and returns the current status. */ |
319 | static uint16_t get_dev_status(struct mxc_nand_host *host) | 297 | static uint16_t get_dev_status(struct mxc_nand_host *host) |
320 | { | 298 | { |
321 | void __iomem *main_buf = host->regs + MAIN_AREA1; | 299 | void __iomem *main_buf = host->main_area1; |
322 | uint32_t store; | 300 | uint32_t store; |
323 | uint16_t ret, tmp; | 301 | uint16_t ret; |
324 | /* Issue status request to NAND device */ | 302 | /* Issue status request to NAND device */ |
325 | 303 | ||
326 | /* store the main area1 first word, later do recovery */ | 304 | /* store the main area1 first word, later do recovery */ |
@@ -329,15 +307,10 @@ static uint16_t get_dev_status(struct mxc_nand_host *host) | |||
329 | * corruption of read/write buffer on status requests. */ | 307 | * corruption of read/write buffer on status requests. */ |
330 | writew(1, host->regs + NFC_BUF_ADDR); | 308 | writew(1, host->regs + NFC_BUF_ADDR); |
331 | 309 | ||
332 | /* Read status into main buffer */ | ||
333 | tmp = readw(host->regs + NFC_CONFIG1); | ||
334 | tmp &= ~NFC_SP_EN; | ||
335 | writew(tmp, host->regs + NFC_CONFIG1); | ||
336 | |||
337 | writew(NFC_STATUS, host->regs + NFC_CONFIG2); | 310 | writew(NFC_STATUS, host->regs + NFC_CONFIG2); |
338 | 311 | ||
339 | /* Wait for operation to complete */ | 312 | /* Wait for operation to complete */ |
340 | wait_op_done(host, TROP_US_DELAY, 0, true); | 313 | wait_op_done(host, true); |
341 | 314 | ||
342 | /* Status is placed in first word of main buffer */ | 315 | /* Status is placed in first word of main buffer */ |
343 | /* get status, then recovery area 1 data */ | 316 | /* get status, then recovery area 1 data */ |
@@ -397,32 +370,14 @@ static u_char mxc_nand_read_byte(struct mtd_info *mtd) | |||
397 | { | 370 | { |
398 | struct nand_chip *nand_chip = mtd->priv; | 371 | struct nand_chip *nand_chip = mtd->priv; |
399 | struct mxc_nand_host *host = nand_chip->priv; | 372 | struct mxc_nand_host *host = nand_chip->priv; |
400 | uint8_t ret = 0; | 373 | uint8_t ret; |
401 | uint16_t col, rd_word; | ||
402 | uint16_t __iomem *main_buf = host->regs + MAIN_AREA0; | ||
403 | uint16_t __iomem *spare_buf = host->regs + SPARE_AREA0; | ||
404 | 374 | ||
405 | /* Check for status request */ | 375 | /* Check for status request */ |
406 | if (host->status_request) | 376 | if (host->status_request) |
407 | return get_dev_status(host) & 0xFF; | 377 | return get_dev_status(host) & 0xFF; |
408 | 378 | ||
409 | /* Get column for 16-bit access */ | 379 | ret = *(uint8_t *)(host->data_buf + host->buf_start); |
410 | col = host->col_addr >> 1; | 380 | host->buf_start++; |
411 | |||
412 | /* If we are accessing the spare region */ | ||
413 | if (host->spare_only) | ||
414 | rd_word = readw(&spare_buf[col]); | ||
415 | else | ||
416 | rd_word = readw(&main_buf[col]); | ||
417 | |||
418 | /* Pick upper/lower byte of word from RAM buffer */ | ||
419 | if (host->col_addr & 0x1) | ||
420 | ret = (rd_word >> 8) & 0xFF; | ||
421 | else | ||
422 | ret = rd_word & 0xFF; | ||
423 | |||
424 | /* Update saved column address */ | ||
425 | host->col_addr++; | ||
426 | 381 | ||
427 | return ret; | 382 | return ret; |
428 | } | 383 | } |
@@ -431,33 +386,10 @@ static uint16_t mxc_nand_read_word(struct mtd_info *mtd) | |||
431 | { | 386 | { |
432 | struct nand_chip *nand_chip = mtd->priv; | 387 | struct nand_chip *nand_chip = mtd->priv; |
433 | struct mxc_nand_host *host = nand_chip->priv; | 388 | struct mxc_nand_host *host = nand_chip->priv; |
434 | uint16_t col, rd_word, ret; | 389 | uint16_t ret; |
435 | uint16_t __iomem *p; | ||
436 | |||
437 | DEBUG(MTD_DEBUG_LEVEL3, | ||
438 | "mxc_nand_read_word(col = %d)\n", host->col_addr); | ||
439 | |||
440 | col = host->col_addr; | ||
441 | /* Adjust saved column address */ | ||
442 | if (col < mtd->writesize && host->spare_only) | ||
443 | col += mtd->writesize; | ||
444 | 390 | ||
445 | if (col < mtd->writesize) | 391 | ret = *(uint16_t *)(host->data_buf + host->buf_start); |
446 | p = (host->regs + MAIN_AREA0) + (col >> 1); | 392 | host->buf_start += 2; |
447 | else | ||
448 | p = (host->regs + SPARE_AREA0) + ((col - mtd->writesize) >> 1); | ||
449 | |||
450 | if (col & 1) { | ||
451 | rd_word = readw(p); | ||
452 | ret = (rd_word >> 8) & 0xff; | ||
453 | rd_word = readw(&p[1]); | ||
454 | ret |= (rd_word << 8) & 0xff00; | ||
455 | |||
456 | } else | ||
457 | ret = readw(p); | ||
458 | |||
459 | /* Update saved column address */ | ||
460 | host->col_addr = col + 2; | ||
461 | 393 | ||
462 | return ret; | 394 | return ret; |
463 | } | 395 | } |
@@ -470,94 +402,14 @@ static void mxc_nand_write_buf(struct mtd_info *mtd, | |||
470 | { | 402 | { |
471 | struct nand_chip *nand_chip = mtd->priv; | 403 | struct nand_chip *nand_chip = mtd->priv; |
472 | struct mxc_nand_host *host = nand_chip->priv; | 404 | struct mxc_nand_host *host = nand_chip->priv; |
473 | int n, col, i = 0; | 405 | u16 col = host->buf_start; |
474 | 406 | int n = mtd->oobsize + mtd->writesize - col; | |
475 | DEBUG(MTD_DEBUG_LEVEL3, | ||
476 | "mxc_nand_write_buf(col = %d, len = %d)\n", host->col_addr, | ||
477 | len); | ||
478 | |||
479 | col = host->col_addr; | ||
480 | |||
481 | /* Adjust saved column address */ | ||
482 | if (col < mtd->writesize && host->spare_only) | ||
483 | col += mtd->writesize; | ||
484 | |||
485 | n = mtd->writesize + mtd->oobsize - col; | ||
486 | n = min(len, n); | ||
487 | |||
488 | DEBUG(MTD_DEBUG_LEVEL3, | ||
489 | "%s:%d: col = %d, n = %d\n", __func__, __LINE__, col, n); | ||
490 | |||
491 | while (n) { | ||
492 | void __iomem *p; | ||
493 | |||
494 | if (col < mtd->writesize) | ||
495 | p = host->regs + MAIN_AREA0 + (col & ~3); | ||
496 | else | ||
497 | p = host->regs + SPARE_AREA0 - | ||
498 | mtd->writesize + (col & ~3); | ||
499 | |||
500 | DEBUG(MTD_DEBUG_LEVEL3, "%s:%d: p = %p\n", __func__, | ||
501 | __LINE__, p); | ||
502 | |||
503 | if (((col | (int)&buf[i]) & 3) || n < 16) { | ||
504 | uint32_t data = 0; | ||
505 | |||
506 | if (col & 3 || n < 4) | ||
507 | data = readl(p); | ||
508 | |||
509 | switch (col & 3) { | ||
510 | case 0: | ||
511 | if (n) { | ||
512 | data = (data & 0xffffff00) | | ||
513 | (buf[i++] << 0); | ||
514 | n--; | ||
515 | col++; | ||
516 | } | ||
517 | case 1: | ||
518 | if (n) { | ||
519 | data = (data & 0xffff00ff) | | ||
520 | (buf[i++] << 8); | ||
521 | n--; | ||
522 | col++; | ||
523 | } | ||
524 | case 2: | ||
525 | if (n) { | ||
526 | data = (data & 0xff00ffff) | | ||
527 | (buf[i++] << 16); | ||
528 | n--; | ||
529 | col++; | ||
530 | } | ||
531 | case 3: | ||
532 | if (n) { | ||
533 | data = (data & 0x00ffffff) | | ||
534 | (buf[i++] << 24); | ||
535 | n--; | ||
536 | col++; | ||
537 | } | ||
538 | } | ||
539 | 407 | ||
540 | writel(data, p); | 408 | n = min(n, len); |
541 | } else { | ||
542 | int m = mtd->writesize - col; | ||
543 | |||
544 | if (col >= mtd->writesize) | ||
545 | m += mtd->oobsize; | ||
546 | 409 | ||
547 | m = min(n, m) & ~3; | 410 | memcpy(host->data_buf + col, buf, n); |
548 | 411 | ||
549 | DEBUG(MTD_DEBUG_LEVEL3, | 412 | host->buf_start += n; |
550 | "%s:%d: n = %d, m = %d, i = %d, col = %d\n", | ||
551 | __func__, __LINE__, n, m, i, col); | ||
552 | |||
553 | memcpy(p, &buf[i], m); | ||
554 | col += m; | ||
555 | i += m; | ||
556 | n -= m; | ||
557 | } | ||
558 | } | ||
559 | /* Update saved column address */ | ||
560 | host->col_addr = col; | ||
561 | } | 413 | } |
562 | 414 | ||
563 | /* Read the data buffer from the NAND Flash. To read the data from NAND | 415 | /* Read the data buffer from the NAND Flash. To read the data from NAND |
@@ -568,75 +420,14 @@ static void mxc_nand_read_buf(struct mtd_info *mtd, u_char *buf, int len) | |||
568 | { | 420 | { |
569 | struct nand_chip *nand_chip = mtd->priv; | 421 | struct nand_chip *nand_chip = mtd->priv; |
570 | struct mxc_nand_host *host = nand_chip->priv; | 422 | struct mxc_nand_host *host = nand_chip->priv; |
571 | int n, col, i = 0; | 423 | u16 col = host->buf_start; |
572 | 424 | int n = mtd->oobsize + mtd->writesize - col; | |
573 | DEBUG(MTD_DEBUG_LEVEL3, | ||
574 | "mxc_nand_read_buf(col = %d, len = %d)\n", host->col_addr, len); | ||
575 | |||
576 | col = host->col_addr; | ||
577 | 425 | ||
578 | /* Adjust saved column address */ | 426 | n = min(n, len); |
579 | if (col < mtd->writesize && host->spare_only) | ||
580 | col += mtd->writesize; | ||
581 | 427 | ||
582 | n = mtd->writesize + mtd->oobsize - col; | 428 | memcpy(buf, host->data_buf + col, len); |
583 | n = min(len, n); | ||
584 | |||
585 | while (n) { | ||
586 | void __iomem *p; | ||
587 | |||
588 | if (col < mtd->writesize) | ||
589 | p = host->regs + MAIN_AREA0 + (col & ~3); | ||
590 | else | ||
591 | p = host->regs + SPARE_AREA0 - | ||
592 | mtd->writesize + (col & ~3); | ||
593 | |||
594 | if (((col | (int)&buf[i]) & 3) || n < 16) { | ||
595 | uint32_t data; | ||
596 | |||
597 | data = readl(p); | ||
598 | switch (col & 3) { | ||
599 | case 0: | ||
600 | if (n) { | ||
601 | buf[i++] = (uint8_t) (data); | ||
602 | n--; | ||
603 | col++; | ||
604 | } | ||
605 | case 1: | ||
606 | if (n) { | ||
607 | buf[i++] = (uint8_t) (data >> 8); | ||
608 | n--; | ||
609 | col++; | ||
610 | } | ||
611 | case 2: | ||
612 | if (n) { | ||
613 | buf[i++] = (uint8_t) (data >> 16); | ||
614 | n--; | ||
615 | col++; | ||
616 | } | ||
617 | case 3: | ||
618 | if (n) { | ||
619 | buf[i++] = (uint8_t) (data >> 24); | ||
620 | n--; | ||
621 | col++; | ||
622 | } | ||
623 | } | ||
624 | } else { | ||
625 | int m = mtd->writesize - col; | ||
626 | |||
627 | if (col >= mtd->writesize) | ||
628 | m += mtd->oobsize; | ||
629 | |||
630 | m = min(n, m) & ~3; | ||
631 | memcpy(&buf[i], p, m); | ||
632 | col += m; | ||
633 | i += m; | ||
634 | n -= m; | ||
635 | } | ||
636 | } | ||
637 | /* Update saved column address */ | ||
638 | host->col_addr = col; | ||
639 | 429 | ||
430 | host->buf_start += len; | ||
640 | } | 431 | } |
641 | 432 | ||
642 | /* Used by the upper layer to verify the data in NAND Flash | 433 | /* Used by the upper layer to verify the data in NAND Flash |
@@ -654,23 +445,6 @@ static void mxc_nand_select_chip(struct mtd_info *mtd, int chip) | |||
654 | struct nand_chip *nand_chip = mtd->priv; | 445 | struct nand_chip *nand_chip = mtd->priv; |
655 | struct mxc_nand_host *host = nand_chip->priv; | 446 | struct mxc_nand_host *host = nand_chip->priv; |
656 | 447 | ||
657 | #ifdef CONFIG_MTD_NAND_MXC_FORCE_CE | ||
658 | if (chip > 0) { | ||
659 | DEBUG(MTD_DEBUG_LEVEL0, | ||
660 | "ERROR: Illegal chip select (chip = %d)\n", chip); | ||
661 | return; | ||
662 | } | ||
663 | |||
664 | if (chip == -1) { | ||
665 | writew(readw(host->regs + NFC_CONFIG1) & ~NFC_CE, | ||
666 | host->regs + NFC_CONFIG1); | ||
667 | return; | ||
668 | } | ||
669 | |||
670 | writew(readw(host->regs + NFC_CONFIG1) | NFC_CE, | ||
671 | host->regs + NFC_CONFIG1); | ||
672 | #endif | ||
673 | |||
674 | switch (chip) { | 448 | switch (chip) { |
675 | case -1: | 449 | case -1: |
676 | /* Disable the NFC clock */ | 450 | /* Disable the NFC clock */ |
@@ -692,94 +466,40 @@ static void mxc_nand_select_chip(struct mtd_info *mtd, int chip) | |||
692 | } | 466 | } |
693 | } | 467 | } |
694 | 468 | ||
695 | /* Used by the upper layer to write command to NAND Flash for | 469 | /* |
696 | * different operations to be carried out on NAND Flash */ | 470 | * Function to transfer data to/from spare area. |
697 | static void mxc_nand_command(struct mtd_info *mtd, unsigned command, | 471 | */ |
698 | int column, int page_addr) | 472 | static void copy_spare(struct mtd_info *mtd, bool bfrom) |
699 | { | 473 | { |
700 | struct nand_chip *nand_chip = mtd->priv; | 474 | struct nand_chip *this = mtd->priv; |
701 | struct mxc_nand_host *host = nand_chip->priv; | 475 | struct mxc_nand_host *host = this->priv; |
702 | int useirq = true; | 476 | u16 i, j; |
703 | 477 | u16 n = mtd->writesize >> 9; | |
704 | DEBUG(MTD_DEBUG_LEVEL3, | 478 | u8 *d = host->data_buf + mtd->writesize; |
705 | "mxc_nand_command (cmd = 0x%x, col = 0x%x, page = 0x%x)\n", | 479 | u8 *s = host->spare0; |
706 | command, column, page_addr); | 480 | u16 t = host->spare_len; |
707 | 481 | ||
708 | /* Reset command state information */ | 482 | j = (mtd->oobsize / n >> 1) << 1; |
709 | host->status_request = false; | 483 | |
710 | 484 | if (bfrom) { | |
711 | /* Command pre-processing step */ | 485 | for (i = 0; i < n - 1; i++) |
712 | switch (command) { | 486 | memcpy(d + i * j, s + i * t, j); |
713 | 487 | ||
714 | case NAND_CMD_STATUS: | 488 | /* the last section */ |
715 | host->col_addr = 0; | 489 | memcpy(d + i * j, s + i * t, mtd->oobsize - i * j); |
716 | host->status_request = true; | 490 | } else { |
717 | break; | 491 | for (i = 0; i < n - 1; i++) |
718 | 492 | memcpy(&s[i * t], &d[i * j], j); | |
719 | case NAND_CMD_READ0: | ||
720 | host->col_addr = column; | ||
721 | host->spare_only = false; | ||
722 | useirq = false; | ||
723 | break; | ||
724 | |||
725 | case NAND_CMD_READOOB: | ||
726 | host->col_addr = column; | ||
727 | host->spare_only = true; | ||
728 | useirq = false; | ||
729 | if (host->pagesize_2k) | ||
730 | command = NAND_CMD_READ0; /* only READ0 is valid */ | ||
731 | break; | ||
732 | |||
733 | case NAND_CMD_SEQIN: | ||
734 | if (column >= mtd->writesize) { | ||
735 | /* | ||
736 | * FIXME: before send SEQIN command for write OOB, | ||
737 | * We must read one page out. | ||
738 | * For K9F1GXX has no READ1 command to set current HW | ||
739 | * pointer to spare area, we must write the whole page | ||
740 | * including OOB together. | ||
741 | */ | ||
742 | if (host->pagesize_2k) | ||
743 | /* call ourself to read a page */ | ||
744 | mxc_nand_command(mtd, NAND_CMD_READ0, 0, | ||
745 | page_addr); | ||
746 | |||
747 | host->col_addr = column - mtd->writesize; | ||
748 | host->spare_only = true; | ||
749 | |||
750 | /* Set program pointer to spare region */ | ||
751 | if (!host->pagesize_2k) | ||
752 | send_cmd(host, NAND_CMD_READOOB, false); | ||
753 | } else { | ||
754 | host->spare_only = false; | ||
755 | host->col_addr = column; | ||
756 | |||
757 | /* Set program pointer to page start */ | ||
758 | if (!host->pagesize_2k) | ||
759 | send_cmd(host, NAND_CMD_READ0, false); | ||
760 | } | ||
761 | useirq = false; | ||
762 | break; | ||
763 | |||
764 | case NAND_CMD_PAGEPROG: | ||
765 | send_prog_page(host, 0, host->spare_only); | ||
766 | |||
767 | if (host->pagesize_2k) { | ||
768 | /* data in 4 areas datas */ | ||
769 | send_prog_page(host, 1, host->spare_only); | ||
770 | send_prog_page(host, 2, host->spare_only); | ||
771 | send_prog_page(host, 3, host->spare_only); | ||
772 | } | ||
773 | |||
774 | break; | ||
775 | 493 | ||
776 | case NAND_CMD_ERASE1: | 494 | /* the last section */ |
777 | useirq = false; | 495 | memcpy(&s[i * t], &d[i * j], mtd->oobsize - i * j); |
778 | break; | ||
779 | } | 496 | } |
497 | } | ||
780 | 498 | ||
781 | /* Write out the command to the device. */ | 499 | static void mxc_do_addr_cycle(struct mtd_info *mtd, int column, int page_addr) |
782 | send_cmd(host, command, useirq); | 500 | { |
501 | struct nand_chip *nand_chip = mtd->priv; | ||
502 | struct mxc_nand_host *host = nand_chip->priv; | ||
783 | 503 | ||
784 | /* Write out column address, if necessary */ | 504 | /* Write out column address, if necessary */ |
785 | if (column != -1) { | 505 | if (column != -1) { |
@@ -791,7 +511,7 @@ static void mxc_nand_command(struct mtd_info *mtd, unsigned command, | |||
791 | * the full page. | 511 | * the full page. |
792 | */ | 512 | */ |
793 | send_addr(host, 0, page_addr == -1); | 513 | send_addr(host, 0, page_addr == -1); |
794 | if (host->pagesize_2k) | 514 | if (mtd->writesize > 512) |
795 | /* another col addr cycle for 2k page */ | 515 | /* another col addr cycle for 2k page */ |
796 | send_addr(host, 0, false); | 516 | send_addr(host, 0, false); |
797 | } | 517 | } |
@@ -801,7 +521,7 @@ static void mxc_nand_command(struct mtd_info *mtd, unsigned command, | |||
801 | /* paddr_0 - p_addr_7 */ | 521 | /* paddr_0 - p_addr_7 */ |
802 | send_addr(host, (page_addr & 0xff), false); | 522 | send_addr(host, (page_addr & 0xff), false); |
803 | 523 | ||
804 | if (host->pagesize_2k) { | 524 | if (mtd->writesize > 512) { |
805 | if (mtd->size >= 0x10000000) { | 525 | if (mtd->size >= 0x10000000) { |
806 | /* paddr_8 - paddr_15 */ | 526 | /* paddr_8 - paddr_15 */ |
807 | send_addr(host, (page_addr >> 8) & 0xff, false); | 527 | send_addr(host, (page_addr >> 8) & 0xff, false); |
@@ -820,43 +540,138 @@ static void mxc_nand_command(struct mtd_info *mtd, unsigned command, | |||
820 | send_addr(host, (page_addr >> 8) & 0xff, true); | 540 | send_addr(host, (page_addr >> 8) & 0xff, true); |
821 | } | 541 | } |
822 | } | 542 | } |
543 | } | ||
544 | |||
545 | /* Used by the upper layer to write command to NAND Flash for | ||
546 | * different operations to be carried out on NAND Flash */ | ||
547 | static void mxc_nand_command(struct mtd_info *mtd, unsigned command, | ||
548 | int column, int page_addr) | ||
549 | { | ||
550 | struct nand_chip *nand_chip = mtd->priv; | ||
551 | struct mxc_nand_host *host = nand_chip->priv; | ||
552 | |||
553 | DEBUG(MTD_DEBUG_LEVEL3, | ||
554 | "mxc_nand_command (cmd = 0x%x, col = 0x%x, page = 0x%x)\n", | ||
555 | command, column, page_addr); | ||
556 | |||
557 | /* Reset command state information */ | ||
558 | host->status_request = false; | ||
823 | 559 | ||
824 | /* Command post-processing step */ | 560 | /* Command pre-processing step */ |
825 | switch (command) { | 561 | switch (command) { |
826 | 562 | ||
827 | case NAND_CMD_RESET: | 563 | case NAND_CMD_STATUS: |
564 | host->buf_start = 0; | ||
565 | host->status_request = true; | ||
566 | |||
567 | send_cmd(host, command, true); | ||
568 | mxc_do_addr_cycle(mtd, column, page_addr); | ||
828 | break; | 569 | break; |
829 | 570 | ||
830 | case NAND_CMD_READOOB: | ||
831 | case NAND_CMD_READ0: | 571 | case NAND_CMD_READ0: |
832 | if (host->pagesize_2k) { | 572 | case NAND_CMD_READOOB: |
833 | /* send read confirm command */ | 573 | if (command == NAND_CMD_READ0) |
574 | host->buf_start = column; | ||
575 | else | ||
576 | host->buf_start = column + mtd->writesize; | ||
577 | |||
578 | if (mtd->writesize > 512) | ||
579 | command = NAND_CMD_READ0; /* only READ0 is valid */ | ||
580 | |||
581 | send_cmd(host, command, false); | ||
582 | mxc_do_addr_cycle(mtd, column, page_addr); | ||
583 | |||
584 | if (mtd->writesize > 512) | ||
834 | send_cmd(host, NAND_CMD_READSTART, true); | 585 | send_cmd(host, NAND_CMD_READSTART, true); |
835 | /* read for each AREA */ | 586 | |
836 | send_read_page(host, 0, host->spare_only); | 587 | send_page(mtd, NFC_OUTPUT); |
837 | send_read_page(host, 1, host->spare_only); | 588 | |
838 | send_read_page(host, 2, host->spare_only); | 589 | memcpy(host->data_buf, host->main_area0, mtd->writesize); |
839 | send_read_page(host, 3, host->spare_only); | 590 | copy_spare(mtd, true); |
840 | } else | ||
841 | send_read_page(host, 0, host->spare_only); | ||
842 | break; | 591 | break; |
843 | 592 | ||
844 | case NAND_CMD_READID: | 593 | case NAND_CMD_SEQIN: |
845 | host->col_addr = 0; | 594 | if (column >= mtd->writesize) { |
846 | send_read_id(host); | 595 | /* |
596 | * FIXME: before send SEQIN command for write OOB, | ||
597 | * We must read one page out. | ||
598 | * For K9F1GXX has no READ1 command to set current HW | ||
599 | * pointer to spare area, we must write the whole page | ||
600 | * including OOB together. | ||
601 | */ | ||
602 | if (mtd->writesize > 512) | ||
603 | /* call ourself to read a page */ | ||
604 | mxc_nand_command(mtd, NAND_CMD_READ0, 0, | ||
605 | page_addr); | ||
606 | |||
607 | host->buf_start = column; | ||
608 | |||
609 | /* Set program pointer to spare region */ | ||
610 | if (mtd->writesize == 512) | ||
611 | send_cmd(host, NAND_CMD_READOOB, false); | ||
612 | } else { | ||
613 | host->buf_start = column; | ||
614 | |||
615 | /* Set program pointer to page start */ | ||
616 | if (mtd->writesize == 512) | ||
617 | send_cmd(host, NAND_CMD_READ0, false); | ||
618 | } | ||
619 | |||
620 | send_cmd(host, command, false); | ||
621 | mxc_do_addr_cycle(mtd, column, page_addr); | ||
847 | break; | 622 | break; |
848 | 623 | ||
849 | case NAND_CMD_PAGEPROG: | 624 | case NAND_CMD_PAGEPROG: |
625 | memcpy(host->main_area0, host->data_buf, mtd->writesize); | ||
626 | copy_spare(mtd, false); | ||
627 | send_page(mtd, NFC_INPUT); | ||
628 | send_cmd(host, command, true); | ||
629 | mxc_do_addr_cycle(mtd, column, page_addr); | ||
850 | break; | 630 | break; |
851 | 631 | ||
852 | case NAND_CMD_STATUS: | 632 | case NAND_CMD_READID: |
633 | send_cmd(host, command, true); | ||
634 | mxc_do_addr_cycle(mtd, column, page_addr); | ||
635 | send_read_id(host); | ||
636 | host->buf_start = column; | ||
853 | break; | 637 | break; |
854 | 638 | ||
639 | case NAND_CMD_ERASE1: | ||
855 | case NAND_CMD_ERASE2: | 640 | case NAND_CMD_ERASE2: |
641 | send_cmd(host, command, false); | ||
642 | mxc_do_addr_cycle(mtd, column, page_addr); | ||
643 | |||
856 | break; | 644 | break; |
857 | } | 645 | } |
858 | } | 646 | } |
859 | 647 | ||
648 | /* | ||
649 | * The generic flash bbt decriptors overlap with our ecc | ||
650 | * hardware, so define some i.MX specific ones. | ||
651 | */ | ||
652 | static uint8_t bbt_pattern[] = { 'B', 'b', 't', '0' }; | ||
653 | static uint8_t mirror_pattern[] = { '1', 't', 'b', 'B' }; | ||
654 | |||
655 | static struct nand_bbt_descr bbt_main_descr = { | ||
656 | .options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE | ||
657 | | NAND_BBT_2BIT | NAND_BBT_VERSION | NAND_BBT_PERCHIP, | ||
658 | .offs = 0, | ||
659 | .len = 4, | ||
660 | .veroffs = 4, | ||
661 | .maxblocks = 4, | ||
662 | .pattern = bbt_pattern, | ||
663 | }; | ||
664 | |||
665 | static struct nand_bbt_descr bbt_mirror_descr = { | ||
666 | .options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE | ||
667 | | NAND_BBT_2BIT | NAND_BBT_VERSION | NAND_BBT_PERCHIP, | ||
668 | .offs = 0, | ||
669 | .len = 4, | ||
670 | .veroffs = 4, | ||
671 | .maxblocks = 4, | ||
672 | .pattern = mirror_pattern, | ||
673 | }; | ||
674 | |||
860 | static int __init mxcnd_probe(struct platform_device *pdev) | 675 | static int __init mxcnd_probe(struct platform_device *pdev) |
861 | { | 676 | { |
862 | struct nand_chip *this; | 677 | struct nand_chip *this; |
@@ -866,12 +681,16 @@ static int __init mxcnd_probe(struct platform_device *pdev) | |||
866 | struct resource *res; | 681 | struct resource *res; |
867 | uint16_t tmp; | 682 | uint16_t tmp; |
868 | int err = 0, nr_parts = 0; | 683 | int err = 0, nr_parts = 0; |
684 | struct nand_ecclayout *oob_smallpage, *oob_largepage; | ||
869 | 685 | ||
870 | /* Allocate memory for MTD device structure and private data */ | 686 | /* Allocate memory for MTD device structure and private data */ |
871 | host = kzalloc(sizeof(struct mxc_nand_host), GFP_KERNEL); | 687 | host = kzalloc(sizeof(struct mxc_nand_host) + NAND_MAX_PAGESIZE + |
688 | NAND_MAX_OOBSIZE, GFP_KERNEL); | ||
872 | if (!host) | 689 | if (!host) |
873 | return -ENOMEM; | 690 | return -ENOMEM; |
874 | 691 | ||
692 | host->data_buf = (uint8_t *)(host + 1); | ||
693 | |||
875 | host->dev = &pdev->dev; | 694 | host->dev = &pdev->dev; |
876 | /* structures must be linked */ | 695 | /* structures must be linked */ |
877 | this = &host->nand; | 696 | this = &host->nand; |
@@ -879,7 +698,7 @@ static int __init mxcnd_probe(struct platform_device *pdev) | |||
879 | mtd->priv = this; | 698 | mtd->priv = this; |
880 | mtd->owner = THIS_MODULE; | 699 | mtd->owner = THIS_MODULE; |
881 | mtd->dev.parent = &pdev->dev; | 700 | mtd->dev.parent = &pdev->dev; |
882 | mtd->name = "mxc_nand"; | 701 | mtd->name = DRIVER_NAME; |
883 | 702 | ||
884 | /* 50 us command delay time */ | 703 | /* 50 us command delay time */ |
885 | this->chip_delay = 5; | 704 | this->chip_delay = 5; |
@@ -909,62 +728,93 @@ static int __init mxcnd_probe(struct platform_device *pdev) | |||
909 | goto eres; | 728 | goto eres; |
910 | } | 729 | } |
911 | 730 | ||
912 | host->regs = ioremap(res->start, res->end - res->start + 1); | 731 | host->base = ioremap(res->start, resource_size(res)); |
913 | if (!host->regs) { | 732 | if (!host->base) { |
914 | err = -ENOMEM; | 733 | err = -ENOMEM; |
915 | goto eres; | 734 | goto eres; |
916 | } | 735 | } |
917 | 736 | ||
737 | host->main_area0 = host->base; | ||
738 | host->main_area1 = host->base + 0x200; | ||
739 | |||
740 | if (nfc_is_v21()) { | ||
741 | host->regs = host->base + 0x1000; | ||
742 | host->spare0 = host->base + 0x1000; | ||
743 | host->spare_len = 64; | ||
744 | oob_smallpage = &nandv2_hw_eccoob_smallpage; | ||
745 | oob_largepage = &nandv2_hw_eccoob_largepage; | ||
746 | } else if (nfc_is_v1()) { | ||
747 | host->regs = host->base; | ||
748 | host->spare0 = host->base + 0x800; | ||
749 | host->spare_len = 16; | ||
750 | oob_smallpage = &nandv1_hw_eccoob_smallpage; | ||
751 | oob_largepage = &nandv1_hw_eccoob_largepage; | ||
752 | } else | ||
753 | BUG(); | ||
754 | |||
755 | /* disable interrupt and spare enable */ | ||
918 | tmp = readw(host->regs + NFC_CONFIG1); | 756 | tmp = readw(host->regs + NFC_CONFIG1); |
919 | tmp |= NFC_INT_MSK; | 757 | tmp |= NFC_INT_MSK; |
758 | tmp &= ~NFC_SP_EN; | ||
920 | writew(tmp, host->regs + NFC_CONFIG1); | 759 | writew(tmp, host->regs + NFC_CONFIG1); |
921 | 760 | ||
922 | init_waitqueue_head(&host->irq_waitq); | 761 | init_waitqueue_head(&host->irq_waitq); |
923 | 762 | ||
924 | host->irq = platform_get_irq(pdev, 0); | 763 | host->irq = platform_get_irq(pdev, 0); |
925 | 764 | ||
926 | err = request_irq(host->irq, mxc_nfc_irq, 0, "mxc_nd", host); | 765 | err = request_irq(host->irq, mxc_nfc_irq, 0, DRIVER_NAME, host); |
927 | if (err) | 766 | if (err) |
928 | goto eirq; | 767 | goto eirq; |
929 | 768 | ||
769 | /* Reset NAND */ | ||
770 | this->cmdfunc(mtd, NAND_CMD_RESET, -1, -1); | ||
771 | |||
772 | /* preset operation */ | ||
773 | /* Unlock the internal RAM Buffer */ | ||
774 | writew(0x2, host->regs + NFC_CONFIG); | ||
775 | |||
776 | /* Blocks to be unlocked */ | ||
777 | if (nfc_is_v21()) { | ||
778 | writew(0x0, host->regs + NFC_V21_UNLOCKSTART_BLKADDR); | ||
779 | writew(0xffff, host->regs + NFC_V21_UNLOCKEND_BLKADDR); | ||
780 | this->ecc.bytes = 9; | ||
781 | } else if (nfc_is_v1()) { | ||
782 | writew(0x0, host->regs + NFC_V1_UNLOCKSTART_BLKADDR); | ||
783 | writew(0x4000, host->regs + NFC_V1_UNLOCKEND_BLKADDR); | ||
784 | this->ecc.bytes = 3; | ||
785 | } else | ||
786 | BUG(); | ||
787 | |||
788 | /* Unlock Block Command for given address range */ | ||
789 | writew(0x4, host->regs + NFC_WRPROT); | ||
790 | |||
791 | this->ecc.size = 512; | ||
792 | this->ecc.layout = oob_smallpage; | ||
793 | |||
930 | if (pdata->hw_ecc) { | 794 | if (pdata->hw_ecc) { |
931 | this->ecc.calculate = mxc_nand_calculate_ecc; | 795 | this->ecc.calculate = mxc_nand_calculate_ecc; |
932 | this->ecc.hwctl = mxc_nand_enable_hwecc; | 796 | this->ecc.hwctl = mxc_nand_enable_hwecc; |
933 | this->ecc.correct = mxc_nand_correct_data; | 797 | this->ecc.correct = mxc_nand_correct_data; |
934 | this->ecc.mode = NAND_ECC_HW; | 798 | this->ecc.mode = NAND_ECC_HW; |
935 | this->ecc.size = 512; | ||
936 | this->ecc.bytes = 3; | ||
937 | tmp = readw(host->regs + NFC_CONFIG1); | 799 | tmp = readw(host->regs + NFC_CONFIG1); |
938 | tmp |= NFC_ECC_EN; | 800 | tmp |= NFC_ECC_EN; |
939 | writew(tmp, host->regs + NFC_CONFIG1); | 801 | writew(tmp, host->regs + NFC_CONFIG1); |
940 | } else { | 802 | } else { |
941 | this->ecc.size = 512; | ||
942 | this->ecc.bytes = 3; | ||
943 | this->ecc.layout = &nand_hw_eccoob_8; | ||
944 | this->ecc.mode = NAND_ECC_SOFT; | 803 | this->ecc.mode = NAND_ECC_SOFT; |
945 | tmp = readw(host->regs + NFC_CONFIG1); | 804 | tmp = readw(host->regs + NFC_CONFIG1); |
946 | tmp &= ~NFC_ECC_EN; | 805 | tmp &= ~NFC_ECC_EN; |
947 | writew(tmp, host->regs + NFC_CONFIG1); | 806 | writew(tmp, host->regs + NFC_CONFIG1); |
948 | } | 807 | } |
949 | 808 | ||
950 | /* Reset NAND */ | ||
951 | this->cmdfunc(mtd, NAND_CMD_RESET, -1, -1); | ||
952 | |||
953 | /* preset operation */ | ||
954 | /* Unlock the internal RAM Buffer */ | ||
955 | writew(0x2, host->regs + NFC_CONFIG); | ||
956 | |||
957 | /* Blocks to be unlocked */ | ||
958 | writew(0x0, host->regs + NFC_UNLOCKSTART_BLKADDR); | ||
959 | writew(0x4000, host->regs + NFC_UNLOCKEND_BLKADDR); | ||
960 | |||
961 | /* Unlock Block Command for given address range */ | ||
962 | writew(0x4, host->regs + NFC_WRPROT); | ||
963 | |||
964 | /* NAND bus width determines access funtions used by upper layer */ | 809 | /* NAND bus width determines access funtions used by upper layer */ |
965 | if (pdata->width == 2) { | 810 | if (pdata->width == 2) |
966 | this->options |= NAND_BUSWIDTH_16; | 811 | this->options |= NAND_BUSWIDTH_16; |
967 | this->ecc.layout = &nand_hw_eccoob_16; | 812 | |
813 | if (pdata->flash_bbt) { | ||
814 | this->bbt_td = &bbt_main_descr; | ||
815 | this->bbt_md = &bbt_mirror_descr; | ||
816 | /* update flash based bbt */ | ||
817 | this->options |= NAND_USE_FLASH_BBT; | ||
968 | } | 818 | } |
969 | 819 | ||
970 | /* first scan to find the device and get the page size */ | 820 | /* first scan to find the device and get the page size */ |
@@ -973,35 +823,8 @@ static int __init mxcnd_probe(struct platform_device *pdev) | |||
973 | goto escan; | 823 | goto escan; |
974 | } | 824 | } |
975 | 825 | ||
976 | host->pagesize_2k = (mtd->writesize == 2048) ? 1 : 0; | 826 | if (mtd->writesize == 2048) |
977 | 827 | this->ecc.layout = oob_largepage; | |
978 | if (this->ecc.mode == NAND_ECC_HW) { | ||
979 | switch (mtd->oobsize) { | ||
980 | case 8: | ||
981 | this->ecc.layout = &nand_hw_eccoob_8; | ||
982 | break; | ||
983 | case 16: | ||
984 | this->ecc.layout = &nand_hw_eccoob_16; | ||
985 | break; | ||
986 | case 64: | ||
987 | this->ecc.layout = &nand_hw_eccoob_64; | ||
988 | break; | ||
989 | default: | ||
990 | /* page size not handled by HW ECC */ | ||
991 | /* switching back to soft ECC */ | ||
992 | this->ecc.size = 512; | ||
993 | this->ecc.bytes = 3; | ||
994 | this->ecc.layout = &nand_hw_eccoob_8; | ||
995 | this->ecc.mode = NAND_ECC_SOFT; | ||
996 | this->ecc.calculate = NULL; | ||
997 | this->ecc.correct = NULL; | ||
998 | this->ecc.hwctl = NULL; | ||
999 | tmp = readw(host->regs + NFC_CONFIG1); | ||
1000 | tmp &= ~NFC_ECC_EN; | ||
1001 | writew(tmp, host->regs + NFC_CONFIG1); | ||
1002 | break; | ||
1003 | } | ||
1004 | } | ||
1005 | 828 | ||
1006 | /* second phase scan */ | 829 | /* second phase scan */ |
1007 | if (nand_scan_tail(mtd)) { | 830 | if (nand_scan_tail(mtd)) { |
@@ -1029,7 +852,7 @@ static int __init mxcnd_probe(struct platform_device *pdev) | |||
1029 | escan: | 852 | escan: |
1030 | free_irq(host->irq, host); | 853 | free_irq(host->irq, host); |
1031 | eirq: | 854 | eirq: |
1032 | iounmap(host->regs); | 855 | iounmap(host->base); |
1033 | eres: | 856 | eres: |
1034 | clk_put(host->clk); | 857 | clk_put(host->clk); |
1035 | eclk: | 858 | eclk: |
@@ -1048,7 +871,7 @@ static int __exit mxcnd_remove(struct platform_device *pdev) | |||
1048 | 871 | ||
1049 | nand_release(&host->mtd); | 872 | nand_release(&host->mtd); |
1050 | free_irq(host->irq, host); | 873 | free_irq(host->irq, host); |
1051 | iounmap(host->regs); | 874 | iounmap(host->base); |
1052 | kfree(host); | 875 | kfree(host); |
1053 | 876 | ||
1054 | return 0; | 877 | return 0; |