aspeed_intc.c 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361
  1. /*
  2. * ASPEED INTC Controller
  3. *
  4. * Copyright (C) 2024 ASPEED Technology Inc.
  5. *
  6. * SPDX-License-Identifier: GPL-2.0-or-later
  7. */
  8. #include "qemu/osdep.h"
  9. #include "hw/intc/aspeed_intc.h"
  10. #include "hw/irq.h"
  11. #include "qemu/log.h"
  12. #include "trace.h"
  13. #include "hw/registerfields.h"
  14. #include "qapi/error.h"
  15. /* INTC Registers */
  16. REG32(GICINT128_EN, 0x1000)
  17. REG32(GICINT128_STATUS, 0x1004)
  18. REG32(GICINT129_EN, 0x1100)
  19. REG32(GICINT129_STATUS, 0x1104)
  20. REG32(GICINT130_EN, 0x1200)
  21. REG32(GICINT130_STATUS, 0x1204)
  22. REG32(GICINT131_EN, 0x1300)
  23. REG32(GICINT131_STATUS, 0x1304)
  24. REG32(GICINT132_EN, 0x1400)
  25. REG32(GICINT132_STATUS, 0x1404)
  26. REG32(GICINT133_EN, 0x1500)
  27. REG32(GICINT133_STATUS, 0x1504)
  28. REG32(GICINT134_EN, 0x1600)
  29. REG32(GICINT134_STATUS, 0x1604)
  30. REG32(GICINT135_EN, 0x1700)
  31. REG32(GICINT135_STATUS, 0x1704)
  32. REG32(GICINT136_EN, 0x1800)
  33. REG32(GICINT136_STATUS, 0x1804)
  34. #define GICINT_STATUS_BASE R_GICINT128_STATUS
  35. static void aspeed_intc_update(AspeedINTCState *s, int irq, int level)
  36. {
  37. AspeedINTCClass *aic = ASPEED_INTC_GET_CLASS(s);
  38. if (irq >= aic->num_ints) {
  39. qemu_log_mask(LOG_GUEST_ERROR, "%s: Invalid interrupt number: %d\n",
  40. __func__, irq);
  41. return;
  42. }
  43. trace_aspeed_intc_update_irq(irq, level);
  44. qemu_set_irq(s->output_pins[irq], level);
  45. }
  46. /*
  47. * The address of GICINT128 to GICINT136 are from 0x1000 to 0x1804.
  48. * Utilize "address & 0x0f00" to get the irq and irq output pin index
  49. * The value of irq should be 0 to num_ints.
  50. * The irq 0 indicates GICINT128, irq 1 indicates GICINT129 and so on.
  51. */
  52. static void aspeed_intc_set_irq(void *opaque, int irq, int level)
  53. {
  54. AspeedINTCState *s = (AspeedINTCState *)opaque;
  55. AspeedINTCClass *aic = ASPEED_INTC_GET_CLASS(s);
  56. uint32_t status_addr = GICINT_STATUS_BASE + ((0x100 * irq) >> 2);
  57. uint32_t select = 0;
  58. uint32_t enable;
  59. int i;
  60. if (irq >= aic->num_ints) {
  61. qemu_log_mask(LOG_GUEST_ERROR, "%s: Invalid interrupt number: %d\n",
  62. __func__, irq);
  63. return;
  64. }
  65. trace_aspeed_intc_set_irq(irq, level);
  66. enable = s->enable[irq];
  67. if (!level) {
  68. return;
  69. }
  70. for (i = 0; i < aic->num_lines; i++) {
  71. if (s->orgates[irq].levels[i]) {
  72. if (enable & BIT(i)) {
  73. select |= BIT(i);
  74. }
  75. }
  76. }
  77. if (!select) {
  78. return;
  79. }
  80. trace_aspeed_intc_select(select);
  81. if (s->mask[irq] || s->regs[status_addr]) {
  82. /*
  83. * a. mask is not 0 means in ISR mode
  84. * sources interrupt routine are executing.
  85. * b. status register value is not 0 means previous
  86. * source interrupt does not be executed, yet.
  87. *
  88. * save source interrupt to pending variable.
  89. */
  90. s->pending[irq] |= select;
  91. trace_aspeed_intc_pending_irq(irq, s->pending[irq]);
  92. } else {
  93. /*
  94. * notify firmware which source interrupt are coming
  95. * by setting status register
  96. */
  97. s->regs[status_addr] = select;
  98. trace_aspeed_intc_trigger_irq(irq, s->regs[status_addr]);
  99. aspeed_intc_update(s, irq, 1);
  100. }
  101. }
  102. static uint64_t aspeed_intc_read(void *opaque, hwaddr offset, unsigned int size)
  103. {
  104. AspeedINTCState *s = ASPEED_INTC(opaque);
  105. uint32_t addr = offset >> 2;
  106. uint32_t value = 0;
  107. if (addr >= ASPEED_INTC_NR_REGS) {
  108. qemu_log_mask(LOG_GUEST_ERROR,
  109. "%s: Out-of-bounds read at offset 0x%" HWADDR_PRIx "\n",
  110. __func__, offset);
  111. return 0;
  112. }
  113. value = s->regs[addr];
  114. trace_aspeed_intc_read(offset, size, value);
  115. return value;
  116. }
  117. static void aspeed_intc_write(void *opaque, hwaddr offset, uint64_t data,
  118. unsigned size)
  119. {
  120. AspeedINTCState *s = ASPEED_INTC(opaque);
  121. AspeedINTCClass *aic = ASPEED_INTC_GET_CLASS(s);
  122. uint32_t addr = offset >> 2;
  123. uint32_t old_enable;
  124. uint32_t change;
  125. uint32_t irq;
  126. if (addr >= ASPEED_INTC_NR_REGS) {
  127. qemu_log_mask(LOG_GUEST_ERROR,
  128. "%s: Out-of-bounds write at offset 0x%" HWADDR_PRIx "\n",
  129. __func__, offset);
  130. return;
  131. }
  132. trace_aspeed_intc_write(offset, size, data);
  133. switch (addr) {
  134. case R_GICINT128_EN:
  135. case R_GICINT129_EN:
  136. case R_GICINT130_EN:
  137. case R_GICINT131_EN:
  138. case R_GICINT132_EN:
  139. case R_GICINT133_EN:
  140. case R_GICINT134_EN:
  141. case R_GICINT135_EN:
  142. case R_GICINT136_EN:
  143. irq = (offset & 0x0f00) >> 8;
  144. if (irq >= aic->num_ints) {
  145. qemu_log_mask(LOG_GUEST_ERROR, "%s: Invalid interrupt number: %d\n",
  146. __func__, irq);
  147. return;
  148. }
  149. /*
  150. * These registers are used for enable sources interrupt and
  151. * mask and unmask source interrupt while executing source ISR.
  152. */
  153. /* disable all source interrupt */
  154. if (!data && !s->enable[irq]) {
  155. s->regs[addr] = data;
  156. return;
  157. }
  158. old_enable = s->enable[irq];
  159. s->enable[irq] |= data;
  160. /* enable new source interrupt */
  161. if (old_enable != s->enable[irq]) {
  162. trace_aspeed_intc_enable(s->enable[irq]);
  163. s->regs[addr] = data;
  164. return;
  165. }
  166. /* mask and unmask source interrupt */
  167. change = s->regs[addr] ^ data;
  168. if (change & data) {
  169. s->mask[irq] &= ~change;
  170. trace_aspeed_intc_unmask(change, s->mask[irq]);
  171. } else {
  172. s->mask[irq] |= change;
  173. trace_aspeed_intc_mask(change, s->mask[irq]);
  174. }
  175. s->regs[addr] = data;
  176. break;
  177. case R_GICINT128_STATUS:
  178. case R_GICINT129_STATUS:
  179. case R_GICINT130_STATUS:
  180. case R_GICINT131_STATUS:
  181. case R_GICINT132_STATUS:
  182. case R_GICINT133_STATUS:
  183. case R_GICINT134_STATUS:
  184. case R_GICINT135_STATUS:
  185. case R_GICINT136_STATUS:
  186. irq = (offset & 0x0f00) >> 8;
  187. if (irq >= aic->num_ints) {
  188. qemu_log_mask(LOG_GUEST_ERROR, "%s: Invalid interrupt number: %d\n",
  189. __func__, irq);
  190. return;
  191. }
  192. /* clear status */
  193. s->regs[addr] &= ~data;
  194. /*
  195. * These status registers are used for notify sources ISR are executed.
  196. * If one source ISR is executed, it will clear one bit.
  197. * If it clear all bits, it means to initialize this register status
  198. * rather than sources ISR are executed.
  199. */
  200. if (data == 0xffffffff) {
  201. return;
  202. }
  203. /* All source ISR execution are done */
  204. if (!s->regs[addr]) {
  205. trace_aspeed_intc_all_isr_done(irq);
  206. if (s->pending[irq]) {
  207. /*
  208. * handle pending source interrupt
  209. * notify firmware which source interrupt are pending
  210. * by setting status register
  211. */
  212. s->regs[addr] = s->pending[irq];
  213. s->pending[irq] = 0;
  214. trace_aspeed_intc_trigger_irq(irq, s->regs[addr]);
  215. aspeed_intc_update(s, irq, 1);
  216. } else {
  217. /* clear irq */
  218. trace_aspeed_intc_clear_irq(irq, 0);
  219. aspeed_intc_update(s, irq, 0);
  220. }
  221. }
  222. break;
  223. default:
  224. s->regs[addr] = data;
  225. break;
  226. }
  227. return;
  228. }
  229. static const MemoryRegionOps aspeed_intc_ops = {
  230. .read = aspeed_intc_read,
  231. .write = aspeed_intc_write,
  232. .endianness = DEVICE_LITTLE_ENDIAN,
  233. .valid = {
  234. .min_access_size = 4,
  235. .max_access_size = 4,
  236. }
  237. };
  238. static void aspeed_intc_instance_init(Object *obj)
  239. {
  240. AspeedINTCState *s = ASPEED_INTC(obj);
  241. AspeedINTCClass *aic = ASPEED_INTC_GET_CLASS(s);
  242. int i;
  243. assert(aic->num_ints <= ASPEED_INTC_NR_INTS);
  244. for (i = 0; i < aic->num_ints; i++) {
  245. object_initialize_child(obj, "intc-orgates[*]", &s->orgates[i],
  246. TYPE_OR_IRQ);
  247. object_property_set_int(OBJECT(&s->orgates[i]), "num-lines",
  248. aic->num_lines, &error_abort);
  249. }
  250. }
  251. static void aspeed_intc_reset(DeviceState *dev)
  252. {
  253. AspeedINTCState *s = ASPEED_INTC(dev);
  254. memset(s->regs, 0, sizeof(s->regs));
  255. memset(s->enable, 0, sizeof(s->enable));
  256. memset(s->mask, 0, sizeof(s->mask));
  257. memset(s->pending, 0, sizeof(s->pending));
  258. }
  259. static void aspeed_intc_realize(DeviceState *dev, Error **errp)
  260. {
  261. SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
  262. AspeedINTCState *s = ASPEED_INTC(dev);
  263. AspeedINTCClass *aic = ASPEED_INTC_GET_CLASS(s);
  264. int i;
  265. memory_region_init_io(&s->iomem, OBJECT(s), &aspeed_intc_ops, s,
  266. TYPE_ASPEED_INTC ".regs", ASPEED_INTC_NR_REGS << 2);
  267. sysbus_init_mmio(sbd, &s->iomem);
  268. qdev_init_gpio_in(dev, aspeed_intc_set_irq, aic->num_ints);
  269. for (i = 0; i < aic->num_ints; i++) {
  270. if (!qdev_realize(DEVICE(&s->orgates[i]), NULL, errp)) {
  271. return;
  272. }
  273. sysbus_init_irq(sbd, &s->output_pins[i]);
  274. }
  275. }
  276. static void aspeed_intc_class_init(ObjectClass *klass, void *data)
  277. {
  278. DeviceClass *dc = DEVICE_CLASS(klass);
  279. dc->desc = "ASPEED INTC Controller";
  280. dc->realize = aspeed_intc_realize;
  281. device_class_set_legacy_reset(dc, aspeed_intc_reset);
  282. dc->vmsd = NULL;
  283. }
  284. static const TypeInfo aspeed_intc_info = {
  285. .name = TYPE_ASPEED_INTC,
  286. .parent = TYPE_SYS_BUS_DEVICE,
  287. .instance_init = aspeed_intc_instance_init,
  288. .instance_size = sizeof(AspeedINTCState),
  289. .class_init = aspeed_intc_class_init,
  290. .class_size = sizeof(AspeedINTCClass),
  291. .abstract = true,
  292. };
  293. static void aspeed_2700_intc_class_init(ObjectClass *klass, void *data)
  294. {
  295. DeviceClass *dc = DEVICE_CLASS(klass);
  296. AspeedINTCClass *aic = ASPEED_INTC_CLASS(klass);
  297. dc->desc = "ASPEED 2700 INTC Controller";
  298. aic->num_lines = 32;
  299. aic->num_ints = 9;
  300. }
  301. static const TypeInfo aspeed_2700_intc_info = {
  302. .name = TYPE_ASPEED_2700_INTC,
  303. .parent = TYPE_ASPEED_INTC,
  304. .class_init = aspeed_2700_intc_class_init,
  305. };
  306. static void aspeed_intc_register_types(void)
  307. {
  308. type_register_static(&aspeed_intc_info);
  309. type_register_static(&aspeed_2700_intc_info);
  310. }
  311. type_init(aspeed_intc_register_types);