2
0

sifive_u_prci.c 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169
  1. /*
  2. * QEMU SiFive U PRCI (Power, Reset, Clock, Interrupt)
  3. *
  4. * Copyright (c) 2019 Bin Meng <bmeng.cn@gmail.com>
  5. *
  6. * Simple model of the PRCI 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/sysbus.h"
  22. #include "qemu/log.h"
  23. #include "qemu/module.h"
  24. #include "hw/riscv/sifive_u_prci.h"
  25. static uint64_t sifive_u_prci_read(void *opaque, hwaddr addr, unsigned int size)
  26. {
  27. SiFiveUPRCIState *s = opaque;
  28. switch (addr) {
  29. case SIFIVE_U_PRCI_HFXOSCCFG:
  30. return s->hfxosccfg;
  31. case SIFIVE_U_PRCI_COREPLLCFG0:
  32. return s->corepllcfg0;
  33. case SIFIVE_U_PRCI_DDRPLLCFG0:
  34. return s->ddrpllcfg0;
  35. case SIFIVE_U_PRCI_DDRPLLCFG1:
  36. return s->ddrpllcfg1;
  37. case SIFIVE_U_PRCI_GEMGXLPLLCFG0:
  38. return s->gemgxlpllcfg0;
  39. case SIFIVE_U_PRCI_GEMGXLPLLCFG1:
  40. return s->gemgxlpllcfg1;
  41. case SIFIVE_U_PRCI_CORECLKSEL:
  42. return s->coreclksel;
  43. case SIFIVE_U_PRCI_DEVICESRESET:
  44. return s->devicesreset;
  45. case SIFIVE_U_PRCI_CLKMUXSTATUS:
  46. return s->clkmuxstatus;
  47. }
  48. qemu_log_mask(LOG_GUEST_ERROR, "%s: read: addr=0x%" HWADDR_PRIx "\n",
  49. __func__, addr);
  50. return 0;
  51. }
  52. static void sifive_u_prci_write(void *opaque, hwaddr addr,
  53. uint64_t val64, unsigned int size)
  54. {
  55. SiFiveUPRCIState *s = opaque;
  56. uint32_t val32 = (uint32_t)val64;
  57. switch (addr) {
  58. case SIFIVE_U_PRCI_HFXOSCCFG:
  59. s->hfxosccfg = val32;
  60. /* OSC stays ready */
  61. s->hfxosccfg |= SIFIVE_U_PRCI_HFXOSCCFG_RDY;
  62. break;
  63. case SIFIVE_U_PRCI_COREPLLCFG0:
  64. s->corepllcfg0 = val32;
  65. /* internal feedback */
  66. s->corepllcfg0 |= SIFIVE_U_PRCI_PLLCFG0_FSE;
  67. /* PLL stays locked */
  68. s->corepllcfg0 |= SIFIVE_U_PRCI_PLLCFG0_LOCK;
  69. break;
  70. case SIFIVE_U_PRCI_DDRPLLCFG0:
  71. s->ddrpllcfg0 = val32;
  72. /* internal feedback */
  73. s->ddrpllcfg0 |= SIFIVE_U_PRCI_PLLCFG0_FSE;
  74. /* PLL stays locked */
  75. s->ddrpllcfg0 |= SIFIVE_U_PRCI_PLLCFG0_LOCK;
  76. break;
  77. case SIFIVE_U_PRCI_DDRPLLCFG1:
  78. s->ddrpllcfg1 = val32;
  79. break;
  80. case SIFIVE_U_PRCI_GEMGXLPLLCFG0:
  81. s->gemgxlpllcfg0 = val32;
  82. /* internal feedback */
  83. s->gemgxlpllcfg0 |= SIFIVE_U_PRCI_PLLCFG0_FSE;
  84. /* PLL stays locked */
  85. s->gemgxlpllcfg0 |= SIFIVE_U_PRCI_PLLCFG0_LOCK;
  86. break;
  87. case SIFIVE_U_PRCI_GEMGXLPLLCFG1:
  88. s->gemgxlpllcfg1 = val32;
  89. break;
  90. case SIFIVE_U_PRCI_CORECLKSEL:
  91. s->coreclksel = val32;
  92. break;
  93. case SIFIVE_U_PRCI_DEVICESRESET:
  94. s->devicesreset = val32;
  95. break;
  96. case SIFIVE_U_PRCI_CLKMUXSTATUS:
  97. s->clkmuxstatus = val32;
  98. break;
  99. default:
  100. qemu_log_mask(LOG_GUEST_ERROR, "%s: bad write: addr=0x%" HWADDR_PRIx
  101. " v=0x%x\n", __func__, addr, val32);
  102. }
  103. }
  104. static const MemoryRegionOps sifive_u_prci_ops = {
  105. .read = sifive_u_prci_read,
  106. .write = sifive_u_prci_write,
  107. .endianness = DEVICE_NATIVE_ENDIAN,
  108. .valid = {
  109. .min_access_size = 4,
  110. .max_access_size = 4
  111. }
  112. };
  113. static void sifive_u_prci_realize(DeviceState *dev, Error **errp)
  114. {
  115. SiFiveUPRCIState *s = SIFIVE_U_PRCI(dev);
  116. memory_region_init_io(&s->mmio, OBJECT(dev), &sifive_u_prci_ops, s,
  117. TYPE_SIFIVE_U_PRCI, SIFIVE_U_PRCI_REG_SIZE);
  118. sysbus_init_mmio(SYS_BUS_DEVICE(dev), &s->mmio);
  119. }
  120. static void sifive_u_prci_reset(DeviceState *dev)
  121. {
  122. SiFiveUPRCIState *s = SIFIVE_U_PRCI(dev);
  123. /* Initialize register to power-on-reset values */
  124. s->hfxosccfg = SIFIVE_U_PRCI_HFXOSCCFG_RDY | SIFIVE_U_PRCI_HFXOSCCFG_EN;
  125. s->corepllcfg0 = SIFIVE_U_PRCI_PLLCFG0_DIVR | SIFIVE_U_PRCI_PLLCFG0_DIVF |
  126. SIFIVE_U_PRCI_PLLCFG0_DIVQ | SIFIVE_U_PRCI_PLLCFG0_FSE |
  127. SIFIVE_U_PRCI_PLLCFG0_LOCK;
  128. s->ddrpllcfg0 = SIFIVE_U_PRCI_PLLCFG0_DIVR | SIFIVE_U_PRCI_PLLCFG0_DIVF |
  129. SIFIVE_U_PRCI_PLLCFG0_DIVQ | SIFIVE_U_PRCI_PLLCFG0_FSE |
  130. SIFIVE_U_PRCI_PLLCFG0_LOCK;
  131. s->gemgxlpllcfg0 = SIFIVE_U_PRCI_PLLCFG0_DIVR | SIFIVE_U_PRCI_PLLCFG0_DIVF |
  132. SIFIVE_U_PRCI_PLLCFG0_DIVQ | SIFIVE_U_PRCI_PLLCFG0_FSE |
  133. SIFIVE_U_PRCI_PLLCFG0_LOCK;
  134. s->coreclksel = SIFIVE_U_PRCI_CORECLKSEL_HFCLK;
  135. }
  136. static void sifive_u_prci_class_init(ObjectClass *klass, void *data)
  137. {
  138. DeviceClass *dc = DEVICE_CLASS(klass);
  139. dc->realize = sifive_u_prci_realize;
  140. dc->reset = sifive_u_prci_reset;
  141. }
  142. static const TypeInfo sifive_u_prci_info = {
  143. .name = TYPE_SIFIVE_U_PRCI,
  144. .parent = TYPE_SYS_BUS_DEVICE,
  145. .instance_size = sizeof(SiFiveUPRCIState),
  146. .class_init = sifive_u_prci_class_init,
  147. };
  148. static void sifive_u_prci_register_types(void)
  149. {
  150. type_register_static(&sifive_u_prci_info);
  151. }
  152. type_init(sifive_u_prci_register_types)