blob: 18f92fb70b00c74ea9ff65e3ec1b0062e828caa4 [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 "sw/device/lib/base/bitfield.h"
#include "sw/device/lib/base/mmio.h"
#include "sw/device/lib/dif/dif_base.h"
#include "clkmgr_regs.h" // Generated
static bool clkmgr_valid_gateable_clock(dif_clkmgr_params_t params,
dif_clkmgr_gateable_clock_t clock) {
// TODO For the moment, last_gateable_clocks has to be less than 32, as we
// only support one enable register for gateable clocks.
// https://github.com/lowRISC/opentitan/issues/4201
return (clock <= params.last_gateable_clock) &&
(params.last_gateable_clock < CLKMGR_PARAM_REG_WIDTH);
}
static bool clkmgr_valid_hintable_clock(dif_clkmgr_params_t params,
dif_clkmgr_hintable_clock_t clock) {
// TODO: For the moment, last_hintable_clocks has to be less than 32, as we
// only support one enable/hint_status register for hintable clocks.
// https://github.com/lowRISC/opentitan/issues/4201
return (clock <= params.last_hintable_clock) &&
(params.last_hintable_clock < CLKMGR_PARAM_REG_WIDTH);
}
dif_result_t dif_clkmgr_init(mmio_region_t base_addr,
dif_clkmgr_params_t params, dif_clkmgr_t *clkmgr) {
if (clkmgr == NULL) {
return kDifBadArg;
}
// TODO: For the moment, `last_hintable_clock` and `last_gateable_clock` has
// to be less than 32, as we only support one register of bits for each.
// https://github.com/lowRISC/opentitan/issues/4201
if (params.last_gateable_clock >= CLKMGR_PARAM_REG_WIDTH ||
params.last_hintable_clock >= CLKMGR_PARAM_REG_WIDTH) {
return kDifBadArg;
}
clkmgr->base_addr = base_addr;
return kDifOk;
}
dif_result_t dif_clkmgr_gateable_clock_get_enabled(
const dif_clkmgr_t *clkmgr, dif_clkmgr_params_t params,
dif_clkmgr_gateable_clock_t clock, bool *is_enabled) {
if (clkmgr == NULL || is_enabled == NULL ||
!clkmgr_valid_gateable_clock(params, clock)) {
return kDifBadArg;
}
uint32_t clk_enables_val =
mmio_region_read32(clkmgr->base_addr, CLKMGR_CLK_ENABLES_REG_OFFSET);
*is_enabled = 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_params_t params,
dif_clkmgr_gateable_clock_t clock, dif_toggle_t new_state) {
if (clkmgr == NULL || !clkmgr_valid_gateable_clock(params, 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_params_t params,
dif_clkmgr_hintable_clock_t clock, bool *is_enabled) {
if (clkmgr == NULL || is_enabled == NULL ||
!clkmgr_valid_hintable_clock(params, clock)) {
return kDifBadArg;
}
uint32_t clk_hints_val =
mmio_region_read32(clkmgr->base_addr, CLKMGR_CLK_HINTS_STATUS_REG_OFFSET);
*is_enabled = 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_params_t params,
dif_clkmgr_hintable_clock_t clock, dif_toggle_t new_state) {
if (clkmgr == NULL || !clkmgr_valid_hintable_clock(params, 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_params_t params,
dif_clkmgr_hintable_clock_t clock, bool *hinted_is_enabled) {
if (clkmgr == NULL || hinted_is_enabled == NULL ||
!clkmgr_valid_hintable_clock(params, clock)) {
return kDifBadArg;
}
uint32_t clk_hints_val =
mmio_region_read32(clkmgr->base_addr, CLKMGR_CLK_HINTS_REG_OFFSET);
*hinted_is_enabled = bitfield_bit32_read(clk_hints_val, clock);
return kDifOk;
}