diff --git a/firmware/target/arm/rk27xx/nand-rk27xx.c b/firmware/target/arm/rk27xx/nand-rk27xx.c index c2c855efee..84e60a47e1 100644 --- a/firmware/target/arm/rk27xx/nand-rk27xx.c +++ b/firmware/target/arm/rk27xx/nand-rk27xx.c @@ -22,6 +22,400 @@ #include "config.h" #include "nand-target.h" +#if 0 +/* This is for documentation purpose as FTL has not been reverse engineered yet + * Raw nand handling functions based on OF disassembly and partially inspired + * by Rockchip patent + */ + +#define MAX_FLASH_NUM 4 +#define CMD_READ_STATUS 0x70 +#define CMD_RESET 0xFF +#define CMD_READ_ID 0x90 +#define READ_PAGE_CMD 0x30 + +/* this is the struct OF uses */ +struct flashspec_t +{ + uint8_t cache_prog; + uint8_t mul_plane; + uint8_t interleave; + uint8_t large; + uint8_t five; + uint8_t mlc; + uint8_t vendor; + uint8_t access_time; + uint8_t sec_per_page; + uint8_t sec_per_page_raw; + uint16_t sec_per_block; + uint16_t sec_per_block_raw; + uint16_t page_per_block; + uint16_t page_per_block_raw; + + uint32_t tot_logic_sec; + uint32_t total_phy_sec; + uint32_t total_bloks; + + uint32_t cmd; + uint32_t addr; + uint32_t data; +}; + +/* holds nand chips characteristics */ +struct flashspec_t flash_spec[MAX_FLASH_NUM]; + +/* sum of all phy sectors in all chips */ +uint32_t total_phy_sec; + +enum vendor_t { + SAMSUNG, + TOSHIBA, + HYNIX, + INFINEON, + MICRON, + RENESAS, + ST +}; + +/* taken from OF */ +const uint8_t device_code[] = { + 0x76, + 0x79, + 0xf1, + 0xda, + 0xdc, + 0xd3, + 0xd7 +}; + +const uint8_t manufacture_id_tbl[] = +{ + 0xec, /* SAMSUNG */ + 0x98, /* TOSHIBA */ + 0xad, /* HYNIX */ + 0xc1, /* INFINEON */ + 0x2c, /* MICRON */ + 0x07, /* RENESAS */ + 0x20 /* ST */ +}; + +/* phisical sectors */ +const uint32_t device_info[] = +{ + 0x20000, /* 64M, small page */ + 0x40000, /* 128M, small page */ + 0x40000, /* 128M, large page */ + 0x80000, /* 256M, large page */ + 0x100000, /* 512M, large page */ + 0x200000, /* 1G, large page */ + 0x400000, /* 2G, large page */ + 0x800000 /* 4G, large page */ +}; + +static int flash_delay(int n) +{ + volatile int cnt, i, j; + + for (j=0; j> 2) & 0x03; + + flash_spec[i].sec_per_page_raw = 2; /* 1KB~8KB */ + + /* set_sec_per_page_raw */ + flash_spec[i].sec_per_page_raw <<= (buff[3] & 3); + + flash_spec[i].sec_per_block_raw = 128; /* 64KB~512KB */ + + /* set_sec_per_block_raw */ + flash_spec[i].sec_per_block_raw <<= ((buff[3]>>4) & 3); + + /* simult_prog */ + if (buff[2] & 0x30) + { + /* buff4_mulplane */ + flash_spec[i].mul_plane <<= ((buff[4]>>2) & 3); + } + + /* set_interleave */ + if (flash_spec[i].vendor == TOSHIBA) + { + flash_spec[i].mul_plane = 2; + if (buff[2] & 3) + flash_spec[i].interleave = 1; + } + + } /* large block */ + + if (flash_spec[i].mul_plane > 2) + { + flash_spec[i].mul_plane = 2; + flash_spec[i].interleave = 1; + } + + flash_spec[i].page_per_block_raw = flash_spec[i].sec_per_block_raw/flash_spec[i].sec_per_page_raw; + flash_spec[i].page_per_block = flash_spec[i].page_per_block_raw * flash_spec[i].mul_plane; + flash_spec[i].sec_per_block = flash_spec[i].sec_per_block_raw * flash_spec[i].mul_plane; + flash_spec[i].sec_per_page = flash_spec[i].sec_per_page_raw * flash_spec[i].mul_plane; + flash_spec[i].total_bloks = flash_spec[i].total_phy_sec / flash_spec[i].sec_per_block; + + total_phy_sec += flash_spec[i].total_phy_sec; + } + + /* read ID block and propagate SysDiskCapacity and SysResBlocks */ +} + +/* read single page in unbuffered mode */ +void flash_read_page(int page, unsigned char *pgbuff) +{ + unsigned int i; + + flash_chip_select(0); + flash_delay(2); + flash_wait_busy(); + + /* setup transfer */ + FLASH_CMD(0) = 0x00; + FLASH_ADDR(0) = 0x00; /* column */ + FLASH_ADDR(0) = 0x00; /* column */ + FLASH_ADDR(0) = page & 0xff; /* row */ + FLASH_ADDR(0) = (page >> 8) & 0xff; /* row */ + FLASH_ADDR(0) = (page >> 16) & 0xff; /* row */ + FLASH_CMD(0) = READ_PAGE_CMD; + + /* wait for operation complete */ + flash_wait_busy(); + + /* copy data from page register + * WARNING flash page size can be different + * for different chips. This value should be set + * based on initialization. + */ + for (i=0; i<(4096+218); i++) + pgbuff[i] = FLASH_DATA(0); + + flash_chip_deselect(); +} + +void flash_read_sector(int page, unsigned char *secbuf, int nsec) +{ + int i = 0; + int j = 0; + + /* WARNING this code assumes only one nand chip + * it does not handle data split across different nand chips + */ + flash_chip_select(0); + flash_delay(2); + flash_wait_busy(); + + FLASH_CMD(0) = 0x00; + FLASH_ADDR(0) = 0x00; + FLASH_ADDR(0) = 0x00; + FLASH_ADDR(0) = page & 0xff; + FLASH_ADDR(0) = (page >> 8) & 0xff; + FLASH_ADDR(0) = (page >> 16) & 0xff; + FLASH_CMD(0) = READ_PAGE_CMD; + + flash_delay(1); + + /* wait for operation to complete */ + flash_wait_busy(); + + /* enables hw checksum control most probably */ + BCHCTL = 1; + + /* This initializes the transfer from the nand to the buffer + * There are 4 consecutive hw buffers 512 bytes long for data (PAGE_BUF) + * and 4 16 bytes long for metadata (BCH code checksum) (SPARE_BUF) + */ + FLCTL = 0xA24; + + /* This scheme utilizes some overlap in data transfers - + * data are copied from buffer to the mem and from nand to the buf + * at the same time. + */ + while (++j < nsec) + { + /* wait for transfer to complete */ + while(! (FLCTL & FL_RDY)); + + /* initialize next transfer to the next buffer */ + FLCTL = 0xA24 | (j&3)<<3; + + /* copy data chunk */ + memcpy(secbuf, (((unsigned char *)&PAGE_BUF)+((i&3)<<9)), 0x200); + secbuf += 0x200; + + /* copy metadata chunk (BCH) + * in real application this can be discarded + */ + memcpy(secbuf, (((unsigned char *)&SPARE_BUF)+((i&3)<<4)), 0x10); + secbuf += 0x10; + i++; + } + + /* wait for transfer to complete */ + while(! (FLCTL & FL_RDY)); + + /* copy data chunk */ + memcpy(secbuf, (((unsigned char *)&PAGE_BUF)+((i&3)<<9)), 0x200); + secbuf += 0x200; + + /* copy metadata chunk (BCH) + * in real application this can be discarded + */ + memcpy(secbuf, (((unsigned char *)&SPARE_BUF)+((i&3)<<4)), 0x10); + secbuf += 0x10; + + flash_chip_deselect(); +} + +#endif const struct nand_device_info_type* nand_get_device_type(uint32_t bank);