diff options
Diffstat (limited to 'drivers/spi/renesas_rpc_spi.c')
| -rw-r--r-- | drivers/spi/renesas_rpc_spi.c | 206 | 
1 files changed, 104 insertions, 102 deletions
| diff --git a/drivers/spi/renesas_rpc_spi.c b/drivers/spi/renesas_rpc_spi.c index cb2b8fb64de..51c37d72eb6 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[] = { | 
