diff options
Diffstat (limited to 'drivers')
| -rw-r--r-- | drivers/gpio/Kconfig | 6 | ||||
| -rw-r--r-- | drivers/gpio/Makefile | 1 | ||||
| -rw-r--r-- | drivers/gpio/sl28cpld-gpio.c | 165 | ||||
| -rw-r--r-- | drivers/misc/Kconfig | 8 | ||||
| -rw-r--r-- | drivers/misc/Makefile | 1 | ||||
| -rw-r--r-- | drivers/misc/sl28cpld.c | 105 | ||||
| -rw-r--r-- | drivers/pci/pci_mvebu.c | 133 | ||||
| -rw-r--r-- | drivers/pinctrl/mvebu/pinctrl-armada-37xx.c | 6 | ||||
| -rw-r--r-- | drivers/rtc/armada38x.c | 2 | ||||
| -rw-r--r-- | drivers/watchdog/Kconfig | 7 | ||||
| -rw-r--r-- | drivers/watchdog/Makefile | 1 | ||||
| -rw-r--r-- | drivers/watchdog/sl28cpld-wdt.c | 109 |
12 files changed, 467 insertions, 77 deletions
diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index 8d0e47c67d9..522dfc195ec 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -544,4 +544,10 @@ config ZYNQMP_GPIO_MODEPIN are accessed using xilinx firmware. In modepin register, [3:0] bits set direction, [7:4] bits read IO, [11:8] bits set/clear IO. +config SL28CPLD_GPIO + bool "Kontron sl28cpld GPIO driver" + depends on DM_GPIO && SL28CPLD + help + Support GPIO access on Kontron sl28cpld board management controllers. + endif diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile index 63e9be6034f..33f7d41b7db 100644 --- a/drivers/gpio/Makefile +++ b/drivers/gpio/Makefile @@ -70,4 +70,5 @@ obj-$(CONFIG_NX_GPIO) += nx_gpio.o obj-$(CONFIG_SIFIVE_GPIO) += sifive-gpio.o obj-$(CONFIG_NOMADIK_GPIO) += nmk_gpio.o obj-$(CONFIG_MAX7320_GPIO) += max7320_gpio.o +obj-$(CONFIG_SL28CPLD_GPIO) += sl28cpld-gpio.o obj-$(CONFIG_ZYNQMP_GPIO_MODEPIN) += zynqmp_gpio_modepin.o diff --git a/drivers/gpio/sl28cpld-gpio.c b/drivers/gpio/sl28cpld-gpio.c new file mode 100644 index 00000000000..700fc3df298 --- /dev/null +++ b/drivers/gpio/sl28cpld-gpio.c @@ -0,0 +1,165 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * GPIO driver for the sl28cpld + * + * Copyright (c) 2021 Michael Walle <michael@walle.cc> + */ + +#include <common.h> +#include <dm.h> +#include <asm/gpio.h> +#include <sl28cpld.h> + +/* GPIO flavor */ +#define SL28CPLD_GPIO_DIR 0x00 +#define SL28CPLD_GPIO_OUT 0x01 +#define SL28CPLD_GPIO_IN 0x02 + +/* input-only flavor */ +#define SL28CPLD_GPI_IN 0x00 + +/* output-only flavor */ +#define SL28CPLD_GPO_OUT 0x00 + +enum { + SL28CPLD_GPIO, + SL28CPLD_GPI, + SL28CPLD_GPO, +}; + +static int sl28cpld_gpio_get_value(struct udevice *dev, unsigned int gpio) +{ + ulong type = dev_get_driver_data(dev); + int val, reg; + + switch (type) { + case SL28CPLD_GPIO: + reg = SL28CPLD_GPIO_IN; + break; + case SL28CPLD_GPI: + reg = SL28CPLD_GPI_IN; + break; + case SL28CPLD_GPO: + /* we are output only, thus just return the output value */ + reg = SL28CPLD_GPO_OUT; + break; + default: + return -EINVAL; + } + + val = sl28cpld_read(dev, reg); + + return val < 0 ? val : !!(val & BIT(gpio)); +} + +static int sl28cpld_gpio_set_value(struct udevice *dev, unsigned int gpio, + int value) +{ + ulong type = dev_get_driver_data(dev); + uint reg; + + switch (type) { + case SL28CPLD_GPIO: + reg = SL28CPLD_GPIO_OUT; + break; + case SL28CPLD_GPO: + reg = SL28CPLD_GPO_OUT; + break; + case SL28CPLD_GPI: + default: + return -EINVAL; + } + + if (value) + return sl28cpld_update(dev, reg, 0, BIT(gpio)); + else + return sl28cpld_update(dev, reg, BIT(gpio), 0); +} + +static int sl28cpld_gpio_direction_input(struct udevice *dev, unsigned int gpio) +{ + ulong type = dev_get_driver_data(dev); + + switch (type) { + case SL28CPLD_GPI: + return 0; + case SL28CPLD_GPIO: + return sl28cpld_update(dev, SL28CPLD_GPIO_DIR, BIT(gpio), 0); + case SL28CPLD_GPO: + default: + return -EINVAL; + } +} + +static int sl28cpld_gpio_direction_output(struct udevice *dev, + unsigned int gpio, int value) +{ + ulong type = dev_get_driver_data(dev); + int ret; + + /* set_value() will report an error if we are input-only */ + ret = sl28cpld_gpio_set_value(dev, gpio, value); + if (ret) + return ret; + + if (type == SL28CPLD_GPIO) + return sl28cpld_update(dev, SL28CPLD_GPIO_DIR, 0, BIT(gpio)); + + return 0; +} + +static int sl28cpld_gpio_get_function(struct udevice *dev, unsigned int gpio) +{ + ulong type = dev_get_driver_data(dev); + int val; + + switch (type) { + case SL28CPLD_GPIO: + val = sl28cpld_read(dev, SL28CPLD_GPIO_DIR); + if (val < 0) + return val; + if (val & BIT(gpio)) + return GPIOF_OUTPUT; + else + return GPIOF_INPUT; + case SL28CPLD_GPI: + return GPIOF_INPUT; + case SL28CPLD_GPO: + return GPIOF_OUTPUT; + default: + return -EINVAL; + } +} + +static const struct dm_gpio_ops sl28cpld_gpio_ops = { + .direction_input = sl28cpld_gpio_direction_input, + .direction_output = sl28cpld_gpio_direction_output, + .get_value = sl28cpld_gpio_get_value, + .set_value = sl28cpld_gpio_set_value, + .get_function = sl28cpld_gpio_get_function, +}; + +static int sl28cpld_gpio_probe(struct udevice *dev) +{ + struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev); + + uc_priv->gpio_count = 8; + uc_priv->bank_name = dev_read_name(dev); + + return 0; +} + +static const struct udevice_id sl28cpld_gpio_ids[] = { + { .compatible = "kontron,sl28cpld-gpio", .data = SL28CPLD_GPIO}, + { .compatible = "kontron,sl28cpld-gpo", .data = SL28CPLD_GPO}, + { .compatible = "kontron,sl28cpld-gpi", .data = SL28CPLD_GPI}, + { } +}; + +U_BOOT_DRIVER(sl28cpld_gpio) = { + .name = "sl28cpld_gpio", + .id = UCLASS_GPIO, + .of_match = sl28cpld_gpio_ids, + .probe = sl28cpld_gpio_probe, + .ops = &sl28cpld_gpio_ops, +}; diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig index 0ade3e32b0e..7029bb7b5c5 100644 --- a/drivers/misc/Kconfig +++ b/drivers/misc/Kconfig @@ -512,4 +512,12 @@ config ESM_PMIC config FSL_IFC bool +config SL28CPLD + bool "Enable Kontron sl28cpld multi-function driver" + depends on DM_I2C + help + Support for the Kontron sl28cpld management controller. This is + the base driver which provides common access methods for the + sub-drivers. + endmenu diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile index bca7b24e99a..f22eff601a1 100644 --- a/drivers/misc/Makefile +++ b/drivers/misc/Makefile @@ -82,3 +82,4 @@ obj-$(CONFIG_MICROCHIP_FLEXCOM) += microchip_flexcom.o obj-$(CONFIG_K3_AVS0) += k3_avs.o obj-$(CONFIG_ESM_K3) += k3_esm.o obj-$(CONFIG_ESM_PMIC) += esm_pmic.o +obj-$(CONFIG_SL28CPLD) += sl28cpld.o diff --git a/drivers/misc/sl28cpld.c b/drivers/misc/sl28cpld.c new file mode 100644 index 00000000000..01ef1c6178f --- /dev/null +++ b/drivers/misc/sl28cpld.c @@ -0,0 +1,105 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (c) 2021 Michael Walle <michael@walle.cc> + */ + +#include <common.h> +#include <dm.h> +#include <i2c.h> + +struct sl28cpld_child_plat { + uint offset; +}; + +/* + * The access methods works either with the first argument being a child + * device or with the MFD device itself. + */ +static int sl28cpld_read_child(struct udevice *dev, uint offset) +{ + struct sl28cpld_child_plat *plat = dev_get_parent_plat(dev); + struct udevice *mfd = dev_get_parent(dev); + + return dm_i2c_reg_read(mfd, offset + plat->offset); +} + +int sl28cpld_read(struct udevice *dev, uint offset) +{ + if (dev->driver == DM_DRIVER_GET(sl28cpld)) + return dm_i2c_reg_read(dev, offset); + else + return sl28cpld_read_child(dev, offset); +} + +static int sl28cpld_write_child(struct udevice *dev, uint offset, + uint8_t value) +{ + struct sl28cpld_child_plat *plat = dev_get_parent_plat(dev); + struct udevice *mfd = dev_get_parent(dev); + + return dm_i2c_reg_write(mfd, offset + plat->offset, value); +} + +int sl28cpld_write(struct udevice *dev, uint offset, uint8_t value) +{ + if (dev->driver == DM_DRIVER_GET(sl28cpld)) + return dm_i2c_reg_write(dev, offset, value); + else + return sl28cpld_write_child(dev, offset, value); +} + +int sl28cpld_update(struct udevice *dev, uint offset, uint8_t clear, + uint8_t set) +{ + int val; + + val = sl28cpld_read(dev, offset); + if (val < 0) + return val; + + val &= ~clear; + val |= set; + + return sl28cpld_write(dev, offset, val); +} + +static int sl28cpld_probe(struct udevice *dev) +{ + i2c_set_chip_flags(dev, DM_I2C_CHIP_RD_ADDRESS | + DM_I2C_CHIP_WR_ADDRESS); + + return 0; +} + +static int sl28cpld_child_post_bind(struct udevice *dev) +{ + struct sl28cpld_child_plat *plat = dev_get_parent_plat(dev); + int offset; + + if (!dev_has_ofnode(dev)) + return 0; + + offset = dev_read_u32_default(dev, "reg", -1); + if (offset == -1) + return -EINVAL; + + plat->offset = offset; + + return 0; +} + +static const struct udevice_id sl28cpld_ids[] = { + { .compatible = "kontron,sl28cpld" }, + {} +}; + +U_BOOT_DRIVER(sl28cpld) = { + .name = "sl28cpld", + .id = UCLASS_NOP, + .of_match = sl28cpld_ids, + .probe = sl28cpld_probe, + .bind = dm_scan_fdt_dev, + .flags = DM_FLAG_PRE_RELOC, + .per_child_plat_auto = sizeof(struct sl28cpld_child_plat), + .child_post_bind = sl28cpld_child_post_bind, +}; diff --git a/drivers/pci/pci_mvebu.c b/drivers/pci/pci_mvebu.c index 5a0a59a8b9e..f07669374d7 100644 --- a/drivers/pci/pci_mvebu.c +++ b/drivers/pci/pci_mvebu.c @@ -30,37 +30,25 @@ #include <linux/sizes.h> /* PCIe unit register offsets */ -#define SELECT(x, n) ((x >> n) & 1UL) - -#define PCIE_DEV_ID_OFF 0x0000 -#define PCIE_CMD_OFF 0x0004 -#define PCIE_DEV_REV_OFF 0x0008 -#define PCIE_BAR_LO_OFF(n) (0x0010 + ((n) << 3)) -#define PCIE_BAR_HI_OFF(n) (0x0014 + ((n) << 3)) -#define PCIE_EXP_ROM_BAR_OFF 0x0030 -#define PCIE_CAPAB_OFF 0x0060 -#define PCIE_CTRL_STAT_OFF 0x0068 -#define PCIE_HEADER_LOG_4_OFF 0x0128 -#define PCIE_BAR_CTRL_OFF(n) (0x1804 + (((n) - 1) * 4)) -#define PCIE_WIN04_CTRL_OFF(n) (0x1820 + ((n) << 4)) -#define PCIE_WIN04_BASE_OFF(n) (0x1824 + ((n) << 4)) -#define PCIE_WIN04_REMAP_OFF(n) (0x182c + ((n) << 4)) -#define PCIE_WIN5_CTRL_OFF 0x1880 -#define PCIE_WIN5_BASE_OFF 0x1884 -#define PCIE_WIN5_REMAP_OFF 0x188c -#define PCIE_CONF_ADDR_OFF 0x18f8 -#define PCIE_CONF_DATA_OFF 0x18fc -#define PCIE_MASK_OFF 0x1910 -#define PCIE_MASK_ENABLE_INTS (0xf << 24) -#define PCIE_CTRL_OFF 0x1a00 -#define PCIE_CTRL_X1_MODE BIT(0) -#define PCIE_CTRL_RC_MODE BIT(1) -#define PCIE_STAT_OFF 0x1a04 -#define PCIE_STAT_BUS (0xff << 8) -#define PCIE_STAT_DEV (0x1f << 16) -#define PCIE_STAT_LINK_DOWN BIT(0) -#define PCIE_DEBUG_CTRL 0x1a60 -#define PCIE_DEBUG_SOFT_RESET BIT(20) +#define MVPCIE_ROOT_PORT_PCI_CFG_OFF 0x0000 +#define MVPCIE_ROOT_PORT_PCI_EXP_OFF 0x0060 +#define MVPCIE_BAR_LO_OFF(n) (0x0010 + ((n) << 3)) +#define MVPCIE_BAR_HI_OFF(n) (0x0014 + ((n) << 3)) +#define MVPCIE_BAR_CTRL_OFF(n) (0x1804 + (((n) - 1) * 4)) +#define MVPCIE_WIN04_CTRL_OFF(n) (0x1820 + ((n) << 4)) +#define MVPCIE_WIN04_BASE_OFF(n) (0x1824 + ((n) << 4)) +#define MVPCIE_WIN04_REMAP_OFF(n) (0x182c + ((n) << 4)) +#define MVPCIE_WIN5_CTRL_OFF 0x1880 +#define MVPCIE_WIN5_BASE_OFF 0x1884 +#define MVPCIE_WIN5_REMAP_OFF 0x188c +#define MVPCIE_CONF_ADDR_OFF 0x18f8 +#define MVPCIE_CONF_DATA_OFF 0x18fc +#define MVPCIE_CTRL_OFF 0x1a00 +#define MVPCIE_CTRL_RC_MODE BIT(1) +#define MVPCIE_STAT_OFF 0x1a04 +#define MVPCIE_STAT_BUS (0xff << 8) +#define MVPCIE_STAT_DEV (0x1f << 16) +#define MVPCIE_STAT_LINK_DOWN BIT(0) #define LINK_WAIT_RETRIES 100 #define LINK_WAIT_TIMEOUT 1000 @@ -77,7 +65,6 @@ struct mvebu_pcie { u32 lane; bool is_x4; int devfn; - u32 lane_mask; int sec_busno; char name[16]; unsigned int mem_target; @@ -90,8 +77,8 @@ struct mvebu_pcie { static inline bool mvebu_pcie_link_up(struct mvebu_pcie *pcie) { u32 val; - val = readl(pcie->base + PCIE_STAT_OFF); - return !(val & PCIE_STAT_LINK_DOWN); + val = readl(pcie->base + MVPCIE_STAT_OFF); + return !(val & MVPCIE_STAT_LINK_DOWN); } static void mvebu_pcie_wait_for_link(struct mvebu_pcie *pcie) @@ -115,20 +102,20 @@ static void mvebu_pcie_set_local_bus_nr(struct mvebu_pcie *pcie, int busno) { u32 stat; - stat = readl(pcie->base + PCIE_STAT_OFF); - stat &= ~PCIE_STAT_BUS; + stat = readl(pcie->base + MVPCIE_STAT_OFF); + stat &= ~MVPCIE_STAT_BUS; stat |= busno << 8; - writel(stat, pcie->base + PCIE_STAT_OFF); + writel(stat, pcie->base + MVPCIE_STAT_OFF); } static void mvebu_pcie_set_local_dev_nr(struct mvebu_pcie *pcie, int devno) { u32 stat; - stat = readl(pcie->base + PCIE_STAT_OFF); - stat &= ~PCIE_STAT_DEV; + stat = readl(pcie->base + MVPCIE_STAT_OFF); + stat &= ~MVPCIE_STAT_DEV; stat |= devno << 16; - writel(stat, pcie->base + PCIE_STAT_OFF); + writel(stat, pcie->base + MVPCIE_STAT_OFF); } static inline struct mvebu_pcie *hose_to_pcie(struct pci_controller *hose) @@ -198,18 +185,18 @@ static int mvebu_pcie_read_config(const struct udevice *bus, pci_dev_t bdf, addr = PCI_CONF1_EXT_ADDRESS(busno, PCI_DEV(bdf), PCI_FUNC(bdf), offset); /* write address */ - writel(addr, pcie->base + PCIE_CONF_ADDR_OFF); + writel(addr, pcie->base + MVPCIE_CONF_ADDR_OFF); /* read data */ switch (size) { case PCI_SIZE_8: - data = readb(pcie->base + PCIE_CONF_DATA_OFF + (offset & 3)); + data = readb(pcie->base + MVPCIE_CONF_DATA_OFF + (offset & 3)); break; case PCI_SIZE_16: - data = readw(pcie->base + PCIE_CONF_DATA_OFF + (offset & 2)); + data = readw(pcie->base + MVPCIE_CONF_DATA_OFF + (offset & 2)); break; case PCI_SIZE_32: - data = readl(pcie->base + PCIE_CONF_DATA_OFF); + data = readl(pcie->base + MVPCIE_CONF_DATA_OFF); break; default: return -EINVAL; @@ -289,18 +276,18 @@ static int mvebu_pcie_write_config(struct udevice *bus, pci_dev_t bdf, addr = PCI_CONF1_EXT_ADDRESS(busno, PCI_DEV(bdf), PCI_FUNC(bdf), offset); /* write address */ - writel(addr, pcie->base + PCIE_CONF_ADDR_OFF); + writel(addr, pcie->base + MVPCIE_CONF_ADDR_OFF); /* write data */ switch (size) { case PCI_SIZE_8: - writeb(value, pcie->base + PCIE_CONF_DATA_OFF + (offset & 3)); + writeb(value, pcie->base + MVPCIE_CONF_DATA_OFF + (offset & 3)); break; case PCI_SIZE_16: - writew(value, pcie->base + PCIE_CONF_DATA_OFF + (offset & 2)); + writew(value, pcie->base + MVPCIE_CONF_DATA_OFF + (offset & 2)); break; case PCI_SIZE_32: - writel(value, pcie->base + PCIE_CONF_DATA_OFF); + writel(value, pcie->base + MVPCIE_CONF_DATA_OFF); break; default: return -EINVAL; @@ -324,20 +311,20 @@ static void mvebu_pcie_setup_wins(struct mvebu_pcie *pcie) /* First, disable and clear BARs and windows. */ for (i = 1; i < 3; i++) { - writel(0, pcie->base + PCIE_BAR_CTRL_OFF(i)); - writel(0, pcie->base + PCIE_BAR_LO_OFF(i)); - writel(0, pcie->base + PCIE_BAR_HI_OFF(i)); + writel(0, pcie->base + MVPCIE_BAR_CTRL_OFF(i)); + writel(0, pcie->base + MVPCIE_BAR_LO_OFF(i)); + writel(0, pcie->base + MVPCIE_BAR_HI_OFF(i)); } for (i = 0; i < 5; i++) { - writel(0, pcie->base + PCIE_WIN04_CTRL_OFF(i)); - writel(0, pcie->base + PCIE_WIN04_BASE_OFF(i)); - writel(0, pcie->base + PCIE_WIN04_REMAP_OFF(i)); + writel(0, pcie->base + MVPCIE_WIN04_CTRL_OFF(i)); + writel(0, pcie->base + MVPCIE_WIN04_BASE_OFF(i)); + writel(0, pcie->base + MVPCIE_WIN04_REMAP_OFF(i)); } - writel(0, pcie->base + PCIE_WIN5_CTRL_OFF); - writel(0, pcie->base + PCIE_WIN5_BASE_OFF); - writel(0, pcie->base + PCIE_WIN5_REMAP_OFF); + writel(0, pcie->base + MVPCIE_WIN5_CTRL_OFF); + writel(0, pcie->base + MVPCIE_WIN5_BASE_OFF); + writel(0, pcie->base + MVPCIE_WIN5_REMAP_OFF); /* Setup windows for DDR banks. Count total DDR size on the fly. */ size = 0; @@ -345,12 +332,12 @@ static void mvebu_pcie_setup_wins(struct mvebu_pcie *pcie) const struct mbus_dram_window *cs = dram->cs + i; writel(cs->base & 0xffff0000, - pcie->base + PCIE_WIN04_BASE_OFF(i)); - writel(0, pcie->base + PCIE_WIN04_REMAP_OFF(i)); + pcie->base + MVPCIE_WIN04_BASE_OFF(i)); + writel(0, pcie->base + MVPCIE_WIN04_REMAP_OFF(i)); writel(((cs->size - 1) & 0xffff0000) | (cs->mbus_attr << 8) | (dram->mbus_dram_target_id << 4) | 1, - pcie->base + PCIE_WIN04_CTRL_OFF(i)); + pcie->base + MVPCIE_WIN04_CTRL_OFF(i)); size += cs->size; } @@ -360,14 +347,14 @@ static void mvebu_pcie_setup_wins(struct mvebu_pcie *pcie) size = 1 << fls(size); /* Setup BAR[1] to all DRAM banks. */ - writel(dram->cs[0].base | 0xc, pcie->base + PCIE_BAR_LO_OFF(1)); - writel(0, pcie->base + PCIE_BAR_HI_OFF(1)); + writel(dram->cs[0].base | 0xc, pcie->base + MVPCIE_BAR_LO_OFF(1)); + writel(0, pcie->base + MVPCIE_BAR_HI_OFF(1)); writel(((size - 1) & 0xffff0000) | 0x1, - pcie->base + PCIE_BAR_CTRL_OFF(1)); + pcie->base + MVPCIE_BAR_CTRL_OFF(1)); /* Setup BAR[0] to internal registers. */ - writel(pcie->intregs, pcie->base + PCIE_BAR_LO_OFF(0)); - writel(0, pcie->base + PCIE_BAR_HI_OFF(0)); + writel(pcie->intregs, pcie->base + MVPCIE_BAR_LO_OFF(0)); + writel(0, pcie->base + MVPCIE_BAR_HI_OFF(0)); } /* Only enable PCIe link, do not setup it */ @@ -406,9 +393,9 @@ static void mvebu_pcie_setup_link(struct mvebu_pcie *pcie) u32 reg; /* Setup PCIe controller to Root Complex mode */ - reg = readl(pcie->base + PCIE_CTRL_OFF); - reg |= PCIE_CTRL_RC_MODE; - writel(reg, pcie->base + PCIE_CTRL_OFF); + reg = readl(pcie->base + MVPCIE_CTRL_OFF); + reg |= MVPCIE_CTRL_RC_MODE; + writel(reg, pcie->base + MVPCIE_CTRL_OFF); /* * Set Maximum Link Width to X1 or X4 in Root Port's PCIe Link @@ -417,10 +404,10 @@ static void mvebu_pcie_setup_link(struct mvebu_pcie *pcie) * be set to number of SerDes PCIe lanes (1 or 4). If this register is * not set correctly then link with endpoint card is not established. */ - reg = readl(pcie->base + PCIE_CAPAB_OFF + PCI_EXP_LNKCAP); + reg = readl(pcie->base + MVPCIE_ROOT_PORT_PCI_EXP_OFF + PCI_EXP_LNKCAP); reg &= ~PCI_EXP_LNKCAP_MLW; reg |= (pcie->is_x4 ? 4 : 1) << 4; - writel(reg, pcie->base + PCIE_CAPAB_OFF + PCI_EXP_LNKCAP); + writel(reg, pcie->base + MVPCIE_ROOT_PORT_PCI_EXP_OFF + PCI_EXP_LNKCAP); } static int mvebu_pcie_probe(struct udevice *dev) @@ -443,7 +430,7 @@ static int mvebu_pcie_probe(struct udevice *dev) * have the same format in Marvell's specification as in PCIe * specification, but their meaning is totally different and they do * different things: they are aliased into internal mvebu registers - * (e.g. PCIE_BAR_LO_OFF) and these should not be changed or + * (e.g. MVPCIE_BAR_LO_OFF) and these should not be changed or * reconfigured by pci device drivers. * * So our driver converts Type 0 config space to Type 1 and reports @@ -451,10 +438,10 @@ static int mvebu_pcie_probe(struct udevice *dev) * Type 1 registers is redirected to the virtual cfgcache[] buffer, * which avoids changing unrelated registers. */ - reg = readl(pcie->base + PCIE_DEV_REV_OFF); + reg = readl(pcie->base + MVPCIE_ROOT_PORT_PCI_CFG_OFF + PCI_CLASS_REVISION); reg &= ~0xffffff00; reg |= (PCI_CLASS_BRIDGE_PCI << 8) << 8; - writel(reg, pcie->base + PCIE_DEV_REV_OFF); + writel(reg, pcie->base + MVPCIE_ROOT_PORT_PCI_CFG_OFF + PCI_CLASS_REVISION); /* * mvebu uses local bus number and local device number to determinate diff --git a/drivers/pinctrl/mvebu/pinctrl-armada-37xx.c b/drivers/pinctrl/mvebu/pinctrl-armada-37xx.c index 1cf1f06f101..e76ef153e60 100644 --- a/drivers/pinctrl/mvebu/pinctrl-armada-37xx.c +++ b/drivers/pinctrl/mvebu/pinctrl-armada-37xx.c @@ -162,11 +162,11 @@ static struct armada_37xx_pin_group armada_37xx_nb_groups[] = { PIN_GRP_GPIO("emmc_nb", 27, 9, BIT(2), "emmc"), PIN_GRP_GPIO_3("pwm0", 11, 1, BIT(3) | BIT(20), 0, BIT(20), BIT(3), "pwm", "led"), - PIN_GRP_GPIO_3("pwm1", 11, 1, BIT(4) | BIT(21), 0, BIT(21), BIT(4), + PIN_GRP_GPIO_3("pwm1", 12, 1, BIT(4) | BIT(21), 0, BIT(21), BIT(4), "pwm", "led"), - PIN_GRP_GPIO_3("pwm2", 11, 1, BIT(5) | BIT(22), 0, BIT(22), BIT(5), + PIN_GRP_GPIO_3("pwm2", 13, 1, BIT(5) | BIT(22), 0, BIT(22), BIT(5), "pwm", "led"), - PIN_GRP_GPIO_3("pwm3", 11, 1, BIT(6) | BIT(23), 0, BIT(23), BIT(6), + PIN_GRP_GPIO_3("pwm3", 14, 1, BIT(6) | BIT(23), 0, BIT(23), BIT(6), "pwm", "led"), PIN_GRP_GPIO("pmic1", 7, 1, BIT(7), "pmic"), PIN_GRP_GPIO("pmic0", 6, 1, BIT(8), "pmic"), diff --git a/drivers/rtc/armada38x.c b/drivers/rtc/armada38x.c index 2d264acf779..2af64e39122 100644 --- a/drivers/rtc/armada38x.c +++ b/drivers/rtc/armada38x.c @@ -121,7 +121,7 @@ static int armada38x_rtc_reset(struct udevice *dev) armada38x_rtc_write(0, rtc, RTC_CONF_TEST); mdelay(500); armada38x_rtc_write(0, rtc, RTC_TIME); - armada38x_rtc_write(BIT(0) | BIT(1), 0, RTC_STATUS); + armada38x_rtc_write(BIT(0) | BIT(1), rtc, RTC_STATUS); } return 0; diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig index cabac290539..f90f0ca02bc 100644 --- a/drivers/watchdog/Kconfig +++ b/drivers/watchdog/Kconfig @@ -266,6 +266,13 @@ config WDT_SBSA In the single stage mode, when the timeout is reached, your system will be reset by WS1. The first signal (WS0) is ignored. +config WDT_SL28CPLD + bool "sl28cpld watchdog timer support" + depends on WDT && SL28CPLD + help + Enable support for the watchdog timer in the Kontron sl28cpld + management controller. + config WDT_SP805 bool "SP805 watchdog timer support" depends on WDT diff --git a/drivers/watchdog/Makefile b/drivers/watchdog/Makefile index 6d2b3822c06..a35bd559f51 100644 --- a/drivers/watchdog/Makefile +++ b/drivers/watchdog/Makefile @@ -35,6 +35,7 @@ obj-$(CONFIG_WDT_OCTEONTX) += octeontx_wdt.o obj-$(CONFIG_WDT_OMAP3) += omap_wdt.o obj-$(CONFIG_WDT_SBSA) += sbsa_gwdt.o obj-$(CONFIG_WDT_K3_RTI) += rti_wdt.o +obj-$(CONFIG_WDT_SL28CPLD) += sl28cpld-wdt.o obj-$(CONFIG_WDT_SP805) += sp805_wdt.o obj-$(CONFIG_WDT_STM32MP) += stm32mp_wdt.o obj-$(CONFIG_WDT_SUNXI) += sunxi_wdt.o diff --git a/drivers/watchdog/sl28cpld-wdt.c b/drivers/watchdog/sl28cpld-wdt.c new file mode 100644 index 00000000000..af5a6b1a28a --- /dev/null +++ b/drivers/watchdog/sl28cpld-wdt.c @@ -0,0 +1,109 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Watchdog driver for the sl28cpld + * + * Copyright (c) 2021 Michael Walle <michael@walle.cc> + */ + +#include <common.h> +#include <dm.h> +#include <wdt.h> +#include <sl28cpld.h> +#include <div64.h> + +#define SL28CPLD_WDT_CTRL 0x00 +#define WDT_CTRL_EN0 BIT(0) +#define WDT_CTRL_EN1 BIT(1) +#define WDT_CTRL_EN_MASK GENMASK(1, 0) +#define WDT_CTRL_LOCK BIT(2) +#define WDT_CTRL_ASSERT_SYS_RESET BIT(6) +#define WDT_CTRL_ASSERT_WDT_TIMEOUT BIT(7) +#define SL28CPLD_WDT_TIMEOUT 0x01 +#define SL28CPLD_WDT_KICK 0x02 +#define WDT_KICK_VALUE 0x6b + +static int sl28cpld_wdt_reset(struct udevice *dev) +{ + return sl28cpld_write(dev, SL28CPLD_WDT_KICK, WDT_KICK_VALUE); +} + +static int sl28cpld_wdt_start(struct udevice *dev, u64 timeout, ulong flags) +{ + int ret, val; + + val = sl28cpld_read(dev, SL28CPLD_WDT_CTRL); + if (val < 0) + return val; + + /* (1) disable watchdog */ + val &= ~WDT_CTRL_EN_MASK; + ret = sl28cpld_write(dev, SL28CPLD_WDT_CTRL, val); + if (ret) + return ret; + + /* (2) set timeout */ + ret = sl28cpld_write(dev, SL28CPLD_WDT_TIMEOUT, lldiv(timeout, 1000)); + if (ret) + return ret; + + /* (3) kick it, will reset timer to the timeout value */ + ret = sl28cpld_wdt_reset(dev); + if (ret) + return ret; + + /* (4) enable either recovery or normal one */ + if (flags & BIT(0)) + val |= WDT_CTRL_EN1; + else + val |= WDT_CTRL_EN0; + + if (flags & BIT(1)) + val |= WDT_CTRL_LOCK; + + if (flags & BIT(2)) + val &= ~WDT_CTRL_ASSERT_SYS_RESET; + else + val |= WDT_CTRL_ASSERT_SYS_RESET; + + if (flags & BIT(3)) + val |= WDT_CTRL_ASSERT_WDT_TIMEOUT; + else + val &= ~WDT_CTRL_ASSERT_WDT_TIMEOUT; + + return sl28cpld_write(dev, SL28CPLD_WDT_CTRL, val); +} + +static int sl28cpld_wdt_stop(struct udevice *dev) +{ + int val; + + val = sl28cpld_read(dev, SL28CPLD_WDT_CTRL); + if (val < 0) + return val; + + return sl28cpld_write(dev, SL28CPLD_WDT_CTRL, val & ~WDT_CTRL_EN_MASK); +} + +static int sl28cpld_wdt_expire_now(struct udevice *dev, ulong flags) +{ + return sl28cpld_wdt_start(dev, 0, flags); +} + +static const struct wdt_ops sl28cpld_wdt_ops = { + .start = sl28cpld_wdt_start, + .reset = sl28cpld_wdt_reset, + .stop = sl28cpld_wdt_stop, + .expire_now = sl28cpld_wdt_expire_now, +}; + +static const struct udevice_id sl28cpld_wdt_ids[] = { + { .compatible = "kontron,sl28cpld-wdt", }, + {} +}; + +U_BOOT_DRIVER(sl28cpld_wdt) = { + .name = "sl28cpld-wdt", + .id = UCLASS_WDT, + .of_match = sl28cpld_wdt_ids, + .ops = &sl28cpld_wdt_ops, +}; |
