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 
137  const dif_flash_ctrl_device_info_t info = {
138  .num_banks = FLASH_CTRL_PARAM_REG_NUM_BANKS,
139  .bytes_per_word = FLASH_CTRL_PARAM_BYTES_PER_WORD,
140  .bytes_per_page = FLASH_CTRL_PARAM_BYTES_PER_PAGE,
141  .data_pages = FLASH_CTRL_PARAM_REG_PAGES_PER_BANK,
142  .info0_pages = FLASH_CTRL_PARAM_NUM_INFOS0,
143  .info1_pages = FLASH_CTRL_PARAM_NUM_INFOS1,
144  .info2_pages = FLASH_CTRL_PARAM_NUM_INFOS2,
145  };
146  return info;
147 }
148 
151  dif_toggle_t enable) {
152  enum multi_bit_bool disable_flash;
153  if (handle == NULL) {
154  return kDifBadArg;
155  }
156  // TODO: Get agreement on how multi-bit bools are used. This register has
157  // negative logic for dif_toggle_t and treats "invalid" values differently
158  // from the typical "true => enable" registers.
159  switch (enable) {
160  case kDifToggleEnabled:
161  disable_flash = kMultiBitBool4False;
162  break;
163  case kDifToggleDisabled:
164  disable_flash = kMultiBitBool4True;
165  break;
166  default:
167  return kDifBadArg;
168  }
169  mmio_region_write32(handle->dev.base_addr, FLASH_CTRL_DIS_REG_OFFSET,
170  disable_flash);
171  return kDifOk;
172 }
173 
176  const dif_flash_ctrl_state_t *handle, dif_toggle_t *enabled_out) {
177  if (handle == NULL || enabled_out == NULL) {
178  return kDifBadArg;
179  }
180  uint32_t reg =
181  mmio_region_read32(handle->dev.base_addr, FLASH_CTRL_DIS_REG_OFFSET);
182  enum multi_bit_bool flash_disabled =
183  bitfield_field32_read(reg, FLASH_CTRL_DIS_VAL_FIELD);
184  // TODO: As above, determine if there is a convention for multi-bit bools
185  // where "true => disable", and consider creating a common function to handle
186  // conversion.
187  if (flash_disabled == kMultiBitBool4False) {
188  *enabled_out = kDifToggleEnabled;
189  } else {
190  *enabled_out = kDifToggleDisabled;
191  }
192  return kDifOk;
193 }
194 
197  dif_toggle_t enable) {
198  uint32_t value;
199  if (handle == NULL) {
200  return kDifBadArg;
201  }
202  switch (enable) {
203  case kDifToggleEnabled:
204  value = FLASH_CTRL_PARAM_EXEC_EN;
205  break;
206  case kDifToggleDisabled:
207  value = 0;
208  break;
209  default:
210  return kDifBadArg;
211  }
212  mmio_region_write32(handle->dev.base_addr, FLASH_CTRL_EXEC_REG_OFFSET, value);
213  return kDifOk;
214 }
215 
218  const dif_flash_ctrl_state_t *handle, dif_toggle_t *enabled_out) {
219  if (handle == NULL || enabled_out == NULL) {
220  return kDifBadArg;
221  }
222  uint32_t reg =
223  mmio_region_read32(handle->dev.base_addr, FLASH_CTRL_EXEC_REG_OFFSET);
224  if (reg == FLASH_CTRL_PARAM_EXEC_EN) {
225  *enabled_out = kDifToggleEnabled;
226  } else {
227  *enabled_out = kDifToggleDisabled;
228  }
229  return kDifOk;
230 }
231 
234  dif_flash_ctrl_state_t *handle) {
235  if (handle == NULL) {
236  return kDifBadArg;
237  }
238  const uint32_t reg =
239  mmio_region_read32(handle->dev.base_addr, FLASH_CTRL_INIT_REG_OFFSET);
240  if (bitfield_bit32_read(reg, FLASH_CTRL_INIT_VAL_BIT)) {
241  // Controller initialization may only be requested once.
242  return kDifError;
243  }
244  uint32_t value = bitfield_bit32_write(0, FLASH_CTRL_INIT_VAL_BIT, true);
245  mmio_region_write32(handle->dev.base_addr, FLASH_CTRL_INIT_REG_OFFSET, value);
246  return kDifOk;
247 }
248 
251  dif_flash_ctrl_status_t *status_out) {
252  if (handle == NULL || status_out == NULL) {
253  return kDifBadArg;
254  }
255  uint32_t reg =
256  mmio_region_read32(handle->dev.base_addr, FLASH_CTRL_STATUS_REG_OFFSET);
258  .read_fifo_full = bitfield_bit32_read(reg, FLASH_CTRL_STATUS_RD_FULL_BIT),
259  .read_fifo_empty =
260  bitfield_bit32_read(reg, FLASH_CTRL_STATUS_RD_EMPTY_BIT),
261  .prog_fifo_full =
262  bitfield_bit32_read(reg, FLASH_CTRL_STATUS_PROG_FULL_BIT),
263  .prog_fifo_empty =
264  bitfield_bit32_read(reg, FLASH_CTRL_STATUS_PROG_EMPTY_BIT),
265  .controller_init_wip =
266  bitfield_bit32_read(reg, FLASH_CTRL_STATUS_INIT_WIP_BIT),
267  .controller_initialized =
268  bitfield_bit32_read(reg, FLASH_CTRL_STATUS_INITIALIZED_BIT),
269  };
270  *status_out = status;
271  return kDifOk;
272 }
273 
276  const dif_flash_ctrl_state_t *handle,
277  dif_flash_ctrl_prog_capabilities_t *allowed_types_out) {
278  if (handle == NULL || allowed_types_out == NULL) {
279  return kDifBadArg;
280  }
281 
282  uint32_t reg = mmio_region_read32(handle->dev.base_addr,
283  FLASH_CTRL_PROG_TYPE_EN_REG_OFFSET);
284  dif_flash_ctrl_prog_capabilities_t allowed_types = {
286  bitfield_bit32_read(reg, FLASH_CTRL_PROG_TYPE_EN_NORMAL_BIT),
287  .repair_prog_type =
288  bitfield_bit32_read(reg, FLASH_CTRL_PROG_TYPE_EN_REPAIR_BIT),
289  };
290  *allowed_types_out = allowed_types;
291  return kDifOk;
292 }
293 
296  dif_flash_ctrl_state_t *handle,
297  dif_flash_ctrl_prog_capabilities_t types_to_disallow) {
298  if (handle == NULL) {
299  return kDifBadArg;
300  }
301 
302  uint32_t ctrl_regwen = mmio_region_read32(handle->dev.base_addr,
303  FLASH_CTRL_CTRL_REGWEN_REG_OFFSET);
304  if (!bitfield_bit32_read(ctrl_regwen, FLASH_CTRL_CTRL_REGWEN_EN_BIT)) {
305  return kDifUnavailable;
306  }
307 
308  uint32_t reg = 0;
309  reg = bitfield_bit32_write(reg, FLASH_CTRL_PROG_TYPE_EN_NORMAL_BIT,
310  !types_to_disallow.normal_prog_type);
311  reg = bitfield_bit32_write(reg, FLASH_CTRL_PROG_TYPE_EN_REPAIR_BIT,
312  !types_to_disallow.repair_prog_type);
313  mmio_region_write32(handle->dev.base_addr, FLASH_CTRL_PROG_TYPE_EN_REG_OFFSET,
314  reg);
315  return kDifOk;
316 }
317 
321  if (handle == NULL) {
322  return kDifBadArg;
323  }
324  uint32_t ctrl_regwen = mmio_region_read32(handle->dev.base_addr,
325  FLASH_CTRL_CTRL_REGWEN_REG_OFFSET);
326  if (!bitfield_bit32_read(ctrl_regwen, FLASH_CTRL_CTRL_REGWEN_EN_BIT)) {
327  return kDifUnavailable;
328  }
329 
330  uint32_t control_reg = bitfield_field32_write(0, FLASH_CTRL_CONTROL_NUM_FIELD,
331  transaction.word_count - 1);
332  switch (transaction.op) {
333  case kDifFlashCtrlOpRead:
334  control_reg =
335  bitfield_field32_write(control_reg, FLASH_CTRL_CONTROL_OP_FIELD,
336  FLASH_CTRL_CONTROL_OP_VALUE_READ);
337  break;
339  control_reg =
340  bitfield_field32_write(control_reg, FLASH_CTRL_CONTROL_OP_FIELD,
341  FLASH_CTRL_CONTROL_OP_VALUE_PROG);
342  control_reg = bitfield_bit32_write(
343  control_reg, FLASH_CTRL_CONTROL_PROG_SEL_BIT, false);
344  break;
346  control_reg =
347  bitfield_field32_write(control_reg, FLASH_CTRL_CONTROL_OP_FIELD,
348  FLASH_CTRL_CONTROL_OP_VALUE_PROG);
349  control_reg = bitfield_bit32_write(control_reg,
350  FLASH_CTRL_CONTROL_PROG_SEL_BIT, true);
351  break;
353  control_reg =
354  bitfield_field32_write(control_reg, FLASH_CTRL_CONTROL_OP_FIELD,
355  FLASH_CTRL_CONTROL_OP_VALUE_ERASE);
356  control_reg = bitfield_bit32_write(
357  control_reg, FLASH_CTRL_CONTROL_ERASE_SEL_BIT, false);
358  break;
360  control_reg =
361  bitfield_field32_write(control_reg, FLASH_CTRL_CONTROL_OP_FIELD,
362  FLASH_CTRL_CONTROL_OP_VALUE_ERASE);
363  control_reg = bitfield_bit32_write(
364  control_reg, FLASH_CTRL_CONTROL_ERASE_SEL_BIT, true);
365  break;
366  default:
367  return kDifBadArg;
368  }
369 
370  switch (transaction.partition_type) {
371  case kDifFlashCtrlPartitionTypeData:
372  control_reg = bitfield_bit32_write(
373  control_reg, FLASH_CTRL_CONTROL_PARTITION_SEL_BIT, false);
374  break;
375  case kDifFlashCtrlPartitionTypeInfo:
376  control_reg =
377  bitfield_field32_write(control_reg, FLASH_CTRL_CONTROL_INFO_SEL_FIELD,
378  transaction.partition_id);
379  control_reg = bitfield_bit32_write(
380  control_reg, FLASH_CTRL_CONTROL_PARTITION_SEL_BIT, true);
381  break;
382  default:
383  return kDifBadArg;
384  }
385 
386  mmio_region_write32(handle->dev.base_addr, FLASH_CTRL_CONTROL_REG_OFFSET,
387  control_reg);
388  mmio_region_write32(handle->dev.base_addr, FLASH_CTRL_ADDR_REG_OFFSET,
389  transaction.byte_address);
390  mmio_region_write32(handle->dev.base_addr, FLASH_CTRL_CONTROL_REG_OFFSET,
391  control_reg | (1u << FLASH_CTRL_CONTROL_START_BIT));
392  if (transaction.op == kDifFlashCtrlOpPageErase ||
393  transaction.op == kDifFlashCtrlOpBankErase) {
394  // Erase operations don't use the FIFO
395  handle->words_remaining = 0;
396  } else {
397  handle->words_remaining = transaction.word_count;
398  }
399  handle->transaction_pending = true;
400  return kDifOk;
401 }
402 
405  dif_flash_ctrl_transaction_t transaction) {
406  if (handle == NULL) {
407  return kDifBadArg;
408  }
409 
410  if (transaction.partition_type == kDifFlashCtrlPartitionTypeInfo &&
411  transaction.partition_id >= FLASH_CTRL_NUM_INFO_TYPES) {
412  return kDifBadArg;
413  }
414 
415  const uint32_t max_word_count = FLASH_CTRL_CONTROL_NUM_MASK;
416  if ((transaction.op != kDifFlashCtrlOpPageErase) &&
417  (transaction.op != kDifFlashCtrlOpBankErase)) {
418  if (transaction.word_count - 1 > max_word_count ||
419  transaction.word_count == 0) {
420  return kDifBadArg;
421  }
422  }
423 
424  if (handle->transaction_pending) {
425  return kDifUnavailable;
426  }
427 
428  // Disallow starting a new transaction if the FIFOs haven't been emptied yet.
430  dif_result_t result = dif_flash_ctrl_get_status(handle, &status);
431  if (result != kDifOk) {
432  return result;
433  }
434  if (!status.read_fifo_empty || !status.prog_fifo_empty) {
435  return kDifIpFifoFull;
436  }
437 
438  return dif_flash_ctrl_start_unsafe(handle, transaction);
439 }
440 
443  if (handle == NULL) {
444  return kDifBadArg;
445  }
446  uint32_t reg =
447  bitfield_bit32_write(0, FLASH_CTRL_ERASE_SUSPEND_REQ_BIT, true);
448  mmio_region_write32(handle->dev.base_addr,
449  FLASH_CTRL_ERASE_SUSPEND_REG_OFFSET, reg);
450  return kDifOk;
451 }
452 
455  dif_flash_ctrl_state_t *handle, bool *request_pending_out) {
456  if (handle == NULL || request_pending_out == NULL) {
457  return kDifBadArg;
458  }
459  uint32_t reg = mmio_region_read32(handle->dev.base_addr,
460  FLASH_CTRL_ERASE_SUSPEND_REG_OFFSET);
461  *request_pending_out =
462  bitfield_bit32_read(reg, FLASH_CTRL_ERASE_SUSPEND_REQ_BIT);
463  return kDifOk;
464 }
465 
466 // TODO(awill): Function to report the maximum FIFO size?
467 
470  dif_flash_ctrl_state_t *handle, uint32_t word_count, const uint32_t *data) {
471  if (handle == NULL || data == NULL) {
472  return kDifBadArg;
473  }
474  uint32_t written = 0;
475  while (written < word_count) {
476  mmio_region_write32(handle->dev.base_addr, FLASH_CTRL_PROG_FIFO_REG_OFFSET,
477  data[written]);
478  ++written;
479  }
480  handle->words_remaining -= written;
481  return kDifOk;
482 }
483 
486  uint32_t word_count,
487  const uint32_t *data) {
488  if (handle == NULL || data == NULL) {
489  return kDifBadArg;
490  }
491  if (!handle->transaction_pending) {
492  return kDifError;
493  }
494  if (handle->words_remaining < word_count) {
495  return kDifBadArg;
496  }
497  const uint32_t control_reg =
498  mmio_region_read32(handle->dev.base_addr, FLASH_CTRL_CONTROL_REG_OFFSET);
499  const uint32_t op =
500  bitfield_field32_read(control_reg, FLASH_CTRL_CONTROL_OP_FIELD);
501  if (op != FLASH_CTRL_CONTROL_OP_VALUE_PROG) {
502  return kDifError;
503  }
504  return dif_flash_ctrl_prog_fifo_push_unsafe(handle, word_count, data);
505 }
506 
509  uint32_t word_count,
510  uint32_t *data) {
511  if (handle == NULL || data == NULL) {
512  return kDifBadArg;
513  }
514  uint32_t read = 0;
515  while (read < word_count) {
516  data[read] = mmio_region_read32(handle->dev.base_addr,
517  FLASH_CTRL_RD_FIFO_REG_OFFSET);
518  ++read;
519  }
520  handle->words_remaining -= read;
521  return kDifOk;
522 }
523 
526  uint32_t word_count, uint32_t *data) {
527  if (handle == NULL || data == NULL) {
528  return kDifBadArg;
529  }
530  if (!handle->transaction_pending) {
531  return kDifError;
532  }
533  if (handle->words_remaining < word_count) {
534  return kDifBadArg;
535  }
536  const uint32_t control_reg =
537  mmio_region_read32(handle->dev.base_addr, FLASH_CTRL_CONTROL_REG_OFFSET);
538  const uint32_t op =
539  bitfield_field32_read(control_reg, FLASH_CTRL_CONTROL_OP_FIELD);
540  if (op != FLASH_CTRL_CONTROL_OP_VALUE_READ) {
541  return kDifError;
542  }
543  return dif_flash_ctrl_read_fifo_pop_unsafe(handle, word_count, data);
544 }
545 
548  const dif_flash_ctrl_state_t *handle,
549  dif_flash_ctrl_error_t *error_code_out) {
550  if (handle == NULL || error_code_out == NULL) {
551  return kDifBadArg;
552  }
553  const uint32_t code_reg =
554  mmio_region_read32(handle->dev.base_addr, FLASH_CTRL_ERR_CODE_REG_OFFSET);
557  bitfield_bit32_read(code_reg, FLASH_CTRL_ERR_CODE_MP_ERR_BIT),
558  .read_error =
559  bitfield_bit32_read(code_reg, FLASH_CTRL_ERR_CODE_RD_ERR_BIT),
560  .prog_window_error =
561  bitfield_bit32_read(code_reg, FLASH_CTRL_ERR_CODE_PROG_WIN_ERR_BIT),
562  .prog_type_error =
563  bitfield_bit32_read(code_reg, FLASH_CTRL_ERR_CODE_PROG_TYPE_ERR_BIT),
564  .shadow_register_error =
565  bitfield_bit32_read(code_reg, FLASH_CTRL_ERR_CODE_UPDATE_ERR_BIT),
566  };
567 
568  const uint32_t address_reg =
569  mmio_region_read32(handle->dev.base_addr, FLASH_CTRL_ERR_ADDR_REG_OFFSET);
570  dif_flash_ctrl_error_t error_code = {
571  .address = address_reg,
572  .codes = codes,
573  };
574  *error_code_out = error_code;
575  return kDifOk;
576 }
577 
581  if (handle == NULL) {
582  return kDifBadArg;
583  }
584  uint32_t code_reg = 0;
585  code_reg = bitfield_bit32_write(code_reg, FLASH_CTRL_ERR_CODE_MP_ERR_BIT,
587  code_reg = bitfield_bit32_write(code_reg, FLASH_CTRL_ERR_CODE_RD_ERR_BIT,
588  codes.read_error);
589  code_reg = bitfield_bit32_write(
590  code_reg, FLASH_CTRL_ERR_CODE_PROG_WIN_ERR_BIT, codes.prog_window_error);
591  code_reg = bitfield_bit32_write(
592  code_reg, FLASH_CTRL_ERR_CODE_PROG_TYPE_ERR_BIT, codes.prog_type_error);
593  code_reg = bitfield_bit32_write(code_reg, FLASH_CTRL_ERR_CODE_UPDATE_ERR_BIT,
594  codes.shadow_register_error);
595  mmio_region_write32(handle->dev.base_addr, FLASH_CTRL_ERR_CODE_REG_OFFSET,
596  code_reg);
597  return kDifOk;
598 }
599 
603  if (handle == NULL || out == NULL) {
604  return kDifBadArg;
605  }
606  if (!handle->transaction_pending) {
607  return kDifError;
608  }
609  uint32_t status_reg = mmio_region_read32(handle->dev.base_addr,
610  FLASH_CTRL_OP_STATUS_REG_OFFSET);
611  if (!bitfield_bit32_read(status_reg, FLASH_CTRL_OP_STATUS_DONE_BIT)) {
612  return kDifUnavailable;
613  }
614  if (handle->words_remaining != 0) {
615  return kDifIpFifoFull;
616  }
617  dif_flash_ctrl_error_t error_code_tmp;
618  DIF_RETURN_IF_ERROR(dif_flash_ctrl_get_error_codes(handle, &error_code_tmp));
619  dif_flash_ctrl_output_t output = {
620  .operation_done =
621  bitfield_bit32_read(status_reg, FLASH_CTRL_OP_STATUS_DONE_BIT),
622  .operation_error =
623  bitfield_bit32_read(status_reg, FLASH_CTRL_OP_STATUS_ERR_BIT),
624  .error_code = error_code_tmp};
625  // Clear the operation status
626  mmio_region_write32(handle->dev.base_addr, FLASH_CTRL_OP_STATUS_REG_OFFSET,
627  0);
628  handle->transaction_pending = false;
629  *out = output;
630  return kDifOk;
631 }
632 
635  dif_flash_ctrl_state_t *handle, uint32_t region, dif_toggle_t enable) {
636  if (handle == NULL || region >= FLASH_CTRL_PARAM_NUM_REGIONS) {
637  return kDifBadArg;
638  }
639 
640  bool locked;
642  dif_flash_ctrl_data_region_is_locked(handle, region, &locked));
643  if (locked) {
644  return kDifLocked;
645  }
646 
647  ptrdiff_t mp_reg_offset = get_data_region_mp_reg_offset(region);
648  uint32_t mp_reg = mmio_region_read32(handle->dev.base_addr, mp_reg_offset);
649  switch (enable) {
650  case kDifToggleEnabled:
651  mp_reg = bitfield_field32_write(
652  mp_reg, FLASH_CTRL_MP_REGION_CFG_0_EN_0_FIELD, kMultiBitBool4True);
653  break;
654  case kDifToggleDisabled:
655  mp_reg = bitfield_field32_write(
656  mp_reg, FLASH_CTRL_MP_REGION_CFG_0_EN_0_FIELD, kMultiBitBool4False);
657  break;
658  default:
659  return kDifBadArg;
660  }
661  mmio_region_write32(handle->dev.base_addr, mp_reg_offset, mp_reg);
662  return kDifOk;
663 }
664 
667  const dif_flash_ctrl_state_t *handle, uint32_t region,
668  dif_toggle_t *enabled_out) {
669  if (handle == NULL || enabled_out == NULL ||
670  region >= FLASH_CTRL_PARAM_NUM_REGIONS) {
671  return kDifBadArg;
672  }
673  ptrdiff_t mp_reg_offset = get_data_region_mp_reg_offset(region);
674  uint32_t mp_reg = mmio_region_read32(handle->dev.base_addr, mp_reg_offset);
675  if (bitfield_field32_read(mp_reg, FLASH_CTRL_MP_REGION_CFG_0_EN_0_FIELD) ==
676  kMultiBitBool4True) {
677  *enabled_out = kDifToggleEnabled;
678  } else {
679  *enabled_out = kDifToggleDisabled;
680  }
681  return kDifOk;
682 }
683 
687  dif_toggle_t enable) {
688  if (handle == NULL || region.bank >= FLASH_CTRL_PARAM_REG_NUM_BANKS ||
689  region.partition_id >= FLASH_CTRL_NUM_INFO_TYPES ||
690  region.page > kNumInfoPagesPerBank[region.partition_id]) {
691  return kDifBadArg;
692  }
693  bool locked;
695  dif_flash_ctrl_info_region_is_locked(handle, region, &locked));
696  if (locked) {
697  return kDifLocked;
698  }
699 
700  ptrdiff_t mp_reg_offset = get_info_region_mp_reg_offset(region);
701  uint32_t mp_reg = mmio_region_read32(handle->dev.base_addr, mp_reg_offset);
702  switch (enable) {
703  case kDifToggleEnabled:
704  mp_reg = bitfield_field32_write(
705  mp_reg, FLASH_CTRL_BANK0_INFO0_PAGE_CFG_0_EN_0_FIELD,
706  kMultiBitBool4True);
707  break;
708  case kDifToggleDisabled:
709  mp_reg = bitfield_field32_write(
710  mp_reg, FLASH_CTRL_BANK0_INFO0_PAGE_CFG_0_EN_0_FIELD,
711  kMultiBitBool4False);
712  break;
713  default:
714  return kDifBadArg;
715  }
716  mmio_region_write32(handle->dev.base_addr, mp_reg_offset, mp_reg);
717  return kDifOk;
718 }
719 
723  dif_toggle_t *enabled_out) {
724  if (handle == NULL || enabled_out == NULL ||
725  region.bank >= FLASH_CTRL_PARAM_REG_NUM_BANKS ||
726  region.partition_id >= FLASH_CTRL_NUM_INFO_TYPES ||
727  region.page > kNumInfoPagesPerBank[region.partition_id]) {
728  return kDifBadArg;
729  }
730  ptrdiff_t mp_reg_offset = get_info_region_mp_reg_offset(region);
731  uint32_t mp_reg = mmio_region_read32(handle->dev.base_addr, mp_reg_offset);
732  if (bitfield_field32_read(mp_reg, FLASH_CTRL_MP_REGION_CFG_0_EN_0_FIELD) ==
733  kMultiBitBool4True) {
734  *enabled_out = kDifToggleEnabled;
735  } else {
736  *enabled_out = kDifToggleDisabled;
737  }
738  return kDifOk;
739 }
740 
743  dif_flash_ctrl_state_t *handle,
745  if (handle == NULL) {
746  return kDifBadArg;
747  }
748  uint32_t reg = 0;
749  reg = bitfield_field32_write(reg, FLASH_CTRL_DEFAULT_REGION_RD_EN_FIELD,
750  properties.rd_en);
751  reg = bitfield_field32_write(reg, FLASH_CTRL_DEFAULT_REGION_PROG_EN_FIELD,
752  properties.prog_en);
753  reg = bitfield_field32_write(reg, FLASH_CTRL_DEFAULT_REGION_ERASE_EN_FIELD,
754  properties.erase_en);
755  reg = bitfield_field32_write(reg, FLASH_CTRL_DEFAULT_REGION_SCRAMBLE_EN_FIELD,
756  properties.scramble_en);
757  reg = bitfield_field32_write(reg, FLASH_CTRL_DEFAULT_REGION_ECC_EN_FIELD,
758  properties.ecc_en);
759  reg = bitfield_field32_write(reg, FLASH_CTRL_DEFAULT_REGION_HE_EN_FIELD,
760  properties.high_endurance_en);
761  mmio_region_write32(handle->dev.base_addr,
762  FLASH_CTRL_DEFAULT_REGION_REG_OFFSET, reg);
763  return kDifOk;
764 }
765 
768  const dif_flash_ctrl_state_t *handle,
769  dif_flash_ctrl_region_properties_t *properties_out) {
770  if (handle == NULL || properties_out == NULL) {
771  return kDifBadArg;
772  }
773  const uint32_t reg = mmio_region_read32(handle->dev.base_addr,
774  FLASH_CTRL_DEFAULT_REGION_REG_OFFSET);
776  .rd_en =
777  bitfield_field32_read(reg, FLASH_CTRL_DEFAULT_REGION_RD_EN_FIELD),
778  .prog_en =
779  bitfield_field32_read(reg, FLASH_CTRL_DEFAULT_REGION_PROG_EN_FIELD),
780  .erase_en =
781  bitfield_field32_read(reg, FLASH_CTRL_DEFAULT_REGION_ERASE_EN_FIELD),
782  .scramble_en = bitfield_field32_read(
783  reg, FLASH_CTRL_DEFAULT_REGION_SCRAMBLE_EN_FIELD),
784  .ecc_en =
785  bitfield_field32_read(reg, FLASH_CTRL_DEFAULT_REGION_ECC_EN_FIELD),
786  .high_endurance_en =
787  bitfield_field32_read(reg, FLASH_CTRL_DEFAULT_REGION_HE_EN_FIELD),
788  };
789  *properties_out = properties;
790  return kDifOk;
791 }
792 
795  dif_flash_ctrl_state_t *handle, uint32_t region,
797  const uint32_t page_limit =
798  FLASH_CTRL_PARAM_REG_NUM_BANKS * FLASH_CTRL_PARAM_REG_PAGES_PER_BANK;
799  if (handle == NULL || region >= FLASH_CTRL_PARAM_NUM_REGIONS ||
800  config.base + config.size > page_limit) {
801  return kDifBadArg;
802  }
803 
804  bool locked;
806  dif_flash_ctrl_data_region_is_locked(handle, region, &locked));
807  if (locked) {
808  return kDifLocked;
809  }
810 
811  ptrdiff_t mp_reg_offset = get_data_region_mp_reg_offset(region);
812  uint32_t reg = mmio_region_read32(handle->dev.base_addr, mp_reg_offset);
813  reg = bitfield_field32_write(reg, FLASH_CTRL_MP_REGION_CFG_0_RD_EN_0_FIELD,
814  config.properties.rd_en);
815  reg = bitfield_field32_write(reg, FLASH_CTRL_MP_REGION_CFG_0_PROG_EN_0_FIELD,
816  config.properties.prog_en);
817  reg = bitfield_field32_write(reg, FLASH_CTRL_MP_REGION_CFG_0_ERASE_EN_0_FIELD,
818  config.properties.erase_en);
819  reg = bitfield_field32_write(reg,
820  FLASH_CTRL_MP_REGION_CFG_0_SCRAMBLE_EN_0_FIELD,
821  config.properties.scramble_en);
822  reg = bitfield_field32_write(reg, FLASH_CTRL_MP_REGION_CFG_0_ECC_EN_0_FIELD,
823  config.properties.ecc_en);
824  reg = bitfield_field32_write(reg, FLASH_CTRL_MP_REGION_CFG_0_HE_EN_0_FIELD,
826 
827  mmio_region_write32(handle->dev.base_addr, mp_reg_offset, reg);
828 
829  // size and base are stored in different registers
830  mp_reg_offset = get_data_region_reg_offset(region);
831 
832  reg = bitfield_field32_write(0, FLASH_CTRL_MP_REGION_0_BASE_0_FIELD,
833  config.base);
834  reg = bitfield_field32_write(reg, FLASH_CTRL_MP_REGION_0_SIZE_0_FIELD,
835  config.size);
836  mmio_region_write32(handle->dev.base_addr, mp_reg_offset, reg);
837  return kDifOk;
838 }
839 
842  const dif_flash_ctrl_state_t *handle, uint32_t region,
844  if (handle == NULL || config_out == NULL ||
845  region >= FLASH_CTRL_PARAM_NUM_REGIONS) {
846  return kDifBadArg;
847  }
848 
849  ptrdiff_t mp_reg_offset = get_data_region_mp_reg_offset(region);
850  uint32_t reg = mmio_region_read32(handle->dev.base_addr, mp_reg_offset);
852  config.properties.rd_en =
853  bitfield_field32_read(reg, FLASH_CTRL_MP_REGION_CFG_0_RD_EN_0_FIELD);
854  config.properties.prog_en =
855  bitfield_field32_read(reg, FLASH_CTRL_MP_REGION_CFG_0_PROG_EN_0_FIELD);
856  config.properties.erase_en =
857  bitfield_field32_read(reg, FLASH_CTRL_MP_REGION_CFG_0_ERASE_EN_0_FIELD);
859  reg, FLASH_CTRL_MP_REGION_CFG_0_SCRAMBLE_EN_0_FIELD);
860  config.properties.ecc_en =
861  bitfield_field32_read(reg, FLASH_CTRL_MP_REGION_CFG_0_ECC_EN_0_FIELD);
863  bitfield_field32_read(reg, FLASH_CTRL_MP_REGION_CFG_0_HE_EN_0_FIELD);
864 
865  mp_reg_offset = get_data_region_reg_offset(region);
866  reg = mmio_region_read32(handle->dev.base_addr, mp_reg_offset);
867  config.base = bitfield_field32_read(reg, FLASH_CTRL_MP_REGION_0_BASE_0_FIELD);
868  config.size = bitfield_field32_read(reg, FLASH_CTRL_MP_REGION_0_SIZE_0_FIELD);
869  *config_out = config;
870  return kDifOk;
871 }
872 
877  if (handle == NULL || region.bank >= FLASH_CTRL_PARAM_REG_NUM_BANKS ||
878  region.partition_id >= FLASH_CTRL_NUM_INFO_TYPES ||
879  region.page > kNumInfoPagesPerBank[region.partition_id]) {
880  return kDifBadArg;
881  }
882 
883  bool locked;
885  dif_flash_ctrl_info_region_is_locked(handle, region, &locked));
886  if (locked) {
887  return kDifLocked;
888  }
889 
890  ptrdiff_t mp_reg_offset = get_info_region_mp_reg_offset(region);
891  uint32_t reg = mmio_region_read32(handle->dev.base_addr, mp_reg_offset);
892  reg = bitfield_field32_write(reg, FLASH_CTRL_MP_REGION_CFG_0_RD_EN_0_FIELD,
893  properties.rd_en);
894  reg = bitfield_field32_write(reg, FLASH_CTRL_MP_REGION_CFG_0_PROG_EN_0_FIELD,
895  properties.prog_en);
896  reg = bitfield_field32_write(reg, FLASH_CTRL_MP_REGION_CFG_0_ERASE_EN_0_FIELD,
897  properties.erase_en);
898  reg = bitfield_field32_write(reg,
899  FLASH_CTRL_MP_REGION_CFG_0_SCRAMBLE_EN_0_FIELD,
900  properties.scramble_en);
901  reg = bitfield_field32_write(reg, FLASH_CTRL_MP_REGION_CFG_0_ECC_EN_0_FIELD,
902  properties.ecc_en);
903  reg = bitfield_field32_write(reg, FLASH_CTRL_MP_REGION_CFG_0_HE_EN_0_FIELD,
904  properties.high_endurance_en);
905  mmio_region_write32(handle->dev.base_addr, mp_reg_offset, reg);
906  return kDifOk;
907 }
908 
912  dif_flash_ctrl_region_properties_t *properties_out) {
913  if (handle == NULL || properties_out == NULL ||
914  region.bank >= FLASH_CTRL_PARAM_REG_NUM_BANKS ||
915  region.partition_id >= FLASH_CTRL_NUM_INFO_TYPES ||
916  region.page > kNumInfoPagesPerBank[region.partition_id]) {
917  return kDifBadArg;
918  }
919 
920  ptrdiff_t mp_reg_offset = get_info_region_mp_reg_offset(region);
921  const uint32_t reg = mmio_region_read32(handle->dev.base_addr, mp_reg_offset);
923  properties.rd_en = bitfield_field32_read(
924  reg, FLASH_CTRL_BANK0_INFO0_PAGE_CFG_0_RD_EN_0_FIELD);
925  properties.prog_en = bitfield_field32_read(
926  reg, FLASH_CTRL_BANK0_INFO0_PAGE_CFG_0_PROG_EN_0_FIELD);
927  properties.erase_en = bitfield_field32_read(
928  reg, FLASH_CTRL_BANK0_INFO0_PAGE_CFG_0_ERASE_EN_0_FIELD);
929  properties.scramble_en = bitfield_field32_read(
930  reg, FLASH_CTRL_BANK0_INFO0_PAGE_CFG_0_SCRAMBLE_EN_0_FIELD);
931  properties.ecc_en = bitfield_field32_read(
932  reg, FLASH_CTRL_BANK0_INFO0_PAGE_CFG_0_ECC_EN_0_FIELD);
934  reg, FLASH_CTRL_BANK0_INFO0_PAGE_CFG_0_HE_EN_0_FIELD);
935  *properties_out = properties;
936  return kDifOk;
937 }
938 
941  dif_flash_ctrl_state_t *handle, uint32_t region) {
942  if (handle == NULL || region >= FLASH_CTRL_PARAM_NUM_REGIONS) {
943  return kDifBadArg;
944  }
945 
946  bool locked;
948  dif_flash_ctrl_data_region_is_locked(handle, region, &locked));
949  if (locked) {
950  return kDifOk;
951  }
952 
953  ptrdiff_t lock_reg_offset = get_data_region_lock_reg_offset(region);
954  uint32_t reg = bitfield_bit32_write(
955  0, FLASH_CTRL_REGION_CFG_REGWEN_0_REGION_0_BIT, false);
956  mmio_region_write32(handle->dev.base_addr, lock_reg_offset, reg);
957  return kDifOk;
958 }
959 
963  if (handle == NULL || region.bank >= FLASH_CTRL_PARAM_REG_NUM_BANKS ||
964  region.partition_id >= FLASH_CTRL_NUM_INFO_TYPES ||
965  region.page > kNumInfoPagesPerBank[region.partition_id]) {
966  return kDifBadArg;
967  }
968 
969  bool locked;
971  dif_flash_ctrl_info_region_is_locked(handle, region, &locked));
972  if (locked) {
973  return kDifOk;
974  }
975 
976  ptrdiff_t lock_reg_offset = get_info_region_lock_reg_offset(region);
977  uint32_t reg = bitfield_bit32_write(
978  0, FLASH_CTRL_BANK0_INFO0_REGWEN_0_REGION_0_BIT, false);
979  mmio_region_write32(handle->dev.base_addr, lock_reg_offset, reg);
980  return kDifOk;
981 }
982 
985  const dif_flash_ctrl_state_t *handle, uint32_t region, bool *locked_out) {
986  if (handle == NULL || locked_out == NULL ||
987  region >= FLASH_CTRL_PARAM_NUM_REGIONS) {
988  return kDifBadArg;
989  }
990  ptrdiff_t lock_reg_offset = get_data_region_lock_reg_offset(region);
991  uint32_t reg = mmio_region_read32(handle->dev.base_addr, lock_reg_offset);
992  *locked_out =
993  !bitfield_bit32_read(reg, FLASH_CTRL_REGION_CFG_REGWEN_0_REGION_0_BIT);
994  return kDifOk;
995 }
996 
1000  bool *locked_out) {
1001  if (handle == NULL || locked_out == NULL ||
1002  region.bank >= FLASH_CTRL_PARAM_REG_NUM_BANKS ||
1003  region.partition_id >= FLASH_CTRL_NUM_INFO_TYPES ||
1004  region.page > kNumInfoPagesPerBank[region.partition_id]) {
1005  return kDifBadArg;
1006  }
1007 
1008  ptrdiff_t lock_reg_offset = get_info_region_lock_reg_offset(region);
1009  uint32_t reg = mmio_region_read32(handle->dev.base_addr, lock_reg_offset);
1010  *locked_out =
1011  !bitfield_bit32_read(reg, FLASH_CTRL_BANK0_INFO0_REGWEN_0_REGION_0_BIT);
1012  return kDifOk;
1013 }
1014 
1017  dif_flash_ctrl_state_t *handle, uint32_t bank, dif_toggle_t enable) {
1018  if (handle == NULL || bank >= FLASH_CTRL_PARAM_REG_NUM_BANKS) {
1019  return kDifBadArg;
1020  }
1021 
1022  bool locked;
1025  if (locked) {
1026  return kDifLocked;
1027  }
1028 
1029  bitfield_bit32_index_t index = bank;
1030  uint32_t value = mmio_region_read32(
1031  handle->dev.base_addr, FLASH_CTRL_MP_BANK_CFG_SHADOWED_REG_OFFSET);
1032  switch (enable) {
1033  case kDifToggleEnabled:
1034  value = bitfield_bit32_write(value, index, true);
1035  break;
1036  case kDifToggleDisabled:
1037  value = bitfield_bit32_write(value, index, false);
1038  break;
1039  default:
1040  return kDifBadArg;
1041  }
1042  mmio_region_write32_shadowed(
1043  handle->dev.base_addr, FLASH_CTRL_MP_BANK_CFG_SHADOWED_REG_OFFSET, value);
1044  return kDifOk;
1045 }
1046 
1049  const dif_flash_ctrl_state_t *handle, uint32_t bank,
1050  dif_toggle_t *enabled_out) {
1051  if (handle == NULL || enabled_out == NULL ||
1052  bank >= FLASH_CTRL_PARAM_REG_NUM_BANKS) {
1053  return kDifBadArg;
1054  }
1055  uint32_t reg = mmio_region_read32(handle->dev.base_addr,
1056  FLASH_CTRL_MP_BANK_CFG_SHADOWED_REG_OFFSET);
1057  bitfield_bit32_index_t index = bank;
1058  bool enabled = bitfield_bit32_read(reg, index);
1059  if (enabled) {
1060  *enabled_out = kDifToggleEnabled;
1061  } else {
1062  *enabled_out = kDifToggleDisabled;
1063  }
1064  return kDifOk;
1065 }
1066 
1069  dif_flash_ctrl_state_t *handle) {
1070  if (handle == NULL) {
1071  return kDifBadArg;
1072  }
1073 
1074  bool locked;
1077  if (locked) {
1078  return kDifLocked;
1079  }
1080 
1081  uint32_t reg =
1082  bitfield_bit32_write(0, FLASH_CTRL_BANK_CFG_REGWEN_BANK_BIT, false);
1083  mmio_region_write32(handle->dev.base_addr,
1084  FLASH_CTRL_BANK_CFG_REGWEN_REG_OFFSET, reg);
1085  return kDifOk;
1086 }
1087 
1090  const dif_flash_ctrl_state_t *handle, bool *locked_out) {
1091  if (handle == NULL || locked_out == NULL) {
1092  return kDifBadArg;
1093  }
1094  const uint32_t reg = mmio_region_read32(
1095  handle->dev.base_addr, FLASH_CTRL_BANK_CFG_REGWEN_REG_OFFSET);
1096  *locked_out = !bitfield_bit32_read(reg, FLASH_CTRL_BANK_CFG_REGWEN_BANK_BIT);
1097  return kDifOk;
1098 }
1099 
1102  dif_flash_ctrl_state_t *handle, uint32_t level) {
1103  if (handle == NULL || level > FLASH_CTRL_FIFO_LVL_PROG_MASK) {
1104  return kDifBadArg;
1105  }
1106  uint32_t reg =
1107  mmio_region_read32(handle->dev.base_addr, FLASH_CTRL_FIFO_LVL_REG_OFFSET);
1108  reg = bitfield_field32_write(reg, FLASH_CTRL_FIFO_LVL_PROG_FIELD, level);
1109  mmio_region_write32(handle->dev.base_addr, FLASH_CTRL_FIFO_LVL_REG_OFFSET,
1110  reg);
1111  return kDifOk;
1112 }
1113 
1116  dif_flash_ctrl_state_t *handle, uint32_t level) {
1117  if (handle == NULL || level > FLASH_CTRL_FIFO_LVL_RD_MASK) {
1118  return kDifBadArg;
1119  }
1120  uint32_t reg =
1121  mmio_region_read32(handle->dev.base_addr, FLASH_CTRL_FIFO_LVL_REG_OFFSET);
1122  reg = bitfield_field32_write(reg, FLASH_CTRL_FIFO_LVL_RD_FIELD, level);
1123  mmio_region_write32(handle->dev.base_addr, FLASH_CTRL_FIFO_LVL_REG_OFFSET,
1124  reg);
1125  return kDifOk;
1126 }
1127 
1130  const dif_flash_ctrl_state_t *handle, uint32_t *prog_out,
1131  uint32_t *read_out) {
1132  if (handle == NULL) {
1133  return kDifBadArg;
1134  }
1135  const uint32_t reg =
1136  mmio_region_read32(handle->dev.base_addr, FLASH_CTRL_FIFO_LVL_REG_OFFSET);
1137  if (prog_out != NULL) {
1138  *prog_out = bitfield_field32_read(reg, FLASH_CTRL_FIFO_LVL_PROG_FIELD);
1139  }
1140  if (read_out != NULL) {
1141  *read_out = bitfield_field32_read(reg, FLASH_CTRL_FIFO_LVL_RD_FIELD);
1142  }
1143  return kDifOk;
1144 }
1145 
1146 // TODO: Allow splitting up turning the reset on and off?
1149  if (handle == NULL) {
1150  return kDifBadArg;
1151  }
1152  uint32_t reg = bitfield_bit32_write(0, FLASH_CTRL_FIFO_RST_EN_BIT, true);
1153  mmio_region_write32(handle->dev.base_addr, FLASH_CTRL_FIFO_RST_REG_OFFSET,
1154  reg);
1155  reg = bitfield_bit32_write(0, FLASH_CTRL_FIFO_RST_EN_BIT, false);
1156  mmio_region_write32(handle->dev.base_addr, FLASH_CTRL_FIFO_RST_REG_OFFSET,
1157  reg);
1158  return kDifOk;
1159 }
1160 
1163  dif_flash_ctrl_faults_t *faults_out) {
1164  if (handle == NULL || faults_out == NULL) {
1165  return kDifBadArg;
1166  }
1167  uint32_t reg = mmio_region_read32(handle->dev.base_addr,
1168  FLASH_CTRL_FAULT_STATUS_REG_OFFSET);
1169  dif_flash_ctrl_faults_t faults;
1170  faults.memory_properties_error =
1171  bitfield_bit32_read(reg, FLASH_CTRL_FAULT_STATUS_MP_ERR_BIT);
1172  faults.read_error =
1173  bitfield_bit32_read(reg, FLASH_CTRL_FAULT_STATUS_RD_ERR_BIT);
1174  faults.prog_window_error =
1175  bitfield_bit32_read(reg, FLASH_CTRL_FAULT_STATUS_PROG_WIN_ERR_BIT);
1176  faults.prog_type_error =
1177  bitfield_bit32_read(reg, FLASH_CTRL_FAULT_STATUS_PROG_TYPE_ERR_BIT);
1178  faults.host_gnt_error =
1179  bitfield_bit32_read(reg, FLASH_CTRL_FAULT_STATUS_HOST_GNT_ERR_BIT);
1180  reg = mmio_region_read32(handle->dev.base_addr,
1181  FLASH_CTRL_STD_FAULT_STATUS_REG_OFFSET);
1182  faults.register_integrity_error =
1183  bitfield_bit32_read(reg, FLASH_CTRL_STD_FAULT_STATUS_REG_INTG_ERR_BIT);
1184  faults.phy_integrity_error =
1185  bitfield_bit32_read(reg, FLASH_CTRL_STD_FAULT_STATUS_PROG_INTG_ERR_BIT);
1186  faults.lifecycle_manager_error =
1187  bitfield_bit32_read(reg, FLASH_CTRL_STD_FAULT_STATUS_LCMGR_ERR_BIT);
1188  faults.shadow_storage_error =
1189  bitfield_bit32_read(reg, FLASH_CTRL_STD_FAULT_STATUS_STORAGE_ERR_BIT);
1190  *faults_out = faults;
1191  return kDifOk;
1192 }
1193 
1196  const dif_flash_ctrl_state_t *handle, uint32_t bank,
1197  dif_flash_ctrl_ecc_errors_t *errors_out) {
1198  if (handle == NULL || errors_out == NULL ||
1199  bank > FLASH_CTRL_PARAM_REG_NUM_BANKS) {
1200  return kDifBadArg;
1201  }
1202  bitfield_field32_t error_count_field;
1203  ptrdiff_t last_addr_reg_offset;
1204 #if FLASH_CTRL_PARAM_REG_NUM_BANKS > 2
1205 #error "Revise this function to handle more banks."
1206 #endif
1207  if (bank == 0) {
1208  error_count_field =
1209  FLASH_CTRL_ECC_SINGLE_ERR_CNT_ECC_SINGLE_ERR_CNT_0_FIELD;
1210  last_addr_reg_offset = FLASH_CTRL_ECC_SINGLE_ERR_ADDR_0_REG_OFFSET;
1211  } else {
1212  error_count_field =
1213  FLASH_CTRL_ECC_SINGLE_ERR_CNT_ECC_SINGLE_ERR_CNT_1_FIELD;
1214  last_addr_reg_offset = FLASH_CTRL_ECC_SINGLE_ERR_ADDR_1_REG_OFFSET;
1215  }
1216 
1217  uint32_t reg = mmio_region_read32(handle->dev.base_addr,
1218  FLASH_CTRL_ECC_SINGLE_ERR_CNT_REG_OFFSET);
1219  errors_out->single_bit_error_count =
1220  bitfield_field32_read(reg, error_count_field);
1221  errors_out->last_error_address =
1222  mmio_region_read32(handle->dev.base_addr, last_addr_reg_offset);
1223  return kDifOk;
1224 }
1225 
1228  const dif_flash_ctrl_state_t *handle,
1229  dif_flash_ctrl_phy_status_t *status_out) {
1230  if (handle == NULL || status_out == NULL) {
1231  return kDifBadArg;
1232  }
1233  const uint32_t reg = mmio_region_read32(handle->dev.base_addr,
1234  FLASH_CTRL_PHY_STATUS_REG_OFFSET);
1236  .phy_init_wip =
1237  bitfield_bit32_read(reg, FLASH_CTRL_PHY_STATUS_INIT_WIP_BIT),
1238  .prog_normal_available =
1239  bitfield_bit32_read(reg, FLASH_CTRL_PHY_STATUS_PROG_NORMAL_AVAIL_BIT),
1240  .prog_repair_available =
1241  bitfield_bit32_read(reg, FLASH_CTRL_PHY_STATUS_PROG_REPAIR_AVAIL_BIT),
1242  };
1243  *status_out = status;
1244  return kDifOk;
1245 }
1246 
1249  uint32_t value) {
1250  if (handle == NULL) {
1251  return kDifBadArg;
1252  }
1253  mmio_region_write32(handle->dev.base_addr, FLASH_CTRL_SCRATCH_REG_OFFSET,
1254  value);
1255  return kDifOk;
1256 }
1257 
1260  uint32_t *value_out) {
1261  if (handle == NULL || value_out == NULL) {
1262  return kDifBadArg;
1263  }
1264  *value_out =
1265  mmio_region_read32(handle->dev.base_addr, FLASH_CTRL_SCRATCH_REG_OFFSET);
1266  return kDifOk;
1267 }