Re: [PATCH 1/2] spi: Add Renesas R-Car RPC SPI controller driver

2018-11-19 Thread Mark Brown
On Mon, Nov 19, 2018 at 03:12:00PM +0100, Marek Vasut wrote:
> On 11/19/2018 11:01 AM, Mason Yang wrote:

> > +++ b/drivers/spi/spi-renesas-rpc.c
> > @@ -0,0 +1,750 @@
> > +// SPDX-License-Identifier: GPL-2.0
> > +//
> > +// Copyright (C) 2018 ~ 2019 Renesas Solutions Corp.
> > +// Copyright (C) 2018 Macronix International Co., Ltd.
> > +//
> > +// R-Car D3 RPC SPI/QSPI/Octa driver
> > +//
> > +// Authors:
> > +// Mason Yang 
> > +//

> Fix multiline comment please.

The SPDX header needs to be C++ style so I push people to make the whole
block C++ otherwise it looks messy.


signature.asc
Description: PGP signature


Re: [PATCH 1/2] spi: Add Renesas R-Car RPC SPI controller driver

2018-11-19 Thread Marek Vasut
On 11/19/2018 11:01 AM, Mason Yang wrote:
> Add a driver for Renesas R-Car D3 RPC SPI controller driver.

The RPC supports both HF and SPI, not just SPI. And it's present in all
of Gen3 , not just D3 .

[...]

> +++ b/drivers/spi/spi-renesas-rpc.c
> @@ -0,0 +1,750 @@
> +// SPDX-License-Identifier: GPL-2.0
> +//
> +// Copyright (C) 2018 ~ 2019 Renesas Solutions Corp.
> +// Copyright (C) 2018 Macronix International Co., Ltd.
> +//
> +// R-Car D3 RPC SPI/QSPI/Octa driver
> +//
> +// Authors:
> +//   Mason Yang 
> +//

Fix multiline comment please.

> +#include 
> +#include 
> +#include 
> +#include 
> +#include 
> +#include 
> +#include 
> +#include 

[...]

> +#define RPC_CMNSR0x0048  /* R */
> +#define RPC_CMNSR_SSLF   BIT(1)
> +#define  RPC_CMNSR_TEND  BIT(0)

#define[SPACE] instead of tab

