Skip to main content
The QSPI (Quad Serial Peripheral Interface) controller is a high-speed, synchronous serial bus master implemented in Qualcomm SoCs. It extends the traditional 4-wire SPI bus by supporting up to four bidirectional data lines (IO0–IO3), enabling up to 4× the throughput of standard SPI at the same clock frequency.
QSPI bus signal interface

Figure : QSPI bus signal interface

Bus Signal Descriptions

SignalDirectionDescription
CLK OutputSerial clock generated by the QSPI master.
CS_N OutputChip select (active low). Asserted to select the first peripheral. Held asserted across fragmented transfers.
IO0 BidirData line 0.
IO1 BidirData line 1.
IO2 BidirData line 2.
IO3 BidirData line 3.

I/O Mode Waveforms

QSPI I/O mode waveforms: 1-bitQSPI I/O mode waveforms: 2-bitQSPI I/O mode waveforms: 4-bit

Figure : QSPI I/O mode waveforms: 1-bit, 2-bit and 4-bit

QSPI Controller Internal Architecture

QSPI controller internal block diagram

Figure : QSPI controller internal block diagram

QSPI Configuration

Linux

This section provides information about the QSPI software driver kernel configuration and device tree node changes. The following driver kernel configurations are required to support the QSPI interface.

QSPI Interface Components

This section provides information about the kernel device tree nodes, and related documentation. Table : QSPI interface: Linux
File typeDescription
Device tree source
Pinctrl settings
QSPI DT node:
 
qspi: spi@88df000 {
        compatible = "qcom,qcs615-qspi",
                      "qcom,qspi-v1";
        reg = <0x0 0x088df000 0x0 0x1000>;

        interrupts = <GIC_SPI 82 IRQ_TYPE_LEVEL_HIGH 0>;

        clocks = <&gcc GCC_QSPI_CNOC_PERIPH_AHB_CLK>,
                <&gcc GCC_QSPI_CORE_CLK>;
        clock-names = "iface",
                      "core";

        interconnects = <&gem_noc MASTER_APPSS_PROC QCOM_ICC_TAG_ACTIVE_ONLY
                        &config_noc SLAVE_QSPI QCOM_ICC_TAG_ACTIVE_ONLY>,
                        <&aggre1_noc MASTER_QSPI QCOM_ICC_TAG_ALWAYS
                        &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ALWAYS>;
        interconnect-names = "qspi-config",
                              "qspi-memory";

        power-domains = <&rpmhpd RPMHPD_CX>;
        operating-points-v2 = <&qspi_opp_table>;

        iommus = <&apps_smmu 0x160 0x0>;

        pinctrl-0 = <&qspi_clk>, <&qspi_cs0>, <&qspi_data0123>;
        pinctrl-names = "default";

        #address-cells = <1>;
        #size-cells = <0>;

        status = "disabled";
};
QSPI Pinctrl:
    qspi_cs0: qspi-cs0-state {
        pins = "gpio44";
        function = "qspi";
        bias-disable;
        drive-strength = <6>;
    };

    qspi_data0123: qspi-data0123-state {
        pins = "gpio45", "gpio46", "gpio47", "gpio49";
        function = "qspi";
        bias-pull-down;
        drive-strength = <6>;
    };

    qspi_clk: qspi-clk-state {
        pins = "gpio48";
        function = "qspi";
        bias-pull-down;
        drive-strength = <6>;
    };

Linux QSPI Validations with SPI-NOR

These validations confirm that the QSPI controller works correctly with a JEDEC-compliant SPI-NOR flash device on Linux. The tests cover three core areas: verifying the hardware is detected and enumerated correctly at boot, confirming data can be read reliably from the flash, and ensuring write operations complete successfully after an erase. Use these checks after bringing up a new board or after modifying the QSPI device tree configuration. The following device tree snippet enables the QSPI controller and binds it to a SPI-NOR flash device :
&qspi {
    status = "okay";
    flash@0 {
        compatible = "jedec,spi-nor";
        reg = <0>;
        spi-max-frequency = <25000000>;
        spi-tx-bus-width = <4>;
        spi-rx-bus-width = <4>;
    };
};
1. Initialization & Detection These tests confirm that the QSPI controller and NOR flash are correctly recognized by Linux at boot time, and that all flash partitions are available as MTD devices before any read or write is attempted.
Test DescriptionSample CommandExpected Result
Check that the QSPI controller starts up successfully on boot with no errors in the kernel logdmesg | grep -i spiQSPI controller initializes without errors
Confirm the NOR flash chip is recognized by reading its JEDEC ID from the sysfs interfacecat /sys/class/mtd/mtd0/device/spi-nor/jedec_idNOR flash detected with correct JEDEC ID
Confirm the flash total size and erase block layout reported by the kernel match the device specificationcat /proc/mtdFlash size and erase size match specs
Confirm all flash partitions are accessible as MTD character devices under /devls -l /dev/mtd*All MTD devices and partitions visible
2. Read Operations These tests validate that data can be read from the flash accurately, including edge cases such as reads from the end of the flash address space and repeated reads under stress conditions.
Test DescriptionSample CommandExpected Result
Read a 256-byte block from the start of the flash and confirm the data is retrieved without errorsdd if=/dev/mtd0 of=/tmp/read.bin bs=256 count=1Data read successfully
Read from the last 256 bytes of the flash to confirm no out-of-bounds access or buffer overflow occursdd if=/dev/mtd0 of=/tmp/boundary.bin bs=1 count=256 skip=$((SIZE-256))No boundary overflow
Perform 100 consecutive read cycles of 4K blocks to confirm stable, error-free operation under repeated accessfor i in {1..100}; do echo "iter $i"; dd if=/dev/mtd0 of=/dev/null bs=4K count=10; doneStable repeated reads
3. Write Operations These tests confirm that data can be written correctly to the flash after an erase, including multi-page writes and overwrite scenarios, which are the most common operations during firmware update workflows.
Test DescriptionSample CommandExpected Result
Erase a flash sector and write a test pattern to confirm basic single-sector write functionalityflash_erase /dev/mtd0 0 1 && echo TEST > /tmp/t.bin && dd if=/tmp/t.bin of=/dev/mtd0Write successful
Write 16 KB of random data spanning multiple pages to confirm the driver handles page-boundary crossing correctlydd if=/dev/urandom of=/tmp/m.bin bs=4K count=4 && flashcp /tmp/m.bin /dev/mtd0Multi-page write succeeds
Erase a previously written sector and rewrite it to confirm the flash correctly accepts new data after erasureflash_erase /dev/mtd0 0 1 && flashcp /tmp/t.bin /dev/mtd0New data written correctly