Software APIs
dif_lc_ctrl.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 #include "sw/device/lib/base/multibits.h"
10 
11 #include "lc_ctrl_regs.h" // Generated.
12 
14  dif_lc_ctrl_state_t *state) {
15  if (lc == NULL || state == NULL) {
16  return kDifBadArg;
17  }
18 
19  uint32_t reg = mmio_region_read32(lc->base_addr, LC_CTRL_LC_STATE_REG_OFFSET);
20  switch (bitfield_field32_read(reg, LC_CTRL_LC_STATE_STATE_FIELD)) {
21  case LC_CTRL_LC_STATE_STATE_VALUE_RAW:
22  *state = kDifLcCtrlStateRaw;
23  break;
24  case LC_CTRL_LC_STATE_STATE_VALUE_TEST_UNLOCKED0:
26  break;
27  case LC_CTRL_LC_STATE_STATE_VALUE_TEST_LOCKED0:
29  break;
30  case LC_CTRL_LC_STATE_STATE_VALUE_TEST_UNLOCKED1:
32  break;
33  case LC_CTRL_LC_STATE_STATE_VALUE_TEST_LOCKED1:
35  break;
36  case LC_CTRL_LC_STATE_STATE_VALUE_TEST_UNLOCKED2:
38  break;
39  case LC_CTRL_LC_STATE_STATE_VALUE_TEST_LOCKED2:
41  break;
42  case LC_CTRL_LC_STATE_STATE_VALUE_TEST_UNLOCKED3:
44  break;
45  case LC_CTRL_LC_STATE_STATE_VALUE_TEST_LOCKED3:
47  break;
48  case LC_CTRL_LC_STATE_STATE_VALUE_TEST_UNLOCKED4:
50  break;
51  case LC_CTRL_LC_STATE_STATE_VALUE_TEST_LOCKED4:
53  break;
54  case LC_CTRL_LC_STATE_STATE_VALUE_TEST_UNLOCKED5:
56  break;
57  case LC_CTRL_LC_STATE_STATE_VALUE_TEST_LOCKED5:
59  break;
60  case LC_CTRL_LC_STATE_STATE_VALUE_TEST_UNLOCKED6:
62  break;
63  case LC_CTRL_LC_STATE_STATE_VALUE_TEST_LOCKED6:
65  break;
66  case LC_CTRL_LC_STATE_STATE_VALUE_TEST_UNLOCKED7:
68  break;
69  case LC_CTRL_LC_STATE_STATE_VALUE_DEV:
70  *state = kDifLcCtrlStateDev;
71  break;
72  case LC_CTRL_LC_STATE_STATE_VALUE_PROD:
73  *state = kDifLcCtrlStateProd;
74  break;
75  case LC_CTRL_LC_STATE_STATE_VALUE_PROD_END:
76  *state = kDifLcCtrlStateProdEnd;
77  break;
78  case LC_CTRL_LC_STATE_STATE_VALUE_RMA:
79  *state = kDifLcCtrlStateRma;
80  break;
81  case LC_CTRL_LC_STATE_STATE_VALUE_SCRAP:
82  *state = kDifLcCtrlStateScrap;
83  break;
84 
85  case LC_CTRL_LC_STATE_STATE_VALUE_POST_TRANSITION:
87  break;
88  case LC_CTRL_LC_STATE_STATE_VALUE_ESCALATE:
89  *state = kDifLcCtrlStateEscalate;
90  break;
91  case LC_CTRL_LC_STATE_STATE_VALUE_INVALID:
92  *state = kDifLcCtrlStateInvalid;
93  break;
94 
95  default:
96  return kDifError;
97  }
98 
99  return kDifOk;
100 }
101 
103  if (lc == NULL || count == NULL) {
104  return kDifBadArg;
105  }
106 
107  uint32_t reg =
108  mmio_region_read32(lc->base_addr, LC_CTRL_LC_TRANSITION_CNT_REG_OFFSET);
109  uint8_t value =
110  (uint8_t)bitfield_field32_read(reg, LC_CTRL_LC_TRANSITION_CNT_CNT_FIELD);
111  if (value == LC_CTRL_LC_TRANSITION_CNT_CNT_MASK) {
112  return kDifError;
113  }
114 
115  *count = value;
116  return kDifOk;
117 }
118 
121  if (lc == NULL || status == NULL) {
122  return kDifBadArg;
123  }
124 
125  uint32_t reg = mmio_region_read32(lc->base_addr, LC_CTRL_STATUS_REG_OFFSET);
126 
127  dif_lc_ctrl_status_t status_word = 0;
128 
129  if (bitfield_bit32_read(reg, LC_CTRL_STATUS_INITIALIZED_BIT)) {
130  status_word = bitfield_bit32_write(status_word,
132  }
133 
134  if (bitfield_bit32_read(reg, LC_CTRL_STATUS_READY_BIT)) {
135  status_word =
137  }
138 
139  if (bitfield_bit32_read(reg, LC_CTRL_STATUS_EXT_CLOCK_SWITCHED_BIT)) {
140  status_word = bitfield_bit32_write(status_word,
142  }
143 
144  if (bitfield_bit32_read(reg, LC_CTRL_STATUS_TRANSITION_SUCCESSFUL_BIT)) {
145  status_word =
147  }
148 
149  if (bitfield_bit32_read(reg, LC_CTRL_STATUS_TRANSITION_COUNT_ERROR_BIT)) {
150  status_word = bitfield_bit32_write(
151  status_word, kDifLcCtrlStatusCodeTooManyTransitions, true);
152  }
153 
154  if (bitfield_bit32_read(reg, LC_CTRL_STATUS_TRANSITION_ERROR_BIT)) {
155  status_word = bitfield_bit32_write(
156  status_word, kDifLcCtrlStatusCodeInvalidTransition, true);
157  }
158 
159  if (bitfield_bit32_read(reg, LC_CTRL_STATUS_TOKEN_ERROR_BIT)) {
160  status_word =
162  }
163 
164  if (bitfield_bit32_read(reg, LC_CTRL_STATUS_FLASH_RMA_ERROR_BIT)) {
165  status_word = bitfield_bit32_write(status_word,
167  }
168 
169  if (bitfield_bit32_read(reg, LC_CTRL_STATUS_OTP_ERROR_BIT)) {
170  status_word =
172  }
173 
174  if (bitfield_bit32_read(reg, LC_CTRL_STATUS_STATE_ERROR_BIT)) {
175  status_word =
177  }
178 
179  if (bitfield_bit32_read(reg, LC_CTRL_STATUS_BUS_INTEG_ERROR_BIT)) {
180  status_word = bitfield_bit32_write(status_word,
182  }
183 
184  if (bitfield_bit32_read(reg, LC_CTRL_STATUS_OTP_PARTITION_ERROR_BIT)) {
185  status_word = bitfield_bit32_write(status_word,
187  }
188 
189  *status = status_word;
190  return kDifOk;
191 }
192 
194  dif_lc_ctrl_id_state_t *state) {
195  if (lc == NULL || state == NULL) {
196  return kDifBadArg;
197  }
198 
199  uint32_t reg =
200  mmio_region_read32(lc->base_addr, LC_CTRL_LC_ID_STATE_REG_OFFSET);
201  switch (reg) {
202  case LC_CTRL_LC_ID_STATE_STATE_VALUE_BLANK:
203  *state = kDifLcCtrlIdStateBlank;
204  break;
205  case LC_CTRL_LC_ID_STATE_STATE_VALUE_PERSONALIZED:
207  break;
208  case LC_CTRL_LC_ID_STATE_STATE_VALUE_INVALID:
209  *state = kDifLcCtrlIdStateInvalid;
210  break;
211  default:
212  return kDifError;
213  }
214 
215  return kDifOk;
216 }
217 
219  dif_lc_ctrl_hw_rev_t *hw_rev) {
220  if (lc == NULL || hw_rev == NULL) {
221  return kDifBadArg;
222  }
223 
224  uint32_t reg =
225  mmio_region_read32(lc->base_addr, LC_CTRL_HW_REVISION0_REG_OFFSET);
226  hw_rev->silicon_creator_id = (uint16_t)bitfield_field32_read(
227  reg, LC_CTRL_HW_REVISION0_SILICON_CREATOR_ID_FIELD);
228  hw_rev->product_id = (uint16_t)bitfield_field32_read(
229  reg, LC_CTRL_HW_REVISION0_PRODUCT_ID_FIELD);
230  hw_rev->revision_id = (uint8_t)bitfield_field32_read(
231  reg, LC_CTRL_HW_REVISION1_REVISION_ID_FIELD);
232  return kDifOk;
233 }
234 
236  dif_lc_ctrl_device_id_t *device_id) {
237  if (lc == NULL || device_id == NULL) {
238  return kDifBadArg;
239  }
240 
241  mmio_region_memcpy_from_mmio32(lc->base_addr, LC_CTRL_DEVICE_ID_0_REG_OFFSET,
242  device_id->data,
243  ARRAYSIZE(device_id->data) * sizeof(uint32_t));
244  return kDifOk;
245 }
246 
248  if (lc == NULL) {
249  return kDifBadArg;
250  }
251 
252  // Check that mutex claim via SW is not locked.
253  if (mmio_region_read32(lc->base_addr,
254  LC_CTRL_CLAIM_TRANSITION_IF_REGWEN_REG_OFFSET) == 0) {
255  return kDifLocked;
256  }
257 
258  mmio_region_write32(lc->base_addr, LC_CTRL_CLAIM_TRANSITION_IF_REG_OFFSET,
259  kMultiBitBool8True);
260  uint32_t reg =
261  mmio_region_read32(lc->base_addr, LC_CTRL_CLAIM_TRANSITION_IF_REG_OFFSET);
262  // If the register is not `kMultiBitBool8True`, that means we failed to take
263  // the mutex for whatever reason.
264  if (reg != kMultiBitBool8True) {
265  return kDifUnavailable;
266  } else {
267  return kDifOk;
268  }
269 }
270 
272  if (lc == NULL) {
273  return kDifBadArg;
274  }
275 
276  uint32_t reg =
277  mmio_region_read32(lc->base_addr, LC_CTRL_CLAIM_TRANSITION_IF_REG_OFFSET);
278  if (reg != kMultiBitBool8True) {
279  // We're not holding the mutex, which is a programmer error.
280  return kDifError;
281  }
282 
283  mmio_region_write32(lc->base_addr, LC_CTRL_CLAIM_TRANSITION_IF_REG_OFFSET,
284  kMultiBitBool8False);
285  return kDifOk;
286 }
287 
289  dif_lc_ctrl_state_t state,
290  bool use_ext_clock,
291  const dif_lc_ctrl_token_t *token) {
292  if (lc == NULL) {
293  return kDifBadArg;
294  }
295 
296  uint32_t target;
297  switch (state) {
298  case kDifLcCtrlStateRaw:
299  target = LC_CTRL_TRANSITION_TARGET_STATE_VALUE_RAW;
300  break;
302  target = LC_CTRL_TRANSITION_TARGET_STATE_VALUE_TEST_UNLOCKED0;
303  break;
305  target = LC_CTRL_TRANSITION_TARGET_STATE_VALUE_TEST_LOCKED0;
306  break;
308  target = LC_CTRL_TRANSITION_TARGET_STATE_VALUE_TEST_UNLOCKED1;
309  break;
311  target = LC_CTRL_TRANSITION_TARGET_STATE_VALUE_TEST_LOCKED1;
312  break;
314  target = LC_CTRL_TRANSITION_TARGET_STATE_VALUE_TEST_UNLOCKED2;
315  break;
317  target = LC_CTRL_TRANSITION_TARGET_STATE_VALUE_TEST_LOCKED2;
318  break;
320  target = LC_CTRL_TRANSITION_TARGET_STATE_VALUE_TEST_UNLOCKED3;
321  break;
323  target = LC_CTRL_TRANSITION_TARGET_STATE_VALUE_TEST_LOCKED3;
324  break;
326  target = LC_CTRL_TRANSITION_TARGET_STATE_VALUE_TEST_UNLOCKED4;
327  break;
329  target = LC_CTRL_TRANSITION_TARGET_STATE_VALUE_TEST_LOCKED4;
330  break;
332  target = LC_CTRL_TRANSITION_TARGET_STATE_VALUE_TEST_UNLOCKED5;
333  break;
335  target = LC_CTRL_TRANSITION_TARGET_STATE_VALUE_TEST_LOCKED5;
336  break;
338  target = LC_CTRL_TRANSITION_TARGET_STATE_VALUE_TEST_UNLOCKED6;
339  break;
341  target = LC_CTRL_TRANSITION_TARGET_STATE_VALUE_TEST_LOCKED6;
342  break;
344  target = LC_CTRL_TRANSITION_TARGET_STATE_VALUE_TEST_UNLOCKED7;
345  break;
346  case kDifLcCtrlStateDev:
347  target = LC_CTRL_TRANSITION_TARGET_STATE_VALUE_DEV;
348  break;
349  case kDifLcCtrlStateProd:
350  target = LC_CTRL_TRANSITION_TARGET_STATE_VALUE_PROD;
351  break;
353  target = LC_CTRL_TRANSITION_TARGET_STATE_VALUE_PROD_END;
354  break;
355  case kDifLcCtrlStateRma:
356  target = LC_CTRL_TRANSITION_TARGET_STATE_VALUE_RMA;
357  break;
359  target = LC_CTRL_TRANSITION_TARGET_STATE_VALUE_SCRAP;
360  break;
361 
362  default:
363  return kDifBadArg;
364  }
365 
366  // Check if the mutex has been acquired.
367  if (!mmio_region_read32(lc->base_addr,
368  LC_CTRL_TRANSITION_REGWEN_REG_OFFSET)) {
369  return kDifUnavailable;
370  }
371 
372  // Set the target for the transition.
373  mmio_region_write32(lc->base_addr, LC_CTRL_TRANSITION_TARGET_REG_OFFSET,
374  target);
375 
376  // Program the clock selection.
377  uint32_t ctrl_reg = 0;
378  if (use_ext_clock) {
379  ctrl_reg = bitfield_bit32_write(
380  ctrl_reg, LC_CTRL_TRANSITION_CTRL_EXT_CLOCK_EN_BIT, true);
381  } else {
382  // Default to internal clock.
383  ctrl_reg = bitfield_bit32_write(
384  ctrl_reg, LC_CTRL_TRANSITION_CTRL_EXT_CLOCK_EN_BIT, false);
385  }
386  mmio_region_write32(lc->base_addr, LC_CTRL_TRANSITION_CTRL_REG_OFFSET,
387  ctrl_reg);
388 
389  // Fill in a token, if necessary.
390  if (token != NULL) {
391  for (int i = 0; i < sizeof(token->data); i += sizeof(uint32_t)) {
392  uint32_t word;
393  memcpy(&word, &token->data[i], sizeof(uint32_t));
394  mmio_region_write32(lc->base_addr,
395  LC_CTRL_TRANSITION_TOKEN_0_REG_OFFSET + i, word);
396  }
397  }
398 
399  return kDifOk;
400 }
401 
403  if (lc == NULL) {
404  return kDifBadArg;
405  }
406 
407  // Check if the mutex has been acquired.
408  if (!mmio_region_read32(lc->base_addr,
409  LC_CTRL_TRANSITION_REGWEN_REG_OFFSET)) {
410  return kDifUnavailable;
411  }
412 
413  mmio_region_write32(lc->base_addr, LC_CTRL_TRANSITION_CMD_REG_OFFSET, 1);
414 
415  return kDifOk;
416 }
417 
419  uint32_t settings) {
420  if (lc == NULL) {
421  return kDifBadArg;
422  }
423 
424  uint32_t busy =
425  mmio_region_read32(lc->base_addr, LC_CTRL_TRANSITION_REGWEN_REG_OFFSET);
426  if (busy == 0) {
427  return kDifUnavailable;
428  }
429 
430  mmio_region_write32(lc->base_addr, LC_CTRL_OTP_VENDOR_TEST_CTRL_REG_OFFSET,
431  settings);
432 
433  return kDifOk;
434 }
435 
437  uint32_t *settings) {
438  if (lc == NULL || settings == NULL) {
439  return kDifBadArg;
440  }
441 
442  uint32_t busy =
443  mmio_region_read32(lc->base_addr, LC_CTRL_TRANSITION_REGWEN_REG_OFFSET);
444  if (busy == 0) {
445  return kDifUnavailable;
446  }
447 
448  *settings = mmio_region_read32(lc->base_addr,
449  LC_CTRL_OTP_VENDOR_TEST_CTRL_REG_OFFSET);
450 
451  return kDifOk;
452 }
453 
455  if (lc == NULL) {
456  return kDifBadArg;
457  }
458 
459  // Clear CLAIM_TRANSITION_IF_REGWEN to lock mutex claim from TL-UL side.
460  mmio_region_write32(lc->base_addr,
461  LC_CTRL_CLAIM_TRANSITION_IF_REGWEN_REG_OFFSET, 0);
462 
463  return kDifOk;
464 }