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 "qapi/error.h"
23 #include "hw/qdev-properties.h"
24 #include "hw/qdev-properties-system.h"
25 #include "hw/sysbus.h"
27 #include "qemu/module.h"
28 #include "hw/misc/sifive_u_otp.h"
29 #include "sysemu/blockdev.h"
30 #include "sysemu/block-backend.h"
32 #define WRITTEN_BIT_ON 0x1
34 #define SET_FUSEARRAY_BIT(map, i, off, bit) \
35 map[i] = bit ? (map[i] | bit << off) : (map[i] & ~(0x1 << off))
37 #define GET_FUSEARRAY_BIT(map, i, off) \
38 ((map[i] >> off) & 0x1)
40 static uint64_t sifive_u_otp_read(void *opaque
, hwaddr addr
, unsigned int size
)
42 SiFiveUOTPState
*s
= opaque
;
47 case SIFIVE_U_OTP_PAIO
:
49 case SIFIVE_U_OTP_PAS
:
51 case SIFIVE_U_OTP_PCE
:
53 case SIFIVE_U_OTP_PCLK
:
55 case SIFIVE_U_OTP_PDIN
:
57 case SIFIVE_U_OTP_PDOUT
:
58 if ((s
->pce
& SIFIVE_U_OTP_PCE_EN
) &&
59 (s
->pdstb
& SIFIVE_U_OTP_PDSTB_EN
) &&
60 (s
->ptrim
& SIFIVE_U_OTP_PTRIM_EN
)) {
62 /* read from backend */
66 if (blk_pread(s
->blk
, s
->pa
* SIFIVE_U_OTP_FUSE_WORD
, &buf
,
67 SIFIVE_U_OTP_FUSE_WORD
) < 0) {
68 qemu_log_mask(LOG_GUEST_ERROR
,
69 "read error index<%d>\n", s
->pa
);
76 return s
->fuse
[s
->pa
& SIFIVE_U_OTP_PA_MASK
];
80 case SIFIVE_U_OTP_PDSTB
:
82 case SIFIVE_U_OTP_PPROG
:
84 case SIFIVE_U_OTP_PTC
:
86 case SIFIVE_U_OTP_PTM
:
88 case SIFIVE_U_OTP_PTM_REP
:
90 case SIFIVE_U_OTP_PTR
:
92 case SIFIVE_U_OTP_PTRIM
:
94 case SIFIVE_U_OTP_PWE
:
98 qemu_log_mask(LOG_GUEST_ERROR
, "%s: read: addr=0x%" HWADDR_PRIx
"\n",
103 static void sifive_u_otp_write(void *opaque
, hwaddr addr
,
104 uint64_t val64
, unsigned int size
)
106 SiFiveUOTPState
*s
= opaque
;
107 uint32_t val32
= (uint32_t)val64
;
110 case SIFIVE_U_OTP_PA
:
111 s
->pa
= val32
& SIFIVE_U_OTP_PA_MASK
;
113 case SIFIVE_U_OTP_PAIO
:
116 case SIFIVE_U_OTP_PAS
:
119 case SIFIVE_U_OTP_PCE
:
122 case SIFIVE_U_OTP_PCLK
:
125 case SIFIVE_U_OTP_PDIN
:
128 case SIFIVE_U_OTP_PDOUT
:
131 case SIFIVE_U_OTP_PDSTB
:
134 case SIFIVE_U_OTP_PPROG
:
137 case SIFIVE_U_OTP_PTC
:
140 case SIFIVE_U_OTP_PTM
:
143 case SIFIVE_U_OTP_PTM_REP
:
146 case SIFIVE_U_OTP_PTR
:
149 case SIFIVE_U_OTP_PTRIM
:
152 case SIFIVE_U_OTP_PWE
:
153 s
->pwe
= val32
& SIFIVE_U_OTP_PWE_EN
;
155 /* PWE is enabled. Ignore PAS=1 (no redundancy cell) */
156 if (s
->pwe
&& !s
->pas
) {
157 if (GET_FUSEARRAY_BIT(s
->fuse_wo
, s
->pa
, s
->paio
)) {
158 qemu_log_mask(LOG_GUEST_ERROR
,
159 "write once error: idx<%u>, bit<%u>\n",
165 SET_FUSEARRAY_BIT(s
->fuse
, s
->pa
, s
->paio
, s
->pdin
);
167 /* write to backend */
169 if (blk_pwrite(s
->blk
, s
->pa
* SIFIVE_U_OTP_FUSE_WORD
,
170 &s
->fuse
[s
->pa
], SIFIVE_U_OTP_FUSE_WORD
,
172 qemu_log_mask(LOG_GUEST_ERROR
,
173 "write error index<%d>\n", s
->pa
);
177 /* update written bit */
178 SET_FUSEARRAY_BIT(s
->fuse_wo
, s
->pa
, s
->paio
, WRITTEN_BIT_ON
);
183 qemu_log_mask(LOG_GUEST_ERROR
, "%s: bad write: addr=0x%" HWADDR_PRIx
184 " v=0x%x\n", __func__
, addr
, val32
);
188 static const MemoryRegionOps sifive_u_otp_ops
= {
189 .read
= sifive_u_otp_read
,
190 .write
= sifive_u_otp_write
,
191 .endianness
= DEVICE_NATIVE_ENDIAN
,
193 .min_access_size
= 4,
198 static Property sifive_u_otp_properties
[] = {
199 DEFINE_PROP_UINT32("serial", SiFiveUOTPState
, serial
, 0),
200 DEFINE_PROP_DRIVE("drive", SiFiveUOTPState
, blk
),
201 DEFINE_PROP_END_OF_LIST(),
204 static void sifive_u_otp_realize(DeviceState
*dev
, Error
**errp
)
206 SiFiveUOTPState
*s
= SIFIVE_U_OTP(dev
);
209 memory_region_init_io(&s
->mmio
, OBJECT(dev
), &sifive_u_otp_ops
, s
,
210 TYPE_SIFIVE_U_OTP
, SIFIVE_U_OTP_REG_SIZE
);
211 sysbus_init_mmio(SYS_BUS_DEVICE(dev
), &s
->mmio
);
213 dinfo
= drive_get_next(IF_NONE
);
220 blk
= blk_by_legacy_dinfo(dinfo
);
221 filesize
= SIFIVE_U_OTP_NUM_FUSES
* SIFIVE_U_OTP_FUSE_WORD
;
222 if (blk_getlength(blk
) < filesize
) {
223 error_setg(errp
, "OTP drive size < 16K");
227 qdev_prop_set_drive_err(dev
, "drive", blk
, errp
);
230 perm
= BLK_PERM_CONSISTENT_READ
|
231 (blk_is_read_only(s
->blk
) ? 0 : BLK_PERM_WRITE
);
232 ret
= blk_set_perm(s
->blk
, perm
, BLK_PERM_ALL
, errp
);
237 if (blk_pread(s
->blk
, 0, s
->fuse
, filesize
) != filesize
) {
238 error_setg(errp
, "failed to read the initial flash content");
244 static void sifive_u_otp_reset(DeviceState
*dev
)
246 SiFiveUOTPState
*s
= SIFIVE_U_OTP(dev
);
248 /* Initialize all fuses' initial value to 0xFFs */
249 memset(s
->fuse
, 0xff, sizeof(s
->fuse
));
251 /* Make a valid content of serial number */
252 s
->fuse
[SIFIVE_U_OTP_SERIAL_ADDR
] = s
->serial
;
253 s
->fuse
[SIFIVE_U_OTP_SERIAL_ADDR
+ 1] = ~(s
->serial
);
256 /* Put serial number to backend as well*/
257 uint32_t serial_data
;
258 int index
= SIFIVE_U_OTP_SERIAL_ADDR
;
260 serial_data
= s
->serial
;
261 if (blk_pwrite(s
->blk
, index
* SIFIVE_U_OTP_FUSE_WORD
,
262 &serial_data
, SIFIVE_U_OTP_FUSE_WORD
, 0) < 0) {
263 qemu_log_mask(LOG_GUEST_ERROR
,
264 "write error index<%d>\n", index
);
267 serial_data
= ~(s
->serial
);
268 if (blk_pwrite(s
->blk
, (index
+ 1) * SIFIVE_U_OTP_FUSE_WORD
,
269 &serial_data
, SIFIVE_U_OTP_FUSE_WORD
, 0) < 0) {
270 qemu_log_mask(LOG_GUEST_ERROR
,
271 "write error index<%d>\n", index
+ 1);
275 /* Initialize write-once map */
276 memset(s
->fuse_wo
, 0x00, sizeof(s
->fuse_wo
));
279 static void sifive_u_otp_class_init(ObjectClass
*klass
, void *data
)
281 DeviceClass
*dc
= DEVICE_CLASS(klass
);
283 device_class_set_props(dc
, sifive_u_otp_properties
);
284 dc
->realize
= sifive_u_otp_realize
;
285 dc
->reset
= sifive_u_otp_reset
;
288 static const TypeInfo sifive_u_otp_info
= {
289 .name
= TYPE_SIFIVE_U_OTP
,
290 .parent
= TYPE_SYS_BUS_DEVICE
,
291 .instance_size
= sizeof(SiFiveUOTPState
),
292 .class_init
= sifive_u_otp_class_init
,
295 static void sifive_u_otp_register_types(void)
297 type_register_static(&sifive_u_otp_info
);
300 type_init(sifive_u_otp_register_types
)