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 Micron MT29F serial NAND driver for SAM3's static memory controller.
35 * \author Stefano Fedrigo <aleph@develer.com>
38 #include "mt29f_sam3.h"
39 #include "cfg/cfg_mt29f.h"
41 // Define log settings for cfg/log.h
42 #define LOG_LEVEL CONFIG_MT29F_LOG_LEVEL
43 #define LOG_FORMAT CONFIG_MT29F_LOG_FORMAT
46 #include <cfg/macros.h>
49 #include <io/kblock.h>
51 #include <drv/timer.h>
52 #include <drv/mt29f.h>
54 #include <cpu/power.h> /* cpu_relax() */
55 #include <cpu/types.h>
57 #include <string.h> /* memcpy() */
60 // NAND flash status codes
61 #define MT29F_STATUS_READY BV(6)
62 #define MT29F_STATUS_ERROR BV(0)
64 // NAND flash commands
65 #define MT29F_CMD_READ_1 0x00
66 #define MT29F_CMD_READ_2 0x30
67 #define MT29F_CMD_COPYBACK_READ_1 0x00
68 #define MT29F_CMD_COPYBACK_READ_2 0x35
69 #define MT29F_CMD_COPYBACK_PROGRAM_1 0x85
70 #define MT29F_CMD_COPYBACK_PROGRAM_2 0x10
71 #define MT29F_CMD_RANDOM_OUT 0x05
72 #define MT29F_CMD_RANDOM_OUT_2 0xE0
73 #define MT29F_CMD_RANDOM_IN 0x85
74 #define MT29F_CMD_READID 0x90
75 #define MT29F_CMD_WRITE_1 0x80
76 #define MT29F_CMD_WRITE_2 0x10
77 #define MT29F_CMD_ERASE_1 0x60
78 #define MT29F_CMD_ERASE_2 0xD0
79 #define MT29F_CMD_STATUS 0x70
80 #define MT29F_CMD_RESET 0xFF
90 * Translate flash memory offset in the five address cycles format
93 * Cycles in x8 mode as the MT29F2G08AAD
94 * CA = column addr, PA = page addr, BA = block addr
96 * Cycle I/O7 I/O6 I/O5 I/O4 I/O3 I/O2 I/O1 I/O0
97 * -------------------------------------------------------
98 * First CA7 CA6 CA5 CA4 CA3 CA2 CA1 CA0
99 * Second LOW LOW LOW LOW CA11 CA10 CA9 CA8
100 * Third BA7 BA6 PA5 PA4 PA3 PA2 PA1 PA0
101 * Fourth BA15 BA14 BA13 BA12 BA11 BA10 BA9 BA8
102 * Fifth LOW LOW LOW LOW LOW LOW LOW BA16
104 static void mt29f_getAddrCycles(size_t offset, uint32_t *cycle0, uint32_t *cycle1234)
107 * offset nibbles 77776666 55554444 33332222 11110000
108 * cycle1234 -------7 66665555 ----4444 33332222
111 *cycle0 = offset & 0xFF;
112 *cycle1234 = ((offset >> 8) & 0x00000fff) | ((offset >> 4) & 0x01ff0000);
116 INLINE bool mt29f_isBusy(void)
118 return HWREG(NFC_CMD_BASE_ADDR + NFC_CMD_NFCCMD) & 0x8000000;
121 INLINE bool mt29f_isCmdDone(void)
123 return SMC_SR & SMC_SR_CMDDONE;
126 INLINE uint8_t mt29f_isReadyBusy(void)
128 return SMC_SR & SMC_SR_RB_EDGE0;
133 * Send command to NAND and wait for completion.
135 static void mt29f_sendCommand(uint32_t cmd, uint32_t cycle0, uint32_t cycle1234)
139 while (mt29f_isBusy());
143 cmd_addr = (reg32_t *)(NFC_CMD_BASE_ADDR + cmd);
144 *cmd_addr = cycle1234;
146 while (!mt29f_isCmdDone());
150 static bool mt29f_isOperationComplete(void)
155 NFC_CMD_NFCCMD | MT29F_CSID | NFC_CMD_ACYCLE_NONE |
156 MT29F_CMD_STATUS << 2, 0, 0);
158 status = (uint8_t)HWREG(MT29F_DATA_ADDR);
159 return (status & MT29F_STATUS_READY) && !(status & MT29F_STATUS_ERROR);
165 NFC_CMD_NFCCMD | MT29F_CSID | NFC_CMD_ACYCLE_NONE |
166 MT29F_CMD_RESET << 2,
167 0, /* Dummy address cylce 1,2,3,4.*/
168 0 /* Dummy address cylce 0.*/
172 * Erase block at given offset.
174 int mt29f_blockErase(Mt29f *fls, size_t blk_offset)
179 mt29f_getAddrCycles(blk_offset, &cycle0, &cycle1234);
182 NFC_CMD_NFCCMD | MT29F_CSID | NFC_CMD_ACYCLE_THREE | NFC_CMD_VCMD2 |
183 (MT29F_CMD_ERASE_2 << 10) | (MT29F_CMD_ERASE_1 << 2),
186 while (!mt29f_isReadyBusy());
188 if (!mt29f_isOperationComplete())
190 LOG_ERR("mt29f: error erasing block\n");
198 static size_t mt29f_readDirect(struct KBlock *blk, block_idx_t idx, void *buf, size_t offset, size_t size)
203 static size_t mt29f_writeDirect(struct KBlock *blk, block_idx_t idx, const void *_buf, size_t offset, size_t size)
208 static int mt29f_error(struct KBlock *blk)
210 Mt29f *fls = FLASH_CAST(blk);
214 static void mt29f_clearerror(struct KBlock *blk)
216 Mt29f *fls = FLASH_CAST(blk);
220 static const KBlockVTable mt29f_buffered_vt =
222 .readDirect = mt29f_readDirect,
223 .writeDirect = mt29f_writeDirect,
225 .readBuf = kblock_swReadBuf,
226 .writeBuf = kblock_swWriteBuf,
227 .load = kblock_swLoad,
228 .store = kblock_swStore,
230 .close = kblock_swClose,
232 .error = mt29f_error,
233 .clearerr = mt29f_clearerror,
237 static const KBlockVTable mt29f_unbuffered_vt =
239 .readDirect = mt29f_readDirect,
240 .writeDirect = mt29f_writeDirect,
242 .close = kblock_swClose,
244 .error = mt29f_error,
245 .clearerr = mt29f_clearerror,
249 static struct Mt29fHardware mt29f_hw;
252 static void common_init(Mt29f *fls)
254 memset(fls, 0, sizeof(*fls));
255 DB(fls->blk.priv.type = KBT_MT29F);
259 fls->blk.blk_size = MT29F_PAGE_SIZE;
260 fls->blk.blk_cnt = MT29F_SIZE / MT29F_PAGE_SIZE;
263 * TODO: put following stuff in hw_ file dependent (and configurable cs?)
264 * Parameters for MT29F8G08AAD
266 pmc_periphEnable(PIOA_ID);
267 pmc_periphEnable(PIOC_ID);
268 pmc_periphEnable(PIOD_ID);
270 PIO_PERIPH_SEL(PIOA_BASE, MT29F_PINS_PORTA, MT29F_PERIPH_PORTA);
271 PIOA_PDR = MT29F_PINS_PORTA;
272 PIOA_PUER = MT29F_PINS_PORTA;
274 PIO_PERIPH_SEL(PIOC_BASE, MT29F_PINS_PORTC, MT29F_PERIPH_PORTC);
275 PIOC_PDR = MT29F_PINS_PORTC;
276 PIOC_PUER = MT29F_PINS_PORTC;
278 PIO_PERIPH_SEL(PIOD_BASE, MT29F_PINS_PORTD, MT29F_PERIPH_PORTD);
279 PIOD_PDR = MT29F_PINS_PORTD;
280 PIOD_PUER = MT29F_PINS_PORTD;
282 pmc_periphEnable(SMC_SDRAMC_ID);
284 SMC_SETUP0 = SMC_SETUP_NWE_SETUP(0)
285 | SMC_SETUP_NCS_WR_SETUP(0)
286 | SMC_SETUP_NRD_SETUP(0)
287 | SMC_SETUP_NCS_RD_SETUP(0);
289 SMC_PULSE0 = SMC_PULSE_NWE_PULSE(2)
290 | SMC_PULSE_NCS_WR_PULSE(3)
291 | SMC_PULSE_NRD_PULSE(2)
292 | SMC_PULSE_NCS_RD_PULSE(3);
294 SMC_CYCLE0 = SMC_CYCLE_NWE_CYCLE(3)
295 | SMC_CYCLE_NRD_CYCLE(3);
297 SMC_TIMINGS0 = SMC_TIMINGS_TCLR(1)
298 | SMC_TIMINGS_TADL(6)
302 | SMC_TIMINGS_RBNSEL(7)
305 SMC_MODE0 = SMC_MODE_READ_MODE
306 | SMC_MODE_WRITE_MODE;
310 void mt29f_hw_init(Mt29f *fls)
313 fls->blk.priv.vt = &mt29f_buffered_vt;
314 fls->blk.priv.flags |= KB_BUFFERED | KB_PARTIAL_WRITE;
315 fls->blk.priv.buf = (void *)NFC_CMD_BASE_ADDR;
317 // Load the first block in the cache
319 memcpy(fls->blk.priv.buf, start, fls->blk.blk_size);
323 void mt29f_hw_initUnbuffered(Mt29f *fls)
326 fls->blk.priv.vt = &mt29f_unbuffered_vt;