mt29f NAND driver: fix I/O pin numbers and row/column addressing.
[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
48 #include <io/sam3.h>
49 #include <io/kblock.h>
50
51 #include <drv/timer.h>
52 #include <drv/mt29f.h>
53
54 #include <cpu/power.h> /* cpu_relax() */
55 #include <cpu/types.h>
56
57 #include <string.h> /* memcpy() */
58
59 // Timeout for NAND operations in ms
60 #define MT29F_TMOUT  100
61
62 // NAND flash status codes
63 #define MT29F_STATUS_READY             BV(6)
64 #define MT29F_STATUS_ERROR             BV(0)
65
66 // NAND flash commands
67 #define MT29F_CMD_READ_1               0x00
68 #define MT29F_CMD_READ_2               0x30
69 #define MT29F_CMD_COPYBACK_READ_1      0x00
70 #define MT29F_CMD_COPYBACK_READ_2      0x35
71 #define MT29F_CMD_COPYBACK_PROGRAM_1   0x85
72 #define MT29F_CMD_COPYBACK_PROGRAM_2   0x10
73 #define MT29F_CMD_RANDOM_OUT           0x05
74 #define MT29F_CMD_RANDOM_OUT_2         0xE0
75 #define MT29F_CMD_RANDOM_IN            0x85
76 #define MT29F_CMD_READID               0x90
77 #define MT29F_CMD_WRITE_1              0x80
78 #define MT29F_CMD_WRITE_2              0x10
79 #define MT29F_CMD_ERASE_1              0x60
80 #define MT29F_CMD_ERASE_2              0xD0
81 #define MT29F_CMD_STATUS               0x70
82 #define MT29F_CMD_RESET                0xFF
83
84 // Addresses for sending command, addresses and data bytes to flash
85 #define MT29F_CMD_ADDR    0x60400000
86 #define MT29F_ADDR_ADDR   0x60200000
87 #define MT29F_DATA_ADDR   0x60000000
88
89
90 struct Mt29fHardware
91 {
92         uint8_t status;
93 };
94
95
96 /*
97  * Translate flash page index plus a byte offset
98  * in the five address cycles format needed by NAND.
99  *
100  * Cycles in x8 mode as the MT29F2G08AAD
101  * CA = column addr, PA = page addr, BA = block addr
102  *
103  * Cycle    I/O7  I/O6  I/O5  I/O4  I/O3  I/O2  I/O1  I/O0
104  * -------------------------------------------------------
105  * First    CA7   CA6   CA5   CA4   CA3   CA2   CA1   CA0
106  * Second   LOW   LOW   LOW   LOW   CA11  CA10  CA9   CA8
107  * Third    BA7   BA6   PA5   PA4   PA3   PA2   PA1   PA0
108  * Fourth   BA15  BA14  BA13  BA12  BA11  BA10  BA9   BA8
109  * Fifth    LOW   LOW   LOW   LOW   LOW   LOW   LOW   BA16
110  */
111 static void mt29f_getAddrCycles(block_idx_t page, size_t offset, uint32_t *cycle0, uint32_t *cycle1234)
112 {
113         ASSERT(offset < MT29F_PAGE_SIZE);
114
115         *cycle0 = offset & 0xff;
116         *cycle1234 = (page << 8) | ((offset >> 8) & 0xf);
117
118         LOG_INFO("mt29f addr: %lx %lx\n", *cycle1234, *cycle0);
119 }
120
121
122 INLINE bool mt29f_isBusy(void)
123 {
124         return HWREG(NFC_CMD_BASE_ADDR + NFC_CMD_NFCCMD) & 0x8000000;
125 }
126
127 INLINE bool mt29f_isCmdDone(void)
128 {
129     return SMC_SR & SMC_SR_CMDDONE;
130 }
131
132 static bool mt29f_waitReadyBusy(void)
133 {
134         time_t start = timer_clock();
135
136         while (!(SMC_SR & SMC_SR_RB_EDGE0))
137         {
138                 cpu_relax();
139                 if (timer_clock() - start > MT29F_TMOUT)
140                 {
141                         LOG_INFO("mt29f: R/B timeout\n");
142                         return false;
143                 }
144         }
145
146         return true;
147 }
148
149 /*
150  * Wait for transfer to complete until timeout.
151  * If transfer completes return true, false in case of timeout.
152  */
153 static bool mt29f_waitTransferComplete(void)
154 {
155         time_t start = timer_clock();
156
157         while (!(SMC_SR & SMC_SR_XFRDONE))
158         {
159                 cpu_relax();
160                 if (timer_clock() - start > MT29F_TMOUT)
161                 {
162                         LOG_INFO("mt29f: xfer complete timeout\n");
163                         return false;
164                 }
165         }
166
167         return true;
168 }
169
170
171 /*
172  * Send command to NAND and wait for completion.
173  */
174 static void mt29f_sendCommand(uint32_t cmd,
175                 int num_cycles, uint32_t cycle0, uint32_t cycle1234)
176 {
177         reg32_t *cmd_addr;
178
179         while (mt29f_isBusy());
180
181         if (num_cycles == 5)
182                 SMC_ADDR = cycle0;
183
184         cmd_addr = (reg32_t *)(NFC_CMD_BASE_ADDR + cmd);
185         *cmd_addr = cycle1234;
186
187         while (!mt29f_isCmdDone());
188 }
189
190
191 static bool mt29f_isOperationComplete(void)
192 {
193         uint8_t status;
194
195         mt29f_sendCommand(
196                 NFC_CMD_NFCCMD | MT29F_CSID | NFC_CMD_ACYCLE_NONE |
197                 MT29F_CMD_STATUS << 2,
198                 0, 0, 0);
199
200         status = (uint8_t)HWREG(MT29F_DATA_ADDR);
201         return (status & MT29F_STATUS_READY) && !(status & MT29F_STATUS_ERROR);
202 }
203
204
205 static void mt29f_reset(void)
206 {
207         mt29f_sendCommand(
208                 NFC_CMD_NFCCMD | MT29F_CSID | NFC_CMD_ACYCLE_NONE |
209                 MT29F_CMD_RESET << 2,
210                 0, 0, 0);
211
212         mt29f_waitReadyBusy();
213 }
214
215
216 /**
217  * Erase the whole block containing given page.
218  */
219 int mt29f_blockErase(Mt29f *fls, block_idx_t page)
220 {
221         uint32_t cycle0;
222         uint32_t cycle1234;
223
224         mt29f_getAddrCycles(page, 0, &cycle0, &cycle1234);
225
226         mt29f_sendCommand(
227                 NFC_CMD_NFCCMD | MT29F_CSID | NFC_CMD_ACYCLE_THREE | NFC_CMD_VCMD2 |
228                 (MT29F_CMD_ERASE_2 << 10) | (MT29F_CMD_ERASE_1 << 2),
229                 3, 0, cycle1234 >> 8);
230
231         mt29f_waitReadyBusy();
232
233         if (!mt29f_isOperationComplete())
234         {
235                 LOG_ERR("mt29f: error erasing block\n");
236                 fls->hw->status |= MT29F_ERR_ERASE;
237                 return -1;
238         }
239
240         return 0;
241 }
242
243
244 /**
245  * Read Device ID and configuration codes.
246  */
247 bool mt29f_getDevId(Mt29f *fls, uint8_t dev_id[5])
248 {
249         mt29f_sendCommand(
250                 NFC_CMD_NFCCMD | NFC_CMD_NFCEN | MT29F_CSID | NFC_CMD_ACYCLE_ONE |
251                 MT29F_CMD_READID << 2,
252                 1, 0, 0);
253
254         mt29f_waitReadyBusy();
255         if (!mt29f_waitTransferComplete())
256         {
257                 LOG_ERR("mt29f: getDevId timeout\n");
258                 fls->hw->status |= MT29F_ERR_RD_TMOUT;
259                 return false;
260         }
261
262         memcpy(dev_id, (void *)NFC_SRAM_BASE_ADDR, 5);
263         return true;
264 }
265
266
267 static size_t mt29f_readDirect(struct KBlock *blk, block_idx_t idx, void *buf, size_t offset, size_t size)
268 {
269         Mt29f *fls = FLASH_CAST(blk);
270         uint32_t cycle0;
271         uint32_t cycle1234;
272
273         ASSERT(offset == 0);
274         ASSERT(size == blk->blk_size);
275
276         LOG_INFO("mt29f_readDirect\n");
277
278         mt29f_getAddrCycles(idx, 0, &cycle0, &cycle1234);
279
280         mt29f_sendCommand(
281                 NFC_CMD_NFCCMD | NFC_CMD_NFCEN | MT29F_CSID | NFC_CMD_ACYCLE_FIVE | NFC_CMD_VCMD2 |
282                 (MT29F_CMD_READ_2 << 10) | (MT29F_CMD_READ_1 << 2),
283                 5, cycle0, cycle1234);
284
285         mt29f_waitReadyBusy();
286         if (!mt29f_waitTransferComplete())
287         {
288                 LOG_ERR("mt29f: read timeout\n");
289                 fls->hw->status |= MT29F_ERR_RD_TMOUT;
290                 return 0;
291         }
292
293         if (!kblock_buffered(blk) && (buf != (void *)NFC_SRAM_BASE_ADDR))
294                 memcpy(buf, (void *)NFC_SRAM_BASE_ADDR, size);
295
296         return size;
297 }
298
299
300 static size_t mt29f_writeDirect(struct KBlock *blk, block_idx_t idx, const void *_buf, size_t offset, size_t size)
301 {
302         Mt29f *fls = FLASH_CAST(blk);
303         uint32_t cycle0;
304         uint32_t cycle1234;
305
306         ASSERT(offset == 0);
307         ASSERT(size == blk->blk_size);
308
309         LOG_INFO("mt29f_writeDirect\n");
310
311         if (!kblock_buffered(blk) && (_buf != (void *)NFC_SRAM_BASE_ADDR))
312                 memcpy((void *)NFC_SRAM_BASE_ADDR, _buf, size);
313
314         mt29f_getAddrCycles(idx, 0, &cycle0, &cycle1234);
315
316         mt29f_sendCommand(
317                         NFC_CMD_NFCCMD | NFC_CMD_NFCWR | NFC_CMD_NFCEN | MT29F_CSID | NFC_CMD_ACYCLE_FIVE |
318                         MT29F_CMD_WRITE_1 << 2,
319                         5, cycle0, cycle1234);
320
321         if (!mt29f_waitTransferComplete())
322         {
323                 LOG_ERR("mt29f: write timeout\n");
324                 fls->hw->status |= MT29F_ERR_WR_TMOUT;
325                 return 0;
326         }
327
328         mt29f_sendCommand(
329                         NFC_CMD_NFCCMD | MT29F_CSID | NFC_CMD_ACYCLE_NONE |
330                         MT29F_CMD_WRITE_2 << 2,
331                         0, 0, 0);
332
333         mt29f_waitReadyBusy();
334
335         if (!mt29f_isOperationComplete())
336         {
337                 LOG_ERR("mt29f: error writing page\n");
338                 fls->hw->status |= MT29F_ERR_WRITE;
339                 return 0;
340         }
341
342         return size;
343 }
344
345
346 static int mt29f_error(struct KBlock *blk)
347 {
348         Mt29f *fls = FLASH_CAST(blk);
349         return fls->hw->status;
350 }
351
352
353 static void mt29f_clearerror(struct KBlock *blk)
354 {
355         Mt29f *fls = FLASH_CAST(blk);
356         fls->hw->status = 0;
357 }
358
359
360 static const KBlockVTable mt29f_buffered_vt =
361 {
362         .readDirect = mt29f_readDirect,
363         .writeDirect = mt29f_writeDirect,
364
365         .readBuf = kblock_swReadBuf,
366         .writeBuf = kblock_swWriteBuf,
367         .load = kblock_swLoad,
368         .store = kblock_swStore,
369
370         .close = kblock_swClose,
371
372         .error = mt29f_error,
373         .clearerr = mt29f_clearerror,
374 };
375
376
377 static const KBlockVTable mt29f_unbuffered_vt =
378 {
379         .readDirect = mt29f_readDirect,
380         .writeDirect = mt29f_writeDirect,
381
382         .close = kblock_swClose,
383
384         .error = mt29f_error,
385         .clearerr = mt29f_clearerror,
386 };
387
388
389 static struct Mt29fHardware mt29f_hw;
390
391
392 static void common_init(Mt29f *fls)
393 {
394         memset(fls, 0, sizeof(*fls));
395         DB(fls->blk.priv.type = KBT_MT29F);
396
397         fls->hw = &mt29f_hw;
398
399         fls->blk.blk_size = MT29F_PAGE_SIZE;
400         fls->blk.blk_cnt =  MT29F_SIZE / MT29F_PAGE_SIZE;
401
402         /*
403          * TODO: put following stuff in hw_ file dependent (and configurable cs?)
404          * Parameters for MT29F8G08AAD
405          */
406         pmc_periphEnable(PIOA_ID);
407         pmc_periphEnable(PIOC_ID);
408         pmc_periphEnable(PIOD_ID);
409
410         PIO_PERIPH_SEL(PIOA_BASE, MT29F_PINS_PORTA, MT29F_PERIPH_PORTA);
411         PIOA_PDR = MT29F_PINS_PORTA;
412         PIOA_PUER = MT29F_PINS_PORTA;
413
414         PIO_PERIPH_SEL(PIOC_BASE, MT29F_PINS_PORTC, MT29F_PERIPH_PORTC);
415         PIOC_PDR = MT29F_PINS_PORTC;
416         PIOC_PUER = MT29F_PINS_PORTC;
417
418         PIO_PERIPH_SEL(PIOD_BASE, MT29F_PINS_PORTD, MT29F_PERIPH_PORTD);
419         PIOD_PDR = MT29F_PINS_PORTD;
420         PIOD_PUER = MT29F_PINS_PORTD;
421
422     pmc_periphEnable(SMC_SDRAMC_ID);
423
424     SMC_SETUP0 = SMC_SETUP_NWE_SETUP(0)
425                 | SMC_SETUP_NCS_WR_SETUP(0)
426                 | SMC_SETUP_NRD_SETUP(0)
427                 | SMC_SETUP_NCS_RD_SETUP(0);
428
429     SMC_PULSE0 = SMC_PULSE_NWE_PULSE(2)
430                 | SMC_PULSE_NCS_WR_PULSE(3)
431                 | SMC_PULSE_NRD_PULSE(2)
432                 | SMC_PULSE_NCS_RD_PULSE(3);
433
434     SMC_CYCLE0 = SMC_CYCLE_NWE_CYCLE(3)
435                 | SMC_CYCLE_NRD_CYCLE(3);
436
437     SMC_TIMINGS0 = SMC_TIMINGS_TCLR(1)
438                 | SMC_TIMINGS_TADL(6)
439                 | SMC_TIMINGS_TAR(4)
440                 | SMC_TIMINGS_TRR(2)
441                 | SMC_TIMINGS_TWB(9)
442                 | SMC_TIMINGS_RBNSEL(7)
443                 | SMC_TIMINGS_NFSEL;
444
445     SMC_MODE0 = SMC_MODE_READ_MODE
446                 | SMC_MODE_WRITE_MODE;
447
448         SMC_CFG = SMC_CFG_PAGESIZE_PS2048_64
449                 | SMC_CFG_EDGECTRL
450                 | SMC_CFG_DTOMUL_X1048576
451                 | SMC_CFG_DTOCYC(0xF);
452
453         // Disable SMC interrupts, reset and enable NFC controller
454         SMC_IDR = ~0;
455         SMC_CTRL = 0;
456         SMC_CTRL = SMC_CTRL_NFCEN;
457
458         mt29f_reset();
459 }
460
461
462 void mt29f_init(Mt29f *fls)
463 {
464         common_init(fls);
465         fls->blk.priv.vt = &mt29f_buffered_vt;
466         fls->blk.priv.flags |= KB_BUFFERED;
467         fls->blk.priv.buf = (void *)NFC_SRAM_BASE_ADDR;
468
469         // Load the first block in the cache
470         mt29f_readDirect(&fls->blk, 0, (void *)NFC_SRAM_BASE_ADDR, 0, MT29F_PAGE_SIZE);
471 }
472
473
474 void mt29f_initUnbuffered(Mt29f *fls)
475 {
476         common_init(fls);
477         fls->blk.priv.vt = &mt29f_unbuffered_vt;
478 }
479