Software APIs
dif_clkmgr.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
11#include "sw/device/lib/base/multibits.h"
13
14#include "clkmgr_regs.h" // Generated
15
16// TODO: For the moment, CLKMGR_PARAM_NUM_SW_GATEABLE_CLOCKS has to be <= than
17// 32, as we only support one enable register for gateable clocks.
18// https://github.com/lowRISC/opentitan/issues/4201
19static_assert(
20 CLKMGR_PARAM_NUM_SW_GATEABLE_CLOCKS <= CLKMGR_PARAM_REG_WIDTH,
21 "Expected the number of gateable clocks to be <= the width of a CSR.");
22
23// TODO: For the moment, CLKMGR_PARAM_NUM_HINTABLE_CLOCKS has to be <= than
24// 32, as we only support one enable/hint_status register for hintable clocks.
25// https://github.com/lowRISC/opentitan/issues/4201
26static_assert(
27 CLKMGR_PARAM_NUM_HINTABLE_CLOCKS <= CLKMGR_PARAM_REG_WIDTH,
28 "Expected the number of hintable clocks to be <= the width of a CSR.");
29
30static bool clkmgr_valid_gateable_clock(dif_clkmgr_gateable_clock_t clock) {
31 return clock < CLKMGR_PARAM_NUM_SW_GATEABLE_CLOCKS;
32}
33
34static bool clkmgr_valid_hintable_clock(dif_clkmgr_hintable_clock_t clock) {
35 return clock < CLKMGR_PARAM_NUM_HINTABLE_CLOCKS;
36}
37
38static bool clkmgr_measure_ctrl_regwen(const dif_clkmgr_t *clkmgr) {
39 uint32_t measure_ctrl_regwen_val = mmio_region_read32(
40 clkmgr->base_addr, CLKMGR_MEASURE_CTRL_REGWEN_REG_OFFSET);
41 return bitfield_bit32_read(measure_ctrl_regwen_val,
42 CLKMGR_MEASURE_CTRL_REGWEN_EN_BIT);
43}
44
45/**
46 * Checks if the jitter enable register is locked.
47 *
48 * The jitter enable register is locked by CLKMGR_JITTER_REGWEN.
49 */
51static bool jitter_enable_register_is_locked(const dif_clkmgr_t *clkmgr) {
52 // Jitter enable register is locked when `CLKMGR_JITTER_REGWEN_EN_BIT` bit
53 // is 0.
54 return !bitfield_bit32_read(
55 mmio_region_read32(clkmgr->base_addr, CLKMGR_JITTER_REGWEN_REG_OFFSET),
56 CLKMGR_JITTER_REGWEN_EN_BIT);
57}
58
59/**
60 * Checks if the external clock control register is locked.
61 *
62 * The external clock control register is locked by CLKMGR_EXTCLK_CTRL_REGWEN.
63 */
65static bool extclk_control_register_is_locked(const dif_clkmgr_t *clkmgr) {
66 // External clock control register is locked when
67 // `CLKMGR_EXTCLK_CTRL_REGWEN_EN_BIT` bit is 0.
68 return !bitfield_bit32_read(
69 mmio_region_read32(clkmgr->base_addr,
70 CLKMGR_EXTCLK_CTRL_REGWEN_REG_OFFSET),
71 CLKMGR_EXTCLK_CTRL_REGWEN_EN_BIT);
72}
73
74dif_result_t dif_clkmgr_external_clock_is_settled(const dif_clkmgr_t *clkmgr,
75 bool *status) {
76 if (clkmgr == NULL || status == NULL) {
77 return kDifBadArg;
78 }
79 uint32_t extclk_status_val =
80 mmio_region_read32(clkmgr->base_addr, CLKMGR_EXTCLK_STATUS_REG_OFFSET);
81 *status = bitfield_field32_read(extclk_status_val,
82 CLKMGR_EXTCLK_STATUS_ACK_FIELD) ==
83 kMultiBitBool4True;
84
85 return kDifOk;
86}
87
88dif_result_t dif_clkmgr_jitter_enable_is_locked(const dif_clkmgr_t *clkmgr,
89 bool *is_locked) {
90 if (clkmgr == NULL || is_locked == NULL) {
91 return kDifBadArg;
92 }
93
94 *is_locked = jitter_enable_register_is_locked(clkmgr);
95
96 return kDifOk;
97}
98
99dif_result_t dif_clkmgr_lock_jitter_enable(const dif_clkmgr_t *clkmgr) {
100 if (clkmgr == NULL) {
101 return kDifBadArg;
102 }
103 mmio_region_write32(clkmgr->base_addr, CLKMGR_JITTER_REGWEN_REG_OFFSET, 0);
104 return kDifOk;
105}
106
107dif_result_t dif_clkmgr_jitter_get_enabled(const dif_clkmgr_t *clkmgr,
108 dif_toggle_t *state) {
109 if (clkmgr == NULL || state == NULL) {
110 return kDifBadArg;
111 }
112
113 multi_bit_bool_t clk_jitter_val =
114 mmio_region_read32(clkmgr->base_addr, CLKMGR_JITTER_ENABLE_REG_OFFSET);
115 // The documentation states that kMultiBitBool4False disables the jittery
116 // clock and all other values enable the jittery clock.
117 *state = clk_jitter_val != kMultiBitBool4False ? kDifToggleEnabled
119
120 return kDifOk;
121}
122
123dif_result_t dif_clkmgr_jitter_set_enabled(const dif_clkmgr_t *clkmgr,
124 dif_toggle_t new_state) {
125 multi_bit_bool_t new_jitter_enable_val;
126 if (clkmgr == NULL) {
127 return kDifBadArg;
128 }
129 if (jitter_enable_register_is_locked(clkmgr)) {
130 return kDifLocked;
131 }
132
133 switch (new_state) {
135 new_jitter_enable_val = kMultiBitBool4True;
136 break;
138 new_jitter_enable_val = kMultiBitBool4False;
139 break;
140 default:
141 return kDifBadArg;
142 }
143 mmio_region_write32(clkmgr->base_addr, CLKMGR_JITTER_ENABLE_REG_OFFSET,
144 new_jitter_enable_val);
145 return kDifOk;
146}
147
149dif_result_t dif_clkmgr_find_gateable_clock(
150 const dif_clkmgr_t *clkmgr, dt_instance_id_t inst_id,
152 if (clkmgr == NULL || clock == NULL) {
153 return kDifBadArg;
154 }
155 dt_clkmgr_t dt;
156 dif_result_t res = dif_clkmgr_get_dt(clkmgr, &dt);
157 if (res != kDifOk) {
158 return res;
159 }
160 // Query the DT to find the information.
161 for (size_t i = 0; i < dt_clkmgr_gateable_clock_count(dt); i++) {
162 if (dt_clkmgr_gateable_clock(dt, i) == inst_id) {
163 *clock = i;
164 return kDifOk;
165 }
166 }
167 return kDifError;
168}
169
170dif_result_t dif_clkmgr_gateable_clock_get_enabled(
171 const dif_clkmgr_t *clkmgr, dif_clkmgr_gateable_clock_t clock,
172 dif_toggle_t *state) {
173 if (clkmgr == NULL || state == NULL || !clkmgr_valid_gateable_clock(clock)) {
174 return kDifBadArg;
175 }
176
177 uint32_t clk_enables_val =
178 mmio_region_read32(clkmgr->base_addr, CLKMGR_CLK_ENABLES_REG_OFFSET);
179 *state = dif_bool_to_toggle(bitfield_bit32_read(clk_enables_val, clock));
180
181 return kDifOk;
182}
183
184dif_result_t dif_clkmgr_gateable_clock_set_enabled(
185 const dif_clkmgr_t *clkmgr, dif_clkmgr_gateable_clock_t clock,
186 dif_toggle_t new_state) {
187 if (clkmgr == NULL || !clkmgr_valid_gateable_clock(clock) ||
188 !dif_is_valid_toggle(new_state)) {
189 return kDifBadArg;
190 }
191
192 bool new_clk_enables_bit = dif_toggle_to_bool(new_state);
193 uint32_t clk_enables_val =
194 mmio_region_read32(clkmgr->base_addr, CLKMGR_CLK_ENABLES_REG_OFFSET);
195 clk_enables_val =
196 bitfield_bit32_write(clk_enables_val, clock, new_clk_enables_bit);
197 mmio_region_write32(clkmgr->base_addr, CLKMGR_CLK_ENABLES_REG_OFFSET,
198 clk_enables_val);
199
200 return kDifOk;
201}
202
204dif_result_t dif_clkmgr_find_hintable_clock(
205 const dif_clkmgr_t *clkmgr, dt_instance_id_t inst_id,
207 if (clkmgr == NULL || clock == NULL) {
208 return kDifBadArg;
209 }
210 dt_clkmgr_t dt;
211 dif_result_t res = dif_clkmgr_get_dt(clkmgr, &dt);
212 if (res != kDifOk) {
213 return res;
214 }
215 // Query the DT to find the information.
216 for (size_t i = 0; i < dt_clkmgr_hintable_clock_count(dt); i++) {
217 if (dt_clkmgr_hintable_clock(dt, i) == inst_id) {
218 *clock = i;
219 return kDifOk;
220 }
221 }
222 return kDifError;
223}
224
225dif_result_t dif_clkmgr_hintable_clock_get_enabled(
226 const dif_clkmgr_t *clkmgr, dif_clkmgr_hintable_clock_t clock,
227 dif_toggle_t *state) {
228 if (clkmgr == NULL || state == NULL || !clkmgr_valid_hintable_clock(clock)) {
229 return kDifBadArg;
230 }
231
232 uint32_t clk_hints_val =
233 mmio_region_read32(clkmgr->base_addr, CLKMGR_CLK_HINTS_STATUS_REG_OFFSET);
234 *state = dif_bool_to_toggle(bitfield_bit32_read(clk_hints_val, clock));
235
236 return kDifOk;
237}
238
239dif_result_t dif_clkmgr_hintable_clock_set_hint(
240 const dif_clkmgr_t *clkmgr, dif_clkmgr_hintable_clock_t clock,
241 dif_toggle_t new_state) {
242 if (clkmgr == NULL || !clkmgr_valid_hintable_clock(clock) ||
243 !dif_is_valid_toggle(new_state)) {
244 return kDifBadArg;
245 }
246
247 bool new_clk_hints_bit = dif_toggle_to_bool(new_state);
248 uint32_t clk_hints_val =
249 mmio_region_read32(clkmgr->base_addr, CLKMGR_CLK_HINTS_REG_OFFSET);
250 clk_hints_val = bitfield_bit32_write(clk_hints_val, clock, new_clk_hints_bit);
251 mmio_region_write32(clkmgr->base_addr, CLKMGR_CLK_HINTS_REG_OFFSET,
252 clk_hints_val);
253
254 return kDifOk;
255}
256
257dif_result_t dif_clkmgr_hintable_clock_get_hint(
258 const dif_clkmgr_t *clkmgr, dif_clkmgr_hintable_clock_t clock,
259 dif_toggle_t *state) {
260 if (clkmgr == NULL || state == NULL || !clkmgr_valid_hintable_clock(clock)) {
261 return kDifBadArg;
262 }
263
264 uint32_t clk_hints_val =
265 mmio_region_read32(clkmgr->base_addr, CLKMGR_CLK_HINTS_REG_OFFSET);
266 *state = dif_bool_to_toggle(bitfield_bit32_read(clk_hints_val, clock));
267
268 return kDifOk;
269}
270
271dif_result_t dif_clkmgr_external_clock_control_is_locked(
272 const dif_clkmgr_t *clkmgr, bool *is_locked) {
273 if (clkmgr == NULL || is_locked == NULL) {
274 return kDifBadArg;
275 }
276
277 *is_locked = extclk_control_register_is_locked(clkmgr);
278
279 return kDifOk;
280}
281
282dif_result_t dif_clkmgr_lock_external_clock_control(
283 const dif_clkmgr_t *clkmgr) {
284 if (clkmgr == NULL) {
285 return kDifBadArg;
286 }
287 mmio_region_write32(clkmgr->base_addr, CLKMGR_EXTCLK_CTRL_REGWEN_REG_OFFSET,
288 0);
289 return kDifOk;
290}
291
292dif_result_t dif_clkmgr_external_clock_set_enabled(const dif_clkmgr_t *clkmgr,
293 bool is_low_speed) {
294 uint32_t extclk_ctrl_reg = 0;
295
296 if (clkmgr == NULL) {
297 return kDifBadArg;
298 }
299
300 if (extclk_control_register_is_locked(clkmgr)) {
301 return kDifLocked;
302 }
303
304 extclk_ctrl_reg = bitfield_field32_write(
305 extclk_ctrl_reg, CLKMGR_EXTCLK_CTRL_SEL_FIELD, kMultiBitBool4True);
306 extclk_ctrl_reg = bitfield_field32_write(
307 extclk_ctrl_reg, CLKMGR_EXTCLK_CTRL_HI_SPEED_SEL_FIELD,
308 is_low_speed ? kMultiBitBool4False : kMultiBitBool4True);
309 mmio_region_write32(clkmgr->base_addr, CLKMGR_EXTCLK_CTRL_REG_OFFSET,
310 extclk_ctrl_reg);
311 return kDifOk;
312}
313
314dif_result_t dif_clkmgr_external_clock_set_disabled(
315 const dif_clkmgr_t *clkmgr) {
316 uint32_t extclk_ctrl_reg = 0;
317
318 if (clkmgr == NULL) {
319 return kDifBadArg;
320 }
321
322 if (extclk_control_register_is_locked(clkmgr)) {
323 return kDifLocked;
324 }
325
326 extclk_ctrl_reg = bitfield_field32_write(
327 extclk_ctrl_reg, CLKMGR_EXTCLK_CTRL_SEL_FIELD, kMultiBitBool4False);
328 // This value is irrelevant when the external clock is disabled.
329 extclk_ctrl_reg = bitfield_field32_write(
330 extclk_ctrl_reg, CLKMGR_EXTCLK_CTRL_HI_SPEED_SEL_FIELD,
331 kMultiBitBool4True);
332 mmio_region_write32(clkmgr->base_addr, CLKMGR_EXTCLK_CTRL_REG_OFFSET,
333 extclk_ctrl_reg);
334 return kDifOk;
335}
336
337dif_result_t dif_clkmgr_measure_ctrl_disable(const dif_clkmgr_t *clkmgr) {
338 if (clkmgr == NULL) {
339 return kDifBadArg;
340 }
341 mmio_region_write32(clkmgr->base_addr, CLKMGR_MEASURE_CTRL_REGWEN_REG_OFFSET,
342 0);
343 return kDifOk;
344}
345
346dif_result_t dif_clkmgr_measure_ctrl_get_enable(const dif_clkmgr_t *clkmgr,
347 dif_toggle_t *state) {
348 if (clkmgr == NULL || state == NULL) {
349 return kDifBadArg;
350 }
351 *state = dif_bool_to_toggle(clkmgr_measure_ctrl_regwen(clkmgr));
352 return kDifOk;
353}
354
355// The earlgrey and englishbreakfast CSR differences mean they have a
356// different number of clock measuremen units. The ideal way to handle
357// this difference is just generating the dif code, and we intend to do
358// that with multi-top. However, for the time being we need to rely on
359// macro trickery, just generating code for a specific measurement if
360// there is a #define for the corresponding enable CSR offset.
361//
362// These macro are a tricky way to implement a macro like the following:
363// #define CONDITIONALLY_DO \ ...
364// #ifdef SOMETHING do_something \ ...
365// #else do_something_else \ ...
366// #endif
367// However, such macros are illegal in C. So the macros below implement
368// the conditional using a suggestion presented in
369// https://stackoverflow.com/questions/72266480/can-ifdef-be-used-inside-a-macro
370//
371// The reason we need these macros is to handle differences between earlgrey
372// and englishbreakfast without generating the dif code.
373
374// TODO(lowrisc/opentitan#19823): Remove this whole macro trickery once this
375// file is generated.
376#define CNCAT_IMPL(a_, b_) a_##b_
377#define CNCAT(a_, b_) CNCAT_IMPL(a_, b_)
378#define CHECK_CLKMGR_IO_MEAS_CTRL_EN_REG_OFFSET ~, ~
379#define CHECK_CLKMGR_IO_DIV2_MEAS_CTRL_EN_REG_OFFSET ~, ~
380#define CHECK_CLKMGR_IO_DIV4_MEAS_CTRL_EN_REG_OFFSET ~, ~
381#define CHECK_CLKMGR_MAIN_MEAS_CTRL_EN_REG_OFFSET ~, ~
382#define CHECK_CLKMGR_USB_MEAS_CTRL_EN_REG_OFFSET ~, ~
383#define CHECK_IMPL(a_, b_, c_, ...) c_
384#define CHECK(tup_) CHECK_IMPL tup_
385
386#define IS_KIND_DEFINED(kind_) \
387 CHECK((CNCAT(CHECK_, CLKMGR_##kind_##_MEAS_CTRL_EN_REG_OFFSET), 0, 1))
388
389#define IIF_0(true_exp_, false_exp_) false_exp_
390#define IIF_1(true_exp_, false_exp_) true_exp_
391#define IIF(condition_, true_exp_, false_exp_) \
392 CNCAT(IIF_, condition_)(true_exp_, false_exp_)
393
394dif_result_t dif_clkmgr_enable_measure_counts(const dif_clkmgr_t *clkmgr,
395 dif_clkmgr_measure_clock_t clock,
396 uint32_t lo_threshold,
397 uint32_t hi_threshold) {
398 if (clkmgr == NULL) {
399 return kDifBadArg;
400 }
401 if (!clkmgr_measure_ctrl_regwen(clkmgr)) {
402 return kDifLocked;
403 }
404
405 uint32_t en_offset = 0;
406 uint32_t reg_offset = 0;
407 bitfield_field32_t en_field = (bitfield_field32_t){.mask = 0, .index = 0};
408 bitfield_field32_t lo_field = (bitfield_field32_t){.mask = 0, .index = 0};
409 bitfield_field32_t hi_field = (bitfield_field32_t){.mask = 0, .index = 0};
410 switch (clock) {
411#define PICK_COUNT_CTRL_FIELDS(kind_) \
412 IIF(IS_KIND_DEFINED(kind_), \
413 en_offset = CLKMGR_##kind_##_MEAS_CTRL_EN_REG_OFFSET; \
414 reg_offset = CLKMGR_##kind_##_MEAS_CTRL_SHADOWED_REG_OFFSET; \
415 en_field = CLKMGR_##kind_##_MEAS_CTRL_EN_EN_FIELD; \
416 lo_field = CLKMGR_##kind_##_MEAS_CTRL_SHADOWED_LO_FIELD; \
417 hi_field = CLKMGR_##kind_##_MEAS_CTRL_SHADOWED_HI_FIELD; break, break)
418
419#if defined(OPENTITAN_IS_EARLGREY)
420 case kDifClkmgrMeasureClockIo:
421 PICK_COUNT_CTRL_FIELDS(IO);
422 case kDifClkmgrMeasureClockIoDiv2:
423 PICK_COUNT_CTRL_FIELDS(IO_DIV2);
424#elif defined(OPENTITAN_IS_DARJEELING)
425// Darjeeling does not have Io / IoDiv2 clock measurements
426#else
427#error "dif_clkmgr does not support this top"
428#endif
430 PICK_COUNT_CTRL_FIELDS(IO_DIV4);
432 PICK_COUNT_CTRL_FIELDS(MAIN);
434 PICK_COUNT_CTRL_FIELDS(USB);
435 default:
436 return kDifBadArg;
437#undef PICK_COUNT_CTRL_FIELDS
438 }
439
440 uint32_t measure_ctrl_reg = 0;
441 measure_ctrl_reg =
442 bitfield_field32_write(measure_ctrl_reg, lo_field, lo_threshold);
443 measure_ctrl_reg =
444 bitfield_field32_write(measure_ctrl_reg, hi_field, hi_threshold);
445 // Two writes, because these registers are shadowed.
446 mmio_region_write32(clkmgr->base_addr, (ptrdiff_t)reg_offset,
447 measure_ctrl_reg);
448 mmio_region_write32(clkmgr->base_addr, (ptrdiff_t)reg_offset,
449 measure_ctrl_reg);
450
451 uint32_t measure_en_reg = 0;
452 measure_en_reg =
453 bitfield_field32_write(measure_en_reg, en_field, kMultiBitBool4True);
454 mmio_region_write32(clkmgr->base_addr, (ptrdiff_t)en_offset, measure_en_reg);
455
456 return kDifOk;
457}
458
459dif_result_t dif_clkmgr_disable_measure_counts(
460 const dif_clkmgr_t *clkmgr, dif_clkmgr_measure_clock_t clock) {
461 if (clkmgr == NULL) {
462 return kDifBadArg;
463 }
464 if (!clkmgr_measure_ctrl_regwen(clkmgr)) {
465 return kDifLocked;
466 }
467
468 uint32_t en_offset = 0;
469 switch (clock) {
470#define PICK_EN_OFFSET(kind_) \
471 IIF(IS_KIND_DEFINED(kind_), \
472 en_offset = CLKMGR_##kind_##_MEAS_CTRL_EN_REG_OFFSET; \
473 break, break)
474
475#if defined(OPENTITAN_IS_EARLGREY)
476 case kDifClkmgrMeasureClockIo:
477 PICK_EN_OFFSET(IO);
478 break;
479 case kDifClkmgrMeasureClockIoDiv2:
480 PICK_EN_OFFSET(IO_DIV2);
481 break;
482#elif defined(OPENTITAN_IS_DARJEELING)
483// Darjeeling does not have Io / IoDiv2 clock measurements
484#else
485#error "dif_clkmgr does not support this top"
486#endif
488 PICK_EN_OFFSET(IO_DIV4);
489 break;
491 PICK_EN_OFFSET(MAIN);
492 break;
494 PICK_EN_OFFSET(USB);
495 break;
496 default:
497 return kDifBadArg;
498#undef PICK_EN_OFFSET
499 }
500 mmio_region_write32(clkmgr->base_addr, (ptrdiff_t)en_offset,
501 kMultiBitBool4False);
502 return kDifOk;
503}
504
505dif_result_t dif_clkmgr_measure_counts_get_enable(
506 const dif_clkmgr_t *clkmgr, dif_clkmgr_measure_clock_t clock,
507 dif_toggle_t *state) {
508 if (clkmgr == NULL || state == NULL) {
509 return kDifBadArg;
510 }
511
512 uint32_t en_offset = 0;
513 switch (clock) {
514#define PICK_EN_OFFSET(kind_) \
515 IIF(IS_KIND_DEFINED(kind_), \
516 en_offset = CLKMGR_##kind_##_MEAS_CTRL_EN_REG_OFFSET; \
517 break, break)
518
519#if defined(OPENTITAN_IS_EARLGREY)
520 case kDifClkmgrMeasureClockIo:
521 PICK_EN_OFFSET(IO);
522 case kDifClkmgrMeasureClockIoDiv2:
523 PICK_EN_OFFSET(IO_DIV2);
524#elif defined(OPENTITAN_IS_DARJEELING)
525// Darjeeling does not have Io / IoDiv2 clock measurements
526#else
527#error "dif_clkmgr does not support this top"
528#endif
530 PICK_EN_OFFSET(IO_DIV4);
532 PICK_EN_OFFSET(MAIN);
534 PICK_EN_OFFSET(USB);
535 default:
536 return kDifBadArg;
537#undef PICK_EN_OFFSET
538 }
539 multi_bit_bool_t en_val =
540 mmio_region_read32(clkmgr->base_addr, (ptrdiff_t)en_offset);
541 *state = dif_multi_bit_bool_to_toggle(en_val);
542
543 return kDifOk;
544}
545
546dif_result_t dif_clkmgr_measure_counts_get_thresholds(
547 const dif_clkmgr_t *clkmgr, dif_clkmgr_measure_clock_t clock,
548 uint32_t *min_threshold, uint32_t *max_threshold) {
549 if (clkmgr == NULL || min_threshold == NULL || max_threshold == NULL) {
550 return kDifBadArg;
551 }
552
553 uint32_t reg_offset = 0;
554 bitfield_field32_t lo_field = (bitfield_field32_t){.mask = 0, .index = 0};
555 bitfield_field32_t hi_field = (bitfield_field32_t){.mask = 0, .index = 0};
556 switch (clock) {
557#define PICK_THRESHOLD_FIELDS(kind_) \
558 IIF(IS_KIND_DEFINED(kind_), \
559 reg_offset = CLKMGR_##kind_##_MEAS_CTRL_SHADOWED_REG_OFFSET; \
560 lo_field = CLKMGR_##kind_##_MEAS_CTRL_SHADOWED_LO_FIELD; \
561 hi_field = CLKMGR_##kind_##_MEAS_CTRL_SHADOWED_HI_FIELD; break, break)
562#if defined(OPENTITAN_IS_EARLGREY)
563 case kDifClkmgrMeasureClockIo:
564 PICK_THRESHOLD_FIELDS(IO);
565 case kDifClkmgrMeasureClockIoDiv2:
566 PICK_THRESHOLD_FIELDS(IO_DIV2);
567#elif defined(OPENTITAN_IS_DARJEELING)
568// Darjeeling does not have Io / IoDiv2 clock measurements
569#else
570#error "dif_clkmgr does not support this top"
571#endif
573 PICK_THRESHOLD_FIELDS(IO_DIV4);
575 PICK_THRESHOLD_FIELDS(MAIN);
577 PICK_THRESHOLD_FIELDS(USB);
578 default:
579 return kDifBadArg;
580#undef PICK_THRESHOLD_FIELDS
581 }
582 uint32_t thresholds_val =
583 mmio_region_read32(clkmgr->base_addr, (ptrdiff_t)reg_offset);
584 *min_threshold = bitfield_field32_read(thresholds_val, lo_field);
585 *max_threshold = bitfield_field32_read(thresholds_val, hi_field);
586
587 return kDifOk;
588}
589
590#undef CNCAT_IMPL
591#undef CNCAT
592#undef CHECK_CLKMGR_IO_MEAS_CTRL_EN_REG_OFFSET
593#undef CHECK_CLKMGR_IO_DIV2_MEAS_CTRL_EN_REG_OFFSET
594#undef CHECK_CLKMGR_IO_DIV4_MEAS_CTRL_EN_REG_OFFSET
595#undef CHECK_CLKMGR_MAIN_MEAS_CTRL_EN_REG_OFFSET
596#undef CHECK_CLKMGR_USB_MEAS_CTRL_EN_REG_OFFSET
597#undef CHECK_IMPL
598#undef CHECK
599#undef IS_KIND_DEFINED
600#undef IIF_0
601#undef IIF_1
602#undef IIF
603
604dif_result_t dif_clkmgr_recov_err_code_get_codes(
605 const dif_clkmgr_t *clkmgr, dif_clkmgr_recov_err_codes_t *codes) {
606 if (clkmgr == NULL || codes == NULL) {
607 return kDifBadArg;
608 }
609 *codes =
610 mmio_region_read32(clkmgr->base_addr, CLKMGR_RECOV_ERR_CODE_REG_OFFSET);
611 return kDifOk;
612}
613
614dif_result_t dif_clkmgr_recov_err_code_clear_codes(
615 const dif_clkmgr_t *clkmgr, dif_clkmgr_recov_err_codes_t codes) {
616 if (clkmgr == NULL) {
617 return kDifBadArg;
618 }
619 mmio_region_write32(clkmgr->base_addr, CLKMGR_RECOV_ERR_CODE_REG_OFFSET,
620 codes);
621 return kDifOk;
622}
623
624dif_result_t dif_clkmgr_fatal_err_code_get_codes(
625 const dif_clkmgr_t *clkmgr, dif_clkmgr_fatal_err_codes_t *codes) {
626 if (clkmgr == NULL || codes == NULL) {
627 return kDifBadArg;
628 }
629 *codes =
630 mmio_region_read32(clkmgr->base_addr, CLKMGR_FATAL_ERR_CODE_REG_OFFSET);
631 return kDifOk;
632}
633
634dif_result_t dif_clkmgr_wait_for_ext_clk_switch(const dif_clkmgr_t *clkmgr) {
635 if (clkmgr == NULL) {
636 return kDifBadArg;
637 }
638 uint32_t ext_status;
639 do {
640 ext_status =
641 mmio_region_read32(clkmgr->base_addr, CLKMGR_EXTCLK_STATUS_REG_OFFSET);
642 } while (ext_status != kMultiBitBool4True);
643 return kDifOk;
644}