blob: cbbbcfd72c94f858beff6ebd8a0c138bcc38e9f2 [file] [log] [blame]
Alphan Ulusoybb457d02020-08-11 23:44:38 -04001// 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_pwrmgr.h"
6
Miguel Young de la Sota5426d252021-04-22 12:12:47 -04007#include <assert.h>
8
Alphan Ulusoy1bbcedd2020-09-30 17:32:06 -04009#include "sw/device/lib/base/bitfield.h"
10#include "sw/device/lib/base/mmio.h"
Alphan Ulusoybb457d02020-08-11 23:44:38 -040011
12#include "pwrmgr_regs.h" // Generated.
13
Alphan Ulusoy1bbcedd2020-09-30 17:32:06 -040014/**
15 * Following static assertions make sure that generated values match the
16 * definitions in the header, which we rely on for a simpler implementation.
17 * These constants and their usages must be revisited if there is a change in
18 * hardware.
19 */
20
21/**
22 * Relevant bits of the control register must start at
Miguel Young de la Sota4e1a4a32020-11-05 10:08:52 -050023 * `PWRMGR_CONTROL_CORE_CLK_EN_BIT` and be in the same order as
Alphan Ulusoy1bbcedd2020-09-30 17:32:06 -040024 * `dif_pwrmgr_domain_option_t` constants.
25 */
Miguel Young de la Sota5426d252021-04-22 12:12:47 -040026static_assert(kDifPwrmgrDomainOptionCoreClockInLowPower ==
27 (1u << (PWRMGR_CONTROL_CORE_CLK_EN_BIT -
28 PWRMGR_CONTROL_CORE_CLK_EN_BIT)),
29 "Layout of control register changed.");
Alphan Ulusoy1bbcedd2020-09-30 17:32:06 -040030
Miguel Young de la Sota5426d252021-04-22 12:12:47 -040031static_assert(kDifPwrmgrDomainOptionIoClockInLowPower ==
32 (1u << (PWRMGR_CONTROL_IO_CLK_EN_BIT -
33 PWRMGR_CONTROL_CORE_CLK_EN_BIT)),
34 "Layout of control register changed.");
Alphan Ulusoy1bbcedd2020-09-30 17:32:06 -040035
Miguel Young de la Sota5426d252021-04-22 12:12:47 -040036static_assert(kDifPwrmgrDomainOptionUsbClockInLowPower ==
37 (1u << (PWRMGR_CONTROL_USB_CLK_EN_LP_BIT -
38 PWRMGR_CONTROL_CORE_CLK_EN_BIT)),
39 "Layout of control register changed.");
Alphan Ulusoy1bbcedd2020-09-30 17:32:06 -040040
Miguel Young de la Sota5426d252021-04-22 12:12:47 -040041static_assert(kDifPwrmgrDomainOptionUsbClockInActivePower ==
42 (1u << (PWRMGR_CONTROL_USB_CLK_EN_ACTIVE_BIT -
43 PWRMGR_CONTROL_CORE_CLK_EN_BIT)),
44 "Layout of control register changed.");
Alphan Ulusoy1bbcedd2020-09-30 17:32:06 -040045
Miguel Young de la Sota5426d252021-04-22 12:12:47 -040046static_assert(kDifPwrmgrDomainOptionMainPowerInLowPower ==
47 (1u << (PWRMGR_CONTROL_MAIN_PD_N_BIT -
48 PWRMGR_CONTROL_CORE_CLK_EN_BIT)),
49 "Layout of control register changed.");
Alphan Ulusoy1bbcedd2020-09-30 17:32:06 -040050
51/**
52 * Bitfield for interpreting the configuration options in the control
53 * register.
54 */
55static const bitfield_field32_t kDomainConfigBitfield = {
56 .mask = kDifPwrmgrDomainOptionCoreClockInLowPower |
57 kDifPwrmgrDomainOptionIoClockInLowPower |
58 kDifPwrmgrDomainOptionUsbClockInLowPower |
59 kDifPwrmgrDomainOptionUsbClockInActivePower |
60 kDifPwrmgrDomainOptionMainPowerInLowPower,
Miguel Young de la Sota4e1a4a32020-11-05 10:08:52 -050061 .index = PWRMGR_CONTROL_CORE_CLK_EN_BIT,
Alphan Ulusoy1bbcedd2020-09-30 17:32:06 -040062};
63
64/**
65 * Relevant bits of the WAKEUP_EN and WAKE_INFO registers must start at `0` and
66 * be in the same order as `dif_pwrmgr_wakeup_request_source_t` constants.
67 */
Miguel Young de la Sota5426d252021-04-22 12:12:47 -040068static_assert(kDifPwrmgrWakeupRequestSourceOne ==
69 (1u << PWRMGR_WAKEUP_EN_EN_0_BIT),
70 "Layout of WAKEUP_EN register changed.");
71static_assert(kDifPwrmgrWakeupRequestSourceOne ==
Michael Schaffner6ca300e2021-08-18 19:12:28 -070072 (1u << PWRMGR_PARAM_AON_SYSRST_CTRL_WKUP_REQ_IDX),
Miguel Young de la Sota5426d252021-04-22 12:12:47 -040073 "Layout of WAKE_INFO register changed.");
74static_assert(kDifPwrmgrWakeupRequestSourceTwo ==
Timothy Chenb74f6122021-04-26 16:57:22 -070075 (1u << PWRMGR_PARAM_DEBUG_CABLE_WAKEUP_IDX),
Miguel Young de la Sota5426d252021-04-22 12:12:47 -040076 "Layout of WAKE_INFO register changed.");
77static_assert(kDifPwrmgrWakeupRequestSourceThree ==
Timothy Chenb74f6122021-04-26 16:57:22 -070078 (1u << PWRMGR_PARAM_AON_WKUP_REQ_IDX),
Miguel Young de la Sota5426d252021-04-22 12:12:47 -040079 "Layout of WAKE_INFO register changed.");
80static_assert(kDifPwrmgrWakeupRequestSourceFour ==
Timothy Chenb74f6122021-04-26 16:57:22 -070081 (1u << PWRMGR_PARAM_USB_WKUP_REQ_IDX),
82 "Layout of WAKE_INFO register changed.");
83static_assert(kDifPwrmgrWakeupRequestSourceFive ==
Miguel Young de la Sota5426d252021-04-22 12:12:47 -040084 (1u << PWRMGR_PARAM_AON_TIMER_WKUP_REQ_IDX),
85 "Layout of WAKE_INFO register changed.");
Alphan Ulusoy1bbcedd2020-09-30 17:32:06 -040086
87/**
88 * Relevant bits of the RESET_EN register must start at `0` and be in the same
89 * order as `dif_pwrmgr_reset_request_source_t` constants.
90 */
Miguel Young de la Sota5426d252021-04-22 12:12:47 -040091static_assert(kDifPwrmgrResetRequestSourceOne ==
92 (1u << PWRMGR_RESET_EN_EN_0_BIT),
93 "Layout of RESET_EN register changed.");
Alphan Ulusoy1bbcedd2020-09-30 17:32:06 -040094
95/**
96 * `dif_pwrmgr_irq_t` constants must match the corresponding generated values.
97 */
Miguel Young de la Sota5426d252021-04-22 12:12:47 -040098static_assert(kDifPwrmgrIrqWakeup == PWRMGR_INTR_COMMON_WAKEUP_BIT,
99 "Layout of interrupt registers changed.");
Alphan Ulusoy1bbcedd2020-09-30 17:32:06 -0400100
101/**
102 * Register information for a request type.
103 */
104typedef struct request_reg_info {
105 ptrdiff_t write_enable_reg_offset;
106 bitfield_bit32_index_t write_enable_bit_index;
107 ptrdiff_t sources_enable_reg_offset;
108 ptrdiff_t cur_req_sources_reg_offset;
109 bitfield_field32_t bitfield;
110} request_reg_info_t;
111
112/**
113 * Register information for wakeup and reset requests.
114 *
115 * Wakeup and reset requests follow the same logic for configuration and
116 * monitoring but use different registers. Defining these constants here
117 * allows us to use the same code for both types of requests.
118 */
119static const request_reg_info_t request_reg_infos[2] = {
120 [kDifPwrmgrReqTypeWakeup] =
121 {
122 .write_enable_reg_offset = PWRMGR_WAKEUP_EN_REGWEN_REG_OFFSET,
Miguel Young de la Sota4e1a4a32020-11-05 10:08:52 -0500123 .write_enable_bit_index = PWRMGR_WAKEUP_EN_REGWEN_EN_BIT,
Alphan Ulusoy1bbcedd2020-09-30 17:32:06 -0400124 .sources_enable_reg_offset = PWRMGR_WAKEUP_EN_REG_OFFSET,
125 .cur_req_sources_reg_offset = PWRMGR_WAKE_STATUS_REG_OFFSET,
126 .bitfield =
127 {
Alphan Ulusoya14b2ce2020-12-09 08:50:51 -0500128 .mask = kDifPwrmgrWakeupRequestSourceOne |
129 kDifPwrmgrWakeupRequestSourceTwo |
130 kDifPwrmgrWakeupRequestSourceThree |
Timothy Chenb74f6122021-04-26 16:57:22 -0700131 kDifPwrmgrWakeupRequestSourceFour |
132 kDifPwrmgrWakeupRequestSourceFive,
Alphan Ulusoy1bbcedd2020-09-30 17:32:06 -0400133 .index = 0,
134 },
135 },
136 [kDifPwrmgrReqTypeReset] =
137 {
138 .write_enable_reg_offset = PWRMGR_RESET_EN_REGWEN_REG_OFFSET,
Miguel Young de la Sota4e1a4a32020-11-05 10:08:52 -0500139 .write_enable_bit_index = PWRMGR_RESET_EN_REGWEN_EN_BIT,
Alphan Ulusoy1bbcedd2020-09-30 17:32:06 -0400140 .sources_enable_reg_offset = PWRMGR_RESET_EN_REG_OFFSET,
141 .cur_req_sources_reg_offset = PWRMGR_RESET_STATUS_REG_OFFSET,
142 .bitfield =
143 {
144 .mask = kDifPwrmgrResetRequestSourceOne,
145 .index = 0,
146 },
147 },
148};
149
150/**
151 * Checks if a value is a valid `dif_pwrmgr_toggle_t` and converts it to `bool`.
152 */
153DIF_WARN_UNUSED_RESULT
154static bool toggle_to_bool(dif_pwrmgr_toggle_t val, bool *val_bool) {
155 switch (val) {
156 case kDifPwrmgrToggleEnabled:
157 *val_bool = true;
158 break;
159 case kDifPwrmgrToggleDisabled:
160 *val_bool = false;
161 break;
162 default:
163 return false;
164 }
165 return true;
166}
167
168/**
169 * Converts a `bool` to `dif_pwrmgr_toggle_t`.
170 */
171static dif_pwrmgr_toggle_t bool_to_toggle(bool val) {
172 return val ? kDifPwrmgrToggleEnabled : kDifPwrmgrToggleDisabled;
173}
174
175/**
176 * Checks if a value is a valid `dif_pwrmgr_req_type_t`.
177 */
178DIF_WARN_UNUSED_RESULT
179static bool is_valid_req_type(dif_pwrmgr_req_type_t val) {
180 return val == kDifPwrmgrReqTypeWakeup || val == kDifPwrmgrReqTypeReset;
181}
182
183/**
184 * Checks if a value is a valid `dif_pwrmgr_irq_t`.
185 */
186DIF_WARN_UNUSED_RESULT
187static bool is_valid_irq(dif_pwrmgr_irq_t val) {
188 return val >= 0 && val <= kDifPwrmgrIrqLast;
189}
190
191/**
192 * Checks if a value is valid for, i.e. fits in the mask of, a
193 * `bitfield_field32_t`.
194 */
195DIF_WARN_UNUSED_RESULT
196static bool is_valid_for_bitfield(uint32_t val, bitfield_field32_t bitfield) {
197 return (val & bitfield.mask) == val;
198}
199
200/**
201 * Checks if the control register is locked.
202 *
203 * Control register is locked when low power is enabled and WFI occurs. It is
204 * unlocked when the chip transitions back to active power state.
205 */
206DIF_WARN_UNUSED_RESULT
207static bool control_register_is_locked(const dif_pwrmgr_t *pwrmgr) {
Miguel Young de la Sota4e1a4a32020-11-05 10:08:52 -0500208 // Control register is locked when `PWRMGR_CTRL_CFG_REGWEN_EN_BIT` bit is 0.
Alphan Ulusoy1bbcedd2020-09-30 17:32:06 -0400209 return !bitfield_bit32_read(
210 mmio_region_read32(pwrmgr->params.base_addr,
211 PWRMGR_CTRL_CFG_REGWEN_REG_OFFSET),
Miguel Young de la Sota4e1a4a32020-11-05 10:08:52 -0500212 PWRMGR_CTRL_CFG_REGWEN_EN_BIT);
Alphan Ulusoy1bbcedd2020-09-30 17:32:06 -0400213}
214
215/**
216 * The configuration registers CONTROL, WAKEUP_EN, and RESET_EN are all written
217 * in the fast clock domain but used in the slow clock domain. Values of these
218 * registers are not propagated across the clock boundary until this function is
219 * called.
220 */
221static void sync_slow_clock_domain_polled(const dif_pwrmgr_t *pwrmgr) {
222 // Start sync and wait for it to finish.
Miguel Young de la Sota4e1a4a32020-11-05 10:08:52 -0500223 mmio_region_write32(
224 pwrmgr->params.base_addr, PWRMGR_CFG_CDC_SYNC_REG_OFFSET,
225 bitfield_bit32_write(0, PWRMGR_CFG_CDC_SYNC_SYNC_BIT, true));
Alphan Ulusoy1bbcedd2020-09-30 17:32:06 -0400226 while (bitfield_bit32_read(mmio_region_read32(pwrmgr->params.base_addr,
227 PWRMGR_CFG_CDC_SYNC_REG_OFFSET),
Miguel Young de la Sota4e1a4a32020-11-05 10:08:52 -0500228 PWRMGR_CFG_CDC_SYNC_SYNC_BIT)) {
Alphan Ulusoy1bbcedd2020-09-30 17:32:06 -0400229 }
230}
231
232/**
233 * Checks if sources of a request type are locked.
234 */
235DIF_WARN_UNUSED_RESULT
236static bool request_sources_is_locked(const dif_pwrmgr_t *pwrmgr,
237 dif_pwrmgr_req_type_t req_type) {
238 request_reg_info_t reg_info = request_reg_infos[req_type];
239 uint32_t reg_val = mmio_region_read32(pwrmgr->params.base_addr,
240 reg_info.write_enable_reg_offset);
241 // Locked if write enable bit is set to 0.
242 return !bitfield_bit32_read(reg_val, reg_info.write_enable_bit_index);
243}
244
245dif_pwrmgr_result_t dif_pwrmgr_init(dif_pwrmgr_params_t params,
246 dif_pwrmgr_t *pwrmgr) {
247 if (pwrmgr == NULL) {
248 return kDifPwrmgrBadArg;
249 }
250
251 *pwrmgr = (dif_pwrmgr_t){.params = params};
252
253 return kDifPwrmgrOk;
254}
255
256dif_pwrmgr_config_result_t dif_pwrmgr_low_power_set_enabled(
257 const dif_pwrmgr_t *pwrmgr, dif_pwrmgr_toggle_t new_state) {
258 if (pwrmgr == NULL) {
259 return kDifPwrmgrConfigBadArg;
260 }
261
262 bool enable = false;
263 if (!toggle_to_bool(new_state, &enable)) {
264 return kDifPwrmgrConfigBadArg;
265 }
266
267 if (control_register_is_locked(pwrmgr)) {
268 return kDifPwrMgrConfigLocked;
269 }
270
271 uint32_t reg_val =
272 mmio_region_read32(pwrmgr->params.base_addr, PWRMGR_CONTROL_REG_OFFSET);
273 reg_val =
Miguel Young de la Sota4e1a4a32020-11-05 10:08:52 -0500274 bitfield_bit32_write(reg_val, PWRMGR_CONTROL_LOW_POWER_HINT_BIT, enable);
Alphan Ulusoy1bbcedd2020-09-30 17:32:06 -0400275 mmio_region_write32(pwrmgr->params.base_addr, PWRMGR_CONTROL_REG_OFFSET,
276 reg_val);
277
278 // Slow clock domain must be synced for changes to take effect.
279 sync_slow_clock_domain_polled(pwrmgr);
280
281 return kDifPwrmgrConfigOk;
282}
283
284dif_pwrmgr_result_t dif_pwrmgr_low_power_get_enabled(
285 const dif_pwrmgr_t *pwrmgr, dif_pwrmgr_toggle_t *cur_state) {
286 if (pwrmgr == NULL || cur_state == NULL) {
287 return kDifPwrmgrBadArg;
288 }
289
290 uint32_t reg_val =
291 mmio_region_read32(pwrmgr->params.base_addr, PWRMGR_CONTROL_REG_OFFSET);
292 *cur_state = bool_to_toggle(
Miguel Young de la Sota4e1a4a32020-11-05 10:08:52 -0500293 bitfield_bit32_read(reg_val, PWRMGR_CONTROL_LOW_POWER_HINT_BIT));
Alphan Ulusoy1bbcedd2020-09-30 17:32:06 -0400294
295 return kDifPwrmgrOk;
296}
297
298dif_pwrmgr_config_result_t dif_pwrmgr_set_domain_config(
299 const dif_pwrmgr_t *pwrmgr, dif_pwrmgr_domain_config_t config) {
300 if (pwrmgr == NULL || !is_valid_for_bitfield(config, kDomainConfigBitfield)) {
301 return kDifPwrmgrConfigBadArg;
302 }
303
304 if (control_register_is_locked(pwrmgr)) {
305 return kDifPwrMgrConfigLocked;
306 }
307
308 uint32_t reg_val =
309 mmio_region_read32(pwrmgr->params.base_addr, PWRMGR_CONTROL_REG_OFFSET);
310 reg_val = bitfield_field32_write(reg_val, kDomainConfigBitfield, config);
311 mmio_region_write32(pwrmgr->params.base_addr, PWRMGR_CONTROL_REG_OFFSET,
312 reg_val);
313
314 // Slow clock domain must be synced for changes to take effect.
315 sync_slow_clock_domain_polled(pwrmgr);
316
317 return kDifPwrmgrConfigOk;
318}
319
320dif_pwrmgr_result_t dif_pwrmgr_get_domain_config(
321 const dif_pwrmgr_t *pwrmgr, dif_pwrmgr_domain_config_t *config) {
322 if (pwrmgr == NULL || config == NULL) {
323 return kDifPwrmgrBadArg;
324 }
325
326 uint32_t reg_val =
327 mmio_region_read32(pwrmgr->params.base_addr, PWRMGR_CONTROL_REG_OFFSET);
328 *config = bitfield_field32_read(reg_val, kDomainConfigBitfield);
329
330 return kDifPwrmgrOk;
331}
332
333dif_pwrmgr_config_result_t dif_pwrmgr_set_request_sources(
334 const dif_pwrmgr_t *pwrmgr, dif_pwrmgr_req_type_t req_type,
335 dif_pwrmgr_request_sources_t sources) {
336 if (pwrmgr == NULL || !is_valid_req_type(req_type)) {
337 return kDifPwrmgrConfigBadArg;
338 }
339
340 request_reg_info_t reg_info = request_reg_infos[req_type];
341
342 if (!is_valid_for_bitfield(sources, reg_info.bitfield)) {
343 return kDifPwrmgrConfigBadArg;
344 }
345
346 // Return early if locked.
347 if (request_sources_is_locked(pwrmgr, req_type)) {
348 return kDifPwrMgrConfigLocked;
349 }
350
351 // Write new value
352 uint32_t reg_val = bitfield_field32_write(0, reg_info.bitfield, sources);
353 mmio_region_write32(pwrmgr->params.base_addr,
354 reg_info.sources_enable_reg_offset, reg_val);
355 // Slow clock domain must be synced for changes to take effect.
356 sync_slow_clock_domain_polled(pwrmgr);
357
358 return kDifPwrmgrConfigOk;
359}
360
361dif_pwrmgr_result_t dif_pwrmgr_get_request_sources(
362 const dif_pwrmgr_t *pwrmgr, dif_pwrmgr_req_type_t req_type,
363 dif_pwrmgr_request_sources_t *sources) {
364 if (pwrmgr == NULL || !is_valid_req_type(req_type) || sources == NULL) {
365 return kDifPwrmgrBadArg;
366 }
367
368 request_reg_info_t reg_info = request_reg_infos[req_type];
369 uint32_t reg_val = mmio_region_read32(pwrmgr->params.base_addr,
370 reg_info.sources_enable_reg_offset);
371 *sources = bitfield_field32_read(reg_val, reg_info.bitfield);
372
373 return kDifPwrmgrOk;
374}
375
376dif_pwrmgr_result_t dif_pwrmgr_get_current_request_sources(
377 const dif_pwrmgr_t *pwrmgr, dif_pwrmgr_req_type_t req_type,
378 dif_pwrmgr_request_sources_t *sources) {
379 if (pwrmgr == NULL || !is_valid_req_type(req_type) || sources == NULL) {
380 return kDifPwrmgrBadArg;
381 }
382
383 request_reg_info_t reg_info = request_reg_infos[req_type];
384 uint32_t reg_val = mmio_region_read32(pwrmgr->params.base_addr,
385 reg_info.cur_req_sources_reg_offset);
386 *sources = bitfield_field32_read(reg_val, reg_info.bitfield);
387
388 return kDifPwrmgrOk;
389}
390
391dif_pwrmgr_result_t dif_pwrmgr_request_sources_lock(
392 const dif_pwrmgr_t *pwrmgr, dif_pwrmgr_req_type_t req_type) {
393 if (pwrmgr == NULL || !is_valid_req_type(req_type)) {
394 return kDifPwrmgrBadArg;
395 }
396
397 // Only a single bit of this register is significant, thus we don't perform a
398 // read-modify-write. Setting this bit to 0 locks sources.
399 mmio_region_write32(pwrmgr->params.base_addr,
400 request_reg_infos[req_type].write_enable_reg_offset, 0);
401
402 return kDifPwrmgrOk;
403}
404
405dif_pwrmgr_result_t dif_pwrmgr_request_sources_is_locked(
406 const dif_pwrmgr_t *pwrmgr, dif_pwrmgr_req_type_t req_type,
407 bool *is_locked) {
408 if (pwrmgr == NULL || !is_valid_req_type(req_type) || is_locked == NULL) {
409 return kDifPwrmgrBadArg;
410 }
411
412 *is_locked = request_sources_is_locked(pwrmgr, req_type);
413
414 return kDifPwrmgrOk;
415}
416
417dif_pwrmgr_result_t dif_pwrmgr_wakeup_request_recording_set_enabled(
418 const dif_pwrmgr_t *pwrmgr, dif_pwrmgr_toggle_t new_state) {
419 if (pwrmgr == NULL) {
420 return kDifPwrmgrBadArg;
421 }
422
423 bool enable = false;
424 if (!toggle_to_bool(new_state, &enable)) {
425 return kDifPwrmgrBadArg;
426 }
427
428 // Only a single bit of this register is significant, thus we don't perform a
429 // read-modify-write. Setting this bit to 1 disables recording.
430 uint32_t reg_val =
Miguel Young de la Sota4e1a4a32020-11-05 10:08:52 -0500431 bitfield_bit32_write(0, PWRMGR_WAKE_INFO_CAPTURE_DIS_VAL_BIT, !enable);
Alphan Ulusoy1bbcedd2020-09-30 17:32:06 -0400432
433 mmio_region_write32(pwrmgr->params.base_addr,
434 PWRMGR_WAKE_INFO_CAPTURE_DIS_REG_OFFSET, reg_val);
435
436 return kDifPwrmgrOk;
437}
438
439dif_pwrmgr_result_t dif_pwrmgr_wakeup_request_recording_get_enabled(
440 const dif_pwrmgr_t *pwrmgr, dif_pwrmgr_toggle_t *cur_state) {
441 if (pwrmgr == NULL || cur_state == NULL) {
442 return kDifPwrmgrBadArg;
443 }
444
445 uint32_t reg_val = mmio_region_read32(
446 pwrmgr->params.base_addr, PWRMGR_WAKE_INFO_CAPTURE_DIS_REG_OFFSET);
447 // Recording is disabled if this bit is set to 1.
448 *cur_state = bool_to_toggle(
Miguel Young de la Sota4e1a4a32020-11-05 10:08:52 -0500449 !bitfield_bit32_read(reg_val, PWRMGR_WAKE_INFO_CAPTURE_DIS_VAL_BIT));
Alphan Ulusoy1bbcedd2020-09-30 17:32:06 -0400450
451 return kDifPwrmgrOk;
452}
453
454dif_pwrmgr_result_t dif_pwrmgr_wakeup_reason_get(
455 const dif_pwrmgr_t *pwrmgr, dif_pwrmgr_wakeup_reason_t *reason) {
456 if (pwrmgr == NULL || reason == NULL) {
457 return kDifPwrmgrBadArg;
458 }
459
460 uint32_t reg_val =
461 mmio_region_read32(pwrmgr->params.base_addr, PWRMGR_WAKE_INFO_REG_OFFSET);
462
463 dif_pwrmgr_wakeup_types_t types = 0;
Miguel Young de la Sota4e1a4a32020-11-05 10:08:52 -0500464 if (bitfield_bit32_read(reg_val, PWRMGR_WAKE_INFO_FALL_THROUGH_BIT)) {
Alphan Ulusoy1bbcedd2020-09-30 17:32:06 -0400465 types |= kDifPwrmgrWakeupTypeFallThrough;
466 }
Miguel Young de la Sota4e1a4a32020-11-05 10:08:52 -0500467 if (bitfield_bit32_read(reg_val, PWRMGR_WAKE_INFO_ABORT_BIT)) {
Alphan Ulusoy1bbcedd2020-09-30 17:32:06 -0400468 types |= kDifPwrmgrWakeupTypeAbort;
469 }
470
471 uint32_t request_sources = bitfield_field32_read(
472 reg_val, request_reg_infos[kDifPwrmgrReqTypeWakeup].bitfield);
473 if (request_sources != 0) {
474 types |= kDifPwrmgrWakeupTypeRequest;
475 }
476
477 *reason = (dif_pwrmgr_wakeup_reason_t){
478 .types = types,
479 .request_sources = request_sources,
480 };
481
482 return kDifPwrmgrOk;
483}
484
485dif_pwrmgr_result_t dif_pwrmgr_wakeup_reason_clear(const dif_pwrmgr_t *pwrmgr) {
486 if (pwrmgr == NULL) {
487 return kDifPwrmgrBadArg;
488 }
489
490 mmio_region_write32(pwrmgr->params.base_addr, PWRMGR_WAKE_INFO_REG_OFFSET,
491 UINT32_MAX);
492
493 return kDifPwrmgrOk;
494}
495
496dif_pwrmgr_result_t dif_pwrmgr_irq_is_pending(const dif_pwrmgr_t *pwrmgr,
497 dif_pwrmgr_irq_t irq,
498 bool *is_pending) {
499 if (pwrmgr == NULL || !is_valid_irq(irq) || is_pending == NULL) {
500 return kDifPwrmgrBadArg;
501 }
502
503 uint32_t reg_val = mmio_region_read32(pwrmgr->params.base_addr,
504 PWRMGR_INTR_STATE_REG_OFFSET);
505 *is_pending = bitfield_bit32_read(reg_val, irq);
506
507 return kDifPwrmgrOk;
508}
509
510dif_pwrmgr_result_t dif_pwrmgr_irq_acknowledge(const dif_pwrmgr_t *pwrmgr,
511 dif_pwrmgr_irq_t irq) {
512 if (pwrmgr == NULL || !is_valid_irq(irq)) {
513 return kDifPwrmgrBadArg;
514 }
515
516 uint32_t reg_val = bitfield_bit32_write(0, irq, true);
517 mmio_region_write32(pwrmgr->params.base_addr, PWRMGR_INTR_STATE_REG_OFFSET,
518 reg_val);
519
520 return kDifPwrmgrOk;
521}
522
523dif_pwrmgr_result_t dif_pwrmgr_irq_get_enabled(const dif_pwrmgr_t *pwrmgr,
524 dif_pwrmgr_irq_t irq,
525 dif_pwrmgr_toggle_t *state) {
526 if (pwrmgr == NULL || !is_valid_irq(irq) || state == NULL) {
527 return kDifPwrmgrBadArg;
528 }
529
530 uint32_t reg_val = mmio_region_read32(pwrmgr->params.base_addr,
531 PWRMGR_INTR_ENABLE_REG_OFFSET);
532 *state = bool_to_toggle(bitfield_bit32_read(reg_val, irq));
533
534 return kDifPwrmgrOk;
535}
536
537dif_pwrmgr_result_t dif_pwrmgr_irq_set_enabled(const dif_pwrmgr_t *pwrmgr,
538 dif_pwrmgr_irq_t irq,
539 dif_pwrmgr_toggle_t state) {
540 if (pwrmgr == NULL || !is_valid_irq(irq)) {
541 return kDifPwrmgrBadArg;
542 }
543
544 bool enable = false;
545 if (!toggle_to_bool(state, &enable)) {
546 return kDifPwrmgrBadArg;
547 }
548
549 uint32_t reg_val = mmio_region_read32(pwrmgr->params.base_addr,
550 PWRMGR_INTR_ENABLE_REG_OFFSET);
551 reg_val = bitfield_bit32_write(reg_val, irq, enable);
552 mmio_region_write32(pwrmgr->params.base_addr, PWRMGR_INTR_ENABLE_REG_OFFSET,
553 reg_val);
554
555 return kDifPwrmgrOk;
556}
557
558dif_pwrmgr_result_t dif_pwrmgr_irq_force(const dif_pwrmgr_t *pwrmgr,
559 dif_pwrmgr_irq_t irq) {
560 if (pwrmgr == NULL || !is_valid_irq(irq)) {
561 return kDifPwrmgrBadArg;
562 }
563
564 uint32_t reg_val = bitfield_bit32_write(0, irq, true);
565 mmio_region_write32(pwrmgr->params.base_addr, PWRMGR_INTR_TEST_REG_OFFSET,
566 reg_val);
567
568 return kDifPwrmgrOk;
569}
570
571dif_pwrmgr_result_t dif_pwrmgr_irq_disable_all(
572 const dif_pwrmgr_t *pwrmgr, dif_pwrmgr_irq_snapshot_t *snapshot) {
573 if (pwrmgr == NULL) {
574 return kDifPwrmgrBadArg;
575 }
576
577 if (snapshot != NULL) {
578 *snapshot = mmio_region_read32(pwrmgr->params.base_addr,
579 PWRMGR_INTR_ENABLE_REG_OFFSET);
580 }
581 mmio_region_write32(pwrmgr->params.base_addr, PWRMGR_INTR_ENABLE_REG_OFFSET,
582 0);
583
584 return kDifPwrmgrOk;
585}
586
587dif_pwrmgr_result_t dif_pwrmgr_irq_restore_all(
Philipp Wagner930dbd32021-06-17 17:50:26 +0100588 const dif_pwrmgr_t *pwrmgr, dif_pwrmgr_irq_snapshot_t snapshot) {
589 if (pwrmgr == NULL) {
Alphan Ulusoy1bbcedd2020-09-30 17:32:06 -0400590 return kDifPwrmgrBadArg;
591 }
592
593 mmio_region_write32(pwrmgr->params.base_addr, PWRMGR_INTR_ENABLE_REG_OFFSET,
Philipp Wagner930dbd32021-06-17 17:50:26 +0100594 snapshot);
Alphan Ulusoy1bbcedd2020-09-30 17:32:06 -0400595 return kDifPwrmgrOk;
596}
Timothy Trippelef5bc5e2021-08-06 22:40:11 +0000597
598dif_pwrmgr_result_t dif_pwrmgr_alert_force(const dif_pwrmgr_t *pwrmgr,
599 dif_pwrmgr_alert_t alert) {
600 if (pwrmgr == NULL) {
601 return kDifPwrmgrBadArg;
602 }
603
604 bitfield_bit32_index_t index;
605 switch (alert) {
606 case kDifPwrmgrAlertFatalFault:
607 index = PWRMGR_ALERT_TEST_FATAL_FAULT_BIT;
608 break;
609 default:
610 return kDifPwrmgrBadArg;
611 }
612
613 uint32_t reg = bitfield_bit32_write(0, index, true);
614 mmio_region_write32(pwrmgr->params.base_addr, PWRMGR_ALERT_TEST_REG_OFFSET,
615 reg);
616
617 return kDifPwrmgrOk;
618}