From 072badeafbf33b49cba38d4d837110a7766b5c8e Mon Sep 17 00:00:00 2001 From: Marcin Bukat Date: Tue, 4 Sep 2012 09:44:18 +0200 Subject: rk27xx: Put some nand handling functions for reference The functions document my reverse engineer findings about nand controller. This code is commented out and is purely for reference as FTL scheme is still unknown. Change-Id: I70edeb4bfb0cbd51b6adc15afa7193dd8f71e8da --- firmware/target/arm/rk27xx/nand-rk27xx.c | 394 +++++++++++++++++++++++++++++++ 1 file changed, 394 insertions(+) (limited to 'firmware/target/arm') 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); -- cgit v1.2.3