On 12/06/2018 08:30 AM, masonccyang@xxxxxxxxxxx wrote: > Hi Marek, Hi, >> >> Re: [PATCH v2 1/2] spi: Add Renesas R-Car Gen3 RPC SPI controller > driver >> >> >> >> On 12/03/2018 10:18 AM, Mason Yang wrote: >> >> > Add a driver for Renesas R-Car Gen3 RPC SPI controller. >> >> > >> >> > Signed-off-by: Mason Yang <masonccyang@xxxxxxxxxxx> >> >> >> >> What changed in this V2 ? >> >> >> >> [...] >> > >> > see some description in [PATH v2 0/2] >> >> I don't see any V2: list there. >> > > including > 1) remove RPC clock enable/dis-able control, > 2) patch run time PM, > 3) add RPC module software reset, > 4) add regmap, > 5) other coding style and so on. Please include a detailed changelog in each subsequent patch series. >> >> > +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; >> >> > + >> >> > + 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, 0x0); >> >> > + regmap_write(rpc->regmap, RPC_SMCMR, rpc->cmd); >> >> > + regmap_write(rpc->regmap, RPC_SMDMCR, rpc->dummy); >> >> > + regmap_write(rpc->regmap, RPC_SMADR, rpc->addr); >> >> > + >> >> > + if (tx_buf) { >> >> > + smenr = rpc->smenr; >> >> > + >> >> > + while (pos < rpc->xferlen) { >> >> > + u32 nbytes = rpc->xferlen - pos; >> >> > + >> >> > + regmap_write(rpc->regmap, RPC_SMWDR0, >> >> > + *(u32 *)(tx_buf + pos)); >> >> >> >> *(u32 *) cast is probably not needed , fix casts globally. >> > >> > It must have it! >> >> Why ? > > Get a compiler warning due to tx_bug is void *, as Geert replied. The compiler warning is usually an indication that this is something to check, not silence with a type cast. > Using get_unaligned(), patched code would be > ----------------------------------------------------- > regmap_write(rpc->regmap, RPC_SMWDR0, > get_unaligned((u32 *)(tx_buf + pos))); > ---------------------------------------------------- Do you need the cast if you use get_unaligned() ? >> >> > + rpc->xferlen = *(u32 *)len; >> >> > + rpc->totalxferlen += *(u32 *)len; >> >> > + } else { >> >> > + rpc->smenr |= RPC_SMENR_SPIDE(rpc_bits_xfer >> >> > + (op->data.nbytes)) | RPC_SMENR_SPIDB >> >> > + (fls(op->data.buswidth >> 1)); >> >> >> >> Drop parenthesis around fls() >> > >> > ? >> > no way. >> >> I would really appreciate it if you could explain things instead. >> >> Geert already did so, by pointing out this is a confusing code >> formatting problem and how it should be fixed, so no need to repeat >> that. But I hope you understand how that sort of explanation is far more >> valuable than "no way" kind of reply. > > okay, understood. > > >> >> > + >> >> > + xfercnt = xferpos; >> >> > + rpc->xferlen = xfer[--xferpos].len; >> >> > + rpc->cmd = RPC_SMCMR_CMD(((u8 *)xfer[0].tx_buf)[0]); >> >> >> >> Is the cast needed ? >> > >> > yes! >> >> Why ? > > Get a compiler warning due to tx_bug is void *, as Geert replied. > Using get_unaligned(), patched code would be > --------------------------------------------------------------- > rpc->cmd = RPC_SMCMR_CMD(get_unaligned((u8 *)xfer[0].tx_buf)); > ---------------------------------------------------------------- See above >> >> > + rpc->smenr = RPC_SMENR_CDE | RPC_SMENR_CDB(fls(xfer[0].tx_nbits >> >>> 1)); >> >> > + rpc->addr = 0; >> >> > + >> >> > + if (xfercnt > 2 && xfer[1].len && xfer[1].tx_buf) { >> >> > + rpc->smenr |= RPC_SMENR_ADB(fls(xfer[1].tx_nbits >> 1)); >> >> > + for (i = 0; i < xfer[1].len; i++) >> >> > + rpc->addr |= (u32)((u8 *)xfer[1].tx_buf)[i] >> >> > + << (8 * (xfer[1].len - i - 1)); >> >> > + >> >> > + if (xfer[1].len == 4) >> >> > + rpc->smenr |= RPC_SMENR_ADE(0xf); >> >> > + else >> >> > + rpc->smenr |= RPC_SMENR_ADE(0x7); >> >> > + } >> >> > + >> >> > + switch (xfercnt) { >> >> > + case 2: >> >> > + if (xfer[1].rx_buf) { >> >> > + rpc->smenr |= RPC_SMENR_SPIDE(rpc_bits_xfer >> >> > + (xfer[1].len)) | RPC_SMENR_SPIDB(fls >> >> > + (xfer[1].rx_nbits >> 1)); >> >> > + } else if (xfer[1].tx_buf) { >> >> > + rpc->smenr |= RPC_SMENR_SPIDE(rpc_bits_xfer >> >> > + (xfer[1].len)) | RPC_SMENR_SPIDB(fls >> >> > + (xfer[1].tx_nbits >> 1)); >> >> > + } >> >> > + break; >> >> > + >> >> > + case 3: >> >> > + if (xfer[2].len && xfer[2].rx_buf && !xfer[2].tx_buf) { >> >> > + rpc->smenr |= RPC_SMENR_SPIDE(rpc_bits_xfer >> >> > + (xfer[2].len)) | RPC_SMENR_SPIDB(fls >> >> > + (xfer[2].rx_nbits >> 1)); >> >> >> >> It seems this SMENR pattern repeats itself throughout the driver, can >> >> this be improved / deduplicated ? >> > >> > It seems no way! >> >> Why ? > > okay, I patch this with for( ) loop. Please do, let's see how it looks . >> >> > + } else if (xfer[2].len && xfer[2].tx_buf && !xfer[2].rx_buf) { >> >> > + rpc->smenr |= RPC_SMENR_SPIDE(rpc_bits_xfer >> >> > + (xfer[2].len)) | RPC_SMENR_SPIDB(fls >> >> > + (xfer[2].tx_nbits >> 1)); >> >> > + } >> >> > + break; >> >> > + >> >> > + case 4: >> >> > + if (xfer[2].len && xfer[2].tx_buf) { >> >> > + rpc->smenr |= RPC_SMENR_DME; >> >> > + rpc->dummy = RPC_SMDMCR_DMCYC(xfer[2].len); >> >> > + } >> >> > + >> >> > + if (xfer[3].len && xfer[3].rx_buf) { >> >> > + rpc->smenr |= RPC_SMENR_SPIDE(rpc_bits_xfer >> >> > + (xfer[3].len)) | RPC_SMENR_SPIDB(fls >> >> > + (xfer[3].rx_nbits >> 1)); >> >> > + } >> >> > + break; >> >> > + >> >> > + default: >> >> > + break; >> >> > + } >> >> > +} >> >> > + >> >> > +static int rpc_spi_xfer_message(struct rpc_spi *rpc, struct >> >> spi_transfer *t) >> >> > +{ >> >> > + int ret; >> >> > + >> >> > + ret = rpc_spi_set_freq(rpc, t->speed_hz); >> >> > + if (ret) >> >> > + return ret; >> >> > + >> >> > + ret = rpc_spi_io_xfer(rpc, >> >> > + rpc->xfer_dir == SPI_MEM_DATA_OUT ? >> >> > + t->tx_buf : NULL, >> >> > + rpc->xfer_dir == SPI_MEM_DATA_IN ? >> >> > + t->rx_buf : NULL); >> >> > + >> >> > + return ret; >> >> > +} >> >> > + >> >> > +static int rpc_spi_transfer_one_message(struct spi_master *master, >> >> > + struct spi_message *msg) >> >> > +{ >> >> > + struct rpc_spi *rpc = spi_master_get_devdata(master); >> >> > + struct spi_transfer *t; >> >> > + int ret; >> >> > + >> >> > + rpc_spi_transfer_setup(rpc, msg); >> >> > + >> >> > + list_for_each_entry(t, &msg->transfers, transfer_list) { >> >> > + if (!list_is_last(&t->transfer_list, &msg->transfers)) >> >> > + continue; >> >> > + ret = rpc_spi_xfer_message(rpc, t); >> >> > + if (ret) >> >> > + goto out; >> >> > + } >> >> > + >> >> > + msg->status = 0; >> >> > + msg->actual_length = rpc->totalxferlen; >> >> > +out: >> >> > + spi_finalize_current_message(master); >> >> > + return 0; >> >> > +} >> >> > + >> >> > +static const struct regmap_range rpc_spi_volatile_ranges[] = { >> >> > + regmap_reg_range(RPC_SMRDR0, RPC_SMRDR0), >> >> > + regmap_reg_range(RPC_SMWDR0, RPC_SMWDR0), >> >> >> >> Why is SMWDR volatile ? >> > >> > No matter is write-back or write-through. >> >> Oh, do you want to assure the SMWDR value is always written directly to >> the hardware ? > > yes, > >> >> btw. I think SMRDR should be precious ? > > so, you think I should drop > regmap_reg_range(RPC_SMWDR0, RPC_SMWDR0) No, I am asking whether SMRDR should be marked precious or not. [...] > CONFIDENTIALITY NOTE: > > This e-mail and any attachments may contain confidential information > and/or personal data, which is protected by applicable laws. Please be > reminded that duplication, disclosure, distribution, or use of this > e-mail (and/or its attachments) or any part thereof is prohibited. If > you receive this e-mail in error, please notify us immediately and > delete this mail as well as its attachment(s) from your system. In > addition, please be informed that collection, processing, and/or use of > personal data is prohibited unless expressly permitted by personal data > protection laws. Thank you for your attention and cooperation. > > Macronix International Co., Ltd. Can you do something about this ^ please ? -- Best regards, Marek Vasut