RE: [PATCH v2 3/5] spi: Add support for Renesas CSI

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Hi Geert,

Thanks for your feedback!

> From: Geert Uytterhoeven <geert@xxxxxxxxxxxxxx>
> Subject: Re: [PATCH v2 3/5] spi: Add support for Renesas CSI
> 
> Hi Fabrizio,
> 
> On Thu, Jun 22, 2023 at 1:34 PM Fabrizio Castro
> <fabrizio.castro.jz@xxxxxxxxxxx> wrote:
> > The RZ/V2M SoC comes with the Clocked Serial Interface (CSI)
> > IP, which is a master/slave SPI controller.
> >
> > This commit adds a driver to support CSI master mode.
> >
> > Signed-off-by: Fabrizio Castro <fabrizio.castro.jz@xxxxxxxxxxx>
> > ---
> >
> > v2: edited includes in drivers/spi/spi-rzv2m-csi.c
> 
> Thanks for your patch!
> 
> > --- a/drivers/spi/Kconfig
> > +++ b/drivers/spi/Kconfig
> > @@ -825,6 +825,12 @@ config SPI_RSPI
> >         help
> >           SPI driver for Renesas RSPI and QSPI blocks.
> >
> > +config SPI_RZV2M_CSI
> > +       tristate "Renesas RZV2M CSI controller"
> 
> RZ/V2M (patch sent)

Thanks for this.

> 
> > +       depends on ARCH_RENESAS || COMPILE_TEST
> > +       help
> > +         SPI driver for Renesas RZ/V2M Clocked Serial Interface (CSI)
> > +
> >  config SPI_QCOM_QSPI
> >         tristate "QTI QSPI controller"
> >         depends on ARCH_QCOM || COMPILE_TEST
> 
> > --- /dev/null
> > +++ b/drivers/spi/spi-rzv2m-csi.c
> > @@ -0,0 +1,667 @@
> > +// SPDX-License-Identifier: GPL-2.0-or-later
> > +/*
> > + * Renesas RZ/V2M Clocked Serial Interface (CSI) driver
> > + *
> > + * Copyright (C) 2023 Renesas Electronics Corporation
> > + */
> > +
> > +#include <linux/clk.h>
> > +#include <linux/count_zeros.h>
> > +#include <linux/interrupt.h>
> > +#include <linux/iopoll.h>
> > +#include <linux/platform_device.h>
> > +#include <linux/reset.h>
> > +#include <linux/spi/spi.h>
> > +
> > +/* Registers */
> > +#define CSI_MODE               0x00    /* CSI mode control */
> > +#define CSI_CLKSEL             0x04    /* CSI clock select */
> > +#define CSI_CNT                        0x08    /* CSI control */
> > +#define CSI_INT                        0x0C    /* CSI interrupt status */
> > +#define CSI_IFIFOL             0x10    /* CSI receive FIFO level display
> */
> > +#define CSI_OFIFOL             0x14    /* CSI transmit FIFO level display
> */
> > +#define CSI_IFIFO              0x18    /* CSI receive window */
> > +#define CSI_OFIFO              0x1C    /* CSI transmit window */
> > +#define CSI_FIFOTRG            0x20    /* CSI FIFO trigger level */
> > +
> > +/* CSI_MODE */
> > +#define CSI_MODE_CSIE          BIT(7)
> > +#define CSI_MODE_TRMD          BIT(6)
> > +#define CSI_MODE_CCL           BIT(5)
> > +#define CSI_MODE_DIR           BIT(4)
> > +#define CSI_MODE_CSOT          BIT(0)
> > +
> > +#define CSI_MODE_SETUP         0x00000040
> > +
> > +/* CSI_CLKSEL */
> > +#define CSI_CLKSEL_CKP         BIT(17)
> > +#define CSI_CLKSEL_DAP         BIT(16)
> > +#define CSI_CLKSEL_SLAVE       BIT(15)
> > +#define CSI_CLKSEL_CKS         GENMASK(14, 1)
> > +
> > +/* CSI_CNT */
> > +#define CSI_CNT_CSIRST         BIT(28)
> > +#define CSI_CNT_R_TRGEN                BIT(19)
> > +#define CSI_CNT_UNDER_E                BIT(13)
> > +#define CSI_CNT_OVERF_E                BIT(12)
> > +#define CSI_CNT_TREND_E                BIT(9)
> > +#define CSI_CNT_CSIEND_E       BIT(8)
> > +#define CSI_CNT_T_TRGR_E       BIT(4)
> > +#define CSI_CNT_R_TRGR_E       BIT(0)
> > +
> > +/* CSI_INT */
> > +#define CSI_INT_UNDER          BIT(13)
> > +#define CSI_INT_OVERF          BIT(12)
> > +#define CSI_INT_TREND          BIT(9)
> > +#define CSI_INT_CSIEND         BIT(8)
> > +#define CSI_INT_T_TRGR         BIT(4)
> > +#define CSI_INT_R_TRGR         BIT(0)
> > +
> > +/* CSI_FIFOTRG */
> > +#define CSI_FIFOTRG_R_TRG       GENMASK(2, 0)
> > +
> > +#define CSI_FIFO_SIZE_BYTES    32
> > +#define CSI_FIFO_HALF_SIZE     16
> > +#define CSI_EN_DIS_TIMEOUT_US  100
> > +#define CSI_CKS_MAX            0x3FFF
> > +
> > +#define UNDERRUN_ERROR         BIT(0)
> > +#define OVERFLOW_ERROR         BIT(1)
> > +#define TX_TIMEOUT_ERROR       BIT(2)
> > +#define RX_TIMEOUT_ERROR       BIT(3)
> > +
> > +#define CSI_MAX_SPI_SCKO       8000000
> > +
> > +struct rzv2m_csi_priv {
> > +       void __iomem *base;
> > +       struct clk *csiclk;
> > +       struct clk *pclk;
> > +       struct device *dev;
> > +       struct spi_controller *controller;
> > +       const u8 *txbuf;
> > +       u8 *rxbuf;
> > +       int buffer_len;
> > +       int bytes_sent;
> > +       int bytes_received;
> > +       int bytes_to_transfer;
> > +       int words_to_transfer;
> 
> All these ints should be unsigned.

Will change.

> 
> > +       unsigned char bytes_per_word;
> 
> 3-byte gap
> 
> > +       wait_queue_head_t wait;
> > +       u8 errors;
> 
> 3 byte gap
> 
> > +       u32 status;
> > +};

