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/**
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_RETURN_IF_ERROR(dif_clkmgr_get_dt(clkmgr, &dt));
157 // Query the DT to find the information.
158 for (size_t i = 0; i < dt_clkmgr_gateable_clock_count(dt); i++) {
159 if (dt_clkmgr_gateable_clock(dt, i) == inst_id) {
160 *clock = i;
161 return kDifOk;
162 }
163 }
164 return kDifError;
165}
166
167dif_result_t dif_clkmgr_gateable_clock_get_enabled(
168 const dif_clkmgr_t *clkmgr, dif_clkmgr_gateable_clock_t clock,
169 dif_toggle_t *state) {
170 if (clkmgr == NULL || state == NULL || !clkmgr_valid_gateable_clock(clock)) {
171 return kDifBadArg;
172 }
173
174 uint32_t clk_enables_val =
175 mmio_region_read32(clkmgr->base_addr, CLKMGR_CLK_ENABLES_REG_OFFSET);
176 *state = dif_bool_to_toggle(bitfield_bit32_read(clk_enables_val, clock));
177
178 return kDifOk;
179}
180
181dif_result_t dif_clkmgr_gateable_clock_set_enabled(
182 const dif_clkmgr_t *clkmgr, dif_clkmgr_gateable_clock_t clock,
183 dif_toggle_t new_state) {
184 if (clkmgr == NULL || !clkmgr_valid_gateable_clock(clock) ||
185 !dif_is_valid_toggle(new_state)) {
186 return kDifBadArg;
187 }
188
189 bool new_clk_enables_bit = dif_toggle_to_bool(new_state);
190 uint32_t clk_enables_val =
191 mmio_region_read32(clkmgr->base_addr, CLKMGR_CLK_ENABLES_REG_OFFSET);
192 clk_enables_val =
193 bitfield_bit32_write(clk_enables_val, clock, new_clk_enables_bit);
194 mmio_region_write32(clkmgr->base_addr, CLKMGR_CLK_ENABLES_REG_OFFSET,
195 clk_enables_val);
196
197 return kDifOk;
198}
199
201dif_result_t dif_clkmgr_find_hintable_clock(
202 const dif_clkmgr_t *clkmgr, dt_instance_id_t inst_id,
204 if (clkmgr == NULL || clock == NULL) {
205 return kDifBadArg;
206 }
207 dt_clkmgr_t dt;
208 DIF_RETURN_IF_ERROR(dif_clkmgr_get_dt(clkmgr, &dt));
209 // Query the DT to find the information.
210 for (size_t i = 0; i < dt_clkmgr_hintable_clock_count(dt); i++) {
211 if (dt_clkmgr_hintable_clock(dt, i) == inst_id) {
212 *clock = i;
213 return kDifOk;
214 }
215 }
216 return kDifError;
217}
218
219dif_result_t dif_clkmgr_hintable_clock_get_enabled(
220 const dif_clkmgr_t *clkmgr, dif_clkmgr_hintable_clock_t clock,
221 dif_toggle_t *state) {
222 if (clkmgr == NULL || state == NULL || !clkmgr_valid_hintable_clock(clock)) {
223 return kDifBadArg;
224 }
225
226 uint32_t clk_hints_val =
227 mmio_region_read32(clkmgr->base_addr, CLKMGR_CLK_HINTS_STATUS_REG_OFFSET);
228 *state = dif_bool_to_toggle(bitfield_bit32_read(clk_hints_val, clock));
229
230 return kDifOk;
231}
232
233dif_result_t dif_clkmgr_hintable_clock_set_hint(
234 const dif_clkmgr_t *clkmgr, dif_clkmgr_hintable_clock_t clock,
235 dif_toggle_t new_state) {
236 if (clkmgr == NULL || !clkmgr_valid_hintable_clock(clock) ||
237 !dif_is_valid_toggle(new_state)) {
238 return kDifBadArg;
239 }
240
241 bool new_clk_hints_bit = dif_toggle_to_bool(new_state);
242 uint32_t clk_hints_val =
243 mmio_region_read32(clkmgr->base_addr, CLKMGR_CLK_HINTS_REG_OFFSET);
244 clk_hints_val = bitfield_bit32_write(clk_hints_val, clock, new_clk_hints_bit);
245 mmio_region_write32(clkmgr->base_addr, CLKMGR_CLK_HINTS_REG_OFFSET,
246 clk_hints_val);
247
248 return kDifOk;
249}
250
251dif_result_t dif_clkmgr_hintable_clock_get_hint(
252 const dif_clkmgr_t *clkmgr, dif_clkmgr_hintable_clock_t clock,
253 dif_toggle_t *state) {
254 if (clkmgr == NULL || state == NULL || !clkmgr_valid_hintable_clock(clock)) {
255 return kDifBadArg;
256 }
257
258 uint32_t clk_hints_val =
259 mmio_region_read32(clkmgr->base_addr, CLKMGR_CLK_HINTS_REG_OFFSET);
260 *state = dif_bool_to_toggle(bitfield_bit32_read(clk_hints_val, clock));
261
262 return kDifOk;
263}
264
265dif_result_t dif_clkmgr_external_clock_control_is_locked(
266 const dif_clkmgr_t *clkmgr, bool *is_locked) {
267 if (clkmgr == NULL || is_locked == NULL) {
268 return kDifBadArg;
269 }
270
271 *is_locked = extclk_control_register_is_locked(clkmgr);
272
273 return kDifOk;
274}
275
276dif_result_t dif_clkmgr_lock_external_clock_control(
277 const dif_clkmgr_t *clkmgr) {
278 if (clkmgr == NULL) {
279 return kDifBadArg;
280 }
281 mmio_region_write32(clkmgr->base_addr, CLKMGR_EXTCLK_CTRL_REGWEN_REG_OFFSET,
282 0);
283 return kDifOk;
284}
285
286dif_result_t dif_clkmgr_external_clock_set_enabled(const dif_clkmgr_t *clkmgr,
287 bool is_low_speed) {
288 uint32_t extclk_ctrl_reg = 0;
289
290 if (clkmgr == NULL) {
291 return kDifBadArg;
292 }
293
294 if (extclk_control_register_is_locked(clkmgr)) {
295 return kDifLocked;
296 }
297
298 extclk_ctrl_reg = bitfield_field32_write(
299 extclk_ctrl_reg, CLKMGR_EXTCLK_CTRL_SEL_FIELD, kMultiBitBool4True);
300 extclk_ctrl_reg = bitfield_field32_write(
301 extclk_ctrl_reg, CLKMGR_EXTCLK_CTRL_HI_SPEED_SEL_FIELD,
302 is_low_speed ? kMultiBitBool4False : kMultiBitBool4True);
303 mmio_region_write32(clkmgr->base_addr, CLKMGR_EXTCLK_CTRL_REG_OFFSET,
304 extclk_ctrl_reg);
305 return kDifOk;
306}
307
308dif_result_t dif_clkmgr_external_clock_set_disabled(
309 const dif_clkmgr_t *clkmgr) {
310 uint32_t extclk_ctrl_reg = 0;
311
312 if (clkmgr == NULL) {
313 return kDifBadArg;
314 }
315
316 if (extclk_control_register_is_locked(clkmgr)) {
317 return kDifLocked;
318 }
319
320 extclk_ctrl_reg = bitfield_field32_write(
321 extclk_ctrl_reg, CLKMGR_EXTCLK_CTRL_SEL_FIELD, kMultiBitBool4False);
322 // This value is irrelevant when the external clock is disabled.
323 extclk_ctrl_reg = bitfield_field32_write(
324 extclk_ctrl_reg, CLKMGR_EXTCLK_CTRL_HI_SPEED_SEL_FIELD,
325 kMultiBitBool4True);
326 mmio_region_write32(clkmgr->base_addr, CLKMGR_EXTCLK_CTRL_REG_OFFSET,
327 extclk_ctrl_reg);
328 return kDifOk;
329}
330
331dif_result_t dif_clkmgr_measure_ctrl_disable(const dif_clkmgr_t *clkmgr) {
332 if (clkmgr == NULL) {
333 return kDifBadArg;
334 }
335 mmio_region_write32(clkmgr->base_addr, CLKMGR_MEASURE_CTRL_REGWEN_REG_OFFSET,
336 0);
337 return kDifOk;
338}
339
340dif_result_t dif_clkmgr_measure_ctrl_get_enable(const dif_clkmgr_t *clkmgr,
341 dif_toggle_t *state) {
342 if (clkmgr == NULL || state == NULL) {
343 return kDifBadArg;
344 }
345 *state = dif_bool_to_toggle(clkmgr_measure_ctrl_regwen(clkmgr));
346 return kDifOk;
347}
348
349dif_result_t dif_clkmgr_find_measure_clock(const dif_clkmgr_t *clkmgr,
350 dt_clock_t dt_clk,
351 dif_clkmgr_measure_clock_t *clock) {
352 if (clkmgr == NULL || clock == NULL) {
353 return kDifBadArg;
354 }
355 dt_clkmgr_t dt;
356 DIF_RETURN_IF_ERROR(dif_clkmgr_get_dt(clkmgr, &dt));
357 // Query the DT to find the information.
358 for (size_t i = 0; i < dt_clkmgr_measurable_clock_count(dt); i++) {
359 if (dt_clkmgr_measurable_clock(dt, i).clock == dt_clk) {
360 *clock = i;
361 return kDifOk;
362 }
363 }
364 return kDifError;
365}
366
367dif_result_t dif_clkmgr_enable_measure_counts(const dif_clkmgr_t *clkmgr,
368 dif_clkmgr_measure_clock_t clock,
369 uint32_t lo_threshold,
370 uint32_t hi_threshold) {
371 if (clkmgr == NULL) {
372 return kDifBadArg;
373 }
374 if (!clkmgr_measure_ctrl_regwen(clkmgr)) {
375 return kDifLocked;
376 }
377
378 dt_clkmgr_t dt;
379 DIF_RETURN_IF_ERROR(dif_clkmgr_get_dt(clkmgr, &dt));
380 if (clock >= dt_clkmgr_measurable_clock_count(dt)) {
381 return kDifBadArg;
382 }
384
385 uint32_t measure_ctrl_reg = 0;
386 measure_ctrl_reg = bitfield_field32_write(
387 measure_ctrl_reg, info.meas_ctrl_shadowed_lo_field, lo_threshold);
388 measure_ctrl_reg = bitfield_field32_write(
389 measure_ctrl_reg, info.meas_ctrl_shadowed_hi_field, hi_threshold);
390 // Two writes, because these registers are shadowed.
391 mmio_region_write32(clkmgr->base_addr, (ptrdiff_t)info.meas_ctrl_shadowed_off,
392 measure_ctrl_reg);
393 mmio_region_write32(clkmgr->base_addr, (ptrdiff_t)info.meas_ctrl_shadowed_off,
394 measure_ctrl_reg);
395
396 uint32_t measure_en_reg =
397 bitfield_field32_write(0, info.meas_ctrl_en_en_field, kMultiBitBool4True);
398 mmio_region_write32(clkmgr->base_addr, (ptrdiff_t)info.meas_ctrl_en_off,
399 measure_en_reg);
400
401 return kDifOk;
402}
403
404dif_result_t dif_clkmgr_disable_measure_counts(
405 const dif_clkmgr_t *clkmgr, dif_clkmgr_measure_clock_t clock) {
406 if (clkmgr == NULL) {
407 return kDifBadArg;
408 }
409 if (!clkmgr_measure_ctrl_regwen(clkmgr)) {
410 return kDifLocked;
411 }
412
413 dt_clkmgr_t dt;
414 DIF_RETURN_IF_ERROR(dif_clkmgr_get_dt(clkmgr, &dt));
415 if (clock >= dt_clkmgr_measurable_clock_count(dt)) {
416 return kDifBadArg;
417 }
419
420 uint32_t measure_en_reg = bitfield_field32_write(
421 0, info.meas_ctrl_en_en_field, kMultiBitBool4False);
422 mmio_region_write32(clkmgr->base_addr, (ptrdiff_t)info.meas_ctrl_en_off,
423 measure_en_reg);
424 return kDifOk;
425}
426
427dif_result_t dif_clkmgr_measure_counts_get_enable(
428 const dif_clkmgr_t *clkmgr, dif_clkmgr_measure_clock_t clock,
429 dif_toggle_t *state) {
430 if (clkmgr == NULL || state == NULL) {
431 return kDifBadArg;
432 }
433
434 dt_clkmgr_t dt;
435 DIF_RETURN_IF_ERROR(dif_clkmgr_get_dt(clkmgr, &dt));
436 if (clock >= dt_clkmgr_measurable_clock_count(dt)) {
437 return kDifBadArg;
438 }
440
441 uint32_t en_val =
442 mmio_region_read32(clkmgr->base_addr, (ptrdiff_t)info.meas_ctrl_en_off);
443 *state = dif_multi_bit_bool_to_toggle(
444 bitfield_field32_read(en_val, info.meas_ctrl_en_en_field));
445
446 return kDifOk;
447}
448
449dif_result_t dif_clkmgr_measure_counts_get_thresholds(
450 const dif_clkmgr_t *clkmgr, dif_clkmgr_measure_clock_t clock,
451 uint32_t *min_threshold, uint32_t *max_threshold) {
452 if (clkmgr == NULL || min_threshold == NULL || max_threshold == NULL) {
453 return kDifBadArg;
454 }
455
456 dt_clkmgr_t dt;
457 DIF_RETURN_IF_ERROR(dif_clkmgr_get_dt(clkmgr, &dt));
458 if (clock >= dt_clkmgr_measurable_clock_count(dt)) {
459 return kDifBadArg;
460 }
462
463 uint32_t thresholds_val = mmio_region_read32(
464 clkmgr->base_addr, (ptrdiff_t)info.meas_ctrl_shadowed_off);
465 *min_threshold =
466 bitfield_field32_read(thresholds_val, info.meas_ctrl_shadowed_lo_field);
467 *max_threshold =
468 bitfield_field32_read(thresholds_val, info.meas_ctrl_shadowed_hi_field);
469
470 return kDifOk;
471}
472
473dif_result_t dif_clkmgr_recov_err_code_get_codes(
474 const dif_clkmgr_t *clkmgr, dif_clkmgr_recov_err_codes_t *codes) {
475 if (clkmgr == NULL || codes == NULL) {
476 return kDifBadArg;
477 }
478 *codes =
479 mmio_region_read32(clkmgr->base_addr, CLKMGR_RECOV_ERR_CODE_REG_OFFSET);
480 return kDifOk;
481}
482
483dif_result_t dif_clkmgr_recov_err_code_clear_codes(
484 const dif_clkmgr_t *clkmgr, dif_clkmgr_recov_err_codes_t codes) {
485 if (clkmgr == NULL) {
486 return kDifBadArg;
487 }
488 mmio_region_write32(clkmgr->base_addr, CLKMGR_RECOV_ERR_CODE_REG_OFFSET,
489 codes);
490 return kDifOk;
491}
492
493dif_result_t dif_clkmgr_fatal_err_code_get_codes(
494 const dif_clkmgr_t *clkmgr, dif_clkmgr_fatal_err_codes_t *codes) {
495 if (clkmgr == NULL || codes == NULL) {
496 return kDifBadArg;
497 }
498 *codes =
499 mmio_region_read32(clkmgr->base_addr, CLKMGR_FATAL_ERR_CODE_REG_OFFSET);
500 return kDifOk;
501}
502
503dif_result_t dif_clkmgr_wait_for_ext_clk_switch(const dif_clkmgr_t *clkmgr) {
504 if (clkmgr == NULL) {
505 return kDifBadArg;
506 }
507 uint32_t ext_status;
508 do {
509 ext_status =
510 mmio_region_read32(clkmgr->base_addr, CLKMGR_EXTCLK_STATUS_REG_OFFSET);
511 } while (ext_status != kMultiBitBool4True);
512 return kDifOk;
513}