summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTom Rini <trini@konsulko.com>2022-03-03 08:24:13 -0500
committerTom Rini <trini@konsulko.com>2022-03-03 08:24:13 -0500
commit705b5840cde496e30dde386f980737a3beaa52e5 (patch)
tree76ba8bb47cadaf79fc8bbf76da7e9496010d5987
parentf64aac4a69007771963eaa52a86e733071f9fdd4 (diff)
parent2058967d2fe8f93142d774bc47241d80894027d5 (diff)
downloadu-boot-705b5840cde496e30dde386f980737a3beaa52e5.tar.gz
u-boot-705b5840cde496e30dde386f980737a3beaa52e5.tar.bz2
u-boot-705b5840cde496e30dde386f980737a3beaa52e5.zip
Merge https://gitlab.denx.de/u-boot/custodians/u-boot-fsl-qoriq
Update and fixes for sl28, lx2, pblimage generation for some powerpc products
-rw-r--r--MAINTAINERS7
-rw-r--r--Makefile2
-rw-r--r--arch/arm/dts/fsl-ls1028a-kontron-sl28-u-boot.dtsi128
-rw-r--r--board/kontron/sl28/sl28.c59
-rw-r--r--configs/kontron_sl28_defconfig13
-rw-r--r--doc/board/kontron/sl28.rst66
-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/watchdog/Kconfig7
-rw-r--r--drivers/watchdog/Makefile1
-rw-r--r--drivers/watchdog/sl28cpld-wdt.c109
-rw-r--r--include/configs/lx2160a_common.h34
-rw-r--r--include/sl28cpld.h16
-rw-r--r--tools/pblimage.c10
-rw-r--r--tools/pblimage.h3
19 files changed, 577 insertions, 164 deletions
diff --git a/MAINTAINERS b/MAINTAINERS
index fb171e0c68..0f39bc6bc9 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -1161,6 +1161,13 @@ S: Maintained
T: git https://source.denx.de/u-boot/custodians/u-boot-sh.git
F: arch/sh/
+SL28CLPD
+M: Michael Walle <michael@walle.cc>
+S: Maintained
+F: drivers/gpio/sl28cpld-gpio.c
+F: drivers/misc/sl28cpld.c
+F: drivers/watchdog/sl28cpld-wdt.c
+
SPI
M: Jagan Teki <jagan@amarulasolutions.com>
S: Maintained
diff --git a/Makefile b/Makefile
index e6fc80aa6f..f8f3f24641 100644
--- a/Makefile
+++ b/Makefile
@@ -1411,7 +1411,7 @@ MKIMAGEFLAGS_u-boot-spl.kwb = -n $(KWD_CONFIG_FILE) \
$(if $(KEYDIR),-k $(KEYDIR))
MKIMAGEFLAGS_u-boot.pbl = -n $(srctree)/$(CONFIG_SYS_FSL_PBL_RCW:"%"=%) \
- -R $(srctree)/$(CONFIG_SYS_FSL_PBL_PBI:"%"=%) -T pblimage
+ -R $(srctree)/$(CONFIG_SYS_FSL_PBL_PBI:"%"=%) -A $(ARCH) -T pblimage
ifeq ($(CONFIG_MPC85xx)$(CONFIG_OF_SEPARATE),yy)
UBOOT_BIN := u-boot-with-dtb.bin
diff --git a/arch/arm/dts/fsl-ls1028a-kontron-sl28-u-boot.dtsi b/arch/arm/dts/fsl-ls1028a-kontron-sl28-u-boot.dtsi
index d4b833284e..2dcb3c2a58 100644
--- a/arch/arm/dts/fsl-ls1028a-kontron-sl28-u-boot.dtsi
+++ b/arch/arm/dts/fsl-ls1028a-kontron-sl28-u-boot.dtsi
@@ -27,6 +27,7 @@
fit {
offset = <CONFIG_SPL_PAD_TO>;
description = "FIT image with multiple configurations";
+ fit,fdt-list = "of-list";
images {
uboot {
@@ -41,95 +42,20 @@
};
};
- fdt-1 {
- description = "fsl-ls1028a-kontron-sl28";
+ @fdt-SEQ {
+ description = "NAME";
type = "flat_dt";
- arch = "arm";
- compression = "none";
-
- blob {
- filename = "arch/arm/dts/fsl-ls1028a-kontron-sl28.dtb";
- };
- };
-
- fdt-2 {
- description = "fsl-ls1028a-kontron-sl28-var1";
- type = "flat_dt";
- arch = "arm";
- compression = "none";
-
- blob {
- filename = "arch/arm/dts/fsl-ls1028a-kontron-sl28-var1.dtb";
- };
- };
-
- fdt-3 {
- description = "fsl-ls1028a-kontron-sl28-var2";
- type = "flat_dt";
- arch = "arm";
- compression = "none";
-
- blob {
- filename = "arch/arm/dts/fsl-ls1028a-kontron-sl28-var2.dtb";
- };
- };
-
- fdt-4 {
- description = "fsl-ls1028a-kontron-sl28-var3";
- type = "flat_dt";
- arch = "arm";
compression = "none";
-
- blob {
- filename = "arch/arm/dts/fsl-ls1028a-kontron-sl28-var3.dtb";
- };
- };
-
- fdt-5 {
- description = "fsl-ls1028a-kontron-sl28-var4";
- type = "flat_dt";
- arch = "arm";
- compression = "none";
-
- blob {
- filename = "arch/arm/dts/fsl-ls1028a-kontron-sl28-var4.dtb";
- };
};
};
configurations {
- default = "conf-1";
-
- conf-1 {
- description = "fsl-ls1028a-kontron-sl28";
- firmware = "uboot";
- fdt = "fdt-1";
- };
-
- conf-2 {
- description = "fsl-ls1028a-kontron-sl28-var1";
- firmware = "uboot";
- fdt = "fdt-2";
- };
-
- conf-3 {
- description = "fsl-ls1028a-kontron-sl28-var2";
- firmware = "uboot";
- fdt = "fdt-3";
- };
-
- conf-4 {
- description = "fsl-ls1028a-kontron-sl28-var3";
- firmware = "uboot";
- loadables = "uboot";
- fdt = "fdt-4";
- };
+ default = "@config-DEFAULT-SEQ";
- conf-5 {
- description = "fsl-ls1028a-kontron-sl28-var4";
+ @config-SEQ {
+ description = "NAME";
firmware = "uboot";
- loadables = "uboot";
- fdt = "fdt-5";
+ fdt = "fdt-SEQ";
};
};
};
@@ -189,27 +115,7 @@
};
configurations {
- conf-1 {
- firmware = "bl31";
- loadables = "uboot";
- };
-
- conf-2 {
- firmware = "bl31";
- loadables = "uboot";
- };
-
- conf-3 {
- firmware = "bl31";
- loadables = "uboot";
- };
-
- conf-4 {
- firmware = "bl31";
- loadables = "uboot";
- };
-
- conf-5 {
+ @config-SEQ {
firmware = "bl31";
loadables = "uboot";
};
@@ -238,23 +144,7 @@
};
configurations {
- conf-1 {
- loadables = "uboot", "bl32";
- };
-
- conf-2 {
- loadables = "uboot", "bl32";
- };
-
- conf-3 {
- loadables = "uboot", "bl32";
- };
-
- conf-4 {
- loadables = "uboot", "bl32";
- };
-
- conf-5 {
+ @config-SEQ {
loadables = "uboot", "bl32";
};
};
diff --git a/board/kontron/sl28/sl28.c b/board/kontron/sl28/sl28.c
index e84b356918..3c48a9141d 100644
--- a/board/kontron/sl28/sl28.c
+++ b/board/kontron/sl28/sl28.c
@@ -1,6 +1,7 @@
// SPDX-License-Identifier: GPL-2.0+
#include <common.h>
+#include <dm.h>
#include <malloc.h>
#include <errno.h>
#include <fsl_ddr.h>
@@ -14,7 +15,9 @@
#include <asm/arch/soc.h>
#include <fsl_immap.h>
#include <netdev.h>
+#include <wdt.h>
+#include <sl28cpld.h>
#include <fdtdec.h>
#include <miiphy.h>
@@ -39,16 +42,68 @@ int board_eth_init(struct bd_info *bis)
return pci_eth_init(bis);
}
+static int __sl28cpld_read(uint reg)
+{
+ struct udevice *dev;
+ int ret;
+
+ ret = uclass_get_device_by_driver(UCLASS_NOP,
+ DM_DRIVER_GET(sl28cpld), &dev);
+ if (ret)
+ return ret;
+
+ return sl28cpld_read(dev, reg);
+}
+
+static void print_cpld_version(void)
+{
+ int version = __sl28cpld_read(SL28CPLD_VERSION);
+
+ if (version < 0)
+ printf("CPLD: error reading version (%d)\n", version);
+ else
+ printf("CPLD: v%d\n", version);
+}
+
int checkboard(void)
{
printf("EL: %d\n", current_el());
+ if (CONFIG_IS_ENABLED(SL28CPLD))
+ print_cpld_version();
+
+ return 0;
+}
+
+static void stop_recovery_watchdog(void)
+{
+ struct udevice *dev;
+ int ret;
+
+ ret = uclass_get_device_by_driver(UCLASS_WDT,
+ DM_DRIVER_GET(sl28cpld_wdt), &dev);
+ if (!ret)
+ wdt_stop(dev);
+}
+
+int fsl_board_late_init(void)
+{
+ /*
+ * Usually, the after a board reset, the watchdog is enabled by
+ * default. This is to supervise the bootloader boot-up. Therefore,
+ * to prevent a watchdog reset if we don't actively kick it, we have
+ * to disable it.
+ *
+ * If the watchdog isn't enabled at reset (which is a configuration
+ * option) disabling it doesn't hurt either.
+ */
+ if (!CONFIG_IS_ENABLED(WATCHDOG_AUTOSTART))
+ stop_recovery_watchdog();
+
return 0;
}
void detail_board_ddr_info(void)
{
- puts("\nDDR ");
- print_size(gd->bd->bi_dram[0].size + gd->bd->bi_dram[1].size, "");
print_ddr_info(0);
}
diff --git a/configs/kontron_sl28_defconfig b/configs/kontron_sl28_defconfig
index b61276cf1d..cf8aedfdfd 100644
--- a/configs/kontron_sl28_defconfig
+++ b/configs/kontron_sl28_defconfig
@@ -42,23 +42,23 @@ CONFIG_CMD_GREPENV=y
CONFIG_CMD_NVEDIT_EFI=y
CONFIG_CMD_DFU=y
CONFIG_CMD_DM=y
+CONFIG_CMD_GPIO=y
CONFIG_CMD_GPT=y
CONFIG_CMD_I2C=y
CONFIG_CMD_MMC=y
CONFIG_CMD_PCI=y
CONFIG_CMD_USB=y
CONFIG_CMD_USB_MASS_STORAGE=y
+CONFIG_CMD_WDT=y
CONFIG_CMD_CACHE=y
CONFIG_CMD_EFIDEBUG=y
CONFIG_CMD_RNG=y
CONFIG_OF_CONTROL=y
CONFIG_SPL_OF_CONTROL=y
-CONFIG_OF_LIST=""
+CONFIG_OF_LIST="fsl-ls1028a-kontron-sl28 fsl-ls1028a-kontron-sl28-var1 fsl-ls1028a-kontron-sl28-var2 fsl-ls1028a-kontron-sl28-var3 fsl-ls1028a-kontron-sl28-var4"
CONFIG_ENV_OVERWRITE=y
CONFIG_ENV_IS_IN_SPI_FLASH=y
CONFIG_SYS_REDUNDAND_ENVIRONMENT=y
-CONFIG_NET_RANDOM_ETHADDR=y
-CONFIG_NETCONSOLE=y
CONFIG_SPL_DM_SEQ_ALIAS=y
CONFIG_SATA=y
CONFIG_SCSI_AHCI=y
@@ -69,8 +69,10 @@ CONFIG_DDR_ECC=y
CONFIG_ECC_INIT_VIA_DDRCONTROLLER=y
CONFIG_DFU_MMC=y
CONFIG_DFU_SF=y
+CONFIG_SL28CPLD_GPIO=y
CONFIG_I2C_SET_DEFAULT_BUS_NUM=y
CONFIG_I2C_MUX=y
+CONFIG_SL28CPLD=y
CONFIG_MMC_HS400_SUPPORT=y
CONFIG_FSL_ESDHC=y
CONFIG_FSL_ESDHC_SUPPORT_ADMA2=y
@@ -102,6 +104,11 @@ CONFIG_USB_DWC3=y
CONFIG_USB_DWC3_LAYERSCAPE=y
CONFIG_USB_GADGET=y
CONFIG_USB_GADGET_DOWNLOAD=y
+# CONFIG_WATCHDOG is not set
+# CONFIG_WATCHDOG_AUTOSTART is not set
+CONFIG_WDT=y
+CONFIG_WDT_SL28CPLD=y
+CONFIG_WDT_SP805=y
CONFIG_OF_LIBFDT_ASSUME_MASK=0x0
CONFIG_OF_LIBFDT_OVERLAY=y
CONFIG_EFI_SET_TIME=y
diff --git a/doc/board/kontron/sl28.rst b/doc/board/kontron/sl28.rst
index c7b18bed10..44435d90c6 100644
--- a/doc/board/kontron/sl28.rst
+++ b/doc/board/kontron/sl28.rst
@@ -23,34 +23,17 @@ Copy u-boot.rom to a TFTP server.
Install the bootloader on the board
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-Please note, this bootloader doesn't support the builtin watchdog (yet),
-therefore you have to disable it, see below. Otherwise you'll end up in
-the failsafe bootloader on every reset::
+To install the bootloader binary use the following command::
> tftp path/to/u-boot.rom
> sf probe 0
> sf update $fileaddr 0x210000 $filesize
-The board is fully failsafe, you can't break anything. But because you've
-disabled the builtin watchdog you might have to manually enter failsafe
-mode by asserting the ``FORCE_RECOV#`` line during board reset.
-
-Disable the builtin watchdog
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-- boot into the failsafe bootloader, either by asserting the
- ``FORCE_RECOV#`` line or if you still have the original bootloader
- installed you can use the command::
-
- > wdt dev cpld_watchdog@4a; wdt expire 1
-
-- in the failsafe bootloader use the "sl28 nvm" command to disable
- the automatic start of the builtin watchdog::
-
- > sl28 nvm 0008
-
-- power-cycle the board
-
+The board is fully failsafe, you can't break anything. If builtin watchdog
+is enabled, you'll automatically end up in the failsafe bootloader if
+something goes wrong. If the watchdog is disabled, you have to manually
+enter failsafe mode by asserting the ``FORCE_RECOV#`` line during board
+reset.
Update image
------------
@@ -67,20 +50,41 @@ Afterward you can copy this file to your ESP into the /EFI/UpdateCapsule/
folder. On the next EFI boot this will automatically update your
bootloader.
-Useful I2C tricks
------------------
+Builtin watchdog
+----------------
+
+The builtin watchdog will supervise the bootloader startup. If anything
+goes wrong it will reset the board and boot into the failsafe bootloader.
+
+Once the bootloader is started successfully, it will disable the watchdog
+timer.
-The board has a board management controller which is not supported in
-u-boot (yet). But you can use the i2c command to access it.
+wdt command flags
+^^^^^^^^^^^^^^^^^
-- reset into failsafe bootloader::
+The `wdt start` as well as the `wdt expire` command take a flags argument.
+The supported bitmask is as follows.
- > i2c mw 4a 5.1 0; i2c mw 4a 6.1 6b; i2c mw 4a 4.1 42
+| Bit | Description |
+| --- | ----------------------------- |
+| 0 | Enable failsafe mode |
+| 1 | Lock the control register |
+| 2 | Disable board reset |
+| 3 | Enable WDT_TIME_OUT# line |
-- read board management controller version::
+For example, you can use `wdt expire 1` to issue a reset and boot into the
+failsafe bootloader.
+
+Disable the builtin watchdog
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^
- > i2c md 4a 3.1 1
+If for some reason, this isn't a desired behavior, the watchdog can also
+be configured to not be enabled on board reset. It's configuration is saved
+in the non-volatile board configuration bits. To change these you can use
+the `sl28 nvm` command.
+For more information on the non-volatile board configuration bits, see the
+following section.
Non-volatile Board Configuration Bits
-------------------------------------
diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig
index 8d0e47c67d..522dfc195e 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 63e9be6034..33f7d41b7d 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 0000000000..700fc3df29
--- /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 0ade3e32b0..7029bb7b5c 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 bca7b24e99..f22eff601a 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 0000000000..01ef1c6178
--- /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/watchdog/Kconfig b/drivers/watchdog/Kconfig
index cabac29053..f90f0ca02b 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 6d2b3822c0..a35bd559f5 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 0000000000..af5a6b1a28
--- /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,
+};
diff --git a/include/configs/lx2160a_common.h b/include/configs/lx2160a_common.h
index e31f8d087f..4f4b5713dc 100644
--- a/include/configs/lx2160a_common.h
+++ b/include/configs/lx2160a_common.h
@@ -244,12 +244,36 @@
"run distro_bootcmd;run sd2_bootcmd;" \
"env exists secureboot && esbc_halt;"
+#ifdef CONFIG_CMD_USB
+#define BOOT_TARGET_DEVICES_USB(func) func(USB, usb, 0)
+#else
+#define BOOT_TARGET_DEVICES_USB(func)
+#endif
+
+#ifdef CONFIG_MMC
+#define BOOT_TARGET_DEVICES_MMC(func, instance) func(MMC, mmc, instance)
+#else
+#define BOOT_TARGET_DEVICES_MMC(func)
+#endif
+
+#ifdef CONFIG_SCSI
+#define BOOT_TARGET_DEVICES_SCSI(func) func(SCSI, scsi, 0)
+#else
+#define BOOT_TARGET_DEVICES_SCSI(func)
+#endif
+
+#ifdef CONFIG_CMD_DHCP
+#define BOOT_TARGET_DEVICES_DHCP(func) func(DHCP, dhcp, na)
+#else
+#define BOOT_TARGET_DEVICES_DHCP(func)
+#endif
+
#define BOOT_TARGET_DEVICES(func) \
- func(USB, usb, 0) \
- func(MMC, mmc, 0) \
- func(MMC, mmc, 1) \
- func(SCSI, scsi, 0) \
- func(DHCP, dhcp, na)
+ BOOT_TARGET_DEVICES_USB(func) \
+ BOOT_TARGET_DEVICES_MMC(func, 0) \
+ BOOT_TARGET_DEVICES_MMC(func, 1) \
+ BOOT_TARGET_DEVICES_SCSI(func) \
+ BOOT_TARGET_DEVICES_DHCP(func)
#include <config_distro_bootcmd.h>
#endif /* __LX2_COMMON_H */
diff --git a/include/sl28cpld.h b/include/sl28cpld.h
new file mode 100644
index 0000000000..9a7c6de31f
--- /dev/null
+++ b/include/sl28cpld.h
@@ -0,0 +1,16 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Copyright (c) 2021 Michael Walle <michael@walle.cc>
+ */
+
+#ifndef __SL28CPLD_H
+#define __SL28CPLD_H
+
+#define SL28CPLD_VERSION 0x03
+
+int sl28cpld_read(struct udevice *dev, uint offset);
+int sl28cpld_write(struct udevice *dev, uint offset, uint8_t value);
+int sl28cpld_update(struct udevice *dev, uint offset, uint8_t clear,
+ uint8_t set);
+
+#endif
diff --git a/tools/pblimage.c b/tools/pblimage.c
index 3c823e96cf..bd639c276f 100644
--- a/tools/pblimage.c
+++ b/tools/pblimage.c
@@ -230,19 +230,25 @@ static int pblimage_verify_header(unsigned char *ptr, int image_size,
struct image_tool_params *params)
{
struct pbl_header *pbl_hdr = (struct pbl_header *) ptr;
+ uint32_t rcwheader;
+
+ if (params->arch == IH_ARCH_ARM)
+ rcwheader = RCW_ARM_HEADER;
+ else
+ rcwheader = RCW_PPC_HEADER;
/* Only a few checks can be done: search for magic numbers */
if (ENDIANNESS == 'l') {
if (pbl_hdr->preamble != reverse_byte(RCW_PREAMBLE))
return -FDT_ERR_BADSTRUCTURE;
- if (pbl_hdr->rcwheader != reverse_byte(RCW_HEADER))
+ if (pbl_hdr->rcwheader != reverse_byte(rcwheader))
return -FDT_ERR_BADSTRUCTURE;
} else {
if (pbl_hdr->preamble != RCW_PREAMBLE)
return -FDT_ERR_BADSTRUCTURE;
- if (pbl_hdr->rcwheader != RCW_HEADER)
+ if (pbl_hdr->rcwheader != rcwheader)
return -FDT_ERR_BADSTRUCTURE;
}
return 0;
diff --git a/tools/pblimage.h b/tools/pblimage.h
index 81c5492926..0222e8067b 100644
--- a/tools/pblimage.h
+++ b/tools/pblimage.h
@@ -8,7 +8,8 @@
#define RCW_BYTES 64
#define RCW_PREAMBLE 0xaa55aa55
-#define RCW_HEADER 0x010e0100
+#define RCW_ARM_HEADER 0x01ee0100
+#define RCW_PPC_HEADER 0x010e0100
struct pbl_header {
uint32_t preamble;