nand_sam3.c

Go to the documentation of this file.
00001 
00038 #include <drv/nand.h>
00039 #include <cfg/log.h>
00040 #include <io/sam3.h>
00041 #include <drv/timer.h>
00042 #include <cpu/power.h> // cpu_relax()
00043 
00044 
00045 /*
00046  * PIO definitions.
00047  */
00048 #define NAND_PIN_CE        BV(6)
00049 #define NAND_PIN_RB        BV(2)
00050 #define NAND_PINS_PORTA    (NAND_PIN_CE | NAND_PIN_RB)
00051 #define NAND_PERIPH_PORTA  PIO_PERIPH_B
00052 
00053 #define NAND_PIN_OE        BV(19)
00054 #define NAND_PIN_WE        BV(20)
00055 #define NAND_PIN_IO        0x0000FFFF
00056 #define NAND_PINS_PORTC    (NAND_PIN_OE | NAND_PIN_WE | NAND_PIN_IO)
00057 #define NAND_PERIPH_PORTC  PIO_PERIPH_A
00058 
00059 #define NAND_PIN_CLE       BV(9)
00060 #define NAND_PIN_ALE       BV(8)
00061 #define NAND_PINS_PORTD    (NAND_PIN_CLE | NAND_PIN_ALE)
00062 #define NAND_PERIPH_PORTD  PIO_PERIPH_A
00063 
00064 
00065 /*
00066  * Wait for edge transition of READY/BUSY NAND
00067  * signal.
00068  * Return true for edge detection, false in case of timeout.
00069  */
00070 bool nand_waitReadyBusy(UNUSED_ARG(Nand *, chip), time_t timeout)
00071 {
00072     time_t start = timer_clock();
00073 
00074     while (!(SMC_SR & SMC_SR_RB_EDGE0))
00075     {
00076         cpu_relax();
00077         if (timer_clock() - start > timeout)
00078         {
00079             LOG_INFO("nand: R/B timeout\n");
00080             return false;
00081         }
00082     }
00083 
00084     return true;
00085 }
00086 
00087 
00088 /*
00089  * Wait for transfer to complete until timeout.
00090  * If transfer completes return true, false in case of timeout.
00091  */
00092 bool nand_waitTransferComplete(UNUSED_ARG(Nand *, chip), time_t timeout)
00093 {
00094     time_t start = timer_clock();
00095 
00096     while (!(SMC_SR & SMC_SR_XFRDONE))
00097     {
00098         cpu_relax();
00099         if (timer_clock() - start > timeout)
00100         {
00101             LOG_INFO("nand: xfer complete timeout\n");
00102             return false;
00103         }
00104     }
00105 
00106     return true;
00107 }
00108 
00109 
00110 /*
00111  * Send command to NAND and wait for completion.
00112  */
00113 void nand_sendCommand(Nand *chip,
00114         uint32_t cmd1, uint32_t cmd2,
00115         int num_cycles, uint32_t cycle0, uint32_t cycle1234)
00116 {
00117     reg32_t *cmd_addr;
00118     uint32_t cmd_val;
00119 
00120     while (HWREG(NFC_CMD_BASE_ADDR + NFC_CMD_NFCCMD) & 0x8000000);
00121 
00122     if (num_cycles == 5)
00123         SMC_ADDR = cycle0;
00124 
00125     cmd_val = NFC_CMD_NFCCMD
00126         | ((chip->chip_select << NFC_CMD_CSID_SHIFT) & NFC_CMD_CSID_MASK)
00127         | ((num_cycles << NFC_CMD_ACYCLE_SHIFT) & NFC_CMD_ACYCLE_MASK)
00128         | cmd1 << 2
00129         | cmd2 << 10;
00130 
00131     // Check for commands transferring data
00132     if (cmd1 == NAND_CMD_WRITE_1 || cmd1 == NAND_CMD_READ_1 || cmd1 == NAND_CMD_READID)
00133         cmd_val |= NFC_CMD_NFCEN;
00134 
00135     // Check for commands writing data
00136     if (cmd1 == NAND_CMD_WRITE_1)
00137         cmd_val |= NFC_CMD_NFCWR;
00138 
00139     // Check for two command cycles
00140     if (cmd2)
00141         cmd_val |= NFC_CMD_VCMD2;
00142 
00143     cmd_addr = (reg32_t *)(NFC_CMD_BASE_ADDR + cmd_val);
00144     *cmd_addr = cycle1234;
00145 
00146     while (!(SMC_SR & SMC_SR_CMDDONE));
00147 }
00148 
00149 
00150 /*
00151  * Get NAND chip status register.
00152  *
00153  * NOTE: this is global between different chip selects, so returns
00154  * the status register of the last used NAND chip.
00155  */
00156 uint8_t nand_getChipStatus(UNUSED_ARG(Nand *, chip))
00157 {
00158     return (uint8_t)HWREG(NFC_CMD_BASE_ADDR);
00159 }
00160 
00161 
00162 /*
00163  * Return pointer to buffer where data are read to or written from
00164  * by nand_sendCommand().
00165  */
00166 void *nand_dataBuffer(UNUSED_ARG(Nand *, chip))
00167 {
00168     return (void *)NFC_SRAM_BASE_ADDR;
00169 }
00170 
00171 
00172 /*
00173  * Extract ECC data from ECC_PRx registers.
00174  */
00175 bool nand_checkEcc(UNUSED_ARG(Nand *, chip))
00176 {
00177     uint32_t sr1 = SMC_ECC_SR1;
00178     if (sr1)
00179     {
00180         LOG_INFO("ECC error, ECC_SR1=0x%lx\n", sr1);
00181         return false;
00182     }
00183     else
00184         return true;
00185 }
00186 
00187 
00188 /*
00189  * Compute ECC on data in a buffer.
00190  *
00191  * \param chip      nand context
00192  * \param buf       buffer containing data
00193  * \param size      size of data buffer
00194  * \param ecc       pointer to buffer where computed ECC is stored
00195  * \param ecc_size  max size for ecc buffer
00196  */
00197 void nand_computeEcc(UNUSED_ARG(Nand *, chip),
00198         UNUSED_ARG(const void *, buf), UNUSED_ARG(size_t, size), uint32_t *ecc, size_t ecc_size)
00199 {
00200     size_t i;
00201     for (i = 0; i < ecc_size; i++)
00202         ecc[i] = *((reg32_t *)(SMC_BASE + SMC_ECC_PR0_OFF) + i);
00203 }
00204 
00205 
00206 /*
00207  * Low-level hardware driver initialization.
00208  */
00209 void nand_hwInit(UNUSED_ARG(Nand *, chip))
00210 {
00211     // FIXME: Parameters specific for MT29F8G08AAD
00212 
00213     // PIO init
00214     pmc_periphEnable(PIOA_ID);
00215     pmc_periphEnable(PIOC_ID);
00216     pmc_periphEnable(PIOD_ID);
00217 
00218     PIO_PERIPH_SEL(PIOA_BASE, NAND_PINS_PORTA, NAND_PERIPH_PORTA);
00219     PIOA_PDR = NAND_PINS_PORTA;
00220     PIOA_PUER = NAND_PINS_PORTA;
00221 
00222     PIO_PERIPH_SEL(PIOC_BASE, NAND_PINS_PORTC, NAND_PERIPH_PORTC);
00223     PIOC_PDR = NAND_PINS_PORTC;
00224     PIOC_PUER = NAND_PINS_PORTC;
00225 
00226     PIO_PERIPH_SEL(PIOD_BASE, NAND_PINS_PORTD, NAND_PERIPH_PORTD);
00227     PIOD_PDR = NAND_PINS_PORTD;
00228     PIOD_PUER = NAND_PINS_PORTD;
00229 
00230     pmc_periphEnable(SMC_SDRAMC_ID);
00231 
00232     // SMC init
00233     SMC_SETUP0 = SMC_SETUP_NWE_SETUP(0)
00234         | SMC_SETUP_NCS_WR_SETUP(0)
00235         | SMC_SETUP_NRD_SETUP(0)
00236         | SMC_SETUP_NCS_RD_SETUP(0);
00237 
00238     SMC_PULSE0 = SMC_PULSE_NWE_PULSE(2)
00239         | SMC_PULSE_NCS_WR_PULSE(3)
00240         | SMC_PULSE_NRD_PULSE(2)
00241         | SMC_PULSE_NCS_RD_PULSE(3);
00242 
00243     SMC_CYCLE0 = SMC_CYCLE_NWE_CYCLE(3)
00244         | SMC_CYCLE_NRD_CYCLE(3);
00245 
00246     SMC_TIMINGS0 = SMC_TIMINGS_TCLR(1)
00247         | SMC_TIMINGS_TADL(6)
00248         | SMC_TIMINGS_TAR(4)
00249         | SMC_TIMINGS_TRR(2)
00250         | SMC_TIMINGS_TWB(9)
00251         | SMC_TIMINGS_RBNSEL(7)
00252         | SMC_TIMINGS_NFSEL;
00253 
00254     SMC_MODE0 = SMC_MODE_READ_MODE
00255         | SMC_MODE_WRITE_MODE;
00256 
00257     SMC_CFG = SMC_CFG_PAGESIZE_PS2048_64
00258         | SMC_CFG_EDGECTRL
00259         | SMC_CFG_DTOMUL_X1048576
00260         | SMC_CFG_DTOCYC(0xF)
00261         | SMC_CFG_WSPARE
00262         | SMC_CFG_RSPARE;
00263 
00264     // Disable SMC interrupts, reset and enable NFC controller
00265     SMC_IDR = ~0;
00266     SMC_CTRL = 0;
00267     SMC_CTRL = SMC_CTRL_NFCEN;
00268 
00269     // Enable ECC, 1 ECC per 256 bytes
00270     SMC_ECC_CTRL = SMC_ECC_CTRL_SWRST;
00271     SMC_ECC_MD = SMC_ECC_MD_ECC_PAGESIZE_PS2048_64 | SMC_ECC_MD_TYPCORREC_C256B;
00272 }