bcm-v4

[Specification

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)

  1. Return (((ns*1000*clk)/1000000) + 1)

nflash_enable(int enable)

  1. If CC Rev == 38
    1. If CC chipstatus & 0x10 is not zero

      1. Return
    2. Write 1 to chipcontrol_addr Register
    3. If enable is true
      1. Set bit 0x10000 in chipcontrol_data Register
    4. Otherwise
      1. Clear bit 0x10000 in chipcontrol_data Register

int nflash_ctrlcmd (uint code)

  1. Set int count to 0
  2. Write (code | 0x80000000) to CC Register nflashctrl
  3. Loop forever
    1. Read CC Register nflashctrl and mask with 0x80000000
    2. If result is zero
      1. Break from loop
    3. Otherwise
      1. Increment count
      2. If count > 1,000,000

        1. Log that nflash control command is not ready
        2. Return -1
  4. Return 0

nflash_cmd (uint code)

  1. Write code to CC Register nand_cmd_start
  2. Do dummy read of that register

char *nflash_check_id(u8 *id)

  1. Set char *name to NULL
  2. If id[0] is 0x01
    1. Set name to "AMD"
  3. Else if id[0] is 0x20
    1. Set name to "Numonyx"
  4. Else if id[0] is 0x2c
    1. Set name to "Micron"
  5. Else if id[0] is 0x98
    1. Set name to "Toshiba"
  6. Else if id[0] is 0xad
    1. Set name to "Hynix"
  7. Else if id[0] is 0xec
    • a, Set name to "Samsung"
  8. Return name

int nflash_poll

  1. If chipid is 0x5300
    1. Loop 1,000,000 times with index i - the value is pretty large
      1. If bit 0x04000000 is set in CC Register nflashctrl
        1. If bit 0x08000000 is set in CC Register nflashctrl
          1. Error condition - return -1
        2. Otherwise
          1. Return 0
  2. Otherwise
    1. Loop 1,000,000 times with index i - also a large loop count
      1. If bits 0xC0000000 are set in CC Register nand_intfc_status
        1. Return 0
  3. Error - nflash not ready
  4. Return -1

