From nobody Mon Feb 9 15:35:32 2026 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass(p=none dis=none) header.from=nongnu.org ARC-Seal: i=1; a=rsa-sha256; t=1745377132; cv=none; d=zohomail.com; s=zohoarc; b=iSEKklvOkBLWejSEPR55F4XE6+CY2263YEkaNdOntqugESj1yNXdKCrhtxEiB1mhWPbJUY3aWSrRtcDRu/QFkxqyRwQA7VmVPB3ov1K0iDG2ZmaNHiU7PK2twvwVYBBK73DbRZ+/WBQxdAsAYTdYRwXwn+qKfw9yHsYh5midS20= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1745377132; h=Content-Type:Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:Reply-To:Reply-To:References:Sender:Subject:Subject:To:To:Message-Id; bh=r33nPRQHCna6qxJYb12rS42rb9sSGAOT+oN+FJNY0IA=; b=F3eVy9XxkALU1llnwgNXldxFz/8Huwt9TVeqNwVMSgWmnK9KGjlAOxfO0Y6ezCfv1Jl3yI7lmBAvHq5nnWHU1txH3A6pFQxC2U2GYDNk0jWh6naJy/Mm+bpVhkzX0mMhg4EEKmXGd+fwYAAjQx3rg73mBiOVH1Z+DqVe4ehrASI= ARC-Authentication-Results: i=1; mx.zohomail.com; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass header.from= (p=none dis=none) Return-Path: Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 17453771320591010.1498961180499; Tue, 22 Apr 2025 19:58:52 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1u7QIa-0007GN-PD; Tue, 22 Apr 2025 22:57:20 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1u7QIO-0007Bk-J7; Tue, 22 Apr 2025 22:57:11 -0400 Received: from mail.aspeedtech.com ([211.20.114.72] helo=TWMBX01.aspeed.com) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1u7QIM-00043I-Cm; Tue, 22 Apr 2025 22:57:08 -0400 Received: from TWMBX01.aspeed.com (192.168.0.62) by TWMBX01.aspeed.com (192.168.0.62) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.1258.12; Wed, 23 Apr 2025 10:56:52 +0800 Received: from mail.aspeedtech.com (192.168.10.10) by TWMBX01.aspeed.com (192.168.0.62) with Microsoft SMTP Server id 15.2.1258.12 via Frontend Transport; Wed, 23 Apr 2025 10:56:52 +0800 To: =?UTF-8?q?C=C3=A9dric=20Le=20Goater?= , Peter Maydell , Steven Lee , Troy Lee , Jamin Lin , Andrew Jeffery , Joel Stanley , "open list:ASPEED BMCs" , "open list:All patches CC here" CC: , Kane-Chen-AS Subject: [PATCH v3 1/3] hw/misc/aspeed_otp: Add Aspeed OTP memory device model Date: Wed, 23 Apr 2025 10:56:49 +0800 Message-ID: <20250423025651.189702-2-kane_chen@aspeedtech.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20250423025651.189702-1-kane_chen@aspeedtech.com> References: <20250423025651.189702-1-kane_chen@aspeedtech.com> MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Received-SPF: pass client-ip=211.20.114.72; envelope-from=kane_chen@aspeedtech.com; helo=TWMBX01.aspeed.com X-Spam_score_int: -18 X-Spam_score: -1.9 X-Spam_bar: - X-Spam_report: (-1.9 / 5.0 requ) BAYES_00=-1.9, RCVD_IN_VALIDITY_CERTIFIED_BLOCKED=0.001, RCVD_IN_VALIDITY_RPBL_BLOCKED=0.001, SPF_HELO_FAIL=0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Reply-to: Kane Chen From: Kane Chen via Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org X-ZM-MESSAGEID: 1745377134527019100 From: Kane-Chen-AS This introduces a new model for the ASPEED OTP (One-Time Programmable) memory. The device is implemented as a `SysBusDevice` and provides an abstracted interface for OTP read, write (program), and default value initialization. OTP content is backed by a block device and supports QEMU=E2=80=99s drive infrastructure via the "drive" property. Features: - Enforces irreversible bit programming logic (0->1 or 1->0) - Provides interface for SoC/secure controller integration - Validates bounds and bit-level constraints - Uses QEMU error handling conventions and logging Signed-off-by: Kane-Chen-AS --- hw/misc/aspeed_otpmem.c | 211 ++++++++++++++++++++++++++++++++ hw/misc/meson.build | 1 + include/hw/misc/aspeed_otpmem.h | 40 ++++++ 3 files changed, 252 insertions(+) create mode 100644 hw/misc/aspeed_otpmem.c create mode 100644 include/hw/misc/aspeed_otpmem.h diff --git a/hw/misc/aspeed_otpmem.c b/hw/misc/aspeed_otpmem.c new file mode 100644 index 0000000000..4f8f2827f7 --- /dev/null +++ b/hw/misc/aspeed_otpmem.c @@ -0,0 +1,211 @@ +/* + * ASPEED OTP (One-Time Programmable) memory + * + * Copyright (C) 2025 Aspeed + * + * This code is licensed under the GPL version 2 or later. See + * the COPYING file in the top-level directory. + */ + +#include "qemu/osdep.h" +#include "hw/block/block.h" +#include "hw/block/flash.h" +#include "hw/qdev-properties.h" +#include "hw/qdev-properties-system.h" +#include "system/block-backend.h" +#include "qemu/log.h" +#include "qemu/option.h" +#include "hw/sysbus.h" +#include "qemu/error-report.h" +#include "hw/misc/aspeed_otpmem.h" + +static const Property aspeed_otpmem_properties[] =3D { + DEFINE_PROP_DRIVE("drive", AspeedOTPMemState, blk), +}; + +static void aspeed_otpmem_read(void *opaque, uint32_t addr, + uint32_t *out, Error **errp) +{ + AspeedOTPMemState *otp =3D ASPEED_OTPMEM(opaque); + + assert(otp->blk); + + if (out =3D=3D NULL) { + error_setg(errp, "out is NULL"); + return; + } + + if (addr > (otp->max_size - 4)) { + error_setg(errp, "OTP memory 0x%x is exceeded", addr); + return; + } + + if (blk_pread(otp->blk, (int64_t)addr, sizeof(uint32_t), out, 0) < 0) { + error_setg(errp, "Failed to read data 0x%x", addr); + return; + } + return; +} + +static bool valid_program_data(uint32_t otp_addr, + uint32_t value, uint32_t prog_bit) +{ + uint32_t programmed_bits, has_programmable_bits; + bool is_odd =3D otp_addr & 1; + + /* + * prog_bit uses 0s to indicate target bits to program: + * - if OTP word is even-indexed, programmed bits flip 0->1 + * - if odd, bits flip 1->0 + * Bit programming is one-way only and irreversible. + */ + if (is_odd) { + programmed_bits =3D ~value & prog_bit; + } else { + programmed_bits =3D value & (~prog_bit); + } + + /* If there is some bit can be programed, to accept the request */ + has_programmable_bits =3D value ^ (~prog_bit); + + if (programmed_bits) { + qemu_log_mask(LOG_GUEST_ERROR, + "%s: Found programmed bits in addr %x\n", + __func__, otp_addr); + for (int i =3D 0; i < 32; ++i) { + if (programmed_bits & (1U << i)) { + qemu_log_mask(LOG_GUEST_ERROR, + " Programmed bit %d\n", + i); + } + } + } + + return has_programmable_bits !=3D 0; +} + +static bool program_otpmem_data(void *opaque, uint32_t otp_addr, + uint32_t prog_bit, uint32_t *value) +{ + AspeedOTPMemState *s =3D ASPEED_OTPMEM(opaque); + bool is_odd =3D otp_addr & 1; + uint32_t otp_offset =3D otp_addr << 2; + + if (blk_pread(s->blk, (int64_t)otp_offset, + sizeof(uint32_t), value, 0) < 0) { + qemu_log_mask(LOG_GUEST_ERROR, + "%s: Failed to read data 0x%x\n", + __func__, otp_offset); + return false; + } + + if (!valid_program_data(otp_addr, *value, prog_bit)) { + return false; + } + + if (is_odd) { + *value &=3D ~prog_bit; + } else { + *value |=3D ~prog_bit; + } + + return true; +} + +static void aspeed_otpmem_prog(void *s, uint32_t otp_addr, + uint32_t data, Error **errp) +{ + AspeedOTPMemState *otp =3D ASPEED_OTPMEM(s); + uint32_t otp_offset, value; + + assert(otp->blk); + + if (otp_addr > (otp->max_size >> 2)) { + error_setg(errp, "OTP memory 0x%x is exceeded", otp_addr); + return; + } + + otp_offset =3D otp_addr << 2; + if (!program_otpmem_data(s, otp_addr, data, &value)) { + error_setg(errp, "Failed to program data"); + return; + } + + if (blk_pwrite(otp->blk, (int64_t)otp_offset, + sizeof(value), &value, 0) < 0) { + error_setg(errp, "Failed to write data"); + } + + return; +} + +static void aspeed_otpmem_set_default(void *s, uint32_t otp_offset, + uint32_t data, Error **errp) +{ + AspeedOTPMemState *otp =3D ASPEED_OTPMEM(s); + + if ((otp_offset + 4) > otp->max_size) { + error_setg(errp, "OTP memory 0x%x is exceeded", otp_offset); + return; + } + + if (blk_pwrite(otp->blk, (int64_t)otp_offset, + sizeof(data), &data, 0) < 0) { + error_setg(errp, "Failed to write data"); + } + return; +} + +static AspeedOTPMemOps aspeed_otpmem_ops =3D { + .read =3D aspeed_otpmem_read, + .prog =3D aspeed_otpmem_prog, + .set_default_value =3D aspeed_otpmem_set_default +}; + +static void aspeed_otpmem_realize(DeviceState *dev, Error **errp) +{ + AspeedOTPMemState *s =3D ASPEED_OTPMEM(dev); + + if (!s->blk) { + error_setg(&error_fatal, "OTP memory is not initialized"); + return; + } + + s->max_size =3D blk_getlength(s->blk); + if (s->max_size < 0 || (s->max_size % 4)) { + error_setg(&error_fatal, + "Unexpected OTP memory size: %" PRId64 "", + s->max_size); + return; + } + + s->ops =3D &aspeed_otpmem_ops; + + return; +} + +static void aspeed_otpmem_system_reset(DeviceState *dev) +{ + return; +} + +static void aspeed_otpmem_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc =3D DEVICE_CLASS(klass); + + device_class_set_legacy_reset(dc, aspeed_otpmem_system_reset); + dc->realize =3D aspeed_otpmem_realize; + device_class_set_props(dc, aspeed_otpmem_properties); + +} + +static const TypeInfo aspeed_otpmem_types[] =3D { + { + .name =3D TYPE_ASPEED_OTPMEM, + .parent =3D TYPE_SYS_BUS_DEVICE, + .instance_size =3D sizeof(AspeedOTPMemState), + .class_init =3D aspeed_otpmem_class_init, + }, +}; + +DEFINE_TYPES(aspeed_otpmem_types) diff --git a/hw/misc/meson.build b/hw/misc/meson.build index 6d47de482c..ed1eaaa2ad 100644 --- a/hw/misc/meson.build +++ b/hw/misc/meson.build @@ -136,6 +136,7 @@ system_ss.add(when: 'CONFIG_ASPEED_SOC', if_true: files( 'aspeed_sbc.c', 'aspeed_sdmc.c', 'aspeed_xdma.c', + 'aspeed_otpmem.c', 'aspeed_peci.c', 'aspeed_sli.c')) =20 diff --git a/include/hw/misc/aspeed_otpmem.h b/include/hw/misc/aspeed_otpme= m.h new file mode 100644 index 0000000000..11e2de70b6 --- /dev/null +++ b/include/hw/misc/aspeed_otpmem.h @@ -0,0 +1,40 @@ +/* + * ASPEED OTP (One-Time Programmable) memory + * + * Copyright (C) 2025 Aspeed + * + * This code is licensed under the GPL version 2 or later. See + * the COPYING file in the top-level directory. + */ + +#ifndef ASPEED_OTPMMEM_H +#define ASPEED_OTPMMEM_H + +#include "hw/sysbus.h" +#include "qapi/error.h" + +#define TYPE_ASPEED_OTPMEM "aspeed.otpmem" +#define ASPEED_OTPMEM_DRIVE "otpmem" + +#define ASPEED_OTPMEM(obj) OBJECT_CHECK(AspeedOTPMemState, (obj), \ + TYPE_ASPEED_OTPMEM) + +typedef struct AspeedOTPMemOps { + void (*read)(void *s, uint32_t addr, uint32_t *out, Error **errp); + void (*prog)(void *s, uint32_t addr, uint32_t data, Error **errp); + void (*set_default_value)(void *s, uint32_t otp_offset, + uint32_t data, Error **errp); +} AspeedOTPMemOps; + +typedef struct AspeedOTPMemState { + SysBusDevice parent_obj; + + MemoryRegion mmio; + BlockBackend *blk; + int64_t max_size; + + AspeedOTPMemOps *ops; +} AspeedOTPMemState; + +#endif /* ASPEED_OTPMMEM_H */ + --=20 2.43.0 From nobody Mon Feb 9 15:35:32 2026 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass(p=none dis=none) header.from=nongnu.org ARC-Seal: i=1; a=rsa-sha256; t=1745377131; cv=none; d=zohomail.com; s=zohoarc; b=VScPxlSk4h31OTT51nAcw5dQKw6eLDghSI+DD9yo4s/96rnecbhNYamsuC8WjMwYGeeg5uyguwLTaExUdMAI1MdfJ27sG6i36mweTEmjL6fiVQza8ByWEyMpKXNBjzfwSb8vpsTP91aDBYETlBDjRmy/8O5OuObXUvmGFKjuEbQ= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1745377131; h=Content-Type:Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:Reply-To:Reply-To:References:Sender:Subject:Subject:To:To:Message-Id; bh=rt7AjKchMlIw1yCZkqrgH15uykh1a7IHLLodkjTUHLc=; b=LpeNksvGJ2zJGMWp9NxNrPns0eSboew7ugMK0jygPQchPfn8pq9k1DqonA9ZgdnJ/iBQCk/fvAwEZimynqY0Zxk3bV/z5oAAetCytarLL8HkSWDCWRrvZDopz5p9JoO0A8Dac4l6ZI9qOYmoAqjDuKcv8+wXUY5r7+XnQp0Nwo0= ARC-Authentication-Results: i=1; mx.zohomail.com; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass header.from= (p=none dis=none) Return-Path: Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 17453771311621.336032693305242; Tue, 22 Apr 2025 19:58:51 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1u7QIZ-0007FI-QM; Tue, 22 Apr 2025 22:57:19 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1u7QIS-0007C4-83; Tue, 22 Apr 2025 22:57:13 -0400 Received: from mail.aspeedtech.com ([211.20.114.72] helo=TWMBX01.aspeed.com) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1u7QIQ-00043I-5S; Tue, 22 Apr 2025 22:57:11 -0400 Received: from TWMBX01.aspeed.com (192.168.0.62) by TWMBX01.aspeed.com (192.168.0.62) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.1258.12; Wed, 23 Apr 2025 10:56:52 +0800 Received: from mail.aspeedtech.com (192.168.10.10) by TWMBX01.aspeed.com (192.168.0.62) with Microsoft SMTP Server id 15.2.1258.12 via Frontend Transport; Wed, 23 Apr 2025 10:56:52 +0800 To: =?UTF-8?q?C=C3=A9dric=20Le=20Goater?= , Peter Maydell , Steven Lee , Troy Lee , Jamin Lin , Andrew Jeffery , Joel Stanley , "open list:ASPEED BMCs" , "open list:All patches CC here" CC: , Kane-Chen-AS Subject: [PATCH v3 2/3] hw/misc/aspeed_sbc: Connect Aspeed OTP memory device to SBC controller Date: Wed, 23 Apr 2025 10:56:50 +0800 Message-ID: <20250423025651.189702-3-kane_chen@aspeedtech.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20250423025651.189702-1-kane_chen@aspeedtech.com> References: <20250423025651.189702-1-kane_chen@aspeedtech.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Received-SPF: pass client-ip=211.20.114.72; envelope-from=kane_chen@aspeedtech.com; helo=TWMBX01.aspeed.com X-Spam_score_int: -18 X-Spam_score: -1.9 X-Spam_bar: - X-Spam_report: (-1.9 / 5.0 requ) BAYES_00=-1.9, RCVD_IN_VALIDITY_CERTIFIED_BLOCKED=0.001, RCVD_IN_VALIDITY_RPBL_BLOCKED=0.001, SPF_HELO_FAIL=0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Reply-to: Kane Chen From: Kane Chen via Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org X-ZM-MESSAGEID: 1745377132467019100 Content-Type: text/plain; charset="utf-8" From: Kane-Chen-AS This patch integrates the `aspeed.otpmem` device with the ASPEED Secure Boot Controller (SBC). The SBC now accepts an OTP backend via a QOM link property ("otpmem"), enabling internal access to OTP content for controller-specific logic. This connection provides the foundation for future enhancements involving fuse storage, device configuration, or secure manufacturing data provisioning. Signed-off-by: Kane-Chen-AS --- hw/misc/aspeed_sbc.c | 146 +++++++++++++++++++++++++++++++++++ include/hw/misc/aspeed_sbc.h | 15 ++++ 2 files changed, 161 insertions(+) diff --git a/hw/misc/aspeed_sbc.c b/hw/misc/aspeed_sbc.c index e4a6bd1581..f0ce7bbdf0 100644 --- a/hw/misc/aspeed_sbc.c +++ b/hw/misc/aspeed_sbc.c @@ -17,7 +17,11 @@ #include "migration/vmstate.h" =20 #define R_PROT (0x000 / 4) +#define R_CMD (0x004 / 4) +#define R_ADDR (0x010 / 4) #define R_STATUS (0x014 / 4) +#define R_CAMP1 (0x020 / 4) +#define R_CAMP2 (0x024 / 4) #define R_QSR (0x040 / 4) =20 /* R_STATUS */ @@ -57,6 +61,143 @@ static uint64_t aspeed_sbc_read(void *opaque, hwaddr ad= dr, unsigned int size) return s->regs[addr]; } =20 +static void aspeed_sbc_otpmem_read(void *opaque) +{ + AspeedSBCState *s =3D ASPEED_SBC(opaque); + uint32_t otp_addr, data, otp_offset; + bool is_data =3D false; + Error *local_err =3D NULL; + + assert(s->otpmem); + + otp_addr =3D s->regs[R_ADDR]; + if (otp_addr < OTP_DATA_DWORD_COUNT) { + is_data =3D true; + } else if (otp_addr >=3D OTP_TOTAL_DWORD_COUNT) { + qemu_log_mask(LOG_GUEST_ERROR, + "%s: Invalid OTP addr 0x%x\n", + __func__, otp_addr); + return; + } + otp_offset =3D otp_addr << 2; + + s->otpmem->ops->read(s->otpmem, otp_offset, &data, &local_err); + if (local_err) { + qemu_log_mask(LOG_GUEST_ERROR, + "%s: Failed to read data 0x%x, %s\n", + __func__, otp_offset, + error_get_pretty(local_err)); + error_free(local_err); + return; + } + s->regs[R_CAMP1] =3D data; + + if (is_data) { + s->otpmem->ops->read(s->otpmem, otp_offset + 4, &data, &local_err); + if (local_err) { + qemu_log_mask(LOG_GUEST_ERROR, + "%s: Failed to read data 0x%x, %s\n", + __func__, otp_offset, + error_get_pretty(local_err)); + error_free(local_err); + return; + } + s->regs[R_CAMP2] =3D data; + } +} + +static void mr_handler(uint32_t otp_addr, uint32_t data) +{ + switch (otp_addr) { + case MODE_REGISTER: + case MODE_REGISTER_A: + case MODE_REGISTER_B: + /* HW behavior, do nothing here */ + break; + default: + qemu_log_mask(LOG_GUEST_ERROR, + "%s: Unsupported address 0x%x\n", + __func__, otp_addr); + return; + } +} + +static void aspeed_sbc_otpmem_write(void *opaque) +{ + AspeedSBCState *s =3D ASPEED_SBC(opaque); + uint32_t otp_addr, data; + + otp_addr =3D s->regs[R_ADDR]; + data =3D s->regs[R_CAMP1]; + + if (otp_addr =3D=3D 0) { + qemu_log_mask(LOG_GUEST_ERROR, + "%s: ignore write program bit request\n", + __func__); + } else if (otp_addr >=3D MODE_REGISTER) { + mr_handler(otp_addr, data); + } else { + qemu_log_mask(LOG_GUEST_ERROR, + "%s: Unhandled OTP write address 0x%x\n", + __func__, otp_addr); + } +} + +static void aspeed_sbc_otpmem_prog(void *opaque) +{ + AspeedSBCState *s =3D ASPEED_SBC(opaque); + uint32_t otp_addr, value; + Error *local_err =3D NULL; + + assert(s->otpmem); + + otp_addr =3D s->regs[R_ADDR]; + value =3D s->regs[R_CAMP1]; + if (otp_addr >=3D OTP_TOTAL_DWORD_COUNT) { + qemu_log_mask(LOG_GUEST_ERROR, + "%s: Invalid OTP addr 0x%x\n", + __func__, otp_addr); + return; + } + + s->otpmem->ops->prog(s->otpmem, otp_addr, value, &local_err); + if (local_err) { + qemu_log_mask(LOG_GUEST_ERROR, + "%s: Failed to program data 0x%x to 0x%x, %s\n", + __func__, value, otp_addr, + error_get_pretty(local_err)); + error_free(local_err); + return; + } +} + +static void aspeed_sbc_handle_command(void *opaque, uint32_t cmd) +{ + AspeedSBCState *s =3D ASPEED_SBC(opaque); + + s->regs[R_STATUS] &=3D ~(OTP_MEM_IDLE | OTP_IDLE); + + switch (cmd) { + case READ_CMD: + aspeed_sbc_otpmem_read(s); + break; + case WRITE_CMD: + aspeed_sbc_otpmem_write(s); + break; + case PROG_CMD: + aspeed_sbc_otpmem_prog(s); + break; + default: + qemu_log_mask(LOG_GUEST_ERROR, + "%s: Unknown command 0x%x\n", + __func__, cmd); + break; + } + + s->regs[R_STATUS] |=3D (OTP_MEM_IDLE | OTP_IDLE); +} + + static void aspeed_sbc_write(void *opaque, hwaddr addr, uint64_t data, unsigned int size) { @@ -78,6 +219,9 @@ static void aspeed_sbc_write(void *opaque, hwaddr addr, = uint64_t data, "%s: write to read only register 0x%" HWADDR_PRIx "\= n", __func__, addr << 2); return; + case R_CMD: + aspeed_sbc_handle_command(opaque, data); + return; default: break; } @@ -139,6 +283,8 @@ static const VMStateDescription vmstate_aspeed_sbc =3D { static const Property aspeed_sbc_properties[] =3D { DEFINE_PROP_BOOL("emmc-abr", AspeedSBCState, emmc_abr, 0), DEFINE_PROP_UINT32("signing-settings", AspeedSBCState, signing_setting= s, 0), + DEFINE_PROP_LINK("otpmem", AspeedSBCState, otpmem, + TYPE_ASPEED_OTPMEM, AspeedOTPMemState *), }; =20 static void aspeed_sbc_class_init(ObjectClass *klass, void *data) diff --git a/include/hw/misc/aspeed_sbc.h b/include/hw/misc/aspeed_sbc.h index 405e6782b9..8ae59d977e 100644 --- a/include/hw/misc/aspeed_sbc.h +++ b/include/hw/misc/aspeed_sbc.h @@ -10,6 +10,7 @@ #define ASPEED_SBC_H =20 #include "hw/sysbus.h" +#include "hw/misc/aspeed_otpmem.h" =20 #define TYPE_ASPEED_SBC "aspeed.sbc" #define TYPE_ASPEED_AST2600_SBC TYPE_ASPEED_SBC "-ast2600" @@ -27,6 +28,18 @@ OBJECT_DECLARE_TYPE(AspeedSBCState, AspeedSBCClass, ASPE= ED_SBC) #define QSR_SHA384 (0x2 << 10) #define QSR_SHA512 (0x3 << 10) =20 +#define READ_CMD (0x23b1e361) +#define WRITE_CMD (0x23b1e362) +#define PROG_CMD (0x23b1e364) + +#define OTP_DATA_DWORD_COUNT (0x800) +#define OTP_TOTAL_DWORD_COUNT (0x1000) +#define OTP_FILE_SIZE (OTP_TOTAL_DWORD_COUNT * sizeof(uint32= _t)) + +#define MODE_REGISTER (0x1000) +#define MODE_REGISTER_A (0x3000) +#define MODE_REGISTER_B (0x5000) + struct AspeedSBCState { SysBusDevice parent; =20 @@ -36,6 +49,8 @@ struct AspeedSBCState { MemoryRegion iomem; =20 uint32_t regs[ASPEED_SBC_NR_REGS]; + + AspeedOTPMemState *otpmem; }; =20 struct AspeedSBCClass { --=20 2.43.0 From nobody Mon Feb 9 15:35:32 2026 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass(p=none dis=none) header.from=nongnu.org ARC-Seal: i=1; a=rsa-sha256; t=1745377103; cv=none; d=zohomail.com; s=zohoarc; b=YyTknQQxIF7Drmo/qTv5x95n37bNHgEpuEXZjoAs+vVu16yp0HXy92qy7iP0o2TSNJINdua9udSonS/NpZaEUvM3C7TxK/cyam4CyyFJ6luHxOXs267uS+RGk1mF1A5bEdQsgIkO4AYafiGyw+WngIS1u0sthjPDmvKIUTxESU0= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1745377103; h=Content-Type:Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:Reply-To:Reply-To:References:Sender:Subject:Subject:To:To:Message-Id; bh=bUjj155XiSLYxlUcyB10Xn0j4Ei6lEwpy/78j8RI4OU=; b=OLwA1FVtuZelG+Zm3dEhbKGFrk+YP8NRYkWvn6SsR4wIVZdv6ZdylKgJ9m/mAgAeJi0oZNdlGi9oQ1XO50VAHQy13bLMYA/U1CqkqUPuZYOwJQNzilAMpan8S4EbdA0Lc/+L9uNQjsNXhOnXhRlXN0x+qXzhz4tDu2zLlh9/fdg= ARC-Authentication-Results: i=1; mx.zohomail.com; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass header.from= (p=none dis=none) Return-Path: Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1745377103889633.2885381603681; Tue, 22 Apr 2025 19:58:23 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1u7QIb-0007HC-QR; Tue, 22 Apr 2025 22:57:21 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1u7QIV-0007Dd-CT; Tue, 22 Apr 2025 22:57:15 -0400 Received: from mail.aspeedtech.com ([211.20.114.72] helo=TWMBX01.aspeed.com) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1u7QIT-00043I-9V; Tue, 22 Apr 2025 22:57:15 -0400 Received: from TWMBX01.aspeed.com (192.168.0.62) by TWMBX01.aspeed.com (192.168.0.62) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.1258.12; Wed, 23 Apr 2025 10:56:52 +0800 Received: from mail.aspeedtech.com (192.168.10.10) by TWMBX01.aspeed.com (192.168.0.62) with Microsoft SMTP Server id 15.2.1258.12 via Frontend Transport; Wed, 23 Apr 2025 10:56:52 +0800 To: =?UTF-8?q?C=C3=A9dric=20Le=20Goater?= , Peter Maydell , Steven Lee , Troy Lee , Jamin Lin , Andrew Jeffery , Joel Stanley , "open list:ASPEED BMCs" , "open list:All patches CC here" CC: , Kane-Chen-AS Subject: [PATCH v3 3/3] hw/arm: Integrate Aspeed OTP memory into AST10x0 and AST2600 SoCs Date: Wed, 23 Apr 2025 10:56:51 +0800 Message-ID: <20250423025651.189702-4-kane_chen@aspeedtech.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20250423025651.189702-1-kane_chen@aspeedtech.com> References: <20250423025651.189702-1-kane_chen@aspeedtech.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Received-SPF: pass client-ip=211.20.114.72; envelope-from=kane_chen@aspeedtech.com; helo=TWMBX01.aspeed.com X-Spam_score_int: -18 X-Spam_score: -1.9 X-Spam_bar: - X-Spam_report: (-1.9 / 5.0 requ) BAYES_00=-1.9, RCVD_IN_VALIDITY_CERTIFIED_BLOCKED=0.001, RCVD_IN_VALIDITY_RPBL_BLOCKED=0.001, SPF_HELO_FAIL=0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Reply-to: Kane Chen From: Kane Chen via Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org X-ZM-MESSAGEID: 1745377108300019100 Content-Type: text/plain; charset="utf-8" From: Kane-Chen-AS This patch wires up the OTP memory device (`aspeed.otpmem`) into the AST1030 and AST2600 SoC models. The device is initialized, attached to a backing block drive (`-drive id=3Dotpmem`) and linked to the SBC controller via a QOM link. The default OTP memory image can be generated using the following command. ```bash for i in $(seq 1 2048); do printf '\x00\x00\x00\x00\xff\xff\xff\xff' done > otpmem.img ``` To load the OTP memory image into the guest, use: ```bash ./qemu-system-arm \ -drive id=3Dotpmem,file=3Dotpmem.img,if=3Dnone,format=3Draw \ ... ``` Note: Do not use the -snapshot option, or OTP data writes will not persist to the image file. Signed-off-by: Kane-Chen-AS --- hw/arm/aspeed_ast10x0.c | 19 +++++++++++++++++++ hw/arm/aspeed_ast2600.c | 19 +++++++++++++++++++ include/hw/arm/aspeed_soc.h | 2 ++ 3 files changed, 40 insertions(+) diff --git a/hw/arm/aspeed_ast10x0.c b/hw/arm/aspeed_ast10x0.c index ec329f4991..eaa70feb9f 100644 --- a/hw/arm/aspeed_ast10x0.c +++ b/hw/arm/aspeed_ast10x0.c @@ -15,6 +15,7 @@ #include "system/system.h" #include "hw/qdev-clock.h" #include "hw/misc/unimp.h" +#include "system/block-backend-global-state.h" #include "hw/arm/aspeed_soc.h" =20 #define ASPEED_SOC_IOMEM_SIZE 0x00200000 @@ -156,6 +157,8 @@ static void aspeed_soc_ast1030_init(Object *obj) =20 object_initialize_child(obj, "sbc", &s->sbc, TYPE_ASPEED_SBC); =20 + object_initialize_child(obj, "otpmem", &s->otpmem, TYPE_ASPEED_OTPMEM); + for (i =3D 0; i < sc->wdts_num; i++) { snprintf(typename, sizeof(typename), "aspeed.wdt-%s", socname); object_initialize_child(obj, "wdt[*]", &s->wdt[i], typename); @@ -194,6 +197,7 @@ static void aspeed_soc_ast1030_realize(DeviceState *dev= _soc, Error **errp) Error *err =3D NULL; int i; g_autofree char *sram_name =3D NULL; + BlockBackend *blk; =20 if (!clock_has_source(s->sysclk)) { error_setg(errp, "sysclk clock must be wired up by the board code"= ); @@ -359,6 +363,21 @@ static void aspeed_soc_ast1030_realize(DeviceState *de= v_soc, Error **errp) ASPEED_SMC_GET_CLASS(&s->spi[i])->flash_window_bas= e); } =20 + /* OTP memory */ + blk =3D blk_by_name(ASPEED_OTPMEM_DRIVE); + if (blk) { + blk_set_perm(blk, BLK_PERM_CONSISTENT_READ | BLK_PERM_WRITE, + 0, &error_fatal); + qdev_prop_set_drive(DEVICE(&s->otpmem), "drive", blk); + + if (!sysbus_realize(SYS_BUS_DEVICE(&s->otpmem), errp)) { + return; + } + /* Assign OTP memory to SBC */ + object_property_set_link(OBJECT(&s->sbc), "otpmem", + OBJECT(&s->otpmem), &error_abort); + } + /* Secure Boot Controller */ if (!sysbus_realize(SYS_BUS_DEVICE(&s->sbc), errp)) { return; diff --git a/hw/arm/aspeed_ast2600.c b/hw/arm/aspeed_ast2600.c index 1f994ba26c..9fe3eeeb0e 100644 --- a/hw/arm/aspeed_ast2600.c +++ b/hw/arm/aspeed_ast2600.c @@ -10,6 +10,7 @@ #include "qemu/osdep.h" #include "qapi/error.h" #include "hw/misc/unimp.h" +#include "system/block-backend-global-state.h" #include "hw/arm/aspeed_soc.h" #include "qemu/module.h" #include "qemu/error-report.h" @@ -263,6 +264,8 @@ static void aspeed_soc_ast2600_init(Object *obj) =20 object_initialize_child(obj, "sbc", &s->sbc, TYPE_ASPEED_SBC); =20 + object_initialize_child(obj, "otpmem", &s->otpmem, TYPE_ASPEED_OTPMEM); + object_initialize_child(obj, "iomem", &s->iomem, TYPE_UNIMPLEMENTED_DE= VICE); object_initialize_child(obj, "video", &s->video, TYPE_UNIMPLEMENTED_DE= VICE); object_initialize_child(obj, "dpmcu", &s->dpmcu, TYPE_UNIMPLEMENTED_DE= VICE); @@ -293,6 +296,7 @@ static void aspeed_soc_ast2600_realize(DeviceState *dev= , Error **errp) AspeedSoCClass *sc =3D ASPEED_SOC_GET_CLASS(s); qemu_irq irq; g_autofree char *sram_name =3D NULL; + BlockBackend *blk; =20 /* Default boot region (SPI memory or ROMs) */ memory_region_init(&s->spi_boot_container, OBJECT(s), @@ -628,6 +632,21 @@ static void aspeed_soc_ast2600_realize(DeviceState *de= v, Error **errp) sysbus_connect_irq(SYS_BUS_DEVICE(&s->i3c.devices[i]), 0, irq); } =20 + /* OTP memory */ + blk =3D blk_by_name(ASPEED_OTPMEM_DRIVE); + if (blk) { + blk_set_perm(blk, BLK_PERM_CONSISTENT_READ | BLK_PERM_WRITE, + 0, &error_fatal); + qdev_prop_set_drive(DEVICE(&s->otpmem), "drive", blk); + + if (!sysbus_realize(SYS_BUS_DEVICE(&s->otpmem), errp)) { + return; + } + /* Assign OTP memory to SBC */ + object_property_set_link(OBJECT(&s->sbc), "otpmem", + OBJECT(&s->otpmem), &error_abort); + } + /* Secure Boot Controller */ if (!sysbus_realize(SYS_BUS_DEVICE(&s->sbc), errp)) { return; diff --git a/include/hw/arm/aspeed_soc.h b/include/hw/arm/aspeed_soc.h index f069d17d16..2d15c6047a 100644 --- a/include/hw/arm/aspeed_soc.h +++ b/include/hw/arm/aspeed_soc.h @@ -36,6 +36,7 @@ #include "hw/usb/hcd-ehci.h" #include "qom/object.h" #include "hw/misc/aspeed_lpc.h" +#include "hw/misc/aspeed_otpmem.h" #include "hw/misc/unimp.h" #include "hw/misc/aspeed_peci.h" #include "hw/fsi/aspeed_apb2opb.h" @@ -73,6 +74,7 @@ struct AspeedSoCState { AspeedSMCState spi[ASPEED_SPIS_NUM]; EHCISysBusState ehci[ASPEED_EHCIS_NUM]; AspeedSBCState sbc; + AspeedOTPMemState otpmem; AspeedSLIState sli; AspeedSLIState sliio; MemoryRegion secsram; --=20 2.43.0