All of lore.kernel.org
 help / color / mirror / Atom feed
From: Kane Chen via <qemu-devel@nongnu.org>
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@aspeedtech.com>, Kane-Chen-AS <kane_chen@aspeedtech.com>
Subject: [RFC v5 1/4] hw/misc/aspeed_otp: Add ASPEED OTP memory device model
Date: Thu, 19 Jun 2025 14:41:10 +0800	[thread overview]
Message-ID: <20250619064115.4182202-2-kane_chen@aspeedtech.com> (raw)
In-Reply-To: <20250619064115.4182202-1-kane_chen@aspeedtech.com>

From: Kane-Chen-AS <kane_chen@aspeedtech.com>

Introduce a QEMU device model for ASPEED's One-Time Programmable (OTP)
memory.

This model simulates a word-addressable OTP region used for secure
fuse storage or boot-time configuration. The OTP memory can operate
with either:

- a file-backed backend via the 'drive' property, which allows
  persistent emulation of burned fuse states using -blockdev, or
- an internal fallback buffer

The OTP model provides a memory-like interface through a dedicated
AddressSpace, allowing other device models (e.g., SBC) to issue
transactions as if accessing a memory-mapped region. Actual data is
maintained in a file-backed or internal buffer.

Logging is included to assist with debugging and to indicate fallback
behavior when no backend is provided.

Signed-off-by: Kane-Chen-AS <kane_chen@aspeedtech.com>
---
 hw/misc/aspeed_otpmem.c         | 117 ++++++++++++++++++++++++++++++++
 hw/misc/meson.build             |   1 +
 include/hw/misc/aspeed_otpmem.h |  35 ++++++++++
 3 files changed, 153 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..c5a67621c9
