Loading...
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 | /* * Copyright (c) 2016 Linaro Limited * * SPDX-License-Identifier: Apache-2.0 */ #define DT_DRV_COMPAT arm_cmsdk_watchdog /** * @brief Driver for CMSDK APB Watchdog. */ #include <errno.h> #include <soc.h> #include <drivers/watchdog.h> #include <sys/printk.h> #include <power/reboot.h> struct wdog_cmsdk_apb { /* offset: 0x000 (r/w) watchdog load register */ volatile uint32_t load; /* offset: 0x004 (r/ ) watchdog value register */ volatile uint32_t value; /* offset: 0x008 (r/w) watchdog control register */ volatile uint32_t ctrl; /* offset: 0x00c ( /w) watchdog clear interrupt register */ volatile uint32_t intclr; /* offset: 0x010 (r/ ) watchdog raw interrupt status register */ volatile uint32_t rawintstat; /* offset: 0x014 (r/ ) watchdog interrupt status register */ volatile uint32_t maskintstat; volatile uint32_t reserved0[762]; /* offset: 0xc00 (r/w) watchdog lock register */ volatile uint32_t lock; volatile uint32_t reserved1[191]; /* offset: 0xf00 (r/w) watchdog integration test control register */ volatile uint32_t itcr; /* offset: 0xf04 ( /w) watchdog integration test output set register */ volatile uint32_t itop; }; #define CMSDK_APB_WDOG_LOAD (0xFFFFFFFF << 0) #define CMSDK_APB_WDOG_RELOAD (0xE4E1C00 << 0) #define CMSDK_APB_WDOG_VALUE (0xFFFFFFFF << 0) #define CMSDK_APB_WDOG_CTRL_RESEN (0x1 << 1) #define CMSDK_APB_WDOG_CTRL_INTEN (0x1 << 0) #define CMSDK_APB_WDOG_INTCLR (0x1 << 0) #define CMSDK_APB_WDOG_RAWINTSTAT (0x1 << 0) #define CMSDK_APB_WDOG_MASKINTSTAT (0x1 << 0) #define CMSDK_APB_WDOG_LOCK (0x1 << 0) #define CMSDK_APB_WDOG_INTEGTESTEN (0x1 << 0) #define CMSDK_APB_WDOG_INTEGTESTOUTSET (0x1 << 1) /* * Value written to the LOCK register to lock or unlock the write access * to all of the registers of the watchdog (except the LOCK register) */ #define CMSDK_APB_WDOG_UNLOCK_VALUE (0x1ACCE551) #define CMSDK_APB_WDOG_LOCK_VALUE (0x2BDDF662) #define WDOG_STRUCT \ ((volatile struct wdog_cmsdk_apb *)(DT_INST_REG_ADDR(0))) /* Keep reference of the device to pass it to the callback */ const struct device *wdog_r; /* watchdog reload value in sec */ static unsigned int reload_s = CMSDK_APB_WDOG_RELOAD; static uint8_t flags; static void (*user_cb)(const struct device *dev, int channel_id); static void wdog_cmsdk_apb_unlock(const struct device *dev) { volatile struct wdog_cmsdk_apb *wdog = WDOG_STRUCT; ARG_UNUSED(dev); wdog->lock = CMSDK_APB_WDOG_UNLOCK_VALUE; } static int wdog_cmsdk_apb_setup(const struct device *dev, uint8_t options) { volatile struct wdog_cmsdk_apb *wdog = WDOG_STRUCT; ARG_UNUSED(dev); ARG_UNUSED(options); /* Start the watchdog counter with INTEN bit */ wdog->ctrl = (CMSDK_APB_WDOG_CTRL_RESEN | CMSDK_APB_WDOG_CTRL_INTEN); return 0; } static int wdog_cmsdk_apb_disable(const struct device *dev) { volatile struct wdog_cmsdk_apb *wdog = WDOG_STRUCT; ARG_UNUSED(dev); /* Stop the watchdog counter with INTEN bit */ wdog->ctrl = ~(CMSDK_APB_WDOG_CTRL_RESEN | CMSDK_APB_WDOG_CTRL_INTEN); return 0; } static int wdog_cmsdk_apb_install_timeout(const struct device *dev, const struct wdt_timeout_cfg *config) { volatile struct wdog_cmsdk_apb *wdog = WDOG_STRUCT; ARG_UNUSED(dev); /* Reload value */ reload_s = config->window.max * DT_INST_PROP_BY_PHANDLE(0, clocks, clock_frequency); flags = config->flags; wdog->load = reload_s; /* Configure only the callback */ user_cb = config->callback; return 0; } static int wdog_cmsdk_apb_feed(const struct device *dev, int channel_id) { volatile struct wdog_cmsdk_apb *wdog = WDOG_STRUCT; ARG_UNUSED(dev); ARG_UNUSED(channel_id); /* Clear the interrupt */ wdog->intclr = CMSDK_APB_WDOG_INTCLR; /* Reload */ wdog->load = reload_s; return 0; } static const struct wdt_driver_api wdog_cmsdk_apb_api = { .setup = wdog_cmsdk_apb_setup, .disable = wdog_cmsdk_apb_disable, .install_timeout = wdog_cmsdk_apb_install_timeout, .feed = wdog_cmsdk_apb_feed, }; #ifdef CONFIG_RUNTIME_NMI extern void z_NmiHandlerSet(void (*pHandler)(void)); static int wdog_cmsdk_apb_has_fired(void) { volatile struct wdog_cmsdk_apb *wdog = WDOG_STRUCT; return (wdog->maskintstat & CMSDK_APB_WDOG_MASKINTSTAT) != 0U; } static void wdog_cmsdk_apb_isr(void) { /* * Check if the watchdog was the reason of the NMI interrupt * and if not, exit immediately */ if (!wdog_cmsdk_apb_has_fired()) { printk("NMI received! Rebooting...\n"); /* In ARM implementation sys_reboot ignores the parameter */ sys_reboot(0); } else { if (user_cb != NULL) { user_cb(wdog_r, 0); } } } #endif /* CONFIG_RUNTIME_NMI */ static int wdog_cmsdk_apb_init(const struct device *dev) { volatile struct wdog_cmsdk_apb *wdog = WDOG_STRUCT; wdog_r = dev; /* unlock access to configuration registers */ wdog_cmsdk_apb_unlock(dev); /* set default reload value */ wdog->load = reload_s; #ifdef CONFIG_RUNTIME_NMI /* Configure the interrupts */ z_NmiHandlerSet(wdog_cmsdk_apb_isr); #endif #ifdef CONFIG_WDOG_CMSDK_APB_START_AT_BOOT wdog_cmsdk_apb_setup(dev, 0); #endif return 0; } DEVICE_DT_INST_DEFINE(0, wdog_cmsdk_apb_init, device_pm_control_nop, NULL, NULL, PRE_KERNEL_1, CONFIG_KERNEL_INIT_PRIORITY_DEVICE, &wdog_cmsdk_apb_api); |