* [PATCH v2 0/2] Add SD card support to the Beagle-V-Fire
@ 2025-05-29 10:21 Eoin Dickson
2025-05-29 10:21 ` [PATCH v2 1/2] gpio: add PolarFire SoC GPIO and Core GPIO driver Eoin Dickson
2025-05-29 10:21 ` [PATCH v2 2/2] spi: coreqspi: add xfer function for PolarFire SoC Eoin Dickson
0 siblings, 2 replies; 5+ messages in thread
From: Eoin Dickson @ 2025-05-29 10:21 UTC (permalink / raw)
To: u-boot
Cc: rick, ycliang, conor.dooley, jamie.gibbons, praveen.kumar,
eoin.dickson, cyril.jean, jagan
From: Eoin Dickson <eoin.dickson@microchip.com>
This series add SD card support for the Beagle-V-Fire. The Beagle-V-Fire uses the
Microchip coreqspi xfer function and a gpio chip select, so this series adds gpio
support for PolarFire SoC and the xfer function into the Microchip coreqspi driver.
Eoin Dickson (2):
gpio: add PolarFire SoC GPIO and Core GPIO driver
spi: coreqspi: add xfer function for PolarFire SoC
drivers/gpio/Kconfig | 5 +
drivers/gpio/Makefile | 1 +
drivers/gpio/mpfs_gpio.c | 198 +++++++++++++++++++++++++++++++
drivers/spi/microchip_coreqspi.c | 113 +++++++++++++++++-
4 files changed, 315 insertions(+), 2 deletions(-)
create mode 100644 drivers/gpio/mpfs_gpio.c
--
2.34.1
^ permalink raw reply [flat|nested] 5+ messages in thread
* [PATCH v2 1/2] gpio: add PolarFire SoC GPIO and Core GPIO driver
2025-05-29 10:21 [PATCH v2 0/2] Add SD card support to the Beagle-V-Fire Eoin Dickson
@ 2025-05-29 10:21 ` Eoin Dickson
2025-06-02 9:44 ` Leo Liang
2025-05-29 10:21 ` [PATCH v2 2/2] spi: coreqspi: add xfer function for PolarFire SoC Eoin Dickson
1 sibling, 1 reply; 5+ messages in thread
From: Eoin Dickson @ 2025-05-29 10:21 UTC (permalink / raw)
To: u-boot
Cc: rick, ycliang, conor.dooley, jamie.gibbons, praveen.kumar,
eoin.dickson, cyril.jean, jagan
From: Eoin Dickson <eoin.dickson@microchip.com>
This driver adds GPIO support for PolarFire SoC family, this is required
to add sd card support on the Beagle-V-Fire as it uses GPIO chip selects
Signed-off-by: Eoin Dickson <eoin.dickson@microchip.com>
---
drivers/gpio/Kconfig | 5 +
drivers/gpio/Makefile | 1 +
drivers/gpio/mpfs_gpio.c | 198 +++++++++++++++++++++++++++++++++++++++
3 files changed, 204 insertions(+)
create mode 100644 drivers/gpio/mpfs_gpio.c
diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig
index e11109fb56d..a47b4be09f7 100644
--- a/drivers/gpio/Kconfig
+++ b/drivers/gpio/Kconfig
@@ -729,5 +729,10 @@ config SPL_ADP5585_GPIO
depends on SPL_DM_GPIO && SPL_I2C
help
Support ADP5585 GPIO expander in SPL.
+config MPFS_GPIO
+ bool "Enable Polarfire SoC GPIO driver"
+ depends on DM_GPIO
+ help
+ Enable to support the GPIO driver on Polarfire SoC
endif
diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile
index d64c14db5cf..222d51b6d89 100644
--- a/drivers/gpio/Makefile
+++ b/drivers/gpio/Makefile
@@ -81,3 +81,4 @@ obj-$(CONFIG_SLG7XL45106_I2C_GPO) += gpio_slg7xl45106.o
obj-$(CONFIG_FTGPIO010) += ftgpio010.o
obj-$(CONFIG_$(PHASE_)ADP5585_GPIO) += adp5585_gpio.o
obj-$(CONFIG_RZG2L_GPIO) += rzg2l-gpio.o
+obj-$(CONFIG_MPFS_GPIO) += mpfs_gpio.o
diff --git a/drivers/gpio/mpfs_gpio.c b/drivers/gpio/mpfs_gpio.c
new file mode 100644
index 00000000000..9bbeada4ef5
--- /dev/null
+++ b/drivers/gpio/mpfs_gpio.c
@@ -0,0 +1,198 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2025 Microchip Technology Inc.
+ * Eoin Dickson <eoin.dickson@microchip.com>
+ */
+
+#include <dm.h>
+#include <asm-generic/gpio.h>
+#include <asm/io.h>
+#include <errno.h>
+#include <asm/gpio.h>
+#include <linux/bitops.h>
+
+#define MPFS_INP_REG 0x84
+#define COREGPIO_INP_REG 0x90
+#define MPFS_OUTP_REG 0x88
+#define COREGPIO_OUTP_REG 0xA0
+#define MPFS_GPIO_CTRL(i) (0x4 * (i))
+#define MPFS_MAX_NUM_GPIO 32
+#define MPFS_GPIO_EN_OUT_BUF BIT(2)
+#define MPFS_GPIO_EN_IN BIT(1)
+#define MPFS_GPIO_EN_OUT BIT(0)
+
+struct mpfs_gpio_reg_offsets {
+ u8 inp;
+ u8 outp;
+};
+
+struct mchp_gpio_plat {
+ void *base;
+ const struct mpfs_gpio_reg_offsets *regs;
+};
+
+static void mchp_update_gpio_reg(void *bptr, u32 offset, bool value)
+{
+ void __iomem *ptr = (void __iomem *)bptr;
+
+ u32 old = readl(ptr);
+
+ if (value)
+ writel(old | offset, ptr);
+ else
+ writel(old & ~offset, ptr);
+}
+
+static int mchp_gpio_direction_input(struct udevice *dev, u32 offset)
+{
+ struct mchp_gpio_plat *plat = dev_get_plat(dev);
+ struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev);
+
+ if (offset > uc_priv->gpio_count)
+ return -EINVAL;
+
+ mchp_update_gpio_reg(plat->base + MPFS_GPIO_CTRL(offset), MPFS_GPIO_EN_IN, true);
+ mchp_update_gpio_reg(plat->base + MPFS_GPIO_CTRL(offset), MPFS_GPIO_EN_OUT, false);
+ mchp_update_gpio_reg(plat->base + MPFS_GPIO_CTRL(offset), MPFS_GPIO_EN_OUT_BUF, false);
+
+ return 0;
+}
+
+static int mchp_gpio_direction_output(struct udevice *dev, u32 offset, int value)
+{
+ struct mchp_gpio_plat *plat = dev_get_plat(dev);
+ struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev);
+
+ if (offset > uc_priv->gpio_count)
+ return -EINVAL;
+
+ mchp_update_gpio_reg(plat->base + MPFS_GPIO_CTRL(offset), MPFS_GPIO_EN_IN, false);
+ mchp_update_gpio_reg(plat->base + MPFS_GPIO_CTRL(offset), MPFS_GPIO_EN_OUT, true);
+ mchp_update_gpio_reg(plat->base + MPFS_GPIO_CTRL(offset), MPFS_GPIO_EN_OUT_BUF, true);
+
+ mchp_update_gpio_reg(plat->base + plat->regs->outp, BIT(offset), value);
+
+ return 0;
+}
+
+static bool mchp_gpio_get_value(struct udevice *dev, u32 offset)
+{
+ struct mchp_gpio_plat *plat = dev_get_plat(dev);
+ struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev);
+ int val, input;
+
+ if (offset > uc_priv->gpio_count)
+ return -EINVAL;
+
+ input = readl(plat->base + MPFS_GPIO_CTRL(offset)) & MPFS_GPIO_EN_IN;
+
+ if (input)
+ val = (readl(plat->base + plat->regs->inp) & BIT(offset));
+ else
+ val = (readl(plat->base + plat->regs->outp) & BIT(offset));
+
+ return val >> offset;
+}
+
+static int mchp_gpio_set_value(struct udevice *dev, u32 offset, int value)
+{
+ struct mchp_gpio_plat *plat = dev_get_plat(dev);
+ struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev);
+
+ if (offset > uc_priv->gpio_count)
+ return -EINVAL;
+
+ mchp_update_gpio_reg(plat->base + plat->regs->outp, BIT(offset), value);
+
+ return 0;
+}
+
+static int mchp_gpio_get_function(struct udevice *dev, unsigned int offset)
+{
+ struct mchp_gpio_plat *plat = dev_get_plat(dev);
+ struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev);
+ u32 outdir, indir, val;
+
+ if (offset > uc_priv->gpio_count)
+ return -EINVAL;
+
+ /* Get direction of the pin */
+ outdir = readl(plat->base + MPFS_GPIO_CTRL(offset)) & MPFS_GPIO_EN_OUT;
+ indir = readl(plat->base + MPFS_GPIO_CTRL(offset)) & MPFS_GPIO_EN_IN;
+
+ if (outdir)
+ val = GPIOF_OUTPUT;
+ else if (indir)
+ val = GPIOF_INPUT;
+ else
+ val = GPIOF_UNUSED;
+
+ return val;
+}
+
+static int mchp_gpio_probe(struct udevice *dev)
+{
+ struct mchp_gpio_plat *plat = dev_get_plat(dev);
+ struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev);
+ char name[18], *str;
+
+ plat->regs = dev_get_driver_data(dev);
+ sprintf(name, "gpio@%4lx_", (uintptr_t)plat->base);
+ str = strdup(name);
+ if (!str)
+ return -ENOMEM;
+ uc_priv->bank_name = str;
+ uc_priv->gpio_count = dev_read_u32_default(dev, "ngpios", MPFS_MAX_NUM_GPIO);
+
+ return 0;
+}
+
+static const struct mpfs_gpio_reg_offsets mpfs_reg_offsets = {
+ .inp = MPFS_INP_REG,
+ .outp = MPFS_OUTP_REG,
+};
+
+static const struct mpfs_gpio_reg_offsets coregpio_reg_offsets = {
+ .inp = COREGPIO_INP_REG,
+ .outp = COREGPIO_OUTP_REG,
+};
+
+static const struct udevice_id mchp_gpio_match[] = {
+ {
+ .compatible = "microchip,mpfs-gpio",
+ .data = &mpfs_reg_offsets,
+ }, {
+ .compatible = "microchip,coregpio-rtl-v3",
+ .data = &coregpio_reg_offsets,
+ },
+ { /* end of list */ }
+};
+
+static const struct dm_gpio_ops mchp_gpio_ops = {
+ .direction_input = mchp_gpio_direction_input,
+ .direction_output = mchp_gpio_direction_output,
+ .get_value = mchp_gpio_get_value,
+ .set_value = mchp_gpio_set_value,
+ .get_function = mchp_gpio_get_function,
+};
+
+static int mchp_gpio_of_to_plat(struct udevice *dev)
+{
+ struct mchp_gpio_plat *plat = dev_get_plat(dev);
+
+ plat->base = dev_read_addr_ptr(dev);
+ if (!plat->base)
+ return -EINVAL;
+
+ return 0;
+}
+
+U_BOOT_DRIVER(gpio_mpfs) = {
+ .name = "gpio_mpfs",
+ .id = UCLASS_GPIO,
+ .of_match = mchp_gpio_match,
+ .of_to_plat = of_match_ptr(mchp_gpio_of_to_plat),
+ .plat_auto = sizeof(struct mchp_gpio_plat),
+ .ops = &mchp_gpio_ops,
+ .probe = mchp_gpio_probe,
+};
--
2.34.1
^ permalink raw reply related [flat|nested] 5+ messages in thread
* [PATCH v2 2/2] spi: coreqspi: add xfer function for PolarFire SoC
2025-05-29 10:21 [PATCH v2 0/2] Add SD card support to the Beagle-V-Fire Eoin Dickson
2025-05-29 10:21 ` [PATCH v2 1/2] gpio: add PolarFire SoC GPIO and Core GPIO driver Eoin Dickson
@ 2025-05-29 10:21 ` Eoin Dickson
2025-06-02 9:45 ` Leo Liang
1 sibling, 1 reply; 5+ messages in thread
From: Eoin Dickson @ 2025-05-29 10:21 UTC (permalink / raw)
To: u-boot
Cc: rick, ycliang, conor.dooley, jamie.gibbons, praveen.kumar,
eoin.dickson, cyril.jean, jagan
From: Eoin Dickson <eoin.dickson@microchip.com>
Add xfer function to PolarFire SoC coreqspi driver. The read and write
operations are limited to one byte at a time instead of four as CMD18
(multiple block read) reads garbage when four byte ops are enabled.
Signed-off-by: Eoin Dickson <eoin.dickson@microchip.com>
---
drivers/spi/microchip_coreqspi.c | 113 ++++++++++++++++++++++++++++++-
1 file changed, 111 insertions(+), 2 deletions(-)
diff --git a/drivers/spi/microchip_coreqspi.c b/drivers/spi/microchip_coreqspi.c
index 234b1688272..84b8965b7fc 100644
--- a/drivers/spi/microchip_coreqspi.c
+++ b/drivers/spi/microchip_coreqspi.c
@@ -16,6 +16,7 @@
#include <linux/delay.h>
#include <linux/types.h>
#include <linux/sizes.h>
+#include <asm/gpio.h>
DECLARE_GLOBAL_DATA_PTR;
@@ -97,6 +98,8 @@ DECLARE_GLOBAL_DATA_PTR;
#define REG_X4_TX_DATA (0x4c)
#define REG_FRAMESUP (0x50)
+#define MAX_CS_COUNT 1
+
/**
* struct mchp_coreqspi - Defines qspi driver instance
* @regs: Address of the QSPI controller registers
@@ -113,6 +116,7 @@ struct mchp_coreqspi {
u8 *rxbuf;
int tx_len;
int rx_len;
+ struct gpio_desc cs_gpios[MAX_CS_COUNT];
};
static void mchp_coreqspi_init_hw(struct mchp_coreqspi *qspi)
@@ -172,7 +176,7 @@ static inline void mchp_coreqspi_write_op(struct mchp_coreqspi *qspi, bool word)
while (qspi->tx_len >= 4) {
while (readl(qspi->regs + REG_STATUS) & STATUS_TXFIFOFULL)
;
- data = *(u32 *)qspi->txbuf;
+ data = qspi->txbuf ? *((u32 *)qspi->txbuf) : 0xFF;
qspi->txbuf += 4;
qspi->tx_len -= 4;
writel(data, qspi->regs + REG_X4_TX_DATA);
@@ -184,7 +188,7 @@ static inline void mchp_coreqspi_write_op(struct mchp_coreqspi *qspi, bool word)
while (qspi->tx_len--) {
while (readl(qspi->regs + REG_STATUS) & STATUS_TXFIFOFULL)
;
- data = *qspi->txbuf++;
+ data = qspi->txbuf ? *qspi->txbuf++ : 0xFF;
writel(data, qspi->regs + REG_TX_DATA);
}
}
@@ -471,6 +475,110 @@ static int mchp_coreqspi_probe(struct udevice *dev)
/* Init the mpfs qspi hw */
mchp_coreqspi_init_hw(qspi);
+ if (CONFIG_IS_ENABLED(DM_GPIO)) {
+ int i;
+
+ ret = gpio_request_list_by_name(dev, "cs-gpios", qspi->cs_gpios,
+ ARRAY_SIZE(qspi->cs_gpios), 0);
+
+ if (ret < 0) {
+ pr_err("Can't get %s gpios! Error: %d", dev->name, ret);
+ return ret;
+ }
+
+ for (i = 0; i < ARRAY_SIZE(qspi->cs_gpios); i++) {
+ if (!dm_gpio_is_valid(&qspi->cs_gpios[i]))
+ continue;
+ dm_gpio_set_dir_flags(&qspi->cs_gpios[i], GPIOD_IS_OUT);
+ }
+ }
+
+ u32 control = readl(qspi->regs + REG_CONTROL);
+
+ control |= (CONTROL_MASTER | CONTROL_ENABLE);
+ control &= ~CONTROL_CLKIDLE;
+ writel(control, qspi->regs + REG_CONTROL);
+
+ return 0;
+}
+
+static void mchp_coreqspi_cs_activate(struct udevice *dev)
+{
+ struct udevice *bus = dev_get_parent(dev);
+ struct mchp_coreqspi *qspi = dev_get_priv(bus);
+ struct dm_spi_slave_plat *slave_plat = dev_get_parent_plat(dev);
+ u32 cs = slave_plat->cs;
+
+ if (CONFIG_IS_ENABLED(DM_GPIO) && dm_gpio_is_valid(&qspi->cs_gpios[cs]))
+ dm_gpio_set_value(&qspi->cs_gpios[cs], 1);
+}
+
+static void mchp_coreqspi_cs_deactivate(struct udevice *dev)
+{
+ struct udevice *bus = dev_get_parent(dev);
+ struct mchp_coreqspi *qspi = dev_get_priv(bus);
+ struct dm_spi_slave_plat *slave_plat = dev_get_parent_plat(dev);
+ u32 cs = slave_plat->cs;
+
+ if (CONFIG_IS_ENABLED(DM_GPIO) && dm_gpio_is_valid(&qspi->cs_gpios[cs]))
+ dm_gpio_set_value(&qspi->cs_gpios[cs], 0);
+}
+
+static int mchp_coreqspi_xfer(struct udevice *dev, unsigned int bitlen,
+ const void *dout, void *din, unsigned long flags)
+{
+ struct udevice *bus = dev_get_parent(dev);
+ struct mchp_coreqspi *qspi = dev_get_priv(bus);
+ struct spi_slave *slave = dev_get_parent_priv(dev);
+ uint total_bytes = bitlen >> 3; /* fixed 8-bit word length */
+ u32 control, frames;
+
+ int err = 0;
+
+ err = mchp_coreqspi_wait_for_ready(slave);
+ if (err)
+ return err;
+
+ control = readl(qspi->regs + REG_CONTROL);
+ control &= ~(CONTROL_MODE12_MASK | CONTROL_MODE0);
+ writel(control, qspi->regs + REG_CONTROL);
+
+ frames = total_bytes & BYTESUPPER_MASK;
+ writel(frames, qspi->regs + REG_FRAMESUP);
+
+ frames |= FRAMES_FLAGBYTE;
+ writel(frames, qspi->regs + REG_FRAMES);
+
+ if (flags & SPI_XFER_BEGIN)
+ mchp_coreqspi_cs_activate(dev);
+
+ if (bitlen == 0)
+ goto out;
+
+ if (bitlen % 8) { // Non byte aligned SPI transfer
+ flags |= SPI_XFER_END;
+ goto out;
+ }
+
+ qspi->txbuf = (u8 *)dout;
+ qspi->rxbuf = (u8 *)din;
+
+ while (total_bytes) {
+ qspi->tx_len = 1;
+ qspi->rx_len = 1;
+ total_bytes--;
+
+ if (din) {
+ mchp_coreqspi_write_op(qspi, true);
+ mchp_coreqspi_read_op(qspi);
+ } else {
+ mchp_coreqspi_write_op(qspi, true);
+ }
+ }
+out:
+ if (flags & SPI_XFER_END)
+ mchp_coreqspi_cs_deactivate(dev);
+
return 0;
}
@@ -483,6 +591,7 @@ static const struct spi_controller_mem_ops mchp_coreqspi_mem_ops = {
static const struct dm_spi_ops mchp_coreqspi_ops = {
.claim_bus = mchp_coreqspi_claim_bus,
.release_bus = mchp_coreqspi_release_bus,
+ .xfer = mchp_coreqspi_xfer,
.set_speed = mchp_coreqspi_set_speed,
.set_mode = mchp_coreqspi_set_mode,
.mem_ops = &mchp_coreqspi_mem_ops,
--
2.34.1
^ permalink raw reply related [flat|nested] 5+ messages in thread
* Re: [PATCH v2 1/2] gpio: add PolarFire SoC GPIO and Core GPIO driver
2025-05-29 10:21 ` [PATCH v2 1/2] gpio: add PolarFire SoC GPIO and Core GPIO driver Eoin Dickson
@ 2025-06-02 9:44 ` Leo Liang
0 siblings, 0 replies; 5+ messages in thread
From: Leo Liang @ 2025-06-02 9:44 UTC (permalink / raw)
To: Eoin Dickson
Cc: u-boot, rick, conor.dooley, jamie.gibbons, praveen.kumar,
cyril.jean, jagan
On Thu, May 29, 2025 at 03:51:11PM +0530, Eoin Dickson wrote:
> [EXTERNAL MAIL]
>
> From: Eoin Dickson <eoin.dickson@microchip.com>
>
> This driver adds GPIO support for PolarFire SoC family, this is required
> to add sd card support on the Beagle-V-Fire as it uses GPIO chip selects
>
> Signed-off-by: Eoin Dickson <eoin.dickson@microchip.com>
> ---
> drivers/gpio/Kconfig | 5 +
> drivers/gpio/Makefile | 1 +
> drivers/gpio/mpfs_gpio.c | 198 +++++++++++++++++++++++++++++++++++++++
> 3 files changed, 204 insertions(+)
> create mode 100644 drivers/gpio/mpfs_gpio.c
Acked-by: Leo Yu-Chi Liang <ycliang@andestech.com>
^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [PATCH v2 2/2] spi: coreqspi: add xfer function for PolarFire SoC
2025-05-29 10:21 ` [PATCH v2 2/2] spi: coreqspi: add xfer function for PolarFire SoC Eoin Dickson
@ 2025-06-02 9:45 ` Leo Liang
0 siblings, 0 replies; 5+ messages in thread
From: Leo Liang @ 2025-06-02 9:45 UTC (permalink / raw)
To: Eoin Dickson
Cc: u-boot, rick, conor.dooley, jamie.gibbons, praveen.kumar,
cyril.jean, jagan
On Thu, May 29, 2025 at 03:51:12PM +0530, Eoin Dickson wrote:
> [EXTERNAL MAIL]
>
> From: Eoin Dickson <eoin.dickson@microchip.com>
>
> Add xfer function to PolarFire SoC coreqspi driver. The read and write
> operations are limited to one byte at a time instead of four as CMD18
> (multiple block read) reads garbage when four byte ops are enabled.
>
> Signed-off-by: Eoin Dickson <eoin.dickson@microchip.com>
> ---
> drivers/spi/microchip_coreqspi.c | 113 ++++++++++++++++++++++++++++++-
> 1 file changed, 111 insertions(+), 2 deletions(-)
Acked-by: Leo Yu-Chi Liang <ycliang@andestech.com>
^ permalink raw reply [flat|nested] 5+ messages in thread
end of thread, other threads:[~2025-06-02 9:45 UTC | newest]
Thread overview: 5+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-05-29 10:21 [PATCH v2 0/2] Add SD card support to the Beagle-V-Fire Eoin Dickson
2025-05-29 10:21 ` [PATCH v2 1/2] gpio: add PolarFire SoC GPIO and Core GPIO driver Eoin Dickson
2025-06-02 9:44 ` Leo Liang
2025-05-29 10:21 ` [PATCH v2 2/2] spi: coreqspi: add xfer function for PolarFire SoC Eoin Dickson
2025-06-02 9:45 ` Leo Liang
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.