Serial Peripheral Interface (SPI) flash memory is often used in an embedded Linux box to hold bootloader. During very initial board bringup, SPI flash memory needs to be programmed properly using device like Dediprog, otherwise the box won’t boot. After the box is up running linux, often there is need to access SPI flash, e.g. upgrade new version of bootloader from linux. I will share what needs to be done for that.
SPI Flash: hardware overview
There are many flash memory devices in the market, often people see USB flash memory, SD card. Those flash memory are parallel flash, eithe NOR or NAND flash. With parell access, the throughput is a lot higher. SPI flash is accessed in a serial way, so it is much slower.
SPI devices communicate in full duplex mode using a master-slave architecture with a single master. The master device originates the frame for reading and writing. Multiple slave devices are supported through selection with individual slave select (SS) lines.
SCK: Serial Clock MOSI: Master Output Slave Input MISO: Master Input Slave Output SS: Slave Select
SPI Master often is provided by SoC, SPI flash device serves as SPI slave.
What are needed to enable SPI flash access from Linux ?
There are three areas to do in order to enable SPI flash access from Linux user space.
Enable SPI controller in device tree.
In my case, Marvell ARMADA 7040 SoC has SPI controller provided, I need do the following:
From the above, DTS defined the SPI flash to have three partitions: “boot”, “Filesystem” and “boot_2nd”. We will see how this definition is manifested in linux system.
Integrate the dtb file into linux boot in a proper way depending your situation.
Enable proper kernel drivers for SPI
Linux kernel has done a lot work to support SPI flash so that user space can access SPI flash easily. It has following architecture:
To enable SPI access, the following kernel configurations are required:
Access from user space
With the changes in DTS and kernel, after linux boots, the below will be observed in kernel space:
From the user space, the first thing can be seen is the mtd device files:
/dev/mtdblock0 is for “boot” (first bootloader) partition; /dev/mtdblock1 is for “FileSystem” partition; /dev/mtdblock2 is for “boot_2nd” partition.
what can we do now? Life is easy with all these infrastructure in place.
- To program a new version bootloader, simply: dd if=new-bootloader.bin of=/dev/mtdblock0
- If we want to use partition as file system, simply:
- mkdir /mnt/spi
- mkfs.jffs2 /dev/mtdblock1
- mount -t jfss2 /dev/mtdblock1 /mnt/spi
Life is good!