Re: [PATCH v4 1/2] spi: Add Renesas R-Car Gen3 RPC SPI controller driver
Hello! On 01/03/2019 09:35 AM, masonccy...@mxic.com.tw wrote: [...] >> >> > +#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) >> >> >> >>Like I said, the above 2 aren't documented in the manual v1.00... >> > >> > okay, add a description as: >> > /* RPC_CMNCR_IO3FV/IO2FV are undocumented bit, but must be set */ >> > #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)) >> > >> > is it ok? >> >>Yes. But would have been enough if you just commented with // on >> the same line -- >> it seems these are legal now... > > on the same line is over 80 char, > #define RPC_CMNCR_IO3FV(val)(((val) & 0x3) << 14) // undocumented bit, > but must be set > #define RPC_CMNCR_IO2FV(val)(((val) & 0x3) << 12) // undocumented bit, > but must be set > > or just > #define RPC_CMNCR_IO3FV(val)(((val) & 0x3) << 14) // undocumented bit > #define RPC_CMNCR_IO2FV(val)(((val) & 0x3) << 12) // undocumented bit > is it ok ? The second variant would be enough. [...] >> >> > + ret = rpc_spi_set_freq(rpc, desc->mem->spi->max_speed_hz); >> >> > + if (ret) >> >> > + return ret; >> >> > + >> >> > + rpc_spi_mem_set_prep_op_cfg(desc->mem->spi, >> >> > +>info.op_tmpl, , ); >> >> > + >> >> > + regmap_write(rpc->regmap, RPC_CMNCR, RPC_CMNCR_SFDE | >> >> > + RPC_CMNCR_MOIIO_HIZ | RPC_CMNCR_IOFV_HIZ | >> >> > + RPC_CMNCR_BSZ(0)); >> >> >> >>Why not set this in the probing time and only set/clear the MD bit? >> >> >> > >> > same above! >> > Make sure the value in these register are setting correctly >> > before RPC starting a SPI transfer. >> >>You can set it once and only change the bits you need to change >> afterwards. >> What's wrong with it? >> > > if so, it will patch to: > -- > regmap_read(rpc->regmap, RPC_CMNCR, ); > data &= ~RPC_CMNCR_MD; > regmap_write(rpc->regmap, RPC_CMNCR, data); > -- > Do you think this way is better ? No, this one is better: regmap_update_bits(rpc->regmap, RPC_CMNCR, RPC_CMNCR_MD, 0); > maybe this is better, > write(read(rpc->regs + RPC_CMNCR) & ~RPC_CMNCR_MD, > rpc->regs + RPC_CMNCR); It's effectively the same code as your 1st variant... [...] >> >> > +static void rpc_spi_transfer_setup(struct rpc_spi *rpc, >> >> > + struct spi_message *msg) >> >> > +{ >> >> [...] >> >> > + for (i = xfercnt - 1; i < xfercnt && xfercnt > 1; i++) { >> >> > + if (xfer[i].rx_buf) { >> >> > + rpc->smenr |= >> >> > +RPC_SMENR_SPIDE(rpc_bits_set(xfer[i].len)) | >> >> > +RPC_SMENR_SPIDB >> >> > +(ilog2((unsigned int)xfer[i].rx_nbits)); >> >> >> >>Mhm, I would indent this contination line by 1 extra tab... >> >> >> >> > + } else if (xfer[i].tx_buf) { >> >> > + rpc->smenr |= >> >> > +RPC_SMENR_SPIDE(rpc_bits_set(xfer[i].len)) | >> >> > +RPC_SMENR_SPIDB >> >> > +(ilog2((unsigned int)xfer[i].tx_nbits)); >> >> >> >>And this one... >> > >> > like this ? >> > >> > for (i = xfercnt - 1; i < xfercnt && xfercnt > 1; i++) { >> > if (xfer[i].rx_buf) { >> > rpc->smenr |= >> > RPC_SMENR_SPIDE(rpc_bits_set(xfer >> [i].len)) | >> > RPC_SMENR_SPIDB( >> > ilog2((unsigned int)xfer >> [i].rx_nbits)); >> > } else if (xfer[i].tx_buf) { >> > rpc->smenr |= >> > RPC_SMENR_SPIDE(rpc_bits_set(xfer >> [i].len)) | >> > RPC_SMENR_SPIDB( >> > ilog2((unsigned int)xfer >> [i].tx_nbits)); >> >>I didn't mean you need to leave ( on the first line, can be left >> on the new >> line, as before. >> > > how about this style ? > - > for (i = xfercnt - 1; i < xfercnt && xfercnt > 1; i++) { > if (xfer[i].rx_buf) { >
Re: [PATCH v4 1/2] spi: Add Renesas R-Car Gen3 RPC SPI controller driver
Hello! On 12/26/2018 07:24 AM, masonccy...@mxic.com.tw wrote: >> [...] >> > diff --git a/drivers/spi/spi-renesas-rpc.c b/drivers/spi/spi-renesas-rpc.c >> > new file mode 100644 >> > index 000..6dd739a >> > --- /dev/null >> > +++ b/drivers/spi/spi-renesas-rpc.c >> > @@ -0,0 +1,788 @@ [...] >> > +#define RPC_CMNCR 0x /* R/W */ >> > +#define RPC_CMNCR_MD BIT(31) >> > +#define RPC_CMNCR_SFDE BIT(24) /* undocumented bit but must be set */ >> > +#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) >> >>Like I said, the above 2 aren't documented in the manual v1.00... > > okay, add a description as: > /* RPC_CMNCR_IO3FV/IO2FV are undocumented bit, but must be set */ > #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)) > > is it ok? Yes. But would have been enough if you just commented with // on the same line -- it seems these are legal now... >> [...] >> > +static void rpc_spi_hw_init(struct rpc_spi *rpc) >> > +{ >> > + /* >> > +* NOTE: The 0x260 are undocumented bits, but they must be set. >> > +* RPC_PHYCNT_STRTIM is strobe timing adjustment bit, >> > +* 0x0 : the delay is biggest, >> > +* 0x1 : the delay is 2nd biggest, >> > +* On H3 ES1.x, the value should be 0, while on others, >> > +* the value should be 6. >> > +*/ >> > + regmap_write(rpc->regmap, RPC_PHYCNT, RPC_PHYCNT_CAL | >> > + RPC_PHYCNT_STRTIM(6) | 0x260); >> > + >> > + /* >> > +* NOTE: The 0x31511144 are undocumented bits, but they must be set >> > +* for RPC_PHYOFFSET1. >> > +*The 0x31 are undocumented bits, but they must be set >> > +*for RPC_PHYOFFSET2. >> > +*/ >> > + regmap_write(rpc->regmap, RPC_PHYOFFSET1, 0x31511144); >> >> 0x3000 is documented, missed that last time... >> > > okay,patch it to: > > #define RPC_PHYOFFSET1_DDRTMG(v) (((v) & 0x3) << 28) > > regmap_write(rpc->regmap, RPC_PHYOFFSET1, > RPC_PHYOFFSET1_DDRTMG(3) | 0x1511144); > OK, thanx. >> [...] >> > +static int rpc_spi_do_reset(struct rpc_spi *rpc) >> > +{ >> > + int ret; >> > + >> > + ret = reset_control_reset(rpc->rstc); >> > + if (ret) >> > + return ret; >> > + >> > + return 0; >> > +} >> >>Like I said, this function folds to a mere reset_control_reset() call... >> > > Do you mean just drop this rpc_spi_do_reset( ) I mean we don't need this wrapper, we can call reset_contreol_reset() directly. > because driver is never > come here from an error path ? You are mixing things up -- of course we call it from the error path. >> [...] >> > + >> > + while (pos < rpc->xferlen) { >> > + u32 nbytes = rpc->xferlen - pos; >> > + >> > + if (nbytes > 4) >> > +nbytes = 4; >> > + >> > + smcr = rpc->smcr | RPC_SMCR_SPIE; >> > + >> > + if (rpc->xferlen > 4 && rpc->xferlen < 8 && pos == 0) >> > +smcr |= RPC_SMCR_SSLKP; >> > + >> > + regmap_write(rpc->regmap, RPC_SMENR, smenr); >> > + regmap_write(rpc->regmap, RPC_SMCR, smcr); >> > + ret = wait_msg_xfer_end(rpc); >> > + if (ret) >> > +goto out; >> > + >> > + regmap_read(rpc->regmap, RPC_SMRDR0, ); >> > + memcpy(rx_buf + pos, , nbytes); >> > + pos += nbytes; >> > + >> > + if (rpc->xferlen > 4 && rpc->xferlen < 8 && pos == 4) { >> >>This looks hackish. What I think matters is whether the address >> bits are set or not. >> Anyway, maybe it works OK for you but not for me (on V3H), the 4th >> byte of the JEDEC ID >> is clobbered from 0 to 3... I've been working on a better workaround >> using Marek's >> approach (reading in extended memory mode) -- should port to v4 of >> your patch yet... > > Do you mean I also patch external address space read mode > for RPC to read ID and data ? No, I meant using the dirmap read mode for RDID and company. I have the patch almost ready now and I hope you'll merge it with yours... either that or add it to your series atop of this patch. [...] > I also think this is kind of RPC HW bug in manual I/O mode. Yes. > Renesas FAE@Taiwan has replied me that their the last bare-metal code, > mini-monitor v5.x still use one command to read 4 bytes data each time > and I think RPC HW designer
Re: [PATCH v4 1/2] spi: Add Renesas R-Car Gen3 RPC SPI controller driver
On 12/24/2018 09:52 AM, Mason Yang wrote: > Add a driver for Renesas R-Car Gen3 RPC SPI controller. > > Signed-off-by: Mason Yang > --- > drivers/spi/Kconfig | 6 + > drivers/spi/Makefile | 1 + > drivers/spi/spi-renesas-rpc.c | 788 > ++ > 3 files changed, 795 insertions(+) > create mode 100644 drivers/spi/spi-renesas-rpc.c > > diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig > index 7d3a5c9..54b40f8 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 Gen3 RPC SPI controller" Well, technically it's called RPC-IF in the manual, not just RPC... > + depends on ARCH_RENESAS || COMPILE_TEST > + help > + SPI driver for Renesas R-Car Gen3 RPC. > + > config SPI_QCOM_QSPI > tristate "QTI QSPI controller" > depends on ARCH_QCOM [...] > diff --git a/drivers/spi/spi-renesas-rpc.c b/drivers/spi/spi-renesas-rpc.c > new file mode 100644 > index 000..6dd739a > --- /dev/null > +++ b/drivers/spi/spi-renesas-rpc.c > @@ -0,0 +1,788 @@ > +// SPDX-License-Identifier: GPL-2.0 > +// > +// Copyright (C) 2018 ~ 2019 Renesas Solutions Corp. > +// Copyright (C) 2018 Macronix International Co., Ltd. > +// > +// R-Car Gen3 RPC SPI/QSPI/Octa driver > +// > +// Authors: > +// Mason Yang > +// > + > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > + > +#include > + > +#define RPC_CMNCR0x /* R/W */ > +#define RPC_CMNCR_MD BIT(31) > +#define RPC_CMNCR_SFDE BIT(24) /* undocumented bit but must be > set */ > +#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) Like I said, the above 2 aren't documented in the manual v1.00... > +#define RPC_CMNCR_IO0FV(val) (((val) & 0x3) << 8) Only this one is... [...] > +static void rpc_spi_hw_init(struct rpc_spi *rpc) > +{ > + /* > + * NOTE: The 0x260 are undocumented bits, but they must be set. > + * RPC_PHYCNT_STRTIM is strobe timing adjustment bit, > + * 0x0 : the delay is biggest, > + * 0x1 : the delay is 2nd biggest, > + * On H3 ES1.x, the value should be 0, while on others, > + * the value should be 6. > + */ > + regmap_write(rpc->regmap, RPC_PHYCNT, RPC_PHYCNT_CAL | > + RPC_PHYCNT_STRTIM(6) | 0x260); > + > + /* > + * NOTE: The 0x31511144 are undocumented bits, but they must be set > + * for RPC_PHYOFFSET1. > + * The 0x31 are undocumented bits, but they must be set > + * for RPC_PHYOFFSET2. > + */ > + regmap_write(rpc->regmap, RPC_PHYOFFSET1, 0x31511144); 0x3000 is documented, missed that last time... [...] > +static int rpc_spi_do_reset(struct rpc_spi *rpc) > +{ > + int ret; > + > + ret = reset_control_reset(rpc->rstc); > + if (ret) > + return ret; > + > + return 0; > +} Like I said, this function folds to a mere reset_control_reset() call... [...] > +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; Looks like we don't need this variable... > + > + regmap_write(rpc->regmap, RPC_CMNCR, RPC_CMNCR_MD | RPC_CMNCR_SFDE | > + RPC_CMNCR_MOIIO_HIZ | RPC_CMNCR_IOFV_HIZ | > + RPC_CMNCR_BSZ(0)); > + regmap_write(rpc->regmap, RPC_SMDRENR, 0); > + regmap_write(rpc->regmap, RPC_SMCMR, rpc->cmd); > + regmap_write(rpc->regmap, RPC_SMDMCR, rpc->dummy); > + regmap_write(rpc->regmap, RPC_SMADR, rpc->addr); [...] > + } else if (rx_buf) { > + smenr = rpc->smenr; Could be done before the *if*... > + > + while (pos < rpc->xferlen) { > + u32 nbytes = rpc->xferlen - pos; > + > + if (nbytes > 4) > + nbytes = 4; > + > + smcr = rpc->smcr | RPC_SMCR_SPIE; > + > + if (rpc->xferlen > 4 && rpc->xferlen < 8 && pos == 0) > + smcr |= RPC_SMCR_SSLKP; > + > + regmap_write(rpc->regmap, RPC_SMENR, smenr); > + regmap_write(rpc->regmap, RPC_SMCR,
[PATCH v4 1/2] spi: Add Renesas R-Car Gen3 RPC SPI controller driver
Add a driver for Renesas R-Car Gen3 RPC SPI controller. Signed-off-by: Mason Yang --- drivers/spi/Kconfig | 6 + drivers/spi/Makefile | 1 + drivers/spi/spi-renesas-rpc.c | 788 ++ 3 files changed, 795 insertions(+) create mode 100644 drivers/spi/spi-renesas-rpc.c diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig index 7d3a5c9..54b40f8 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 Gen3 RPC SPI controller" + depends on ARCH_RENESAS || COMPILE_TEST + help + SPI driver for Renesas R-Car Gen3 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..6dd739a --- /dev/null +++ b/drivers/spi/spi-renesas-rpc.c @@ -0,0 +1,788 @@ +// SPDX-License-Identifier: GPL-2.0 +// +// Copyright (C) 2018 ~ 2019 Renesas Solutions Corp. +// Copyright (C) 2018 Macronix International Co., Ltd. +// +// R-Car Gen3 RPC SPI/QSPI/Octa driver +// +// Authors: +// Mason Yang +// + +#include +#include +#include +#include +#include +#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) /* undocumented bit but must be set */ +#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_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) - 1) & 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(c) (((c) & 0x7) << 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_OPD3(o) (((o) & 0xFF) << 24) +#define RPC_SMOPR_OPD2(o) (((o) & 0xFF) << 16) +#define RPC_SMOPR_OPD1(o) (((o) & 0xFF) << 8) +#define RPC_SMOPR_OPD0(o) (((o) & 0xFF) << 0) + +#define RPC_SMENR 0x0030 /* R/W */