15cbd8b3aSClément Léger // SPDX-License-Identifier: BSD-2-Clause 25cbd8b3aSClément Léger /* 35cbd8b3aSClément Léger * Copyright 2022 Microchip 45cbd8b3aSClément Léger */ 55cbd8b3aSClément Léger 65cbd8b3aSClément Léger #include <assert.h> 75cbd8b3aSClément Léger #include <drivers/clk.h> 85cbd8b3aSClément Léger #include <drivers/clk_dt.h> 95cbd8b3aSClément Léger #include <drivers/wdt.h> 105cbd8b3aSClément Léger #include <io.h> 115cbd8b3aSClément Léger #include <kernel/delay.h> 125cbd8b3aSClément Léger #include <kernel/dt.h> 139e3c57c8SEtienne Carriere #include <kernel/dt_driver.h> 1433a0c835SEtienne Carriere #include <kernel/interrupt.h> 155cbd8b3aSClément Léger #include <kernel/pm.h> 165cbd8b3aSClément Léger #include <matrix.h> 17c64c658bSEtienne Carriere #include <mm/core_mmu.h> 186370f75dSTony Han #include <platform_config.h> 195cbd8b3aSClément Léger #include <tee_api_types.h> 205cbd8b3aSClément Léger 215cbd8b3aSClément Léger #define WDT_CR 0x0 225cbd8b3aSClément Léger #define WDT_CR_KEY SHIFT_U32(0xA5, 24) 235cbd8b3aSClément Léger #define WDT_CR_WDRSTT BIT(0) 245cbd8b3aSClément Léger 255cbd8b3aSClément Léger #define WDT_MR 0x4 265cbd8b3aSClément Léger #define WDT_MR_WDV GENMASK_32(11, 0) 275cbd8b3aSClément Léger #define WDT_MR_WDV_SET(val) ((val) & WDT_MR_WDV) 285cbd8b3aSClément Léger #define WDT_MR_WDFIEN BIT(12) 295cbd8b3aSClément Léger #define WDT_MR_WDRSTEN BIT(13) 30*ea9329ecSTony Han #define WDT_MR_WDDIS BIT(15) /* Watchdog Disable of WDT on bit 15 */ 31*ea9329ecSTony Han #define WDT_MR_WDDIS_DWDT BIT(12) /* Watchdog Disable of DWDT on bit 12 */ 325cbd8b3aSClément Léger #define WDT_MR_WDD_SHIFT 16 335cbd8b3aSClément Léger #define WDT_MR_WDD_MASK GENMASK_32(11, 0) 345cbd8b3aSClément Léger #define WDT_MR_WDD SHIFT_U32(WDT_MR_WDD_MASK, WDT_MR_WDD_SHIFT) 355cbd8b3aSClément Léger #define WDT_MR_WDD_SET(val) \ 365cbd8b3aSClément Léger SHIFT_U32(((val) & WDT_MR_WDD_MASK), WDT_MR_WDD_SHIFT) 375cbd8b3aSClément Léger #define WDT_MR_WDDBGHLT BIT(28) 385cbd8b3aSClément Léger #define WDT_MR_WDIDLEHLT BIT(29) 395cbd8b3aSClément Léger 405cbd8b3aSClément Léger #define WDT_SR 0x8 415cbd8b3aSClément Léger #define WDT_SR_DUNF BIT(0) 425cbd8b3aSClément Léger #define WDT_SR_DERR BIT(1) 435cbd8b3aSClément Léger 44*ea9329ecSTony Han /* DWDT: Watchdog Timer Mode Register */ 45*ea9329ecSTony Han #define WDT_MR_PERIODRST BIT(4) 46*ea9329ecSTony Han #define WDT_MR_RPTHRST BIT(5) 47*ea9329ecSTony Han 48*ea9329ecSTony Han /* DWDT: Watchdog Timer Value Register (Read-only) */ 49*ea9329ecSTony Han #define WDT_VR 0x8 50*ea9329ecSTony Han #define WDT_VR_COUNTER_SHIFT 0 51*ea9329ecSTony Han #define WDT_VR_COUNTER_MASK GENMASK_32(11, 0) 52*ea9329ecSTony Han 53*ea9329ecSTony Han /* DWDT: Watchdog Timer Window Level Register */ 54*ea9329ecSTony Han #define WDT_WL 0xc 55*ea9329ecSTony Han #define WDT_WL_RPTH_SHIFT 16 56*ea9329ecSTony Han #define WDT_WL_RPTH_MASK GENMASK_32(27, 16) 57*ea9329ecSTony Han #define WDT_WL_PERIOD_SHIFT 0 58*ea9329ecSTony Han #define WDT_WL_PERIOD_MASK GENMASK_32(11, 0) 59*ea9329ecSTony Han 60*ea9329ecSTony Han /* DWDT: Watchdog Timer Interrupt Level Register */ 61*ea9329ecSTony Han #define WDT_IL 0x10 62*ea9329ecSTony Han #define WDT_IL_LVLTH_SHIFT 0 63*ea9329ecSTony Han #define WDT_IL_LVLTH_MASK GENMASK_32(11, 0) 64*ea9329ecSTony Han 65*ea9329ecSTony Han /* DWDT: Watchdog Timer Interrupt Enable/Disable/Status/Mask Register */ 66*ea9329ecSTony Han #define WDT_IER 0x14 67*ea9329ecSTony Han #define WDT_IDR 0x18 68*ea9329ecSTony Han #define WDT_ISR 0x1c 69*ea9329ecSTony Han #define WDT_IMR 0x20 70*ea9329ecSTony Han #define WDT_NSRPTHINT BIT(4) 71*ea9329ecSTony Han #define WDT_NSPERINT BIT(3) 72*ea9329ecSTony Han #define WDT_LVLINT BIT(2) 73*ea9329ecSTony Han #define WDT_RPTHINT BIT(1) 74*ea9329ecSTony Han #define WDT_PERINT BIT(0) 75*ea9329ecSTony Han 765cbd8b3aSClément Léger /* 775cbd8b3aSClément Léger * The watchdog is clocked by a 32768Hz clock/128 and the counter is on 785cbd8b3aSClément Léger * 12 bits. 795cbd8b3aSClément Léger */ 805cbd8b3aSClément Léger #define SLOW_CLOCK_FREQ (32768) 815cbd8b3aSClément Léger #define WDT_CLOCK_FREQ (SLOW_CLOCK_FREQ / 128) 825cbd8b3aSClément Léger #define WDT_MIN_TIMEOUT 1 835cbd8b3aSClément Léger #define WDT_MAX_TIMEOUT (BIT(12) / WDT_CLOCK_FREQ) 845cbd8b3aSClément Léger 855cbd8b3aSClément Léger #define WDT_DEFAULT_TIMEOUT WDT_MAX_TIMEOUT 865cbd8b3aSClément Léger 875cbd8b3aSClément Léger /* 885cbd8b3aSClément Léger * We must wait at least 3 clocks period before accessing registers MR and CR. 895cbd8b3aSClément Léger * Ensure that we see at least 4 edges 905cbd8b3aSClément Léger */ 915cbd8b3aSClément Léger #define WDT_REG_ACCESS_UDELAY (1000000ULL / SLOW_CLOCK_FREQ * 4) 925cbd8b3aSClément Léger 935cbd8b3aSClément Léger #define SEC_TO_WDT(sec) (((sec) * WDT_CLOCK_FREQ) - 1) 945cbd8b3aSClément Léger 95*ea9329ecSTony Han #define WDT_ENABLED(mr, dis_mask) (!((mr) & (dis_mask))) 96*ea9329ecSTony Han 97*ea9329ecSTony Han enum wdt_type { 98*ea9329ecSTony Han WDT_TYPE_WDT, /* Watchdog Timer */ 99*ea9329ecSTony Han WDT_TYPE_DWDT, /* Dual Watchdog Timer */ 100*ea9329ecSTony Han }; 101*ea9329ecSTony Han 102*ea9329ecSTony Han struct wdt_compat { 103*ea9329ecSTony Han bool wdt_ps; /* Is Peripheral SHDWC Programmable Secure */ 104*ea9329ecSTony Han enum wdt_type type; /* Type of Watchdog Timer */ 105*ea9329ecSTony Han uint32_t dis_mask; /* Mask of Watchdog Disable in Mode Register */ 106*ea9329ecSTony Han }; 1075cbd8b3aSClément Léger 1085cbd8b3aSClément Léger struct atmel_wdt { 1095cbd8b3aSClément Léger struct wdt_chip chip; 110*ea9329ecSTony Han enum wdt_type type; 111*ea9329ecSTony Han uint32_t dis_mask; 1125cbd8b3aSClément Léger vaddr_t base; 1135cbd8b3aSClément Léger unsigned long rate; 1145cbd8b3aSClément Léger uint32_t mr; 1155cbd8b3aSClément Léger bool enabled; 1165cbd8b3aSClément Léger }; 1175cbd8b3aSClément Léger 1185cbd8b3aSClément Léger static void atmel_wdt_write_sleep(struct atmel_wdt *wdt, uint32_t reg, 1195cbd8b3aSClément Léger uint32_t val) 1205cbd8b3aSClément Léger { 1215cbd8b3aSClément Léger udelay(WDT_REG_ACCESS_UDELAY); 1225cbd8b3aSClément Léger 1235cbd8b3aSClément Léger io_write32(wdt->base + reg, val); 1245cbd8b3aSClément Léger } 1255cbd8b3aSClément Léger 1265cbd8b3aSClément Léger static TEE_Result atmel_wdt_settimeout(struct wdt_chip *chip, 1275cbd8b3aSClément Léger unsigned long timeout) 1285cbd8b3aSClément Léger { 1295cbd8b3aSClément Léger struct atmel_wdt *wdt = container_of(chip, struct atmel_wdt, chip); 1305cbd8b3aSClément Léger 131*ea9329ecSTony Han if (wdt->type == WDT_TYPE_WDT) { 1325cbd8b3aSClément Léger wdt->mr &= ~WDT_MR_WDV; 1335cbd8b3aSClément Léger wdt->mr |= WDT_MR_WDV_SET(SEC_TO_WDT(timeout)); 1345cbd8b3aSClément Léger 135*ea9329ecSTony Han /* WDV and WDD only be updated when the watchdog is running */ 136*ea9329ecSTony Han if (WDT_ENABLED(wdt->mr, wdt->dis_mask)) 1375cbd8b3aSClément Léger atmel_wdt_write_sleep(wdt, WDT_MR, wdt->mr); 138*ea9329ecSTony Han } else { 139*ea9329ecSTony Han io_write32(wdt->base + WDT_WL, 140*ea9329ecSTony Han SHIFT_U32(SEC_TO_WDT(timeout), WDT_WL_PERIOD_SHIFT)); 141*ea9329ecSTony Han } 1425cbd8b3aSClément Léger 1435cbd8b3aSClément Léger return TEE_SUCCESS; 1445cbd8b3aSClément Léger } 1455cbd8b3aSClément Léger 1465cbd8b3aSClément Léger static void atmel_wdt_ping(struct wdt_chip *chip) 1475cbd8b3aSClément Léger { 1485cbd8b3aSClément Léger struct atmel_wdt *wdt = container_of(chip, struct atmel_wdt, chip); 1495cbd8b3aSClément Léger 1505cbd8b3aSClément Léger atmel_wdt_write_sleep(wdt, WDT_CR, WDT_CR_KEY | WDT_CR_WDRSTT); 1515cbd8b3aSClément Léger } 1525cbd8b3aSClément Léger 1535cbd8b3aSClément Léger static void atmel_wdt_start(struct atmel_wdt *wdt) 1545cbd8b3aSClément Léger { 155*ea9329ecSTony Han wdt->mr &= ~wdt->dis_mask; 1565cbd8b3aSClément Léger atmel_wdt_write_sleep(wdt, WDT_MR, wdt->mr); 1575cbd8b3aSClément Léger } 1585cbd8b3aSClément Léger 1595cbd8b3aSClément Léger static void atmel_wdt_enable(struct wdt_chip *chip) 1605cbd8b3aSClément Léger { 1615cbd8b3aSClément Léger struct atmel_wdt *wdt = container_of(chip, struct atmel_wdt, chip); 1625cbd8b3aSClément Léger 1635cbd8b3aSClément Léger wdt->enabled = true; 1645cbd8b3aSClément Léger atmel_wdt_start(wdt); 1655cbd8b3aSClément Léger } 1665cbd8b3aSClément Léger 1675cbd8b3aSClément Léger static void atmel_wdt_stop(struct atmel_wdt *wdt) 1685cbd8b3aSClément Léger { 169*ea9329ecSTony Han wdt->mr |= wdt->dis_mask; 1705cbd8b3aSClément Léger atmel_wdt_write_sleep(wdt, WDT_MR, wdt->mr); 1715cbd8b3aSClément Léger } 1725cbd8b3aSClément Léger 1735cbd8b3aSClément Léger static void atmel_wdt_disable(struct wdt_chip *chip) 1745cbd8b3aSClément Léger { 1755cbd8b3aSClément Léger struct atmel_wdt *wdt = container_of(chip, struct atmel_wdt, chip); 1765cbd8b3aSClément Léger 1775cbd8b3aSClément Léger wdt->enabled = false; 1785cbd8b3aSClément Léger atmel_wdt_stop(wdt); 1795cbd8b3aSClément Léger } 1805cbd8b3aSClément Léger 1815cbd8b3aSClément Léger static enum itr_return atmel_wdt_itr_cb(struct itr_handler *h) 1825cbd8b3aSClément Léger { 1835cbd8b3aSClément Léger struct atmel_wdt *wdt = h->data; 184*ea9329ecSTony Han uint32_t sr = 0; 185*ea9329ecSTony Han 186*ea9329ecSTony Han if (wdt->type == WDT_TYPE_WDT) { 187*ea9329ecSTony Han sr = io_read32(wdt->base + WDT_SR); 1885cbd8b3aSClément Léger 1895cbd8b3aSClément Léger if (sr & WDT_SR_DUNF) 190*ea9329ecSTony Han DMSG("Watchdog Underflow"); 1915cbd8b3aSClément Léger if (sr & WDT_SR_DERR) 192*ea9329ecSTony Han DMSG("Watchdog Error"); 193*ea9329ecSTony Han } else if (wdt->type == WDT_TYPE_DWDT) { 194*ea9329ecSTony Han sr = io_read32(wdt->base + WDT_ISR); 195*ea9329ecSTony Han 196*ea9329ecSTony Han if (sr & WDT_NSRPTHINT) 197*ea9329ecSTony Han DMSG("NS Watchdog Repeat Threshold Interrupt"); 198*ea9329ecSTony Han if (sr & WDT_NSPERINT) 199*ea9329ecSTony Han DMSG("NS Watchdog Period Interrupt"); 200*ea9329ecSTony Han if (sr & WDT_LVLINT) 201*ea9329ecSTony Han DMSG("Watchdog Level Threshold Interrupt"); 202*ea9329ecSTony Han if (sr & WDT_RPTHINT) 203*ea9329ecSTony Han DMSG("Watchdog Repeat Threshold Interrupt"); 204*ea9329ecSTony Han if (sr & WDT_PERINT) 205*ea9329ecSTony Han DMSG("Watchdog Period Interrupt"); 206*ea9329ecSTony Han } 2075cbd8b3aSClément Léger 2085cbd8b3aSClément Léger panic("Watchdog interrupt"); 2095cbd8b3aSClément Léger 2105cbd8b3aSClément Léger return ITRR_HANDLED; 2115cbd8b3aSClément Léger } 2125cbd8b3aSClément Léger 2135cbd8b3aSClément Léger static TEE_Result atmel_wdt_init(struct wdt_chip *chip __unused, 2145cbd8b3aSClément Léger unsigned long *min_timeout, 2155cbd8b3aSClément Léger unsigned long *max_timeout) 2165cbd8b3aSClément Léger { 2175cbd8b3aSClément Léger *min_timeout = WDT_MIN_TIMEOUT; 2185cbd8b3aSClément Léger *max_timeout = WDT_MAX_TIMEOUT; 2195cbd8b3aSClément Léger 2205cbd8b3aSClément Léger return TEE_SUCCESS; 2215cbd8b3aSClément Léger } 2225cbd8b3aSClément Léger 2235cbd8b3aSClément Léger static const struct wdt_ops atmel_wdt_ops = { 2245cbd8b3aSClément Léger .init = atmel_wdt_init, 2255cbd8b3aSClément Léger .start = atmel_wdt_enable, 2265cbd8b3aSClément Léger .stop = atmel_wdt_disable, 2275cbd8b3aSClément Léger .ping = atmel_wdt_ping, 2285cbd8b3aSClément Léger .set_timeout = atmel_wdt_settimeout, 2295cbd8b3aSClément Léger }; 2305cbd8b3aSClément Léger 2315cbd8b3aSClément Léger static void atmel_wdt_init_hw(struct atmel_wdt *wdt) 2325cbd8b3aSClément Léger { 2335cbd8b3aSClément Léger uint32_t mr = 0; 2345cbd8b3aSClément Léger 2355cbd8b3aSClément Léger /* 2365cbd8b3aSClément Léger * If we are resuming, we disabled the watchdog on suspend but the 2375cbd8b3aSClément Léger * bootloader might have enabled the watchdog. If so, disable it 2385cbd8b3aSClément Léger * properly. 2395cbd8b3aSClément Léger */ 240*ea9329ecSTony Han if (!WDT_ENABLED(wdt->mr, wdt->dis_mask)) { 2415cbd8b3aSClément Léger mr = io_read32(wdt->base + WDT_MR); 242*ea9329ecSTony Han if (WDT_ENABLED(mr, wdt->dis_mask)) 243*ea9329ecSTony Han io_write32(wdt->base + WDT_MR, mr | wdt->dis_mask); 2445cbd8b3aSClément Léger } 2455cbd8b3aSClément Léger 246*ea9329ecSTony Han if (wdt->type == WDT_TYPE_WDT) { 2475cbd8b3aSClément Léger /* Enable interrupt, and disable watchdog in debug and idle */ 2485cbd8b3aSClément Léger wdt->mr |= WDT_MR_WDFIEN | WDT_MR_WDDBGHLT | WDT_MR_WDIDLEHLT; 249d5d94b35SClément Léger /* Enable watchdog reset */ 250d5d94b35SClément Léger wdt->mr |= WDT_MR_WDRSTEN; 2515cbd8b3aSClément Léger wdt->mr |= WDT_MR_WDD_SET(SEC_TO_WDT(WDT_MAX_TIMEOUT)); 2525cbd8b3aSClément Léger wdt->mr |= WDT_MR_WDV_SET(SEC_TO_WDT(WDT_DEFAULT_TIMEOUT)); 253*ea9329ecSTony Han } else if (wdt->type == WDT_TYPE_DWDT) { 254*ea9329ecSTony Han /* Enable interrupt */ 255*ea9329ecSTony Han io_write32(wdt->base + WDT_ISR, WDT_PERINT); 256*ea9329ecSTony Han /* Disable watchdog in debug and idle */ 257*ea9329ecSTony Han wdt->mr |= WDT_MR_WDDBGHLT | WDT_MR_WDIDLEHLT; 258*ea9329ecSTony Han /* Enable watchdog period reset */ 259*ea9329ecSTony Han wdt->mr |= WDT_MR_PERIODRST; 260*ea9329ecSTony Han io_write32(wdt->base + WDT_WL, 261*ea9329ecSTony Han SHIFT_U32(SEC_TO_WDT(WDT_DEFAULT_TIMEOUT), 262*ea9329ecSTony Han WDT_WL_PERIOD_SHIFT)); 263*ea9329ecSTony Han } else { 264*ea9329ecSTony Han panic("Invalid Watchdog"); 265*ea9329ecSTony Han } 2665cbd8b3aSClément Léger 2675cbd8b3aSClément Léger /* 2685cbd8b3aSClément Léger * If the watchdog was enabled, write the configuration which will ping 2695cbd8b3aSClément Léger * the watchdog. 2705cbd8b3aSClément Léger */ 271*ea9329ecSTony Han if (WDT_ENABLED(wdt->mr, wdt->dis_mask)) 2725cbd8b3aSClément Léger io_write32(wdt->base + WDT_MR, wdt->mr); 2735cbd8b3aSClément Léger } 2745cbd8b3aSClément Léger 2755cbd8b3aSClément Léger #ifdef CFG_PM_ARM32 2765cbd8b3aSClément Léger static TEE_Result atmel_wdt_pm(enum pm_op op, uint32_t pm_hint __unused, 2775cbd8b3aSClément Léger const struct pm_callback_handle *hdl) 2785cbd8b3aSClément Léger { 2795cbd8b3aSClément Léger struct atmel_wdt *wdt = hdl->handle; 2805cbd8b3aSClément Léger 2815cbd8b3aSClément Léger switch (op) { 2825cbd8b3aSClément Léger case PM_OP_RESUME: 2835cbd8b3aSClément Léger atmel_wdt_init_hw(wdt); 2845cbd8b3aSClément Léger if (wdt->enabled) 2855cbd8b3aSClément Léger atmel_wdt_start(wdt); 2865cbd8b3aSClément Léger break; 2875cbd8b3aSClément Léger case PM_OP_SUSPEND: 2885cbd8b3aSClément Léger if (wdt->enabled) 2895cbd8b3aSClément Léger atmel_wdt_stop(wdt); 2905cbd8b3aSClément Léger break; 2915cbd8b3aSClément Léger default: 2925cbd8b3aSClément Léger panic("Invalid PM operation"); 2935cbd8b3aSClément Léger } 2945cbd8b3aSClément Léger 2955cbd8b3aSClément Léger return TEE_SUCCESS; 2965cbd8b3aSClément Léger } 2975cbd8b3aSClément Léger 2985cbd8b3aSClément Léger static void atmel_wdt_register_pm(struct atmel_wdt *wdt) 2995cbd8b3aSClément Léger { 3005cbd8b3aSClément Léger register_pm_driver_cb(atmel_wdt_pm, wdt, "atmel_wdt"); 3015cbd8b3aSClément Léger } 3025cbd8b3aSClément Léger #else 3035cbd8b3aSClément Léger static void atmel_wdt_register_pm(struct atmel_wdt *wdt __unused) 3045cbd8b3aSClément Léger { 3055cbd8b3aSClément Léger } 3065cbd8b3aSClément Léger #endif 3075cbd8b3aSClément Léger 3085cbd8b3aSClément Léger static TEE_Result wdt_node_probe(const void *fdt, int node, 309*ea9329ecSTony Han const void *compat_data) 3105cbd8b3aSClément Léger { 311*ea9329ecSTony Han const struct wdt_compat *compat = compat_data; 3125cbd8b3aSClément Léger size_t size = 0; 3135cbd8b3aSClément Léger struct atmel_wdt *wdt; 3145cbd8b3aSClément Léger uint32_t irq_type = 0; 3155cbd8b3aSClément Léger uint32_t irq_prio = 0; 3165cbd8b3aSClément Léger int it = DT_INFO_INVALID_INTERRUPT; 317c64c658bSEtienne Carriere struct itr_handler *it_hdlr = NULL; 318c64c658bSEtienne Carriere TEE_Result res = TEE_ERROR_GENERIC; 3195cbd8b3aSClément Léger 320f354a5d8SGatien Chevallier if (fdt_get_status(fdt, node) != DT_STATUS_OK_SEC) 3215cbd8b3aSClément Léger return TEE_ERROR_BAD_PARAMETERS; 3225cbd8b3aSClément Léger 323*ea9329ecSTony Han if (compat->wdt_ps) 3245cbd8b3aSClément Léger matrix_configure_periph_secure(AT91C_ID_WDT); 3255cbd8b3aSClément Léger 3265cbd8b3aSClément Léger wdt = calloc(1, sizeof(*wdt)); 3275cbd8b3aSClément Léger if (!wdt) 3285cbd8b3aSClément Léger return TEE_ERROR_OUT_OF_MEMORY; 3295cbd8b3aSClément Léger 3305cbd8b3aSClément Léger wdt->chip.ops = &atmel_wdt_ops; 331*ea9329ecSTony Han wdt->type = compat->type; 332*ea9329ecSTony Han wdt->dis_mask = compat->dis_mask; 3335cbd8b3aSClément Léger 3345cbd8b3aSClément Léger it = dt_get_irq_type_prio(fdt, node, &irq_type, &irq_prio); 3355cbd8b3aSClément Léger if (it == DT_INFO_INVALID_INTERRUPT) 336c64c658bSEtienne Carriere goto err_free; 3375cbd8b3aSClément Léger 338c64c658bSEtienne Carriere res = interrupt_alloc_add_conf_handler(interrupt_get_main_chip(), 339c64c658bSEtienne Carriere it, atmel_wdt_itr_cb, 0, wdt, 340c64c658bSEtienne Carriere irq_type, irq_prio, &it_hdlr); 341c64c658bSEtienne Carriere if (res) 342c64c658bSEtienne Carriere goto err_free; 3435cbd8b3aSClément Léger 344a5d5bbc8SVesa Jääskeläinen if (dt_map_dev(fdt, node, &wdt->base, &size, DT_MAP_AUTO) < 0) 345c64c658bSEtienne Carriere goto err_remove_handler; 3465cbd8b3aSClément Léger 3475cbd8b3aSClément Léger /* Get current state of the watchdog */ 348*ea9329ecSTony Han wdt->mr = io_read32(wdt->base + WDT_MR) & wdt->dis_mask; 3495cbd8b3aSClément Léger 3505cbd8b3aSClément Léger atmel_wdt_init_hw(wdt); 351c64c658bSEtienne Carriere interrupt_enable(it_hdlr->chip, it_hdlr->it); 352c64c658bSEtienne Carriere 353c64c658bSEtienne Carriere res = watchdog_register(&wdt->chip); 354c64c658bSEtienne Carriere if (res) 355c64c658bSEtienne Carriere goto err_disable_unmap; 356c64c658bSEtienne Carriere 3575cbd8b3aSClément Léger atmel_wdt_register_pm(wdt); 3585cbd8b3aSClément Léger 359c64c658bSEtienne Carriere return TEE_SUCCESS; 3605cbd8b3aSClément Léger 361c64c658bSEtienne Carriere err_disable_unmap: 362c64c658bSEtienne Carriere interrupt_disable(it_hdlr->chip, it_hdlr->it); 363c64c658bSEtienne Carriere core_mmu_remove_mapping(MEM_AREA_IO_SEC, (void *)wdt->base, size); 364c64c658bSEtienne Carriere err_remove_handler: 365c64c658bSEtienne Carriere interrupt_remove_free_handler(it_hdlr); 366c64c658bSEtienne Carriere err_free: 3675cbd8b3aSClément Léger free(wdt); 3685cbd8b3aSClément Léger 3695cbd8b3aSClément Léger return TEE_ERROR_GENERIC; 3705cbd8b3aSClément Léger } 3715cbd8b3aSClément Léger 372*ea9329ecSTony Han static const struct wdt_compat sama5d2_compat = { 373*ea9329ecSTony Han .wdt_ps = true, 374*ea9329ecSTony Han .type = WDT_TYPE_WDT, 375*ea9329ecSTony Han .dis_mask = WDT_MR_WDDIS, 376*ea9329ecSTony Han }; 377*ea9329ecSTony Han 378*ea9329ecSTony Han static const struct wdt_compat sama7g5_compat = { 379*ea9329ecSTony Han .wdt_ps = false, 380*ea9329ecSTony Han .type = WDT_TYPE_DWDT, 381*ea9329ecSTony Han .dis_mask = WDT_MR_WDDIS_DWDT, 382*ea9329ecSTony Han }; 383*ea9329ecSTony Han 3845cbd8b3aSClément Léger static const struct dt_device_match atmel_wdt_match_table[] = { 385*ea9329ecSTony Han { 386*ea9329ecSTony Han .compatible = "atmel,sama5d4-wdt", 387*ea9329ecSTony Han .compat_data = &sama5d2_compat, 388*ea9329ecSTony Han }, 389*ea9329ecSTony Han { 390*ea9329ecSTony Han .compatible = "microchip,sama7g5-wdt", 391*ea9329ecSTony Han .compat_data = &sama7g5_compat, 392*ea9329ecSTony Han }, 3935cbd8b3aSClément Léger { } 3945cbd8b3aSClément Léger }; 3955cbd8b3aSClément Léger 3965cbd8b3aSClément Léger DEFINE_DT_DRIVER(atmel_wdt_dt_driver) = { 3975cbd8b3aSClément Léger .name = "atmel_wdt", 3985cbd8b3aSClément Léger .type = DT_DRIVER_NOTYPE, 3995cbd8b3aSClément Léger .match_table = atmel_wdt_match_table, 4005cbd8b3aSClément Léger .probe = wdt_node_probe, 4015cbd8b3aSClément Léger }; 402