112ef88d8SKane-Chen-AS /* 212ef88d8SKane-Chen-AS * ASPEED OTP (One-Time Programmable) memory 312ef88d8SKane-Chen-AS * 412ef88d8SKane-Chen-AS * Copyright (C) 2025 Aspeed 512ef88d8SKane-Chen-AS * 612ef88d8SKane-Chen-AS * SPDX-License-Identifier: GPL-2.0-or-later 712ef88d8SKane-Chen-AS */ 812ef88d8SKane-Chen-AS 912ef88d8SKane-Chen-AS #include "qemu/osdep.h" 1012ef88d8SKane-Chen-AS #include "qemu/log.h" 1112ef88d8SKane-Chen-AS #include "qapi/error.h" 1212ef88d8SKane-Chen-AS #include "system/block-backend.h" 1312ef88d8SKane-Chen-AS #include "hw/qdev-properties.h" 1412ef88d8SKane-Chen-AS #include "hw/nvram/aspeed_otp.h" 1512ef88d8SKane-Chen-AS 1612ef88d8SKane-Chen-AS static uint64_t aspeed_otp_read(void *opaque, hwaddr offset, unsigned size) 1712ef88d8SKane-Chen-AS { 1812ef88d8SKane-Chen-AS AspeedOTPState *s = opaque; 1912ef88d8SKane-Chen-AS uint64_t val = 0; 2012ef88d8SKane-Chen-AS 2112ef88d8SKane-Chen-AS memcpy(&val, s->storage + offset, size); 2212ef88d8SKane-Chen-AS 2312ef88d8SKane-Chen-AS return val; 2412ef88d8SKane-Chen-AS } 2512ef88d8SKane-Chen-AS 2612ef88d8SKane-Chen-AS static void aspeed_otp_write(void *opaque, hwaddr otp_addr, 2712ef88d8SKane-Chen-AS uint64_t val, unsigned size) 2812ef88d8SKane-Chen-AS { 2912ef88d8SKane-Chen-AS AspeedOTPState *s = opaque; 3012ef88d8SKane-Chen-AS 3112ef88d8SKane-Chen-AS memcpy(s->storage + otp_addr, &val, size); 3212ef88d8SKane-Chen-AS } 3312ef88d8SKane-Chen-AS 3412ef88d8SKane-Chen-AS static bool aspeed_otp_init_storage(AspeedOTPState *s, Error **errp) 3512ef88d8SKane-Chen-AS { 3612ef88d8SKane-Chen-AS uint32_t *p; 3712ef88d8SKane-Chen-AS int i, num; 38*c79e29efSKane-Chen-AS uint64_t perm; 3912ef88d8SKane-Chen-AS 40*c79e29efSKane-Chen-AS if (s->blk) { 41*c79e29efSKane-Chen-AS perm = BLK_PERM_CONSISTENT_READ | 42*c79e29efSKane-Chen-AS (blk_supports_write_perm(s->blk) ? BLK_PERM_WRITE : 0); 43*c79e29efSKane-Chen-AS if (blk_set_perm(s->blk, perm, BLK_PERM_ALL, errp) < 0) { 44*c79e29efSKane-Chen-AS return false; 45*c79e29efSKane-Chen-AS } 46*c79e29efSKane-Chen-AS if (blk_pread(s->blk, 0, s->size, s->storage, 0) < 0) { 47*c79e29efSKane-Chen-AS error_setg(errp, "Failed to read the initial flash content"); 48*c79e29efSKane-Chen-AS return false; 49*c79e29efSKane-Chen-AS } 50*c79e29efSKane-Chen-AS } else { 5112ef88d8SKane-Chen-AS num = s->size / sizeof(uint32_t); 5212ef88d8SKane-Chen-AS p = (uint32_t *)s->storage; 5312ef88d8SKane-Chen-AS for (i = 0; i < num; i++) { 5412ef88d8SKane-Chen-AS p[i] = (i % 2 == 0) ? 0x00000000 : 0xFFFFFFFF; 5512ef88d8SKane-Chen-AS } 56*c79e29efSKane-Chen-AS } 5712ef88d8SKane-Chen-AS return true; 5812ef88d8SKane-Chen-AS } 5912ef88d8SKane-Chen-AS 6012ef88d8SKane-Chen-AS static const MemoryRegionOps aspeed_otp_ops = { 6112ef88d8SKane-Chen-AS .read = aspeed_otp_read, 6212ef88d8SKane-Chen-AS .write = aspeed_otp_write, 6312ef88d8SKane-Chen-AS .endianness = DEVICE_LITTLE_ENDIAN, 6412ef88d8SKane-Chen-AS .valid.min_access_size = 1, 6512ef88d8SKane-Chen-AS .valid.max_access_size = 4, 6612ef88d8SKane-Chen-AS }; 6712ef88d8SKane-Chen-AS 6812ef88d8SKane-Chen-AS static void aspeed_otp_realize(DeviceState *dev, Error **errp) 6912ef88d8SKane-Chen-AS { 7012ef88d8SKane-Chen-AS AspeedOTPState *s = ASPEED_OTP(dev); 7112ef88d8SKane-Chen-AS 7212ef88d8SKane-Chen-AS if (s->size == 0) { 7312ef88d8SKane-Chen-AS error_setg(errp, "aspeed.otp: 'size' property must be set"); 7412ef88d8SKane-Chen-AS return; 7512ef88d8SKane-Chen-AS } 7612ef88d8SKane-Chen-AS 7712ef88d8SKane-Chen-AS s->storage = blk_blockalign(s->blk, s->size); 7812ef88d8SKane-Chen-AS 7912ef88d8SKane-Chen-AS if (!aspeed_otp_init_storage(s, errp)) { 8012ef88d8SKane-Chen-AS return; 8112ef88d8SKane-Chen-AS } 8212ef88d8SKane-Chen-AS 8312ef88d8SKane-Chen-AS memory_region_init_io(&s->mmio, OBJECT(dev), &aspeed_otp_ops, 8412ef88d8SKane-Chen-AS s, "aspeed.otp", s->size); 8512ef88d8SKane-Chen-AS address_space_init(&s->as, &s->mmio, NULL); 8612ef88d8SKane-Chen-AS } 8712ef88d8SKane-Chen-AS 8812ef88d8SKane-Chen-AS static const Property aspeed_otp_properties[] = { 8912ef88d8SKane-Chen-AS DEFINE_PROP_UINT64("size", AspeedOTPState, size, 0), 90*c79e29efSKane-Chen-AS DEFINE_PROP_DRIVE("drive", AspeedOTPState, blk), 9112ef88d8SKane-Chen-AS }; 9212ef88d8SKane-Chen-AS 9312ef88d8SKane-Chen-AS static void aspeed_otp_class_init(ObjectClass *klass, const void *data) 9412ef88d8SKane-Chen-AS { 9512ef88d8SKane-Chen-AS DeviceClass *dc = DEVICE_CLASS(klass); 9612ef88d8SKane-Chen-AS dc->realize = aspeed_otp_realize; 9712ef88d8SKane-Chen-AS device_class_set_props(dc, aspeed_otp_properties); 9812ef88d8SKane-Chen-AS } 9912ef88d8SKane-Chen-AS 10012ef88d8SKane-Chen-AS static const TypeInfo aspeed_otp_info = { 10112ef88d8SKane-Chen-AS .name = TYPE_ASPEED_OTP, 10212ef88d8SKane-Chen-AS .parent = TYPE_DEVICE, 10312ef88d8SKane-Chen-AS .instance_size = sizeof(AspeedOTPState), 10412ef88d8SKane-Chen-AS .class_init = aspeed_otp_class_init, 10512ef88d8SKane-Chen-AS }; 10612ef88d8SKane-Chen-AS 10712ef88d8SKane-Chen-AS static void aspeed_otp_register_types(void) 10812ef88d8SKane-Chen-AS { 10912ef88d8SKane-Chen-AS type_register_static(&aspeed_otp_info); 11012ef88d8SKane-Chen-AS } 11112ef88d8SKane-Chen-AS 11212ef88d8SKane-Chen-AS type_init(aspeed_otp_register_types) 113