I'll go over the gaps and improve.

> 
> > +
> > +static int rzv2m_csi_fill_txfifo(struct rzv2m_csi_priv *csi)
> > +{
> > +       int i;
> 
> unsigned int

Will change.

> 
> > +
> > +       if (readl(csi->base + CSI_OFIFOL))
> > +               return -EIO;
> > +
> > +       if (csi->bytes_per_word == 2) {
> > +               u16 *buf = (u16 *)csi->txbuf;
> 
> I think you can get rid of the casts by making rxbuf a const void *.

I'll try and see if I can improve this.

> 
> > +
> > +               for (i = 0; i < csi->words_to_transfer; i++)
> > +                       writel(buf[i], csi->base + CSI_OFIFO);
> > +       } else {
> > +               u8 *buf = (u8 *)csi->txbuf;
> > +
> > +               for (i = 0; i < csi->words_to_transfer; i++)
> > +                       writel(buf[i], csi->base + CSI_OFIFO);
> > +       }
> > +
> > +       csi->txbuf += csi->bytes_to_transfer;
> > +       csi->bytes_sent += csi->bytes_to_transfer;
> > +
> > +       return 0;
> > +}
> > +
> > +static int rzv2m_csi_read_rxfifo(struct rzv2m_csi_priv *csi)
> > +{
> > +       int i;
> > +
> > +       if (readl(csi->base + CSI_IFIFOL) != csi->bytes_to_transfer)
> > +               return -EIO;
> > +
> > +       if (csi->bytes_per_word == 2) {
> > +               u16 *buf = (u16 *)csi->rxbuf;
> 
> Similar for rxbuf.

Okay.

> 
> > +
> > +               for (i = 0; i < csi->words_to_transfer; i++)
> > +                       buf[i] = (u16)readl(csi->base + CSI_IFIFO);
> > +       } else {
> > +               u8 *buf = (u8 *)csi->rxbuf;
> > +
> > +               for (i = 0; i < csi->words_to_transfer; i++)
> > +                       buf[i] = (u8)readl(csi->base + CSI_IFIFO);
> > +       }
> > +
> > +       csi->rxbuf += csi->bytes_to_transfer;
> > +       csi->bytes_received += csi->bytes_to_transfer;
> > +
> > +       return 0;
> > +}
> > +
> > +static inline void rzv2m_csi_calc_current_transfer(struct rzv2m_csi_priv
> *csi)
> > +{
> > +       int bytes_transferred = max_t(int, csi->bytes_received, csi-
> >bytes_sent);
> > +       int bytes_remaining = csi->buffer_len - bytes_transferred;
> > +       int to_transfer;
> 
> unsigned...

Okay

> 
> > +
> > +       if (csi->txbuf)
> > +               /*
> > +                * Leaving a little bit of headroom in the FIFOs makes it
> very
> > +                * hard to raise an overflow error (which is only possible
> > +                * when IP transmits and receives at the same time).
> > +                */
> > +               to_transfer = min_t(int, CSI_FIFO_HALF_SIZE,
> bytes_remaining);
> > +       else
> > +               to_transfer = min_t(int, CSI_FIFO_SIZE_BYTES,
> bytes_remaining);
> 
> Why min_t(int, ...)? Both values are int.
> 
> It would be better to make both unsigned, though.

Will do.

> 
> > +
> > +       if (csi->bytes_per_word == 2)
> > +               to_transfer >>= 1;
> > +
> > +       /*
> > +        * We can only choose a trigger level from a predefined set of
> values.
> > +        * This will pick a value that is the greatest possible integer
> that's
> > +        * less than or equal to the number of bytes we need to transfer.
> > +        * This may result in multiple smaller transfers.
> > +        */
> > +       csi->words_to_transfer = x_trg_words[to_transfer - 1];
> > +
> > +       if (csi->bytes_per_word == 2)
> > +               csi->bytes_to_transfer = csi->words_to_transfer << 1;
> > +       else
> > +               csi->bytes_to_transfer = csi->words_to_transfer;
> > +}

Thanks,
Fab

> 
> Gr{oetje,eeting}s,
> 
>                         Geert
> 
> --
> Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- geert@linux-
> m68k.org
> 
> In personal conversations with technical people, I call myself a hacker. But
> when I'm talking to journalists I just say "programmer" or something like
> that.
>                                 -- Linus Torvalds




[Index of Archives]     [Linux Samsung SOC]     [Linux Wireless]     [Linux Kernel]     [ATH6KL]     [Linux Bluetooth]     [Linux Netdev]     [Kernel Newbies]     [IDE]     [Security]     [Git]     [Netfilter]     [Bugtraq]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Linux ATA RAID]     [Samba]     [Device Mapper]

  Powered by Linux