xref: /openbmc/qemu/hw/nvram/bcm2835_otp.c (revision c1bf7540)
1*c1bf7540SRayhan Faizel /*
2*c1bf7540SRayhan Faizel  * BCM2835 One-Time Programmable (OTP) Memory
3*c1bf7540SRayhan Faizel  *
4*c1bf7540SRayhan Faizel  * The OTP implementation is mostly a stub except for the OTP rows
5*c1bf7540SRayhan Faizel  * which are accessed directly by other peripherals such as the mailbox.
6*c1bf7540SRayhan Faizel  *
7*c1bf7540SRayhan Faizel  * The OTP registers are unimplemented due to lack of documentation.
8*c1bf7540SRayhan Faizel  *
9*c1bf7540SRayhan Faizel  * Copyright (c) 2024 Rayhan Faizel <rayhan.faizel@gmail.com>
10*c1bf7540SRayhan Faizel  *
11*c1bf7540SRayhan Faizel  * SPDX-License-Identifier: MIT
12*c1bf7540SRayhan Faizel  */
13*c1bf7540SRayhan Faizel 
14*c1bf7540SRayhan Faizel #include "qemu/osdep.h"
15*c1bf7540SRayhan Faizel #include "qemu/log.h"
16*c1bf7540SRayhan Faizel #include "hw/nvram/bcm2835_otp.h"
17*c1bf7540SRayhan Faizel #include "migration/vmstate.h"
18*c1bf7540SRayhan Faizel 
19*c1bf7540SRayhan Faizel /* OTP rows are 1-indexed */
bcm2835_otp_get_row(BCM2835OTPState * s,unsigned int row)20*c1bf7540SRayhan Faizel uint32_t bcm2835_otp_get_row(BCM2835OTPState *s, unsigned int row)
21*c1bf7540SRayhan Faizel {
22*c1bf7540SRayhan Faizel     assert(row <= BCM2835_OTP_ROW_COUNT && row >= 1);
23*c1bf7540SRayhan Faizel 
24*c1bf7540SRayhan Faizel     return s->otp_rows[row - 1];
25*c1bf7540SRayhan Faizel }
26*c1bf7540SRayhan Faizel 
bcm2835_otp_set_row(BCM2835OTPState * s,unsigned int row,uint32_t value)27*c1bf7540SRayhan Faizel void bcm2835_otp_set_row(BCM2835OTPState *s, unsigned int row,
28*c1bf7540SRayhan Faizel                            uint32_t value)
29*c1bf7540SRayhan Faizel {
30*c1bf7540SRayhan Faizel     assert(row <= BCM2835_OTP_ROW_COUNT && row >= 1);
31*c1bf7540SRayhan Faizel 
32*c1bf7540SRayhan Faizel     /* Real OTP rows work as e-fuses */
33*c1bf7540SRayhan Faizel     s->otp_rows[row - 1] |= value;
34*c1bf7540SRayhan Faizel }
35*c1bf7540SRayhan Faizel 
bcm2835_otp_read(void * opaque,hwaddr addr,unsigned size)36*c1bf7540SRayhan Faizel static uint64_t bcm2835_otp_read(void *opaque, hwaddr addr, unsigned size)
37*c1bf7540SRayhan Faizel {
38*c1bf7540SRayhan Faizel     switch (addr) {
39*c1bf7540SRayhan Faizel     case BCM2835_OTP_BOOTMODE_REG:
40*c1bf7540SRayhan Faizel         qemu_log_mask(LOG_UNIMP,
41*c1bf7540SRayhan Faizel                       "bcm2835_otp: BCM2835_OTP_BOOTMODE_REG\n");
42*c1bf7540SRayhan Faizel         break;
43*c1bf7540SRayhan Faizel     case BCM2835_OTP_CONFIG_REG:
44*c1bf7540SRayhan Faizel         qemu_log_mask(LOG_UNIMP,
45*c1bf7540SRayhan Faizel                       "bcm2835_otp: BCM2835_OTP_CONFIG_REG\n");
46*c1bf7540SRayhan Faizel         break;
47*c1bf7540SRayhan Faizel     case BCM2835_OTP_CTRL_LO_REG:
48*c1bf7540SRayhan Faizel         qemu_log_mask(LOG_UNIMP,
49*c1bf7540SRayhan Faizel                       "bcm2835_otp: BCM2835_OTP_CTRL_LO_REG\n");
50*c1bf7540SRayhan Faizel         break;
51*c1bf7540SRayhan Faizel     case BCM2835_OTP_CTRL_HI_REG:
52*c1bf7540SRayhan Faizel         qemu_log_mask(LOG_UNIMP,
53*c1bf7540SRayhan Faizel                       "bcm2835_otp: BCM2835_OTP_CTRL_HI_REG\n");
54*c1bf7540SRayhan Faizel         break;
55*c1bf7540SRayhan Faizel     case BCM2835_OTP_STATUS_REG:
56*c1bf7540SRayhan Faizel         qemu_log_mask(LOG_UNIMP,
57*c1bf7540SRayhan Faizel                       "bcm2835_otp: BCM2835_OTP_STATUS_REG\n");
58*c1bf7540SRayhan Faizel         break;
59*c1bf7540SRayhan Faizel     case BCM2835_OTP_BITSEL_REG:
60*c1bf7540SRayhan Faizel         qemu_log_mask(LOG_UNIMP,
61*c1bf7540SRayhan Faizel                       "bcm2835_otp: BCM2835_OTP_BITSEL_REG\n");
62*c1bf7540SRayhan Faizel         break;
63*c1bf7540SRayhan Faizel     case BCM2835_OTP_DATA_REG:
64*c1bf7540SRayhan Faizel         qemu_log_mask(LOG_UNIMP,
65*c1bf7540SRayhan Faizel                       "bcm2835_otp: BCM2835_OTP_DATA_REG\n");
66*c1bf7540SRayhan Faizel         break;
67*c1bf7540SRayhan Faizel     case BCM2835_OTP_ADDR_REG:
68*c1bf7540SRayhan Faizel         qemu_log_mask(LOG_UNIMP,
69*c1bf7540SRayhan Faizel                       "bcm2835_otp: BCM2835_OTP_ADDR_REG\n");
70*c1bf7540SRayhan Faizel         break;
71*c1bf7540SRayhan Faizel     case BCM2835_OTP_WRITE_DATA_READ_REG:
72*c1bf7540SRayhan Faizel         qemu_log_mask(LOG_UNIMP,
73*c1bf7540SRayhan Faizel                       "bcm2835_otp: BCM2835_OTP_WRITE_DATA_READ_REG\n");
74*c1bf7540SRayhan Faizel         break;
75*c1bf7540SRayhan Faizel     case BCM2835_OTP_INIT_STATUS_REG:
76*c1bf7540SRayhan Faizel         qemu_log_mask(LOG_UNIMP,
77*c1bf7540SRayhan Faizel                       "bcm2835_otp: BCM2835_OTP_INIT_STATUS_REG\n");
78*c1bf7540SRayhan Faizel         break;
79*c1bf7540SRayhan Faizel     default:
80*c1bf7540SRayhan Faizel         qemu_log_mask(LOG_GUEST_ERROR,
81*c1bf7540SRayhan Faizel                       "%s: Bad offset 0x%" HWADDR_PRIx "\n", __func__, addr);
82*c1bf7540SRayhan Faizel     }
83*c1bf7540SRayhan Faizel 
84*c1bf7540SRayhan Faizel     return 0;
85*c1bf7540SRayhan Faizel }
86*c1bf7540SRayhan Faizel 
bcm2835_otp_write(void * opaque,hwaddr addr,uint64_t value,unsigned int size)87*c1bf7540SRayhan Faizel static void bcm2835_otp_write(void *opaque, hwaddr addr,
88*c1bf7540SRayhan Faizel                               uint64_t value, unsigned int size)
89*c1bf7540SRayhan Faizel {
90*c1bf7540SRayhan Faizel     switch (addr) {
91*c1bf7540SRayhan Faizel     case BCM2835_OTP_BOOTMODE_REG:
92*c1bf7540SRayhan Faizel         qemu_log_mask(LOG_UNIMP,
93*c1bf7540SRayhan Faizel                       "bcm2835_otp: BCM2835_OTP_BOOTMODE_REG\n");
94*c1bf7540SRayhan Faizel         break;
95*c1bf7540SRayhan Faizel     case BCM2835_OTP_CONFIG_REG:
96*c1bf7540SRayhan Faizel         qemu_log_mask(LOG_UNIMP,
97*c1bf7540SRayhan Faizel                       "bcm2835_otp: BCM2835_OTP_CONFIG_REG\n");
98*c1bf7540SRayhan Faizel         break;
99*c1bf7540SRayhan Faizel     case BCM2835_OTP_CTRL_LO_REG:
100*c1bf7540SRayhan Faizel         qemu_log_mask(LOG_UNIMP,
101*c1bf7540SRayhan Faizel                       "bcm2835_otp: BCM2835_OTP_CTRL_LO_REG\n");
102*c1bf7540SRayhan Faizel         break;
103*c1bf7540SRayhan Faizel     case BCM2835_OTP_CTRL_HI_REG:
104*c1bf7540SRayhan Faizel         qemu_log_mask(LOG_UNIMP,
105*c1bf7540SRayhan Faizel                       "bcm2835_otp: BCM2835_OTP_CTRL_HI_REG\n");
106*c1bf7540SRayhan Faizel         break;
107*c1bf7540SRayhan Faizel     case BCM2835_OTP_STATUS_REG:
108*c1bf7540SRayhan Faizel         qemu_log_mask(LOG_UNIMP,
109*c1bf7540SRayhan Faizel                       "bcm2835_otp: BCM2835_OTP_STATUS_REG\n");
110*c1bf7540SRayhan Faizel         break;
111*c1bf7540SRayhan Faizel     case BCM2835_OTP_BITSEL_REG:
112*c1bf7540SRayhan Faizel         qemu_log_mask(LOG_UNIMP,
113*c1bf7540SRayhan Faizel                       "bcm2835_otp: BCM2835_OTP_BITSEL_REG\n");
114*c1bf7540SRayhan Faizel         break;
115*c1bf7540SRayhan Faizel     case BCM2835_OTP_DATA_REG:
116*c1bf7540SRayhan Faizel         qemu_log_mask(LOG_UNIMP,
117*c1bf7540SRayhan Faizel                       "bcm2835_otp: BCM2835_OTP_DATA_REG\n");
118*c1bf7540SRayhan Faizel         break;
119*c1bf7540SRayhan Faizel     case BCM2835_OTP_ADDR_REG:
120*c1bf7540SRayhan Faizel         qemu_log_mask(LOG_UNIMP,
121*c1bf7540SRayhan Faizel                       "bcm2835_otp: BCM2835_OTP_ADDR_REG\n");
122*c1bf7540SRayhan Faizel         break;
123*c1bf7540SRayhan Faizel     case BCM2835_OTP_WRITE_DATA_READ_REG:
124*c1bf7540SRayhan Faizel         qemu_log_mask(LOG_UNIMP,
125*c1bf7540SRayhan Faizel                       "bcm2835_otp: BCM2835_OTP_WRITE_DATA_READ_REG\n");
126*c1bf7540SRayhan Faizel         break;
127*c1bf7540SRayhan Faizel     case BCM2835_OTP_INIT_STATUS_REG:
128*c1bf7540SRayhan Faizel         qemu_log_mask(LOG_UNIMP,
129*c1bf7540SRayhan Faizel                       "bcm2835_otp: BCM2835_OTP_INIT_STATUS_REG\n");
130*c1bf7540SRayhan Faizel         break;
131*c1bf7540SRayhan Faizel     default:
132*c1bf7540SRayhan Faizel         qemu_log_mask(LOG_GUEST_ERROR,
133*c1bf7540SRayhan Faizel                       "%s: Bad offset 0x%" HWADDR_PRIx "\n", __func__, addr);
134*c1bf7540SRayhan Faizel     }
135*c1bf7540SRayhan Faizel }
136*c1bf7540SRayhan Faizel 
137*c1bf7540SRayhan Faizel static const MemoryRegionOps bcm2835_otp_ops = {
138*c1bf7540SRayhan Faizel     .read = bcm2835_otp_read,
139*c1bf7540SRayhan Faizel     .write = bcm2835_otp_write,
140*c1bf7540SRayhan Faizel     .endianness = DEVICE_NATIVE_ENDIAN,
141*c1bf7540SRayhan Faizel     .impl = {
142*c1bf7540SRayhan Faizel         .min_access_size = 4,
143*c1bf7540SRayhan Faizel         .max_access_size = 4,
144*c1bf7540SRayhan Faizel     },
145*c1bf7540SRayhan Faizel };
146*c1bf7540SRayhan Faizel 
bcm2835_otp_realize(DeviceState * dev,Error ** errp)147*c1bf7540SRayhan Faizel static void bcm2835_otp_realize(DeviceState *dev, Error **errp)
148*c1bf7540SRayhan Faizel {
149*c1bf7540SRayhan Faizel     BCM2835OTPState *s = BCM2835_OTP(dev);
150*c1bf7540SRayhan Faizel     memory_region_init_io(&s->iomem, OBJECT(dev), &bcm2835_otp_ops, s,
151*c1bf7540SRayhan Faizel                           TYPE_BCM2835_OTP, 0x80);
152*c1bf7540SRayhan Faizel     sysbus_init_mmio(SYS_BUS_DEVICE(dev), &s->iomem);
153*c1bf7540SRayhan Faizel 
154*c1bf7540SRayhan Faizel     memset(s->otp_rows, 0x00, sizeof(s->otp_rows));
155*c1bf7540SRayhan Faizel }
156*c1bf7540SRayhan Faizel 
157*c1bf7540SRayhan Faizel static const VMStateDescription vmstate_bcm2835_otp = {
158*c1bf7540SRayhan Faizel     .name = TYPE_BCM2835_OTP,
159*c1bf7540SRayhan Faizel     .version_id = 1,
160*c1bf7540SRayhan Faizel     .minimum_version_id = 1,
161*c1bf7540SRayhan Faizel     .fields = (const VMStateField[]) {
162*c1bf7540SRayhan Faizel         VMSTATE_UINT32_ARRAY(otp_rows, BCM2835OTPState, BCM2835_OTP_ROW_COUNT),
163*c1bf7540SRayhan Faizel         VMSTATE_END_OF_LIST()
164*c1bf7540SRayhan Faizel     }
165*c1bf7540SRayhan Faizel };
166*c1bf7540SRayhan Faizel 
bcm2835_otp_class_init(ObjectClass * klass,void * data)167*c1bf7540SRayhan Faizel static void bcm2835_otp_class_init(ObjectClass *klass, void *data)
168*c1bf7540SRayhan Faizel {
169*c1bf7540SRayhan Faizel     DeviceClass *dc = DEVICE_CLASS(klass);
170*c1bf7540SRayhan Faizel 
171*c1bf7540SRayhan Faizel     dc->realize = bcm2835_otp_realize;
172*c1bf7540SRayhan Faizel     dc->vmsd = &vmstate_bcm2835_otp;
173*c1bf7540SRayhan Faizel }
174*c1bf7540SRayhan Faizel 
175*c1bf7540SRayhan Faizel static const TypeInfo bcm2835_otp_info = {
176*c1bf7540SRayhan Faizel     .name = TYPE_BCM2835_OTP,
177*c1bf7540SRayhan Faizel     .parent = TYPE_SYS_BUS_DEVICE,
178*c1bf7540SRayhan Faizel     .instance_size = sizeof(BCM2835OTPState),
179*c1bf7540SRayhan Faizel     .class_init = bcm2835_otp_class_init,
180*c1bf7540SRayhan Faizel };
181*c1bf7540SRayhan Faizel 
bcm2835_otp_register_types(void)182*c1bf7540SRayhan Faizel static void bcm2835_otp_register_types(void)
183*c1bf7540SRayhan Faizel {
184*c1bf7540SRayhan Faizel     type_register_static(&bcm2835_otp_info);
185*c1bf7540SRayhan Faizel }
186*c1bf7540SRayhan Faizel 
187*c1bf7540SRayhan Faizel type_init(bcm2835_otp_register_types)
188