summaryrefslogtreecommitdiff
path: root/firmware
diff options
context:
space:
mode:
Diffstat (limited to 'firmware')
-rw-r--r--firmware/export/tcc77x.h78
-rw-r--r--firmware/export/tcc780x.h24
-rw-r--r--firmware/target/arm/ata-nand-telechips.c144
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 */
37int ata_spinup_time = 0; 40int ata_spinup_time = 0;
@@ -140,12 +143,6 @@ static struct write_cache write_caches[MAX_WRITE_CACHES];
140 143
141static int write_caches_in_use = 0; 144static int write_caches_in_use = 0;
142 145
143#ifdef USE_ECC_CORRECTION
144static unsigned int ecc_sectors_corrected = 0;
145static unsigned int ecc_bits_corrected = 0;
146static 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
318static void nand_read_raw(int bank, int row, int column, int size, void* buf) 315static 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
358static void nand_end_read(void)
359{
360 nand_chip_select(-1);
361
362 /* Disable NFC bus clock */
363 BCLKCTR &= ~DEV_NAND;
364}
365
366
367static 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)
477static bool nand_read_sector_of_phys_page(int bank, int page, 488static 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