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