summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'drivers')
-rw-r--r--drivers/clk/mpc83xx_clk.c7
-rw-r--r--drivers/gpio/Kconfig18
-rw-r--r--drivers/gpio/Makefile1
-rw-r--r--drivers/gpio/qe_gpio.c170
-rw-r--r--drivers/spi/mpc8xxx_spi.c13
-rw-r--r--drivers/watchdog/Kconfig26
-rw-r--r--drivers/watchdog/Makefile2
-rw-r--r--drivers/watchdog/mpc8xx_wdt.c75
-rw-r--r--drivers/watchdog/mpc8xxx_wdt.c112
9 files changed, 343 insertions, 81 deletions
diff --git a/drivers/clk/mpc83xx_clk.c b/drivers/clk/mpc83xx_clk.c
index 0255ccaf8a..cc734450ef 100644
--- a/drivers/clk/mpc83xx_clk.c
+++ b/drivers/clk/mpc83xx_clk.c
@@ -346,8 +346,10 @@ static int mpc83xx_clk_probe(struct udevice *dev)
type = dev_get_driver_data(dev);
+#ifdef CONFIG_FSL_ESDHC
if (mpc83xx_has_sdhc(type))
gd->arch.sdhc_clk = priv->speed[MPC83XX_CLK_SDHC];
+#endif
gd->arch.core_clk = priv->speed[MPC83XX_CLK_CORE];
gd->arch.i2c1_clk = priv->speed[MPC83XX_CLK_I2C1];
@@ -362,6 +364,11 @@ static int mpc83xx_clk_probe(struct udevice *dev)
gd->cpu_clk = priv->speed[MPC83XX_CLK_CORE];
gd->bus_clk = priv->speed[MPC83XX_CLK_CSB];
+#ifdef CONFIG_QE
+ gd->arch.qe_clk = priv->speed[MPC83XX_CLK_QE];
+ gd->arch.brg_clk = priv->speed[MPC83XX_CLK_BRG];
+#endif
+
return 0;
}
diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig
index 7d5ddbdee0..9bf6e428de 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 1e81e36962..64a36c472e 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 0000000000..16e8d1eae6
--- /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 <christophe.leroy@csgroup.eu>
+ */
+
+#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),
+};
diff --git a/drivers/spi/mpc8xxx_spi.c b/drivers/spi/mpc8xxx_spi.c
index 6869d60d97..78892173dc 100644
--- a/drivers/spi/mpc8xxx_spi.c
+++ b/drivers/spi/mpc8xxx_spi.c
@@ -16,6 +16,7 @@
#include <dm/device_compat.h>
#include <linux/bitops.h>
#include <linux/delay.h>
+#include <asm/arch/soc.h>
enum {
SPI_EV_NE = BIT(31 - 22), /* Receiver Not Empty */
@@ -30,6 +31,7 @@ enum {
SPI_MODE_REV = BIT(31 - 5), /* Reverse mode - MSB first */
SPI_MODE_MS = BIT(31 - 6), /* Always master */
SPI_MODE_EN = BIT(31 - 7), /* Enable interface */
+ SPI_MODE_OP = BIT(31 - 17), /* CPU Mode, QE otherwise */
SPI_MODE_LEN_MASK = 0xf00000,
SPI_MODE_LEN_SHIFT = 20,
@@ -89,6 +91,9 @@ static int mpc8xxx_spi_probe(struct udevice *dev)
*/
out_be32(&priv->spi->mode, SPI_MODE_REV | SPI_MODE_MS);
+ if (dev_get_driver_data(dev) == SOC_MPC832X)
+ setbits_be32(&priv->spi->mode, SPI_MODE_OP);
+
/* set len to 8 bits */
setbits_be32(&spi->mode, (8 - 1) << SPI_MODE_LEN_SHIFT);
@@ -130,6 +135,7 @@ static int mpc8xxx_spi_xfer(struct udevice *dev, uint bitlen,
u32 tmpdin = 0, tmpdout = 0, n;
const u8 *cout = dout;
u8 *cin = din;
+ ulong type = dev_get_driver_data(bus);
debug("%s: slave %s:%u dout %08X din %08X bitlen %u\n", __func__,
bus->name, plat->cs, (uint)dout, (uint)din, bitlen);
@@ -157,6 +163,9 @@ static int mpc8xxx_spi_xfer(struct udevice *dev, uint bitlen,
if (cout)
tmpdout = *cout++;
+ if (type == SOC_MPC832X)
+ tmpdout <<= 24;
+
/* Write the data out */
out_be32(&spi->tx, tmpdout);
@@ -179,6 +188,9 @@ static int mpc8xxx_spi_xfer(struct udevice *dev, uint bitlen,
tmpdin = in_be32(&spi->rx);
setbits_be32(&spi->event, SPI_EV_NE);
+ if (type == SOC_MPC832X)
+ tmpdin >>= 16;
+
if (cin)
*cin++ = tmpdin;
@@ -271,6 +283,7 @@ static const struct dm_spi_ops mpc8xxx_spi_ops = {
static const struct udevice_id mpc8xxx_spi_ids[] = {
{ .compatible = "fsl,spi" },
+ { .compatible = "fsl,mpc832x-spi", .data = SOC_MPC832X },
{ }
};
diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig
index a15fbd6cbf..646663528a 100644
--- a/drivers/watchdog/Kconfig
+++ b/drivers/watchdog/Kconfig
@@ -185,12 +185,28 @@ config WDT_MESON_GXBB
Select this to enable Meson watchdog timer,
which can be found on some Amlogic platforms.
-config WDT_MPC8xx
- bool "MPC8xx watchdog timer support"
- depends on WDT && MPC8xx
- select HW_WATCHDOG
+config WDT_MPC8xxx
+ bool "MPC8xxx watchdog timer support"
+ depends on WDT && (MPC8xx || MPC83xx)
+ help
+ Select this to enable mpc8xxx watchdog timer
+
+config WDT_MPC8xxx_BME
+ bool "Enable MPC8xx Bus Monitoring"
+ depends on WDT_MPC8xxx && MPC8xx
help
- Select this to enable mpc8xx watchdog timer
+ Select this to enable mpc8xx Bus Monitor.
+
+config WDT_MPC8xxx_BMT
+ int "MPC8xx Bus Monitor Timing" if WDT_MPC8xxx_BME
+ range 0 255
+ default 255
+ depends on WDT_MPC8xxx
+ help
+ Bus monitor timing. Defines the timeout period, in 8 system clock
+ resolution, for the bus monitor.
+
+ Maximum timeout is 2,040 clocks (255 x 8).
config WDT_MT7620
bool "MediaTek MT7620 watchdog timer support"
diff --git a/drivers/watchdog/Makefile b/drivers/watchdog/Makefile
index 4da338669e..fd5d9c7376 100644
--- a/drivers/watchdog/Makefile
+++ b/drivers/watchdog/Makefile
@@ -32,7 +32,7 @@ obj-$(CONFIG_WDT_FTWDT010) += ftwdt010_wdt.o
obj-$(CONFIG_WDT_GPIO) += gpio_wdt.o
obj-$(CONFIG_WDT_MAX6370) += max6370_wdt.o
obj-$(CONFIG_WDT_MESON_GXBB) += meson_gxbb_wdt.o
-obj-$(CONFIG_WDT_MPC8xx) += mpc8xx_wdt.o
+obj-$(CONFIG_WDT_MPC8xxx) += mpc8xxx_wdt.o
obj-$(CONFIG_WDT_MT7620) += mt7620_wdt.o
obj-$(CONFIG_WDT_MT7621) += mt7621_wdt.o
obj-$(CONFIG_WDT_MTK) += mtk_wdt.o
diff --git a/drivers/watchdog/mpc8xx_wdt.c b/drivers/watchdog/mpc8xx_wdt.c
deleted file mode 100644
index c8b104d8f5..0000000000
--- a/drivers/watchdog/mpc8xx_wdt.c
+++ /dev/null
@@ -1,75 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0+
-/*
- * Copyright 2017 CS Systemes d'Information
- */
-
-#include <common.h>
-#include <env.h>
-#include <dm.h>
-#include <wdt.h>
-#include <mpc8xx.h>
-#include <asm/cpm_8xx.h>
-#include <asm/io.h>
-
-void hw_watchdog_reset(void)
-{
- immap_t __iomem *immap = (immap_t __iomem *)CONFIG_SYS_IMMR;
-
- out_be16(&immap->im_siu_conf.sc_swsr, 0x556c); /* write magic1 */
- out_be16(&immap->im_siu_conf.sc_swsr, 0xaa39); /* write magic2 */
-}
-
-static int mpc8xx_wdt_start(struct udevice *dev, u64 timeout, ulong flags)
-{
- immap_t __iomem *immap = (immap_t __iomem *)CONFIG_SYS_IMMR;
- u32 val = CONFIG_SYS_SYPCR;
- const char *mode = env_get("watchdog_mode");
-
- if (strcmp(mode, "off") == 0)
- val = val & ~(SYPCR_SWE | SYPCR_SWRI);
- else if (strcmp(mode, "nmi") == 0)
- val = (val & ~SYPCR_SWRI) | SYPCR_SWE;
-
- out_be32(&immap->im_siu_conf.sc_sypcr, val);
-
- if (!(in_be32(&immap->im_siu_conf.sc_sypcr) & SYPCR_SWE))
- return -EBUSY;
- return 0;
-
-}
-
-static int mpc8xx_wdt_stop(struct udevice *dev)
-{
- immap_t __iomem *immap = (immap_t __iomem *)CONFIG_SYS_IMMR;
-
- out_be32(&immap->im_siu_conf.sc_sypcr, CONFIG_SYS_SYPCR & ~SYPCR_SWE);
-
- if (in_be32(&immap->im_siu_conf.sc_sypcr) & SYPCR_SWE)
- return -EBUSY;
- return 0;
-}
-
-static int mpc8xx_wdt_reset(struct udevice *dev)
-{
- hw_watchdog_reset();
-
- return 0;
-}
-
-static const struct wdt_ops mpc8xx_wdt_ops = {
- .start = mpc8xx_wdt_start,
- .reset = mpc8xx_wdt_reset,
- .stop = mpc8xx_wdt_stop,
-};
-
-static const struct udevice_id mpc8xx_wdt_ids[] = {
- { .compatible = "fsl,pq1-wdt" },
- {}
-};
-
-U_BOOT_DRIVER(wdt_mpc8xx) = {
- .name = "wdt_mpc8xx",
- .id = UCLASS_WDT,
- .of_match = mpc8xx_wdt_ids,
- .ops = &mpc8xx_wdt_ops,
-};
diff --git a/drivers/watchdog/mpc8xxx_wdt.c b/drivers/watchdog/mpc8xxx_wdt.c
new file mode 100644
index 0000000000..f28636ca90
--- /dev/null
+++ b/drivers/watchdog/mpc8xxx_wdt.c
@@ -0,0 +1,112 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright 2017 CS Systemes d'Information
+ */
+
+#include <common.h>
+#include <env.h>
+#include <dm.h>
+#include <wdt.h>
+#include <clock_legacy.h>
+#include <asm/io.h>
+
+struct mpc8xxx_wdt {
+ __be32 res0;
+ __be32 swcrr; /* System watchdog control register */
+#define SWCRR_SWTC 0xFFFF0000 /* Software Watchdog Time Count. */
+#define SWCRR_BME 0x00000080 /* Bus monitor enable (mpc8xx) */
+#define SWCRR_SWF 0x00000008 /* Software Watchdog Freeze (mpc8xx). */
+#define SWCRR_SWEN 0x00000004 /* Watchdog Enable bit. */
+#define SWCRR_SWRI 0x00000002 /* Software Watchdog Reset/Interrupt Select bit.*/
+#define SWCRR_SWPR 0x00000001 /* Software Watchdog Counter Prescale bit. */
+ __be32 swcnr; /* System watchdog count register */
+ u8 res1[2];
+ __be16 swsrr; /* System watchdog service register */
+ u8 res2[0xf0];
+};
+
+struct mpc8xxx_wdt_priv {
+ struct mpc8xxx_wdt __iomem *base;
+};
+
+static int mpc8xxx_wdt_reset(struct udevice *dev)
+{
+ struct mpc8xxx_wdt_priv *priv = dev_get_priv(dev);
+
+ out_be16(&priv->base->swsrr, 0x556c); /* write magic1 */
+ out_be16(&priv->base->swsrr, 0xaa39); /* write magic2 */
+
+ return 0;
+}
+
+static int mpc8xxx_wdt_start(struct udevice *dev, u64 timeout, ulong flags)
+{
+ struct mpc8xxx_wdt_priv *priv = dev_get_priv(dev);
+ const char *mode = env_get("watchdog_mode");
+ ulong prescaler = dev_get_driver_data(dev);
+ u16 swtc = min_t(u16, timeout * get_board_sys_clk() / 1000 / prescaler, U16_MAX);
+ u32 val;
+
+ mpc8xxx_wdt_reset(dev);
+
+ if (strcmp(mode, "off") == 0)
+ val = (swtc << 16) | SWCRR_SWPR;
+ else if (strcmp(mode, "nmi") == 0)
+ val = (swtc << 16) | SWCRR_SWPR | SWCRR_SWEN;
+ else
+ val = (swtc << 16) | SWCRR_SWPR | SWCRR_SWEN | SWCRR_SWRI;
+
+ if (IS_ENABLED(CONFIG_WDT_MPC8xxx_BME))
+ val |= (CONFIG_WDT_MPC8xxx_BMT << 8) | SWCRR_BME;
+
+ out_be32(&priv->base->swcrr, val);
+
+ if (!(in_be32(&priv->base->swcrr) & SWCRR_SWEN))
+ return -EBUSY;
+ return 0;
+
+}
+
+static int mpc8xxx_wdt_stop(struct udevice *dev)
+{
+ struct mpc8xxx_wdt_priv *priv = dev_get_priv(dev);
+
+ clrbits_be32(&priv->base->swcrr, SWCRR_SWEN);
+
+ if (in_be32(&priv->base->swcrr) & SWCRR_SWEN)
+ return -EBUSY;
+ return 0;
+}
+
+static int mpc8xxx_wdt_of_to_plat(struct udevice *dev)
+{
+ struct mpc8xxx_wdt_priv *priv = dev_get_priv(dev);
+
+ priv->base = (void __iomem *)devfdt_remap_addr(dev);
+
+ if (!priv->base)
+ return -EINVAL;
+
+ return 0;
+}
+
+static const struct wdt_ops mpc8xxx_wdt_ops = {
+ .start = mpc8xxx_wdt_start,
+ .reset = mpc8xxx_wdt_reset,
+ .stop = mpc8xxx_wdt_stop,
+};
+
+static const struct udevice_id mpc8xxx_wdt_ids[] = {
+ { .compatible = "fsl,pq1-wdt", .data = 0x800 },
+ { .compatible = "fsl,pq2pro-wdt", .data = 0x10000 },
+ {}
+};
+
+U_BOOT_DRIVER(wdt_mpc8xxx) = {
+ .name = "wdt_mpc8xxx",
+ .id = UCLASS_WDT,
+ .of_match = mpc8xxx_wdt_ids,
+ .ops = &mpc8xxx_wdt_ops,
+ .of_to_plat = mpc8xxx_wdt_of_to_plat,
+ .priv_auto = sizeof(struct mpc8xxx_wdt_priv),
+};