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  */
27 static 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 
33 static 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 
39 static 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.
47 static_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.
58 static 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 
75 static 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 
92 static 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  */
107 static 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 
114 static 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 
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 
136  dt_flash_ctrl_t dt) {
138  handle, mmio_region_from_addr(dt_flash_ctrl_primary_reg_block(dt)));
139 }
140 
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 
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) {
166  case kDifToggleEnabled:
167  disable_flash = kMultiBitBool4False;
168  break;
169  case kDifToggleDisabled:
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 
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 
203  dif_toggle_t enable) {
204  uint32_t value;
205  if (handle == NULL) {
206  return kDifBadArg;
207  }
208  switch (enable) {
209  case kDifToggleEnabled:
210  value = FLASH_CTRL_PARAM_EXEC_EN;
211  break;
212  case kDifToggleDisabled:
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 
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 
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 
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 
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 = {
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 
302  dif_flash_ctrl_state_t *handle,
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 
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) {
339  case kDifFlashCtrlOpRead:
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 
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 
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 
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 
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 
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 
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 
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 
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);
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 
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,
600  codes.shadow_register_error);
601  mmio_region_write32(handle->dev.base_addr, FLASH_CTRL_ERR_CODE_REG_OFFSET,
602  code_reg);
603  return kDifOk;
604 }
605 
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 
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) {
656  case kDifToggleEnabled:
657  mp_reg = bitfield_field32_write(
658  mp_reg, FLASH_CTRL_MP_REGION_CFG_0_EN_0_FIELD, kMultiBitBool4True);
659  break;
660  case kDifToggleDisabled:
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 
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 
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) {
709  case kDifToggleEnabled:
710  mp_reg = bitfield_field32_write(
711  mp_reg, FLASH_CTRL_BANK0_INFO0_PAGE_CFG_0_EN_0_FIELD,
712  kMultiBitBool4True);
713  break;
714  case kDifToggleDisabled:
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 
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 
749  dif_flash_ctrl_state_t *handle,
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 
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 
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 
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);
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 
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 
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);
940  reg, FLASH_CTRL_BANK0_INFO0_PAGE_CFG_0_HE_EN_0_FIELD);
941  *properties_out = properties;
942  return kDifOk;
943 }
944 
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 
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 
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 
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 
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;
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 
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 
1075  dif_flash_ctrl_state_t *handle) {
1076  if (handle == NULL) {
1077  return kDifBadArg;
1078  }
1079 
1080  bool 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 
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 
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 
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 
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?
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 
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;
1176  faults.memory_properties_error =
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);
1188  faults.register_integrity_error =
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);
1192  faults.lifecycle_manager_error =
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 
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 
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);
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 
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 
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 }