1*12ef88d8SKane-Chen-AS /* 2*12ef88d8SKane-Chen-AS * ASPEED OTP (One-Time Programmable) memory 3*12ef88d8SKane-Chen-AS * 4*12ef88d8SKane-Chen-AS * Copyright (C) 2025 Aspeed 5*12ef88d8SKane-Chen-AS * 6*12ef88d8SKane-Chen-AS * SPDX-License-Identifier: GPL-2.0-or-later 7*12ef88d8SKane-Chen-AS */ 8*12ef88d8SKane-Chen-AS 9*12ef88d8SKane-Chen-AS #include "qemu/osdep.h" 10*12ef88d8SKane-Chen-AS #include "qemu/log.h" 11*12ef88d8SKane-Chen-AS #include "qapi/error.h" 12*12ef88d8SKane-Chen-AS #include "system/block-backend.h" 13*12ef88d8SKane-Chen-AS #include "hw/qdev-properties.h" 14*12ef88d8SKane-Chen-AS #include "hw/nvram/aspeed_otp.h" 15*12ef88d8SKane-Chen-AS 16*12ef88d8SKane-Chen-AS static uint64_t aspeed_otp_read(void *opaque, hwaddr offset, unsigned size) 17*12ef88d8SKane-Chen-AS { 18*12ef88d8SKane-Chen-AS AspeedOTPState *s = opaque; 19*12ef88d8SKane-Chen-AS uint64_t val = 0; 20*12ef88d8SKane-Chen-AS 21*12ef88d8SKane-Chen-AS memcpy(&val, s->storage + offset, size); 22*12ef88d8SKane-Chen-AS 23*12ef88d8SKane-Chen-AS return val; 24*12ef88d8SKane-Chen-AS } 25*12ef88d8SKane-Chen-AS 26*12ef88d8SKane-Chen-AS static void aspeed_otp_write(void *opaque, hwaddr otp_addr, 27*12ef88d8SKane-Chen-AS uint64_t val, unsigned size) 28*12ef88d8SKane-Chen-AS { 29*12ef88d8SKane-Chen-AS AspeedOTPState *s = opaque; 30*12ef88d8SKane-Chen-AS 31*12ef88d8SKane-Chen-AS memcpy(s->storage + otp_addr, &val, size); 32*12ef88d8SKane-Chen-AS } 33*12ef88d8SKane-Chen-AS 34*12ef88d8SKane-Chen-AS static bool aspeed_otp_init_storage(AspeedOTPState *s, Error **errp) 35*12ef88d8SKane-Chen-AS { 36*12ef88d8SKane-Chen-AS uint32_t *p; 37*12ef88d8SKane-Chen-AS int i, num; 38*12ef88d8SKane-Chen-AS 39*12ef88d8SKane-Chen-AS num = s->size / sizeof(uint32_t); 40*12ef88d8SKane-Chen-AS p = (uint32_t *)s->storage; 41*12ef88d8SKane-Chen-AS for (i = 0; i < num; i++) { 42*12ef88d8SKane-Chen-AS p[i] = (i % 2 == 0) ? 0x00000000 : 0xFFFFFFFF; 43*12ef88d8SKane-Chen-AS } 44*12ef88d8SKane-Chen-AS 45*12ef88d8SKane-Chen-AS return true; 46*12ef88d8SKane-Chen-AS } 47*12ef88d8SKane-Chen-AS 48*12ef88d8SKane-Chen-AS static const MemoryRegionOps aspeed_otp_ops = { 49*12ef88d8SKane-Chen-AS .read = aspeed_otp_read, 50*12ef88d8SKane-Chen-AS .write = aspeed_otp_write, 51*12ef88d8SKane-Chen-AS .endianness = DEVICE_LITTLE_ENDIAN, 52*12ef88d8SKane-Chen-AS .valid.min_access_size = 1, 53*12ef88d8SKane-Chen-AS .valid.max_access_size = 4, 54*12ef88d8SKane-Chen-AS }; 55*12ef88d8SKane-Chen-AS 56*12ef88d8SKane-Chen-AS static void aspeed_otp_realize(DeviceState *dev, Error **errp) 57*12ef88d8SKane-Chen-AS { 58*12ef88d8SKane-Chen-AS AspeedOTPState *s = ASPEED_OTP(dev); 59*12ef88d8SKane-Chen-AS 60*12ef88d8SKane-Chen-AS if (s->size == 0) { 61*12ef88d8SKane-Chen-AS error_setg(errp, "aspeed.otp: 'size' property must be set"); 62*12ef88d8SKane-Chen-AS return; 63*12ef88d8SKane-Chen-AS } 64*12ef88d8SKane-Chen-AS 65*12ef88d8SKane-Chen-AS s->storage = blk_blockalign(s->blk, s->size); 66*12ef88d8SKane-Chen-AS 67*12ef88d8SKane-Chen-AS if (!aspeed_otp_init_storage(s, errp)) { 68*12ef88d8SKane-Chen-AS return; 69*12ef88d8SKane-Chen-AS } 70*12ef88d8SKane-Chen-AS 71*12ef88d8SKane-Chen-AS memory_region_init_io(&s->mmio, OBJECT(dev), &aspeed_otp_ops, 72*12ef88d8SKane-Chen-AS s, "aspeed.otp", s->size); 73*12ef88d8SKane-Chen-AS address_space_init(&s->as, &s->mmio, NULL); 74*12ef88d8SKane-Chen-AS } 75*12ef88d8SKane-Chen-AS 76*12ef88d8SKane-Chen-AS static const Property aspeed_otp_properties[] = { 77*12ef88d8SKane-Chen-AS DEFINE_PROP_UINT64("size", AspeedOTPState, size, 0), 78*12ef88d8SKane-Chen-AS }; 79*12ef88d8SKane-Chen-AS 80*12ef88d8SKane-Chen-AS static void aspeed_otp_class_init(ObjectClass *klass, const void *data) 81*12ef88d8SKane-Chen-AS { 82*12ef88d8SKane-Chen-AS DeviceClass *dc = DEVICE_CLASS(klass); 83*12ef88d8SKane-Chen-AS dc->realize = aspeed_otp_realize; 84*12ef88d8SKane-Chen-AS device_class_set_props(dc, aspeed_otp_properties); 85*12ef88d8SKane-Chen-AS } 86*12ef88d8SKane-Chen-AS 87*12ef88d8SKane-Chen-AS static const TypeInfo aspeed_otp_info = { 88*12ef88d8SKane-Chen-AS .name = TYPE_ASPEED_OTP, 89*12ef88d8SKane-Chen-AS .parent = TYPE_DEVICE, 90*12ef88d8SKane-Chen-AS .instance_size = sizeof(AspeedOTPState), 91*12ef88d8SKane-Chen-AS .class_init = aspeed_otp_class_init, 92*12ef88d8SKane-Chen-AS }; 93*12ef88d8SKane-Chen-AS 94*12ef88d8SKane-Chen-AS static void aspeed_otp_register_types(void) 95*12ef88d8SKane-Chen-AS { 96*12ef88d8SKane-Chen-AS type_register_static(&aspeed_otp_info); 97*12ef88d8SKane-Chen-AS } 98*12ef88d8SKane-Chen-AS 99*12ef88d8SKane-Chen-AS type_init(aspeed_otp_register_types) 100