bcm2835_ic.c 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243
  1. /*
  2. * Raspberry Pi emulation (c) 2012 Gregory Estrade
  3. * Refactoring for Pi2 Copyright (c) 2015, Microsoft. Written by Andrew Baumann.
  4. * Heavily based on pl190.c, copyright terms below:
  5. *
  6. * Arm PrimeCell PL190 Vector Interrupt Controller
  7. *
  8. * Copyright (c) 2006 CodeSourcery.
  9. * Written by Paul Brook
  10. *
  11. * This work is licensed under the terms of the GNU GPL, version 2 or later.
  12. * See the COPYING file in the top-level directory.
  13. */
  14. #include "qemu/osdep.h"
  15. #include "hw/intc/bcm2835_ic.h"
  16. #include "hw/irq.h"
  17. #include "migration/vmstate.h"
  18. #include "qemu/log.h"
  19. #include "qemu/module.h"
  20. #include "trace.h"
  21. #define GPU_IRQS 64
  22. #define ARM_IRQS 8
  23. #define IRQ_PENDING_BASIC 0x00 /* IRQ basic pending */
  24. #define IRQ_PENDING_1 0x04 /* IRQ pending 1 */
  25. #define IRQ_PENDING_2 0x08 /* IRQ pending 2 */
  26. #define FIQ_CONTROL 0x0C /* FIQ register */
  27. #define IRQ_ENABLE_1 0x10 /* Interrupt enable register 1 */
  28. #define IRQ_ENABLE_2 0x14 /* Interrupt enable register 2 */
  29. #define IRQ_ENABLE_BASIC 0x18 /* Base interrupt enable register */
  30. #define IRQ_DISABLE_1 0x1C /* Interrupt disable register 1 */
  31. #define IRQ_DISABLE_2 0x20 /* Interrupt disable register 2 */
  32. #define IRQ_DISABLE_BASIC 0x24 /* Base interrupt disable register */
  33. /* Update interrupts. */
  34. static void bcm2835_ic_update(BCM2835ICState *s)
  35. {
  36. bool set = false;
  37. if (s->fiq_enable) {
  38. if (s->fiq_select >= GPU_IRQS) {
  39. /* ARM IRQ */
  40. set = extract32(s->arm_irq_level, s->fiq_select - GPU_IRQS, 1);
  41. } else {
  42. set = extract64(s->gpu_irq_level, s->fiq_select, 1);
  43. }
  44. }
  45. qemu_set_irq(s->fiq, set);
  46. set = (s->gpu_irq_level & s->gpu_irq_enable)
  47. || (s->arm_irq_level & s->arm_irq_enable);
  48. qemu_set_irq(s->irq, set);
  49. }
  50. static void bcm2835_ic_set_gpu_irq(void *opaque, int irq, int level)
  51. {
  52. BCM2835ICState *s = opaque;
  53. assert(irq >= 0 && irq < 64);
  54. trace_bcm2835_ic_set_gpu_irq(irq, level);
  55. s->gpu_irq_level = deposit64(s->gpu_irq_level, irq, 1, level != 0);
  56. bcm2835_ic_update(s);
  57. }
  58. static void bcm2835_ic_set_arm_irq(void *opaque, int irq, int level)
  59. {
  60. BCM2835ICState *s = opaque;
  61. assert(irq >= 0 && irq < 8);
  62. trace_bcm2835_ic_set_cpu_irq(irq, level);
  63. s->arm_irq_level = deposit32(s->arm_irq_level, irq, 1, level != 0);
  64. bcm2835_ic_update(s);
  65. }
  66. static const int irq_dups[] = { 7, 9, 10, 18, 19, 53, 54, 55, 56, 57, 62 };
  67. static uint64_t bcm2835_ic_read(void *opaque, hwaddr offset, unsigned size)
  68. {
  69. BCM2835ICState *s = opaque;
  70. uint32_t res = 0;
  71. uint64_t gpu_pending = s->gpu_irq_level & s->gpu_irq_enable;
  72. int i;
  73. switch (offset) {
  74. case IRQ_PENDING_BASIC:
  75. /* bits 0-7: ARM irqs */
  76. res = s->arm_irq_level & s->arm_irq_enable;
  77. /* bits 8 & 9: pending registers 1 & 2 */
  78. res |= (((uint32_t)gpu_pending) != 0) << 8;
  79. res |= ((gpu_pending >> 32) != 0) << 9;
  80. /* bits 10-20: selected GPU IRQs */
  81. for (i = 0; i < ARRAY_SIZE(irq_dups); i++) {
  82. res |= extract64(gpu_pending, irq_dups[i], 1) << (i + 10);
  83. }
  84. break;
  85. case IRQ_PENDING_1:
  86. res = gpu_pending;
  87. break;
  88. case IRQ_PENDING_2:
  89. res = gpu_pending >> 32;
  90. break;
  91. case FIQ_CONTROL:
  92. res = (s->fiq_enable << 7) | s->fiq_select;
  93. break;
  94. case IRQ_ENABLE_1:
  95. res = s->gpu_irq_enable;
  96. break;
  97. case IRQ_ENABLE_2:
  98. res = s->gpu_irq_enable >> 32;
  99. break;
  100. case IRQ_ENABLE_BASIC:
  101. res = s->arm_irq_enable;
  102. break;
  103. case IRQ_DISABLE_1:
  104. res = ~s->gpu_irq_enable;
  105. break;
  106. case IRQ_DISABLE_2:
  107. res = ~s->gpu_irq_enable >> 32;
  108. break;
  109. case IRQ_DISABLE_BASIC:
  110. res = ~s->arm_irq_enable;
  111. break;
  112. default:
  113. qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset %"HWADDR_PRIx"\n",
  114. __func__, offset);
  115. return 0;
  116. }
  117. return res;
  118. }
  119. static void bcm2835_ic_write(void *opaque, hwaddr offset, uint64_t val,
  120. unsigned size)
  121. {
  122. BCM2835ICState *s = opaque;
  123. switch (offset) {
  124. case FIQ_CONTROL:
  125. s->fiq_select = extract32(val, 0, 7);
  126. s->fiq_enable = extract32(val, 7, 1);
  127. break;
  128. case IRQ_ENABLE_1:
  129. s->gpu_irq_enable |= val;
  130. break;
  131. case IRQ_ENABLE_2:
  132. s->gpu_irq_enable |= val << 32;
  133. break;
  134. case IRQ_ENABLE_BASIC:
  135. s->arm_irq_enable |= val & 0xff;
  136. break;
  137. case IRQ_DISABLE_1:
  138. s->gpu_irq_enable &= ~val;
  139. break;
  140. case IRQ_DISABLE_2:
  141. s->gpu_irq_enable &= ~(val << 32);
  142. break;
  143. case IRQ_DISABLE_BASIC:
  144. s->arm_irq_enable &= ~val & 0xff;
  145. break;
  146. default:
  147. qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset %"HWADDR_PRIx"\n",
  148. __func__, offset);
  149. return;
  150. }
  151. bcm2835_ic_update(s);
  152. }
  153. static const MemoryRegionOps bcm2835_ic_ops = {
  154. .read = bcm2835_ic_read,
  155. .write = bcm2835_ic_write,
  156. .endianness = DEVICE_NATIVE_ENDIAN,
  157. .valid.min_access_size = 4,
  158. .valid.max_access_size = 4,
  159. };
  160. static void bcm2835_ic_reset(DeviceState *d)
  161. {
  162. BCM2835ICState *s = BCM2835_IC(d);
  163. s->gpu_irq_enable = 0;
  164. s->arm_irq_enable = 0;
  165. s->fiq_enable = false;
  166. s->fiq_select = 0;
  167. }
  168. static void bcm2835_ic_init(Object *obj)
  169. {
  170. BCM2835ICState *s = BCM2835_IC(obj);
  171. memory_region_init_io(&s->iomem, obj, &bcm2835_ic_ops, s, TYPE_BCM2835_IC,
  172. 0x200);
  173. sysbus_init_mmio(SYS_BUS_DEVICE(s), &s->iomem);
  174. qdev_init_gpio_in_named(DEVICE(s), bcm2835_ic_set_gpu_irq,
  175. BCM2835_IC_GPU_IRQ, GPU_IRQS);
  176. qdev_init_gpio_in_named(DEVICE(s), bcm2835_ic_set_arm_irq,
  177. BCM2835_IC_ARM_IRQ, ARM_IRQS);
  178. sysbus_init_irq(SYS_BUS_DEVICE(s), &s->irq);
  179. sysbus_init_irq(SYS_BUS_DEVICE(s), &s->fiq);
  180. }
  181. static const VMStateDescription vmstate_bcm2835_ic = {
  182. .name = TYPE_BCM2835_IC,
  183. .version_id = 1,
  184. .minimum_version_id = 1,
  185. .fields = (const VMStateField[]) {
  186. VMSTATE_UINT64(gpu_irq_level, BCM2835ICState),
  187. VMSTATE_UINT64(gpu_irq_enable, BCM2835ICState),
  188. VMSTATE_UINT8(arm_irq_level, BCM2835ICState),
  189. VMSTATE_UINT8(arm_irq_enable, BCM2835ICState),
  190. VMSTATE_BOOL(fiq_enable, BCM2835ICState),
  191. VMSTATE_UINT8(fiq_select, BCM2835ICState),
  192. VMSTATE_END_OF_LIST()
  193. }
  194. };
  195. static void bcm2835_ic_class_init(ObjectClass *klass, void *data)
  196. {
  197. DeviceClass *dc = DEVICE_CLASS(klass);
  198. device_class_set_legacy_reset(dc, bcm2835_ic_reset);
  199. dc->vmsd = &vmstate_bcm2835_ic;
  200. }
  201. static const TypeInfo bcm2835_ic_info = {
  202. .name = TYPE_BCM2835_IC,
  203. .parent = TYPE_SYS_BUS_DEVICE,
  204. .instance_size = sizeof(BCM2835ICState),
  205. .class_init = bcm2835_ic_class_init,
  206. .instance_init = bcm2835_ic_init,
  207. };
  208. static void bcm2835_ic_register_types(void)
  209. {
  210. type_register_static(&bcm2835_ic_info);
  211. }
  212. type_init(bcm2835_ic_register_types)