[linux-yocto] [kernel v5.2/standard/xlnx-soc][PATCH 2/2] spi: spi-mem: zynq-qspi: add is-dual support for zc706 board
quanyang.wang at windriver.com
quanyang.wang at windriver.com
Thu Sep 19 04:58:07 PDT 2019
From: Quanyang Wang <quanyang.wang at windriver.com>
There are 2 SPI flash memories in zc706 board and it use the
configuration "Dual SS, 8-bit Parallel" which means separate
Slave-Select lines and separate 4 data lines. So add the is-dual
support for zc706 board according to the spi driver in SDK.
Refer to bd2c1810ae87 ("spi: zynq-qspi: Add driver for zynq qspi")
in https://github.com/Xilinx/linux-xlnx.git xlnx_rebase_v4.19
Signed-off-by: Quanyang Wang <quanyang.wang at windriver.com>
---
drivers/spi/spi-zynq-qspi.c | 43 +++++++++++++++++++++++++++++++++++--
1 file changed, 41 insertions(+), 2 deletions(-)
diff --git a/drivers/spi/spi-zynq-qspi.c b/drivers/spi/spi-zynq-qspi.c
index c6bee67decb5..2041d5dcf294 100644
--- a/drivers/spi/spi-zynq-qspi.c
+++ b/drivers/spi/spi-zynq-qspi.c
@@ -129,6 +129,9 @@
* @rxbuf: Pointer to the RX buffer
* @tx_bytes: Number of bytes left to transfer
* @rx_bytes: Number of bytes left to receive
+ * @is_dual: Flag to indicate whether dual flash memories are used
+ * @is_instr: Flag to indicate if transfer contains an instruction
+ * (Used in dual parallel configuration)
* @data_completion: completion structure
*/
struct zynq_qspi {
@@ -141,6 +144,8 @@ struct zynq_qspi {
u8 *rxbuf;
int tx_bytes;
int rx_bytes;
+ u32 is_dual;
+ u8 is_instr;
struct completion data_completion;
};
@@ -213,6 +218,14 @@ static void zynq_qspi_init_hw(struct zynq_qspi *xqspi)
zynq_qspi_write(xqspi, ZYNQ_QSPI_TX_THRESH_OFFSET,
ZYNQ_QSPI_TX_THRESHOLD);
+ if (xqspi->is_dual)
+ /* Enable two memories on separate buses */
+ zynq_qspi_write(xqspi, ZYNQ_QSPI_LINEAR_CFG_OFFSET,
+ (ZYNQ_QSPI_LCFG_TWO_MEM_MASK |
+ ZYNQ_QSPI_LCFG_SEP_BUS_MASK |
+ (1 << ZYNQ_QSPI_LCFG_DUMMY_SHIFT) |
+ ZYNQ_QSPI_FAST_READ_QOUT_CODE));
+
zynq_qspi_write(xqspi, ZYNQ_QSPI_ENABLE_OFFSET,
ZYNQ_QSPI_ENABLE_ENABLE_MASK);
}
@@ -236,15 +249,23 @@ static bool zynq_qspi_supports_op(struct spi_mem *mem,
* zynq_qspi_rxfifo_op - Read 1..4 bytes from RxFIFO to RX buffer
* @xqspi: Pointer to the zynq_qspi structure
* @size: Number of bytes to be read (1..4)
+ *
+ * Note: In case of dual parallel connection, even number of bytes are read
+ * when odd bytes are requested to avoid transfer of a nibble to each flash.
+ * The receive buffer though, is populated with the number of bytes requested.
*/
static void zynq_qspi_rxfifo_op(struct zynq_qspi *xqspi, unsigned int size)
{
+ unsigned int xsize;
u32 data;
data = zynq_qspi_read(xqspi, ZYNQ_QSPI_RXD_OFFSET);
if (xqspi->rxbuf) {
- memcpy(xqspi->rxbuf, ((u8 *)&data) + 4 - size, size);
+ xsize = size;
+ if (xqspi->is_dual && !xqspi->is_instr && (size % 2))
+ xsize++;
+ memcpy(xqspi->rxbuf, ((u8 *)&data) + 4 - xsize, size);
xqspi->rxbuf += size;
}
@@ -257,12 +278,19 @@ static void zynq_qspi_rxfifo_op(struct zynq_qspi *xqspi, unsigned int size)
* zynq_qspi_txfifo_op - Write 1..4 bytes from TX buffer to TxFIFO
* @xqspi: Pointer to the zynq_qspi structure
* @size: Number of bytes to be written (1..4)
+ *
+ * In dual parallel configuration, when read/write data operations
+ * are performed, odd data bytes have to be converted to even to
+ * avoid a nibble (of data when programming / dummy when reading)
+ * going to individual flash devices, where a byte is expected.
+ * This check is only for data and will not apply for commands.
*/
static void zynq_qspi_txfifo_op(struct zynq_qspi *xqspi, unsigned int size)
{
static const unsigned int offset[4] = {
ZYNQ_QSPI_TXD_00_01_OFFSET, ZYNQ_QSPI_TXD_00_10_OFFSET,
ZYNQ_QSPI_TXD_00_11_OFFSET, ZYNQ_QSPI_TXD_00_00_OFFSET };
+ unsigned int xsize;
u32 data;
if (xqspi->txbuf) {
@@ -274,7 +302,11 @@ static void zynq_qspi_txfifo_op(struct zynq_qspi *xqspi, unsigned int size)
}
xqspi->tx_bytes -= size;
- zynq_qspi_write(xqspi, offset[size - 1], data);
+
+ xsize = size;
+ if (xqspi->is_dual && !xqspi->is_instr && (size % 2))
+ xsize++;
+ zynq_qspi_write(xqspi, offset[xsize - 1], data);
}
/**
@@ -295,6 +327,7 @@ static void zynq_qspi_chipselect(struct spi_device *spi, bool assert)
config_reg |= (((~(BIT(spi->chip_select))) <<
ZYNQ_QSPI_SS_SHIFT) &
ZYNQ_QSPI_CONFIG_SSCTRL_MASK);
+ xqspi->is_instr = 1;
} else {
config_reg |= ZYNQ_QSPI_CONFIG_SSCTRL_MASK;
}
@@ -637,6 +670,12 @@ static int zynq_qspi_probe(struct platform_device *pdev)
goto remove_master;
}
+ if (of_property_read_u32(pdev->dev.of_node, "is-dual",
+ &xqspi->is_dual)) {
+ dev_warn(&pdev->dev, "couldn't determine configuration info");
+ dev_warn(&pdev->dev, "about dual memories. defaulting to single memory\n");
+ }
+
xqspi->pclk = devm_clk_get(&pdev->dev, "pclk");
if (IS_ERR(xqspi->pclk)) {
dev_err(&pdev->dev, "pclk clock not found.\n");
--
2.17.1
More information about the linux-yocto
mailing list