1 // SPDX-License-Identifier: BSD-2-Clause 2 /* 3 * Copyright 2022 Microchip 4 */ 5 6 #include <assert.h> 7 #include <drivers/wdt.h> 8 #include <io.h> 9 #include <kernel/delay.h> 10 #include <kernel/dt.h> 11 #include <kernel/dt_driver.h> 12 #include <kernel/interrupt.h> 13 #include <kernel/panic.h> 14 #include <kernel/pm.h> 15 #include <matrix.h> 16 #include <mm/core_mmu.h> 17 #include <tee_api_defines.h> 18 19 #define WDT_CR 0x0 20 #define WDT_CR_KEY SHIFT_U32(0xA5, 24) 21 #define WDT_CR_WDRSTT BIT(0) 22 23 #define WDT_MR 0x4 24 #define WDT_MR_WDV GENMASK_32(11, 0) 25 #define WDT_MR_WDV_SET(val) ((val) & WDT_MR_WDV) 26 #define WDT_MR_WDFIEN BIT(12) 27 #define WDT_MR_WDRSTEN BIT(13) 28 #define WDT_MR_WDDIS BIT(15) /* Watchdog Disable of WDT on bit 15 */ 29 #define WDT_MR_WDDIS_DWDT BIT(12) /* Watchdog Disable of DWDT on bit 12 */ 30 #define WDT_MR_WDD_SHIFT 16 31 #define WDT_MR_WDD_MASK GENMASK_32(11, 0) 32 #define WDT_MR_WDD SHIFT_U32(WDT_MR_WDD_MASK, WDT_MR_WDD_SHIFT) 33 #define WDT_MR_WDD_SET(val) \ 34 SHIFT_U32(((val) & WDT_MR_WDD_MASK), WDT_MR_WDD_SHIFT) 35 #define WDT_MR_WDDBGHLT BIT(28) 36 #define WDT_MR_WDIDLEHLT BIT(29) 37 38 #define WDT_SR 0x8 39 #define WDT_SR_DUNF BIT(0) 40 #define WDT_SR_DERR BIT(1) 41 42 /* DWDT: Watchdog Timer Mode Register */ 43 #define WDT_MR_PERIODRST BIT(4) 44 #define WDT_MR_RPTHRST BIT(5) 45 46 /* DWDT: Watchdog Timer Value Register (Read-only) */ 47 #define WDT_VR 0x8 48 #define WDT_VR_COUNTER_SHIFT 0 49 #define WDT_VR_COUNTER_MASK GENMASK_32(11, 0) 50 51 /* DWDT: Watchdog Timer Window Level Register */ 52 #define WDT_WL 0xc 53 #define WDT_WL_RPTH_SHIFT 16 54 #define WDT_WL_RPTH_MASK GENMASK_32(27, 16) 55 #define WDT_WL_PERIOD_SHIFT 0 56 #define WDT_WL_PERIOD_MASK GENMASK_32(11, 0) 57 58 /* DWDT: Watchdog Timer Interrupt Level Register */ 59 #define WDT_IL 0x10 60 #define WDT_IL_LVLTH_SHIFT 0 61 #define WDT_IL_LVLTH_MASK GENMASK_32(11, 0) 62 63 /* DWDT: Watchdog Timer Interrupt Enable/Disable/Status/Mask Register */ 64 #define WDT_IER 0x14 65 #define WDT_IDR 0x18 66 #define WDT_ISR 0x1c 67 #define WDT_IMR 0x20 68 #define WDT_NSRPTHINT BIT(4) 69 #define WDT_NSPERINT BIT(3) 70 #define WDT_LVLINT BIT(2) 71 #define WDT_RPTHINT BIT(1) 72 #define WDT_PERINT BIT(0) 73 74 /* 75 * The watchdog is clocked by a 32768Hz clock/128 and the counter is on 76 * 12 bits. 77 */ 78 #define SLOW_CLOCK_FREQ (32768) 79 #define WDT_CLOCK_FREQ (SLOW_CLOCK_FREQ / 128) 80 #define WDT_MIN_TIMEOUT 1 81 #define WDT_MAX_TIMEOUT (BIT(12) / WDT_CLOCK_FREQ) 82 83 #define WDT_DEFAULT_TIMEOUT WDT_MAX_TIMEOUT 84 85 /* 86 * We must wait at least 3 clocks period before accessing registers MR and CR. 87 * Ensure that we see at least 4 edges 88 */ 89 #define WDT_REG_ACCESS_UDELAY (1000000ULL / SLOW_CLOCK_FREQ * 4) 90 91 #define SEC_TO_WDT(sec) (((sec) * WDT_CLOCK_FREQ) - 1) 92 93 #define WDT_ENABLED(mr, dis_mask) (!((mr) & (dis_mask))) 94 95 enum wdt_type { 96 WDT_TYPE_WDT, /* Watchdog Timer */ 97 WDT_TYPE_DWDT, /* Dual Watchdog Timer */ 98 }; 99 100 struct wdt_compat { 101 bool wdt_ps; /* Is Peripheral SHDWC Programmable Secure */ 102 enum wdt_type type; /* Type of Watchdog Timer */ 103 uint32_t dis_mask; /* Mask of Watchdog Disable in Mode Register */ 104 }; 105 106 struct atmel_wdt { 107 struct wdt_chip chip; 108 enum wdt_type type; 109 uint32_t dis_mask; 110 vaddr_t base; 111 uint32_t mr; 112 bool enabled; 113 }; 114 115 static void atmel_wdt_write_sleep(struct atmel_wdt *wdt, uint32_t reg, 116 uint32_t val) 117 { 118 udelay(WDT_REG_ACCESS_UDELAY); 119 120 io_write32(wdt->base + reg, val); 121 } 122 123 static TEE_Result atmel_wdt_settimeout(struct wdt_chip *chip, 124 unsigned long timeout) 125 { 126 struct atmel_wdt *wdt = container_of(chip, struct atmel_wdt, chip); 127 128 if (wdt->type == WDT_TYPE_WDT) { 129 wdt->mr &= ~WDT_MR_WDV; 130 wdt->mr |= WDT_MR_WDV_SET(SEC_TO_WDT(timeout)); 131 132 /* WDV and WDD only be updated when the watchdog is running */ 133 if (WDT_ENABLED(wdt->mr, wdt->dis_mask)) 134 atmel_wdt_write_sleep(wdt, WDT_MR, wdt->mr); 135 } else { 136 io_write32(wdt->base + WDT_WL, 137 SHIFT_U32(SEC_TO_WDT(timeout), WDT_WL_PERIOD_SHIFT)); 138 } 139 140 return TEE_SUCCESS; 141 } 142 143 static void atmel_wdt_ping(struct wdt_chip *chip) 144 { 145 struct atmel_wdt *wdt = container_of(chip, struct atmel_wdt, chip); 146 147 atmel_wdt_write_sleep(wdt, WDT_CR, WDT_CR_KEY | WDT_CR_WDRSTT); 148 } 149 150 static void atmel_wdt_start(struct atmel_wdt *wdt) 151 { 152 wdt->mr &= ~wdt->dis_mask; 153 atmel_wdt_write_sleep(wdt, WDT_MR, wdt->mr); 154 } 155 156 static void atmel_wdt_enable(struct wdt_chip *chip) 157 { 158 struct atmel_wdt *wdt = container_of(chip, struct atmel_wdt, chip); 159 160 wdt->enabled = true; 161 atmel_wdt_start(wdt); 162 } 163 164 static void atmel_wdt_stop(struct atmel_wdt *wdt) 165 { 166 wdt->mr |= wdt->dis_mask; 167 atmel_wdt_write_sleep(wdt, WDT_MR, wdt->mr); 168 } 169 170 static void atmel_wdt_disable(struct wdt_chip *chip) 171 { 172 struct atmel_wdt *wdt = container_of(chip, struct atmel_wdt, chip); 173 174 wdt->enabled = false; 175 atmel_wdt_stop(wdt); 176 } 177 178 static enum itr_return atmel_wdt_itr_cb(struct itr_handler *h) 179 { 180 struct atmel_wdt *wdt = h->data; 181 uint32_t sr = 0; 182 183 if (wdt->type == WDT_TYPE_WDT) { 184 sr = io_read32(wdt->base + WDT_SR); 185 186 if (sr & WDT_SR_DUNF) 187 DMSG("Watchdog Underflow"); 188 if (sr & WDT_SR_DERR) 189 DMSG("Watchdog Error"); 190 } else if (wdt->type == WDT_TYPE_DWDT) { 191 sr = io_read32(wdt->base + WDT_ISR); 192 193 if (sr & WDT_NSRPTHINT) 194 DMSG("NS Watchdog Repeat Threshold Interrupt"); 195 if (sr & WDT_NSPERINT) 196 DMSG("NS Watchdog Period Interrupt"); 197 if (sr & WDT_LVLINT) 198 DMSG("Watchdog Level Threshold Interrupt"); 199 if (sr & WDT_RPTHINT) 200 DMSG("Watchdog Repeat Threshold Interrupt"); 201 if (sr & WDT_PERINT) 202 DMSG("Watchdog Period Interrupt"); 203 } 204 205 panic("Watchdog interrupt"); 206 207 return ITRR_HANDLED; 208 } 209 210 static TEE_Result atmel_wdt_init(struct wdt_chip *chip __unused, 211 unsigned long *min_timeout, 212 unsigned long *max_timeout) 213 { 214 *min_timeout = WDT_MIN_TIMEOUT; 215 *max_timeout = WDT_MAX_TIMEOUT; 216 217 return TEE_SUCCESS; 218 } 219 220 static const struct wdt_ops atmel_wdt_ops = { 221 .init = atmel_wdt_init, 222 .start = atmel_wdt_enable, 223 .stop = atmel_wdt_disable, 224 .ping = atmel_wdt_ping, 225 .set_timeout = atmel_wdt_settimeout, 226 }; 227 228 static void atmel_wdt_init_hw(struct atmel_wdt *wdt) 229 { 230 uint32_t mr = 0; 231 232 /* 233 * If we are resuming, we disabled the watchdog on suspend but the 234 * bootloader might have enabled the watchdog. If so, disable it 235 * properly. 236 */ 237 if (!WDT_ENABLED(wdt->mr, wdt->dis_mask)) { 238 mr = io_read32(wdt->base + WDT_MR); 239 if (WDT_ENABLED(mr, wdt->dis_mask)) 240 io_write32(wdt->base + WDT_MR, mr | wdt->dis_mask); 241 } 242 243 if (wdt->type == WDT_TYPE_WDT) { 244 /* Enable interrupt, and disable watchdog in debug and idle */ 245 wdt->mr |= WDT_MR_WDFIEN | WDT_MR_WDDBGHLT | WDT_MR_WDIDLEHLT; 246 /* Enable watchdog reset */ 247 wdt->mr |= WDT_MR_WDRSTEN; 248 wdt->mr |= WDT_MR_WDD_SET(SEC_TO_WDT(WDT_MAX_TIMEOUT)); 249 wdt->mr |= WDT_MR_WDV_SET(SEC_TO_WDT(WDT_DEFAULT_TIMEOUT)); 250 } else if (wdt->type == WDT_TYPE_DWDT) { 251 /* Enable interrupt */ 252 io_write32(wdt->base + WDT_ISR, WDT_PERINT); 253 /* Disable watchdog in debug and idle */ 254 wdt->mr |= WDT_MR_WDDBGHLT | WDT_MR_WDIDLEHLT; 255 /* Enable watchdog period reset */ 256 wdt->mr |= WDT_MR_PERIODRST; 257 io_write32(wdt->base + WDT_WL, 258 SHIFT_U32(SEC_TO_WDT(WDT_DEFAULT_TIMEOUT), 259 WDT_WL_PERIOD_SHIFT)); 260 } else { 261 panic("Invalid Watchdog"); 262 } 263 264 /* 265 * If the watchdog was enabled, write the configuration which will ping 266 * the watchdog. 267 */ 268 if (WDT_ENABLED(wdt->mr, wdt->dis_mask)) 269 io_write32(wdt->base + WDT_MR, wdt->mr); 270 } 271 272 #ifdef CFG_PM_ARM32 273 static TEE_Result atmel_wdt_pm(enum pm_op op, uint32_t pm_hint __unused, 274 const struct pm_callback_handle *hdl) 275 { 276 struct atmel_wdt *wdt = hdl->handle; 277 278 switch (op) { 279 case PM_OP_RESUME: 280 atmel_wdt_init_hw(wdt); 281 if (wdt->enabled) 282 atmel_wdt_start(wdt); 283 break; 284 case PM_OP_SUSPEND: 285 if (wdt->enabled) 286 atmel_wdt_stop(wdt); 287 break; 288 default: 289 panic("Invalid PM operation"); 290 } 291 292 return TEE_SUCCESS; 293 } 294 295 static void atmel_wdt_register_pm(struct atmel_wdt *wdt) 296 { 297 register_pm_driver_cb(atmel_wdt_pm, wdt, "atmel_wdt"); 298 } 299 #else 300 static void atmel_wdt_register_pm(struct atmel_wdt *wdt __unused) 301 { 302 } 303 #endif 304 305 static TEE_Result wdt_node_probe(const void *fdt, int node, 306 const void *compat_data) 307 { 308 const struct wdt_compat *compat = compat_data; 309 size_t size = 0; 310 struct atmel_wdt *wdt; 311 uint32_t irq_type = 0; 312 uint32_t irq_prio = 0; 313 int it = DT_INFO_INVALID_INTERRUPT; 314 struct itr_handler *it_hdlr = NULL; 315 TEE_Result res = TEE_ERROR_GENERIC; 316 317 if (fdt_get_status(fdt, node) != DT_STATUS_OK_SEC) 318 return TEE_ERROR_BAD_PARAMETERS; 319 320 if (compat->wdt_ps) 321 matrix_configure_periph_secure(AT91C_ID_WDT); 322 323 wdt = calloc(1, sizeof(*wdt)); 324 if (!wdt) 325 return TEE_ERROR_OUT_OF_MEMORY; 326 327 wdt->chip.ops = &atmel_wdt_ops; 328 wdt->type = compat->type; 329 wdt->dis_mask = compat->dis_mask; 330 331 it = dt_get_irq_type_prio(fdt, node, &irq_type, &irq_prio); 332 if (it == DT_INFO_INVALID_INTERRUPT) 333 goto err_free; 334 335 res = interrupt_alloc_add_conf_handler(interrupt_get_main_chip(), 336 it, atmel_wdt_itr_cb, 0, wdt, 337 irq_type, irq_prio, &it_hdlr); 338 if (res) 339 goto err_free; 340 341 if (dt_map_dev(fdt, node, &wdt->base, &size, DT_MAP_AUTO) < 0) 342 goto err_remove_handler; 343 344 /* Get current state of the watchdog */ 345 wdt->mr = io_read32(wdt->base + WDT_MR) & wdt->dis_mask; 346 347 atmel_wdt_init_hw(wdt); 348 interrupt_enable(it_hdlr->chip, it_hdlr->it); 349 350 res = watchdog_register(&wdt->chip); 351 if (res) 352 goto err_disable_unmap; 353 354 atmel_wdt_register_pm(wdt); 355 356 return TEE_SUCCESS; 357 358 err_disable_unmap: 359 interrupt_disable(it_hdlr->chip, it_hdlr->it); 360 core_mmu_remove_mapping(MEM_AREA_IO_SEC, (void *)wdt->base, size); 361 err_remove_handler: 362 interrupt_remove_free_handler(it_hdlr); 363 err_free: 364 free(wdt); 365 366 return TEE_ERROR_GENERIC; 367 } 368 369 static const struct wdt_compat sama5d2_compat = { 370 .wdt_ps = true, 371 .type = WDT_TYPE_WDT, 372 .dis_mask = WDT_MR_WDDIS, 373 }; 374 375 static const struct wdt_compat sama7g5_compat = { 376 .wdt_ps = false, 377 .type = WDT_TYPE_DWDT, 378 .dis_mask = WDT_MR_WDDIS_DWDT, 379 }; 380 381 static const struct dt_device_match atmel_wdt_match_table[] = { 382 { 383 .compatible = "atmel,sama5d4-wdt", 384 .compat_data = &sama5d2_compat, 385 }, 386 { 387 .compatible = "microchip,sama7g5-wdt", 388 .compat_data = &sama7g5_compat, 389 }, 390 { } 391 }; 392 393 DEFINE_DT_DRIVER(atmel_wdt_dt_driver) = { 394 .name = "atmel_wdt", 395 .type = DT_DRIVER_NOTYPE, 396 .match_table = atmel_wdt_match_table, 397 .probe = wdt_node_probe, 398 }; 399