From mboxrd@z Thu Jan 1 00:00:00 1970 From: Stefan Roese Date: Thu, 30 Jul 2020 10:06:46 +0200 Subject: [PATCH v2 06/10] drivers: spi: Add SPI controller driver for Octeon In-Reply-To: References: <20200723101724.953325-1-sr@denx.de> <20200723101724.953325-7-sr@denx.de> Message-ID: <115638e4-db6e-1eab-e676-2f8e864af32f@denx.de> List-Id: MIME-Version: 1.0 Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit To: u-boot@lists.denx.de Hi Jagan, On 30.07.20 09:44, Jagan Teki wrote: > On Thu, Jul 23, 2020 at 3:47 PM Stefan Roese wrote: >> >> From: Suneel Garapati >> >> Adds support for SPI controllers found on Octeon II/III and Octeon TX >> TX2 SoC platforms. >> >> Signed-off-by: Aaron Williams >> Signed-off-by: Suneel Garapati >> Signed-off-by: Stefan Roese >> Cc: Daniel Schwierzeck >> Cc: Aaron Williams >> Cc: Chandrakala Chavva >> Cc: Jagan Teki >> >> --- >> >> Changes in v2: >> - Newly added to this series >> - Removed inclusion of "common.h" >> - Added "depends on DM_PCI" to Kconfig >> - Tested on MIPS Octeon and ARM Octeon TX2 >> - Fixed issues with Octeon TX2 registration. Now only one driver is >> registered and the "ops" is overwritten in the Octeon TX2 case. >> - Use dev_get_driver_data() to get the driver data struct >> - Removed "struct pci_device_id" definition and U_BOOT_PCI_DEVICE() >> as its not needed for the PCI based probing on Octeon TX2 >> >> drivers/spi/Kconfig | 8 + >> drivers/spi/Makefile | 1 + >> drivers/spi/octeon_spi.c | 647 +++++++++++++++++++++++++++++++++++++++ >> 3 files changed, 656 insertions(+) >> create mode 100644 drivers/spi/octeon_spi.c >> >> diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig >> index 30d808d7bb..3fc2d0674a 100644 >> --- a/drivers/spi/Kconfig >> +++ b/drivers/spi/Kconfig >> @@ -240,6 +240,14 @@ config NXP_FSPI >> Enable the NXP FlexSPI (FSPI) driver. This driver can be used to >> access the SPI NOR flash on platforms embedding this NXP IP core. >> >> +config OCTEON_SPI >> + bool "Octeon SPI driver" >> + depends on DM_PCI && (ARCH_OCTEON || ARCH_OCTEONTX || ARCH_OCTEONTX2) >> + help >> + Enable the Octeon SPI driver. This driver can be used to >> + access the SPI NOR flash on Octeon II/III and OcteonTX/TX2 >> + SoC platforms. >> + >> config OMAP3_SPI >> bool "McSPI driver for OMAP" >> help >> diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile >> index 4e7461771f..b5c9ff1af8 100644 >> --- a/drivers/spi/Makefile >> +++ b/drivers/spi/Makefile >> @@ -43,6 +43,7 @@ obj-$(CONFIG_MXC_SPI) += mxc_spi.o >> obj-$(CONFIG_MXS_SPI) += mxs_spi.o >> obj-$(CONFIG_NXP_FSPI) += nxp_fspi.o >> obj-$(CONFIG_ATCSPI200_SPI) += atcspi200_spi.o >> +obj-$(CONFIG_OCTEON_SPI) += octeon_spi.o >> obj-$(CONFIG_OMAP3_SPI) += omap3_spi.o >> obj-$(CONFIG_PIC32_SPI) += pic32_spi.o >> obj-$(CONFIG_PL022_SPI) += pl022_spi.o >> diff --git a/drivers/spi/octeon_spi.c b/drivers/spi/octeon_spi.c >> new file mode 100644 >> index 0000000000..2fb39e444c >> --- /dev/null >> +++ b/drivers/spi/octeon_spi.c >> @@ -0,0 +1,647 @@ >> +// SPDX-License-Identifier: GPL-2.0 >> +/* >> + * Copyright (C) 2018 Marvell International Ltd. >> + * >> + * https://spdx.org/licenses >> + */ >> + >> +#include >> +#include >> +#include >> +#include >> +#include >> +#include >> +#include >> +#include >> +#include >> +#include >> +#include >> + >> +#define OCTEON_SPI_MAX_BYTES 9 >> +#define OCTEON_SPI_MAX_CLOCK_HZ 50000000 >> + >> +#define OCTEON_SPI_NUM_CS 4 >> + >> +#define OCTEON_SPI_CS_VALID(cs) ((cs) < OCTEON_SPI_NUM_CS) >> + >> +#define MPI_CFG 0x0000 >> +#define MPI_STS 0x0008 >> +#define MPI_TX 0x0010 >> +#define MPI_XMIT 0x0018 >> +#define MPI_WIDE_DAT 0x0040 >> +#define MPI_IO_CTL 0x0048 >> +#define MPI_DAT(X) (0x0080 + ((X) << 3)) >> +#define MPI_WIDE_BUF(X) (0x0800 + ((X) << 3)) >> +#define MPI_CYA_CFG 0x1000 >> +#define MPI_CLKEN 0x1080 >> + >> +#define MPI_CFG_ENABLE BIT_ULL(0) >> +#define MPI_CFG_IDLELO BIT_ULL(1) >> +#define MPI_CFG_CLK_CONT BIT_ULL(2) >> +#define MPI_CFG_WIREOR BIT_ULL(3) >> +#define MPI_CFG_LSBFIRST BIT_ULL(4) >> +#define MPI_CFG_CS_STICKY BIT_ULL(5) >> +#define MPI_CFG_CSHI BIT_ULL(7) >> +#define MPI_CFG_IDLECLKS GENMASK_ULL(9, 8) >> +#define MPI_CFG_TRITX BIT_ULL(10) >> +#define MPI_CFG_CSLATE BIT_ULL(11) >> +#define MPI_CFG_CSENA0 BIT_ULL(12) >> +#define MPI_CFG_CSENA1 BIT_ULL(13) >> +#define MPI_CFG_CSENA2 BIT_ULL(14) >> +#define MPI_CFG_CSENA3 BIT_ULL(15) >> +#define MPI_CFG_CLKDIV GENMASK_ULL(28, 16) >> +#define MPI_CFG_LEGACY_DIS BIT_ULL(31) >> +#define MPI_CFG_IOMODE GENMASK_ULL(35, 34) >> +#define MPI_CFG_TB100_EN BIT_ULL(49) >> + >> +#define MPI_DAT_DATA GENMASK_ULL(7, 0) >> + >> +#define MPI_STS_BUSY BIT_ULL(0) >> +#define MPI_STS_MPI_INTR BIT_ULL(1) >> +#define MPI_STS_RXNUM GENMASK_ULL(12, 8) >> + >> +#define MPI_TX_TOTNUM GENMASK_ULL(4, 0) >> +#define MPI_TX_TXNUM GENMASK_ULL(12, 8) >> +#define MPI_TX_LEAVECS BIT_ULL(16) >> +#define MPI_TX_CSID GENMASK_ULL(21, 20) >> + >> +#define MPI_XMIT_TOTNUM GENMASK_ULL(10, 0) >> +#define MPI_XMIT_TXNUM GENMASK_ULL(30, 20) >> +#define MPI_XMIT_BUF_SEL BIT_ULL(59) >> +#define MPI_XMIT_LEAVECS BIT_ULL(60) >> +#define MPI_XMIT_CSID GENMASK_ULL(62, 61) >> + >> +enum { >> + PROBE_PCI = 0, /* PCI based probing */ >> + PROBE_DT, /* DT based probing */ >> +}; >> + >> +/* Used on Octeon TX2 */ >> +void board_acquire_flash_arb(bool acquire); >> + >> +struct octeon_spi_data { >> + int probe; >> + u32 reg_offs; >> +}; >> + >> +/* Local driver data structure */ >> +struct octeon_spi { >> + void __iomem *base; /* Register base address */ >> + struct clk clk; >> + u32 clkdiv; /* Clock divisor for device speed */ >> +}; >> + >> +static u64 octeon_spi_set_mpicfg(struct udevice *dev) >> +{ >> + struct dm_spi_slave_platdata *slave = dev_get_parent_platdata(dev); >> + struct udevice *bus = dev_get_parent(dev); >> + struct octeon_spi *priv = dev_get_priv(bus); >> + u64 mpi_cfg; >> + uint max_speed = slave->max_hz; >> + bool cpha, cpol; >> + >> + if (!max_speed) >> + max_speed = 12500000; >> + if (max_speed > OCTEON_SPI_MAX_CLOCK_HZ) >> + max_speed = OCTEON_SPI_MAX_CLOCK_HZ; >> + >> + debug("\n slave params %d %d %d\n", slave->cs, >> + slave->max_hz, slave->mode); >> + cpha = !!(slave->mode & SPI_CPHA); >> + cpol = !!(slave->mode & SPI_CPOL); >> + >> + mpi_cfg = FIELD_PREP(MPI_CFG_CLKDIV, priv->clkdiv & 0x1fff) | >> + FIELD_PREP(MPI_CFG_CSHI, !!(slave->mode & SPI_CS_HIGH)) | >> + FIELD_PREP(MPI_CFG_LSBFIRST, !!(slave->mode & SPI_LSB_FIRST)) | >> + FIELD_PREP(MPI_CFG_WIREOR, !!(slave->mode & SPI_3WIRE)) | >> + FIELD_PREP(MPI_CFG_IDLELO, cpha != cpol) | >> + FIELD_PREP(MPI_CFG_CSLATE, cpha) | >> + MPI_CFG_CSENA0 | MPI_CFG_CSENA1 | >> + MPI_CFG_CSENA2 | MPI_CFG_CSENA1 | >> + MPI_CFG_ENABLE; >> + >> + debug("\n mpi_cfg %llx\n", mpi_cfg); >> + return mpi_cfg; >> +} >> + >> +/** >> + * Wait until the SPI bus is ready >> + * >> + * @param dev SPI device to wait for >> + */ >> +static void octeon_spi_wait_ready(struct udevice *dev) >> +{ >> + struct udevice *bus = dev_get_parent(dev); >> + struct octeon_spi *priv = dev_get_priv(bus); >> + void *base = priv->base; >> + u64 mpi_sts; >> + >> + do { >> + mpi_sts = readq(base + MPI_STS); >> + WATCHDOG_RESET(); >> + } while (mpi_sts & MPI_STS_BUSY); >> + >> + debug("%s(%s)\n", __func__, dev->name); >> +} >> + >> +/** >> + * Claim the bus for a slave device >> + * >> + * @param dev SPI bus >> + * >> + * @return 0 for success, -EINVAL if chip select is invalid >> + */ >> +static int octeon_spi_claim_bus(struct udevice *dev) >> +{ >> + struct udevice *bus = dev_get_parent(dev); >> + struct octeon_spi *priv = dev_get_priv(bus); >> + void *base = priv->base; >> + u64 mpi_cfg; >> + >> + debug("\n\n%s(%s)\n", __func__, dev->name); >> + if (!OCTEON_SPI_CS_VALID(spi_chip_select(dev))) >> + return -EINVAL; >> + >> + if (IS_ENABLED(CONFIG_ARCH_OCTEONTX2)) >> + board_acquire_flash_arb(true); >> + >> + mpi_cfg = readq(base + MPI_CFG); >> + mpi_cfg &= ~MPI_CFG_TRITX; >> + mpi_cfg |= MPI_CFG_ENABLE; >> + writeq(mpi_cfg, base + MPI_CFG); >> + mpi_cfg = readq(base + MPI_CFG); >> + udelay(5); /** Wait for bus to settle */ >> + >> + return 0; >> +} >> + >> +/** >> + * Release the bus to a slave device >> + * >> + * @param dev SPI bus >> + * >> + * @return 0 for success, -EINVAL if chip select is invalid >> + */ >> +static int octeon_spi_release_bus(struct udevice *dev) >> +{ >> + struct udevice *bus = dev_get_parent(dev); >> + struct octeon_spi *priv = dev_get_priv(bus); >> + void *base = priv->base; >> + u64 mpi_cfg; >> + >> + debug("%s(%s)\n\n", __func__, dev->name); >> + if (!OCTEON_SPI_CS_VALID(spi_chip_select(dev))) >> + return -EINVAL; >> + >> + if (IS_ENABLED(CONFIG_ARCH_OCTEONTX2)) >> + board_acquire_flash_arb(false); > > Does this acquire flash depends on soc? Yes. Only Octeon TX2 implements it - the other SoC's using this driver (MIPS Octeon and ARM Octeon TX) do not. > what exactly it does? It controls the arbiter for the boot device between multiple internal resources (SCP, MCP, AP Secure, AP Nonsecure). > I > believe it can go in separate uclass drivers and spi drivers get that > functionality like other drivers. I'm not fond of calling an > architecture or other places code in the driver. However if it local > spi driver then attach driver_data on respective compatible and use it > locally. I could move this board_acquire_flash_arb() implementation into this SPI driver, which might make sense. Its not called from other places AFAICT. Thanks, Stefan