bcm2835_ic.c 6.8 KB

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