> ## Documentation Index
> Fetch the complete documentation index at: https://dragonwingdocs.qualcomm.com/llms.txt
> Use this file to discover all available pages before exploring further.

# QSPI

export const tdA = {
  border: "1px solid #ddd",
  padding: "10px 14px",
  textAlign: "left",
  verticalAlign: "top"
};
export const thA1 = {
  border: "1px solid #ddd",
  padding: "10px 14px",
  textAlign: "center",
  backgroundColor: "#f5f5f5",
  fontWeight: "600",
  color: "#333",
  width: "20%"
};
export const thA2 = {
  border: "1px solid #ddd",
  padding: "10px 14px",
  textAlign: "center",
  backgroundColor: "#f5f5f5",
  fontWeight: "600",
  color: "#333",
  width: "80%"
};
export const thAeq = {
  border: "1px solid #ddd",
  padding: "10px 14px",
  textAlign: "center",
  backgroundColor: "#f5f5f5",
  fontWeight: "600",
  color: "#333"
};
export const tblA = {
  borderCollapse: "collapse",
  width: "100%",
  fontSize: "14px",
  tableLayout: "fixed"
};

QSPI（四线串行外设接口，Quad Serial Peripheral Interface）控制器是 Qualcomm SoC 中实现的一种高速同步串行总线主控制器。它扩展了传统的 4 线 SPI 总线，支持最多四条双向数据线（IO0–IO3），在相同时钟频率下可实现标准 SPI 4 倍的吞吐量。

<Frame>
  <img src="https://mintcdn.com/qualcomm-prod/rpHTx_a6zriKQll9/System/Interfaces/images/QSPI_data_flow.svg?fit=max&auto=format&n=rpHTx_a6zriKQll9&q=85&s=9bac2acf47409159bead21535540d2c1" alt="QSPI 总线信号接口" width="800" height="560" data-path="System/Interfaces/images/QSPI_data_flow.svg" />
</Frame>

<p align="center"><strong>图：QSPI 总线信号接口</strong></p>

## **总线信号说明**

<table style={tblA}>
  <thead>
    <tr>
      <th style={thAeq}>信号</th>
      <th style={thAeq}>方向</th>
      <th style={thAeq}>说明</th>
    </tr>
  </thead>

  <tbody>
    <tr>
      <td style={tdA}>`CLK` </td>
      <td style={tdA}>输出</td>
      <td style={tdA}>由 QSPI 主控制器生成的串行时钟。</td>
    </tr>

    <tr>
      <td style={tdA}>`CS_N`  </td>
      <td style={tdA}>输出</td>
      <td style={tdA}>片选（低电平有效）。置位以选择第一个外设。在分段传输期间保持置位。</td>
    </tr>

    <tr>
      <td style={tdA}>`IO0` </td>
      <td style={tdA}>双向</td>
      <td style={tdA}>数据线 0。</td>
    </tr>

    <tr>
      <td style={tdA}>`IO1` </td>
      <td style={tdA}>双向</td>
      <td style={tdA}>数据线 1。</td>
    </tr>

    <tr>
      <td style={tdA}>`IO2` </td>
      <td style={tdA}>双向</td>
      <td style={tdA}>数据线 2。</td>
    </tr>

    <tr>
      <td style={tdA}>`IO3` </td>
      <td style={tdA}>双向</td>
      <td style={tdA}>数据线 3。</td>
    </tr>
  </tbody>
</table>

## **I/O 模式波形**

<div style={{ textAlign: "center" }}>
  <div style={{ backgroundColor: "#000", padding: "16px", borderRadius: "8px", display: "inline-block" }}>
    <img src="https://mintcdn.com/qualcomm-prod/rpHTx_a6zriKQll9/System/Interfaces/images/QSPI_1bit_IO_Mode_waveforms.png?fit=max&auto=format&n=rpHTx_a6zriKQll9&q=85&s=acf106ed7b649b18924ce6b4f9f1d97d" alt="QSPI I/O 模式波形：1 位" width="375" height="100" data-path="System/Interfaces/images/QSPI_1bit_IO_Mode_waveforms.png" />

    <img src="https://mintcdn.com/qualcomm-prod/rpHTx_a6zriKQll9/System/Interfaces/images/QSPI_2bit_IO_Mode_waveforms.png?fit=max&auto=format&n=rpHTx_a6zriKQll9&q=85&s=db8f15fb92e13d833c921740355839f8" alt="QSPI I/O 模式波形：2 位" width="345" height="127" data-path="System/Interfaces/images/QSPI_2bit_IO_Mode_waveforms.png" />

    <img src="https://mintcdn.com/qualcomm-prod/rpHTx_a6zriKQll9/System/Interfaces/images/QSPI_4bit_IO_Mode_waveforms.png?fit=max&auto=format&n=rpHTx_a6zriKQll9&q=85&s=99e5438ffb55354df993004d29d27200" alt="QSPI I/O 模式波形：4 位" width="346" height="145" data-path="System/Interfaces/images/QSPI_4bit_IO_Mode_waveforms.png" />
  </div>
