Software APIs
dif_pwm.h
Go to the documentation of this file.
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
5#ifndef OPENTITAN_SW_DEVICE_LIB_DIF_DIF_PWM_H_
6#define OPENTITAN_SW_DEVICE_LIB_DIF_DIF_PWM_H_
7
8/**
9 * @file
10 * @brief <a href="/hw/ip/pwm/doc/">PWM</a> Device Interface Functions
11 *
12 * The PWM block contains a 16-bit "phase counter" that controls each channel's
13 * output signal. The "phase counter" acts as a point of reference for a single
14 * PWM "pulse cycle", that is further broken into "beats", depending on the
15 * `beats_per_cycle` parameter. Specifically, a "pulse cycle" may contain [2,
16 * 2^16] "beats". Within a "pulse cycle", users can configure the duty cycle in
17 * number of "beats". Additionally, the duration of a single "beat", is computed
18 * by dividing the core clock frequency by `clock_divisor + 1`.
19 *
20 * PWM "pulse cycle" defined by 16-bit phase counter
21 * ___________________________________________________________
22 * | |
23 * v v
24 * |-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-| ... |-|-|-|-|
25 *
26 * |-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-| ... |-|-|-|-|
27 * min beat size = 1 phase counter tick --> 2^16 "beats" / "pulse cycle"
28 *
29 * |---------------------------------------------- ... | ... --|
30 * max beat size = 2^15 phase counter ticks --> 2 "beats" / "pulse cycle"
31 */
32
33#include <stdint.h>
34
36
37#ifdef __cplusplus
38extern "C" {
39#endif // __cplusplus
40
41/**
42 * Helper X macro for defining enums and case statements related to PWM
43 * channels. If an additional channel is ever added to the hardware, this list
44 * can be updated.
45 */
46#define DIF_PWM_CHANNEL_LIST(X) \
47 X(0) \
48 X(1) \
49 X(2) \
50 X(3) \
51 X(4) \
52 X(5)
53
54/**
55 * Helper macro for defining a `dif_pwm_channel_t` enumeration constant.
56 * @channel_ PWM channel of the enumeration constant.
57 */
58#define PWM_CHANNEL_ENUM_INIT_(channel_) \
59 kDifPwmChannel##channel_ = 1U << channel_,
60
61/**
62 * A PWM channel.
63 */
67
68#undef PWM_CHANNEL_ENUM_INIT_
69
70/**
71 * Runtime configuration for PWM.
72 *
73 * This struct describes runtime configuration for one-time configuration of the
74 * PWM "pulse cycle" and "beat" durations that impact all PWM channels.
75 */
76typedef struct dif_pwm_config {
77 /**
78 * The core clock frequency divisor that determines the period of a single
79 * "beat" within a PWM "pulse cycle".
80 *
81 * Valid range: [0, 2^26)
82 *
83 * A value of zero, configures the "beat" period to the core clock period.
84 */
85 uint32_t clock_divisor;
86 /**
87 * The total number of "beats" in a "pulse cycle", including both "on" and
88 * "off" beats in a "pulse cycle".
89 *
90 * Valid range: [2, 2^16]
91 *
92 * Note: while any value in the range is acceptable, values will be rounded
93 * down to closest power-of-two.
94 *
95 * A "beat" represents a unit of time of the PWM output signal. Higher values
96 * provide higher duty cycle resolutions, at the expense of longer "pulse
97 * cycles", while lower values provide shorter "pulse cycles", at the expense
98 * of lower duty cycle resolutions (since duty cycles are configured in
99 * "beats" / "pulse cycle").
100 */
103
104/**
105 * A PWM channel mode.
106 */
107typedef enum dif_pwm_mode {
108 /**
109 * The PWM duty cycle is set by the firmware and remains constant.
110 */
112 /**
113 * The PWM duty cycle linearly sweeps between both primary and secondary
114 * firmware-configured values, based on a firmware-configured step size.
115 */
117 /**
118 * The PWM duty cycle alternates between both primary and secondary
119 * firmware-configured values, based on two firmware-configured durations.
120 */
123
124/**
125 * A PWM channel polarity.
126 */
127typedef enum dif_pwm_polarity {
128 /**
129 * A PWM signal is active-high.
130 */
132 /**
133 * A PWM signal is active-low.
134 */
137
138/**
139 * Runtime configuration for a specific PWM channel.
140 *
141 * This struct describes runtime configuration for one-time configuration of a
142 * specific PWM channel.
143 */
145 /**
146 * Primary duty cycle, in number of "beats" / "pulse cycle".
147 *
148 * Valid range: [0, beats_per_pulse_cycle)
149 *
150 * Note: the raw value written to the `A_*` bitfield in each PWM channel's
151 * `DUTY_CYCLE_*` CSR is in units of "phase counter ticks", not "beats".
152 * However, the hardware only takes into account the first `DC_RESN` + 1
153 * MSBs of the raw duty cycle value to determine the number of "beats"
154 * for a given duty cycle. To make this configuration easier, the
155 * software manages the conversion from "beats_per_cycle" to
156 * "phase_counter_ticks" under the hood.
157 */
158 uint16_t duty_cycle_a;
159 /**
160 * Secondary duty cycle, in number of "beats" / "pulse cycle", that is only
161 * relevant in heartbeat and blink modes.
162 *
163 * Valid range: [0, beats_per_pulse_cycle)
164 *
165 * Note: above notes for `duty_cycle_a` apply here too.
166 */
167 uint16_t duty_cycle_b;
168 /**
169 * Phase delay at the beginning of a "pulse cycle" to delay the active
170 * duty cycle "beats" for, in number of "beats".
171 *
172 * Valid range: [0, beats_per_pulse_cycle)
173 */
174 uint16_t phase_delay;
175 /**
176 * The operation mode to configure the channel in, see `dif_pwm_mode_t`.
177 */
179 /**
180 * The polarity to configure the channel in, see `dif_pwm_polarity_t`.
181 */
183 /**
184 * One of two blink parameters that only impact the "Heartbeat" and "Blink"
185 * operation modes.
186 *
187 * The meaning of this parameter is different based on the operation mode:
188 * - Heartbeat mode: determines the number of "pulse cycles" between
189 * increments/decrements to the duty cycle.
190 *
191 * - Blink mode: determines the number of "pulse cycles" to pulse at duty
192 * cycle A, before switching to duty cycle B.
193 */
195 /**
196 * One of two blink parameters that only impact the "Heartbeat" and "Blink"
197 * operation modes.
198 *
199 * The meaning of this parameter is different based on the operation mode:
200 * - Heartbeat mode: determines the increment/decrement amount in number
201 * of duty cycle "beats".
202 *
203 * - Blink mode: determines the number of "pulse cycles" to pulse at duty
204 * cycle B, before switching to duty cycle A.
205 *
206 * Note: the raw value written to the `blink_parameter_x` bitfield in each PWM
207 * channel's `BLINK_PARAM_*` CSR is in units of "phase counter ticks", not
208 * "beats". However, for ease of configuration, the software manages this
209 * conversion under the hood.
210 */
213
214/**
215 * Configures "phase cycle" and "beat" durations of all PWM channels.
216 *
217 * Since changes to `CLK_DIV` and `DC_RESN` are only allowed when the PWM is
218 * disabled, this function has the side effect of temporarily disabling all PWM
219 * channels while configurations are updated, before restoring the original
220 * enablement state.
221 *
222 * This function should only need to be called once for the lifetime of
223 * `handle`.
224 *
225 * @param pwm A PWM handle.
226 * @param config Runtime configuration parameters.
227 * @return The result of the operation.
228 */
231
232/**
233 * Configures a single PWM channel.
234 *
235 * This function should only need to be called once for each PWM channel that
236 * will be used.
237 *
238 * @param pwm A PWM handle.
239 * @param channel A PWM channel to configure.
240 * @param config Runtime configuration parameters for the channel.
241 * @return The result of the operation.
242 */
245 dif_pwm_channel_t channel,
247
248/**
249 * Sets the enablement state of the PWM phase counter, which controls the
250 * enablement of all PWM channels.
251 *
252 * @param pwm A PWM handle.
253 * @param enabled The enablement state to configure the PWM phase counter in.
254 * @return The result of the operation.
255 */
258 dif_toggle_t enabled);
259
260/**
261 * Gets the enablement state of the PWM phase counter, which controls the
262 * enablement of all PWM channels.
263 *
264 * @param pwm A PWM handle.
265 * @param[out] is_enabled The enablement state of the PWM phase counter.
266 * @return The result of the operation.
267 */
270 dif_toggle_t *is_enabled);
271
272/**
273 * Sets the enablement states of one or more PWM channels.
274 *
275 * @param pwm A PWM handle.
276 * @param channels The channels to enable (one or more `dif_pmw_channel_t`s
277 * ORed together.)
278 * @param enabled The enablement state to set.
279 * @return The result of the operation.
280 */
283 uint32_t channels,
284 dif_toggle_t enabled);
285
286/**
287 * Gets the enablement state of one PWM channel.
288 *
289 * @param pwm A PWM handle.
290 * @param channel The PWM channel to get the enablement state of.
291 * @param[out] is_enabled The enablement state of the PWM channel.
292 * @return The result of the operation.
293 */
296 dif_pwm_channel_t channel,
297 dif_toggle_t *is_enabled);
298
299/**
300 * Locks PWM configurations.
301 *
302 * This function is reentrant: calling it while locked will have no effect and
303 * return `kDifOk`.
304 *
305 * @param pwm A PWM handle.
306 * @return The result of the operation.
307 */
310
311/**
312 * Checks whether PWM configurations are locked.
313 *
314 * @param pwm A PWM handle.
315 * @param[out] is_locked Out-param for the locked state.
316 * @return The result of the operation.
317 */
319dif_result_t dif_pwm_is_locked(const dif_pwm_t *pwm, bool *is_locked);
320
321#ifdef __cplusplus
322} // extern "C"
323#endif // __cplusplus
324
325#endif // OPENTITAN_SW_DEVICE_LIB_DIF_DIF_PWM_H_