
On Mon, 20 Jan 2020 at 02:53, Alex Nemirovsky Alex.Nemirovsky@cortina-access.com wrote:
From: Jason Li jason.li@cortina-access.com
Add support for hardware watchdog timer on all Cortina Access CAxxxx family of SoCs.
Signed-off-by: Jason Li jason.li@cortina-access.com Signed-off-by: Alex Nemirovsky alex.nemirovsky@cortina-access.com
MAINTAINERS | 2 + drivers/watchdog/Kconfig | 8 +++ drivers/watchdog/Makefile | 1 + drivers/watchdog/cortina_wdt.c | 144 +++++++++++++++++++++++++++++++++++++++++ 4 files changed, 155 insertions(+) create mode 100644 drivers/watchdog/cortina_wdt.c
diff --git a/MAINTAINERS b/MAINTAINERS index b7b3359..f9334f9 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -180,6 +180,7 @@ F: board/cortina/common/* F: board/cortina/common/Kconfig F: board/cortina/common/armv8/lowlevel_init.S F: drivers/gpio/cortina_gpio.c +F: drivers/watchdog/cortina_wdt.c
ARM/CZ.NIC TURRIS MOX SUPPORT M: Marek Behun marek.behun@nic.cz @@ -662,6 +663,7 @@ F: board/cortina/common/* F: board/cortina/common/Kconfig F: board/cortina/common/mips/* F: drivers/gpio/cortina_gpio.c +F: drivers/watchdog/cortina_wdt.c
MIPS MSCC M: Gregory CLEMENT gregory.clement@bootlin.com diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig index 8c16d69..2f7dedb 100644 --- a/drivers/watchdog/Kconfig +++ b/drivers/watchdog/Kconfig @@ -99,6 +99,14 @@ config WDT_CDNS Select this to enable Cadence watchdog timer, which can be found on some Xilinx Microzed Platform.
+config WDT_CORTINA
bool "Cortina Access CAxxxx watchdog timer support"
depends on WDT
help
Cortina Access CAxxxx watchdog timer support.
This driver support all CPU ISAs supported by Cortina
Access CAxxxx SoCs.
config WDT_MPC8xx bool "MPC8xx watchdog timer support" depends on WDT && MPC8xx diff --git a/drivers/watchdog/Makefile b/drivers/watchdog/Makefile index 955caef..87f92a4 100644 --- a/drivers/watchdog/Makefile +++ b/drivers/watchdog/Makefile @@ -20,6 +20,7 @@ obj-$(CONFIG_WDT_SANDBOX) += sandbox_wdt.o obj-$(CONFIG_WDT_ARMADA_37XX) += armada-37xx-wdt.o obj-$(CONFIG_WDT_ASPEED) += ast_wdt.o obj-$(CONFIG_WDT_BCM6345) += bcm6345_wdt.o +obj-$(CONFIG_WDT_CORTINA) += cortina_wdt.o obj-$(CONFIG_WDT_ORION) += orion_wdt.o obj-$(CONFIG_WDT_CDNS) += cdns_wdt.o obj-$(CONFIG_WDT_MPC8xx) += mpc8xx_wdt.o diff --git a/drivers/watchdog/cortina_wdt.c b/drivers/watchdog/cortina_wdt.c new file mode 100644 index 0000000..61df802 --- /dev/null +++ b/drivers/watchdog/cortina_wdt.c @@ -0,0 +1,144 @@ +// SPDX-License-Identifier: GPL-2.0+
+/*
- Copyright (C) 2020 Cortina-Access
- Author: Jason Li jason.li@cortina-access.com
- */
+#include <common.h> +#include <dm.h> +#include <asm/io.h> +#include <wdt.h>
+#define CA_WDT_CTRL 0x00
Use stryct?
+#define CA_WDT_PS 0x04 +#define CA_WDT_DIV 0x08 +#define CA_WDT_LD 0x0C +#define CA_WDT_LOADE 0x10 +#define CA_WDT_CNT 0x14 +#define CA_WDT_IE 0x18 +#define CA_WDT_INT 0x1C +#define CA_WDT_STAT 0x20
+/* CA_WDT_CTRL */ +#define CTL_WDT_EN BIT(0) +#define CTL_WDT_RSTEN BIT(1) +#define CTL_WDT_CLK_SEL BIT(2) +/* CA_WDT_LOADE */ +#define WDT_UPD BIT(0) +#define WDT_UPD_PS BIT(1)
+/* Global config */ +#define WDT_RESET_SUB BIT(4) +#define WDT_RESET_ALL_BLOCK BIT(6) +#define WDT_RESET_REMAP BIT(7) +#define WDT_EXT_RESET BIT(8) +#define WDT_RESET_DEFAULT (WDT_EXT_RESET | WDT_RESET_REMAP |
WDT_RESET_ALL_BLOCK | WDT_RESET_SUB)
struct comment
+struct ca_wdt_priv {
void __iomem *base;
void __iomem *global_config;
+};
+static void cortina_wdt_set_timeout(struct udevice *dev, u64 timeout_ms) +{
struct ca_wdt_priv *priv = dev_get_priv(dev);
/* Prescale using millisecond unit */
writel(CORTINA_PER_IO_FREQ / 1000, priv->base + CA_WDT_PS);
/* Millisecond */
writel(1, priv->base + CA_WDT_DIV);
writel(timeout_ms, priv->base + CA_WDT_LD);
writel(WDT_UPD | WDT_UPD_PS, priv->base + CA_WDT_LOADE);
+}
+static int cortina_wdt_start(struct udevice *dev, u64 timeout, ulong flags) +{
struct ca_wdt_priv *priv = dev_get_priv(dev);
unsigned int reg_v;
cortina_wdt_set_timeout(dev, timeout);
/* WDT Reset option */
reg_v = readl(priv->global_config);
reg_v |= WDT_RESET_DEFAULT;
writel(reg_v, priv->global_config);
setbits_le32(), and below
/* Enable WDT */
reg_v = readl(priv->base);
reg_v |= (CTL_WDT_EN | CTL_WDT_RSTEN | CTL_WDT_CLK_SEL);
writel(reg_v, priv->base);
return 0;
+}
+static int cortina_wdt_stop(struct udevice *dev) +{
struct ca_wdt_priv *priv = dev_get_priv(dev);
/* Disable WDT */
writel(0, priv->base);
return 0;
+}
+static int cortina_wdt_reset(struct udevice *dev) +{
struct ca_wdt_priv *priv = dev_get_priv(dev);
/* Reload WDT counter */
writel(WDT_UPD, priv->base + CA_WDT_LOADE);
return 0;
+}
+static int cortina_wdt_expire_now(struct udevice *dev, ulong flags) +{
/* Set 1ms timeout to reset system */
cortina_wdt_set_timeout(dev, 1);
hang();
This hang() should be moved to the calling function, wdt_expire_now() and drivers adjusted accordingly. This is a bit like the sysreset case. This function should return -EINPROGRESS.
return 0;
+}
+static int cortina_wdt_probe(struct udevice *dev) +{
struct ca_wdt_priv *priv = dev_get_priv(dev);
priv->base = dev_remap_addr_index(dev, 0);
if (!priv->base)
return -ENOENT;
-EINVAL
priv->global_config = dev_remap_addr_index(dev, 1);
if (!priv->global_config)
return -ENOENT;
Same
BTW both of these should be in an ofdata_to_platadata() method.
/* Stop WDT */
cortina_wdt_stop(dev);
Only this should be in the prove() method.
return 0;
+}
+static const struct wdt_ops cortina_wdt_ops = {
.start = cortina_wdt_start,
.reset = cortina_wdt_reset,
.stop = cortina_wdt_stop,
.expire_now = cortina_wdt_expire_now,
+};
+static const struct udevice_id cortina_wdt_ids[] = {
{.compatible = "cortina,cortina-wdt"},
{}
+};
+U_BOOT_DRIVER(cortina_wdt) = {
.name = "cortina_wdt",
.id = UCLASS_WDT,
.probe = cortina_wdt_probe,
.of_match = cortina_wdt_ids,
.ops = &cortina_wdt_ops,
+};
2.7.4
Regards, Simon