Tool/software:
Hello,
We are working with a custom board that features an AM623 processor and an FPGA, connected via QSPI.
The AM623 is running Linux Kernel version 6.6.87, obtained from: https://git.ti.com/cgit/ti-linux-kernel/ti-linux-kernel/log/?h=ti-linux-6.6.y-cicd
Within the kernel, I examined TI's low-level OSPI driver located at: linux-kernel/drivers/spi/spi-cadence-quadspi.c
Based on this driver, I developed a higher-level driver for our FPGA. I'm using the spi_mem_exec_op() API from the Linux kernel to send and receive QSPI frames.
Each time I call spi_mem_exec_op(), it invokes a function from spi-cadence-quadspi.c that performs the actual data transfer over QSPI.
According to my tests, I am able to successfully read data from the FPGA in 4-4-4 mode using the following code:
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; }
Below is the oscilloscope output, confirming that the communication works correctly and all signals appear as expected:
I’m also able to read 16 bytes at a time without any failures.
However, the issue arises with writing. Every time I attempt a write operation—whether in 4-4-4, 1-4-4, 1-1-4, or even 1-1-1 mode—it fails, returning an error that the operation is not supported.
This error message originates from the spi-cadence-quadspi.c driver, but I haven’t been able to understand the exact reason behind it.
In the device tree, the OSPI module is bound as follows:
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"; };
So it matches with the compatible string "ti,am654-ospi" first.
Then on top of it I have our custom driver bound like:
&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>; }; };
And here is the write test function but fails:
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; }
And finally here my questions:
1. Which transfer modes are supported by spi-cadence-quadspi.c?
2. Why do you think read operations succeed while similar write operations fail?
3. When comparing TI’s spi-cadence-quadspi driver in the TI repository versus the one in the mainline Linux kernel, which repository offers broader feature support? Shall we go with linux main stream instead of TI's downstream?
Thanks.