Software APIs
dif_rram_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// Generated.
13
14/**
15 * Helper function to get the offset of a data region's configuration register.
16 * Does not check that the region actually exists, which is deferred to callers.
17 * Since data region registers are split into two (one containing properties the
18 * other containing address info), there are two helper functions below.
19 *
20 * @param region The data region's index.
21 * @return The offset from the RRAM controller's base address where the region
22 * configuration register is located.
23 */
24static ptrdiff_t get_data_region_mp_reg_offset(uint32_t region) {
25 return RRAM_CTRL_MP_REGION_CFG_0_REG_OFFSET +
26 (ptrdiff_t)region * (ptrdiff_t)sizeof(uint32_t);
27}
28
29static ptrdiff_t get_data_region_reg_offset(uint32_t region) {
30 return RRAM_CTRL_MP_REGION_0_REG_OFFSET +
31 (ptrdiff_t)region * (ptrdiff_t)sizeof(uint32_t);
32}
33
34static ptrdiff_t get_data_region_lock_reg_offset(uint32_t region) {
35 return RRAM_CTRL_REGION_CFG_REGWEN_0_REG_OFFSET +
36 (ptrdiff_t)region * (ptrdiff_t)sizeof(uint32_t);
37}
38
39// generated parameters from hjson
40enum {
41 kNumInfoPages = RRAM_CTRL_PARAM_NUM_INFO_PAGES,
42 // The full physical data partition, OTP tail included.
43 kNumDataPages = RRAM_CTRL_PARAM_NUM_DATA_PAGES,
44 // Excludes the OTP tail (unlike `kNumDataPages` above).
45 kNumUsableDataPages =
46 RRAM_CTRL_PARAM_NUM_DATA_PAGES - RRAM_CTRL_PARAM_NUM_OTP_PAGES,
47 kBytesPerWord = RRAM_CTRL_PARAM_BYTES_PER_WORD,
48 kBytesPerPage = RRAM_CTRL_PARAM_BYTES_PER_PAGE,
49 kExecEn = RRAM_CTRL_PARAM_EXEC_EN,
50 kNumRegions = RRAM_CTRL_PARAM_NUM_REGIONS,
51};
52
53/**
54 * Helper function to get the offset of an info region's configuration register.
55 * Does not check that the region actually exists, which is deferred to callers.
56 *
57 * @param region The info region's description.
58 * @return The offset from the RRAM controller's base address where the region
59 * configuration register is located.
60 */
61static ptrdiff_t get_info_region_mp_reg_offset(
63 return RRAM_CTRL_INFO_PAGE_CFG_0_REG_OFFSET +
64 (ptrdiff_t)region.page * (ptrdiff_t)sizeof(uint32_t);
65}
66
67static ptrdiff_t get_info_region_lock_reg_offset(
69 return RRAM_CTRL_INFO_REGWEN_0_REG_OFFSET +
70 (ptrdiff_t)region.page * (ptrdiff_t)sizeof(uint32_t);
71}
72
73dif_result_t dif_rram_ctrl_init_state(dif_rram_ctrl_state_t *handle,
74 mmio_region_t base_addr) {
75 if (handle == NULL) {
76 return kDifBadArg;
77 }
78 DIF_RETURN_IF_ERROR(dif_rram_ctrl_init(base_addr, &handle->dev));
79 handle->words_remaining = 0;
80 handle->transaction_pending = false;
81 return kDifOk;
82}
83
84dif_result_t dif_rram_ctrl_init_state_from_dt(dif_rram_ctrl_state_t *handle,
85 dt_rram_ctrl_t dt) {
86 return dif_rram_ctrl_init_state(
87 handle, mmio_region_from_addr(dt_rram_ctrl_primary_reg_block(dt)));
88}
89
90dif_rram_ctrl_device_info_t dif_rram_ctrl_get_device_info(void) {
91 const dif_rram_ctrl_device_info_t info = {
92 .bytes_per_word = kBytesPerWord,
93 .bytes_per_page = kBytesPerPage,
94 .data_pages = kNumDataPages,
95 .info_pages = kNumInfoPages,
96 };
97 return info;
98}
99
100dif_result_t dif_rram_ctrl_set_rram_enablement(dif_rram_ctrl_state_t *handle,
101 dif_toggle_t enable) {
102 multi_bit_bool_t disable_rram;
103 if (handle == NULL) {
104 return kDifBadArg;
105 }
106 switch (enable) {
108 disable_rram = kMultiBitBool4False;
109 break;
111 disable_rram = kMultiBitBool4True;
112 break;
113 default:
114 return kDifBadArg;
115 }
116 uint32_t reg;
117 reg = mmio_region_read32(handle->dev.base_addr, RRAM_CTRL_DIS_REG_OFFSET);
118 reg = bitfield_field32_write(reg, RRAM_CTRL_DIS_SW_DIS_FIELD, disable_rram);
119 mmio_region_write32(handle->dev.base_addr, RRAM_CTRL_DIS_REG_OFFSET, reg);
120 return kDifOk;
121}
122
123dif_result_t dif_rram_ctrl_get_rram_enablement(
124 const dif_rram_ctrl_state_t *handle, dif_toggle_t *enabled_out) {
125 if (handle == NULL || enabled_out == NULL) {
126 return kDifBadArg;
127 }
128 uint32_t reg =
129 mmio_region_read32(handle->dev.base_addr, RRAM_CTRL_DIS_REG_OFFSET);
130 multi_bit_bool_t rram_disabled =
131 bitfield_field32_read(reg, RRAM_CTRL_DIS_SW_DIS_FIELD);
132 if (rram_disabled == kMultiBitBool4False) {
133 *enabled_out = kDifToggleEnabled;
134 } else {
135 *enabled_out = kDifToggleDisabled;
136 }
137 return kDifOk;
138}
139
140dif_result_t dif_rram_ctrl_set_exec_enablement(dif_rram_ctrl_state_t *handle,
141 dif_toggle_t enable) {
142 uint32_t value;
143 if (handle == NULL) {
144 return kDifBadArg;
145 }
146 switch (enable) {
148 value = kExecEn;
149 break;
151 value = 0;
152 break;
153 default:
154 return kDifBadArg;
155 }
156 mmio_region_write32(handle->dev.base_addr, RRAM_CTRL_EXEC_REG_OFFSET, value);
157 return kDifOk;
158}
159
160dif_result_t dif_rram_ctrl_get_exec_enablement(
161 const dif_rram_ctrl_state_t *handle, dif_toggle_t *enabled_out) {
162 if (handle == NULL || enabled_out == NULL) {
163 return kDifBadArg;
164 }
165 uint32_t reg =
166 mmio_region_read32(handle->dev.base_addr, RRAM_CTRL_EXEC_REG_OFFSET);
167 if (reg == kExecEn) {
168 *enabled_out = kDifToggleEnabled;
169 } else {
170 *enabled_out = kDifToggleDisabled;
171 }
172 return kDifOk;
173}
174
175dif_result_t dif_rram_ctrl_start_controller_init(
176 dif_rram_ctrl_state_t *handle) {
177 if (handle == NULL) {
178 return kDifBadArg;
179 }
180 const uint32_t reg =
181 mmio_region_read32(handle->dev.base_addr, RRAM_CTRL_INIT_REG_OFFSET);
182 if (bitfield_bit32_read(reg, RRAM_CTRL_INIT_VAL_BIT)) {
183 // Controller initialization may only be requested once.
184 return kDifError;
185 }
186 uint32_t value = bitfield_bit32_write(0, RRAM_CTRL_INIT_VAL_BIT, true);
187 mmio_region_write32(handle->dev.base_addr, RRAM_CTRL_INIT_REG_OFFSET, value);
188 return kDifOk;
189}
190
191dif_result_t dif_rram_ctrl_get_status(const dif_rram_ctrl_state_t *handle,
192 dif_rram_ctrl_status_t *status_out) {
193 if (handle == NULL || status_out == NULL) {
194 return kDifBadArg;
195 }
196 uint32_t reg =
197 mmio_region_read32(handle->dev.base_addr, RRAM_CTRL_STATUS_REG_OFFSET);
199 .read_fifo_full = bitfield_bit32_read(reg, RRAM_CTRL_STATUS_RD_FULL_BIT),
200 .read_fifo_empty =
201 bitfield_bit32_read(reg, RRAM_CTRL_STATUS_RD_EMPTY_BIT),
202 .write_fifo_full = bitfield_bit32_read(reg, RRAM_CTRL_STATUS_WR_FULL_BIT),
203 .write_fifo_empty =
204 bitfield_bit32_read(reg, RRAM_CTRL_STATUS_WR_EMPTY_BIT),
205 .controller_init_done =
206 bitfield_bit32_read(reg, RRAM_CTRL_STATUS_INIT_DONE_BIT),
207 .controller_keys_valid =
208 bitfield_bit32_read(reg, RRAM_CTRL_STATUS_KEYS_VALID_BIT),
209 };
210 *status_out = status;
211 return kDifOk;
212}
213
214dif_result_t dif_rram_ctrl_start_unsafe(
215 dif_rram_ctrl_state_t *handle, dif_rram_ctrl_transaction_t transaction) {
216 if (handle == NULL) {
217 return kDifBadArg;
218 }
219 uint32_t ctrl_regwen = mmio_region_read32(handle->dev.base_addr,
220 RRAM_CTRL_CTRL_REGWEN_REG_OFFSET);
221 if (!bitfield_bit32_read(ctrl_regwen, RRAM_CTRL_CTRL_REGWEN_EN_BIT)) {
222 return kDifUnavailable;
223 }
224
225 // Hardware ignores the NUM field for kDifRramCtrlOpRewrite (a rewrite always
226 // affects exactly one word), so `transaction.word_count` is not meaningful
227 // for that operation and isn't validated in `dif_rram_ctrl_start()`.
228 uint32_t control_reg = bitfield_field32_write(0, RRAM_CTRL_CONTROL_NUM_FIELD,
229 transaction.word_count - 1);
230 switch (transaction.op) {
232 control_reg =
233 bitfield_field32_write(control_reg, RRAM_CTRL_CONTROL_OP_FIELD,
234 RRAM_CTRL_CONTROL_OP_VALUE_READ);
235 break;
237 control_reg =
238 bitfield_field32_write(control_reg, RRAM_CTRL_CONTROL_OP_FIELD,
239 RRAM_CTRL_CONTROL_OP_VALUE_WRITE);
240 break;
242 control_reg =
243 bitfield_field32_write(control_reg, RRAM_CTRL_CONTROL_OP_FIELD,
244 RRAM_CTRL_CONTROL_OP_VALUE_REWRITE);
245 break;
246 default:
247 return kDifBadArg;
248 }
249
250 switch (transaction.partition_type) {
251 case kDifRramCtrlPartitionTypeData:
252 control_reg = bitfield_bit32_write(
253 control_reg, RRAM_CTRL_CONTROL_PARTITION_BIT, false);
254 break;
255 case kDifRramCtrlPartitionTypeInfo:
256 control_reg = bitfield_bit32_write(control_reg,
257 RRAM_CTRL_CONTROL_PARTITION_BIT, true);
258 break;
259 default:
260 return kDifBadArg;
261 }
262
263 mmio_region_write32(handle->dev.base_addr, RRAM_CTRL_CONTROL_REG_OFFSET,
264 control_reg);
265 mmio_region_write32(handle->dev.base_addr, RRAM_CTRL_ADDR_REG_OFFSET,
266 transaction.byte_address);
267 mmio_region_write32(handle->dev.base_addr, RRAM_CTRL_CONTROL_REG_OFFSET,
268 control_reg | (1u << RRAM_CTRL_CONTROL_START_BIT));
269 if (transaction.op == kDifRramCtrlOpRewrite) {
270 // Rewrite operations don't use the FIFO
271 handle->words_remaining = 0;
272 } else {
273 handle->words_remaining = transaction.word_count;
274 }
275 handle->transaction_pending = true;
276 return kDifOk;
277}
278
279dif_result_t dif_rram_ctrl_start(dif_rram_ctrl_state_t *handle,
280 dif_rram_ctrl_transaction_t transaction) {
281 if (handle == NULL) {
282 return kDifBadArg;
283 }
284
285 const uint32_t max_word_count = RRAM_CTRL_CONTROL_NUM_MASK;
286 if (transaction.op != kDifRramCtrlOpRewrite) {
287 if (transaction.word_count - 1 > max_word_count ||
288 transaction.word_count == 0) {
289 return kDifBadArg;
290 }
291 }
292 // We can only write a multiple of `kBytesPerWord` worth of 32b words.
293 if (transaction.op == kDifRramCtrlOpWrite) {
294 if (transaction.word_count % (kBytesPerWord / sizeof(uint32_t)) != 0) {
295 return kDifBadArg;
296 }
297 }
298
299 // start address must be aligned to `kBytesPerWord` for write operations
300 if (transaction.op == kDifRramCtrlOpWrite) {
301 if (transaction.byte_address % kBytesPerWord != 0) {
302 return kDifBadArg;
303 }
304 }
305
306 if (handle->transaction_pending) {
307 return kDifUnavailable;
308 }
309
310 // Disallow starting a new transaction if the FIFOs haven't been emptied yet.
312 DIF_RETURN_IF_ERROR(dif_rram_ctrl_get_status(handle, &status));
313 if (!status.read_fifo_empty || !status.write_fifo_empty) {
314 return kDifIpFifoFull;
315 }
316
317 return dif_rram_ctrl_start_unsafe(handle, transaction);
318}
319
320dif_result_t dif_rram_ctrl_wr_fifo_push_unsafe(dif_rram_ctrl_state_t *handle,
321 uint32_t word_count,
322 const uint32_t *data) {
323 if (handle == NULL || data == NULL) {
324 return kDifBadArg;
325 }
326 uint32_t written;
327 for (written = 0; written < word_count; ++written) {
328 mmio_region_write32(handle->dev.base_addr, RRAM_CTRL_WR_FIFO_REG_OFFSET,
329 data[written]);
330 }
331 handle->words_remaining -= written;
332 return kDifOk;
333}
334
335dif_result_t dif_rram_ctrl_wr_fifo_push(dif_rram_ctrl_state_t *handle,
336 uint32_t word_count,
337 const uint32_t *data) {
338 if (handle == NULL || data == NULL) {
339 return kDifBadArg;
340 }
341 if (!handle->transaction_pending) {
342 return kDifError;
343 }
344 if (handle->words_remaining < word_count) {
345 return kDifBadArg;
346 }
347 const uint32_t control_reg =
348 mmio_region_read32(handle->dev.base_addr, RRAM_CTRL_CONTROL_REG_OFFSET);
349 const uint32_t op =
350 bitfield_field32_read(control_reg, RRAM_CTRL_CONTROL_OP_FIELD);
351 if (op != RRAM_CTRL_CONTROL_OP_VALUE_WRITE) {
352 return kDifError;
353 }
354 return dif_rram_ctrl_wr_fifo_push_unsafe(handle, word_count, data);
355}
356
357dif_result_t dif_rram_ctrl_read_fifo_pop_unsafe(dif_rram_ctrl_state_t *handle,
358 uint32_t word_count,
359 uint32_t *data) {
360 if (handle == NULL || data == NULL) {
361 return kDifBadArg;
362 }
363 uint32_t read;
364 for (read = 0; read < word_count; ++read) {
365 data[read] =
366 mmio_region_read32(handle->dev.base_addr, RRAM_CTRL_RD_FIFO_REG_OFFSET);
367 }
368 handle->words_remaining -= read;
369 return kDifOk;
370}
371
372dif_result_t dif_rram_ctrl_read_fifo_pop(dif_rram_ctrl_state_t *handle,
373 uint32_t word_count, uint32_t *data) {
374 if (handle == NULL || data == NULL) {
375 return kDifBadArg;
376 }
377 if (!handle->transaction_pending) {
378 return kDifError;
379 }
380 if (handle->words_remaining < word_count) {
381 return kDifBadArg;
382 }
383 const uint32_t control_reg =
384 mmio_region_read32(handle->dev.base_addr, RRAM_CTRL_CONTROL_REG_OFFSET);
385 const uint32_t op =
386 bitfield_field32_read(control_reg, RRAM_CTRL_CONTROL_OP_FIELD);
387 if (op != RRAM_CTRL_CONTROL_OP_VALUE_READ) {
388 return kDifError;
389 }
390 return dif_rram_ctrl_read_fifo_pop_unsafe(handle, word_count, data);
391}
392
393dif_result_t dif_rram_ctrl_get_error_codes(
394 const dif_rram_ctrl_state_t *handle,
395 dif_rram_ctrl_error_t *error_code_out) {
396 if (handle == NULL || error_code_out == NULL) {
397 return kDifBadArg;
398 }
399 const uint32_t code_reg =
400 mmio_region_read32(handle->dev.base_addr, RRAM_CTRL_ERR_CODE_REG_OFFSET);
401 dif_rram_ctrl_error_codes_t codes = {
402 .operation_error =
403 bitfield_bit32_read(code_reg, RRAM_CTRL_ERR_CODE_OP_ERR_BIT),
404 .memory_protection_error =
405 bitfield_bit32_read(code_reg, RRAM_CTRL_ERR_CODE_MP_ERR_BIT),
406 .read_error =
407 bitfield_bit32_read(code_reg, RRAM_CTRL_ERR_CODE_RD_ERR_BIT),
408 .write_error =
409 bitfield_bit32_read(code_reg, RRAM_CTRL_ERR_CODE_WR_ERR_BIT),
410 };
411
412 const uint32_t address_reg =
413 mmio_region_read32(handle->dev.base_addr, RRAM_CTRL_ERR_ADDR_REG_OFFSET);
414 dif_rram_ctrl_error_t error_code = {
415 .address = address_reg,
416 .codes = codes,
417 };
418 *error_code_out = error_code;
419 return kDifOk;
420}
421
422dif_result_t dif_rram_ctrl_clear_error_codes(
423 dif_rram_ctrl_state_t *handle, dif_rram_ctrl_error_codes_t codes) {
424 if (handle == NULL) {
425 return kDifBadArg;
426 }
427 uint32_t code_reg = 0;
428 code_reg = bitfield_bit32_write(code_reg, RRAM_CTRL_ERR_CODE_OP_ERR_BIT,
429 codes.operation_error);
430 code_reg = bitfield_bit32_write(code_reg, RRAM_CTRL_ERR_CODE_MP_ERR_BIT,
432 code_reg = bitfield_bit32_write(code_reg, RRAM_CTRL_ERR_CODE_RD_ERR_BIT,
433 codes.read_error);
434 code_reg = bitfield_bit32_write(code_reg, RRAM_CTRL_ERR_CODE_WR_ERR_BIT,
435 codes.write_error);
436 mmio_region_write32(handle->dev.base_addr, RRAM_CTRL_ERR_CODE_REG_OFFSET,
437 code_reg);
438 return kDifOk;
439}
440
441dif_result_t dif_rram_ctrl_end(dif_rram_ctrl_state_t *handle,
442 dif_rram_ctrl_output_t *out) {
443 if (handle == NULL || out == NULL) {
444 return kDifBadArg;
445 }
446 if (!handle->transaction_pending) {
447 return kDifError;
448 }
449 uint32_t status_reg =
450 mmio_region_read32(handle->dev.base_addr, RRAM_CTRL_OP_STATUS_REG_OFFSET);
451 if (!bitfield_bit32_read(status_reg, RRAM_CTRL_OP_STATUS_DONE_BIT)) {
452 return kDifUnavailable;
453 }
454 if (handle->words_remaining != 0) {
455 return kDifIpFifoFull;
456 }
457 dif_rram_ctrl_error_t error_code_tmp;
458 DIF_RETURN_IF_ERROR(dif_rram_ctrl_get_error_codes(handle, &error_code_tmp));
459 dif_rram_ctrl_output_t output = {
460 .operation_done =
461 bitfield_bit32_read(status_reg, RRAM_CTRL_OP_STATUS_DONE_BIT),
462 .operation_error =
463 bitfield_bit32_read(status_reg, RRAM_CTRL_OP_STATUS_ERR_BIT),
464 .error_code = error_code_tmp};
465 // Clear the operation status
466 mmio_region_write32(handle->dev.base_addr, RRAM_CTRL_OP_STATUS_REG_OFFSET, 0);
467 handle->transaction_pending = false;
468 *out = output;
469 return kDifOk;
470}
471
472dif_result_t dif_rram_ctrl_set_data_region_enablement(
473 dif_rram_ctrl_state_t *handle, uint32_t region, dif_toggle_t enable) {
474 if (handle == NULL || region >= kNumRegions) {
475 return kDifBadArg;
476 }
477
478 bool locked;
480 dif_rram_ctrl_data_region_is_locked(handle, region, &locked));
481 if (locked) {
482 return kDifLocked;
483 }
484
485 ptrdiff_t mp_reg_offset = get_data_region_mp_reg_offset(region);
486 uint32_t mp_reg = mmio_region_read32(handle->dev.base_addr, mp_reg_offset);
487 switch (enable) {
489 mp_reg = bitfield_field32_write(
490 mp_reg, RRAM_CTRL_MP_REGION_CFG_0_EN_0_FIELD, kMultiBitBool4True);
491 break;
493 mp_reg = bitfield_field32_write(
494 mp_reg, RRAM_CTRL_MP_REGION_CFG_0_EN_0_FIELD, kMultiBitBool4False);
495 break;
496 default:
497 return kDifBadArg;
498 }
499 mmio_region_write32(handle->dev.base_addr, mp_reg_offset, mp_reg);
500 return kDifOk;
501}
502
503dif_result_t dif_rram_ctrl_get_data_region_enablement(
504 const dif_rram_ctrl_state_t *handle, uint32_t region,
505 dif_toggle_t *enabled_out) {
506 if (handle == NULL || enabled_out == NULL || region >= kNumRegions) {
507 return kDifBadArg;
508 }
509 ptrdiff_t mp_reg_offset = get_data_region_mp_reg_offset(region);
510 uint32_t mp_reg = mmio_region_read32(handle->dev.base_addr, mp_reg_offset);
511 if (bitfield_field32_read(mp_reg, RRAM_CTRL_MP_REGION_CFG_0_EN_0_FIELD) ==
512 kMultiBitBool4True) {
513 *enabled_out = kDifToggleEnabled;
514 } else {
515 *enabled_out = kDifToggleDisabled;
516 }
517 return kDifOk;
518}
519
520dif_result_t dif_rram_ctrl_set_info_region_enablement(
522 dif_toggle_t enable) {
523 if (handle == NULL || region.page >= kNumInfoPages) {
524 return kDifBadArg;
525 }
526 bool locked;
528 dif_rram_ctrl_info_region_is_locked(handle, region, &locked));
529 if (locked) {
530 return kDifLocked;
531 }
532
533 ptrdiff_t mp_reg_offset = get_info_region_mp_reg_offset(region);
534 uint32_t mp_reg = mmio_region_read32(handle->dev.base_addr, mp_reg_offset);
535 switch (enable) {
537 mp_reg = bitfield_field32_write(
538 mp_reg, RRAM_CTRL_INFO_PAGE_CFG_0_EN_0_FIELD, kMultiBitBool4True);
539 break;
541 mp_reg = bitfield_field32_write(
542 mp_reg, RRAM_CTRL_INFO_PAGE_CFG_0_EN_0_FIELD, kMultiBitBool4False);
543 break;
544 default:
545 return kDifBadArg;
546 }
547 mmio_region_write32(handle->dev.base_addr, mp_reg_offset, mp_reg);
548 return kDifOk;
549}
550
551dif_result_t dif_rram_ctrl_get_info_region_enablement(
553 dif_toggle_t *enabled_out) {
554 if (handle == NULL || enabled_out == NULL || region.page >= kNumInfoPages) {
555 return kDifBadArg;
556 }
557 ptrdiff_t mp_reg_offset = get_info_region_mp_reg_offset(region);
558 uint32_t mp_reg = mmio_region_read32(handle->dev.base_addr, mp_reg_offset);
559 if (bitfield_field32_read(mp_reg, RRAM_CTRL_INFO_PAGE_CFG_0_EN_0_FIELD) ==
560 kMultiBitBool4True) {
561 *enabled_out = kDifToggleEnabled;
562 } else {
563 *enabled_out = kDifToggleDisabled;
564 }
565 return kDifOk;
566}
567
568dif_result_t dif_rram_ctrl_set_default_region_properties(
569 dif_rram_ctrl_state_t *handle,
571 if (handle == NULL) {
572 return kDifBadArg;
573 }
574 uint32_t reg = 0;
575 reg = bitfield_field32_write(reg, RRAM_CTRL_DEFAULT_REGION_RD_EN_FIELD,
576 properties.rd_en);
577 reg = bitfield_field32_write(reg, RRAM_CTRL_DEFAULT_REGION_WR_EN_FIELD,
578 properties.wr_en);
579 reg = bitfield_field32_write(reg, RRAM_CTRL_DEFAULT_REGION_SCRAMBLE_EN_FIELD,
580 properties.scramble_en);
581 reg = bitfield_field32_write(reg, RRAM_CTRL_DEFAULT_REGION_ECC_EN_FIELD,
582 properties.ecc_en);
583 mmio_region_write32(handle->dev.base_addr,
584 RRAM_CTRL_DEFAULT_REGION_REG_OFFSET, reg);
585 return kDifOk;
586}
587
588dif_result_t dif_rram_ctrl_get_default_region_properties(
589 const dif_rram_ctrl_state_t *handle,
590 dif_rram_ctrl_region_properties_t *properties_out) {
591 if (handle == NULL || properties_out == NULL) {
592 return kDifBadArg;
593 }
594 const uint32_t reg = mmio_region_read32(handle->dev.base_addr,
595 RRAM_CTRL_DEFAULT_REGION_REG_OFFSET);
597 .rd_en = bitfield_field32_read(reg, RRAM_CTRL_DEFAULT_REGION_RD_EN_FIELD),
598 .wr_en = bitfield_field32_read(reg, RRAM_CTRL_DEFAULT_REGION_WR_EN_FIELD),
599 .scramble_en = bitfield_field32_read(
600 reg, RRAM_CTRL_DEFAULT_REGION_SCRAMBLE_EN_FIELD),
601 .ecc_en =
602 bitfield_field32_read(reg, RRAM_CTRL_DEFAULT_REGION_ECC_EN_FIELD),
603 };
604 *properties_out = properties;
605 return kDifOk;
606}
607
608dif_result_t dif_rram_ctrl_set_data_region_properties(
609 dif_rram_ctrl_state_t *handle, uint32_t region,
611 const uint32_t page_limit = kNumUsableDataPages;
612 if (handle == NULL || region >= kNumRegions ||
613 config.base + config.size > page_limit) {
614 return kDifBadArg;
615 }
616
617 bool locked;
619 dif_rram_ctrl_data_region_is_locked(handle, region, &locked));
620 if (locked) {
621 return kDifLocked;
622 }
623
624 ptrdiff_t mp_reg_offset = get_data_region_mp_reg_offset(region);
625 uint32_t reg = mmio_region_read32(handle->dev.base_addr, mp_reg_offset);
626 reg = bitfield_field32_write(reg, RRAM_CTRL_MP_REGION_CFG_0_RD_EN_0_FIELD,
627 config.properties.rd_en);
628 reg = bitfield_field32_write(reg, RRAM_CTRL_MP_REGION_CFG_0_WR_EN_0_FIELD,
629 config.properties.wr_en);
630 reg =
631 bitfield_field32_write(reg, RRAM_CTRL_MP_REGION_CFG_0_SCRAMBLE_EN_0_FIELD,
632 config.properties.scramble_en);
633 reg = bitfield_field32_write(reg, RRAM_CTRL_MP_REGION_CFG_0_ECC_EN_0_FIELD,
634 config.properties.ecc_en);
635
636 mmio_region_write32(handle->dev.base_addr, mp_reg_offset, reg);
637
638 // size and base are stored in different registers
639 mp_reg_offset = get_data_region_reg_offset(region);
640
641 reg = bitfield_field32_write(0, RRAM_CTRL_MP_REGION_0_BASE_0_FIELD,
642 config.base);
643 reg = bitfield_field32_write(reg, RRAM_CTRL_MP_REGION_0_SIZE_0_FIELD,
644 config.size);
645 mmio_region_write32(handle->dev.base_addr, mp_reg_offset, reg);
646 return kDifOk;
647}
648
649dif_result_t dif_rram_ctrl_get_data_region_properties(
650 const dif_rram_ctrl_state_t *handle, uint32_t region,
652 if (handle == NULL || config_out == NULL || region >= kNumRegions) {
653 return kDifBadArg;
654 }
655
656 ptrdiff_t mp_reg_offset = get_data_region_mp_reg_offset(region);
657 uint32_t reg = mmio_region_read32(handle->dev.base_addr, mp_reg_offset);
659 config.properties.rd_en =
660 bitfield_field32_read(reg, RRAM_CTRL_MP_REGION_CFG_0_RD_EN_0_FIELD);
661 config.properties.wr_en =
662 bitfield_field32_read(reg, RRAM_CTRL_MP_REGION_CFG_0_WR_EN_0_FIELD);
663 config.properties.scramble_en =
664 bitfield_field32_read(reg, RRAM_CTRL_MP_REGION_CFG_0_SCRAMBLE_EN_0_FIELD);
665 config.properties.ecc_en =
666 bitfield_field32_read(reg, RRAM_CTRL_MP_REGION_CFG_0_ECC_EN_0_FIELD);
667
668 mp_reg_offset = get_data_region_reg_offset(region);
669 reg = mmio_region_read32(handle->dev.base_addr, mp_reg_offset);
670 config.base = bitfield_field32_read(reg, RRAM_CTRL_MP_REGION_0_BASE_0_FIELD);
671 config.size = bitfield_field32_read(reg, RRAM_CTRL_MP_REGION_0_SIZE_0_FIELD);
672 *config_out = config;
673 return kDifOk;
674}
675
676dif_result_t dif_rram_ctrl_set_info_region_properties(
679 if (handle == NULL || region.page >= kNumInfoPages) {
680 return kDifBadArg;
681 }
682
683 bool locked;
685 dif_rram_ctrl_info_region_is_locked(handle, region, &locked));
686 if (locked) {
687 return kDifLocked;
688 }
689
690 ptrdiff_t mp_reg_offset = get_info_region_mp_reg_offset(region);
691 uint32_t reg = mmio_region_read32(handle->dev.base_addr, mp_reg_offset);
692 reg = bitfield_field32_write(reg, RRAM_CTRL_INFO_PAGE_CFG_0_RD_EN_0_FIELD,
693 properties.rd_en);
694 reg = bitfield_field32_write(reg, RRAM_CTRL_INFO_PAGE_CFG_0_WR_EN_0_FIELD,
695 properties.wr_en);
696 reg =
697 bitfield_field32_write(reg, RRAM_CTRL_INFO_PAGE_CFG_0_SCRAMBLE_EN_0_FIELD,
698 properties.scramble_en);
699 reg = bitfield_field32_write(reg, RRAM_CTRL_INFO_PAGE_CFG_0_ECC_EN_0_FIELD,
700 properties.ecc_en);
701 mmio_region_write32(handle->dev.base_addr, mp_reg_offset, reg);
702 return kDifOk;
703}
704
705dif_result_t dif_rram_ctrl_get_info_region_properties(
707 dif_rram_ctrl_region_properties_t *properties_out) {
708 if (handle == NULL || properties_out == NULL ||
709 region.page >= kNumInfoPages) {
710 return kDifBadArg;
711 }
712
713 ptrdiff_t mp_reg_offset = get_info_region_mp_reg_offset(region);
714 const uint32_t reg = mmio_region_read32(handle->dev.base_addr, mp_reg_offset);
716 properties.rd_en =
717 bitfield_field32_read(reg, RRAM_CTRL_INFO_PAGE_CFG_0_RD_EN_0_FIELD);
718 properties.wr_en =
719 bitfield_field32_read(reg, RRAM_CTRL_INFO_PAGE_CFG_0_WR_EN_0_FIELD);
720 properties.scramble_en =
721 bitfield_field32_read(reg, RRAM_CTRL_INFO_PAGE_CFG_0_SCRAMBLE_EN_0_FIELD);
722 properties.ecc_en =
723 bitfield_field32_read(reg, RRAM_CTRL_INFO_PAGE_CFG_0_ECC_EN_0_FIELD);
724 *properties_out = properties;
725 return kDifOk;
726}
727
728dif_result_t dif_rram_ctrl_lock_data_region_properties(
729 dif_rram_ctrl_state_t *handle, uint32_t region) {
730 if (handle == NULL || region >= kNumRegions) {
731 return kDifBadArg;
732 }
733
734 bool locked;
736 dif_rram_ctrl_data_region_is_locked(handle, region, &locked));
737 if (locked) {
738 return kDifLocked;
739 }
740
741 ptrdiff_t lock_reg_offset = get_data_region_lock_reg_offset(region);
742 // rw0c: write 0 to lock.
743 mmio_region_write32(handle->dev.base_addr, lock_reg_offset, 0);
744 return kDifOk;
745}
746
747dif_result_t dif_rram_ctrl_lock_info_region_properties(
749 if (handle == NULL || region.page >= kNumInfoPages) {
750 return kDifBadArg;
751 }
752
753 bool locked;
755 dif_rram_ctrl_info_region_is_locked(handle, region, &locked));
756 if (locked) {
757 return kDifLocked;
758 }
759
760 ptrdiff_t lock_reg_offset = get_info_region_lock_reg_offset(region);
761 // rw0c: write 0 to lock.
762 mmio_region_write32(handle->dev.base_addr, lock_reg_offset, 0);
763 return kDifOk;
764}
765
766dif_result_t dif_rram_ctrl_data_region_is_locked(
767 const dif_rram_ctrl_state_t *handle, uint32_t region, bool *locked_out) {
768 if (handle == NULL || locked_out == NULL || region >= kNumRegions) {
769 return kDifBadArg;
770 }
771 ptrdiff_t lock_reg_offset = get_data_region_lock_reg_offset(region);
772 uint32_t reg = mmio_region_read32(handle->dev.base_addr, lock_reg_offset);
773 *locked_out =
774 !bitfield_bit32_read(reg, RRAM_CTRL_REGION_CFG_REGWEN_0_REGION_0_BIT);
775 return kDifOk;
776}
777
778dif_result_t dif_rram_ctrl_info_region_is_locked(
780 bool *locked_out) {
781 if (handle == NULL || locked_out == NULL || region.page >= kNumInfoPages) {
782 return kDifBadArg;
783 }
784
785 ptrdiff_t lock_reg_offset = get_info_region_lock_reg_offset(region);
786 uint32_t reg = mmio_region_read32(handle->dev.base_addr, lock_reg_offset);
787 *locked_out = !bitfield_bit32_read(reg, RRAM_CTRL_INFO_REGWEN_0_REGION_0_BIT);
788 return kDifOk;
789}
790
791dif_result_t dif_rram_ctrl_set_wr_fifo_watermark(dif_rram_ctrl_state_t *handle,
792 uint32_t level) {
793 if (handle == NULL || level > RRAM_CTRL_FIFO_LVL_WR_MASK) {
794 return kDifBadArg;
795 }
796 uint32_t reg =
797 mmio_region_read32(handle->dev.base_addr, RRAM_CTRL_FIFO_LVL_REG_OFFSET);
798 reg = bitfield_field32_write(reg, RRAM_CTRL_FIFO_LVL_WR_FIELD, level);
799 mmio_region_write32(handle->dev.base_addr, RRAM_CTRL_FIFO_LVL_REG_OFFSET,
800 reg);
801 return kDifOk;
802}
803
804dif_result_t dif_rram_ctrl_set_read_fifo_watermark(
805 dif_rram_ctrl_state_t *handle, uint32_t level) {
806 if (handle == NULL || level > RRAM_CTRL_FIFO_LVL_RD_MASK) {
807 return kDifBadArg;
808 }
809 uint32_t reg =
810 mmio_region_read32(handle->dev.base_addr, RRAM_CTRL_FIFO_LVL_REG_OFFSET);
811 reg = bitfield_field32_write(reg, RRAM_CTRL_FIFO_LVL_RD_FIELD, level);
812 mmio_region_write32(handle->dev.base_addr, RRAM_CTRL_FIFO_LVL_REG_OFFSET,
813 reg);
814 return kDifOk;
815}
816
817dif_result_t dif_rram_ctrl_get_fifo_watermarks(
818 const dif_rram_ctrl_state_t *handle, uint32_t *write_out,
819 uint32_t *read_out) {
820 if (handle == NULL) {
821 return kDifBadArg;
822 }
823 const uint32_t reg =
824 mmio_region_read32(handle->dev.base_addr, RRAM_CTRL_FIFO_LVL_REG_OFFSET);
825 if (write_out != NULL) {
826 *write_out = bitfield_field32_read(reg, RRAM_CTRL_FIFO_LVL_WR_FIELD);
827 }
828 if (read_out != NULL) {
829 *read_out = bitfield_field32_read(reg, RRAM_CTRL_FIFO_LVL_RD_FIELD);
830 }
831 return kDifOk;
832}
833
834dif_result_t dif_rram_ctrl_clear_wr_fifo(dif_rram_ctrl_state_t *handle) {
835 if (handle == NULL) {
836 return kDifBadArg;
837 }
838 uint32_t reg = bitfield_bit32_write(0, RRAM_CTRL_FIFO_CLR_WR_BIT, true);
839 mmio_region_write32(handle->dev.base_addr, RRAM_CTRL_FIFO_CLR_REG_OFFSET,
840 reg);
841 return kDifOk;
842}
843
844dif_result_t dif_rram_ctrl_clear_rd_fifo(dif_rram_ctrl_state_t *handle) {
845 if (handle == NULL) {
846 return kDifBadArg;
847 }
848 uint32_t reg = bitfield_bit32_write(0, RRAM_CTRL_FIFO_CLR_RD_BIT, true);
849 mmio_region_write32(handle->dev.base_addr, RRAM_CTRL_FIFO_CLR_REG_OFFSET,
850 reg);
851 return kDifOk;
852}
853
854dif_result_t dif_rram_ctrl_get_faults(const dif_rram_ctrl_state_t *handle,
855 dif_rram_ctrl_faults_t *faults_out) {
856 if (handle == NULL || faults_out == NULL) {
857 return kDifBadArg;
858 }
859 uint32_t reg = mmio_region_read32(handle->dev.base_addr,
860 RRAM_CTRL_FAULT_STATUS_REG_OFFSET);
861 dif_rram_ctrl_faults_t faults;
862 faults.lcmgr_operation_error =
863 bitfield_bit32_read(reg, RRAM_CTRL_FAULT_STATUS_LCMGR_OP_ERR_BIT);
865 bitfield_bit32_read(reg, RRAM_CTRL_FAULT_STATUS_LCMGR_MP_ERR_BIT);
866 faults.lcmgr_read_error =
867 bitfield_bit32_read(reg, RRAM_CTRL_FAULT_STATUS_LCMGR_RD_ERR_BIT);
868 faults.lcmgr_write_error =
869 bitfield_bit32_read(reg, RRAM_CTRL_FAULT_STATUS_LCMGR_WR_ERR_BIT);
870 faults.otp_operation_error =
871 bitfield_bit32_read(reg, RRAM_CTRL_FAULT_STATUS_OTP_OP_ERR_BIT);
873 bitfield_bit32_read(reg, RRAM_CTRL_FAULT_STATUS_OTP_MP_ERR_BIT);
874 faults.otp_read_error =
875 bitfield_bit32_read(reg, RRAM_CTRL_FAULT_STATUS_OTP_RD_ERR_BIT);
876 faults.otp_write_error =
877 bitfield_bit32_read(reg, RRAM_CTRL_FAULT_STATUS_OTP_WR_ERR_BIT);
878 // TODO: Add more faults?
879 *faults_out = faults;
880 return kDifOk;
881}
882
883dif_result_t dif_rram_ctrl_get_ecc_errors(
884 const dif_rram_ctrl_state_t *handle,
885 dif_rram_ctrl_ecc_errors_t *errors_out) {
886 if (handle == NULL || errors_out == NULL) {
887 return kDifBadArg;
888 }
889
890 uint32_t reg = mmio_region_read32(handle->dev.base_addr,
891 RRAM_CTRL_CORR_ERR_CNT_REG_OFFSET);
892 errors_out->corr_error_count =
893 bitfield_field32_read(reg, RRAM_CTRL_CORR_ERR_CNT_VAL_FIELD);
894
895 reg = mmio_region_read32(handle->dev.base_addr,
896 RRAM_CTRL_CORR_ERR_LOC_REG_OFFSET);
897
898 errors_out->last_error_address =
899 bitfield_field32_read(reg, RRAM_CTRL_CORR_ERR_LOC_ADDR_FIELD);
900 errors_out->last_error_partition =
901 bitfield_bit32_read(reg, RRAM_CTRL_CORR_ERR_LOC_PART_BIT);
902 return kDifOk;
903}
904
905dif_result_t dif_rram_ctrl_get_phy_status(
906 const dif_rram_ctrl_state_t *handle,
907 dif_rram_ctrl_phy_status_t *status_out) {
908 if (handle == NULL || status_out == NULL) {
909 return kDifBadArg;
910 }
911 const uint32_t reg = mmio_region_read32(handle->dev.base_addr,
912 RRAM_CTRL_PHY_STATUS_REG_OFFSET);
913 dif_rram_ctrl_phy_status_t status = {
914 .phy_init_done =
915 bitfield_bit32_read(reg, RRAM_CTRL_PHY_STATUS_INIT_DONE_BIT),
916 .phy_wr_busy = bitfield_bit32_read(reg, RRAM_CTRL_PHY_STATUS_WR_BUSY_BIT),
917 };
918 *status_out = status;
919 return kDifOk;
920}
921
922dif_result_t dif_rram_ctrl_set_scratch(dif_rram_ctrl_state_t *handle,
923 uint32_t value) {
924 if (handle == NULL) {
925 return kDifBadArg;
926 }
927 mmio_region_write32(handle->dev.base_addr, RRAM_CTRL_SCRATCH_REG_OFFSET,
928 value);
929 return kDifOk;
930}
931
932dif_result_t dif_rram_ctrl_get_scratch(const dif_rram_ctrl_state_t *handle,
933 uint32_t *value_out) {
934 if (handle == NULL || value_out == NULL) {
935 return kDifBadArg;
936 }
937 *value_out =
938 mmio_region_read32(handle->dev.base_addr, RRAM_CTRL_SCRATCH_REG_OFFSET);
939 return kDifOk;
940}