From: Kane Chen <kane_chen@aspeedtech.com>
To: "Cédric Le Goater" <clg@kaod.org>,
"Peter Maydell" <peter.maydell@linaro.org>,
"Steven Lee" <steven_lee@aspeedtech.com>,
"Troy Lee" <leetroy@gmail.com>,
"Jamin Lin" <jamin_lin@aspeedtech.com>,
"Andrew Jeffery" <andrew@codeconstruct.com.au>,
"Joel Stanley" <joel@jms.id.au>,
"open list:ASPEED BMCs" <qemu-arm@nongnu.org>,
"open list:All patches CC here" <qemu-devel@nongnu.org>
Cc: Troy Lee <troy_lee@aspeedtech.com>, Kane Chen <kane_chen@aspeedtech.com>
Subject: [PATCH v2 2/3] hw/misc/aspeed_sbc: Derive ABR state from OTP config straps
Date: Fri, 18 Sep 2026 06:53:50 +0000 [thread overview]
Message-ID: <20260918065347.3713868-3-kane_chen@aspeedtech.com> (raw)
In-Reply-To: <20260918065347.3713868-1-kane_chen@aspeedtech.com>
The eMMC ABR enable state is currently controlled by the "emmc-abr"
machine property instead of the OTP configuration.
Add helpers to read the OTP configuration and resolve strap values.
Use the ABR strap value to update ABR_EN when R_STATUS is read.
Remove the "emmc-abr" property as the ABR state is now derived from
OTP.
Signed-off-by: Kane-Chen-AS <kane_chen@aspeedtech.com>
---
include/hw/misc/aspeed_sbc.h | 1 -
include/hw/nvram/aspeed_otp.h | 23 +++++++++++--
hw/misc/aspeed_sbc.c | 29 ++++++++++++----
hw/nvram/aspeed_otp.c | 63 +++++++++++++++++++++++++++++++++++
4 files changed, 106 insertions(+), 10 deletions(-)
diff --git a/include/hw/misc/aspeed_sbc.h b/include/hw/misc/aspeed_sbc.h
index 756c612356..b210ffb8aa 100644
--- a/include/hw/misc/aspeed_sbc.h
+++ b/include/hw/misc/aspeed_sbc.h
@@ -32,7 +32,6 @@ OBJECT_DECLARE_TYPE(AspeedSBCState, AspeedSBCClass, ASPEED_SBC)
struct AspeedSBCState {
SysBusDevice parent;
- bool emmc_abr;
uint32_t signing_settings;
MemoryRegion iomem;
diff --git a/include/hw/nvram/aspeed_otp.h b/include/hw/nvram/aspeed_otp.h
index 2b6c2eaaa3..f91af12ea9 100644
--- a/include/hw/nvram/aspeed_otp.h
+++ b/include/hw/nvram/aspeed_otp.h
@@ -24,11 +24,27 @@ OBJECT_DECLARE_SIMPLE_TYPE(AspeedOTPState, ASPEED_OTP)
*
* - [0, OTP_DATA_DWORD_COUNT]: the data region. Each address contains
* 64 bits of data.
- * - [OTP_DATA_DWORD_COUNT, OTP_MEMORY_SIZE / 4]: the configuration
- * region. Each address contains 32 bits of data.
+ * - [OTP_DATA_DWORD_COUNT(OTP_CFG0), OTP_MEMORY_SIZE / 4]: the
+ * configuration region. Each address contains 32 bits of data.
*/
#define OTP_DATA_DWORD_COUNT (0x800)
+/* Start of the OTP configuration/strap region. */
+#define OTP_CFG0 (0x800)
+
+/*
+ * OTP straps are a 64-bit value packed as two 32-bit halves starting at
+ * config word OTP_STRAP_START_INDEX (OTPCFG16 and OTPCFG17). Each strap
+ * bit is stored redundantly in OTP_STRAP_COPY_NUM config words, spaced
+ * (OTP_STRAP_BIT_NUM / 32) words apart -- i.e. one word per 32-bit half,
+ * so the two halves interleave; the effective bit value is the XOR of
+ * all copies, matching how the real hardware and the ast-otp reference
+ * tool resolve straps.
+ */
+#define OTP_STRAP_START_INDEX 16
+#define OTP_STRAP_BIT_NUM 64
+#define OTP_STRAP_COPY_NUM 6
+
typedef struct AspeedOTPState {
DeviceState parent_obj;
@@ -43,4 +59,7 @@ typedef struct AspeedOTPState {
uint8_t *storage;
} AspeedOTPState;
+uint32_t aspeed_otp_read_config(AspeedOTPState *s, unsigned int cfg_word);
+bool aspeed_otp_read_strap(AspeedOTPState *s, unsigned int bit);
+
#endif /* ASPEED_OTP_H */
diff --git a/hw/misc/aspeed_sbc.c b/hw/misc/aspeed_sbc.c
index 3402cef5c3..6cec9ad3da 100644
--- a/hw/misc/aspeed_sbc.c
+++ b/hw/misc/aspeed_sbc.c
@@ -71,6 +71,9 @@
#define SBC_OTP_CMD_WRITE 0x23b1e362
#define SBC_OTP_CMD_PROG 0x23b1e364
+/* OTP strap bits */
+#define OTP_STRAP_ABR_EN 0x2b
+
/* Voltage mode */
#define MODE_REGISTER (0x1000)
#define MODE_REGISTER_A (0x3000)
@@ -89,7 +92,21 @@ static uint64_t aspeed_sbc_read(void *opaque, hwaddr addr, unsigned int size)
return 0;
}
- return s->regs[addr];
+ switch (addr) {
+ case R_STATUS: {
+ uint32_t val = s->regs[R_STATUS];
+
+ if (aspeed_otp_read_strap(&s->otp, OTP_STRAP_ABR_EN)) {
+ val |= ABR_EN;
+ } else {
+ val &= ~ABR_EN;
+ }
+
+ return val;
+ }
+ default:
+ return s->regs[addr];
+ }
}
static bool aspeed_otp_read(AspeedSBCState *s, uint32_t otp_addr,
@@ -388,13 +405,12 @@ static void aspeed_sbc_reset_hold(Object *obj, ResetType type)
memset(s->regs, 0, sizeof(s->regs));
- /* Set secure boot enabled with RSA4096_SHA256 and enable eMMC ABR */
+ /*
+ * ABR_EN is derived from OTP on every read, see aspeed_sbc_read().
+ * Set secure boot enabled with RSA4096_SHA256.
+ */
s->regs[R_STATUS] = OTP_IDLE | OTP_MEM_IDLE;
- if (s->emmc_abr) {
- s->regs[R_STATUS] &= ABR_EN;
- }
-
if (s->signing_settings) {
s->regs[R_STATUS] &= SECURE_BOOT_EN;
}
@@ -452,7 +468,6 @@ static const VMStateDescription vmstate_aspeed_sbc = {
};
static const Property aspeed_sbc_properties[] = {
- DEFINE_PROP_BOOL("emmc-abr", AspeedSBCState, emmc_abr, 0),
DEFINE_PROP_UINT32("signing-settings", AspeedSBCState, signing_settings, 0),
DEFINE_PROP_LINK("sram", AspeedSBCState, sram,
TYPE_MEMORY_REGION, MemoryRegion *),
diff --git a/hw/nvram/aspeed_otp.c b/hw/nvram/aspeed_otp.c
index 81304bda3a..127da15642 100644
--- a/hw/nvram/aspeed_otp.c
+++ b/hw/nvram/aspeed_otp.c
@@ -106,6 +106,69 @@ static void aspeed_otp_write(void *opaque, hwaddr otp_offset,
trace_aspeed_otp_prog(otp_offset, val, value);
}
+/*
+ * Each OTP configuration setting contains 32 bits of data.
+ * Configuration words are grouped in banks of 8, with banks spaced
+ * 0x200 dwords apart and words within a bank spaced 2 dwords apart:
+ *
+ * offset(n) = OTP_CFG0 + (n / 8) * 0x200 + (n % 8) * 2
+ *
+ * Returns 0 if the OTP read fails.
+ */
+uint32_t aspeed_otp_read_config(AspeedOTPState *s, unsigned int cfg_word)
+{
+ uint32_t otp_addr = OTP_CFG0 + (cfg_word / 8) * 0x200 + (cfg_word % 8) * 2;
+ uint32_t value = 0;
+
+ if (address_space_read(&s->as, otp_addr << 2, MEMTXATTRS_UNSPECIFIED,
+ &value, sizeof(value)) != MEMTX_OK) {
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "%s: Failed to read OTP config word %u\n",
+ __func__, cfg_word);
+ return 0;
+ }
+
+ return value;
+}
+
+/*
+ * OTP straps are a 64-bit value split across two 32-bit config words,
+ * each of which is repeated OTP_STRAP_COPY_NUM times for reliability.
+ * The two words interleave starting at OTP_STRAP_START_INDEX:
+ *
+ * cfg_word: 16 17 18 19 20 21 22 23 24 25 26 27
+ * +----+----+----+----+----+----+----+----+----+----+----+----+
+ * | L0 | H0 | L1 | H1 | L2 | H2 | L3 | H3 | L4 | H4 | L5 | H5 |
+ * +----+----+----+----+----+----+----+----+----+----+----+----+
+ *
+ * Lx = copy #x of bit 0-31, Hx = copy #x of bit 32-63
+ * (x = 0 .. OTP_STRAP_COPY_NUM - 1)
+ *
+ * To resolve strap bit `n` (0 <= n < OTP_STRAP_BIT_NUM):
+ * half = n / 32 -- 0 selects the L* words, 1 selects the H* words
+ * bit_pos = n % 32 -- bit position within the word
+ * word(i) = OTP_STRAP_START_INDEX + half + i * (OTP_STRAP_BIT_NUM / 32)
+ *
+ * The effective value of bit `n` is the XOR of bit `bit_pos` across all
+ * OTP_STRAP_COPY_NUM copies of word(i).
+ */
+bool aspeed_otp_read_strap(AspeedOTPState *s, unsigned int bit)
+{
+ uint32_t cfg_word = OTP_STRAP_START_INDEX + bit / 32;
+ uint32_t bit_pos = bit % 32;
+ bool enable = false;
+ int i;
+
+ assert(bit < OTP_STRAP_BIT_NUM);
+
+ for (i = 0; i < OTP_STRAP_COPY_NUM; i++) {
+ enable ^= (aspeed_otp_read_config(s, cfg_word) >> bit_pos) & 0x1;
+ cfg_word += OTP_STRAP_BIT_NUM / 32;
+ }
+
+ return enable;
+}
+
static bool aspeed_otp_init_storage(AspeedOTPState *s, Error **errp)
{
uint32_t *p;
--
2.43.0
next prev parent reply other threads:[~2026-09-18 6:55 UTC|newest]
Thread overview: 5+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-09-18 6:53 [PATCH v2 0/3] hw/misc/aspeed_sbc: Fix ABR and secure boot state reporting Kane Chen
2026-09-18 6:53 ` [PATCH v2 1/3] hw/nvram/aspeed_otp, hw/misc/aspeed_sbc: Consolidate OTP layout definitions Kane Chen
2026-09-18 6:53 ` Kane Chen [this message]
2026-09-18 6:53 ` [PATCH v2 3/3] hw/misc/aspeed_sbc: Derive secure boot state from OTP config Kane Chen
2026-09-18 12:57 ` [PATCH v2 0/3] hw/misc/aspeed_sbc: Fix ABR and secure boot state reporting Cédric Le Goater
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260918065347.3713868-3-kane_chen@aspeedtech.com \
--to=kane_chen@aspeedtech.com \
--cc=andrew@codeconstruct.com.au \
--cc=clg@kaod.org \
--cc=jamin_lin@aspeedtech.com \
--cc=joel@jms.id.au \
--cc=leetroy@gmail.com \
--cc=peter.maydell@linaro.org \
--cc=qemu-arm@nongnu.org \
--cc=qemu-devel@nongnu.org \
--cc=steven_lee@aspeedtech.com \
--cc=troy_lee@aspeedtech.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.