2 * QEMU SiFive U OTP (One-Time Programmable) Memory interface
4 * Copyright (c) 2019 Bin Meng <bmeng.cn@gmail.com>
6 * Simple model of the OTP to emulate register reads made by the SDK BSP
8 * This program is free software; you can redistribute it and/or modify it
9 * under the terms and conditions of the GNU General Public License,
10 * version 2 or later, as published by the Free Software Foundation.
12 * This program is distributed in the hope it will be useful, but WITHOUT
13 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
17 * You should have received a copy of the GNU General Public License along with
18 * this program. If not, see <http://www.gnu.org/licenses/>.
21 #include "qemu/osdep.h"
22 #include "hw/qdev-properties.h"
23 #include "hw/sysbus.h"
25 #include "qemu/module.h"
26 #include "hw/misc/sifive_u_otp.h"
28 static uint64_t sifive_u_otp_read(void *opaque
, hwaddr addr
, unsigned int size
)
30 SiFiveUOTPState
*s
= opaque
;
35 case SIFIVE_U_OTP_PAIO
:
37 case SIFIVE_U_OTP_PAS
:
39 case SIFIVE_U_OTP_PCE
:
41 case SIFIVE_U_OTP_PCLK
:
43 case SIFIVE_U_OTP_PDIN
:
45 case SIFIVE_U_OTP_PDOUT
:
46 if ((s
->pce
& SIFIVE_U_OTP_PCE_EN
) &&
47 (s
->pdstb
& SIFIVE_U_OTP_PDSTB_EN
) &&
48 (s
->ptrim
& SIFIVE_U_OTP_PTRIM_EN
)) {
49 return s
->fuse
[s
->pa
& SIFIVE_U_OTP_PA_MASK
];
53 case SIFIVE_U_OTP_PDSTB
:
55 case SIFIVE_U_OTP_PPROG
:
57 case SIFIVE_U_OTP_PTC
:
59 case SIFIVE_U_OTP_PTM
:
61 case SIFIVE_U_OTP_PTM_REP
:
63 case SIFIVE_U_OTP_PTR
:
65 case SIFIVE_U_OTP_PTRIM
:
67 case SIFIVE_U_OTP_PWE
:
71 qemu_log_mask(LOG_GUEST_ERROR
, "%s: read: addr=0x%" HWADDR_PRIx
"\n",
76 static void sifive_u_otp_write(void *opaque
, hwaddr addr
,
77 uint64_t val64
, unsigned int size
)
79 SiFiveUOTPState
*s
= opaque
;
80 uint32_t val32
= (uint32_t)val64
;
84 s
->pa
= val32
& SIFIVE_U_OTP_PA_MASK
;
86 case SIFIVE_U_OTP_PAIO
:
89 case SIFIVE_U_OTP_PAS
:
92 case SIFIVE_U_OTP_PCE
:
95 case SIFIVE_U_OTP_PCLK
:
98 case SIFIVE_U_OTP_PDIN
:
101 case SIFIVE_U_OTP_PDOUT
:
104 case SIFIVE_U_OTP_PDSTB
:
107 case SIFIVE_U_OTP_PPROG
:
110 case SIFIVE_U_OTP_PTC
:
113 case SIFIVE_U_OTP_PTM
:
116 case SIFIVE_U_OTP_PTM_REP
:
119 case SIFIVE_U_OTP_PTR
:
122 case SIFIVE_U_OTP_PTRIM
:
125 case SIFIVE_U_OTP_PWE
:
129 qemu_log_mask(LOG_GUEST_ERROR
, "%s: bad write: addr=0x%" HWADDR_PRIx
130 " v=0x%x\n", __func__
, addr
, val32
);
134 static const MemoryRegionOps sifive_u_otp_ops
= {
135 .read
= sifive_u_otp_read
,
136 .write
= sifive_u_otp_write
,
137 .endianness
= DEVICE_NATIVE_ENDIAN
,
139 .min_access_size
= 4,
144 static Property sifive_u_otp_properties
[] = {
145 DEFINE_PROP_UINT32("serial", SiFiveUOTPState
, serial
, 0),
146 DEFINE_PROP_END_OF_LIST(),
149 static void sifive_u_otp_realize(DeviceState
*dev
, Error
**errp
)
151 SiFiveUOTPState
*s
= SIFIVE_U_OTP(dev
);
153 memory_region_init_io(&s
->mmio
, OBJECT(dev
), &sifive_u_otp_ops
, s
,
154 TYPE_SIFIVE_U_OTP
, SIFIVE_U_OTP_REG_SIZE
);
155 sysbus_init_mmio(SYS_BUS_DEVICE(dev
), &s
->mmio
);
158 static void sifive_u_otp_reset(DeviceState
*dev
)
160 SiFiveUOTPState
*s
= SIFIVE_U_OTP(dev
);
162 /* Initialize all fuses' initial value to 0xFFs */
163 memset(s
->fuse
, 0xff, sizeof(s
->fuse
));
165 /* Make a valid content of serial number */
166 s
->fuse
[SIFIVE_U_OTP_SERIAL_ADDR
] = s
->serial
;
167 s
->fuse
[SIFIVE_U_OTP_SERIAL_ADDR
+ 1] = ~(s
->serial
);
170 static void sifive_u_otp_class_init(ObjectClass
*klass
, void *data
)
172 DeviceClass
*dc
= DEVICE_CLASS(klass
);
174 device_class_set_props(dc
, sifive_u_otp_properties
);
175 dc
->realize
= sifive_u_otp_realize
;
176 dc
->reset
= sifive_u_otp_reset
;
179 static const TypeInfo sifive_u_otp_info
= {
180 .name
= TYPE_SIFIVE_U_OTP
,
181 .parent
= TYPE_SYS_BUS_DEVICE
,
182 .instance_size
= sizeof(SiFiveUOTPState
),
183 .class_init
= sifive_u_otp_class_init
,
186 static void sifive_u_otp_register_types(void)
188 type_register_static(&sifive_u_otp_info
);
191 type_init(sifive_u_otp_register_types
)