diff options
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/clk/mpc83xx_clk.c | 7 | ||||
-rw-r--r-- | drivers/gpio/Kconfig | 18 | ||||
-rw-r--r-- | drivers/gpio/Makefile | 1 | ||||
-rw-r--r-- | drivers/gpio/qe_gpio.c | 170 | ||||
-rw-r--r-- | drivers/spi/mpc8xxx_spi.c | 13 | ||||
-rw-r--r-- | drivers/watchdog/Kconfig | 26 | ||||
-rw-r--r-- | drivers/watchdog/Makefile | 2 | ||||
-rw-r--r-- | drivers/watchdog/mpc8xx_wdt.c | 75 | ||||
-rw-r--r-- | drivers/watchdog/mpc8xxx_wdt.c | 112 |
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), +}; |