summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSascha Hauer <s.hauer@pengutronix.de>2019-07-12 07:10:19 +0200
committerSascha Hauer <s.hauer@pengutronix.de>2019-07-12 07:10:19 +0200
commitf9dfe479ebacbb3efacef4525682546713b11597 (patch)
tree64b26ae51c86b9b1419d8a62baf5d2f5948f3f51
parentac5e1f63aafb73a6ea2356822029ef391b6234d2 (diff)
parent9f30aa3f143eda22ba3cf9e36c05213239a2fe83 (diff)
downloadbarebox-f9dfe479ebacbb3efacef4525682546713b11597.tar.gz
barebox-f9dfe479ebacbb3efacef4525682546713b11597.tar.xz
Merge branch 'for-next/stm32'
-rw-r--r--Documentation/user/reset-reason.rst4
-rw-r--r--arch/arm/Kconfig5
-rw-r--r--arch/arm/Makefile2
-rw-r--r--arch/arm/boards/stm32mp157c-dk2/lowlevel.c4
-rw-r--r--arch/arm/configs/stm32mp_defconfig (renamed from arch/arm/configs/stm32mp1_defconfig)16
-rw-r--r--arch/arm/cpu/psci.c6
-rw-r--r--arch/arm/cpu/sm.c29
-rw-r--r--arch/arm/dts/stm32mp157a-dk1.dts58
-rw-r--r--arch/arm/dts/stm32mp157a-dk1.dtsi36
-rw-r--r--arch/arm/dts/stm32mp157c-dk2.dts10
-rw-r--r--arch/arm/dts/stm32mp157c.dtsi15
-rw-r--r--arch/arm/include/asm/gic.h29
-rw-r--r--arch/arm/mach-stm32mp/Kconfig (renamed from arch/arm/mach-stm32mp1/Kconfig)3
-rw-r--r--arch/arm/mach-stm32mp/Makefile (renamed from arch/arm/mach-stm32mp1/Makefile)0
-rw-r--r--arch/arm/mach-stm32mp/include/mach/debug_ll.h (renamed from arch/arm/mach-stm32mp1/include/mach/debug_ll.h)0
-rw-r--r--arch/arm/mach-stm32mp/include/mach/stm32.h (renamed from arch/arm/mach-stm32mp1/include/mach/stm32.h)0
-rw-r--r--common/reset_source.c1
-rw-r--r--drivers/gpio/gpiolib.c7
-rw-r--r--drivers/pinctrl/Kconfig6
-rw-r--r--drivers/pinctrl/Makefile1
-rw-r--r--drivers/pinctrl/pinctrl-stm32.c429
-rw-r--r--drivers/watchdog/Kconfig8
-rw-r--r--drivers/watchdog/Makefile1
-rw-r--r--drivers/watchdog/stm32_iwdg.c293
-rw-r--r--images/Makefile2
-rw-r--r--images/Makefile.stm32mp (renamed from images/Makefile.stm32mp1)2
-rw-r--r--include/gpio.h1
-rw-r--r--include/hwspinlock.h31
-rw-r--r--include/reset_source.h1
-rw-r--r--include/soc/stm32/gpio.h120
30 files changed, 1013 insertions, 107 deletions
diff --git a/Documentation/user/reset-reason.rst b/Documentation/user/reset-reason.rst
index 26d37f86dd..e46f2ca684 100644
--- a/Documentation/user/reset-reason.rst
+++ b/Documentation/user/reset-reason.rst
@@ -41,6 +41,10 @@ The following values can help to detect the reason why the bootloader runs:
* ``EXT`` (EXTernal): some SoCs have special device pins for external reset
signals other than the ``RST`` one. Application specific how to handle this
state.
+* ``BROWNOUT``: some SoCs detect undervoltage conditions and stay in reset
+ till the supply voltage crosses a predefined threshold voltage. This avoids
+ erratic behavior that may occur when running out-of-spec. Application specific
+ how to handle this state.
It depends on your board/SoC and its features if the hardware is able to detect
these reset reasons. Most of the time only ``POR`` and ``RST`` are supported
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index 480c6f0117..0f5190b417 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -207,7 +207,7 @@ config ARCH_S3C64xx
select CPU_V6
select GENERIC_GPIO
-config ARCH_STM32MP1
+config ARCH_STM32MP
bool "ST stm32mp1xx"
select CPU_V7
select HAVE_PBL_MULTI_IMAGES
@@ -216,6 +216,7 @@ config ARCH_STM32MP1
select COMMON_CLK_OF_PROVIDER
select HAS_DEBUG_LL
select HAVE_CLK
+ select GPIOLIB
config ARCH_VERSATILE
bool "ARM Versatile boards (ARM926EJ-S)"
@@ -304,7 +305,7 @@ source "arch/arm/mach-pxa/Kconfig"
source "arch/arm/mach-rockchip/Kconfig"
source "arch/arm/mach-samsung/Kconfig"
source "arch/arm/mach-socfpga/Kconfig"
-source "arch/arm/mach-stm32mp1/Kconfig"
+source "arch/arm/mach-stm32mp/Kconfig"
source "arch/arm/mach-versatile/Kconfig"
source "arch/arm/mach-vexpress/Kconfig"
source "arch/arm/mach-tegra/Kconfig"
diff --git a/arch/arm/Makefile b/arch/arm/Makefile
index 4d54f339f1..5cb46f6613 100644
--- a/arch/arm/Makefile
+++ b/arch/arm/Makefile
@@ -98,7 +98,7 @@ machine-$(CONFIG_ARCH_PXA) := pxa
machine-$(CONFIG_ARCH_ROCKCHIP) := rockchip
machine-$(CONFIG_ARCH_SAMSUNG) := samsung
machine-$(CONFIG_ARCH_SOCFPGA) := socfpga
-machine-$(CONFIG_ARCH_STM32MP1) := stm32mp1
+machine-$(CONFIG_ARCH_STM32MP) := stm32mp
machine-$(CONFIG_ARCH_VERSATILE) := versatile
machine-$(CONFIG_ARCH_VEXPRESS) := vexpress
machine-$(CONFIG_ARCH_TEGRA) := tegra
diff --git a/arch/arm/boards/stm32mp157c-dk2/lowlevel.c b/arch/arm/boards/stm32mp157c-dk2/lowlevel.c
index b8e5959bef..566ace79c9 100644
--- a/arch/arm/boards/stm32mp157c-dk2/lowlevel.c
+++ b/arch/arm/boards/stm32mp157c-dk2/lowlevel.c
@@ -5,7 +5,7 @@
#include <mach/stm32.h>
#include <debug_ll.h>
-extern char __dtb_stm32mp157c_dk2_start[];
+extern char __dtb_z_stm32mp157c_dk2_start[];
ENTRY_FUNCTION(start_stm32mp157c_dk2, r0, r1, r2)
{
@@ -13,7 +13,7 @@ ENTRY_FUNCTION(start_stm32mp157c_dk2, r0, r1, r2)
arm_cpu_lowlevel_init();
- fdt = __dtb_stm32mp157c_dk2_start + get_runtime_offset();
+ fdt = __dtb_z_stm32mp157c_dk2_start + get_runtime_offset();
barebox_arm_entry(STM32_DDR_BASE, SZ_512M, fdt);
}
diff --git a/arch/arm/configs/stm32mp1_defconfig b/arch/arm/configs/stm32mp_defconfig
index 0afbbff7fd..9f30bb1caa 100644
--- a/arch/arm/configs/stm32mp1_defconfig
+++ b/arch/arm/configs/stm32mp_defconfig
@@ -1,4 +1,4 @@
-CONFIG_ARCH_STM32MP1=y
+CONFIG_ARCH_STM32MP=y
CONFIG_MACH_STM32MP157C_DK2=y
CONFIG_THUMB2_BAREBOX=y
CONFIG_ARM_BOARD_APPEND_ATAG=y
@@ -25,7 +25,6 @@ CONFIG_CONSOLE_ALLOW_COLOR=y
CONFIG_PBL_CONSOLE=y
CONFIG_PARTITION=y
CONFIG_DEFAULT_ENVIRONMENT_GENERIC_NEW=y
-CONFIG_POLLER=y
CONFIG_RESET_SOURCE=y
CONFIG_DEBUG_INITCALLS=y
CONFIG_CMD_DMESG=y
@@ -71,6 +70,9 @@ CONFIG_CMD_MM=y
CONFIG_CMD_CLK=y
CONFIG_CMD_DETECT=y
CONFIG_CMD_FLASH=y
+CONFIG_CMD_GPIO=y
+CONFIG_CMD_LED=y
+CONFIG_CMD_WD=y
CONFIG_CMD_BAREBOX_UPDATE=y
CONFIG_CMD_OF_NODE=y
CONFIG_CMD_OF_PROPERTY=y
@@ -85,7 +87,14 @@ CONFIG_DRIVER_NET_DESIGNWARE_GENERIC=y
CONFIG_AT803X_PHY=y
CONFIG_MICREL_PHY=y
# CONFIG_SPI is not set
-# CONFIG_PINCTRL is not set
+CONFIG_LED=y
+CONFIG_LED_GPIO=y
+CONFIG_LED_GPIO_OF=y
+CONFIG_WATCHDOG=y
+CONFIG_WATCHDOG_POLLER=y
+CONFIG_STM32_IWDG_WATCHDOG=y
+CONFIG_REGULATOR=y
+CONFIG_REGULATOR_FIXED=y
CONFIG_FS_EXT4=y
CONFIG_FS_TFTP=y
CONFIG_FS_NFS=y
@@ -93,5 +102,4 @@ CONFIG_FS_FAT=y
CONFIG_FS_FAT_WRITE=y
CONFIG_FS_FAT_LFN=y
CONFIG_ZLIB=y
-CONFIG_LZO_DECOMPRESS=y
CONFIG_CRC8=y
diff --git a/arch/arm/cpu/psci.c b/arch/arm/cpu/psci.c
index 5c662cd0b9..a976ddbb5c 100644
--- a/arch/arm/cpu/psci.c
+++ b/arch/arm/cpu/psci.c
@@ -138,8 +138,8 @@ static unsigned long psci_system_off(void)
{
psci_printf("%s\n", __func__);
- if (psci_ops->system_reset)
- psci_ops->system_reset();
+ if (psci_ops->system_off)
+ psci_ops->system_off();
while(1);
@@ -293,4 +293,4 @@ BAREBOX_CMD_START(smc)
BAREBOX_CMD_DESC("secure monitor test command")
BAREBOX_CMD_GROUP(CMD_GRP_MISC)
BAREBOX_CMD_END
-#endif \ No newline at end of file
+#endif
diff --git a/arch/arm/cpu/sm.c b/arch/arm/cpu/sm.c
index d9d62fbd9d..b7a9eae89b 100644
--- a/arch/arm/cpu/sm.c
+++ b/arch/arm/cpu/sm.c
@@ -22,9 +22,6 @@
#include "mmu.h"
-/* valid bits in CBAR register / PERIPHBASE value */
-#define CBAR_MASK 0xFFFF8000
-
static unsigned int read_id_pfr1(void)
{
unsigned int reg;
@@ -51,30 +48,6 @@ static void write_mvbar(u32 val)
asm("mcr p15, 0, %0, c12, c0, 1" : : "r"(val));
}
-static unsigned long get_cbar(void)
-{
- unsigned periphbase;
-
- /* get the GIC base address from the CBAR register */
- asm("mrc p15, 4, %0, c15, c0, 0\n" : "=r" (periphbase));
-
- /* the PERIPHBASE can be mapped above 4 GB (lower 8 bits used to
- * encode this). Bail out here since we cannot access this without
- * enabling paging.
- */
- if ((periphbase & 0xff) != 0) {
- pr_err("PERIPHBASE is above 4 GB, no access.\n");
- return -1;
- }
-
- return periphbase & CBAR_MASK;
-}
-
-static unsigned long get_gicd_base_address(void)
-{
- return get_cbar() + GIC_DIST_OFFSET;
-}
-
static int cpu_is_virt_capable(void)
{
return read_id_pfr1() & (1 << 12);
@@ -267,4 +240,4 @@ static int sm_init(void)
return 0;
}
-device_initcall(sm_init); \ No newline at end of file
+device_initcall(sm_init);
diff --git a/arch/arm/dts/stm32mp157a-dk1.dts b/arch/arm/dts/stm32mp157a-dk1.dts
index 741284a444..f2cafae66b 100644
--- a/arch/arm/dts/stm32mp157a-dk1.dts
+++ b/arch/arm/dts/stm32mp157a-dk1.dts
@@ -4,59 +4,5 @@
* Author: Alexandre Torgue <alexandre.torgue@st.com>.
*/
-/dts-v1/;
-
-#include "stm32mp157c.dtsi"
-#include <arm/stm32mp157c.dtsi>
-#include <arm/stm32mp157-pinctrl.dtsi>
-
-/ {
- model = "STMicroelectronics STM32MP157A-DK1 Discovery Board";
- compatible = "st,stm32mp157a-dk1", "st,stm32mp157";
-
- aliases {
- ethernet0 = &ethernet0;
- serial0 = &uart4;
- };
-
- chosen {
- stdout-path = "serial0:115200n8";
- };
-
- sram: sram@10050000 {
- compatible = "mmio-sram";
- reg = <0x10050000 0x10000>;
- #address-cells = <1>;
- #size-cells = <1>;
- ranges = <0 0x10050000 0x10000>;
-
- dma_pool: dma_pool@0 {
- reg = <0x0 0x10000>;
- pool;
- };
- };
-};
-
-&ethernet0 {
- status = "okay";
- pinctrl-0 = <&ethernet0_rgmii_pins_a>;
- pinctrl-names = "default", "sleep";
- phy-mode = "rgmii";
- max-speed = <1000>;
- phy-handle = <&phy0>;
-
- mdio0 {
- #address-cells = <1>;
- #size-cells = <0>;
- compatible = "snps,dwmac-mdio";
- phy0: ethernet-phy@0 {
- reg = <0>;
- };
- };
-};
-
-&uart4 {
- pinctrl-names = "default";
- pinctrl-0 = <&uart4_pins_a>;
- status = "okay";
-};
+#include <arm/stm32mp157a-dk1.dts>
+#include "stm32mp157a-dk1.dtsi"
diff --git a/arch/arm/dts/stm32mp157a-dk1.dtsi b/arch/arm/dts/stm32mp157a-dk1.dtsi
new file mode 100644
index 0000000000..cd3d614d46
--- /dev/null
+++ b/arch/arm/dts/stm32mp157a-dk1.dtsi
@@ -0,0 +1,36 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause)
+/*
+ * Copyright (C) STMicroelectronics 2018 - All Rights Reserved
+ * Author: Alexandre Torgue <alexandre.torgue@st.com>.
+ */
+
+#include "stm32mp157c.dtsi"
+#include <dt-bindings/gpio/gpio.h>
+
+/ {
+ led {
+ red {
+ label = "error";
+ gpios = <&gpioa 13 GPIO_ACTIVE_LOW>;
+ default-state = "off";
+ status = "okay";
+ };
+
+ blue {
+ default-state = "on";
+ };
+ };
+
+ sram: sram@10050000 {
+ compatible = "mmio-sram";
+ reg = <0x10050000 0x10000>;
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges = <0 0x10050000 0x10000>;
+
+ dma_pool: dma_pool@0 {
+ reg = <0x0 0x10000>;
+ pool;
+ };
+ };
+};
diff --git a/arch/arm/dts/stm32mp157c-dk2.dts b/arch/arm/dts/stm32mp157c-dk2.dts
index 7565cabc3d..6e73162ea4 100644
--- a/arch/arm/dts/stm32mp157c-dk2.dts
+++ b/arch/arm/dts/stm32mp157c-dk2.dts
@@ -4,11 +4,5 @@
* Author: Alexandre Torgue <alexandre.torgue@st.com>.
*/
-/dts-v1/;
-
-#include "stm32mp157a-dk1.dts"
-
-/ {
- model = "STMicroelectronics STM32MP157C-DK2 Discovery Board";
- compatible = "st,stm32mp157c-dk2", "st,stm32mp157";
-};
+#include <arm/stm32mp157c-dk2.dts>
+#include "stm32mp157a-dk1.dtsi"
diff --git a/arch/arm/dts/stm32mp157c.dtsi b/arch/arm/dts/stm32mp157c.dtsi
index fa0d00ff02..b97622c8d4 100644
--- a/arch/arm/dts/stm32mp157c.dtsi
+++ b/arch/arm/dts/stm32mp157c.dtsi
@@ -4,4 +4,19 @@
/* Needed to let barebox find the clock nodes */
compatible = "simple-bus";
};
+
+ aliases {
+ gpio0 = &gpioa;
+ gpio1 = &gpiob;
+ gpio2 = &gpioc;
+ gpio3 = &gpiod;
+ gpio4 = &gpioe;
+ gpio5 = &gpiof;
+ gpio6 = &gpiog;
+ gpio7 = &gpioh;
+ gpio8 = &gpioi;
+ gpio9 = &gpioj;
+ gpio10 = &gpiok;
+ gpio11 = &gpioz;
+ };
};
diff --git a/arch/arm/include/asm/gic.h b/arch/arm/include/asm/gic.h
index bd3a80cdf7..f83f528141 100644
--- a/arch/arm/include/asm/gic.h
+++ b/arch/arm/include/asm/gic.h
@@ -107,4 +107,33 @@
#define ICC_SGI1R_EL1 S3_0_C12_C11_5
#define ICC_ASGI1R_EL1 S3_0_C12_C11_6
+#ifndef __ASSEMBLY__
+/* valid bits in CBAR register / PERIPHBASE value */
+#define CBAR_MASK 0xFFFF8000
+
+static inline unsigned long get_cbar(void)
+{
+ unsigned periphbase;
+
+ /* get the GIC base address from the CBAR register */
+ asm("mrc p15, 4, %0, c15, c0, 0\n" : "=r" (periphbase));
+
+ /* the PERIPHBASE can be mapped above 4 GB (lower 8 bits used to
+ * encode this). Bail out here since we cannot access this without
+ * enabling paging.
+ */
+ if ((periphbase & 0xff) != 0) {
+ pr_err("PERIPHBASE is above 4 GB, no access.\n");
+ return -1;
+ }
+
+ return periphbase & CBAR_MASK;
+}
+
+static inline unsigned long get_gicd_base_address(void)
+{
+ return get_cbar() + GIC_DIST_OFFSET;
+}
+#endif
+
#endif /* __GIC_H__ */
diff --git a/arch/arm/mach-stm32mp1/Kconfig b/arch/arm/mach-stm32mp/Kconfig
index cc7cf23cfb..be16294f5a 100644
--- a/arch/arm/mach-stm32mp1/Kconfig
+++ b/arch/arm/mach-stm32mp/Kconfig
@@ -1,10 +1,11 @@
-if ARCH_STM32MP1
+if ARCH_STM32MP
config ARCH_STM32MP1157
bool
config MACH_STM32MP157C_DK2
select ARCH_STM32MP1157
+ select ARM_USE_COMPRESSED_DTB
bool "STM32MP157C-DK2 board"
endif
diff --git a/arch/arm/mach-stm32mp1/Makefile b/arch/arm/mach-stm32mp/Makefile
index 16a218658a..16a218658a 100644
--- a/arch/arm/mach-stm32mp1/Makefile
+++ b/arch/arm/mach-stm32mp/Makefile
diff --git a/arch/arm/mach-stm32mp1/include/mach/debug_ll.h b/arch/arm/mach-stm32mp/include/mach/debug_ll.h
index 99fedb91fe..99fedb91fe 100644
--- a/arch/arm/mach-stm32mp1/include/mach/debug_ll.h
+++ b/arch/arm/mach-stm32mp/include/mach/debug_ll.h
diff --git a/arch/arm/mach-stm32mp1/include/mach/stm32.h b/arch/arm/mach-stm32mp/include/mach/stm32.h
index f9bdb788b9..f9bdb788b9 100644
--- a/arch/arm/mach-stm32mp1/include/mach/stm32.h
+++ b/arch/arm/mach-stm32mp/include/mach/stm32.h
diff --git a/common/reset_source.c b/common/reset_source.c
index 338d7b9acb..1955d3f87e 100644
--- a/common/reset_source.c
+++ b/common/reset_source.c
@@ -28,6 +28,7 @@ static const char * const reset_src_names[] = {
[RESET_JTAG] = "JTAG",
[RESET_THERM] = "THERM",
[RESET_EXT] = "EXT",
+ [RESET_BROWNOUT] = "BROWNOUT",
};
static enum reset_src_type reset_source;
diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c
index 4c7aee4a0b..f96009896a 100644
--- a/drivers/gpio/gpiolib.c
+++ b/drivers/gpio/gpiolib.c
@@ -475,6 +475,13 @@ int gpio_get_num(struct device_d *dev, int gpio)
return -EPROBE_DEFER;
}
+struct gpio_chip *gpio_get_chip(int gpio)
+{
+ struct gpio_info *gi = gpio_to_desc(gpio);
+
+ return gi ? gi->chip : NULL;
+}
+
#ifdef CONFIG_CMD_GPIO
static int do_gpiolib(int argc, char *argv[])
{
diff --git a/drivers/pinctrl/Kconfig b/drivers/pinctrl/Kconfig
index 46badeee06..e2fb0af756 100644
--- a/drivers/pinctrl/Kconfig
+++ b/drivers/pinctrl/Kconfig
@@ -90,6 +90,12 @@ config PINCTRL_VF610
default y if ARCH_VF610
help
Pinmux controller found on Vybrid VF610 family of SoCs
+
+config PINCTRL_STM32
+ bool
+ default y if ARCH_STM32MP
+ help
+ Pinmux and GPIO controller found on STM32 family
endif
endmenu
diff --git a/drivers/pinctrl/Makefile b/drivers/pinctrl/Makefile
index 35b2d4707c..9cb5e99477 100644
--- a/drivers/pinctrl/Makefile
+++ b/drivers/pinctrl/Makefile
@@ -11,5 +11,6 @@ obj-$(CONFIG_PINCTRL_TEGRA20) += pinctrl-tegra20.o
obj-$(CONFIG_PINCTRL_TEGRA30) += pinctrl-tegra30.o
obj-$(CONFIG_PINCTRL_TEGRA_XUSB) += pinctrl-tegra-xusb.o
obj-$(CONFIG_PINCTRL_VF610) += pinctrl-vf610.o
+obj-$(CONFIG_PINCTRL_STM32) += pinctrl-stm32.o
obj-$(CONFIG_ARCH_MVEBU) += mvebu/
diff --git a/drivers/pinctrl/pinctrl-stm32.c b/drivers/pinctrl/pinctrl-stm32.c
new file mode 100644
index 0000000000..7f04cea50b
--- /dev/null
+++ b/drivers/pinctrl/pinctrl-stm32.c
@@ -0,0 +1,429 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2015 Maxime Coquelin
+ * Copyright (C) 2017 STMicroelectronics
+ * Copyright (C) 2019 Ahmad Fatoum, Pengutronix
+ */
+
+#include <common.h>
+#include <init.h>
+#include <io.h>
+#include <of.h>
+#include <of_address.h>
+#include <pinctrl.h>
+#include <gpio.h>
+#include <hwspinlock.h>
+#include <malloc.h>
+#include <linux/clk.h>
+#include <soc/stm32/gpio.h>
+
+#define STM32_PIN_NO(x) ((x) << 8)
+#define STM32_GET_PIN_NO(x) ((x) >> 8)
+#define STM32_GET_PIN_FUNC(x) ((x) & 0xff)
+
+struct stm32_gpio_bank {
+ void __iomem *base;
+ struct gpio_chip chip;
+ struct clk *clk;
+ const char *name;
+};
+
+struct stm32_pinctrl {
+ struct pinctrl_device pdev;
+ struct hwspinlock hws;
+ struct stm32_gpio_bank gpio_banks[];
+};
+
+static inline struct stm32_pinctrl *to_stm32_pinctrl(struct pinctrl_device *pdev)
+{
+ return container_of(pdev, struct stm32_pinctrl, pdev);
+}
+
+static inline struct stm32_gpio_bank *to_stm32_gpio_bank(struct gpio_chip *chip)
+{
+ return container_of(chip, struct stm32_gpio_bank, chip);
+}
+
+static inline int stm32_gpio_pin(int gpio, struct stm32_gpio_bank **bank)
+{
+ if (bank) {
+ struct gpio_chip *chip;
+
+ chip = gpio_get_chip(gpio);
+ if (!chip)
+ return -EINVAL;
+
+ *bank = to_stm32_gpio_bank(chip);
+ }
+
+ return gpio % STM32_GPIO_PINS_PER_BANK;
+}
+
+static inline u32 stm32_gpio_get_mode(u32 function)
+{
+ switch (function) {
+ case STM32_PIN_GPIO:
+ return 0;
+ case STM32_PIN_AF(0) ... STM32_PIN_AF(15):
+ return 2;
+ case STM32_PIN_ANALOG:
+ return 3;
+ }
+
+ return 0;
+}
+
+static inline u32 stm32_gpio_get_alt(u32 function)
+{
+ switch (function) {
+ case STM32_PIN_GPIO:
+ return 0;
+ case STM32_PIN_AF(0) ... STM32_PIN_AF(15):
+ return function - 1;
+ case STM32_PIN_ANALOG:
+ return 0;
+ }
+
+ return 0;
+}
+
+static int stm32_pinctrl_set_state(struct pinctrl_device *pdev, struct device_node *group)
+{
+ struct stm32_pinctrl *pinctrl = to_stm32_pinctrl(pdev);
+ struct device_node *pins;
+ int ret;
+
+ ret = hwspinlock_lock_timeout(&pinctrl->hws, 10);
+ if (ret == -ETIMEDOUT) {
+ dev_err(pdev->dev, "hw spinlock timeout\n");
+ return ret;
+ }
+
+ for_each_child_of_node(group, pins) {
+ int num_pins = 0, i;
+ u32 slew_rate;
+ bool adjust_slew_rate = false;
+ enum stm32_pin_bias bias = -1;
+ enum stm32_pin_out_type out_type = -1;
+ enum { PIN_INPUT, PIN_OUTPUT_LOW, PIN_OUTPUT_HIGH } dir = -1;
+
+ of_get_property(pins, "pinmux", &num_pins);
+ num_pins /= sizeof(__be32);
+ if (!num_pins) {
+ dev_err(pdev->dev, "Invalid pinmux property in %s\n",
+ pins->full_name);
+ return -EINVAL;
+ }
+
+ ret = of_property_read_u32(pins, "slew-rate", &slew_rate);
+ if (!ret)
+ adjust_slew_rate = true;
+
+ if (of_get_property(pins, "bias-disable", NULL))
+ bias = STM32_PIN_NO_BIAS;
+ else if (of_get_property(pins, "bias-pull-up", NULL))
+ bias = STM32_PIN_PULL_UP;
+ else if (of_get_property(pins, "bias-pull-down", NULL))
+ bias = STM32_PIN_PULL_DOWN;
+
+ if (of_get_property(pins, "drive-push-pull", NULL))
+ out_type = STM32_PIN_OUT_PUSHPULL;
+ else if (of_get_property(pins, "drive-open-drain", NULL))
+ out_type = STM32_PIN_OUT_OPENDRAIN;
+
+ if (of_get_property(pins, "input-enable", NULL))
+ dir = PIN_INPUT;
+ else if (of_get_property(pins, "output-low", NULL))
+ dir = PIN_OUTPUT_LOW;
+ else if (of_get_property(pins, "output-high", NULL))
+ dir = PIN_OUTPUT_HIGH;
+
+ dev_dbg(pdev->dev, "%s: multiplexing %d pins\n",
+ pins->full_name, num_pins);
+
+ for (i = 0; i < num_pins; i++) {
+ struct stm32_gpio_bank *bank = NULL;
+ u32 pinfunc, mode, alt;
+ unsigned func;
+ int offset;
+
+ ret = of_property_read_u32_index(pins, "pinmux",
+ i, &pinfunc);
+ if (ret)
+ return ret;
+
+ func = STM32_GET_PIN_FUNC(pinfunc);
+ offset = stm32_gpio_pin(STM32_GET_PIN_NO(pinfunc), &bank);
+ if (offset < 0)
+ return -ENODEV;
+
+ dev_dbg(pdev->dev, "configuring port %s pin %u with:\n\t"
+ "fn %u, mode %u, alt %u\n",
+ bank->name, offset, func, mode, alt);
+
+ mode = stm32_gpio_get_mode(func);
+ alt = stm32_gpio_get_alt(func);
+
+ clk_enable(bank->clk);
+
+ __stm32_pmx_set_mode(bank->base, offset, mode, alt);
+
+ if (adjust_slew_rate)
+ __stm32_pmx_set_speed(bank->base, offset, slew_rate);
+
+ if (bias != -1)
+ __stm32_pmx_set_bias(bank->base, offset, bias);
+
+ if (out_type != -1)
+ __stm32_pmx_set_output_type(bank->base, offset, out_type);
+
+ if (dir == PIN_INPUT)
+ __stm32_pmx_gpio_input(bank->base, offset);
+ else if (dir == PIN_OUTPUT_LOW)
+ __stm32_pmx_gpio_output(bank->base, offset, 0);
+ else if (dir == PIN_OUTPUT_HIGH)
+ __stm32_pmx_gpio_output(bank->base, offset, 1);
+
+ clk_disable(bank->clk);
+ }
+ }
+
+ hwspinlock_unlock(&pinctrl->hws);
+
+ return 0;
+}
+
+/* GPIO functions */
+
+static int stm32_gpio_get_direction(struct gpio_chip *chip, unsigned int gpio)
+{
+ struct stm32_gpio_bank *bank = to_stm32_gpio_bank(chip);
+ int ret;
+ u32 mode, alt;
+
+ clk_enable(bank->clk);
+
+ __stm32_pmx_get_mode(bank->base, stm32_gpio_pin(gpio, NULL), &mode, &alt);
+ if ((alt == 0) && (mode == 0))
+ ret = 1;
+ else if ((alt == 0) && (mode == 1))
+ ret = 0;
+ else
+ ret = -EINVAL;
+
+ clk_disable(bank->clk);
+
+ return ret;
+}
+
+static void stm32_gpio_set(struct gpio_chip *chip, unsigned gpio, int value)
+{
+ struct stm32_gpio_bank *bank = to_stm32_gpio_bank(chip);
+
+ clk_enable(bank->clk);
+
+ __stm32_pmx_gpio_set(bank->base, stm32_gpio_pin(gpio, NULL), value);
+
+ clk_disable(bank->clk);
+}
+
+static int stm32_gpio_get(struct gpio_chip *chip, unsigned gpio)
+{
+ struct stm32_gpio_bank *bank = to_stm32_gpio_bank(chip);
+ int ret;
+
+ clk_enable(bank->clk);
+
+ ret = __stm32_pmx_gpio_get(bank->base, stm32_gpio_pin(gpio, NULL));
+
+ clk_disable(bank->clk);
+
+ return ret;
+}
+
+static int stm32_gpio_direction_input(struct gpio_chip *chip, unsigned gpio)
+{
+ struct stm32_gpio_bank *bank = to_stm32_gpio_bank(chip);
+
+ clk_enable(bank->clk);
+
+ __stm32_pmx_gpio_input(bank->base, stm32_gpio_pin(gpio, NULL));
+
+ clk_disable(bank->clk);
+
+ return 0;
+}
+
+static int stm32_gpio_direction_output(struct gpio_chip *chip,
+ unsigned gpio, int value)
+{
+ struct stm32_gpio_bank *bank = to_stm32_gpio_bank(chip);
+
+ clk_enable(bank->clk);
+
+ __stm32_pmx_gpio_output(bank->base, stm32_gpio_pin(gpio, NULL), value);
+
+ clk_disable(bank->clk);
+
+ return 0;
+}
+
+static struct gpio_ops stm32_gpio_ops = {
+ .direction_input = stm32_gpio_direction_input,
+ .direction_output = stm32_gpio_direction_output,
+ .get_direction = stm32_gpio_get_direction,
+ .get = stm32_gpio_get,
+ .set = stm32_gpio_set,
+};
+
+static int stm32_gpiochip_add(struct stm32_gpio_bank *bank,
+ struct device_node *np,
+ struct device_d *parent)
+{
+ struct device_d *dev;
+ struct resource *iores;
+ enum { PINCTRL_PHANDLE, GPIOCTRL_OFFSET, PINCTRL_OFFSET, PINCOUNT, GPIO_RANGE_NCELLS };
+ const __be32 *gpio_ranges;
+ u32 ngpios;
+ int id, ret, size;
+
+ dev = of_platform_device_create(np, parent);
+ if (!dev)
+ return -ENODEV;
+
+ gpio_ranges = of_get_property(np, "gpio-ranges", &size);
+ size /= sizeof(__be32);
+ if (!gpio_ranges || size < GPIO_RANGE_NCELLS) {
+ dev_err(dev, "Couldn't read 'gpio-ranges' property in %s\n",
+ np->full_name);
+ return -EINVAL;
+ }
+
+ ret = of_property_read_u32(np, "ngpios", &ngpios);
+ if (ret)
+ ngpios = be32_to_cpu(gpio_ranges[PINCOUNT]);
+
+ bank->chip.ngpio = ngpios;
+
+ if (size > GPIO_RANGE_NCELLS) {
+ dev_err(dev, "Unsupported disjunct 'gpio-ranges' in %s\n",
+ np->full_name);
+ return -EINVAL;
+ }
+
+ if (ngpios > STM32_GPIO_PINS_PER_BANK) {
+ dev_err(dev, "ngpios property expected to be %u at most in %s\n",
+ ngpios, np->full_name);
+ return -EINVAL;
+ }
+
+ ret = of_property_read_string(np, "st,bank-name", &bank->name);
+ if (ret)
+ bank->name = np->name;
+
+ iores = dev_request_mem_resource(dev, 0);
+ if (IS_ERR(iores)) {
+ dev_err(dev, "Failed to request GPIO memory resource\n");
+ return PTR_ERR(iores);
+ }
+
+ bank->base = IOMEM(iores->start);
+
+ if (dev->id >= 0) {
+ id = dev->id;
+ } else {
+ id = of_alias_get_id(np, "gpio");
+ if (id < 0) {
+ dev_err(dev, "Failed to get GPIO alias\n");
+ return id;
+ }
+ }
+
+ bank->chip.base = id * STM32_GPIO_PINS_PER_BANK;
+ bank->chip.ops = &stm32_gpio_ops;
+ bank->chip.dev = dev;
+ bank->clk = clk_get(dev, NULL);
+ if (IS_ERR(bank->clk)) {
+ dev_err(dev, "failed to get clk (%ld)\n", PTR_ERR(bank->clk));
+ return PTR_ERR(bank->clk);
+ }
+
+ return gpiochip_add(&bank->chip);
+}
+
+static struct pinctrl_ops stm32_pinctrl_ops = {
+ .set_state = stm32_pinctrl_set_state,
+};
+
+static int stm32_pinctrl_probe(struct device_d *dev)
+{
+ struct stm32_pinctrl *pinctrl;
+ unsigned nbanks = 0;
+ struct stm32_gpio_bank *gpio_bank;
+ struct device_node *np = dev->device_node, *child;
+ int ret;
+
+ if (!of_find_property(np, "pins-are-numbered", NULL)) {
+ dev_err(dev, "only pins-are-numbered format supported\n");
+ return -EINVAL;
+ }
+
+ for_each_available_child_of_node(np, child)
+ if (of_property_read_bool(child, "gpio-controller"))
+ nbanks++;
+
+ pinctrl = xzalloc(sizeof(*pinctrl) + nbanks * sizeof(struct stm32_gpio_bank));
+
+ pinctrl->pdev.dev = dev;
+ pinctrl->pdev.ops = &stm32_pinctrl_ops;
+
+ /* hwspinlock property is optional, just log the error */
+ ret = hwspinlock_get_by_index(dev, 0, &pinctrl->hws);
+ if (ret)
+ dev_dbg(dev, "proceeding without hw spinlock support: (%d)\n",
+ ret);
+
+ ret = pinctrl_register(&pinctrl->pdev);
+ if (ret) {
+ dev_dbg(dev, "pinctrl_register failed: (%d)\n", ret);
+ return ret;
+ }
+
+ gpio_bank = pinctrl->gpio_banks;
+ for_each_available_child_of_node(np, child) {
+ if (!of_property_read_bool(child, "gpio-controller"))
+ continue;
+
+ ret = stm32_gpiochip_add(gpio_bank++, child, dev);
+ if (ret) {
+ dev_err(dev, "couldn't add gpiochip %s, ret = %d\n", child->name, ret);
+ return ret;
+ }
+ }
+
+ dev_info(dev, "pinctrl/gpio driver registered\n");
+
+ return 0;
+}
+
+static __maybe_unused struct of_device_id stm32_pinctrl_dt_ids[] = {
+ { .compatible = "st,stm32f429-pinctrl" },
+ { .compatible = "st,stm32f469-pinctrl" },
+ { .compatible = "st,stm32f746-pinctrl" },
+ { .compatible = "st,stm32h743-pinctrl" },
+ { .compatible = "st,stm32mp157-pinctrl" },
+ { .compatible = "st,stm32mp157-z-pinctrl" },
+ { /* sentinel */ }
+};
+
+static struct driver_d stm32_pinctrl_driver = {
+ .name = "stm32-pinctrl",
+ .probe = stm32_pinctrl_probe,
+ .of_compatible = DRV_OF_COMPAT(stm32_pinctrl_dt_ids),
+};
+
+static int stm32_pinctrl_init(void)
+{
+ return platform_driver_register(&stm32_pinctrl_driver);
+}
+core_initcall(stm32_pinctrl_init);
diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig
index 04efb1a3c8..486ef784eb 100644
--- a/drivers/watchdog/Kconfig
+++ b/drivers/watchdog/Kconfig
@@ -81,4 +81,12 @@ config RAVE_SP_WATCHDOG
depends on RAVE_SP_CORE
help
Support for the watchdog on RAVE SP device.
+
+config STM32_IWDG_WATCHDOG
+ bool "STM32 IWDG"
+ depends on ARCH_STM32MP
+ select MFD_SYSCON
+ help
+ Enable to support configuration of the STM32's on-SoC IWDG watchdog.
+ Once started by the user, the IWDG can't be disabled.
endif
diff --git a/drivers/watchdog/Makefile b/drivers/watchdog/Makefile
index 6c8d36c8b8..e731c632c9 100644
--- a/drivers/watchdog/Makefile
+++ b/drivers/watchdog/Makefile
@@ -11,3 +11,4 @@ obj-$(CONFIG_WATCHDOG_IMX) += imxwd.o
obj-$(CONFIG_WATCHDOG_ORION) += orion_wdt.o
obj-$(CONFIG_ARCH_BCM283X) += bcm2835_wdt.o
obj-$(CONFIG_RAVE_SP_WATCHDOG) += rave-sp-wdt.o
+obj-$(CONFIG_STM32_IWDG_WATCHDOG) += stm32_iwdg.o
diff --git a/drivers/watchdog/stm32_iwdg.c b/drivers/watchdog/stm32_iwdg.c
new file mode 100644
index 0000000000..7c2dc077af
--- /dev/null
+++ b/drivers/watchdog/stm32_iwdg.c
@@ -0,0 +1,293 @@
+// SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause
+/*
+ * Copyright (C) 2018, STMicroelectronics - All Rights Reserved
+ */
+
+#include <common.h>
+#include <init.h>
+#include <watchdog.h>
+#include <restart.h>
+#include <asm/io.h>
+#include <of_device.h>
+#include <linux/log2.h>
+#include <linux/iopoll.h>
+#include <linux/clk.h>
+#include <mfd/syscon.h>
+#include <reset_source.h>
+
+/* IWDG registers */
+#define IWDG_KR 0x00 /* Key register */
+#define IWDG_PR 0x04 /* Prescaler Register */
+#define IWDG_RLR 0x08 /* ReLoad Register */
+#define IWDG_SR 0x0C /* Status Register */
+
+/* IWDG_KR register bit mask */
+#define KR_KEY_RELOAD 0xAAAA /* Reload counter enable */
+#define KR_KEY_ENABLE 0xCCCC /* Peripheral enable */
+#define KR_KEY_EWA 0x5555 /* Write access enable */
+
+/* IWDG_PR register bit values */
+#define PR_SHIFT 2
+
+/* IWDG_RLR register values */
+#define RLR_MAX GENMASK(11, 0)
+
+/* IWDG_SR register bit mask */
+#define SR_PVU BIT(0) /* Watchdog prescaler value update */
+#define SR_RVU BIT(1) /* Watchdog counter reload value update */
+
+#define RCC_MP_GRSTCSETR 0x404
+#define RCC_MP_RSTSCLRR 0x408
+#define RCC_MP_GRSTCSETR_MPSYSRST BIT(0)
+
+#define STM32MP_RCC_RSTF_POR BIT(0)
+#define STM32MP_RCC_RSTF_BOR BIT(1)
+#define STM32MP_RCC_RSTF_PAD BIT(2)
+#define STM32MP_RCC_RSTF_HCSS BIT(3)
+#define STM32MP_RCC_RSTF_VCORE BIT(4)
+
+#define STM32MP_RCC_RSTF_MPSYS BIT(6)
+#define STM32MP_RCC_RSTF_MCSYS BIT(7)
+#define STM32MP_RCC_RSTF_IWDG1 BIT(8)
+#define STM32MP_RCC_RSTF_IWDG2 BIT(9)
+
+#define STM32MP_RCC_RSTF_STDBY BIT(11)
+#define STM32MP_RCC_RSTF_CSTDBY BIT(12)
+#define STM32MP_RCC_RSTF_MPUP0 BIT(13)
+#define STM32MP_RCC_RSTF_MPUP1 BIT(14)
+
+/* set timeout to 100 ms */
+#define TIMEOUT_US 100000
+
+struct stm32_reset_reason {
+ uint32_t mask;
+ enum reset_src_type type;
+ int instance;
+};
+
+struct stm32_iwdg {
+ struct watchdog wdd;
+ struct restart_handler restart;
+ void __iomem *iwdg_base;
+ struct regmap *rcc_regmap;
+ unsigned int timeout;
+ unsigned int rate;
+};
+
+static inline struct stm32_iwdg *to_stm32_iwdg(struct watchdog *wdd)
+{
+ return container_of(wdd, struct stm32_iwdg, wdd);
+}
+
+static void __noreturn stm32_iwdg_restart_handler(struct restart_handler *rst)
+{
+ struct stm32_iwdg *wd = container_of(rst, struct stm32_iwdg, restart);
+
+ regmap_update_bits(wd->rcc_regmap, RCC_MP_GRSTCSETR,
+ RCC_MP_GRSTCSETR_MPSYSRST, RCC_MP_GRSTCSETR_MPSYSRST);
+
+ mdelay(1000);
+ hang();
+}
+
+static void stm32_iwdg_ping(struct stm32_iwdg *wd)
+{
+ writel(KR_KEY_RELOAD, wd->iwdg_base + IWDG_KR);
+}
+
+static int stm32_iwdg_start(struct stm32_iwdg *wd, unsigned int timeout)
+{
+ u32 presc, iwdg_rlr, iwdg_pr, iwdg_sr;
+ int ret;
+
+ presc = DIV_ROUND_UP(timeout * wd->rate, RLR_MAX + 1);
+
+ /* The prescaler is align on power of 2 and start at 2 ^ PR_SHIFT. */
+ presc = roundup_pow_of_two(presc);
+ iwdg_pr = presc <= 1 << PR_SHIFT ? 0 : ilog2(presc) - PR_SHIFT;
+ iwdg_rlr = ((timeout * wd->rate) / presc) - 1;
+
+ /* enable write access */
+ writel(KR_KEY_EWA, wd->iwdg_base + IWDG_KR);
+
+ /* set prescaler & reload registers */
+ writel(iwdg_pr, wd->iwdg_base + IWDG_PR);
+ writel(iwdg_rlr, wd->iwdg_base + IWDG_RLR);
+ writel(KR_KEY_ENABLE, wd->iwdg_base + IWDG_KR);
+
+ /* wait for the registers to be updated (max 100ms) */
+ ret = readl_poll_timeout(wd->iwdg_base + IWDG_SR, iwdg_sr,
+ !(iwdg_sr & (SR_PVU | SR_RVU)),
+ TIMEOUT_US);
+ if (!ret)
+ wd->timeout = timeout;
+
+ return ret;
+}
+
+
+static int stm32_iwdg_set_timeout(struct watchdog *wdd, unsigned int timeout)
+{
+ struct stm32_iwdg *wd = to_stm32_iwdg(wdd);
+ int ret;
+
+ if (!timeout)
+ return -EINVAL; /* can't disable */
+
+ if (timeout > wdd->timeout_max)
+ return -EINVAL;
+
+ if (wd->timeout != timeout) {
+ ret = stm32_iwdg_start(wd, timeout);
+ if (ret) {
+ dev_err(wdd->hwdev, "Fail to (re)start watchdog\n");
+ return ret;
+ }
+ }
+
+ stm32_iwdg_ping(wd);
+ return 0;
+}
+
+static const struct stm32_reset_reason stm32_reset_reasons[] = {
+ { STM32MP_RCC_RSTF_POR, RESET_POR, 0 },
+ { STM32MP_RCC_RSTF_BOR, RESET_BROWNOUT, 0 },
+ { STM32MP_RCC_RSTF_STDBY, RESET_WKE, 0 },
+ { STM32MP_RCC_RSTF_CSTDBY, RESET_WKE, 1 },
+ { STM32MP_RCC_RSTF_MPSYS, RESET_RST, 2 },
+ { STM32MP_RCC_RSTF_MPUP0, RESET_RST, 0 },
+ { STM32MP_RCC_RSTF_MPUP1, RESET_RST, 1 },
+ { STM32MP_RCC_RSTF_IWDG1, RESET_WDG, 0 },
+ { STM32MP_RCC_RSTF_IWDG2, RESET_WDG, 1 },
+ { STM32MP_RCC_RSTF_PAD, RESET_EXT, 1 },
+ { /* sentinel */ }
+};
+
+static int stm32_set_reset_reason(struct regmap *rcc)
+{
+ enum reset_src_type type = RESET_UKWN;
+ u32 reg;
+ int ret;
+ int i, instance = 0;
+
+ ret = regmap_read(rcc, RCC_MP_RSTSCLRR, &reg);
+ if (ret)
+ return ret;
+
+ for (i = 0; stm32_reset_reasons[i].mask; i++) {
+ if (reg & stm32_reset_reasons[i].mask) {
+ type = stm32_reset_reasons[i].type;
+ instance = stm32_reset_reasons[i].instance;
+ break;
+ }
+ }
+
+ reset_source_set_priority(type, RESET_SOURCE_DEFAULT_PRIORITY);
+ reset_source_set_instance(type, instance);
+
+ pr_info("STM32 RCC reset reason %s (MP_RSTSR: 0x%08x)\n",
+ reset_source_name(), reg);
+
+ return 0;
+}
+
+struct stm32_iwdg_data {
+ bool has_pclk;
+ u32 max_prescaler;
+};
+
+static const struct stm32_iwdg_data stm32_iwdg_data = {
+ .has_pclk = false, .max_prescaler = 256,
+};
+
+static const struct stm32_iwdg_data stm32mp1_iwdg_data = {
+ .has_pclk = true, .max_prescaler = 1024,
+};
+
+static const struct of_device_id stm32_iwdg_of_match[] = {
+ { .compatible = "st,stm32-iwdg", .data = &stm32_iwdg_data },
+ { .compatible = "st,stm32mp1-iwdg", .data = &stm32mp1_iwdg_data },
+ { /* sentinel */ }
+};
+
+static int stm32_iwdg_probe(struct device_d *dev)
+{
+ struct stm32_iwdg_data *data;
+ struct stm32_iwdg *wd;
+ struct resource *res;
+ struct watchdog *wdd;
+ struct clk *clk;
+ int ret;
+
+ wd = xzalloc(sizeof(*wd));
+
+ ret = dev_get_drvdata(dev, (const void **)&data);
+ if (ret)
+ return -ENODEV;
+
+ res = dev_request_mem_resource(dev, 0);
+ if (IS_ERR(res)) {
+ dev_err(dev, "could not get timer memory region\n");
+ return PTR_ERR(res);
+ }
+ wd->iwdg_base = IOMEM(res->start);
+
+ clk = clk_get(dev, "lsi");
+ if (IS_ERR(clk))
+ return PTR_ERR(clk);
+
+ ret = clk_enable(clk);
+ if (ret)
+ return ret;
+
+ wd->rate = clk_get_rate(clk);
+
+ if (data->has_pclk) {
+ clk = clk_get(dev, "pclk");
+ if (IS_ERR(clk))
+ return PTR_ERR(clk);
+
+ ret = clk_enable(clk);
+ if (ret)
+ return ret;
+ }
+
+ wdd = &wd->wdd;
+ wdd->hwdev = dev;
+ wdd->set_timeout = stm32_iwdg_set_timeout;
+ wdd->timeout_max = (RLR_MAX + 1) * data->max_prescaler * 1000;
+ wdd->timeout_max /= wd->rate * 1000;
+ wdd->timeout_cur = wdd->timeout_max;
+
+ ret = watchdog_register(wdd);
+ if (ret) {
+ dev_err(dev, "Failed to register watchdog device\n");
+ return ret;
+ }
+
+ wd->restart.name = "stm32-iwdg";
+ wd->restart.restart = stm32_iwdg_restart_handler;
+ wd->restart.priority = 200;
+
+ wd->rcc_regmap = syscon_regmap_lookup_by_compatible("st,stm32mp1-rcc");
+ if (IS_ERR(wd->rcc_regmap))
+ dev_warn(dev, "Cannot register restart handler\n");
+
+ ret = restart_handler_register(&wd->restart);
+ if (ret)
+ dev_warn(dev, "Cannot register restart handler\n");
+
+ ret = stm32_set_reset_reason(wd->rcc_regmap);
+ if (ret)
+ dev_warn(dev, "Cannot determine reset reason\n");
+
+ dev_info(dev, "probed\n");
+ return 0;
+}
+
+static struct driver_d stm32_iwdg_driver = {
+ .name = "stm32-iwdg",
+ .probe = stm32_iwdg_probe,
+ .of_compatible = DRV_OF_COMPAT(stm32_iwdg_of_match),
+};
+device_platform_driver(stm32_iwdg_driver);
diff --git a/images/Makefile b/images/Makefile
index 479647a827..293e644319 100644
--- a/images/Makefile
+++ b/images/Makefile
@@ -140,7 +140,7 @@ include $(srctree)/images/Makefile.mxs
include $(srctree)/images/Makefile.omap3
include $(srctree)/images/Makefile.rockchip
include $(srctree)/images/Makefile.socfpga
-include $(srctree)/images/Makefile.stm32mp1
+include $(srctree)/images/Makefile.stm32mp
include $(srctree)/images/Makefile.tegra
include $(srctree)/images/Makefile.vexpress
include $(srctree)/images/Makefile.xburst
diff --git a/images/Makefile.stm32mp1 b/images/Makefile.stm32mp
index d26231cd92..c49b1d72b7 100644
--- a/images/Makefile.stm32mp1
+++ b/images/Makefile.stm32mp
@@ -3,6 +3,6 @@
# barebox image generation Makefile for STMicroelectronics MP1
#
-pblb-$(CONFIG_MACH_STM32MP157C_DK2) += start_stm32mp157c_dk2.pblb
+pblb-$(CONFIG_MACH_STM32MP157C_DK2) += start_stm32mp157c_dk2
FILE_barebox-stm32mp157c-dk2.img = start_stm32mp157c_dk2.pblb
image-$(CONFIG_MACH_STM32MP157C_DK2) += barebox-stm32mp157c-dk2.img
diff --git a/include/gpio.h b/include/gpio.h
index 38d6ba2df9..e822fd5347 100644
--- a/include/gpio.h
+++ b/include/gpio.h
@@ -153,5 +153,6 @@ int gpiochip_add(struct gpio_chip *chip);
void gpiochip_remove(struct gpio_chip *chip);
int gpio_get_num(struct device_d *dev, int gpio);
+struct gpio_chip *gpio_get_chip(int gpio);
#endif /* __GPIO_H */
diff --git a/include/hwspinlock.h b/include/hwspinlock.h
new file mode 100644
index 0000000000..ba21c6d296
--- /dev/null
+++ b/include/hwspinlock.h
@@ -0,0 +1,31 @@
+/* SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause */
+/*
+ * Copyright (C) 2018, STMicroelectronics - All Rights Reserved
+ */
+
+#ifndef __HWSPINLOCK_H
+#define __HWSPINLOCK_H
+
+struct hwspinlock { /* TODO to be implemented */ };
+
+static inline int hwspinlock_get_by_index(struct device_d *dev,
+ int index,
+ struct hwspinlock *hws)
+{
+ return -ENOSYS;
+}
+
+static inline int hwspinlock_lock_timeout(struct hwspinlock *hws,
+ int timeout_ms)
+{
+ return -ENOSYS;
+}
+
+static inline int hwspinlock_unlock(struct hwspinlock *hws)
+{
+ return -ENOSYS;
+}
+
+struct hwspinlock_ops { /* TODO to be implemented */ };
+
+#endif /* __HWSPINLOCK_H */
diff --git a/include/reset_source.h b/include/reset_source.h
index 86e415abcf..13bc3bcfde 100644
--- a/include/reset_source.h
+++ b/include/reset_source.h
@@ -22,6 +22,7 @@ enum reset_src_type {
RESET_JTAG, /* JTAG reset */
RESET_THERM, /* SoC shut down because of overtemperature */
RESET_EXT, /* External reset through device pin */
+ RESET_BROWNOUT, /* Brownout Reset */
};
#ifdef CONFIG_RESET_SOURCE
diff --git a/include/soc/stm32/gpio.h b/include/soc/stm32/gpio.h
new file mode 100644
index 0000000000..13b492a693
--- /dev/null
+++ b/include/soc/stm32/gpio.h
@@ -0,0 +1,120 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2015 Maxime Coquelin
+ * Copyright (C) 2017 STMicroelectronics
+ * Copyright (C) 2019 Ahmad Fatoum, Pengutronix
+ */
+
+#ifndef __STM32_GPIO_H__
+#define __STM32_GPIO_H__
+
+#include <io.h>
+
+#define STM32_GPIO_MODER 0x00
+#define STM32_GPIO_TYPER 0x04
+#define STM32_GPIO_SPEEDR 0x08
+#define STM32_GPIO_PUPDR 0x0c
+#define STM32_GPIO_IDR 0x10
+#define STM32_GPIO_ODR 0x14
+#define STM32_GPIO_BSRR 0x18
+#define STM32_GPIO_LCKR 0x1c
+#define STM32_GPIO_AFRL 0x20
+#define STM32_GPIO_AFRH 0x24
+
+#define STM32_PIN_GPIO 0
+#define STM32_PIN_AF(x) ((x) + 1)
+#define STM32_PIN_ANALOG (STM32_PIN_AF(15) + 1)
+
+#define STM32_GPIO_PINS_PER_BANK 16
+
+enum stm32_pin_bias { STM32_PIN_NO_BIAS, STM32_PIN_PULL_UP, STM32_PIN_PULL_DOWN };
+enum stm32_pin_out_type { STM32_PIN_OUT_PUSHPULL, STM32_PIN_OUT_OPENDRAIN };
+
+static inline void __stm32_pmx_set_speed(void __iomem *base,
+ unsigned offset, u32 speed)
+{
+ u32 val = readl(base + STM32_GPIO_SPEEDR);
+ val &= ~GENMASK(offset * 2 + 1, offset * 2);
+ val |= speed << (offset * 2);
+ writel(val, base + STM32_GPIO_SPEEDR);
+}
+
+static inline void __stm32_pmx_set_bias(void __iomem *base, unsigned offset,
+ enum stm32_pin_bias bias)
+{
+ u32 val = readl(base + STM32_GPIO_PUPDR);
+ val &= ~GENMASK(offset * 2 + 1, offset * 2);
+ val |= bias << (offset * 2);
+ writel(val, base + STM32_GPIO_PUPDR);
+}
+
+static inline void __stm32_pmx_set_mode(void __iomem *base,
+ int pin, u32 mode, u32 alt)
+{
+ u32 val;
+ int alt_shift = (pin % 8) * 4;
+ int alt_offset = STM32_GPIO_AFRL + (pin / 8) * 4;
+
+ val = readl(base + alt_offset);
+ val &= ~GENMASK(alt_shift + 3, alt_shift);
+ val |= (alt << alt_shift);
+ writel(val, base + alt_offset);
+
+ val = readl(base + STM32_GPIO_MODER);
+ val &= ~GENMASK(pin * 2 + 1, pin * 2);
+ val |= mode << (pin * 2);
+ writel(val, base + STM32_GPIO_MODER);
+}
+
+static inline void __stm32_pmx_get_mode(void __iomem *base, int pin,
+ u32 *mode, u32 *alt)
+{
+ u32 val;
+ int alt_shift = (pin % 8) * 4;
+ int alt_offset = STM32_GPIO_AFRL + (pin / 8) * 4;
+
+ val = readl(base + alt_offset);
+ val &= GENMASK(alt_shift + 3, alt_shift);
+ *alt = val >> alt_shift;
+
+ val = readl(base + STM32_GPIO_MODER);
+ val &= GENMASK(pin * 2 + 1, pin * 2);
+ *mode = val >> (pin * 2);
+}
+
+static inline int __stm32_pmx_gpio_get(void __iomem *base, unsigned offset)
+{
+ return !!(readl(base + STM32_GPIO_IDR) & BIT(offset));
+}
+
+static inline void __stm32_pmx_gpio_set(void __iomem *base, unsigned offset,
+ unsigned value)
+{
+ if (!value)
+ offset += STM32_GPIO_PINS_PER_BANK;
+
+ writel(BIT(offset), base + STM32_GPIO_BSRR);
+}
+
+static inline void __stm32_pmx_gpio_input(void __iomem *base, unsigned offset)
+{
+ __stm32_pmx_set_mode(base, offset, 0, 0);
+}
+
+static inline void __stm32_pmx_gpio_output(void __iomem *base, unsigned offset,
+ unsigned value)
+{
+ __stm32_pmx_gpio_set(base, offset, value);
+ __stm32_pmx_set_mode(base, offset, 1, 0);
+}
+
+static inline void __stm32_pmx_set_output_type(void __iomem *base, unsigned offset,
+ enum stm32_pin_out_type type)
+{
+ u32 val = readl(base + STM32_GPIO_TYPER);
+ val &= ~BIT(offset);
+ val |= type << offset;
+ writel(val, base + STM32_GPIO_TYPER);
+}
+
+#endif /* __STM32_GPIO_H__ */