linux/arch/arm/mach-pxa/irq.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-only
   2/*
   3 *  linux/arch/arm/mach-pxa/irq.c
   4 *
   5 *  Generic PXA IRQ handling
   6 *
   7 *  Author:     Nicolas Pitre
   8 *  Created:    Jun 15, 2001
   9 *  Copyright:  MontaVista Software Inc.
  10 */
  11#include <linux/bitops.h>
  12#include <linux/init.h>
  13#include <linux/module.h>
  14#include <linux/interrupt.h>
  15#include <linux/syscore_ops.h>
  16#include <linux/io.h>
  17#include <linux/irq.h>
  18#include <linux/of_address.h>
  19#include <linux/of_irq.h>
  20
  21#include <asm/exception.h>
  22
  23#include <mach/hardware.h>
  24#include <mach/irqs.h>
  25
  26#include "generic.h"
  27
  28#define ICIP                    (0x000)
  29#define ICMR                    (0x004)
  30#define ICLR                    (0x008)
  31#define ICFR                    (0x00c)
  32#define ICPR                    (0x010)
  33#define ICCR                    (0x014)
  34#define ICHP                    (0x018)
  35#define IPR(i)                  (((i) < 32) ? (0x01c + ((i) << 2)) :            \
  36                                ((i) < 64) ? (0x0b0 + (((i) - 32) << 2)) :      \
  37                                      (0x144 + (((i) - 64) << 2)))
  38#define ICHP_VAL_IRQ            (1 << 31)
  39#define ICHP_IRQ(i)             (((i) >> 16) & 0x7fff)
  40#define IPR_VALID               (1 << 31)
  41
  42#define MAX_INTERNAL_IRQS       128
  43
  44/*
  45 * This is for peripheral IRQs internal to the PXA chip.
  46 */
  47
  48static void __iomem *pxa_irq_base;
  49static int pxa_internal_irq_nr;
  50static bool cpu_has_ipr;
  51static struct irq_domain *pxa_irq_domain;
  52
  53static inline void __iomem *irq_base(int i)
  54{
  55        static unsigned long phys_base_offset[] = {
  56                0x0,
  57                0x9c,
  58                0x130,
  59        };
  60
  61        return pxa_irq_base + phys_base_offset[i];
  62}
  63
  64void pxa_mask_irq(struct irq_data *d)
  65{
  66        void __iomem *base = irq_data_get_irq_chip_data(d);
  67        irq_hw_number_t irq = irqd_to_hwirq(d);
  68        uint32_t icmr = __raw_readl(base + ICMR);
  69
  70        icmr &= ~BIT(irq & 0x1f);
  71        __raw_writel(icmr, base + ICMR);
  72}
  73
  74void pxa_unmask_irq(struct irq_data *d)
  75{
  76        void __iomem *base = irq_data_get_irq_chip_data(d);
  77        irq_hw_number_t irq = irqd_to_hwirq(d);
  78        uint32_t icmr = __raw_readl(base + ICMR);
  79
  80        icmr |= BIT(irq & 0x1f);
  81        __raw_writel(icmr, base + ICMR);
  82}
  83
  84static struct irq_chip pxa_internal_irq_chip = {
  85        .name           = "SC",
  86        .irq_ack        = pxa_mask_irq,
  87        .irq_mask       = pxa_mask_irq,
  88        .irq_unmask     = pxa_unmask_irq,
  89};
  90
  91asmlinkage void __exception_irq_entry icip_handle_irq(struct pt_regs *regs)
  92{
  93        uint32_t icip, icmr, mask;
  94
  95        do {
  96                icip = __raw_readl(pxa_irq_base + ICIP);
  97                icmr = __raw_readl(pxa_irq_base + ICMR);
  98                mask = icip & icmr;
  99
 100                if (mask == 0)
 101                        break;
 102
 103                handle_IRQ(PXA_IRQ(fls(mask) - 1), regs);
 104        } while (1);
 105}
 106
 107asmlinkage void __exception_irq_entry ichp_handle_irq(struct pt_regs *regs)
 108{
 109        uint32_t ichp;
 110
 111        do {
 112                __asm__ __volatile__("mrc p6, 0, %0, c5, c0, 0\n": "=r"(ichp));
 113
 114                if ((ichp & ICHP_VAL_IRQ) == 0)
 115                        break;
 116
 117                handle_IRQ(PXA_IRQ(ICHP_IRQ(ichp)), regs);
 118        } while (1);
 119}
 120
 121static int pxa_irq_map(struct irq_domain *h, unsigned int virq,
 122                       irq_hw_number_t hw)
 123{
 124        void __iomem *base = irq_base(hw / 32);
 125
 126        /* initialize interrupt priority */
 127        if (cpu_has_ipr)
 128                __raw_writel(hw | IPR_VALID, pxa_irq_base + IPR(hw));
 129
 130        irq_set_chip_and_handler(virq, &pxa_internal_irq_chip,
 131                                 handle_level_irq);
 132        irq_set_chip_data(virq, base);
 133
 134        return 0;
 135}
 136
 137static const struct irq_domain_ops pxa_irq_ops = {
 138        .map    = pxa_irq_map,
 139        .xlate  = irq_domain_xlate_onecell,
 140};
 141
 142static __init void
 143pxa_init_irq_common(struct device_node *node, int irq_nr,
 144                    int (*fn)(struct irq_data *, unsigned int))
 145{
 146        int n;
 147
 148        pxa_internal_irq_nr = irq_nr;
 149        pxa_irq_domain = irq_domain_add_legacy(node, irq_nr,
 150                                               PXA_IRQ(0), 0,
 151                                               &pxa_irq_ops, NULL);
 152        if (!pxa_irq_domain)
 153                panic("Unable to add PXA IRQ domain\n");
 154        irq_set_default_host(pxa_irq_domain);
 155
 156        for (n = 0; n < irq_nr; n += 32) {
 157                void __iomem *base = irq_base(n >> 5);
 158
 159                __raw_writel(0, base + ICMR);   /* disable all IRQs */
 160                __raw_writel(0, base + ICLR);   /* all IRQs are IRQ, not FIQ */
 161        }
 162        /* only unmasked interrupts kick us out of idle */
 163        __raw_writel(1, irq_base(0) + ICCR);
 164
 165        pxa_internal_irq_chip.irq_set_wake = fn;
 166}
 167
 168void __init pxa_init_irq(int irq_nr, int (*fn)(struct irq_data *, unsigned int))
 169{
 170        BUG_ON(irq_nr > MAX_INTERNAL_IRQS);
 171
 172        pxa_irq_base = io_p2v(0x40d00000);
 173        cpu_has_ipr = !cpu_is_pxa25x();
 174        pxa_init_irq_common(NULL, irq_nr, fn);
 175}
 176
 177#ifdef CONFIG_PM
 178static unsigned long saved_icmr[MAX_INTERNAL_IRQS/32];
 179static unsigned long saved_ipr[MAX_INTERNAL_IRQS];
 180
 181static int pxa_irq_suspend(void)
 182{
 183        int i;
 184
 185        for (i = 0; i < DIV_ROUND_UP(pxa_internal_irq_nr, 32); i++) {
 186                void __iomem *base = irq_base(i);
 187
 188                saved_icmr[i] = __raw_readl(base + ICMR);
 189                __raw_writel(0, base + ICMR);
 190        }
 191
 192        if (cpu_has_ipr) {
 193                for (i = 0; i < pxa_internal_irq_nr; i++)
 194                        saved_ipr[i] = __raw_readl(pxa_irq_base + IPR(i));
 195        }
 196
 197        return 0;
 198}
 199
 200static void pxa_irq_resume(void)
 201{
 202        int i;
 203
 204        for (i = 0; i < DIV_ROUND_UP(pxa_internal_irq_nr, 32); i++) {
 205                void __iomem *base = irq_base(i);
 206
 207                __raw_writel(saved_icmr[i], base + ICMR);
 208                __raw_writel(0, base + ICLR);
 209        }
 210
 211        if (cpu_has_ipr)
 212                for (i = 0; i < pxa_internal_irq_nr; i++)
 213                        __raw_writel(saved_ipr[i], pxa_irq_base + IPR(i));
 214
 215        __raw_writel(1, pxa_irq_base + ICCR);
 216}
 217#else
 218#define pxa_irq_suspend         NULL
 219#define pxa_irq_resume          NULL
 220#endif
 221
 222struct syscore_ops pxa_irq_syscore_ops = {
 223        .suspend        = pxa_irq_suspend,
 224        .resume         = pxa_irq_resume,
 225};
 226
 227#ifdef CONFIG_OF
 228static const struct of_device_id intc_ids[] __initconst = {
 229        { .compatible = "marvell,pxa-intc", },
 230        {}
 231};
 232
 233void __init pxa_dt_irq_init(int (*fn)(struct irq_data *, unsigned int))
 234{
 235        struct device_node *node;
 236        struct resource res;
 237        int ret;
 238
 239        node = of_find_matching_node(NULL, intc_ids);
 240        if (!node) {
 241                pr_err("Failed to find interrupt controller in arch-pxa\n");
 242                return;
 243        }
 244
 245        ret = of_property_read_u32(node, "marvell,intc-nr-irqs",
 246                                   &pxa_internal_irq_nr);
 247        if (ret) {
 248                pr_err("Not found marvell,intc-nr-irqs property\n");
 249                return;
 250        }
 251
 252        ret = of_address_to_resource(node, 0, &res);
 253        if (ret < 0) {
 254                pr_err("No registers defined for node\n");
 255                return;
 256        }
 257        pxa_irq_base = io_p2v(res.start);
 258
 259        if (of_find_property(node, "marvell,intc-priority", NULL))
 260                cpu_has_ipr = 1;
 261
 262        ret = irq_alloc_descs(-1, 0, pxa_internal_irq_nr, 0);
 263        if (ret < 0) {
 264                pr_err("Failed to allocate IRQ numbers\n");
 265                return;
 266        }
 267
 268        pxa_init_irq_common(node, pxa_internal_irq_nr, fn);
 269}
 270#endif /* CONFIG_OF */
 271