10fa9e329SBin Meng /* 20fa9e329SBin Meng * QEMU SiFive U OTP (One-Time Programmable) Memory interface 30fa9e329SBin Meng * 40fa9e329SBin Meng * Copyright (c) 2019 Bin Meng <bmeng.cn@gmail.com> 50fa9e329SBin Meng * 60fa9e329SBin Meng * Simple model of the OTP to emulate register reads made by the SDK BSP 70fa9e329SBin Meng * 80fa9e329SBin Meng * This program is free software; you can redistribute it and/or modify it 90fa9e329SBin Meng * under the terms and conditions of the GNU General Public License, 100fa9e329SBin Meng * version 2 or later, as published by the Free Software Foundation. 110fa9e329SBin Meng * 120fa9e329SBin Meng * This program is distributed in the hope it will be useful, but WITHOUT 130fa9e329SBin Meng * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 140fa9e329SBin Meng * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 150fa9e329SBin Meng * more details. 160fa9e329SBin Meng * 170fa9e329SBin Meng * You should have received a copy of the GNU General Public License along with 180fa9e329SBin Meng * this program. If not, see <http://www.gnu.org/licenses/>. 190fa9e329SBin Meng */ 200fa9e329SBin Meng 210fa9e329SBin Meng #include "qemu/osdep.h" 22*51b6c1bbSGreen Wan #include "qapi/error.h" 230fa9e329SBin Meng #include "hw/qdev-properties.h" 240fa9e329SBin Meng #include "hw/sysbus.h" 250fa9e329SBin Meng #include "qemu/log.h" 260fa9e329SBin Meng #include "qemu/module.h" 270fa9e329SBin Meng #include "hw/misc/sifive_u_otp.h" 28*51b6c1bbSGreen Wan #include "sysemu/blockdev.h" 29*51b6c1bbSGreen Wan #include "sysemu/block-backend.h" 300fa9e329SBin Meng 31a54d2591SGreen Wan #define WRITTEN_BIT_ON 0x1 32a54d2591SGreen Wan 33a54d2591SGreen Wan #define SET_FUSEARRAY_BIT(map, i, off, bit) \ 34a54d2591SGreen Wan map[i] = bit ? (map[i] | bit << off) : (map[i] & ~(0x1 << off)) 35a54d2591SGreen Wan 36a54d2591SGreen Wan #define GET_FUSEARRAY_BIT(map, i, off) \ 37a54d2591SGreen Wan ((map[i] >> off) & 0x1) 38a54d2591SGreen Wan 390fa9e329SBin Meng static uint64_t sifive_u_otp_read(void *opaque, hwaddr addr, unsigned int size) 400fa9e329SBin Meng { 410fa9e329SBin Meng SiFiveUOTPState *s = opaque; 420fa9e329SBin Meng 430fa9e329SBin Meng switch (addr) { 440fa9e329SBin Meng case SIFIVE_U_OTP_PA: 450fa9e329SBin Meng return s->pa; 460fa9e329SBin Meng case SIFIVE_U_OTP_PAIO: 470fa9e329SBin Meng return s->paio; 480fa9e329SBin Meng case SIFIVE_U_OTP_PAS: 490fa9e329SBin Meng return s->pas; 500fa9e329SBin Meng case SIFIVE_U_OTP_PCE: 510fa9e329SBin Meng return s->pce; 520fa9e329SBin Meng case SIFIVE_U_OTP_PCLK: 530fa9e329SBin Meng return s->pclk; 540fa9e329SBin Meng case SIFIVE_U_OTP_PDIN: 550fa9e329SBin Meng return s->pdin; 560fa9e329SBin Meng case SIFIVE_U_OTP_PDOUT: 570fa9e329SBin Meng if ((s->pce & SIFIVE_U_OTP_PCE_EN) && 580fa9e329SBin Meng (s->pdstb & SIFIVE_U_OTP_PDSTB_EN) && 590fa9e329SBin Meng (s->ptrim & SIFIVE_U_OTP_PTRIM_EN)) { 60*51b6c1bbSGreen Wan 61*51b6c1bbSGreen Wan /* read from backend */ 62*51b6c1bbSGreen Wan if (s->blk) { 63*51b6c1bbSGreen Wan int32_t buf; 64*51b6c1bbSGreen Wan 65*51b6c1bbSGreen Wan blk_pread(s->blk, s->pa * SIFIVE_U_OTP_FUSE_WORD, &buf, 66*51b6c1bbSGreen Wan SIFIVE_U_OTP_FUSE_WORD); 67*51b6c1bbSGreen Wan return buf; 68*51b6c1bbSGreen Wan } 69*51b6c1bbSGreen Wan 700fa9e329SBin Meng return s->fuse[s->pa & SIFIVE_U_OTP_PA_MASK]; 710fa9e329SBin Meng } else { 720fa9e329SBin Meng return 0xff; 730fa9e329SBin Meng } 740fa9e329SBin Meng case SIFIVE_U_OTP_PDSTB: 750fa9e329SBin Meng return s->pdstb; 760fa9e329SBin Meng case SIFIVE_U_OTP_PPROG: 770fa9e329SBin Meng return s->pprog; 780fa9e329SBin Meng case SIFIVE_U_OTP_PTC: 790fa9e329SBin Meng return s->ptc; 800fa9e329SBin Meng case SIFIVE_U_OTP_PTM: 810fa9e329SBin Meng return s->ptm; 820fa9e329SBin Meng case SIFIVE_U_OTP_PTM_REP: 830fa9e329SBin Meng return s->ptm_rep; 840fa9e329SBin Meng case SIFIVE_U_OTP_PTR: 850fa9e329SBin Meng return s->ptr; 860fa9e329SBin Meng case SIFIVE_U_OTP_PTRIM: 870fa9e329SBin Meng return s->ptrim; 880fa9e329SBin Meng case SIFIVE_U_OTP_PWE: 890fa9e329SBin Meng return s->pwe; 900fa9e329SBin Meng } 910fa9e329SBin Meng 920fa9e329SBin Meng qemu_log_mask(LOG_GUEST_ERROR, "%s: read: addr=0x%" HWADDR_PRIx "\n", 930fa9e329SBin Meng __func__, addr); 940fa9e329SBin Meng return 0; 950fa9e329SBin Meng } 960fa9e329SBin Meng 970fa9e329SBin Meng static void sifive_u_otp_write(void *opaque, hwaddr addr, 980fa9e329SBin Meng uint64_t val64, unsigned int size) 990fa9e329SBin Meng { 1000fa9e329SBin Meng SiFiveUOTPState *s = opaque; 1010fa9e329SBin Meng uint32_t val32 = (uint32_t)val64; 1020fa9e329SBin Meng 1030fa9e329SBin Meng switch (addr) { 1040fa9e329SBin Meng case SIFIVE_U_OTP_PA: 1050fa9e329SBin Meng s->pa = val32 & SIFIVE_U_OTP_PA_MASK; 1060fa9e329SBin Meng break; 1070fa9e329SBin Meng case SIFIVE_U_OTP_PAIO: 1080fa9e329SBin Meng s->paio = val32; 1090fa9e329SBin Meng break; 1100fa9e329SBin Meng case SIFIVE_U_OTP_PAS: 1110fa9e329SBin Meng s->pas = val32; 1120fa9e329SBin Meng break; 1130fa9e329SBin Meng case SIFIVE_U_OTP_PCE: 1140fa9e329SBin Meng s->pce = val32; 1150fa9e329SBin Meng break; 1160fa9e329SBin Meng case SIFIVE_U_OTP_PCLK: 1170fa9e329SBin Meng s->pclk = val32; 1180fa9e329SBin Meng break; 1190fa9e329SBin Meng case SIFIVE_U_OTP_PDIN: 1200fa9e329SBin Meng s->pdin = val32; 1210fa9e329SBin Meng break; 1220fa9e329SBin Meng case SIFIVE_U_OTP_PDOUT: 1230fa9e329SBin Meng /* read-only */ 1240fa9e329SBin Meng break; 1250fa9e329SBin Meng case SIFIVE_U_OTP_PDSTB: 1260fa9e329SBin Meng s->pdstb = val32; 1270fa9e329SBin Meng break; 1280fa9e329SBin Meng case SIFIVE_U_OTP_PPROG: 1290fa9e329SBin Meng s->pprog = val32; 1300fa9e329SBin Meng break; 1310fa9e329SBin Meng case SIFIVE_U_OTP_PTC: 1320fa9e329SBin Meng s->ptc = val32; 1330fa9e329SBin Meng break; 1340fa9e329SBin Meng case SIFIVE_U_OTP_PTM: 1350fa9e329SBin Meng s->ptm = val32; 1360fa9e329SBin Meng break; 1370fa9e329SBin Meng case SIFIVE_U_OTP_PTM_REP: 1380fa9e329SBin Meng s->ptm_rep = val32; 1390fa9e329SBin Meng break; 1400fa9e329SBin Meng case SIFIVE_U_OTP_PTR: 1410fa9e329SBin Meng s->ptr = val32; 1420fa9e329SBin Meng break; 1430fa9e329SBin Meng case SIFIVE_U_OTP_PTRIM: 1440fa9e329SBin Meng s->ptrim = val32; 1450fa9e329SBin Meng break; 1460fa9e329SBin Meng case SIFIVE_U_OTP_PWE: 147a54d2591SGreen Wan s->pwe = val32 & SIFIVE_U_OTP_PWE_EN; 148a54d2591SGreen Wan 149a54d2591SGreen Wan /* PWE is enabled. Ignore PAS=1 (no redundancy cell) */ 150a54d2591SGreen Wan if (s->pwe && !s->pas) { 151a54d2591SGreen Wan if (GET_FUSEARRAY_BIT(s->fuse_wo, s->pa, s->paio)) { 152a54d2591SGreen Wan qemu_log_mask(LOG_GUEST_ERROR, 153a54d2591SGreen Wan "write once error: idx<%u>, bit<%u>\n", 154a54d2591SGreen Wan s->pa, s->paio); 155a54d2591SGreen Wan break; 156a54d2591SGreen Wan } 157a54d2591SGreen Wan 158a54d2591SGreen Wan /* write bit data */ 159a54d2591SGreen Wan SET_FUSEARRAY_BIT(s->fuse, s->pa, s->paio, s->pdin); 160a54d2591SGreen Wan 161*51b6c1bbSGreen Wan /* write to backend */ 162*51b6c1bbSGreen Wan if (s->blk) { 163*51b6c1bbSGreen Wan blk_pwrite(s->blk, s->pa * SIFIVE_U_OTP_FUSE_WORD, 164*51b6c1bbSGreen Wan &s->fuse[s->pa], SIFIVE_U_OTP_FUSE_WORD, 0); 165*51b6c1bbSGreen Wan } 166*51b6c1bbSGreen Wan 167a54d2591SGreen Wan /* update written bit */ 168a54d2591SGreen Wan SET_FUSEARRAY_BIT(s->fuse_wo, s->pa, s->paio, WRITTEN_BIT_ON); 169a54d2591SGreen Wan } 170a54d2591SGreen Wan 1710fa9e329SBin Meng break; 1720fa9e329SBin Meng default: 1730fa9e329SBin Meng qemu_log_mask(LOG_GUEST_ERROR, "%s: bad write: addr=0x%" HWADDR_PRIx 1740fa9e329SBin Meng " v=0x%x\n", __func__, addr, val32); 1750fa9e329SBin Meng } 1760fa9e329SBin Meng } 1770fa9e329SBin Meng 1780fa9e329SBin Meng static const MemoryRegionOps sifive_u_otp_ops = { 1790fa9e329SBin Meng .read = sifive_u_otp_read, 1800fa9e329SBin Meng .write = sifive_u_otp_write, 1810fa9e329SBin Meng .endianness = DEVICE_NATIVE_ENDIAN, 1820fa9e329SBin Meng .valid = { 1830fa9e329SBin Meng .min_access_size = 4, 1840fa9e329SBin Meng .max_access_size = 4 1850fa9e329SBin Meng } 1860fa9e329SBin Meng }; 1870fa9e329SBin Meng 1880fa9e329SBin Meng static Property sifive_u_otp_properties[] = { 1890fa9e329SBin Meng DEFINE_PROP_UINT32("serial", SiFiveUOTPState, serial, 0), 190*51b6c1bbSGreen Wan DEFINE_PROP_DRIVE("drive", SiFiveUOTPState, blk), 1910fa9e329SBin Meng DEFINE_PROP_END_OF_LIST(), 1920fa9e329SBin Meng }; 1930fa9e329SBin Meng 1940fa9e329SBin Meng static void sifive_u_otp_realize(DeviceState *dev, Error **errp) 1950fa9e329SBin Meng { 1960fa9e329SBin Meng SiFiveUOTPState *s = SIFIVE_U_OTP(dev); 197*51b6c1bbSGreen Wan DriveInfo *dinfo; 1980fa9e329SBin Meng 1990fa9e329SBin Meng memory_region_init_io(&s->mmio, OBJECT(dev), &sifive_u_otp_ops, s, 2000fa9e329SBin Meng TYPE_SIFIVE_U_OTP, SIFIVE_U_OTP_REG_SIZE); 2010fa9e329SBin Meng sysbus_init_mmio(SYS_BUS_DEVICE(dev), &s->mmio); 202*51b6c1bbSGreen Wan 203*51b6c1bbSGreen Wan dinfo = drive_get_next(IF_NONE); 204*51b6c1bbSGreen Wan if (dinfo) { 205*51b6c1bbSGreen Wan int ret; 206*51b6c1bbSGreen Wan uint64_t perm; 207*51b6c1bbSGreen Wan int filesize; 208*51b6c1bbSGreen Wan BlockBackend *blk; 209*51b6c1bbSGreen Wan 210*51b6c1bbSGreen Wan blk = blk_by_legacy_dinfo(dinfo); 211*51b6c1bbSGreen Wan filesize = SIFIVE_U_OTP_NUM_FUSES * SIFIVE_U_OTP_FUSE_WORD; 212*51b6c1bbSGreen Wan if (blk_getlength(blk) < filesize) { 213*51b6c1bbSGreen Wan error_setg(errp, "OTP drive size < 16K"); 214*51b6c1bbSGreen Wan return; 215*51b6c1bbSGreen Wan } 216*51b6c1bbSGreen Wan 217*51b6c1bbSGreen Wan qdev_prop_set_drive_err(dev, "drive", blk, errp); 218*51b6c1bbSGreen Wan 219*51b6c1bbSGreen Wan if (s->blk) { 220*51b6c1bbSGreen Wan perm = BLK_PERM_CONSISTENT_READ | 221*51b6c1bbSGreen Wan (blk_is_read_only(s->blk) ? 0 : BLK_PERM_WRITE); 222*51b6c1bbSGreen Wan ret = blk_set_perm(s->blk, perm, BLK_PERM_ALL, errp); 223*51b6c1bbSGreen Wan if (ret < 0) { 224*51b6c1bbSGreen Wan return; 225*51b6c1bbSGreen Wan } 226*51b6c1bbSGreen Wan 227*51b6c1bbSGreen Wan if (blk_pread(s->blk, 0, s->fuse, filesize) != filesize) { 228*51b6c1bbSGreen Wan error_setg(errp, "failed to read the initial flash content"); 229*51b6c1bbSGreen Wan } 230*51b6c1bbSGreen Wan } 231*51b6c1bbSGreen Wan } 2320fa9e329SBin Meng } 2330fa9e329SBin Meng 2340fa9e329SBin Meng static void sifive_u_otp_reset(DeviceState *dev) 2350fa9e329SBin Meng { 2360fa9e329SBin Meng SiFiveUOTPState *s = SIFIVE_U_OTP(dev); 2370fa9e329SBin Meng 2380fa9e329SBin Meng /* Initialize all fuses' initial value to 0xFFs */ 2390fa9e329SBin Meng memset(s->fuse, 0xff, sizeof(s->fuse)); 2400fa9e329SBin Meng 2410fa9e329SBin Meng /* Make a valid content of serial number */ 2420fa9e329SBin Meng s->fuse[SIFIVE_U_OTP_SERIAL_ADDR] = s->serial; 2430fa9e329SBin Meng s->fuse[SIFIVE_U_OTP_SERIAL_ADDR + 1] = ~(s->serial); 244a54d2591SGreen Wan 245*51b6c1bbSGreen Wan if (s->blk) { 246*51b6c1bbSGreen Wan /* Put serial number to backend as well*/ 247*51b6c1bbSGreen Wan uint32_t serial_data; 248*51b6c1bbSGreen Wan int index = SIFIVE_U_OTP_SERIAL_ADDR; 249*51b6c1bbSGreen Wan 250*51b6c1bbSGreen Wan serial_data = s->serial; 251*51b6c1bbSGreen Wan blk_pwrite(s->blk, index * SIFIVE_U_OTP_FUSE_WORD, 252*51b6c1bbSGreen Wan &serial_data, SIFIVE_U_OTP_FUSE_WORD, 0); 253*51b6c1bbSGreen Wan 254*51b6c1bbSGreen Wan serial_data = ~(s->serial); 255*51b6c1bbSGreen Wan blk_pwrite(s->blk, (index + 1) * SIFIVE_U_OTP_FUSE_WORD, 256*51b6c1bbSGreen Wan &serial_data, SIFIVE_U_OTP_FUSE_WORD, 0); 257*51b6c1bbSGreen Wan } 258*51b6c1bbSGreen Wan 259a54d2591SGreen Wan /* Initialize write-once map */ 260a54d2591SGreen Wan memset(s->fuse_wo, 0x00, sizeof(s->fuse_wo)); 2610fa9e329SBin Meng } 2620fa9e329SBin Meng 2630fa9e329SBin Meng static void sifive_u_otp_class_init(ObjectClass *klass, void *data) 2640fa9e329SBin Meng { 2650fa9e329SBin Meng DeviceClass *dc = DEVICE_CLASS(klass); 2660fa9e329SBin Meng 2670fa9e329SBin Meng device_class_set_props(dc, sifive_u_otp_properties); 2680fa9e329SBin Meng dc->realize = sifive_u_otp_realize; 2690fa9e329SBin Meng dc->reset = sifive_u_otp_reset; 2700fa9e329SBin Meng } 2710fa9e329SBin Meng 2720fa9e329SBin Meng static const TypeInfo sifive_u_otp_info = { 2730fa9e329SBin Meng .name = TYPE_SIFIVE_U_OTP, 2740fa9e329SBin Meng .parent = TYPE_SYS_BUS_DEVICE, 2750fa9e329SBin Meng .instance_size = sizeof(SiFiveUOTPState), 2760fa9e329SBin Meng .class_init = sifive_u_otp_class_init, 2770fa9e329SBin Meng }; 2780fa9e329SBin Meng 2790fa9e329SBin Meng static void sifive_u_otp_register_types(void) 2800fa9e329SBin Meng { 2810fa9e329SBin Meng type_register_static(&sifive_u_otp_info); 2820fa9e329SBin Meng } 2830fa9e329SBin Meng 2840fa9e329SBin Meng type_init(sifive_u_otp_register_types) 285