tinyusb  0.4
Click here to lend your support to tinyusb donation and make a donation at pledgie.com
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Groups Pages
nand.c
1 /*****************************************************************************
2  *
3  * Copyright(C) 2011, Embedded Artists AB
4  * All rights reserved.
5  *
6  ******************************************************************************
7  * Software that is described herein is for illustrative purposes only
8  * which provides customers with programming information regarding the
9  * products. This software is supplied "AS IS" without any warranties.
10  * Embedded Artists AB assumes no responsibility or liability for the
11  * use of the software, conveys no license or title under any patent,
12  * copyright, or mask work right to the product. Embedded Artists AB
13  * reserves the right to make changes in the software without
14  * notification. Embedded Artists AB also make no representation or
15  * warranty that such application will be suitable for the specified
16  * use without further testing or modification.
17  *****************************************************************************/
18 
19 
20 /******************************************************************************
21  * Includes
22  *****************************************************************************/
23 #include "../../board.h"
24 
25 #if BOARD == BOARD_EA4357
26 
27 #include "lpc_types.h"
28 #include "lpc43xx_scu.h"
29 #include "lpc43xx_timer.h"
30 #include "nand.h"
31 
32 
33 /******************************************************************************
34  * Defines and typedefs
35  *****************************************************************************/
36 
37 #define K9F1G_CLE ((volatile uint8_t *)0x1D100000)
38 #define K9F1G_ALE ((volatile uint8_t *)0x1D080000)
39 #define K9F1G_DATA ((volatile uint8_t *)0x1D000000)
40 
41 #define K9FXX_WAIT()
42 
43 #define K9FXX_READ_1 0x00
44 #define K9FXX_READ_2 0x30
45 
46 #define K9FXX_SET_ADDR_A 0x00
47 #define K9FXX_SET_ADDR_B 0x01
48 #define K9FXX_SET_ADDR_C 0x50
49 #define K9FXX_READ_ID 0x90
50 #define K9FXX_RESET 0xff
51 #define K9FXX_BLOCK_PROGRAM_1 0x80
52 #define K9FXX_BLOCK_PROGRAM_2 0x10
53 #define K9FXX_BLOCK_ERASE_1 0x60
54 #define K9FXX_BLOCK_ERASE_2 0xd0
55 #define K9FXX_READ_STATUS 0x70
56 #define K9FXX_BUSY (1 << 6)
57 #define K9FXX_OK (1 << 0)
58 
59 #define ID_MARKER_CODE (0xEC)
60 #define ID_SAMSUNG (0xF1)
61 
62 #define ID_PAGE_SZ_1KB (0x00)
63 #define ID_PAGE_SZ_2KB (0x01)
64 #define ID_PAGE_SZ_4KB (0x02)
65 #define ID_PAGE_SZ_8KB (0x03)
66 
67 #define ID_BLOCK_SZ_64KB (0x00)
68 #define ID_BLOCK_SZ_128KB (0x01)
69 #define ID_BLOCK_SZ_256KB (0x02)
70 #define ID_BLOCK_SZ_512KB (0x03)
71 
72 #define ID_PAGE_SZ_1KB (0x00)
73 #define ID_PAGE_SZ_2KB (0x01)
74 #define ID_PAGE_SZ_4KB (0x02)
75 #define ID_PAGE_SZ_8KB (0x03)
76 
77 #define ID_REDUND_SZ_8 (0x00)
78 #define ID_REDUND_SZ_16 (0x01)
79 
80 
81 
82 /* This macro could be changed to check the ready pin */
83 #define WAIT_READY() (TIM_Waitus(25))
84 
85 
86 /******************************************************************************
87  * External global variables
88  *****************************************************************************/
89 
90 /******************************************************************************
91  * Local variables
92  *****************************************************************************/
93 
94 static uint32_t pageSize = 0;
95 static uint32_t blockSize = 0;
96 static uint32_t reduntSize = 0;
97 
98 
99 /******************************************************************************
100  * Local Functions
101  *****************************************************************************/
102 
103 static void pinConfig(void)
104 {
105  /* Set up EMC pin */
106  scu_pinmux( 2 , 9 , MD_PLN_FAST , 3 );//A0
107  scu_pinmux( 2 , 10 , MD_PLN_FAST , 3 );//A1
108  scu_pinmux( 2 , 11 , MD_PLN_FAST , 3 );//A2
109  scu_pinmux( 2 , 12 , MD_PLN_FAST , 3 );//A3
110  scu_pinmux( 2 , 13 , MD_PLN_FAST , 3 );//A4
111  scu_pinmux( 1 , 0 , MD_PLN_FAST , 2 );//A5
112  scu_pinmux( 1 , 1 , MD_PLN_FAST , 2 );//A6
113  scu_pinmux( 1 , 2 , MD_PLN_FAST , 2 );//A7
114  scu_pinmux( 2 , 8 , MD_PLN_FAST , 3 );//A8
115  scu_pinmux( 2 , 7 , MD_PLN_FAST , 3 );//A9
116  scu_pinmux( 2 , 6 , MD_PLN_FAST , 2 );//A10
117  scu_pinmux( 2 , 2 , MD_PLN_FAST , 2 );//A11
118  scu_pinmux( 2 , 1 , MD_PLN_FAST , 2 );//A12
119  scu_pinmux( 2 , 0 , MD_PLN_FAST , 2 );//A13
120  scu_pinmux( 6 , 8 , MD_PLN_FAST , 1 );//A14
121  scu_pinmux( 6 , 7 , MD_PLN_FAST , 1 );//A15
122  scu_pinmux( 13 , 16 , MD_PLN_FAST , 2 );//A16
123  scu_pinmux( 13 , 15 , MD_PLN_FAST , 2 );//A17
124  scu_pinmux( 14 , 0 , MD_PLN_FAST , 3 );//A18
125  scu_pinmux( 14 , 1 , MD_PLN_FAST , 3 );//A19
126  scu_pinmux( 14 , 2 , MD_PLN_FAST , 3 );//A20
127  scu_pinmux( 14 , 3 , MD_PLN_FAST , 3 );//A21
128  scu_pinmux( 14 , 4 , MD_PLN_FAST , 3 );//A22
129  scu_pinmux( 10 , 4 , MD_PLN_FAST , 3 );//A23
130 
131  scu_pinmux( 1 , 7 , MD_PLN_FAST , 3 );//D0
132  scu_pinmux( 1 , 8 , MD_PLN_FAST , 3 );//D1
133  scu_pinmux( 1 , 9 , MD_PLN_FAST , 3 );//D2
134  scu_pinmux( 1 , 10 , MD_PLN_FAST , 3 );//D3
135  scu_pinmux( 1 , 11 , MD_PLN_FAST , 3 );//D4
136  scu_pinmux( 1 , 12 , MD_PLN_FAST , 3 );//D5
137  scu_pinmux( 1 , 13 , MD_PLN_FAST , 3 );//D6
138  scu_pinmux( 1 , 14 , MD_PLN_FAST , 3 );//D7
139  scu_pinmux( 5 , 4 , MD_PLN_FAST , 2 );//D8
140  scu_pinmux( 5 , 5 , MD_PLN_FAST , 2 );//D9
141  scu_pinmux( 5 , 6 , MD_PLN_FAST , 2 );//D10
142  scu_pinmux( 5 , 7 , MD_PLN_FAST , 2 );//D11
143  scu_pinmux( 5 , 0 , MD_PLN_FAST , 2 );//D12
144  scu_pinmux( 5 , 1 , MD_PLN_FAST , 2 );//D13
145  scu_pinmux( 5 , 2 , MD_PLN_FAST , 2 );//D14
146  scu_pinmux( 5 , 3 , MD_PLN_FAST , 2 );//D15
147  scu_pinmux( 13 , 2 , MD_PLN_FAST , 2 );//D16
148  scu_pinmux( 13 , 3 , MD_PLN_FAST , 2 );//D17
149  scu_pinmux( 13 , 4 , MD_PLN_FAST , 2 );//D18
150  scu_pinmux( 13 , 5 , MD_PLN_FAST , 2 );//D19
151  scu_pinmux( 13 , 6 , MD_PLN_FAST , 2 );//D20
152  scu_pinmux( 13 , 7 , MD_PLN_FAST , 2 );//D21
153  scu_pinmux( 13 , 8 , MD_PLN_FAST , 2 );//D22
154  scu_pinmux( 13 , 9 , MD_PLN_FAST , 2 );//D23
155  scu_pinmux( 14 , 5 , MD_PLN_FAST , 3 );//D24
156  scu_pinmux( 14 , 6 , MD_PLN_FAST , 3 );//D25
157  scu_pinmux( 14 , 7 , MD_PLN_FAST , 3 );//D26
158  scu_pinmux( 14 , 8 , MD_PLN_FAST , 3 );//D27
159  scu_pinmux( 14 , 9 , MD_PLN_FAST , 3 );//D28
160  scu_pinmux( 14 , 10 , MD_PLN_FAST , 3 );//D29
161  scu_pinmux( 14 , 11 , MD_PLN_FAST , 3 );//D30
162  scu_pinmux( 14 , 12 , MD_PLN_FAST , 3 );//D31
163 
164  scu_pinmux( 1 , 3 , MD_PLN_FAST , 3 );//OE
165  scu_pinmux( 1 , 6 , MD_PLN_FAST , 3 );//WE
166 
167  scu_pinmux( 1 , 4 , MD_PLN_FAST , 3 );//BLS0
168  scu_pinmux( 6 , 6 , MD_PLN_FAST , 1 );//BLS1
169  scu_pinmux( 13 , 13 , MD_PLN_FAST , 2 );//BLS2
170  scu_pinmux( 13 , 10 , MD_PLN_FAST , 2 );//BLS3
171 
172  scu_pinmux( 1 , 5 , MD_PLN_FAST , 3 );//CS0
173  scu_pinmux( 6 , 3 , MD_PLN_FAST , 3 );//CS1
174  scu_pinmux( 13 , 12 , MD_PLN_FAST , 2 );//CS2
175  scu_pinmux( 13 , 11 , MD_PLN_FAST , 2 );//CS3
176 }
177 
178 
179 static uint32_t nandReadId(void)
180 {
181  uint8_t a, b, c, d;
182  volatile uint8_t *pCLE;
183  volatile uint8_t *pALE;
184  volatile uint8_t *pData;
185 
186  pCLE = K9F1G_CLE;
187  pALE = K9F1G_ALE;
188  pData = K9F1G_DATA;
189 
190  *pCLE = K9FXX_READ_ID;
191  *pALE = 0;
192 
193  a = *pData;
194  b = *pData;
195  c = *pData;
196  d = *pData;
197 
198 
199  return (a << 24) | (b << 16) | (c << 8) | d;
200 }
201 
202 static uint8_t nandStatus(void)
203 {
204  uint8_t status = 0;
205  volatile uint8_t *pCLE;
206  volatile uint8_t *pALE;
207  volatile uint8_t *pData;
208 
209  pCLE = K9F1G_CLE;
210  pALE = K9F1G_ALE;
211  pData = K9F1G_DATA;
212 
213  *pCLE = K9FXX_READ_STATUS;
214  *pALE = 0;
215 
216  status = *pData;
217 
218  /* remove bits not used */
219  return (status & 0xC1);
220 }
221 
222 static void nandWaitReady(void)
223 {
224  while( !(nandStatus() & (1<<6)) );
225 }
226 
227 /******************************************************************************
228  * Public Functions
229  *****************************************************************************/
230 
231 
232 
233 /******************************************************************************
234  *
235  * Description:
236  * Initialize the NAND Flash
237  *
238  * Returns:
239  * TRUE if initialization successful; otherwise FALSE
240  *
241  *****************************************************************************/
242 uint32_t nand_init (void)
243 {
244  uint32_t nandId = 0;
245  TIM_TIMERCFG_Type timerCfg;
246 
247 // LPC_SC->PCONP |= 0x00000800;
248  LPC_EMC->CONTROL = 0x00000001;
249  LPC_EMC->CONFIG = 0x00000000;
250 
251  pinConfig();
252 
253  TIM_ConfigStructInit(TIM_TIMER_MODE, &timerCfg);
254  TIM_Init(LPC_TIMER0, TIM_TIMER_MODE, &timerCfg);
255 
256  LPC_EMC->STATICCONFIG1 = 0x00000080;
257 
258  LPC_EMC->STATICWAITWEN1 = 0x00000002;
259  LPC_EMC->STATICWAITOEN1 = 0x00000002;
260  LPC_EMC->STATICWAITRD1 = 0x00000008;
261  LPC_EMC->STATICWAITPAG1 = 0x0000001f;
262  LPC_EMC->STATICWAITWR1 = 0x00000008;
263  LPC_EMC->STATICWAITTURN1 = 0x0000000f;
264 
265  nandId = nandReadId();
266 
267  if ((nandId & 0xffff0000) !=
268  (((uint32_t)(ID_MARKER_CODE) << 24) | ID_SAMSUNG << 16)) {
269  /* unknown NAND chip */
270  return FALSE;
271  }
272 
273  pageSize = 1024 * (1 << (nandId & 0x03));
274  blockSize = 64*1024 * (1 << ((nandId>>4) & 0x03));
275  reduntSize = 8 * (1 << ((nandId >> 1) & 0x1));
276 
277 
278  return TRUE;
279 }
280 
281 /******************************************************************************
282  *
283  * Description:
284  * Get the page size of the NAND flash
285  *
286  * Returns:
287  * page size in bytes
288  *
289  *****************************************************************************/
290 uint32_t nand_getPageSize(void)
291 {
292  return pageSize;
293 }
294 
295 /******************************************************************************
296  *
297  * Description:
298  * Get the block size of the NAND flash
299  *
300  * Returns:
301  * block size in bytes
302  *
303  *****************************************************************************/
304 uint32_t nand_getBlockSize(void)
305 {
306  return blockSize;
307 }
308 
309 /******************************************************************************
310  *
311  * Description:
312  * Get the redundant (spare) size per page
313  *
314  * Returns:
315  * redundant/spare size in bytes
316  *
317  *****************************************************************************/
318 uint32_t nand_getRedundantSize(void)
319 {
320  return reduntSize * (pageSize/512);
321 }
322 
323 /******************************************************************************
324  *
325  * Description:
326  * Check if a block is valid
327  *
328  * Returns:
329  * TRUE if the block is valid; otherwise FALSE
330  *
331  *****************************************************************************/
332 uint32_t nand_isBlockValid(uint32_t block)
333 {
334  uint32_t addr = 0;
335  uint32_t page = 0;
336 
337  volatile uint8_t *pCLE;
338  volatile uint8_t *pALE;
339  volatile uint8_t *pData;
340 
341 
342  pCLE = K9F1G_CLE;
343  pALE = K9F1G_ALE;
344  pData = K9F1G_DATA;
345 
346  if (block >= NAND_NUM_BLOCKS) {
347  return FALSE;
348  }
349 
350  addr = block * (blockSize/pageSize);
351 
352  /*
353  * Check page 0 and page 1 in each block. If the first byte
354  * in the spare area (of either page 0 or page 1) is != 0xFF
355  * the block is invalid.
356  */
357 
358  nandWaitReady();
359 
360  for (page = 0; page < 2; page++) {
361  addr += page;
362 
363  *pCLE = K9FXX_READ_1;
364  *pALE = (uint8_t) (pageSize & 0x00FF);
365  *pALE = (uint8_t)((pageSize & 0xFF00) >> 8);
366  *pALE = (uint8_t)((addr & 0x00FF));
367  *pALE = (uint8_t)((addr & 0xFF00) >> 8);
368  *pCLE = K9FXX_READ_2;
369 
370  WAIT_READY();
371 
372  if (*pData != 0xFF) {
373  return FALSE;
374  }
375 
376  }
377 
378  return TRUE;
379 }
380 
381 
382 /******************************************************************************
383  *
384  * Description:
385  * Read a page from the NAND memory
386  *
387  * Params:
388  * block - block number to read from
389  * page - page with�n block to read from
390  * pageBuf - data is copied to this buffer. The size must be at least
391  * pageSize.
392  *
393  * Returns:
394  * TRUE if read successful; otherwise FALSE
395  *
396  *****************************************************************************/
397 uint32_t nand_readPage(uint32_t block, uint32_t page, uint8_t* pageBuf)
398 {
399  uint32_t i = 0;
400  uint32_t addr = 0;
401 
402  volatile uint8_t *pCLE;
403  volatile uint8_t *pALE;
404  volatile uint8_t *pData;
405 
406 
407  pCLE = K9F1G_CLE;
408  pALE = K9F1G_ALE;
409  pData = K9F1G_DATA;
410 
411  if (block >= NAND_NUM_BLOCKS) {
412  return FALSE;
413  }
414 
415  if (page >= blockSize/pageSize) {
416  return FALSE;
417  }
418 
419  addr = block * (blockSize/pageSize) + page;
420 
421  /*
422  * Always reading from start of a page address.
423  * This means that the column address is always 0.
424  */
425 
426  *pCLE = K9FXX_READ_1;
427  *pALE = 0;
428  *pALE = 0;
429  *pALE = (uint8_t)((addr & 0x00FF));
430  *pALE = (uint8_t)((addr & 0xFF00) >> 8);
431  *pCLE = K9FXX_READ_2;
432 
433  WAIT_READY();
434 
435 
436  for (i = 0; i < pageSize; i++) {
437  *pageBuf++ = *pData;
438  }
439 
440 
441  return TRUE;
442 }
443 
444 /******************************************************************************
445  *
446  * Description:
447  * Write a page of data to the NAND memory
448  *
449  * Params:
450  * block - block number to write to
451  * page - page within block to write to
452  * pageBuf - data is copied from this buffer. The size must be at least
453  * pageSize.
454  *
455  * Returns:
456  * TRUE if write successful; otherwise FALSE
457  *
458  *****************************************************************************/
459 uint32_t nand_writePage(uint32_t block, uint32_t page, uint8_t* pageBuf)
460 {
461  uint32_t i = 0;
462  uint32_t addr = 0;
463 
464  volatile uint8_t *pCLE;
465  volatile uint8_t *pALE;
466  volatile uint8_t *pData;
467 
468 
469  pCLE = K9F1G_CLE;
470  pALE = K9F1G_ALE;
471  pData = K9F1G_DATA;
472 
473  if (block >= NAND_NUM_BLOCKS) {
474  return FALSE;
475  }
476 
477  if (page >= blockSize/pageSize) {
478  return FALSE;
479  }
480 
481  addr = block * (blockSize/pageSize) + page;
482 
483  /*
484  * Always writing to start of a page address.
485  * This means that the column address is always 0.
486  */
487 
488  *pCLE = K9FXX_BLOCK_PROGRAM_1;
489  *pALE = 0;
490  *pALE = 0;
491  *pALE = (uint8_t)((addr & 0x00FF));
492  *pALE = (uint8_t)((addr & 0xFF00) >> 8);
493 
494 
495  for (i = 0; i < pageSize; i++) {
496  *pData = *pageBuf++;
497  }
498 
499  *pCLE = K9FXX_BLOCK_PROGRAM_2;
500 
501  TIM_Waitus(700);
502  nandWaitReady();
503 
504  return ((nandStatus() & 0x01) != 0x01);
505 }
506 
507 /******************************************************************************
508  *
509  * Description:
510  * Erase a block
511  *
512  * Params:
513  * block - block number to erase
514  *
515  * Returns:
516  * TRUE if eras successful; otherwise FALSE
517  *
518  *****************************************************************************/
519 uint32_t nand_eraseBlock(uint32_t block)
520 {
521  uint32_t addr = 0;
522 
523  volatile uint8_t *pCLE;
524  volatile uint8_t *pALE;
525 
526  pCLE = K9F1G_CLE;
527  pALE = K9F1G_ALE;
528 
529  if (block >= NAND_NUM_BLOCKS) {
530  return FALSE;
531  }
532 
533  addr = block * (blockSize/pageSize);
534 
535  *pCLE = K9FXX_BLOCK_ERASE_1;
536  *pALE = (uint8_t)(addr & 0x00FF);
537  *pALE = (uint8_t)((addr & 0xFF00) >> 8);
538  *pCLE = K9FXX_BLOCK_ERASE_2;
539 
540  TIM_Waitus(700);
541  nandWaitReady();
542 
543  return ((nandStatus() & 0x01) != 0x01);
544 }
545 
546 #endif