130b251eaacf170e9b12d61129f4d6fd8ad8b27a
[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 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();
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 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 int mt29f_error(Mt29f *chip)
454 {
455         return chip->status;
456 }
457
458
459 void mt29f_clearError(Mt29f *chip)
460 {
461         chip->status = 0;
462 }
463
464
465 /*
466  * Check if the given block is marked bad: ONFI standard mandates
467  * that bad block are marked with "00" bytes on the spare area of the
468  * first page in block.
469  */
470 static bool blockIsGood(Mt29f *chip, uint16_t blk)
471 {
472         uint8_t *first_byte = (uint8_t *)NFC_SRAM_BASE_ADDR;
473         bool good;
474
475         // Check first byte in spare area of first page in block
476         mt29f_readPage(chip, blk * MT29F_PAGES_PER_BLOCK, MT29F_DATA_SIZE);
477         good = *first_byte == 0xFF;
478
479         if (!good)
480                 LOG_INFO("mt29f: bad block %d\n", blk);
481
482         return good;
483 }
484
485
486 /*
487  * Return the main partition block remapped on given block in the remap
488  * partition (dest_blk).
489  */
490 static int getBadBlockFromRemapBlock(Mt29f *chip, uint16_t dest_blk)
491 {
492         struct RemapInfo *remap_info = (struct RemapInfo *)NFC_SRAM_BASE_ADDR;
493
494         if (!mt29f_readPage(chip, dest_blk * MT29F_PAGES_PER_BLOCK, MT29F_DATA_SIZE + MT29F_REMAP_TAG_OFFSET))
495                 return -1;
496
497         if (remap_info->tag == MT29F_REMAP_TAG)
498                 return remap_info->mapped_blk;
499         else
500                 return -1;
501 }
502
503
504 /*
505  * Set a block remapping: src_blk (a block in main data partition) is remappend
506  * on dest_blk (block in reserved remapped blocks partition).
507  */
508 static bool setMapping(Mt29f *chip, uint32_t src_blk, uint32_t dest_blk)
509 {
510         struct RemapInfo *remap_info = (struct RemapInfo *)NFC_SRAM_BASE_ADDR;
511
512         LOG_INFO("mt29f, setMapping(): src=%ld dst=%ld\n", src_blk, dest_blk);
513
514         if (!mt29f_readPage(chip, dest_blk * MT29F_PAGES_PER_BLOCK, MT29F_DATA_SIZE + MT29F_REMAP_TAG_OFFSET))
515                 return false;
516
517         remap_info->tag = MT29F_REMAP_TAG;
518         remap_info->mapped_blk = src_blk;
519
520         return mt29f_writePage(chip, dest_blk * MT29F_PAGES_PER_BLOCK, MT29F_DATA_SIZE + MT29F_REMAP_TAG_OFFSET);
521 }
522
523
524 /*
525  * Get a new block from the remap partition to use as a substitute
526  * for a bad block.
527  */
528 static uint16_t getFreeRemapBlock(Mt29f *chip)
529 {
530         int blk;
531
532         for (blk = chip->remap_start; blk < MT29F_NUM_BLOCKS; blk++)
533         {
534                 if (blockIsGood(chip, blk))
535                 {
536                         chip->remap_start = blk + 1;
537                         return blk;
538                 }
539         }
540
541         LOG_ERR("mt29f: reserved blocks for bad block remapping exhausted!\n");
542         return 0;
543 }
544
545
546 /*
547  * Check if NAND is initialized.
548  */
549 static bool chipIsMarked(Mt29f *chip)
550 {
551         return getBadBlockFromRemapBlock(chip, MT29F_NUM_USER_BLOCKS) != -1;
552 }
553
554
555 /*
556  * Initialize NAND (format). Scan NAND for factory marked bad blocks.
557  * All bad blocks found are remapped to the remap partition: each
558  * block in the remap partition used to remap bad blocks is marked.
559  */
560 static void initBlockMap(Mt29f *chip)
561 {
562         unsigned b, last;
563
564         // Default is for each block to not be remapped
565         for (b = 0; b < MT29F_NUM_USER_BLOCKS; b++)
566                 chip->block_map[b] = b;
567         chip->remap_start = MT29F_NUM_USER_BLOCKS;
568
569         if (chipIsMarked(chip))
570         {
571                 LOG_INFO("mt29f: found initialized NAND, searching for remapped blocks\n");
572
573                 // Scan for assigned blocks in remap area
574                 for (b = last = MT29F_NUM_USER_BLOCKS; b < MT29F_NUM_BLOCKS; b++)
575                 {
576                         if (blockIsGood(chip, b))
577                         {
578                                 int remapped_blk = getBadBlockFromRemapBlock(chip, b);
579                                 if (remapped_blk != -1 && remapped_blk != MT29F_NULL_REMAP)
580                                 {
581                                         LOG_INFO("mt29f: found remapped block %d->%d\n", remapped_blk, b);
582                                         chip->block_map[remapped_blk] = b;
583                                         last = b + 1;
584                                 }
585                         }
586                 }
587                 chip->remap_start = last;
588         }
589         else
590         {
591                 bool remapped_anything = false;
592
593                 LOG_INFO("mt29f: found new NAND, searching for bad blocks\n");
594
595                 for (b = 0; b < MT29F_NUM_USER_BLOCKS; b++)
596                 {
597                         if (!blockIsGood(chip, b))
598                         {
599                                 chip->block_map[b] = getFreeRemapBlock(chip);
600                                 setMapping(chip, b, chip->block_map[b]);
601                                 remapped_anything = true;
602                                 LOG_INFO("mt29f: found new bad block %d, remapped to %d\n", b, chip->block_map[b]);
603                         }
604                 }
605
606                 /*
607              * If no bad blocks are found (we're lucky!) write a dummy
608                  * remap to mark NAND and detect we already scanned it next time.
609                  */
610                 if (!remapped_anything)
611                 {
612                         setMapping(chip, MT29F_NULL_REMAP, MT29F_NUM_USER_BLOCKS);
613                         LOG_INFO("mt29f: no bad block founds, marked NAND\n");
614                 }
615         }
616 }
617
618
619 #ifdef _DEBUG
620
621 /*
622  * Erase all blocks.
623  * DON'T USE on production chips: this function will try to erase
624  * factory marked bad blocks too.
625  */
626 static void mt29f_wipe(Mt29f *chip)
627 {
628         int b;
629         for (b = 0; b < MT29F_NUM_BLOCKS; b++)
630         {
631                 LOG_INFO("mt29f: erasing block %d\n", b);
632                 mt29f_blockErase(chip, b);
633         }
634 }
635
636 /*
637  * Create some bad blocks, erasing them and writing the bad block mark.
638  */
639 static void mt29f_ruinSomeBlocks(Mt29f *chip)
640 {
641         int bads[] = { 7, 99, 555, 1003, 1004, 1432 };
642         unsigned i;
643
644         LOG_INFO("mt29f: erasing mark\n");
645         mt29f_blockErase(chip, MT29F_NUM_USER_BLOCKS);
646
647         for (i = 0; i < countof(bads); i++)
648         {
649                 LOG_INFO("mt29f: erasing block %d\n", bads[i]);
650                 mt29f_blockErase(chip, bads[i]);
651
652                 LOG_INFO("mt29f: marking page %d as bad\n", bads[i] * MT29F_PAGES_PER_BLOCK);
653                 memset((void *)NFC_SRAM_BASE_ADDR, 0, MT29F_SPARE_SIZE);
654                 mt29f_writePage(chip, bads[i] * MT29F_PAGES_PER_BLOCK, MT29F_DATA_SIZE);
655         }
656 }
657
658 #endif
659
660
661 static void initPio(void)
662 {
663         /*
664          * TODO: put following stuff in hw_ file dependent
665          * Parameters for MT29F8G08AAD
666          */
667         pmc_periphEnable(PIOA_ID);
668         pmc_periphEnable(PIOC_ID);
669         pmc_periphEnable(PIOD_ID);
670
671         PIO_PERIPH_SEL(PIOA_BASE, MT29F_PINS_PORTA, MT29F_PERIPH_PORTA);
672         PIOA_PDR = MT29F_PINS_PORTA;
673         PIOA_PUER = MT29F_PINS_PORTA;
674
675         PIO_PERIPH_SEL(PIOC_BASE, MT29F_PINS_PORTC, MT29F_PERIPH_PORTC);
676         PIOC_PDR = MT29F_PINS_PORTC;
677         PIOC_PUER = MT29F_PINS_PORTC;
678
679         PIO_PERIPH_SEL(PIOD_BASE, MT29F_PINS_PORTD, MT29F_PERIPH_PORTD);
680         PIOD_PDR = MT29F_PINS_PORTD;
681         PIOD_PUER = MT29F_PINS_PORTD;
682
683     pmc_periphEnable(SMC_SDRAMC_ID);
684 }
685
686
687 static void initSmc(void)
688 {
689     SMC_SETUP0 = SMC_SETUP_NWE_SETUP(0)
690                 | SMC_SETUP_NCS_WR_SETUP(0)
691                 | SMC_SETUP_NRD_SETUP(0)
692                 | SMC_SETUP_NCS_RD_SETUP(0);
693
694     SMC_PULSE0 = SMC_PULSE_NWE_PULSE(2)
695                 | SMC_PULSE_NCS_WR_PULSE(3)
696                 | SMC_PULSE_NRD_PULSE(2)
697                 | SMC_PULSE_NCS_RD_PULSE(3);
698
699     SMC_CYCLE0 = SMC_CYCLE_NWE_CYCLE(3)
700                 | SMC_CYCLE_NRD_CYCLE(3);
701
702     SMC_TIMINGS0 = SMC_TIMINGS_TCLR(1)
703                 | SMC_TIMINGS_TADL(6)
704                 | SMC_TIMINGS_TAR(4)
705                 | SMC_TIMINGS_TRR(2)
706                 | SMC_TIMINGS_TWB(9)
707                 | SMC_TIMINGS_RBNSEL(7)
708                 | SMC_TIMINGS_NFSEL;
709
710     SMC_MODE0 = SMC_MODE_READ_MODE
711                 | SMC_MODE_WRITE_MODE;
712
713         SMC_CFG = SMC_CFG_PAGESIZE_PS2048_64
714                 | SMC_CFG_EDGECTRL
715                 | SMC_CFG_DTOMUL_X1048576
716                 | SMC_CFG_DTOCYC(0xF)
717                 | SMC_CFG_WSPARE
718                 | SMC_CFG_RSPARE;
719
720         // Disable SMC interrupts, reset and enable NFC controller
721         SMC_IDR = ~0;
722         SMC_CTRL = 0;
723         SMC_CTRL = SMC_CTRL_NFCEN;
724
725         // Enable ECC, 1 ECC per 256 bytes
726         SMC_ECC_CTRL = SMC_ECC_CTRL_SWRST;
727         SMC_ECC_MD = SMC_ECC_MD_ECC_PAGESIZE_PS2048_64 | SMC_ECC_MD_TYPCORREC_C256B;
728 }
729
730
731 bool mt29f_init(Mt29f *chip, struct Heap *heap, uint8_t chip_select)
732 {
733         memset(chip, 0, sizeof(Mt29f));
734
735         chip->chip_select = chip_select;
736         chip->block_map = heap_allocmem(heap, MT29F_NUM_USER_BLOCKS * sizeof(*chip->block_map));
737         if (!chip->block_map)
738         {
739                 LOG_ERR("mt29f: error allocating block map\n");
740                 return false;
741         }
742
743         initPio();
744         initSmc();
745         chipReset(chip);
746         initBlockMap(chip);
747
748         return true;
749 }
750