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