blob: a30eeb04d2dfda6121aa05c365151267cca36896 [file] [log] [blame]
Silvestrs Timofejevs947a44a2020-12-04 16:42:29 +00001// Copyright lowRISC contributors.
2// Licensed under the Apache License, Version 2.0, see LICENSE for details.
3// SPDX-License-Identifier: Apache-2.0
4
5#include "sw/device/lib/dif/dif_aon_timer.h"
6
Miguel Young de la Sota5426d252021-04-22 12:12:47 -04007#include <assert.h>
Silvestrs Timofejevs6b2beaf2021-03-16 10:46:20 +00008#include <stddef.h>
9
10#include "sw/device/lib/base/bitfield.h"
11#include "sw/device/lib/base/mmio.h"
12
Silvestrs Timofejevs947a44a2020-12-04 16:42:29 +000013#include "aon_timer_regs.h" // Generated.
14
Miguel Young de la Sota5426d252021-04-22 12:12:47 -040015static_assert(AON_TIMER_INTR_STATE_WKUP_TIMER_EXPIRED_BIT ==
16 AON_TIMER_INTR_TEST_WKUP_TIMER_EXPIRED_BIT,
17 "Wake-up IRQ have different indexes in different registers!");
18static_assert(AON_TIMER_INTR_STATE_WDOG_TIMER_EXPIRED_BIT ==
19 AON_TIMER_INTR_TEST_WDOG_TIMER_EXPIRED_BIT,
20 "Watchdog IRQ have different indexes in different registers!");
Silvestrs Timofejevs6b2beaf2021-03-16 10:46:20 +000021
22const size_t kAonTimerWakeupIrqIndex =
23 AON_TIMER_INTR_STATE_WKUP_TIMER_EXPIRED_BIT;
24
25const size_t kAonTimerWatchdogIrqIndex =
26 AON_TIMER_INTR_STATE_WDOG_TIMER_EXPIRED_BIT;
27
Silvestrs Timofejevs8235b732021-03-31 15:37:52 +010028static void aon_timer_wakeup_clear_counter(const dif_aon_timer_t *aon) {
Silvestrs Timofejevs6b2beaf2021-03-16 10:46:20 +000029 mmio_region_write32(aon->params.base_addr, AON_TIMER_WKUP_COUNT_REG_OFFSET,
30 0);
31}
32
Silvestrs Timofejevs8235b732021-03-31 15:37:52 +010033static void aon_timer_wakeup_toggle(const dif_aon_timer_t *aon, bool enable) {
Silvestrs Timofejevs6b2beaf2021-03-16 10:46:20 +000034 uint32_t reg =
35 mmio_region_read32(aon->params.base_addr, AON_TIMER_WKUP_CTRL_REG_OFFSET);
36 reg = bitfield_bit32_write(reg, AON_TIMER_WKUP_CTRL_ENABLE_BIT, enable);
37 mmio_region_write32(aon->params.base_addr, AON_TIMER_WKUP_CTRL_REG_OFFSET,
38 reg);
39}
40
Silvestrs Timofejevs8235b732021-03-31 15:37:52 +010041static void aon_timer_watchdog_clear_counter(const dif_aon_timer_t *aon) {
Silvestrs Timofejevs6b2beaf2021-03-16 10:46:20 +000042 mmio_region_write32(aon->params.base_addr, AON_TIMER_WDOG_COUNT_REG_OFFSET,
43 0);
44}
45
Silvestrs Timofejevs8235b732021-03-31 15:37:52 +010046static void aon_timer_watchdog_toggle(const dif_aon_timer_t *aon, bool enable) {
Silvestrs Timofejevs6b2beaf2021-03-16 10:46:20 +000047 uint32_t reg =
48 mmio_region_read32(aon->params.base_addr, AON_TIMER_WDOG_CTRL_REG_OFFSET);
49 reg = bitfield_bit32_write(reg, AON_TIMER_WDOG_CTRL_ENABLE_BIT, enable);
50 mmio_region_write32(aon->params.base_addr, AON_TIMER_WDOG_CTRL_REG_OFFSET,
51 reg);
52}
53
54static void aon_timer_watchdog_lock(const dif_aon_timer_t *aon) {
55 // Clear bit to lock the watchdog configuration register until the next reset.
56 // Write one to clear the bit.
57 mmio_region_write32(aon->params.base_addr, AON_TIMER_WDOG_REGWEN_REG_OFFSET,
58 0x00000001);
59}
60
Silvestrs Timofejevs8235b732021-03-31 15:37:52 +010061static bool aon_timer_watchdog_is_locked(const dif_aon_timer_t *aon) {
Silvestrs Timofejevs6b2beaf2021-03-16 10:46:20 +000062 uint32_t reg = mmio_region_read32(aon->params.base_addr,
63 AON_TIMER_WDOG_REGWEN_REG_OFFSET);
64
65 // Locked when bit is cleared.
66 return !bitfield_bit32_read(reg, AON_TIMER_WDOG_REGWEN_REGWEN_BIT);
67}
68
69static bool aon_timer_get_irq_index(dif_aon_timer_irq_t irq, uint32_t *index) {
70 switch (irq) {
71 case kDifAonTimerIrqWakeupThreshold:
72 *index = kAonTimerWakeupIrqIndex;
73 break;
74 case kDifAonTimerIrqWatchdogBarkThreshold:
75 *index = kAonTimerWatchdogIrqIndex;
76 break;
77 default:
78 return false;
79 }
80
81 return true;
82}
83
84dif_aon_timer_result_t dif_aon_timer_init(dif_aon_timer_params_t params,
85 dif_aon_timer_t *aon) {
86 if (aon == NULL) {
87 return kDifAonTimerBadArg;
88 }
89
90 *aon = (dif_aon_timer_t){.params = params};
91
92 return kDifAonTimerOk;
93}
94
95dif_aon_timer_result_t dif_aon_timer_wakeup_start(const dif_aon_timer_t *aon,
96 uint32_t threshold,
97 uint32_t prescaler) {
98 if (aon == NULL || prescaler > AON_TIMER_WKUP_CTRL_PRESCALER_MASK) {
99 return kDifAonTimerBadArg;
100 }
101
102 // The timer should be stopped first, otherwise it will continue counting up.
Silvestrs Timofejevs8235b732021-03-31 15:37:52 +0100103 aon_timer_wakeup_toggle(aon, false);
104 aon_timer_wakeup_clear_counter(aon);
Silvestrs Timofejevs6b2beaf2021-03-16 10:46:20 +0000105
106 mmio_region_write32(aon->params.base_addr, AON_TIMER_WKUP_THOLD_REG_OFFSET,
107 threshold);
108
109 uint32_t reg =
110 bitfield_field32_write(0, AON_TIMER_WKUP_CTRL_PRESCALER_FIELD, prescaler);
111 reg = bitfield_bit32_write(reg, AON_TIMER_WKUP_CTRL_ENABLE_BIT, true);
112 mmio_region_write32(aon->params.base_addr, AON_TIMER_WKUP_CTRL_REG_OFFSET,
113 reg);
114
115 return kDifAonTimerOk;
116}
117
118dif_aon_timer_result_t dif_aon_timer_wakeup_stop(const dif_aon_timer_t *aon) {
119 if (aon == NULL) {
120 return kDifAonTimerBadArg;
121 }
122
Silvestrs Timofejevs8235b732021-03-31 15:37:52 +0100123 aon_timer_wakeup_toggle(aon, false);
Silvestrs Timofejevs6b2beaf2021-03-16 10:46:20 +0000124
125 return kDifAonTimerOk;
126}
127
128dif_aon_timer_result_t dif_aon_timer_wakeup_restart(
129 const dif_aon_timer_t *aon) {
130 if (aon == NULL) {
131 return kDifAonTimerBadArg;
132 }
133
Silvestrs Timofejevs8235b732021-03-31 15:37:52 +0100134 aon_timer_wakeup_clear_counter(aon);
135 aon_timer_wakeup_toggle(aon, true);
Silvestrs Timofejevs6b2beaf2021-03-16 10:46:20 +0000136
137 return kDifAonTimerOk;
138}
139
140dif_aon_timer_result_t dif_aon_timer_wakeup_get_count(
141 const dif_aon_timer_t *aon, uint32_t *count) {
142 if (aon == NULL || count == NULL) {
143 return kDifAonTimerBadArg;
144 }
145
146 *count = mmio_region_read32(aon->params.base_addr,
147 AON_TIMER_WKUP_COUNT_REG_OFFSET);
148
149 return kDifAonTimerOk;
150}
151
152dif_aon_timer_watchdog_result_t dif_aon_timer_watchdog_start(
153 const dif_aon_timer_t *aon, uint32_t bark_threshold,
154 uint32_t bite_threshold, bool pause_in_sleep, bool lock) {
155 if (aon == NULL) {
156 return kDifAonTimerWatchdogBadArg;
157 }
158
Silvestrs Timofejevs8235b732021-03-31 15:37:52 +0100159 if (aon_timer_watchdog_is_locked(aon)) {
Silvestrs Timofejevs6b2beaf2021-03-16 10:46:20 +0000160 return kDifAonTimerWatchdogLocked;
161 }
162
163 // The timer should be stopped first, otherwise it will continue counting up.
Silvestrs Timofejevs8235b732021-03-31 15:37:52 +0100164 aon_timer_watchdog_toggle(aon, false);
165 aon_timer_watchdog_clear_counter(aon);
Silvestrs Timofejevs6b2beaf2021-03-16 10:46:20 +0000166
167 mmio_region_write32(aon->params.base_addr,
168 AON_TIMER_WDOG_BARK_THOLD_REG_OFFSET, bark_threshold);
169 mmio_region_write32(aon->params.base_addr,
170 AON_TIMER_WDOG_BITE_THOLD_REG_OFFSET, bite_threshold);
171
172 uint32_t reg = bitfield_bit32_write(0, AON_TIMER_WDOG_CTRL_ENABLE_BIT, true);
173 if (pause_in_sleep) {
174 reg =
175 bitfield_bit32_write(reg, AON_TIMER_WDOG_CTRL_PAUSE_IN_SLEEP_BIT, true);
176 }
177 mmio_region_write32(aon->params.base_addr, AON_TIMER_WDOG_CTRL_REG_OFFSET,
178 reg);
179
180 // Watchdog control register should only be locked after the last
181 // control register access.
182 if (lock) {
183 aon_timer_watchdog_lock(aon);
184 }
185
186 return kDifAonTimerWatchdogOk;
187}
188
189dif_aon_timer_watchdog_result_t dif_aon_timer_watchdog_stop(
190 const dif_aon_timer_t *aon) {
191 if (aon == NULL) {
192 return kDifAonTimerWatchdogBadArg;
193 }
194
Silvestrs Timofejevs8235b732021-03-31 15:37:52 +0100195 if (aon_timer_watchdog_is_locked(aon)) {
Silvestrs Timofejevs6b2beaf2021-03-16 10:46:20 +0000196 return kDifAonTimerWatchdogLocked;
197 }
198
Silvestrs Timofejevs8235b732021-03-31 15:37:52 +0100199 aon_timer_watchdog_toggle(aon, false);
Silvestrs Timofejevs6b2beaf2021-03-16 10:46:20 +0000200
201 return kDifAonTimerWatchdogOk;
202}
203
204dif_aon_timer_watchdog_result_t dif_aon_timer_watchdog_restart(
205 const dif_aon_timer_t *aon) {
206 if (aon == NULL) {
207 return kDifAonTimerWatchdogBadArg;
208 }
209
Silvestrs Timofejevs8235b732021-03-31 15:37:52 +0100210 if (aon_timer_watchdog_is_locked(aon)) {
Silvestrs Timofejevs6b2beaf2021-03-16 10:46:20 +0000211 return kDifAonTimerWatchdogLocked;
212 }
213
Silvestrs Timofejevs8235b732021-03-31 15:37:52 +0100214 aon_timer_watchdog_clear_counter(aon);
215 aon_timer_watchdog_toggle(aon, true);
Silvestrs Timofejevs6b2beaf2021-03-16 10:46:20 +0000216
217 return kDifAonTimerWatchdogOk;
218}
219
220dif_aon_timer_result_t dif_aon_timer_watchdog_get_count(
221 const dif_aon_timer_t *aon, uint32_t *count) {
222 if (aon == NULL || count == NULL) {
223 return kDifAonTimerBadArg;
224 }
225
226 *count = mmio_region_read32(aon->params.base_addr,
227 AON_TIMER_WDOG_COUNT_REG_OFFSET);
228
229 return kDifAonTimerOk;
230}
231
232dif_aon_timer_result_t dif_aon_timer_watchdog_pet(const dif_aon_timer_t *aon) {
233 if (aon == NULL) {
234 return kDifAonTimerBadArg;
235 }
236
Silvestrs Timofejevs8235b732021-03-31 15:37:52 +0100237 aon_timer_watchdog_clear_counter(aon);
Silvestrs Timofejevs6b2beaf2021-03-16 10:46:20 +0000238
239 return kDifAonTimerOk;
240}
241
242dif_aon_timer_watchdog_result_t dif_aon_timer_watchdog_lock(
243 const dif_aon_timer_t *aon) {
244 if (aon == NULL) {
245 return kDifAonTimerWatchdogBadArg;
246 }
247
248 aon_timer_watchdog_lock(aon);
249
250 return kDifAonTimerWatchdogOk;
251}
252
253dif_aon_timer_result_t dif_aon_timer_watchdog_is_locked(
254 const dif_aon_timer_t *aon, bool *is_locked) {
255 if (aon == NULL || is_locked == NULL) {
256 return kDifAonTimerBadArg;
257 }
258
Silvestrs Timofejevs8235b732021-03-31 15:37:52 +0100259 *is_locked = aon_timer_watchdog_is_locked(aon);
Silvestrs Timofejevs6b2beaf2021-03-16 10:46:20 +0000260
261 return kDifAonTimerOk;
262}
263
264dif_aon_timer_result_t dif_aon_timer_irq_is_pending(const dif_aon_timer_t *aon,
265 dif_aon_timer_irq_t irq,
266 bool *is_pending) {
267 if (aon == NULL || is_pending == NULL) {
268 return kDifAonTimerBadArg;
269 }
270
271 uint32_t index = 0;
272 if (!aon_timer_get_irq_index(irq, &index)) {
273 return kDifAonTimerError;
274 }
275
276 uint32_t reg = mmio_region_read32(aon->params.base_addr,
277 AON_TIMER_INTR_STATE_REG_OFFSET);
278 *is_pending = bitfield_bit32_read(reg, index);
279
280 return kDifAonTimerOk;
281}
282
283dif_aon_timer_result_t dif_aon_timer_irq_acknowledge(const dif_aon_timer_t *aon,
284 dif_aon_timer_irq_t irq) {
285 if (aon == NULL) {
286 return kDifAonTimerBadArg;
287 }
288
289 uint32_t index = 0;
290 if (!aon_timer_get_irq_index(irq, &index)) {
291 return kDifAonTimerError;
292 }
293
294 // Write one to clear.
295 uint32_t reg = bitfield_bit32_write(0, index, true);
296 mmio_region_write32(aon->params.base_addr, AON_TIMER_INTR_STATE_REG_OFFSET,
297 reg);
298
299 return kDifAonTimerOk;
300}
301
302dif_aon_timer_result_t dif_aon_timer_irq_force(const dif_aon_timer_t *aon,
303 dif_aon_timer_irq_t irq) {
304 if (aon == NULL) {
305 return kDifAonTimerBadArg;
306 }
307
308 uint32_t index = 0;
309 if (!aon_timer_get_irq_index(irq, &index)) {
310 return kDifAonTimerError;
311 }
312
313 // Write only register.
314 uint32_t reg = bitfield_bit32_write(0, index, true);
315 mmio_region_write32(aon->params.base_addr, AON_TIMER_INTR_TEST_REG_OFFSET,
316 reg);
317
318 return kDifAonTimerOk;
319}