summaryrefslogtreecommitdiff
path: root/firmware/target/arm/s5l8700/ipodnano2g/nand-nano2g.c
diff options
context:
space:
mode:
authorMichael Sparmann <theseven@rockbox.org>2010-03-13 00:43:34 +0000
committerMichael Sparmann <theseven@rockbox.org>2010-03-13 00:43:34 +0000
commit131bb698ada664a49e0a548b515b14733914654e (patch)
treeea3558892078fd667e43d55b739b0bc78b1f7d4f /firmware/target/arm/s5l8700/ipodnano2g/nand-nano2g.c
parenta4caff91f9e3aed8f512d51ca9012a220d4abdef (diff)
downloadrockbox-131bb698ada664a49e0a548b515b14733914654e.tar.gz
rockbox-131bb698ada664a49e0a548b515b14733914654e.zip
Revert r25099, r25101, r25109 and r25137 for now. This doesn't seem to be quite stable on some NAND types yet.
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@25139 a1c6a512-1295-4272-9138-f99709370657
Diffstat (limited to 'firmware/target/arm/s5l8700/ipodnano2g/nand-nano2g.c')
-rw-r--r--firmware/target/arm/s5l8700/ipodnano2g/nand-nano2g.c261
1 files changed, 33 insertions, 228 deletions
diff --git a/firmware/target/arm/s5l8700/ipodnano2g/nand-nano2g.c b/firmware/target/arm/s5l8700/ipodnano2g/nand-nano2g.c
index 687a3179f9..3b5f88d3c2 100644
--- a/firmware/target/arm/s5l8700/ipodnano2g/nand-nano2g.c
+++ b/firmware/target/arm/s5l8700/ipodnano2g/nand-nano2g.c
@@ -89,7 +89,6 @@ uint8_t nand_tunk2[4];
89uint8_t nand_tunk3[4]; 89uint8_t nand_tunk3[4];
90uint32_t nand_type[4]; 90uint32_t nand_type[4];
91int nand_powered = 0; 91int nand_powered = 0;
92int nand_sequential = 0;
93long nand_last_activity_value = -1; 92long nand_last_activity_value = -1;
94static long nand_stack[32]; 93static long nand_stack[32];
95 94
@@ -100,14 +99,13 @@ static struct wakeup ecc_wakeup;
100 99
101static uint8_t nand_data[0x800] __attribute__((aligned(16))); 100static uint8_t nand_data[0x800] __attribute__((aligned(16)));
102static uint8_t nand_ctrl[0x200] __attribute__((aligned(16))); 101static uint8_t nand_ctrl[0x200] __attribute__((aligned(16)));
103static uint8_t nand_spare[4][0x40] __attribute__((aligned(16))); 102static uint8_t nand_spare[0x40] __attribute__((aligned(16)));
104static uint8_t nand_ecc[0x30] __attribute__((aligned(16))); 103static uint8_t nand_ecc[0x30] __attribute__((aligned(16)));
105 104
106 105
107uint32_t nand_unlock(uint32_t rc) 106uint32_t nand_unlock(uint32_t rc)
108{ 107{
109 led(false); 108 led(false);
110 nand_last_activity_value = current_tick;
111 mutex_unlock(&nand_mtx); 109 mutex_unlock(&nand_mtx);
112 return rc; 110 return rc;
113} 111}
@@ -216,9 +214,10 @@ uint32_t nand_wait_status_ready(uint32_t bank)
216 return nand_send_cmd(NAND_CMD_READ); 214 return nand_send_cmd(NAND_CMD_READ);
217} 215}
218 216
219void nand_transfer_data_start(uint32_t bank, uint32_t direction, 217uint32_t nand_transfer_data(uint32_t bank, uint32_t direction,
220 void* buffer, uint32_t size) 218 void* buffer, uint32_t size)
221{ 219{
220 long timeout = current_tick + HZ / 50;
222 nand_set_fmctrl0(bank, FMCTRL0_ENABLEDMA); 221 nand_set_fmctrl0(bank, FMCTRL0_ENABLEDMA);
223 FMDNUM = size - 1; 222 FMDNUM = size - 1;
224 FMCTRL1 = FMCTRL1_DOREADDATA << direction; 223 FMCTRL1 = FMCTRL1_DOREADDATA << direction;
@@ -232,11 +231,6 @@ void nand_transfer_data_start(uint32_t bank, uint32_t direction,
232 DMATCNT3 = (size >> 4) - 1; 231 DMATCNT3 = (size >> 4) - 1;
233 clean_dcache(); 232 clean_dcache();
234 DMACOM3 = 4; 233 DMACOM3 = 4;
235}
236
237uint32_t nand_transfer_data_collect(uint32_t direction)
238{
239 long timeout = current_tick + HZ / 50;
240 while ((DMAALLST & DMAALLST_DMABUSY3)) 234 while ((DMAALLST & DMAALLST_DMABUSY3))
241 if (nand_timeout(timeout)) return 1; 235 if (nand_timeout(timeout)) return 1;
242 if (!direction) invalidate_dcache(); 236 if (!direction) invalidate_dcache();
@@ -246,29 +240,17 @@ uint32_t nand_transfer_data_collect(uint32_t direction)
246 return 0; 240 return 0;
247} 241}
248 242
249uint32_t nand_transfer_data(uint32_t bank, uint32_t direction, 243uint32_t ecc_decode(uint32_t size, void* databuffer, void* sparebuffer)
250 void* buffer, uint32_t size)
251{
252 nand_transfer_data_start(bank, direction, buffer, size);
253 uint32_t rc = nand_transfer_data_collect(direction);
254 return rc;
255}
256
257void ecc_start(uint32_t size, void* databuffer, void* sparebuffer, uint32_t type)
258{ 244{
259 mutex_lock(&ecc_mtx); 245 mutex_lock(&ecc_mtx);
246 long timeout = current_tick + HZ / 50;
260 ECC_INT_CLR = 1; 247 ECC_INT_CLR = 1;
261 SRCPND = INTMSK_ECC; 248 SRCPND = INTMSK_ECC;
262 ECC_UNK1 = size; 249 ECC_UNK1 = size;
263 ECC_DATA_PTR = (uint32_t)databuffer; 250 ECC_DATA_PTR = (uint32_t)databuffer;
264 ECC_SPARE_PTR = (uint32_t)sparebuffer; 251 ECC_SPARE_PTR = (uint32_t)sparebuffer;
265 clean_dcache(); 252 clean_dcache();
266 ECC_CTRL = type; 253 ECC_CTRL = ECCCTRL_STARTDECODING;
267}
268
269uint32_t ecc_collect(void)
270{
271 long timeout = current_tick + HZ / 50;
272 while (!(SRCPND & INTMSK_ECC)) 254 while (!(SRCPND & INTMSK_ECC))
273 if (nand_timeout(timeout)) return ecc_unlock(1); 255 if (nand_timeout(timeout)) return ecc_unlock(1);
274 invalidate_dcache(); 256 invalidate_dcache();
@@ -277,18 +259,23 @@ uint32_t ecc_collect(void)
277 return ecc_unlock(ECC_RESULT); 259 return ecc_unlock(ECC_RESULT);
278} 260}
279 261
280uint32_t ecc_decode(uint32_t size, void* databuffer, void* sparebuffer)
281{
282 ecc_start(size, databuffer, sparebuffer, ECCCTRL_STARTDECODING);
283 uint32_t rc = ecc_collect();
284 return rc;
285}
286
287uint32_t ecc_encode(uint32_t size, void* databuffer, void* sparebuffer) 262uint32_t ecc_encode(uint32_t size, void* databuffer, void* sparebuffer)
288{ 263{
289 ecc_start(size, databuffer, sparebuffer, ECCCTRL_STARTENCODING); 264 mutex_lock(&ecc_mtx);
290 ecc_collect(); 265 long timeout = current_tick + HZ / 50;
291 return 0; 266 ECC_INT_CLR = 1;
267 SRCPND = INTMSK_ECC;
268 ECC_UNK1 = size;
269 ECC_DATA_PTR = (uint32_t)databuffer;
270 ECC_SPARE_PTR = (uint32_t)sparebuffer;
271 clean_dcache();
272 ECC_CTRL = ECCCTRL_STARTENCODING;
273 while (!(SRCPND & INTMSK_ECC))
274 if (nand_timeout(timeout)) return ecc_unlock(1);
275 invalidate_dcache();
276 ECC_INT_CLR = 1;
277 SRCPND = INTMSK_ECC;
278 return ecc_unlock(0);
292} 279}
293 280
294uint32_t nand_check_empty(uint8_t* buffer) 281uint32_t nand_check_empty(uint8_t* buffer)
@@ -384,7 +371,7 @@ uint32_t nand_read_page(uint32_t bank, uint32_t page, void* databuffer,
384 uint32_t checkempty) 371 uint32_t checkempty)
385{ 372{
386 uint8_t* data = nand_data; 373 uint8_t* data = nand_data;
387 uint8_t* spare = nand_spare[0]; 374 uint8_t* spare = nand_spare;
388 if (databuffer && !((uint32_t)databuffer & 0xf)) 375 if (databuffer && !((uint32_t)databuffer & 0xf))
389 data = (uint8_t*)databuffer; 376 data = (uint8_t*)databuffer;
390 if (sparebuffer && !((uint32_t)sparebuffer & 0xf)) 377 if (sparebuffer && !((uint32_t)sparebuffer & 0xf))
@@ -441,11 +428,11 @@ uint32_t nand_read_page(uint32_t bank, uint32_t page, void* databuffer,
441 return nand_unlock(rc); 428 return nand_unlock(rc);
442} 429}
443 430
444uint32_t nand_write_page_int(uint32_t bank, uint32_t page, void* databuffer, 431uint32_t nand_write_page(uint32_t bank, uint32_t page, void* databuffer,
445 void* sparebuffer, uint32_t doecc, uint32_t wait) 432 void* sparebuffer, uint32_t doecc)
446{ 433{
447 uint8_t* data = nand_data; 434 uint8_t* data = nand_data;
448 uint8_t* spare = nand_spare[0]; 435 uint8_t* spare = nand_spare;
449 if (databuffer && !((uint32_t)databuffer & 0xf)) 436 if (databuffer && !((uint32_t)databuffer & 0xf))
450 data = (uint8_t*)databuffer; 437 data = (uint8_t*)databuffer;
451 if (sparebuffer && !((uint32_t)sparebuffer & 0xf)) 438 if (sparebuffer && !((uint32_t)sparebuffer & 0xf))
@@ -459,14 +446,9 @@ uint32_t nand_write_page_int(uint32_t bank, uint32_t page, void* databuffer,
459 if (spare != sparebuffer) memcpy(spare, sparebuffer, 0x40); 446 if (spare != sparebuffer) memcpy(spare, sparebuffer, 0x40);
460 } 447 }
461 else memset(spare, 0xFF, 0x40); 448 else memset(spare, 0xFF, 0x40);
462 nand_set_fmctrl0(bank, FMCTRL0_ENABLEDMA);
463 if (nand_send_cmd(NAND_CMD_PROGRAM)) return nand_unlock(1);
464 if (nand_send_address(page, databuffer ? 0 : 0x800))
465 return nand_unlock(1);
466 if (databuffer && data != databuffer) memcpy(data, databuffer, 0x800);
467 if (databuffer) nand_transfer_data_start(bank, 1, data, 0x800);
468 if (doecc) 449 if (doecc)
469 { 450 {
451 if (databuffer && data != databuffer) memcpy(data, databuffer, 0x800);
470 if (ecc_encode(3, data, nand_ecc)) return nand_unlock(1); 452 if (ecc_encode(3, data, nand_ecc)) return nand_unlock(1);
471 memcpy(&spare[0xC], nand_ecc, 0x28); 453 memcpy(&spare[0xC], nand_ecc, 0x28);
472 memset(nand_ctrl, 0xFF, 0x200); 454 memset(nand_ctrl, 0xFF, 0x200);
@@ -474,15 +456,18 @@ uint32_t nand_write_page_int(uint32_t bank, uint32_t page, void* databuffer,
474 if (ecc_encode(0, nand_ctrl, nand_ecc)) return nand_unlock(1); 456 if (ecc_encode(0, nand_ctrl, nand_ecc)) return nand_unlock(1);
475 memcpy(&spare[0x34], nand_ecc, 0xC); 457 memcpy(&spare[0x34], nand_ecc, 0xC);
476 } 458 }
459 nand_set_fmctrl0(bank, FMCTRL0_ENABLEDMA);
460 if (nand_send_cmd(NAND_CMD_PROGRAM)) return nand_unlock(1);
461 if (nand_send_address(page, databuffer ? 0 : 0x800))
462 return nand_unlock(1);
477 if (databuffer) 463 if (databuffer)
478 if (nand_transfer_data_collect(1)) 464 if (nand_transfer_data(bank, 1, data, 0x800))
479 return nand_unlock(1); 465 return nand_unlock(1);
480 if (sparebuffer || doecc) 466 if (sparebuffer || doecc)
481 if (nand_transfer_data(bank, 1, spare, 0x40)) 467 if (nand_transfer_data(bank, 1, spare, 0x40))
482 return nand_unlock(1); 468 return nand_unlock(1);
483 if (nand_send_cmd(NAND_CMD_PROGCNFRM)) return nand_unlock(1); 469 if (nand_send_cmd(NAND_CMD_PROGCNFRM)) return nand_unlock(1);
484 if (wait) if (nand_wait_status_ready(bank)) return nand_unlock(1); 470 return nand_unlock(nand_wait_status_ready(bank));
485 return nand_unlock(0);
486} 471}
487 472
488uint32_t nand_block_erase(uint32_t bank, uint32_t page) 473uint32_t nand_block_erase(uint32_t bank, uint32_t page)
@@ -502,185 +487,6 @@ uint32_t nand_block_erase(uint32_t bank, uint32_t page)
502 return nand_unlock(0); 487 return nand_unlock(0);
503} 488}
504 489
505uint32_t nand_read_page_fast(uint32_t page, void* databuffer,
506 void* sparebuffer, uint32_t doecc,
507 uint32_t checkempty)
508{
509 uint32_t i, rc = 0;
510 if (((uint32_t)databuffer & 0xf) || ((uint32_t)sparebuffer & 0xf)
511 || !databuffer || !sparebuffer || !doecc)
512 {
513 for (i = 0; i < 4; i++)
514 {
515 if (nand_type[i] == 0xFFFFFFFF) continue;
516 void* databuf = (void*)0;
517 void* sparebuf = (void*)0;
518 if (databuffer) databuf = (void*)((uint32_t)databuffer + 0x800 * i);
519 if (sparebuffer) sparebuf = (void*)((uint32_t)sparebuffer + 0x40 * i);
520 uint32_t ret = nand_read_page(i, page, databuf, sparebuf, doecc, checkempty);
521 if (ret & 1) rc |= 1 << (i << 2);
522 if (ret & 2) rc |= 2 << (i << 2);
523 if (ret & 0x10) rc |= 4 << (i << 2);
524 if (ret & 0x100) rc |= 8 << (i << 2);
525 }
526 return rc;
527 }
528 mutex_lock(&nand_mtx);
529 nand_last_activity_value = current_tick;
530 led(true);
531 if (!nand_powered) nand_power_up();
532 uint8_t status[4];
533 for (i = 0; i < 4; i++) status[i] = (nand_type[i] == 0xFFFFFFFF);
534 if (!status[0])
535 {
536 nand_set_fmctrl0(0, FMCTRL0_ENABLEDMA);
537 if (nand_send_cmd(NAND_CMD_READ))
538 status[0] = 1;
539 }
540 if (!status[0])
541 if (nand_send_address(page, 0))
542 status[0] = 1;
543 if (!status[0])
544 if (nand_send_cmd(NAND_CMD_READ2))
545 status[0] = 1;
546 if (!status[0])
547 if (nand_wait_status_ready(0))
548 status[0] = 1;
549 if (!status[0])
550 if (nand_transfer_data(0, 0, databuffer, 0x800))
551 status[0] = 1;
552 if (!status[0])
553 if (nand_transfer_data(0, 0, sparebuffer, 0x40))
554 status[0] = 1;
555 for (i = 1; i < 4; i++)
556 {
557 if (!status[i])
558 {
559 nand_set_fmctrl0(i, FMCTRL0_ENABLEDMA);
560 if (nand_send_cmd(NAND_CMD_READ))
561 status[i] = 1;
562 }
563 if (!status[i])
564 if (nand_send_address(page, 0))
565 status[i] = 1;
566 if (!status[i])
567 if (nand_send_cmd(NAND_CMD_READ2))
568 status[i] = 1;
569 if (!status[i])
570 if (nand_wait_status_ready(i))
571 status[i] = 1;
572 if (!status[i])
573 nand_transfer_data_start(i, 0, (void*)((uint32_t)databuffer
574 + 0x800 * i), 0x800);
575 if (!status[i - 1])
576 {
577 memcpy(nand_ecc, (void*)((uint32_t)sparebuffer + 0x40 * (i - 1) + 0xC), 0x28);
578 ecc_start(3, (void*)((uint32_t)databuffer
579 + 0x800 * (i - 1)), nand_ecc, ECCCTRL_STARTDECODING);
580 }
581 if (!status[i])
582 if (nand_transfer_data_collect(0))
583 status[i] = 1;
584 if (!status[i])
585 nand_transfer_data_start(i, 0, (void*)((uint32_t)sparebuffer
586 + 0x40 * i), 0x40);
587 if (!status[i - 1])
588 if (ecc_collect() & 1)
589 status[i - 1] = 4;
590 if (!status[i - 1])
591 {
592 memset(nand_ctrl, 0xFF, 0x200);
593 memcpy(nand_ctrl, (void*)((uint32_t)sparebuffer + 0x40 * (i - 1)), 0xC);
594 memcpy(nand_ecc, (void*)((uint32_t)sparebuffer + 0x40 * (i - 1) + 0x34), 0xC);
595 ecc_start(0, nand_ctrl, nand_ecc, ECCCTRL_STARTDECODING);
596 }
597 if (!status[i])
598 if (nand_transfer_data_collect(0))
599 status[i] = 1;
600 if (!status[i - 1])
601 {
602 if (ecc_collect() & 1)
603 {
604 status[i - 1] |= 8;
605 memset((void*)((uint32_t)sparebuffer + 0x40 * (i - 1)), 0xFF, 0xC);
606 }
607 else memcpy((void*)((uint32_t)sparebuffer + 0x40 * (i - 1)), nand_ctrl, 0xC);
608 if (checkempty)
609 status[i - 1] |= nand_check_empty((void*)((uint32_t)sparebuffer
610 + 0x40 * (i - 1))) << 1;
611 }
612 }
613 if (!status[i - 1])
614 {
615 memcpy(nand_ecc,(void*)((uint32_t)sparebuffer + 0x40 * (i - 1) + 0xC), 0x28);
616 if (ecc_decode(3, (void*)((uint32_t)databuffer
617 + 0x800 * (i - 1)), nand_ecc) & 1)
618 status[i - 1] = 4;
619 }
620 if (!status[i - 1])
621 {
622 memset(nand_ctrl, 0xFF, 0x200);
623 memcpy(nand_ctrl, (void*)((uint32_t)sparebuffer + 0x40 * (i - 1)), 0xC);
624 memcpy(nand_ecc, (void*)((uint32_t)sparebuffer + 0x40 * (i - 1) + 0x34), 0xC);
625 if (ecc_decode(0, nand_ctrl, nand_ecc) & 1)
626 {
627 status[i - 1] |= 8;
628 memset((void*)((uint32_t)sparebuffer + 0x40 * (i - 1)), 0xFF, 0xC);
629 }
630 else memcpy((void*)((uint32_t)sparebuffer + 0x40 * (i - 1)), nand_ctrl, 0xC);
631 if (checkempty)
632 status[i - 1] |= nand_check_empty((void*)((uint32_t)sparebuffer
633 + 0x40 * (i - 1))) << 1;
634 }
635 for (i = 0; i < 4; i++)
636 if (nand_type[i] != 0xFFFFFFFF)
637 rc |= status[i] << (i << 2);
638 return nand_unlock(rc);
639}
640
641uint32_t nand_write_page(uint32_t bank, uint32_t page, void* databuffer,
642 void* sparebuffer, uint32_t doecc)
643{
644 return nand_write_page_int(bank, page, databuffer, sparebuffer, doecc, 1);
645}
646
647uint32_t nand_write_page_start(uint32_t bank, uint32_t page, void* databuffer,
648 void* sparebuffer, uint32_t doecc)
649{
650 if (((uint32_t)databuffer & 0xf) || ((uint32_t)sparebuffer & 0xf)
651 || !databuffer || !sparebuffer || !doecc || nand_sequential)
652 return nand_write_page_int(bank, page, databuffer, sparebuffer, doecc, nand_sequential);
653
654 mutex_lock(&nand_mtx);
655 nand_last_activity_value = current_tick;
656 led(true);
657 if (!nand_powered) nand_power_up();
658 nand_set_fmctrl0(bank, FMCTRL0_ENABLEDMA);
659 if (nand_send_cmd(NAND_CMD_PROGRAM))
660 return nand_unlock(1);
661 if (nand_send_address(page, 0))
662 return nand_unlock(1);
663 nand_transfer_data_start(bank, 1, databuffer, 0x800);
664 if (ecc_encode(3, databuffer, nand_ecc))
665 return nand_unlock(1);
666 memcpy((void*)((uint32_t)sparebuffer + 0xC), nand_ecc, 0x28);
667 memset(nand_ctrl, 0xFF, 0x200);
668 memcpy(nand_ctrl, sparebuffer, 0xC);
669 if (ecc_encode(0, nand_ctrl, nand_ecc))
670 return nand_unlock(1);
671 memcpy((void*)((uint32_t)sparebuffer + 0x34), nand_ecc, 0xC);
672 if (nand_transfer_data_collect(0))
673 return nand_unlock(1);
674 if (nand_transfer_data(bank, 1, sparebuffer, 0x40))
675 return nand_unlock(1);
676 return nand_unlock(nand_send_cmd(NAND_CMD_PROGCNFRM));
677}
678
679uint32_t nand_write_page_collect(uint32_t bank)
680{
681 return nand_wait_status_ready(bank);
682}
683
684const struct nand_device_info_type* nand_get_device_type(uint32_t bank) 490const struct nand_device_info_type* nand_get_device_type(uint32_t bank)
685{ 491{
686 if (nand_type[bank] == 0xFFFFFFFF) 492 if (nand_type[bank] == 0xFFFFFFFF)
@@ -739,7 +545,6 @@ uint32_t nand_device_init(void)
739 nand_tunk3[i] = nand_deviceinfotable[nand_type[i]].tunk3; 545 nand_tunk3[i] = nand_deviceinfotable[nand_type[i]].tunk3;
740 } 546 }
741 if (nand_type[0] == 0xFFFFFFFF) return 1; 547 if (nand_type[0] == 0xFFFFFFFF) return 1;
742 nand_sequential = !((nand_type[0] >> 22) & 1);
743 548
744 nand_last_activity_value = current_tick; 549 nand_last_activity_value = current_tick;
745 create_thread(nand_thread, nand_stack, 550 create_thread(nand_thread, nand_stack,