mirror of
https://github.com/rd-stuffs/msm-4.14.git
synced 2025-02-20 11:45:48 +08:00
ARM: EXYNOS: Add irq_domain support for interrupt combiner
Add irq_domain support for hardware interrupts of the interrupt combiner. The hardware interrupts of all the instances of the combiner are grouped in a single irq_domain. Cc: Grant Likely <grant.likely@secretlab.ca> Signed-off-by: Thomas Abraham <thomas.abraham@linaro.org> Acked-by: Rob Herring <rob.herring@calxeda.com> Signed-off-by: Kukjin Kim <kgene.kim@samsung.com>
This commit is contained in:
parent
9ee6af9c3f
commit
1e60bc0b5f
@ -19,6 +19,8 @@
|
|||||||
#include <linux/serial_core.h>
|
#include <linux/serial_core.h>
|
||||||
#include <linux/of.h>
|
#include <linux/of.h>
|
||||||
#include <linux/of_irq.h>
|
#include <linux/of_irq.h>
|
||||||
|
#include <linux/export.h>
|
||||||
|
#include <linux/irqdomain.h>
|
||||||
|
|
||||||
#include <asm/proc-fns.h>
|
#include <asm/proc-fns.h>
|
||||||
#include <asm/exception.h>
|
#include <asm/exception.h>
|
||||||
@ -399,6 +401,7 @@ struct combiner_chip_data {
|
|||||||
void __iomem *base;
|
void __iomem *base;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static struct irq_domain *combiner_irq_domain;
|
||||||
static struct combiner_chip_data combiner_data[MAX_COMBINER_NR];
|
static struct combiner_chip_data combiner_data[MAX_COMBINER_NR];
|
||||||
|
|
||||||
static inline void __iomem *combiner_base(struct irq_data *data)
|
static inline void __iomem *combiner_base(struct irq_data *data)
|
||||||
@ -411,14 +414,14 @@ static inline void __iomem *combiner_base(struct irq_data *data)
|
|||||||
|
|
||||||
static void combiner_mask_irq(struct irq_data *data)
|
static void combiner_mask_irq(struct irq_data *data)
|
||||||
{
|
{
|
||||||
u32 mask = 1 << (data->irq % 32);
|
u32 mask = 1 << (data->hwirq % 32);
|
||||||
|
|
||||||
__raw_writel(mask, combiner_base(data) + COMBINER_ENABLE_CLEAR);
|
__raw_writel(mask, combiner_base(data) + COMBINER_ENABLE_CLEAR);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void combiner_unmask_irq(struct irq_data *data)
|
static void combiner_unmask_irq(struct irq_data *data)
|
||||||
{
|
{
|
||||||
u32 mask = 1 << (data->irq % 32);
|
u32 mask = 1 << (data->hwirq % 32);
|
||||||
|
|
||||||
__raw_writel(mask, combiner_base(data) + COMBINER_ENABLE_SET);
|
__raw_writel(mask, combiner_base(data) + COMBINER_ENABLE_SET);
|
||||||
}
|
}
|
||||||
@ -474,36 +477,58 @@ static void __init combiner_cascade_irq(unsigned int combiner_nr, unsigned int i
|
|||||||
irq_set_chained_handler(irq, combiner_handle_cascade_irq);
|
irq_set_chained_handler(irq, combiner_handle_cascade_irq);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void __init combiner_init(unsigned int combiner_nr, void __iomem *base,
|
static void __init combiner_init_one(unsigned int combiner_nr,
|
||||||
unsigned int irq_start)
|
void __iomem *base)
|
||||||
{
|
{
|
||||||
unsigned int i;
|
|
||||||
unsigned int max_nr;
|
|
||||||
|
|
||||||
if (soc_is_exynos5250())
|
|
||||||
max_nr = EXYNOS5_MAX_COMBINER_NR;
|
|
||||||
else
|
|
||||||
max_nr = EXYNOS4_MAX_COMBINER_NR;
|
|
||||||
|
|
||||||
if (combiner_nr >= max_nr)
|
|
||||||
BUG();
|
|
||||||
|
|
||||||
combiner_data[combiner_nr].base = base;
|
combiner_data[combiner_nr].base = base;
|
||||||
combiner_data[combiner_nr].irq_offset = irq_start;
|
combiner_data[combiner_nr].irq_offset = irq_find_mapping(
|
||||||
|
combiner_irq_domain, combiner_nr * MAX_IRQ_IN_COMBINER);
|
||||||
combiner_data[combiner_nr].irq_mask = 0xff << ((combiner_nr % 4) << 3);
|
combiner_data[combiner_nr].irq_mask = 0xff << ((combiner_nr % 4) << 3);
|
||||||
|
|
||||||
/* Disable all interrupts */
|
/* Disable all interrupts */
|
||||||
|
|
||||||
__raw_writel(combiner_data[combiner_nr].irq_mask,
|
__raw_writel(combiner_data[combiner_nr].irq_mask,
|
||||||
base + COMBINER_ENABLE_CLEAR);
|
base + COMBINER_ENABLE_CLEAR);
|
||||||
|
}
|
||||||
|
|
||||||
/* Setup the Linux IRQ subsystem */
|
static int combiner_irq_domain_map(struct irq_domain *d, unsigned int irq,
|
||||||
|
irq_hw_number_t hw)
|
||||||
|
{
|
||||||
|
irq_set_chip_and_handler(irq, &combiner_chip, handle_level_irq);
|
||||||
|
irq_set_chip_data(irq, &combiner_data[hw >> 3]);
|
||||||
|
set_irq_flags(irq, IRQF_VALID | IRQF_PROBE);
|
||||||
|
|
||||||
for (i = irq_start; i < combiner_data[combiner_nr].irq_offset
|
return 0;
|
||||||
+ MAX_IRQ_IN_COMBINER; i++) {
|
}
|
||||||
irq_set_chip_and_handler(i, &combiner_chip, handle_level_irq);
|
|
||||||
irq_set_chip_data(i, &combiner_data[combiner_nr]);
|
static struct irq_domain_ops combiner_irq_domain_ops = {
|
||||||
set_irq_flags(i, IRQF_VALID | IRQF_PROBE);
|
.map = combiner_irq_domain_map,
|
||||||
|
};
|
||||||
|
|
||||||
|
void __init combiner_init(void __iomem *combiner_base, struct device_node *np)
|
||||||
|
{
|
||||||
|
int i, irq_base;
|
||||||
|
unsigned int max_nr, nr_irq;
|
||||||
|
|
||||||
|
max_nr = soc_is_exynos5250() ? EXYNOS5_MAX_COMBINER_NR :
|
||||||
|
EXYNOS4_MAX_COMBINER_NR;
|
||||||
|
nr_irq = max_nr * MAX_IRQ_IN_COMBINER;
|
||||||
|
|
||||||
|
irq_base = irq_alloc_descs(COMBINER_IRQ(0, 0), 1, nr_irq, 0);
|
||||||
|
if (IS_ERR_VALUE(irq_base)) {
|
||||||
|
irq_base = COMBINER_IRQ(0, 0);
|
||||||
|
pr_warning("%s: irq desc alloc failed. Continuing with %d as linux irq base\n", __func__, irq_base);
|
||||||
|
}
|
||||||
|
|
||||||
|
combiner_irq_domain = irq_domain_add_legacy(np, nr_irq, irq_base, 0,
|
||||||
|
&combiner_irq_domain_ops, &combiner_data);
|
||||||
|
if (WARN_ON(!combiner_irq_domain)) {
|
||||||
|
pr_warning("%s: irq domain init failed\n", __func__);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < max_nr; i++) {
|
||||||
|
combiner_init_one(i, combiner_base + (i >> 2) * 0x10);
|
||||||
|
combiner_cascade_irq(i, IRQ_SPI(i));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -516,7 +541,6 @@ static const struct of_device_id exynos4_dt_irq_match[] = {
|
|||||||
|
|
||||||
void __init exynos4_init_irq(void)
|
void __init exynos4_init_irq(void)
|
||||||
{
|
{
|
||||||
int irq;
|
|
||||||
unsigned int gic_bank_offset;
|
unsigned int gic_bank_offset;
|
||||||
|
|
||||||
gic_bank_offset = soc_is_exynos4412() ? 0x4000 : 0x8000;
|
gic_bank_offset = soc_is_exynos4412() ? 0x4000 : 0x8000;
|
||||||
@ -528,12 +552,7 @@ void __init exynos4_init_irq(void)
|
|||||||
of_irq_init(exynos4_dt_irq_match);
|
of_irq_init(exynos4_dt_irq_match);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
for (irq = 0; irq < EXYNOS4_MAX_COMBINER_NR; irq++) {
|
combiner_init(S5P_VA_COMBINER_BASE, NULL);
|
||||||
|
|
||||||
combiner_init(irq, (void __iomem *)S5P_VA_COMBINER(irq),
|
|
||||||
COMBINER_IRQ(irq, 0));
|
|
||||||
combiner_cascade_irq(irq, IRQ_SPI(irq));
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The parameters of s5p_init_irq() are for VIC init.
|
* The parameters of s5p_init_irq() are for VIC init.
|
||||||
@ -545,17 +564,10 @@ void __init exynos4_init_irq(void)
|
|||||||
|
|
||||||
void __init exynos5_init_irq(void)
|
void __init exynos5_init_irq(void)
|
||||||
{
|
{
|
||||||
int irq;
|
|
||||||
|
|
||||||
#ifdef CONFIG_OF
|
#ifdef CONFIG_OF
|
||||||
of_irq_init(exynos4_dt_irq_match);
|
of_irq_init(exynos4_dt_irq_match);
|
||||||
#endif
|
#endif
|
||||||
|
combiner_init(S5P_VA_COMBINER_BASE, NULL);
|
||||||
for (irq = 0; irq < EXYNOS5_MAX_COMBINER_NR; irq++) {
|
|
||||||
combiner_init(irq, (void __iomem *)S5P_VA_COMBINER(irq),
|
|
||||||
COMBINER_IRQ(irq, 0));
|
|
||||||
combiner_cascade_irq(irq, IRQ_SPI(irq));
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The parameters of s5p_init_irq() are for VIC init.
|
* The parameters of s5p_init_irq() are for VIC init.
|
||||||
|
Loading…
x
Reference in New Issue
Block a user