1 // SPDX-License-Identifier: GPL-2.0+
3 * Copyright (c) 2022 BayLibre, SAS.
8 #include <dm/device_compat.h>
12 #include <linux/bitops.h>
14 #define GXBB_WDT_CTRL_REG 0x0
15 #define GXBB_WDT_TCNT_REG 0x8
16 #define GXBB_WDT_RSET_REG 0xc
18 #define GXBB_WDT_CTRL_SYS_RESET_NOW BIT(26)
19 #define GXBB_WDT_CTRL_CLKDIV_EN BIT(25)
20 #define GXBB_WDT_CTRL_CLK_EN BIT(24)
21 #define GXBB_WDT_CTRL_EE_RESET BIT(21)
22 #define GXBB_WDT_CTRL_EN BIT(18)
24 #define GXBB_WDT_CTRL_DIV_MASK GENMASK(17, 0)
25 #define GXBB_WDT_TCNT_SETUP_MASK GENMASK(15, 0)
28 struct amlogic_wdt_priv
{
29 void __iomem
*reg_base
;
32 static int amlogic_wdt_set_timeout(struct udevice
*dev
, u64 timeout_ms
)
34 struct amlogic_wdt_priv
*data
= dev_get_priv(dev
);
36 if (timeout_ms
> GXBB_WDT_TCNT_SETUP_MASK
) {
37 dev_warn(dev
, "%s: timeout_ms=%llu: maximum watchdog timeout exceeded\n",
38 __func__
, timeout_ms
);
39 timeout_ms
= GXBB_WDT_TCNT_SETUP_MASK
;
42 writel(timeout_ms
, data
->reg_base
+ GXBB_WDT_TCNT_REG
);
47 static int amlogic_wdt_stop(struct udevice
*dev
)
49 struct amlogic_wdt_priv
*data
= dev_get_priv(dev
);
51 writel(readl(data
->reg_base
+ GXBB_WDT_CTRL_REG
) & ~GXBB_WDT_CTRL_EN
,
52 data
->reg_base
+ GXBB_WDT_CTRL_REG
);
57 static int amlogic_wdt_start(struct udevice
*dev
, u64 time_ms
, ulong flags
)
59 struct amlogic_wdt_priv
*data
= dev_get_priv(dev
);
61 writel(readl(data
->reg_base
+ GXBB_WDT_CTRL_REG
) | GXBB_WDT_CTRL_EN
,
62 data
->reg_base
+ GXBB_WDT_CTRL_REG
);
64 return amlogic_wdt_set_timeout(dev
, time_ms
);
67 static int amlogic_wdt_reset(struct udevice
*dev
)
69 struct amlogic_wdt_priv
*data
= dev_get_priv(dev
);
71 writel(0, data
->reg_base
+ GXBB_WDT_RSET_REG
);
76 static int amlogic_wdt_expire_now(struct udevice
*dev
, ulong flags
)
78 struct amlogic_wdt_priv
*data
= dev_get_priv(dev
);
80 writel(0, data
->reg_base
+ GXBB_WDT_CTRL_SYS_RESET_NOW
);
85 static int amlogic_wdt_probe(struct udevice
*dev
)
87 struct amlogic_wdt_priv
*data
= dev_get_priv(dev
);
90 data
->reg_base
= dev_remap_addr(dev
);
96 ret
= clk_get_by_index(dev
, 0, &clk
);
100 ret
= clk_enable(&clk
);
104 /* Setup with 1ms timebase */
105 writel(((clk_get_rate(&clk
) / 1000) & GXBB_WDT_CTRL_DIV_MASK
) |
106 GXBB_WDT_CTRL_EE_RESET
|
107 GXBB_WDT_CTRL_CLK_EN
|
108 GXBB_WDT_CTRL_CLKDIV_EN
,
109 data
->reg_base
+ GXBB_WDT_CTRL_REG
);
114 static const struct wdt_ops amlogic_wdt_ops
= {
115 .start
= amlogic_wdt_start
,
116 .reset
= amlogic_wdt_reset
,
117 .stop
= amlogic_wdt_stop
,
118 .expire_now
= amlogic_wdt_expire_now
,
121 static const struct udevice_id amlogic_wdt_ids
[] = {
122 { .compatible
= "amlogic,meson-gxbb-wdt" },
126 U_BOOT_DRIVER(amlogic_wdt
) = {
127 .name
= "amlogic_wdt",
129 .of_match
= amlogic_wdt_ids
,
130 .priv_auto
= sizeof(struct amlogic_wdt_priv
),
131 .probe
= amlogic_wdt_probe
,
132 .ops
= &amlogic_wdt_ops
,
133 .flags
= DM_FLAG_PRE_RELOC
,