Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ot_flash: Add program/erase, memory protection, multi-word ops, FIFO watermarks & fixes #137

Merged
merged 14 commits into from
Feb 7, 2025

Conversation

AlexJones0
Copy link

@AlexJones0 AlexJones0 commented Feb 6, 2025

This PR contains a lot of changes - I recommend reviewing by commit. More details about each change are in the commit messages & comments. A list of remaining unimplemented features has been added to the documentation on the file itself.

This PR does most of the work to get Earlgrey's Flash Controller to a full implementation; the main missing features now are scrambling/ECC/ICVs and alerts. In summary, this PR:

  • Adds program operation support, including program resolution & type errors.
  • Adds erase operation support (both page/bank erase).
  • Adds logic to allow for correct multi-word reads (current multi-word reads may be wrong, see the desc. of 99dad46)
  • Adds memory protection functionality (info pages, data regions and bank erase protection)
  • Fixes FIFO resets and adds watermark (fifo_lvl) functionality
  • Fixes register description and RW type mismatches
  • Implements missing register writes
  • Fixes disable functionality
  • Adds "partway" erase suspend support.
  • Adds documentation for missing functionality.

This PR has been tested against master on OpenTitan via Bazel by overriding the QEMU binary:

Test ot-earlgrey-9.2.0 result New result
flash_ctrl_clock_freqs_test FAIL PASS
flash_ctrl_idle_low_power_test FAIL FAIL
flash_ctrl_info_access_lc_dev FAIL FAIL
flash_ctrl_info_access_lc_dev_personalized FAIL PASS
flash_ctrl_info_access_lc_prod_end FAIL PASS
flash_ctrl_info_access_lc_prod_end_personalized FAIL PASS
flash_ctrl_info_access_lc_prod_personalized FAIL PASS
flash_ctrl_info_access_lc_rma FAIL PASS
flash_ctrl_info_access_lc_test_unlocked0 FAIL PASS
flash_ctrl_mem_protection_test FAIL PASS
flash_ctrl_ops_test FAIL PASS
flash_ctrl_test FAIL PASS
flash_ctrl_write_clear_test FAIL PASS
rom_e2e_flash_ctrl_init FAIL PASS

The failure in flash_ctrl_idle_low_power_test is because the reset reason is low power instead of POR; this is probably an issue in another block (rstmgr/pwrmgr etc.). I'm not sure where the failure in flash_ctrl_info_access_lc_dev is. The test just fails to boot, so this might be an OTP issue or maybe this test needs additional flags/parameters that I'm not aware of.

The `mp_region_cfg` registers were missing an initial "Enable" shared
field, which also caused the corresponding configuration feature
enabling fields to all be at the incorrect offsets.

Also now resets interrupt state so that the `prog_lvl` and
`prog_empty` Program FIFO interrupts are set by default.

Signed-off-by: Alex Jones <[email protected]>
The write to the `INIT` register needs to be stored so that it can be
read out by software, so that software can poll this register to
determine if controller initialization has already been requested.

Signed-off-by: Alex Jones <[email protected]>
@AlexJones0 AlexJones0 force-pushed the eg_flash_ctrl branch 2 times, most recently from 84e62cb to 136082b Compare February 6, 2025 18:36
@AlexJones0 AlexJones0 linked an issue Feb 6, 2025 that may be closed by this pull request
Copy link

@rivos-eblot rivos-eblot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I do not know the flash controller behavior enough to check all the code, but it looks great. Thanks.

@AlexJones0 AlexJones0 changed the title ot_flash: Add program/erase, memory protection, mutli-word ops, FIFO watermarks & fixes ot_flash: Add program/erase, memory protection, multi-word ops, FIFO watermarks & fixes Feb 7, 2025
Implements functionality related to register writes that did not already
exist, based on the register description in the specification.

Also, a couple of changes to literals in the code for consistent styling.

Signed-off-by: Alex Jones <[email protected]>
Previously, the INTR_STATE register was modelled as being entirely RW1C.
This is not correct, as only the `corr_err` and `op_done` interrupts are
RW1C. All other interrupts are R/O, and must be cleared by the hardware.

Signed-off-by: Alex Jones <[email protected]>
The existing implementation sets the error code / address at the same
time as completing the operation, in the same function. In practice,
these functions need to be separate. Whilst operations with errors should
still complete, you are able to error without completing.

Example: a multi-word program (write) encounters an error, but the
program FIFO has not been filled enough for it to have programmed all
its data. At this point, the flash controller should display an error,
but that the program transaction is not done.

Signed-off-by: Alex Jones <[email protected]>
@rivos-eblot
Copy link

The failure in flash_ctrl_idle_low_power_test is because the reset reason is low power instead of POR; this is probably an issue in another block (rstmgr/pwrmgr etc.). I'm not sure where the failure in flash_ctrl_info_access_lc_dev is. The test just fails to boot, so this might be an OTP issue or maybe this test needs additional flags/parameters that I'm not aware of.

  1. ot_clkmgr is basically an empty shell at the moment. I'm still trying to figure out a way to implement it in a generic way as it is highly configurable and top-dependent (not a high priority though)
  2. ot_pwrmgr handles fast clock FSM, but the slow clock FSM is also mostly empty, as up to now we never had strong requirements to implement it.
  3. I do not think we've added LC management to the embedded flash controller, since we've implemented OTP/LC much later then ot_flash, and have not really uses ot_flash since.

It is likely that many signals (and associated behavior) are missing at the moment.

@AlexJones0
Copy link
Author

I believe my latest force push should have addressed all of the outstanding comments. The test results remain the same as the original post. Thanks for the reviews and detailed comments - I appreciate that this is quite a large PR to review.

