From 49096f9924a7ec94e16a9736254f6fa752779dcb Mon Sep 17 00:00:00 2001 From: Hai Pham Date: Mon, 16 Aug 2021 09:26:36 +0700 Subject: mtd: spi: renesas: Extract strobe delay setting code into separate function Move strobe delay setting code into extra function and reflect the latest setting in datasheet (R-Car Gen3 v2.20, R-Car V3U v0.50). i.e. STRTIM[2:0] should be set to 110 (RCar M3-W) or 111 (Other products) This is also a preparation for new R-Car Gen4 SoC which has 4-bits STRTIM Reviewed-by: Marek Vasut Signed-off-by: Hai Pham Signed-off-by: Marek Vasut # Fix for RZ/A1 --- drivers/spi/renesas_rpc_spi.c | 29 +++++++++++++++++++++-------- 1 file changed, 21 insertions(+), 8 deletions(-) diff --git a/drivers/spi/renesas_rpc_spi.c b/drivers/spi/renesas_rpc_spi.c index cb2b8fb64de..07ff2d29fd4 100644 --- a/drivers/spi/renesas_rpc_spi.c +++ b/drivers/spi/renesas_rpc_spi.c @@ -202,18 +202,31 @@ static void rpc_spi_flush_read_cache(struct udevice *dev) } +static u32 rpc_spi_get_strobe_delay(void) +{ +#ifndef CONFIG_RZA1 + u32 cpu_type = rmobile_get_cpu_type(); + + /* + * NOTE: RPC_PHYCNT_STRTIM value: + * 0: On H3 ES1.x (not supported in mainline U-Boot) + * 6: On M3 ES1.x + * 7: On other R-Car Gen3 + */ + if (cpu_type == RMOBILE_CPU_TYPE_R8A7796 && rmobile_get_cpu_rev_integer() == 1) + return RPC_PHYCNT_STRTIM(6); + else +#endif + return RPC_PHYCNT_STRTIM(7); +} + static int rpc_spi_claim_bus(struct udevice *dev, bool manual) { struct udevice *bus = dev->parent; struct rpc_spi_priv *priv = dev_get_priv(bus); - /* - * NOTE: The 0x260 are undocumented bits, but they must be set. - * NOTE: On H3 ES1.x (not supported in mainline U-Boot), the - * RPC_PHYCNT_STRTIM shall be 0, while on newer parts, the - * RPC_PHYCNT_STRTIM shall be 6. - */ - writel(RPC_PHYCNT_CAL | RPC_PHYCNT_STRTIM(6) | 0x260, + /* NOTE: The 0x260 are undocumented bits, but they must be set. */ + writel(RPC_PHYCNT_CAL | rpc_spi_get_strobe_delay() | 0x260, priv->regs + RPC_PHYCNT); writel((manual ? RPC_CMNCR_MD : 0) | RPC_CMNCR_SFDE | RPC_CMNCR_MOIIO_HIZ | RPC_CMNCR_IOFV_HIZ | RPC_CMNCR_BSZ(0), @@ -233,7 +246,7 @@ static int rpc_spi_release_bus(struct udevice *dev) struct rpc_spi_priv *priv = dev_get_priv(bus); /* NOTE: The 0x260 are undocumented bits, but they must be set. */ - writel(RPC_PHYCNT_STRTIM(6) | 0x260, priv->regs + RPC_PHYCNT); + writel(rpc_spi_get_strobe_delay() | 0x260, priv->regs + RPC_PHYCNT); rpc_spi_flush_read_cache(dev); -- cgit v1.2.3 From 89208dba38035007dcbe3618b2beda0aafac5fca Mon Sep 17 00:00:00 2001 From: Hai Pham Date: Thu, 25 Aug 2022 10:32:56 +0700 Subject: mtd: spi: renesas: Enable SPI_FLASH_SFDP_SUPPORT Enable support for parsing and auto discovery of parameters for SPI NOR flashes using Serial Flash Discoverable Parameters (SFDP) tables as per JESD216 standard. Reviewed-by: Marek Vasut Signed-off-by: Hai Pham Signed-off-by: Cong Dang Signed-off-by: Marek Vasut # Make SFDP the default unconditionally --- drivers/spi/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig index 4f435fd2681..453a5983b2a 100644 --- a/drivers/spi/Kconfig +++ b/drivers/spi/Kconfig @@ -382,7 +382,7 @@ config SPI_QUP config RENESAS_RPC_SPI bool "Renesas RPC SPI driver" depends on RCAR_64 || RZA1 - imply SPI_FLASH_BAR + imply SPI_FLASH_SFDP_SUPPORT help Enable the Renesas RPC SPI driver, used to access SPI NOR flash on Renesas RCar Gen3 SoCs. This uses driver model and requires a -- cgit v1.2.3 From 8e8cb7e1a845a36e73ff839732328c76d2cc0e99 Mon Sep 17 00:00:00 2001 From: Hai Pham Date: Thu, 5 Aug 2021 14:38:26 +0700 Subject: mtd: spi: renesas: Add R-Car Gen4 support Support RPC SPI on R-Car Gen4 R8A779F0 S4 and R8A779G0 V4H SoCs. Reviewed-by: Marek Vasut Signed-off-by: Hai Pham Signed-off-by: Marek Vasut [Marek: Squash S4 and V4H patches, fix brackets around STRTIM2] --- drivers/spi/renesas_rpc_spi.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/spi/renesas_rpc_spi.c b/drivers/spi/renesas_rpc_spi.c index 07ff2d29fd4..af1b368f69e 100644 --- a/drivers/spi/renesas_rpc_spi.c +++ b/drivers/spi/renesas_rpc_spi.c @@ -140,6 +140,7 @@ #define PRC_PHYCNT_EXDS BIT(21) #define RPC_PHYCNT_OCT BIT(20) #define RPC_PHYCNT_STRTIM(v) (((v) & 0x7) << 15) +#define RPC_PHYCNT_STRTIM2(v) ((((v) & 0x7) << 15) | (((v) & 0x8) << 24)) #define RPC_PHYCNT_WBUF2 BIT(4) #define RPC_PHYCNT_WBUF BIT(2) #define RPC_PHYCNT_MEM(v) (((v) & 0x3) << 0) @@ -212,9 +213,13 @@ static u32 rpc_spi_get_strobe_delay(void) * 0: On H3 ES1.x (not supported in mainline U-Boot) * 6: On M3 ES1.x * 7: On other R-Car Gen3 + * 15: On R-Car Gen4 */ if (cpu_type == RMOBILE_CPU_TYPE_R8A7796 && rmobile_get_cpu_rev_integer() == 1) return RPC_PHYCNT_STRTIM(6); + else if (cpu_type == RMOBILE_CPU_TYPE_R8A779F0 || + cpu_type == RMOBILE_CPU_TYPE_R8A779G0) + return RPC_PHYCNT_STRTIM2(15); else #endif return RPC_PHYCNT_STRTIM(7); -- cgit v1.2.3 From 2e6a1f9fde934ac15eab28fa46495e8d31a29bce Mon Sep 17 00:00:00 2001 From: Cong Dang Date: Thu, 25 Aug 2022 06:06:54 +0700 Subject: mtd: spi: renesas: Add 4 bytes address mode support This patch adds 4-byte address mode support. Because traditional access based on FIFO/shift register, it's complex to specify information like opcode, address length, dummy bytes etc to flash. Replace the traditional access by spi-mem layer which is essential to make 4-byte address mode support possible. Reviewed-by: Marek Vasut Signed-off-by: Cong Dang Signed-off-by: Hai Pham Signed-off-by: Marek Vasut --- drivers/spi/renesas_rpc_spi.c | 172 +++++++++++++++++++----------------------- 1 file changed, 78 insertions(+), 94 deletions(-) diff --git a/drivers/spi/renesas_rpc_spi.c b/drivers/spi/renesas_rpc_spi.c index af1b368f69e..51c37d72eb6 100644 --- a/drivers/spi/renesas_rpc_spi.c +++ b/drivers/spi/renesas_rpc_spi.c @@ -17,6 +17,7 @@ #include #include #include +#include #include #define RPC_CMNCR 0x0000 /* R/W */ @@ -168,10 +169,6 @@ struct rpc_spi_priv { fdt_addr_t regs; fdt_addr_t extr; struct clk clk; - - u8 cmdcopy[8]; - u32 cmdlen; - bool cmdstarted; }; static int rpc_spi_wait_sslf(struct udevice *dev) @@ -258,72 +255,84 @@ static int rpc_spi_release_bus(struct udevice *dev) return 0; } -static int rpc_spi_xfer(struct udevice *dev, unsigned int bitlen, - const void *dout, void *din, unsigned long flags) +static int rpc_spi_mem_exec_op(struct spi_slave *spi, + const struct spi_mem_op *op) { - struct udevice *bus = dev->parent; + struct udevice *bus = spi->dev->parent; struct rpc_spi_priv *priv = dev_get_priv(bus); - u32 wlen = dout ? (bitlen / 8) : 0; - u32 rlen = din ? (bitlen / 8) : 0; - u32 wloop = DIV_ROUND_UP(wlen, 4); - u32 smenr, smcr, offset; + const void *dout = op->data.buf.out ? op->data.buf.out : NULL; + void *din = op->data.buf.in ? op->data.buf.in : NULL; int ret = 0; - - if (!priv->cmdstarted) { - if (!wlen || rlen) - BUG(); - - memcpy(priv->cmdcopy, dout, wlen); - priv->cmdlen = wlen; - - /* Command transfer start */ - priv->cmdstarted = true; - if (!(flags & SPI_XFER_END)) - return 0; - } - - offset = (priv->cmdcopy[1] << 16) | (priv->cmdcopy[2] << 8) | - (priv->cmdcopy[3] << 0); + u32 offset = 0; + u32 smenr, smcr; smenr = 0; + offset = op->addr.val; + + switch (op->data.dir) { + case SPI_MEM_DATA_IN: + rpc_spi_claim_bus(spi->dev, false); + + writel(0, priv->regs + RPC_DRCMR); + writel(RPC_DRCMR_CMD(op->cmd.opcode), priv->regs + RPC_DRCMR); + smenr |= RPC_DRENR_CDE; + + writel(0, priv->regs + RPC_DREAR); + if (op->addr.nbytes == 4) { + writel(RPC_DREAR_EAV(offset >> 25) | RPC_DREAR_EAC(1), + priv->regs + RPC_DREAR); + smenr |= RPC_DRENR_ADE(0xF); + } else if (op->addr.nbytes == 3) { + smenr |= RPC_DRENR_ADE(0x7); + } else { + smenr |= RPC_DRENR_ADE(0); + } - if (wlen || (!rlen && !wlen) || flags == SPI_XFER_ONCE) { - if (wlen && flags == SPI_XFER_END) - smenr = RPC_SMENR_SPIDE(0xf); + writel(0, priv->regs + RPC_DRDMCR); + if (op->dummy.nbytes) { + writel(8 * op->dummy.nbytes - 1, priv->regs + RPC_DRDMCR); + smenr |= RPC_DRENR_DME; + } - rpc_spi_claim_bus(dev, true); + writel(0, priv->regs + RPC_DROPR); + writel(smenr, priv->regs + RPC_DRENR); - writel(0, priv->regs + RPC_SMCR); + memcpy_fromio(din, (void *)(priv->extr + offset), op->data.nbytes); - if (priv->cmdlen >= 1) { /* Command(1) */ - writel(RPC_SMCMR_CMD(priv->cmdcopy[0]), - priv->regs + RPC_SMCMR); - smenr |= RPC_SMENR_CDE; - } else { - writel(0, priv->regs + RPC_SMCMR); - } + rpc_spi_release_bus(spi->dev); + break; + case SPI_MEM_DATA_OUT: + case SPI_MEM_NO_DATA: + rpc_spi_claim_bus(spi->dev, true); - if (priv->cmdlen >= 4) { /* Address(3) */ - writel(offset, priv->regs + RPC_SMADR); - smenr |= RPC_SMENR_ADE(7); - } else { - writel(0, priv->regs + RPC_SMADR); - } + writel(0, priv->regs + RPC_SMCR); + writel(0, priv->regs + RPC_SMCMR); + writel(RPC_SMCMR_CMD(op->cmd.opcode), priv->regs + RPC_SMCMR); + smenr |= RPC_SMENR_CDE; + + writel(0, priv->regs + RPC_SMADR); + if (op->addr.nbytes == 4) + smenr |= RPC_SMENR_ADE(0xF); + else if (op->addr.nbytes == 3) + smenr |= RPC_SMENR_ADE(0x7); + else + smenr |= RPC_SMENR_ADE(0); + writel(offset, priv->regs + RPC_SMADR); - if (priv->cmdlen >= 5) { /* Dummy(n) */ - writel(8 * (priv->cmdlen - 4) - 1, - priv->regs + RPC_SMDMCR); + writel(0, priv->regs + RPC_SMDMCR); + if (op->dummy.nbytes) { + writel(8 * op->dummy.nbytes - 1, priv->regs + RPC_SMDMCR); smenr |= RPC_SMENR_DME; - } else { - writel(0, priv->regs + RPC_SMDMCR); } writel(0, priv->regs + RPC_SMOPR); - writel(0, priv->regs + RPC_SMDRENR); - if (wlen && flags == SPI_XFER_END) { + if (dout && op->data.nbytes) { u32 *datout = (u32 *)dout; + u32 wloop = DIV_ROUND_UP(op->data.nbytes, 4); + + smenr |= RPC_SMENR_SPIDE(0xF); while (wloop--) { smcr = RPC_SMCR_SPIWE | RPC_SMCR_SPIE; @@ -332,57 +341,28 @@ static int rpc_spi_xfer(struct udevice *dev, unsigned int bitlen, writel(smenr, priv->regs + RPC_SMENR); writel(*datout, priv->regs + RPC_SMWDR0); writel(smcr, priv->regs + RPC_SMCR); - ret = rpc_spi_wait_tend(dev); - if (ret) - goto err; + ret = rpc_spi_wait_tend(spi->dev); + if (ret) { + rpc_spi_release_bus(spi->dev); + return ret; + } datout++; - smenr = RPC_SMENR_SPIDE(0xf); + smenr &= (~RPC_SMENR_CDE & ~RPC_SMENR_ADE(0xF)); } - ret = rpc_spi_wait_sslf(dev); - + ret = rpc_spi_wait_sslf(spi->dev); } else { writel(smenr, priv->regs + RPC_SMENR); writel(RPC_SMCR_SPIE, priv->regs + RPC_SMCR); - ret = rpc_spi_wait_tend(dev); + ret = rpc_spi_wait_tend(spi->dev); } - } else { /* Read data only, using DRx ext access */ - rpc_spi_claim_bus(dev, false); - if (priv->cmdlen >= 1) { /* Command(1) */ - writel(RPC_DRCMR_CMD(priv->cmdcopy[0]), - priv->regs + RPC_DRCMR); - smenr |= RPC_DRENR_CDE; - } else { - writel(0, priv->regs + RPC_DRCMR); - } - - if (priv->cmdlen >= 4) /* Address(3) */ - smenr |= RPC_DRENR_ADE(7); - - if (priv->cmdlen >= 5) { /* Dummy(n) */ - writel(8 * (priv->cmdlen - 4) - 1, - priv->regs + RPC_DRDMCR); - smenr |= RPC_DRENR_DME; - } else { - writel(0, priv->regs + RPC_DRDMCR); - } - - writel(0, priv->regs + RPC_DROPR); - - writel(smenr, priv->regs + RPC_DRENR); - - if (rlen) - memcpy_fromio(din, (void *)(priv->extr + offset), rlen); - else - readl(priv->extr); /* Dummy read */ + rpc_spi_release_bus(spi->dev); + break; + default: + break; } -err: - priv->cmdstarted = false; - - rpc_spi_release_bus(dev); - return ret; } @@ -398,6 +378,10 @@ static int rpc_spi_set_mode(struct udevice *bus, uint mode) return 0; } +static const struct spi_controller_mem_ops rpc_spi_mem_ops = { + .exec_op = rpc_spi_mem_exec_op +}; + static int rpc_spi_bind(struct udevice *parent) { const void *fdt = gd->fdt_blob; @@ -461,9 +445,9 @@ static int rpc_spi_of_to_plat(struct udevice *bus) } 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[] = { -- cgit v1.2.3