struct nflash *nflash_init

  1. If (chipid is not 0x5300) AND (CC Rev is not 0x38)
    1. Chip is not supported - return NULL
  2. If bit 0x80000000 is not set in CC Capabilities
    1. Return NULL
  3. If firsttime is false AND nflash.size is not zero
    1. Return nflash
  4. Memset nflash to zero
  5. If chipid is 0x5300
    1. Set bit 0x8 in CC flashstrconfig Register
    2. Read CC chipstatus and mask with 1
    3. If result is not zero
      1. Set freq to 100,000,000
    4. Otherwise
      1. Write 4 to pllcontrol_addr
      2. Read pllcontrol_data and mask with 0xFFF and right shift result by 3
      3. Set freq to the above result times 25000000 and right shift result by 3
    5. Set clock to freq / 1000000
    6. Set w0 to nflash_ns_to_cycle(15, clock)
    7. Set w1 to nflash_ns_to_cycle(20, clock)
    8. Set w2 to nflash_ns_to_cycle(10, clock)
    9. Set w3 to nflash_ns_to_cycle(10, clock)
    10. Set w4 to nflash_ns_to_cycle(100, clock)
    11. Write (w4 << 24 | w3 << 18 | w2 << 12 | w1 << 6 | w0) CC Register nflashwaitcnt0

    12. Set code to NFC_CSA | NFC_SPECADDR | NFC_CMD1W | NFC_CMD0 | NFCTRL_ID (0x41090090)
    13. If nflash_ctrlcmd(code) is not zero
      1. Return NULL
    14. Loop 5 times with index i starting at 0
      1. If loop index <= 4 (No, this is not a mistake - this is what the code says)

        1. Set code to NFC_CSA | NFC_1BYTE (0x40000000 | 0x00100000)
      2. Otherwise
        1. Set code to NFC_1BYTE (0x00100000)
      3. If nflash_ctrlcmd(code) is not zero
        1. Return NULL
      4. Otherwise
        1. Set nflash.id[i] to (CC Register nflashdata & 0xFF)

    15. Set char *name = nflash_check_id(nflash.id)
    16. If name equals NULL
      1. Clear bit 8 of Register flashstrconfig
      2. Return NULL
    17. Set nflash.type to nflash.id[0]
    18. Set nflash.pagesize to 1024 << (nflash.id[3] & 0x3)

    19. Set nflash.blocksize to (64 * 1024) << ((nflash.id[3] >> 4) & 0x3)

    20. Set tmp to (8 << ((nflash.id[3] >> 2) & 0x1))

    21. Set nflash.oobsize to tmp * nflash.pagesize / 512
    22. Set nflash.size to (8 << ((nflash.id[4] >> 4) & 0x7)) * (1 << ((nflash.id[4] >> 2) & 0x3))

    23. Set tbits to 0
    24. Loop 32 times with index i starting at 0
      1. If (1 << i) equals nflash.size

        1. Set tbits to i + 20
        2. Break
    25. If tbits is zero
      1. Return NULL
    26. Set cbits to 0
    27. Loop 32 times with index i starting at 0
      1. If (1 << i) equals nflash.pagesize

        1. Set cbits = i + 1
        2. Break
    28. If cbits is zero
      1. Return NULL
    29. Set nflash_col_mask to (1 << cbits) - 1

    30. Set nflash_row_shift to cbits
    31. Set csize to (cbits + 7) / 8
    32. Set rbits to tbits - cbits + 1
    33. Set bsize to (rbits + 7) / 8
    34. Set val to ((bsize - 1) << 6) | ((csize - 1) << 4) | 2

    35. Write val to CC Register nflashconf
  6. Otherwise
    1. Call nflash_enable with argument 1
    2. Call nflash_cmd with argument 7
    3. If nflash_poll() < 0

      1. Call nflash_enable with argument 0
      2. Return NULL
    4. Call nflash_enable with argument 0
    5. Read CC Register nand_devid and save as id
    6. Read CC Register nand_devid_x and save as id2
    7. Loop 5 times with index i
      1. If i < 4

        1. Set nflash.id[i] to (id >> (8*i)) & 0xff

      2. Otherwise
        1. Set nflash.id[i] to id2 & 0xff

    8. Set name to the output of nflash_check_id(nflash.id)
    9. If name is NULL
      1. Return NULL
    10. Set nflash.type to nflash.id[0]
    11. Set ncf to CC Register nand_config
    12. Set val to (ncf & 0x00300000) >> 20

    13. If val is 0
      1. Set nflash.pagesize to 512
    14. Else if val is 1
      1. Set nflash.pagesize to 1 << 11

    15. Else if val is 2
      1. Set nflash.pagesize to 1 << 12

    16. Otherwise
      1. Set nflash.pagesize to 1 << 13

    17. Set val to (ncf & 0x70000000) >> 28

    18. If If val is 0
      1. Set nflash.blocksize to 1 << 14

    19. Else if val is 1
      1. Set nflash.blocksize to 0x20000
    20. Else if val is 2
      1. Set nflash.blocksize to 1 << 13

    21. Else if val is 3
      1. Set nflash.blocksize to 0x80000
    22. Else if val is 4
      1. Set nflash.blocksize to 0x40000
    23. Else
      1. The block size is unknown
      2. Return NULL
    24. Set nflash.size to (1 << (val - 1)) * 8

    25. Set control to the contents of CC Register nand_acc_control
    26. Set nflash.ecclevel to ((control & 0x000f0000) >> 16

    27. Set nflash.ecclevel0 to (control & 0x00f00000) >> 20

    28. If nflash.ecclevel not equal to nflash.ecclevel0
      1. Set control to control AND ~(0x00ff0000)
      2. Set control to control OR (nflash.ecclevel0 << 20) | (nflash.ecclevel0 << 16)

      3. Write control to CC Register nand_acc_control
      4. Set nflash.ecclevel to nflash.ecclevel0
    29. Set nflash.numblocks to (nflash.size * (1 << 10)) / (nflash.blocksize >> 10)

    30. Set firsttime to false
    31. If nflash.size > 0

      1. Return pointer to nflash
    32. Return NULL

int read_nand (uint offset, uint len, uchar *buf)

  1. Set u32 mask to 511 (sector size - 1)
  2. If offset & mask not equal to 0 or len & mask not equal to 0

    1. Return 0
  3. Set u32 tmp to (offset + len) >> 20

  4. If tmp greater than nflash.size
    1. Return 0
  5. If tmp equals nflash.size AND ((offset + len) & ((1 << 20) -1)) not equal to 0

    1. Return 0
  6. Set remains to len
  7. Set u32 pointer dest to buf
  8. If chip ID is 0x5300
    1. While res > 0

      1. Set page_offset to offset & (nflash.pagesize - 1)

      2. Set page_addr to (offset & ~(nflash.pagesize - 1)) * 2 + page_offset

      3. Write (page_addr & nflashcolmask) to CC register nflashcoladdr

      4. Write (page_addr >> nflashrowshift) to CC register nflashrowaddr

      5. Set ctrlcode to 0x40000000 | 0x00080000 | 0x00040000 | 0x00020000 | 0x00010000 | 0x3000
      6. Call nflash_ctrlcmd with ctrlcode as argument
      7. If result is not 0
        1. Break from loop
      8. If nflash_poll() returns a value less than zero
        1. Break from loop
      9. Loop from 0 till 512 with index i incremented by 4, Increment dest each loop
        1. If i < 508

          1. Set ctrlcode to 0x40000000 | 0x30000000 | 0x00100000
        2. Else
          1. Set ctrlcode to 0x30000000 | 0x00100000
        3. If the returned value of nflash_ctrlcmd(ctrlcode) is not 0
          1. Return len - remains
        4. Read CC register nflashdata and store result in *dest
      10. Decrement remains by 512
      11. Increment offset by 512
  9. Otherwise
    1. Call nflash_enable with argument 1
    2. While remains is greater than 0
      1. Write offset to CC register nand_cmd_addr
      2. Call nflash_cmd with argument 1 (page read)
      3. If nflash_poll() less than 0
        1. Break from loop
      4. If the results of (Read CC Register nand_intfc_status & 0x20000000) is 0

        1. Break from loop
      5. Loop from 0 to 512 with indec i incremented by 4, Increment dest each loop
        1. Read CC register nand_cache_data and store result in *dest
      6. Decrement remains by 512
      7. Increment offset by 512
    3. Call nflash_enable with argument 0
  10. Return len - remains

Exported/Archived from the wiki to HTML on 2016-10-27