/*
* This file is subject to the terms and conditions of the GNU General Public
* License. See the file "COPYING" in the main directory of this archive
* for more details.
*
* Copyright (C) 2008 Ralf Baechle (ralf@linux-mips.org)
* Copyright (C) 2012 MIPS Technologies, Inc. All rights reserved.
*/
#include <linux/bitmap.h>
#include <linux/clocksource.h>
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/irqchip.h>
#include <linux/irqchip/mips-gic.h>
#include <linux/of_address.h>
#include <linux/sched.h>
#include <linux/smp.h>
#include <asm/mips-cm.h>
#include <asm/setup.h>
#include <asm/traps.h>
#include <dt-bindings/interrupt-controller/mips-gic.h>
unsigned int gic_present;
struct gic_pcpu_mask {
DECLARE_BITMAP(pcpu_mask, GIC_MAX_INTRS);
};
struct gic_irq_spec {
enum {
GIC_DEVICE,
GIC_IPI
} type;
union {
struct cpumask *ipimask;
unsigned int hwirq;
};
};
static unsigned long __gic_base_addr;
static void __iomem *gic_base;
static struct gic_pcpu_mask pcpu_masks[NR_CPUS];
static DEFINE_SPINLOCK(gic_lock);
static struct irq_domain *gic_irq_domain;
static struct irq_domain *gic_dev_domain;
static struct irq_domain *gic_ipi_domain;
static int gic_shared_intrs;
static int gic_vpes;
static unsigned int gic_cpu_pin;
static unsigned int timer_cpu_pin;
static struct irq_chip gic_level_irq_controller, gic_edge_irq_controller;
DECLARE_BITMAP(ipi_resrv, GIC_MAX_INTRS);
DECLARE_BITMAP(ipi_available, GIC_MAX_INTRS);
static void __gic_irq_dispatch(void);
static inline u32 gic_read32(unsigned int reg)
{
return __raw_readl(gic_base + reg);
}
static inline u64 gic_read64(unsigned int reg)
{
return __raw_readq(gic_base + reg);
}
static inline unsigned long gic_read(unsigned int reg)
{
if (!mips_cm_is64)
return gic_read32(reg);
else
return gic_read64(reg);
}
static inline void gic_write32(unsigned int reg, u32 val)
{
return __raw_writel(val, gic_base + reg);
}
static inline void gic_write64(unsigned int reg, u64 val)
{
return __raw_writeq(val, gic_base + reg);
}
static inline void gic_write(unsigned int reg, unsigned long val)
{
if (!mips_cm_is64)
return gic_write32(reg, (u32)val);
else
return gic_write64(reg, (u64)val);
}
static inline void gic_update_bits(unsigned int reg, unsigned long mask,
unsigned long val)
{
unsigned long regval;
regval = gic_read(reg);
regval &= ~mask;
regval |= val;
gic_write(reg, regval);
}
static inline void gic_reset_mask(unsigned int intr)
{
gic_write(GIC_REG(SHARED, GIC_SH_RMASK) + GIC_INTR_OFS(intr),
1ul << GIC_INTR_BIT(intr));
}
static inline void gic_set_mask(unsigned int intr)
{
gic_write(GIC_REG(SHARED, GIC_SH_SMASK) + GIC_INTR_OFS(intr),
1ul << GIC_INTR_BIT(intr));
}
static inline void gic_set_polarity(unsigned int intr, unsigned int pol)
{
gic_update_bits(GIC_REG(SHARED, GIC_SH_SET_POLARITY) +
GIC_INTR_OFS(intr), 1ul << GIC_INTR_BIT(intr),
(unsigned long)pol << GIC_INTR_BIT(intr));
}
static inline void gic_set_trigger(unsigned int intr, unsigned int trig)
{
gic_update_bits(GIC_REG(SHARED, GIC_SH_SET_TRIGGER) +
GIC_INTR_OFS(intr), 1ul << GIC_INTR_BIT(intr),
(unsigned long)trig << GIC_INTR_BIT(intr));
}
static inline void gic_set_dual_edge(unsigned int intr, unsigned int dual)
{
gic_update_bits(GIC_REG(SHARED, GIC_SH_SET_DUAL) + GIC_INTR_OFS(intr),
1ul << GIC_INTR_BIT(intr),
(unsigned long)dual << GIC_INTR_BIT(intr));
}
static inline void gic_map_to_pin(unsigned int intr, unsigned int pin)
{
gic_write32(GIC_REG(SHARED, GIC_SH_INTR_MAP_TO_PIN_BASE) +
GIC_SH_MAP_TO_PIN(intr), GIC_MAP_TO_PIN_MSK | pin);
}
static inline void gic_map_to_vpe(unsigned int intr, unsigned int vpe)
{
gic_write(GIC_REG(SHARED, GIC_SH_INTR_MAP_TO_VPE_BASE) +
GIC_SH_MAP_TO_VPE_REG_OFF(intr,