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