On 8/12/25 11:40, Kane Chen wrote:
> From: Kane-Chen-AS <kane_chen@aspeedtech.com>
>
> Extend OTP command handling to recognize specific voltage mode register
> addresses and emulate the expected hardware behavior. Without this
> change, legitimate voltage mode change requests would be incorrectly
> reported as "Unknown command" and logged as an error.
>
> This implementation does not perform actual mode changes, but ensures
> that valid requests are accepted and ignored as per hardware behavior.
>
> Signed-off-by: Kane-Chen-AS <kane_chen@aspeedtech.com>
Reviewed-by: Cédric Le Goater <clg@redhat.com>
Thanks,
C.
> ---
> hw/misc/aspeed_sbc.c | 41 +++++++++++++++++++++++++++++++++++++++++
> hw/misc/trace-events | 1 +
> 2 files changed, 42 insertions(+)
>
> diff --git a/hw/misc/aspeed_sbc.c b/hw/misc/aspeed_sbc.c
> index 787e2d0489..2fc5db749d 100644
> --- a/hw/misc/aspeed_sbc.c
> +++ b/hw/misc/aspeed_sbc.c
> @@ -49,10 +49,17 @@
> #define OTP_MEMORY_SIZE 0x4000
> /* OTP command */
> #define SBC_OTP_CMD_READ 0x23b1e361
> +#define SBC_OTP_CMD_WRITE 0x23b1e362
> #define SBC_OTP_CMD_PROG 0x23b1e364
>
> #define OTP_DATA_DWORD_COUNT (0x800)
> #define OTP_TOTAL_DWORD_COUNT (0x1000)
> +
> +/* Voltage mode */
> +#define MODE_REGISTER (0x1000)
> +#define MODE_REGISTER_A (0x3000)
> +#define MODE_REGISTER_B (0x5000)
> +
> static uint64_t aspeed_sbc_read(void *opaque, hwaddr addr, unsigned int size)
> {
> AspeedSBCState *s = ASPEED_SBC(opaque);
> @@ -115,6 +122,37 @@ static bool aspeed_sbc_otp_read(AspeedSBCState *s,
> return true;
> }
>
> +static bool mode_handler(uint32_t otp_addr)
> +{
> + switch (otp_addr) {
> + case MODE_REGISTER:
> + case MODE_REGISTER_A:
> + case MODE_REGISTER_B:
> + /* HW behavior, do nothing here */
> + return true;
> + default:
> + qemu_log_mask(LOG_GUEST_ERROR,
> + "Unsupported address 0x%x\n",
> + otp_addr);
> + return false;
> + }
> +}
> +
> +static bool aspeed_sbc_otp_write(AspeedSBCState *s,
> + uint32_t otp_addr)
> +{
> + if (otp_addr == 0) {
> + trace_aspeed_sbc_ignore_cmd(otp_addr);
> + return true;
> + } else {
> + if (mode_handler(otp_addr) == false) {
> + return false;
> + }
> + }
> +
> + return true;
> +}
> +
> static bool aspeed_sbc_otp_prog(AspeedSBCState *s,
> uint32_t otp_addr)
> {
> @@ -157,6 +195,9 @@ static void aspeed_sbc_handle_command(void *opaque, uint32_t cmd)
> case SBC_OTP_CMD_READ:
> ret = aspeed_sbc_otp_read(s, otp_addr);
> break;
> + case SBC_OTP_CMD_WRITE:
> + ret = aspeed_sbc_otp_write(s, otp_addr);
> + break;
> case SBC_OTP_CMD_PROG:
> ret = aspeed_sbc_otp_prog(s, otp_addr);
> break;
> diff --git a/hw/misc/trace-events b/hw/misc/trace-events
> index 9e05b82f37..eeb9243898 100644
> --- a/hw/misc/trace-events
> +++ b/hw/misc/trace-events
> @@ -91,6 +91,7 @@ slavio_led_mem_writew(uint32_t val) "Write diagnostic LED 0x%04x"
> slavio_led_mem_readw(uint32_t ret) "Read diagnostic LED 0x%04x"
>
> # aspeed_sbc.c
> +aspeed_sbc_ignore_cmd(uint32_t cmd) "Ignoring command 0x%" PRIx32
> aspeed_sbc_handle_cmd(uint32_t cmd, uint32_t addr, bool ret) "Handling command 0x%" PRIx32 " for OTP addr 0x%" PRIx32 " Result: %d"
> aspeed_sbc_otp_read(uint32_t addr, uint32_t value) "OTP Memory read: addr 0x%" PRIx32 " value 0x%" PRIx32
> aspeed_sbc_otp_prog(uint32_t addr, uint32_t value) "OTP Memory write: addr 0x%" PRIx32 " value 0x%" PRIx32