xlnx-zynqmp-crf.c 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266
  1. /*
  2. * QEMU model of the CRF - Clock Reset FPD.
  3. *
  4. * Copyright (c) 2022 Xilinx Inc.
  5. * SPDX-License-Identifier: GPL-2.0-or-later
  6. * Written by Edgar E. Iglesias <edgar.iglesias@xilinx.com>
  7. */
  8. #include "qemu/osdep.h"
  9. #include "hw/sysbus.h"
  10. #include "hw/register.h"
  11. #include "qemu/bitops.h"
  12. #include "qemu/log.h"
  13. #include "migration/vmstate.h"
  14. #include "hw/irq.h"
  15. #include "hw/misc/xlnx-zynqmp-crf.h"
  16. #include "target/arm/arm-powerctl.h"
  17. #ifndef XLNX_ZYNQMP_CRF_ERR_DEBUG
  18. #define XLNX_ZYNQMP_CRF_ERR_DEBUG 0
  19. #endif
  20. #define CRF_MAX_CPU 4
  21. static void ir_update_irq(XlnxZynqMPCRF *s)
  22. {
  23. bool pending = s->regs[R_IR_STATUS] & ~s->regs[R_IR_MASK];
  24. qemu_set_irq(s->irq_ir, pending);
  25. }
  26. static void ir_status_postw(RegisterInfo *reg, uint64_t val64)
  27. {
  28. XlnxZynqMPCRF *s = XLNX_ZYNQMP_CRF(reg->opaque);
  29. ir_update_irq(s);
  30. }
  31. static uint64_t ir_enable_prew(RegisterInfo *reg, uint64_t val64)
  32. {
  33. XlnxZynqMPCRF *s = XLNX_ZYNQMP_CRF(reg->opaque);
  34. uint32_t val = val64;
  35. s->regs[R_IR_MASK] &= ~val;
  36. ir_update_irq(s);
  37. return 0;
  38. }
  39. static uint64_t ir_disable_prew(RegisterInfo *reg, uint64_t val64)
  40. {
  41. XlnxZynqMPCRF *s = XLNX_ZYNQMP_CRF(reg->opaque);
  42. uint32_t val = val64;
  43. s->regs[R_IR_MASK] |= val;
  44. ir_update_irq(s);
  45. return 0;
  46. }
  47. static uint64_t rst_fpd_apu_prew(RegisterInfo *reg, uint64_t val64)
  48. {
  49. XlnxZynqMPCRF *s = XLNX_ZYNQMP_CRF(reg->opaque);
  50. uint32_t val = val64;
  51. uint32_t val_old = s->regs[R_RST_FPD_APU];
  52. unsigned int i;
  53. for (i = 0; i < CRF_MAX_CPU; i++) {
  54. uint32_t mask = (1 << (R_RST_FPD_APU_ACPU0_RESET_SHIFT + i));
  55. if ((val ^ val_old) & mask) {
  56. if (val & mask) {
  57. arm_set_cpu_off(i);
  58. } else {
  59. arm_set_cpu_on_and_reset(i);
  60. }
  61. }
  62. }
  63. return val64;
  64. }
  65. static const RegisterAccessInfo crf_regs_info[] = {
  66. { .name = "ERR_CTRL", .addr = A_ERR_CTRL,
  67. },{ .name = "IR_STATUS", .addr = A_IR_STATUS,
  68. .w1c = 0x1,
  69. .post_write = ir_status_postw,
  70. },{ .name = "IR_MASK", .addr = A_IR_MASK,
  71. .reset = 0x1,
  72. .ro = 0x1,
  73. },{ .name = "IR_ENABLE", .addr = A_IR_ENABLE,
  74. .pre_write = ir_enable_prew,
  75. },{ .name = "IR_DISABLE", .addr = A_IR_DISABLE,
  76. .pre_write = ir_disable_prew,
  77. },{ .name = "CRF_WPROT", .addr = A_CRF_WPROT,
  78. },{ .name = "APLL_CTRL", .addr = A_APLL_CTRL,
  79. .reset = 0x12c09,
  80. .rsvd = 0xf88c80f6,
  81. },{ .name = "APLL_CFG", .addr = A_APLL_CFG,
  82. .rsvd = 0x1801210,
  83. },{ .name = "APLL_FRAC_CFG", .addr = A_APLL_FRAC_CFG,
  84. .rsvd = 0x7e330000,
  85. },{ .name = "DPLL_CTRL", .addr = A_DPLL_CTRL,
  86. .reset = 0x2c09,
  87. .rsvd = 0xf88c80f6,
  88. },{ .name = "DPLL_CFG", .addr = A_DPLL_CFG,
  89. .rsvd = 0x1801210,
  90. },{ .name = "DPLL_FRAC_CFG", .addr = A_DPLL_FRAC_CFG,
  91. .rsvd = 0x7e330000,
  92. },{ .name = "VPLL_CTRL", .addr = A_VPLL_CTRL,
  93. .reset = 0x12809,
  94. .rsvd = 0xf88c80f6,
  95. },{ .name = "VPLL_CFG", .addr = A_VPLL_CFG,
  96. .rsvd = 0x1801210,
  97. },{ .name = "VPLL_FRAC_CFG", .addr = A_VPLL_FRAC_CFG,
  98. .rsvd = 0x7e330000,
  99. },{ .name = "PLL_STATUS", .addr = A_PLL_STATUS,
  100. .reset = 0x3f,
  101. .rsvd = 0xc0,
  102. .ro = 0x3f,
  103. },{ .name = "APLL_TO_LPD_CTRL", .addr = A_APLL_TO_LPD_CTRL,
  104. .reset = 0x400,
  105. .rsvd = 0xc0ff,
  106. },{ .name = "DPLL_TO_LPD_CTRL", .addr = A_DPLL_TO_LPD_CTRL,
  107. .reset = 0x400,
  108. .rsvd = 0xc0ff,
  109. },{ .name = "VPLL_TO_LPD_CTRL", .addr = A_VPLL_TO_LPD_CTRL,
  110. .reset = 0x400,
  111. .rsvd = 0xc0ff,
  112. },{ .name = "ACPU_CTRL", .addr = A_ACPU_CTRL,
  113. .reset = 0x3000400,
  114. .rsvd = 0xfcffc0f8,
  115. },{ .name = "DBG_TRACE_CTRL", .addr = A_DBG_TRACE_CTRL,
  116. .reset = 0x2500,
  117. .rsvd = 0xfeffc0f8,
  118. },{ .name = "DBG_FPD_CTRL", .addr = A_DBG_FPD_CTRL,
  119. .reset = 0x1002500,
  120. .rsvd = 0xfeffc0f8,
  121. },{ .name = "DP_VIDEO_REF_CTRL", .addr = A_DP_VIDEO_REF_CTRL,
  122. .reset = 0x1002300,
  123. .rsvd = 0xfec0c0f8,
  124. },{ .name = "DP_AUDIO_REF_CTRL", .addr = A_DP_AUDIO_REF_CTRL,
  125. .reset = 0x1032300,
  126. .rsvd = 0xfec0c0f8,
  127. },{ .name = "DP_STC_REF_CTRL", .addr = A_DP_STC_REF_CTRL,
  128. .reset = 0x1203200,
  129. .rsvd = 0xfec0c0f8,
  130. },{ .name = "DDR_CTRL", .addr = A_DDR_CTRL,
  131. .reset = 0x1000500,
  132. .rsvd = 0xfeffc0f8,
  133. },{ .name = "GPU_REF_CTRL", .addr = A_GPU_REF_CTRL,
  134. .reset = 0x1500,
  135. .rsvd = 0xf8ffc0f8,
  136. },{ .name = "SATA_REF_CTRL", .addr = A_SATA_REF_CTRL,
  137. .reset = 0x1001600,
  138. .rsvd = 0xfeffc0f8,
  139. },{ .name = "PCIE_REF_CTRL", .addr = A_PCIE_REF_CTRL,
  140. .reset = 0x1500,
  141. .rsvd = 0xfeffc0f8,
  142. },{ .name = "GDMA_REF_CTRL", .addr = A_GDMA_REF_CTRL,
  143. .reset = 0x1000500,
  144. .rsvd = 0xfeffc0f8,
  145. },{ .name = "DPDMA_REF_CTRL", .addr = A_DPDMA_REF_CTRL,
  146. .reset = 0x1000500,
  147. .rsvd = 0xfeffc0f8,
  148. },{ .name = "TOPSW_MAIN_CTRL", .addr = A_TOPSW_MAIN_CTRL,
  149. .reset = 0x1000400,
  150. .rsvd = 0xfeffc0f8,
  151. },{ .name = "TOPSW_LSBUS_CTRL", .addr = A_TOPSW_LSBUS_CTRL,
  152. .reset = 0x1000800,
  153. .rsvd = 0xfeffc0f8,
  154. },{ .name = "DBG_TSTMP_CTRL", .addr = A_DBG_TSTMP_CTRL,
  155. .reset = 0xa00,
  156. .rsvd = 0xffffc0f8,
  157. },
  158. { .name = "RST_FPD_TOP", .addr = A_RST_FPD_TOP,
  159. .reset = 0xf9ffe,
  160. .rsvd = 0xf06001,
  161. },{ .name = "RST_FPD_APU", .addr = A_RST_FPD_APU,
  162. .reset = 0x3d0f,
  163. .rsvd = 0xc2f0,
  164. .pre_write = rst_fpd_apu_prew,
  165. },{ .name = "RST_DDR_SS", .addr = A_RST_DDR_SS,
  166. .reset = 0xf,
  167. .rsvd = 0xf3,
  168. }
  169. };
  170. static void crf_reset_enter(Object *obj, ResetType type)
  171. {
  172. XlnxZynqMPCRF *s = XLNX_ZYNQMP_CRF(obj);
  173. unsigned int i;
  174. for (i = 0; i < ARRAY_SIZE(s->regs_info); ++i) {
  175. register_reset(&s->regs_info[i]);
  176. }
  177. }
  178. static void crf_reset_hold(Object *obj, ResetType type)
  179. {
  180. XlnxZynqMPCRF *s = XLNX_ZYNQMP_CRF(obj);
  181. ir_update_irq(s);
  182. }
  183. static const MemoryRegionOps crf_ops = {
  184. .read = register_read_memory,
  185. .write = register_write_memory,
  186. .endianness = DEVICE_LITTLE_ENDIAN,
  187. .valid = {
  188. .min_access_size = 4,
  189. .max_access_size = 4,
  190. },
  191. };
  192. static void crf_init(Object *obj)
  193. {
  194. XlnxZynqMPCRF *s = XLNX_ZYNQMP_CRF(obj);
  195. SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
  196. s->reg_array =
  197. register_init_block32(DEVICE(obj), crf_regs_info,
  198. ARRAY_SIZE(crf_regs_info),
  199. s->regs_info, s->regs,
  200. &crf_ops,
  201. XLNX_ZYNQMP_CRF_ERR_DEBUG,
  202. CRF_R_MAX * 4);
  203. sysbus_init_mmio(sbd, &s->reg_array->mem);
  204. sysbus_init_irq(sbd, &s->irq_ir);
  205. }
  206. static void crf_finalize(Object *obj)
  207. {
  208. XlnxZynqMPCRF *s = XLNX_ZYNQMP_CRF(obj);
  209. register_finalize_block(s->reg_array);
  210. }
  211. static const VMStateDescription vmstate_crf = {
  212. .name = TYPE_XLNX_ZYNQMP_CRF,
  213. .version_id = 1,
  214. .minimum_version_id = 1,
  215. .fields = (const VMStateField[]) {
  216. VMSTATE_UINT32_ARRAY(regs, XlnxZynqMPCRF, CRF_R_MAX),
  217. VMSTATE_END_OF_LIST(),
  218. }
  219. };
  220. static void crf_class_init(ObjectClass *klass, void *data)
  221. {
  222. ResettableClass *rc = RESETTABLE_CLASS(klass);
  223. DeviceClass *dc = DEVICE_CLASS(klass);
  224. dc->vmsd = &vmstate_crf;
  225. rc->phases.enter = crf_reset_enter;
  226. rc->phases.hold = crf_reset_hold;
  227. }
  228. static const TypeInfo crf_info = {
  229. .name = TYPE_XLNX_ZYNQMP_CRF,
  230. .parent = TYPE_SYS_BUS_DEVICE,
  231. .instance_size = sizeof(XlnxZynqMPCRF),
  232. .class_init = crf_class_init,
  233. .instance_init = crf_init,
  234. .instance_finalize = crf_finalize,
  235. };
  236. static void crf_register_types(void)
  237. {
  238. type_register_static(&crf_info);
  239. }
  240. type_init(crf_register_types)