--- /dev/null
+++ b/hw/misc/aspeed_otpmem.c
@@ -0,0 +1,117 @@
+/*
+ *  ASPEED OTP (One-Time Programmable) memory
+ *
+ *  Copyright (C) 2025 Aspeed
+ *
+ *  SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#include "qemu/osdep.h"
+#include "qemu/log.h"
+#include "qapi/error.h"
+#include "trace.h"
+#include "system/block-backend-global-state.h"
+#include "system/block-backend-io.h"
+#include "hw/misc/aspeed_otpmem.h"
+
+static uint64_t aspeed_otpmem_read(void *opaque, hwaddr offset, unsigned size)
+{
+    AspeedOTPMemState *s = opaque;
+    uint64_t val = 0;
+
+    memcpy(&val, s->storage + offset, size);
+
+    return val;
+}
+
+static void aspeed_otpmem_write(void *opaque, hwaddr offset,
+                                uint64_t val, unsigned size)
+{
+    int ret;
+    AspeedOTPMemState *s = opaque;
+
+    memcpy(s->storage + offset, &val, size);
+    if (s->blk) {
+        ret = blk_pwrite(s->blk, offset, size, &val, BDRV_REQ_FUA);
+        if (ret < 0) {
+            qemu_log_mask(LOG_GUEST_ERROR,
+                          "blk_pwrite failed offset 0x%" HWADDR_PRIx
+                          ", ret = %d\n",
+                          offset, ret);
+        }
+    }
+}
+
+static const MemoryRegionOps aspeed_otpmem_ops = {
+    .read = aspeed_otpmem_read,
+    .write = aspeed_otpmem_write,
+    .endianness = DEVICE_LITTLE_ENDIAN,
+    .valid.min_access_size = 1,
+    .valid.max_access_size = 4,
+};
+
+static void aspeed_otpmem_realize(DeviceState *dev, Error **errp)
+{
+    AspeedOTPMemState *s = ASPEED_OTPMEM(dev);
+    const size_t size = OTPMEM_SIZE;
+    int i, num;
+    uint32_t *p;
+
+    s->storage = blk_blockalign(s->blk, size);
+    if (!s->storage) {
+        error_setg(errp, "Failed to allocate OTP memory storage buffer");
+        return;
+    }
+
+    if (s->blk) {
+        uint64_t perm = BLK_PERM_CONSISTENT_READ |
+                        (blk_supports_write_perm(s->blk) ? BLK_PERM_WRITE : 0);
+        if (blk_set_perm(s->blk, perm, BLK_PERM_ALL, errp) < 0) {
+            error_setg(errp, "Failed to set permission");
+            return;
+        }
+
+        if (blk_pread(s->blk, 0, s->size, s->storage, 0) < 0) {
+            error_setg(errp, "Failed to read the initial flash content");
+            return;
+        }
+    } else {
+        num = size / sizeof(uint32_t);
+        p = (uint32_t *)s->storage;
+        for (i = 0; i < num; i++) {
+            p[i] = (i % 2 == 0) ? 0x00000000 : 0xFFFFFFFF;
+        }
+        qemu_log_mask(LOG_GUEST_ERROR,
+                      "OTP image is not presented, use local buffer\n");
+    }
+
+    memory_region_init_io(&s->mmio, OBJECT(dev), &aspeed_otpmem_ops,
+                          s, "aspeed.otpmem", size);
+    address_space_init(&s->as, &s->mmio, NULL);
+}
+
+static const Property aspeed_otpmem_properties[] = {
+    DEFINE_PROP_UINT64("size", AspeedOTPMemState, size, OTPMEM_SIZE),
+    DEFINE_PROP_DRIVE("drive", AspeedOTPMemState, blk),
+};
+
+static void aspeed_otpmem_class_init(ObjectClass *klass, const void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    dc->realize = aspeed_otpmem_realize;
+    device_class_set_props(dc, aspeed_otpmem_properties);
+}
+
+static const TypeInfo aspeed_otpmem_info = {
+    .name          = TYPE_ASPEED_OTPMEM,
+    .parent        = TYPE_DEVICE,
+    .instance_size = sizeof(AspeedOTPMemState),
+    .class_init    = aspeed_otpmem_class_init,
+};
+
+static void aspeed_otpmem_register_types(void)
+{
+    type_register_static(&aspeed_otpmem_info);
+}
+
+type_init(aspeed_otpmem_register_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'))
 
diff --git a/include/hw/misc/aspeed_otpmem.h b/include/hw/misc/aspeed_otpmem.h
new file mode 100644
index 0000000000..7f469d9fd7
--- /dev/null
+++ b/include/hw/misc/aspeed_otpmem.h
@@ -0,0 +1,35 @@
+/*
+ *  ASPEED OTP (One-Time Programmable) memory
+ *
+ *  Copyright (C) 2025 Aspeed
+ *
+ *  SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#ifndef ASPEED_OTPMMEM_H
+#define ASPEED_OTPMMEM_H
+
+#include "system/memory.h"
+#include "hw/block/block.h"
+#include "system/memory.h"
+#include "system/address-spaces.h"
+
+#define OTPMEM_SIZE 0x4000
+#define TYPE_ASPEED_OTPMEM "aspeed.otpmem"
+OBJECT_DECLARE_SIMPLE_TYPE(AspeedOTPMemState, ASPEED_OTPMEM)
+
+typedef struct AspeedOTPMemState {
+    DeviceState parent_obj;
+
+    BlockBackend *blk;
+
+    uint64_t size;
+
+    AddressSpace as;
+
+    MemoryRegion mmio;
+
+    uint8_t *storage;
+} AspeedOTPMemState;
+
+#endif /* ASPEED_OTPMMEM_H */
-- 
2.43.0


  reply	other threads:[~2025-06-19  6:43 UTC|newest]

Thread overview: 10+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2025-06-19  6:41 [RFC v5 0/4] Add QEMU model for ASPEED OTP memory and integrate with SoCs Kane Chen via
2025-06-19  6:41 ` Kane Chen via [this message]
2025-06-19  6:41 ` [RFC v5 2/4] hw/misc/aspeed_sbc: Connect ASPEED OTP memory device to SBC Kane Chen via
2025-06-19  6:41   ` Kane Chen via
2025-06-19  6:41 ` [RFC v5 3/4] hw/arm: Integrate ASPEED OTP memory support into AST10x0 and AST2600 SoCs Kane Chen via
2025-06-19  6:41 ` [RFC v5 4/4] tests/functional: Add integration tests for ASPEED OTP memory model Kane Chen via
2025-06-19  6:41   ` Kane Chen via
2025-06-20  5:44 ` [RFC v5 0/4] Add QEMU model for ASPEED OTP memory and integrate with SoCs Cédric Le Goater
2025-06-23  3:23   ` Kane Chen
2025-06-23  6:45     ` 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=20250619064115.4182202-2-kane_chen@aspeedtech.com \
    --to=qemu-devel@nongnu.org \
    --cc=andrew@codeconstruct.com.au \
    --cc=clg@kaod.org \
    --cc=jamin_lin@aspeedtech.com \
    --cc=joel@jms.id.au \
    --cc=kane_chen@aspeedtech.com \
    --cc=leetroy@gmail.com \
    --cc=peter.maydell@linaro.org \
    --cc=qemu-arm@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.