</div>

<p align="center"><strong>图：QSPI I/O 模式波形：1 位、2 位和 4 位</strong></p>

## **QSPI 控制器内部架构**

<Frame>
  <img src="https://mintcdn.com/qualcomm-prod/rpHTx_a6zriKQll9/System/Interfaces/images/QSPI_Controller_internal_architecture.png?fit=max&auto=format&n=rpHTx_a6zriKQll9&q=85&s=88a46b16f13e922f7fe61f258af4bfd2" alt="QSPI 控制器内部框图" width="912" height="454" data-path="System/Interfaces/images/QSPI_Controller_internal_architecture.png" />
</Frame>

<p align="center"><strong>图：QSPI 控制器内部框图</strong></p>

## **QSPI 配置**

### **Linux**

本节介绍 QSPI 软件驱动的内核配置和设备树节点更改。

支持 QSPI 接口需要以下驱动内核配置。

* 驱动源文件位于：[https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/tree/drivers/spi/spi-qcom-qspi.c](https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/tree/drivers/spi/spi-qcom-qspi.c)
* 内核 defconfig 文件位于：[https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/tree/arch/arm64/configs/defconfig](https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/tree/arch/arm64/configs/defconfig)
* 启用内核配置 `CONFIG_SPI_QCOM_QSPI=m`
* Dtsi 文件路径：[https://git.kernel.org/pub/scm/linux/kernel/git/next/linux-next.git/tree/arch/arm64/boot/dts/qcom/talos.dtsi](https://git.kernel.org/pub/scm/linux/kernel/git/next/linux-next.git/tree/arch/arm64/boot/dts/qcom/talos.dtsi)

## **QSPI 接口组件**

本节介绍内核设备树节点及相关文档。

**表：QSPI 接口：Linux**

<table style={tblA}>
  <thead>
    <tr>
      <th style={thA1}>文件类型</th>
      <th style={thA2}>说明</th>
    </tr>
  </thead>

  <tbody>
    <tr>
      <td style={tdA}>设备树源文件</td>

      <td style={tdA}>
        <ul>
          <li>Dragonwing IQ-615: [https://git.kernel.org/pub/scm/linux/kernel/git/next/linux-next.git/tree/arch/arm64/boot/dts/qcom/talos.dtsi](https://git.kernel.org/pub/scm/linux/kernel/git/next/linux-next.git/tree/arch/arm64/boot/dts/qcom/talos.dtsi)</li>
        </ul>
      </td>
    </tr>

    <tr>
      <td style={tdA}>Pinctrl 设置</td>

      <td style={tdA}>
        <ul>
          <li>Dragonwing IQ-615: [https://git.kernel.org/pub/scm/linux/kernel/git/next/linux-next.git/tree/arch/arm64/boot/dts/qcom/talos.dtsi](https://git.kernel.org/pub/scm/linux/kernel/git/next/linux-next.git/tree/arch/arm64/boot/dts/qcom/talos.dtsi)</li>
        </ul>
      </td>
    </tr>
  </tbody>
</table>

```text theme={null}
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";
};
```

```text theme={null}
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 下使用 SPI-NOR 进行 QSPI 验证**

这些验证可确认 QSPI 控制器在 Linux 上与符合 JEDEC 标准的 SPI-NOR 闪存设备正常协同工作。测试涵盖三个核心方面：验证硬件在启动时被正确检测和枚举、确认可以可靠地从闪存读取数据，以及确保擦除后写入操作能成功完成。在新板卡启动（bring-up）后或修改 QSPI 设备树配置后，请使用这些检查。

以下设备树代码片段启用 QSPI 控制器并将其绑定到 SPI-NOR 闪存设备：

```text theme={null}
&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. 初始化与检测**

这些测试确认 QSPI 控制器和 NOR 闪存在启动时被 Linux 正确识别，并且在尝试任何读写之前，所有闪存分区都可作为 MTD 设备使用。

<table style={tblA}>
  <thead>
    <tr>
      <th style={thAeq}>测试说明</th>
      <th style={thAeq}>示例命令</th>
      <th style={thAeq}>预期结果</th>
    </tr>
  </thead>

  <tbody>
    <tr>
      <td style={tdA}>检查 QSPI 控制器在启动时成功启动，内核日志中无错误</td>
      <td style={tdA}>`dmesg | grep -i spi`</td>
      <td style={tdA}>QSPI 控制器初始化无错误</td>
    </tr>

    <tr>
      <td style={tdA}>通过从 sysfs 接口读取 JEDEC ID，确认 NOR 闪存芯片被识别</td>
      <td style={tdA}>`cat /sys/class/mtd/mtd0/device/spi-nor/jedec_id`</td>
      <td style={tdA}>检测到 NOR 闪存且 JEDEC ID 正确</td>
    </tr>

    <tr>
      <td style={tdA}>确认内核报告的闪存总容量和擦除块布局与设备规格一致</td>
      <td style={tdA}>`cat /proc/mtd`</td>
      <td style={tdA}>闪存容量和擦除大小符合规格</td>
    </tr>

    <tr>
      <td style={tdA}>确认所有闪存分区都可作为 /dev 下的 MTD 字符设备访问</td>
      <td style={tdA}>`ls -l /dev/mtd*`</td>
      <td style={tdA}>所有 MTD 设备和分区可见</td>
    </tr>
  </tbody>
</table>

**2. 读操作**

这些测试验证可以准确地从闪存读取数据，包括从闪存地址空间末尾读取以及在压力条件下重复读取等边界情况。

<table style={tblA}>
  <thead>
    <tr>
      <th style={thAeq}>测试说明</th>
      <th style={thAeq}>示例命令</th>
      <th style={thAeq}>预期结果</th>
    </tr>
  </thead>

  <tbody>
    <tr>
      <td style={tdA}>从闪存起始位置读取一个 256 字节块，确认数据读取无错误</td>
      <td style={tdA}>`dd if=/dev/mtd0 of=/tmp/read.bin bs=256 count=1`</td>
      <td style={tdA}>数据读取成功</td>
    </tr>

    <tr>
      <td style={tdA}>从闪存最后 256 字节读取，确认不会发生越界访问或缓冲区溢出</td>
      <td style={tdA}>`dd if=/dev/mtd0 of=/tmp/boundary.bin bs=1 count=256 skip=$((SIZE-256))`</td>
      <td style={tdA}>无边界溢出</td>
    </tr>

    <tr>
      <td style={tdA}>执行 100 次连续的 4K 块读取循环，确认在重复访问下运行稳定且无错误</td>
      <td style={tdA}>`for i in {1..100}; do echo "iter $i"; dd if=/dev/mtd0 of=/dev/null bs=4K count=10; done`</td>
      <td style={tdA}>重复读取稳定</td>
    </tr>
  </tbody>
</table>

**3. 写操作**

这些测试确认擦除后可以正确地向闪存写入数据，包括多页写入和覆写场景，这些是固件更新流程中最常见的操作。

<table style={tblA}>
  <thead>
    <tr>
      <th style={thAeq}>测试说明</th>
      <th style={thAeq}>示例命令</th>
      <th style={thAeq}>预期结果</th>
    </tr>
  </thead>

  <tbody>
    <tr>
      <td style={tdA}>擦除一个闪存扇区并写入测试模式，确认基本的单扇区写入功能</td>
      <td style={tdA}>`flash_erase /dev/mtd0 0 1 && echo TEST > /tmp/t.bin && dd if=/tmp/t.bin of=/dev/mtd0`</td>
      <td style={tdA}>写入成功</td>
    </tr>

    <tr>
      <td style={tdA}>写入跨多个页面的 16 KB 随机数据，确认驱动正确处理跨页边界的情况</td>
      <td style={tdA}>`dd if=/dev/urandom of=/tmp/m.bin bs=4K count=4 && flashcp /tmp/m.bin /dev/mtd0`</td>
      <td style={tdA}>多页写入成功</td>
    </tr>

    <tr>
      <td style={tdA}>擦除先前写入的扇区并重新写入，确认闪存在擦除后能正确接受新数据</td>
      <td style={tdA}>`flash_erase /dev/mtd0 0 1 && flashcp /tmp/t.bin /dev/mtd0`</td>
      <td style={tdA}>新数据写入正确</td>
    </tr>
  </tbody>
</table>
