pic-gicv2m.c 9.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378
  1. /*
  2. * Copyright (c) 2006-2022, RT-Thread Development Team
  3. *
  4. * SPDX-License-Identifier: Apache-2.0
  5. *
  6. * Change Logs:
  7. * Date Author Notes
  8. * 2022-11-07 GuEe-GUI first version
  9. */
  10. #include <rthw.h>
  11. #include <rtthread.h>
  12. #include <rtdevice.h>
  13. #define DBG_TAG "pic.gicv2m"
  14. #define DBG_LVL DBG_INFO
  15. #include <rtdbg.h>
  16. #include <mmu.h>
  17. #include <cpuport.h>
  18. #include "pic-gic-common.h"
  19. /*
  20. * MSI_TYPER:
  21. * [31:26] Reserved
  22. * [25:16] lowest SPI assigned to MSI
  23. * [15:10] Reserved
  24. * [9:0] Numer of SPIs assigned to MSI
  25. */
  26. #define V2M_MSI_TYPER 0x008
  27. #define V2M_MSI_TYPER_BASE_SHIFT 16
  28. #define V2M_MSI_TYPER_BASE_MASK 0x3ff
  29. #define V2M_MSI_TYPER_NUM_MASK 0x3ff
  30. #define V2M_MSI_SETSPI_NS 0x040
  31. #define V2M_MIN_SPI 32
  32. #define V2M_MAX_SPI 1019
  33. #define V2M_MSI_IIDR 0xfcc
  34. #define V2M_MSI_TYPER_BASE_SPI(x) (((x) >> V2M_MSI_TYPER_BASE_SHIFT) & V2M_MSI_TYPER_BASE_MASK)
  35. #define V2M_MSI_TYPER_NUM_SPI(x) ((x) & V2M_MSI_TYPER_NUM_MASK)
  36. /* APM X-Gene with GICv2m MSI_IIDR register value */
  37. #define XGENE_GICV2M_MSI_IIDR 0x06000170
  38. /* Broadcom NS2 GICv2m MSI_IIDR register value */
  39. #define BCM_NS2_GICV2M_MSI_IIDR 0x0000013f
  40. /* List of flags for specific v2m implementation */
  41. #define GICV2M_NEEDS_SPI_OFFSET 0x00000001
  42. #define GICV2M_GRAVITON_ADDRESS_ONLY 0x00000002
  43. struct gicv2m
  44. {
  45. struct rt_pic parent;
  46. void *base;
  47. void *base_phy;
  48. rt_uint32_t spi_start; /* The SPI number that MSIs start */
  49. rt_uint32_t spis_nr; /* The number of SPIs for MSIs */
  50. rt_uint32_t spi_offset; /* Offset to be subtracted from SPI number */
  51. rt_bitmap_t *vectors; /* MSI vector bitmap */
  52. rt_uint32_t flags; /* Flags for v2m's specific implementation */
  53. void *gic;
  54. struct rt_spinlock lock;
  55. };
  56. #define raw_to_gicv2m(raw) rt_container_of(raw, struct gicv2m, parent)
  57. static rt_ubase_t gicv2m_get_msi_addr(struct gicv2m *v2m, int hwirq)
  58. {
  59. rt_ubase_t addr;
  60. if (v2m->flags & GICV2M_GRAVITON_ADDRESS_ONLY)
  61. {
  62. addr = (rt_ubase_t)v2m->base_phy | ((hwirq - 32) << 3);
  63. }
  64. else
  65. {
  66. addr = (rt_ubase_t)v2m->base_phy + V2M_MSI_SETSPI_NS;
  67. }
  68. return addr;
  69. }
  70. static rt_bool_t is_msi_spi_valid(rt_uint32_t base, rt_uint32_t num)
  71. {
  72. if (base < V2M_MIN_SPI)
  73. {
  74. LOG_E("Invalid MSI base SPI (base: %u)", base);
  75. return RT_FALSE;
  76. }
  77. else if ((num == 0) || (base + num > V2M_MAX_SPI))
  78. {
  79. LOG_E("Number of SPIs (%u) exceed maximum (%u)", num, V2M_MAX_SPI - V2M_MIN_SPI + 1);
  80. return RT_FALSE;
  81. }
  82. return RT_TRUE;
  83. }
  84. static void gicv2m_irq_mask(struct rt_pic_irq *pirq)
  85. {
  86. rt_pci_msi_mask_irq(pirq);
  87. rt_pic_irq_parent_mask(pirq);
  88. }
  89. static void gicv2m_irq_unmask(struct rt_pic_irq *pirq)
  90. {
  91. rt_pci_msi_unmask_irq(pirq);
  92. rt_pic_irq_parent_unmask(pirq);
  93. }
  94. static void gicv2m_compose_msi_msg(struct rt_pic_irq *pirq, struct rt_pci_msi_msg *msg)
  95. {
  96. rt_ubase_t addr;
  97. struct gicv2m *v2m = raw_to_gicv2m(pirq->pic);
  98. addr = gicv2m_get_msi_addr(v2m, pirq->hwirq);
  99. msg->address_hi = rt_upper_32_bits(addr);
  100. msg->address_lo = rt_lower_32_bits(addr);
  101. if (v2m->flags & GICV2M_GRAVITON_ADDRESS_ONLY)
  102. {
  103. msg->data = 0;
  104. }
  105. else
  106. {
  107. msg->data = pirq->hwirq;
  108. }
  109. if (v2m->flags & GICV2M_NEEDS_SPI_OFFSET)
  110. {
  111. msg->data -= v2m->spi_offset;
  112. }
  113. }
  114. static int gicv2m_irq_alloc_msi(struct rt_pic *pic, struct rt_pci_msi_desc *msi_desc)
  115. {
  116. rt_ubase_t level;
  117. int irq, parent_irq, hwirq, hwirq_index;
  118. struct rt_pic_irq *pirq;
  119. struct gicv2m *v2m = raw_to_gicv2m(pic);
  120. struct rt_pic *ppic = v2m->gic;
  121. level = rt_spin_lock_irqsave(&v2m->lock);
  122. hwirq_index = rt_bitmap_next_clear_bit(v2m->vectors, 0, v2m->spis_nr);
  123. if (hwirq_index >= v2m->spis_nr)
  124. {
  125. irq = -RT_EEMPTY;
  126. goto _out_lock;
  127. }
  128. hwirq = v2m->spi_start + v2m->spi_offset + hwirq_index;
  129. parent_irq = ppic->ops->irq_map(ppic, hwirq, RT_IRQ_MODE_EDGE_RISING);
  130. if (parent_irq < 0)
  131. {
  132. irq = parent_irq;
  133. goto _out_lock;
  134. }
  135. irq = rt_pic_config_irq(pic, hwirq_index, hwirq);
  136. if (irq < 0)
  137. {
  138. goto _out_lock;
  139. }
  140. pirq = rt_pic_find_irq(pic, hwirq_index);
  141. pirq->mode = RT_IRQ_MODE_EDGE_RISING;
  142. rt_pic_cascade(pirq, parent_irq);
  143. rt_bitmap_set_bit(v2m->vectors, hwirq_index);
  144. _out_lock:
  145. rt_spin_unlock_irqrestore(&v2m->lock, level);
  146. return irq;
  147. }
  148. static void gicv2m_irq_free_msi(struct rt_pic *pic, int irq)
  149. {
  150. rt_ubase_t level;
  151. struct rt_pic_irq *pirq;
  152. struct gicv2m *v2m = raw_to_gicv2m(pic);
  153. pirq = rt_pic_find_pirq(pic, irq);
  154. if (!pirq)
  155. {
  156. return;
  157. }
  158. rt_pic_uncascade(pirq);
  159. level = rt_spin_lock_irqsave(&v2m->lock);
  160. rt_bitmap_clear_bit(v2m->vectors, pirq->hwirq - (v2m->spi_start + v2m->spi_offset));
  161. rt_spin_unlock_irqrestore(&v2m->lock, level);
  162. }
  163. static rt_err_t gicv2m_irq_set_state(struct rt_pic *pic, int hwirq, int type, rt_bool_t state)
  164. {
  165. struct gicv2m *v2m = raw_to_gicv2m(pic);
  166. struct rt_pic *ppic = v2m->gic;
  167. return ppic->ops->irq_set_state(ppic, hwirq, type, state);
  168. }
  169. static rt_err_t gicv2m_irq_get_state(struct rt_pic *pic, int hwirq, int type, rt_bool_t *out_state)
  170. {
  171. struct gicv2m *v2m = raw_to_gicv2m(pic);
  172. struct rt_pic *ppic = v2m->gic;
  173. return ppic->ops->irq_get_state(ppic, hwirq, type, out_state);
  174. }
  175. const static struct rt_pic_ops gicv2m_ops =
  176. {
  177. .name = "GICv2m",
  178. .irq_ack = rt_pic_irq_parent_ack,
  179. .irq_mask = gicv2m_irq_mask,
  180. .irq_unmask = gicv2m_irq_unmask,
  181. .irq_eoi = rt_pic_irq_parent_eoi,
  182. .irq_set_priority = rt_pic_irq_parent_set_priority,
  183. .irq_set_affinity = rt_pic_irq_parent_set_affinity,
  184. .irq_compose_msi_msg = gicv2m_compose_msi_msg,
  185. .irq_alloc_msi = gicv2m_irq_alloc_msi,
  186. .irq_free_msi = gicv2m_irq_free_msi,
  187. .irq_set_state = gicv2m_irq_set_state,
  188. .irq_get_state = gicv2m_irq_get_state,
  189. .flags = RT_PIC_F_IRQ_ROUTING,
  190. };
  191. static const struct rt_ofw_node_id gicv2m_ofw_match[] =
  192. {
  193. { .compatible = "arm,gic-v2m-frame" },
  194. { /* sentinel */ }
  195. };
  196. rt_err_t gicv2m_ofw_probe(struct rt_ofw_node *np, const struct rt_ofw_node_id *id)
  197. {
  198. rt_err_t err = RT_EOK;
  199. struct rt_ofw_node *v2m_np;
  200. rt_ofw_foreach_available_child_node(np, v2m_np)
  201. {
  202. struct gicv2m *v2m;
  203. rt_size_t bitmap_size;
  204. rt_uint32_t spi_start = 0, spis_nr = 0;
  205. if (!rt_ofw_node_match(v2m_np, gicv2m_ofw_match))
  206. {
  207. continue;
  208. }
  209. if (!rt_ofw_prop_read_bool(v2m_np, "msi-controller"))
  210. {
  211. continue;
  212. }
  213. if (!(v2m = rt_malloc(sizeof(*v2m))))
  214. {
  215. rt_ofw_node_put(v2m_np);
  216. err = -RT_ENOMEM;
  217. break;
  218. }
  219. v2m->base = rt_ofw_iomap(v2m_np, 0);
  220. if (!v2m->base)
  221. {
  222. LOG_E("%s: IO map failed", rt_ofw_node_full_name(v2m_np));
  223. continue;
  224. }
  225. v2m->base_phy = rt_kmem_v2p(v2m->base);
  226. v2m->flags = 0;
  227. if (!rt_ofw_prop_read_u32(v2m_np, "arm,msi-base-spi", &spi_start) &&
  228. !rt_ofw_prop_read_u32(v2m_np, "arm,msi-num-spis", &spis_nr))
  229. {
  230. LOG_I("DT overriding V2M MSI_TYPER (base:%u, num:%u)", spi_start, spis_nr);
  231. }
  232. if (spi_start && spis_nr)
  233. {
  234. v2m->spi_start = spi_start;
  235. v2m->spis_nr = spis_nr;
  236. }
  237. else
  238. {
  239. rt_uint32_t typer;
  240. /* Graviton should always have explicit spi_start/spis_nr */
  241. if (v2m->flags & GICV2M_GRAVITON_ADDRESS_ONLY)
  242. {
  243. goto _fail;
  244. }
  245. typer = HWREG32(v2m->base + V2M_MSI_TYPER);
  246. v2m->spi_start = V2M_MSI_TYPER_BASE_SPI(typer);
  247. v2m->spis_nr = V2M_MSI_TYPER_NUM_SPI(typer);
  248. }
  249. if (!is_msi_spi_valid(v2m->spi_start, v2m->spis_nr))
  250. {
  251. goto _fail;
  252. }
  253. /*
  254. * APM X-Gene GICv2m implementation has an erratum where
  255. * the MSI data needs to be the offset from the spi_start
  256. * in order to trigger the correct MSI interrupt. This is
  257. * different from the standard GICv2m implementation where
  258. * the MSI data is the absolute value within the range from
  259. * spi_start to (spi_start + num_spis).
  260. *
  261. * Broadcom NS2 GICv2m implementation has an erratum where the MSI data
  262. * is 'spi_number - 32'
  263. *
  264. * Reading that register fails on the Graviton implementation
  265. */
  266. if (!(v2m->flags & GICV2M_GRAVITON_ADDRESS_ONLY))
  267. {
  268. switch (HWREG32(v2m->base + V2M_MSI_IIDR))
  269. {
  270. case XGENE_GICV2M_MSI_IIDR:
  271. v2m->flags |= GICV2M_NEEDS_SPI_OFFSET;
  272. v2m->spi_offset = v2m->spi_start;
  273. break;
  274. case BCM_NS2_GICV2M_MSI_IIDR:
  275. v2m->flags |= GICV2M_NEEDS_SPI_OFFSET;
  276. v2m->spi_offset = 32;
  277. break;
  278. }
  279. }
  280. bitmap_size = RT_BITMAP_LEN(v2m->spis_nr) * sizeof(rt_bitmap_t);
  281. if (!(v2m->vectors = rt_calloc(1, bitmap_size)))
  282. {
  283. err = -RT_ENOMEM;
  284. goto _fail;
  285. }
  286. rt_spin_lock_init(&v2m->lock);
  287. v2m->parent.priv_data = v2m;
  288. v2m->parent.ops = &gicv2m_ops;
  289. v2m->gic = rt_ofw_data(np);
  290. rt_pic_linear_irq(&v2m->parent, v2m->spis_nr);
  291. rt_pic_user_extends(&v2m->parent);
  292. rt_ofw_data(v2m_np) = &v2m->parent;
  293. rt_ofw_node_set_flag(v2m_np, RT_OFW_F_READLY);
  294. continue;
  295. _fail:
  296. rt_iounmap(v2m->base);
  297. rt_free(v2m);
  298. if (err)
  299. {
  300. rt_ofw_node_put(v2m_np);
  301. break;
  302. }
  303. }
  304. return err;
  305. }