irq-loongson-pch-pic.c 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378
  1. // SPDX-License-Identifier: GPL-2.0
  2. /*
  3. * Copyright (C) 2020, Jiaxun Yang <[email protected]>
  4. * Loongson PCH PIC support
  5. */
  6. #define pr_fmt(fmt) "pch-pic: " fmt
  7. #include <linux/interrupt.h>
  8. #include <linux/irq.h>
  9. #include <linux/irqchip.h>
  10. #include <linux/irqdomain.h>
  11. #include <linux/kernel.h>
  12. #include <linux/platform_device.h>
  13. #include <linux/of_address.h>
  14. #include <linux/of_irq.h>
  15. #include <linux/of_platform.h>
  16. /* Registers */
  17. #define PCH_PIC_MASK 0x20
  18. #define PCH_PIC_HTMSI_EN 0x40
  19. #define PCH_PIC_EDGE 0x60
  20. #define PCH_PIC_CLR 0x80
  21. #define PCH_PIC_AUTO0 0xc0
  22. #define PCH_PIC_AUTO1 0xe0
  23. #define PCH_INT_ROUTE(irq) (0x100 + irq)
  24. #define PCH_INT_HTVEC(irq) (0x200 + irq)
  25. #define PCH_PIC_POL 0x3e0
  26. #define PIC_COUNT_PER_REG 32
  27. #define PIC_REG_COUNT 2
  28. #define PIC_COUNT (PIC_COUNT_PER_REG * PIC_REG_COUNT)
  29. #define PIC_REG_IDX(irq_id) ((irq_id) / PIC_COUNT_PER_REG)
  30. #define PIC_REG_BIT(irq_id) ((irq_id) % PIC_COUNT_PER_REG)
  31. static int nr_pics;
  32. struct pch_pic {
  33. void __iomem *base;
  34. struct irq_domain *pic_domain;
  35. u32 ht_vec_base;
  36. raw_spinlock_t pic_lock;
  37. u32 vec_count;
  38. u32 gsi_base;
  39. };
  40. static struct pch_pic *pch_pic_priv[MAX_IO_PICS];
  41. struct fwnode_handle *pch_pic_handle[MAX_IO_PICS];
  42. static void pch_pic_bitset(struct pch_pic *priv, int offset, int bit)
  43. {
  44. u32 reg;
  45. void __iomem *addr = priv->base + offset + PIC_REG_IDX(bit) * 4;
  46. raw_spin_lock(&priv->pic_lock);
  47. reg = readl(addr);
  48. reg |= BIT(PIC_REG_BIT(bit));
  49. writel(reg, addr);
  50. raw_spin_unlock(&priv->pic_lock);
  51. }
  52. static void pch_pic_bitclr(struct pch_pic *priv, int offset, int bit)
  53. {
  54. u32 reg;
  55. void __iomem *addr = priv->base + offset + PIC_REG_IDX(bit) * 4;
  56. raw_spin_lock(&priv->pic_lock);
  57. reg = readl(addr);
  58. reg &= ~BIT(PIC_REG_BIT(bit));
  59. writel(reg, addr);
  60. raw_spin_unlock(&priv->pic_lock);
  61. }
  62. static void pch_pic_mask_irq(struct irq_data *d)
  63. {
  64. struct pch_pic *priv = irq_data_get_irq_chip_data(d);
  65. pch_pic_bitset(priv, PCH_PIC_MASK, d->hwirq);
  66. irq_chip_mask_parent(d);
  67. }
  68. static void pch_pic_unmask_irq(struct irq_data *d)
  69. {
  70. struct pch_pic *priv = irq_data_get_irq_chip_data(d);
  71. writel(BIT(PIC_REG_BIT(d->hwirq)),
  72. priv->base + PCH_PIC_CLR + PIC_REG_IDX(d->hwirq) * 4);
  73. irq_chip_unmask_parent(d);
  74. pch_pic_bitclr(priv, PCH_PIC_MASK, d->hwirq);
  75. }
  76. static int pch_pic_set_type(struct irq_data *d, unsigned int type)
  77. {
  78. struct pch_pic *priv = irq_data_get_irq_chip_data(d);
  79. int ret = 0;
  80. switch (type) {
  81. case IRQ_TYPE_EDGE_RISING:
  82. pch_pic_bitset(priv, PCH_PIC_EDGE, d->hwirq);
  83. pch_pic_bitclr(priv, PCH_PIC_POL, d->hwirq);
  84. irq_set_handler_locked(d, handle_edge_irq);
  85. break;
  86. case IRQ_TYPE_EDGE_FALLING:
  87. pch_pic_bitset(priv, PCH_PIC_EDGE, d->hwirq);
  88. pch_pic_bitset(priv, PCH_PIC_POL, d->hwirq);
  89. irq_set_handler_locked(d, handle_edge_irq);
  90. break;
  91. case IRQ_TYPE_LEVEL_HIGH:
  92. pch_pic_bitclr(priv, PCH_PIC_EDGE, d->hwirq);
  93. pch_pic_bitclr(priv, PCH_PIC_POL, d->hwirq);
  94. irq_set_handler_locked(d, handle_level_irq);
  95. break;
  96. case IRQ_TYPE_LEVEL_LOW:
  97. pch_pic_bitclr(priv, PCH_PIC_EDGE, d->hwirq);
  98. pch_pic_bitset(priv, PCH_PIC_POL, d->hwirq);
  99. irq_set_handler_locked(d, handle_level_irq);
  100. break;
  101. default:
  102. ret = -EINVAL;
  103. break;
  104. }
  105. return ret;
  106. }
  107. static void pch_pic_ack_irq(struct irq_data *d)
  108. {
  109. unsigned int reg;
  110. struct pch_pic *priv = irq_data_get_irq_chip_data(d);
  111. reg = readl(priv->base + PCH_PIC_EDGE + PIC_REG_IDX(d->hwirq) * 4);
  112. if (reg & BIT(PIC_REG_BIT(d->hwirq))) {
  113. writel(BIT(PIC_REG_BIT(d->hwirq)),
  114. priv->base + PCH_PIC_CLR + PIC_REG_IDX(d->hwirq) * 4);
  115. }
  116. irq_chip_ack_parent(d);
  117. }
  118. static struct irq_chip pch_pic_irq_chip = {
  119. .name = "PCH PIC",
  120. .irq_mask = pch_pic_mask_irq,
  121. .irq_unmask = pch_pic_unmask_irq,
  122. .irq_ack = pch_pic_ack_irq,
  123. .irq_set_affinity = irq_chip_set_affinity_parent,
  124. .irq_set_type = pch_pic_set_type,
  125. };
  126. static int pch_pic_domain_translate(struct irq_domain *d,
  127. struct irq_fwspec *fwspec,
  128. unsigned long *hwirq,
  129. unsigned int *type)
  130. {
  131. struct pch_pic *priv = d->host_data;
  132. struct device_node *of_node = to_of_node(fwspec->fwnode);
  133. if (fwspec->param_count < 1)
  134. return -EINVAL;
  135. if (of_node) {
  136. if (fwspec->param_count < 2)
  137. return -EINVAL;
  138. *hwirq = fwspec->param[0];
  139. *type = fwspec->param[1] & IRQ_TYPE_SENSE_MASK;
  140. } else {
  141. *hwirq = fwspec->param[0] - priv->gsi_base;
  142. *type = IRQ_TYPE_NONE;
  143. }
  144. return 0;
  145. }
  146. static int pch_pic_alloc(struct irq_domain *domain, unsigned int virq,
  147. unsigned int nr_irqs, void *arg)
  148. {
  149. int err;
  150. unsigned int type;
  151. unsigned long hwirq;
  152. struct irq_fwspec *fwspec = arg;
  153. struct irq_fwspec parent_fwspec;
  154. struct pch_pic *priv = domain->host_data;
  155. err = pch_pic_domain_translate(domain, fwspec, &hwirq, &type);
  156. if (err)
  157. return err;
  158. parent_fwspec.fwnode = domain->parent->fwnode;
  159. parent_fwspec.param_count = 1;
  160. parent_fwspec.param[0] = hwirq + priv->ht_vec_base;
  161. err = irq_domain_alloc_irqs_parent(domain, virq, 1, &parent_fwspec);
  162. if (err)
  163. return err;
  164. irq_domain_set_info(domain, virq, hwirq,
  165. &pch_pic_irq_chip, priv,
  166. handle_level_irq, NULL, NULL);
  167. irq_set_probe(virq);
  168. return 0;
  169. }
  170. static const struct irq_domain_ops pch_pic_domain_ops = {
  171. .translate = pch_pic_domain_translate,
  172. .alloc = pch_pic_alloc,
  173. .free = irq_domain_free_irqs_parent,
  174. };
  175. static void pch_pic_reset(struct pch_pic *priv)
  176. {
  177. int i;
  178. for (i = 0; i < PIC_COUNT; i++) {
  179. /* Write vector ID */
  180. writeb(priv->ht_vec_base + i, priv->base + PCH_INT_HTVEC(i));
  181. /* Hardcode route to HT0 Lo */
  182. writeb(1, priv->base + PCH_INT_ROUTE(i));
  183. }
  184. for (i = 0; i < PIC_REG_COUNT; i++) {
  185. /* Clear IRQ cause registers, mask all interrupts */
  186. writel_relaxed(0xFFFFFFFF, priv->base + PCH_PIC_MASK + 4 * i);
  187. writel_relaxed(0xFFFFFFFF, priv->base + PCH_PIC_CLR + 4 * i);
  188. /* Clear auto bounce, we don't need that */
  189. writel_relaxed(0, priv->base + PCH_PIC_AUTO0 + 4 * i);
  190. writel_relaxed(0, priv->base + PCH_PIC_AUTO1 + 4 * i);
  191. /* Enable HTMSI transformer */
  192. writel_relaxed(0xFFFFFFFF, priv->base + PCH_PIC_HTMSI_EN + 4 * i);
  193. }
  194. }
  195. static int pch_pic_init(phys_addr_t addr, unsigned long size, int vec_base,
  196. struct irq_domain *parent_domain, struct fwnode_handle *domain_handle,
  197. u32 gsi_base)
  198. {
  199. struct pch_pic *priv;
  200. priv = kzalloc(sizeof(*priv), GFP_KERNEL);
  201. if (!priv)
  202. return -ENOMEM;
  203. raw_spin_lock_init(&priv->pic_lock);
  204. priv->base = ioremap(addr, size);
  205. if (!priv->base)
  206. goto free_priv;
  207. priv->ht_vec_base = vec_base;
  208. priv->vec_count = ((readq(priv->base) >> 48) & 0xff) + 1;
  209. priv->gsi_base = gsi_base;
  210. priv->pic_domain = irq_domain_create_hierarchy(parent_domain, 0,
  211. priv->vec_count, domain_handle,
  212. &pch_pic_domain_ops, priv);
  213. if (!priv->pic_domain) {
  214. pr_err("Failed to create IRQ domain\n");
  215. goto iounmap_base;
  216. }
  217. pch_pic_reset(priv);
  218. pch_pic_handle[nr_pics] = domain_handle;
  219. pch_pic_priv[nr_pics++] = priv;
  220. return 0;
  221. iounmap_base:
  222. iounmap(priv->base);
  223. free_priv:
  224. kfree(priv);
  225. return -EINVAL;
  226. }
  227. #ifdef CONFIG_OF
  228. static int pch_pic_of_init(struct device_node *node,
  229. struct device_node *parent)
  230. {
  231. int err, vec_base;
  232. struct resource res;
  233. struct irq_domain *parent_domain;
  234. if (of_address_to_resource(node, 0, &res))
  235. return -EINVAL;
  236. parent_domain = irq_find_host(parent);
  237. if (!parent_domain) {
  238. pr_err("Failed to find the parent domain\n");
  239. return -ENXIO;
  240. }
  241. if (of_property_read_u32(node, "loongson,pic-base-vec", &vec_base)) {
  242. pr_err("Failed to determine pic-base-vec\n");
  243. return -EINVAL;
  244. }
  245. err = pch_pic_init(res.start, resource_size(&res), vec_base,
  246. parent_domain, of_node_to_fwnode(node), 0);
  247. if (err < 0)
  248. return err;
  249. return 0;
  250. }
  251. IRQCHIP_DECLARE(pch_pic, "loongson,pch-pic-1.0", pch_pic_of_init);
  252. #endif
  253. #ifdef CONFIG_ACPI
  254. int find_pch_pic(u32 gsi)
  255. {
  256. int i;
  257. /* Find the PCH_PIC that manages this GSI. */
  258. for (i = 0; i < MAX_IO_PICS; i++) {
  259. struct pch_pic *priv = pch_pic_priv[i];
  260. if (!priv)
  261. return -1;
  262. if (gsi >= priv->gsi_base && gsi < (priv->gsi_base + priv->vec_count))
  263. return i;
  264. }
  265. pr_err("ERROR: Unable to locate PCH_PIC for GSI %d\n", gsi);
  266. return -1;
  267. }
  268. static int __init pch_lpc_parse_madt(union acpi_subtable_headers *header,
  269. const unsigned long end)
  270. {
  271. struct acpi_madt_lpc_pic *pchlpc_entry = (struct acpi_madt_lpc_pic *)header;
  272. return pch_lpc_acpi_init(pch_pic_priv[0]->pic_domain, pchlpc_entry);
  273. }
  274. static int __init acpi_cascade_irqdomain_init(void)
  275. {
  276. int r;
  277. r = acpi_table_parse_madt(ACPI_MADT_TYPE_LPC_PIC, pch_lpc_parse_madt, 0);
  278. if (r < 0)
  279. return r;
  280. return 0;
  281. }
  282. int __init pch_pic_acpi_init(struct irq_domain *parent,
  283. struct acpi_madt_bio_pic *acpi_pchpic)
  284. {
  285. int ret;
  286. struct fwnode_handle *domain_handle;
  287. if (find_pch_pic(acpi_pchpic->gsi_base) >= 0)
  288. return 0;
  289. domain_handle = irq_domain_alloc_fwnode(&acpi_pchpic->address);
  290. if (!domain_handle) {
  291. pr_err("Unable to allocate domain handle\n");
  292. return -ENOMEM;
  293. }
  294. ret = pch_pic_init(acpi_pchpic->address, acpi_pchpic->size,
  295. 0, parent, domain_handle, acpi_pchpic->gsi_base);
  296. if (ret < 0) {
  297. irq_domain_free_fwnode(domain_handle);
  298. return ret;
  299. }
  300. if (acpi_pchpic->id == 0)
  301. ret = acpi_cascade_irqdomain_init();
  302. return ret;
  303. }
  304. #endif