Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * Driver code for Tegra's Legacy Interrupt Controller
0004  *
0005  * Author: Marc Zyngier <marc.zyngier@arm.com>
0006  *
0007  * Heavily based on the original arch/arm/mach-tegra/irq.c code:
0008  * Copyright (C) 2011 Google, Inc.
0009  *
0010  * Author:
0011  *  Colin Cross <ccross@android.com>
0012  *
0013  * Copyright (C) 2010,2013, NVIDIA Corporation
0014  */
0015 
0016 #include <linux/io.h>
0017 #include <linux/irq.h>
0018 #include <linux/irqchip.h>
0019 #include <linux/irqdomain.h>
0020 #include <linux/of_address.h>
0021 #include <linux/slab.h>
0022 #include <linux/syscore_ops.h>
0023 
0024 #include <dt-bindings/interrupt-controller/arm-gic.h>
0025 
0026 #define ICTLR_CPU_IEP_VFIQ  0x08
0027 #define ICTLR_CPU_IEP_FIR   0x14
0028 #define ICTLR_CPU_IEP_FIR_SET   0x18
0029 #define ICTLR_CPU_IEP_FIR_CLR   0x1c
0030 
0031 #define ICTLR_CPU_IER       0x20
0032 #define ICTLR_CPU_IER_SET   0x24
0033 #define ICTLR_CPU_IER_CLR   0x28
0034 #define ICTLR_CPU_IEP_CLASS 0x2C
0035 
0036 #define ICTLR_COP_IER       0x30
0037 #define ICTLR_COP_IER_SET   0x34
0038 #define ICTLR_COP_IER_CLR   0x38
0039 #define ICTLR_COP_IEP_CLASS 0x3c
0040 
0041 #define TEGRA_MAX_NUM_ICTLRS    6
0042 
0043 static unsigned int num_ictlrs;
0044 
0045 struct tegra_ictlr_soc {
0046     unsigned int num_ictlrs;
0047 };
0048 
0049 static const struct tegra_ictlr_soc tegra20_ictlr_soc = {
0050     .num_ictlrs = 4,
0051 };
0052 
0053 static const struct tegra_ictlr_soc tegra30_ictlr_soc = {
0054     .num_ictlrs = 5,
0055 };
0056 
0057 static const struct tegra_ictlr_soc tegra210_ictlr_soc = {
0058     .num_ictlrs = 6,
0059 };
0060 
0061 static const struct of_device_id ictlr_matches[] = {
0062     { .compatible = "nvidia,tegra210-ictlr", .data = &tegra210_ictlr_soc },
0063     { .compatible = "nvidia,tegra30-ictlr", .data = &tegra30_ictlr_soc },
0064     { .compatible = "nvidia,tegra20-ictlr", .data = &tegra20_ictlr_soc },
0065     { }
0066 };
0067 
0068 struct tegra_ictlr_info {
0069     void __iomem *base[TEGRA_MAX_NUM_ICTLRS];
0070 #ifdef CONFIG_PM_SLEEP
0071     u32 cop_ier[TEGRA_MAX_NUM_ICTLRS];
0072     u32 cop_iep[TEGRA_MAX_NUM_ICTLRS];
0073     u32 cpu_ier[TEGRA_MAX_NUM_ICTLRS];
0074     u32 cpu_iep[TEGRA_MAX_NUM_ICTLRS];
0075 
0076     u32 ictlr_wake_mask[TEGRA_MAX_NUM_ICTLRS];
0077 #endif
0078 };
0079 
0080 static struct tegra_ictlr_info *lic;
0081 
0082 static inline void tegra_ictlr_write_mask(struct irq_data *d, unsigned long reg)
0083 {
0084     void __iomem *base = (void __iomem __force *)d->chip_data;
0085     u32 mask;
0086 
0087     mask = BIT(d->hwirq % 32);
0088     writel_relaxed(mask, base + reg);
0089 }
0090 
0091 static void tegra_mask(struct irq_data *d)
0092 {
0093     tegra_ictlr_write_mask(d, ICTLR_CPU_IER_CLR);
0094     irq_chip_mask_parent(d);
0095 }
0096 
0097 static void tegra_unmask(struct irq_data *d)
0098 {
0099     tegra_ictlr_write_mask(d, ICTLR_CPU_IER_SET);
0100     irq_chip_unmask_parent(d);
0101 }
0102 
0103 static void tegra_eoi(struct irq_data *d)
0104 {
0105     tegra_ictlr_write_mask(d, ICTLR_CPU_IEP_FIR_CLR);
0106     irq_chip_eoi_parent(d);
0107 }
0108 
0109 static int tegra_retrigger(struct irq_data *d)
0110 {
0111     tegra_ictlr_write_mask(d, ICTLR_CPU_IEP_FIR_SET);
0112     return irq_chip_retrigger_hierarchy(d);
0113 }
0114 
0115 #ifdef CONFIG_PM_SLEEP
0116 static int tegra_set_wake(struct irq_data *d, unsigned int enable)
0117 {
0118     u32 irq = d->hwirq;
0119     u32 index, mask;
0120 
0121     index = (irq / 32);
0122     mask = BIT(irq % 32);
0123     if (enable)
0124         lic->ictlr_wake_mask[index] |= mask;
0125     else
0126         lic->ictlr_wake_mask[index] &= ~mask;
0127 
0128     /*
0129      * Do *not* call into the parent, as the GIC doesn't have any
0130      * wake-up facility...
0131      */
0132     return 0;
0133 }
0134 
0135 static int tegra_ictlr_suspend(void)
0136 {
0137     unsigned long flags;
0138     unsigned int i;
0139 
0140     local_irq_save(flags);
0141     for (i = 0; i < num_ictlrs; i++) {
0142         void __iomem *ictlr = lic->base[i];
0143 
0144         /* Save interrupt state */
0145         lic->cpu_ier[i] = readl_relaxed(ictlr + ICTLR_CPU_IER);
0146         lic->cpu_iep[i] = readl_relaxed(ictlr + ICTLR_CPU_IEP_CLASS);
0147         lic->cop_ier[i] = readl_relaxed(ictlr + ICTLR_COP_IER);
0148         lic->cop_iep[i] = readl_relaxed(ictlr + ICTLR_COP_IEP_CLASS);
0149 
0150         /* Disable COP interrupts */
0151         writel_relaxed(GENMASK(31, 0), ictlr + ICTLR_COP_IER_CLR);
0152 
0153         /* Disable CPU interrupts */
0154         writel_relaxed(GENMASK(31, 0), ictlr + ICTLR_CPU_IER_CLR);
0155 
0156         /* Enable the wakeup sources of ictlr */
0157         writel_relaxed(lic->ictlr_wake_mask[i], ictlr + ICTLR_CPU_IER_SET);
0158     }
0159     local_irq_restore(flags);
0160 
0161     return 0;
0162 }
0163 
0164 static void tegra_ictlr_resume(void)
0165 {
0166     unsigned long flags;
0167     unsigned int i;
0168 
0169     local_irq_save(flags);
0170     for (i = 0; i < num_ictlrs; i++) {
0171         void __iomem *ictlr = lic->base[i];
0172 
0173         writel_relaxed(lic->cpu_iep[i],
0174                    ictlr + ICTLR_CPU_IEP_CLASS);
0175         writel_relaxed(GENMASK(31, 0), ictlr + ICTLR_CPU_IER_CLR);
0176         writel_relaxed(lic->cpu_ier[i],
0177                    ictlr + ICTLR_CPU_IER_SET);
0178         writel_relaxed(lic->cop_iep[i],
0179                    ictlr + ICTLR_COP_IEP_CLASS);
0180         writel_relaxed(GENMASK(31, 0), ictlr + ICTLR_COP_IER_CLR);
0181         writel_relaxed(lic->cop_ier[i],
0182                    ictlr + ICTLR_COP_IER_SET);
0183     }
0184     local_irq_restore(flags);
0185 }
0186 
0187 static struct syscore_ops tegra_ictlr_syscore_ops = {
0188     .suspend    = tegra_ictlr_suspend,
0189     .resume     = tegra_ictlr_resume,
0190 };
0191 
0192 static void tegra_ictlr_syscore_init(void)
0193 {
0194     register_syscore_ops(&tegra_ictlr_syscore_ops);
0195 }
0196 #else
0197 #define tegra_set_wake  NULL
0198 static inline void tegra_ictlr_syscore_init(void) {}
0199 #endif
0200 
0201 static struct irq_chip tegra_ictlr_chip = {
0202     .name           = "LIC",
0203     .irq_eoi        = tegra_eoi,
0204     .irq_mask       = tegra_mask,
0205     .irq_unmask     = tegra_unmask,
0206     .irq_retrigger      = tegra_retrigger,
0207     .irq_set_wake       = tegra_set_wake,
0208     .irq_set_type       = irq_chip_set_type_parent,
0209     .flags          = IRQCHIP_MASK_ON_SUSPEND,
0210 #ifdef CONFIG_SMP
0211     .irq_set_affinity   = irq_chip_set_affinity_parent,
0212 #endif
0213 };
0214 
0215 static int tegra_ictlr_domain_translate(struct irq_domain *d,
0216                     struct irq_fwspec *fwspec,
0217                     unsigned long *hwirq,
0218                     unsigned int *type)
0219 {
0220     if (is_of_node(fwspec->fwnode)) {
0221         if (fwspec->param_count != 3)
0222             return -EINVAL;
0223 
0224         /* No PPI should point to this domain */
0225         if (fwspec->param[0] != 0)
0226             return -EINVAL;
0227 
0228         *hwirq = fwspec->param[1];
0229         *type = fwspec->param[2] & IRQ_TYPE_SENSE_MASK;
0230         return 0;
0231     }
0232 
0233     return -EINVAL;
0234 }
0235 
0236 static int tegra_ictlr_domain_alloc(struct irq_domain *domain,
0237                     unsigned int virq,
0238                     unsigned int nr_irqs, void *data)
0239 {
0240     struct irq_fwspec *fwspec = data;
0241     struct irq_fwspec parent_fwspec;
0242     struct tegra_ictlr_info *info = domain->host_data;
0243     irq_hw_number_t hwirq;
0244     unsigned int i;
0245 
0246     if (fwspec->param_count != 3)
0247         return -EINVAL; /* Not GIC compliant */
0248     if (fwspec->param[0] != GIC_SPI)
0249         return -EINVAL; /* No PPI should point to this domain */
0250 
0251     hwirq = fwspec->param[1];
0252     if (hwirq >= (num_ictlrs * 32))
0253         return -EINVAL;
0254 
0255     for (i = 0; i < nr_irqs; i++) {
0256         int ictlr = (hwirq + i) / 32;
0257 
0258         irq_domain_set_hwirq_and_chip(domain, virq + i, hwirq + i,
0259                           &tegra_ictlr_chip,
0260                           (void __force *)info->base[ictlr]);
0261     }
0262 
0263     parent_fwspec = *fwspec;
0264     parent_fwspec.fwnode = domain->parent->fwnode;
0265     return irq_domain_alloc_irqs_parent(domain, virq, nr_irqs,
0266                         &parent_fwspec);
0267 }
0268 
0269 static const struct irq_domain_ops tegra_ictlr_domain_ops = {
0270     .translate  = tegra_ictlr_domain_translate,
0271     .alloc      = tegra_ictlr_domain_alloc,
0272     .free       = irq_domain_free_irqs_common,
0273 };
0274 
0275 static int __init tegra_ictlr_init(struct device_node *node,
0276                    struct device_node *parent)
0277 {
0278     struct irq_domain *parent_domain, *domain;
0279     const struct of_device_id *match;
0280     const struct tegra_ictlr_soc *soc;
0281     unsigned int i;
0282     int err;
0283 
0284     if (!parent) {
0285         pr_err("%pOF: no parent, giving up\n", node);
0286         return -ENODEV;
0287     }
0288 
0289     parent_domain = irq_find_host(parent);
0290     if (!parent_domain) {
0291         pr_err("%pOF: unable to obtain parent domain\n", node);
0292         return -ENXIO;
0293     }
0294 
0295     match = of_match_node(ictlr_matches, node);
0296     if (!match)     /* Should never happen... */
0297         return -ENODEV;
0298 
0299     soc = match->data;
0300 
0301     lic = kzalloc(sizeof(*lic), GFP_KERNEL);
0302     if (!lic)
0303         return -ENOMEM;
0304 
0305     for (i = 0; i < TEGRA_MAX_NUM_ICTLRS; i++) {
0306         void __iomem *base;
0307 
0308         base = of_iomap(node, i);
0309         if (!base)
0310             break;
0311 
0312         lic->base[i] = base;
0313 
0314         /* Disable all interrupts */
0315         writel_relaxed(GENMASK(31, 0), base + ICTLR_CPU_IER_CLR);
0316         /* All interrupts target IRQ */
0317         writel_relaxed(0, base + ICTLR_CPU_IEP_CLASS);
0318 
0319         num_ictlrs++;
0320     }
0321 
0322     if (!num_ictlrs) {
0323         pr_err("%pOF: no valid regions, giving up\n", node);
0324         err = -ENOMEM;
0325         goto out_free;
0326     }
0327 
0328     WARN(num_ictlrs != soc->num_ictlrs,
0329          "%pOF: Found %u interrupt controllers in DT; expected %u.\n",
0330          node, num_ictlrs, soc->num_ictlrs);
0331 
0332 
0333     domain = irq_domain_add_hierarchy(parent_domain, 0, num_ictlrs * 32,
0334                       node, &tegra_ictlr_domain_ops,
0335                       lic);
0336     if (!domain) {
0337         pr_err("%pOF: failed to allocated domain\n", node);
0338         err = -ENOMEM;
0339         goto out_unmap;
0340     }
0341 
0342     tegra_ictlr_syscore_init();
0343 
0344     pr_info("%pOF: %d interrupts forwarded to %pOF\n",
0345         node, num_ictlrs * 32, parent);
0346 
0347     return 0;
0348 
0349 out_unmap:
0350     for (i = 0; i < num_ictlrs; i++)
0351         iounmap(lic->base[i]);
0352 out_free:
0353     kfree(lic);
0354     return err;
0355 }
0356 
0357 IRQCHIP_DECLARE(tegra20_ictlr, "nvidia,tegra20-ictlr", tegra_ictlr_init);
0358 IRQCHIP_DECLARE(tegra30_ictlr, "nvidia,tegra30-ictlr", tegra_ictlr_init);
0359 IRQCHIP_DECLARE(tegra210_ictlr, "nvidia,tegra210-ictlr", tegra_ictlr_init);