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" 26a033d800SBin Meng #include "qemu/error-report.h" 270fa9e329SBin Meng #include "qemu/log.h" 280fa9e329SBin Meng #include "qemu/module.h" 290fa9e329SBin Meng #include "hw/misc/sifive_u_otp.h" 3051b6c1bbSGreen Wan #include "sysemu/blockdev.h" 3151b6c1bbSGreen Wan #include "sysemu/block-backend.h" 320fa9e329SBin Meng 33a54d2591SGreen Wan #define WRITTEN_BIT_ON 0x1 34a54d2591SGreen Wan 35a54d2591SGreen Wan #define SET_FUSEARRAY_BIT(map, i, off, bit) \ 36a54d2591SGreen Wan map[i] = bit ? (map[i] | bit << off) : (map[i] & ~(0x1 << off)) 37a54d2591SGreen Wan 38a54d2591SGreen Wan #define GET_FUSEARRAY_BIT(map, i, off) \ 39a54d2591SGreen Wan ((map[i] >> off) & 0x1) 40a54d2591SGreen Wan 410fa9e329SBin Meng static uint64_t sifive_u_otp_read(void *opaque, hwaddr addr, unsigned int size) 420fa9e329SBin Meng { 430fa9e329SBin Meng SiFiveUOTPState *s = opaque; 440fa9e329SBin Meng 450fa9e329SBin Meng switch (addr) { 460fa9e329SBin Meng case SIFIVE_U_OTP_PA: 470fa9e329SBin Meng return s->pa; 480fa9e329SBin Meng case SIFIVE_U_OTP_PAIO: 490fa9e329SBin Meng return s->paio; 500fa9e329SBin Meng case SIFIVE_U_OTP_PAS: 510fa9e329SBin Meng return s->pas; 520fa9e329SBin Meng case SIFIVE_U_OTP_PCE: 530fa9e329SBin Meng return s->pce; 540fa9e329SBin Meng case SIFIVE_U_OTP_PCLK: 550fa9e329SBin Meng return s->pclk; 560fa9e329SBin Meng case SIFIVE_U_OTP_PDIN: 570fa9e329SBin Meng return s->pdin; 580fa9e329SBin Meng case SIFIVE_U_OTP_PDOUT: 590fa9e329SBin Meng if ((s->pce & SIFIVE_U_OTP_PCE_EN) && 600fa9e329SBin Meng (s->pdstb & SIFIVE_U_OTP_PDSTB_EN) && 610fa9e329SBin Meng (s->ptrim & SIFIVE_U_OTP_PTRIM_EN)) { 6251b6c1bbSGreen Wan 6351b6c1bbSGreen Wan /* read from backend */ 6451b6c1bbSGreen Wan if (s->blk) { 6551b6c1bbSGreen Wan int32_t buf; 6651b6c1bbSGreen Wan 6729b5fe0dSGreen Wan if (blk_pread(s->blk, s->pa * SIFIVE_U_OTP_FUSE_WORD, &buf, 6829b5fe0dSGreen Wan SIFIVE_U_OTP_FUSE_WORD) < 0) { 69a033d800SBin Meng error_report("read error index<%d>", s->pa); 7029b5fe0dSGreen Wan return 0xff; 7129b5fe0dSGreen Wan } 7229b5fe0dSGreen 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) { 16929b5fe0dSGreen Wan if (blk_pwrite(s->blk, s->pa * SIFIVE_U_OTP_FUSE_WORD, 17029b5fe0dSGreen Wan &s->fuse[s->pa], SIFIVE_U_OTP_FUSE_WORD, 17129b5fe0dSGreen Wan 0) < 0) { 172a033d800SBin Meng error_report("write error index<%d>", s->pa); 17329b5fe0dSGreen Wan } 17451b6c1bbSGreen Wan } 17551b6c1bbSGreen Wan 176a54d2591SGreen Wan /* update written bit */ 177a54d2591SGreen Wan SET_FUSEARRAY_BIT(s->fuse_wo, s->pa, s->paio, WRITTEN_BIT_ON); 178a54d2591SGreen Wan } 179a54d2591SGreen Wan 1800fa9e329SBin Meng break; 1810fa9e329SBin Meng default: 1820fa9e329SBin Meng qemu_log_mask(LOG_GUEST_ERROR, "%s: bad write: addr=0x%" HWADDR_PRIx 1830fa9e329SBin Meng " v=0x%x\n", __func__, addr, val32); 1840fa9e329SBin Meng } 1850fa9e329SBin Meng } 1860fa9e329SBin Meng 1870fa9e329SBin Meng static const MemoryRegionOps sifive_u_otp_ops = { 1880fa9e329SBin Meng .read = sifive_u_otp_read, 1890fa9e329SBin Meng .write = sifive_u_otp_write, 1900fa9e329SBin Meng .endianness = DEVICE_NATIVE_ENDIAN, 1910fa9e329SBin Meng .valid = { 1920fa9e329SBin Meng .min_access_size = 4, 1930fa9e329SBin Meng .max_access_size = 4 1940fa9e329SBin Meng } 1950fa9e329SBin Meng }; 1960fa9e329SBin Meng 1970fa9e329SBin Meng static Property sifive_u_otp_properties[] = { 1980fa9e329SBin Meng DEFINE_PROP_UINT32("serial", SiFiveUOTPState, serial, 0), 19951b6c1bbSGreen Wan DEFINE_PROP_DRIVE("drive", SiFiveUOTPState, blk), 2000fa9e329SBin Meng DEFINE_PROP_END_OF_LIST(), 2010fa9e329SBin Meng }; 2020fa9e329SBin Meng 2030fa9e329SBin Meng static void sifive_u_otp_realize(DeviceState *dev, Error **errp) 2040fa9e329SBin Meng { 2050fa9e329SBin Meng SiFiveUOTPState *s = SIFIVE_U_OTP(dev); 20651b6c1bbSGreen Wan DriveInfo *dinfo; 2070fa9e329SBin Meng 2080fa9e329SBin Meng memory_region_init_io(&s->mmio, OBJECT(dev), &sifive_u_otp_ops, s, 2090fa9e329SBin Meng TYPE_SIFIVE_U_OTP, SIFIVE_U_OTP_REG_SIZE); 2100fa9e329SBin Meng sysbus_init_mmio(SYS_BUS_DEVICE(dev), &s->mmio); 21151b6c1bbSGreen Wan 212*64eaa820SMarkus Armbruster dinfo = drive_get(IF_PFLASH, 0, 0); 2136b717a8dSThomas Huth if (!dinfo) { 214*64eaa820SMarkus Armbruster dinfo = drive_get(IF_NONE, 0, 0); 21551b6c1bbSGreen Wan if (dinfo) { 2166b717a8dSThomas Huth warn_report("using \"-drive if=none\" for the OTP is deprecated, " 2176b717a8dSThomas Huth "use \"-drive if=pflash\" instead."); 2186b717a8dSThomas Huth } 2196b717a8dSThomas Huth } 2206b717a8dSThomas Huth if (dinfo) { 22151b6c1bbSGreen Wan int ret; 22251b6c1bbSGreen Wan uint64_t perm; 22351b6c1bbSGreen Wan int filesize; 22451b6c1bbSGreen Wan BlockBackend *blk; 22551b6c1bbSGreen Wan 22651b6c1bbSGreen Wan blk = blk_by_legacy_dinfo(dinfo); 22751b6c1bbSGreen Wan filesize = SIFIVE_U_OTP_NUM_FUSES * SIFIVE_U_OTP_FUSE_WORD; 22851b6c1bbSGreen Wan if (blk_getlength(blk) < filesize) { 22951b6c1bbSGreen Wan error_setg(errp, "OTP drive size < 16K"); 23051b6c1bbSGreen Wan return; 23151b6c1bbSGreen Wan } 23251b6c1bbSGreen Wan 23351b6c1bbSGreen Wan qdev_prop_set_drive_err(dev, "drive", blk, errp); 23451b6c1bbSGreen Wan 23551b6c1bbSGreen Wan if (s->blk) { 23651b6c1bbSGreen Wan perm = BLK_PERM_CONSISTENT_READ | 23786b1cf32SKevin Wolf (blk_supports_write_perm(s->blk) ? BLK_PERM_WRITE : 0); 23851b6c1bbSGreen Wan ret = blk_set_perm(s->blk, perm, BLK_PERM_ALL, errp); 23951b6c1bbSGreen Wan if (ret < 0) { 24051b6c1bbSGreen Wan return; 24151b6c1bbSGreen Wan } 24251b6c1bbSGreen Wan 24351b6c1bbSGreen Wan if (blk_pread(s->blk, 0, s->fuse, filesize) != filesize) { 24451b6c1bbSGreen Wan error_setg(errp, "failed to read the initial flash content"); 245526e7443SPhilippe Mathieu-Daudé return; 24651b6c1bbSGreen Wan } 24751b6c1bbSGreen Wan } 24851b6c1bbSGreen Wan } 2490fa9e329SBin Meng 2500fa9e329SBin Meng /* Initialize all fuses' initial value to 0xFFs */ 2510fa9e329SBin Meng memset(s->fuse, 0xff, sizeof(s->fuse)); 2520fa9e329SBin Meng 2530fa9e329SBin Meng /* Make a valid content of serial number */ 2540fa9e329SBin Meng s->fuse[SIFIVE_U_OTP_SERIAL_ADDR] = s->serial; 2550fa9e329SBin Meng s->fuse[SIFIVE_U_OTP_SERIAL_ADDR + 1] = ~(s->serial); 256a54d2591SGreen Wan 25751b6c1bbSGreen Wan if (s->blk) { 25851b6c1bbSGreen Wan /* Put serial number to backend as well*/ 25951b6c1bbSGreen Wan uint32_t serial_data; 26051b6c1bbSGreen Wan int index = SIFIVE_U_OTP_SERIAL_ADDR; 26151b6c1bbSGreen Wan 26251b6c1bbSGreen Wan serial_data = s->serial; 26329b5fe0dSGreen Wan if (blk_pwrite(s->blk, index * SIFIVE_U_OTP_FUSE_WORD, 26429b5fe0dSGreen Wan &serial_data, SIFIVE_U_OTP_FUSE_WORD, 0) < 0) { 265526e7443SPhilippe Mathieu-Daudé error_setg(errp, "failed to write index<%d>", index); 266526e7443SPhilippe Mathieu-Daudé return; 26729b5fe0dSGreen Wan } 26851b6c1bbSGreen Wan 26951b6c1bbSGreen Wan serial_data = ~(s->serial); 27029b5fe0dSGreen Wan if (blk_pwrite(s->blk, (index + 1) * SIFIVE_U_OTP_FUSE_WORD, 27129b5fe0dSGreen Wan &serial_data, SIFIVE_U_OTP_FUSE_WORD, 0) < 0) { 272526e7443SPhilippe Mathieu-Daudé error_setg(errp, "failed to write index<%d>", index + 1); 273526e7443SPhilippe Mathieu-Daudé return; 27429b5fe0dSGreen Wan } 27551b6c1bbSGreen Wan } 27651b6c1bbSGreen Wan 277a54d2591SGreen Wan /* Initialize write-once map */ 278a54d2591SGreen Wan memset(s->fuse_wo, 0x00, sizeof(s->fuse_wo)); 2790fa9e329SBin Meng } 2800fa9e329SBin Meng 2810fa9e329SBin Meng static void sifive_u_otp_class_init(ObjectClass *klass, void *data) 2820fa9e329SBin Meng { 2830fa9e329SBin Meng DeviceClass *dc = DEVICE_CLASS(klass); 2840fa9e329SBin Meng 2850fa9e329SBin Meng device_class_set_props(dc, sifive_u_otp_properties); 2860fa9e329SBin Meng dc->realize = sifive_u_otp_realize; 2870fa9e329SBin Meng } 2880fa9e329SBin Meng 2890fa9e329SBin Meng static const TypeInfo sifive_u_otp_info = { 2900fa9e329SBin Meng .name = TYPE_SIFIVE_U_OTP, 2910fa9e329SBin Meng .parent = TYPE_SYS_BUS_DEVICE, 2920fa9e329SBin Meng .instance_size = sizeof(SiFiveUOTPState), 2930fa9e329SBin Meng .class_init = sifive_u_otp_class_init, 2940fa9e329SBin Meng }; 2950fa9e329SBin Meng 2960fa9e329SBin Meng static void sifive_u_otp_register_types(void) 2970fa9e329SBin Meng { 2980fa9e329SBin Meng type_register_static(&sifive_u_otp_info); 2990fa9e329SBin Meng } 3000fa9e329SBin Meng 3010fa9e329SBin Meng type_init(sifive_u_otp_register_types) 302