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
38 extern "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  */
64 typedef enum dif_pwm_channel {
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  */
76 typedef 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  */
107 typedef 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  */
127 typedef 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  */
144 typedef struct dif_pwm_channel_config {
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,
246  dif_pwm_channel_config_t config);
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  */
319 dif_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_