linux-chenxing.org

SPI Memory controllers

All known chips contain a set of SPI controllers that are responsible for driving an SPI NOR or NAND chip connected to the PM SPI pins.

There seems to be one controller called “ISP”, another called “FSP” and finally “QSPI”.

There seems to be three ways to read flash content:

There seems to be two ways to write flash content:

To make things really fun all of these blocks seem to have their own clock setup:

Maybe the hardware looks something like this?

 ------
| ISP  |-\
 ------   |   ---------------      -------------------
| FSP  | ----| ?? bus arb ?? | -- | SPI NOR/NAND chip |
 ------   |   ---------------      -------------------
| QSPI |-/
 ------

 *
 * ISP registers
 *
 * 0x00 - password
 * 0x04 - cmd
 * 0x10 - wdata - data to be written
 * 0x14 - rdata - data to be read
 * 0x18 - clkdiv?
 * 0x20 - ceclr - chip select control
 * 0x30 - rdreq - read trigger
 * 0x54 - rd_datardy - read data poll
 * 0x58 - wr_datardy - write data poll
 * 0x7e - reset
 *   2
 * ~rst
 * 0xa8 - trigger mode
 *
 * 0xfc - rst
 *
 *    2     |
 *   rst    |
 * 0 - rst  |
 * 1 - nrst |
 *
 * FSP
 *
 * The idea of the FSP seems to be to allow fast page writes.
 * You load a page of data into it's buffer, setup some bytes
 * that go before and after it for the flash protocol and then
 * fire the whole lot off.
 *
 * 0x0
 *  .
 *  . Seems to be a 256 byte buffer that is writable by
 *  . the bdma controller
 *  .
 * 0xFF
 *
 * 0x1b0 - ctrl
 *
 * |  3   |    2   |   1  |  0
 * | chk? | int en | ~rst | en
 *
 * 0x1b4 - trigger
 *    0
 * trigger
 *
 * 0x1b8 - status
 *   0
 * done
 *
 * QSPI register
 *
 * 0x01c - pm code: spi_arb_ctrl[1:0]
 * 0x020 - pm code: non_pm_ack_timeout_len[15:0]
 *
 * 0x028 - burst write control
 * 0x1 enable burst
 * 0x2 disable burst
 *
 * 0x150 - wrap val
 *
 * 0x1e8 - chip select
 */

QSPI Registers

offset name 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 notes
0x1c0 clock             addr_cont_dis         user_dummy_en   dummy cycles dummy cycles dummy cycles dummy cycles:</br> 0x1 - 4</br> 0x3 - 2</br> 0x7 - 1
0x1c4 cs timing                                  
0x1c8 read mode                         read mode read mode read mode read mode  
0x1f4 function select     wrap_en dummy_en addr2_en                       addr2_en:</br> 0 - 3 byte address (NOR)</br> 1 - 2 byte address (NAND)</br>
                                     

Read mode

val mode spi command
0x0   0x03
0x1 fast 0x0b
0x2 1_1_2 0x3b
0x3 1_2_2 0xbb
0xa 1_1_4 0x6b
0xb 1_4_4 0xeb
0xc   0x0b
0xd 4eb? ?

misc findings

$ md5sum /dev/mtd0
f8a994631cf2943fca8ceab1cdc0126f  /dev/mtd0
$ echo 3 > /proc/sys/vm/drop_caches 
[  160.959159] sh (175): drop_caches: 3
$ devmem 0x1f002fc8 16 0xa
$ md5sum /dev/mtd0
f17072fbb71420715a7469352766252a  /dev/mtd0
$ devmem 0x1f002fc8 16 0x2
$ echo 3 > /proc/sys/vm/drop_caches 
[  178.665619] sh (175): drop_caches: 3
$ md5sum /dev/mtd0
f8a994631cf2943fca8ceab1cdc0126f  /dev/mtd0

QSPI readmode register does seem to change what BDMA uses. Switching to quad mode changes the md5 sum.