blob: a769da788ce350116fa4c709c5739e75a786e25d [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_pattgen.h"
#include "sw/device/lib/base/bitfield.h"
#include "sw/device/lib/dif/dif_base.h"
#include "pattgen_regs.h" // Generated.
dif_result_t dif_pattgen_configure_channel(
const dif_pattgen_t *pattgen, dif_pattgen_channel_t channel,
dif_pattgen_channel_config_t config) {
if (pattgen == NULL || config.polarity >= kDifPattgenPolarityCount ||
config.seed_pattern_length == 0 || config.seed_pattern_length > 64 ||
config.num_pattern_repetitions == 0 ||
config.num_pattern_repetitions > 1024) {
return kDifBadArg;
}
bitfield_bit32_index_t enable_bit_idx;
bitfield_bit32_index_t polarity_bit_idx;
ptrdiff_t clock_divisor_reg_offset;
ptrdiff_t seed_lower_reg_offset;
ptrdiff_t seed_upper_reg_offset;
bitfield_field32_t seed_pattern_length_field;
bitfield_field32_t num_pattern_repetitions_field;
#define DIF_PATTGEN_CHANNEL_CONFIG_CASE_(channel_) \
case kDifPattgenChannel##channel_: \
enable_bit_idx = PATTGEN_CTRL_ENABLE_CH##channel_##_BIT; \
polarity_bit_idx = PATTGEN_CTRL_POLARITY_CH##channel_##_BIT; \
clock_divisor_reg_offset = PATTGEN_PREDIV_CH##channel_##_REG_OFFSET; \
seed_lower_reg_offset = PATTGEN_DATA_CH##channel_##_0_REG_OFFSET; \
seed_upper_reg_offset = PATTGEN_DATA_CH##channel_##_1_REG_OFFSET; \
seed_pattern_length_field = PATTGEN_SIZE_LEN_CH##channel_##_FIELD; \
num_pattern_repetitions_field = PATTGEN_SIZE_REPS_CH##channel_##_FIELD; \
break;
switch (channel) {
DIF_PATTGEN_CHANNEL_LIST(DIF_PATTGEN_CHANNEL_CONFIG_CASE_)
default:
return kDifBadArg;
}
#undef DIF_PATTGEN_CHANNEL_CONFIG_CASE_
uint32_t ctrl_reg =
mmio_region_read32(pattgen->base_addr, PATTGEN_CTRL_REG_OFFSET);
// Check if channel is enabled. We cannot configure the channel if so.
if (bitfield_bit32_read(ctrl_reg, enable_bit_idx)) {
return kDifError;
}
// Set the polarity.
ctrl_reg = bitfield_bit32_write(ctrl_reg, polarity_bit_idx, config.polarity);
mmio_region_write32(pattgen->base_addr, PATTGEN_CTRL_REG_OFFSET, ctrl_reg);
// Set the clock divisor.
mmio_region_write32(pattgen->base_addr, clock_divisor_reg_offset,
config.clock_divisor);
// Write the seed data.
mmio_region_write32(pattgen->base_addr, seed_lower_reg_offset,
config.seed_pattern_lower_word);
if (config.seed_pattern_length > 31) {
mmio_region_write32(pattgen->base_addr, seed_upper_reg_offset,
config.seed_pattern_upper_word);
}
// Set the size and repetition values.
uint32_t size_reg =
mmio_region_read32(pattgen->base_addr, PATTGEN_SIZE_REG_OFFSET);
size_reg = bitfield_field32_write(size_reg, seed_pattern_length_field,
config.seed_pattern_length - 1);
size_reg = bitfield_field32_write(size_reg, num_pattern_repetitions_field,
config.num_pattern_repetitions - 1);
mmio_region_write32(pattgen->base_addr, PATTGEN_SIZE_REG_OFFSET, size_reg);
return kDifOk;
}
dif_result_t dif_pattgen_channel_set_enabled(const dif_pattgen_t *pattgen,
dif_pattgen_channel_t channel,
dif_toggle_t enabled) {
if (pattgen == NULL || !dif_is_valid_toggle(enabled)) {
return kDifBadArg;
}
bitfield_bit32_index_t enable_bit_idx;
#define DIF_PATTGEN_CHANNEL_SET_ENABLED_CASE_(channel_) \
case kDifPattgenChannel##channel_: \
enable_bit_idx = PATTGEN_CTRL_ENABLE_CH##channel_##_BIT; \
break;
switch (channel) {
DIF_PATTGEN_CHANNEL_LIST(DIF_PATTGEN_CHANNEL_SET_ENABLED_CASE_)
default:
return kDifBadArg;
}
#undef DIF_PATTGEN_CHANNEL_SET_ENABLED_CASE_
uint32_t ctrl_reg =
mmio_region_read32(pattgen->base_addr, PATTGEN_CTRL_REG_OFFSET);
ctrl_reg = bitfield_bit32_write(ctrl_reg, enable_bit_idx,
dif_toggle_to_bool(enabled));
mmio_region_write32(pattgen->base_addr, PATTGEN_CTRL_REG_OFFSET, ctrl_reg);
return kDifOk;
}
dif_result_t dif_pattgen_channel_get_enabled(const dif_pattgen_t *pattgen,
dif_pattgen_channel_t channel,
dif_toggle_t *is_enabled) {
if (pattgen == NULL || is_enabled == NULL) {
return kDifBadArg;
}
bitfield_bit32_index_t enable_bit_idx;
#define DIF_PATTGEN_CHANNEL_SET_ENABLED_CASE_(channel_) \
case kDifPattgenChannel##channel_: \
enable_bit_idx = PATTGEN_CTRL_ENABLE_CH##channel_##_BIT; \
break;
switch (channel) {
DIF_PATTGEN_CHANNEL_LIST(DIF_PATTGEN_CHANNEL_SET_ENABLED_CASE_)
default:
return kDifBadArg;
}
#undef DIF_PATTGEN_CHANNEL_SET_ENABLED_CASE_
uint32_t ctrl_reg =
mmio_region_read32(pattgen->base_addr, PATTGEN_CTRL_REG_OFFSET);
*is_enabled =
dif_bool_to_toggle(bitfield_bit32_read(ctrl_reg, enable_bit_idx));
return kDifOk;
}