xilinx_intc.c 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238
  1. /*
  2. * QEMU Xilinx OPB Interrupt Controller.
  3. *
  4. * Copyright (c) 2009 Edgar E. Iglesias.
  5. *
  6. * https://docs.amd.com/v/u/en-US/xps_intc
  7. * DS572: LogiCORE IP XPS Interrupt Controller (v2.01a)
  8. *
  9. * Permission is hereby granted, free of charge, to any person obtaining a copy
  10. * of this software and associated documentation files (the "Software"), to deal
  11. * in the Software without restriction, including without limitation the rights
  12. * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  13. * copies of the Software, and to permit persons to whom the Software is
  14. * furnished to do so, subject to the following conditions:
  15. *
  16. * The above copyright notice and this permission notice shall be included in
  17. * all copies or substantial portions of the Software.
  18. *
  19. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  20. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  21. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
  22. * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  23. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  24. * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  25. * THE SOFTWARE.
  26. */
  27. #include "qemu/osdep.h"
  28. #include "qapi/error.h"
  29. #include "hw/sysbus.h"
  30. #include "qemu/module.h"
  31. #include "hw/irq.h"
  32. #include "hw/qdev-properties.h"
  33. #include "hw/qdev-properties-system.h"
  34. #include "qom/object.h"
  35. #define D(x)
  36. #define R_ISR 0
  37. #define R_IPR 1
  38. #define R_IER 2
  39. #define R_IAR 3
  40. #define R_SIE 4
  41. #define R_CIE 5
  42. #define R_IVR 6
  43. #define R_MER 7
  44. #define R_MAX 8
  45. #define TYPE_XILINX_INTC "xlnx.xps-intc"
  46. typedef struct XpsIntc XpsIntc;
  47. DECLARE_INSTANCE_CHECKER(XpsIntc, XILINX_INTC, TYPE_XILINX_INTC)
  48. struct XpsIntc
  49. {
  50. SysBusDevice parent_obj;
  51. EndianMode model_endianness;
  52. MemoryRegion mmio;
  53. qemu_irq parent_irq;
  54. /* Configuration reg chosen at synthesis-time. QEMU populates
  55. the bits at board-setup. */
  56. uint32_t c_kind_of_intr;
  57. /* Runtime control registers. */
  58. uint32_t regs[R_MAX];
  59. /* state of the interrupt input pins */
  60. uint32_t irq_pin_state;
  61. };
  62. static void update_irq(XpsIntc *p)
  63. {
  64. uint32_t i;
  65. /* level triggered interrupt */
  66. if (p->regs[R_MER] & 2) {
  67. p->regs[R_ISR] |= p->irq_pin_state & ~p->c_kind_of_intr;
  68. }
  69. /* Update the pending register. */
  70. p->regs[R_IPR] = p->regs[R_ISR] & p->regs[R_IER];
  71. /* Update the vector register. */
  72. for (i = 0; i < 32; i++) {
  73. if (p->regs[R_IPR] & (1U << i)) {
  74. break;
  75. }
  76. }
  77. if (i == 32)
  78. i = ~0;
  79. p->regs[R_IVR] = i;
  80. qemu_set_irq(p->parent_irq, (p->regs[R_MER] & 1) && p->regs[R_IPR]);
  81. }
  82. static uint64_t pic_read(void *opaque, hwaddr addr, unsigned int size)
  83. {
  84. XpsIntc *p = opaque;
  85. uint32_t r = 0;
  86. addr >>= 2;
  87. switch (addr)
  88. {
  89. default:
  90. if (addr < ARRAY_SIZE(p->regs))
  91. r = p->regs[addr];
  92. break;
  93. }
  94. D(printf("%s %x=%x\n", __func__, addr * 4, r));
  95. return r;
  96. }
  97. static void pic_write(void *opaque, hwaddr addr,
  98. uint64_t val64, unsigned int size)
  99. {
  100. XpsIntc *p = opaque;
  101. uint32_t value = val64;
  102. addr >>= 2;
  103. D(qemu_log("%s addr=%x val=%x\n", __func__, addr * 4, value));
  104. switch (addr)
  105. {
  106. case R_IAR:
  107. p->regs[R_ISR] &= ~value; /* ACK. */
  108. break;
  109. case R_SIE:
  110. p->regs[R_IER] |= value; /* Atomic set ie. */
  111. break;
  112. case R_CIE:
  113. p->regs[R_IER] &= ~value; /* Atomic clear ie. */
  114. break;
  115. case R_MER:
  116. p->regs[R_MER] = value & 0x3;
  117. break;
  118. case R_ISR:
  119. if ((p->regs[R_MER] & 2)) {
  120. break;
  121. }
  122. /* fallthrough */
  123. default:
  124. if (addr < ARRAY_SIZE(p->regs))
  125. p->regs[addr] = value;
  126. break;
  127. }
  128. update_irq(p);
  129. }
  130. static const MemoryRegionOps pic_ops[2] = {
  131. [0 ... 1] = {
  132. .read = pic_read,
  133. .write = pic_write,
  134. .impl = {
  135. .min_access_size = 4,
  136. .max_access_size = 4,
  137. },
  138. .valid = {
  139. /*
  140. * All XPS INTC registers are accessed through the PLB interface.
  141. * The base address for these registers is provided by the
  142. * configuration parameter, C_BASEADDR. Each register is 32 bits
  143. * although some bits may be unused and is accessed on a 4-byte
  144. * boundary offset from the base address.
  145. */
  146. .min_access_size = 4,
  147. .max_access_size = 4,
  148. },
  149. },
  150. [0].endianness = DEVICE_LITTLE_ENDIAN,
  151. [1].endianness = DEVICE_BIG_ENDIAN,
  152. };
  153. static void irq_handler(void *opaque, int irq, int level)
  154. {
  155. XpsIntc *p = opaque;
  156. /* edge triggered interrupt */
  157. if (p->c_kind_of_intr & (1 << irq) && p->regs[R_MER] & 2) {
  158. p->regs[R_ISR] |= (level << irq);
  159. }
  160. p->irq_pin_state &= ~(1 << irq);
  161. p->irq_pin_state |= level << irq;
  162. update_irq(p);
  163. }
  164. static void xilinx_intc_init(Object *obj)
  165. {
  166. XpsIntc *p = XILINX_INTC(obj);
  167. qdev_init_gpio_in(DEVICE(obj), irq_handler, 32);
  168. sysbus_init_irq(SYS_BUS_DEVICE(obj), &p->parent_irq);
  169. sysbus_init_mmio(SYS_BUS_DEVICE(obj), &p->mmio);
  170. }
  171. static void xilinx_intc_realize(DeviceState *dev, Error **errp)
  172. {
  173. XpsIntc *p = XILINX_INTC(dev);
  174. if (p->model_endianness == ENDIAN_MODE_UNSPECIFIED) {
  175. error_setg(errp, TYPE_XILINX_INTC " property 'endianness'"
  176. " must be set to 'big' or 'little'");
  177. return;
  178. }
  179. memory_region_init_io(&p->mmio, OBJECT(dev),
  180. &pic_ops[p->model_endianness == ENDIAN_MODE_BIG],
  181. p, "xlnx.xps-intc",
  182. R_MAX * 4);
  183. }
  184. static const Property xilinx_intc_properties[] = {
  185. DEFINE_PROP_ENDIAN_NODEFAULT("endianness", XpsIntc, model_endianness),
  186. DEFINE_PROP_UINT32("kind-of-intr", XpsIntc, c_kind_of_intr, 0),
  187. };
  188. static void xilinx_intc_class_init(ObjectClass *klass, void *data)
  189. {
  190. DeviceClass *dc = DEVICE_CLASS(klass);
  191. dc->realize = xilinx_intc_realize;
  192. device_class_set_props(dc, xilinx_intc_properties);
  193. }
  194. static const TypeInfo xilinx_intc_info = {
  195. .name = TYPE_XILINX_INTC,
  196. .parent = TYPE_SYS_BUS_DEVICE,
  197. .instance_size = sizeof(XpsIntc),
  198. .instance_init = xilinx_intc_init,
  199. .class_init = xilinx_intc_class_init,
  200. };
  201. static void xilinx_intc_register_types(void)
  202. {
  203. type_register_static(&xilinx_intc_info);
  204. }
  205. type_init(xilinx_intc_register_types)