> +#define RPC_DRDMCR   0x0058  /* R/W */
> +#define RPC_DRDRENR  0x005C  /* R/W */
> +
> +#define RPC_SMDMCR   0x0060  /* R/W */
> +#define RPC_SMDMCR_DMCYC(v)  v) - 1) & 0x1F) << 0)
> +
> +#define RPC_SMDRENR  0x0064  /* R/W */
> +#define RPC_SMDRENR_HYPE (0x5 << 12)
> +#define RPC_SMDRENR_ADDREBIT(8)
> +#define RPC_SMDRENR_OPDREBIT(4)
> +#define RPC_SMDRENR_SPIDRE   BIT(0)
> +
> +#define RPC_PHYCNT   0x007C  /* R/W */
> +#define RPC_PHYCNT_CAL   BIT(31)
> +#define PRC_PHYCNT_OCTA_AA   BIT(22)
> +#define PRC_PHYCNT_OCTA_SA   BIT(23)
> +#define PRC_PHYCNT_EXDS  BIT(21)
> +#define RPC_PHYCNT_OCT   BIT(20)
> +#define RPC_PHYCNT_STRTIM(v) (((v) & 0x7) << 15)
> +#define RPC_PHYCNT_WBUF2 BIT(4)
> +#define RPC_PHYCNT_WBUF  BIT(2)
> +#define RPC_PHYCNT_MEM(v)(((v) & 0x3) << 0)
> +
> +#define RPC_PHYOFFSET1   0x0080  /* R/W */
> +#define RPC_PHYOFFSET2   0x0084  /* R/W */
> +
> +#define RPC_WBUF 0x8000  /* Write Buffer */
> +#define RPC_WBUF_SIZE256 /* Write Buffer size */
> +
> +struct rpc_spi {
> + struct clk *clk_rpc;
> + void __iomem *regs;
> + struct {
> + void __iomem *map;
> + dma_addr_t dma;
> + size_t size;
> + } linear;

Does this need it's own struct ?

> + u32 cur_speed_hz;
> + u32 cmd;
> + u32 addr;
> + u32 dummy;
> + u32 smcr;
> + u32 smenr;
> + u32 xferlen;
> + u32 totalxferlen;

This register cache might be a good candidate for regmap ?

> + enum spi_mem_data_dir xfer_dir;
> +};
> +
> +static int rpc_spi_set_freq(struct rpc_spi *rpc, unsigned long freq)
> +{
> + int ret;
> +
> + if (rpc->cur_speed_hz == freq)
> + return 0;
> +
> + clk_disable_unprepare(rpc->clk_rpc);
> + ret = clk_set_rate(rpc->clk_rpc, freq);
> + if (ret)
> + return ret;
> +
> + ret = clk_prepare_enable(rpc->clk_rpc);
> + if (ret)
> + return ret;

Is this clock disable/update/enable really needed ? I'd think that
clk_set_rate() would handle the rate update correctly.

> + rpc->cur_speed_hz = freq;
> + return ret;
> +}
> +
> +static void rpc_spi_hw_init(struct rpc_spi *rpc)
> +{
> + /*
> +  * NOTE: The 0x260 are undocumented bits, but they must be set.
> +  */

FYI:
http://git.denx.de/?p=u-boot.git;a=blob;f=drivers/spi/renesas_rpc_spi.c#l207

I think the STRTIM should be 6 .

> + writel(RPC_PHYCNT_CAL | RPC_PHYCNT_STRTIM(0x3) | 0x260,
> +rpc->regs + RPC_PHYCNT);
> +
> + /*
> +  * NOTE: The 0x31511144 and 0x431 are undocumented bits,
> +  *   but they must be set for RPC_PHYOFFSET1 & RPC_PHYOFFSET2.
> +  */
> + writel(0x31511144, rpc->regs + RPC_PHYOFFSET1);
> + writel(0x431, rpc->regs + RPC_PHYOFFSET2);
> +
> + writel(RPC_SSLDR_SPNDL(7) | RPC_SSLDR_SLNDL(7) |
> +RPC_SSLDR_SCKDL(7), rpc->regs + RPC_SSLDR);
> +}
> +
> +static int wait_msg_xfer_end(struct rpc_spi *rpc)
> +{
> + u32 sts;
> +
> + return readl_poll_timeout(rpc->regs + RPC_CMNSR, sts,
> +   sts & RPC_CMNSR_TEND, 0, USEC_PER_SEC);
> +}
> +
> +static u8 rpc_bits_xfer(u32 nbytes)
> +{
> + u8 databyte;
> +
> + switch (nbytes) {

Did you ever test unaligned writes and reads ? There are some nasty edge
cases in those.

Also, I think you can calculate the number of set bits using a simple
function, so the switch-case might not even be needed.

> + case 1:
> + databyte = 0x8;
> + break;
> + case 2:
> + databyte = 0xc;
> + break;
> + default:
> + databyte = 0xf;
> + break;
> + }
> +
> + return databyte;
> +}
> +
> +static int rpc_spi_io_xfer(struct rpc_spi *rpc,
> +const void *tx_buf, void *rx_buf)
> +{
> + u32 smenr, smcr, data, pos = 0;
> + int ret = 0;
> +
> + writel(RPC_CMNCR_MD | RPC_CMNCR_SFDE | RPC_CMNCR_MOIIO_HIZ |
> +RPC_CMNCR_IOFV_HIZ | RPC_CMNCR_BSZ(0), rpc->regs + 

[PATCH 1/2] spi: Add Renesas R-Car RPC SPI controller driver

2018-11-19 Thread Mason Yang
Add a driver for Renesas R-Car D3 RPC SPI controller driver.

Signed-off-by: Mason Yang 
---
 drivers/spi/Kconfig   |   6 +
 drivers/spi/Makefile  |   1 +
 drivers/spi/spi-renesas-rpc.c | 750 ++
 3 files changed, 757 insertions(+)
 create mode 100644 drivers/spi/spi-renesas-rpc.c

diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig
index 7d3a5c9..093006a 100644
--- a/drivers/spi/Kconfig
+++ b/drivers/spi/Kconfig
@@ -528,6 +528,12 @@ config SPI_RSPI
help
  SPI driver for Renesas RSPI and QSPI blocks.
 
+config SPI_RENESAS_RPC
+   tristate "Renesas R-Car D3 RPC SPI controller"
+   depends on SUPERH || ARCH_RENESAS || COMPILE_TEST
+   help
+ SPI driver for Renesas R-Car D3 RPC.
+
 config SPI_QCOM_QSPI
tristate "QTI QSPI controller"
depends on ARCH_QCOM
diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile
index 3575205..5d5c523 100644
--- a/drivers/spi/Makefile
+++ b/drivers/spi/Makefile
@@ -81,6 +81,7 @@ obj-$(CONFIG_SPI_QUP) += spi-qup.o
 obj-$(CONFIG_SPI_ROCKCHIP) += spi-rockchip.o
 obj-$(CONFIG_SPI_RB4XX)+= spi-rb4xx.o
 obj-$(CONFIG_SPI_RSPI) += spi-rspi.o
+obj-$(CONFIG_SPI_RENESAS_RPC)  += spi-renesas-rpc.o
 obj-$(CONFIG_SPI_S3C24XX)  += spi-s3c24xx-hw.o
 spi-s3c24xx-hw-y   := spi-s3c24xx.o
 spi-s3c24xx-hw-$(CONFIG_SPI_S3C24XX_FIQ) += spi-s3c24xx-fiq.o
diff --git a/drivers/spi/spi-renesas-rpc.c b/drivers/spi/spi-renesas-rpc.c
new file mode 100644
index 000..00b9d8f
--- /dev/null
+++ b/drivers/spi/spi-renesas-rpc.c
@@ -0,0 +1,750 @@
+// SPDX-License-Identifier: GPL-2.0
+//
+// Copyright (C) 2018 ~ 2019 Renesas Solutions Corp.
+// Copyright (C) 2018 Macronix International Co., Ltd.
+//
+// R-Car D3 RPC SPI/QSPI/Octa driver
+//
+// Authors:
+// Mason Yang 
+//
+
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+
+#define RPC_CMNCR  0x  /* R/W */
+#define RPC_CMNCR_MD   BIT(31)
+#define RPC_CMNCR_SFDE BIT(24)
+#define RPC_CMNCR_MOIIO3(val)  (((val) & 0x3) << 22)
+#define RPC_CMNCR_MOIIO2(val)  (((val) & 0x3) << 20)
+#define RPC_CMNCR_MOIIO1(val)  (((val) & 0x3) << 18)
+#define RPC_CMNCR_MOIIO0(val)  (((val) & 0x3) << 16)
+#define RPC_CMNCR_MOIIO_HIZ(RPC_CMNCR_MOIIO0(3) | RPC_CMNCR_MOIIO1(3) | \
+RPC_CMNCR_MOIIO2(3) | RPC_CMNCR_MOIIO3(3))
+#define RPC_CMNCR_IO3FV(val)   (((val) & 0x3) << 14)
+#define RPC_CMNCR_IO2FV(val)   (((val) & 0x3) << 12)
+#define RPC_CMNCR_IO0FV(val)   (((val) & 0x3) << 8)
+#define RPC_CMNCR_IOFV_HIZ (RPC_CMNCR_IO0FV(3) | RPC_CMNCR_IO2FV(3) | \
+RPC_CMNCR_IO3FV(3))
+#define RPC_CMNCR_CPHATBIT(6)
+#define RPC_CMNCR_CPHARBIT(5)
+#define RPC_CMNCR_SSLP BIT(4)
+#define RPC_CMNCR_CPOL BIT(3)
+#define RPC_CMNCR_BSZ(val) (((val) & 0x3) << 0)
+
+#define RPC_SSLDR  0x0004  /* R/W */
+#define RPC_SSLDR_SPNDL(d) (((d) & 0x7) << 16)
+#define RPC_SSLDR_SLNDL(d) (((d) & 0x7) << 8)
+#define RPC_SSLDR_SCKDL(d) (((d) & 0x7) << 0)
+
+#define RPC_DRCR   0x000C  /* R/W */
+#define RPC_DRCR_SSLN  BIT(24)
+#define RPC_DRCR_RBURST(v) (((v) & 0x1F) << 16)
+#define RPC_DRCR_RCF   BIT(9)
+#define RPC_DRCR_RBE   BIT(8)
+#define RPC_DRCR_SSLE  BIT(0)
+
+#define RPC_DRCMR  0x0010  /* R/W */
+#define RPC_DRCMR_CMD(c)   (((c) & 0xFF) << 16)
+#define RPC_DRCMR_OCMD(c)  (((c) & 0xFF) << 0)
+
+#define RPC_DREAR  0x0014  /* R/W */
+#define RPC_DREAR_EAC  BIT(0)
+
+#define RPC_DROPR  0x0018  /* R/W */
+
+#define RPC_DRENR  0x001C  /* R/W */
+#define RPC_DRENR_CDB(o)   (u32)o) & 0x3) << 30))
+#define RPC_DRENR_OCDB(o)  (((o) & 0x3) << 28)
+#define RPC_DRENR_ADB(o)   (((o) & 0x3) << 24)
+#define RPC_DRENR_OPDB(o)  (((o) & 0x3) << 20)
+#define RPC_DRENR_SPIDB(o) (((o) & 0x3) << 16)
+#define RPC_DRENR_DME  BIT(15)
+#define RPC_DRENR_CDE  BIT(14)
+#define RPC_DRENR_OCDE BIT(12)
+#define RPC_DRENR_ADE(v)   (((v) & 0xF) << 8)
+#define RPC_DRENR_OPDE(v)  (((v) & 0xF) << 4)
+
+#define RPC_SMCR   0x0020  /* R/W */
+#define RPC_SMCR_SSLKP BIT(8)
+#define RPC_SMCR_SPIRE BIT(2)
+#define RPC_SMCR_SPIWE BIT(1)
+#define RPC_SMCR_SPIE  BIT(0)
+
+#define RPC_SMCMR  0x0024  /* R/W */
+#define RPC_SMCMR_CMD(c)   (((c) & 0xFF) << 16)
+#define RPC_SMCMR_OCMD(c)  (((c) & 0xFF) << 0)
+
+#define RPC_SMADR  0x0028  /* R/W */
+#define RPC_SMOPR  0x002C  /* R/W */
+#define RPC_SMOPR_OPD0(o)  (((o) & 0xFF) << 0)
+#define RPC_SMOPR_OPD1(o)  (((o) & 0xFF) << 8)
+#define RPC_SMOPR_OPD2(o)  (((o) & 0xFF) << 16)
+#define RPC_SMOPR_OPD3(o)  (((o)