summaryrefslogtreecommitdiff
path: root/drivers/spi/renesas_rpc_spi.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/spi/renesas_rpc_spi.c')
-rw-r--r--drivers/spi/renesas_rpc_spi.c206
1 files changed, 104 insertions, 102 deletions
diff --git a/drivers/spi/renesas_rpc_spi.c b/drivers/spi/renesas_rpc_spi.c
index cb2b8fb64d..51c37d72eb 100644
--- a/drivers/spi/renesas_rpc_spi.c
+++ b/drivers/spi/renesas_rpc_spi.c
@@ -17,6 +17,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 */
@@ -140,6 +141,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)
@@ -167,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)
@@ -202,18 +200,35 @@ 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
+ * 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);
+}
+
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,79 +248,91 @@ 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);
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;
@@ -314,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);
- }
- } 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);
+ ret = rpc_spi_wait_tend(spi->dev);
}
- 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;
}
@@ -380,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;
@@ -443,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[] = {