Commit eec3fa5d authored by Philippe Gerum's avatar Philippe Gerum

ARM: imx/gpc: ipipe: enable interrupt pipelining

parent adb60c02
......@@ -13,6 +13,7 @@
#include <linux/io.h>
#include <linux/irq.h>
#include <linux/irqchip.h>
#include <linux/ipipe.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/of_irq.h>
......@@ -36,6 +37,7 @@
static void __iomem *gpc_base;
static u32 gpc_wake_irqs[IMR_NUM];
static u32 gpc_saved_imrs[IMR_NUM];
static IPIPE_DEFINE_RAW_SPINLOCK(gpc_lock);
void imx_gpc_set_arm_power_up_timing(u32 sw2iso, u32 sw)
{
......@@ -68,28 +70,38 @@ void imx_gpc_set_l2_mem_power_in_lpm(bool power_off)
void imx_gpc_pre_suspend(bool arm_power_off)
{
void __iomem *reg_imr1 = gpc_base + GPC_IMR1;
unsigned long flags;
int i;
/* Tell GPC to power off ARM core when suspend */
if (arm_power_off)
imx_gpc_set_arm_power_in_lpm(arm_power_off);
flags = hard_cond_local_irq_save();
for (i = 0; i < IMR_NUM; i++) {
gpc_saved_imrs[i] = readl_relaxed(reg_imr1 + i * 4);
writel_relaxed(~gpc_wake_irqs[i], reg_imr1 + i * 4);
}
hard_cond_local_irq_restore(flags);
}
void imx_gpc_post_resume(void)
{
void __iomem *reg_imr1 = gpc_base + GPC_IMR1;
unsigned long flags;
int i;
/* Keep ARM core powered on for other low-power modes */
imx_gpc_set_arm_power_in_lpm(false);
flags = hard_cond_local_irq_save();
for (i = 0; i < IMR_NUM; i++)
writel_relaxed(gpc_saved_imrs[i], reg_imr1 + i * 4);
hard_cond_local_irq_restore(flags);
}
static int imx_gpc_irq_set_wake(struct irq_data *d, unsigned int on)
......@@ -111,22 +123,31 @@ static int imx_gpc_irq_set_wake(struct irq_data *d, unsigned int on)
void imx_gpc_mask_all(void)
{
void __iomem *reg_imr1 = gpc_base + GPC_IMR1;
unsigned long flags;
int i;
flags = hard_cond_local_irq_save();
for (i = 0; i < IMR_NUM; i++) {
gpc_saved_imrs[i] = readl_relaxed(reg_imr1 + i * 4);
writel_relaxed(~0, reg_imr1 + i * 4);
}
hard_cond_local_irq_restore(flags);
}
void imx_gpc_restore_all(void)
{
void __iomem *reg_imr1 = gpc_base + GPC_IMR1;
unsigned long flags;
int i;
flags = hard_cond_local_irq_save();
for (i = 0; i < IMR_NUM; i++)
writel_relaxed(gpc_saved_imrs[i], reg_imr1 + i * 4);
hard_cond_local_irq_restore(flags);
}
void imx_gpc_hwirq_unmask(unsigned int hwirq)
......@@ -153,16 +174,49 @@ void imx_gpc_hwirq_mask(unsigned int hwirq)
static void imx_gpc_irq_unmask(struct irq_data *d)
{
unsigned long flags;
raw_spin_lock_irqsave(&gpc_lock, flags);
imx_gpc_hwirq_unmask(d->hwirq);
__ipipe_spin_unlock_irqbegin(&gpc_lock);
irq_chip_unmask_parent(d);
__ipipe_spin_unlock_irqcomplete(flags);
}
static void imx_gpc_irq_mask(struct irq_data *d)
{
unsigned long flags;
raw_spin_lock_irqsave(&gpc_lock, flags);
/* Parent IC will handle virtual locking */
imx_gpc_hwirq_mask(d->hwirq);
__ipipe_spin_unlock_irqbegin(&gpc_lock);
irq_chip_mask_parent(d);
__ipipe_spin_unlock_irqcomplete(flags);
}
#ifdef CONFIG_IPIPE
static void imx_gpc_hold_irq(struct irq_data *d)
{
raw_spin_lock(&gpc_lock);
imx_gpc_hwirq_mask(d->hwirq);
raw_spin_unlock(&gpc_lock);
irq_chip_hold_parent(d);
}
static void imx_gpc_release_irq(struct irq_data *d)
{
unsigned long flags;
raw_spin_lock_irqsave(&gpc_lock, flags);
imx_gpc_hwirq_unmask(d->hwirq);
raw_spin_unlock_irqrestore(&gpc_lock, flags);
irq_chip_release_parent(d);
}
#endif /* CONFIG_IPIPE */
static struct irq_chip imx_gpc_chip = {
.name = "GPC",
.irq_eoi = irq_chip_eoi_parent,
......@@ -174,6 +228,11 @@ static struct irq_chip imx_gpc_chip = {
#ifdef CONFIG_SMP
.irq_set_affinity = irq_chip_set_affinity_parent,
#endif
#ifdef CONFIG_IPIPE
.irq_hold = imx_gpc_hold_irq,
.irq_release = imx_gpc_release_irq,
#endif
.flags = IRQCHIP_PIPELINE_SAFE,
};
static int imx_gpc_domain_translate(struct irq_domain *d,
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment