Software APIs
dif_pattgen.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
9
10#include "pattgen_regs.h" // Generated.
11
12dif_result_t dif_pattgen_configure_channel(
13 const dif_pattgen_t *pattgen, dif_pattgen_channel_t channel,
15 if (pattgen == NULL || config.polarity >= kDifPattgenPolarityCount ||
16 config.seed_pattern_length == 0 || config.seed_pattern_length > 64 ||
17 config.num_pattern_repetitions == 0 ||
18 config.num_pattern_repetitions > 1024) {
19 return kDifBadArg;
20 }
21
22 bitfield_bit32_index_t enable_bit_idx;
23 bitfield_bit32_index_t polarity_bit_idx;
24 bitfield_bit32_index_t inactive_level_pda_bit_idx;
25 bitfield_bit32_index_t inactive_level_pcl_bit_idx;
26 ptrdiff_t clock_divisor_reg_offset;
27 ptrdiff_t seed_lower_reg_offset;
28 ptrdiff_t seed_upper_reg_offset;
29 bitfield_field32_t seed_pattern_length_field;
30 bitfield_field32_t num_pattern_repetitions_field;
31
32#define DIF_PATTGEN_CHANNEL_CONFIG_CASE_(channel_) \
33 case kDifPattgenChannel##channel_: \
34 enable_bit_idx = PATTGEN_CTRL_ENABLE_CH##channel_##_BIT; \
35 polarity_bit_idx = PATTGEN_CTRL_POLARITY_CH##channel_##_BIT; \
36 inactive_level_pda_bit_idx = \
37 PATTGEN_CTRL_INACTIVE_LEVEL_PDA_CH##channel_##_BIT; \
38 inactive_level_pcl_bit_idx = \
39 PATTGEN_CTRL_INACTIVE_LEVEL_PCL_CH##channel_##_BIT; \
40 clock_divisor_reg_offset = PATTGEN_PREDIV_CH##channel_##_REG_OFFSET; \
41 seed_lower_reg_offset = PATTGEN_DATA_CH##channel_##_0_REG_OFFSET; \
42 seed_upper_reg_offset = PATTGEN_DATA_CH##channel_##_1_REG_OFFSET; \
43 seed_pattern_length_field = PATTGEN_SIZE_LEN_CH##channel_##_FIELD; \
44 num_pattern_repetitions_field = PATTGEN_SIZE_REPS_CH##channel_##_FIELD; \
45 break;
46
47 switch (channel) {
48 DIF_PATTGEN_CHANNEL_LIST(DIF_PATTGEN_CHANNEL_CONFIG_CASE_)
49 default:
50 return kDifBadArg;
51 }
52#undef DIF_PATTGEN_CHANNEL_CONFIG_CASE_
53
54 uint32_t ctrl_reg =
55 mmio_region_read32(pattgen->base_addr, PATTGEN_CTRL_REG_OFFSET);
56
57 // Check if channel is enabled. We cannot configure the channel if so.
58 if (bitfield_bit32_read(ctrl_reg, enable_bit_idx)) {
59 return kDifError;
60 }
61
62 // Set the polarity and inactive levels.
63 ctrl_reg = bitfield_bit32_write(ctrl_reg, polarity_bit_idx, config.polarity);
64 ctrl_reg = bitfield_bit32_write(ctrl_reg, inactive_level_pda_bit_idx,
65 config.inactive_level_pda);
66 ctrl_reg = bitfield_bit32_write(ctrl_reg, inactive_level_pcl_bit_idx,
67 config.inactive_level_pcl);
68 mmio_region_write32(pattgen->base_addr, PATTGEN_CTRL_REG_OFFSET, ctrl_reg);
69
70 // Set the clock divisor.
71 mmio_region_write32(pattgen->base_addr, clock_divisor_reg_offset,
72 config.clock_divisor);
73
74 // Write the seed data.
75 mmio_region_write32(pattgen->base_addr, seed_lower_reg_offset,
77 if (config.seed_pattern_length > 31) {
78 mmio_region_write32(pattgen->base_addr, seed_upper_reg_offset,
80 }
81
82 // Set the size and repetition values.
83 uint32_t size_reg =
84 mmio_region_read32(pattgen->base_addr, PATTGEN_SIZE_REG_OFFSET);
85 size_reg = bitfield_field32_write(size_reg, seed_pattern_length_field,
86 config.seed_pattern_length - 1);
87 size_reg = bitfield_field32_write(size_reg, num_pattern_repetitions_field,
88 config.num_pattern_repetitions - 1);
89 mmio_region_write32(pattgen->base_addr, PATTGEN_SIZE_REG_OFFSET, size_reg);
90
91 return kDifOk;
92}
93
94dif_result_t dif_pattgen_channel_set_enabled(const dif_pattgen_t *pattgen,
96 dif_toggle_t enabled) {
97 if (pattgen == NULL || !dif_is_valid_toggle(enabled)) {
98 return kDifBadArg;
99 }
100
101 bitfield_bit32_index_t enable_bit_idx;
102
103#define DIF_PATTGEN_CHANNEL_SET_ENABLED_CASE_(channel_) \
104 case kDifPattgenChannel##channel_: \
105 enable_bit_idx = PATTGEN_CTRL_ENABLE_CH##channel_##_BIT; \
106 break;
107
108 switch (channel) {
109 DIF_PATTGEN_CHANNEL_LIST(DIF_PATTGEN_CHANNEL_SET_ENABLED_CASE_)
110 default:
111 return kDifBadArg;
112 }
113#undef DIF_PATTGEN_CHANNEL_SET_ENABLED_CASE_
114
115 uint32_t ctrl_reg =
116 mmio_region_read32(pattgen->base_addr, PATTGEN_CTRL_REG_OFFSET);
117 ctrl_reg = bitfield_bit32_write(ctrl_reg, enable_bit_idx,
118 dif_toggle_to_bool(enabled));
119 mmio_region_write32(pattgen->base_addr, PATTGEN_CTRL_REG_OFFSET, ctrl_reg);
120
121 return kDifOk;
122}
123
124dif_result_t dif_pattgen_channel_get_enabled(const dif_pattgen_t *pattgen,
125 dif_pattgen_channel_t channel,
126 dif_toggle_t *is_enabled) {
127 if (pattgen == NULL || is_enabled == NULL) {
128 return kDifBadArg;
129 }
130
131 bitfield_bit32_index_t enable_bit_idx;
132
133#define DIF_PATTGEN_CHANNEL_SET_ENABLED_CASE_(channel_) \
134 case kDifPattgenChannel##channel_: \
135 enable_bit_idx = PATTGEN_CTRL_ENABLE_CH##channel_##_BIT; \
136 break;
137
138 switch (channel) {
139 DIF_PATTGEN_CHANNEL_LIST(DIF_PATTGEN_CHANNEL_SET_ENABLED_CASE_)
140 default:
141 return kDifBadArg;
142 }
143#undef DIF_PATTGEN_CHANNEL_SET_ENABLED_CASE_
144
145 uint32_t ctrl_reg =
146 mmio_region_read32(pattgen->base_addr, PATTGEN_CTRL_REG_OFFSET);
147 *is_enabled =
148 dif_bool_to_toggle(bitfield_bit32_read(ctrl_reg, enable_bit_idx));
149
150 return kDifOk;
151}