diff options
-rw-r--r-- | firmware/export/tcc77x.h | 78 | ||||
-rw-r--r-- | firmware/export/tcc780x.h | 24 | ||||
-rw-r--r-- | firmware/target/arm/ata-nand-telechips.c | 144 |
3 files changed, 170 insertions, 76 deletions
diff --git a/firmware/export/tcc77x.h b/firmware/export/tcc77x.h index ad1a8a17aa..db128b68f6 100644 --- a/firmware/export/tcc77x.h +++ b/firmware/export/tcc77x.h | |||
@@ -182,51 +182,43 @@ | |||
182 | 182 | ||
183 | /* ECC controller */ | 183 | /* ECC controller */ |
184 | 184 | ||
185 | #define ECC_CTRL (*(volatile unsigned long *)0x80000900) | 185 | #define ECC_CTRL (*(volatile unsigned long *)0x80000900) |
186 | #define ECC_DMA_REQ (1<<28) | 186 | #define ECC_DMA_REQ (1<<28) |
187 | #define ECC_ENC (1<<27) /* MLC ECC3/4 */ | 187 | #define ECC_ENC (1<<27) /* MLC ECC3/4 */ |
188 | #define ECC_FLG (1<<26) | 188 | #define ECC_READY (1<<26) |
189 | #define ECC_IEN (1<<25) | 189 | #define ECC_IEN (1<<25) |
190 | #define ECC_MANUAL (1<<22) | 190 | #define ECC_MANUAL (1<<22) |
191 | #define ECC_WCNT (1<<12) /* [21:12] */ | 191 | #define ECC_WCNT (1<<12) /* [21:12] */ |
192 | #define ECC_HOLD (1<<7) | 192 | #define ECC_HOLD (1<<7) |
193 | #define ECC_M4EN (1<<6) | 193 | #define ECC_M4EN (1<<6) |
194 | #define ECC_ZERO (1<<5) | 194 | #define ECC_ZERO (1<<5) |
195 | #define ECC_M3EN (1<<4) | 195 | #define ECC_M3EN (1<<4) |
196 | #define ECC_CNT_MASK (7<<1) | 196 | #define ECC_CNT_MASK (7<<1) |
197 | #define ECC_CNT (1<<1) | 197 | #define ECC_CNT (1<<1) |
198 | #define ECC_SLC (1<<0) | 198 | #define ECC_SLC (1<<0) |
199 | 199 | ||
200 | #define ECC_BASE (*(volatile unsigned long *)0x80000904) | 200 | #define ECC_BASE (*(volatile unsigned long *)0x80000904) |
201 | #define ECC_MASK (*(volatile unsigned long *)0x80000908) | 201 | #define ECC_MASK (*(volatile unsigned long *)0x80000908) |
202 | #define ECC_CLR (*(volatile unsigned long *)0x8000090c) | 202 | #define ECC_CLR (*(volatile unsigned long *)0x8000090c) |
203 | #define SLC_ECC0 (*(volatile unsigned long *)0x80000910) | 203 | #define SLC_ECC0 (*(volatile unsigned long *)0x80000910) |
204 | #define SLC_ECC1 (*(volatile unsigned long *)0x80000914) | 204 | #define SLC_ECC1 (*(volatile unsigned long *)0x80000914) |
205 | #define SLC_ECC2 (*(volatile unsigned long *)0x80000918) | 205 | #define SLC_ECC2 (*(volatile unsigned long *)0x80000918) |
206 | #define SLC_ECC3 (*(volatile unsigned long *)0x8000091c) | 206 | #define SLC_ECC3 (*(volatile unsigned long *)0x8000091c) |
207 | #define SLC_ECC4 (*(volatile unsigned long *)0x80000920) | 207 | #define SLC_ECC4 (*(volatile unsigned long *)0x80000920) |
208 | #define SLC_ECC5 (*(volatile unsigned long *)0x80000924) | 208 | #define SLC_ECC5 (*(volatile unsigned long *)0x80000924) |
209 | #define SLC_ECC6 (*(volatile unsigned long *)0x80000928) | 209 | #define SLC_ECC6 (*(volatile unsigned long *)0x80000928) |
210 | #define SLC_ECC7 (*(volatile unsigned long *)0x8000092c) | 210 | #define SLC_ECC7 (*(volatile unsigned long *)0x8000092c) |
211 | #define MLC_ECC0W (*(volatile unsigned long *)0x80000930) | 211 | #define MLC_ECC0W (*(volatile unsigned long *)0x80000930) |
212 | #define MLC_ECC1W (*(volatile unsigned long *)0x80000934) | 212 | #define MLC_ECC1W (*(volatile unsigned long *)0x80000934) |
213 | #define MLC_ECC2W (*(volatile unsigned long *)0x80000938) | 213 | #define MLC_ECC2W (*(volatile unsigned long *)0x80000938) |
214 | #define MLC_ECC0R (*(volatile unsigned long *)0x80000940) | 214 | #define MLC_ECC0R (*(volatile unsigned long *)0x80000940) |
215 | #define MLC_ECC1R (*(volatile unsigned long *)0x80000944) | 215 | #define MLC_ECC1R (*(volatile unsigned long *)0x80000944) |
216 | #define MLC_ECC2R (*(volatile unsigned long *)0x80000948) | 216 | #define MLC_ECC2R (*(volatile unsigned long *)0x80000948) |
217 | #define ECC_CORR_START (*(volatile unsigned long *)0x8000094c) | 217 | #define ECC_CORR_START (*(volatile unsigned long *)0x8000094c) |
218 | #define ECC_ERRADDR1 (*(volatile unsigned long *)0x80000950) | 218 | #define ECC_ERRADDR(x) (*(volatile unsigned long *)(0x80000950+4*(x))) |
219 | #define ECC_ERRADDR2 (*(volatile unsigned long *)0x80000954) | 219 | #define ECC_ERRDATA(x) (*(volatile unsigned long *)(0x80000960+4*(x))) |
220 | #define ECC_ERRADDR3 (*(volatile unsigned long *)0x80000958) | 220 | #define ECC_ERR_NUM (*(volatile unsigned long *)0x80000970) |
221 | #define ECC_ERRADDR4 (*(volatile unsigned long *)0x8000095c) | 221 | |
222 | #define ECC_ERRDATA1 (*(volatile unsigned long *)0x80000960) | ||
223 | #define ECC_ERRDATA2 (*(volatile unsigned long *)0x80000964) | ||
224 | #define ECC_ERRDATA3 (*(volatile unsigned long *)0x80000968) | ||
225 | #define ECC_ERRDATA4 (*(volatile unsigned long *)0x8000096c) | ||
226 | #define ECC_ERR_NUM (*(volatile unsigned long *)0x80000970) | ||
227 | |||
228 | #define ECC_ERRDATA(x) (*(volatile unsigned long *)(0x80000960 + (x) * 4)) | ||
229 | #define ECC_ERRADDR(x) (*(volatile unsigned long *)(0x80000950 + (x) * 4)) | ||
230 | 222 | ||
231 | /* Digital Audio Interface */ | 223 | /* Digital Audio Interface */ |
232 | #define DADI_L0 (*(volatile unsigned long *)0x80000000) | 224 | #define DADI_L0 (*(volatile unsigned long *)0x80000000) |
diff --git a/firmware/export/tcc780x.h b/firmware/export/tcc780x.h index 24a4415ef3..497f1514e0 100644 --- a/firmware/export/tcc780x.h +++ b/firmware/export/tcc780x.h | |||
@@ -232,18 +232,18 @@ | |||
232 | 232 | ||
233 | /* ECC Controller */ | 233 | /* ECC Controller */ |
234 | 234 | ||
235 | #define ECC_CTRL (*(volatile unsigned long *)0xF005B000) | 235 | #define ECC_CTRL (*(volatile unsigned long *)0xF005B000) |
236 | #define ECC_M4EN (1<<6) | 236 | #define ECC_ENC (1<<27) |
237 | #define ECC_ENC (1<<27) | 237 | #define ECC_READY (1<<26) |
238 | #define ECC_READY (1<<26) | 238 | #define ECC_M4EN (1<<6) |
239 | #define ECC_BASE (*(volatile unsigned long *)0xF005B004) | 239 | #define ECC_BASE (*(volatile unsigned long *)0xF005B004) |
240 | #define ECC_CLR (*(volatile unsigned long *)0xF005B00C) | 240 | #define ECC_CLR (*(volatile unsigned long *)0xF005B00C) |
241 | #define ECC_MLC0W (*(volatile unsigned long *)0xF005B030) | 241 | #define MLC_ECC0W (*(volatile unsigned long *)0xF005B030) |
242 | #define ECC_MLC1W (*(volatile unsigned long *)0xF005B034) | 242 | #define MLC_ECC1W (*(volatile unsigned long *)0xF005B034) |
243 | #define ECC_MLC2W (*(volatile unsigned long *)0xF005B038) | 243 | #define MLC_ECC2W (*(volatile unsigned long *)0xF005B038) |
244 | #define ECC_ERRADDR (*(volatile unsigned long *)0xF005B050) | 244 | #define ECC_ERRADDR(x) (*(volatile unsigned long *)(0xF005B050+4*(x))) |
245 | #define ECC_ERRDATA (*(volatile unsigned long *)0xF005B060) | 245 | #define ECC_ERRDATA(x) (*(volatile unsigned long *)(0xF005B060+4*(x))) |
246 | #define ECC_ERR (*(volatile unsigned long *)0xF005B070) | 246 | #define ECC_ERR_NUM (*(volatile unsigned long *)0xF005B070) |
247 | 247 | ||
248 | /* SD/MMC Controller */ | 248 | /* SD/MMC Controller */ |
249 | 249 | ||
diff --git a/firmware/target/arm/ata-nand-telechips.c b/firmware/target/arm/ata-nand-telechips.c index ffe6de897e..7250211eb9 100644 --- a/firmware/target/arm/ata-nand-telechips.c +++ b/firmware/target/arm/ata-nand-telechips.c | |||
@@ -31,7 +31,10 @@ | |||
31 | 31 | ||
32 | #define SECTOR_SIZE 512 | 32 | #define SECTOR_SIZE 512 |
33 | 33 | ||
34 | /* #define USE_ECC_CORRECTION */ | 34 | /* ECC on read is implemented on the assumption that MLC-style 4-bit correction |
35 | is always used regardless of NAND chip type. This assumption is true for at | ||
36 | least D2 (MLC) and M200 (SLC). */ | ||
37 | #define USE_ECC_CORRECTION | ||
35 | 38 | ||
36 | /* for compatibility */ | 39 | /* for compatibility */ |
37 | int ata_spinup_time = 0; | 40 | int ata_spinup_time = 0; |
@@ -140,12 +143,6 @@ static struct write_cache write_caches[MAX_WRITE_CACHES]; | |||
140 | 143 | ||
141 | static int write_caches_in_use = 0; | 144 | static int write_caches_in_use = 0; |
142 | 145 | ||
143 | #ifdef USE_ECC_CORRECTION | ||
144 | static unsigned int ecc_sectors_corrected = 0; | ||
145 | static unsigned int ecc_bits_corrected = 0; | ||
146 | static unsigned int ecc_fail_count = 0; | ||
147 | #endif | ||
148 | |||
149 | 146 | ||
150 | /* Conversion functions */ | 147 | /* Conversion functions */ |
151 | 148 | ||
@@ -315,7 +312,7 @@ static void nand_read_uid(int bank, unsigned int* uid_buf) | |||
315 | } | 312 | } |
316 | 313 | ||
317 | 314 | ||
318 | static void nand_read_raw(int bank, int row, int column, int size, void* buf) | 315 | static void nand_setup_read(int bank, int row, int column) |
319 | { | 316 | { |
320 | int i; | 317 | int i; |
321 | 318 | ||
@@ -355,6 +352,23 @@ static void nand_read_raw(int bank, int row, int column, int size, void* buf) | |||
355 | 352 | ||
356 | /* Wait until complete */ | 353 | /* Wait until complete */ |
357 | while (!(NFC_CTRL & NFC_READY)) {}; | 354 | while (!(NFC_CTRL & NFC_READY)) {}; |
355 | } | ||
356 | |||
357 | |||
358 | static void nand_end_read(void) | ||
359 | { | ||
360 | nand_chip_select(-1); | ||
361 | |||
362 | /* Disable NFC bus clock */ | ||
363 | BCLKCTR &= ~DEV_NAND; | ||
364 | } | ||
365 | |||
366 | |||
367 | static void nand_read_raw(int bank, int row, int column, int size, void* buf) | ||
368 | { | ||
369 | int i; | ||
370 | |||
371 | nand_setup_read(bank, row, column); | ||
358 | 372 | ||
359 | /* Read data into page buffer */ | 373 | /* Read data into page buffer */ |
360 | if (((unsigned int)buf & 3) || (size & 3)) | 374 | if (((unsigned int)buf & 3) || (size & 3)) |
@@ -374,11 +388,8 @@ static void nand_read_raw(int bank, int row, int column, int size, void* buf) | |||
374 | ((unsigned int*)buf)[i] = NFC_WDATA; | 388 | ((unsigned int*)buf)[i] = NFC_WDATA; |
375 | } | 389 | } |
376 | } | 390 | } |
377 | 391 | ||
378 | nand_chip_select(-1); | 392 | nand_end_read(); |
379 | |||
380 | /* Disable NFC bus clock */ | ||
381 | BCLKCTR &= ~DEV_NAND; | ||
382 | } | 393 | } |
383 | 394 | ||
384 | 395 | ||
@@ -477,15 +488,106 @@ static void nand_get_chip_info(void) | |||
477 | static bool nand_read_sector_of_phys_page(int bank, int page, | 488 | static bool nand_read_sector_of_phys_page(int bank, int page, |
478 | int sector, void* buf) | 489 | int sector, void* buf) |
479 | { | 490 | { |
480 | #ifndef USE_ECC_CORRECTION | 491 | bool ret = true; |
481 | nand_read_raw(bank, page, | 492 | int i; |
482 | sector * (SECTOR_SIZE+16), | 493 | int page_offset = sector * (SECTOR_SIZE + 16); |
483 | SECTOR_SIZE, buf); | 494 | |
484 | return true; | 495 | #ifdef USE_ECC_CORRECTION |
485 | #else | 496 | unsigned long spare_buf[4]; |
486 | /* Not yet implemented */ | 497 | |
487 | return false; | 498 | /* Set up the ECC controller to monitor reads from NFC_WDATA */ |
499 | BCLKCTR |= DEV_ECC; | ||
500 | ECC_BASE = (unsigned long)&NFC_WDATA; | ||
501 | ECC_CTRL |= ECC_M4EN; | ||
502 | ECC_CTRL &= ~ECC_ENC; | ||
503 | ECC_CTRL |= ECC_READY; | ||
504 | ECC_CLR = 0; | ||
488 | #endif | 505 | #endif |
506 | |||
507 | /* Read the sector data */ | ||
508 | nand_setup_read(bank, page, page_offset); | ||
509 | |||
510 | /* Read data into page buffer */ | ||
511 | if ((unsigned int)buf & 3) | ||
512 | { | ||
513 | /* If unaligned, read into a temporary buffer and copy to destination. | ||
514 | This way, reads are always done through NFC_WDATA - otherwise they | ||
515 | would not be 'seen' by the ECC controller. */ | ||
516 | static char temp_buf[SECTOR_SIZE]; | ||
517 | |||
518 | unsigned int* ptr = (unsigned int*) temp_buf; | ||
519 | |||
520 | for (i = 0; i < (SECTOR_SIZE/4); i++) | ||
521 | { | ||
522 | *ptr++ = NFC_WDATA; | ||
523 | } | ||
524 | |||
525 | memcpy(buf, temp_buf, SECTOR_SIZE); | ||
526 | } | ||
527 | else | ||
528 | { | ||
529 | /* Use straight word copy as buffer and size are both word-aligned */ | ||
530 | unsigned int* ptr = (unsigned int*) buf; | ||
531 | |||
532 | for (i = 0; i < (SECTOR_SIZE/4); i++) | ||
533 | { | ||
534 | *ptr++ = NFC_WDATA; | ||
535 | } | ||
536 | } | ||
537 | |||
538 | #ifdef USE_ECC_CORRECTION | ||
539 | /* Stop monitoring before we read the OOB data */ | ||
540 | ECC_CTRL &= ~ECC_M4EN; | ||
541 | BCLKCTR &= ~DEV_ECC; | ||
542 | |||
543 | /* Read a further 4 words (sector OOB data) */ | ||
544 | spare_buf[0] = NFC_WDATA; | ||
545 | spare_buf[1] = NFC_WDATA; | ||
546 | spare_buf[2] = NFC_WDATA; | ||
547 | spare_buf[3] = NFC_WDATA; | ||
548 | |||
549 | /* Calculate MLC4 ECC using bytes 0,1,8-15 */ | ||
550 | BCLKCTR |= DEV_ECC; | ||
551 | ECC_CTRL |= ECC_M4EN; | ||
552 | |||
553 | MLC_ECC0W = *(unsigned short*)spare_buf; | ||
554 | MLC_ECC1W = spare_buf[2]; | ||
555 | MLC_ECC2W = spare_buf[3]; | ||
556 | |||
557 | while (!(ECC_CTRL & ECC_READY)) {}; | ||
558 | |||
559 | int errors = ECC_ERR_NUM & 7; | ||
560 | |||
561 | switch (errors) | ||
562 | { | ||
563 | case 4: /* nothing to correct */ | ||
564 | break; | ||
565 | |||
566 | case 7: /* fail, can't correct */ | ||
567 | ret = false; | ||
568 | break; | ||
569 | |||
570 | default: /* between 1 and 4 errors */ | ||
571 | { | ||
572 | int i; | ||
573 | unsigned char* char_buf = (unsigned char*)buf; | ||
574 | |||
575 | for (i = 0; i < errors + 1; i++) | ||
576 | { | ||
577 | int offset = 0x207 - ECC_ERRADDR(i); | ||
578 | char_buf[offset] ^= ECC_ERRDATA(i); | ||
579 | } | ||
580 | } | ||
581 | } | ||
582 | |||
583 | /* Disable ECC block */ | ||
584 | ECC_CTRL &= ~ECC_M4EN; | ||
585 | BCLKCTR &= ~DEV_ECC; | ||
586 | #endif | ||
587 | |||
588 | nand_end_read(); | ||
589 | |||
590 | return ret; | ||
489 | } | 591 | } |
490 | 592 | ||
491 | 593 | ||