diff options
Diffstat (limited to 'firmware/target/mips/ingenic_jz47xx/ata-nand-jz4740.c')
-rw-r--r-- | firmware/target/mips/ingenic_jz47xx/ata-nand-jz4740.c | 167 |
1 files changed, 126 insertions, 41 deletions
diff --git a/firmware/target/mips/ingenic_jz47xx/ata-nand-jz4740.c b/firmware/target/mips/ingenic_jz47xx/ata-nand-jz4740.c index 851472bf62..c9ca85cfaf 100644 --- a/firmware/target/mips/ingenic_jz47xx/ata-nand-jz4740.c +++ b/firmware/target/mips/ingenic_jz47xx/ata-nand-jz4740.c | |||
@@ -85,21 +85,20 @@ struct nand_param | |||
85 | * | 85 | * |
86 | */ | 86 | */ |
87 | 87 | ||
88 | #define NAND_DATAPORT 0xB8000000 | 88 | static volatile unsigned long nand_address; |
89 | #define NAND_ADDRPORT 0xB8010000 | 89 | #define NAND_DATAPORT (nand_address) |
90 | #define NAND_COMMPORT 0xB8008000 | 90 | #define NAND_ADDRPORT (nand_address+0x10000) |
91 | #define NAND_COMMPORT (nand_address+0x08000) | ||
91 | 92 | ||
92 | #define ECC_BLOCK 512 | 93 | #define ECC_BLOCK 512 |
93 | #define ECC_POS 6 | 94 | #define ECC_POS 6 |
94 | #define PAR_SIZE 9 | 95 | #define PAR_SIZE 9 |
95 | 96 | ||
96 | #define __nand_cmd(n) (REG8(NAND_COMMPORT) = (n)) | 97 | #define __nand_cmd(n) (REG8(NAND_COMMPORT) = (n)) |
97 | #define __nand_addr(n) (REG8(NAND_ADDRPORT) = (n)) | 98 | #define __nand_addr(n) (REG8(NAND_ADDRPORT) = (n)) |
98 | #define __nand_data8() (REG8(NAND_DATAPORT)) | 99 | #define __nand_data8() (REG8(NAND_DATAPORT)) |
99 | #define __nand_data16() (REG16(NAND_DATAPORT)) | 100 | #define __nand_data16() (REG16(NAND_DATAPORT)) |
100 | 101 | ||
101 | #define __nand_enable() (REG_EMC_NFCSR |= EMC_NFCSR_NFE1 | EMC_NFCSR_NFCE1) | ||
102 | #define __nand_disable() (REG_EMC_NFCSR &= ~(EMC_NFCSR_NFCE1)) | ||
103 | #define __nand_ecc_rs_encoding() \ | 102 | #define __nand_ecc_rs_encoding() \ |
104 | (REG_EMC_NFECR = EMC_NFECR_ECCE | EMC_NFECR_ERST | EMC_NFECR_RS | EMC_NFECR_RS_ENCODING) | 103 | (REG_EMC_NFECR = EMC_NFECR_ECCE | EMC_NFECR_ERST | EMC_NFECR_RS | EMC_NFECR_RS_ENCODING) |
105 | #define __nand_ecc_rs_decoding() \ | 104 | #define __nand_ecc_rs_decoding() \ |
@@ -111,6 +110,9 @@ struct nand_param | |||
111 | /*--------------------------------------------------------------*/ | 110 | /*--------------------------------------------------------------*/ |
112 | 111 | ||
113 | static struct nand_info* chip_info = NULL; | 112 | static struct nand_info* chip_info = NULL; |
113 | static struct nand_info* banks[4]; | ||
114 | static unsigned int nr_banks = 1; | ||
115 | static unsigned long bank_size; | ||
114 | static struct nand_param internal_param; | 116 | static struct nand_param internal_param; |
115 | #ifdef USE_DMA | 117 | #ifdef USE_DMA |
116 | static struct mutex nand_mtx; | 118 | static struct mutex nand_mtx; |
@@ -344,6 +346,9 @@ static int jz_nand_read_page(unsigned long page_addr, unsigned char *dst) | |||
344 | int i, j; | 346 | int i, j; |
345 | unsigned char *data_buf; | 347 | unsigned char *data_buf; |
346 | unsigned char oob_buf[nandp->oob_size]; | 348 | unsigned char oob_buf[nandp->oob_size]; |
349 | |||
350 | if(nand_address == 0) | ||
351 | return -1; | ||
347 | 352 | ||
348 | page_size = nandp->page_size; | 353 | page_size = nandp->page_size; |
349 | oob_size = nandp->oob_size; | 354 | oob_size = nandp->oob_size; |
@@ -463,44 +468,112 @@ static int jz_nand_read_page(unsigned long page_addr, unsigned char *dst) | |||
463 | } | 468 | } |
464 | 469 | ||
465 | /* | 470 | /* |
471 | * Disable NAND controller | ||
472 | */ | ||
473 | static void jz_nand_disable(void) | ||
474 | { | ||
475 | REG_EMC_NFCSR &= ~(EMC_NFCSR_NFCE1 | EMC_NFCSR_NFCE2 | | ||
476 | EMC_NFCSR_NFCE3 | EMC_NFCSR_NFCE4 | | ||
477 | EMC_NFCSR_NFE1 | EMC_NFCSR_NFE2 | | ||
478 | EMC_NFCSR_NFE3 | EMC_NFCSR_NFE4 ); | ||
479 | } | ||
480 | |||
481 | /* | ||
466 | * Enable NAND controller | 482 | * Enable NAND controller |
467 | */ | 483 | */ |
468 | static void jz_nand_enable(void) | 484 | static void jz_nand_enable(void) |
485 | { | ||
486 | #if 0 | ||
487 | /* OF RE */ | ||
488 | REG_GPIO_PXFUNS(1) = 0x1E018000; // __gpio_as_func0() start | ||
489 | REG_GPIO_PXSELC(1) = 0x1E018000; // __gpio_as_func0() end | ||
490 | |||
491 | REG_GPIO_PXFUNS(2) = 0x3000<<16; // __gpio_as_func0() start | ||
492 | REG_GPIO_PXSELC(2) = 0x3000<<16; // __gpio_as_func0() end | ||
493 | |||
494 | REG_GPIO_PXFUNC(2) = 0x4000<<16; // __gpio_port_as_input() start | ||
495 | REG_GPIO_PXSELC(2) = 0x4000<<16; | ||
496 | REG_GPIO_PXDIRC(2) = 0x4000<<16; // __gpio_port_as_input() end | ||
497 | REG_GPIO_PXPES(2) = 0x4000<<16; // __gpio_disable_pull() | ||
498 | |||
499 | REG_GPIO_PXFUNS(1) = 0x40<<16; // __gpio_as_func0() start | ||
500 | REG_GPIO_PXSELC(1) = 0x40<<16; // __gpio_as_func0() end | ||
501 | |||
502 | REG_EMC_SMCR1 = (REG_EMC_SMCR1 & 0xFF) | 0x4621200; | ||
503 | REG_EMC_SMCR2 = (REG_EMC_SMCR2 & 0xFF) | 0x4621200; | ||
504 | REG_EMC_SMCR3 = (REG_EMC_SMCR3 & 0xFF) | 0x4621200; | ||
505 | REG_EMC_SMCR4 = (REG_EMC_SMCR4 & 0xFF) | 0x4621200; | ||
506 | |||
507 | REG_EMC_SMCR1 = REG_EMC_SMCR2 = REG_EMC_SMCR3 = REG_EMC_SMCR4 = 0x6621200; | ||
508 | #else | ||
509 | REG_EMC_SMCR1 = REG_EMC_SMCR2 = REG_EMC_SMCR3 = REG_EMC_SMCR4 = 0x04444400; | ||
510 | #endif | ||
511 | } | ||
512 | |||
513 | static void jz_nand_select(int bank) | ||
469 | { | 514 | { |
470 | __nand_enable(); | 515 | REG_EMC_NFCSR |= (EMC_NFCSR_NFE(bank+1) | EMC_NFCSR_NFCE(bank+1)); |
471 | 516 | ||
472 | REG_EMC_SMCR1 = 0x04444400; | 517 | switch(bank) |
518 | { | ||
519 | case 0: | ||
520 | nand_address = 0xB8000000; | ||
521 | break; | ||
522 | case 1: | ||
523 | nand_address = 0xB4000000; | ||
524 | break; | ||
525 | case 2: | ||
526 | nand_address = 0xAC000000; | ||
527 | break; | ||
528 | case 3: | ||
529 | nand_address = 0xA8000000; | ||
530 | break; | ||
531 | } | ||
473 | } | 532 | } |
474 | 533 | ||
475 | /* | 534 | static void jz_nand_deselect(int bank) |
476 | * Disable NAND controller | ||
477 | */ | ||
478 | static void jz_nand_disable(void) | ||
479 | { | 535 | { |
480 | __nand_disable(); | 536 | REG_EMC_NFCSR &= ~(EMC_NFCSR_NFE(bank+1) | EMC_NFCSR_NFCE(bank+1)); |
537 | nand_address = 0; | ||
481 | } | 538 | } |
482 | 539 | ||
483 | static int jz_nand_init(void) | 540 | static int jz_nand_init(void) |
484 | { | 541 | { |
485 | unsigned char cData[5]; | 542 | unsigned char cData[5]; |
543 | int i; | ||
486 | 544 | ||
487 | jz_nand_enable(); | 545 | jz_nand_enable(); |
488 | 546 | ||
489 | __nand_cmd(NAND_CMD_READID); | 547 | for(i=0; i<4; i++) |
490 | __nand_addr(NAND_CMD_READ0); | ||
491 | cData[0] = __nand_data8(); | ||
492 | cData[1] = __nand_data8(); | ||
493 | cData[2] = __nand_data8(); | ||
494 | cData[3] = __nand_data8(); | ||
495 | cData[4] = __nand_data8(); | ||
496 | |||
497 | chip_info = nand_identify(cData); | ||
498 | if(chip_info == NULL) | ||
499 | { | 548 | { |
500 | panicf("Unknown NAND flash chip: 0x%x 0x%x 0x%x 0x%x 0x%x", cData[0], | 549 | jz_nand_select(i); |
501 | cData[1], cData[2], cData[3], cData[4]); | 550 | |
502 | return -1; /* panicf() doesn't return though */ | 551 | __nand_cmd(NAND_CMD_READID); |
552 | __nand_addr(NAND_CMD_READ0); | ||
553 | cData[0] = __nand_data8(); | ||
554 | cData[1] = __nand_data8(); | ||
555 | cData[2] = __nand_data8(); | ||
556 | cData[3] = __nand_data8(); | ||
557 | cData[4] = __nand_data8(); | ||
558 | |||
559 | jz_nand_deselect(i); | ||
560 | |||
561 | logf("NAND chip %d: 0x%x 0x%x 0x%x 0x%x 0x%x", i+1, cData[0], cData[1], | ||
562 | cData[2], cData[3], cData[4]); | ||
563 | |||
564 | banks[i] = nand_identify(cData); | ||
565 | |||
566 | if(banks[i] != NULL) | ||
567 | nr_banks++; | ||
568 | |||
569 | if(i == 0 && banks[i] == NULL) | ||
570 | { | ||
571 | panicf("Unknown NAND flash chip: 0x%x 0x%x 0x%x 0x%x 0x%x", cData[0], | ||
572 | cData[1], cData[2], cData[3], cData[4]); | ||
573 | return -1; /* panicf() doesn't return though */ | ||
574 | } | ||
503 | } | 575 | } |
576 | chip_info = banks[0]; | ||
504 | 577 | ||
505 | internal_param.bus_width = 8; | 578 | internal_param.bus_width = 8; |
506 | internal_param.row_cycle = chip_info->row_cycles; | 579 | internal_param.row_cycle = chip_info->row_cycles; |
@@ -508,13 +581,17 @@ static int jz_nand_init(void) | |||
508 | internal_param.oob_size = chip_info->spare_size; | 581 | internal_param.oob_size = chip_info->spare_size; |
509 | internal_param.page_per_block = chip_info->pages_per_block; | 582 | internal_param.page_per_block = chip_info->pages_per_block; |
510 | 583 | ||
584 | bank_size = chip_info->page_size * chip_info->blocks_per_bank / 512 * chip_info->pages_per_block; | ||
585 | |||
586 | jz_nand_disable(); | ||
587 | |||
511 | return 0; | 588 | return 0; |
512 | } | 589 | } |
513 | 590 | ||
514 | static bool inited = false; | ||
515 | int nand_init(void) | 591 | int nand_init(void) |
516 | { | 592 | { |
517 | int res = 0; | 593 | int res = 0; |
594 | static bool inited = false; | ||
518 | 595 | ||
519 | if(!inited) | 596 | if(!inited) |
520 | { | 597 | { |
@@ -533,29 +610,37 @@ int nand_init(void) | |||
533 | 610 | ||
534 | int nand_read_sectors(IF_MV2(int drive,) unsigned long start, int count, void* buf) | 611 | int nand_read_sectors(IF_MV2(int drive,) unsigned long start, int count, void* buf) |
535 | { | 612 | { |
536 | int i, ret = 0; | 613 | int i, ret = 0, chip_size = chip_info->page_size; |
537 | 614 | ||
538 | logf("nand_read_sectors(%ld, %d, 0x%x)", start, count, (int)buf); | 615 | logf("nand_read_sectors(%ld, %d, 0x%x)", start, count, (int)buf); |
539 | 616 | ||
540 | start *= 512; | 617 | start *= 512; |
541 | count *= 512; | 618 | count *= 512; |
542 | 619 | ||
543 | if(count <= chip_info->page_size) | 620 | if(count <= chip_size) |
544 | { | 621 | { |
545 | ret = jz_nand_read_page(start/chip_info->page_size, temp_page); | 622 | jz_nand_select(start / 512 / bank_size); |
546 | memcpy(buf, temp_page+(start%chip_info->page_size), count); | 623 | |
547 | return ret; | 624 | ret = jz_nand_read_page(start/chip_size, temp_page); |
625 | memcpy(buf, temp_page+(start%chip_size), count); | ||
626 | |||
627 | jz_nand_deselect(start / 512 / bank_size); | ||
548 | } | 628 | } |
549 | else | 629 | else |
550 | { | 630 | { |
551 | for(i=0; i<count && ret==0; i+=chip_info->page_size) | 631 | for(i=0; i<count && ret==0; i+=chip_size) |
552 | { | 632 | { |
553 | ret = jz_nand_read_page((start+i)/chip_info->page_size, temp_page); | 633 | jz_nand_select((start/512+i) / bank_size); |
554 | memcpy(buf+i, temp_page+((start+i)%chip_info->page_size), | 634 | |
555 | (count-i < chip_info->page_size ? count-i : chip_info->page_size)); | 635 | ret = jz_nand_read_page((start+i)/chip_size, temp_page); |
636 | memcpy(buf+i, temp_page+((start+i)%chip_size), | ||
637 | (count-i < chip_size ? count-i : chip_size)); | ||
638 | |||
639 | jz_nand_deselect((start/512+i) / bank_size); | ||
556 | } | 640 | } |
557 | return ret; | ||
558 | } | 641 | } |
642 | |||
643 | return ret; | ||
559 | } | 644 | } |
560 | 645 | ||
561 | /* TODO */ | 646 | /* TODO */ |
@@ -605,6 +690,7 @@ void nand_enable(bool on) | |||
605 | void nand_get_info(IF_MV2(int drive,) struct storage_info *info) | 690 | void nand_get_info(IF_MV2(int drive,) struct storage_info *info) |
606 | { | 691 | { |
607 | (void)drive; | 692 | (void)drive; |
693 | |||
608 | /* firmware version */ | 694 | /* firmware version */ |
609 | info->revision="0.00"; | 695 | info->revision="0.00"; |
610 | 696 | ||
@@ -612,8 +698,7 @@ void nand_get_info(IF_MV2(int drive,) struct storage_info *info) | |||
612 | info->product="NAND Storage"; | 698 | info->product="NAND Storage"; |
613 | 699 | ||
614 | /* blocks count */ | 700 | /* blocks count */ |
615 | /* TODO: proper amount of sectors! */ | 701 | info->num_sectors = bank_size * nr_banks; |
616 | info->num_sectors = ((chip_info->page_size+chip_info->spare_size) / 512) * chip_info->pages_per_block * chip_info->blocks_per_bank; | ||
617 | info->sector_size = 512; | 702 | info->sector_size = 512; |
618 | } | 703 | } |
619 | #endif | 704 | #endif |