Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * Driver for Socionext External Interrupt Unit (EXIU)
0004  *
0005  * Copyright (c) 2017-2019 Linaro, Ltd. <ard.biesheuvel@linaro.org>
0006  *
0007  * Based on irq-tegra.c:
0008  *   Copyright (C) 2011 Google, Inc.
0009  *   Copyright (C) 2010,2013, NVIDIA Corporation
0010  */
0011 
0012 #include <linux/interrupt.h>
0013 #include <linux/io.h>
0014 #include <linux/irq.h>
0015 #include <linux/irqchip.h>
0016 #include <linux/irqdomain.h>
0017 #include <linux/of.h>
0018 #include <linux/of_address.h>
0019 #include <linux/of_irq.h>
0020 #include <linux/platform_device.h>
0021 
0022 #include <dt-bindings/interrupt-controller/arm-gic.h>
0023 
0024 #define NUM_IRQS    32
0025 
0026 #define EIMASK      0x00
0027 #define EISRCSEL    0x04
0028 #define EIREQSTA    0x08
0029 #define EIRAWREQSTA 0x0C
0030 #define EIREQCLR    0x10
0031 #define EILVL       0x14
0032 #define EIEDG       0x18
0033 #define EISIR       0x1C
0034 
0035 struct exiu_irq_data {
0036     void __iomem    *base;
0037     u32     spi_base;
0038 };
0039 
0040 static void exiu_irq_ack(struct irq_data *d)
0041 {
0042     struct exiu_irq_data *data = irq_data_get_irq_chip_data(d);
0043 
0044     writel(BIT(d->hwirq), data->base + EIREQCLR);
0045 }
0046 
0047 static void exiu_irq_eoi(struct irq_data *d)
0048 {
0049     struct exiu_irq_data *data = irq_data_get_irq_chip_data(d);
0050 
0051     /*
0052      * Level triggered interrupts are latched and must be cleared during
0053      * EOI or the interrupt will be jammed on. Of course if a level
0054      * triggered interrupt is still asserted then the write will not clear
0055      * the interrupt.
0056      */
0057     if (irqd_is_level_type(d))
0058         writel(BIT(d->hwirq), data->base + EIREQCLR);
0059 
0060     irq_chip_eoi_parent(d);
0061 }
0062 
0063 static void exiu_irq_mask(struct irq_data *d)
0064 {
0065     struct exiu_irq_data *data = irq_data_get_irq_chip_data(d);
0066     u32 val;
0067 
0068     val = readl_relaxed(data->base + EIMASK) | BIT(d->hwirq);
0069     writel_relaxed(val, data->base + EIMASK);
0070     irq_chip_mask_parent(d);
0071 }
0072 
0073 static void exiu_irq_unmask(struct irq_data *d)
0074 {
0075     struct exiu_irq_data *data = irq_data_get_irq_chip_data(d);
0076     u32 val;
0077 
0078     val = readl_relaxed(data->base + EIMASK) & ~BIT(d->hwirq);
0079     writel_relaxed(val, data->base + EIMASK);
0080     irq_chip_unmask_parent(d);
0081 }
0082 
0083 static void exiu_irq_enable(struct irq_data *d)
0084 {
0085     struct exiu_irq_data *data = irq_data_get_irq_chip_data(d);
0086     u32 val;
0087 
0088     /* clear interrupts that were latched while disabled */
0089     writel_relaxed(BIT(d->hwirq), data->base + EIREQCLR);
0090 
0091     val = readl_relaxed(data->base + EIMASK) & ~BIT(d->hwirq);
0092     writel_relaxed(val, data->base + EIMASK);
0093     irq_chip_enable_parent(d);
0094 }
0095 
0096 static int exiu_irq_set_type(struct irq_data *d, unsigned int type)
0097 {
0098     struct exiu_irq_data *data = irq_data_get_irq_chip_data(d);
0099     u32 val;
0100 
0101     val = readl_relaxed(data->base + EILVL);
0102     if (type == IRQ_TYPE_EDGE_RISING || type == IRQ_TYPE_LEVEL_HIGH)
0103         val |= BIT(d->hwirq);
0104     else
0105         val &= ~BIT(d->hwirq);
0106     writel_relaxed(val, data->base + EILVL);
0107 
0108     val = readl_relaxed(data->base + EIEDG);
0109     if (type == IRQ_TYPE_LEVEL_LOW || type == IRQ_TYPE_LEVEL_HIGH) {
0110         val &= ~BIT(d->hwirq);
0111         irq_set_handler_locked(d, handle_fasteoi_irq);
0112     } else {
0113         val |= BIT(d->hwirq);
0114         irq_set_handler_locked(d, handle_fasteoi_ack_irq);
0115     }
0116     writel_relaxed(val, data->base + EIEDG);
0117 
0118     writel_relaxed(BIT(d->hwirq), data->base + EIREQCLR);
0119 
0120     return irq_chip_set_type_parent(d, IRQ_TYPE_LEVEL_HIGH);
0121 }
0122 
0123 static struct irq_chip exiu_irq_chip = {
0124     .name           = "EXIU",
0125     .irq_ack        = exiu_irq_ack,
0126     .irq_eoi        = exiu_irq_eoi,
0127     .irq_enable     = exiu_irq_enable,
0128     .irq_mask       = exiu_irq_mask,
0129     .irq_unmask     = exiu_irq_unmask,
0130     .irq_set_type       = exiu_irq_set_type,
0131     .irq_set_affinity   = irq_chip_set_affinity_parent,
0132     .flags          = IRQCHIP_SET_TYPE_MASKED |
0133                   IRQCHIP_SKIP_SET_WAKE |
0134                   IRQCHIP_EOI_THREADED |
0135                   IRQCHIP_MASK_ON_SUSPEND,
0136 };
0137 
0138 static int exiu_domain_translate(struct irq_domain *domain,
0139                  struct irq_fwspec *fwspec,
0140                  unsigned long *hwirq,
0141                  unsigned int *type)
0142 {
0143     struct exiu_irq_data *info = domain->host_data;
0144 
0145     if (is_of_node(fwspec->fwnode)) {
0146         if (fwspec->param_count != 3)
0147             return -EINVAL;
0148 
0149         if (fwspec->param[0] != GIC_SPI)
0150             return -EINVAL; /* No PPI should point to this domain */
0151 
0152         *hwirq = fwspec->param[1] - info->spi_base;
0153         *type = fwspec->param[2] & IRQ_TYPE_SENSE_MASK;
0154     } else {
0155         if (fwspec->param_count != 2)
0156             return -EINVAL;
0157         *hwirq = fwspec->param[0];
0158         *type = fwspec->param[1] & IRQ_TYPE_SENSE_MASK;
0159     }
0160     return 0;
0161 }
0162 
0163 static int exiu_domain_alloc(struct irq_domain *dom, unsigned int virq,
0164                  unsigned int nr_irqs, void *data)
0165 {
0166     struct irq_fwspec *fwspec = data;
0167     struct irq_fwspec parent_fwspec;
0168     struct exiu_irq_data *info = dom->host_data;
0169     irq_hw_number_t hwirq;
0170 
0171     parent_fwspec = *fwspec;
0172     if (is_of_node(dom->parent->fwnode)) {
0173         if (fwspec->param_count != 3)
0174             return -EINVAL; /* Not GIC compliant */
0175         if (fwspec->param[0] != GIC_SPI)
0176             return -EINVAL; /* No PPI should point to this domain */
0177 
0178         hwirq = fwspec->param[1] - info->spi_base;
0179     } else {
0180         hwirq = fwspec->param[0];
0181         parent_fwspec.param[0] = hwirq + info->spi_base + 32;
0182     }
0183     WARN_ON(nr_irqs != 1);
0184     irq_domain_set_hwirq_and_chip(dom, virq, hwirq, &exiu_irq_chip, info);
0185 
0186     parent_fwspec.fwnode = dom->parent->fwnode;
0187     return irq_domain_alloc_irqs_parent(dom, virq, nr_irqs, &parent_fwspec);
0188 }
0189 
0190 static const struct irq_domain_ops exiu_domain_ops = {
0191     .translate  = exiu_domain_translate,
0192     .alloc      = exiu_domain_alloc,
0193     .free       = irq_domain_free_irqs_common,
0194 };
0195 
0196 static struct exiu_irq_data *exiu_init(const struct fwnode_handle *fwnode,
0197                        struct resource *res)
0198 {
0199     struct exiu_irq_data *data;
0200     int err;
0201 
0202     data = kzalloc(sizeof(*data), GFP_KERNEL);
0203     if (!data)
0204         return ERR_PTR(-ENOMEM);
0205 
0206     if (fwnode_property_read_u32_array(fwnode, "socionext,spi-base",
0207                        &data->spi_base, 1)) {
0208         err = -ENODEV;
0209         goto out_free;
0210     }
0211 
0212     data->base = ioremap(res->start, resource_size(res));
0213     if (!data->base) {
0214         err = -ENODEV;
0215         goto out_free;
0216     }
0217 
0218     /* clear and mask all interrupts */
0219     writel_relaxed(0xFFFFFFFF, data->base + EIREQCLR);
0220     writel_relaxed(0xFFFFFFFF, data->base + EIMASK);
0221 
0222     return data;
0223 
0224 out_free:
0225     kfree(data);
0226     return ERR_PTR(err);
0227 }
0228 
0229 static int __init exiu_dt_init(struct device_node *node,
0230                    struct device_node *parent)
0231 {
0232     struct irq_domain *parent_domain, *domain;
0233     struct exiu_irq_data *data;
0234     struct resource res;
0235 
0236     if (!parent) {
0237         pr_err("%pOF: no parent, giving up\n", node);
0238         return -ENODEV;
0239     }
0240 
0241     parent_domain = irq_find_host(parent);
0242     if (!parent_domain) {
0243         pr_err("%pOF: unable to obtain parent domain\n", node);
0244         return -ENXIO;
0245     }
0246 
0247     if (of_address_to_resource(node, 0, &res)) {
0248         pr_err("%pOF: failed to parse memory resource\n", node);
0249         return -ENXIO;
0250     }
0251 
0252     data = exiu_init(of_node_to_fwnode(node), &res);
0253     if (IS_ERR(data))
0254         return PTR_ERR(data);
0255 
0256     domain = irq_domain_add_hierarchy(parent_domain, 0, NUM_IRQS, node,
0257                       &exiu_domain_ops, data);
0258     if (!domain) {
0259         pr_err("%pOF: failed to allocate domain\n", node);
0260         goto out_unmap;
0261     }
0262 
0263     pr_info("%pOF: %d interrupts forwarded to %pOF\n", node, NUM_IRQS,
0264         parent);
0265 
0266     return 0;
0267 
0268 out_unmap:
0269     iounmap(data->base);
0270     kfree(data);
0271     return -ENOMEM;
0272 }
0273 IRQCHIP_DECLARE(exiu, "socionext,synquacer-exiu", exiu_dt_init);
0274 
0275 #ifdef CONFIG_ACPI
0276 static int exiu_acpi_probe(struct platform_device *pdev)
0277 {
0278     struct irq_domain *domain;
0279     struct exiu_irq_data *data;
0280     struct resource *res;
0281 
0282     res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
0283     if (!res) {
0284         dev_err(&pdev->dev, "failed to parse memory resource\n");
0285         return -ENXIO;
0286     }
0287 
0288     data = exiu_init(dev_fwnode(&pdev->dev), res);
0289     if (IS_ERR(data))
0290         return PTR_ERR(data);
0291 
0292     domain = acpi_irq_create_hierarchy(0, NUM_IRQS, dev_fwnode(&pdev->dev),
0293                        &exiu_domain_ops, data);
0294     if (!domain) {
0295         dev_err(&pdev->dev, "failed to create IRQ domain\n");
0296         goto out_unmap;
0297     }
0298 
0299     dev_info(&pdev->dev, "%d interrupts forwarded\n", NUM_IRQS);
0300 
0301     return 0;
0302 
0303 out_unmap:
0304     iounmap(data->base);
0305     kfree(data);
0306     return -ENOMEM;
0307 }
0308 
0309 static const struct acpi_device_id exiu_acpi_ids[] = {
0310     { "SCX0008" },
0311     { /* sentinel */ }
0312 };
0313 MODULE_DEVICE_TABLE(acpi, exiu_acpi_ids);
0314 
0315 static struct platform_driver exiu_driver = {
0316     .driver = {
0317         .name = "exiu",
0318         .acpi_match_table = exiu_acpi_ids,
0319     },
0320     .probe = exiu_acpi_probe,
0321 };
0322 builtin_platform_driver(exiu_driver);
0323 #endif