linux/drivers/irqchip/irq-sirfsoc.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-or-later
   2/*
   3 * interrupt controller support for CSR SiRFprimaII
   4 *
   5 * Copyright (c) 2011 Cambridge Silicon Radio Limited, a CSR plc group company.
   6 */
   7
   8#include <linux/init.h>
   9#include <linux/io.h>
  10#include <linux/irq.h>
  11#include <linux/of.h>
  12#include <linux/of_address.h>
  13#include <linux/irqchip.h>
  14#include <linux/irqdomain.h>
  15#include <linux/syscore_ops.h>
  16#include <asm/mach/irq.h>
  17#include <asm/exception.h>
  18
  19#define SIRFSOC_INT_RISC_MASK0          0x0018
  20#define SIRFSOC_INT_RISC_MASK1          0x001C
  21#define SIRFSOC_INT_RISC_LEVEL0         0x0020
  22#define SIRFSOC_INT_RISC_LEVEL1         0x0024
  23#define SIRFSOC_INIT_IRQ_ID             0x0038
  24#define SIRFSOC_INT_BASE_OFFSET         0x0004
  25
  26#define SIRFSOC_NUM_IRQS                64
  27#define SIRFSOC_NUM_BANKS               (SIRFSOC_NUM_IRQS / 32)
  28
  29static struct irq_domain *sirfsoc_irqdomain;
  30
  31static void __iomem *sirfsoc_irq_get_regbase(void)
  32{
  33        return (void __iomem __force *)sirfsoc_irqdomain->host_data;
  34}
  35
  36static __init void sirfsoc_alloc_gc(void __iomem *base)
  37{
  38        unsigned int clr = IRQ_NOREQUEST | IRQ_NOPROBE | IRQ_NOAUTOEN;
  39        unsigned int set = IRQ_LEVEL;
  40        struct irq_chip_generic *gc;
  41        struct irq_chip_type *ct;
  42        int i;
  43
  44        irq_alloc_domain_generic_chips(sirfsoc_irqdomain, 32, 1, "irq_sirfsoc",
  45                                       handle_level_irq, clr, set,
  46                                       IRQ_GC_INIT_MASK_CACHE);
  47
  48        for (i = 0; i < SIRFSOC_NUM_BANKS; i++) {
  49                gc = irq_get_domain_generic_chip(sirfsoc_irqdomain, i * 32);
  50                gc->reg_base = base + i * SIRFSOC_INT_BASE_OFFSET;
  51                ct = gc->chip_types;
  52                ct->chip.irq_mask = irq_gc_mask_clr_bit;
  53                ct->chip.irq_unmask = irq_gc_mask_set_bit;
  54                ct->regs.mask = SIRFSOC_INT_RISC_MASK0;
  55        }
  56}
  57
  58static void __exception_irq_entry sirfsoc_handle_irq(struct pt_regs *regs)
  59{
  60        void __iomem *base = sirfsoc_irq_get_regbase();
  61        u32 irqstat;
  62
  63        irqstat = readl_relaxed(base + SIRFSOC_INIT_IRQ_ID);
  64        handle_domain_irq(sirfsoc_irqdomain, irqstat & 0xff, regs);
  65}
  66
  67static int __init sirfsoc_irq_init(struct device_node *np,
  68        struct device_node *parent)
  69{
  70        void __iomem *base = of_iomap(np, 0);
  71        if (!base)
  72                panic("unable to map intc cpu registers\n");
  73
  74        sirfsoc_irqdomain = irq_domain_add_linear(np, SIRFSOC_NUM_IRQS,
  75                                                  &irq_generic_chip_ops, base);
  76        sirfsoc_alloc_gc(base);
  77
  78        writel_relaxed(0, base + SIRFSOC_INT_RISC_LEVEL0);
  79        writel_relaxed(0, base + SIRFSOC_INT_RISC_LEVEL1);
  80
  81        writel_relaxed(0, base + SIRFSOC_INT_RISC_MASK0);
  82        writel_relaxed(0, base + SIRFSOC_INT_RISC_MASK1);
  83
  84        set_handle_irq(sirfsoc_handle_irq);
  85
  86        return 0;
  87}
  88IRQCHIP_DECLARE(sirfsoc_intc, "sirf,prima2-intc", sirfsoc_irq_init);
  89
  90struct sirfsoc_irq_status {
  91        u32 mask0;
  92        u32 mask1;
  93        u32 level0;
  94        u32 level1;
  95};
  96
  97static struct sirfsoc_irq_status sirfsoc_irq_st;
  98
  99static int sirfsoc_irq_suspend(void)
 100{
 101        void __iomem *base = sirfsoc_irq_get_regbase();
 102
 103        sirfsoc_irq_st.mask0 = readl_relaxed(base + SIRFSOC_INT_RISC_MASK0);
 104        sirfsoc_irq_st.mask1 = readl_relaxed(base + SIRFSOC_INT_RISC_MASK1);
 105        sirfsoc_irq_st.level0 = readl_relaxed(base + SIRFSOC_INT_RISC_LEVEL0);
 106        sirfsoc_irq_st.level1 = readl_relaxed(base + SIRFSOC_INT_RISC_LEVEL1);
 107
 108        return 0;
 109}
 110
 111static void sirfsoc_irq_resume(void)
 112{
 113        void __iomem *base = sirfsoc_irq_get_regbase();
 114
 115        writel_relaxed(sirfsoc_irq_st.mask0, base + SIRFSOC_INT_RISC_MASK0);
 116        writel_relaxed(sirfsoc_irq_st.mask1, base + SIRFSOC_INT_RISC_MASK1);
 117        writel_relaxed(sirfsoc_irq_st.level0, base + SIRFSOC_INT_RISC_LEVEL0);
 118        writel_relaxed(sirfsoc_irq_st.level1, base + SIRFSOC_INT_RISC_LEVEL1);
 119}
 120
 121static struct syscore_ops sirfsoc_irq_syscore_ops = {
 122        .suspend        = sirfsoc_irq_suspend,
 123        .resume         = sirfsoc_irq_resume,
 124};
 125
 126static int __init sirfsoc_irq_pm_init(void)
 127{
 128        if (!sirfsoc_irqdomain)
 129                return 0;
 130
 131        register_syscore_ops(&sirfsoc_irq_syscore_ops);
 132        return 0;
 133}
 134device_initcall(sirfsoc_irq_pm_init);
 135