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 blk_pread(s
->blk
, s
->pa
* SIFIVE_U_OTP_FUSE_WORD
, &buf
,
67 SIFIVE_U_OTP_FUSE_WORD
);
71 return s
->fuse
[s
->pa
& SIFIVE_U_OTP_PA_MASK
];
75 case SIFIVE_U_OTP_PDSTB
:
77 case SIFIVE_U_OTP_PPROG
:
79 case SIFIVE_U_OTP_PTC
:
81 case SIFIVE_U_OTP_PTM
:
83 case SIFIVE_U_OTP_PTM_REP
:
85 case SIFIVE_U_OTP_PTR
:
87 case SIFIVE_U_OTP_PTRIM
:
89 case SIFIVE_U_OTP_PWE
:
93 qemu_log_mask(LOG_GUEST_ERROR
, "%s: read: addr=0x%" HWADDR_PRIx
"\n",
98 static void sifive_u_otp_write(void *opaque
, hwaddr addr
,
99 uint64_t val64
, unsigned int size
)
101 SiFiveUOTPState
*s
= opaque
;
102 uint32_t val32
= (uint32_t)val64
;
105 case SIFIVE_U_OTP_PA
:
106 s
->pa
= val32
& SIFIVE_U_OTP_PA_MASK
;
108 case SIFIVE_U_OTP_PAIO
:
111 case SIFIVE_U_OTP_PAS
:
114 case SIFIVE_U_OTP_PCE
:
117 case SIFIVE_U_OTP_PCLK
:
120 case SIFIVE_U_OTP_PDIN
:
123 case SIFIVE_U_OTP_PDOUT
:
126 case SIFIVE_U_OTP_PDSTB
:
129 case SIFIVE_U_OTP_PPROG
:
132 case SIFIVE_U_OTP_PTC
:
135 case SIFIVE_U_OTP_PTM
:
138 case SIFIVE_U_OTP_PTM_REP
:
141 case SIFIVE_U_OTP_PTR
:
144 case SIFIVE_U_OTP_PTRIM
:
147 case SIFIVE_U_OTP_PWE
:
148 s
->pwe
= val32
& SIFIVE_U_OTP_PWE_EN
;
150 /* PWE is enabled. Ignore PAS=1 (no redundancy cell) */
151 if (s
->pwe
&& !s
->pas
) {
152 if (GET_FUSEARRAY_BIT(s
->fuse_wo
, s
->pa
, s
->paio
)) {
153 qemu_log_mask(LOG_GUEST_ERROR
,
154 "write once error: idx<%u>, bit<%u>\n",
160 SET_FUSEARRAY_BIT(s
->fuse
, s
->pa
, s
->paio
, s
->pdin
);
162 /* write to backend */
164 blk_pwrite(s
->blk
, s
->pa
* SIFIVE_U_OTP_FUSE_WORD
,
165 &s
->fuse
[s
->pa
], SIFIVE_U_OTP_FUSE_WORD
, 0);
168 /* update written bit */
169 SET_FUSEARRAY_BIT(s
->fuse_wo
, s
->pa
, s
->paio
, WRITTEN_BIT_ON
);
174 qemu_log_mask(LOG_GUEST_ERROR
, "%s: bad write: addr=0x%" HWADDR_PRIx
175 " v=0x%x\n", __func__
, addr
, val32
);
179 static const MemoryRegionOps sifive_u_otp_ops
= {
180 .read
= sifive_u_otp_read
,
181 .write
= sifive_u_otp_write
,
182 .endianness
= DEVICE_NATIVE_ENDIAN
,
184 .min_access_size
= 4,
189 static Property sifive_u_otp_properties
[] = {
190 DEFINE_PROP_UINT32("serial", SiFiveUOTPState
, serial
, 0),
191 DEFINE_PROP_DRIVE("drive", SiFiveUOTPState
, blk
),
192 DEFINE_PROP_END_OF_LIST(),
195 static void sifive_u_otp_realize(DeviceState
*dev
, Error
**errp
)
197 SiFiveUOTPState
*s
= SIFIVE_U_OTP(dev
);
200 memory_region_init_io(&s
->mmio
, OBJECT(dev
), &sifive_u_otp_ops
, s
,
201 TYPE_SIFIVE_U_OTP
, SIFIVE_U_OTP_REG_SIZE
);
202 sysbus_init_mmio(SYS_BUS_DEVICE(dev
), &s
->mmio
);
204 dinfo
= drive_get_next(IF_NONE
);
211 blk
= blk_by_legacy_dinfo(dinfo
);
212 filesize
= SIFIVE_U_OTP_NUM_FUSES
* SIFIVE_U_OTP_FUSE_WORD
;
213 if (blk_getlength(blk
) < filesize
) {
214 error_setg(errp
, "OTP drive size < 16K");
218 qdev_prop_set_drive_err(dev
, "drive", blk
, errp
);
221 perm
= BLK_PERM_CONSISTENT_READ
|
222 (blk_is_read_only(s
->blk
) ? 0 : BLK_PERM_WRITE
);
223 ret
= blk_set_perm(s
->blk
, perm
, BLK_PERM_ALL
, errp
);
228 if (blk_pread(s
->blk
, 0, s
->fuse
, filesize
) != filesize
) {
229 error_setg(errp
, "failed to read the initial flash content");
235 static void sifive_u_otp_reset(DeviceState
*dev
)
237 SiFiveUOTPState
*s
= SIFIVE_U_OTP(dev
);
239 /* Initialize all fuses' initial value to 0xFFs */
240 memset(s
->fuse
, 0xff, sizeof(s
->fuse
));
242 /* Make a valid content of serial number */
243 s
->fuse
[SIFIVE_U_OTP_SERIAL_ADDR
] = s
->serial
;
244 s
->fuse
[SIFIVE_U_OTP_SERIAL_ADDR
+ 1] = ~(s
->serial
);
247 /* Put serial number to backend as well*/
248 uint32_t serial_data
;
249 int index
= SIFIVE_U_OTP_SERIAL_ADDR
;
251 serial_data
= s
->serial
;
252 blk_pwrite(s
->blk
, index
* SIFIVE_U_OTP_FUSE_WORD
,
253 &serial_data
, SIFIVE_U_OTP_FUSE_WORD
, 0);
255 serial_data
= ~(s
->serial
);
256 blk_pwrite(s
->blk
, (index
+ 1) * SIFIVE_U_OTP_FUSE_WORD
,
257 &serial_data
, SIFIVE_U_OTP_FUSE_WORD
, 0);
260 /* Initialize write-once map */
261 memset(s
->fuse_wo
, 0x00, sizeof(s
->fuse_wo
));
264 static void sifive_u_otp_class_init(ObjectClass
*klass
, void *data
)
266 DeviceClass
*dc
= DEVICE_CLASS(klass
);
268 device_class_set_props(dc
, sifive_u_otp_properties
);
269 dc
->realize
= sifive_u_otp_realize
;
270 dc
->reset
= sifive_u_otp_reset
;
273 static const TypeInfo sifive_u_otp_info
= {
274 .name
= TYPE_SIFIVE_U_OTP
,
275 .parent
= TYPE_SYS_BUS_DEVICE
,
276 .instance_size
= sizeof(SiFiveUOTPState
),
277 .class_init
= sifive_u_otp_class_init
,
280 static void sifive_u_otp_register_types(void)
282 type_register_static(&sifive_u_otp_info
);
285 type_init(sifive_u_otp_register_types
)