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 "hw/top/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#if OPENTITAN_CLKMGR_HAS_SW_EXTCLK_REGWEN
60/**
61 * Checks if the external clock control register is locked.
62 *
63 * The external clock control register is locked by CLKMGR_EXTCLK_CTRL_REGWEN.
64 */
66static bool extclk_control_register_is_locked(const dif_clkmgr_t *clkmgr) {
67 // External clock control register is locked when
68 // `CLKMGR_EXTCLK_CTRL_REGWEN_EN_BIT` bit is 0.
69 return !bitfield_bit32_read(
70 mmio_region_read32(clkmgr->base_addr,
71 CLKMGR_EXTCLK_CTRL_REGWEN_REG_OFFSET),
72 CLKMGR_EXTCLK_CTRL_REGWEN_EN_BIT);
73}
74
75dif_result_t dif_clkmgr_external_clock_is_settled(const dif_clkmgr_t *clkmgr,
76 bool *status) {
77 if (clkmgr == NULL || status == NULL) {
78 return kDifBadArg;
79 }
80 uint32_t extclk_status_val =
81 mmio_region_read32(clkmgr->base_addr, CLKMGR_EXTCLK_STATUS_REG_OFFSET);
82 *status = bitfield_field32_read(extclk_status_val,
83 CLKMGR_EXTCLK_STATUS_ACK_FIELD) ==
84 kMultiBitBool4True;
85
86 return kDifOk;
87}
88#endif
89
90dif_result_t dif_clkmgr_jitter_enable_is_locked(const dif_clkmgr_t *clkmgr,
91 bool *is_locked) {
92 if (clkmgr == NULL || is_locked == NULL) {
93 return kDifBadArg;
94 }
95
96 *is_locked = jitter_enable_register_is_locked(clkmgr);
97
98 return kDifOk;
99}
100
101dif_result_t dif_clkmgr_lock_jitter_enable(const dif_clkmgr_t *clkmgr) {
102 if (clkmgr == NULL) {
103 return kDifBadArg;
104 }
105 mmio_region_write32(clkmgr->base_addr, CLKMGR_JITTER_REGWEN_REG_OFFSET, 0);
106 return kDifOk;
107}
108
109dif_result_t dif_clkmgr_jitter_get_enabled(const dif_clkmgr_t *clkmgr,
110 dif_toggle_t *state) {
111 if (clkmgr == NULL || state == NULL) {
112 return kDifBadArg;
113 }
114
115 multi_bit_bool_t clk_jitter_val =
116 mmio_region_read32(clkmgr->base_addr, CLKMGR_JITTER_ENABLE_REG_OFFSET);
117 // The documentation states that kMultiBitBool4False disables the jittery
118 // clock and all other values enable the jittery clock.
119 *state = clk_jitter_val != kMultiBitBool4False ? kDifToggleEnabled
121
122 return kDifOk;
123}
124
125dif_result_t dif_clkmgr_jitter_set_enabled(const dif_clkmgr_t *clkmgr,
126 dif_toggle_t new_state) {
127 multi_bit_bool_t new_jitter_enable_val;
128 if (clkmgr == NULL) {
129 return kDifBadArg;
130 }
131 if (jitter_enable_register_is_locked(clkmgr)) {
132 return kDifLocked;
133 }
134
135 switch (new_state) {
137 new_jitter_enable_val = kMultiBitBool4True;
138 break;
140 new_jitter_enable_val = kMultiBitBool4False;
141 break;
142 default:
143 return kDifBadArg;
144 }
145 mmio_region_write32(clkmgr->base_addr, CLKMGR_JITTER_ENABLE_REG_OFFSET,
146 new_jitter_enable_val);
147 return kDifOk;
148}
149
151dif_result_t dif_clkmgr_find_gateable_clock(
152 const dif_clkmgr_t *clkmgr, dt_instance_id_t inst_id,
154 if (clkmgr == NULL || clock == NULL) {
155 return kDifBadArg;
156 }
157 dt_clkmgr_t dt;
158 DIF_RETURN_IF_ERROR(dif_clkmgr_get_dt(clkmgr, &dt));
159 // Query the DT to find the information.
160 for (size_t i = 0; i < dt_clkmgr_gateable_clock_count(dt); i++) {
161 if (dt_clkmgr_gateable_clock(dt, i) == inst_id) {
162 *clock = i;
163 return kDifOk;
164 }
165 }
166 return kDifError;
167}
168
169dif_result_t dif_clkmgr_gateable_clock_get_enabled(
170 const dif_clkmgr_t *clkmgr, dif_clkmgr_gateable_clock_t clock,
171 dif_toggle_t *state) {
172 if (clkmgr == NULL || state == NULL || !clkmgr_valid_gateable_clock(clock)) {
173 return kDifBadArg;
174 }
175
176 uint32_t clk_enables_val =
177 mmio_region_read32(clkmgr->base_addr, CLKMGR_CLK_ENABLES_REG_OFFSET);
178 *state = dif_bool_to_toggle(bitfield_bit32_read(clk_enables_val, clock));
179
180 return kDifOk;
181}
182
183dif_result_t dif_clkmgr_gateable_clock_set_enabled(
184 const dif_clkmgr_t *clkmgr, dif_clkmgr_gateable_clock_t clock,
185 dif_toggle_t new_state) {
186 if (clkmgr == NULL || !clkmgr_valid_gateable_clock(clock) ||
187 !dif_is_valid_toggle(new_state)) {
188 return kDifBadArg;
189 }
190
191 bool new_clk_enables_bit = dif_toggle_to_bool(new_state);
192 uint32_t clk_enables_val =
193 mmio_region_read32(clkmgr->base_addr, CLKMGR_CLK_ENABLES_REG_OFFSET);
194 clk_enables_val =
195 bitfield_bit32_write(clk_enables_val, clock, new_clk_enables_bit);
196 mmio_region_write32(clkmgr->base_addr, CLKMGR_CLK_ENABLES_REG_OFFSET,
197 clk_enables_val);
198
199 return kDifOk;
200}
201
203dif_result_t dif_clkmgr_find_hintable_clock(
204 const dif_clkmgr_t *clkmgr, dt_instance_id_t inst_id,
206 if (clkmgr == NULL || clock == NULL) {
207 return kDifBadArg;
208 }
209 dt_clkmgr_t dt;
210 DIF_RETURN_IF_ERROR(dif_clkmgr_get_dt(clkmgr, &dt));
211 // Query the DT to find the information.
212 for (size_t i = 0; i < dt_clkmgr_hintable_clock_count(dt); i++) {
213 if (dt_clkmgr_hintable_clock(dt, i) == inst_id) {
214 *clock = i;
215 return kDifOk;
216 }
217 }
218 return kDifError;
219}
220
221dif_result_t dif_clkmgr_hintable_clock_get_enabled(
222 const dif_clkmgr_t *clkmgr, dif_clkmgr_hintable_clock_t clock,
223 dif_toggle_t *state) {
224 if (clkmgr == NULL || state == NULL || !clkmgr_valid_hintable_clock(clock)) {
225 return kDifBadArg;
226 }
227
228 uint32_t clk_hints_val =
229 mmio_region_read32(clkmgr->base_addr, CLKMGR_CLK_HINTS_STATUS_REG_OFFSET);
230 *state = dif_bool_to_toggle(bitfield_bit32_read(clk_hints_val, clock));
231
232 return kDifOk;
233}
234
235dif_result_t dif_clkmgr_hintable_clock_set_hint(
236 const dif_clkmgr_t *clkmgr, dif_clkmgr_hintable_clock_t clock,
237 dif_toggle_t new_state) {
238 if (clkmgr == NULL || !clkmgr_valid_hintable_clock(clock) ||
239 !dif_is_valid_toggle(new_state)) {
240 return kDifBadArg;
241 }
242
243 bool new_clk_hints_bit = dif_toggle_to_bool(new_state);
244 uint32_t clk_hints_val =
245 mmio_region_read32(clkmgr->base_addr, CLKMGR_CLK_HINTS_REG_OFFSET);
246 clk_hints_val = bitfield_bit32_write(clk_hints_val, clock, new_clk_hints_bit);
247 mmio_region_write32(clkmgr->base_addr, CLKMGR_CLK_HINTS_REG_OFFSET,
248 clk_hints_val);
249
250 return kDifOk;
251}
252
253dif_result_t dif_clkmgr_hintable_clock_get_hint(
254 const dif_clkmgr_t *clkmgr, dif_clkmgr_hintable_clock_t clock,
255 dif_toggle_t *state) {
256 if (clkmgr == NULL || state == NULL || !clkmgr_valid_hintable_clock(clock)) {
257 return kDifBadArg;
258 }
259
260 uint32_t clk_hints_val =
261 mmio_region_read32(clkmgr->base_addr, CLKMGR_CLK_HINTS_REG_OFFSET);
262 *state = dif_bool_to_toggle(bitfield_bit32_read(clk_hints_val, clock));
263
264 return kDifOk;
265}
266
267#if OPENTITAN_CLKMGR_HAS_SW_EXTCLK_REGWEN
268dif_result_t dif_clkmgr_external_clock_control_is_locked(
269 const dif_clkmgr_t *clkmgr, bool *is_locked) {
270 if (clkmgr == NULL || is_locked == NULL) {
271 return kDifBadArg;
272 }
273
274 *is_locked = extclk_control_register_is_locked(clkmgr);
275
276 return kDifOk;
277}
278
279dif_result_t dif_clkmgr_lock_external_clock_control(
280 const dif_clkmgr_t *clkmgr) {
281 if (clkmgr == NULL) {
282 return kDifBadArg;
283 }
284 mmio_region_write32(clkmgr->base_addr, CLKMGR_EXTCLK_CTRL_REGWEN_REG_OFFSET,
285 0);
286 return kDifOk;
287}
288
289dif_result_t dif_clkmgr_external_clock_set_enabled(const dif_clkmgr_t *clkmgr,
290 bool is_low_speed) {
291 uint32_t extclk_ctrl_reg = 0;
292
293 if (clkmgr == NULL) {
294 return kDifBadArg;
295 }
296
297 if (extclk_control_register_is_locked(clkmgr)) {
298 return kDifLocked;
299 }
300
301 extclk_ctrl_reg = bitfield_field32_write(
302 extclk_ctrl_reg, CLKMGR_EXTCLK_CTRL_SEL_FIELD, kMultiBitBool4True);
303 extclk_ctrl_reg = bitfield_field32_write(
304 extclk_ctrl_reg, CLKMGR_EXTCLK_CTRL_HI_SPEED_SEL_FIELD,
305 is_low_speed ? kMultiBitBool4False : kMultiBitBool4True);
306 mmio_region_write32(clkmgr->base_addr, CLKMGR_EXTCLK_CTRL_REG_OFFSET,
307 extclk_ctrl_reg);
308 return kDifOk;
309}
310
311dif_result_t dif_clkmgr_external_clock_set_disabled(
312 const dif_clkmgr_t *clkmgr) {
313 uint32_t extclk_ctrl_reg = 0;
314
315 if (clkmgr == NULL) {
316 return kDifBadArg;
317 }
318
319 if (extclk_control_register_is_locked(clkmgr)) {
320 return kDifLocked;
321 }
322
323 extclk_ctrl_reg = bitfield_field32_write(
324 extclk_ctrl_reg, CLKMGR_EXTCLK_CTRL_SEL_FIELD, kMultiBitBool4False);
325 // This value is irrelevant when the external clock is disabled.
326 extclk_ctrl_reg = bitfield_field32_write(
327 extclk_ctrl_reg, CLKMGR_EXTCLK_CTRL_HI_SPEED_SEL_FIELD,
328 kMultiBitBool4True);
329 mmio_region_write32(clkmgr->base_addr, CLKMGR_EXTCLK_CTRL_REG_OFFSET,
330 extclk_ctrl_reg);
331 return kDifOk;
332}
333#endif
334
335dif_result_t dif_clkmgr_measure_ctrl_disable(const dif_clkmgr_t *clkmgr) {
336 if (clkmgr == NULL) {
337 return kDifBadArg;
338 }
339 mmio_region_write32(clkmgr->base_addr, CLKMGR_MEASURE_CTRL_REGWEN_REG_OFFSET,
340 0);
341 return kDifOk;
342}
343
344dif_result_t dif_clkmgr_measure_ctrl_get_enable(const dif_clkmgr_t *clkmgr,
345 dif_toggle_t *state) {
346 if (clkmgr == NULL || state == NULL) {
347 return kDifBadArg;
348 }
349 *state = dif_bool_to_toggle(clkmgr_measure_ctrl_regwen(clkmgr));
350 return kDifOk;
351}
352
353dif_result_t dif_clkmgr_find_measure_clock(const dif_clkmgr_t *clkmgr,
354 dt_clock_t dt_clk,
355 dif_clkmgr_measure_clock_t *clock) {
356 if (clkmgr == NULL || clock == NULL) {
357 return kDifBadArg;
358 }
359 dt_clkmgr_t dt;
360 DIF_RETURN_IF_ERROR(dif_clkmgr_get_dt(clkmgr, &dt));
361 // Query the DT to find the information.
362 for (size_t i = 0; i < dt_clkmgr_measurable_clock_count(dt); i++) {
363 if (dt_clkmgr_measurable_clock(dt, i).clock == dt_clk) {
364 *clock = i;
365 return kDifOk;
366 }
367 }
368 return kDifError;
369}
370
371dif_result_t dif_clkmgr_enable_measure_counts(const dif_clkmgr_t *clkmgr,
372 dif_clkmgr_measure_clock_t clock,
373 uint32_t lo_threshold,
374 uint32_t hi_threshold) {
375 if (clkmgr == NULL) {
376 return kDifBadArg;
377 }
378 if (!clkmgr_measure_ctrl_regwen(clkmgr)) {
379 return kDifLocked;
380 }
381
382 dt_clkmgr_t dt;
383 DIF_RETURN_IF_ERROR(dif_clkmgr_get_dt(clkmgr, &dt));
384 if (clock >= dt_clkmgr_measurable_clock_count(dt)) {
385 return kDifBadArg;
386 }
388
389 uint32_t measure_ctrl_reg = 0;
390 measure_ctrl_reg = bitfield_field32_write(
391 measure_ctrl_reg, info.meas_ctrl_shadowed_lo_field, lo_threshold);
392 measure_ctrl_reg = bitfield_field32_write(
393 measure_ctrl_reg, info.meas_ctrl_shadowed_hi_field, hi_threshold);
394 // Two writes, because these registers are shadowed.
395 mmio_region_write32(clkmgr->base_addr, (ptrdiff_t)info.meas_ctrl_shadowed_off,
396 measure_ctrl_reg);
397 mmio_region_write32(clkmgr->base_addr, (ptrdiff_t)info.meas_ctrl_shadowed_off,
398 measure_ctrl_reg);
399
400 uint32_t measure_en_reg =
401 bitfield_field32_write(0, info.meas_ctrl_en_en_field, kMultiBitBool4True);
402 mmio_region_write32(clkmgr->base_addr, (ptrdiff_t)info.meas_ctrl_en_off,
403 measure_en_reg);
404
405 return kDifOk;
406}
407
408dif_result_t dif_clkmgr_disable_measure_counts(
409 const dif_clkmgr_t *clkmgr, dif_clkmgr_measure_clock_t clock) {
410 if (clkmgr == NULL) {
411 return kDifBadArg;
412 }
413 if (!clkmgr_measure_ctrl_regwen(clkmgr)) {
414 return kDifLocked;
415 }
416
417 dt_clkmgr_t dt;
418 DIF_RETURN_IF_ERROR(dif_clkmgr_get_dt(clkmgr, &dt));
419 if (clock >= dt_clkmgr_measurable_clock_count(dt)) {
420 return kDifBadArg;
421 }
423
424 uint32_t measure_en_reg = bitfield_field32_write(
425 0, info.meas_ctrl_en_en_field, kMultiBitBool4False);
426 mmio_region_write32(clkmgr->base_addr, (ptrdiff_t)info.meas_ctrl_en_off,
427 measure_en_reg);
428 return kDifOk;
429}
430
431dif_result_t dif_clkmgr_measure_counts_get_enable(
432 const dif_clkmgr_t *clkmgr, dif_clkmgr_measure_clock_t clock,
433 dif_toggle_t *state) {
434 if (clkmgr == NULL || state == NULL) {
435 return kDifBadArg;
436 }
437
438 dt_clkmgr_t dt;
439 DIF_RETURN_IF_ERROR(dif_clkmgr_get_dt(clkmgr, &dt));
440 if (clock >= dt_clkmgr_measurable_clock_count(dt)) {
441 return kDifBadArg;
442 }
444
445 uint32_t en_val =
446 mmio_region_read32(clkmgr->base_addr, (ptrdiff_t)info.meas_ctrl_en_off);
447 *state = dif_multi_bit_bool_to_toggle(
448 bitfield_field32_read(en_val, info.meas_ctrl_en_en_field));
449
450 return kDifOk;
451}
452
453dif_result_t dif_clkmgr_measure_counts_get_thresholds(
454 const dif_clkmgr_t *clkmgr, dif_clkmgr_measure_clock_t clock,
455 uint32_t *min_threshold, uint32_t *max_threshold) {
456 if (clkmgr == NULL || min_threshold == NULL || max_threshold == NULL) {
457 return kDifBadArg;
458 }
459
460 dt_clkmgr_t dt;
461 DIF_RETURN_IF_ERROR(dif_clkmgr_get_dt(clkmgr, &dt));
462 if (clock >= dt_clkmgr_measurable_clock_count(dt)) {
463 return kDifBadArg;
464 }
466
467 uint32_t thresholds_val = mmio_region_read32(
468 clkmgr->base_addr, (ptrdiff_t)info.meas_ctrl_shadowed_off);
469 *min_threshold =
470 bitfield_field32_read(thresholds_val, info.meas_ctrl_shadowed_lo_field);
471 *max_threshold =
472 bitfield_field32_read(thresholds_val, info.meas_ctrl_shadowed_hi_field);
473
474 return kDifOk;
475}
476
477dif_result_t dif_clkmgr_recov_err_code_get_codes(
478 const dif_clkmgr_t *clkmgr, dif_clkmgr_recov_err_codes_t *codes) {
479 if (clkmgr == NULL || codes == NULL) {
480 return kDifBadArg;
481 }
482 *codes =
483 mmio_region_read32(clkmgr->base_addr, CLKMGR_RECOV_ERR_CODE_REG_OFFSET);
484 return kDifOk;
485}
486
487dif_result_t dif_clkmgr_recov_err_code_clear_codes(
488 const dif_clkmgr_t *clkmgr, dif_clkmgr_recov_err_codes_t codes) {
489 if (clkmgr == NULL) {
490 return kDifBadArg;
491 }
492 mmio_region_write32(clkmgr->base_addr, CLKMGR_RECOV_ERR_CODE_REG_OFFSET,
493 codes);
494 return kDifOk;
495}
496
497dif_result_t dif_clkmgr_fatal_err_code_get_codes(
498 const dif_clkmgr_t *clkmgr, dif_clkmgr_fatal_err_codes_t *codes) {
499 if (clkmgr == NULL || codes == NULL) {
500 return kDifBadArg;
501 }
502 *codes =
503 mmio_region_read32(clkmgr->base_addr, CLKMGR_FATAL_ERR_CODE_REG_OFFSET);
504 return kDifOk;
505}
506
507#if OPENTITAN_CLKMGR_HAS_SW_EXTCLK_REGWEN
508dif_result_t dif_clkmgr_wait_for_ext_clk_switch(const dif_clkmgr_t *clkmgr) {
509 if (clkmgr == NULL) {
510 return kDifBadArg;
511 }
512 uint32_t ext_status;
513 do {
514 ext_status =
515 mmio_region_read32(clkmgr->base_addr, CLKMGR_EXTCLK_STATUS_REG_OFFSET);
516 } while (ext_status != kMultiBitBool4True);
517 return kDifOk;
518}
519#endif