1- /* $NetBSD: sunxi_wdt.c,v 1.6 2021/01/27 03:10:20 thorpej Exp $ */
1+ /* $NetBSD: sunxi_wdt.c,v 1.7 2026/03/18 06:37:09 skrll Exp $ */
22
33/*-
44 * Copyright (c) 2017 Jared McNeill <jmcneill@invisible.ca>
2727 */
2828
2929#include <sys/cdefs.h>
30- __KERNEL_RCSID (0 , "$NetBSD: sunxi_wdt.c,v 1.6 2021/01/27 03:10:20 thorpej Exp $" );
30+ __KERNEL_RCSID (0 , "$NetBSD: sunxi_wdt.c,v 1.7 2026/03/18 06:37:09 skrll Exp $" );
3131
3232#include <sys/param.h>
3333#include <sys/bus.h>
@@ -68,6 +68,9 @@ __KERNEL_RCSID(0, "$NetBSD: sunxi_wdt.c,v 1.6 2021/01/27 03:10:20 thorpej Exp $"
6868#define SUN6I_WDT_MODE_INTV __BITS(7,4)
6969#define SUN6I_WDT_MODE_EN __BIT(0)
7070
71+ #define SUNXI_WDT_KEY_FIELD __BITS(31,16)
72+ #define SUNXI_WDT_KEY_FIELD_V 0x16aa
73+
7174static const int sunxi_periods [] = {
7275 500 , 1000 , 2000 , 3000 ,
7376 4000 , 5000 , 6000 , 8000 ,
@@ -78,11 +81,13 @@ static const int sunxi_periods[] = {
7881enum sunxi_wdt_type {
7982 WDT_SUN4I = 1 ,
8083 WDT_SUN6I ,
84+ WDT_SUN20I ,
8185};
8286
8387static const struct device_compatible_entry compat_data [] = {
8488 { .compat = "allwinner,sun4i-a10-wdt" , .value = WDT_SUN4I },
8589 { .compat = "allwinner,sun6i-a31-wdt" , .value = WDT_SUN6I },
90+ { .compat = "allwinner,sun20i-d1-wdt" , .value = WDT_SUN20I },
8691 DEVICE_COMPAT_EOL
8792};
8893
@@ -197,6 +202,36 @@ sun6i_wdt_tickle(struct sysmon_wdog *smw)
197202 return 0 ;
198203}
199204
205+ static int
206+ sun20i_wdt_setmode (struct sysmon_wdog * smw )
207+ {
208+ struct sunxi_wdt_softc * const sc = smw -> smw_cookie ;
209+ uint32_t cfg , mode ;
210+ int intv ;
211+
212+ if ((smw -> smw_mode & WDOG_MODE_MASK ) == WDOG_MODE_DISARMED ) {
213+ mode = __SHIFTIN (SUNXI_WDT_KEY_FIELD_V , SUNXI_WDT_KEY_FIELD );
214+ WDT_WRITE (sc , SUN6I_WDT_MODE_REG , mode );
215+ } else {
216+ if (smw -> smw_period == WDOG_PERIOD_DEFAULT )
217+ smw -> smw_period = SUNXI_WDT_PERIOD_DEFAULT ;
218+ intv = sunxi_wdt_map_period (sc , smw -> smw_period ,
219+ & sc -> sc_smw .smw_period );
220+ if (intv == -1 )
221+ return EINVAL ;
222+
223+ cfg = __SHIFTIN (SUN6I_WDT_CFG_CONFIG_SYS , SUN6I_WDT_CFG_CONFIG );
224+ cfg |= __SHIFTIN (SUNXI_WDT_KEY_FIELD_V , SUNXI_WDT_KEY_FIELD );
225+ mode = SUN6I_WDT_MODE_EN | __SHIFTIN (intv , SUN6I_WDT_MODE_INTV );
226+ mode |= __SHIFTIN (SUNXI_WDT_KEY_FIELD_V , SUNXI_WDT_KEY_FIELD );
227+
228+ WDT_WRITE (sc , SUN6I_WDT_CFG_REG , cfg );
229+ WDT_WRITE (sc , SUN6I_WDT_MODE_REG , mode );
230+ }
231+
232+ return 0 ;
233+ }
234+
200235static int
201236sunxi_wdt_match (device_t parent , cfdata_t cf , void * aux )
202237{
@@ -214,6 +249,7 @@ sunxi_wdt_attach(device_t parent, device_t self, void *aux)
214249 enum sunxi_wdt_type type ;
215250 bus_addr_t addr ;
216251 bus_size_t size ;
252+ uint32_t mode ;
217253
218254 if (fdtbus_get_reg (phandle , 0 , & addr , & size ) != 0 ) {
219255 aprint_error (": couldn't get registers\n" );
@@ -245,6 +281,17 @@ sunxi_wdt_attach(device_t parent, device_t self, void *aux)
245281 sc -> sc_smw .smw_setmode = sun6i_wdt_setmode ;
246282 sc -> sc_smw .smw_tickle = sun6i_wdt_tickle ;
247283
284+ /* Disable watchdog IRQs */
285+ WDT_WRITE (sc , SUN6I_WDT_IRQ_EN_REG , 0 );
286+ break ;
287+ case WDT_SUN20I :
288+ sc -> sc_smw .smw_setmode = sun20i_wdt_setmode ;
289+ sc -> sc_smw .smw_tickle = sun6i_wdt_tickle ;
290+
291+ /* Disable watchdog */
292+ mode = __SHIFTIN (SUNXI_WDT_KEY_FIELD_V , SUNXI_WDT_KEY_FIELD );
293+ WDT_WRITE (sc , SUN6I_WDT_MODE_REG , mode );
294+
248295 /* Disable watchdog IRQs */
249296 WDT_WRITE (sc , SUN6I_WDT_IRQ_EN_REG , 0 );
250297 break ;
0 commit comments