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"
26 #include "qemu/error-report.h"
28 #include "qemu/module.h"
29 #include "hw/misc/sifive_u_otp.h"
30 #include "sysemu/blockdev.h"
31 #include "sysemu/block-backend.h"
33 #define WRITTEN_BIT_ON 0x1
35 #define SET_FUSEARRAY_BIT(map, i, off, bit) \
36 map[i] = bit ? (map[i] | bit << off) : (map[i] & ~(0x1 << off))
38 #define GET_FUSEARRAY_BIT(map, i, off) \
39 ((map[i] >> off) & 0x1)
41 static uint64_t sifive_u_otp_read(void *opaque
, hwaddr addr
, unsigned int size
)
43 SiFiveUOTPState
*s
= opaque
;
48 case SIFIVE_U_OTP_PAIO
:
50 case SIFIVE_U_OTP_PAS
:
52 case SIFIVE_U_OTP_PCE
:
54 case SIFIVE_U_OTP_PCLK
:
56 case SIFIVE_U_OTP_PDIN
:
58 case SIFIVE_U_OTP_PDOUT
:
59 if ((s
->pce
& SIFIVE_U_OTP_PCE_EN
) &&
60 (s
->pdstb
& SIFIVE_U_OTP_PDSTB_EN
) &&
61 (s
->ptrim
& SIFIVE_U_OTP_PTRIM_EN
)) {
63 /* read from backend */
67 if (blk_pread(s
->blk
, s
->pa
* SIFIVE_U_OTP_FUSE_WORD
, &buf
,
68 SIFIVE_U_OTP_FUSE_WORD
) < 0) {
69 error_report("read error index<%d>", 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 error_report("write error index<%d>", s
->pa
);
176 /* update written bit */
177 SET_FUSEARRAY_BIT(s
->fuse_wo
, s
->pa
, s
->paio
, WRITTEN_BIT_ON
);
182 qemu_log_mask(LOG_GUEST_ERROR
, "%s: bad write: addr=0x%" HWADDR_PRIx
183 " v=0x%x\n", __func__
, addr
, val32
);
187 static const MemoryRegionOps sifive_u_otp_ops
= {
188 .read
= sifive_u_otp_read
,
189 .write
= sifive_u_otp_write
,
190 .endianness
= DEVICE_NATIVE_ENDIAN
,
192 .min_access_size
= 4,
197 static Property sifive_u_otp_properties
[] = {
198 DEFINE_PROP_UINT32("serial", SiFiveUOTPState
, serial
, 0),
199 DEFINE_PROP_DRIVE("drive", SiFiveUOTPState
, blk
),
200 DEFINE_PROP_END_OF_LIST(),
203 static void sifive_u_otp_realize(DeviceState
*dev
, Error
**errp
)
205 SiFiveUOTPState
*s
= SIFIVE_U_OTP(dev
);
208 memory_region_init_io(&s
->mmio
, OBJECT(dev
), &sifive_u_otp_ops
, s
,
209 TYPE_SIFIVE_U_OTP
, SIFIVE_U_OTP_REG_SIZE
);
210 sysbus_init_mmio(SYS_BUS_DEVICE(dev
), &s
->mmio
);
212 dinfo
= drive_get_next(IF_NONE
);
219 blk
= blk_by_legacy_dinfo(dinfo
);
220 filesize
= SIFIVE_U_OTP_NUM_FUSES
* SIFIVE_U_OTP_FUSE_WORD
;
221 if (blk_getlength(blk
) < filesize
) {
222 error_setg(errp
, "OTP drive size < 16K");
226 qdev_prop_set_drive_err(dev
, "drive", blk
, errp
);
229 perm
= BLK_PERM_CONSISTENT_READ
|
230 (blk_supports_write_perm(s
->blk
) ? BLK_PERM_WRITE
: 0);
231 ret
= blk_set_perm(s
->blk
, perm
, BLK_PERM_ALL
, errp
);
236 if (blk_pread(s
->blk
, 0, s
->fuse
, filesize
) != filesize
) {
237 error_setg(errp
, "failed to read the initial flash content");
243 static void sifive_u_otp_reset(DeviceState
*dev
)
245 SiFiveUOTPState
*s
= SIFIVE_U_OTP(dev
);
247 /* Initialize all fuses' initial value to 0xFFs */
248 memset(s
->fuse
, 0xff, sizeof(s
->fuse
));
250 /* Make a valid content of serial number */
251 s
->fuse
[SIFIVE_U_OTP_SERIAL_ADDR
] = s
->serial
;
252 s
->fuse
[SIFIVE_U_OTP_SERIAL_ADDR
+ 1] = ~(s
->serial
);
255 /* Put serial number to backend as well*/
256 uint32_t serial_data
;
257 int index
= SIFIVE_U_OTP_SERIAL_ADDR
;
259 serial_data
= s
->serial
;
260 if (blk_pwrite(s
->blk
, index
* SIFIVE_U_OTP_FUSE_WORD
,
261 &serial_data
, SIFIVE_U_OTP_FUSE_WORD
, 0) < 0) {
262 error_report("write error index<%d>", index
);
265 serial_data
= ~(s
->serial
);
266 if (blk_pwrite(s
->blk
, (index
+ 1) * SIFIVE_U_OTP_FUSE_WORD
,
267 &serial_data
, SIFIVE_U_OTP_FUSE_WORD
, 0) < 0) {
268 error_report("write error index<%d>", index
+ 1);
272 /* Initialize write-once map */
273 memset(s
->fuse_wo
, 0x00, sizeof(s
->fuse_wo
));
276 static void sifive_u_otp_class_init(ObjectClass
*klass
, void *data
)
278 DeviceClass
*dc
= DEVICE_CLASS(klass
);
280 device_class_set_props(dc
, sifive_u_otp_properties
);
281 dc
->realize
= sifive_u_otp_realize
;
282 dc
->reset
= sifive_u_otp_reset
;
285 static const TypeInfo sifive_u_otp_info
= {
286 .name
= TYPE_SIFIVE_U_OTP
,
287 .parent
= TYPE_SYS_BUS_DEVICE
,
288 .instance_size
= sizeof(SiFiveUOTPState
),
289 .class_init
= sifive_u_otp_class_init
,
292 static void sifive_u_otp_register_types(void)
294 type_register_static(&sifive_u_otp_info
);
297 type_init(sifive_u_otp_register_types
)