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