1 /* 2 * QEMU SiFive U OTP (One-Time Programmable) Memory interface 3 * 4 * Copyright (c) 2019 Bin Meng <bmeng.cn@gmail.com> 5 * 6 * Simple model of the OTP to emulate register reads made by the SDK BSP 7 * 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. 11 * 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 15 * more details. 16 * 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/>. 19 */ 20 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" 27 #include "qemu/log.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" 32 33 #define WRITTEN_BIT_ON 0x1 34 35 #define SET_FUSEARRAY_BIT(map, i, off, bit) \ 36 map[i] = bit ? (map[i] | bit << off) : (map[i] & ~(0x1 << off)) 37 38 #define GET_FUSEARRAY_BIT(map, i, off) \ 39 ((map[i] >> off) & 0x1) 40 41 static uint64_t sifive_u_otp_read(void *opaque, hwaddr addr, unsigned int size) 42 { 43 SiFiveUOTPState *s = opaque; 44 45 switch (addr) { 46 case SIFIVE_U_OTP_PA: 47 return s->pa; 48 case SIFIVE_U_OTP_PAIO: 49 return s->paio; 50 case SIFIVE_U_OTP_PAS: 51 return s->pas; 52 case SIFIVE_U_OTP_PCE: 53 return s->pce; 54 case SIFIVE_U_OTP_PCLK: 55 return s->pclk; 56 case SIFIVE_U_OTP_PDIN: 57 return s->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)) { 62 63 /* read from backend */ 64 if (s->blk) { 65 int32_t buf; 66 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); 70 return 0xff; 71 } 72 73 return buf; 74 } 75 76 return s->fuse[s->pa & SIFIVE_U_OTP_PA_MASK]; 77 } else { 78 return 0xff; 79 } 80 case SIFIVE_U_OTP_PDSTB: 81 return s->pdstb; 82 case SIFIVE_U_OTP_PPROG: 83 return s->pprog; 84 case SIFIVE_U_OTP_PTC: 85 return s->ptc; 86 case SIFIVE_U_OTP_PTM: 87 return s->ptm; 88 case SIFIVE_U_OTP_PTM_REP: 89 return s->ptm_rep; 90 case SIFIVE_U_OTP_PTR: 91 return s->ptr; 92 case SIFIVE_U_OTP_PTRIM: 93 return s->ptrim; 94 case SIFIVE_U_OTP_PWE: 95 return s->pwe; 96 } 97 98 qemu_log_mask(LOG_GUEST_ERROR, "%s: read: addr=0x%" HWADDR_PRIx "\n", 99 __func__, addr); 100 return 0; 101 } 102 103 static void sifive_u_otp_write(void *opaque, hwaddr addr, 104 uint64_t val64, unsigned int size) 105 { 106 SiFiveUOTPState *s = opaque; 107 uint32_t val32 = (uint32_t)val64; 108 109 switch (addr) { 110 case SIFIVE_U_OTP_PA: 111 s->pa = val32 & SIFIVE_U_OTP_PA_MASK; 112 break; 113 case SIFIVE_U_OTP_PAIO: 114 s->paio = val32; 115 break; 116 case SIFIVE_U_OTP_PAS: 117 s->pas = val32; 118 break; 119 case SIFIVE_U_OTP_PCE: 120 s->pce = val32; 121 break; 122 case SIFIVE_U_OTP_PCLK: 123 s->pclk = val32; 124 break; 125 case SIFIVE_U_OTP_PDIN: 126 s->pdin = val32; 127 break; 128 case SIFIVE_U_OTP_PDOUT: 129 /* read-only */ 130 break; 131 case SIFIVE_U_OTP_PDSTB: 132 s->pdstb = val32; 133 break; 134 case SIFIVE_U_OTP_PPROG: 135 s->pprog = val32; 136 break; 137 case SIFIVE_U_OTP_PTC: 138 s->ptc = val32; 139 break; 140 case SIFIVE_U_OTP_PTM: 141 s->ptm = val32; 142 break; 143 case SIFIVE_U_OTP_PTM_REP: 144 s->ptm_rep = val32; 145 break; 146 case SIFIVE_U_OTP_PTR: 147 s->ptr = val32; 148 break; 149 case SIFIVE_U_OTP_PTRIM: 150 s->ptrim = val32; 151 break; 152 case SIFIVE_U_OTP_PWE: 153 s->pwe = val32 & SIFIVE_U_OTP_PWE_EN; 154 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", 160 s->pa, s->paio); 161 break; 162 } 163 164 /* write bit data */ 165 SET_FUSEARRAY_BIT(s->fuse, s->pa, s->paio, s->pdin); 166 167 /* write to backend */ 168 if (s->blk) { 169 if (blk_pwrite(s->blk, s->pa * SIFIVE_U_OTP_FUSE_WORD, 170 &s->fuse[s->pa], SIFIVE_U_OTP_FUSE_WORD, 171 0) < 0) { 172 error_report("write error index<%d>", s->pa); 173 } 174 } 175 176 /* update written bit */ 177 SET_FUSEARRAY_BIT(s->fuse_wo, s->pa, s->paio, WRITTEN_BIT_ON); 178 } 179 180 break; 181 default: 182 qemu_log_mask(LOG_GUEST_ERROR, "%s: bad write: addr=0x%" HWADDR_PRIx 183 " v=0x%x\n", __func__, addr, val32); 184 } 185 } 186 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, 191 .valid = { 192 .min_access_size = 4, 193 .max_access_size = 4 194 } 195 }; 196 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(), 201 }; 202 203 static void sifive_u_otp_realize(DeviceState *dev, Error **errp) 204 { 205 SiFiveUOTPState *s = SIFIVE_U_OTP(dev); 206 DriveInfo *dinfo; 207 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); 211 212 dinfo = drive_get(IF_PFLASH, 0, 0); 213 if (!dinfo) { 214 dinfo = drive_get(IF_NONE, 0, 0); 215 if (dinfo) { 216 warn_report("using \"-drive if=none\" for the OTP is deprecated, " 217 "use \"-drive if=pflash\" instead."); 218 } 219 } 220 if (dinfo) { 221 int ret; 222 uint64_t perm; 223 int filesize; 224 BlockBackend *blk; 225 226 blk = blk_by_legacy_dinfo(dinfo); 227 filesize = SIFIVE_U_OTP_NUM_FUSES * SIFIVE_U_OTP_FUSE_WORD; 228 if (blk_getlength(blk) < filesize) { 229 error_setg(errp, "OTP drive size < 16K"); 230 return; 231 } 232 233 qdev_prop_set_drive_err(dev, "drive", blk, errp); 234 235 if (s->blk) { 236 perm = BLK_PERM_CONSISTENT_READ | 237 (blk_supports_write_perm(s->blk) ? BLK_PERM_WRITE : 0); 238 ret = blk_set_perm(s->blk, perm, BLK_PERM_ALL, errp); 239 if (ret < 0) { 240 return; 241 } 242 243 if (blk_pread(s->blk, 0, s->fuse, filesize) != filesize) { 244 error_setg(errp, "failed to read the initial flash content"); 245 return; 246 } 247 } 248 } 249 250 /* Initialize all fuses' initial value to 0xFFs */ 251 memset(s->fuse, 0xff, sizeof(s->fuse)); 252 253 /* Make a valid content of serial number */ 254 s->fuse[SIFIVE_U_OTP_SERIAL_ADDR] = s->serial; 255 s->fuse[SIFIVE_U_OTP_SERIAL_ADDR + 1] = ~(s->serial); 256 257 if (s->blk) { 258 /* Put serial number to backend as well*/ 259 uint32_t serial_data; 260 int index = SIFIVE_U_OTP_SERIAL_ADDR; 261 262 serial_data = s->serial; 263 if (blk_pwrite(s->blk, index * SIFIVE_U_OTP_FUSE_WORD, 264 &serial_data, SIFIVE_U_OTP_FUSE_WORD, 0) < 0) { 265 error_setg(errp, "failed to write index<%d>", index); 266 return; 267 } 268 269 serial_data = ~(s->serial); 270 if (blk_pwrite(s->blk, (index + 1) * SIFIVE_U_OTP_FUSE_WORD, 271 &serial_data, SIFIVE_U_OTP_FUSE_WORD, 0) < 0) { 272 error_setg(errp, "failed to write index<%d>", index + 1); 273 return; 274 } 275 } 276 277 /* Initialize write-once map */ 278 memset(s->fuse_wo, 0x00, sizeof(s->fuse_wo)); 279 } 280 281 static void sifive_u_otp_class_init(ObjectClass *klass, void *data) 282 { 283 DeviceClass *dc = DEVICE_CLASS(klass); 284 285 device_class_set_props(dc, sifive_u_otp_properties); 286 dc->realize = sifive_u_otp_realize; 287 } 288 289 static const TypeInfo sifive_u_otp_info = { 290 .name = TYPE_SIFIVE_U_OTP, 291 .parent = TYPE_SYS_BUS_DEVICE, 292 .instance_size = sizeof(SiFiveUOTPState), 293 .class_init = sifive_u_otp_class_init, 294 }; 295 296 static void sifive_u_otp_register_types(void) 297 { 298 type_register_static(&sifive_u_otp_info); 299 } 300 301 type_init(sifive_u_otp_register_types) 302