1 // SPDX-License-Identifier: BSD-2-Clause 2 /* 3 * Copyright 2022 Microchip 4 */ 5 6 #include <assert.h> 7 #include <drivers/clk.h> 8 #include <drivers/clk_dt.h> 9 #include <drivers/wdt.h> 10 #include <io.h> 11 #include <kernel/delay.h> 12 #include <kernel/dt.h> 13 #include <kernel/dt_driver.h> 14 #include <kernel/interrupt.h> 15 #include <kernel/pm.h> 16 #include <matrix.h> 17 #include <mm/core_mmu.h> 18 #include <sama5d2.h> 19 #include <tee_api_types.h> 20 21 #define WDT_CR 0x0 22 #define WDT_CR_KEY SHIFT_U32(0xA5, 24) 23 #define WDT_CR_WDRSTT BIT(0) 24 25 #define WDT_MR 0x4 26 #define WDT_MR_WDV GENMASK_32(11, 0) 27 #define WDT_MR_WDV_SET(val) ((val) & WDT_MR_WDV) 28 #define WDT_MR_WDFIEN BIT(12) 29 #define WDT_MR_WDRSTEN BIT(13) 30 #define WDT_MR_WDDIS BIT(15) 31 #define WDT_MR_WDD_SHIFT 16 32 #define WDT_MR_WDD_MASK GENMASK_32(11, 0) 33 #define WDT_MR_WDD SHIFT_U32(WDT_MR_WDD_MASK, WDT_MR_WDD_SHIFT) 34 #define WDT_MR_WDD_SET(val) \ 35 SHIFT_U32(((val) & WDT_MR_WDD_MASK), WDT_MR_WDD_SHIFT) 36 #define WDT_MR_WDDBGHLT BIT(28) 37 #define WDT_MR_WDIDLEHLT BIT(29) 38 39 #define WDT_SR 0x8 40 #define WDT_SR_DUNF BIT(0) 41 #define WDT_SR_DERR BIT(1) 42 43 /* 44 * The watchdog is clocked by a 32768Hz clock/128 and the counter is on 45 * 12 bits. 46 */ 47 #define SLOW_CLOCK_FREQ (32768) 48 #define WDT_CLOCK_FREQ (SLOW_CLOCK_FREQ / 128) 49 #define WDT_MIN_TIMEOUT 1 50 #define WDT_MAX_TIMEOUT (BIT(12) / WDT_CLOCK_FREQ) 51 52 #define WDT_DEFAULT_TIMEOUT WDT_MAX_TIMEOUT 53 54 /* 55 * We must wait at least 3 clocks period before accessing registers MR and CR. 56 * Ensure that we see at least 4 edges 57 */ 58 #define WDT_REG_ACCESS_UDELAY (1000000ULL / SLOW_CLOCK_FREQ * 4) 59 60 #define SEC_TO_WDT(sec) (((sec) * WDT_CLOCK_FREQ) - 1) 61 62 #define WDT_ENABLED(mr) (!((mr) & WDT_MR_WDDIS)) 63 64 struct atmel_wdt { 65 struct wdt_chip chip; 66 vaddr_t base; 67 unsigned long rate; 68 uint32_t mr; 69 bool enabled; 70 }; 71 72 static void atmel_wdt_write_sleep(struct atmel_wdt *wdt, uint32_t reg, 73 uint32_t val) 74 { 75 udelay(WDT_REG_ACCESS_UDELAY); 76 77 io_write32(wdt->base + reg, val); 78 } 79 80 static TEE_Result atmel_wdt_settimeout(struct wdt_chip *chip, 81 unsigned long timeout) 82 { 83 struct atmel_wdt *wdt = container_of(chip, struct atmel_wdt, chip); 84 85 wdt->mr &= ~WDT_MR_WDV; 86 wdt->mr |= WDT_MR_WDV_SET(SEC_TO_WDT(timeout)); 87 88 /* WDV and WDD can only be updated when the watchdog is running */ 89 if (WDT_ENABLED(wdt->mr)) 90 atmel_wdt_write_sleep(wdt, WDT_MR, wdt->mr); 91 92 return TEE_SUCCESS; 93 } 94 95 static void atmel_wdt_ping(struct wdt_chip *chip) 96 { 97 struct atmel_wdt *wdt = container_of(chip, struct atmel_wdt, chip); 98 99 atmel_wdt_write_sleep(wdt, WDT_CR, WDT_CR_KEY | WDT_CR_WDRSTT); 100 } 101 102 static void atmel_wdt_start(struct atmel_wdt *wdt) 103 { 104 wdt->mr &= ~WDT_MR_WDDIS; 105 atmel_wdt_write_sleep(wdt, WDT_MR, wdt->mr); 106 } 107 108 static void atmel_wdt_enable(struct wdt_chip *chip) 109 { 110 struct atmel_wdt *wdt = container_of(chip, struct atmel_wdt, chip); 111 112 wdt->enabled = true; 113 atmel_wdt_start(wdt); 114 } 115 116 static void atmel_wdt_stop(struct atmel_wdt *wdt) 117 { 118 wdt->mr |= WDT_MR_WDDIS; 119 atmel_wdt_write_sleep(wdt, WDT_MR, wdt->mr); 120 } 121 122 static void atmel_wdt_disable(struct wdt_chip *chip) 123 { 124 struct atmel_wdt *wdt = container_of(chip, struct atmel_wdt, chip); 125 126 wdt->enabled = false; 127 atmel_wdt_stop(wdt); 128 } 129 130 static enum itr_return atmel_wdt_itr_cb(struct itr_handler *h) 131 { 132 struct atmel_wdt *wdt = h->data; 133 uint32_t sr = io_read32(wdt->base + WDT_SR); 134 135 if (sr & WDT_SR_DUNF) 136 DMSG("Watchdog Underflow !"); 137 if (sr & WDT_SR_DERR) 138 DMSG("Watchdog Error !"); 139 140 panic("Watchdog interrupt"); 141 142 return ITRR_HANDLED; 143 } 144 145 static TEE_Result atmel_wdt_init(struct wdt_chip *chip __unused, 146 unsigned long *min_timeout, 147 unsigned long *max_timeout) 148 { 149 *min_timeout = WDT_MIN_TIMEOUT; 150 *max_timeout = WDT_MAX_TIMEOUT; 151 152 return TEE_SUCCESS; 153 } 154 155 static const struct wdt_ops atmel_wdt_ops = { 156 .init = atmel_wdt_init, 157 .start = atmel_wdt_enable, 158 .stop = atmel_wdt_disable, 159 .ping = atmel_wdt_ping, 160 .set_timeout = atmel_wdt_settimeout, 161 }; 162 163 static void atmel_wdt_init_hw(struct atmel_wdt *wdt) 164 { 165 uint32_t mr = 0; 166 167 /* 168 * If we are resuming, we disabled the watchdog on suspend but the 169 * bootloader might have enabled the watchdog. If so, disable it 170 * properly. 171 */ 172 if (!WDT_ENABLED(wdt->mr)) { 173 mr = io_read32(wdt->base + WDT_MR); 174 if (WDT_ENABLED(mr)) 175 io_write32(wdt->base + WDT_MR, mr | WDT_MR_WDDIS); 176 } 177 178 /* Enable interrupt, and disable watchdog in debug and idle */ 179 wdt->mr |= WDT_MR_WDFIEN | WDT_MR_WDDBGHLT | WDT_MR_WDIDLEHLT; 180 /* Enable watchdog reset */ 181 wdt->mr |= WDT_MR_WDRSTEN; 182 wdt->mr |= WDT_MR_WDD_SET(SEC_TO_WDT(WDT_MAX_TIMEOUT)); 183 wdt->mr |= WDT_MR_WDV_SET(SEC_TO_WDT(WDT_DEFAULT_TIMEOUT)); 184 185 /* 186 * If the watchdog was enabled, write the configuration which will ping 187 * the watchdog. 188 */ 189 if (WDT_ENABLED(wdt->mr)) 190 io_write32(wdt->base + WDT_MR, wdt->mr); 191 } 192 193 #ifdef CFG_PM_ARM32 194 static TEE_Result atmel_wdt_pm(enum pm_op op, uint32_t pm_hint __unused, 195 const struct pm_callback_handle *hdl) 196 { 197 struct atmel_wdt *wdt = hdl->handle; 198 199 switch (op) { 200 case PM_OP_RESUME: 201 atmel_wdt_init_hw(wdt); 202 if (wdt->enabled) 203 atmel_wdt_start(wdt); 204 break; 205 case PM_OP_SUSPEND: 206 if (wdt->enabled) 207 atmel_wdt_stop(wdt); 208 break; 209 default: 210 panic("Invalid PM operation"); 211 } 212 213 return TEE_SUCCESS; 214 } 215 216 static void atmel_wdt_register_pm(struct atmel_wdt *wdt) 217 { 218 register_pm_driver_cb(atmel_wdt_pm, wdt, "atmel_wdt"); 219 } 220 #else 221 static void atmel_wdt_register_pm(struct atmel_wdt *wdt __unused) 222 { 223 } 224 #endif 225 226 static TEE_Result wdt_node_probe(const void *fdt, int node, 227 const void *compat_data __unused) 228 { 229 size_t size = 0; 230 struct atmel_wdt *wdt; 231 uint32_t irq_type = 0; 232 uint32_t irq_prio = 0; 233 int it = DT_INFO_INVALID_INTERRUPT; 234 struct itr_handler *it_hdlr = NULL; 235 TEE_Result res = TEE_ERROR_GENERIC; 236 237 if (fdt_get_status(fdt, node) != DT_STATUS_OK_SEC) 238 return TEE_ERROR_BAD_PARAMETERS; 239 240 matrix_configure_periph_secure(AT91C_ID_WDT); 241 242 wdt = calloc(1, sizeof(*wdt)); 243 if (!wdt) 244 return TEE_ERROR_OUT_OF_MEMORY; 245 246 wdt->chip.ops = &atmel_wdt_ops; 247 248 it = dt_get_irq_type_prio(fdt, node, &irq_type, &irq_prio); 249 if (it == DT_INFO_INVALID_INTERRUPT) 250 goto err_free; 251 252 res = interrupt_alloc_add_conf_handler(interrupt_get_main_chip(), 253 it, atmel_wdt_itr_cb, 0, wdt, 254 irq_type, irq_prio, &it_hdlr); 255 if (res) 256 goto err_free; 257 258 if (dt_map_dev(fdt, node, &wdt->base, &size, DT_MAP_AUTO) < 0) 259 goto err_remove_handler; 260 261 /* Get current state of the watchdog */ 262 wdt->mr = io_read32(wdt->base + WDT_MR) & WDT_MR_WDDIS; 263 264 atmel_wdt_init_hw(wdt); 265 interrupt_enable(it_hdlr->chip, it_hdlr->it); 266 267 res = watchdog_register(&wdt->chip); 268 if (res) 269 goto err_disable_unmap; 270 271 atmel_wdt_register_pm(wdt); 272 273 return TEE_SUCCESS; 274 275 err_disable_unmap: 276 interrupt_disable(it_hdlr->chip, it_hdlr->it); 277 core_mmu_remove_mapping(MEM_AREA_IO_SEC, (void *)wdt->base, size); 278 err_remove_handler: 279 interrupt_remove_free_handler(it_hdlr); 280 err_free: 281 free(wdt); 282 283 return TEE_ERROR_GENERIC; 284 } 285 286 static const struct dt_device_match atmel_wdt_match_table[] = { 287 { .compatible = "atmel,sama5d4-wdt" }, 288 { } 289 }; 290 291 DEFINE_DT_DRIVER(atmel_wdt_dt_driver) = { 292 .name = "atmel_wdt", 293 .type = DT_DRIVER_NOTYPE, 294 .match_table = atmel_wdt_match_table, 295 .probe = wdt_node_probe, 296 }; 297