Skip to content

Conversation

AlexJones0
Copy link

@AlexJones0 AlexJones0 commented Aug 26, 2025

Depends on #159.

This PR contains changes to the OpenTitan QEMU Earlgrey model to specifically target the Earlgrey 1.0.0 release. The intention is then to stop using the existing ot-earlgrey_1.0.0-9.2.0 branch of the QEMU fork. Specifically:

  • Update documentation and versioning names referring to EarlGrey 2.5.2-RC0 to instead point to EarlGrey 1.0.0
  • Effectively drop support for the "moving/current" Earlgrey target. ot_earlgrey is changed to explicitly support 1.0.0, and moving Earlgrey (i.e. Earlgrey OpenTitan master) is no longer explicitly supported. This change is made both to reduce maintenance burden and due to the limited value of emulation.
  • The definitions of the spi_host, clkmgr, entropy_src, pwrmgr and rstmgr are updated on the Earlgrey machine to match the behaviour of these IPs in the earlgrey_1.0.0 release.
  • Some hard-coded keys/nonces and TAP ID code definitions are updated.

See the commit messages for more details. Note for review: commit 43a7858 which separates the definitions just duplicate the files and rename with top-specific extensions. Any behavioural changes are then introduced in subsequent commits, to ease the review process.

One open question - this PR introduces a fair bit of duplication. The spi_host and entropy_src definitions are duplicated for small diffs in the register definitions which cannot be trivially handled via a runtime property.

  • Splitting the entropy_src makes a fair bit of sense: the register removal shifts the offsets of ~50 registers, and we likely expect it to change more in the moving Darjeeling target in the future.
  • Splitting the spi_host is a bit more contentious, as the change comprises just fields in a single register. I'm curious about whether there is potential for a better solution here that I'm missing that can still conform to upstream QEMU standards and avoid the need for conditional compilation.

Copy link

@jwnrt jwnrt left a comment

Choose a reason for hiding this comment

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

Looks good from my end.

Comment on lines +1196 to +1199
IBEX_DEV_STRING_PROP("nonce", "fee457dee82b6e06"),
IBEX_DEV_STRING_PROP("key", "663c291739ff0e7d644758fee1c58564")
Copy link

Choose a reason for hiding this comment

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

Doesn't cfggen extract keys like these from the system verilog for the LC_CTRL and OTP_CTRL? Maybe we can do the same here in the future. Fine for now.

Choose a reason for hiding this comment

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

Those keys are already extracted by cfggen but the machines still contain default values (that can be overridden by the runtime config file).
Maybe we can remove all keys/nonces/seeds/secrets from the machines source code and provide default config files instead?

Copy link
Author

Choose a reason for hiding this comment

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

Removing the keys from the sources and providing a default config file definitely sounds like a better option, but I'd prefer to leave that to a separate PR to keep this PR more simple and self-contained.

@loiclefort
Copy link

loiclefort commented Aug 26, 2025

Splitting the spi_host is a bit more contentious, as the change comprises just fields in a single register. I'm curious about whether there is potential for a better solution here that I'm missing that can still conform to upstream QEMU standards and avoid the need for conditional compilation

Maybe something like this?

REG32(COMMAND, 0x20u)
    FIELD(COMMAND, CSAAT, 0u, 1u)
    FIELD(COMMAND, SPEED, 1u, 2u)
    FIELD(COMMAND, DIRECTION, 3u, 2u)
    FIELD(COMMAND, LEN, 5u, 20u)
    FIELD(COMMAND, EG100_LEN, 0u, 9u)
    FIELD(COMMAND, EG100_CSAAT, 9u, 1u)
    FIELD(COMMAND, EG100_SPEED, 10u, 2u)
    FIELD(COMMAND, EG100_DIRECTION, 12u, 2u)

and then add a version property and replace all FIELD32_EX(command, COMMAND, XXX) by helper functions like this:

if (s->version == OT_SPIHOST_VERSION_EG_1_0_0) {
    return FIELD32_EX(command, COMMAND, EG100_XXX);
} else {
    return FIELD32_EX(command, COMMAND, XXX);
}

It's not pretty but maybe less maintenance work than a complete fork of the source file.

(alternatively, you could just add some code in ot_spi_host_io_read/ot_spi_host_io_write to swap the fields on the fly then s->version is OT_SPIHOST_VERSION_EG_1_0_0)

@AlexJones0
Copy link
Author

Maybe something like this?

That makes sense. I agree that it's not pretty but I also think for a small difference like this it is worth it to reduce maintenance work, whereas I will probably just keep the entropy source split due to potential future changes.

I'll work on that change now and push it to this PR.

Introduce IP versioning to the clkmgr IP to properly emulate a bug in
the Earlgrey 1.0.0 version of the clkmgr.

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

@loiclefort I've tried to make the change you suggested. Here is an initial look at what this change would require.

Because the COMMAND register is used in a lot of different places I'm not that sure if this is that much more maintainable. How does it look to you? If you let me know which of the two approaches you think will be better long-term (or if you have any alternative ideas for me to test out) I can change the PR.

@loiclefort
Copy link

