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 "hw/qdev-properties.h" 23 #include "hw/sysbus.h" 24 #include "qemu/log.h" 25 #include "qemu/module.h" 26 #include "hw/misc/sifive_u_otp.h" 27 28 static uint64_t sifive_u_otp_read(void *opaque, hwaddr addr, unsigned int size) 29 { 30 SiFiveUOTPState *s = opaque; 31 32 switch (addr) { 33 case SIFIVE_U_OTP_PA: 34 return s->pa; 35 case SIFIVE_U_OTP_PAIO: 36 return s->paio; 37 case SIFIVE_U_OTP_PAS: 38 return s->pas; 39 case SIFIVE_U_OTP_PCE: 40 return s->pce; 41 case SIFIVE_U_OTP_PCLK: 42 return s->pclk; 43 case SIFIVE_U_OTP_PDIN: 44 return s->pdin; 45 case SIFIVE_U_OTP_PDOUT: 46 if ((s->pce & SIFIVE_U_OTP_PCE_EN) && 47 (s->pdstb & SIFIVE_U_OTP_PDSTB_EN) && 48 (s->ptrim & SIFIVE_U_OTP_PTRIM_EN)) { 49 return s->fuse[s->pa & SIFIVE_U_OTP_PA_MASK]; 50 } else { 51 return 0xff; 52 } 53 case SIFIVE_U_OTP_PDSTB: 54 return s->pdstb; 55 case SIFIVE_U_OTP_PPROG: 56 return s->pprog; 57 case SIFIVE_U_OTP_PTC: 58 return s->ptc; 59 case SIFIVE_U_OTP_PTM: 60 return s->ptm; 61 case SIFIVE_U_OTP_PTM_REP: 62 return s->ptm_rep; 63 case SIFIVE_U_OTP_PTR: 64 return s->ptr; 65 case SIFIVE_U_OTP_PTRIM: 66 return s->ptrim; 67 case SIFIVE_U_OTP_PWE: 68 return s->pwe; 69 } 70 71 qemu_log_mask(LOG_GUEST_ERROR, "%s: read: addr=0x%" HWADDR_PRIx "\n", 72 __func__, addr); 73 return 0; 74 } 75 76 static void sifive_u_otp_write(void *opaque, hwaddr addr, 77 uint64_t val64, unsigned int size) 78 { 79 SiFiveUOTPState *s = opaque; 80 uint32_t val32 = (uint32_t)val64; 81 82 switch (addr) { 83 case SIFIVE_U_OTP_PA: 84 s->pa = val32 & SIFIVE_U_OTP_PA_MASK; 85 break; 86 case SIFIVE_U_OTP_PAIO: 87 s->paio = val32; 88 break; 89 case SIFIVE_U_OTP_PAS: 90 s->pas = val32; 91 break; 92 case SIFIVE_U_OTP_PCE: 93 s->pce = val32; 94 break; 95 case SIFIVE_U_OTP_PCLK: 96 s->pclk = val32; 97 break; 98 case SIFIVE_U_OTP_PDIN: 99 s->pdin = val32; 100 break; 101 case SIFIVE_U_OTP_PDOUT: 102 /* read-only */ 103 break; 104 case SIFIVE_U_OTP_PDSTB: 105 s->pdstb = val32; 106 break; 107 case SIFIVE_U_OTP_PPROG: 108 s->pprog = val32; 109 break; 110 case SIFIVE_U_OTP_PTC: 111 s->ptc = val32; 112 break; 113 case SIFIVE_U_OTP_PTM: 114 s->ptm = val32; 115 break; 116 case SIFIVE_U_OTP_PTM_REP: 117 s->ptm_rep = val32; 118 break; 119 case SIFIVE_U_OTP_PTR: 120 s->ptr = val32; 121 break; 122 case SIFIVE_U_OTP_PTRIM: 123 s->ptrim = val32; 124 break; 125 case SIFIVE_U_OTP_PWE: 126 s->pwe = val32; 127 break; 128 default: 129 qemu_log_mask(LOG_GUEST_ERROR, "%s: bad write: addr=0x%" HWADDR_PRIx 130 " v=0x%x\n", __func__, addr, val32); 131 } 132 } 133 134 static const MemoryRegionOps sifive_u_otp_ops = { 135 .read = sifive_u_otp_read, 136 .write = sifive_u_otp_write, 137 .endianness = DEVICE_NATIVE_ENDIAN, 138 .valid = { 139 .min_access_size = 4, 140 .max_access_size = 4 141 } 142 }; 143 144 static Property sifive_u_otp_properties[] = { 145 DEFINE_PROP_UINT32("serial", SiFiveUOTPState, serial, 0), 146 DEFINE_PROP_END_OF_LIST(), 147 }; 148 149 static void sifive_u_otp_realize(DeviceState *dev, Error **errp) 150 { 151 SiFiveUOTPState *s = SIFIVE_U_OTP(dev); 152 153 memory_region_init_io(&s->mmio, OBJECT(dev), &sifive_u_otp_ops, s, 154 TYPE_SIFIVE_U_OTP, SIFIVE_U_OTP_REG_SIZE); 155 sysbus_init_mmio(SYS_BUS_DEVICE(dev), &s->mmio); 156 } 157 158 static void sifive_u_otp_reset(DeviceState *dev) 159 { 160 SiFiveUOTPState *s = SIFIVE_U_OTP(dev); 161 162 /* Initialize all fuses' initial value to 0xFFs */ 163 memset(s->fuse, 0xff, sizeof(s->fuse)); 164 165 /* Make a valid content of serial number */ 166 s->fuse[SIFIVE_U_OTP_SERIAL_ADDR] = s->serial; 167 s->fuse[SIFIVE_U_OTP_SERIAL_ADDR + 1] = ~(s->serial); 168 } 169 170 static void sifive_u_otp_class_init(ObjectClass *klass, void *data) 171 { 172 DeviceClass *dc = DEVICE_CLASS(klass); 173 174 device_class_set_props(dc, sifive_u_otp_properties); 175 dc->realize = sifive_u_otp_realize; 176 dc->reset = sifive_u_otp_reset; 177 } 178 179 static const TypeInfo sifive_u_otp_info = { 180 .name = TYPE_SIFIVE_U_OTP, 181 .parent = TYPE_SYS_BUS_DEVICE, 182 .instance_size = sizeof(SiFiveUOTPState), 183 .class_init = sifive_u_otp_class_init, 184 }; 185 186 static void sifive_u_otp_register_types(void) 187 { 188 type_register_static(&sifive_u_otp_info); 189 } 190 191 type_init(sifive_u_otp_register_types) 192