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/sysbus.h"
26 #include "qemu/module.h"
27 #include "hw/misc/sifive_u_otp.h"
28 #include "sysemu/blockdev.h"
29 #include "sysemu/block-backend.h"
31 #define WRITTEN_BIT_ON 0x1
33 #define SET_FUSEARRAY_BIT(map, i, off, bit) \
34 map[i] = bit ? (map[i] | bit << off) : (map[i] & ~(0x1 << off))
36 #define GET_FUSEARRAY_BIT(map, i, off) \
37 ((map[i] >> off) & 0x1)
39 static uint64_t sifive_u_otp_read(void *opaque
, hwaddr addr
, unsigned int size
)
41 SiFiveUOTPState
*s
= opaque
;
46 case SIFIVE_U_OTP_PAIO
:
48 case SIFIVE_U_OTP_PAS
:
50 case SIFIVE_U_OTP_PCE
:
52 case SIFIVE_U_OTP_PCLK
:
54 case SIFIVE_U_OTP_PDIN
:
56 case SIFIVE_U_OTP_PDOUT
:
57 if ((s
->pce
& SIFIVE_U_OTP_PCE_EN
) &&
58 (s
->pdstb
& SIFIVE_U_OTP_PDSTB_EN
) &&
59 (s
->ptrim
& SIFIVE_U_OTP_PTRIM_EN
)) {
61 /* read from backend */
65 blk_pread(s
->blk
, s
->pa
* SIFIVE_U_OTP_FUSE_WORD
, &buf
,
66 SIFIVE_U_OTP_FUSE_WORD
);
70 return s
->fuse
[s
->pa
& SIFIVE_U_OTP_PA_MASK
];
74 case SIFIVE_U_OTP_PDSTB
:
76 case SIFIVE_U_OTP_PPROG
:
78 case SIFIVE_U_OTP_PTC
:
80 case SIFIVE_U_OTP_PTM
:
82 case SIFIVE_U_OTP_PTM_REP
:
84 case SIFIVE_U_OTP_PTR
:
86 case SIFIVE_U_OTP_PTRIM
:
88 case SIFIVE_U_OTP_PWE
:
92 qemu_log_mask(LOG_GUEST_ERROR
, "%s: read: addr=0x%" HWADDR_PRIx
"\n",
97 static void sifive_u_otp_write(void *opaque
, hwaddr addr
,
98 uint64_t val64
, unsigned int size
)
100 SiFiveUOTPState
*s
= opaque
;
101 uint32_t val32
= (uint32_t)val64
;
104 case SIFIVE_U_OTP_PA
:
105 s
->pa
= val32
& SIFIVE_U_OTP_PA_MASK
;
107 case SIFIVE_U_OTP_PAIO
:
110 case SIFIVE_U_OTP_PAS
:
113 case SIFIVE_U_OTP_PCE
:
116 case SIFIVE_U_OTP_PCLK
:
119 case SIFIVE_U_OTP_PDIN
:
122 case SIFIVE_U_OTP_PDOUT
:
125 case SIFIVE_U_OTP_PDSTB
:
128 case SIFIVE_U_OTP_PPROG
:
131 case SIFIVE_U_OTP_PTC
:
134 case SIFIVE_U_OTP_PTM
:
137 case SIFIVE_U_OTP_PTM_REP
:
140 case SIFIVE_U_OTP_PTR
:
143 case SIFIVE_U_OTP_PTRIM
:
146 case SIFIVE_U_OTP_PWE
:
147 s
->pwe
= val32
& SIFIVE_U_OTP_PWE_EN
;
149 /* PWE is enabled. Ignore PAS=1 (no redundancy cell) */
150 if (s
->pwe
&& !s
->pas
) {
151 if (GET_FUSEARRAY_BIT(s
->fuse_wo
, s
->pa
, s
->paio
)) {
152 qemu_log_mask(LOG_GUEST_ERROR
,
153 "write once error: idx<%u>, bit<%u>\n",
159 SET_FUSEARRAY_BIT(s
->fuse
, s
->pa
, s
->paio
, s
->pdin
);
161 /* write to backend */
163 blk_pwrite(s
->blk
, s
->pa
* SIFIVE_U_OTP_FUSE_WORD
,
164 &s
->fuse
[s
->pa
], SIFIVE_U_OTP_FUSE_WORD
, 0);
167 /* update written bit */
168 SET_FUSEARRAY_BIT(s
->fuse_wo
, s
->pa
, s
->paio
, WRITTEN_BIT_ON
);
173 qemu_log_mask(LOG_GUEST_ERROR
, "%s: bad write: addr=0x%" HWADDR_PRIx
174 " v=0x%x\n", __func__
, addr
, val32
);
178 static const MemoryRegionOps sifive_u_otp_ops
= {
179 .read
= sifive_u_otp_read
,
180 .write
= sifive_u_otp_write
,
181 .endianness
= DEVICE_NATIVE_ENDIAN
,
183 .min_access_size
= 4,
188 static Property sifive_u_otp_properties
[] = {
189 DEFINE_PROP_UINT32("serial", SiFiveUOTPState
, serial
, 0),
190 DEFINE_PROP_DRIVE("drive", SiFiveUOTPState
, blk
),
191 DEFINE_PROP_END_OF_LIST(),
194 static void sifive_u_otp_realize(DeviceState
*dev
, Error
**errp
)
196 SiFiveUOTPState
*s
= SIFIVE_U_OTP(dev
);
199 memory_region_init_io(&s
->mmio
, OBJECT(dev
), &sifive_u_otp_ops
, s
,
200 TYPE_SIFIVE_U_OTP
, SIFIVE_U_OTP_REG_SIZE
);
201 sysbus_init_mmio(SYS_BUS_DEVICE(dev
), &s
->mmio
);
203 dinfo
= drive_get_next(IF_NONE
);
210 blk
= blk_by_legacy_dinfo(dinfo
);
211 filesize
= SIFIVE_U_OTP_NUM_FUSES
* SIFIVE_U_OTP_FUSE_WORD
;
212 if (blk_getlength(blk
) < filesize
) {
213 error_setg(errp
, "OTP drive size < 16K");
217 qdev_prop_set_drive_err(dev
, "drive", blk
, errp
);
220 perm
= BLK_PERM_CONSISTENT_READ
|
221 (blk_is_read_only(s
->blk
) ? 0 : BLK_PERM_WRITE
);
222 ret
= blk_set_perm(s
->blk
, perm
, BLK_PERM_ALL
, errp
);
227 if (blk_pread(s
->blk
, 0, s
->fuse
, filesize
) != filesize
) {
228 error_setg(errp
, "failed to read the initial flash content");
234 static void sifive_u_otp_reset(DeviceState
*dev
)
236 SiFiveUOTPState
*s
= SIFIVE_U_OTP(dev
);
238 /* Initialize all fuses' initial value to 0xFFs */
239 memset(s
->fuse
, 0xff, sizeof(s
->fuse
));
241 /* Make a valid content of serial number */
242 s
->fuse
[SIFIVE_U_OTP_SERIAL_ADDR
] = s
->serial
;
243 s
->fuse
[SIFIVE_U_OTP_SERIAL_ADDR
+ 1] = ~(s
->serial
);
246 /* Put serial number to backend as well*/
247 uint32_t serial_data
;
248 int index
= SIFIVE_U_OTP_SERIAL_ADDR
;
250 serial_data
= s
->serial
;
251 blk_pwrite(s
->blk
, index
* SIFIVE_U_OTP_FUSE_WORD
,
252 &serial_data
, SIFIVE_U_OTP_FUSE_WORD
, 0);
254 serial_data
= ~(s
->serial
);
255 blk_pwrite(s
->blk
, (index
+ 1) * SIFIVE_U_OTP_FUSE_WORD
,
256 &serial_data
, SIFIVE_U_OTP_FUSE_WORD
, 0);
259 /* Initialize write-once map */
260 memset(s
->fuse_wo
, 0x00, sizeof(s
->fuse_wo
));
263 static void sifive_u_otp_class_init(ObjectClass
*klass
, void *data
)
265 DeviceClass
*dc
= DEVICE_CLASS(klass
);
267 device_class_set_props(dc
, sifive_u_otp_properties
);
268 dc
->realize
= sifive_u_otp_realize
;
269 dc
->reset
= sifive_u_otp_reset
;
272 static const TypeInfo sifive_u_otp_info
= {
273 .name
= TYPE_SIFIVE_U_OTP
,
274 .parent
= TYPE_SYS_BUS_DEVICE
,
275 .instance_size
= sizeof(SiFiveUOTPState
),
276 .class_init
= sifive_u_otp_class_init
,
279 static void sifive_u_otp_register_types(void)
281 type_register_static(&sifive_u_otp_info
);
284 type_init(sifive_u_otp_register_types
)