Because the COMMAND register is used in a lot of different places I'm not that sure if this is that much more maintainable. How does it look to you?

Indeed that's a lot of changes...

What about my other suggestion? We can keep all internal state in "DJ/master" register encoding and convert on-the-fly to EG 1.0.0 encoding in ot_spi_host_io_read/ot_spi_host_io_write when s->version is OT_SPIHOST_VERSION_EG_1_0_0.
For example for the write part:

static uint32_t ot_spi_host_convert_from_eg100_command(OtSPIHostState *s, uint32_t eg_cmd)
{
    uint32_t csaat = FIELD_EX32(eg_cmd, COMMAND, EG_1_0_0_CSAAT);
    uint32_t speed = FIELD_EX32(eg_cmd, COMMAND, EG_1_0_0_SPEED);
    uint32_t direction = FIELD_EX32(eg_cmd, COMMAND, EG_1_0_0_DIRECTION);
    uint32_t len = FIELD_EX32(eg_cmd, COMMAND, EG_1_0_0_LEN);

    uint32_t command = 0;
    command = FIELD_DP32(command, COMMAND, CSAAT, csaat);
    command = FIELD_DP32(command, COMMAND, SPEED, speed);
    command = FIELD_DP32(command, COMMAND, DIRECTION, direction);
    command = FIELD_DP32(command, COMMAND, LEN, len);
    return command;
}

static void ot_spi_host_io_write(void *opaque, hwaddr addr, uint64_t val64,
                                 unsigned int size)
{
 (...)
    case R_COMMAND: {
        if (s->version == OT_SPI_HOST_VERSION_EG_1_0_0) {
            val32 = ot_spi_host_convert_from_eg100_command(s, val32);
        }

        val32 &= R_COMMAND_MASK;
(...)

and the opposite for ot_spi_host_io_read.

@AlexJones0 AlexJones0 force-pushed the switch-to-earlgrey-1.0.0 branch from 644b392 to 748ab40 Compare August 27, 2025 09:25
@AlexJones0
Copy link
Author

AlexJones0 commented Aug 27, 2025

What about my other suggestion?

That's a great idea, thanks. I've incorporated that now, and pushed the changes to this PR (you can see the changes here). I think it works out a lot cleaner and the additional conversion for Earlgrey 1.0.0 backwards compatibility seems reasonable.

Actually, the lack of ability to read the command register and the nature of the change (widening the length field, which should be decreasing in nature) should mean that the snippet you provided (with versioning added on top) is sufficient. I'm running some tests right now to check for any regressions, but I definitely think this is preferable over splitting the files for now.

edit: I didn't find any issues with this approach running tests on earlgrey_1.0.0.

@AlexJones0 AlexJones0 force-pushed the switch-to-earlgrey-1.0.0 branch from 748ab40 to 05e03f7 Compare August 27, 2025 09:47
This adds backwards compatibility with the Earlgrey 1.0.0 COMMAND
register fields for the SPI Host. Since the Earlgrey release, the length
field has been widened and thus the fields have been re-arranged
accordingly. Implement this difference and add versioning to the
SPI Host to allow Earlgrey and Darjeeling to choose different peripheral
versions.

Because we never read back the written command, and the length field
should be monotonically decreasing, we do not need to add additional
checks that the length ever exceeds the field size on EG 1.0.0. This
should also minimise runtime cost to the existing Darjeeling SPI Host
target.

Signed-off-by: Alex Jones <[email protected]>
Since the targeted Earlgrey 1.0.0 target, the `REV` register was
removed, shifting the ~49 subsequent register offsets. Since this
difference cannot be easily maintained via a runtime property, instead
opt to split the IP definitions for Earlgrey (stable release) and
Darjeeling (moving target), as further changes will cause the IPs to
further diverge and become harder to maintain.

Note: this commit does not actually introduce the register offset
changes needed for Earlgrey emulation. Instead, it just duplicates the
entropy source file and performs the relevant renaming and build system
definition logic (and then necessarily reformats the contents).

Signed-off-by: Alex Jones <[email protected]>
This commit effectively reverts
628600b,
but only for the Earlgrey 1.0.0 entropy source definition which
still contained this register. The moving Darjeeling target does not
have this register and so the removal is maintained in the Darjeeling
definition.

Signed-off-by: Alex Jones <[email protected]>
Also document where these values are being sourced from

Signed-off-by: Alex Jones <[email protected]>
Change the supported version to be `earlgrey_1.0.0` instead of
`2.5.2-RC0` - the former is a stable silicon release whereas the latter
contains a variety of outdated hardware and bugs which does not make as
much sense as an emulation target.

This changes the supported version of the `ot_earlgrey` machine to be
Earlgrey 1.0.0 specifically.

Also add a small amount more documentation for some updated IP that was
missed, and more completely enumerate the current list of IP that are
not supported in QEMU Earlgrey emulation.

Signed-off-by: Alex Jones <[email protected]>
@AlexJones0 AlexJones0 force-pushed the switch-to-earlgrey-1.0.0 branch from 05e03f7 to 63e180d Compare August 27, 2025 10:09
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.

3 participants