diff options
Diffstat (limited to 'firmware/target/mips/ingenic_jz47xx/ata-nand-jz4760.c')
-rw-r--r-- | firmware/target/mips/ingenic_jz47xx/ata-nand-jz4760.c | 692 |
1 files changed, 692 insertions, 0 deletions
diff --git a/firmware/target/mips/ingenic_jz47xx/ata-nand-jz4760.c b/firmware/target/mips/ingenic_jz47xx/ata-nand-jz4760.c new file mode 100644 index 0000000000..b3cc589528 --- /dev/null +++ b/firmware/target/mips/ingenic_jz47xx/ata-nand-jz4760.c | |||
@@ -0,0 +1,692 @@ | |||
1 | /*************************************************************************** | ||
2 | * __________ __ ___. | ||
3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ | ||
4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / | ||
5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | ||
6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | ||
7 | * \/ \/ \/ \/ \/ | ||
8 | * $Id$ | ||
9 | * | ||
10 | * Copyright (C) 2016 by Roman Stolyarov | ||
11 | * | ||
12 | * This program is free software; you can redistribute it and/or | ||
13 | * modify it under the terms of the GNU General Public License | ||
14 | * as published by the Free Software Foundation; either version 2 | ||
15 | * of the License, or (at your option) any later version. | ||
16 | * | ||
17 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY | ||
18 | * KIND, either express or implied. | ||
19 | * | ||
20 | ****************************************************************************/ | ||
21 | |||
22 | #include "config.h" | ||
23 | #include "cpu.h" | ||
24 | #include "nand.h" | ||
25 | #include "nand_id.h" | ||
26 | #include "system.h" | ||
27 | #include "panic.h" | ||
28 | #include "kernel.h" | ||
29 | #include "storage.h" | ||
30 | #include "string.h" | ||
31 | /*#define LOGF_ENABLE*/ | ||
32 | #include "logf.h" | ||
33 | |||
34 | //#define USE_DMA | ||
35 | //#define USE_ECC | ||
36 | |||
37 | /* | ||
38 | * Standard NAND flash commands | ||
39 | */ | ||
40 | #define NAND_CMD_READ0 0 | ||
41 | #define NAND_CMD_READ1 1 | ||
42 | #define NAND_CMD_RNDOUT 5 | ||
43 | #define NAND_CMD_PAGEPROG 0x10 | ||
44 | #define NAND_CMD_READOOB 0x50 | ||
45 | #define NAND_CMD_ERASE1 0x60 | ||
46 | #define NAND_CMD_STATUS 0x70 | ||
47 | #define NAND_CMD_STATUS_MULTI 0x71 | ||
48 | #define NAND_CMD_SEQIN 0x80 | ||
49 | #define NAND_CMD_RNDIN 0x85 | ||
50 | #define NAND_CMD_READID 0x90 | ||
51 | #define NAND_CMD_ERASE2 0xd0 | ||
52 | #define NAND_CMD_RESET 0xff | ||
53 | |||
54 | /* Extended commands for large page devices */ | ||
55 | #define NAND_CMD_READSTART 0x30 | ||
56 | #define NAND_CMD_RNDOUTSTART 0xE0 | ||
57 | #define NAND_CMD_CACHEDPROG 0x15 | ||
58 | |||
59 | /* Status bits */ | ||
60 | #define NAND_STATUS_FAIL 0x01 | ||
61 | #define NAND_STATUS_FAIL_N1 0x02 | ||
62 | #define NAND_STATUS_TRUE_READY 0x20 | ||
63 | #define NAND_STATUS_READY 0x40 | ||
64 | #define NAND_STATUS_WP 0x80 | ||
65 | |||
66 | /* | ||
67 | * NAND parameter struct | ||
68 | */ | ||
69 | struct nand_param { | ||
70 | unsigned int bus_width; /* data bus width: 8-bit/16-bit */ | ||
71 | unsigned int row_cycle; /* row address cycles: 2/3 */ | ||
72 | unsigned int page_size; /* page size in bytes: 512/2048/4096 */ | ||
73 | unsigned int oob_size; /* oob size in bytes: 16/64/128 */ | ||
74 | unsigned int page_per_block; /* pages per block: 32/64/128 */ | ||
75 | unsigned int bad_block_pos; /* bad block pos in oob: 0/5 */ | ||
76 | }; | ||
77 | |||
78 | /* | ||
79 | * jz4760_nand.c | ||
80 | * | ||
81 | * NAND read routine for JZ4760 | ||
82 | * | ||
83 | * Copyright (c) 2005-2008 Ingenic Semiconductor Inc. | ||
84 | * | ||
85 | */ | ||
86 | |||
87 | #define CFG_NAND_BASE 0xBA000000 | ||
88 | #define NAND_ADDR_OFFSET 0x00800000 | ||
89 | #define NAND_CMD_OFFSET 0x00400000 | ||
90 | |||
91 | #define CFG_NAND_SMCR1 0x0d444400 | ||
92 | |||
93 | #define NAND_DATAPORT CFG_NAND_BASE | ||
94 | #define NAND_ADDRPORT (CFG_NAND_BASE | NAND_ADDR_OFFSET) | ||
95 | #define NAND_COMMPORT (CFG_NAND_BASE | NAND_CMD_OFFSET) | ||
96 | |||
97 | #define ECC_BLOCK 512 | ||
98 | #define ECC_POS 24 | ||
99 | #define PAR_SIZE 13 | ||
100 | |||
101 | #define __nand_cmd(n) (REG8(NAND_COMMPORT) = (n)) | ||
102 | #define __nand_addr(n) (REG8(NAND_ADDRPORT) = (n)) | ||
103 | #define __nand_data8() (REG8(NAND_DATAPORT)) | ||
104 | #define __nand_data16() (REG16(NAND_DATAPORT)) | ||
105 | |||
106 | #define __nand_select() (REG_NEMC_NFCSR |= NEMC_NFCSR_NFE1 | NEMC_NFCSR_NFCE1) | ||
107 | #define __nand_deselect() (REG_NEMC_NFCSR &= ~(NEMC_NFCSR_NFE1 | NEMC_NFCSR_NFCE1)) | ||
108 | |||
109 | /*--------------------------------------------------------------*/ | ||
110 | |||
111 | static struct nand_info* chip_info = NULL; | ||
112 | static struct nand_info* bank; | ||
113 | static unsigned long nand_size; | ||
114 | static struct nand_param internal_param; | ||
115 | static struct mutex nand_mtx; | ||
116 | #ifdef USE_DMA | ||
117 | static struct mutex nand_dma_mtx; | ||
118 | static struct semaphore nand_dma_complete; | ||
119 | #endif | ||
120 | static unsigned char temp_page[2048]; /* Max page size */ | ||
121 | |||
122 | static inline void jz_nand_wait_ready(void) | ||
123 | { | ||
124 | unsigned int timeout = 1000; | ||
125 | while ((REG_GPIO_PXPIN(0) & 0x00100000) && timeout--); | ||
126 | while (!(REG_GPIO_PXPIN(0) & 0x00100000)); | ||
127 | } | ||
128 | |||
129 | #ifndef USE_DMA | ||
130 | static inline void jz_nand_read_buf16(void *buf, int count) | ||
131 | { | ||
132 | register int i; | ||
133 | register unsigned short *p = (unsigned short *)buf; | ||
134 | |||
135 | for (i = 0; i < count; i += 2) | ||
136 | *p++ = __nand_data16(); | ||
137 | } | ||
138 | |||
139 | static inline void jz_nand_read_buf8(void *buf, int count) | ||
140 | { | ||
141 | register int i; | ||
142 | register unsigned char *p = (unsigned char *)buf; | ||
143 | |||
144 | for (i = 0; i < count; i++) | ||
145 | *p++ = __nand_data8(); | ||
146 | } | ||
147 | #else | ||
148 | static void jz_nand_write_dma(void *source, unsigned int len, int bw) | ||
149 | { | ||
150 | mutex_lock(&nand_dma_mtx); | ||
151 | |||
152 | if(((unsigned int)source < 0xa0000000) && len) | ||
153 | dma_cache_wback_inv((unsigned long)source, len); | ||
154 | |||
155 | dma_enable(); | ||
156 | |||
157 | REG_DMAC_DCCSR(DMA_NAND_CHANNEL) = DMAC_DCCSR_NDES; | ||
158 | REG_DMAC_DSAR(DMA_NAND_CHANNEL) = PHYSADDR((unsigned long)source); | ||
159 | REG_DMAC_DTAR(DMA_NAND_CHANNEL) = PHYSADDR((unsigned long)NAND_DATAPORT); | ||
160 | REG_DMAC_DTCR(DMA_NAND_CHANNEL) = len / 16; | ||
161 | REG_DMAC_DRSR(DMA_NAND_CHANNEL) = DMAC_DRSR_RS_AUTO; | ||
162 | REG_DMAC_DCMD(DMA_NAND_CHANNEL) = (DMAC_DCMD_SAI| DMAC_DCMD_DAI | DMAC_DCMD_SWDH_32 | DMAC_DCMD_DS_16BYTE | | ||
163 | (bw == 8 ? DMAC_DCMD_DWDH_8 : DMAC_DCMD_DWDH_16)); | ||
164 | |||
165 | REG_DMAC_DCCSR(DMA_NAND_CHANNEL) |= DMAC_DCCSR_EN; /* Enable DMA channel */ | ||
166 | #if 1 | ||
167 | while( REG_DMAC_DTCR(DMA_NAND_CHANNEL) ) | ||
168 | yield(); | ||
169 | #else | ||
170 | REG_DMAC_DCMD(DMA_NAND_CHANNEL) |= DMAC_DCMD_TIE; /* Enable DMA interrupt */ | ||
171 | semaphore_wait(&nand_dma_complete, TIMEOUT_BLOCK); | ||
172 | #endif | ||
173 | |||
174 | REG_DMAC_DCCSR(DMA_NAND_CHANNEL) &= ~DMAC_DCCSR_EN; /* Disable DMA channel */ | ||
175 | |||
176 | dma_disable(); | ||
177 | |||
178 | mutex_unlock(&nand_dma_mtx); | ||
179 | } | ||
180 | |||
181 | static void jz_nand_read_dma(void *target, unsigned int len, int bw) | ||
182 | { | ||
183 | mutex_lock(&nand_dma_mtx); | ||
184 | |||
185 | if(((unsigned int)target < 0xa0000000) && len) | ||
186 | dma_cache_wback_inv((unsigned long)target, len); | ||
187 | |||
188 | dma_enable(); | ||
189 | |||
190 | REG_DMAC_DCCSR(DMA_NAND_CHANNEL) = DMAC_DCCSR_NDES ; | ||
191 | REG_DMAC_DSAR(DMA_NAND_CHANNEL) = PHYSADDR((unsigned long)NAND_DATAPORT); | ||
192 | REG_DMAC_DTAR(DMA_NAND_CHANNEL) = PHYSADDR((unsigned long)target); | ||
193 | REG_DMAC_DTCR(DMA_NAND_CHANNEL) = len / 4; | ||
194 | REG_DMAC_DRSR(DMA_NAND_CHANNEL) = DMAC_DRSR_RS_AUTO; | ||
195 | REG_DMAC_DCMD(DMA_NAND_CHANNEL) = (DMAC_DCMD_SAI| DMAC_DCMD_DAI | DMAC_DCMD_DWDH_32 | DMAC_DCMD_DS_32BIT | | ||
196 | (bw == 8 ? DMAC_DCMD_SWDH_8 : DMAC_DCMD_SWDH_16)); | ||
197 | REG_DMAC_DCCSR(DMA_NAND_CHANNEL) |= DMAC_DCCSR_EN; /* Enable DMA channel */ | ||
198 | #if 1 | ||
199 | while( REG_DMAC_DTCR(DMA_NAND_CHANNEL) ) | ||
200 | yield(); | ||
201 | #else | ||
202 | REG_DMAC_DCMD(DMA_NAND_CHANNEL) |= DMAC_DCMD_TIE; /* Enable DMA interrupt */ | ||
203 | semaphore_wait(&nand_dma_complete, TIMEOUT_BLOCK); | ||
204 | #endif | ||
205 | |||
206 | //REG_DMAC_DCCSR(DMA_NAND_CHANNEL) &= ~DMAC_DCCSR_EN; /* Disable DMA channel */ | ||
207 | |||
208 | dma_disable(); | ||
209 | |||
210 | mutex_unlock(&nand_dma_mtx); | ||
211 | } | ||
212 | |||
213 | void DMA_CALLBACK(DMA_NAND_CHANNEL)(void) | ||
214 | { | ||
215 | if (REG_DMAC_DCCSR(DMA_NAND_CHANNEL) & DMAC_DCCSR_HLT) | ||
216 | REG_DMAC_DCCSR(DMA_NAND_CHANNEL) &= ~DMAC_DCCSR_HLT; | ||
217 | |||
218 | if (REG_DMAC_DCCSR(DMA_NAND_CHANNEL) & DMAC_DCCSR_AR) | ||
219 | REG_DMAC_DCCSR(DMA_NAND_CHANNEL) &= ~DMAC_DCCSR_AR; | ||
220 | |||
221 | if (REG_DMAC_DCCSR(DMA_NAND_CHANNEL) & DMAC_DCCSR_CT) | ||
222 | REG_DMAC_DCCSR(DMA_NAND_CHANNEL) &= ~DMAC_DCCSR_CT; | ||
223 | |||
224 | if (REG_DMAC_DCCSR(DMA_NAND_CHANNEL) & DMAC_DCCSR_TT) | ||
225 | REG_DMAC_DCCSR(DMA_NAND_CHANNEL) &= ~DMAC_DCCSR_TT; | ||
226 | |||
227 | semaphore_release(&nand_dma_complete); | ||
228 | } | ||
229 | #endif /* USE_DMA */ | ||
230 | |||
231 | static inline void jz_nand_read_buf(void *buf, int count, int bw) | ||
232 | { | ||
233 | #ifdef USE_DMA | ||
234 | if (bw == 8) | ||
235 | jz_nand_read_dma(buf, count, 8); | ||
236 | else | ||
237 | jz_nand_read_dma(buf, count, 16); | ||
238 | #else | ||
239 | if (bw == 8) | ||
240 | jz_nand_read_buf8(buf, count); | ||
241 | else | ||
242 | jz_nand_read_buf16(buf, count); | ||
243 | #endif | ||
244 | } | ||
245 | |||
246 | #ifdef USE_ECC | ||
247 | /* | ||
248 | * Correct 1~9-bit errors in 512-bytes data | ||
249 | */ | ||
250 | static void jz_rs_correct(unsigned char *dat, int idx, int mask) | ||
251 | { | ||
252 | int i, j; | ||
253 | unsigned short d, d1, dm; | ||
254 | |||
255 | i = (idx * 9) >> 3; | ||
256 | j = (idx * 9) & 0x7; | ||
257 | |||
258 | i = (j == 0) ? (i - 1) : i; | ||
259 | j = (j == 0) ? 7 : (j - 1); | ||
260 | |||
261 | if (i > 512) | ||
262 | return; | ||
263 | |||
264 | if (i == 512) | ||
265 | d = dat[i - 1]; | ||
266 | else | ||
267 | d = (dat[i] << 8) | dat[i - 1]; | ||
268 | |||
269 | d1 = (d >> j) & 0x1ff; | ||
270 | d1 ^= mask; | ||
271 | |||
272 | dm = ~(0x1ff << j); | ||
273 | d = (d & dm) | (d1 << j); | ||
274 | |||
275 | dat[i - 1] = d & 0xff; | ||
276 | if (i < 512) | ||
277 | dat[i] = (d >> 8) & 0xff; | ||
278 | } | ||
279 | #endif | ||
280 | |||
281 | /* | ||
282 | * Read oob | ||
283 | */ | ||
284 | static int jz_nand_read_oob(unsigned long page_addr, unsigned char *buf, int size) | ||
285 | { | ||
286 | struct nand_param *nandp = &internal_param; | ||
287 | int page_size, row_cycle, bus_width; | ||
288 | int col_addr; | ||
289 | |||
290 | page_size = nandp->page_size; | ||
291 | row_cycle = nandp->row_cycle; | ||
292 | bus_width = nandp->bus_width; | ||
293 | |||
294 | if (page_size >= 2048) | ||
295 | col_addr = page_size; | ||
296 | else | ||
297 | col_addr = 0; | ||
298 | |||
299 | if (page_size >= 2048) | ||
300 | /* Send READ0 command */ | ||
301 | __nand_cmd(NAND_CMD_READ0); | ||
302 | else | ||
303 | /* Send READOOB command */ | ||
304 | __nand_cmd(NAND_CMD_READOOB); | ||
305 | |||
306 | /* Send column address */ | ||
307 | __nand_addr(col_addr & 0xff); | ||
308 | if (page_size >= 2048) | ||
309 | __nand_addr((col_addr >> 8) & 0xff); | ||
310 | |||
311 | /* Send page address */ | ||
312 | __nand_addr(page_addr & 0xff); | ||
313 | __nand_addr((page_addr >> 8) & 0xff); | ||
314 | if (row_cycle == 3) | ||
315 | __nand_addr((page_addr >> 16) & 0xff); | ||
316 | |||
317 | /* Send READSTART command for 2048 ps NAND */ | ||
318 | if (page_size >= 2048) | ||
319 | __nand_cmd(NAND_CMD_READSTART); | ||
320 | |||
321 | /* Wait for device ready */ | ||
322 | jz_nand_wait_ready(); | ||
323 | |||
324 | /* Read oob data */ | ||
325 | jz_nand_read_buf(buf, size, bus_width); | ||
326 | |||
327 | return 0; | ||
328 | } | ||
329 | |||
330 | |||
331 | /* | ||
332 | * nand_read_page() | ||
333 | * | ||
334 | * Input: | ||
335 | * | ||
336 | * block - block number: 0, 1, 2, ... | ||
337 | * page - page number within a block: 0, 1, 2, ... | ||
338 | * dst - pointer to target buffer | ||
339 | */ | ||
340 | static int jz_nand_read_page(unsigned long page_addr, unsigned char *dst) | ||
341 | { | ||
342 | struct nand_param *nandp = &internal_param; | ||
343 | int page_size, oob_size, page_per_block; | ||
344 | int row_cycle, bus_width, ecc_count; | ||
345 | int i; | ||
346 | #ifdef USE_ECC | ||
347 | int j; | ||
348 | #endif | ||
349 | unsigned char *data_buf; | ||
350 | unsigned char oob_buf[nandp->oob_size]; | ||
351 | |||
352 | page_size = nandp->page_size; | ||
353 | oob_size = nandp->oob_size; | ||
354 | page_per_block = nandp->page_per_block; | ||
355 | row_cycle = nandp->row_cycle; | ||
356 | bus_width = nandp->bus_width; | ||
357 | |||
358 | /* | ||
359 | * Read oob data | ||
360 | */ | ||
361 | jz_nand_read_oob(page_addr, oob_buf, oob_size); | ||
362 | |||
363 | /* | ||
364 | * Read page data | ||
365 | */ | ||
366 | |||
367 | /* Send READ0 command */ | ||
368 | __nand_cmd(NAND_CMD_READ0); | ||
369 | |||
370 | /* Send column address */ | ||
371 | __nand_addr(0); | ||
372 | if (page_size >= 2048) | ||
373 | __nand_addr(0); | ||
374 | |||
375 | /* Send page address */ | ||
376 | __nand_addr(page_addr & 0xff); | ||
377 | __nand_addr((page_addr >> 8) & 0xff); | ||
378 | if (row_cycle >= 3) | ||
379 | __nand_addr((page_addr >> 16) & 0xff); | ||
380 | |||
381 | /* Send READSTART command for 2048 ps NAND */ | ||
382 | if (page_size >= 2048) | ||
383 | __nand_cmd(NAND_CMD_READSTART); | ||
384 | |||
385 | /* Wait for device ready */ | ||
386 | jz_nand_wait_ready(); | ||
387 | |||
388 | /* Read page data */ | ||
389 | data_buf = dst; | ||
390 | |||
391 | ecc_count = page_size / ECC_BLOCK; | ||
392 | |||
393 | for (i = 0; i < ecc_count; i++) | ||
394 | { | ||
395 | #ifdef USE_ECC | ||
396 | volatile unsigned char *paraddr = (volatile unsigned char *)EMC_NFPAR0; | ||
397 | unsigned int stat; | ||
398 | |||
399 | /* Enable RS decoding */ | ||
400 | REG_EMC_NFINTS = 0x0; | ||
401 | __ecc_decoding_4bit(); | ||
402 | #endif | ||
403 | |||
404 | /* Read data */ | ||
405 | jz_nand_read_buf((void *)data_buf, ECC_BLOCK, bus_width); | ||
406 | |||
407 | #ifdef USE_ECC | ||
408 | /* Set PAR values */ | ||
409 | for (j = 0; j < PAR_SIZE; j++) | ||
410 | *paraddr++ = oob_buf[ECC_POS + i*PAR_SIZE + j]; | ||
411 | |||
412 | /* Set PRDY */ | ||
413 | REG_EMC_NFECR |= EMC_NFECR_PRDY; | ||
414 | |||
415 | /* Wait for completion */ | ||
416 | __ecc_decode_sync(); | ||
417 | |||
418 | /* Disable decoding */ | ||
419 | __ecc_disable(); | ||
420 | |||
421 | /* Check result of decoding */ | ||
422 | stat = REG_EMC_NFINTS; | ||
423 | if (stat & EMC_NFINTS_ERR) | ||
424 | { | ||
425 | /* Error occurred */ | ||
426 | if (stat & EMC_NFINTS_UNCOR) | ||
427 | { | ||
428 | /* Uncorrectable error occurred */ | ||
429 | logf("Uncorrectable ECC error at NAND page address 0x%lx", page_addr); | ||
430 | return -1; | ||
431 | } | ||
432 | else | ||
433 | { | ||
434 | unsigned int errcnt, index, mask; | ||
435 | |||
436 | errcnt = (stat & EMC_NFINTS_ERRCNT_MASK) >> EMC_NFINTS_ERRCNT_BIT; | ||
437 | switch (errcnt) | ||
438 | { | ||
439 | case 4: | ||
440 | index = (REG_EMC_NFERR3 & EMC_NFERR_INDEX_MASK) >> EMC_NFERR_INDEX_BIT; | ||
441 | mask = (REG_EMC_NFERR3 & EMC_NFERR_MASK_MASK) >> EMC_NFERR_MASK_BIT; | ||
442 | jz_rs_correct(data_buf, index, mask); | ||
443 | case 3: | ||
444 | index = (REG_EMC_NFERR2 & EMC_NFERR_INDEX_MASK) >> EMC_NFERR_INDEX_BIT; | ||
445 | mask = (REG_EMC_NFERR2 & EMC_NFERR_MASK_MASK) >> EMC_NFERR_MASK_BIT; | ||
446 | jz_rs_correct(data_buf, index, mask); | ||
447 | case 2: | ||
448 | index = (REG_EMC_NFERR1 & EMC_NFERR_INDEX_MASK) >> EMC_NFERR_INDEX_BIT; | ||
449 | mask = (REG_EMC_NFERR1 & EMC_NFERR_MASK_MASK) >> EMC_NFERR_MASK_BIT; | ||
450 | jz_rs_correct(data_buf, index, mask); | ||
451 | case 1: | ||
452 | index = (REG_EMC_NFERR0 & EMC_NFERR_INDEX_MASK) >> EMC_NFERR_INDEX_BIT; | ||
453 | mask = (REG_EMC_NFERR0 & EMC_NFERR_MASK_MASK) >> EMC_NFERR_MASK_BIT; | ||
454 | jz_rs_correct(data_buf, index, mask); | ||
455 | break; | ||
456 | default: | ||
457 | break; | ||
458 | } | ||
459 | } | ||
460 | } | ||
461 | #endif | ||
462 | |||
463 | data_buf += ECC_BLOCK; | ||
464 | } | ||
465 | |||
466 | return 0; | ||
467 | } | ||
468 | |||
469 | static int jz_nand_init(void) | ||
470 | { | ||
471 | unsigned char cData[5]; | ||
472 | |||
473 | __gpio_as_nand_16bit(1); | ||
474 | |||
475 | REG_NEMC_SMCR1 = CFG_NAND_SMCR1 | 0x40; | ||
476 | |||
477 | __nand_select(); | ||
478 | |||
479 | __nand_cmd(NAND_CMD_READID); | ||
480 | __nand_addr(NAND_CMD_READ0); | ||
481 | cData[0] = __nand_data8(); | ||
482 | cData[1] = __nand_data8(); | ||
483 | cData[2] = __nand_data8(); | ||
484 | cData[3] = __nand_data8(); | ||
485 | cData[4] = __nand_data8(); | ||
486 | |||
487 | __nand_deselect(); | ||
488 | |||
489 | logf("NAND chip %d: 0x%x 0x%x 0x%x 0x%x 0x%x", i+1, cData[0], cData[1], | ||
490 | cData[2], cData[3], cData[4]); | ||
491 | |||
492 | bank = nand_identify(cData); | ||
493 | |||
494 | if(bank == NULL) | ||
495 | { | ||
496 | panicf("Unknown NAND flash chip: 0x%x 0x%x 0x%x 0x%x 0x%x", cData[0], | ||
497 | cData[1], cData[2], cData[3], cData[4]); | ||
498 | return -1; /* panicf() doesn't return though */ | ||
499 | } | ||
500 | |||
501 | chip_info = bank; | ||
502 | |||
503 | internal_param.bus_width = 16; | ||
504 | internal_param.row_cycle = chip_info->row_cycles; | ||
505 | internal_param.page_size = chip_info->page_size; | ||
506 | internal_param.oob_size = chip_info->spare_size; | ||
507 | internal_param.page_per_block = chip_info->pages_per_block; | ||
508 | internal_param.bad_block_pos = 0; | ||
509 | |||
510 | nand_size = ((chip_info->page_size * chip_info->blocks_per_bank * chip_info->pages_per_block) - 0x200000) / 512; | ||
511 | |||
512 | return 0; | ||
513 | } | ||
514 | |||
515 | int nand_init(void) | ||
516 | { | ||
517 | int res = 0; | ||
518 | static bool inited = false; | ||
519 | |||
520 | if(!inited) | ||
521 | { | ||
522 | res = jz_nand_init(); | ||
523 | mutex_init(&nand_mtx); | ||
524 | #ifdef USE_DMA | ||
525 | mutex_init(&nand_dma_mtx); | ||
526 | semaphore_init(&nand_dma_complete, 1, 0); | ||
527 | system_enable_irq(DMA_IRQ(DMA_NAND_CHANNEL)); | ||
528 | #endif | ||
529 | |||
530 | inited = true; | ||
531 | } | ||
532 | |||
533 | return res; | ||
534 | } | ||
535 | |||
536 | static inline int read_sector(unsigned long start, unsigned int count, | ||
537 | void* buf, unsigned int chip_size) | ||
538 | { | ||
539 | register int ret; | ||
540 | |||
541 | if(UNLIKELY(start % chip_size == 0 && count == chip_size)) | ||
542 | ret = jz_nand_read_page(start / chip_size, buf); | ||
543 | else | ||
544 | { | ||
545 | ret = jz_nand_read_page(start / chip_size, temp_page); | ||
546 | memcpy(buf, temp_page + (start % chip_size), count); | ||
547 | } | ||
548 | |||
549 | return ret; | ||
550 | } | ||
551 | |||
552 | static inline int write_sector(unsigned long start, unsigned int count, | ||
553 | const void* buf, unsigned int chip_size) | ||
554 | { | ||
555 | int ret = 0; | ||
556 | |||
557 | (void)start; | ||
558 | (void)count; | ||
559 | (void)buf; | ||
560 | (void)chip_size; | ||
561 | |||
562 | /* TODO */ | ||
563 | |||
564 | return ret; | ||
565 | } | ||
566 | |||
567 | int nand_read_sectors(IF_MV(int drive,) unsigned long start, int count, void* buf) | ||
568 | { | ||
569 | #ifdef HAVE_MULTIVOLUME | ||
570 | (void)drive; | ||
571 | #endif | ||
572 | int ret = 0; | ||
573 | unsigned int _count, chip_size = chip_info->page_size; | ||
574 | unsigned long _start; | ||
575 | |||
576 | logf("start"); | ||
577 | mutex_lock(&nand_mtx); | ||
578 | |||
579 | _start = start << 9; | ||
580 | _start += 0x200000; /* skip BL */ | ||
581 | _count = count << 9; | ||
582 | |||
583 | __nand_select(); | ||
584 | ret = read_sector(_start, _count, buf, chip_size); | ||
585 | __nand_deselect(); | ||
586 | |||
587 | mutex_unlock(&nand_mtx); | ||
588 | |||
589 | logf("nand_read_sectors(%ld, %d, 0x%x): %d", start, count, (int)buf, ret); | ||
590 | |||
591 | return ret; | ||
592 | } | ||
593 | |||
594 | int nand_write_sectors(IF_MV(int drive,) unsigned long start, int count, const void* buf) | ||
595 | { | ||
596 | #ifdef HAVE_MULTIVOLUME | ||
597 | (void)drive; | ||
598 | #endif | ||
599 | int ret = 0; | ||
600 | unsigned int _count, chip_size = chip_info->page_size; | ||
601 | unsigned long _start; | ||
602 | |||
603 | logf("start"); | ||
604 | mutex_lock(&nand_mtx); | ||
605 | |||
606 | _start = start << 9; | ||
607 | _start += chip_info->page_size * chip_info->pages_per_block; /* skip BL */ | ||
608 | _count = count << 9; | ||
609 | |||
610 | __nand_select(); | ||
611 | ret = write_sector(_start, _count, buf, chip_size); | ||
612 | __nand_deselect(); | ||
613 | |||
614 | mutex_unlock(&nand_mtx); | ||
615 | |||
616 | logf("nand_write_sectors(%ld, %d, 0x%x): %d", start, count, (int)buf, ret); | ||
617 | |||
618 | return ret; | ||
619 | } | ||
620 | |||
621 | #ifdef HAVE_STORAGE_FLUSH | ||
622 | int nand_flush(void) | ||
623 | { | ||
624 | return 0; | ||
625 | } | ||
626 | #endif | ||
627 | |||
628 | void nand_spindown(int seconds) | ||
629 | { | ||
630 | /* null */ | ||
631 | (void)seconds; | ||
632 | } | ||
633 | |||
634 | void nand_sleep(void) | ||
635 | { | ||
636 | /* null */ | ||
637 | } | ||
638 | |||
639 | void nand_spin(void) | ||
640 | { | ||
641 | /* null */ | ||
642 | } | ||
643 | |||
644 | void nand_enable(bool on) | ||
645 | { | ||
646 | /* null - flash controller is enabled/disabled as needed. */ | ||
647 | (void)on; | ||
648 | } | ||
649 | |||
650 | /* TODO */ | ||
651 | long nand_last_disk_activity(void) | ||
652 | { | ||
653 | return 0; | ||
654 | } | ||
655 | |||
656 | int nand_spinup_time(void) | ||
657 | { | ||
658 | return 0; | ||
659 | } | ||
660 | |||
661 | void nand_sleepnow(void) | ||
662 | { | ||
663 | } | ||
664 | |||
665 | #ifdef STORAGE_GET_INFO | ||
666 | void nand_get_info(IF_MV(int drive,) struct storage_info *info) | ||
667 | { | ||
668 | #ifdef HAVE_MULTIVOLUME | ||
669 | (void)drive; | ||
670 | #endif | ||
671 | |||
672 | /* firmware version */ | ||
673 | info->revision="0.00"; | ||
674 | |||
675 | info->vendor="Rockbox"; | ||
676 | info->product="NAND Storage"; | ||
677 | |||
678 | /* blocks count */ | ||
679 | info->num_sectors = nand_size; | ||
680 | info->sector_size = 512; | ||
681 | } | ||
682 | #endif | ||
683 | |||
684 | #ifdef CONFIG_STORAGE_MULTI | ||
685 | int nand_num_drives(int first_drive) | ||
686 | { | ||
687 | /* We don't care which logical drive number(s) we have been assigned */ | ||
688 | (void)first_drive; | ||
689 | |||
690 | return 1; | ||
691 | } | ||
692 | #endif | ||