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 */
bcm2835_otp_get_row(BCM2835OTPState * s,unsigned int row)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
bcm2835_otp_set_row(BCM2835OTPState * s,unsigned int row,uint32_t value)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
bcm2835_otp_read(void * opaque,hwaddr addr,unsigned size)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
bcm2835_otp_write(void * opaque,hwaddr addr,uint64_t value,unsigned int size)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
bcm2835_otp_realize(DeviceState * dev,Error ** errp)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
bcm2835_otp_class_init(ObjectClass * klass,void * data)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
bcm2835_otp_register_types(void)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