This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

[参考译文] AM623:AM623 与 FPGA 之间的 QSPI 通信–读取操作有效、但写入

Guru**** 2419530 points
Other Parts Discussed in Thread: AM623

请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

https://e2e.ti.com/support/processors-group/processors/f/processors-forum/1529823/am623-qspi-communication-between-am623-and-fpga-read-operation-working-but-writing

器件型号:AM623

工具/软件:

您好:

我们正在使用一款具有 AM623 处理器和 FPGA(通过 QSPI 连接)的定制电路板。

AM623 运行的是 Linux 内核版本 6.6.87、可从以下位置获取: https://git.ti.com/cgit/ti-linux-kernel/ti-linux-kernel/log/?h=ti-linux-6.6.y-cicd

在内核中、我检查了 TI 的低级 OSPI 驱动程序、该驱动程序位于:linux-kernel/drivers/spi/ spi-cadence-quadspi.c

基于这个驱动器、我为 FPGA 开发了一个更高级别的驱动器。 我正在使用 spi_mem_exec_op () 来自 Linux 内核的 API、用于发送和接收 QSPI 帧。

每次我打电话 spi_mem_exec_op () 、它从调用函数 spi-cadence-quadspi.c 它通过 QSPI 执行实际数据传输。

根据我的测试、我可以使用以下代码在 4-4-4 模式下成功从 FPGA 读取数据:

static int fpga_qspi_read(struct spi_mem *mem)
{
    struct spi_mem_op op;
    u8 *rx_buf;
    int ret;

    // Allocate RX buffer
    rx_buf = devm_kzalloc(&mem->spi->dev, 16, GFP_KERNEL);
    if (!rx_buf)
        return -ENOMEM;
    
    op = (struct spi_mem_op)SPI_MEM_OP(
                                       SPI_MEM_OP_CMD(READ_OPCODE, 4),      // Command  2 clock
                                       SPI_MEM_OP_ADDR(3, 0x00AA55, 4),     // 3-byte address 6 clocks                                       
                                       SPI_MEM_OP_NO_DUMMY,                 
                                       SPI_MEM_OP_DATA_IN(2, rx_buf, 4)     // 16-byte read, 4-bit bus 4 clocks
                                       );

    if (!spi_mem_supports_op(mem, &op))
    {
        dev_err(&mem->spi->dev, "Controller does not support this Quad Read op\n");
        return -EOPNOTSUPP;
    }

    ret = spi_mem_exec_op(mem, &op);
    if (ret)
    {
        dev_err(&mem->spi->dev, "Quad read failed: %d\n", ret);
        return ret;
    }

    dev_info(&mem->spi->dev, "Read data:");
    print_hex_dump(KERN_INFO, "FPGA: ", DUMP_PREFIX_OFFSET, 16, 1, rx_buf, 16, true);

    return 0;
}

下面是示波器输出、用于确认通信正常工作且所有信号均按预期显示:

我还可以一次读取 16 个字节、而不会出现任何故障。

但是、这一问题出现在写入问题上。 每次我尝试写入操作(无论是在 4-4-4-4、1-4-4、1-1-4、甚至 1-1-1 模式下)都会失败、并返回一个错误、指出该操作不受支持。

此错误消息源自 spi-cadence-quadspi.c 司机、但我没能理解背后的确切原因。

在器件树中、OSPI 模块绑定如下:

		ospi0: spi@fc40000 {
			compatible = "ti,am654-ospi", "cdns,qspi-nor";
			reg = <0x00 0x0fc40000 0x00 0x100>,
			      <0x05 0x00000000 0x01 0x00000000>;
			interrupts = <GIC_SPI 139 IRQ_TYPE_LEVEL_HIGH>;
			cdns,fifo-depth = <256>;
			cdns,fifo-width = <4>;
			cdns,trigger-address = <0x0>;
			cdns,phase-detect-selector = <2>;
			clocks = <&k3_clks 75 7>;
			assigned-clocks = <&k3_clks 75 7>;
			assigned-clock-parents = <&k3_clks 75 8>;
			assigned-clock-rates = <166666666>;
			power-domains = <&k3_pds 75 TI_SCI_PD_EXCLUSIVE>;
			#address-cells = <1>;
			#size-cells = <0>;
			status = "disabled";
		};

因此、它 首先与兼容字符串“ti、am654-ospi“匹配。

然后、在此基础上、我将自定义驱动程序绑定如下:

&ospi0 {	
	status = "okay";
	
	fpga@0{
		compatible = "XYZ,fpga-qspi";
		reg = <0x0>;
		spi-tx-bus-width = <4>;
		spi-rx-bus-width = <4>;
		spi-max-frequency = <25000000>;
	};
};

这是写入测试函数、但失败了:

