BeRTOS
mt29f_sam3.c
Go to the documentation of this file.
00001 
00038 #include "mt29f_sam3.h"
00039 #include "cfg/cfg_mt29f.h"
00040 
00041 // Define log settings for cfg/log.h
00042 #define LOG_LEVEL    CONFIG_MT29F_LOG_LEVEL
00043 #define LOG_FORMAT   CONFIG_MT29F_LOG_FORMAT
00044 
00045 #include <cfg/log.h>
00046 #include <cfg/macros.h>
00047 
00048 #include <io/sam3.h>
00049 
00050 #include <drv/timer.h>
00051 #include <drv/mt29f.h>
00052 
00053 #include <cpu/power.h> /* cpu_relax() */
00054 #include <cpu/types.h>
00055 
00056 #include <string.h> /* memcpy() */
00057 
00058 // Timeout for NAND operations in ms
00059 #define MT29F_TMOUT  100
00060 
00061 // NAND flash status codes
00062 #define MT29F_STATUS_READY             BV(6)
00063 #define MT29F_STATUS_ERROR             BV(0)
00064 
00065 // NAND flash commands
00066 #define MT29F_CMD_READ_1               0x00
00067 #define MT29F_CMD_READ_2               0x30
00068 #define MT29F_CMD_COPYBACK_READ_1      0x00
00069 #define MT29F_CMD_COPYBACK_READ_2      0x35
00070 #define MT29F_CMD_COPYBACK_PROGRAM_1   0x85
00071 #define MT29F_CMD_COPYBACK_PROGRAM_2   0x10
00072 #define MT29F_CMD_RANDOM_OUT           0x05
00073 #define MT29F_CMD_RANDOM_OUT_2         0xE0
00074 #define MT29F_CMD_RANDOM_IN            0x85
00075 #define MT29F_CMD_READID               0x90
00076 #define MT29F_CMD_WRITE_1              0x80
00077 #define MT29F_CMD_WRITE_2              0x10
00078 #define MT29F_CMD_ERASE_1              0x60
00079 #define MT29F_CMD_ERASE_2              0xD0
00080 #define MT29F_CMD_STATUS               0x70
00081 #define MT29F_CMD_RESET                0xFF
00082 
00083 // Addresses for sending command, addresses and data bytes to flash
00084 #define MT29F_CMD_ADDR    0x60400000
00085 #define MT29F_ADDR_ADDR   0x60200000
00086 #define MT29F_DATA_ADDR   0x60000000
00087 
00088 // Get chip select mask for command register
00089 #define MT29F_CSID(chip)  (((chip)->chip_select << NFC_CMD_CSID_SHIFT) & NFC_CMD_CSID_MASK)
00090 
00091 
00092 /*
00093  * Translate flash page index plus a byte offset
00094  * in the five address cycles format needed by NAND.
00095  *
00096  * Cycles in x8 mode as the MT29F2G08AAD
00097  * CA = column addr, PA = page addr, BA = block addr
00098  *
00099  * Cycle    I/O7  I/O6  I/O5  I/O4  I/O3  I/O2  I/O1  I/O0
00100  * -------------------------------------------------------
00101  * First    CA7   CA6   CA5   CA4   CA3   CA2   CA1   CA0
00102  * Second   LOW   LOW   LOW   LOW   CA11  CA10  CA9   CA8
00103  * Third    BA7   BA6   PA5   PA4   PA3   PA2   PA1   PA0
00104  * Fourth   BA15  BA14  BA13  BA12  BA11  BA10  BA9   BA8
00105  * Fifth    LOW   LOW   LOW   LOW   LOW   LOW   LOW   BA16
00106  */
00107 static void getAddrCycles(uint32_t page, uint16_t offset, uint32_t *cycle0, uint32_t *cycle1234)
00108 {
00109     ASSERT(offset < MT29F_PAGE_SIZE);
00110 
00111     *cycle0 = offset & 0xff;
00112     *cycle1234 = (page << 8) | ((offset >> 8) & 0xf);
00113 
00114     LOG_INFO("mt29f addr: %lx %lx\n", *cycle1234, *cycle0);
00115 }
00116 
00117 
00118 INLINE bool nfcIsBusy(void)
00119 {
00120     return HWREG(NFC_CMD_BASE_ADDR + NFC_CMD_NFCCMD) & 0x8000000;
00121 }
00122 
00123 INLINE bool isCmdDone(void)
00124 {
00125     return SMC_SR & SMC_SR_CMDDONE;
00126 }
00127 
00128 static bool waitReadyBusy(void)
00129 {
00130     time_t start = timer_clock();
00131 
00132     while (!(SMC_SR & SMC_SR_RB_EDGE0))
00133     {
00134         cpu_relax();
00135         if (timer_clock() - start > MT29F_TMOUT)
00136         {
00137             LOG_INFO("mt29f: R/B timeout\n");
00138             return false;
00139         }
00140     }
00141 
00142     return true;
00143 }
00144 
00145 /*
00146  * Wait for transfer to complete until timeout.
00147  * If transfer completes return true, false in case of timeout.
00148  */
00149 static bool waitTransferComplete(void)
00150 {
00151     time_t start = timer_clock();
00152 
00153     while (!(SMC_SR & SMC_SR_XFRDONE))
00154     {
00155         cpu_relax();
00156         if (timer_clock() - start > MT29F_TMOUT)
00157         {
00158             LOG_INFO("mt29f: xfer complete timeout\n");
00159             return false;
00160         }
00161     }
00162 
00163     return true;
00164 }
00165 
00166 
00167 /*
00168  * Send command to NAND and wait for completion.
00169  */
00170 static void sendCommand(uint32_t cmd,
00171         int num_cycles, uint32_t cycle0, uint32_t cycle1234)
00172 {
00173     reg32_t *cmd_addr;
00174 
00175     while (nfcIsBusy());
00176 
00177     if (num_cycles == 5)
00178         SMC_ADDR = cycle0;
00179 
00180     cmd_addr = (reg32_t *)(NFC_CMD_BASE_ADDR + cmd);
00181     *cmd_addr = cycle1234;
00182 
00183     while (!isCmdDone());
00184 }
00185 
00186 
00187 static bool isOperationComplete(Mt29f *chip)
00188 {
00189     uint8_t status;
00190 
00191     sendCommand(MT29F_CSID(chip) |
00192         NFC_CMD_NFCCMD | NFC_CMD_ACYCLE_NONE |
00193         MT29F_CMD_STATUS << 2,
00194         0, 0, 0);
00195 
00196     status = (uint8_t)HWREG(MT29F_DATA_ADDR);
00197     return (status & MT29F_STATUS_READY) && !(status & MT29F_STATUS_ERROR);
00198 }
00199 
00200 
00201 static void chipReset(Mt29f *chip)
00202 {
00203     sendCommand(MT29F_CSID(chip) |
00204         NFC_CMD_NFCCMD | NFC_CMD_ACYCLE_NONE |
00205         MT29F_CMD_RESET << 2,
00206         0, 0, 0);
00207 
00208     waitReadyBusy();
00209 }
00210 
00211 
00215 int mt29f_blockErase(Mt29f *chip, uint32_t page)
00216 {
00217     uint32_t cycle0;
00218     uint32_t cycle1234;
00219 
00220     getAddrCycles(page, 0, &cycle0, &cycle1234);
00221 
00222     sendCommand(MT29F_CSID(chip) |
00223         NFC_CMD_NFCCMD | NFC_CMD_ACYCLE_THREE | NFC_CMD_VCMD2 |
00224         (MT29F_CMD_ERASE_2 << 10) | (MT29F_CMD_ERASE_1 << 2),
00225         3, 0, cycle1234 >> 8);
00226 
00227     waitReadyBusy();
00228 
00229     if (!isOperationComplete(chip))
00230     {
00231         LOG_ERR("mt29f: error erasing block\n");
00232         chip->status |= MT29F_ERR_ERASE;
00233         return -1;
00234     }
00235 
00236     return 0;
00237 }
00238 
00239 
00243 bool mt29f_getDevId(Mt29f *chip, uint8_t dev_id[5])
00244 {
00245     sendCommand(MT29F_CSID(chip) |
00246         NFC_CMD_NFCCMD | NFC_CMD_NFCEN | NFC_CMD_ACYCLE_ONE |
00247         MT29F_CMD_READID << 2,
00248         1, 0, 0);
00249 
00250     waitReadyBusy();
00251     if (!waitTransferComplete())
00252     {
00253         LOG_ERR("mt29f: getDevId timeout\n");
00254         chip->status |= MT29F_ERR_RD_TMOUT;
00255         return false;
00256     }
00257 
00258     memcpy(dev_id, (void *)NFC_SRAM_BASE_ADDR, 5);
00259     return true;
00260 }
00261 
00262 
00263 static bool checkEcc(void)
00264 {
00265     uint32_t sr1 = SMC_ECC_SR1;
00266 
00267     if (sr1)
00268     {
00269         LOG_INFO("ECC error, ECC_SR1=0x%lx\n", sr1);
00270         return false;
00271     }
00272     else
00273         return true;
00274 }
00275 
00276 
00277 static bool mt29f_readPage(Mt29f *chip, uint32_t page, uint16_t offset)
00278 {
00279     uint32_t cycle0;
00280     uint32_t cycle1234;
00281 
00282     LOG_INFO("mt29f_readPage: page 0x%lx off 0x%x\n", page, offset);
00283 
00284     getAddrCycles(page, offset, &cycle0, &cycle1234);
00285 
00286     sendCommand(MT29F_CSID(chip) |
00287         NFC_CMD_NFCCMD | NFC_CMD_NFCEN | NFC_CMD_ACYCLE_FIVE | NFC_CMD_VCMD2 |
00288         (MT29F_CMD_READ_2 << 10) | (MT29F_CMD_READ_1 << 2),
00289         5, cycle0, cycle1234);
00290 
00291     waitReadyBusy();
00292     if (!waitTransferComplete())
00293     {
00294         LOG_ERR("mt29f: read timeout\n");
00295         chip->status |= MT29F_ERR_RD_TMOUT;
00296         return false;
00297     }
00298 
00299     return true;
00300 }
00301 
00302 
00303 /*
00304  * Read page data and ECC, checking for errors.
00305  * TODO: fix errors with ECC when possible.
00306  */
00307 bool mt29f_read(Mt29f *chip, uint32_t page, void *buf, uint16_t size)
00308 {
00309     ASSERT(size <= MT29F_DATA_SIZE);
00310 
00311     if (!mt29f_readPage(chip, page, 0))
00312         return false;
00313 
00314     memcpy(buf, (void *)NFC_SRAM_BASE_ADDR, size);
00315 
00316     return checkEcc();
00317 }
00318 
00319 
00320 /*
00321  * Write data in NFC SRAM buffer to a NAND page, starting at a given offset.
00322  * Usually offset will be 0 to write data or MT29F_DATA_SIZE to write the spare
00323  * area.
00324  *
00325  * According to datasheet to get ECC computed by hardware is sufficient
00326  * to write the main area.  But it seems that in that way the last ECC_PR
00327  * register is not generated.  The workaround is to write data and dummy (ff)
00328  * spare data in one write, at this point the last ECC_PR is correct and
00329  * ECC data can be written in the spare area with a second program operation.
00330  */
00331 static bool mt29f_writePage(Mt29f *chip, uint32_t page, uint16_t offset)
00332 {
00333     uint32_t cycle0;
00334     uint32_t cycle1234;
00335 
00336     LOG_INFO("mt29f_writePage: page 0x%lx off 0x%x\n", page, offset);
00337 
00338     getAddrCycles(page, offset, &cycle0, &cycle1234);
00339 
00340     sendCommand(MT29F_CSID(chip) |
00341             NFC_CMD_NFCCMD | NFC_CMD_NFCWR | NFC_CMD_NFCEN | NFC_CMD_ACYCLE_FIVE |
00342             MT29F_CMD_WRITE_1 << 2,
00343             5, cycle0, cycle1234);
00344 
00345     if (!waitTransferComplete())
00346     {
00347         LOG_ERR("mt29f: write timeout\n");
00348         chip->status |= MT29F_ERR_WR_TMOUT;
00349         return false;
00350     }
00351 
00352     sendCommand(MT29F_CSID(chip) |
00353             NFC_CMD_NFCCMD | NFC_CMD_ACYCLE_NONE |
00354             MT29F_CMD_WRITE_2 << 2,
00355             0, 0, 0);
00356 
00357     waitReadyBusy();
00358 
00359     if (!isOperationComplete(chip))
00360     {
00361         LOG_ERR("mt29f: error writing page\n");
00362         chip->status |= MT29F_ERR_WRITE;
00363         return false;
00364     }
00365 
00366     return true;
00367 }
00368 
00369 
00370 /*
00371  * Write data in a page.
00372  */
00373 static bool mt29f_writePageData(Mt29f *chip, uint32_t page, const void *buf, uint16_t size)
00374 {
00375     ASSERT(size <= MT29F_DATA_SIZE);
00376 
00377     memset((void *)NFC_SRAM_BASE_ADDR, 0xff, MT29F_PAGE_SIZE);
00378     memcpy((void *)NFC_SRAM_BASE_ADDR, buf, size);
00379 
00380     return mt29f_writePage(chip, page, 0);
00381 }
00382 
00383 
00384 /*
00385  * Write the ECC for a page.
00386  *
00387  * ECC data are extracted from ECC_PRx registers and written
00388  * in the page's spare area.
00389  * For 2048 bytes pages and 1 ECC word each 256 bytes,
00390  * 24 bytes of ECC data are stored.
00391  */
00392 static bool mt29f_writePageEcc(Mt29f *chip, uint32_t page)
00393 {
00394     int i;
00395     uint32_t *buf = (uint32_t *)NFC_SRAM_BASE_ADDR;
00396 
00397     memset((void *)NFC_SRAM_BASE_ADDR, 0xff, MT29F_SPARE_SIZE);
00398 
00399     for (i = 0; i < MT29F_ECC_NWORDS; i++)
00400         buf[i] = *((reg32_t *)(SMC_BASE + SMC_ECC_PR0_OFF) + i);
00401 
00402     return mt29f_writePage(chip, page, MT29F_DATA_SIZE);
00403 }
00404 
00405 
00406 bool mt29f_write(Mt29f *chip, uint32_t page, const void *buf, uint16_t size)
00407 {
00408     return
00409         mt29f_writePageData(chip, page, buf, size) &&
00410         mt29f_writePageEcc(chip, page);
00411 }
00412 
00413 
00414 int mt29f_error(Mt29f *chip)
00415 {
00416     return chip->status;
00417 }
00418 
00419 
00420 void mt29f_clearError(Mt29f *chip)
00421 {
00422     chip->status = 0;
00423 }
00424 
00425 
00426 static void initPio(void)
00427 {
00428     /*
00429      * TODO: put following stuff in hw_ file dependent
00430      * Parameters for MT29F8G08AAD
00431      */
00432     pmc_periphEnable(PIOA_ID);
00433     pmc_periphEnable(PIOC_ID);
00434     pmc_periphEnable(PIOD_ID);
00435 
00436     PIO_PERIPH_SEL(PIOA_BASE, MT29F_PINS_PORTA, MT29F_PERIPH_PORTA);
00437     PIOA_PDR = MT29F_PINS_PORTA;
00438     PIOA_PUER = MT29F_PINS_PORTA;
00439 
00440     PIO_PERIPH_SEL(PIOC_BASE, MT29F_PINS_PORTC, MT29F_PERIPH_PORTC);
00441     PIOC_PDR = MT29F_PINS_PORTC;
00442     PIOC_PUER = MT29F_PINS_PORTC;
00443 
00444     PIO_PERIPH_SEL(PIOD_BASE, MT29F_PINS_PORTD, MT29F_PERIPH_PORTD);
00445     PIOD_PDR = MT29F_PINS_PORTD;
00446     PIOD_PUER = MT29F_PINS_PORTD;
00447 
00448     pmc_periphEnable(SMC_SDRAMC_ID);
00449 }
00450 
00451 
00452 static void initSmc(void)
00453 {
00454     SMC_SETUP0 = SMC_SETUP_NWE_SETUP(0)
00455         | SMC_SETUP_NCS_WR_SETUP(0)
00456         | SMC_SETUP_NRD_SETUP(0)
00457         | SMC_SETUP_NCS_RD_SETUP(0);
00458 
00459     SMC_PULSE0 = SMC_PULSE_NWE_PULSE(2)
00460         | SMC_PULSE_NCS_WR_PULSE(3)
00461         | SMC_PULSE_NRD_PULSE(2)
00462         | SMC_PULSE_NCS_RD_PULSE(3);
00463 
00464     SMC_CYCLE0 = SMC_CYCLE_NWE_CYCLE(3)
00465         | SMC_CYCLE_NRD_CYCLE(3);
00466 
00467     SMC_TIMINGS0 = SMC_TIMINGS_TCLR(1)
00468         | SMC_TIMINGS_TADL(6)
00469         | SMC_TIMINGS_TAR(4)
00470         | SMC_TIMINGS_TRR(2)
00471         | SMC_TIMINGS_TWB(9)
00472         | SMC_TIMINGS_RBNSEL(7)
00473         | SMC_TIMINGS_NFSEL;
00474 
00475     SMC_MODE0 = SMC_MODE_READ_MODE
00476         | SMC_MODE_WRITE_MODE;
00477 
00478     SMC_CFG = SMC_CFG_PAGESIZE_PS2048_64
00479         | SMC_CFG_EDGECTRL
00480         | SMC_CFG_DTOMUL_X1048576
00481         | SMC_CFG_DTOCYC(0xF)
00482         | SMC_CFG_WSPARE
00483         | SMC_CFG_RSPARE;
00484 
00485     // Disable SMC interrupts, reset and enable NFC controller
00486     SMC_IDR = ~0;
00487     SMC_CTRL = 0;
00488     SMC_CTRL = SMC_CTRL_NFCEN;
00489 
00490     // Enable ECC, 1 ECC per 256 bytes
00491     SMC_ECC_CTRL = SMC_ECC_CTRL_SWRST;
00492     SMC_ECC_MD = SMC_ECC_MD_ECC_PAGESIZE_PS2048_64 | SMC_ECC_MD_TYPCORREC_C256B;
00493 }
00494 
00495 
00496 void mt29f_init(Mt29f *chip, uint8_t chip_select)
00497 {
00498     memset(chip, 0, sizeof(Mt29f));
00499 
00500     chip->chip_select = chip_select;
00501 
00502     initPio();
00503     initSmc();
00504     chipReset(chip);
00505 }
00506