
+ 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@amarulasolutions.com wrote:
On Wed, Aug 25, 2021 at 6:55 PM Bharat Kumar Reddy Gooty bharat.gooty@broadcom.com wrote:
From: Rayagonda Kokatanur rayagonda.kokatanur@broadcom.com
IPROC qspi driver supports both BSPI and MSPI modes.
Signed-off-by: Rayagonda Kokatanur rayagonda.kokatanur@broadcom.com Signed-off-by: Bharat Gooty bharat.gooty@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) &
== 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.