Software APIs
dif_flash_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
7#include <assert.h>
8
11#include "sw/device/lib/base/multibits.h"
12
13// Generated.
14#include "flash_ctrl_regs.h"
15
16/**
17 * Helper function to get the offset of a data region's configuration register.
18 * Does not check that the region actually exists, which is deferred to callers.
19 * Since data region registers are split into two (one containing properties the
20 * other containing address info), there are two helper functions below.
21 *
22 * @param region The data region's index.
23 * @return The offset from the flash controller's base address where the region
24 * configuration register is located.
25 */
27static ptrdiff_t get_data_region_mp_reg_offset(uint32_t region) {
28 return FLASH_CTRL_MP_REGION_CFG_0_REG_OFFSET +
29 (ptrdiff_t)region * (ptrdiff_t)sizeof(uint32_t);
30}
31
33static ptrdiff_t get_data_region_reg_offset(uint32_t region) {
34 return FLASH_CTRL_MP_REGION_0_REG_OFFSET +
35 (ptrdiff_t)region * (ptrdiff_t)sizeof(uint32_t);
36}
37
39static ptrdiff_t get_data_region_lock_reg_offset(uint32_t region) {
40 return FLASH_CTRL_REGION_CFG_REGWEN_0_REG_OFFSET +
41 (ptrdiff_t)region * (ptrdiff_t)sizeof(uint32_t);
42}
43
44// The info region register tables have contents that depend on a particular
45// number of flash banks. If that number changes, the tables will need to be
46// updated.
47static_assert(FLASH_CTRL_PARAM_REG_NUM_BANKS == 2,
48 "Please update the info region register tables.");
49
50// TODO: Can we populate the number of info partition types in the header too?
51// The number of different types of info regions.
52#ifndef FLASH_CTRL_NUM_INFO_TYPES
53#define FLASH_CTRL_NUM_INFO_TYPES 3
54#endif
55
56// A more convenient mapping between the info regions and their configuration
57// register offset.
58static const ptrdiff_t
59 kInfoConfigOffsets[FLASH_CTRL_NUM_INFO_TYPES]
60 [FLASH_CTRL_PARAM_REG_NUM_BANKS] = {
61 {
62 FLASH_CTRL_BANK0_INFO0_PAGE_CFG_0_REG_OFFSET,
63 FLASH_CTRL_BANK1_INFO0_PAGE_CFG_0_REG_OFFSET,
64 },
65 {
66 FLASH_CTRL_BANK0_INFO1_PAGE_CFG_REG_OFFSET,
67 FLASH_CTRL_BANK1_INFO1_PAGE_CFG_REG_OFFSET,
68 },
69 {
70 FLASH_CTRL_BANK0_INFO2_PAGE_CFG_0_REG_OFFSET,
71 FLASH_CTRL_BANK1_INFO2_PAGE_CFG_0_REG_OFFSET,
72 },
73};
74
75static const ptrdiff_t
76 kInfoLockOffsets[FLASH_CTRL_NUM_INFO_TYPES]
77 [FLASH_CTRL_PARAM_REG_NUM_BANKS] = {
78 {
79 FLASH_CTRL_BANK0_INFO0_REGWEN_0_REG_OFFSET,
80 FLASH_CTRL_BANK1_INFO0_REGWEN_0_REG_OFFSET,
81 },
82 {
83 FLASH_CTRL_BANK0_INFO1_REGWEN_REG_OFFSET,
84 FLASH_CTRL_BANK1_INFO1_REGWEN_REG_OFFSET,
85 },
86 {
87 FLASH_CTRL_BANK0_INFO2_REGWEN_0_REG_OFFSET,
88 FLASH_CTRL_BANK1_INFO2_REGWEN_0_REG_OFFSET,
89 },
90};
91
92static const uint32_t kNumInfoPagesPerBank[FLASH_CTRL_NUM_INFO_TYPES] = {
93 FLASH_CTRL_PARAM_NUM_INFOS0,
94 FLASH_CTRL_PARAM_NUM_INFOS1,
95 FLASH_CTRL_PARAM_NUM_INFOS2,
96};
97
98/**
99 * Helper function to get the offset of an info region's configuration register.
100 * Does not check that the region actually exists, which is deferred to callers.
101 *
102 * @param region The info region's description.
103 * @return The offset from the flash controller's base address where the region
104 * configuration register is located.
105 */
107static ptrdiff_t get_info_region_mp_reg_offset(
109 return kInfoConfigOffsets[region.partition_id][region.bank] +
110 (ptrdiff_t)region.page * (ptrdiff_t)sizeof(uint32_t);
111}
112
114static ptrdiff_t get_info_region_lock_reg_offset(
116 return kInfoLockOffsets[region.partition_id][region.bank] +
117 (ptrdiff_t)region.page * (ptrdiff_t)sizeof(uint32_t);
118}
119
121dif_result_t dif_flash_ctrl_init_state(dif_flash_ctrl_state_t *handle,
122 mmio_region_t base_addr) {
123 if (handle == NULL) {
124 return kDifBadArg;
125 }
126 dif_result_t result = dif_flash_ctrl_init(base_addr, &handle->dev);
127 if (result != kDifOk) {
128 return result;
129 }
130 handle->words_remaining = 0;
131 handle->transaction_pending = false;
132 return kDifOk;
133}
134
135dif_result_t dif_flash_ctrl_init_state_from_dt(dif_flash_ctrl_state_t *handle,
136 dt_flash_ctrl_t dt) {
137 return dif_flash_ctrl_init_state(
138 handle, mmio_region_from_addr(dt_flash_ctrl_primary_reg_block(dt)));
139}
140
142dif_flash_ctrl_device_info_t dif_flash_ctrl_get_device_info(void) {
143 const dif_flash_ctrl_device_info_t info = {
144 .num_banks = FLASH_CTRL_PARAM_REG_NUM_BANKS,
145 .bytes_per_word = FLASH_CTRL_PARAM_BYTES_PER_WORD,
146 .bytes_per_page = FLASH_CTRL_PARAM_BYTES_PER_PAGE,
147 .data_pages = FLASH_CTRL_PARAM_REG_PAGES_PER_BANK,
148 .info0_pages = FLASH_CTRL_PARAM_NUM_INFOS0,
149 .info1_pages = FLASH_CTRL_PARAM_NUM_INFOS1,
150 .info2_pages = FLASH_CTRL_PARAM_NUM_INFOS2,
151 };
152 return info;
153}
154
156dif_result_t dif_flash_ctrl_set_flash_enablement(dif_flash_ctrl_state_t *handle,
157 dif_toggle_t enable) {
158 enum multi_bit_bool disable_flash;
159 if (handle == NULL) {
160 return kDifBadArg;
161 }
162 // TODO: Get agreement on how multi-bit bools are used. This register has
163 // negative logic for dif_toggle_t and treats "invalid" values differently
164 // from the typical "true => enable" registers.
165 switch (enable) {
167 disable_flash = kMultiBitBool4False;
168 break;
170 disable_flash = kMultiBitBool4True;
171 break;
172 default:
173 return kDifBadArg;
174 }
175 mmio_region_write32(handle->dev.base_addr, FLASH_CTRL_DIS_REG_OFFSET,
176 disable_flash);
177 return kDifOk;
178}
179
181dif_result_t dif_flash_ctrl_get_flash_enablement(
182 const dif_flash_ctrl_state_t *handle, dif_toggle_t *enabled_out) {
183 if (handle == NULL || enabled_out == NULL) {
184 return kDifBadArg;
185 }
186 uint32_t reg =
187 mmio_region_read32(handle->dev.base_addr, FLASH_CTRL_DIS_REG_OFFSET);
188 enum multi_bit_bool flash_disabled =
189 bitfield_field32_read(reg, FLASH_CTRL_DIS_VAL_FIELD);
190 // TODO: As above, determine if there is a convention for multi-bit bools
191 // where "true => disable", and consider creating a common function to handle
192 // conversion.
193 if (flash_disabled == kMultiBitBool4False) {
194 *enabled_out = kDifToggleEnabled;
195 } else {
196 *enabled_out = kDifToggleDisabled;
197 }
198 return kDifOk;
199}
200
202dif_result_t dif_flash_ctrl_set_exec_enablement(dif_flash_ctrl_state_t *handle,
203 dif_toggle_t enable) {
204 uint32_t value;
205 if (handle == NULL) {
206 return kDifBadArg;
207 }
208 switch (enable) {
210 value = FLASH_CTRL_PARAM_EXEC_EN;
211 break;
213 value = 0;
214 break;
215 default:
216 return kDifBadArg;
217 }
218 mmio_region_write32(handle->dev.base_addr, FLASH_CTRL_EXEC_REG_OFFSET, value);
219 return kDifOk;
220}
221
223dif_result_t dif_flash_ctrl_get_exec_enablement(
224 const dif_flash_ctrl_state_t *handle, dif_toggle_t *enabled_out) {
225 if (handle == NULL || enabled_out == NULL) {
226 return kDifBadArg;
227 }
228 uint32_t reg =
229 mmio_region_read32(handle->dev.base_addr, FLASH_CTRL_EXEC_REG_OFFSET);
230 if (reg == FLASH_CTRL_PARAM_EXEC_EN) {
231 *enabled_out = kDifToggleEnabled;
232 } else {
233 *enabled_out = kDifToggleDisabled;
234 }
235 return kDifOk;
236}
237
239dif_result_t dif_flash_ctrl_start_controller_init(
240 dif_flash_ctrl_state_t *handle) {
241 if (handle == NULL) {
242 return kDifBadArg;
243 }
244 const uint32_t reg =
245 mmio_region_read32(handle->dev.base_addr, FLASH_CTRL_INIT_REG_OFFSET);
246 if (bitfield_bit32_read(reg, FLASH_CTRL_INIT_VAL_BIT)) {
247 // Controller initialization may only be requested once.
248 return kDifError;
249 }
250 uint32_t value = bitfield_bit32_write(0, FLASH_CTRL_INIT_VAL_BIT, true);
251 mmio_region_write32(handle->dev.base_addr, FLASH_CTRL_INIT_REG_OFFSET, value);
252 return kDifOk;
253}
254
256dif_result_t dif_flash_ctrl_get_status(const dif_flash_ctrl_state_t *handle,
257 dif_flash_ctrl_status_t *status_out) {
258 if (handle == NULL || status_out == NULL) {
259 return kDifBadArg;
260 }
261 uint32_t reg =
262 mmio_region_read32(handle->dev.base_addr, FLASH_CTRL_STATUS_REG_OFFSET);
264 .read_fifo_full = bitfield_bit32_read(reg, FLASH_CTRL_STATUS_RD_FULL_BIT),
265 .read_fifo_empty =
266 bitfield_bit32_read(reg, FLASH_CTRL_STATUS_RD_EMPTY_BIT),
267 .prog_fifo_full =
268 bitfield_bit32_read(reg, FLASH_CTRL_STATUS_PROG_FULL_BIT),
269 .prog_fifo_empty =
270 bitfield_bit32_read(reg, FLASH_CTRL_STATUS_PROG_EMPTY_BIT),
271 .controller_init_wip =
272 bitfield_bit32_read(reg, FLASH_CTRL_STATUS_INIT_WIP_BIT),
273 .controller_initialized =
274 bitfield_bit32_read(reg, FLASH_CTRL_STATUS_INITIALIZED_BIT),
275 };
276 *status_out = status;
277 return kDifOk;
278}
279
281dif_result_t dif_flash_ctrl_get_allowed_prog_types(
282 const dif_flash_ctrl_state_t *handle,
283 dif_flash_ctrl_prog_capabilities_t *allowed_types_out) {
284 if (handle == NULL || allowed_types_out == NULL) {
285 return kDifBadArg;
286 }
287
288 uint32_t reg = mmio_region_read32(handle->dev.base_addr,
289 FLASH_CTRL_PROG_TYPE_EN_REG_OFFSET);
290 dif_flash_ctrl_prog_capabilities_t allowed_types = {
291 .normal_prog_type =
292 bitfield_bit32_read(reg, FLASH_CTRL_PROG_TYPE_EN_NORMAL_BIT),
293 .repair_prog_type =
294 bitfield_bit32_read(reg, FLASH_CTRL_PROG_TYPE_EN_REPAIR_BIT),
295 };
296 *allowed_types_out = allowed_types;
297 return kDifOk;
298}
299
301dif_result_t dif_flash_ctrl_disallow_prog_types(
303 dif_flash_ctrl_prog_capabilities_t types_to_disallow) {
304 if (handle == NULL) {
305 return kDifBadArg;
306 }
307
308 uint32_t ctrl_regwen = mmio_region_read32(handle->dev.base_addr,
309 FLASH_CTRL_CTRL_REGWEN_REG_OFFSET);
310 if (!bitfield_bit32_read(ctrl_regwen, FLASH_CTRL_CTRL_REGWEN_EN_BIT)) {
311 return kDifUnavailable;
312 }
313
314 uint32_t reg = 0;
315 reg = bitfield_bit32_write(reg, FLASH_CTRL_PROG_TYPE_EN_NORMAL_BIT,
316 !types_to_disallow.normal_prog_type);
317 reg = bitfield_bit32_write(reg, FLASH_CTRL_PROG_TYPE_EN_REPAIR_BIT,
318 !types_to_disallow.repair_prog_type);
319 mmio_region_write32(handle->dev.base_addr, FLASH_CTRL_PROG_TYPE_EN_REG_OFFSET,
320 reg);
321 return kDifOk;
322}
323
325dif_result_t dif_flash_ctrl_start_unsafe(
326 dif_flash_ctrl_state_t *handle, dif_flash_ctrl_transaction_t transaction) {
327 if (handle == NULL) {
328 return kDifBadArg;
329 }
330 uint32_t ctrl_regwen = mmio_region_read32(handle->dev.base_addr,
331 FLASH_CTRL_CTRL_REGWEN_REG_OFFSET);
332 if (!bitfield_bit32_read(ctrl_regwen, FLASH_CTRL_CTRL_REGWEN_EN_BIT)) {
333 return kDifUnavailable;
334 }
335
336 uint32_t control_reg = bitfield_field32_write(0, FLASH_CTRL_CONTROL_NUM_FIELD,
337 transaction.word_count - 1);
338 switch (transaction.op) {
340 control_reg =
341 bitfield_field32_write(control_reg, FLASH_CTRL_CONTROL_OP_FIELD,
342 FLASH_CTRL_CONTROL_OP_VALUE_READ);
343 break;
345 control_reg =
346 bitfield_field32_write(control_reg, FLASH_CTRL_CONTROL_OP_FIELD,
347 FLASH_CTRL_CONTROL_OP_VALUE_PROG);
348 control_reg = bitfield_bit32_write(
349 control_reg, FLASH_CTRL_CONTROL_PROG_SEL_BIT, false);
350 break;
352 control_reg =
353 bitfield_field32_write(control_reg, FLASH_CTRL_CONTROL_OP_FIELD,
354 FLASH_CTRL_CONTROL_OP_VALUE_PROG);
355 control_reg = bitfield_bit32_write(control_reg,
356 FLASH_CTRL_CONTROL_PROG_SEL_BIT, true);
357 break;
359 control_reg =
360 bitfield_field32_write(control_reg, FLASH_CTRL_CONTROL_OP_FIELD,
361 FLASH_CTRL_CONTROL_OP_VALUE_ERASE);
362 control_reg = bitfield_bit32_write(
363 control_reg, FLASH_CTRL_CONTROL_ERASE_SEL_BIT, false);
364 break;
366 control_reg =
367 bitfield_field32_write(control_reg, FLASH_CTRL_CONTROL_OP_FIELD,
368 FLASH_CTRL_CONTROL_OP_VALUE_ERASE);
369 control_reg = bitfield_bit32_write(
370 control_reg, FLASH_CTRL_CONTROL_ERASE_SEL_BIT, true);
371 break;
372 default:
373 return kDifBadArg;
374 }
375
376 switch (transaction.partition_type) {
377 case kDifFlashCtrlPartitionTypeData:
378 control_reg = bitfield_bit32_write(
379 control_reg, FLASH_CTRL_CONTROL_PARTITION_SEL_BIT, false);
380 break;
381 case kDifFlashCtrlPartitionTypeInfo:
382 control_reg =
383 bitfield_field32_write(control_reg, FLASH_CTRL_CONTROL_INFO_SEL_FIELD,
384 transaction.partition_id);
385 control_reg = bitfield_bit32_write(
386 control_reg, FLASH_CTRL_CONTROL_PARTITION_SEL_BIT, true);
387 break;
388 default:
389 return kDifBadArg;
390 }
391
392 mmio_region_write32(handle->dev.base_addr, FLASH_CTRL_CONTROL_REG_OFFSET,
393 control_reg);
394 mmio_region_write32(handle->dev.base_addr, FLASH_CTRL_ADDR_REG_OFFSET,
395 transaction.byte_address);
396 mmio_region_write32(handle->dev.base_addr, FLASH_CTRL_CONTROL_REG_OFFSET,
397 control_reg | (1u << FLASH_CTRL_CONTROL_START_BIT));
398 if (transaction.op == kDifFlashCtrlOpPageErase ||
399 transaction.op == kDifFlashCtrlOpBankErase) {
400 // Erase operations don't use the FIFO
401 handle->words_remaining = 0;
402 } else {
403 handle->words_remaining = transaction.word_count;
404 }
405 handle->transaction_pending = true;
406 return kDifOk;
407}
408
410dif_result_t dif_flash_ctrl_start(dif_flash_ctrl_state_t *handle,
411 dif_flash_ctrl_transaction_t transaction) {
412 if (handle == NULL) {
413 return kDifBadArg;
414 }
415
416 if (transaction.partition_type == kDifFlashCtrlPartitionTypeInfo &&
417 transaction.partition_id >= FLASH_CTRL_NUM_INFO_TYPES) {
418 return kDifBadArg;
419 }
420
421 const uint32_t max_word_count = FLASH_CTRL_CONTROL_NUM_MASK;
422 if ((transaction.op != kDifFlashCtrlOpPageErase) &&
423 (transaction.op != kDifFlashCtrlOpBankErase)) {
424 if (transaction.word_count - 1 > max_word_count ||
425 transaction.word_count == 0) {
426 return kDifBadArg;
427 }
428 }
429
430 if (handle->transaction_pending) {
431 return kDifUnavailable;
432 }
433
434 // Disallow starting a new transaction if the FIFOs haven't been emptied yet.
436 dif_result_t result = dif_flash_ctrl_get_status(handle, &status);
437 if (result != kDifOk) {
438 return result;
439 }
440 if (!status.read_fifo_empty || !status.prog_fifo_empty) {
441 return kDifIpFifoFull;
442 }
443
444 return dif_flash_ctrl_start_unsafe(handle, transaction);
445}
446
448dif_result_t dif_flash_ctrl_suspend_erase(dif_flash_ctrl_state_t *handle) {
449 if (handle == NULL) {
450 return kDifBadArg;
451 }
452 uint32_t reg =
453 bitfield_bit32_write(0, FLASH_CTRL_ERASE_SUSPEND_REQ_BIT, true);
454 mmio_region_write32(handle->dev.base_addr,
455 FLASH_CTRL_ERASE_SUSPEND_REG_OFFSET, reg);
456 return kDifOk;
457}
458
460dif_result_t dif_flash_ctrl_get_erase_suspend_status(
461 dif_flash_ctrl_state_t *handle, bool *request_pending_out) {
462 if (handle == NULL || request_pending_out == NULL) {
463 return kDifBadArg;
464 }
465 uint32_t reg = mmio_region_read32(handle->dev.base_addr,
466 FLASH_CTRL_ERASE_SUSPEND_REG_OFFSET);
467 *request_pending_out =
468 bitfield_bit32_read(reg, FLASH_CTRL_ERASE_SUSPEND_REQ_BIT);
469 return kDifOk;
470}
471
472// TODO(awill): Function to report the maximum FIFO size?
473
475dif_result_t dif_flash_ctrl_prog_fifo_push_unsafe(
476 dif_flash_ctrl_state_t *handle, uint32_t word_count, const uint32_t *data) {
477 if (handle == NULL || data == NULL) {
478 return kDifBadArg;
479 }
480 uint32_t written = 0;
481 while (written < word_count) {
482 mmio_region_write32(handle->dev.base_addr, FLASH_CTRL_PROG_FIFO_REG_OFFSET,
483 data[written]);
484 ++written;
485 }
486 handle->words_remaining -= written;
487 return kDifOk;
488}
489
491dif_result_t dif_flash_ctrl_prog_fifo_push(dif_flash_ctrl_state_t *handle,
492 uint32_t word_count,
493 const uint32_t *data) {
494 if (handle == NULL || data == NULL) {
495 return kDifBadArg;
496 }
497 if (!handle->transaction_pending) {
498 return kDifError;
499 }
500 if (handle->words_remaining < word_count) {
501 return kDifBadArg;
502 }
503 const uint32_t control_reg =
504 mmio_region_read32(handle->dev.base_addr, FLASH_CTRL_CONTROL_REG_OFFSET);
505 const uint32_t op =
506 bitfield_field32_read(control_reg, FLASH_CTRL_CONTROL_OP_FIELD);
507 if (op != FLASH_CTRL_CONTROL_OP_VALUE_PROG) {
508 return kDifError;
509 }
510 return dif_flash_ctrl_prog_fifo_push_unsafe(handle, word_count, data);
511}
512
514dif_result_t dif_flash_ctrl_read_fifo_pop_unsafe(dif_flash_ctrl_state_t *handle,
515 uint32_t word_count,
516 uint32_t *data) {
517 if (handle == NULL || data == NULL) {
518 return kDifBadArg;
519 }
520 uint32_t read = 0;
521 while (read < word_count) {
522 data[read] = mmio_region_read32(handle->dev.base_addr,
523 FLASH_CTRL_RD_FIFO_REG_OFFSET);
524 ++read;
525 }
526 handle->words_remaining -= read;
527 return kDifOk;
528}
529
531dif_result_t dif_flash_ctrl_read_fifo_pop(dif_flash_ctrl_state_t *handle,
532 uint32_t word_count, uint32_t *data) {
533 if (handle == NULL || data == NULL) {
534 return kDifBadArg;
535 }
536 if (!handle->transaction_pending) {
537 return kDifError;
538 }
539 if (handle->words_remaining < word_count) {
540 return kDifBadArg;
541 }
542 const uint32_t control_reg =
543 mmio_region_read32(handle->dev.base_addr, FLASH_CTRL_CONTROL_REG_OFFSET);
544 const uint32_t op =
545 bitfield_field32_read(control_reg, FLASH_CTRL_CONTROL_OP_FIELD);
546 if (op != FLASH_CTRL_CONTROL_OP_VALUE_READ) {
547 return kDifError;
548 }
549 return dif_flash_ctrl_read_fifo_pop_unsafe(handle, word_count, data);
550}
551
553dif_result_t dif_flash_ctrl_get_error_codes(
554 const dif_flash_ctrl_state_t *handle,
555 dif_flash_ctrl_error_t *error_code_out) {
556 if (handle == NULL || error_code_out == NULL) {
557 return kDifBadArg;
558 }
559 const uint32_t code_reg =
560 mmio_region_read32(handle->dev.base_addr, FLASH_CTRL_ERR_CODE_REG_OFFSET);
561 dif_flash_ctrl_error_codes_t codes = {
562 .memory_properties_error =
563 bitfield_bit32_read(code_reg, FLASH_CTRL_ERR_CODE_MP_ERR_BIT),
564 .read_error =
565 bitfield_bit32_read(code_reg, FLASH_CTRL_ERR_CODE_RD_ERR_BIT),
566 .prog_window_error =
567 bitfield_bit32_read(code_reg, FLASH_CTRL_ERR_CODE_PROG_WIN_ERR_BIT),
568 .prog_type_error =
569 bitfield_bit32_read(code_reg, FLASH_CTRL_ERR_CODE_PROG_TYPE_ERR_BIT),
570 .shadow_register_error =
571 bitfield_bit32_read(code_reg, FLASH_CTRL_ERR_CODE_UPDATE_ERR_BIT),
572 };
573
574 const uint32_t address_reg =
575 mmio_region_read32(handle->dev.base_addr, FLASH_CTRL_ERR_ADDR_REG_OFFSET);
576 dif_flash_ctrl_error_t error_code = {
577 .address = address_reg,
578 .codes = codes,
579 };
580 *error_code_out = error_code;
581 return kDifOk;
582}
583
585dif_result_t dif_flash_ctrl_clear_error_codes(
586 dif_flash_ctrl_state_t *handle, dif_flash_ctrl_error_codes_t codes) {
587 if (handle == NULL) {
588 return kDifBadArg;
589 }
590 uint32_t code_reg = 0;
591 code_reg = bitfield_bit32_write(code_reg, FLASH_CTRL_ERR_CODE_MP_ERR_BIT,
593 code_reg = bitfield_bit32_write(code_reg, FLASH_CTRL_ERR_CODE_RD_ERR_BIT,
594 codes.read_error);
595 code_reg = bitfield_bit32_write(
596 code_reg, FLASH_CTRL_ERR_CODE_PROG_WIN_ERR_BIT, codes.prog_window_error);
597 code_reg = bitfield_bit32_write(
598 code_reg, FLASH_CTRL_ERR_CODE_PROG_TYPE_ERR_BIT, codes.prog_type_error);
599 code_reg = bitfield_bit32_write(code_reg, FLASH_CTRL_ERR_CODE_UPDATE_ERR_BIT,
601 mmio_region_write32(handle->dev.base_addr, FLASH_CTRL_ERR_CODE_REG_OFFSET,
602 code_reg);
603 return kDifOk;
604}
605
607dif_result_t dif_flash_ctrl_end(dif_flash_ctrl_state_t *handle,
608 dif_flash_ctrl_output_t *out) {
609 if (handle == NULL || out == NULL) {
610 return kDifBadArg;
611 }
612 if (!handle->transaction_pending) {
613 return kDifError;
614 }
615 uint32_t status_reg = mmio_region_read32(handle->dev.base_addr,
616 FLASH_CTRL_OP_STATUS_REG_OFFSET);
617 if (!bitfield_bit32_read(status_reg, FLASH_CTRL_OP_STATUS_DONE_BIT)) {
618 return kDifUnavailable;
619 }
620 if (handle->words_remaining != 0) {
621 return kDifIpFifoFull;
622 }
623 dif_flash_ctrl_error_t error_code_tmp;
624 DIF_RETURN_IF_ERROR(dif_flash_ctrl_get_error_codes(handle, &error_code_tmp));
625 dif_flash_ctrl_output_t output = {
626 .operation_done =
627 bitfield_bit32_read(status_reg, FLASH_CTRL_OP_STATUS_DONE_BIT),
628 .operation_error =
629 bitfield_bit32_read(status_reg, FLASH_CTRL_OP_STATUS_ERR_BIT),
630 .error_code = error_code_tmp};
631 // Clear the operation status
632 mmio_region_write32(handle->dev.base_addr, FLASH_CTRL_OP_STATUS_REG_OFFSET,
633 0);
634 handle->transaction_pending = false;
635 *out = output;
636 return kDifOk;
637}
638
640dif_result_t dif_flash_ctrl_set_data_region_enablement(
641 dif_flash_ctrl_state_t *handle, uint32_t region, dif_toggle_t enable) {
642 if (handle == NULL || region >= FLASH_CTRL_PARAM_NUM_REGIONS) {
643 return kDifBadArg;
644 }
645
646 bool locked;
648 dif_flash_ctrl_data_region_is_locked(handle, region, &locked));
649 if (locked) {
650 return kDifLocked;
651 }
652
653 ptrdiff_t mp_reg_offset = get_data_region_mp_reg_offset(region);
654 uint32_t mp_reg = mmio_region_read32(handle->dev.base_addr, mp_reg_offset);
655 switch (enable) {
657 mp_reg = bitfield_field32_write(
658 mp_reg, FLASH_CTRL_MP_REGION_CFG_0_EN_0_FIELD, kMultiBitBool4True);
659 break;
661 mp_reg = bitfield_field32_write(
662 mp_reg, FLASH_CTRL_MP_REGION_CFG_0_EN_0_FIELD, kMultiBitBool4False);
663 break;
664 default:
665 return kDifBadArg;
666 }
667 mmio_region_write32(handle->dev.base_addr, mp_reg_offset, mp_reg);
668 return kDifOk;
669}
670
672dif_result_t dif_flash_ctrl_get_data_region_enablement(
673 const dif_flash_ctrl_state_t *handle, uint32_t region,
674 dif_toggle_t *enabled_out) {
675 if (handle == NULL || enabled_out == NULL ||
676 region >= FLASH_CTRL_PARAM_NUM_REGIONS) {
677 return kDifBadArg;
678 }
679 ptrdiff_t mp_reg_offset = get_data_region_mp_reg_offset(region);
680 uint32_t mp_reg = mmio_region_read32(handle->dev.base_addr, mp_reg_offset);
681 if (bitfield_field32_read(mp_reg, FLASH_CTRL_MP_REGION_CFG_0_EN_0_FIELD) ==
682 kMultiBitBool4True) {
683 *enabled_out = kDifToggleEnabled;
684 } else {
685 *enabled_out = kDifToggleDisabled;
686 }
687 return kDifOk;
688}
689
691dif_result_t dif_flash_ctrl_set_info_region_enablement(
693 dif_toggle_t enable) {
694 if (handle == NULL || region.bank >= FLASH_CTRL_PARAM_REG_NUM_BANKS ||
695 region.partition_id >= FLASH_CTRL_NUM_INFO_TYPES ||
696 region.page > kNumInfoPagesPerBank[region.partition_id]) {
697 return kDifBadArg;
698 }
699 bool locked;
701 dif_flash_ctrl_info_region_is_locked(handle, region, &locked));
702 if (locked) {
703 return kDifLocked;
704 }
705
706 ptrdiff_t mp_reg_offset = get_info_region_mp_reg_offset(region);
707 uint32_t mp_reg = mmio_region_read32(handle->dev.base_addr, mp_reg_offset);
708 switch (enable) {
710 mp_reg = bitfield_field32_write(
711 mp_reg, FLASH_CTRL_BANK0_INFO0_PAGE_CFG_0_EN_0_FIELD,
712 kMultiBitBool4True);
713 break;
715 mp_reg = bitfield_field32_write(
716 mp_reg, FLASH_CTRL_BANK0_INFO0_PAGE_CFG_0_EN_0_FIELD,
717 kMultiBitBool4False);
718 break;
719 default:
720 return kDifBadArg;
721 }
722 mmio_region_write32(handle->dev.base_addr, mp_reg_offset, mp_reg);
723 return kDifOk;
724}
725
727dif_result_t dif_flash_ctrl_get_info_region_enablement(
729 dif_toggle_t *enabled_out) {
730 if (handle == NULL || enabled_out == NULL ||
731 region.bank >= FLASH_CTRL_PARAM_REG_NUM_BANKS ||
732 region.partition_id >= FLASH_CTRL_NUM_INFO_TYPES ||
733 region.page > kNumInfoPagesPerBank[region.partition_id]) {
734 return kDifBadArg;
735 }
736 ptrdiff_t mp_reg_offset = get_info_region_mp_reg_offset(region);
737 uint32_t mp_reg = mmio_region_read32(handle->dev.base_addr, mp_reg_offset);
738 if (bitfield_field32_read(mp_reg, FLASH_CTRL_MP_REGION_CFG_0_EN_0_FIELD) ==
739 kMultiBitBool4True) {
740 *enabled_out = kDifToggleEnabled;
741 } else {
742 *enabled_out = kDifToggleDisabled;
743 }
744 return kDifOk;
745}
746
748dif_result_t dif_flash_ctrl_set_default_region_properties(
751 if (handle == NULL) {
752 return kDifBadArg;
753 }
754 uint32_t reg = 0;
755 reg = bitfield_field32_write(reg, FLASH_CTRL_DEFAULT_REGION_RD_EN_FIELD,
756 properties.rd_en);
757 reg = bitfield_field32_write(reg, FLASH_CTRL_DEFAULT_REGION_PROG_EN_FIELD,
758 properties.prog_en);
759 reg = bitfield_field32_write(reg, FLASH_CTRL_DEFAULT_REGION_ERASE_EN_FIELD,
760 properties.erase_en);
761 reg = bitfield_field32_write(reg, FLASH_CTRL_DEFAULT_REGION_SCRAMBLE_EN_FIELD,
762 properties.scramble_en);
763 reg = bitfield_field32_write(reg, FLASH_CTRL_DEFAULT_REGION_ECC_EN_FIELD,
764 properties.ecc_en);
765 reg = bitfield_field32_write(reg, FLASH_CTRL_DEFAULT_REGION_HE_EN_FIELD,
766 properties.high_endurance_en);
767 mmio_region_write32(handle->dev.base_addr,
768 FLASH_CTRL_DEFAULT_REGION_REG_OFFSET, reg);
769 return kDifOk;
770}
771
773dif_result_t dif_flash_ctrl_get_default_region_properties(
774 const dif_flash_ctrl_state_t *handle,
775 dif_flash_ctrl_region_properties_t *properties_out) {
776 if (handle == NULL || properties_out == NULL) {
777 return kDifBadArg;
778 }
779 const uint32_t reg = mmio_region_read32(handle->dev.base_addr,
780 FLASH_CTRL_DEFAULT_REGION_REG_OFFSET);
782 .rd_en =
783 bitfield_field32_read(reg, FLASH_CTRL_DEFAULT_REGION_RD_EN_FIELD),
784 .prog_en =
785 bitfield_field32_read(reg, FLASH_CTRL_DEFAULT_REGION_PROG_EN_FIELD),
786 .erase_en =
787 bitfield_field32_read(reg, FLASH_CTRL_DEFAULT_REGION_ERASE_EN_FIELD),
788 .scramble_en = bitfield_field32_read(
789 reg, FLASH_CTRL_DEFAULT_REGION_SCRAMBLE_EN_FIELD),
790 .ecc_en =
791 bitfield_field32_read(reg, FLASH_CTRL_DEFAULT_REGION_ECC_EN_FIELD),
792 .high_endurance_en =
793 bitfield_field32_read(reg, FLASH_CTRL_DEFAULT_REGION_HE_EN_FIELD),
794 };
795 *properties_out = properties;
796 return kDifOk;
797}
798
800dif_result_t dif_flash_ctrl_set_data_region_properties(
801 dif_flash_ctrl_state_t *handle, uint32_t region,
803 const uint32_t page_limit =
804 FLASH_CTRL_PARAM_REG_NUM_BANKS * FLASH_CTRL_PARAM_REG_PAGES_PER_BANK;
805 if (handle == NULL || region >= FLASH_CTRL_PARAM_NUM_REGIONS ||
806 config.base + config.size > page_limit) {
807 return kDifBadArg;
808 }
809
810 bool locked;
812 dif_flash_ctrl_data_region_is_locked(handle, region, &locked));
813 if (locked) {
814 return kDifLocked;
815 }
816
817 ptrdiff_t mp_reg_offset = get_data_region_mp_reg_offset(region);
818 uint32_t reg = mmio_region_read32(handle->dev.base_addr, mp_reg_offset);
819 reg = bitfield_field32_write(reg, FLASH_CTRL_MP_REGION_CFG_0_RD_EN_0_FIELD,
820 config.properties.rd_en);
821 reg = bitfield_field32_write(reg, FLASH_CTRL_MP_REGION_CFG_0_PROG_EN_0_FIELD,
822 config.properties.prog_en);
823 reg = bitfield_field32_write(reg, FLASH_CTRL_MP_REGION_CFG_0_ERASE_EN_0_FIELD,
824 config.properties.erase_en);
825 reg = bitfield_field32_write(reg,
826 FLASH_CTRL_MP_REGION_CFG_0_SCRAMBLE_EN_0_FIELD,
827 config.properties.scramble_en);
828 reg = bitfield_field32_write(reg, FLASH_CTRL_MP_REGION_CFG_0_ECC_EN_0_FIELD,
829 config.properties.ecc_en);
830 reg = bitfield_field32_write(reg, FLASH_CTRL_MP_REGION_CFG_0_HE_EN_0_FIELD,
832
833 mmio_region_write32(handle->dev.base_addr, mp_reg_offset, reg);
834
835 // size and base are stored in different registers
836 mp_reg_offset = get_data_region_reg_offset(region);
837
838 reg = bitfield_field32_write(0, FLASH_CTRL_MP_REGION_0_BASE_0_FIELD,
839 config.base);
840 reg = bitfield_field32_write(reg, FLASH_CTRL_MP_REGION_0_SIZE_0_FIELD,
841 config.size);
842 mmio_region_write32(handle->dev.base_addr, mp_reg_offset, reg);
843 return kDifOk;
844}
845
847dif_result_t dif_flash_ctrl_get_data_region_properties(
848 const dif_flash_ctrl_state_t *handle, uint32_t region,
850 if (handle == NULL || config_out == NULL ||
851 region >= FLASH_CTRL_PARAM_NUM_REGIONS) {
852 return kDifBadArg;
853 }
854
855 ptrdiff_t mp_reg_offset = get_data_region_mp_reg_offset(region);
856 uint32_t reg = mmio_region_read32(handle->dev.base_addr, mp_reg_offset);
858 config.properties.rd_en =
859 bitfield_field32_read(reg, FLASH_CTRL_MP_REGION_CFG_0_RD_EN_0_FIELD);
860 config.properties.prog_en =
861 bitfield_field32_read(reg, FLASH_CTRL_MP_REGION_CFG_0_PROG_EN_0_FIELD);
862 config.properties.erase_en =
863 bitfield_field32_read(reg, FLASH_CTRL_MP_REGION_CFG_0_ERASE_EN_0_FIELD);
864 config.properties.scramble_en = bitfield_field32_read(
865 reg, FLASH_CTRL_MP_REGION_CFG_0_SCRAMBLE_EN_0_FIELD);
866 config.properties.ecc_en =
867 bitfield_field32_read(reg, FLASH_CTRL_MP_REGION_CFG_0_ECC_EN_0_FIELD);
869 bitfield_field32_read(reg, FLASH_CTRL_MP_REGION_CFG_0_HE_EN_0_FIELD);
870
871 mp_reg_offset = get_data_region_reg_offset(region);
872 reg = mmio_region_read32(handle->dev.base_addr, mp_reg_offset);
873 config.base = bitfield_field32_read(reg, FLASH_CTRL_MP_REGION_0_BASE_0_FIELD);
874 config.size = bitfield_field32_read(reg, FLASH_CTRL_MP_REGION_0_SIZE_0_FIELD);
875 *config_out = config;
876 return kDifOk;
877}
878
880dif_result_t dif_flash_ctrl_set_info_region_properties(
883 if (handle == NULL || region.bank >= FLASH_CTRL_PARAM_REG_NUM_BANKS ||
884 region.partition_id >= FLASH_CTRL_NUM_INFO_TYPES ||
885 region.page > kNumInfoPagesPerBank[region.partition_id]) {
886 return kDifBadArg;
887 }
888
889 bool locked;
891 dif_flash_ctrl_info_region_is_locked(handle, region, &locked));
892 if (locked) {
893 return kDifLocked;
894 }
895
896 ptrdiff_t mp_reg_offset = get_info_region_mp_reg_offset(region);
897 uint32_t reg = mmio_region_read32(handle->dev.base_addr, mp_reg_offset);
898 reg = bitfield_field32_write(reg, FLASH_CTRL_MP_REGION_CFG_0_RD_EN_0_FIELD,
899 properties.rd_en);
900 reg = bitfield_field32_write(reg, FLASH_CTRL_MP_REGION_CFG_0_PROG_EN_0_FIELD,
901 properties.prog_en);
902 reg = bitfield_field32_write(reg, FLASH_CTRL_MP_REGION_CFG_0_ERASE_EN_0_FIELD,
903 properties.erase_en);
904 reg = bitfield_field32_write(reg,
905 FLASH_CTRL_MP_REGION_CFG_0_SCRAMBLE_EN_0_FIELD,
906 properties.scramble_en);
907 reg = bitfield_field32_write(reg, FLASH_CTRL_MP_REGION_CFG_0_ECC_EN_0_FIELD,
908 properties.ecc_en);
909 reg = bitfield_field32_write(reg, FLASH_CTRL_MP_REGION_CFG_0_HE_EN_0_FIELD,
910 properties.high_endurance_en);
911 mmio_region_write32(handle->dev.base_addr, mp_reg_offset, reg);
912 return kDifOk;
913}
914
916dif_result_t dif_flash_ctrl_get_info_region_properties(
918 dif_flash_ctrl_region_properties_t *properties_out) {
919 if (handle == NULL || properties_out == NULL ||
920 region.bank >= FLASH_CTRL_PARAM_REG_NUM_BANKS ||
921 region.partition_id >= FLASH_CTRL_NUM_INFO_TYPES ||
922 region.page > kNumInfoPagesPerBank[region.partition_id]) {
923 return kDifBadArg;
924 }
925
926 ptrdiff_t mp_reg_offset = get_info_region_mp_reg_offset(region);
927 const uint32_t reg = mmio_region_read32(handle->dev.base_addr, mp_reg_offset);
929 properties.rd_en = bitfield_field32_read(
930 reg, FLASH_CTRL_BANK0_INFO0_PAGE_CFG_0_RD_EN_0_FIELD);
931 properties.prog_en = bitfield_field32_read(
932 reg, FLASH_CTRL_BANK0_INFO0_PAGE_CFG_0_PROG_EN_0_FIELD);
933 properties.erase_en = bitfield_field32_read(
934 reg, FLASH_CTRL_BANK0_INFO0_PAGE_CFG_0_ERASE_EN_0_FIELD);
935 properties.scramble_en = bitfield_field32_read(
936 reg, FLASH_CTRL_BANK0_INFO0_PAGE_CFG_0_SCRAMBLE_EN_0_FIELD);
937 properties.ecc_en = bitfield_field32_read(
938 reg, FLASH_CTRL_BANK0_INFO0_PAGE_CFG_0_ECC_EN_0_FIELD);
939 properties.high_endurance_en = bitfield_field32_read(
940 reg, FLASH_CTRL_BANK0_INFO0_PAGE_CFG_0_HE_EN_0_FIELD);
941 *properties_out = properties;
942 return kDifOk;
943}
944
946dif_result_t dif_flash_ctrl_lock_data_region_properties(
947 dif_flash_ctrl_state_t *handle, uint32_t region) {
948 if (handle == NULL || region >= FLASH_CTRL_PARAM_NUM_REGIONS) {
949 return kDifBadArg;
950 }
951
952 bool locked;
954 dif_flash_ctrl_data_region_is_locked(handle, region, &locked));
955 if (locked) {
956 return kDifOk;
957 }
958
959 ptrdiff_t lock_reg_offset = get_data_region_lock_reg_offset(region);
960 uint32_t reg = bitfield_bit32_write(
961 0, FLASH_CTRL_REGION_CFG_REGWEN_0_REGION_0_BIT, false);
962 mmio_region_write32(handle->dev.base_addr, lock_reg_offset, reg);
963 return kDifOk;
964}
965
967dif_result_t dif_flash_ctrl_lock_info_region_properties(
969 if (handle == NULL || region.bank >= FLASH_CTRL_PARAM_REG_NUM_BANKS ||
970 region.partition_id >= FLASH_CTRL_NUM_INFO_TYPES ||
971 region.page > kNumInfoPagesPerBank[region.partition_id]) {
972 return kDifBadArg;
973 }
974
975 bool locked;
977 dif_flash_ctrl_info_region_is_locked(handle, region, &locked));
978 if (locked) {
979 return kDifOk;
980 }
981
982 ptrdiff_t lock_reg_offset = get_info_region_lock_reg_offset(region);
983 uint32_t reg = bitfield_bit32_write(
984 0, FLASH_CTRL_BANK0_INFO0_REGWEN_0_REGION_0_BIT, false);
985 mmio_region_write32(handle->dev.base_addr, lock_reg_offset, reg);
986 return kDifOk;
987}
988
990dif_result_t dif_flash_ctrl_data_region_is_locked(
991 const dif_flash_ctrl_state_t *handle, uint32_t region, bool *locked_out) {
992 if (handle == NULL || locked_out == NULL ||
993 region >= FLASH_CTRL_PARAM_NUM_REGIONS) {
994 return kDifBadArg;
995 }
996 ptrdiff_t lock_reg_offset = get_data_region_lock_reg_offset(region);
997 uint32_t reg = mmio_region_read32(handle->dev.base_addr, lock_reg_offset);
998 *locked_out =
999 !bitfield_bit32_read(reg, FLASH_CTRL_REGION_CFG_REGWEN_0_REGION_0_BIT);
1000 return kDifOk;
1001}
1002
1004dif_result_t dif_flash_ctrl_info_region_is_locked(
1006 bool *locked_out) {
1007 if (handle == NULL || locked_out == NULL ||
1008 region.bank >= FLASH_CTRL_PARAM_REG_NUM_BANKS ||
1009 region.partition_id >= FLASH_CTRL_NUM_INFO_TYPES ||
1010 region.page > kNumInfoPagesPerBank[region.partition_id]) {
1011 return kDifBadArg;
1012 }
1013
1014 ptrdiff_t lock_reg_offset = get_info_region_lock_reg_offset(region);
1015 uint32_t reg = mmio_region_read32(handle->dev.base_addr, lock_reg_offset);
1016 *locked_out =
1017 !bitfield_bit32_read(reg, FLASH_CTRL_BANK0_INFO0_REGWEN_0_REGION_0_BIT);
1018 return kDifOk;
1019}
1020
1022dif_result_t dif_flash_ctrl_set_bank_erase_enablement(
1023 dif_flash_ctrl_state_t *handle, uint32_t bank, dif_toggle_t enable) {
1024 if (handle == NULL || bank >= FLASH_CTRL_PARAM_REG_NUM_BANKS) {
1025 return kDifBadArg;
1026 }
1027
1028 bool locked;
1030 dif_flash_ctrl_bank_configuration_is_locked(handle, &locked));
1031 if (locked) {
1032 return kDifLocked;
1033 }
1034
1035 bitfield_bit32_index_t index = bank;
1036 uint32_t value = mmio_region_read32(
1037 handle->dev.base_addr, FLASH_CTRL_MP_BANK_CFG_SHADOWED_REG_OFFSET);
1038 switch (enable) {
1039 case kDifToggleEnabled:
1040 value = bitfield_bit32_write(value, index, true);
1041 break;
1042 case kDifToggleDisabled:
1043 value = bitfield_bit32_write(value, index, false);
1044 break;
1045 default:
1046 return kDifBadArg;
1047 }
1048 mmio_region_write32_shadowed(
1049 handle->dev.base_addr, FLASH_CTRL_MP_BANK_CFG_SHADOWED_REG_OFFSET, value);
1050 return kDifOk;
1051}
1052
1054dif_result_t dif_flash_ctrl_get_bank_erase_enablement(
1055 const dif_flash_ctrl_state_t *handle, uint32_t bank,
1056 dif_toggle_t *enabled_out) {
1057 if (handle == NULL || enabled_out == NULL ||
1058 bank >= FLASH_CTRL_PARAM_REG_NUM_BANKS) {
1059 return kDifBadArg;
1060 }
1061 uint32_t reg = mmio_region_read32(handle->dev.base_addr,
1062 FLASH_CTRL_MP_BANK_CFG_SHADOWED_REG_OFFSET);
1063 bitfield_bit32_index_t index = bank;
1064 bool enabled = bitfield_bit32_read(reg, index);
1065 if (enabled) {
1066 *enabled_out = kDifToggleEnabled;
1067 } else {
1068 *enabled_out = kDifToggleDisabled;
1069 }
1070 return kDifOk;
1071}
1072
1074dif_result_t dif_flash_ctrl_lock_bank_configuration(
1075 dif_flash_ctrl_state_t *handle) {
1076 if (handle == NULL) {
1077 return kDifBadArg;
1078 }
1079
1080 bool locked;
1082 dif_flash_ctrl_bank_configuration_is_locked(handle, &locked));
1083 if (locked) {
1084 return kDifLocked;
1085 }
1086
1087 uint32_t reg =
1088 bitfield_bit32_write(0, FLASH_CTRL_BANK_CFG_REGWEN_BANK_BIT, false);
1089 mmio_region_write32(handle->dev.base_addr,
1090 FLASH_CTRL_BANK_CFG_REGWEN_REG_OFFSET, reg);
1091 return kDifOk;
1092}
1093
1095dif_result_t dif_flash_ctrl_bank_configuration_is_locked(
1096 const dif_flash_ctrl_state_t *handle, bool *locked_out) {
1097 if (handle == NULL || locked_out == NULL) {
1098 return kDifBadArg;
1099 }
1100 const uint32_t reg = mmio_region_read32(
1101 handle->dev.base_addr, FLASH_CTRL_BANK_CFG_REGWEN_REG_OFFSET);
1102 *locked_out = !bitfield_bit32_read(reg, FLASH_CTRL_BANK_CFG_REGWEN_BANK_BIT);
1103 return kDifOk;
1104}
1105
1107dif_result_t dif_flash_ctrl_set_prog_fifo_watermark(
1108 dif_flash_ctrl_state_t *handle, uint32_t level) {
1109 if (handle == NULL || level > FLASH_CTRL_FIFO_LVL_PROG_MASK) {
1110 return kDifBadArg;
1111 }
1112 uint32_t reg =
1113 mmio_region_read32(handle->dev.base_addr, FLASH_CTRL_FIFO_LVL_REG_OFFSET);
1114 reg = bitfield_field32_write(reg, FLASH_CTRL_FIFO_LVL_PROG_FIELD, level);
1115 mmio_region_write32(handle->dev.base_addr, FLASH_CTRL_FIFO_LVL_REG_OFFSET,
1116 reg);
1117 return kDifOk;
1118}
1119
1121dif_result_t dif_flash_ctrl_set_read_fifo_watermark(
1122 dif_flash_ctrl_state_t *handle, uint32_t level) {
1123 if (handle == NULL || level > FLASH_CTRL_FIFO_LVL_RD_MASK) {
1124 return kDifBadArg;
1125 }
1126 uint32_t reg =
1127 mmio_region_read32(handle->dev.base_addr, FLASH_CTRL_FIFO_LVL_REG_OFFSET);
1128 reg = bitfield_field32_write(reg, FLASH_CTRL_FIFO_LVL_RD_FIELD, level);
1129 mmio_region_write32(handle->dev.base_addr, FLASH_CTRL_FIFO_LVL_REG_OFFSET,
1130 reg);
1131 return kDifOk;
1132}
1133
1135dif_result_t dif_flash_ctrl_get_fifo_watermarks(
1136 const dif_flash_ctrl_state_t *handle, uint32_t *prog_out,
1137 uint32_t *read_out) {
1138 if (handle == NULL) {
1139 return kDifBadArg;
1140 }
1141 const uint32_t reg =
1142 mmio_region_read32(handle->dev.base_addr, FLASH_CTRL_FIFO_LVL_REG_OFFSET);
1143 if (prog_out != NULL) {
1144 *prog_out = bitfield_field32_read(reg, FLASH_CTRL_FIFO_LVL_PROG_FIELD);
1145 }
1146 if (read_out != NULL) {
1147 *read_out = bitfield_field32_read(reg, FLASH_CTRL_FIFO_LVL_RD_FIELD);
1148 }
1149 return kDifOk;
1150}
1151
1152// TODO: Allow splitting up turning the reset on and off?
1154dif_result_t dif_flash_ctrl_reset_fifos(dif_flash_ctrl_state_t *handle) {
1155 if (handle == NULL) {
1156 return kDifBadArg;
1157 }
1158 uint32_t reg = bitfield_bit32_write(0, FLASH_CTRL_FIFO_RST_EN_BIT, true);
1159 mmio_region_write32(handle->dev.base_addr, FLASH_CTRL_FIFO_RST_REG_OFFSET,
1160 reg);
1161 reg = bitfield_bit32_write(0, FLASH_CTRL_FIFO_RST_EN_BIT, false);
1162 mmio_region_write32(handle->dev.base_addr, FLASH_CTRL_FIFO_RST_REG_OFFSET,
1163 reg);
1164 return kDifOk;
1165}
1166
1168dif_result_t dif_flash_ctrl_get_faults(const dif_flash_ctrl_state_t *handle,
1169 dif_flash_ctrl_faults_t *faults_out) {
1170 if (handle == NULL || faults_out == NULL) {
1171 return kDifBadArg;
1172 }
1173 uint32_t reg = mmio_region_read32(handle->dev.base_addr,
1174 FLASH_CTRL_FAULT_STATUS_REG_OFFSET);
1175 dif_flash_ctrl_faults_t faults;
1177 bitfield_bit32_read(reg, FLASH_CTRL_FAULT_STATUS_MP_ERR_BIT);
1178 faults.read_error =
1179 bitfield_bit32_read(reg, FLASH_CTRL_FAULT_STATUS_RD_ERR_BIT);
1180 faults.prog_window_error =
1181 bitfield_bit32_read(reg, FLASH_CTRL_FAULT_STATUS_PROG_WIN_ERR_BIT);
1182 faults.prog_type_error =
1183 bitfield_bit32_read(reg, FLASH_CTRL_FAULT_STATUS_PROG_TYPE_ERR_BIT);
1184 faults.host_gnt_error =
1185 bitfield_bit32_read(reg, FLASH_CTRL_FAULT_STATUS_HOST_GNT_ERR_BIT);
1186 reg = mmio_region_read32(handle->dev.base_addr,
1187 FLASH_CTRL_STD_FAULT_STATUS_REG_OFFSET);
1189 bitfield_bit32_read(reg, FLASH_CTRL_STD_FAULT_STATUS_REG_INTG_ERR_BIT);
1190 faults.phy_integrity_error =
1191 bitfield_bit32_read(reg, FLASH_CTRL_STD_FAULT_STATUS_PROG_INTG_ERR_BIT);
1193 bitfield_bit32_read(reg, FLASH_CTRL_STD_FAULT_STATUS_LCMGR_ERR_BIT);
1194 faults.shadow_storage_error =
1195 bitfield_bit32_read(reg, FLASH_CTRL_STD_FAULT_STATUS_STORAGE_ERR_BIT);
1196 *faults_out = faults;
1197 return kDifOk;
1198}
1199
1201dif_result_t dif_flash_ctrl_get_ecc_errors(
1202 const dif_flash_ctrl_state_t *handle, uint32_t bank,
1203 dif_flash_ctrl_ecc_errors_t *errors_out) {
1204 if (handle == NULL || errors_out == NULL ||
1205 bank > FLASH_CTRL_PARAM_REG_NUM_BANKS) {
1206 return kDifBadArg;
1207 }
1208 bitfield_field32_t error_count_field;
1209 ptrdiff_t last_addr_reg_offset;
1210#if FLASH_CTRL_PARAM_REG_NUM_BANKS > 2
1211#error "Revise this function to handle more banks."
1212#endif
1213 if (bank == 0) {
1214 error_count_field =
1215 FLASH_CTRL_ECC_SINGLE_ERR_CNT_ECC_SINGLE_ERR_CNT_0_FIELD;
1216 last_addr_reg_offset = FLASH_CTRL_ECC_SINGLE_ERR_ADDR_0_REG_OFFSET;
1217 } else {
1218 error_count_field =
1219 FLASH_CTRL_ECC_SINGLE_ERR_CNT_ECC_SINGLE_ERR_CNT_1_FIELD;
1220 last_addr_reg_offset = FLASH_CTRL_ECC_SINGLE_ERR_ADDR_1_REG_OFFSET;
1221 }
1222
1223 uint32_t reg = mmio_region_read32(handle->dev.base_addr,
1224 FLASH_CTRL_ECC_SINGLE_ERR_CNT_REG_OFFSET);
1225 errors_out->single_bit_error_count =
1226 bitfield_field32_read(reg, error_count_field);
1227 errors_out->last_error_address =
1228 mmio_region_read32(handle->dev.base_addr, last_addr_reg_offset);
1229 return kDifOk;
1230}
1231
1233dif_result_t dif_flash_ctrl_get_phy_status(
1234 const dif_flash_ctrl_state_t *handle,
1235 dif_flash_ctrl_phy_status_t *status_out) {
1236 if (handle == NULL || status_out == NULL) {
1237 return kDifBadArg;
1238 }
1239 const uint32_t reg = mmio_region_read32(handle->dev.base_addr,
1240 FLASH_CTRL_PHY_STATUS_REG_OFFSET);
1241 dif_flash_ctrl_phy_status_t status = {
1242 .phy_init_wip =
1243 bitfield_bit32_read(reg, FLASH_CTRL_PHY_STATUS_INIT_WIP_BIT),
1244 .prog_normal_available =
1245 bitfield_bit32_read(reg, FLASH_CTRL_PHY_STATUS_PROG_NORMAL_AVAIL_BIT),
1246 .prog_repair_available =
1247 bitfield_bit32_read(reg, FLASH_CTRL_PHY_STATUS_PROG_REPAIR_AVAIL_BIT),
1248 };
1249 *status_out = status;
1250 return kDifOk;
1251}
1252
1254dif_result_t dif_flash_ctrl_set_scratch(dif_flash_ctrl_state_t *handle,
1255 uint32_t value) {
1256 if (handle == NULL) {
1257 return kDifBadArg;
1258 }
1259 mmio_region_write32(handle->dev.base_addr, FLASH_CTRL_SCRATCH_REG_OFFSET,
1260 value);
1261 return kDifOk;
1262}
1263
1265dif_result_t dif_flash_ctrl_get_scratch(const dif_flash_ctrl_state_t *handle,
1266 uint32_t *value_out) {
1267 if (handle == NULL || value_out == NULL) {
1268 return kDifBadArg;
1269 }
1270 *value_out =
1271 mmio_region_read32(handle->dev.base_addr, FLASH_CTRL_SCRATCH_REG_OFFSET);
1272 return kDifOk;
1273}