All of lore.kernel.org
 help / color / mirror / Atom feed
From: "Cédric Le Goater" <clg@redhat.com>
To: qemu-arm@nongnu.org, qemu-devel@nongnu.org
Cc: "Kane Chen" <kane_chen@aspeedtech.com>,
	"Cédric Le Goater" <clg@redhat.com>
Subject: [PULL 04/21] hw/misc/aspeed_sbc: Derive ABR state from OTP config straps
Date: Thu, 15 Oct 2026 14:21:34 +0200	[thread overview]
Message-ID: <20261015122151.889017-5-clg@redhat.com> (raw)
In-Reply-To: <20261015122151.889017-1-clg@redhat.com>

From: Kane Chen <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>
Reviewed-by: Cédric Le Goater <clg@redhat.com>
Link: https://lore.kernel.org/qemu-devel/20260918065347.3713868-3-kane_chen@aspeedtech.com
Signed-off-by: Cédric Le Goater <clg@redhat.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 756c61235697..b210ffb8aa86 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 2b6c2eaaa353..f91af12ea9ef 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 3402cef5c3ec..6cec9ad3daf0 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 81304bda3abe..127da15642f2 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.56.0



  parent reply	other threads:[~2026-10-15 12:23 UTC|newest]

Thread overview: 23+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-10-15 12:21 [PULL 00/21] aspeed queue Cédric Le Goater
2026-10-15 12:21 ` [PULL 01/21] hw/misc/aspeed_hace: Fix OOB read in has_padding() Cédric Le Goater
2026-10-15 12:21 ` [PULL 02/21] tests/qtest/aspeed-acry: Allocate SRAM buffers on the heap Cédric Le Goater
2026-10-15 12:21 ` [PULL 03/21] hw/nvram/aspeed_otp, hw/misc/aspeed_sbc: Consolidate OTP layout definitions Cédric Le Goater
2026-10-15 12:21 ` Cédric Le Goater [this message]
2026-10-15 12:21 ` [PULL 05/21] hw/misc/aspeed_sbc: Derive secure boot state from OTP config Cédric Le Goater
2026-10-15 12:21 ` [PULL 06/21] hw/arm/aspeed: Sort device IDs alphabetically Cédric Le Goater
2026-10-15 12:21 ` [PULL 07/21] tests/functional/aarch64/test_aspeed_ast2700a2: Add I2C test for IO expander 1 Cédric Le Goater
2026-10-15 12:21 ` [PULL 08/21] MAINTAINERS: Update ASPEED BMCs reviewers Cédric Le Goater
2026-10-15 12:21 ` [PULL 09/21] hw/misc/unimp: Add create_unimplemented_devices() helper Cédric Le Goater
2026-10-15 12:21 ` [PULL 10/21] hw/arm/aspeed_ast2400: Use a table for unimplemented devices Cédric Le Goater
2026-10-15 12:21 ` [PULL 11/21] hw/arm/aspeed_ast2600: " Cédric Le Goater
2026-10-15 12:21 ` [PULL 12/21] hw/arm/aspeed_ast27x0: " Cédric Le Goater
2026-10-15 12:21 ` [PULL 13/21] hw/arm/aspeed_ast10x0: " Cédric Le Goater
2026-10-15 12:21 ` [PULL 14/21] hw/arm/aspeed_ast1040: " Cédric Le Goater
2026-10-15 12:21 ` [PULL 15/21] hw/arm/aspeed: Remove unused unimplemented device fields Cédric Le Goater
2026-10-15 12:21 ` [PULL 16/21] hw/arm/aspeed_ast27x0: Use a table for unimplemented devices for SSP/TSP Cédric Le Goater
2026-10-15 12:21 ` [PULL 17/21] hw/arm/aspeed_coprocessor: Remove unused unimplemented device fields Cédric Le Goater
2026-10-15 12:21 ` [PULL 18/21] hw/arm/aspeed_ast1700: Use a table for unimplemented devices Cédric Le Goater
2026-10-15 12:21 ` [PULL 19/21] hw/arm/aspeed_ast1700: Remove unused unimplemented device field Cédric Le Goater
2026-10-15 12:21 ` [PULL 20/21] hw/arm/aspeed: Remove unused aspeed_mmio_map_unimplemented() Cédric Le Goater
2026-10-15 12:21 ` [PULL 21/21] tests/functional: give the set_machine probe VM the test workdir Cédric Le Goater
2026-10-15 14:55 ` [PULL 00/21] aspeed queue Richard Henderson

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=20261015122151.889017-5-clg@redhat.com \
    --to=clg@redhat.com \
    --cc=kane_chen@aspeedtech.com \
    --cc=qemu-arm@nongnu.org \
    --cc=qemu-devel@nongnu.org \
    /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.