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