[PATCH v1] driver: spi: add bcm iproc qspi support.

Bharat Gooty bharat.gooty at broadcom.com
Mon Oct 11 09:03:12 CEST 2021


+ Roman
Thanks for the review Jagan. Will look and get back to you.

Thanks,
-Bharat

On Fri, Oct 8, 2021 at 5:57 PM Jagan Teki <jagan at amarulasolutions.com>
wrote:

> On Wed, Aug 25, 2021 at 6:55 PM Bharat Kumar Reddy Gooty
> <bharat.gooty at broadcom.com> wrote:
> >
> > From: Rayagonda Kokatanur <rayagonda.kokatanur at broadcom.com>
> >
> > IPROC qspi driver supports both BSPI and MSPI modes.
> >
> > Signed-off-by: Rayagonda Kokatanur <rayagonda.kokatanur at broadcom.com>
> > Signed-off-by: Bharat Gooty <bharat.gooty at broadcom.com>
> > ---
> >  drivers/spi/Kconfig      |   6 +
> >  drivers/spi/Makefile     |   1 +
> >  drivers/spi/iproc_qspi.c | 736 +++++++++++++++++++++++++++++++++++++++
> >  drivers/spi/iproc_qspi.h |  18 +
> >  4 files changed, 761 insertions(+)
> >  create mode 100644 drivers/spi/iproc_qspi.c
> >  create mode 100644 drivers/spi/iproc_qspi.h
> >
> > diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig
> > index e12699bec7..3253d6badf 100644
> > --- a/drivers/spi/Kconfig
> > +++ b/drivers/spi/Kconfig
> > @@ -178,6 +178,12 @@ config ICH_SPI
> >           access the SPI NOR flash on platforms embedding this Intel
> >           ICH IP core.
> >
> > +config IPROC_QSPI
> > +       bool "QSPI driver for BCM iProc QSPI Controller"
> > +       help
> > +         This selects the BCM iProc QSPI controller.
> > +         This driver support spi flash single, quad and memory reads.
> > +
> >  config KIRKWOOD_SPI
> >         bool "Marvell Kirkwood SPI Driver"
> >         help
> > diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile
> > index d2f24bccef..8697631870 100644
> > --- a/drivers/spi/Makefile
> > +++ b/drivers/spi/Makefile
> > @@ -33,6 +33,7 @@ obj-$(CONFIG_FSL_DSPI) += fsl_dspi.o
> >  obj-$(CONFIG_FSL_ESPI) += fsl_espi.o
> >  obj-$(CONFIG_SYNQUACER_SPI) += spi-synquacer.o
> >  obj-$(CONFIG_ICH_SPI) +=  ich.o
> > +obj-$(CONFIG_IPROC_QSPI) += iproc_qspi.o
> >  obj-$(CONFIG_KIRKWOOD_SPI) += kirkwood_spi.o
> >  obj-$(CONFIG_MESON_SPIFC) += meson_spifc.o
> >  obj-$(CONFIG_MPC8XX_SPI) += mpc8xx_spi.o
> > diff --git a/drivers/spi/iproc_qspi.c b/drivers/spi/iproc_qspi.c
> > new file mode 100644
> > index 0000000000..89c6a56858
> > --- /dev/null
> > +++ b/drivers/spi/iproc_qspi.c
> > @@ -0,0 +1,736 @@
> > +// SPDX-License-Identifier: GPL-2.0+
> > +/*
> > + * Copyright 2020-2021 Broadcom
> > + */
> > +
> > +#include <common.h>
> > +#include <dm.h>
> > +#include <errno.h>
> > +#include <malloc.h>
> > +#include <spi.h>
> > +#include <asm/io.h>
> > +#include <linux/err.h>
> > +#include <linux/mtd/spi-nor.h>
>
> Why spi-nor header in spi driver?
>
> > +#include "iproc_qspi.h"
> > +
> > +/* 175MHz */
> > +#define QSPI_AXI_CLK                           175000000
> > +#define QSPI_DEF_SCK_FREQ                      50000000
> > +#define QSPI_WAIT_TIMEOUT_MS                   200U
> > +#define DWORD_ALIGNED(a)                       (!(((ulong)(a)) & 3))
> > +
> > +/* Chip attributes */
> > +#define SPBR_MIN                               8U
> > +#define SPBR_MAX                               255U
> > +#define NUM_CDRAM                              16U
> > +
> > +#define CDRAM_PCS0                             2
> > +#define CDRAM_CONT                             BIT(7)
> > +#define CDRAM_BITS_EN                          BIT(6)
> > +#define CDRAM_QUAD_MODE                                BIT(8)
> > +#define CDRAM_RBIT_INPUT                       BIT(10)
> > +#define MSPI_SPE                               BIT(6)
> > +#define MSPI_CONT_AFTER_CMD                    BIT(7)
> > +
> > +/* Register fields */
> > +#define MSPI_SPCR0_MSB_BITS_8                  0x00000020
> > +#define BSPI_RAF_CONTROL_START_MASK            0x00000001
> > +#define BSPI_RAF_STATUS_SESSION_BUSY_MASK      0x00000001
> > +#define BSPI_RAF_STATUS_FIFO_EMPTY_MASK                0x00000002
> > +#define BSPI_BITS_PER_PHASE_ADDR_MARK          0x00010000
> > +#define BSPI_BITS_PER_CYCLE_DATA_SHIFT         0
> > +#define BSPI_BITS_PER_CYCLE_ADDR_SHIFT         16
> > +#define BSPI_STRAP_OVERRIDE_DATA_QUAD_SHIFT    3
> > +#define BSPI_STRAP_OVERRIDE_DATA_DUAL_SHIFT    1
> > +#define BSPI_STRAP_OVERRIDE_SHIFT              0
> > +
> > +/* MSPI registers */
> > +#define MSPI_SPCR0_LSB_REG                     0x000
> > +#define MSPI_SPCR0_MSB_REG                     0x004
> > +#define MSPI_SPCR1_LSB_REG                     0x008
> > +#define MSPI_SPCR1_MSB_REG                     0x00c
> > +#define MSPI_NEWQP_REG                         0x010
> > +#define MSPI_ENDQP_REG                         0x014
> > +#define MSPI_SPCR2_REG                         0x018
> > +#define MSPI_STATUS_REG                                0x020
> > +#define MSPI_CPTQP_REG                         0x024
> > +#define MSPI_TXRAM_REG                         0x040
> > +#define MSPI_RXRAM_REG                         0x0c0
> > +#define MSPI_CDRAM_REG                         0x140
> > +#define MSPI_WRITE_LOCK_REG                    0x180
> > +#define MSPI_DISABLE_FLUSH_GEN_REG             0x184
> > +
> > +/* BSPI registers */
> > +#define BSPI_REVISION_ID_REG                   0x000
> > +#define BSPI_SCRATCH_REG                       0x004
> > +#define BSPI_MAST_N_BOOT_CTRL_REG              0x008
> > +#define BSPI_BUSY_STATUS_REG                   0x00c
> > +#define BSPI_INTR_STATUS_REG                   0x010
> > +#define BSPI_B0_STATUS_REG                     0x014
> > +#define BSPI_B0_CTRL_REG                       0x018
> > +#define BSPI_B1_STATUS_REG                     0x01c
> > +#define BSPI_B1_CTRL_REG                       0x020
> > +#define BSPI_STRAP_OVERRIDE_CTRL_REG           0x024
> > +#define BSPI_FLEX_MODE_ENABLE_REG              0x028
> > +#define BSPI_BITS_PER_CYCLE_REG                        0x02C
> > +#define BSPI_BITS_PER_PHASE_REG                        0x030
> > +#define BSPI_CMD_AND_MODE_BYTE_REG             0x034
> > +#define BSPI_FLASH_UPPER_ADDR_BYTE_REG         0x038
> > +#define BSPI_XOR_VALUE_REG                     0x03C
> > +#define BSPI_XOR_ENABLE_REG                    0x040
> > +#define BSPI_PIO_MODE_ENABLE_REG               0x044
> > +#define BSPI_PIO_IODIR_REG                     0x048
> > +#define BSPI_PIO_DATA_REG                      0x04C
> > +
> > +/* RAF registers */
> > +#define BSPI_RAF_START_ADDRESS_REG             0x00
> > +#define BSPI_RAF_NUM_WORDS_REG                 0x04
> > +#define BSPI_RAF_CTRL_REG                      0x08
> > +#define BSPI_RAF_FULLNESS_REG                  0x0C
> > +#define BSPI_RAF_WATERMARK_REG                 0x10
> > +#define BSPI_RAF_STATUS_REG                    0x14
> > +#define BSPI_RAF_READ_DATA_REG                 0x18
> > +#define BSPI_RAF_WORD_CNT_REG                  0x1C
> > +#define BSPI_RAF_CURR_ADDR_REG                 0x20
> > +
> > +#define XFER_DUAL                              BIT(30)
> > +#define XFER_QUAD                              BIT(31)
> > +
> > +/* state */
> > +enum bcm_qspi_state {
> > +       QSPI_STATE_DISABLED,
> > +       QSPI_STATE_MSPI,
> > +       QSPI_STATE_BSPI
> > +};
> > +
> > +/**
> > + * struct bcmspi_priv - qspi private structure
> > + *
> > + * @max_hz: device transfer speed
> > + * @spi_mode: spi mode (SPI_... flags)
> > + * @frequency: spi max frequency
> > + * @state: device state (MSPI/BSPI)
> > + * @bspi_addr: bspi read address
> > + * @mspi_16bit: mspi transfer mode
> > + * @use_bspi: flag to indicate BSPI use for read operation
> > + * @mspi: mspi registers block address
> > + * @bspi: bspi registers block address
> > + * @bspi_raf: bspi raf registers block address
> > + */
> > +struct bcmspi_priv {
> > +       uint max_hz;
> > +       uint spi_mode;
> > +       s32 frequency;
> > +       enum bcm_qspi_state state;
> > +       u32 bspi_addr;
> > +       int mspi_16bit;
> > +       int mode_4byte;
> > +       int use_bspi;
> > +       void __iomem *mspi;
> > +       void __iomem *bspi;
> > +       void __iomem *bspi_raf;
> > +};
> > +
> > +static void bspi_flush_prefetch_buffers(struct bcmspi_priv *priv)
> > +{
> > +       writel(0, priv->bspi + BSPI_B0_CTRL_REG);
> > +       writel(0, priv->bspi + BSPI_B1_CTRL_REG);
> > +       writel(1, priv->bspi + BSPI_B0_CTRL_REG);
> > +       writel(1, priv->bspi + BSPI_B1_CTRL_REG);
>
> Use BIT name instead of magic numbers?
>
> > +}
> > +
> > +static int bcmspi_enable_bspi(struct bcmspi_priv *priv)
> > +{
> > +       if (priv->state == QSPI_STATE_BSPI)
> > +               return 0;
> > +
> > +       /* Disable write lock */
> > +       writel(0, priv->mspi + MSPI_WRITE_LOCK_REG);
> > +       /* Flush prefetch buffers */
> > +       bspi_flush_prefetch_buffers(priv);
> > +       /* Switch to BSPI */
> > +       writel(0, priv->bspi + BSPI_MAST_N_BOOT_CTRL_REG);
> > +       /* Update state */
> > +       priv->state = QSPI_STATE_BSPI;
> > +
> > +       return 0;
> > +}
> > +
> > +static int bcmspi_disable_bspi(struct bcmspi_priv *priv)
> > +{
> > +       if (priv->state == QSPI_STATE_MSPI)
> > +               return 0;
> > +
> > +       /* Switch to MSPI if not yet */
> > +       if ((readl(priv->bspi + BSPI_MAST_N_BOOT_CTRL_REG) & 1) == 0) {
> > +               ulong start = get_timer(0);
> > +
> > +               while (get_timer(start) <
> > +                      QSPI_WAIT_TIMEOUT_MS * CONFIG_SYS_HZ / 1000) {
> > +                       if ((readl(priv->bspi + BSPI_BUSY_STATUS_REG) &
> 1)
> > +                           == 0) {
> > +                               writel(1, priv->bspi +
> > +                                      BSPI_MAST_N_BOOT_CTRL_REG);
> > +                               udelay(1);
> > +                               break;
> > +                       }
> > +                       udelay(1);
> > +               }
> > +               if ((readl(priv->bspi + BSPI_MAST_N_BOOT_CTRL_REG) & 1)
> != 1)
> > +                       return -1;
> > +       }
> > +
> > +       /* Update state */
> > +       priv->state = QSPI_STATE_MSPI;
>
> How can we find the state? can it be any reg bits?
>
> > +
> > +       return 0;
> > +}
> > +
> > +static void bspi_set_4byte_mode(struct bcmspi_priv *priv, int enable)
> > +{
> > +       /* Disable flex mode first */
> > +       writel(0, priv->bspi + BSPI_FLEX_MODE_ENABLE_REG);
> > +
> > +       if (enable) {
> > +               /* Enable 32-bit address */
> > +               setbits_le32(priv->bspi + BSPI_BITS_PER_PHASE_REG,
> > +                            BSPI_BITS_PER_PHASE_ADDR_MARK);
> > +               /* Enable flex mode to take effect */
> > +               writel(1, priv->bspi + BSPI_FLEX_MODE_ENABLE_REG);
> > +       } else {
> > +               /* Disable 32-bit address */
> > +               clrbits_le32(priv->bspi + BSPI_BITS_PER_PHASE_REG,
> > +                            BSPI_BITS_PER_PHASE_ADDR_MARK);
> > +               /* Clear upper address byte */
> > +               writel(0, priv->bspi + BSPI_FLASH_UPPER_ADDR_BYTE_REG);
> > +               /*
> > +                * Flush prefetch buffers since 32MB window BSPI
> > +                * could be used
> > +                */
> > +               bspi_flush_prefetch_buffers(priv);
> > +       }
> > +
> > +       /* Record current mode */
> > +       priv->mode_4byte = enable;
>
> How come spi controller decides to flash 4byte mode?
>
> > +}
> > +
> > +static void bspi_read_via_raf(struct bcmspi_priv *priv, u8 *rx, uint
> bytes)
> > +{
> > +       u32 status;
> > +       uint words;
> > +       int aligned;
> > +
> > +       /* Flush data from the previous session (unlikely) */
> > +       for (;;) {
> > +               status = readl(priv->bspi_raf + BSPI_RAF_STATUS_REG);
> > +               if (!(status & BSPI_RAF_STATUS_FIFO_EMPTY_MASK)) {
> > +                       readl(priv->bspi_raf + BSPI_RAF_READ_DATA_REG);
> > +                       continue;
> > +               }
> > +               if (!(status & BSPI_RAF_STATUS_SESSION_BUSY_MASK))
> > +                       break;
> > +       }
> > +
> > +       /* Transfer is in words */
> > +       words = (bytes + 3) / 4;
> > +
> > +       /* Setup hardware */
> > +       if (priv->mode_4byte) {
> > +               u32 val = priv->bspi_addr & 0xFF000000;
> > +
> > +               if (val != readl(priv->bspi +
> BSPI_FLASH_UPPER_ADDR_BYTE_REG)) {
> > +                       writel(val,
> > +                              priv->bspi +
> BSPI_FLASH_UPPER_ADDR_BYTE_REG);
> > +                       bspi_flush_prefetch_buffers(priv);
> > +               }
> > +       }
> > +       writel(priv->bspi_addr & 0x00FFFFFF,
> > +              priv->bspi_raf + BSPI_RAF_START_ADDRESS_REG);
> > +       writel(words, priv->bspi_raf + BSPI_RAF_NUM_WORDS_REG);
> > +       writel(0, priv->bspi_raf + BSPI_RAF_WATERMARK_REG);
>
> Seems like this driver is handling the flash-specific job in spi
> controller which is indeed the wrong implementation. If so, find a
> proper way to support this on mtd/spi side?
>
> thanks,
> Jagan.
>

-- 
This electronic communication and the information and any files transmitted 
with it, or attached to it, are confidential and are intended solely for 
the use of the individual or entity to whom it is addressed and may contain 
information that is confidential, legally privileged, protected by privacy 
laws, or otherwise restricted from disclosure to anyone else. If you are 
not the intended recipient or the person responsible for delivering the 
e-mail to the intended recipient, you are hereby notified that any use, 
copying, distributing, dissemination, forwarding, printing, or copying of 
this e-mail is strictly prohibited. If you received this e-mail in error, 
please return the e-mail to the sender, delete it from your computer, and 
destroy any printed copy of it.


More information about the U-Boot mailing list