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 
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 
95  dif_pattgen_channel_t channel,
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 
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 }