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