[PATCH v1] spi: nuvoton: add NPCM PSPI controller driver

Jim Liu jim.t90615 at gmail.com
Thu Oct 27 09:06:30 CEST 2022


Hi Jagan

My upstream topic status is Awaiting Upstream.
but now Meta needs to use this driver.
What could I do to make it merge fast?

Best regards,
Jim





On Thu, Oct 27, 2022 at 2:57 PM JJLIU0 at nuvoton.com <JJLIU0 at nuvoton.com> wrote:
>
> fyi
>
> -----Original Message-----
> From: Jim Liu <jim.t90615 at gmail.com>
> Sent: Tuesday, May 31, 2022 6:14 PM
> To: CS20 JJLiu0 <JJLIU0 at nuvoton.com>; jagan at amarulasolutions.com; CS20 YSChu <YSCHU at nuvoton.com>; CS20 KWLiu <KWLIU at nuvoton.com>
> Cc: u-boot at lists.denx.de
> Subject: [PATCH v1] spi: nuvoton: add NPCM PSPI controller driver
>
> Add Nuvoton NPCM BMC Peripheral SPI controller driver.
> NPCM750 include two general-purpose SPI interface.
>
> Signed-off-by: Jim Liu <JJLIU0 at nuvoton.com>
> ---
>  drivers/spi/Kconfig     |   5 +
>  drivers/spi/Makefile    |   1 +
>  drivers/spi/npcm_pspi.c | 226 ++++++++++++++++++++++++++++++++++++++++
>  3 files changed, 232 insertions(+)
>  create mode 100644 drivers/spi/npcm_pspi.c
>
> diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig index a1e515cb2b..4e4e05f849 100644
> --- a/drivers/spi/Kconfig
> +++ b/drivers/spi/Kconfig
> @@ -289,6 +289,11 @@ config NPCM_FIU_SPI
>           This enables support for the Flash Interface Unit SPI controller
>           in master mode.
>
> +config NPCM_PSPI
> +       bool "PSPI driver for Nuvoton NPCM SoC"
> +       help
> +         PSPI driver for NPCM SoC
> +
>  config NXP_FSPI
>         bool "NXP FlexSPI driver"
>         depends on SPI_MEM
> diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile index 06e81b465b..1b843636bc 100644
> --- a/drivers/spi/Makefile
> +++ b/drivers/spi/Makefile
> @@ -48,6 +48,7 @@ obj-$(CONFIG_MVEBU_A3700_SPI) += mvebu_a3700_spi.o
>  obj-$(CONFIG_MXC_SPI) += mxc_spi.o
>  obj-$(CONFIG_MXS_SPI) += mxs_spi.o
>  obj-$(CONFIG_NPCM_FIU_SPI) += npcm_fiu_spi.o
> +obj-$(CONFIG_NPCM_PSPI) += npcm_pspi.o
>  obj-$(CONFIG_NXP_FSPI) += nxp_fspi.o
>  obj-$(CONFIG_ATCSPI200_SPI) += atcspi200_spi.o
>  obj-$(CONFIG_OCTEON_SPI) += octeon_spi.o diff --git a/drivers/spi/npcm_pspi.c b/drivers/spi/npcm_pspi.c new file mode 100644 index 0000000000..bd9ac65411
> --- /dev/null
> +++ b/drivers/spi/npcm_pspi.c
> @@ -0,0 +1,226 @@
> +// SPDX-License-Identifier: GPL-2.0+
> +/*
> + * Copyright (c) 2021 Nuvoton Technology.
> + */
> +
> +#include <common.h>
> +#include <dm.h>
> +#include <spi.h>
> +#include <clk.h>
> +#include <asm/gpio.h>
> +#include <linux/iopoll.h>
> +
> +#define MAX_DIV        127
> +
> +/* Register offsets */
> +#define PSPI_DATA              0
> +#define PSPI_CTL1              2
> +#define PSPI_STAT              4
> +
> +/* PSPI_CTL1 fields */
> +#define PSPI_CTL1_SPIEN                BIT(0)
> +#define PSPI_CTL1_SCM          BIT(7)
> +#define PSPI_CTL1_SCIDL                BIT(8)
> +#define PSPI_CTL1_SCDV_MASK    GENMASK(15, 9)
> +#define PSPI_CTL1_SCDV_SHIFT   9
> +
> +/* PSPI_STAT fields */
> +#define PSPI_STAT_BSY          BIT(0)
> +#define PSPI_STAT_RBF          BIT(1)
> +
> +struct npcm_pspi_priv {
> +       void __iomem *base;
> +       struct clk clk;
> +       struct gpio_desc cs_gpio;
> +       u32 max_hz;
> +};
> +
> +static inline void spi_cs_activate(struct udevice *dev) {
> +       struct udevice *bus = dev->parent;
> +       struct npcm_pspi_priv *priv = dev_get_priv(bus);
> +
> +       dm_gpio_set_value(&priv->cs_gpio, 0);
> +}
> +
> +static inline void spi_cs_deactivate(struct udevice *dev) {
> +       struct udevice *bus = dev->parent;
> +       struct npcm_pspi_priv *priv = dev_get_priv(bus);
> +
> +       dm_gpio_set_value(&priv->cs_gpio, 1);
> +}
> +
> +static inline void npcm_pspi_enable(struct npcm_pspi_priv *priv) {
> +       u16 val;
> +
> +       val = readw(priv->base + PSPI_CTL1);
> +       val |= PSPI_CTL1_SPIEN;
> +       writew(val, priv->base + PSPI_CTL1);
> +}
> +
> +static inline void npcm_pspi_disable(struct npcm_pspi_priv *priv) {
> +       u16 val;
> +
> +       val = readw(priv->base + PSPI_CTL1);
> +       val &= ~PSPI_CTL1_SPIEN;
> +       writew(val, priv->base + PSPI_CTL1);
> +}
> +
> +static int npcm_pspi_xfer(struct udevice *dev, unsigned int bitlen,
> +                         const void *dout, void *din, unsigned long flags) {
> +       struct udevice *bus = dev->parent;
> +       struct npcm_pspi_priv *priv = dev_get_priv(bus);
> +       void __iomem *base = priv->base;
> +       const u8 *tx = dout;
> +       u8 *rx = din;
> +       u32 bytes = bitlen / 8;
> +       u8 tmp;
> +       u32 val;
> +       int i, ret = 0;
> +
> +       npcm_pspi_enable(priv);
> +
> +       if (flags & SPI_XFER_BEGIN)
> +               spi_cs_activate(dev);
> +
> +       for (i = 0; i < bytes; i++) {
> +               /* Making sure we can write */
> +               ret = readb_poll_timeout(base + PSPI_STAT, val,
> +                                        !(val & PSPI_STAT_BSY),
> +                                        1000000);
> +               if (ret < 0)
> +                       break;
> +
> +               if (tx)
> +                       writeb(*tx++, base + PSPI_DATA);
> +               else
> +                       writeb(0, base + PSPI_DATA);
> +
> +               /* Wait till write completed */
> +               ret = readb_poll_timeout(base + PSPI_STAT, val,
> +                                        !(val & PSPI_STAT_BSY),
> +                                        1000000);
> +               if (ret < 0)
> +                       break;
> +
> +               /* Wait till read buffer full */
> +               ret = readb_poll_timeout(base + PSPI_STAT, val,
> +                                        (val & PSPI_STAT_RBF),
> +                                        1000000);
> +               if (ret < 0)
> +                       break;
> +
> +               tmp = readb(base + PSPI_DATA);
> +               if (rx)
> +                       *rx++ = tmp;
> +       }
> +
> +       if (flags & SPI_XFER_END)
> +               spi_cs_deactivate(dev);
> +
> +       npcm_pspi_disable(priv);
> +
> +       return ret;
> +}
> +
> +static int npcm_pspi_set_speed(struct udevice *bus, uint speed) {
> +       struct npcm_pspi_priv *priv = dev_get_priv(bus);
> +       ulong apb_clock;
> +       u32 divisor;
> +       u16 val;
> +
> +       apb_clock = clk_get_rate(&priv->clk);
> +       if (!apb_clock)
> +               return -EINVAL;
> +
> +       if (speed > priv->max_hz)
> +               speed = priv->max_hz;
> +
> +       divisor = DIV_ROUND_CLOSEST(apb_clock, (2 * speed) - 1);
> +       if (divisor > MAX_DIV)
> +               divisor = MAX_DIV;
> +
> +       val = readw(priv->base + PSPI_CTL1);
> +       val &= ~PSPI_CTL1_SCDV_MASK;
> +       val |= divisor << PSPI_CTL1_SCDV_SHIFT;
> +       writew(val, priv->base + PSPI_CTL1);
> +
> +       debug("%s: apb_clock=%lu speed=%d divisor=%u\n",
> +             __func__, apb_clock, speed, divisor);
> +
> +       return 0;
> +}
> +
> +static int npcm_pspi_set_mode(struct udevice *bus, uint mode) {
> +       struct npcm_pspi_priv *priv = dev_get_priv(bus);
> +       u16 pspi_mode, val;
> +
> +       switch (mode & (SPI_CPOL | SPI_CPHA)) {
> +       case SPI_MODE_0:
> +               pspi_mode = 0;
> +               break;
> +       case SPI_MODE_1:
> +               pspi_mode = PSPI_CTL1_SCM;
> +               break;
> +       case SPI_MODE_2:
> +               pspi_mode = PSPI_CTL1_SCIDL;
> +               break;
> +       case SPI_MODE_3:
> +               pspi_mode = PSPI_CTL1_SCIDL | PSPI_CTL1_SCM;
> +               break;
> +       default:
> +               break;
> +       }
> +
> +       val = readw(priv->base + PSPI_CTL1);
> +       val &= ~(PSPI_CTL1_SCIDL | PSPI_CTL1_SCM);
> +       val |= pspi_mode;
> +       writew(val, priv->base + PSPI_CTL1);
> +
> +       return 0;
> +}
> +
> +static int npcm_pspi_probe(struct udevice *bus) {
> +       struct npcm_pspi_priv *priv = dev_get_priv(bus);
> +       int node = dev_of_offset(bus);
> +       int ret;
> +
> +       ret = clk_get_by_index(bus, 0, &priv->clk);
> +       if (ret < 0)
> +               return ret;
> +
> +       priv->base = dev_read_addr_ptr(bus);
> +       priv->max_hz = dev_read_u32_default(bus, "spi-max-frequency", 0);
> +       gpio_request_by_name_nodev(offset_to_ofnode(node), "cs-gpios", 0,
> +                                  &priv->cs_gpio, GPIOD_IS_OUT);
> +
> +       return 0;
> +}
> +
> +static const struct dm_spi_ops npcm_pspi_ops = {
> +       .xfer           = npcm_pspi_xfer,
> +       .set_speed      = npcm_pspi_set_speed,
> +       .set_mode       = npcm_pspi_set_mode,
> +};
> +
> +static const struct udevice_id npcm_pspi_ids[] = {
> +       { .compatible = "nuvoton,npcm845-pspi"},
> +       { .compatible = "nuvoton,npcm750-pspi"},
> +       { }
> +};
> +
> +U_BOOT_DRIVER(npcm_pspi) = {
> +       .name   = "npcm_pspi",
> +       .id     = UCLASS_SPI,
> +       .of_match = npcm_pspi_ids,
> +       .ops    = &npcm_pspi_ops,
> +       .priv_auto = sizeof(struct npcm_pspi_priv),
> +       .probe  = npcm_pspi_probe,
> +};
> --
> 2.17.1
>
> ________________________________
> ________________________________
>  The privileged confidential information contained in this email is intended for use only by the addressees as indicated by the original sender of this email. If you are not the addressee indicated in this email or are not responsible for delivery of the email to such a person, please kindly reply to the sender indicating this fact and delete all copies of it from your computer and network server immediately. Your cooperation is highly appreciated. It is advised that any unauthorized use of confidential information of Nuvoton is strictly prohibited; and any information in this email irrelevant to the official business of Nuvoton shall be deemed as neither given nor endorsed by Nuvoton.


More information about the U-Boot mailing list