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