From patchwork Thu Apr 23 17:00:53 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jagan Teki X-Patchwork-Id: 238400 List-Id: U-Boot discussion From: jagan at amarulasolutions.com (Jagan Teki) Date: Thu, 23 Apr 2020 22:30:53 +0530 Subject: [PATCH v4 1/5] spi: sifive: Add spi-mem exec op In-Reply-To: <20200423170057.1976-1-jagan@amarulasolutions.com> References: <20200423170057.1976-1-jagan@amarulasolutions.com> Message-ID: <20200423170057.1976-2-jagan@amarulasolutions.com> SiFive SPI controller is responsible to handle the slave devices like mmc spi and spi nor flash. The controller is designed such a way that it would handle the slave transactions based on the I/O protocol numbers, example if spi nor slave send quad write opcode it has to send alone with I/O protocol number of 4 and if it try to send data it has to send I/O protocol number along with 4 line data. But the current spi-xfer code from spi-mem is combining the opcode and address in a single transaction, so the SPI controller will be unable to identify the I/O protocol number of opcode vs address. So, add the spi-mem exec_op with spi-xfer of opcode, address and data as a separate transaction. This doesn't remove the .xfer of dm_spi_ops since mmc spi will make use of it. Note: This code might have moved to the spi-mem core area once we have done the dedicated tests on other controllers and have real reason to move. Cc: Vignesh R Signed-off-by: Jagan Teki --- Changes for v4: - new patch drivers/spi/spi-sifive.c | 75 +++++++++++++++++++++++++++++++++++++++- 1 file changed, 74 insertions(+), 1 deletion(-) diff --git a/drivers/spi/spi-sifive.c b/drivers/spi/spi-sifive.c index 8f5efb51a3..5e612edcff 100644 --- a/drivers/spi/spi-sifive.c +++ b/drivers/spi/spi-sifive.c @@ -8,8 +8,9 @@ #include #include +#include #include -#include +#include #include #include #include @@ -241,6 +242,73 @@ static int sifive_spi_xfer(struct udevice *dev, unsigned int bitlen, return 0; } +static int sifive_spi_exec_op(struct spi_slave *slave, + const struct spi_mem_op *op) +{ + struct udevice *dev = slave->dev; + unsigned long flags = SPI_XFER_BEGIN; + u8 opcode = op->cmd.opcode; + unsigned int pos = 0; + const void *tx_buf = NULL; + void *rx_buf = NULL; + int op_len, i; + int ret; + + if (!op->addr.nbytes && !op->dummy.nbytes && !op->data.nbytes) + flags |= SPI_XFER_END; + + /* send the opcode */ + ret = sifive_spi_xfer(dev, 8, (void *)&opcode, NULL, flags); + if (ret < 0) { + dev_err(dev, "failed to xfer opcode\n"); + return ret; + } + + op_len = op->addr.nbytes + op->dummy.nbytes; + u8 op_buf[op_len]; + + /* send the addr + dummy */ + if (op->addr.nbytes) { + /* fill address */ + for (i = 0; i < op->addr.nbytes; i++) + op_buf[pos + i] = op->addr.val >> + (8 * (op->addr.nbytes - i - 1)); + + pos += op->addr.nbytes; + + /* fill dummy */ + if (op->dummy.nbytes) + memset(op_buf + pos, 0xff, op->dummy.nbytes); + + /* make sure to set end flag, if no data bytes */ + if (!op->data.nbytes) + flags |= SPI_XFER_END; + + ret = sifive_spi_xfer(dev, op_len * 8, op_buf, NULL, flags); + if (ret < 0) { + dev_err(dev, "failed to xfer addr + dummy\n"); + return ret; + } + } + + /* send/received the data */ + if (op->data.nbytes) { + if (op->data.dir == SPI_MEM_DATA_IN) + rx_buf = op->data.buf.in; + else + tx_buf = op->data.buf.out; + + ret = sifive_spi_xfer(dev, op->data.nbytes * 8, + tx_buf, rx_buf, SPI_XFER_END); + if (ret) { + dev_err(dev, "failed to xfer data\n"); + return ret; + } + } + + return 0; +} + static int sifive_spi_set_speed(struct udevice *bus, uint speed) { struct sifive_spi *spi = dev_get_priv(bus); @@ -348,11 +416,16 @@ static int sifive_spi_probe(struct udevice *bus) return 0; } +static const struct spi_controller_mem_ops sifive_spi_mem_ops = { + .exec_op = sifive_spi_exec_op, +}; + static const struct dm_spi_ops sifive_spi_ops = { .xfer = sifive_spi_xfer, .set_speed = sifive_spi_set_speed, .set_mode = sifive_spi_set_mode, .cs_info = sifive_spi_cs_info, + .mem_ops = &sifive_spi_mem_ops, }; static const struct udevice_id sifive_spi_ids[] = { From patchwork Thu Apr 23 17:00:54 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jagan Teki X-Patchwork-Id: 238401 List-Id: U-Boot discussion From: jagan at amarulasolutions.com (Jagan Teki) Date: Thu, 23 Apr 2020 22:30:54 +0530 Subject: [PATCH v4 2/5] spi: sifive: Fix format register proto field In-Reply-To: <20200423170057.1976-1-jagan@amarulasolutions.com> References: <20200423170057.1976-1-jagan@amarulasolutions.com> Message-ID: <20200423170057.1976-3-jagan@amarulasolutions.com> SiFive SPI controller has a proto bit field in frame format register which would be used to configure the SPI I/O protocol lines used on specific transfer.? Right now the driver is configuring this proto using slave->mode, for all types of transctions. This makes the driver unable to function since the proto needs to configure dynamically for each and every transaction separately at runtime. Now, the controller driver supports per transfer via spi-mem exec_opo, so add the fmt_proto flag and fill the per transfer buswidth so that the controller configures the proto bit at runtime. This patch fixes the SPI controller works with SPI NOR flash on quad read with page program. Cc: Vignesh R Signed-off-by: Jagan Teki --- Changes for v4: - new patch drivers/spi/spi-sifive.c | 24 +++++++++++++++++++++--- 1 file changed, 21 insertions(+), 3 deletions(-) diff --git a/drivers/spi/spi-sifive.c b/drivers/spi/spi-sifive.c index 5e612edcff..0ea4930a0a 100644 --- a/drivers/spi/spi-sifive.c +++ b/drivers/spi/spi-sifive.c @@ -86,6 +86,11 @@ #define SIFIVE_SPI_IP_TXWM BIT(0) #define SIFIVE_SPI_IP_RXWM BIT(1) +/* format protocol */ +#define SIFIVE_SPI_PROTO_QUAD 4 /* 4 lines I/O protocol transfer */ +#define SIFIVE_SPI_PROTO_DUAL 2 /* 2 lines I/O protocol transfer */ +#define SIFIVE_SPI_PROTO_SINGLE 1 /* 1 line I/O protocol transfer */ + struct sifive_spi { void *regs; /* base address of the registers */ u32 fifo_depth; @@ -93,6 +98,7 @@ struct sifive_spi { u32 cs_inactive; /* Level of the CS pins when inactive*/ u32 freq; u32 num_cs; + u8 fmt_proto; }; static void sifive_spi_prep_device(struct sifive_spi *spi, @@ -147,12 +153,17 @@ static void sifive_spi_prep_transfer(struct sifive_spi *spi, /* Number of wires ? */ cr &= ~SIFIVE_SPI_FMT_PROTO_MASK; - if ((slave_plat->mode & SPI_TX_QUAD) || (slave_plat->mode & SPI_RX_QUAD)) + switch (spi->fmt_proto) { + case SIFIVE_SPI_PROTO_QUAD: cr |= SIFIVE_SPI_FMT_PROTO_QUAD; - else if ((slave_plat->mode & SPI_TX_DUAL) || (slave_plat->mode & SPI_RX_DUAL)) + break; + case SIFIVE_SPI_PROTO_DUAL: cr |= SIFIVE_SPI_FMT_PROTO_DUAL; - else + break; + default: cr |= SIFIVE_SPI_FMT_PROTO_SINGLE; + break; + } /* SPI direction in/out ? */ cr &= ~SIFIVE_SPI_FMT_DIR; @@ -246,6 +257,7 @@ static int sifive_spi_exec_op(struct spi_slave *slave, const struct spi_mem_op *op) { struct udevice *dev = slave->dev; + struct sifive_spi *spi = dev_get_priv(dev->parent); unsigned long flags = SPI_XFER_BEGIN; u8 opcode = op->cmd.opcode; unsigned int pos = 0; @@ -257,6 +269,8 @@ static int sifive_spi_exec_op(struct spi_slave *slave, if (!op->addr.nbytes && !op->dummy.nbytes && !op->data.nbytes) flags |= SPI_XFER_END; + spi->fmt_proto = op->cmd.buswidth; + /* send the opcode */ ret = sifive_spi_xfer(dev, 8, (void *)&opcode, NULL, flags); if (ret < 0) { @@ -284,6 +298,8 @@ static int sifive_spi_exec_op(struct spi_slave *slave, if (!op->data.nbytes) flags |= SPI_XFER_END; + spi->fmt_proto = op->addr.buswidth; + ret = sifive_spi_xfer(dev, op_len * 8, op_buf, NULL, flags); if (ret < 0) { dev_err(dev, "failed to xfer addr + dummy\n"); @@ -298,6 +314,8 @@ static int sifive_spi_exec_op(struct spi_slave *slave, else tx_buf = op->data.buf.out; + spi->fmt_proto = op->data.buswidth; + ret = sifive_spi_xfer(dev, op->data.nbytes * 8, tx_buf, rx_buf, SPI_XFER_END); if (ret) { From patchwork Thu Apr 23 17:00:55 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jagan Teki X-Patchwork-Id: 238402 List-Id: U-Boot discussion From: jagan at amarulasolutions.com (Jagan Teki) Date: Thu, 23 Apr 2020 22:30:55 +0530 Subject: [PATCH v4 3/5] spi: sifive: Fix QPP transfer In-Reply-To: <20200423170057.1976-1-jagan@amarulasolutions.com> References: <20200423170057.1976-1-jagan@amarulasolutions.com> Message-ID: <20200423170057.1976-4-jagan@amarulasolutions.com> The guessed reason is that the existing logic of filling tx fifo with data, rx fifo with NULL for tx transfer and filling rx fifo with data, tx fifo with NULL for rx transfer is not clear enough to support the Quad Page Program. ? ? SiFive SPI controllers have specific sets of watermark registers and SPI I/O directions bits in order to program SPI controllers clear enough to support all sets of operating modes. ? ? Here is the exact programing sequence that would follow on this patch and tested via SPI-NOR and MMC_SPI. ? ? - set the frame format proto, endian - set the frame format dir, set it for tx and clear it for rx - TX transfer: ? fill tx fifo with data. ? wait for TX watermark bit to clear. - RX transfer: ? fill tx fifo with 0xff. ? write nbytes to rx watermark register ? wait for rx watermark bit to clear. ? read the rx fifo data. So, this patch adopts this program sequence and fixes the existing I/O direction bit. Cc: Vignesh R Signed-off-by: Jagan Teki --- Changes for v4: - update commit message drivers/spi/spi-sifive.c | 57 ++++++++++++++++++++++++++-------------- 1 file changed, 37 insertions(+), 20 deletions(-) diff --git a/drivers/spi/spi-sifive.c b/drivers/spi/spi-sifive.c index 0ea4930a0a..4cab0391f7 100644 --- a/drivers/spi/spi-sifive.c +++ b/drivers/spi/spi-sifive.c @@ -11,6 +11,7 @@ #include #include #include +#include #include #include #include @@ -134,8 +135,8 @@ static void sifive_spi_clear_cs(struct sifive_spi *spi) } static void sifive_spi_prep_transfer(struct sifive_spi *spi, - bool is_rx_xfer, - struct dm_spi_slave_platdata *slave_plat) + struct dm_spi_slave_platdata *slave_plat, + u8 *rx_ptr) { u32 cr; @@ -167,7 +168,7 @@ static void sifive_spi_prep_transfer(struct sifive_spi *spi, /* SPI direction in/out ? */ cr &= ~SIFIVE_SPI_FMT_DIR; - if (!is_rx_xfer) + if (!rx_ptr) cr |= SIFIVE_SPI_FMT_DIR; writel(cr, spi->regs + SIFIVE_SPI_REG_FMT); @@ -198,13 +199,19 @@ static void sifive_spi_tx(struct sifive_spi *spi, const u8 *tx_ptr) writel(tx_data, spi->regs + SIFIVE_SPI_REG_TXDATA); } +static int sifive_spi_wait(struct sifive_spi *spi, u32 bit) +{ + return wait_for_bit_le32(spi->regs + SIFIVE_SPI_REG_IP, + bit, true, 100, false); +} + static int sifive_spi_xfer(struct udevice *dev, unsigned int bitlen, const void *dout, void *din, unsigned long flags) { struct udevice *bus = dev->parent; struct sifive_spi *spi = dev_get_priv(bus); struct dm_spi_slave_platdata *slave_plat = dev_get_parent_platdata(dev); - const unsigned char *tx_ptr = dout; + const u8 *tx_ptr = dout; u8 *rx_ptr = din; u32 remaining_len; int ret; @@ -217,31 +224,37 @@ static int sifive_spi_xfer(struct udevice *dev, unsigned int bitlen, return ret; } - sifive_spi_prep_transfer(spi, true, slave_plat); + sifive_spi_prep_transfer(spi, slave_plat, rx_ptr); remaining_len = bitlen / 8; while (remaining_len) { - int n_words, tx_words, rx_words; - - n_words = min(remaining_len, spi->fifo_depth); + unsigned int n_words = min(remaining_len, spi->fifo_depth); + unsigned int tx_words, rx_words; /* Enqueue n_words for transmission */ - if (tx_ptr) { - for (tx_words = 0; tx_words < n_words; ++tx_words) { - sifive_spi_tx(spi, tx_ptr); - sifive_spi_rx(spi, NULL); - tx_ptr++; - } + for (tx_words = 0; tx_words < n_words; tx_words++) { + if (!tx_ptr) + sifive_spi_tx(spi, NULL); + else + sifive_spi_tx(spi, tx_ptr++); } - /* Read out all the data from the RX FIFO */ if (rx_ptr) { - for (rx_words = 0; rx_words < n_words; ++rx_words) { - sifive_spi_tx(spi, NULL); - sifive_spi_rx(spi, rx_ptr); - rx_ptr++; - } + /* Wait for transmission + reception to complete */ + writel(n_words - 1, spi->regs + SIFIVE_SPI_REG_RXMARK); + ret = sifive_spi_wait(spi, SIFIVE_SPI_IP_RXWM); + if (ret) + return ret; + + /* Read out all the data from the RX FIFO */ + for (rx_words = 0; rx_words < n_words; rx_words++) + sifive_spi_rx(spi, rx_ptr++); + } else { + /* Wait for transmission to complete */ + ret = sifive_spi_wait(spi, SIFIVE_SPI_IP_TXWM); + if (ret) + return ret; } remaining_len -= n_words; @@ -395,6 +408,10 @@ static void sifive_spi_init_hw(struct sifive_spi *spi) /* Watermark interrupts are disabled by default */ writel(0, spi->regs + SIFIVE_SPI_REG_IE); + /* Default watermark FIFO threshold values */ + writel(1, spi->regs + SIFIVE_SPI_REG_TXMARK); + writel(0, spi->regs + SIFIVE_SPI_REG_RXMARK); + /* Set CS/SCK Delays and Inactive Time to defaults */ writel(SIFIVE_SPI_DELAY0_CSSCK(1) | SIFIVE_SPI_DELAY0_SCKCS(1), spi->regs + SIFIVE_SPI_REG_DELAY0); From patchwork Thu Apr 23 17:00:56 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jagan Teki X-Patchwork-Id: 238403 List-Id: U-Boot discussion From: jagan at amarulasolutions.com (Jagan Teki) Date: Thu, 23 Apr 2020 22:30:56 +0530 Subject: [PATCH v4 4/5] riscv: dts: hifive-unleashed-a00: Add -u-boot.dtsi In-Reply-To: <20200423170057.1976-1-jagan@amarulasolutions.com> References: <20200423170057.1976-1-jagan@amarulasolutions.com> Message-ID: <20200423170057.1976-5-jagan@amarulasolutions.com> Add U-Boot specific dts file for hifive-unleashed-a00, this would help to add u-boot specific properties and other node changes without touching the base dts(i) files which are easy to sync from Linux. Added spi2 alias for qspi2 as an initial u-boot specific property change. spi probing in current dm model is very much rely on aliases numbering. Even though the qspi2 can't come under any associated spi nor flash it would require to specify the same to make proper binding happen for other spi slaves. Signed-off-by: Jagan Teki Reviewed-by: Bin Meng Acked-by: Rick Chen --- Changes for v4: - update licence arch/riscv/dts/hifive-unleashed-a00-u-boot.dtsi | 10 ++++++++++ 1 file changed, 10 insertions(+) create mode 100644 arch/riscv/dts/hifive-unleashed-a00-u-boot.dtsi diff --git a/arch/riscv/dts/hifive-unleashed-a00-u-boot.dtsi b/arch/riscv/dts/hifive-unleashed-a00-u-boot.dtsi new file mode 100644 index 0000000000..8a784b5661 --- /dev/null +++ b/arch/riscv/dts/hifive-unleashed-a00-u-boot.dtsi @@ -0,0 +1,10 @@ +// SPDX-License-Identifier: (GPL-2.0 OR MIT) +/* + * Copyright (C) 2019 Jagan Teki + */ + +/ { + aliases { + spi2 = &qspi2; + }; +}; From patchwork Thu Apr 23 17:00:57 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jagan Teki X-Patchwork-Id: 238404 List-Id: U-Boot discussion From: jagan at amarulasolutions.com (Jagan Teki) Date: Thu, 23 Apr 2020 22:30:57 +0530 Subject: [PATCH v4 5/5] sifive: fu540: Enable spi-nor flash support In-Reply-To: <20200423170057.1976-1-jagan@amarulasolutions.com> References: <20200423170057.1976-1-jagan@amarulasolutions.com> Message-ID: <20200423170057.1976-6-jagan@amarulasolutions.com> HiFive Unleashed A00 support is25wp256 spi-nor flash, So enable the same and add test result log for future reference. Tested on SiFive FU540 board. Signed-off-by: Jagan Teki Reviewed-by: Bin Meng Acked-by: Rick Chen --- Changes for v4: - none arch/riscv/dts/hifive-unleashed-a00-u-boot.dtsi | 1 + board/sifive/fu540/Kconfig | 3 +++ 2 files changed, 4 insertions(+) diff --git a/arch/riscv/dts/hifive-unleashed-a00-u-boot.dtsi b/arch/riscv/dts/hifive-unleashed-a00-u-boot.dtsi index 8a784b5661..2aebfab646 100644 --- a/arch/riscv/dts/hifive-unleashed-a00-u-boot.dtsi +++ b/arch/riscv/dts/hifive-unleashed-a00-u-boot.dtsi @@ -5,6 +5,7 @@ / { aliases { + spi0 = &qspi0; spi2 = &qspi2; }; }; diff --git a/board/sifive/fu540/Kconfig b/board/sifive/fu540/Kconfig index 5ca21474de..75661f35f8 100644 --- a/board/sifive/fu540/Kconfig +++ b/board/sifive/fu540/Kconfig @@ -26,6 +26,7 @@ config BOARD_SPECIFIC_OPTIONS # dummy imply CMD_FS_GENERIC imply CMD_NET imply CMD_PING + imply CMD_SF imply CLK_SIFIVE imply CLK_SIFIVE_FU540_PRCI imply DOS_PARTITION @@ -40,6 +41,8 @@ config BOARD_SPECIFIC_OPTIONS # dummy imply SIFIVE_SERIAL imply SPI imply SPI_SIFIVE + imply SPI_FLASH + imply SPI_FLASH_ISSI imply MMC imply MMC_SPI imply MMC_BROKEN_CD