static int fpga_qspi_write(struct spi_mem *mem)
{
    u8 tx_buf[16] = {
        0x00, 0x01, 0x02, 0x03,
        0x04, 0x05, 0x06, 0x07,
        0x08, 0x09, 0x0A, 0x0B,
        0x0C, 0x0D, 0x0E, 0x0F
    };

    int ret;

    struct spi_mem_op op = (struct spi_mem_op)SPI_MEM_OP(
                                        SPI_MEM_OP_CMD(0x55, 4),            // CMD
                                        SPI_MEM_OP_ADDR(3, 0x00AA55, 4),    // 3-byte address (1-bit lines)
                                        SPI_MEM_OP_NO_DUMMY,
                                        SPI_MEM_OP_DATA_OUT(16, tx_buf, 4)   // 16-byte write over 4-bit bus
                                       );

    
    if (!spi_mem_supports_op(mem, &op))
    {
        dev_err(&mem->spi->dev, "spi_mem_supports_op() for writing failed!\n");
        return -EOPNOTSUPP;
    }
    
    ret = spi_mem_exec_op(mem, &op);
    if (ret)
    {
        dev_err(&mem->spi->dev, "spi_mem_exec_op() failed for write operation: %d\n", ret);
        return ret;
    }

    return 0;
}

最后在这里我的问题:

1. spi-cadence-quadspi.c 支持哪些传输模式?

2.为什么你认为读操作成功,而类似的写操作失败?

3.比较 TI 时 spi-cadence-quadspi TI 存储库中的驱动程序与主线 Linux 内核中的驱动程序相比、哪个存储库提供更广泛的功能支持? 我们应该使用 Linux 主流而不是 TI 的下游器件吗?

