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