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" 220fa9e329SBin Meng #include "hw/qdev-properties.h" 230fa9e329SBin Meng #include "hw/sysbus.h" 240fa9e329SBin Meng #include "qemu/log.h" 250fa9e329SBin Meng #include "qemu/module.h" 260fa9e329SBin Meng #include "hw/misc/sifive_u_otp.h" 270fa9e329SBin Meng 28*a54d2591SGreen Wan #define WRITTEN_BIT_ON 0x1 29*a54d2591SGreen Wan 30*a54d2591SGreen Wan #define SET_FUSEARRAY_BIT(map, i, off, bit) \ 31*a54d2591SGreen Wan map[i] = bit ? (map[i] | bit << off) : (map[i] & ~(0x1 << off)) 32*a54d2591SGreen Wan 33*a54d2591SGreen Wan #define GET_FUSEARRAY_BIT(map, i, off) \ 34*a54d2591SGreen Wan ((map[i] >> off) & 0x1) 35*a54d2591SGreen Wan 360fa9e329SBin Meng static uint64_t sifive_u_otp_read(void *opaque, hwaddr addr, unsigned int size) 370fa9e329SBin Meng { 380fa9e329SBin Meng SiFiveUOTPState *s = opaque; 390fa9e329SBin Meng 400fa9e329SBin Meng switch (addr) { 410fa9e329SBin Meng case SIFIVE_U_OTP_PA: 420fa9e329SBin Meng return s->pa; 430fa9e329SBin Meng case SIFIVE_U_OTP_PAIO: 440fa9e329SBin Meng return s->paio; 450fa9e329SBin Meng case SIFIVE_U_OTP_PAS: 460fa9e329SBin Meng return s->pas; 470fa9e329SBin Meng case SIFIVE_U_OTP_PCE: 480fa9e329SBin Meng return s->pce; 490fa9e329SBin Meng case SIFIVE_U_OTP_PCLK: 500fa9e329SBin Meng return s->pclk; 510fa9e329SBin Meng case SIFIVE_U_OTP_PDIN: 520fa9e329SBin Meng return s->pdin; 530fa9e329SBin Meng case SIFIVE_U_OTP_PDOUT: 540fa9e329SBin Meng if ((s->pce & SIFIVE_U_OTP_PCE_EN) && 550fa9e329SBin Meng (s->pdstb & SIFIVE_U_OTP_PDSTB_EN) && 560fa9e329SBin Meng (s->ptrim & SIFIVE_U_OTP_PTRIM_EN)) { 570fa9e329SBin Meng return s->fuse[s->pa & SIFIVE_U_OTP_PA_MASK]; 580fa9e329SBin Meng } else { 590fa9e329SBin Meng return 0xff; 600fa9e329SBin Meng } 610fa9e329SBin Meng case SIFIVE_U_OTP_PDSTB: 620fa9e329SBin Meng return s->pdstb; 630fa9e329SBin Meng case SIFIVE_U_OTP_PPROG: 640fa9e329SBin Meng return s->pprog; 650fa9e329SBin Meng case SIFIVE_U_OTP_PTC: 660fa9e329SBin Meng return s->ptc; 670fa9e329SBin Meng case SIFIVE_U_OTP_PTM: 680fa9e329SBin Meng return s->ptm; 690fa9e329SBin Meng case SIFIVE_U_OTP_PTM_REP: 700fa9e329SBin Meng return s->ptm_rep; 710fa9e329SBin Meng case SIFIVE_U_OTP_PTR: 720fa9e329SBin Meng return s->ptr; 730fa9e329SBin Meng case SIFIVE_U_OTP_PTRIM: 740fa9e329SBin Meng return s->ptrim; 750fa9e329SBin Meng case SIFIVE_U_OTP_PWE: 760fa9e329SBin Meng return s->pwe; 770fa9e329SBin Meng } 780fa9e329SBin Meng 790fa9e329SBin Meng qemu_log_mask(LOG_GUEST_ERROR, "%s: read: addr=0x%" HWADDR_PRIx "\n", 800fa9e329SBin Meng __func__, addr); 810fa9e329SBin Meng return 0; 820fa9e329SBin Meng } 830fa9e329SBin Meng 840fa9e329SBin Meng static void sifive_u_otp_write(void *opaque, hwaddr addr, 850fa9e329SBin Meng uint64_t val64, unsigned int size) 860fa9e329SBin Meng { 870fa9e329SBin Meng SiFiveUOTPState *s = opaque; 880fa9e329SBin Meng uint32_t val32 = (uint32_t)val64; 890fa9e329SBin Meng 900fa9e329SBin Meng switch (addr) { 910fa9e329SBin Meng case SIFIVE_U_OTP_PA: 920fa9e329SBin Meng s->pa = val32 & SIFIVE_U_OTP_PA_MASK; 930fa9e329SBin Meng break; 940fa9e329SBin Meng case SIFIVE_U_OTP_PAIO: 950fa9e329SBin Meng s->paio = val32; 960fa9e329SBin Meng break; 970fa9e329SBin Meng case SIFIVE_U_OTP_PAS: 980fa9e329SBin Meng s->pas = val32; 990fa9e329SBin Meng break; 1000fa9e329SBin Meng case SIFIVE_U_OTP_PCE: 1010fa9e329SBin Meng s->pce = val32; 1020fa9e329SBin Meng break; 1030fa9e329SBin Meng case SIFIVE_U_OTP_PCLK: 1040fa9e329SBin Meng s->pclk = val32; 1050fa9e329SBin Meng break; 1060fa9e329SBin Meng case SIFIVE_U_OTP_PDIN: 1070fa9e329SBin Meng s->pdin = val32; 1080fa9e329SBin Meng break; 1090fa9e329SBin Meng case SIFIVE_U_OTP_PDOUT: 1100fa9e329SBin Meng /* read-only */ 1110fa9e329SBin Meng break; 1120fa9e329SBin Meng case SIFIVE_U_OTP_PDSTB: 1130fa9e329SBin Meng s->pdstb = val32; 1140fa9e329SBin Meng break; 1150fa9e329SBin Meng case SIFIVE_U_OTP_PPROG: 1160fa9e329SBin Meng s->pprog = val32; 1170fa9e329SBin Meng break; 1180fa9e329SBin Meng case SIFIVE_U_OTP_PTC: 1190fa9e329SBin Meng s->ptc = val32; 1200fa9e329SBin Meng break; 1210fa9e329SBin Meng case SIFIVE_U_OTP_PTM: 1220fa9e329SBin Meng s->ptm = val32; 1230fa9e329SBin Meng break; 1240fa9e329SBin Meng case SIFIVE_U_OTP_PTM_REP: 1250fa9e329SBin Meng s->ptm_rep = val32; 1260fa9e329SBin Meng break; 1270fa9e329SBin Meng case SIFIVE_U_OTP_PTR: 1280fa9e329SBin Meng s->ptr = val32; 1290fa9e329SBin Meng break; 1300fa9e329SBin Meng case SIFIVE_U_OTP_PTRIM: 1310fa9e329SBin Meng s->ptrim = val32; 1320fa9e329SBin Meng break; 1330fa9e329SBin Meng case SIFIVE_U_OTP_PWE: 134*a54d2591SGreen Wan s->pwe = val32 & SIFIVE_U_OTP_PWE_EN; 135*a54d2591SGreen Wan 136*a54d2591SGreen Wan /* PWE is enabled. Ignore PAS=1 (no redundancy cell) */ 137*a54d2591SGreen Wan if (s->pwe && !s->pas) { 138*a54d2591SGreen Wan if (GET_FUSEARRAY_BIT(s->fuse_wo, s->pa, s->paio)) { 139*a54d2591SGreen Wan qemu_log_mask(LOG_GUEST_ERROR, 140*a54d2591SGreen Wan "write once error: idx<%u>, bit<%u>\n", 141*a54d2591SGreen Wan s->pa, s->paio); 142*a54d2591SGreen Wan break; 143*a54d2591SGreen Wan } 144*a54d2591SGreen Wan 145*a54d2591SGreen Wan /* write bit data */ 146*a54d2591SGreen Wan SET_FUSEARRAY_BIT(s->fuse, s->pa, s->paio, s->pdin); 147*a54d2591SGreen Wan 148*a54d2591SGreen Wan /* update written bit */ 149*a54d2591SGreen Wan SET_FUSEARRAY_BIT(s->fuse_wo, s->pa, s->paio, WRITTEN_BIT_ON); 150*a54d2591SGreen Wan } 151*a54d2591SGreen Wan 1520fa9e329SBin Meng break; 1530fa9e329SBin Meng default: 1540fa9e329SBin Meng qemu_log_mask(LOG_GUEST_ERROR, "%s: bad write: addr=0x%" HWADDR_PRIx 1550fa9e329SBin Meng " v=0x%x\n", __func__, addr, val32); 1560fa9e329SBin Meng } 1570fa9e329SBin Meng } 1580fa9e329SBin Meng 1590fa9e329SBin Meng static const MemoryRegionOps sifive_u_otp_ops = { 1600fa9e329SBin Meng .read = sifive_u_otp_read, 1610fa9e329SBin Meng .write = sifive_u_otp_write, 1620fa9e329SBin Meng .endianness = DEVICE_NATIVE_ENDIAN, 1630fa9e329SBin Meng .valid = { 1640fa9e329SBin Meng .min_access_size = 4, 1650fa9e329SBin Meng .max_access_size = 4 1660fa9e329SBin Meng } 1670fa9e329SBin Meng }; 1680fa9e329SBin Meng 1690fa9e329SBin Meng static Property sifive_u_otp_properties[] = { 1700fa9e329SBin Meng DEFINE_PROP_UINT32("serial", SiFiveUOTPState, serial, 0), 1710fa9e329SBin Meng DEFINE_PROP_END_OF_LIST(), 1720fa9e329SBin Meng }; 1730fa9e329SBin Meng 1740fa9e329SBin Meng static void sifive_u_otp_realize(DeviceState *dev, Error **errp) 1750fa9e329SBin Meng { 1760fa9e329SBin Meng SiFiveUOTPState *s = SIFIVE_U_OTP(dev); 1770fa9e329SBin Meng 1780fa9e329SBin Meng memory_region_init_io(&s->mmio, OBJECT(dev), &sifive_u_otp_ops, s, 1790fa9e329SBin Meng TYPE_SIFIVE_U_OTP, SIFIVE_U_OTP_REG_SIZE); 1800fa9e329SBin Meng sysbus_init_mmio(SYS_BUS_DEVICE(dev), &s->mmio); 1810fa9e329SBin Meng } 1820fa9e329SBin Meng 1830fa9e329SBin Meng static void sifive_u_otp_reset(DeviceState *dev) 1840fa9e329SBin Meng { 1850fa9e329SBin Meng SiFiveUOTPState *s = SIFIVE_U_OTP(dev); 1860fa9e329SBin Meng 1870fa9e329SBin Meng /* Initialize all fuses' initial value to 0xFFs */ 1880fa9e329SBin Meng memset(s->fuse, 0xff, sizeof(s->fuse)); 1890fa9e329SBin Meng 1900fa9e329SBin Meng /* Make a valid content of serial number */ 1910fa9e329SBin Meng s->fuse[SIFIVE_U_OTP_SERIAL_ADDR] = s->serial; 1920fa9e329SBin Meng s->fuse[SIFIVE_U_OTP_SERIAL_ADDR + 1] = ~(s->serial); 193*a54d2591SGreen Wan 194*a54d2591SGreen Wan /* Initialize write-once map */ 195*a54d2591SGreen Wan memset(s->fuse_wo, 0x00, sizeof(s->fuse_wo)); 1960fa9e329SBin Meng } 1970fa9e329SBin Meng 1980fa9e329SBin Meng static void sifive_u_otp_class_init(ObjectClass *klass, void *data) 1990fa9e329SBin Meng { 2000fa9e329SBin Meng DeviceClass *dc = DEVICE_CLASS(klass); 2010fa9e329SBin Meng 2020fa9e329SBin Meng device_class_set_props(dc, sifive_u_otp_properties); 2030fa9e329SBin Meng dc->realize = sifive_u_otp_realize; 2040fa9e329SBin Meng dc->reset = sifive_u_otp_reset; 2050fa9e329SBin Meng } 2060fa9e329SBin Meng 2070fa9e329SBin Meng static const TypeInfo sifive_u_otp_info = { 2080fa9e329SBin Meng .name = TYPE_SIFIVE_U_OTP, 2090fa9e329SBin Meng .parent = TYPE_SYS_BUS_DEVICE, 2100fa9e329SBin Meng .instance_size = sizeof(SiFiveUOTPState), 2110fa9e329SBin Meng .class_init = sifive_u_otp_class_init, 2120fa9e329SBin Meng }; 2130fa9e329SBin Meng 2140fa9e329SBin Meng static void sifive_u_otp_register_types(void) 2150fa9e329SBin Meng { 2160fa9e329SBin Meng type_register_static(&sifive_u_otp_info); 2170fa9e329SBin Meng } 2180fa9e329SBin Meng 2190fa9e329SBin Meng type_init(sifive_u_otp_register_types) 220