summaryrefslogtreecommitdiff
path: root/drivers/gpio
diff options
context:
space:
mode:
authorTom Rini <[email protected]>2023-04-29 09:29:41 -0400
committerTom Rini <[email protected]>2023-04-29 09:29:41 -0400
commitfe3a77cb157a6210d8036845f5f80ea67c183563 (patch)
tree1d53e64cbcdf10c6e5dfb95cefd098e643820bed /drivers/gpio
parent076f13308c6f06e2c4feb8b408e997bc732586e1 (diff)
parent4d0c8db74d83e43dec4e7481b2d1e194f51d907b (diff)
Merge branch 'for-2023.07' of https://source.denx.de/u-boot/custodians/u-boot-mpc8xx
This pull request adds support for the last CPU board from CS GROUP France (previously CSSI). That CPU board called CMPCPRO has a mpc8321E CPU (Family PQII PRO hence its name) and can be plugged in place of the CMPC885 board. In order to support that new board, the following changes are included in this series: - Make the mpc8xx watchdog driver more generic for reusing it with mpc83xx - Fix various small problems on mpc83xx platform - Add a GPIO Driver for QE GPIOs - Add support for mpc832x into mpc83xx SPI driver - Refactor existing board code that will be shared with new board - Add the new board
Diffstat (limited to 'drivers/gpio')
-rw-r--r--drivers/gpio/Kconfig18
-rw-r--r--drivers/gpio/Makefile1
-rw-r--r--drivers/gpio/qe_gpio.c170
3 files changed, 189 insertions, 0 deletions
diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig
index 7d5ddbdee0c..9bf6e428ded 100644
--- a/drivers/gpio/Kconfig
+++ b/drivers/gpio/Kconfig
@@ -547,6 +547,24 @@ config MPC8XXX_GPIO
value setting, the open-drain feature, which can configure individual
GPIOs to work as open-drain outputs, is supported.
+config QE_GPIO
+ bool "Freescale QUICC ENGINE GPIO driver"
+ depends on DM_GPIO
+ depends on QE
+ help
+ This driver supports the QUICC Engine GPIOs of MPC83XX CPUs.
+ Each GPIO bank is identified by its own entry in the device tree,
+ i.e.
+
+ qe_pio_a: gpio-controller@1400 {
+ compatible = "fsl,mpc8323-qe-pario-bank";
+ reg = <0x1400 0x18>;
+ gpio-controller;
+ #gpio-cells = <2>;
+ };
+
+ Each bank has 32 GPIOs.
+
config MPC8XX_GPIO
bool "Freescale MPC8XX GPIO driver"
depends on DM_GPIO
diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile
index 1e81e369629..64a36c472eb 100644
--- a/drivers/gpio/Makefile
+++ b/drivers/gpio/Makefile
@@ -38,6 +38,7 @@ obj-$(CONFIG_TEGRA186_GPIO) += tegra186_gpio.o
obj-$(CONFIG_DA8XX_GPIO) += da8xx_gpio.o
obj-$(CONFIG_ALTERA_PIO) += altera_pio.o
obj-$(CONFIG_MPC8XXX_GPIO) += mpc8xxx_gpio.o
+obj-$(CONFIG_QE_GPIO) += qe_gpio.o
obj-$(CONFIG_MPC8XX_GPIO) += mpc8xx_gpio.o
obj-$(CONFIG_MPC83XX_SPISEL_BOOT) += mpc83xx_spisel_boot.o
obj-$(CONFIG_SH_GPIO_PFC) += sh_pfc.o
diff --git a/drivers/gpio/qe_gpio.c b/drivers/gpio/qe_gpio.c
new file mode 100644
index 00000000000..16e8d1eae6e
--- /dev/null
+++ b/drivers/gpio/qe_gpio.c
@@ -0,0 +1,170 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright 2023 CR GROUP France
+ * Christophe Leroy <[email protected]>
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <mapmem.h>
+#include <asm/gpio.h>
+#include <asm/immap_83xx.h>
+#include <asm/io.h>
+#include <dm/of_access.h>
+
+#define QE_DIR_NONE 0
+#define QE_DIR_OUT 1
+#define QE_DIR_IN 2
+#define QE_DIR_IN_OUT 3
+
+struct qe_gpio_data {
+ /* The bank's register base in memory */
+ struct gpio_n __iomem *base;
+ /* The address of the registers; used to identify the bank */
+ phys_addr_t addr;
+};
+
+static inline u32 gpio_mask(uint gpio)
+{
+ return 1U << (31 - (gpio));
+}
+
+static inline u32 gpio_mask2(uint gpio)
+{
+ return 1U << (30 - ((gpio & 15) << 1));
+}
+
+static int qe_gpio_direction_input(struct udevice *dev, uint gpio)
+{
+ struct qe_gpio_data *data = dev_get_priv(dev);
+ struct gpio_n __iomem *base = data->base;
+ u32 mask2 = gpio_mask2(gpio);
+
+ if (gpio < 16)
+ clrsetbits_be32(&base->dir1, mask2 * QE_DIR_OUT, mask2 * QE_DIR_IN);
+ else
+ clrsetbits_be32(&base->dir2, mask2 * QE_DIR_OUT, mask2 * QE_DIR_IN);
+
+ return 0;
+}
+
+static int qe_gpio_set_value(struct udevice *dev, uint gpio, int value)
+{
+ struct qe_gpio_data *data = dev_get_priv(dev);
+ struct gpio_n __iomem *base = data->base;
+ u32 mask = gpio_mask(gpio);
+ u32 mask2 = gpio_mask2(gpio);
+
+ if (gpio < 16)
+ clrsetbits_be32(&base->dir1, mask2 * QE_DIR_IN, mask2 * QE_DIR_OUT);
+ else
+ clrsetbits_be32(&base->dir2, mask2 * QE_DIR_IN, mask2 * QE_DIR_OUT);
+
+ if (value)
+ setbits_be32(&base->pdat, mask);
+ else
+ clrbits_be32(&base->pdat, mask);
+
+ return 0;
+}
+
+static int qe_gpio_get_value(struct udevice *dev, uint gpio)
+{
+ struct qe_gpio_data *data = dev_get_priv(dev);
+ struct gpio_n __iomem *base = data->base;
+ u32 mask = gpio_mask(gpio);
+
+ return !!(in_be32(&base->pdat) & mask);
+}
+
+static int qe_gpio_get_function(struct udevice *dev, uint gpio)
+{
+ struct qe_gpio_data *data = dev_get_priv(dev);
+ struct gpio_n __iomem *base = data->base;
+ u32 mask2 = gpio_mask2(gpio);
+ int dir;
+
+ if (gpio < 16)
+ dir = in_be32(&base->dir1);
+ else
+ dir = in_be32(&base->dir2);
+
+ if ((dir & (mask2 * QE_DIR_IN_OUT)) == (mask2 & QE_DIR_IN))
+ return GPIOF_INPUT;
+ else if ((dir & (mask2 * QE_DIR_IN_OUT)) == (mask2 & QE_DIR_OUT))
+ return GPIOF_OUTPUT;
+ else
+ return GPIOF_UNKNOWN;
+}
+
+static int qe_gpio_of_to_plat(struct udevice *dev)
+{
+ struct qe_gpio_plat *plat = dev_get_plat(dev);
+
+ plat->addr = dev_read_addr_size_index(dev, 0, (fdt_size_t *)&plat->size);
+
+ return 0;
+}
+
+static int qe_gpio_plat_to_priv(struct udevice *dev)
+{
+ struct qe_gpio_data *priv = dev_get_priv(dev);
+ struct qe_gpio_plat *plat = dev_get_plat(dev);
+ unsigned long size = plat->size;
+
+ if (size == 0)
+ size = sizeof(struct gpio_n);
+
+ priv->addr = plat->addr;
+ priv->base = (void __iomem *)plat->addr;
+
+ if (!priv->base)
+ return -ENOMEM;
+
+ return 0;
+}
+
+static int qe_gpio_probe(struct udevice *dev)
+{
+ struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev);
+ struct qe_gpio_data *data = dev_get_priv(dev);
+ char name[32], *str;
+
+ qe_gpio_plat_to_priv(dev);
+
+ snprintf(name, sizeof(name), "QE@%.8llx",
+ (unsigned long long)data->addr);
+ str = strdup(name);
+
+ if (!str)
+ return -ENOMEM;
+
+ uc_priv->bank_name = str;
+ uc_priv->gpio_count = 32;
+
+ return 0;
+}
+
+static const struct dm_gpio_ops gpio_qe_ops = {
+ .direction_input = qe_gpio_direction_input,
+ .direction_output = qe_gpio_set_value,
+ .get_value = qe_gpio_get_value,
+ .set_value = qe_gpio_set_value,
+ .get_function = qe_gpio_get_function,
+};
+
+static const struct udevice_id qe_gpio_ids[] = {
+ { .compatible = "fsl,mpc8323-qe-pario-bank"},
+ { /* sentinel */ }
+};
+
+U_BOOT_DRIVER(gpio_qe) = {
+ .name = "gpio_qe",
+ .id = UCLASS_GPIO,
+ .ops = &gpio_qe_ops,
+ .of_to_plat = qe_gpio_of_to_plat,
+ .plat_auto = sizeof(struct qe_gpio_plat),
+ .of_match = qe_gpio_ids,
+ .probe = qe_gpio_probe,
+ .priv_auto = sizeof(struct qe_gpio_data),
+};