imx6_src.c 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265
  1. /*
  2. * IMX6 System Reset Controller
  3. *
  4. * Copyright (c) 2015 Jean-Christophe Dubois <jcd@tribudubois.net>
  5. *
  6. * This work is licensed under the terms of the GNU GPL, version 2 or later.
  7. * See the COPYING file in the top-level directory.
  8. *
  9. */
  10. #include "qemu/osdep.h"
  11. #include "hw/misc/imx6_src.h"
  12. #include "sysemu/sysemu.h"
  13. #include "qemu/bitops.h"
  14. #include "qemu/log.h"
  15. #include "arm-powerctl.h"
  16. #ifndef DEBUG_IMX6_SRC
  17. #define DEBUG_IMX6_SRC 0
  18. #endif
  19. #define DPRINTF(fmt, args...) \
  20. do { \
  21. if (DEBUG_IMX6_SRC) { \
  22. fprintf(stderr, "[%s]%s: " fmt , TYPE_IMX6_SRC, \
  23. __func__, ##args); \
  24. } \
  25. } while (0)
  26. static char const *imx6_src_reg_name(uint32_t reg)
  27. {
  28. static char unknown[20];
  29. switch (reg) {
  30. case SRC_SCR:
  31. return "SRC_SCR";
  32. case SRC_SBMR1:
  33. return "SRC_SBMR1";
  34. case SRC_SRSR:
  35. return "SRC_SRSR";
  36. case SRC_SISR:
  37. return "SRC_SISR";
  38. case SRC_SIMR:
  39. return "SRC_SIMR";
  40. case SRC_SBMR2:
  41. return "SRC_SBMR2";
  42. case SRC_GPR1:
  43. return "SRC_GPR1";
  44. case SRC_GPR2:
  45. return "SRC_GPR2";
  46. case SRC_GPR3:
  47. return "SRC_GPR3";
  48. case SRC_GPR4:
  49. return "SRC_GPR4";
  50. case SRC_GPR5:
  51. return "SRC_GPR5";
  52. case SRC_GPR6:
  53. return "SRC_GPR6";
  54. case SRC_GPR7:
  55. return "SRC_GPR7";
  56. case SRC_GPR8:
  57. return "SRC_GPR8";
  58. case SRC_GPR9:
  59. return "SRC_GPR9";
  60. case SRC_GPR10:
  61. return "SRC_GPR10";
  62. default:
  63. sprintf(unknown, "%d ?", reg);
  64. return unknown;
  65. }
  66. }
  67. static const VMStateDescription vmstate_imx6_src = {
  68. .name = TYPE_IMX6_SRC,
  69. .version_id = 1,
  70. .minimum_version_id = 1,
  71. .fields = (VMStateField[]) {
  72. VMSTATE_UINT32_ARRAY(regs, IMX6SRCState, SRC_MAX),
  73. VMSTATE_END_OF_LIST()
  74. },
  75. };
  76. static void imx6_src_reset(DeviceState *dev)
  77. {
  78. IMX6SRCState *s = IMX6_SRC(dev);
  79. DPRINTF("\n");
  80. memset(s->regs, 0, sizeof(s->regs));
  81. /* Set reset values */
  82. s->regs[SRC_SCR] = 0x521;
  83. s->regs[SRC_SRSR] = 0x1;
  84. s->regs[SRC_SIMR] = 0x1F;
  85. }
  86. static uint64_t imx6_src_read(void *opaque, hwaddr offset, unsigned size)
  87. {
  88. uint32_t value = 0;
  89. IMX6SRCState *s = (IMX6SRCState *)opaque;
  90. uint32_t index = offset >> 2;
  91. if (index < SRC_MAX) {
  92. value = s->regs[index];
  93. } else {
  94. qemu_log_mask(LOG_GUEST_ERROR, "[%s]%s: Bad register at offset 0x%"
  95. HWADDR_PRIx "\n", TYPE_IMX6_SRC, __func__, offset);
  96. }
  97. DPRINTF("reg[%s] => 0x%" PRIx32 "\n", imx6_src_reg_name(index), value);
  98. return value;
  99. }
  100. static void imx6_src_write(void *opaque, hwaddr offset, uint64_t value,
  101. unsigned size)
  102. {
  103. IMX6SRCState *s = (IMX6SRCState *)opaque;
  104. uint32_t index = offset >> 2;
  105. unsigned long change_mask;
  106. unsigned long current_value = value;
  107. if (index >= SRC_MAX) {
  108. qemu_log_mask(LOG_GUEST_ERROR, "[%s]%s: Bad register at offset 0x%"
  109. HWADDR_PRIx "\n", TYPE_IMX6_SRC, __func__, offset);
  110. return;
  111. }
  112. DPRINTF("reg[%s] <= 0x%" PRIx32 "\n", imx6_src_reg_name(index),
  113. (uint32_t)current_value);
  114. change_mask = s->regs[index] ^ (uint32_t)current_value;
  115. switch (index) {
  116. case SRC_SCR:
  117. /*
  118. * On real hardware when the system reset controller starts a
  119. * secondary CPU it runs through some boot ROM code which reads
  120. * the SRC_GPRX registers controlling the start address and branches
  121. * to it.
  122. * Here we are taking a short cut and branching directly to the
  123. * requested address (we don't want to run the boot ROM code inside
  124. * QEMU)
  125. */
  126. if (EXTRACT(change_mask, CORE3_ENABLE)) {
  127. if (EXTRACT(current_value, CORE3_ENABLE)) {
  128. /* CORE 3 is brought up */
  129. arm_set_cpu_on(3, s->regs[SRC_GPR7], s->regs[SRC_GPR8],
  130. 3, false);
  131. } else {
  132. /* CORE 3 is shut down */
  133. arm_set_cpu_off(3);
  134. }
  135. /* We clear the reset bits as the processor changed state */
  136. clear_bit(CORE3_RST_SHIFT, &current_value);
  137. clear_bit(CORE3_RST_SHIFT, &change_mask);
  138. }
  139. if (EXTRACT(change_mask, CORE2_ENABLE)) {
  140. if (EXTRACT(current_value, CORE2_ENABLE)) {
  141. /* CORE 2 is brought up */
  142. arm_set_cpu_on(2, s->regs[SRC_GPR5], s->regs[SRC_GPR6],
  143. 3, false);
  144. } else {
  145. /* CORE 3 is shut down */
  146. arm_set_cpu_off(2);
  147. }
  148. /* We clear the reset bits as the processor changed state */
  149. clear_bit(CORE2_RST_SHIFT, &current_value);
  150. clear_bit(CORE2_RST_SHIFT, &change_mask);
  151. }
  152. if (EXTRACT(change_mask, CORE1_ENABLE)) {
  153. if (EXTRACT(current_value, CORE1_ENABLE)) {
  154. /* CORE 1 is brought up */
  155. arm_set_cpu_on(1, s->regs[SRC_GPR3], s->regs[SRC_GPR4],
  156. 3, false);
  157. } else {
  158. /* CORE 3 is shut down */
  159. arm_set_cpu_off(1);
  160. }
  161. /* We clear the reset bits as the processor changed state */
  162. clear_bit(CORE1_RST_SHIFT, &current_value);
  163. clear_bit(CORE1_RST_SHIFT, &change_mask);
  164. }
  165. if (EXTRACT(change_mask, CORE0_RST)) {
  166. arm_reset_cpu(0);
  167. clear_bit(CORE0_RST_SHIFT, &current_value);
  168. }
  169. if (EXTRACT(change_mask, CORE1_RST)) {
  170. arm_reset_cpu(1);
  171. clear_bit(CORE1_RST_SHIFT, &current_value);
  172. }
  173. if (EXTRACT(change_mask, CORE2_RST)) {
  174. arm_reset_cpu(2);
  175. clear_bit(CORE2_RST_SHIFT, &current_value);
  176. }
  177. if (EXTRACT(change_mask, CORE3_RST)) {
  178. arm_reset_cpu(3);
  179. clear_bit(CORE3_RST_SHIFT, &current_value);
  180. }
  181. if (EXTRACT(change_mask, SW_IPU2_RST)) {
  182. /* We pretend the IPU2 is reset */
  183. clear_bit(SW_IPU2_RST_SHIFT, &current_value);
  184. }
  185. if (EXTRACT(change_mask, SW_IPU1_RST)) {
  186. /* We pretend the IPU1 is reset */
  187. clear_bit(SW_IPU1_RST_SHIFT, &current_value);
  188. }
  189. s->regs[index] = current_value;
  190. break;
  191. default:
  192. s->regs[index] = current_value;
  193. break;
  194. }
  195. }
  196. static const struct MemoryRegionOps imx6_src_ops = {
  197. .read = imx6_src_read,
  198. .write = imx6_src_write,
  199. .endianness = DEVICE_NATIVE_ENDIAN,
  200. .valid = {
  201. /*
  202. * Our device would not work correctly if the guest was doing
  203. * unaligned access. This might not be a limitation on the real
  204. * device but in practice there is no reason for a guest to access
  205. * this device unaligned.
  206. */
  207. .min_access_size = 4,
  208. .max_access_size = 4,
  209. .unaligned = false,
  210. },
  211. };
  212. static void imx6_src_realize(DeviceState *dev, Error **errp)
  213. {
  214. IMX6SRCState *s = IMX6_SRC(dev);
  215. memory_region_init_io(&s->iomem, OBJECT(dev), &imx6_src_ops, s,
  216. TYPE_IMX6_SRC, 0x1000);
  217. sysbus_init_mmio(SYS_BUS_DEVICE(dev), &s->iomem);
  218. }
  219. static void imx6_src_class_init(ObjectClass *klass, void *data)
  220. {
  221. DeviceClass *dc = DEVICE_CLASS(klass);
  222. dc->realize = imx6_src_realize;
  223. dc->reset = imx6_src_reset;
  224. dc->vmsd = &vmstate_imx6_src;
  225. dc->desc = "i.MX6 System Reset Controller";
  226. }
  227. static const TypeInfo imx6_src_info = {
  228. .name = TYPE_IMX6_SRC,
  229. .parent = TYPE_SYS_BUS_DEVICE,
  230. .instance_size = sizeof(IMX6SRCState),
  231. .class_init = imx6_src_class_init,
  232. };
  233. static void imx6_src_register_types(void)
  234. {
  235. type_register_static(&imx6_src_info);
  236. }
  237. type_init(imx6_src_register_types)