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 | /* * Copyright (c) 2016 Linaro Limited * * SPDX-License-Identifier: Apache-2.0 */ /** * @brief Driver for CMSDK APB Watchdog. */ #include <errno.h> #include <soc.h> #include <watchdog.h> #include <misc/printk.h> #include <misc/reboot.h> struct wdog_cmsdk_apb { /* offset: 0x000 (r/w) watchdog load register */ volatile u32_t load; /* offset: 0x004 (r/ ) watchdog value register */ volatile u32_t value; /* offset: 0x008 (r/w) watchdog control register */ volatile u32_t ctrl; /* offset: 0x00c ( /w) watchdog clear interrupt register */ volatile u32_t intclr; /* offset: 0x010 (r/ ) watchdog raw interrupt status register */ volatile u32_t rawintstat; /* offset: 0x014 (r/ ) watchdog interrupt status register */ volatile u32_t maskintstat; volatile u32_t reserved0[762]; /* offset: 0xc00 (r/w) watchdog lock register */ volatile u32_t lock; volatile u32_t reserved1[191]; /* offset: 0xf00 (r/w) watchdog integration test control register */ volatile u32_t itcr; /* offset: 0xf04 ( /w) watchdog integration test output set register */ volatile u32_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_ARM_CMSDK_WATCHDOG_0_BASE_ADDRESS)) /* Keep reference of the device to pass it to the callback */ struct device *wdog_r; /* watchdog reload value in sec */ static unsigned int reload_s = CMSDK_APB_WDOG_RELOAD; static u8_t flags; static void (*user_cb)(struct device *dev, int channel_id); static void wdog_cmsdk_apb_unlock(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(struct device *dev, u8_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(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(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 * CONFIG_SYS_CLOCK_HW_CYCLES_PER_SEC; flags = config->flags; wdog->load = reload_s; /* Configure only the callback */ user_cb = config->callback; return 0; } static int wdog_cmsdk_apb_feed(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(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_enable(dev); #endif return 0; } DEVICE_AND_API_INIT(wdog_cmsdk_apb, CONFIG_WDT_0_NAME, wdog_cmsdk_apb_init, NULL, NULL, PRE_KERNEL_1, CONFIG_KERNEL_INIT_PRIORITY_DEVICE, &wdog_cmsdk_apb_api); |