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