Re: [PATCH 1/2] spi: Add Renesas R-Car RPC SPI controller driver
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
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
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)