2
0

sifive_u_otp.c 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191
  1. /*
  2. * QEMU SiFive U OTP (One-Time Programmable) Memory interface
  3. *
  4. * Copyright (c) 2019 Bin Meng <bmeng.cn@gmail.com>
  5. *
  6. * Simple model of the OTP to emulate register reads made by the SDK BSP
  7. *
  8. * This program is free software; you can redistribute it and/or modify it
  9. * under the terms and conditions of the GNU General Public License,
  10. * version 2 or later, as published by the Free Software Foundation.
  11. *
  12. * This program is distributed in the hope it will be useful, but WITHOUT
  13. * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  14. * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
  15. * more details.
  16. *
  17. * You should have received a copy of the GNU General Public License along with
  18. * this program. If not, see <http://www.gnu.org/licenses/>.
  19. */
  20. #include "qemu/osdep.h"
  21. #include "hw/qdev-properties.h"
  22. #include "hw/sysbus.h"
  23. #include "qemu/log.h"
  24. #include "qemu/module.h"
  25. #include "hw/misc/sifive_u_otp.h"
  26. static uint64_t sifive_u_otp_read(void *opaque, hwaddr addr, unsigned int size)
  27. {
  28. SiFiveUOTPState *s = opaque;
  29. switch (addr) {
  30. case SIFIVE_U_OTP_PA:
  31. return s->pa;
  32. case SIFIVE_U_OTP_PAIO:
  33. return s->paio;
  34. case SIFIVE_U_OTP_PAS:
  35. return s->pas;
  36. case SIFIVE_U_OTP_PCE:
  37. return s->pce;
  38. case SIFIVE_U_OTP_PCLK:
  39. return s->pclk;
  40. case SIFIVE_U_OTP_PDIN:
  41. return s->pdin;
  42. case SIFIVE_U_OTP_PDOUT:
  43. if ((s->pce & SIFIVE_U_OTP_PCE_EN) &&
  44. (s->pdstb & SIFIVE_U_OTP_PDSTB_EN) &&
  45. (s->ptrim & SIFIVE_U_OTP_PTRIM_EN)) {
  46. return s->fuse[s->pa & SIFIVE_U_OTP_PA_MASK];
  47. } else {
  48. return 0xff;
  49. }
  50. case SIFIVE_U_OTP_PDSTB:
  51. return s->pdstb;
  52. case SIFIVE_U_OTP_PPROG:
  53. return s->pprog;
  54. case SIFIVE_U_OTP_PTC:
  55. return s->ptc;
  56. case SIFIVE_U_OTP_PTM:
  57. return s->ptm;
  58. case SIFIVE_U_OTP_PTM_REP:
  59. return s->ptm_rep;
  60. case SIFIVE_U_OTP_PTR:
  61. return s->ptr;
  62. case SIFIVE_U_OTP_PTRIM:
  63. return s->ptrim;
  64. case SIFIVE_U_OTP_PWE:
  65. return s->pwe;
  66. }
  67. qemu_log_mask(LOG_GUEST_ERROR, "%s: read: addr=0x%" HWADDR_PRIx "\n",
  68. __func__, addr);
  69. return 0;
  70. }
  71. static void sifive_u_otp_write(void *opaque, hwaddr addr,
  72. uint64_t val64, unsigned int size)
  73. {
  74. SiFiveUOTPState *s = opaque;
  75. uint32_t val32 = (uint32_t)val64;
  76. switch (addr) {
  77. case SIFIVE_U_OTP_PA:
  78. s->pa = val32 & SIFIVE_U_OTP_PA_MASK;
  79. break;
  80. case SIFIVE_U_OTP_PAIO:
  81. s->paio = val32;
  82. break;
  83. case SIFIVE_U_OTP_PAS:
  84. s->pas = val32;
  85. break;
  86. case SIFIVE_U_OTP_PCE:
  87. s->pce = val32;
  88. break;
  89. case SIFIVE_U_OTP_PCLK:
  90. s->pclk = val32;
  91. break;
  92. case SIFIVE_U_OTP_PDIN:
  93. s->pdin = val32;
  94. break;
  95. case SIFIVE_U_OTP_PDOUT:
  96. /* read-only */
  97. break;
  98. case SIFIVE_U_OTP_PDSTB:
  99. s->pdstb = val32;
  100. break;
  101. case SIFIVE_U_OTP_PPROG:
  102. s->pprog = val32;
  103. break;
  104. case SIFIVE_U_OTP_PTC:
  105. s->ptc = val32;
  106. break;
  107. case SIFIVE_U_OTP_PTM:
  108. s->ptm = val32;
  109. break;
  110. case SIFIVE_U_OTP_PTM_REP:
  111. s->ptm_rep = val32;
  112. break;
  113. case SIFIVE_U_OTP_PTR:
  114. s->ptr = val32;
  115. break;
  116. case SIFIVE_U_OTP_PTRIM:
  117. s->ptrim = val32;
  118. break;
  119. case SIFIVE_U_OTP_PWE:
  120. s->pwe = val32;
  121. break;
  122. default:
  123. qemu_log_mask(LOG_GUEST_ERROR, "%s: bad write: addr=0x%" HWADDR_PRIx
  124. " v=0x%x\n", __func__, addr, val32);
  125. }
  126. }
  127. static const MemoryRegionOps sifive_u_otp_ops = {
  128. .read = sifive_u_otp_read,
  129. .write = sifive_u_otp_write,
  130. .endianness = DEVICE_NATIVE_ENDIAN,
  131. .valid = {
  132. .min_access_size = 4,
  133. .max_access_size = 4
  134. }
  135. };
  136. static Property sifive_u_otp_properties[] = {
  137. DEFINE_PROP_UINT32("serial", SiFiveUOTPState, serial, 0),
  138. DEFINE_PROP_END_OF_LIST(),
  139. };
  140. static void sifive_u_otp_realize(DeviceState *dev, Error **errp)
  141. {
  142. SiFiveUOTPState *s = SIFIVE_U_OTP(dev);
  143. memory_region_init_io(&s->mmio, OBJECT(dev), &sifive_u_otp_ops, s,
  144. TYPE_SIFIVE_U_OTP, SIFIVE_U_OTP_REG_SIZE);
  145. sysbus_init_mmio(SYS_BUS_DEVICE(dev), &s->mmio);
  146. }
  147. static void sifive_u_otp_reset(DeviceState *dev)
  148. {
  149. SiFiveUOTPState *s = SIFIVE_U_OTP(dev);
  150. /* Initialize all fuses' initial value to 0xFFs */
  151. memset(s->fuse, 0xff, sizeof(s->fuse));
  152. /* Make a valid content of serial number */
  153. s->fuse[SIFIVE_U_OTP_SERIAL_ADDR] = s->serial;
  154. s->fuse[SIFIVE_U_OTP_SERIAL_ADDR + 1] = ~(s->serial);
  155. }
  156. static void sifive_u_otp_class_init(ObjectClass *klass, void *data)
  157. {
  158. DeviceClass *dc = DEVICE_CLASS(klass);
  159. device_class_set_props(dc, sifive_u_otp_properties);
  160. dc->realize = sifive_u_otp_realize;
  161. dc->reset = sifive_u_otp_reset;
  162. }
  163. static const TypeInfo sifive_u_otp_info = {
  164. .name = TYPE_SIFIVE_U_OTP,
  165. .parent = TYPE_SYS_BUS_DEVICE,
  166. .instance_size = sizeof(SiFiveUOTPState),
  167. .class_init = sifive_u_otp_class_init,
  168. };
  169. static void sifive_u_otp_register_types(void)
  170. {
  171. type_register_static(&sifive_u_otp_info);
  172. }
  173. type_init(sifive_u_otp_register_types)