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