Software APIs
dif_pinmux.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 
11 
12 #include "pinmux_regs.h" // Generated.
13 
14 static bool dif_pinmux_get_reg_offset(dif_pinmux_index_t index,
16  ptrdiff_t mio_reg_base,
17  ptrdiff_t dio_reg_base,
18  ptrdiff_t *reg_offset) {
19  uint32_t num_pads;
20  ptrdiff_t reg_base;
21 
22  switch (kind) {
24  num_pads = PINMUX_PARAM_N_MIO_PADS;
25  reg_base = mio_reg_base;
26  break;
28  num_pads = PINMUX_PARAM_N_DIO_PADS;
29  reg_base = dio_reg_base;
30  break;
31  default:
32  return false;
33  }
34  if (index >= num_pads) {
35  return false;
36  }
37  *reg_offset = reg_base + (ptrdiff_t)(index * sizeof(uint32_t));
38  return true;
39 }
40 
41 static bool dif_pinmux_get_sleep_status_bit(dif_pinmux_pad_kind_t kind,
42  dif_pinmux_index_t index,
43  ptrdiff_t *reg_offset,
45  uint32_t num_pads;
46  ptrdiff_t reg_base;
47 
48  switch (kind) {
50  num_pads = PINMUX_PARAM_N_MIO_PADS;
51  reg_base = PINMUX_MIO_PAD_SLEEP_STATUS_0_REG_OFFSET;
52  break;
54  num_pads = PINMUX_PARAM_N_DIO_PADS;
55  reg_base = PINMUX_DIO_PAD_SLEEP_STATUS_REG_OFFSET;
56  break;
57  default:
58  return false;
59  }
60  if (index >= num_pads) {
61  return false;
62  }
63  *reg_offset = (ptrdiff_t)index / 32 + reg_base;
64  *bit = index % 32;
65  return true;
66 }
67 
68 static bool dif_pinmux_get_lock_reg_offset(dif_pinmux_index_t index,
70  ptrdiff_t *reg_offset) {
71  ptrdiff_t reg_base;
72  size_t reg_count;
73  switch (target) {
75  reg_base = PINMUX_MIO_PERIPH_INSEL_REGWEN_0_REG_OFFSET;
76  reg_count = PINMUX_MIO_PERIPH_INSEL_REGWEN_MULTIREG_COUNT;
77  break;
79  reg_base = PINMUX_MIO_OUTSEL_REGWEN_0_REG_OFFSET;
80  reg_count = PINMUX_MIO_OUTSEL_REGWEN_MULTIREG_COUNT;
81  break;
83  reg_base = PINMUX_MIO_PAD_SLEEP_REGWEN_0_REG_OFFSET;
84  reg_count = PINMUX_MIO_PAD_SLEEP_REGWEN_MULTIREG_COUNT;
85  break;
87  reg_base = PINMUX_DIO_PAD_SLEEP_REGWEN_0_REG_OFFSET;
88  reg_count = PINMUX_DIO_PAD_SLEEP_REGWEN_MULTIREG_COUNT;
89  break;
91  reg_base = PINMUX_MIO_PAD_ATTR_REGWEN_0_REG_OFFSET;
92  reg_count = PINMUX_MIO_PAD_ATTR_REGWEN_MULTIREG_COUNT;
93  break;
95  reg_base = PINMUX_DIO_PAD_ATTR_REGWEN_0_REG_OFFSET;
96  reg_count = PINMUX_DIO_PAD_ATTR_REGWEN_MULTIREG_COUNT;
97  break;
99  reg_base = PINMUX_WKUP_DETECTOR_REGWEN_0_REG_OFFSET;
100  reg_count = PINMUX_WKUP_DETECTOR_REGWEN_MULTIREG_COUNT;
101  break;
102  default:
103  return false;
104  }
105 
106  if (index >= reg_count) {
107  return false;
108  }
109 
110  *reg_offset = reg_base + (ptrdiff_t)index * (ptrdiff_t)sizeof(uint32_t);
111  return true;
112 }
113 
115  dif_pinmux_index_t index,
116  dif_pinmux_lock_target_t target) {
117  if (pinmux == NULL) {
118  return kDifBadArg;
119  }
120 
121  ptrdiff_t reg_offset;
122  if (!dif_pinmux_get_lock_reg_offset(index, target, &reg_offset)) {
123  return kDifBadArg;
124  }
125  mmio_region_write32(pinmux->base_addr, reg_offset, /*value=*/0);
126  return kDifOk;
127 }
128 
130  dif_pinmux_index_t index,
132  bool *is_locked) {
133  if (pinmux == NULL || is_locked == NULL) {
134  return kDifBadArg;
135  }
136 
137  ptrdiff_t reg_offset;
138  if (!dif_pinmux_get_lock_reg_offset(index, target, &reg_offset)) {
139  return kDifBadArg;
140  }
141 
142  uint32_t reg_value = mmio_region_read32(pinmux->base_addr, reg_offset);
143  *is_locked = !bitfield_bit32_read(reg_value,
144  PINMUX_MIO_PERIPH_INSEL_REGWEN_0_EN_0_BIT);
145  return kDifOk;
146 }
147 
149  dif_pinmux_index_t peripheral_input,
150  dif_pinmux_index_t insel) {
151  if (pinmux == NULL || peripheral_input >= PINMUX_PARAM_N_MIO_PERIPH_IN ||
152  insel >= (2 + PINMUX_PARAM_N_MIO_PADS)) {
153  return kDifBadArg;
154  }
155  bool is_locked;
157  pinmux, peripheral_input, kDifPinmuxLockTargetInsel, &is_locked);
158  if (result != kDifOk) {
159  return result;
160  }
161  if (is_locked) {
162  return kDifLocked;
163  }
164  ptrdiff_t reg_offset =
165  PINMUX_MIO_PERIPH_INSEL_0_REG_OFFSET + (ptrdiff_t)(peripheral_input << 2);
166  uint32_t reg_value =
167  bitfield_field32_write(0, PINMUX_MIO_PERIPH_INSEL_0_IN_0_FIELD, insel);
168  mmio_region_write32(pinmux->base_addr, reg_offset, reg_value);
169  return kDifOk;
170 }
171 
173  dif_pinmux_index_t mio_pad_output,
174  dif_pinmux_index_t outsel) {
175  if (pinmux == NULL || mio_pad_output >= PINMUX_PARAM_N_MIO_PADS ||
176  outsel >= (3 + PINMUX_PARAM_N_MIO_PERIPH_OUT)) {
177  return kDifBadArg;
178  }
179  bool is_locked;
181  pinmux, mio_pad_output, kDifPinmuxLockTargetOutsel, &is_locked);
182  if (result != kDifOk) {
183  return result;
184  }
185  if (is_locked) {
186  return kDifLocked;
187  }
188  ptrdiff_t reg_offset =
189  PINMUX_MIO_OUTSEL_0_REG_OFFSET + (ptrdiff_t)(mio_pad_output << 2);
190  uint32_t reg_value =
191  bitfield_field32_write(0, PINMUX_MIO_OUTSEL_0_OUT_0_FIELD, outsel);
192  mmio_region_write32(pinmux->base_addr, reg_offset, reg_value);
193  return kDifOk;
194 }
195 
196 static dif_pinmux_pad_attr_t dif_pinmux_reg_to_pad_attr(uint32_t reg_value) {
197  dif_pinmux_pad_attr_t pad_attrs = {0};
199  reg_value, PINMUX_MIO_PAD_ATTR_0_SLEW_RATE_0_FIELD);
200  pad_attrs.drive_strength =
202  reg_value, PINMUX_MIO_PAD_ATTR_0_DRIVE_STRENGTH_0_FIELD);
203  if (bitfield_bit32_read(reg_value, PINMUX_MIO_PAD_ATTR_0_INVERT_0_BIT)) {
204  pad_attrs.flags |= kDifPinmuxPadAttrInvertLevel;
205  }
206  if (bitfield_bit32_read(reg_value,
207  PINMUX_MIO_PAD_ATTR_0_VIRTUAL_OD_EN_0_BIT)) {
208  pad_attrs.flags |= kDifPinmuxPadAttrVirtualOpenDrain;
209  }
210  if (bitfield_bit32_read(reg_value, PINMUX_MIO_PAD_ATTR_0_PULL_EN_0_BIT)) {
211  pad_attrs.flags |= kDifPinmuxPadAttrPullResistorEnable;
212  }
213  if (bitfield_bit32_read(reg_value, PINMUX_MIO_PAD_ATTR_0_PULL_SELECT_0_BIT)) {
214  pad_attrs.flags |= kDifPinmuxPadAttrPullResistorUp;
215  }
216  if (bitfield_bit32_read(reg_value, PINMUX_MIO_PAD_ATTR_0_KEEPER_EN_0_BIT)) {
217  pad_attrs.flags |= kDifPinmuxPadAttrKeeper;
218  }
219  if (bitfield_bit32_read(reg_value, PINMUX_MIO_PAD_ATTR_0_SCHMITT_EN_0_BIT)) {
220  pad_attrs.flags |= kDifPinmuxPadAttrSchmittTrigger;
221  }
222  if (bitfield_bit32_read(reg_value, PINMUX_MIO_PAD_ATTR_0_OD_EN_0_BIT)) {
223  pad_attrs.flags |= kDifPinmuxPadAttrOpenDrain;
224  }
225  return pad_attrs;
226 }
227 
228 enum { kDifPinmuxPadAttrSpinWaitMicros = 5 };
229 
231  dif_pinmux_index_t pad,
233  dif_pinmux_pad_attr_t attrs_in,
234  dif_pinmux_pad_attr_t *attrs_out) {
235  if (pinmux == NULL || attrs_out == NULL) {
236  return kDifBadArg;
237  }
238  if (attrs_in.drive_strength > PINMUX_MIO_PAD_ATTR_0_DRIVE_STRENGTH_0_MASK ||
239  attrs_in.slew_rate > PINMUX_MIO_PAD_ATTR_0_SLEW_RATE_0_MASK) {
240  return kDifBadArg;
241  }
242  ptrdiff_t reg_offset;
243  if (!dif_pinmux_get_reg_offset(pad, type, PINMUX_MIO_PAD_ATTR_0_REG_OFFSET,
244  PINMUX_DIO_PAD_ATTR_0_REG_OFFSET,
245  &reg_offset)) {
246  return kDifBadArg;
247  }
248  const dif_pinmux_lock_target_t lock_target =
251  bool is_locked;
252  dif_result_t result =
253  dif_pinmux_is_locked(pinmux, pad, lock_target, &is_locked);
254  if (result != kDifOk) {
255  return result;
256  }
257  if (is_locked) {
258  return kDifLocked;
259  }
260 
261  uint32_t reg_before = mmio_region_read32(pinmux->base_addr, reg_offset);
262 
263  uint32_t reg_value = bitfield_field32_write(
264  0, PINMUX_MIO_PAD_ATTR_0_SLEW_RATE_0_FIELD, attrs_in.slew_rate);
265  reg_value = bitfield_field32_write(
266  reg_value, PINMUX_MIO_PAD_ATTR_0_DRIVE_STRENGTH_0_FIELD,
267  attrs_in.drive_strength);
268  reg_value =
269  bitfield_bit32_write(reg_value, PINMUX_MIO_PAD_ATTR_0_INVERT_0_BIT,
270  attrs_in.flags & kDifPinmuxPadAttrInvertLevel);
271  reg_value =
272  bitfield_bit32_write(reg_value, PINMUX_MIO_PAD_ATTR_0_VIRTUAL_OD_EN_0_BIT,
273  attrs_in.flags & kDifPinmuxPadAttrVirtualOpenDrain);
274  reg_value = bitfield_bit32_write(
275  reg_value, PINMUX_MIO_PAD_ATTR_0_PULL_EN_0_BIT,
276  attrs_in.flags & kDifPinmuxPadAttrPullResistorEnable);
277  reg_value =
278  bitfield_bit32_write(reg_value, PINMUX_MIO_PAD_ATTR_0_PULL_SELECT_0_BIT,
279  attrs_in.flags & kDifPinmuxPadAttrPullResistorUp);
280  reg_value =
281  bitfield_bit32_write(reg_value, PINMUX_MIO_PAD_ATTR_0_KEEPER_EN_0_BIT,
282  attrs_in.flags & kDifPinmuxPadAttrKeeper);
283  reg_value =
284  bitfield_bit32_write(reg_value, PINMUX_MIO_PAD_ATTR_0_SCHMITT_EN_0_BIT,
285  attrs_in.flags & kDifPinmuxPadAttrSchmittTrigger);
286  reg_value = bitfield_bit32_write(reg_value, PINMUX_MIO_PAD_ATTR_0_OD_EN_0_BIT,
287  attrs_in.flags & kDifPinmuxPadAttrOpenDrain);
288  mmio_region_write32(pinmux->base_addr, reg_offset, reg_value);
289 
290  // Wait for pull enable/disable changes to propagate to the physical pad.
291  dif_pinmux_pad_attr_t attrs_before = dif_pinmux_reg_to_pad_attr(reg_before);
292  if ((attrs_before.flags & kDifPinmuxPadAttrPullResistorEnable) !=
293  (attrs_in.flags & kDifPinmuxPadAttrPullResistorEnable)) {
294  busy_spin_micros(kDifPinmuxPadAttrSpinWaitMicros);
295  }
296 
297  uint32_t read_value = mmio_region_read32(pinmux->base_addr, reg_offset);
298  *attrs_out = dif_pinmux_reg_to_pad_attr(read_value);
299 
300  if (reg_value != read_value) {
301  return kDifError;
302  }
303  return kDifOk;
304 }
305 
307  dif_pinmux_index_t pad,
309  dif_pinmux_pad_attr_t *attrs) {
310  if (pinmux == NULL || attrs == NULL) {
311  return kDifBadArg;
312  }
313  ptrdiff_t reg_offset;
314  if (!dif_pinmux_get_reg_offset(pad, type, PINMUX_MIO_PAD_ATTR_0_REG_OFFSET,
315  PINMUX_DIO_PAD_ATTR_0_REG_OFFSET,
316  &reg_offset)) {
317  return kDifBadArg;
318  }
319  uint32_t reg_value = mmio_region_read32(pinmux->base_addr, reg_offset);
320  *attrs = dif_pinmux_reg_to_pad_attr(reg_value);
321  return kDifOk;
322 }
323 
325  dif_pinmux_index_t pad,
328  if (pinmux == NULL) {
329  return kDifBadArg;
330  }
331 
332  ptrdiff_t en_reg_offset, mode_reg_offset;
333  if (!dif_pinmux_get_reg_offset(
334  pad, type, PINMUX_MIO_PAD_SLEEP_EN_0_REG_OFFSET,
335  PINMUX_DIO_PAD_SLEEP_EN_0_REG_OFFSET, &en_reg_offset)) {
336  return kDifBadArg;
337  }
338  if (!dif_pinmux_get_reg_offset(
339  pad, type, PINMUX_MIO_PAD_SLEEP_MODE_0_REG_OFFSET,
340  PINMUX_DIO_PAD_SLEEP_MODE_0_REG_OFFSET, &mode_reg_offset)) {
341  return kDifBadArg;
342  }
343  const dif_pinmux_lock_target_t lock_target =
346  bool is_locked;
347  dif_result_t result =
348  dif_pinmux_is_locked(pinmux, pad, lock_target, &is_locked);
349  if (result != kDifOk) {
350  return result;
351  }
352  if (is_locked) {
353  return kDifLocked;
354  }
355 
356  // Sleep Mode Value
357  uint32_t reg_value;
358  switch (mode) {
360  reg_value = PINMUX_MIO_PAD_SLEEP_MODE_0_OUT_0_VALUE_TIE_LOW;
361  break;
363  reg_value = PINMUX_MIO_PAD_SLEEP_MODE_0_OUT_0_VALUE_TIE_HIGH;
364  break;
366  reg_value = PINMUX_MIO_PAD_SLEEP_MODE_0_OUT_0_VALUE_HIGH_Z;
367  break;
369  reg_value = PINMUX_MIO_PAD_SLEEP_MODE_0_OUT_0_VALUE_KEEP;
370  break;
371  default:
372  return kDifBadArg;
373  }
374  mmio_region_write32(pinmux->base_addr, mode_reg_offset, reg_value);
375 
376  // Sleep Mode Enable
377  reg_value = bitfield_bit32_write(0, PINMUX_MIO_PAD_SLEEP_EN_0_EN_0_BIT, 1);
378  mmio_region_write32(pinmux->base_addr, en_reg_offset, reg_value);
379  return kDifOk;
380 }
381 
383  dif_pinmux_index_t pad,
384  dif_pinmux_pad_kind_t type) {
385  if (pinmux == NULL) {
386  return kDifBadArg;
387  }
388 
389  ptrdiff_t en_reg_offset;
390  if (!dif_pinmux_get_reg_offset(
391  pad, type, PINMUX_MIO_PAD_SLEEP_EN_0_REG_OFFSET,
392  PINMUX_DIO_PAD_SLEEP_EN_0_REG_OFFSET, &en_reg_offset)) {
393  return kDifBadArg;
394  }
395 
396  const dif_pinmux_lock_target_t lock_target =
399  bool is_locked;
400  dif_result_t result =
401  dif_pinmux_is_locked(pinmux, pad, lock_target, &is_locked);
402  if (result != kDifOk) {
403  return result;
404  }
405  if (is_locked) {
406  return kDifLocked;
407  }
408 
409  mmio_region_write32(pinmux->base_addr, en_reg_offset, 0);
410  return kDifOk;
411 }
412 
414  dif_pinmux_index_t pad,
416  bool *in_sleep_mode) {
417  if (pinmux == NULL || in_sleep_mode == NULL) {
418  return kDifBadArg;
419  }
420 
421  ptrdiff_t reg_offset;
423  if (!dif_pinmux_get_sleep_status_bit(type, pad, &reg_offset, &bit)) {
424  return kDifBadArg;
425  }
426 
427  uint32_t reg_value = mmio_region_read32(pinmux->base_addr, reg_offset);
428  *in_sleep_mode = bitfield_bit32_read(reg_value, bit);
429  return kDifOk;
430 }
431 
433  dif_pinmux_index_t pad,
434  dif_pinmux_pad_kind_t type) {
435  if (pinmux == NULL) {
436  return kDifBadArg;
437  }
438 
439  ptrdiff_t reg_offset;
441  if (!dif_pinmux_get_sleep_status_bit(type, pad, &reg_offset, &bit)) {
442  return kDifBadArg;
443  }
444 
445  uint32_t reg_value = mmio_region_read32(pinmux->base_addr, reg_offset);
446  reg_value = bitfield_bit32_write(reg_value, bit, 0);
447  mmio_region_write32(pinmux->base_addr, reg_offset, reg_value);
448  return kDifOk;
449 }
450 
452  const dif_pinmux_t *pinmux, dif_pinmux_index_t detector,
454  // Disable the detector before changing config, and use that function for
455  // some input checking (null pointer, lock status, and detector validity
456  // checks).
457  dif_result_t result = dif_pinmux_wakeup_detector_disable(pinmux, detector);
458  if (result != kDifOk) {
459  return result;
460  }
461 
462  bool set_count = false;
463  uint32_t reg_mode_value;
464  switch (config.mode) {
466  reg_mode_value = PINMUX_WKUP_DETECTOR_0_MODE_0_VALUE_POSEDGE;
467  break;
469  reg_mode_value = PINMUX_WKUP_DETECTOR_0_MODE_0_VALUE_NEGEDGE;
470  break;
472  reg_mode_value = PINMUX_WKUP_DETECTOR_0_MODE_0_VALUE_EDGE;
473  break;
475  set_count = true;
476  reg_mode_value = PINMUX_WKUP_DETECTOR_0_MODE_0_VALUE_TIMEDHIGH;
477  break;
479  set_count = true;
480  reg_mode_value = PINMUX_WKUP_DETECTOR_0_MODE_0_VALUE_TIMEDLOW;
481  break;
482  default:
483  return kDifBadArg;
484  }
485 
486  bool reg_filter_value = dif_toggle_to_bool(config.signal_filter);
487  if (!dif_is_valid_toggle(config.signal_filter)) {
488  return kDifBadArg;
489  }
490 
491  bool reg_miodio_value;
492  switch (config.pad_type) {
494  if (config.pad_select >= (2 + PINMUX_PARAM_N_MIO_PADS)) {
495  return kDifBadArg;
496  }
497  reg_miodio_value = false;
498  break;
500  if (config.pad_select >= PINMUX_PARAM_N_DIO_PADS) {
501  return kDifBadArg;
502  }
503  reg_miodio_value = true;
504  break;
505  default:
506  return kDifBadArg;
507  }
508 
509  ptrdiff_t reg_offset = PINMUX_WKUP_DETECTOR_0_REG_OFFSET +
510  (ptrdiff_t)detector * (ptrdiff_t)sizeof(uint32_t);
511  uint32_t reg_value = bitfield_field32_write(
512  0, PINMUX_WKUP_DETECTOR_0_MODE_0_FIELD, reg_mode_value);
513  reg_value = bitfield_bit32_write(
514  reg_value, PINMUX_WKUP_DETECTOR_0_FILTER_0_BIT, reg_filter_value);
515  reg_value = bitfield_bit32_write(
516  reg_value, PINMUX_WKUP_DETECTOR_0_MIODIO_0_BIT, reg_miodio_value);
517  mmio_region_write32(pinmux->base_addr, reg_offset, reg_value);
518 
519  if (set_count) {
520  reg_offset = PINMUX_WKUP_DETECTOR_CNT_TH_0_REG_OFFSET +
521  (ptrdiff_t)detector * (ptrdiff_t)sizeof(uint32_t);
522  reg_value = bitfield_field32_write(
523  0, PINMUX_WKUP_DETECTOR_CNT_TH_0_TH_0_FIELD, config.counter_threshold);
524  mmio_region_write32(pinmux->base_addr, reg_offset, reg_value);
525  }
526 
527  reg_offset = PINMUX_WKUP_DETECTOR_PADSEL_0_REG_OFFSET +
528  (ptrdiff_t)detector * (ptrdiff_t)sizeof(uint32_t);
529  reg_value = bitfield_field32_write(
530  0, PINMUX_WKUP_DETECTOR_PADSEL_0_SEL_0_FIELD, config.pad_select);
531  mmio_region_write32(pinmux->base_addr, reg_offset, reg_value);
532 
533  reg_offset = PINMUX_WKUP_DETECTOR_EN_0_REG_OFFSET +
534  (ptrdiff_t)detector * (ptrdiff_t)sizeof(uint32_t);
535  reg_value = bitfield_bit32_write(0, PINMUX_WKUP_DETECTOR_EN_0_EN_0_BIT, true);
536  mmio_region_write32(pinmux->base_addr, reg_offset, reg_value);
537  return kDifOk;
538 }
539 
541  dif_pinmux_index_t detector) {
542  if (pinmux == NULL) {
543  return kDifBadArg;
544  }
545  if (detector >= PINMUX_PARAM_N_WKUP_DETECT) {
546  return kDifBadArg;
547  }
548  bool is_locked;
550  pinmux, detector, kDifPinmuxLockTargetWakeupDetector, &is_locked);
551  if (result != kDifOk) {
552  return result;
553  }
554  if (is_locked) {
555  return kDifLocked;
556  }
557 
558  ptrdiff_t reg_offset = PINMUX_WKUP_DETECTOR_EN_0_REG_OFFSET +
559  (ptrdiff_t)sizeof(uint32_t) * (ptrdiff_t)detector;
560  mmio_region_write32(pinmux->base_addr, reg_offset, 0);
561  return kDifOk;
562 }
563 
565  if (pinmux == NULL) {
566  return kDifBadArg;
567  }
568  mmio_region_write32(pinmux->base_addr, PINMUX_WKUP_CAUSE_REG_OFFSET, 0);
569  return kDifOk;
570 }
571 
573  uint32_t *detector_map) {
574  if (pinmux == NULL) {
575  return kDifBadArg;
576  }
577  *detector_map =
578  mmio_region_read32(pinmux->base_addr, PINMUX_WKUP_CAUSE_REG_OFFSET);
579  return kDifOk;
580 }