summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'drivers')
-rw-r--r--drivers/gpio/Kconfig6
-rw-r--r--drivers/gpio/Makefile1
-rw-r--r--drivers/gpio/sl28cpld-gpio.c165
-rw-r--r--drivers/misc/Kconfig8
-rw-r--r--drivers/misc/Makefile1
-rw-r--r--drivers/misc/sl28cpld.c105
-rw-r--r--drivers/pci/pci_mvebu.c133
-rw-r--r--drivers/pinctrl/mvebu/pinctrl-armada-37xx.c6
-rw-r--r--drivers/rtc/armada38x.c2
-rw-r--r--drivers/watchdog/Kconfig7
-rw-r--r--drivers/watchdog/Makefile1
-rw-r--r--drivers/watchdog/sl28cpld-wdt.c109
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,
+};