mt29f nand driver: add kblock interface.
[bertos.git] / bertos / cpu / cortex-m3 / drv / mt29f_sam3.c
1 /**
2  * \file
3  * <!--
4  * This file is part of BeRTOS.
5  *
6  * Bertos is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
19  *
20  * As a special exception, you may use this file as part of a free software
21  * library without restriction.  Specifically, if other files instantiate
22  * templates or use macros or inline functions from this file, or you compile
23  * this file and link it with other files to produce an executable, this
24  * file does not by itself cause the resulting executable to be covered by
25  * the GNU General Public License.  This exception does not however
26  * invalidate any other reasons why the executable file might be covered by
27  * the GNU General Public License.
28  *
29  * Copyright 2011 Develer S.r.l. (http://www.develer.com/)
30  *
31  * -->
32  *
33  * \brief Micron MT29F serial NAND driver for SAM3's static memory controller.
34  *
35  * \author Stefano Fedrigo <aleph@develer.com>
36  */
37
38 #include "mt29f_sam3.h"
39 #include "cfg/cfg_mt29f.h"
40
41 // Define log settings for cfg/log.h
42 #define LOG_LEVEL    CONFIG_MT29F_LOG_LEVEL
43 #define LOG_FORMAT   CONFIG_MT29F_LOG_FORMAT
44
45 #include <cfg/log.h>
46 #include <cfg/macros.h>
47 #include <io/sam3.h>
48 #include <drv/timer.h>
49 #include <drv/mt29f.h>
50 #include <struct/heap.h>
51 #include <cpu/power.h> /* cpu_relax() */
52 #include <cpu/types.h>
53
54 #include <string.h> /* memcpy() */
55
56 // Timeout for NAND operations in ms
57 #define MT29F_TMOUT  100
58
59 // NAND flash status codes
60 #define MT29F_STATUS_READY             BV(6)
61 #define MT29F_STATUS_ERROR             BV(0)
62
63 // NAND flash commands
64 #define MT29F_CMD_READ_1               0x00
65 #define MT29F_CMD_READ_2               0x30
66 #define MT29F_CMD_COPYBACK_READ_1      0x00
67 #define MT29F_CMD_COPYBACK_READ_2      0x35
68 #define MT29F_CMD_COPYBACK_PROGRAM_1   0x85
69 #define MT29F_CMD_COPYBACK_PROGRAM_2   0x10
70 #define MT29F_CMD_RANDOM_OUT           0x05
71 #define MT29F_CMD_RANDOM_OUT_2         0xE0
72 #define MT29F_CMD_RANDOM_IN            0x85
73 #define MT29F_CMD_READID               0x90
74 #define MT29F_CMD_WRITE_1              0x80
75 #define MT29F_CMD_WRITE_2              0x10
76 #define MT29F_CMD_ERASE_1              0x60
77 #define MT29F_CMD_ERASE_2              0xD0
78 #define MT29F_CMD_STATUS               0x70
79 #define MT29F_CMD_RESET                0xFF
80
81 // Addresses for sending command, addresses and data bytes to flash
82 #define MT29F_CMD_ADDR    0x60400000
83 #define MT29F_ADDR_ADDR   0x60200000
84 #define MT29F_DATA_ADDR   0x60000000
85
86 // Get chip select mask for command register
87 #define MT29F_CSID(chip)  (((chip)->chip_select << NFC_CMD_CSID_SHIFT) & NFC_CMD_CSID_MASK)
88
89
90 /*
91  * Remap info written in the first page of each block
92  * used to remap bad blocks.
93  */
94 struct RemapInfo
95 {
96         uint32_t tag;         // Magic number to detect valid info
97         uint16_t mapped_blk;  // Bad block the block containing this info is remapping
98 };
99
100
101 /*
102  * Translate flash page index plus a byte offset
103  * in the five address cycles format needed by NAND.
104  *
105  * Cycles in x8 mode as the MT29F2G08AAD
106  * CA = column addr, PA = page addr, BA = block addr
107  *
108  * Cycle    I/O7  I/O6  I/O5  I/O4  I/O3  I/O2  I/O1  I/O0
109  * -------------------------------------------------------
110  * First    CA7   CA6   CA5   CA4   CA3   CA2   CA1   CA0
111  * Second   LOW   LOW   LOW   LOW   CA11  CA10  CA9   CA8
112  * Third    BA7   BA6   PA5   PA4   PA3   PA2   PA1   PA0
113  * Fourth   BA15  BA14  BA13  BA12  BA11  BA10  BA9   BA8
114  * Fifth    LOW   LOW   LOW   LOW   LOW   LOW   LOW   BA16
115  */
116 static void getAddrCycles(uint32_t page, uint16_t offset, uint32_t *cycle0, uint32_t *cycle1234)
117 {
118         ASSERT(offset < MT29F_PAGE_SIZE);
119
120         *cycle0 = offset & 0xff;
121         *cycle1234 = (page << 8) | ((offset >> 8) & 0xf);
122
123         //LOG_INFO("mt29f addr: %lx %lx\n", *cycle1234, *cycle0);
124 }
125
126
127 INLINE bool nfcIsBusy(void)
128 {
129         return HWREG(NFC_CMD_BASE_ADDR + NFC_CMD_NFCCMD) & 0x8000000;
130 }
131
132
133 /*
134  * Return true if SMC/NFC controller completed the last operations.
135  */
136 INLINE bool isCmdDone(void)
137 {
138     return SMC_SR & SMC_SR_CMDDONE;
139 }
140
141
142 /*
143  * Wait for edge transition of READY/BUSY NAND
144  * signal.
145  * Return true for edge detection, false in case of timeout.
146  */
147 static bool waitReadyBusy(void)
148 {
149         time_t start = timer_clock();
150
151         while (!(SMC_SR & SMC_SR_RB_EDGE0))
152         {
153                 cpu_relax();
154                 if (timer_clock() - start > MT29F_TMOUT)
155                 {
156                         LOG_INFO("mt29f: R/B timeout\n");
157                         return false;
158                 }
159         }
160
161         return true;
162 }
163
164 /*
165  * Wait for transfer to complete until timeout.
166  * If transfer completes return true, false in case of timeout.
167  */
168 static bool waitTransferComplete(void)
169 {
170         time_t start = timer_clock();
171
172         while (!(SMC_SR & SMC_SR_XFRDONE))
173         {
174                 cpu_relax();
175                 if (timer_clock() - start > MT29F_TMOUT)
176                 {
177                         LOG_INFO("mt29f: xfer complete timeout\n");
178                         return false;
179                 }
180         }
181
182         return true;
183 }
184
185
186 /*
187  * Send command to NAND and wait for completion.
188  */
189 static void sendCommand(uint32_t cmd,
190                 int num_cycles, uint32_t cycle0, uint32_t cycle1234)
191 {
192         reg32_t *cmd_addr;
193
194         while (nfcIsBusy());
195
196         if (num_cycles == 5)
197                 SMC_ADDR = cycle0;
198
199         cmd_addr = (reg32_t *)(NFC_CMD_BASE_ADDR + cmd);
200         *cmd_addr = cycle1234;
201
202         while (!isCmdDone());
203 }
204
205
206 static bool isOperationComplete(Mt29f *chip)
207 {
208         uint8_t status;
209
210         sendCommand(MT29F_CSID(chip) |
211                 NFC_CMD_NFCCMD | NFC_CMD_ACYCLE_NONE |
212                 MT29F_CMD_STATUS << 2,
213                 0, 0, 0);
214
215         status = (uint8_t)HWREG(MT29F_DATA_ADDR);
216         return (status & MT29F_STATUS_READY) && !(status & MT29F_STATUS_ERROR);
217 }
218
219
220 static void chipReset(Mt29f *chip)
221 {
222         sendCommand(MT29F_CSID(chip) |
223                 NFC_CMD_NFCCMD | NFC_CMD_ACYCLE_NONE |
224                 MT29F_CMD_RESET << 2,
225                 0, 0, 0);
226
227         waitReadyBusy();
228 }
229
230
231 /**
232  * Erase the whole block.
233  */
234 int mt29f_blockErase(Mt29f *chip, uint16_t block)
235 {
236         uint32_t cycle0;
237         uint32_t cycle1234;
238
239         getAddrCycles(block * MT29F_PAGES_PER_BLOCK, 0, &cycle0, &cycle1234);
240
241         sendCommand(MT29F_CSID(chip) |
242                 NFC_CMD_NFCCMD | NFC_CMD_ACYCLE_THREE | NFC_CMD_VCMD2 |
243                 (MT29F_CMD_ERASE_2 << 10) | (MT29F_CMD_ERASE_1 << 2),
244                 3, 0, cycle1234 >> 8);
245
246         waitReadyBusy();
247
248         if (!isOperationComplete(chip))
249         {
250                 LOG_ERR("mt29f: error erasing block\n");
251                 chip->status |= MT29F_ERR_ERASE;
252                 return -1;
253         }
254
255         return 0;
256 }
257
258
259 /**
260  * Read Device ID and configuration codes.
261  */
262 bool mt29f_getDevId(Mt29f *chip, uint8_t dev_id[5])
263 {
264         sendCommand(MT29F_CSID(chip) |
265                 NFC_CMD_NFCCMD | NFC_CMD_NFCEN | NFC_CMD_ACYCLE_ONE |
266                 MT29F_CMD_READID << 2,
267                 1, 0, 0);
268
269         waitReadyBusy();
270         if (!waitTransferComplete())
271         {
272                 LOG_ERR("mt29f: getDevId timeout\n");
273                 chip->status |= MT29F_ERR_RD_TMOUT;
274                 return false;
275         }
276
277         memcpy(dev_id, (void *)NFC_SRAM_BASE_ADDR, 5);
278         return true;
279 }
280
281
282 static bool checkEcc(Mt29f *chip)
283 {
284         struct RemapInfo *remap_info = (struct RemapInfo *)(NFC_SRAM_BASE_ADDR + MT29F_REMAP_TAG_OFFSET);
285
286         /*
287          * Check for ECC hardware status only if a valid RemapInfo structure is found.
288          * That guarantees we wrote the block and a valid ECC is present.
289          */
290         if (remap_info->tag == MT29F_REMAP_TAG)
291         {
292                 uint32_t sr1 = SMC_ECC_SR1;
293                 if (sr1)
294                 {
295                         LOG_INFO("ECC error, ECC_SR1=0x%lx\n", sr1);
296                         chip->status |= MT29F_ERR_ECC;
297                         return false;
298                 }
299         }
300
301         return true;
302 }
303
304
305 static bool mt29f_readPage(Mt29f *chip, uint32_t page, uint16_t offset)
306 {
307         uint32_t cycle0;
308         uint32_t cycle1234;
309
310         //LOG_INFO("mt29f_readPage: page 0x%lx off 0x%x\n", page, offset);
311
312         getAddrCycles(page, offset, &cycle0, &cycle1234);
313
314         sendCommand(MT29F_CSID(chip) |
315                 NFC_CMD_NFCCMD | NFC_CMD_NFCEN | NFC_CMD_ACYCLE_FIVE | NFC_CMD_VCMD2 |
316                 (MT29F_CMD_READ_2 << 10) | (MT29F_CMD_READ_1 << 2),
317                 5, cycle0, cycle1234);
318
319         waitReadyBusy();
320         if (!waitTransferComplete())
321         {
322                 LOG_ERR("mt29f: read timeout\n");
323                 chip->status |= MT29F_ERR_RD_TMOUT;
324                 return false;
325         }
326
327         return true;
328 }
329
330
331 /*
332  * Read page data and ECC, checking for errors.
333  * TODO: fix errors with ECC when possible.
334  */
335 static bool mt29f_read(Mt29f *chip, uint32_t page, void *buf, uint16_t size)
336 {
337         ASSERT(size <= MT29F_DATA_SIZE);
338
339         if (!mt29f_readPage(chip, page, 0))
340                 return false;
341
342         memcpy(buf, (void *)NFC_SRAM_BASE_ADDR, size);
343
344         return checkEcc(chip);
345 }
346
347
348 /*
349  * Write data in NFC SRAM buffer to a NAND page, starting at a given offset.
350  * Usually offset will be 0 to write data or MT29F_DATA_SIZE to write the spare
351  * area.
352  *
353  * According to datasheet to get ECC computed by hardware is sufficient
354  * to write the main area.  But it seems that in that way the last ECC_PR
355  * register is not generated.  The workaround is to write data and dummy (ff)
356  * spare data in one write, at this point the last ECC_PR is correct and
357  * ECC data can be written in the spare area with a second program operation.
358  */
359 static bool mt29f_writePage(Mt29f *chip, uint32_t page, uint16_t offset)
360 {
361         uint32_t cycle0;
362         uint32_t cycle1234;
363
364         LOG_INFO("mt29f_writePage: page 0x%lx off 0x%x\n", page, offset);
365
366         getAddrCycles(page, offset, &cycle0, &cycle1234);
367
368         sendCommand(MT29F_CSID(chip) |
369                         NFC_CMD_NFCCMD | NFC_CMD_NFCWR | NFC_CMD_NFCEN | NFC_CMD_ACYCLE_FIVE |
370                         MT29F_CMD_WRITE_1 << 2,
371                         5, cycle0, cycle1234);
372
373         if (!waitTransferComplete())
374         {
375                 LOG_ERR("mt29f: write timeout\n");
376                 chip->status |= MT29F_ERR_WR_TMOUT;
377                 return false;
378         }
379
380         sendCommand(MT29F_CSID(chip) |
381                         NFC_CMD_NFCCMD | NFC_CMD_ACYCLE_NONE |
382                         MT29F_CMD_WRITE_2 << 2,
383                         0, 0, 0);
384
385         waitReadyBusy();
386
387         if (!isOperationComplete(chip))
388         {
389                 LOG_ERR("mt29f: error writing page\n");
390                 chip->status |= MT29F_ERR_WRITE;
391                 return false;
392         }
393
394         return true;
395 }
396
397
398 /*
399  * Write data in a page.
400  */
401 static bool mt29f_writePageData(Mt29f *chip, uint32_t page, const void *buf, uint16_t size)
402 {
403         ASSERT(size <= MT29F_DATA_SIZE);
404
405         memset((void *)NFC_SRAM_BASE_ADDR, 0xff, MT29F_PAGE_SIZE);
406         memcpy((void *)NFC_SRAM_BASE_ADDR, buf, size);
407
408         return mt29f_writePage(chip, page, 0);
409 }
410
411
412 /*
413  * Write the spare area in a page: ECC and remap block index.
414  *
415  * ECC data are extracted from ECC_PRx registers and written
416  * in the page's spare area.
417  * For 2048 bytes pages and 1 ECC word each 256 bytes,
418  * 24 bytes of ECC data are stored.
419  */
420 static bool mt29f_writePageSpare(Mt29f *chip, uint32_t page)
421 {
422         int i;
423         uint32_t *buf = (uint32_t *)NFC_SRAM_BASE_ADDR;
424         uint16_t  blk = page / MT29F_PAGES_PER_BLOCK;
425         uint16_t  page_in_blk = page % MT29F_PAGES_PER_BLOCK;
426         struct RemapInfo *remap_info = (struct RemapInfo *)(NFC_SRAM_BASE_ADDR + MT29F_REMAP_TAG_OFFSET);
427
428         memset((void *)NFC_SRAM_BASE_ADDR, 0xff, MT29F_SPARE_SIZE);
429
430         for (i = 0; i < MT29F_ECC_NWORDS; i++)
431                 buf[i] = *((reg32_t *)(SMC_BASE + SMC_ECC_PR0_OFF) + i);
432
433         // Check for remapped block
434         if (chip->block_map[blk] != blk)
435                 page = chip->block_map[blk] * MT29F_PAGES_PER_BLOCK + page_in_blk;
436
437         // Write remap tag
438         remap_info->tag = MT29F_REMAP_TAG;
439         remap_info->mapped_blk = blk;
440
441         return mt29f_writePage(chip, page, MT29F_DATA_SIZE);
442 }
443
444
445 static bool mt29f_write(Mt29f *chip, uint32_t page, const void *buf, uint16_t size)
446 {
447         return
448                 mt29f_writePageData(chip, page, buf, size) &&
449                 mt29f_writePageSpare(chip, page);
450 }
451
452
453 /*
454  * Check if the given block is marked bad: ONFI standard mandates
455  * that bad block are marked with "00" bytes on the spare area of the
456  * first page in block.
457  */
458 static bool blockIsGood(Mt29f *chip, uint16_t blk)
459 {
460         uint8_t *first_byte = (uint8_t *)NFC_SRAM_BASE_ADDR;
461         bool good;
462
463         // Check first byte in spare area of first page in block
464         mt29f_readPage(chip, blk * MT29F_PAGES_PER_BLOCK, MT29F_DATA_SIZE);
465         good = *first_byte == 0xFF;
466
467         if (!good)
468                 LOG_INFO("mt29f: bad block %d\n", blk);
469
470         return good;
471 }
472
473
474 /*
475  * Return the main partition block remapped on given block in the remap
476  * partition (dest_blk).
477  */
478 static int getBadBlockFromRemapBlock(Mt29f *chip, uint16_t dest_blk)
479 {
480         struct RemapInfo *remap_info = (struct RemapInfo *)NFC_SRAM_BASE_ADDR;
481
482         if (!mt29f_readPage(chip, dest_blk * MT29F_PAGES_PER_BLOCK, MT29F_DATA_SIZE + MT29F_REMAP_TAG_OFFSET))
483                 return -1;
484
485         if (remap_info->tag == MT29F_REMAP_TAG)
486                 return remap_info->mapped_blk;
487         else
488                 return -1;
489 }
490
491
492 /*
493  * Set a block remapping: src_blk (a block in main data partition) is remappend
494  * on dest_blk (block in reserved remapped blocks partition).
495  */
496 static bool setMapping(Mt29f *chip, uint32_t src_blk, uint32_t dest_blk)
497 {
498         struct RemapInfo *remap_info = (struct RemapInfo *)NFC_SRAM_BASE_ADDR;
499
500         LOG_INFO("mt29f, setMapping(): src=%ld dst=%ld\n", src_blk, dest_blk);
501
502         if (!mt29f_readPage(chip, dest_blk * MT29F_PAGES_PER_BLOCK, MT29F_DATA_SIZE + MT29F_REMAP_TAG_OFFSET))
503                 return false;
504
505         remap_info->tag = MT29F_REMAP_TAG;
506         remap_info->mapped_blk = src_blk;
507
508         return mt29f_writePage(chip, dest_blk * MT29F_PAGES_PER_BLOCK, MT29F_DATA_SIZE + MT29F_REMAP_TAG_OFFSET);
509 }
510
511
512 /*
513  * Get a new block from the remap partition to use as a substitute
514  * for a bad block.
515  */
516 static uint16_t getFreeRemapBlock(Mt29f *chip)
517 {
518         int blk;
519
520         for (blk = chip->remap_start; blk < MT29F_NUM_BLOCKS; blk++)
521         {
522                 if (blockIsGood(chip, blk))
523                 {
524                         chip->remap_start = blk + 1;
525                         return blk;
526                 }
527         }
528
529         LOG_ERR("mt29f: reserved blocks for bad block remapping exhausted!\n");
530         return 0;
531 }
532
533
534 /*
535  * Check if NAND is initialized.
536  */
537 static bool chipIsMarked(Mt29f *chip)
538 {
539         return getBadBlockFromRemapBlock(chip, MT29F_NUM_USER_BLOCKS) != -1;
540 }
541
542
543 /*
544  * Initialize NAND (format). Scan NAND for factory marked bad blocks.
545  * All bad blocks found are remapped to the remap partition: each
546  * block in the remap partition used to remap bad blocks is marked.
547  */
548 static void initBlockMap(Mt29f *chip)
549 {
550         unsigned b, last;
551
552         // Default is for each block to not be remapped
553         for (b = 0; b < MT29F_NUM_USER_BLOCKS; b++)
554                 chip->block_map[b] = b;
555         chip->remap_start = MT29F_NUM_USER_BLOCKS;
556
557         if (chipIsMarked(chip))
558         {
559                 LOG_INFO("mt29f: found initialized NAND, searching for remapped blocks\n");
560
561                 // Scan for assigned blocks in remap area
562                 for (b = last = MT29F_NUM_USER_BLOCKS; b < MT29F_NUM_BLOCKS; b++)
563                 {
564                         if (blockIsGood(chip, b))
565                         {
566                                 int remapped_blk = getBadBlockFromRemapBlock(chip, b);
567                                 if (remapped_blk != -1 && remapped_blk != MT29F_NULL_REMAP)
568                                 {
569                                         LOG_INFO("mt29f: found remapped block %d->%d\n", remapped_blk, b);
570                                         chip->block_map[remapped_blk] = b;
571                                         last = b + 1;
572                                 }
573                         }
574                 }
575                 chip->remap_start = last;
576         }
577         else
578         {
579                 bool remapped_anything = false;
580
581                 LOG_INFO("mt29f: found new NAND, searching for bad blocks\n");
582
583                 for (b = 0; b < MT29F_NUM_USER_BLOCKS; b++)
584                 {
585                         if (!blockIsGood(chip, b))
586                         {
587                                 chip->block_map[b] = getFreeRemapBlock(chip);
588                                 setMapping(chip, b, chip->block_map[b]);
589                                 remapped_anything = true;
590                                 LOG_INFO("mt29f: found new bad block %d, remapped to %d\n", b, chip->block_map[b]);
591                         }
592                 }
593
594                 /*
595              * If no bad blocks are found (we're lucky!) write a dummy
596                  * remap to mark NAND and detect we already scanned it next time.
597                  */
598                 if (!remapped_anything)
599                 {
600                         setMapping(chip, MT29F_NULL_REMAP, MT29F_NUM_USER_BLOCKS);
601                         LOG_INFO("mt29f: no bad block founds, marked NAND\n");
602                 }
603         }
604 }
605
606
607 #ifdef _DEBUG
608
609 /*
610  * Erase all blocks.
611  * DON'T USE on production chips: this function will try to erase
612  * factory marked bad blocks too.
613  */
614 static void mt29f_wipe(Mt29f *chip)
615 {
616         int b;
617         for (b = 0; b < MT29F_NUM_BLOCKS; b++)
618         {
619                 LOG_INFO("mt29f: erasing block %d\n", b);
620                 mt29f_blockErase(chip, b);
621         }
622 }
623
624 /*
625  * Create some bad blocks, erasing them and writing the bad block mark.
626  */
627 static void mt29f_ruinSomeBlocks(Mt29f *chip)
628 {
629         int bads[] = { 7, 99, 555, 1003, 1004, 1432 };
630         unsigned i;
631
632         LOG_INFO("mt29f: erasing mark\n");
633         mt29f_blockErase(chip, MT29F_NUM_USER_BLOCKS);
634
635         for (i = 0; i < countof(bads); i++)
636         {
637                 LOG_INFO("mt29f: erasing block %d\n", bads[i]);
638                 mt29f_blockErase(chip, bads[i]);
639
640                 LOG_INFO("mt29f: marking page %d as bad\n", bads[i] * MT29F_PAGES_PER_BLOCK);
641                 memset((void *)NFC_SRAM_BASE_ADDR, 0, MT29F_SPARE_SIZE);
642                 mt29f_writePage(chip, bads[i] * MT29F_PAGES_PER_BLOCK, MT29F_DATA_SIZE);
643         }
644 }
645
646 #endif
647
648
649 static void initPio(void)
650 {
651         /*
652          * TODO: put following stuff in hw_ file dependent
653          * Parameters for MT29F8G08AAD
654          */
655         pmc_periphEnable(PIOA_ID);
656         pmc_periphEnable(PIOC_ID);
657         pmc_periphEnable(PIOD_ID);
658
659         PIO_PERIPH_SEL(PIOA_BASE, MT29F_PINS_PORTA, MT29F_PERIPH_PORTA);
660         PIOA_PDR = MT29F_PINS_PORTA;
661         PIOA_PUER = MT29F_PINS_PORTA;
662
663         PIO_PERIPH_SEL(PIOC_BASE, MT29F_PINS_PORTC, MT29F_PERIPH_PORTC);
664         PIOC_PDR = MT29F_PINS_PORTC;
665         PIOC_PUER = MT29F_PINS_PORTC;
666
667         PIO_PERIPH_SEL(PIOD_BASE, MT29F_PINS_PORTD, MT29F_PERIPH_PORTD);
668         PIOD_PDR = MT29F_PINS_PORTD;
669         PIOD_PUER = MT29F_PINS_PORTD;
670
671     pmc_periphEnable(SMC_SDRAMC_ID);
672 }
673
674
675 static void initSmc(void)
676 {
677     SMC_SETUP0 = SMC_SETUP_NWE_SETUP(0)
678                 | SMC_SETUP_NCS_WR_SETUP(0)
679                 | SMC_SETUP_NRD_SETUP(0)
680                 | SMC_SETUP_NCS_RD_SETUP(0);
681
682     SMC_PULSE0 = SMC_PULSE_NWE_PULSE(2)
683                 | SMC_PULSE_NCS_WR_PULSE(3)
684                 | SMC_PULSE_NRD_PULSE(2)
685                 | SMC_PULSE_NCS_RD_PULSE(3);
686
687     SMC_CYCLE0 = SMC_CYCLE_NWE_CYCLE(3)
688                 | SMC_CYCLE_NRD_CYCLE(3);
689
690     SMC_TIMINGS0 = SMC_TIMINGS_TCLR(1)
691                 | SMC_TIMINGS_TADL(6)
692                 | SMC_TIMINGS_TAR(4)
693                 | SMC_TIMINGS_TRR(2)
694                 | SMC_TIMINGS_TWB(9)
695                 | SMC_TIMINGS_RBNSEL(7)
696                 | SMC_TIMINGS_NFSEL;
697
698     SMC_MODE0 = SMC_MODE_READ_MODE
699                 | SMC_MODE_WRITE_MODE;
700
701         SMC_CFG = SMC_CFG_PAGESIZE_PS2048_64
702                 | SMC_CFG_EDGECTRL
703                 | SMC_CFG_DTOMUL_X1048576
704                 | SMC_CFG_DTOCYC(0xF)
705                 | SMC_CFG_WSPARE
706                 | SMC_CFG_RSPARE;
707
708         // Disable SMC interrupts, reset and enable NFC controller
709         SMC_IDR = ~0;
710         SMC_CTRL = 0;
711         SMC_CTRL = SMC_CTRL_NFCEN;
712
713         // Enable ECC, 1 ECC per 256 bytes
714         SMC_ECC_CTRL = SMC_ECC_CTRL_SWRST;
715         SMC_ECC_MD = SMC_ECC_MD_ECC_PAGESIZE_PS2048_64 | SMC_ECC_MD_TYPCORREC_C256B;
716 }
717
718
719 static bool commonInit(Mt29f *chip, struct Heap *heap, unsigned chip_select)
720 {
721         memset(chip, 0, sizeof(Mt29f));
722
723         DB(chip->kblock.priv.type = KBT_NAND);
724         chip->kblock.blk_size = MT29F_BLOCK_SIZE;
725         chip->kblock.blk_cnt  = MT29F_NUM_USER_BLOCKS;
726
727         chip->chip_select = chip_select;
728         chip->block_map = heap_allocmem(heap, MT29F_NUM_USER_BLOCKS * sizeof(*chip->block_map));
729         if (!chip->block_map)
730         {
731                 LOG_ERR("mt29f: error allocating block map\n");
732                 return false;
733         }
734
735         initPio();
736         initSmc();
737         chipReset(chip);
738         initBlockMap(chip);
739
740         return true;
741 }
742
743
744 /**************** Kblock interface ****************/
745
746
747 static size_t mt29f_writeDirect(struct KBlock *kblk, block_idx_t idx, const void *buf, size_t offset, size_t size)
748 {
749         ASSERT(offset <= MT29F_BLOCK_SIZE);
750         ASSERT(offset % MT29F_DATA_SIZE == 0);
751         ASSERT(size <= MT29F_BLOCK_SIZE);
752         ASSERT(size % MT29F_DATA_SIZE == 0);
753
754         while (offset < size)
755         {
756                 uint32_t page = (idx * MT29F_PAGES_PER_BLOCK) + (offset / MT29F_DATA_SIZE);
757
758                 if (!mt29f_write(MT29F_CAST(kblk), page, buf, MT29F_DATA_SIZE))
759                         break;
760
761                 offset += MT29F_DATA_SIZE;
762                 buf = (const char *)buf + MT29F_DATA_SIZE;
763         }
764
765         return offset;
766 }
767
768
769 static size_t mt29f_readDirect(struct KBlock *kblk, block_idx_t idx, void *buf, size_t offset, size_t size)
770 {
771         ASSERT(offset <= MT29F_BLOCK_SIZE);
772         ASSERT(offset % MT29F_DATA_SIZE == 0);
773         ASSERT(size <= MT29F_BLOCK_SIZE);
774         ASSERT(size % MT29F_DATA_SIZE == 0);
775
776         while (offset < size)
777         {
778                 uint32_t page = (idx * MT29F_PAGES_PER_BLOCK) + (offset / MT29F_DATA_SIZE);
779
780                 if (!mt29f_read(MT29F_CAST(kblk), page, buf, MT29F_DATA_SIZE))
781                         break;
782
783                 offset += MT29F_DATA_SIZE;
784                 buf = (char *)buf + MT29F_DATA_SIZE;
785         }
786
787         return offset;
788 }
789
790
791 static int mt29f_error(struct KBlock *kblk)
792 {
793         Mt29f *chip = MT29F_CAST(kblk);
794         return chip->status;
795 }
796
797
798 static void mt29f_clearError(struct KBlock *kblk)
799 {
800         Mt29f *chip = MT29F_CAST(kblk);
801         chip->status = 0;
802 }
803
804
805 static const KBlockVTable mt29f_buffered_vt =
806 {
807         .readDirect = mt29f_readDirect,
808         .writeDirect = mt29f_writeDirect,
809
810         .readBuf = kblock_swReadBuf,
811         .writeBuf = kblock_swWriteBuf,
812         .load = kblock_swLoad,
813         .store = kblock_swStore,
814
815         .error = mt29f_error,
816         .clearerr = mt29f_clearError,
817 };
818
819 static const KBlockVTable mt29f_unbuffered_vt =
820 {
821         .readDirect = mt29f_readDirect,
822         .writeDirect = mt29f_writeDirect,
823
824         .error = mt29f_error,
825         .clearerr = mt29f_clearError,
826 };
827
828
829 bool mt29f_init(Mt29f *chip, struct Heap *heap, unsigned chip_select)
830 {
831         if (!commonInit(chip, heap, chip_select))
832                 return false;
833
834         chip->kblock.priv.vt = &mt29f_buffered_vt;
835         chip->kblock.priv.flags |= KB_BUFFERED;
836
837         chip->kblock.priv.buf = heap_allocmem(heap, MT29F_BLOCK_SIZE);
838         if (!chip->kblock.priv.buf)
839         {
840                 LOG_ERR("mt29f: error allocating block buffer\n");
841                 return false;
842         }
843
844         // Load the first block in the cache
845         return mt29f_readDirect(&chip->kblock, 0, chip->kblock.priv.buf, 0, MT29F_DATA_SIZE);
846 }
847
848
849 bool mt29f_initUnbuffered(Mt29f *chip, struct Heap *heap, unsigned chip_select)
850 {
851         chip->kblock.priv.vt = &mt29f_unbuffered_vt;
852         return commonInit(chip, heap, chip_select);
853 }
854
855