diff options
Diffstat (limited to 'firmware/target')
-rw-r--r-- | firmware/target/mips/ingenic_jz47xx/ata-nand-jz4740.c | 78 |
1 files changed, 42 insertions, 36 deletions
diff --git a/firmware/target/mips/ingenic_jz47xx/ata-nand-jz4740.c b/firmware/target/mips/ingenic_jz47xx/ata-nand-jz4740.c index 8c4ad40f72..851472bf62 100644 --- a/firmware/target/mips/ingenic_jz47xx/ata-nand-jz4740.c +++ b/firmware/target/mips/ingenic_jz47xx/ata-nand-jz4740.c | |||
@@ -30,8 +30,10 @@ | |||
30 | #include "storage.h" | 30 | #include "storage.h" |
31 | #include "buffer.h" | 31 | #include "buffer.h" |
32 | #include "string.h" | 32 | #include "string.h" |
33 | #include "logf.h" | ||
33 | 34 | ||
34 | //#define USE_DMA | 35 | //#define USE_DMA |
36 | //#define USE_ECC | ||
35 | 37 | ||
36 | /* | 38 | /* |
37 | * Standard NAND flash commands | 39 | * Standard NAND flash commands |
@@ -51,9 +53,9 @@ | |||
51 | #define NAND_CMD_RESET 0xff | 53 | #define NAND_CMD_RESET 0xff |
52 | 54 | ||
53 | /* Extended commands for large page devices */ | 55 | /* Extended commands for large page devices */ |
54 | #define NAND_CMD_READSTART 0x30 | 56 | #define NAND_CMD_READSTART 0x30 |
55 | #define NAND_CMD_RNDOUTSTART 0xE0 | 57 | #define NAND_CMD_RNDOUTSTART 0xE0 |
56 | #define NAND_CMD_CACHEDPROG 0x15 | 58 | #define NAND_CMD_CACHEDPROG 0x15 |
57 | 59 | ||
58 | /* Status bits */ | 60 | /* Status bits */ |
59 | #define NAND_STATUS_FAIL 0x01 | 61 | #define NAND_STATUS_FAIL 0x01 |
@@ -69,8 +71,8 @@ struct nand_param | |||
69 | { | 71 | { |
70 | unsigned int bus_width; /* data bus width: 8-bit/16-bit */ | 72 | unsigned int bus_width; /* data bus width: 8-bit/16-bit */ |
71 | unsigned int row_cycle; /* row address cycles: 2/3 */ | 73 | unsigned int row_cycle; /* row address cycles: 2/3 */ |
72 | unsigned int page_size; /* page size in bytes: 512/2048 */ | 74 | unsigned int page_size; /* page size in bytes: 512/2048/4096 */ |
73 | unsigned int oob_size; /* oob size in bytes: 16/64 */ | 75 | unsigned int oob_size; /* oob size in bytes: 16/64/128 */ |
74 | unsigned int page_per_block; /* pages per block: 32/64/128 */ | 76 | unsigned int page_per_block; /* pages per block: 32/64/128 */ |
75 | }; | 77 | }; |
76 | 78 | ||
@@ -83,9 +85,9 @@ struct nand_param | |||
83 | * | 85 | * |
84 | */ | 86 | */ |
85 | 87 | ||
86 | #define NAND_DATAPORT 0xb8000000 | 88 | #define NAND_DATAPORT 0xB8000000 |
87 | #define NAND_ADDRPORT 0xb8010000 | 89 | #define NAND_ADDRPORT 0xB8010000 |
88 | #define NAND_COMMPORT 0xb8008000 | 90 | #define NAND_COMMPORT 0xB8008000 |
89 | 91 | ||
90 | #define ECC_BLOCK 512 | 92 | #define ECC_BLOCK 512 |
91 | #define ECC_POS 6 | 93 | #define ECC_POS 6 |
@@ -93,8 +95,8 @@ struct nand_param | |||
93 | 95 | ||
94 | #define __nand_cmd(n) (REG8(NAND_COMMPORT) = (n)) | 96 | #define __nand_cmd(n) (REG8(NAND_COMMPORT) = (n)) |
95 | #define __nand_addr(n) (REG8(NAND_ADDRPORT) = (n)) | 97 | #define __nand_addr(n) (REG8(NAND_ADDRPORT) = (n)) |
96 | #define __nand_data8() REG8(NAND_DATAPORT) | 98 | #define __nand_data8() (REG8(NAND_DATAPORT)) |
97 | #define __nand_data16() REG16(NAND_DATAPORT) | 99 | #define __nand_data16() (REG16(NAND_DATAPORT)) |
98 | 100 | ||
99 | #define __nand_enable() (REG_EMC_NFCSR |= EMC_NFCSR_NFE1 | EMC_NFCSR_NFCE1) | 101 | #define __nand_enable() (REG_EMC_NFCSR |= EMC_NFCSR_NFE1 | EMC_NFCSR_NFCE1) |
100 | #define __nand_disable() (REG_EMC_NFCSR &= ~(EMC_NFCSR_NFCE1)) | 102 | #define __nand_disable() (REG_EMC_NFCSR &= ~(EMC_NFCSR_NFCE1)) |
@@ -118,17 +120,16 @@ static unsigned char temp_page[4096]; /* Max page size */ | |||
118 | 120 | ||
119 | static inline void jz_nand_wait_ready(void) | 121 | static inline void jz_nand_wait_ready(void) |
120 | { | 122 | { |
121 | unsigned int timeout = 1000; | 123 | register unsigned int timeout = 1000; |
122 | while ((REG_GPIO_PXPIN(2) & 0x40000000) && timeout--); | 124 | while ((REG_GPIO_PXPIN(2) & 0x40000000) && timeout--); |
123 | while (!(REG_GPIO_PXPIN(2) & 0x40000000)); | 125 | while (!(REG_GPIO_PXPIN(2) & 0x40000000)); |
124 | } | 126 | } |
125 | 127 | ||
126 | #ifndef USE_DMA | 128 | #ifndef USE_DMA |
127 | |||
128 | static inline void jz_nand_read_buf16(void *buf, int count) | 129 | static inline void jz_nand_read_buf16(void *buf, int count) |
129 | { | 130 | { |
130 | int i; | 131 | register int i; |
131 | unsigned short *p = (unsigned short *)buf; | 132 | register unsigned short *p = (unsigned short *)buf; |
132 | 133 | ||
133 | for (i = 0; i < count; i += 2) | 134 | for (i = 0; i < count; i += 2) |
134 | *p++ = __nand_data16(); | 135 | *p++ = __nand_data16(); |
@@ -136,15 +137,13 @@ static inline void jz_nand_read_buf16(void *buf, int count) | |||
136 | 137 | ||
137 | static inline void jz_nand_read_buf8(void *buf, int count) | 138 | static inline void jz_nand_read_buf8(void *buf, int count) |
138 | { | 139 | { |
139 | int i; | 140 | register int i; |
140 | unsigned char *p = (unsigned char *)buf; | 141 | register unsigned char *p = (unsigned char *)buf; |
141 | 142 | ||
142 | for (i = 0; i < count; i++) | 143 | for (i = 0; i < count; i++) |
143 | *p++ = __nand_data8(); | 144 | *p++ = __nand_data8(); |
144 | } | 145 | } |
145 | |||
146 | #else | 146 | #else |
147 | |||
148 | static void jz_nand_write_dma(void *source, unsigned int len, int bw) | 147 | static void jz_nand_write_dma(void *source, unsigned int len, int bw) |
149 | { | 148 | { |
150 | mutex_lock(&nand_mtx); | 149 | mutex_lock(&nand_mtx); |
@@ -226,8 +225,7 @@ void DMA_CALLBACK(DMA_NAND_CHANNEL)(void) | |||
226 | 225 | ||
227 | wakeup_signal(&nand_wkup); | 226 | wakeup_signal(&nand_wkup); |
228 | } | 227 | } |
229 | 228 | #endif /* USE_DMA */ | |
230 | #endif | ||
231 | 229 | ||
232 | static inline void jz_nand_read_buf(void *buf, int count, int bw) | 230 | static inline void jz_nand_read_buf(void *buf, int count, int bw) |
233 | { | 231 | { |
@@ -244,6 +242,7 @@ static inline void jz_nand_read_buf(void *buf, int count, int bw) | |||
244 | #endif | 242 | #endif |
245 | } | 243 | } |
246 | 244 | ||
245 | #ifdef USE_ECC | ||
247 | /* | 246 | /* |
248 | * Correct 1~9-bit errors in 512-bytes data | 247 | * Correct 1~9-bit errors in 512-bytes data |
249 | */ | 248 | */ |
@@ -258,7 +257,8 @@ static void jz_rs_correct(unsigned char *dat, int idx, int mask) | |||
258 | i = (j == 0) ? (i - 1) : i; | 257 | i = (j == 0) ? (i - 1) : i; |
259 | j = (j == 0) ? 7 : (j - 1); | 258 | j = (j == 0) ? 7 : (j - 1); |
260 | 259 | ||
261 | if (i > 512) return; | 260 | if (i > 512) |
261 | return; | ||
262 | 262 | ||
263 | if (i == 512) | 263 | if (i == 512) |
264 | d = dat[i - 1]; | 264 | d = dat[i - 1]; |
@@ -275,11 +275,12 @@ static void jz_rs_correct(unsigned char *dat, int idx, int mask) | |||
275 | if (i < 512) | 275 | if (i < 512) |
276 | dat[i] = (d >> 8) & 0xff; | 276 | dat[i] = (d >> 8) & 0xff; |
277 | } | 277 | } |
278 | #endif | ||
278 | 279 | ||
279 | /* | 280 | /* |
280 | * Read oob | 281 | * Read oob |
281 | */ | 282 | */ |
282 | static int jz_nand_read_oob(int page_addr, unsigned char *buf, int size) | 283 | static int jz_nand_read_oob(unsigned long page_addr, unsigned char *buf, int size) |
283 | { | 284 | { |
284 | struct nand_param *nandp = &internal_param; | 285 | struct nand_param *nandp = &internal_param; |
285 | int page_size, row_cycle, bus_width; | 286 | int page_size, row_cycle, bus_width; |
@@ -335,14 +336,14 @@ static int jz_nand_read_oob(int page_addr, unsigned char *buf, int size) | |||
335 | * page - page number within a block: 0, 1, 2, ... | 336 | * page - page number within a block: 0, 1, 2, ... |
336 | * dst - pointer to target buffer | 337 | * dst - pointer to target buffer |
337 | */ | 338 | */ |
338 | static int jz_nand_read_page(int block, int page, unsigned char *dst) | 339 | static int jz_nand_read_page(unsigned long page_addr, unsigned char *dst) |
339 | { | 340 | { |
340 | struct nand_param *nandp = &internal_param; | 341 | struct nand_param *nandp = &internal_param; |
341 | int page_size, oob_size, page_per_block; | 342 | int page_size, oob_size, page_per_block; |
342 | int row_cycle, bus_width, ecc_count; | 343 | int row_cycle, bus_width, ecc_count; |
343 | int page_addr, i, j; | 344 | int i, j; |
344 | unsigned char *data_buf; | 345 | unsigned char *data_buf; |
345 | unsigned char oob_buf[128]; | 346 | unsigned char oob_buf[nandp->oob_size]; |
346 | 347 | ||
347 | page_size = nandp->page_size; | 348 | page_size = nandp->page_size; |
348 | oob_size = nandp->oob_size; | 349 | oob_size = nandp->oob_size; |
@@ -350,8 +351,6 @@ static int jz_nand_read_page(int block, int page, unsigned char *dst) | |||
350 | row_cycle = nandp->row_cycle; | 351 | row_cycle = nandp->row_cycle; |
351 | bus_width = nandp->bus_width; | 352 | bus_width = nandp->bus_width; |
352 | 353 | ||
353 | page_addr = page + block * page_per_block; | ||
354 | |||
355 | /* | 354 | /* |
356 | * Read oob data | 355 | * Read oob data |
357 | */ | 356 | */ |
@@ -372,7 +371,7 @@ static int jz_nand_read_page(int block, int page, unsigned char *dst) | |||
372 | /* Send page address */ | 371 | /* Send page address */ |
373 | __nand_addr(page_addr & 0xff); | 372 | __nand_addr(page_addr & 0xff); |
374 | __nand_addr((page_addr >> 8) & 0xff); | 373 | __nand_addr((page_addr >> 8) & 0xff); |
375 | if (row_cycle == 3) | 374 | if (row_cycle >= 3) |
376 | __nand_addr((page_addr >> 16) & 0xff); | 375 | __nand_addr((page_addr >> 16) & 0xff); |
377 | 376 | ||
378 | /* Send READSTART command for 2048 ps NAND */ | 377 | /* Send READSTART command for 2048 ps NAND */ |
@@ -389,16 +388,19 @@ static int jz_nand_read_page(int block, int page, unsigned char *dst) | |||
389 | 388 | ||
390 | for (i = 0; i < ecc_count; i++) | 389 | for (i = 0; i < ecc_count; i++) |
391 | { | 390 | { |
391 | #ifdef USE_ECC | ||
392 | volatile unsigned char *paraddr = (volatile unsigned char *)EMC_NFPAR0; | 392 | volatile unsigned char *paraddr = (volatile unsigned char *)EMC_NFPAR0; |
393 | unsigned int stat; | 393 | unsigned int stat; |
394 | 394 | ||
395 | /* Enable RS decoding */ | 395 | /* Enable RS decoding */ |
396 | REG_EMC_NFINTS = 0x0; | 396 | REG_EMC_NFINTS = 0x0; |
397 | __nand_ecc_rs_decoding(); | 397 | __nand_ecc_rs_decoding(); |
398 | #endif | ||
398 | 399 | ||
399 | /* Read data */ | 400 | /* Read data */ |
400 | jz_nand_read_buf((void *)data_buf, ECC_BLOCK, bus_width); | 401 | jz_nand_read_buf((void *)data_buf, ECC_BLOCK, bus_width); |
401 | 402 | ||
403 | #ifdef USE_ECC | ||
402 | /* Set PAR values */ | 404 | /* Set PAR values */ |
403 | for (j = 0; j < PAR_SIZE; j++) | 405 | for (j = 0; j < PAR_SIZE; j++) |
404 | *paraddr++ = oob_buf[ECC_POS + i*PAR_SIZE + j]; | 406 | *paraddr++ = oob_buf[ECC_POS + i*PAR_SIZE + j]; |
@@ -420,7 +422,7 @@ static int jz_nand_read_page(int block, int page, unsigned char *dst) | |||
420 | if (stat & EMC_NFINTS_UNCOR) | 422 | if (stat & EMC_NFINTS_UNCOR) |
421 | { | 423 | { |
422 | /* Uncorrectable error occurred */ | 424 | /* Uncorrectable error occurred */ |
423 | panicf("Uncorrectable ECC error at NAND page 0x%x block 0x%x", page, block); | 425 | panicf("Uncorrectable ECC error at NAND page address 0x%lx", page_addr); |
424 | return -1; | 426 | return -1; |
425 | } | 427 | } |
426 | else | 428 | else |
@@ -452,6 +454,7 @@ static int jz_nand_read_page(int block, int page, unsigned char *dst) | |||
452 | } | 454 | } |
453 | } | 455 | } |
454 | } | 456 | } |
457 | #endif | ||
455 | 458 | ||
456 | data_buf += ECC_BLOCK; | 459 | data_buf += ECC_BLOCK; |
457 | } | 460 | } |
@@ -502,7 +505,7 @@ static int jz_nand_init(void) | |||
502 | internal_param.bus_width = 8; | 505 | internal_param.bus_width = 8; |
503 | internal_param.row_cycle = chip_info->row_cycles; | 506 | internal_param.row_cycle = chip_info->row_cycles; |
504 | internal_param.page_size = chip_info->page_size; | 507 | internal_param.page_size = chip_info->page_size; |
505 | internal_param.oob_size = chip_info->page_size/32; | 508 | internal_param.oob_size = chip_info->spare_size; |
506 | internal_param.page_per_block = chip_info->pages_per_block; | 509 | internal_param.page_per_block = chip_info->pages_per_block; |
507 | 510 | ||
508 | return 0; | 511 | return 0; |
@@ -532,21 +535,24 @@ int nand_read_sectors(IF_MV2(int drive,) unsigned long start, int count, void* b | |||
532 | { | 535 | { |
533 | int i, ret = 0; | 536 | int i, ret = 0; |
534 | 537 | ||
538 | logf("nand_read_sectors(%ld, %d, 0x%x)", start, count, (int)buf); | ||
539 | |||
535 | start *= 512; | 540 | start *= 512; |
536 | count *= 512; | 541 | count *= 512; |
537 | 542 | ||
538 | if(count <= chip_info->page_size) | 543 | if(count <= chip_info->page_size) |
539 | { | 544 | { |
540 | ret = jz_nand_read_page(start % (chip_info->page_size * chip_info->pages_per_block), start % chip_info->page_size, temp_page); | 545 | ret = jz_nand_read_page(start/chip_info->page_size, temp_page); |
541 | memcpy(buf, temp_page, count); | 546 | memcpy(buf, temp_page+(start%chip_info->page_size), count); |
542 | return ret; | 547 | return ret; |
543 | } | 548 | } |
544 | else | 549 | else |
545 | { | 550 | { |
546 | for(i=0; i<count && ret == 0; i+=chip_info->page_size) | 551 | for(i=0; i<count && ret==0; i+=chip_info->page_size) |
547 | { | 552 | { |
548 | ret = jz_nand_read_page((start+i) % (chip_info->page_size * chip_info->pages_per_block), (start+i) % chip_info->page_size, temp_page); | 553 | ret = jz_nand_read_page((start+i)/chip_info->page_size, temp_page); |
549 | memcpy(buf+i, temp_page, (count-i < chip_info->page_size ? count-i : chip_info->page_size)); | 554 | memcpy(buf+i, temp_page+((start+i)%chip_info->page_size), |
555 | (count-i < chip_info->page_size ? count-i : chip_info->page_size)); | ||
550 | } | 556 | } |
551 | return ret; | 557 | return ret; |
552 | } | 558 | } |
@@ -607,7 +613,7 @@ void nand_get_info(IF_MV2(int drive,) struct storage_info *info) | |||
607 | 613 | ||
608 | /* blocks count */ | 614 | /* blocks count */ |
609 | /* TODO: proper amount of sectors! */ | 615 | /* TODO: proper amount of sectors! */ |
610 | info->num_sectors = (chip_info->page_size / 512) * chip_info->pages_per_block * chip_info->blocks_per_bank; | 616 | info->num_sectors = ((chip_info->page_size+chip_info->spare_size) / 512) * chip_info->pages_per_block * chip_info->blocks_per_bank; |
611 | info->sector_size = 512; | 617 | info->sector_size = 512; |
612 | } | 618 | } |
613 | #endif | 619 | #endif |