[PATCH 0/4] Add octal mode on Renesas Draak board

The MX66UW2G345G is Macronix flash with single and octal mode. Hence, for testing purposes, this patch adds SPI-MEM framework to support the octal mode on Renesas Draak board. The datasheet can be found in https://www.macronix.com/zh-tw/products/NOR-Flash/Pages/octaflash.aspx#1.8V.
zhengxunli (4): mtd: spi-nor-ids: Add Macronix MX66UW2G345G arm: dts: Add DT spi0 alias to Renesas Draak board arm: dts: r8a77995-u-boot: Add SPI Flash Support driver: spi: renesas_rpc_spi: Add mem_ops
arch/arm/dts/r8a77995-draak.dts | 1 + arch/arm/dts/r8a77995-u-boot.dtsi | 11 ++- drivers/mtd/spi/spi-nor-ids.c | 1 + drivers/spi/renesas_rpc_spi.c | 144 ++++++++++++++++++++++++++++++++++++++ 4 files changed, 156 insertions(+), 1 deletion(-)

The MX66UW2G345G is Macronix Flash with SINGLE and OCTAL I/O. Hence, add SPI_NOR_OCTAL_READ flag for this flash.
Signed-off-by: zhengxunli zhengxunli@mxic.com.tw --- drivers/mtd/spi/spi-nor-ids.c | 1 + 1 file changed, 1 insertion(+)
diff --git a/drivers/mtd/spi/spi-nor-ids.c b/drivers/mtd/spi/spi-nor-ids.c index 5bd5dd3..4e8ab46 100644 --- a/drivers/mtd/spi/spi-nor-ids.c +++ b/drivers/mtd/spi/spi-nor-ids.c @@ -162,6 +162,7 @@ const struct flash_info spi_nor_ids[] = { { INFO("mx66l1g45g", 0xc2201b, 0, 64 * 1024, 2048, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, { INFO("mx25l1633e", 0xc22415, 0, 64 * 1024, 32, SPI_NOR_QUAD_READ | SPI_NOR_4B_OPCODES | SECT_4K) }, { INFO("mx25r6435f", 0xc22817, 0, 64 * 1024, 128, SECT_4K) }, + { INFO("mx66uw2g345g", 0xc2943c, 0, 64 * 1024, 4096, SECT_4K | SPI_NOR_OCTAL_READ | SPI_NOR_4B_OPCODES) }, #endif
#ifdef CONFIG_SPI_FLASH_STMICRO /* STMICRO */

The spi0 alias is needed by the environment code to retrieve the SPI flash. This patch provides the spi0 aliases, for Renesas Draak board.
Signed-off-by: zhengxunli zhengxunli@mxic.com.tw --- arch/arm/dts/r8a77995-draak.dts | 1 + 1 file changed, 1 insertion(+)
diff --git a/arch/arm/dts/r8a77995-draak.dts b/arch/arm/dts/r8a77995-draak.dts index 67634cb..cc2bc89 100644 --- a/arch/arm/dts/r8a77995-draak.dts +++ b/arch/arm/dts/r8a77995-draak.dts @@ -17,6 +17,7 @@ aliases { serial0 = &scif2; ethernet0 = &avb; + spi0 = &rpc; };
backlight: backlight {

Add U-Boot SPI Flash support for the Renesas Draak board and configure RX and TX bus-width values to support octal I/O mode.
Signed-off-by: zhengxunli zhengxunli@mxic.com.tw --- arch/arm/dts/r8a77995-u-boot.dtsi | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-)
diff --git a/arch/arm/dts/r8a77995-u-boot.dtsi b/arch/arm/dts/r8a77995-u-boot.dtsi index 0917a80..aa23af1 100644 --- a/arch/arm/dts/r8a77995-u-boot.dtsi +++ b/arch/arm/dts/r8a77995-u-boot.dtsi @@ -14,7 +14,16 @@ reg = <0 0xee200000 0 0x100>, <0 0x08000000 0 0>; clocks = <&cpg CPG_MOD 917>; bank-width = <2>; - status = "disabled"; + status = "okay"; + #address-cells = <1>; + #size-cells = <0>; + + flash0 { + compatible = "jedec,spi-nor"; + reg = <0>; + spi-tx-bus-width = <1>; + spi-rx-bus-width = <8>; + }; }; }; };

On 1/20/21 6:30 AM, zhengxunli wrote:
Add U-Boot SPI Flash support for the Renesas Draak board and configure RX and TX bus-width values to support octal I/O mode.
We had this discussion before off-list, this patch should be dropped since this component is not present on the Draak board.
[...]

This patch adds an implementation of exec_op, which support octal mode and quad mode for reading flash and support existing single mode for reading and writing flash concurrently.
Signed-off-by: zhengxunli zhengxunli@mxic.com.tw --- drivers/spi/renesas_rpc_spi.c | 144 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 144 insertions(+)
diff --git a/drivers/spi/renesas_rpc_spi.c b/drivers/spi/renesas_rpc_spi.c index 1057651..ee8d49c 100644 --- a/drivers/spi/renesas_rpc_spi.c +++ b/drivers/spi/renesas_rpc_spi.c @@ -16,6 +16,7 @@ #include <linux/bug.h> #include <linux/errno.h> #include <spi.h> +#include <spi-mem.h> #include <wait_bit.h>
#define RPC_CMNCR 0x0000 /* R/W */ @@ -367,6 +368,144 @@ err: return ret; }
+static int rpc_spi_exec_mem_op(struct spi_slave *slave, + const struct spi_mem_op *op) +{ + struct rpc_spi_priv *priv; + struct udevice *bus; + u32 wloop = (op->data.dir == SPI_MEM_DATA_OUT) ? + DIV_ROUND_UP(op->data.nbytes, 4) : 0; + u32 smenr, smcr, cmncr; + u32 *datout; + int ret = 0; + + bus = slave->dev->parent; + priv = dev_get_priv(bus); + + if (op->cmd.buswidth == 2 || op->addr.buswidth == 2 || + op->data.buswidth == 2 || op->addr.nbytes > 4) + return -ENOTSUPP; + + smenr = 0; + + if (op->data.dir == SPI_MEM_DATA_OUT || + op->data.dir == SPI_MEM_NO_DATA) { + rpc_spi_claim_bus(slave->dev, true); + + writel(0, priv->regs + RPC_SMCR); + + /* Commnad(1) */ + writel(RPC_SMCMR_CMD(op->cmd.opcode), priv->regs + RPC_SMCMR); + + smenr |= RPC_SMENR_CDE; + + smenr |= RPC_SMENR_CDB(fls(op->cmd.buswidth) - 1); + + /* Address(3 or 4) */ + if (op->addr.nbytes) { + writel(op->addr.val, priv->regs + RPC_SMADR); + if (op->addr.nbytes == 3) + smenr |= RPC_SMENR_ADE(0x7); + else + smenr |= RPC_SMENR_ADE(0xf); + smenr |= RPC_SMENR_ADB(fls(op->addr.buswidth) - 1); + } else { + writel(0, priv->regs + RPC_SMADR); + } + + /* Dummy(0) */ + writel(0, priv->regs + RPC_SMDMCR); + + writel(0, priv->regs + RPC_SMOPR); + + writel(0, priv->regs + RPC_SMDRENR); + + /* Data(n) */ + if (op->data.nbytes) { + datout = (u32 *)op->data.buf.out; + + smenr |= RPC_SMENR_SPIDE(0xf); + + smenr |= RPC_SMENR_SPIDB(fls(op->data.buswidth) - 1); + + while (wloop--) { + smcr = RPC_SMCR_SPIWE | RPC_SMCR_SPIE; + if (wloop >= 1) + smcr |= RPC_SMCR_SSLKP; + writel(smenr, priv->regs + RPC_SMENR); + writel(*datout, priv->regs + RPC_SMWDR0); + writel(smcr, priv->regs + RPC_SMCR); + ret = rpc_spi_wait_tend(slave->dev); + if (ret) + goto err; + datout++; + smenr = RPC_SMENR_SPIDE(0xf); + } + + ret = rpc_spi_wait_sslf(slave->dev); + } else { + writel(smenr, priv->regs + RPC_SMENR); + writel(RPC_SMCR_SPIE, priv->regs + RPC_SMCR); + ret = rpc_spi_wait_tend(slave->dev); + } + } else { /* Read data only, using DRx ext access */ + rpc_spi_claim_bus(slave->dev, false); + + if (op->cmd.buswidth > 4 || op->addr.buswidth > 4 || + op->data.buswidth > 4) { + cmncr = readl(priv->regs + RPC_CMNCR); + cmncr |= RPC_CMNCR_BSZ(1); + writel(cmncr, priv->regs + RPC_CMNCR); + } + + /* Command(1) */ + writel(RPC_DRCMR_CMD(op->cmd.opcode), priv->regs + RPC_DRCMR); + + smenr |= RPC_DRENR_CDE; + + smenr |= RPC_DRENR_CDB(fls(op->cmd.buswidth) - 1); + + /* Address(3 or 4) */ + if (op->addr.nbytes) { + if (op->addr.nbytes == 3) + smenr |= RPC_DRENR_ADE(0x7); + else + smenr |= RPC_DRENR_ADE(0xf); + smenr |= RPC_DRENR_ADB(fls(op->addr.buswidth) - 1); + } + + /* Dummy(n) */ + if (op->dummy.nbytes) { + writel(op->dummy.nbytes, priv->regs + RPC_DRDMCR); + smenr |= RPC_DRENR_DME; + } else { + writel(0, priv->regs + RPC_DRDMCR); + } + + writel(0, priv->regs + RPC_DROPR); + + if (op->data.buswidth > 4) + smenr |= RPC_DRENR_SPIDB(2); + else + smenr |= RPC_DRENR_SPIDB(fls(op->data.buswidth) - 1); + + writel(smenr, priv->regs + RPC_DRENR); + + if (op->data.nbytes) { + memcpy_fromio(op->data.buf.in, + (void *)(priv->extr + op->addr.val), + op->data.nbytes); + } else { + readl(priv->extr); /* Dummy read */ + } + } + +err: + rpc_spi_release_bus(slave->dev); + + return ret; +} + static int rpc_spi_set_speed(struct udevice *bus, uint speed) { /* This is a SPI NOR controller, do nothing. */ @@ -441,10 +580,15 @@ static int rpc_spi_of_to_plat(struct udevice *bus) return 0; }
+static const struct spi_controller_mem_ops rpc_spi_mem_ops = { + .exec_op = rpc_spi_exec_mem_op, +}; + static const struct dm_spi_ops rpc_spi_ops = { .xfer = rpc_spi_xfer, .set_speed = rpc_spi_set_speed, .set_mode = rpc_spi_set_mode, + .mem_ops = &rpc_spi_mem_ops, };
static const struct udevice_id rpc_spi_ids[] = {
participants (2)
-
Marek Vasut
-
zhengxunli