Software APIs
dif_pwrmgr.c
1 // Copyright lowRISC contributors (OpenTitan project).
2 // Licensed under the Apache License, Version 2.0, see LICENSE for details.
3 // SPDX-License-Identifier: Apache-2.0
4 
6 
7 #include <assert.h>
8 
12 
13 #include "pwrmgr_regs.h" // Generated.
14 
15 /**
16  * Following static assertions make sure that generated values match the
17  * definitions in the header, which we rely on for a simpler implementation.
18  * These constants and their usages must be revisited if there is a change in
19  * hardware.
20  */
21 
22 /**
23  * Relevant bits of the control register must start at
24  * `PWRMGR_CONTROL_CORE_CLK_EN_BIT` and be in the same order as
25  * `dif_pwrmgr_domain_option_t` constants.
26  */
28  (1u << (PWRMGR_CONTROL_CORE_CLK_EN_BIT -
29  PWRMGR_CONTROL_CORE_CLK_EN_BIT)),
30  "Layout of control register changed.");
31 
33  (1u << (PWRMGR_CONTROL_IO_CLK_EN_BIT -
34  PWRMGR_CONTROL_CORE_CLK_EN_BIT)),
35  "Layout of control register changed.");
36 
37 #if defined(OPENTITAN_IS_EARLGREY)
38 static_assert(kDifPwrmgrDomainOptionUsbClockInLowPower ==
39  (1u << (PWRMGR_CONTROL_USB_CLK_EN_LP_BIT -
40  PWRMGR_CONTROL_CORE_CLK_EN_BIT)),
41  "Layout of control register changed.");
42 
43 static_assert(kDifPwrmgrDomainOptionUsbClockInActivePower ==
44  (1u << (PWRMGR_CONTROL_USB_CLK_EN_ACTIVE_BIT -
45  PWRMGR_CONTROL_CORE_CLK_EN_BIT)),
46  "Layout of control register changed.");
47 #endif /* OPENTITAN_IS */
48 
49 static_assert(kDifPwrmgrDomainOptionMainPowerInLowPower ==
50  (1u << (PWRMGR_CONTROL_MAIN_PD_N_BIT -
51  PWRMGR_CONTROL_CORE_CLK_EN_BIT)),
52  "Layout of control register changed.");
53 
54 /**
55  * Bitfield for interpreting the configuration options in the control
56  * register.
57  */
58 static const bitfield_field32_t kDomainConfigBitfield = {
61 #if defined(OPENTITAN_IS_EARLGREY)
62  kDifPwrmgrDomainOptionUsbClockInLowPower |
63  kDifPwrmgrDomainOptionUsbClockInActivePower |
64 #elif defined(OPENTITAN_IS_DARJEELING)
65 /* Darjeeling has no USB clock. */
66 #else
67 #error "dif_pwrmgr does not support this top"
68 #endif
69  kDifPwrmgrDomainOptionMainPowerInLowPower,
70  .index = PWRMGR_CONTROL_CORE_CLK_EN_BIT,
71 };
72 
73 /**
74  * `dif_pwrmgr_irq_t` constants must match the corresponding generated values.
75  */
76 static_assert(kDifPwrmgrIrqWakeup == PWRMGR_INTR_COMMON_WAKEUP_BIT,
77  "Layout of interrupt registers changed.");
78 
79 /**
80  * Register information for a request type.
81  */
82 typedef struct request_reg_info {
83  ptrdiff_t write_enable_reg_offset;
84  bitfield_bit32_index_t write_enable_bit_index;
85  ptrdiff_t sources_enable_reg_offset;
86  ptrdiff_t cur_req_sources_reg_offset;
88 
89 /**
90  * Register information for wakeup and reset requests.
91  *
92  * Wakeup and reset requests follow the same logic for configuration and
93  * monitoring but use different registers. Defining these constants here
94  * allows us to use the same code for both types of requests.
95  */
96 static const request_reg_info_t request_reg_infos[2] = {
98  {
99  .write_enable_reg_offset = PWRMGR_WAKEUP_EN_REGWEN_REG_OFFSET,
100  .write_enable_bit_index = PWRMGR_WAKEUP_EN_REGWEN_EN_BIT,
101  .sources_enable_reg_offset = PWRMGR_WAKEUP_EN_REG_OFFSET,
102  .cur_req_sources_reg_offset = PWRMGR_WAKE_STATUS_REG_OFFSET,
103  },
105  {
106  .write_enable_reg_offset = PWRMGR_RESET_EN_REGWEN_REG_OFFSET,
107  .write_enable_bit_index = PWRMGR_RESET_EN_REGWEN_EN_BIT,
108  .sources_enable_reg_offset = PWRMGR_RESET_EN_REG_OFFSET,
109  .cur_req_sources_reg_offset = PWRMGR_RESET_STATUS_REG_OFFSET,
110  },
111 };
112 
114  const dif_pwrmgr_t *pwrmgr, dif_pwrmgr_req_type_t req_type,
115  dt_instance_id_t inst_id, size_t sig_idx,
116  dif_pwrmgr_request_sources_t *sources) {
117  if (pwrmgr == NULL || sources == NULL) {
118  return kDifBadArg;
119  }
120  dt_pwrmgr_t dt;
121  DIF_RETURN_IF_ERROR(dif_pwrmgr_get_dt(pwrmgr, &dt));
122  // Query the DT to find the information.
123  if (req_type == kDifPwrmgrReqTypeWakeup) {
124  for (size_t i = 0; i < dt_pwrmgr_wakeup_src_count(dt); i++) {
125  dt_pwrmgr_wakeup_src_t src = dt_pwrmgr_wakeup_src(dt, i);
126  if (src.inst_id == inst_id && src.wakeup == sig_idx) {
127  *sources = 1u << i;
128  return kDifOk;
129  }
130  }
131  return kDifError;
132  } else if (req_type == kDifPwrmgrReqTypeReset) {
133  for (size_t i = 0; i < dt_pwrmgr_reset_request_src_count(dt); i++) {
134  dt_pwrmgr_reset_req_src_t src = dt_pwrmgr_reset_request_src(dt, i);
135  if (src.inst_id == inst_id && src.reset_req == sig_idx) {
136  *sources = 1u << i;
137  return kDifOk;
138  }
139  }
140  return kDifError;
141  } else {
142  return kDifBadArg;
143  }
144 }
145 
146 /**
147  * Obtain the bitfield in PWRMGR_{WAKEUP,RESET}_EN_REG_OFFSET which
148  * represents all wakeup/reset sources.
149  */
151 static dif_result_t request_reg_bitfield(const dif_pwrmgr_t *pwrmgr,
152  dif_pwrmgr_req_type_t req_type,
153  bitfield_field32_t *bitfield) {
154  dt_pwrmgr_t dt;
155  dif_result_t res = dif_pwrmgr_get_dt(pwrmgr, &dt);
156  if (res != kDifOk) {
157  return res;
158  }
159 
160  size_t count = 0;
161  if (req_type == kDifPwrmgrReqTypeWakeup) {
162  count = dt_pwrmgr_wakeup_src_count(dt);
163  } else if (req_type == kDifPwrmgrReqTypeReset) {
164  count = dt_pwrmgr_reset_request_src_count(dt);
165  } else {
166  return kDifBadArg;
167  }
168  bitfield->index = 0;
169  bitfield->mask = (1 << count) - 1;
170  return kDifOk;
171 }
172 
174  const dif_pwrmgr_t *pwrmgr, dif_pwrmgr_req_type_t req_type,
175  dif_pwrmgr_request_sources_t *sources) {
176  bitfield_field32_t bitfield;
177  dif_result_t res = request_reg_bitfield(pwrmgr, req_type, &bitfield);
178  if (res == kDifOk) {
179  *sources = bitfield.mask;
180  }
181  return res;
182 }
183 
184 /**
185  * Checks if a value is a valid `dif_pwrmgr_req_type_t`.
186  */
188 static bool is_valid_req_type(dif_pwrmgr_req_type_t val) {
189  return val == kDifPwrmgrReqTypeWakeup || val == kDifPwrmgrReqTypeReset;
190 }
191 
192 /**
193  * Checks if a value is valid for, i.e. fits in the mask of, a
194  * `bitfield_field32_t`.
195  */
197 static bool is_valid_for_bitfield(uint32_t val, bitfield_field32_t bitfield) {
198  return (val & bitfield.mask) == val;
199 }
200 
201 /**
202  * Checks if the control register is locked.
203  *
204  * Control register is locked when low power is enabled and WFI occurs. It is
205  * unlocked when the chip transitions back to active power state.
206  */
208 static bool control_register_is_locked(const dif_pwrmgr_t *pwrmgr) {
209  // Control register is locked when `PWRMGR_CTRL_CFG_REGWEN_EN_BIT` bit is 0.
210  return !bitfield_bit32_read(
211  mmio_region_read32(pwrmgr->base_addr, PWRMGR_CTRL_CFG_REGWEN_REG_OFFSET),
212  PWRMGR_CTRL_CFG_REGWEN_EN_BIT);
213 }
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  */
221 static void sync_slow_clock_domain_polled(const dif_pwrmgr_t *pwrmgr) {
222  // Start sync and wait for it to finish.
223  mmio_region_write32(
224  pwrmgr->base_addr, PWRMGR_CFG_CDC_SYNC_REG_OFFSET,
225  bitfield_bit32_write(0, PWRMGR_CFG_CDC_SYNC_SYNC_BIT, true));
226  while (bitfield_bit32_read(
227  mmio_region_read32(pwrmgr->base_addr, PWRMGR_CFG_CDC_SYNC_REG_OFFSET),
228  PWRMGR_CFG_CDC_SYNC_SYNC_BIT)) {
229  }
230 }
231 
232 /**
233  * Checks if sources of a request type are locked.
234  */
236 static 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 =
240  mmio_region_read32(pwrmgr->base_addr, 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 
246  dif_toggle_t new_state,
247  dif_toggle_t sync_state) {
248  if (pwrmgr == NULL || !dif_is_valid_toggle(new_state) ||
249  !dif_is_valid_toggle(sync_state)) {
250  return kDifBadArg;
251  }
252 
253  if (control_register_is_locked(pwrmgr)) {
254  return kDifLocked;
255  }
256 
257  uint32_t reg_val =
258  mmio_region_read32(pwrmgr->base_addr, PWRMGR_CONTROL_REG_OFFSET);
259  reg_val = bitfield_bit32_write(reg_val, PWRMGR_CONTROL_LOW_POWER_HINT_BIT,
260  dif_toggle_to_bool(new_state));
261  mmio_region_write32(pwrmgr->base_addr, PWRMGR_CONTROL_REG_OFFSET, reg_val);
262 
263  // Slow clock domain may be synced for changes to take effect.
264  if (sync_state == kDifToggleEnabled)
265  sync_slow_clock_domain_polled(pwrmgr);
266 
267  return kDifOk;
268 }
269 
271  dif_toggle_t *cur_state) {
272  if (pwrmgr == NULL || cur_state == NULL) {
273  return kDifBadArg;
274  }
275 
276  uint32_t reg_val =
277  mmio_region_read32(pwrmgr->base_addr, PWRMGR_CONTROL_REG_OFFSET);
278  *cur_state = dif_bool_to_toggle(
279  bitfield_bit32_read(reg_val, PWRMGR_CONTROL_LOW_POWER_HINT_BIT));
280 
281  return kDifOk;
282 }
283 
284 dif_result_t dif_pwrmgr_set_domain_config(const dif_pwrmgr_t *pwrmgr,
286  dif_toggle_t sync_state) {
287  if (pwrmgr == NULL || !is_valid_for_bitfield(config, kDomainConfigBitfield) ||
288  !dif_is_valid_toggle(sync_state)) {
289  return kDifBadArg;
290  }
291 
292  if (control_register_is_locked(pwrmgr)) {
293  return kDifLocked;
294  }
295 
296  uint32_t reg_val =
297  mmio_region_read32(pwrmgr->base_addr, PWRMGR_CONTROL_REG_OFFSET);
298  reg_val = bitfield_field32_write(reg_val, kDomainConfigBitfield, config);
299  mmio_region_write32(pwrmgr->base_addr, PWRMGR_CONTROL_REG_OFFSET, reg_val);
300 
301  // Slow clock domain must be synced for changes to take effect.
302  if (sync_state == kDifToggleEnabled)
303  sync_slow_clock_domain_polled(pwrmgr);
304 
305  return kDifOk;
306 }
307 
308 dif_result_t dif_pwrmgr_get_domain_config(const dif_pwrmgr_t *pwrmgr,
309  dif_pwrmgr_domain_config_t *config) {
310  if (pwrmgr == NULL || config == NULL) {
311  return kDifBadArg;
312  }
313 
314  uint32_t reg_val =
315  mmio_region_read32(pwrmgr->base_addr, PWRMGR_CONTROL_REG_OFFSET);
317  reg_val, kDomainConfigBitfield);
318 
319  return kDifOk;
320 }
321 
323  const dif_pwrmgr_t *pwrmgr, dif_pwrmgr_req_type_t req_type,
324  dif_pwrmgr_request_sources_t sources, dif_toggle_t sync_state) {
325  if (pwrmgr == NULL || !is_valid_req_type(req_type) ||
326  !dif_is_valid_toggle(sync_state)) {
327  return kDifBadArg;
328  }
329 
330  request_reg_info_t reg_info = request_reg_infos[req_type];
331  bitfield_field32_t bitfield;
332  DIF_RETURN_IF_ERROR(request_reg_bitfield(pwrmgr, req_type, &bitfield));
333 
334  if (!is_valid_for_bitfield(sources, bitfield)) {
335  return kDifBadArg;
336  }
337 
338  // Return early if locked.
339  if (request_sources_is_locked(pwrmgr, req_type)) {
340  return kDifLocked;
341  }
342 
343  // Write new value
344  uint32_t reg_val = bitfield_field32_write(0, bitfield, sources);
345  mmio_region_write32(pwrmgr->base_addr, reg_info.sources_enable_reg_offset,
346  reg_val);
347  // Slow clock domain may be synced for changes to take effect.
348  if (sync_state == kDifToggleEnabled)
349  sync_slow_clock_domain_polled(pwrmgr);
350 
351  return kDifOk;
352 }
353 
355  const dif_pwrmgr_t *pwrmgr, dif_pwrmgr_req_type_t req_type,
356  dif_pwrmgr_request_sources_t *sources) {
357  if (pwrmgr == NULL || !is_valid_req_type(req_type) || sources == NULL) {
358  return kDifBadArg;
359  }
360 
361  request_reg_info_t reg_info = request_reg_infos[req_type];
362  bitfield_field32_t bitfield;
363  dif_result_t res = request_reg_bitfield(pwrmgr, req_type, &bitfield);
364  if (res != kDifOk) {
365  return res;
366  }
367  uint32_t reg_val =
368  mmio_region_read32(pwrmgr->base_addr, reg_info.sources_enable_reg_offset);
369  *sources = bitfield_field32_read(reg_val, bitfield);
370 
371  return kDifOk;
372 }
373 
375  const dif_pwrmgr_t *pwrmgr, dif_pwrmgr_req_type_t req_type,
376  dif_pwrmgr_request_sources_t *sources) {
377  if (pwrmgr == NULL || !is_valid_req_type(req_type) || sources == NULL) {
378  return kDifBadArg;
379  }
380 
381  request_reg_info_t reg_info = request_reg_infos[req_type];
382  bitfield_field32_t bitfield;
383  dif_result_t res = request_reg_bitfield(pwrmgr, req_type, &bitfield);
384  if (res != kDifOk) {
385  return res;
386  }
387  uint32_t reg_val = mmio_region_read32(pwrmgr->base_addr,
388  reg_info.cur_req_sources_reg_offset);
389  *sources = bitfield_field32_read(reg_val, bitfield);
390 
391  return kDifOk;
392 }
393 
395  dif_pwrmgr_req_type_t req_type) {
396  if (pwrmgr == NULL || !is_valid_req_type(req_type)) {
397  return kDifBadArg;
398  }
399 
400  // Only a single bit of this register is significant, thus we don't perform a
401  // read-modify-write. Setting this bit to 0 locks sources.
402  mmio_region_write32(pwrmgr->base_addr,
403  request_reg_infos[req_type].write_enable_reg_offset, 0);
404 
405  return kDifOk;
406 }
407 
409  const dif_pwrmgr_t *pwrmgr, dif_pwrmgr_req_type_t req_type,
410  bool *is_locked) {
411  if (pwrmgr == NULL || !is_valid_req_type(req_type) || is_locked == NULL) {
412  return kDifBadArg;
413  }
414 
415  *is_locked = request_sources_is_locked(pwrmgr, req_type);
416 
417  return kDifOk;
418 }
419 
421  const dif_pwrmgr_t *pwrmgr, dif_toggle_t new_state) {
422  if (pwrmgr == NULL || !dif_is_valid_toggle(new_state)) {
423  return kDifBadArg;
424  }
425 
426  // Only a single bit of this register is significant, thus we don't perform a
427  // read-modify-write. Setting this bit to 1 disables recording.
428  uint32_t reg_val = bitfield_bit32_write(
429  0, PWRMGR_WAKE_INFO_CAPTURE_DIS_VAL_BIT, !dif_toggle_to_bool(new_state));
430  mmio_region_write32(pwrmgr->base_addr,
431  PWRMGR_WAKE_INFO_CAPTURE_DIS_REG_OFFSET, reg_val);
432 
433  return kDifOk;
434 }
435 
437  const dif_pwrmgr_t *pwrmgr, dif_toggle_t *cur_state) {
438  if (pwrmgr == NULL || cur_state == NULL) {
439  return kDifBadArg;
440  }
441 
442  uint32_t reg_val = mmio_region_read32(
443  pwrmgr->base_addr, PWRMGR_WAKE_INFO_CAPTURE_DIS_REG_OFFSET);
444  // Recording is disabled if this bit is set to 1.
445  *cur_state = dif_bool_to_toggle(
446  !bitfield_bit32_read(reg_val, PWRMGR_WAKE_INFO_CAPTURE_DIS_VAL_BIT));
447 
448  return kDifOk;
449 }
450 
451 dif_result_t dif_pwrmgr_wakeup_reason_get(const dif_pwrmgr_t *pwrmgr,
452  dif_pwrmgr_wakeup_reason_t *reason) {
453  if (pwrmgr == NULL || reason == NULL) {
454  return kDifBadArg;
455  }
456 
457  uint32_t reg_val =
458  mmio_region_read32(pwrmgr->base_addr, PWRMGR_WAKE_INFO_REG_OFFSET);
459 
460  dif_pwrmgr_wakeup_types_t types = 0;
461  if (bitfield_bit32_read(reg_val, PWRMGR_WAKE_INFO_FALL_THROUGH_BIT)) {
463  }
464  if (bitfield_bit32_read(reg_val, PWRMGR_WAKE_INFO_ABORT_BIT)) {
465  types |= kDifPwrmgrWakeupTypeAbort;
466  }
467 
468  bitfield_field32_t bitfield;
469  dif_result_t res =
470  request_reg_bitfield(pwrmgr, kDifPwrmgrReqTypeWakeup, &bitfield);
471  if (res != kDifOk) {
472  return res;
473  }
474  uint32_t request_sources = bitfield_field32_read(reg_val, bitfield);
475  if (request_sources != 0) {
477  }
478 
479  *reason = (dif_pwrmgr_wakeup_reason_t){
480  .types = types,
481  .request_sources = request_sources,
482  };
483 
484  return kDifOk;
485 }
486 
487 dif_result_t dif_pwrmgr_wakeup_reason_clear(const dif_pwrmgr_t *pwrmgr) {
488  if (pwrmgr == NULL) {
489  return kDifBadArg;
490  }
491 
492  mmio_region_write32(pwrmgr->base_addr, PWRMGR_WAKE_INFO_REG_OFFSET,
493  UINT32_MAX);
494 
495  return kDifOk;
496 }
497 
499  const dif_pwrmgr_t *pwrmgr, dif_pwrmgr_fatal_err_codes_t *codes) {
500  if (pwrmgr == NULL || codes == NULL) {
501  return kDifBadArg;
502  }
503  *codes =
504  mmio_region_read32(pwrmgr->base_addr, PWRMGR_FAULT_STATUS_REG_OFFSET);
505  return kDifOk;
506 }