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" 2251b6c1bbSGreen Wan #include "qapi/error.h" 230fa9e329SBin Meng #include "hw/qdev-properties.h" 24ce35e229SEduardo Habkost #include "hw/qdev-properties-system.h" 250fa9e329SBin Meng #include "hw/sysbus.h" 260fa9e329SBin Meng #include "qemu/log.h" 270fa9e329SBin Meng #include "qemu/module.h" 280fa9e329SBin Meng #include "hw/misc/sifive_u_otp.h" 2951b6c1bbSGreen Wan #include "sysemu/blockdev.h" 3051b6c1bbSGreen Wan #include "sysemu/block-backend.h" 310fa9e329SBin Meng 32a54d2591SGreen Wan #define WRITTEN_BIT_ON 0x1 33a54d2591SGreen Wan 34a54d2591SGreen Wan #define SET_FUSEARRAY_BIT(map, i, off, bit) \ 35a54d2591SGreen Wan map[i] = bit ? (map[i] | bit << off) : (map[i] & ~(0x1 << off)) 36a54d2591SGreen Wan 37a54d2591SGreen Wan #define GET_FUSEARRAY_BIT(map, i, off) \ 38a54d2591SGreen Wan ((map[i] >> off) & 0x1) 39a54d2591SGreen Wan 400fa9e329SBin Meng static uint64_t sifive_u_otp_read(void *opaque, hwaddr addr, unsigned int size) 410fa9e329SBin Meng { 420fa9e329SBin Meng SiFiveUOTPState *s = opaque; 430fa9e329SBin Meng 440fa9e329SBin Meng switch (addr) { 450fa9e329SBin Meng case SIFIVE_U_OTP_PA: 460fa9e329SBin Meng return s->pa; 470fa9e329SBin Meng case SIFIVE_U_OTP_PAIO: 480fa9e329SBin Meng return s->paio; 490fa9e329SBin Meng case SIFIVE_U_OTP_PAS: 500fa9e329SBin Meng return s->pas; 510fa9e329SBin Meng case SIFIVE_U_OTP_PCE: 520fa9e329SBin Meng return s->pce; 530fa9e329SBin Meng case SIFIVE_U_OTP_PCLK: 540fa9e329SBin Meng return s->pclk; 550fa9e329SBin Meng case SIFIVE_U_OTP_PDIN: 560fa9e329SBin Meng return s->pdin; 570fa9e329SBin Meng case SIFIVE_U_OTP_PDOUT: 580fa9e329SBin Meng if ((s->pce & SIFIVE_U_OTP_PCE_EN) && 590fa9e329SBin Meng (s->pdstb & SIFIVE_U_OTP_PDSTB_EN) && 600fa9e329SBin Meng (s->ptrim & SIFIVE_U_OTP_PTRIM_EN)) { 6151b6c1bbSGreen Wan 6251b6c1bbSGreen Wan /* read from backend */ 6351b6c1bbSGreen Wan if (s->blk) { 6451b6c1bbSGreen Wan int32_t buf; 6551b6c1bbSGreen Wan 66*29b5fe0dSGreen Wan if (blk_pread(s->blk, s->pa * SIFIVE_U_OTP_FUSE_WORD, &buf, 67*29b5fe0dSGreen Wan SIFIVE_U_OTP_FUSE_WORD) < 0) { 68*29b5fe0dSGreen Wan qemu_log_mask(LOG_GUEST_ERROR, 69*29b5fe0dSGreen Wan "read error index<%d>\n", s->pa); 70*29b5fe0dSGreen Wan return 0xff; 71*29b5fe0dSGreen Wan } 72*29b5fe0dSGreen Wan 7351b6c1bbSGreen Wan return buf; 7451b6c1bbSGreen Wan } 7551b6c1bbSGreen Wan 760fa9e329SBin Meng return s->fuse[s->pa & SIFIVE_U_OTP_PA_MASK]; 770fa9e329SBin Meng } else { 780fa9e329SBin Meng return 0xff; 790fa9e329SBin Meng } 800fa9e329SBin Meng case SIFIVE_U_OTP_PDSTB: 810fa9e329SBin Meng return s->pdstb; 820fa9e329SBin Meng case SIFIVE_U_OTP_PPROG: 830fa9e329SBin Meng return s->pprog; 840fa9e329SBin Meng case SIFIVE_U_OTP_PTC: 850fa9e329SBin Meng return s->ptc; 860fa9e329SBin Meng case SIFIVE_U_OTP_PTM: 870fa9e329SBin Meng return s->ptm; 880fa9e329SBin Meng case SIFIVE_U_OTP_PTM_REP: 890fa9e329SBin Meng return s->ptm_rep; 900fa9e329SBin Meng case SIFIVE_U_OTP_PTR: 910fa9e329SBin Meng return s->ptr; 920fa9e329SBin Meng case SIFIVE_U_OTP_PTRIM: 930fa9e329SBin Meng return s->ptrim; 940fa9e329SBin Meng case SIFIVE_U_OTP_PWE: 950fa9e329SBin Meng return s->pwe; 960fa9e329SBin Meng } 970fa9e329SBin Meng 980fa9e329SBin Meng qemu_log_mask(LOG_GUEST_ERROR, "%s: read: addr=0x%" HWADDR_PRIx "\n", 990fa9e329SBin Meng __func__, addr); 1000fa9e329SBin Meng return 0; 1010fa9e329SBin Meng } 1020fa9e329SBin Meng 1030fa9e329SBin Meng static void sifive_u_otp_write(void *opaque, hwaddr addr, 1040fa9e329SBin Meng uint64_t val64, unsigned int size) 1050fa9e329SBin Meng { 1060fa9e329SBin Meng SiFiveUOTPState *s = opaque; 1070fa9e329SBin Meng uint32_t val32 = (uint32_t)val64; 1080fa9e329SBin Meng 1090fa9e329SBin Meng switch (addr) { 1100fa9e329SBin Meng case SIFIVE_U_OTP_PA: 1110fa9e329SBin Meng s->pa = val32 & SIFIVE_U_OTP_PA_MASK; 1120fa9e329SBin Meng break; 1130fa9e329SBin Meng case SIFIVE_U_OTP_PAIO: 1140fa9e329SBin Meng s->paio = val32; 1150fa9e329SBin Meng break; 1160fa9e329SBin Meng case SIFIVE_U_OTP_PAS: 1170fa9e329SBin Meng s->pas = val32; 1180fa9e329SBin Meng break; 1190fa9e329SBin Meng case SIFIVE_U_OTP_PCE: 1200fa9e329SBin Meng s->pce = val32; 1210fa9e329SBin Meng break; 1220fa9e329SBin Meng case SIFIVE_U_OTP_PCLK: 1230fa9e329SBin Meng s->pclk = val32; 1240fa9e329SBin Meng break; 1250fa9e329SBin Meng case SIFIVE_U_OTP_PDIN: 1260fa9e329SBin Meng s->pdin = val32; 1270fa9e329SBin Meng break; 1280fa9e329SBin Meng case SIFIVE_U_OTP_PDOUT: 1290fa9e329SBin Meng /* read-only */ 1300fa9e329SBin Meng break; 1310fa9e329SBin Meng case SIFIVE_U_OTP_PDSTB: 1320fa9e329SBin Meng s->pdstb = val32; 1330fa9e329SBin Meng break; 1340fa9e329SBin Meng case SIFIVE_U_OTP_PPROG: 1350fa9e329SBin Meng s->pprog = val32; 1360fa9e329SBin Meng break; 1370fa9e329SBin Meng case SIFIVE_U_OTP_PTC: 1380fa9e329SBin Meng s->ptc = val32; 1390fa9e329SBin Meng break; 1400fa9e329SBin Meng case SIFIVE_U_OTP_PTM: 1410fa9e329SBin Meng s->ptm = val32; 1420fa9e329SBin Meng break; 1430fa9e329SBin Meng case SIFIVE_U_OTP_PTM_REP: 1440fa9e329SBin Meng s->ptm_rep = val32; 1450fa9e329SBin Meng break; 1460fa9e329SBin Meng case SIFIVE_U_OTP_PTR: 1470fa9e329SBin Meng s->ptr = val32; 1480fa9e329SBin Meng break; 1490fa9e329SBin Meng case SIFIVE_U_OTP_PTRIM: 1500fa9e329SBin Meng s->ptrim = val32; 1510fa9e329SBin Meng break; 1520fa9e329SBin Meng case SIFIVE_U_OTP_PWE: 153a54d2591SGreen Wan s->pwe = val32 & SIFIVE_U_OTP_PWE_EN; 154a54d2591SGreen Wan 155a54d2591SGreen Wan /* PWE is enabled. Ignore PAS=1 (no redundancy cell) */ 156a54d2591SGreen Wan if (s->pwe && !s->pas) { 157a54d2591SGreen Wan if (GET_FUSEARRAY_BIT(s->fuse_wo, s->pa, s->paio)) { 158a54d2591SGreen Wan qemu_log_mask(LOG_GUEST_ERROR, 159a54d2591SGreen Wan "write once error: idx<%u>, bit<%u>\n", 160a54d2591SGreen Wan s->pa, s->paio); 161a54d2591SGreen Wan break; 162a54d2591SGreen Wan } 163a54d2591SGreen Wan 164a54d2591SGreen Wan /* write bit data */ 165a54d2591SGreen Wan SET_FUSEARRAY_BIT(s->fuse, s->pa, s->paio, s->pdin); 166a54d2591SGreen Wan 16751b6c1bbSGreen Wan /* write to backend */ 16851b6c1bbSGreen Wan if (s->blk) { 169*29b5fe0dSGreen Wan if (blk_pwrite(s->blk, s->pa * SIFIVE_U_OTP_FUSE_WORD, 170*29b5fe0dSGreen Wan &s->fuse[s->pa], SIFIVE_U_OTP_FUSE_WORD, 171*29b5fe0dSGreen Wan 0) < 0) { 172*29b5fe0dSGreen Wan qemu_log_mask(LOG_GUEST_ERROR, 173*29b5fe0dSGreen Wan "write error index<%d>\n", s->pa); 174*29b5fe0dSGreen Wan } 17551b6c1bbSGreen Wan } 17651b6c1bbSGreen Wan 177a54d2591SGreen Wan /* update written bit */ 178a54d2591SGreen Wan SET_FUSEARRAY_BIT(s->fuse_wo, s->pa, s->paio, WRITTEN_BIT_ON); 179a54d2591SGreen Wan } 180a54d2591SGreen Wan 1810fa9e329SBin Meng break; 1820fa9e329SBin Meng default: 1830fa9e329SBin Meng qemu_log_mask(LOG_GUEST_ERROR, "%s: bad write: addr=0x%" HWADDR_PRIx 1840fa9e329SBin Meng " v=0x%x\n", __func__, addr, val32); 1850fa9e329SBin Meng } 1860fa9e329SBin Meng } 1870fa9e329SBin Meng 1880fa9e329SBin Meng static const MemoryRegionOps sifive_u_otp_ops = { 1890fa9e329SBin Meng .read = sifive_u_otp_read, 1900fa9e329SBin Meng .write = sifive_u_otp_write, 1910fa9e329SBin Meng .endianness = DEVICE_NATIVE_ENDIAN, 1920fa9e329SBin Meng .valid = { 1930fa9e329SBin Meng .min_access_size = 4, 1940fa9e329SBin Meng .max_access_size = 4 1950fa9e329SBin Meng } 1960fa9e329SBin Meng }; 1970fa9e329SBin Meng 1980fa9e329SBin Meng static Property sifive_u_otp_properties[] = { 1990fa9e329SBin Meng DEFINE_PROP_UINT32("serial", SiFiveUOTPState, serial, 0), 20051b6c1bbSGreen Wan DEFINE_PROP_DRIVE("drive", SiFiveUOTPState, blk), 2010fa9e329SBin Meng DEFINE_PROP_END_OF_LIST(), 2020fa9e329SBin Meng }; 2030fa9e329SBin Meng 2040fa9e329SBin Meng static void sifive_u_otp_realize(DeviceState *dev, Error **errp) 2050fa9e329SBin Meng { 2060fa9e329SBin Meng SiFiveUOTPState *s = SIFIVE_U_OTP(dev); 20751b6c1bbSGreen Wan DriveInfo *dinfo; 2080fa9e329SBin Meng 2090fa9e329SBin Meng memory_region_init_io(&s->mmio, OBJECT(dev), &sifive_u_otp_ops, s, 2100fa9e329SBin Meng TYPE_SIFIVE_U_OTP, SIFIVE_U_OTP_REG_SIZE); 2110fa9e329SBin Meng sysbus_init_mmio(SYS_BUS_DEVICE(dev), &s->mmio); 21251b6c1bbSGreen Wan 21351b6c1bbSGreen Wan dinfo = drive_get_next(IF_NONE); 21451b6c1bbSGreen Wan if (dinfo) { 21551b6c1bbSGreen Wan int ret; 21651b6c1bbSGreen Wan uint64_t perm; 21751b6c1bbSGreen Wan int filesize; 21851b6c1bbSGreen Wan BlockBackend *blk; 21951b6c1bbSGreen Wan 22051b6c1bbSGreen Wan blk = blk_by_legacy_dinfo(dinfo); 22151b6c1bbSGreen Wan filesize = SIFIVE_U_OTP_NUM_FUSES * SIFIVE_U_OTP_FUSE_WORD; 22251b6c1bbSGreen Wan if (blk_getlength(blk) < filesize) { 22351b6c1bbSGreen Wan error_setg(errp, "OTP drive size < 16K"); 22451b6c1bbSGreen Wan return; 22551b6c1bbSGreen Wan } 22651b6c1bbSGreen Wan 22751b6c1bbSGreen Wan qdev_prop_set_drive_err(dev, "drive", blk, errp); 22851b6c1bbSGreen Wan 22951b6c1bbSGreen Wan if (s->blk) { 23051b6c1bbSGreen Wan perm = BLK_PERM_CONSISTENT_READ | 23151b6c1bbSGreen Wan (blk_is_read_only(s->blk) ? 0 : BLK_PERM_WRITE); 23251b6c1bbSGreen Wan ret = blk_set_perm(s->blk, perm, BLK_PERM_ALL, errp); 23351b6c1bbSGreen Wan if (ret < 0) { 23451b6c1bbSGreen Wan return; 23551b6c1bbSGreen Wan } 23651b6c1bbSGreen Wan 23751b6c1bbSGreen Wan if (blk_pread(s->blk, 0, s->fuse, filesize) != filesize) { 23851b6c1bbSGreen Wan error_setg(errp, "failed to read the initial flash content"); 23951b6c1bbSGreen Wan } 24051b6c1bbSGreen Wan } 24151b6c1bbSGreen Wan } 2420fa9e329SBin Meng } 2430fa9e329SBin Meng 2440fa9e329SBin Meng static void sifive_u_otp_reset(DeviceState *dev) 2450fa9e329SBin Meng { 2460fa9e329SBin Meng SiFiveUOTPState *s = SIFIVE_U_OTP(dev); 2470fa9e329SBin Meng 2480fa9e329SBin Meng /* Initialize all fuses' initial value to 0xFFs */ 2490fa9e329SBin Meng memset(s->fuse, 0xff, sizeof(s->fuse)); 2500fa9e329SBin Meng 2510fa9e329SBin Meng /* Make a valid content of serial number */ 2520fa9e329SBin Meng s->fuse[SIFIVE_U_OTP_SERIAL_ADDR] = s->serial; 2530fa9e329SBin Meng s->fuse[SIFIVE_U_OTP_SERIAL_ADDR + 1] = ~(s->serial); 254a54d2591SGreen Wan 25551b6c1bbSGreen Wan if (s->blk) { 25651b6c1bbSGreen Wan /* Put serial number to backend as well*/ 25751b6c1bbSGreen Wan uint32_t serial_data; 25851b6c1bbSGreen Wan int index = SIFIVE_U_OTP_SERIAL_ADDR; 25951b6c1bbSGreen Wan 26051b6c1bbSGreen Wan serial_data = s->serial; 261*29b5fe0dSGreen Wan if (blk_pwrite(s->blk, index * SIFIVE_U_OTP_FUSE_WORD, 262*29b5fe0dSGreen Wan &serial_data, SIFIVE_U_OTP_FUSE_WORD, 0) < 0) { 263*29b5fe0dSGreen Wan qemu_log_mask(LOG_GUEST_ERROR, 264*29b5fe0dSGreen Wan "write error index<%d>\n", index); 265*29b5fe0dSGreen Wan } 26651b6c1bbSGreen Wan 26751b6c1bbSGreen Wan serial_data = ~(s->serial); 268*29b5fe0dSGreen Wan if (blk_pwrite(s->blk, (index + 1) * SIFIVE_U_OTP_FUSE_WORD, 269*29b5fe0dSGreen Wan &serial_data, SIFIVE_U_OTP_FUSE_WORD, 0) < 0) { 270*29b5fe0dSGreen Wan qemu_log_mask(LOG_GUEST_ERROR, 271*29b5fe0dSGreen Wan "write error index<%d>\n", index + 1); 272*29b5fe0dSGreen Wan } 27351b6c1bbSGreen Wan } 27451b6c1bbSGreen Wan 275a54d2591SGreen Wan /* Initialize write-once map */ 276a54d2591SGreen Wan memset(s->fuse_wo, 0x00, sizeof(s->fuse_wo)); 2770fa9e329SBin Meng } 2780fa9e329SBin Meng 2790fa9e329SBin Meng static void sifive_u_otp_class_init(ObjectClass *klass, void *data) 2800fa9e329SBin Meng { 2810fa9e329SBin Meng DeviceClass *dc = DEVICE_CLASS(klass); 2820fa9e329SBin Meng 2830fa9e329SBin Meng device_class_set_props(dc, sifive_u_otp_properties); 2840fa9e329SBin Meng dc->realize = sifive_u_otp_realize; 2850fa9e329SBin Meng dc->reset = sifive_u_otp_reset; 2860fa9e329SBin Meng } 2870fa9e329SBin Meng 2880fa9e329SBin Meng static const TypeInfo sifive_u_otp_info = { 2890fa9e329SBin Meng .name = TYPE_SIFIVE_U_OTP, 2900fa9e329SBin Meng .parent = TYPE_SYS_BUS_DEVICE, 2910fa9e329SBin Meng .instance_size = sizeof(SiFiveUOTPState), 2920fa9e329SBin Meng .class_init = sifive_u_otp_class_init, 2930fa9e329SBin Meng }; 2940fa9e329SBin Meng 2950fa9e329SBin Meng static void sifive_u_otp_register_types(void) 2960fa9e329SBin Meng { 2970fa9e329SBin Meng type_register_static(&sifive_u_otp_info); 2980fa9e329SBin Meng } 2990fa9e329SBin Meng 3000fa9e329SBin Meng type_init(sifive_u_otp_register_types) 301