MT29F NAND driver: implement bad block handling and remapping.
[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(void)
283 {
284         uint32_t sr1 = SMC_ECC_SR1;
285
286         if (sr1)
287         {
288                 LOG_INFO("ECC error, ECC_SR1=0x%lx\n", sr1);
289                 return false;
290         }
291         else
292                 return true;
293 }
294
295
296 static bool mt29f_readPage(Mt29f *chip, uint32_t page, uint16_t offset)
297 {
298         uint32_t cycle0;
299         uint32_t cycle1234;
300
301         //LOG_INFO("mt29f_readPage: page 0x%lx off 0x%x\n", page, offset);
302
303         getAddrCycles(page, offset, &cycle0, &cycle1234);
304
305         sendCommand(MT29F_CSID(chip) |
306                 NFC_CMD_NFCCMD | NFC_CMD_NFCEN | NFC_CMD_ACYCLE_FIVE | NFC_CMD_VCMD2 |
307                 (MT29F_CMD_READ_2 << 10) | (MT29F_CMD_READ_1 << 2),
308                 5, cycle0, cycle1234);
309
310         waitReadyBusy();
311         if (!waitTransferComplete())
312         {
313                 LOG_ERR("mt29f: read timeout\n");
314                 chip->status |= MT29F_ERR_RD_TMOUT;
315                 return false;
316         }
317
318         return true;
319 }
320
321
322 /*
323  * Read page data and ECC, checking for errors.
324  * TODO: fix errors with ECC when possible.
325  */
326 bool mt29f_read(Mt29f *chip, uint32_t page, void *buf, uint16_t size)
327 {
328         ASSERT(size <= MT29F_DATA_SIZE);
329
330         if (!mt29f_readPage(chip, page, 0))
331                 return false;
332
333         memcpy(buf, (void *)NFC_SRAM_BASE_ADDR, size);
334
335         return checkEcc();
336 }
337
338
339 /*
340  * Write data in NFC SRAM buffer to a NAND page, starting at a given offset.
341  * Usually offset will be 0 to write data or MT29F_DATA_SIZE to write the spare
342  * area.
343  *
344  * According to datasheet to get ECC computed by hardware is sufficient
345  * to write the main area.  But it seems that in that way the last ECC_PR
346  * register is not generated.  The workaround is to write data and dummy (ff)
347  * spare data in one write, at this point the last ECC_PR is correct and
348  * ECC data can be written in the spare area with a second program operation.
349  */
350 static bool mt29f_writePage(Mt29f *chip, uint32_t page, uint16_t offset)
351 {
352         uint32_t cycle0;
353         uint32_t cycle1234;
354
355         LOG_INFO("mt29f_writePage: page 0x%lx off 0x%x\n", page, offset);
356
357         getAddrCycles(page, offset, &cycle0, &cycle1234);
358
359         sendCommand(MT29F_CSID(chip) |
360                         NFC_CMD_NFCCMD | NFC_CMD_NFCWR | NFC_CMD_NFCEN | NFC_CMD_ACYCLE_FIVE |
361                         MT29F_CMD_WRITE_1 << 2,
362                         5, cycle0, cycle1234);
363
364         if (!waitTransferComplete())
365         {
366                 LOG_ERR("mt29f: write timeout\n");
367                 chip->status |= MT29F_ERR_WR_TMOUT;
368                 return false;
369         }
370
371         sendCommand(MT29F_CSID(chip) |
372                         NFC_CMD_NFCCMD | NFC_CMD_ACYCLE_NONE |
373                         MT29F_CMD_WRITE_2 << 2,
374                         0, 0, 0);
375
376         waitReadyBusy();
377
378         if (!isOperationComplete(chip))
379         {
380                 LOG_ERR("mt29f: error writing page\n");
381                 chip->status |= MT29F_ERR_WRITE;
382                 return false;
383         }
384
385         return true;
386 }
387
388
389 /*
390  * Write data in a page.
391  */
392 static bool mt29f_writePageData(Mt29f *chip, uint32_t page, const void *buf, uint16_t size)
393 {
394         ASSERT(size <= MT29F_DATA_SIZE);
395
396         memset((void *)NFC_SRAM_BASE_ADDR, 0xff, MT29F_PAGE_SIZE);
397         memcpy((void *)NFC_SRAM_BASE_ADDR, buf, size);
398
399         return mt29f_writePage(chip, page, 0);
400 }
401
402
403 /*
404  * Write the spare area in a page: ECC and remap block index.
405  *
406  * ECC data are extracted from ECC_PRx registers and written
407  * in the page's spare area.
408  * For 2048 bytes pages and 1 ECC word each 256 bytes,
409  * 24 bytes of ECC data are stored.
410  */
411 static bool mt29f_writePageSpare(Mt29f *chip, uint32_t page)
412 {
413         int i;
414         uint32_t *buf = (uint32_t *)NFC_SRAM_BASE_ADDR;
415         uint16_t  blk = page / MT29F_PAGES_PER_BLOCK;
416         uint16_t  page_in_blk = page % MT29F_PAGES_PER_BLOCK;
417         struct RemapInfo *remap_info = (struct RemapInfo *)(NFC_SRAM_BASE_ADDR + MT29F_REMAP_TAG_OFFSET);
418
419         memset((void *)NFC_SRAM_BASE_ADDR, 0xff, MT29F_SPARE_SIZE);
420
421         for (i = 0; i < MT29F_ECC_NWORDS; i++)
422                 buf[i] = *((reg32_t *)(SMC_BASE + SMC_ECC_PR0_OFF) + i);
423
424         // Check for remapped block
425         if (chip->block_map[blk] != blk)
426                 page = chip->block_map[blk] * MT29F_PAGES_PER_BLOCK + page_in_blk;
427
428         // Write remap tag in first page in block
429         if (page_in_blk == 0)
430         {
431                 remap_info->tag = MT29F_REMAP_TAG;
432                 remap_info->mapped_blk = blk;
433         }
434
435         return mt29f_writePage(chip, page, MT29F_DATA_SIZE);
436 }
437
438
439 bool mt29f_write(Mt29f *chip, uint32_t page, const void *buf, uint16_t size)
440 {
441         return
442                 mt29f_writePageData(chip, page, buf, size) &&
443                 mt29f_writePageSpare(chip, page);
444 }
445
446
447 int mt29f_error(Mt29f *chip)
448 {
449         return chip->status;
450 }
451
452
453 void mt29f_clearError(Mt29f *chip)
454 {
455         chip->status = 0;
456 }
457
458
459 /*
460  * Check if the given block is marked bad: ONFI standard mandates
461  * that bad block are marked with "00" bytes on the spare area of the
462  * first page in block.
463  */
464 static bool blockIsGood(Mt29f *chip, uint16_t blk)
465 {
466         uint8_t *first_byte = (uint8_t *)NFC_SRAM_BASE_ADDR;
467         bool good;
468
469         // Check first byte in spare area of first page in block
470         mt29f_readPage(chip, blk * MT29F_PAGES_PER_BLOCK, MT29F_DATA_SIZE);
471         good = *first_byte == 0xFF;
472
473         if (!good)
474                 LOG_INFO("mt29f: bad block %d\n", blk);
475
476         return good;
477 }
478
479
480 /*
481  * Return the main partition block remapped on given block in the remap
482  * partition (dest_blk).
483  */
484 static int getBadBlockFromRemapBlock(Mt29f *chip, uint16_t dest_blk)
485 {
486         struct RemapInfo *remap_info = (struct RemapInfo *)NFC_SRAM_BASE_ADDR;
487
488         if (!mt29f_readPage(chip, dest_blk * MT29F_PAGES_PER_BLOCK, MT29F_DATA_SIZE + MT29F_REMAP_TAG_OFFSET))
489                 return -1;
490
491         if (remap_info->tag == MT29F_REMAP_TAG)
492                 return remap_info->mapped_blk;
493         else
494                 return -1;
495 }
496
497
498 /*
499  * Set a block remapping: src_blk (a block in main data partition) is remappend
500  * on dest_blk (block in reserved remapped blocks partition).
501  */
502 static bool setMapping(Mt29f *chip, uint32_t src_blk, uint32_t dest_blk)
503 {
504         struct RemapInfo *remap_info = (struct RemapInfo *)NFC_SRAM_BASE_ADDR;
505
506         LOG_INFO("mt29f, setMapping(): src=%ld dst=%ld\n", src_blk, dest_blk);
507
508         if (!mt29f_readPage(chip, dest_blk * MT29F_PAGES_PER_BLOCK, MT29F_DATA_SIZE + MT29F_REMAP_TAG_OFFSET))
509                 return false;
510
511         remap_info->tag = MT29F_REMAP_TAG;
512         remap_info->mapped_blk = src_blk;
513
514         return mt29f_writePage(chip, dest_blk * MT29F_PAGES_PER_BLOCK, MT29F_DATA_SIZE + MT29F_REMAP_TAG_OFFSET);
515 }
516
517
518 /*
519  * Get a new block from the remap partition to use as a substitute
520  * for a bad block.
521  */
522 static uint16_t getFreeRemapBlock(Mt29f *chip)
523 {
524         int blk;
525
526         for (blk = chip->remap_start; blk < MT29F_NUM_BLOCKS; blk++)
527         {
528                 if (blockIsGood(chip, blk))
529                 {
530                         chip->remap_start = blk + 1;
531                         return blk;
532                 }
533         }
534
535         LOG_ERR("mt29f: reserved blocks for bad block remapping exhausted!\n");
536         return 0;
537 }
538
539
540 /*
541  * Check if NAND is initialized.
542  */
543 static bool chipIsMarked(Mt29f *chip)
544 {
545         return getBadBlockFromRemapBlock(chip, MT29F_NUM_USER_BLOCKS) != -1;
546 }
547
548
549 /*
550  * Initialize NAND (format). Scan NAND for factory marked bad blocks.
551  * All bad blocks found are remapped to the remap partition: each
552  * block in the remap partition used to remap bad blocks is marked.
553  */
554 static void initBlockMap(Mt29f *chip)
555 {
556         unsigned b, last;
557
558         // Default is for each block to not be remapped
559         for (b = 0; b < MT29F_NUM_USER_BLOCKS; b++)
560                 chip->block_map[b] = b;
561         chip->remap_start = MT29F_NUM_USER_BLOCKS;
562
563         if (chipIsMarked(chip))
564         {
565                 LOG_INFO("mt29f: found initialized NAND, searching for remapped blocks\n");
566
567                 // Scan for assigned blocks in remap area
568                 for (b = last = MT29F_NUM_USER_BLOCKS; b < MT29F_NUM_BLOCKS; b++)
569                 {
570                         if (blockIsGood(chip, b))
571                         {
572                                 int remapped_blk = getBadBlockFromRemapBlock(chip, b);
573                                 if (remapped_blk != -1 && remapped_blk != MT29F_NULL_REMAP)
574                                 {
575                                         LOG_INFO("mt29f: found remapped block %d->%d\n", remapped_blk, b);
576                                         chip->block_map[remapped_blk] = b;
577                                         last = b + 1;
578                                 }
579                         }
580                 }
581                 chip->remap_start = last;
582         }
583         else
584         {
585                 bool remapped_anything = false;
586
587                 LOG_INFO("mt29f: found new NAND, searching for bad blocks\n");
588
589                 for (b = 0; b < MT29F_NUM_USER_BLOCKS; b++)
590                 {
591                         if (!blockIsGood(chip, b))
592                         {
593                                 chip->block_map[b] = getFreeRemapBlock(chip);
594                                 setMapping(chip, b, chip->block_map[b]);
595                                 remapped_anything = true;
596                                 LOG_INFO("mt29f: found new bad block %d, remapped to %d\n", b, chip->block_map[b]);
597                         }
598                 }
599
600                 /*
601              * If no bad blocks are found (we're lucky!) write a dummy
602                  * remap to mark NAND and detect we already scanned it next time.
603                  */
604                 if (!remapped_anything)
605                 {
606                         setMapping(chip, MT29F_NULL_REMAP, MT29F_NUM_USER_BLOCKS);
607                         LOG_INFO("mt29f: no bad block founds, marked NAND\n");
608                 }
609         }
610 }
611
612
613 #ifdef _DEBUG
614
615 /*
616  * Erase all blocks.
617  * DON'T USE on production chips: this function will try to erase
618  * factory marked bad blocks too.
619  */
620 static void mt29f_wipe(Mt29f *chip)
621 {
622         int b;
623         for (b = 0; b < MT29F_NUM_BLOCKS; b++)
624         {
625                 LOG_INFO("mt29f: erasing block %d\n", b);
626                 mt29f_blockErase(chip, b);
627         }
628 }
629
630 /*
631  * Create some bad blocks, erasing them and writing the bad block mark.
632  */
633 static void mt29f_ruinSomeBlocks(Mt29f *chip)
634 {
635         int bads[] = { 7, 99, 555, 1003, 1004, 1432 };
636         unsigned i;
637
638         LOG_INFO("mt29f: erasing mark\n");
639         mt29f_blockErase(chip, MT29F_NUM_USER_BLOCKS);
640
641         for (i = 0; i < countof(bads); i++)
642         {
643                 LOG_INFO("mt29f: erasing block %d\n", bads[i]);
644                 mt29f_blockErase(chip, bads[i]);
645
646                 LOG_INFO("mt29f: marking page %d as bad\n", bads[i] * MT29F_PAGES_PER_BLOCK);
647                 memset((void *)NFC_SRAM_BASE_ADDR, 0, MT29F_SPARE_SIZE);
648                 mt29f_writePage(chip, bads[i] * MT29F_PAGES_PER_BLOCK, MT29F_DATA_SIZE);
649         }
650 }
651
652 #endif
653
654
655 static void initPio(void)
656 {
657         /*
658          * TODO: put following stuff in hw_ file dependent
659          * Parameters for MT29F8G08AAD
660          */
661         pmc_periphEnable(PIOA_ID);
662         pmc_periphEnable(PIOC_ID);
663         pmc_periphEnable(PIOD_ID);
664
665         PIO_PERIPH_SEL(PIOA_BASE, MT29F_PINS_PORTA, MT29F_PERIPH_PORTA);
666         PIOA_PDR = MT29F_PINS_PORTA;
667         PIOA_PUER = MT29F_PINS_PORTA;
668
669         PIO_PERIPH_SEL(PIOC_BASE, MT29F_PINS_PORTC, MT29F_PERIPH_PORTC);
670         PIOC_PDR = MT29F_PINS_PORTC;
671         PIOC_PUER = MT29F_PINS_PORTC;
672
673         PIO_PERIPH_SEL(PIOD_BASE, MT29F_PINS_PORTD, MT29F_PERIPH_PORTD);
674         PIOD_PDR = MT29F_PINS_PORTD;
675         PIOD_PUER = MT29F_PINS_PORTD;
676
677     pmc_periphEnable(SMC_SDRAMC_ID);
678 }
679
680
681 static void initSmc(void)
682 {
683     SMC_SETUP0 = SMC_SETUP_NWE_SETUP(0)
684                 | SMC_SETUP_NCS_WR_SETUP(0)
685                 | SMC_SETUP_NRD_SETUP(0)
686                 | SMC_SETUP_NCS_RD_SETUP(0);
687
688     SMC_PULSE0 = SMC_PULSE_NWE_PULSE(2)
689                 | SMC_PULSE_NCS_WR_PULSE(3)
690                 | SMC_PULSE_NRD_PULSE(2)
691                 | SMC_PULSE_NCS_RD_PULSE(3);
692
693     SMC_CYCLE0 = SMC_CYCLE_NWE_CYCLE(3)
694                 | SMC_CYCLE_NRD_CYCLE(3);
695
696     SMC_TIMINGS0 = SMC_TIMINGS_TCLR(1)
697                 | SMC_TIMINGS_TADL(6)
698                 | SMC_TIMINGS_TAR(4)
699                 | SMC_TIMINGS_TRR(2)
700                 | SMC_TIMINGS_TWB(9)
701                 | SMC_TIMINGS_RBNSEL(7)
702                 | SMC_TIMINGS_NFSEL;
703
704     SMC_MODE0 = SMC_MODE_READ_MODE
705                 | SMC_MODE_WRITE_MODE;
706
707         SMC_CFG = SMC_CFG_PAGESIZE_PS2048_64
708                 | SMC_CFG_EDGECTRL
709                 | SMC_CFG_DTOMUL_X1048576
710                 | SMC_CFG_DTOCYC(0xF)
711                 | SMC_CFG_WSPARE
712                 | SMC_CFG_RSPARE;
713
714         // Disable SMC interrupts, reset and enable NFC controller
715         SMC_IDR = ~0;
716         SMC_CTRL = 0;
717         SMC_CTRL = SMC_CTRL_NFCEN;
718
719         // Enable ECC, 1 ECC per 256 bytes
720         SMC_ECC_CTRL = SMC_ECC_CTRL_SWRST;
721         SMC_ECC_MD = SMC_ECC_MD_ECC_PAGESIZE_PS2048_64 | SMC_ECC_MD_TYPCORREC_C256B;
722 }
723
724
725 bool mt29f_init(Mt29f *chip, struct Heap *heap, uint8_t chip_select)
726 {
727         memset(chip, 0, sizeof(Mt29f));
728
729         chip->chip_select = chip_select;
730         chip->block_map = heap_allocmem(heap, MT29F_NUM_USER_BLOCKS * sizeof(*chip->block_map));
731         if (!chip->block_map)
732         {
733                 LOG_ERR("mt29f: error allocating block map\n");
734                 return false;
735         }
736
737         initPio();
738         initSmc();
739         chipReset(chip);
740         initBlockMap(chip);
741
742         return true;
743 }
744