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 static void pch_pic_bitset(struct pch_pic *priv, int offset, int bit) 52 { 53 u32 reg; 54 void __iomem *addr = priv->base + offset + PIC_REG_IDX(bit) * 4; 55 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 63 static void pch_pic_bitclr(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_mask_irq(struct irq_data *d) 76 { 77 struct pch_pic *priv = irq_data_get_irq_chip_data(d); 78 79 pch_pic_bitset(priv, PCH_PIC_MASK, d->hwirq); 80 irq_chip_mask_parent(d); 81 } 82 83 static void pch_pic_unmask_irq(struct irq_data *d) 84 { 85 struct pch_pic *priv = irq_data_get_irq_chip_data(d); 86 87 writel(BIT(PIC_REG_BIT(d->hwirq)), 88 priv->base + PCH_PIC_CLR + PIC_REG_IDX(d->hwirq) * 4); 89 90 irq_chip_unmask_parent(d); 91 pch_pic_bitclr(priv, PCH_PIC_MASK, d->hwirq); 92 } 93 94 static int pch_pic_set_type(struct irq_data *d, unsigned int type) 95 { 96 struct pch_pic *priv = irq_data_get_irq_chip_data(d); 97 int ret = 0; 98 99 switch (type) { 100 case IRQ_TYPE_EDGE_RISING: 101 pch_pic_bitset(priv, PCH_PIC_EDGE, d->hwirq); 102 pch_pic_bitclr(priv, PCH_PIC_POL, d->hwirq); 103 irq_set_handler_locked(d, handle_edge_irq); 104 break; 105 case IRQ_TYPE_EDGE_FALLING: 106 pch_pic_bitset(priv, PCH_PIC_EDGE, d->hwirq); 107 pch_pic_bitset(priv, PCH_PIC_POL, d->hwirq); 108 irq_set_handler_locked(d, handle_edge_irq); 109 break; 110 case IRQ_TYPE_LEVEL_HIGH: 111 pch_pic_bitclr(priv, PCH_PIC_EDGE, d->hwirq); 112 pch_pic_bitclr(priv, PCH_PIC_POL, d->hwirq); 113 irq_set_handler_locked(d, handle_level_irq); 114 break; 115 case IRQ_TYPE_LEVEL_LOW: 116 pch_pic_bitclr(priv, PCH_PIC_EDGE, d->hwirq); 117 pch_pic_bitset(priv, PCH_PIC_POL, d->hwirq); 118 irq_set_handler_locked(d, handle_level_irq); 119 break; 120 default: 121 ret = -EINVAL; 122 break; 123 } 124 125 return ret; 126 } 127 128 static void pch_pic_ack_irq(struct irq_data *d) 129 { 130 unsigned int reg; 131 struct pch_pic *priv = irq_data_get_irq_chip_data(d); 132 133 reg = readl(priv->base + PCH_PIC_EDGE + PIC_REG_IDX(d->hwirq) * 4); 134 if (reg & BIT(PIC_REG_BIT(d->hwirq))) { 135 writel(BIT(PIC_REG_BIT(d->hwirq)), 136 priv->base + PCH_PIC_CLR + PIC_REG_IDX(d->hwirq) * 4); 137 } 138 irq_chip_ack_parent(d); 139 } 140 141 static struct irq_chip pch_pic_irq_chip = { 142 .name = "PCH PIC", 143 .irq_mask = pch_pic_mask_irq, 144 .irq_unmask = pch_pic_unmask_irq, 145 .irq_ack = pch_pic_ack_irq, 146 .irq_set_affinity = irq_chip_set_affinity_parent, 147 .irq_set_type = pch_pic_set_type, 148 }; 149 150 static int pch_pic_domain_translate(struct irq_domain *d, 151 struct irq_fwspec *fwspec, 152 unsigned long *hwirq, 153 unsigned int *type) 154 { 155 struct pch_pic *priv = d->host_data; 156 struct device_node *of_node = to_of_node(fwspec->fwnode); 157 158 if (fwspec->param_count < 1) 159 return -EINVAL; 160 161 if (of_node) { 162 *hwirq = fwspec->param[0] + priv->ht_vec_base; 163 *type = fwspec->param[1] & IRQ_TYPE_SENSE_MASK; 164 } else { 165 *hwirq = fwspec->param[0] - priv->gsi_base; 166 *type = IRQ_TYPE_NONE; 167 } 168 169 return 0; 170 } 171 172 static int pch_pic_alloc(struct irq_domain *domain, unsigned int virq, 173 unsigned int nr_irqs, void *arg) 174 { 175 int err; 176 unsigned int type; 177 unsigned long hwirq; 178 struct irq_fwspec *fwspec = arg; 179 struct irq_fwspec parent_fwspec; 180 struct pch_pic *priv = domain->host_data; 181 182 err = pch_pic_domain_translate(domain, fwspec, &hwirq, &type); 183 if (err) 184 return err; 185 186 parent_fwspec.fwnode = domain->parent->fwnode; 187 parent_fwspec.param_count = 1; 188 parent_fwspec.param[0] = hwirq; 189 190 err = irq_domain_alloc_irqs_parent(domain, virq, 1, &parent_fwspec); 191 if (err) 192 return err; 193 194 irq_domain_set_info(domain, virq, hwirq, 195 &pch_pic_irq_chip, priv, 196 handle_level_irq, NULL, NULL); 197 irq_set_probe(virq); 198 199 return 0; 200 } 201 202 static const struct irq_domain_ops pch_pic_domain_ops = { 203 .translate = pch_pic_domain_translate, 204 .alloc = pch_pic_alloc, 205 .free = irq_domain_free_irqs_parent, 206 }; 207 208 static void pch_pic_reset(struct pch_pic *priv) 209 { 210 int i; 211 212 for (i = 0; i < PIC_COUNT; i++) { 213 /* Write vector ID */ 214 writeb(priv->ht_vec_base + i, priv->base + PCH_INT_HTVEC(i)); 215 /* Hardcode route to HT0 Lo */ 216 writeb(1, priv->base + PCH_INT_ROUTE(i)); 217 } 218 219 for (i = 0; i < PIC_REG_COUNT; i++) { 220 /* Clear IRQ cause registers, mask all interrupts */ 221 writel_relaxed(0xFFFFFFFF, priv->base + PCH_PIC_MASK + 4 * i); 222 writel_relaxed(0xFFFFFFFF, priv->base + PCH_PIC_CLR + 4 * i); 223 /* Clear auto bounce, we don't need that */ 224 writel_relaxed(0, priv->base + PCH_PIC_AUTO0 + 4 * i); 225 writel_relaxed(0, priv->base + PCH_PIC_AUTO1 + 4 * i); 226 /* Enable HTMSI transformer */ 227 writel_relaxed(0xFFFFFFFF, priv->base + PCH_PIC_HTMSI_EN + 4 * i); 228 } 229 } 230 231 static int pch_pic_init(phys_addr_t addr, unsigned long size, int vec_base, 232 struct irq_domain *parent_domain, struct fwnode_handle *domain_handle, 233 u32 gsi_base) 234 { 235 struct pch_pic *priv; 236 237 priv = kzalloc(sizeof(*priv), GFP_KERNEL); 238 if (!priv) 239 return -ENOMEM; 240 241 raw_spin_lock_init(&priv->pic_lock); 242 priv->base = ioremap(addr, size); 243 if (!priv->base) 244 goto free_priv; 245 246 priv->ht_vec_base = vec_base; 247 priv->vec_count = ((readq(priv->base) >> 48) & 0xff) + 1; 248 priv->gsi_base = gsi_base; 249 250 priv->pic_domain = irq_domain_create_hierarchy(parent_domain, 0, 251 priv->vec_count, domain_handle, 252 &pch_pic_domain_ops, priv); 253 254 if (!priv->pic_domain) { 255 pr_err("Failed to create IRQ domain\n"); 256 goto iounmap_base; 257 } 258 259 pch_pic_reset(priv); 260 pch_pic_handle[nr_pics] = domain_handle; 261 pch_pic_priv[nr_pics++] = priv; 262 263 return 0; 264 265 iounmap_base: 266 iounmap(priv->base); 267 free_priv: 268 kfree(priv); 269 270 return -EINVAL; 271 } 272 273 #ifdef CONFIG_OF 274 275 static int pch_pic_of_init(struct device_node *node, 276 struct device_node *parent) 277 { 278 int err, vec_base; 279 struct resource res; 280 struct irq_domain *parent_domain; 281 282 if (of_address_to_resource(node, 0, &res)) 283 return -EINVAL; 284 285 parent_domain = irq_find_host(parent); 286 if (!parent_domain) { 287 pr_err("Failed to find the parent domain\n"); 288 return -ENXIO; 289 } 290 291 if (of_property_read_u32(node, "loongson,pic-base-vec", &vec_base)) { 292 pr_err("Failed to determine pic-base-vec\n"); 293 return -EINVAL; 294 } 295 296 err = pch_pic_init(res.start, resource_size(&res), vec_base, 297 parent_domain, of_node_to_fwnode(node), 0); 298 if (err < 0) 299 return err; 300 301 return 0; 302 } 303 304 IRQCHIP_DECLARE(pch_pic, "loongson,pch-pic-1.0", pch_pic_of_init); 305 306 #endif 307 308 #ifdef CONFIG_ACPI 309 int find_pch_pic(u32 gsi) 310 { 311 int i; 312 313 /* Find the PCH_PIC that manages this GSI. */ 314 for (i = 0; i < MAX_IO_PICS; i++) { 315 struct pch_pic *priv = pch_pic_priv[i]; 316 317 if (!priv) 318 return -1; 319 320 if (gsi >= priv->gsi_base && gsi < (priv->gsi_base + priv->vec_count)) 321 return i; 322 } 323 324 pr_err("ERROR: Unable to locate PCH_PIC for GSI %d\n", gsi); 325 return -1; 326 } 327 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(&acpi_pchpic->address); 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