Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /*
0003  *  Copyright (C) 2020, Jiaxun Yang <jiaxun.yang@flygoat.com>
0004  *  Loongson PCH PIC support
0005  */
0006 
0007 #define pr_fmt(fmt) "pch-pic: " fmt
0008 
0009 #include <linux/interrupt.h>
0010 #include <linux/irq.h>
0011 #include <linux/irqchip.h>
0012 #include <linux/irqdomain.h>
0013 #include <linux/kernel.h>
0014 #include <linux/platform_device.h>
0015 #include <linux/of_address.h>
0016 #include <linux/of_irq.h>
0017 #include <linux/of_platform.h>
0018 
0019 /* Registers */
0020 #define PCH_PIC_MASK        0x20
0021 #define PCH_PIC_HTMSI_EN    0x40
0022 #define PCH_PIC_EDGE        0x60
0023 #define PCH_PIC_CLR     0x80
0024 #define PCH_PIC_AUTO0       0xc0
0025 #define PCH_PIC_AUTO1       0xe0
0026 #define PCH_INT_ROUTE(irq)  (0x100 + irq)
0027 #define PCH_INT_HTVEC(irq)  (0x200 + irq)
0028 #define PCH_PIC_POL     0x3e0
0029 
0030 #define PIC_COUNT_PER_REG   32
0031 #define PIC_REG_COUNT       2
0032 #define PIC_COUNT       (PIC_COUNT_PER_REG * PIC_REG_COUNT)
0033 #define PIC_REG_IDX(irq_id) ((irq_id) / PIC_COUNT_PER_REG)
0034 #define PIC_REG_BIT(irq_id) ((irq_id) % PIC_COUNT_PER_REG)
0035 
0036 static int nr_pics;
0037 
0038 struct pch_pic {
0039     void __iomem        *base;
0040     struct irq_domain   *pic_domain;
0041     u32         ht_vec_base;
0042     raw_spinlock_t      pic_lock;
0043     u32         vec_count;
0044     u32         gsi_base;
0045 };
0046 
0047 static struct pch_pic *pch_pic_priv[MAX_IO_PICS];
0048 
0049 struct fwnode_handle *pch_pic_handle[MAX_IO_PICS];
0050 
0051 static void pch_pic_bitset(struct pch_pic *priv, int offset, int bit)
0052 {
0053     u32 reg;
0054     void __iomem *addr = priv->base + offset + PIC_REG_IDX(bit) * 4;
0055 
0056     raw_spin_lock(&priv->pic_lock);
0057     reg = readl(addr);
0058     reg |= BIT(PIC_REG_BIT(bit));
0059     writel(reg, addr);
0060     raw_spin_unlock(&priv->pic_lock);
0061 }
0062 
0063 static void pch_pic_bitclr(struct pch_pic *priv, int offset, int bit)
0064 {
0065     u32 reg;
0066     void __iomem *addr = priv->base + offset + PIC_REG_IDX(bit) * 4;
0067 
0068     raw_spin_lock(&priv->pic_lock);
0069     reg = readl(addr);
0070     reg &= ~BIT(PIC_REG_BIT(bit));
0071     writel(reg, addr);
0072     raw_spin_unlock(&priv->pic_lock);
0073 }
0074 
0075 static void pch_pic_mask_irq(struct irq_data *d)
0076 {
0077     struct pch_pic *priv = irq_data_get_irq_chip_data(d);
0078 
0079     pch_pic_bitset(priv, PCH_PIC_MASK, d->hwirq);
0080     irq_chip_mask_parent(d);
0081 }
0082 
0083 static void pch_pic_unmask_irq(struct irq_data *d)
0084 {
0085     struct pch_pic *priv = irq_data_get_irq_chip_data(d);
0086 
0087     writel(BIT(PIC_REG_BIT(d->hwirq)),
0088             priv->base + PCH_PIC_CLR + PIC_REG_IDX(d->hwirq) * 4);
0089 
0090     irq_chip_unmask_parent(d);
0091     pch_pic_bitclr(priv, PCH_PIC_MASK, d->hwirq);
0092 }
0093 
0094 static int pch_pic_set_type(struct irq_data *d, unsigned int type)
0095 {
0096     struct pch_pic *priv = irq_data_get_irq_chip_data(d);
0097     int ret = 0;
0098 
0099     switch (type) {
0100     case IRQ_TYPE_EDGE_RISING:
0101         pch_pic_bitset(priv, PCH_PIC_EDGE, d->hwirq);
0102         pch_pic_bitclr(priv, PCH_PIC_POL, d->hwirq);
0103         irq_set_handler_locked(d, handle_edge_irq);
0104         break;
0105     case IRQ_TYPE_EDGE_FALLING:
0106         pch_pic_bitset(priv, PCH_PIC_EDGE, d->hwirq);
0107         pch_pic_bitset(priv, PCH_PIC_POL, d->hwirq);
0108         irq_set_handler_locked(d, handle_edge_irq);
0109         break;
0110     case IRQ_TYPE_LEVEL_HIGH:
0111         pch_pic_bitclr(priv, PCH_PIC_EDGE, d->hwirq);
0112         pch_pic_bitclr(priv, PCH_PIC_POL, d->hwirq);
0113         irq_set_handler_locked(d, handle_level_irq);
0114         break;
0115     case IRQ_TYPE_LEVEL_LOW:
0116         pch_pic_bitclr(priv, PCH_PIC_EDGE, d->hwirq);
0117         pch_pic_bitset(priv, PCH_PIC_POL, d->hwirq);
0118         irq_set_handler_locked(d, handle_level_irq);
0119         break;
0120     default:
0121         ret = -EINVAL;
0122         break;
0123     }
0124 
0125     return ret;
0126 }
0127 
0128 static void pch_pic_ack_irq(struct irq_data *d)
0129 {
0130     unsigned int reg;
0131     struct pch_pic *priv = irq_data_get_irq_chip_data(d);
0132 
0133     reg = readl(priv->base + PCH_PIC_EDGE + PIC_REG_IDX(d->hwirq) * 4);
0134     if (reg & BIT(PIC_REG_BIT(d->hwirq))) {
0135         writel(BIT(PIC_REG_BIT(d->hwirq)),
0136             priv->base + PCH_PIC_CLR + PIC_REG_IDX(d->hwirq) * 4);
0137     }
0138     irq_chip_ack_parent(d);
0139 }
0140 
0141 static struct irq_chip pch_pic_irq_chip = {
0142     .name           = "PCH PIC",
0143     .irq_mask       = pch_pic_mask_irq,
0144     .irq_unmask     = pch_pic_unmask_irq,
0145     .irq_ack        = pch_pic_ack_irq,
0146     .irq_set_affinity   = irq_chip_set_affinity_parent,
0147     .irq_set_type       = pch_pic_set_type,
0148 };
0149 
0150 static int pch_pic_domain_translate(struct irq_domain *d,
0151                     struct irq_fwspec *fwspec,
0152                     unsigned long *hwirq,
0153                     unsigned int *type)
0154 {
0155     struct pch_pic *priv = d->host_data;
0156     struct device_node *of_node = to_of_node(fwspec->fwnode);
0157 
0158     if (fwspec->param_count < 1)
0159         return -EINVAL;
0160 
0161     if (of_node) {
0162         *hwirq = fwspec->param[0] + priv->ht_vec_base;
0163         *type = fwspec->param[1] & IRQ_TYPE_SENSE_MASK;
0164     } else {
0165         *hwirq = fwspec->param[0] - priv->gsi_base;
0166         *type = IRQ_TYPE_NONE;
0167     }
0168 
0169     return 0;
0170 }
0171 
0172 static int pch_pic_alloc(struct irq_domain *domain, unsigned int virq,
0173                   unsigned int nr_irqs, void *arg)
0174 {
0175     int err;
0176     unsigned int type;
0177     unsigned long hwirq;
0178     struct irq_fwspec *fwspec = arg;
0179     struct irq_fwspec parent_fwspec;
0180     struct pch_pic *priv = domain->host_data;
0181 
0182     err = pch_pic_domain_translate(domain, fwspec, &hwirq, &type);
0183     if (err)
0184         return err;
0185 
0186     parent_fwspec.fwnode = domain->parent->fwnode;
0187     parent_fwspec.param_count = 1;
0188     parent_fwspec.param[0] = hwirq;
0189 
0190     err = irq_domain_alloc_irqs_parent(domain, virq, 1, &parent_fwspec);
0191     if (err)
0192         return err;
0193 
0194     irq_domain_set_info(domain, virq, hwirq,
0195                 &pch_pic_irq_chip, priv,
0196                 handle_level_irq, NULL, NULL);
0197     irq_set_probe(virq);
0198 
0199     return 0;
0200 }
0201 
0202 static const struct irq_domain_ops pch_pic_domain_ops = {
0203     .translate  = pch_pic_domain_translate,
0204     .alloc      = pch_pic_alloc,
0205     .free       = irq_domain_free_irqs_parent,
0206 };
0207 
0208 static void pch_pic_reset(struct pch_pic *priv)
0209 {
0210     int i;
0211 
0212     for (i = 0; i < PIC_COUNT; i++) {
0213         /* Write vector ID */
0214         writeb(priv->ht_vec_base + i, priv->base + PCH_INT_HTVEC(i));
0215         /* Hardcode route to HT0 Lo */
0216         writeb(1, priv->base + PCH_INT_ROUTE(i));
0217     }
0218 
0219     for (i = 0; i < PIC_REG_COUNT; i++) {
0220         /* Clear IRQ cause registers, mask all interrupts */
0221         writel_relaxed(0xFFFFFFFF, priv->base + PCH_PIC_MASK + 4 * i);
0222         writel_relaxed(0xFFFFFFFF, priv->base + PCH_PIC_CLR + 4 * i);
0223         /* Clear auto bounce, we don't need that */
0224         writel_relaxed(0, priv->base + PCH_PIC_AUTO0 + 4 * i);
0225         writel_relaxed(0, priv->base + PCH_PIC_AUTO1 + 4 * i);
0226         /* Enable HTMSI transformer */
0227         writel_relaxed(0xFFFFFFFF, priv->base + PCH_PIC_HTMSI_EN + 4 * i);
0228     }
0229 }
0230 
0231 static int pch_pic_init(phys_addr_t addr, unsigned long size, int vec_base,
0232             struct irq_domain *parent_domain, struct fwnode_handle *domain_handle,
0233             u32 gsi_base)
0234 {
0235     struct pch_pic *priv;
0236 
0237     priv = kzalloc(sizeof(*priv), GFP_KERNEL);
0238     if (!priv)
0239         return -ENOMEM;
0240 
0241     raw_spin_lock_init(&priv->pic_lock);
0242     priv->base = ioremap(addr, size);
0243     if (!priv->base)
0244         goto free_priv;
0245 
0246     priv->ht_vec_base = vec_base;
0247     priv->vec_count = ((readq(priv->base) >> 48) & 0xff) + 1;
0248     priv->gsi_base = gsi_base;
0249 
0250     priv->pic_domain = irq_domain_create_hierarchy(parent_domain, 0,
0251                         priv->vec_count, domain_handle,
0252                         &pch_pic_domain_ops, priv);
0253 
0254     if (!priv->pic_domain) {
0255         pr_err("Failed to create IRQ domain\n");
0256         goto iounmap_base;
0257     }
0258 
0259     pch_pic_reset(priv);
0260     pch_pic_handle[nr_pics] = domain_handle;
0261     pch_pic_priv[nr_pics++] = priv;
0262 
0263     return 0;
0264 
0265 iounmap_base:
0266     iounmap(priv->base);
0267 free_priv:
0268     kfree(priv);
0269 
0270     return -EINVAL;
0271 }
0272 
0273 #ifdef CONFIG_OF
0274 
0275 static int pch_pic_of_init(struct device_node *node,
0276                 struct device_node *parent)
0277 {
0278     int err, vec_base;
0279     struct resource res;
0280     struct irq_domain *parent_domain;
0281 
0282     if (of_address_to_resource(node, 0, &res))
0283         return -EINVAL;
0284 
0285     parent_domain = irq_find_host(parent);
0286     if (!parent_domain) {
0287         pr_err("Failed to find the parent domain\n");
0288         return -ENXIO;
0289     }
0290 
0291     if (of_property_read_u32(node, "loongson,pic-base-vec", &vec_base)) {
0292         pr_err("Failed to determine pic-base-vec\n");
0293         return -EINVAL;
0294     }
0295 
0296     err = pch_pic_init(res.start, resource_size(&res), vec_base,
0297                 parent_domain, of_node_to_fwnode(node), 0);
0298     if (err < 0)
0299         return err;
0300 
0301     return 0;
0302 }
0303 
0304 IRQCHIP_DECLARE(pch_pic, "loongson,pch-pic-1.0", pch_pic_of_init);
0305 
0306 #endif
0307 
0308 #ifdef CONFIG_ACPI
0309 int find_pch_pic(u32 gsi)
0310 {
0311     int i;
0312 
0313     /* Find the PCH_PIC that manages this GSI. */
0314     for (i = 0; i < MAX_IO_PICS; i++) {
0315         struct pch_pic *priv = pch_pic_priv[i];
0316 
0317         if (!priv)
0318             return -1;
0319 
0320         if (gsi >= priv->gsi_base && gsi < (priv->gsi_base + priv->vec_count))
0321             return i;
0322     }
0323 
0324     pr_err("ERROR: Unable to locate PCH_PIC for GSI %d\n", gsi);
0325     return -1;
0326 }
0327 
0328 static int __init
0329 pch_lpc_parse_madt(union acpi_subtable_headers *header,
0330                const unsigned long end)
0331 {
0332     struct acpi_madt_lpc_pic *pchlpc_entry = (struct acpi_madt_lpc_pic *)header;
0333 
0334     return pch_lpc_acpi_init(pch_pic_priv[0]->pic_domain, pchlpc_entry);
0335 }
0336 
0337 static int __init acpi_cascade_irqdomain_init(void)
0338 {
0339     acpi_table_parse_madt(ACPI_MADT_TYPE_LPC_PIC,
0340                   pch_lpc_parse_madt, 0);
0341     return 0;
0342 }
0343 
0344 int __init pch_pic_acpi_init(struct irq_domain *parent,
0345                     struct acpi_madt_bio_pic *acpi_pchpic)
0346 {
0347     int ret, vec_base;
0348     struct fwnode_handle *domain_handle;
0349 
0350     vec_base = acpi_pchpic->gsi_base - GSI_MIN_PCH_IRQ;
0351 
0352     domain_handle = irq_domain_alloc_fwnode(&acpi_pchpic->address);
0353     if (!domain_handle) {
0354         pr_err("Unable to allocate domain handle\n");
0355         return -ENOMEM;
0356     }
0357 
0358     ret = pch_pic_init(acpi_pchpic->address, acpi_pchpic->size,
0359                 vec_base, parent, domain_handle, acpi_pchpic->gsi_base);
0360 
0361     if (ret < 0) {
0362         irq_domain_free_fwnode(domain_handle);
0363         return ret;
0364     }
0365 
0366     if (acpi_pchpic->id == 0)
0367         acpi_cascade_irqdomain_init();
0368 
0369     return ret;
0370 }
0371 #endif