2
0

stm32_rcc.c 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162
  1. /*
  2. * STM32 RCC (only reset and enable registers are implemented)
  3. *
  4. * Copyright (c) 2024 Román Cárdenas <rcardenas.rod@gmail.com>
  5. *
  6. * Permission is hereby granted, free of charge, to any person obtaining a copy
  7. * of this software and associated documentation files (the "Software"), to deal
  8. * in the Software without restriction, including without limitation the rights
  9. * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  10. * copies of the Software, and to permit persons to whom the Software is
  11. * furnished to do so, subject to the following conditions:
  12. *
  13. * The above copyright notice and this permission notice shall be included in
  14. * all copies or substantial portions of the Software.
  15. *
  16. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  17. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  18. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
  19. * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  20. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  21. * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  22. * THE SOFTWARE.
  23. */
  24. #include "qemu/osdep.h"
  25. #include "qemu/log.h"
  26. #include "trace.h"
  27. #include "hw/irq.h"
  28. #include "migration/vmstate.h"
  29. #include "hw/misc/stm32_rcc.h"
  30. static void stm32_rcc_reset(DeviceState *dev)
  31. {
  32. STM32RccState *s = STM32_RCC(dev);
  33. for (int i = 0; i < STM32_RCC_NREGS; i++) {
  34. s->regs[i] = 0;
  35. }
  36. }
  37. static uint64_t stm32_rcc_read(void *opaque, hwaddr addr, unsigned int size)
  38. {
  39. STM32RccState *s = STM32_RCC(opaque);
  40. uint32_t value = 0;
  41. if (addr > STM32_RCC_DCKCFGR2) {
  42. qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset 0x%"HWADDR_PRIx"\n",
  43. __func__, addr);
  44. } else {
  45. value = s->regs[addr >> 2];
  46. }
  47. trace_stm32_rcc_read(addr, value);
  48. return value;
  49. }
  50. static void stm32_rcc_write(void *opaque, hwaddr addr,
  51. uint64_t val64, unsigned int size)
  52. {
  53. STM32RccState *s = STM32_RCC(opaque);
  54. uint32_t value = val64;
  55. uint32_t prev_value, new_value, irq_offset;
  56. trace_stm32_rcc_write(value, addr);
  57. if (addr > STM32_RCC_DCKCFGR2) {
  58. qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset 0x%"HWADDR_PRIx"\n",
  59. __func__, addr);
  60. return;
  61. }
  62. switch (addr) {
  63. case STM32_RCC_AHB1_RSTR...STM32_RCC_APB2_RSTR:
  64. prev_value = s->regs[addr / 4];
  65. s->regs[addr / 4] = value;
  66. irq_offset = ((addr - STM32_RCC_AHB1_RSTR) / 4) * 32;
  67. for (int i = 0; i < 32; i++) {
  68. new_value = extract32(value, i, 1);
  69. if (extract32(prev_value, i, 1) && !new_value) {
  70. trace_stm32_rcc_pulse_reset(irq_offset + i, new_value);
  71. qemu_set_irq(s->reset_irq[irq_offset + i], new_value);
  72. }
  73. }
  74. return;
  75. case STM32_RCC_AHB1_ENR...STM32_RCC_APB2_ENR:
  76. prev_value = s->regs[addr / 4];
  77. s->regs[addr / 4] = value;
  78. irq_offset = ((addr - STM32_RCC_AHB1_ENR) / 4) * 32;
  79. for (int i = 0; i < 32; i++) {
  80. new_value = extract32(value, i, 1);
  81. if (!extract32(prev_value, i, 1) && new_value) {
  82. trace_stm32_rcc_pulse_enable(irq_offset + i, new_value);
  83. qemu_set_irq(s->enable_irq[irq_offset + i], new_value);
  84. }
  85. }
  86. return;
  87. default:
  88. qemu_log_mask(
  89. LOG_UNIMP,
  90. "%s: The RCC peripheral only supports enable and reset in QEMU\n",
  91. __func__
  92. );
  93. s->regs[addr >> 2] = value;
  94. }
  95. }
  96. static const MemoryRegionOps stm32_rcc_ops = {
  97. .read = stm32_rcc_read,
  98. .write = stm32_rcc_write,
  99. .endianness = DEVICE_NATIVE_ENDIAN,
  100. };
  101. static void stm32_rcc_init(Object *obj)
  102. {
  103. STM32RccState *s = STM32_RCC(obj);
  104. memory_region_init_io(&s->mmio, obj, &stm32_rcc_ops, s,
  105. TYPE_STM32_RCC, STM32_RCC_PERIPHERAL_SIZE);
  106. sysbus_init_mmio(SYS_BUS_DEVICE(obj), &s->mmio);
  107. qdev_init_gpio_out(DEVICE(obj), s->reset_irq, STM32_RCC_NIRQS);
  108. qdev_init_gpio_out(DEVICE(obj), s->enable_irq, STM32_RCC_NIRQS);
  109. for (int i = 0; i < STM32_RCC_NIRQS; i++) {
  110. sysbus_init_irq(SYS_BUS_DEVICE(obj), &s->reset_irq[i]);
  111. sysbus_init_irq(SYS_BUS_DEVICE(obj), &s->enable_irq[i]);
  112. }
  113. }
  114. static const VMStateDescription vmstate_stm32_rcc = {
  115. .name = TYPE_STM32_RCC,
  116. .version_id = 1,
  117. .minimum_version_id = 1,
  118. .fields = (const VMStateField[]) {
  119. VMSTATE_UINT32_ARRAY(regs, STM32RccState, STM32_RCC_NREGS),
  120. VMSTATE_END_OF_LIST()
  121. }
  122. };
  123. static void stm32_rcc_class_init(ObjectClass *klass, void *data)
  124. {
  125. DeviceClass *dc = DEVICE_CLASS(klass);
  126. dc->vmsd = &vmstate_stm32_rcc;
  127. device_class_set_legacy_reset(dc, stm32_rcc_reset);
  128. }
  129. static const TypeInfo stm32_rcc_info = {
  130. .name = TYPE_STM32_RCC,
  131. .parent = TYPE_SYS_BUS_DEVICE,
  132. .instance_size = sizeof(STM32RccState),
  133. .instance_init = stm32_rcc_init,
  134. .class_init = stm32_rcc_class_init,
  135. };
  136. static void stm32_rcc_register_types(void)
  137. {
  138. type_register_static(&stm32_rcc_info);
  139. }
  140. type_init(stm32_rcc_register_types)