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