/* * SPDX-License-Identifier: BSD-2-Clause * * Copyright (c) 2021 Samuel Holland */ #include #include #include #include #include #include #include #define WDT_KEY_VAL 0x16aa0000 #define WDT_SOFT_RST_REG 0x08 #define WDT_SOFT_RST_EN BIT(0) #define WDT_MODE_REG 0x18 static volatile void *sunxi_wdt_base; static int sunxi_wdt_system_reset_check(u32 type, u32 reason) { switch (type) { case SBI_SRST_RESET_TYPE_COLD_REBOOT: case SBI_SRST_RESET_TYPE_WARM_REBOOT: return 1; } return 0; } static void sunxi_wdt_system_reset(u32 type, u32 reason) { /* Disable the watchdog. */ writel_relaxed(WDT_KEY_VAL, sunxi_wdt_base + WDT_MODE_REG); /* Trigger soft reset. */ writel_relaxed(WDT_KEY_VAL | WDT_SOFT_RST_EN, sunxi_wdt_base + WDT_SOFT_RST_REG); } static struct sbi_system_reset_device sunxi_wdt_reset = { .name = "sunxi-wdt-reset", .system_reset_check = sunxi_wdt_system_reset_check, .system_reset = sunxi_wdt_system_reset, }; static int sunxi_wdt_reset_init(void *fdt, int nodeoff, const struct fdt_match *match) { uint64_t reg_addr; int rc; rc = fdt_get_node_addr_size(fdt, nodeoff, 0, ®_addr, NULL); if (rc < 0 || !reg_addr) return SBI_ENODEV; sunxi_wdt_base = (volatile void *)(unsigned long)reg_addr; sbi_system_reset_add_device(&sunxi_wdt_reset); return 0; } static const struct fdt_match sunxi_wdt_reset_match[] = { { .compatible = "allwinner,sun20i-d1-wdt-reset" }, { }, }; struct fdt_reset fdt_reset_sunxi_wdt = { .match_table = sunxi_wdt_reset_match, .init = sunxi_wdt_reset_init, };