4 * This file is part of BeRTOS.
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.
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.
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
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.
29 * Copyright 2011 Develer S.r.l. (http://www.develer.com/)
33 * \brief NAND driver for SAM3's static memory controller.
35 * \author Stefano Fedrigo <aleph@develer.com>
38 #include "nand_sam3.h"
41 #include <cfg/macros.h>
43 #include <drv/timer.h>
44 #include <cpu/power.h> /* cpu_relax() */
45 #include <cpu/types.h>
47 #include <string.h> /* memcpy, memset */
53 #define NAND_PIN_CE BV(6)
54 #define NAND_PIN_RB BV(2)
55 #define NAND_PINS_PORTA (NAND_PIN_CE | NAND_PIN_RB)
56 #define NAND_PERIPH_PORTA PIO_PERIPH_B
58 #define NAND_PIN_OE BV(19)
59 #define NAND_PIN_WE BV(20)
60 #define NAND_PIN_IO 0x0000FFFF
61 #define NAND_PINS_PORTC (NAND_PIN_OE | NAND_PIN_WE | NAND_PIN_IO)
62 #define NAND_PERIPH_PORTC PIO_PERIPH_A
64 #define NAND_PIN_CLE BV(9)
65 #define NAND_PIN_ALE BV(8)
66 #define NAND_PINS_PORTD (NAND_PIN_CLE | NAND_PIN_ALE)
67 #define NAND_PERIPH_PORTD PIO_PERIPH_A
71 * Wait for edge transition of READY/BUSY NAND
73 * Return true for edge detection, false in case of timeout.
75 bool nand_waitReadyBusy(UNUSED_ARG(Nand *, chip), time_t timeout)
77 time_t start = timer_clock();
79 while (!(SMC_SR & SMC_SR_RB_EDGE0))
82 if (timer_clock() - start > timeout)
84 LOG_INFO("nand: R/B timeout\n");
93 * Wait for transfer to complete until timeout.
94 * If transfer completes return true, false in case of timeout.
96 bool nand_waitTransferComplete(UNUSED_ARG(Nand *, chip), time_t timeout)
98 time_t start = timer_clock();
100 while (!(SMC_SR & SMC_SR_XFRDONE))
103 if (timer_clock() - start > timeout)
105 LOG_INFO("nand: xfer complete timeout\n");
115 * Send command to NAND and wait for completion.
117 void nand_sendCommand(Nand *chip,
118 uint32_t cmd1, uint32_t cmd2,
119 int num_cycles, uint32_t cycle0, uint32_t cycle1234)
124 while (HWREG(NFC_CMD_BASE_ADDR + NFC_CMD_NFCCMD) & 0x8000000);
129 cmd_val = NFC_CMD_NFCCMD
130 | ((chip->chip_select << NFC_CMD_CSID_SHIFT) & NFC_CMD_CSID_MASK)
131 | ((num_cycles << NFC_CMD_ACYCLE_SHIFT) & NFC_CMD_ACYCLE_MASK)
135 // Check for commands transferring data
136 if (cmd1 == NAND_CMD_WRITE_1 || cmd1 == NAND_CMD_READ_1 || cmd1 == NAND_CMD_READID)
137 cmd_val |= NFC_CMD_NFCEN;
139 // Check for commands writing data
140 if (cmd1 == NAND_CMD_WRITE_1)
141 cmd_val |= NFC_CMD_NFCWR;
143 // Check for two command cycles
145 cmd_val |= NFC_CMD_VCMD2;
147 cmd_addr = (reg32_t *)(NFC_CMD_BASE_ADDR + cmd_val);
148 *cmd_addr = cycle1234;
150 while (!(SMC_SR & SMC_SR_CMDDONE));
155 * Get NAND chip status register.
157 * NOTE: this is global between different chip selects, so returns
158 * the status register of the last used NAND chip.
160 uint8_t nand_getChipStatus(UNUSED_ARG(Nand *, chip))
162 return (uint8_t)HWREG(NFC_CMD_BASE_ADDR);
166 void *nand_dataBuffer(UNUSED_ARG(Nand *, chip))
168 return (void *)NFC_SRAM_BASE_ADDR;
172 bool nand_checkEcc(Nand *chip)
174 uint32_t sr1 = SMC_ECC_SR1;
177 LOG_INFO("ECC error, ECC_SR1=0x%lx\n", sr1);
178 chip->status |= NAND_ERR_ECC;
187 * Compute ECC on data in a buffer.
189 * \param chip nand context
190 * \param buf buffer containing data
191 * \param size size of data buffer
192 * \param ecc pointer to buffer where computed ECC is stored
193 * \param ecc_size max size for ecc buffer
195 void nand_computeEcc(UNUSED_ARG(Nand *, chip),
196 UNUSED_ARG(const void *, buf), UNUSED_ARG(size_t, size), uint32_t *ecc, size_t ecc_size)
199 for (i = 0; i < ecc_size; i++)
200 ecc[i] = *((reg32_t *)(SMC_BASE + SMC_ECC_PR0_OFF) + i);
204 void nand_hwInit(UNUSED_ARG(Nand *, chip))
206 // FIXME: Parameters specific for MT29F8G08AAD
209 pmc_periphEnable(PIOA_ID);
210 pmc_periphEnable(PIOC_ID);
211 pmc_periphEnable(PIOD_ID);
213 PIO_PERIPH_SEL(PIOA_BASE, NAND_PINS_PORTA, NAND_PERIPH_PORTA);
214 PIOA_PDR = NAND_PINS_PORTA;
215 PIOA_PUER = NAND_PINS_PORTA;
217 PIO_PERIPH_SEL(PIOC_BASE, NAND_PINS_PORTC, NAND_PERIPH_PORTC);
218 PIOC_PDR = NAND_PINS_PORTC;
219 PIOC_PUER = NAND_PINS_PORTC;
221 PIO_PERIPH_SEL(PIOD_BASE, NAND_PINS_PORTD, NAND_PERIPH_PORTD);
222 PIOD_PDR = NAND_PINS_PORTD;
223 PIOD_PUER = NAND_PINS_PORTD;
225 pmc_periphEnable(SMC_SDRAMC_ID);
228 SMC_SETUP0 = SMC_SETUP_NWE_SETUP(0)
229 | SMC_SETUP_NCS_WR_SETUP(0)
230 | SMC_SETUP_NRD_SETUP(0)
231 | SMC_SETUP_NCS_RD_SETUP(0);
233 SMC_PULSE0 = SMC_PULSE_NWE_PULSE(2)
234 | SMC_PULSE_NCS_WR_PULSE(3)
235 | SMC_PULSE_NRD_PULSE(2)
236 | SMC_PULSE_NCS_RD_PULSE(3);
238 SMC_CYCLE0 = SMC_CYCLE_NWE_CYCLE(3)
239 | SMC_CYCLE_NRD_CYCLE(3);
241 SMC_TIMINGS0 = SMC_TIMINGS_TCLR(1)
242 | SMC_TIMINGS_TADL(6)
246 | SMC_TIMINGS_RBNSEL(7)
249 SMC_MODE0 = SMC_MODE_READ_MODE
250 | SMC_MODE_WRITE_MODE;
252 SMC_CFG = SMC_CFG_PAGESIZE_PS2048_64
254 | SMC_CFG_DTOMUL_X1048576
255 | SMC_CFG_DTOCYC(0xF)
259 // Disable SMC interrupts, reset and enable NFC controller
262 SMC_CTRL = SMC_CTRL_NFCEN;
264 // Enable ECC, 1 ECC per 256 bytes
265 SMC_ECC_CTRL = SMC_ECC_CTRL_SWRST;
266 SMC_ECC_MD = SMC_ECC_MD_ECC_PAGESIZE_PS2048_64 | SMC_ECC_MD_TYPCORREC_C256B;