Contents
NAND Flash
Flash parameters are stored in struct nflash with the following definition:
uint blocksize |
Block size |
uint pagesize |
Page size |
uint oobsize |
OOB size per page |
uint numblocks |
Number of blocks |
uint32 type |
Type |
uint size |
Total size in bytes |
uint8 id[5] |
|
uint ecclevel |
ECC algorithm for blocks other than block 0 |
uint ecclevel0 |
ECC algorithm for blocks 0 |
The following global variables are declared.
nflash |
struct nflash |
nflash_col_mask |
u32 |
nflash_row_shift |
u32 |
firsttime |
bool (initialized to true |
u32 nflash_ns_to_cycle (u32 ns, u32 clk)
- Return (((ns*1000*clk)/1000000) + 1)
nflash_enable(int enable)
- If CC Rev == 38
If CC chipstatus & 0x10 is not zero
- Return
- Write 1 to chipcontrol_addr Register
- If enable is true
- Set bit 0x10000 in chipcontrol_data Register
- Otherwise
- Clear bit 0x10000 in chipcontrol_data Register
int nflash_ctrlcmd (uint code)
- Set int count to 0
- Write (code | 0x80000000) to CC Register nflashctrl
- Loop forever
- Read CC Register nflashctrl and mask with 0x80000000
- If result is zero
- Break from loop
- Otherwise
- Increment count
If count > 1,000,000
- Log that nflash control command is not ready
- Return -1
- Return 0
nflash_cmd (uint code)
- Write code to CC Register nand_cmd_start
- Do dummy read of that register
char *nflash_check_id(u8 *id)
- Set char *name to NULL
- If id[0] is 0x01
- Set name to "AMD"
- Else if id[0] is 0x20
- Set name to "Numonyx"
- Else if id[0] is 0x2c
- Set name to "Micron"
- Else if id[0] is 0x98
- Set name to "Toshiba"
- Else if id[0] is 0xad
- Set name to "Hynix"
- Else if id[0] is 0xec
- a, Set name to "Samsung"
- Return name
int nflash_poll
- If chipid is 0x5300
- Loop 1,000,000 times with index i - the value is pretty large
- If bit 0x04000000 is set in CC Register nflashctrl
- If bit 0x08000000 is set in CC Register nflashctrl
- Error condition - return -1
- Otherwise
- Return 0
- If bit 0x08000000 is set in CC Register nflashctrl
- If bit 0x04000000 is set in CC Register nflashctrl
- Loop 1,000,000 times with index i - the value is pretty large
- Otherwise
- Loop 1,000,000 times with index i - also a large loop count
- If bits 0xC0000000 are set in CC Register nand_intfc_status
- Return 0
- If bits 0xC0000000 are set in CC Register nand_intfc_status
- Loop 1,000,000 times with index i - also a large loop count
- Error - nflash not ready
- Return -1
struct nflash *nflash_init
- If (chipid is not 0x5300) AND (CC Rev is not 0x38)
- Chip is not supported - return NULL
- If bit 0x80000000 is not set in CC Capabilities
- Return NULL
- If firsttime is false AND nflash.size is not zero
- Return nflash
- Memset nflash to zero
- If chipid is 0x5300
- Set bit 0x8 in CC flashstrconfig Register
- Read CC chipstatus and mask with 1
- If result is not zero
- Set freq to 100,000,000
- Otherwise
- Write 4 to pllcontrol_addr
- Read pllcontrol_data and mask with 0xFFF and right shift result by 3
- Set freq to the above result times 25000000 and right shift result by 3
- Set clock to freq / 1000000
- Set w0 to nflash_ns_to_cycle(15, clock)
- Set w1 to nflash_ns_to_cycle(20, clock)
- Set w2 to nflash_ns_to_cycle(10, clock)
- Set w3 to nflash_ns_to_cycle(10, clock)
- Set w4 to nflash_ns_to_cycle(100, clock)
Write (w4 << 24 | w3 << 18 | w2 << 12 | w1 << 6 | w0) CC Register nflashwaitcnt0
- Set code to NFC_CSA | NFC_SPECADDR | NFC_CMD1W | NFC_CMD0 | NFCTRL_ID (0x41090090)
- If nflash_ctrlcmd(code) is not zero
- Return NULL
- Loop 5 times with index i starting at 0
If loop index <= 4 (No, this is not a mistake - this is what the code says)
- Set code to NFC_CSA | NFC_1BYTE (0x40000000 | 0x00100000)
- Otherwise
- Set code to NFC_1BYTE (0x00100000)
- If nflash_ctrlcmd(code) is not zero
- Return NULL
- Otherwise
Set nflash.id[i] to (CC Register nflashdata & 0xFF)
- Set char *name = nflash_check_id(nflash.id)
- If name equals NULL
- Clear bit 8 of Register flashstrconfig
- Return NULL
- Set nflash.type to nflash.id[0]
Set nflash.pagesize to 1024 << (nflash.id[3] & 0x3)
Set nflash.blocksize to (64 * 1024) << ((nflash.id[3] >> 4) & 0x3)
Set tmp to (8 << ((nflash.id[3] >> 2) & 0x1))
- Set nflash.oobsize to tmp * nflash.pagesize / 512
Set nflash.size to (8 << ((nflash.id[4] >> 4) & 0x7)) * (1 << ((nflash.id[4] >> 2) & 0x3))
- Set tbits to 0
- Loop 32 times with index i starting at 0
If (1 << i) equals nflash.size
- Set tbits to i + 20
- Break
- If tbits is zero
- Return NULL
- Set cbits to 0
- Loop 32 times with index i starting at 0
If (1 << i) equals nflash.pagesize
- Set cbits = i + 1
- Break
- If cbits is zero
- Return NULL
Set nflash_col_mask to (1 << cbits) - 1
- Set nflash_row_shift to cbits
- Set csize to (cbits + 7) / 8
- Set rbits to tbits - cbits + 1
- Set bsize to (rbits + 7) / 8
Set val to ((bsize - 1) << 6) | ((csize - 1) << 4) | 2
- Write val to CC Register nflashconf
- Otherwise
- Call nflash_enable with argument 1
- Call nflash_cmd with argument 7
If nflash_poll() < 0
- Call nflash_enable with argument 0
- Return NULL
- Call nflash_enable with argument 0
- Read CC Register nand_devid and save as id
- Read CC Register nand_devid_x and save as id2
- Loop 5 times with index i
If i < 4
Set nflash.id[i] to (id >> (8*i)) & 0xff
- Otherwise
Set nflash.id[i] to id2 & 0xff
- Set name to the output of nflash_check_id(nflash.id)
- If name is NULL
- Return NULL
- Set nflash.type to nflash.id[0]
- Set ncf to CC Register nand_config
Set val to (ncf & 0x00300000) >> 20
- If val is 0
- Set nflash.pagesize to 512
- Else if val is 1
Set nflash.pagesize to 1 << 11
- Else if val is 2
Set nflash.pagesize to 1 << 12
- Otherwise
Set nflash.pagesize to 1 << 13
Set val to (ncf & 0x70000000) >> 28
- If If val is 0
Set nflash.blocksize to 1 << 14
- Else if val is 1
- Set nflash.blocksize to 0x20000
- Else if val is 2
Set nflash.blocksize to 1 << 13
- Else if val is 3
- Set nflash.blocksize to 0x80000
- Else if val is 4
- Set nflash.blocksize to 0x40000
- Else
- The block size is unknown
- Return NULL
Set nflash.size to (1 << (val - 1)) * 8
- Set control to the contents of CC Register nand_acc_control
Set nflash.ecclevel to ((control & 0x000f0000) >> 16
Set nflash.ecclevel0 to (control & 0x00f00000) >> 20
- If nflash.ecclevel not equal to nflash.ecclevel0
- Set control to control AND ~(0x00ff0000)
Set control to control OR (nflash.ecclevel0 << 20) | (nflash.ecclevel0 << 16)
- Write control to CC Register nand_acc_control
- Set nflash.ecclevel to nflash.ecclevel0
Set nflash.numblocks to (nflash.size * (1 << 10)) / (nflash.blocksize >> 10)
- Set firsttime to false
If nflash.size > 0
- Return pointer to nflash
- Return NULL
int read_nand (uint offset, uint len, uchar *buf)
- Set u32 mask to 511 (sector size - 1)
If offset & mask not equal to 0 or len & mask not equal to 0
- Return 0
Set u32 tmp to (offset + len) >> 20
- If tmp greater than nflash.size
- Return 0
If tmp equals nflash.size AND ((offset + len) & ((1 << 20) -1)) not equal to 0
- Return 0
- Set remains to len
- Set u32 pointer dest to buf
- If chip ID is 0x5300
While res > 0
Set page_offset to offset & (nflash.pagesize - 1)
Set page_addr to (offset & ~(nflash.pagesize - 1)) * 2 + page_offset
Write (page_addr & nflashcolmask) to CC register nflashcoladdr
Write (page_addr >> nflashrowshift) to CC register nflashrowaddr
- Set ctrlcode to 0x40000000 | 0x00080000 | 0x00040000 | 0x00020000 | 0x00010000 | 0x3000
- Call nflash_ctrlcmd with ctrlcode as argument
- If result is not 0
- Break from loop
- If nflash_poll() returns a value less than zero
- Break from loop
- Loop from 0 till 512 with index i incremented by 4, Increment dest each loop
If i < 508
- Set ctrlcode to 0x40000000 | 0x30000000 | 0x00100000
- Else
- Set ctrlcode to 0x30000000 | 0x00100000
- If the returned value of nflash_ctrlcmd(ctrlcode) is not 0
- Return len - remains
- Read CC register nflashdata and store result in *dest
- Decrement remains by 512
- Increment offset by 512
- Otherwise
- Call nflash_enable with argument 1
- While remains is greater than 0
- Write offset to CC register nand_cmd_addr
- Call nflash_cmd with argument 1 (page read)
- If nflash_poll() less than 0
- Break from loop
If the results of (Read CC Register nand_intfc_status & 0x20000000) is 0
- Break from loop
- Loop from 0 to 512 with indec i incremented by 4, Increment dest each loop
- Read CC register nand_cache_data and store result in *dest
- Decrement remains by 512
- Increment offset by 512
- Call nflash_enable with argument 0
- Return len - remains