xref: /openbmc/qemu/hw/nvram/bcm2835_otp.c (revision c80a339587fe4148292c260716482dd2f86d4476)
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