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 <[email protected]> --- 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