谢谢。

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    尊敬的 Mehmt:

    但是、写入时会出现问题。 每次我尝试写入操作(无论是在 4-4-4-4、1-4-4、1-1-4、甚至 1-1-1 模式下)时都会失败、并返回一个错误、表明该操作不受支持。

    在任何写入尝试中、示波器上是否都有任何信号(例如时钟信号)从器件发出?

    [quote userid=“542216" url="“ url="~“~/support/processors-group/processors/f/processors-forum/1529823/am623-qspi-communication-between-am623-and-fpga-read-operation-working-but-writing spi-cadence-quadspi.c 支持哪些传输模式?

    问题 TI-Linux-6.6.y 内核版本应具有包含以下提交的驱动程序、该驱动程序专门添加了 SPI_TX_Quad 传输模式:

    $ git show 7a78c89eb58bad042c55b7b0234300ab9f561919
    commit 7a78c89eb58bad042c55b7b0234300ab9f561919
    Author: Santhosh Kumar K <s-k6@ti.com>
    Date:   Wed Jul 17 11:56:01 2024 +0530
    
        spi: cadence-quadspi: Enable SPI_TX_QUAD
    
        Enable SPI_TX_QUAD in spi_controller->mode_bits to add support for
        the 1S-4S-4S operations.
    
        Signed-off-by: Santhosh Kumar K <s-k6@ti.com>
        Tested-by: Prasanth Babu Mantena <p-mantena@ti.com>
    
    diff --git a/drivers/spi/spi-cadence-quadspi.c b/drivers/spi/spi-cadence-quadspi.c
    index 97069f8d27847..c2f83d2c50988 100644
    --- a/drivers/spi/spi-cadence-quadspi.c
    +++ b/drivers/spi/spi-cadence-quadspi.c
    @@ -2801,7 +2801,7 @@ static int cqspi_probe(struct platform_device *pdev)
                    dev_err(&pdev->dev, "devm_spi_alloc_host failed\n");
                    return -ENOMEM;
            }
    -       host->mode_bits = SPI_RX_QUAD | SPI_RX_DUAL;
    +       host->mode_bits = SPI_RX_QUAD | SPI_TX_QUAD | SPI_RX_DUAL;
            host->mem_ops = &cqspi_mem_ops;
            host->mem_caps = &cqspi_mem_caps;
            host->dev.of_node = pdev->dev.of_node;

    [quote userid=“542216" url="“ url="~“~/support/processors-group/processors/f/processors-forum/1529823/am623-qspi-communication-between-am623-and-fpga-read-operation-working-but-writing 为什么您认为在类似的写入操作失败的情况下读取操作成功?

    我不能说,我们应该做进一步的实验。 如何换用  “XXYZ、FPGA-QSPI“ 现有四路 SPI 器件的从器件、内核支持该器件、仅用于 API 实验目的(并查看是否获得向外传输的数据)。 例如(可能有更好的起点,但这是一个)...

    • 使用 n ü` drivers/MTD/SPI-NOR/core.c` 驱动器作为定制 FPGA 驱动器的参考
    • 对不会触发自动检测的驱动程序使用设备树兼容字符串。 类似的情况 “m25p05- nonjedec“ 应该可以工作(我还没有尝试过,只是查看代码)
    • 看看你是否可以让你的 4 位宽的写入工作的方式,只是为了测试目的
    • 驱动程序栈可能需要通过 FPGA 驱动程序显式配置写入操作。 例如  spi_nor_create_write_dirmap () 调用的传递函数 `dΩ Rivers/MTD/SPI-NOR/CORE.c` 对您的定制代码中的模拟非常重要
    [quote userid=“542216" url="“ url="~“~/support/processors-group/processors/f/processors-forum/1529823/am623-qspi-communication-between-am623-and-fpga-read-operation-working-but-writing 在比较 TI 的产品时 spi-cadence-quadspi TI 存储库中的驱动程序与主线 Linux 内核中的驱动程序相比、哪个存储库提供更广泛的功能支持? 我们应该使用 Linux 主流而不是 TI 的下游器件吗?

    TI 树中的驱动程序通常比相应的上游驱动程序更具特性完整性;不过、随着时间的推移、我们会努力使这些内容尽可能收敛(根据我们的“上游优先“理念)

    我认为这不会有什么不同、但我还是建议您尝试我们最新的 TI-Linux-6.12.y 构建所有基础。

    此致、Andreas

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    尊敬的 Andreas:

    >>在任何写入尝试中、您是否在示波器上看到设备发出的任何信号(例如时钟信号)?

    写入时示波器上不显示任何内容。 该问题发生在 spi_mem_support_op() API 调用中、该调用在 spi_mem_exec_op() 之前使用。

    如果我直接调用 spi_mem_exec_op() 而不检查是否支持该操作、则返回一个“无效参数“错误——同样、作用域上不显示任何内容。

    您提到的提交SPI_TX_QUAD存在于我们的内核版本 6.6.87 中、我们从 TI 的下游分支获得了该版本。

    有趣的是、我检查了最新的主线 Linux 内核(截至今天的版本 6.16-RC2)、并且该提交似乎没有包含在其中。

    根据这个小补丁、我们似乎应该坚持使用 TI 下游分支。 也许我们可以按照您的建议、从您的下游试用版本 6.12。

    在我们的 FPGA 中、我们并不打算完全仿真 NOR 闪存、而是在 4-4-4 模式下实现自定义读取和写入操作。 例如、我们可以定义一个自定义命令 1 以在 1 到 4096 字节之间读取、以及一个自定义命令 2 以在 1 到 4096 字节之间写入。 我们不需要遵循标准 JEDEC 命令、但我们确实遵循 JEDEC 建议的相同帧格式(命令,地址,数据)。

    TI 驱动程序是否会支持此功能 (  TI、am654-ospi  )、还是严格限于标准 JEDEC 命令?  到目前为止,阅读似乎是受支持的,但写作是这个主题中关注的主要主题。

    我将在下周度假。 回来后、我会尝试用替换器件树中的 FPGA 绑定 m25p05- nonjedec 并告知您我是否在示波器上观察到任何写入序列活动。

    同时、我对器件树 OSPI 绑定有一些问题。  中的一个 k3-am62-main.dtsi 、OSPI 兼容驱动程序被定义为“ TI、am654-ospi “、“ CDN、QSPI-NOR “。 不过、在中 spi-cadence-quadspi.c 、这两个字符串都列在兼容性表中、每个字符串都与不同的查询相关。  据我所知、Linux 仅匹配设备树中的第一个兼容字符串、这会使第二个条目不相关、对吧? 这很重要、因为 hwcaps_MASK 用于探针功能的参数是根据这些兼容性条目中定义的查询来确定的、并且它们是不同的。

    在探头函数 SPI_TX_QUAD 中、仅在以下情况下添加了 SPI_TX_QUAD 支持 hwcaps_MASK 具有 CSQSPI_SUPPORT_QUAD、但“ CDN、QSPI-NOR “但是“ TI、am654-ospi

    关于您检查 devm_spi_mem_dirmap_create() 的建议、我们对直接模式不感兴趣、直接模式将外部闪存映射到 Linux 地址空间。 相反、我们计划通过我们的驱动程序、使用未由 JEDEC 标准定义的自定义命令来间接地(逐帧)处理读取和写入操作。 我希望您的底层 QSPI 驱动器支持这种情况。

    感谢您的支持、希望下周见。

    此致、
    mf

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。
    与此同时、我对器件树 OSPI 绑定有一些问题。  中的一个 k3-am62-main.dtsi 、OSPI 兼容驱动程序被定义为“ TI、am654-ospi “、“ CDN、QSPI-NOR “。 不过、在中 spi-cadence-quadspi.c 、这两个字符串都列在兼容性表中、每个字符串都与不同的查询相关。  据我所知、Linux 仅匹配设备树中的第一个兼容字符串、这会使第二个条目不相关、对吧?

    它将从 DTS 文件的列表中选择第一个项目并尝试匹配它。 如果失败、则选择第二个。 以此类推。 另一方面、驱动程序代码中匹配表中条目的顺序并不重要。

    如果我直接调用 spi_mem_exec_op() 而不检查是否支持该操作、它将返回一个“无效参数“错误

    您能否尝试在内核驱动程序中的哪个位置进行跟踪?

    此致、Andreas

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    您好 Andreas、

    我已经查看了 Linux 内核源代码、并确定了一个影响我的写测试例程的限制:读取或写入缓冲区不得驻留在栈上。 如果是、内核会立即返回EINVAL并且不会将请求传递给较低级别的驱动程序spi-cadence-quadspi.c ()。

    切换到为 TX 缓冲区动态分配的内存、而不是使用静态数组后、我也开始在示波器上观察写入活动。

    此主题可以关闭。 感谢你的帮助。