QSPI Flash

From krtkl wiki
Jump to: navigation, search

snickerdoodle has one of several QSPI flash ICs. Each flash interface adheres to JEDEC-standard JESD216


Part Number Manifacturer ID Device ID
N25Q128A11 (obsolete) 0x20 0xBB18
MT25QL128
W25Q128FW 0xEF 0x6018


U-Boot Driver

drivers/mtd/spi/spi_flash_ids.c

        {"n25q128a",       INFO(0x20bb18, 0x0,  64 * 1024,   256, RD_FULL | WR_QPP) },
...
        {"w25q128fw",      INFO(0xef6018, 0x0,  64 * 1024,   256, RD_FULL | WR_QPP | SECT_4K) },

Linux Driver

As a result of standardization, various QSPI flash devices are supported by a single driver. Differences between devices are resolved by the driver with a table of device parameters. The JEDEC manufacturer and device ID are used to lookup device parameters from the table in drivers/mtd/spi-nor/spi-nor.c.

        { "n25q128a11",  INFO(0x20bb18, 0, 64 * 1024,  256, SECT_4K | SPI_NOR_QUAD_READ | USE_FSR | SPI_NOR_HAS_LOCK) },
...
        {
                "w25q128fw", INFO(0xef6018, 0, 64 * 1024, 256,
                        SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ |
                        SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB)
        },

Device Tree

&qspi {
        status = "okay";
        is-dual = <0>;
        num-cs = <1>;
        xlnx,qspi-mode = <1>;

        flash@0 {
                #address-cells = <1>;
                #size-cells = <1>;
                compatible = "jedec,spi-nor";
                reg = <0x0>;
                spi-max-frequency = <50000000>;
                m25p,fast-read;

                partition@fsbl-uboot {
                        label = "fsbl-uboot";
                        reg = <0x0 0xe0000>;
                };
                partition@uenv {
                        label = "uenv";
                        reg = <0xe0000 0x20000>;
                };
                partition@device-tree {
                        label = "device-tree";
                        reg = <0x100000 0x20000>;
                };
                partition@linux {
                        label = "linux";
                        reg = <0x120000 0x600000>;
                };
                partition@ramfs {
                        label = "ramfs";
                        reg = <0x720000 0x4E0000>;
                };
                partition@bitstream {
                        label = "bitstream";
                        reg = <0xC00000 0x400000>;
                };
        };
};


Updating QSPI Images

boot image format

Updating with U-Boot

Updating with Linux

The QSPI flash images can be independently updated using the partition layout specified by the device tree node. Each partition is represented in the Linux system with an MTD block device.

# flashcp -v /boot/qspi/boot.bin /dev/mtd0
# flashcp -v /boot/qspi/uenv.bin /dev/mtd1
# flashcp -v /boot/qspi/devicetree.dtb.bin /dev/mtd2
# flashcp -v /boot/qspi/uImage.bin /dev/mtd3
# flashcp -v /boot/qspi/uramdisk.image.gz.bin /dev/mtd4
# flashcp -v /boot/qspi/bitstream.bin /dev/mtd5

Updating with JTAG

A U-Boot binary is used by program_flash to perform operations on the QSPI flash. This binary must be updated to support the ISSI IS25WP128. To do this, the U-Boot binary in XSDK installation directory. The configuration for the U-Boot binary sets the console to JTAG DDC which allows the process to be controlled by program_flash.

/opt/Xilinx/SDK/2017.3/data/xicom/cfgmem/uboot/zynq_qspi_x1_single.bin

$ program_flash -f boot.bin -verify -flash_type qspi_single -offset 0 -cable type xilinx_tcf url TCP:localhost:3121

To force the program_flash utility to print the U-Boot messages, set the environmental variable XIL_CSE_ZYNQ_DISPLAY_UBOOT_MESSAGES

Build U-Boot with the QSPI configuration.

$ make ARCH=arm zynq_cse_qspi_defconfig


Set CONFIG_SYS_PROMPT to "zynq-uboot> "

$ make ARCH=arm CROSS_COMPILE=arm-none-eabi-


$ cp u-boot /opt/Xilinx/SDK/<release>/data/xicom/cfgmem/uboot/zynq_qspi_x1_single.bin


Quad mode enable for IS25WP128

	WriteBuffer[0] = WRITE_ENABLE_CMD;
	XQspiPs_PolledTransfer(QspiInstancePtr, WriteBuffer, ReadBuffer, 1);

	WriteBuffer[0] = READ_STATUS_CMD;
	XQspiPs_PolledTransfer(QspiInstancePtr, WriteBuffer, ReadBuffer, 2);

	WriteBuffer[0] = WRITE_STATUS_CMD;        /* non-volatile status register */
	WriteBuffer[1] = ReadBuffer[1] | 0x40;    /* quad enable bit */
	XQspiPs_PolledTransfer(QspiInstancePtr, WriteBuffer, ReadBuffer, 2);

	WriteBuffer[0] = READ_STATUS_CMD;
	XQspiPs_PolledTransfer(QspiInstancePtr, WriteBuffer, ReadBuffer, 2);