blob: 5052ea44da14188d9949c1e77859a7f3cf981cb1 [file] [log] [blame]
// Copyright lowRISC contributors.
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
// SPDX-License-Identifier: Apache-2.0
#include "sw/device/lib/dif/dif_clkmgr.h"
#include <assert.h>
#include "sw/device/lib/base/bitfield.h"
#include "sw/device/lib/base/mmio.h"
#include "sw/device/lib/base/multibits.h"
#include "sw/device/lib/dif/dif_base.h"
#include "clkmgr_regs.h" // Generated
// TODO: For the moment, CLKMGR_PARAM_NUM_SW_GATEABLE_CLOCKS has to be <= than
// 32, as we only support one enable register for gateable clocks.
// https://github.com/lowRISC/opentitan/issues/4201
static_assert(
CLKMGR_PARAM_NUM_SW_GATEABLE_CLOCKS <= CLKMGR_PARAM_REG_WIDTH,
"Expected the number of gateable clocks to be <= the width of a CSR.");
// TODO: For the moment, CLKMGR_PARAM_NUM_HINTABLE_CLOCKS has to be <= than
// 32, as we only support one enable/hint_status register for hintable clocks.
// https://github.com/lowRISC/opentitan/issues/4201
static_assert(
CLKMGR_PARAM_NUM_HINTABLE_CLOCKS <= CLKMGR_PARAM_REG_WIDTH,
"Expected the number of hintable clocks to be <= the width of a CSR.");
/**
* Converts a `bool` to `dif_toggle_t`.
*/
static dif_toggle_t bool_to_toggle(bool val) {
return val ? kDifToggleEnabled : kDifToggleDisabled;
}
/**
* Converts a `multi_bit_bool_t` to `dif_toggle_t`.
*/
static dif_toggle_t mubi4_to_toggle(multi_bit_bool_t val) {
return (val == kMultiBitBool4True) ? kDifToggleEnabled : kDifToggleDisabled;
}
static bool clkmgr_valid_gateable_clock(dif_clkmgr_gateable_clock_t clock) {
return clock < CLKMGR_PARAM_NUM_SW_GATEABLE_CLOCKS;
}
static bool clkmgr_valid_hintable_clock(dif_clkmgr_hintable_clock_t clock) {
return clock < CLKMGR_PARAM_NUM_HINTABLE_CLOCKS;
}
dif_result_t dif_clkmgr_jitter_get_enabled(const dif_clkmgr_t *clkmgr,
dif_toggle_t *state) {
if (clkmgr == NULL || state == NULL) {
return kDifBadArg;
}
multi_bit_bool_t clk_jitter_val =
mmio_region_read32(clkmgr->base_addr, CLKMGR_JITTER_ENABLE_REG_OFFSET);
*state = mubi4_to_toggle(clk_jitter_val);
return kDifOk;
}
dif_result_t dif_clkmgr_jitter_set_enabled(const dif_clkmgr_t *clkmgr,
dif_toggle_t new_state) {
multi_bit_bool_t new_jitter_enable_val;
if (clkmgr == NULL) {
return kDifBadArg;
}
switch (new_state) {
case kDifToggleEnabled:
new_jitter_enable_val = kMultiBitBool4True;
break;
case kDifToggleDisabled:
new_jitter_enable_val = kMultiBitBool4False;
break;
default:
return kDifBadArg;
}
mmio_region_write32(clkmgr->base_addr, CLKMGR_JITTER_ENABLE_REG_OFFSET,
new_jitter_enable_val);
return kDifOk;
}
dif_result_t dif_clkmgr_gateable_clock_get_enabled(
const dif_clkmgr_t *clkmgr, dif_clkmgr_gateable_clock_t clock,
dif_toggle_t *state) {
if (clkmgr == NULL || state == NULL || !clkmgr_valid_gateable_clock(clock)) {
return kDifBadArg;
}
uint32_t clk_enables_val =
mmio_region_read32(clkmgr->base_addr, CLKMGR_CLK_ENABLES_REG_OFFSET);
*state = bool_to_toggle(bitfield_bit32_read(clk_enables_val, clock));
return kDifOk;
}
dif_result_t dif_clkmgr_gateable_clock_set_enabled(
const dif_clkmgr_t *clkmgr, dif_clkmgr_gateable_clock_t clock,
dif_toggle_t new_state) {
if (clkmgr == NULL || !clkmgr_valid_gateable_clock(clock)) {
return kDifBadArg;
}
bool new_clk_enables_bit;
switch (new_state) {
case kDifToggleEnabled:
new_clk_enables_bit = true;
break;
case kDifToggleDisabled:
new_clk_enables_bit = false;
break;
default:
return kDifBadArg;
}
uint32_t clk_enables_val =
mmio_region_read32(clkmgr->base_addr, CLKMGR_CLK_ENABLES_REG_OFFSET);
clk_enables_val =
bitfield_bit32_write(clk_enables_val, clock, new_clk_enables_bit);
mmio_region_write32(clkmgr->base_addr, CLKMGR_CLK_ENABLES_REG_OFFSET,
clk_enables_val);
return kDifOk;
}
dif_result_t dif_clkmgr_hintable_clock_get_enabled(
const dif_clkmgr_t *clkmgr, dif_clkmgr_hintable_clock_t clock,
dif_toggle_t *state) {
if (clkmgr == NULL || state == NULL || !clkmgr_valid_hintable_clock(clock)) {
return kDifBadArg;
}
uint32_t clk_hints_val =
mmio_region_read32(clkmgr->base_addr, CLKMGR_CLK_HINTS_STATUS_REG_OFFSET);
*state = bool_to_toggle(bitfield_bit32_read(clk_hints_val, clock));
return kDifOk;
}
dif_result_t dif_clkmgr_hintable_clock_set_hint(
const dif_clkmgr_t *clkmgr, dif_clkmgr_hintable_clock_t clock,
dif_toggle_t new_state) {
if (clkmgr == NULL || !clkmgr_valid_hintable_clock(clock)) {
return kDifBadArg;
}
bool new_clk_hints_bit;
switch (new_state) {
case kDifToggleEnabled:
new_clk_hints_bit = true;
break;
case kDifToggleDisabled:
new_clk_hints_bit = false;
break;
default:
return kDifBadArg;
}
uint32_t clk_hints_val =
mmio_region_read32(clkmgr->base_addr, CLKMGR_CLK_HINTS_REG_OFFSET);
clk_hints_val = bitfield_bit32_write(clk_hints_val, clock, new_clk_hints_bit);
mmio_region_write32(clkmgr->base_addr, CLKMGR_CLK_HINTS_REG_OFFSET,
clk_hints_val);
return kDifOk;
}
dif_result_t dif_clkmgr_hintable_clock_get_hint(
const dif_clkmgr_t *clkmgr, dif_clkmgr_hintable_clock_t clock,
dif_toggle_t *state) {
if (clkmgr == NULL || state == NULL || !clkmgr_valid_hintable_clock(clock)) {
return kDifBadArg;
}
uint32_t clk_hints_val =
mmio_region_read32(clkmgr->base_addr, CLKMGR_CLK_HINTS_REG_OFFSET);
*state = bool_to_toggle(bitfield_bit32_read(clk_hints_val, clock));
return kDifOk;
}