xref: /openbmc/qemu/hw/misc/sifive_u_otp.c (revision a54d2591)
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