This commit implements some of the initial types & control register
logic required for implementing the program & erase commands, which
will be added later.

Signed-off-by: Alex Jones <[email protected]>
Copy link

@rivos-eblot rivos-eblot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

one last thing :-)

Models the behaviour of OpenTitan's RTL: at the start of any (single- or
multi-word) program transaction, two checks are performed.
 1. Check that the start of the program beat is in the same program
 window as the end beat. This window boundary is typically, though not
 always, nicely aligned in memory.
 2. Check that the selected type of program command is enabled.

If either of these fail, the transaction is aborted before it starts.

Signed-off-by: Alex Jones <[email protected]>
Copy link

@rivos-eblot rivos-eblot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

In the existing flash, if you write to the `DIS` register to disable the
flash, it completely removes the ability to read from or write to any of
the CSRs.

Referencing the documentation:
https://opentitan.org/book/hw/top_earlgrey/ip_autogen/flash_ctrl/doc/theory_of_operation.html#flash-access-disable

Upon disabling the flash, it should instead finish existing stateful
operations, and then give a memory protection error for any further
flash protocol controller initiated operations. That is; you should
still be able to interact with the registers, but no new flash
transactions can be started via the Flash Controller. The host-facing
TL-UL adapter errors back all host initiated operations when disabled,
so the disabling the relevant mem region is kept.

Signed-off-by: Alex Jones <[email protected]>
This commit introduces the `prog_fifo` counterpart to the existing
`rd_fifo`, and adds additional functionality relating to the two FIFOs,
whilst fixing some existing issues. This includes properly resetting
related status and interrupt state values when FIFOs are reset. Basic
functionality for writing to the prog FIFO is added, though the
corresponding program operation is not yet implemented.

Watermarks have been added via the use of the FIFO_LVL register, and
these are hooked up to the corresponding interrupts.

Signed-off-by: Alex Jones <[email protected]>
This commit refactors `ot_flash_op_read` so that it can properly support
multi-word reads.

Two fields: `remaining`/`error` are introduced to the operation to count
the number of processed/remaining words in the current transaction, and
to track errors in multi-word transactions. These fields are used to
allow us to retain the initial operation configuration and calculate the
current address at any time.

Under previous operation, if the read FIFO filled, the re-execution of
the `ot_flash_op_read` function read from the initial `op.address`,
thus reading repeated (garbage) data. This new logic fixes the issue and
allows multi-word reads, whilst remaining generic for future operations.

Calculation of the address has moved inside of the iteration, because
this functionality is needed for the later addition of memory protection
region functionality, and because it makes it easier to implement
correct errors for individual operations in multi-word transactions. It
also better decouples the transaction's memory accesses from our flash
backend structure; it is possible for multi-word operations to occur
over some boundary (e.g. read over a page boundary).

Signed-off-by: Alex Jones <[email protected]>
Adds functionality that allows single/multi-word program (write)
operations. This is similar to reading, but must also propagate changes
back to our flash backend via the `blk_pwrite` API. The existing
address calculation functionality from the flash read is re-used, as
the flash controller transaction arbitration logic remains common
across these operations.

Upon encountering an error in a multi-word program transaction, the
flash controller will continue to empty the program FIFO, but not
perform any further writes. Writes before the error are valid.

Signed-off-by: Alex Jones <[email protected]>
Adds flash erase operation functionality, which works at either page or
bank granularities. Erase ops hence do not have lengths/counts, and the
area to be erased is determine based on the address and partition
selections. Successful erases are then propagated to the flash backend.

Page erases use similar functionality to read/programs to calculate the
page address and erase the page. Bank erases are more involved: they
bypass regular memory protection mechanisms. This commit implements
these bank protection mechanisms, as well as the logic for erasing just
the data partition of the bank, or both data and info partitions.

Signed-off-by: Alex Jones <[email protected]>
Adds the functionality for the flash controller's Memory Protection, for
both info and data partitions.

For access to info partitions, each page has a separate register
`BANKX_INFOY_PAGE_CFG_Z` which controls the permissions for that
specific page. For access to data partitions, there are a sequence of
10 `MP_REGION_X` and `MP_REGION_CFG_X` registers which define the
size/bounds and permissions of 10 different regions of flash memory
respectively. Data MP regions are defined by a base page and a size in
base pages, used to calculate their relative bounds. Any data page
accesses that do not fall under any of these 10 (enabled) regions will
instead use the memory protection permissions of the default region,
which is configured through the DEFAULT_REGION register.

All MP configuration registers (except the DEFAULT_REGION) can be
enabled/disabled. If enabled, they will match and their permissions
apply. For data pages, if multiple regions match a given address, the
region with the lowest matching index is applied. Implemented MP
permissions include read/program/erase.

This commit also introduces a `no-protection` property to allow the
optional disabling of these MP checks if not needed. Although manual
testing suggests low overheads, this avoids the overhead introduced by
querying the ranges of all 10 regions for every data word read/progs.

Signed-off-by: Alex Jones <[email protected]>
This commit adds a "partway" fix for erase suspend implementation,
immediately clearing the request to simulate the response of "no erase
ongoing", as currently QEMU flash erases are modelled as synchronous
(i.e. the entire erase happens at once, and cannot be suspended).

Also updates the author information in the file prologue, and introduces
some additional documentation about the limitations of the current QEMU
model, and a couple of relevant TODOs.

Signed-off-by: Alex Jones <[email protected]>
@AlexJones0 AlexJones0 merged commit 55bf323 into lowRISC:ot-earlgrey-9.2.0 Feb 7, 2025
7 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Add support for writing to internal flash
3 participants