ARM: tegra: irq: add wake up handling
Add the wake up handling for legacy irq controller, and using IRQCHIP_MASK_ON_SUSPEND for wake irq handling. Based on the work by: Varun Wadekar <vwadekar@nvidia.com> Signed-off-by: Joseph Lo <josephl@nvidia.com> Signed-off-by: Stephen Warren <swarren@nvidia.com>
This commit is contained in:
parent
203f31cb86
commit
e307cc8941
|
@ -33,6 +33,7 @@
|
||||||
#include "common.h"
|
#include "common.h"
|
||||||
#include "fuse.h"
|
#include "fuse.h"
|
||||||
#include "iomap.h"
|
#include "iomap.h"
|
||||||
|
#include "irq.h"
|
||||||
#include "pmc.h"
|
#include "pmc.h"
|
||||||
#include "apbio.h"
|
#include "apbio.h"
|
||||||
#include "sleep.h"
|
#include "sleep.h"
|
||||||
|
@ -64,6 +65,7 @@ void __init tegra_dt_init_irq(void)
|
||||||
tegra_pmc_init();
|
tegra_pmc_init();
|
||||||
tegra_init_irq();
|
tegra_init_irq();
|
||||||
irqchip_init();
|
irqchip_init();
|
||||||
|
tegra_legacy_irq_syscore_init();
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
* Author:
|
* Author:
|
||||||
* Colin Cross <ccross@android.com>
|
* Colin Cross <ccross@android.com>
|
||||||
*
|
*
|
||||||
* Copyright (C) 2010, NVIDIA Corporation
|
* Copyright (C) 2010,2013, NVIDIA Corporation
|
||||||
*
|
*
|
||||||
* This software is licensed under the terms of the GNU General Public
|
* This software is licensed under the terms of the GNU General Public
|
||||||
* License version 2, as published by the Free Software Foundation, and
|
* License version 2, as published by the Free Software Foundation, and
|
||||||
|
@ -23,6 +23,7 @@
|
||||||
#include <linux/io.h>
|
#include <linux/io.h>
|
||||||
#include <linux/of.h>
|
#include <linux/of.h>
|
||||||
#include <linux/irqchip/arm-gic.h>
|
#include <linux/irqchip/arm-gic.h>
|
||||||
|
#include <linux/syscore_ops.h>
|
||||||
|
|
||||||
#include "board.h"
|
#include "board.h"
|
||||||
#include "iomap.h"
|
#include "iomap.h"
|
||||||
|
@ -43,6 +44,7 @@
|
||||||
#define ICTLR_COP_IEP_CLASS 0x3c
|
#define ICTLR_COP_IEP_CLASS 0x3c
|
||||||
|
|
||||||
#define FIRST_LEGACY_IRQ 32
|
#define FIRST_LEGACY_IRQ 32
|
||||||
|
#define TEGRA_MAX_NUM_ICTLRS 5
|
||||||
|
|
||||||
#define SGI_MASK 0xFFFF
|
#define SGI_MASK 0xFFFF
|
||||||
|
|
||||||
|
@ -56,6 +58,15 @@ static void __iomem *ictlr_reg_base[] = {
|
||||||
IO_ADDRESS(TEGRA_QUINARY_ICTLR_BASE),
|
IO_ADDRESS(TEGRA_QUINARY_ICTLR_BASE),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#ifdef CONFIG_PM_SLEEP
|
||||||
|
static u32 cop_ier[TEGRA_MAX_NUM_ICTLRS];
|
||||||
|
static u32 cop_iep[TEGRA_MAX_NUM_ICTLRS];
|
||||||
|
static u32 cpu_ier[TEGRA_MAX_NUM_ICTLRS];
|
||||||
|
static u32 cpu_iep[TEGRA_MAX_NUM_ICTLRS];
|
||||||
|
|
||||||
|
static u32 ictlr_wake_mask[TEGRA_MAX_NUM_ICTLRS];
|
||||||
|
#endif
|
||||||
|
|
||||||
bool tegra_pending_sgi(void)
|
bool tegra_pending_sgi(void)
|
||||||
{
|
{
|
||||||
u32 pending_set;
|
u32 pending_set;
|
||||||
|
@ -125,6 +136,87 @@ static int tegra_retrigger(struct irq_data *d)
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef CONFIG_PM_SLEEP
|
||||||
|
static int tegra_set_wake(struct irq_data *d, unsigned int enable)
|
||||||
|
{
|
||||||
|
u32 irq = d->irq;
|
||||||
|
u32 index, mask;
|
||||||
|
|
||||||
|
if (irq < FIRST_LEGACY_IRQ ||
|
||||||
|
irq >= FIRST_LEGACY_IRQ + num_ictlrs * 32)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
index = ((irq - FIRST_LEGACY_IRQ) / 32);
|
||||||
|
mask = BIT((irq - FIRST_LEGACY_IRQ) % 32);
|
||||||
|
if (enable)
|
||||||
|
ictlr_wake_mask[index] |= mask;
|
||||||
|
else
|
||||||
|
ictlr_wake_mask[index] &= ~mask;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int tegra_legacy_irq_suspend(void)
|
||||||
|
{
|
||||||
|
unsigned long flags;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
local_irq_save(flags);
|
||||||
|
for (i = 0; i < num_ictlrs; i++) {
|
||||||
|
void __iomem *ictlr = ictlr_reg_base[i];
|
||||||
|
/* Save interrupt state */
|
||||||
|
cpu_ier[i] = readl_relaxed(ictlr + ICTLR_CPU_IER);
|
||||||
|
cpu_iep[i] = readl_relaxed(ictlr + ICTLR_CPU_IEP_CLASS);
|
||||||
|
cop_ier[i] = readl_relaxed(ictlr + ICTLR_COP_IER);
|
||||||
|
cop_iep[i] = readl_relaxed(ictlr + ICTLR_COP_IEP_CLASS);
|
||||||
|
|
||||||
|
/* Disable COP interrupts */
|
||||||
|
writel_relaxed(~0ul, ictlr + ICTLR_COP_IER_CLR);
|
||||||
|
|
||||||
|
/* Disable CPU interrupts */
|
||||||
|
writel_relaxed(~0ul, ictlr + ICTLR_CPU_IER_CLR);
|
||||||
|
|
||||||
|
/* Enable the wakeup sources of ictlr */
|
||||||
|
writel_relaxed(ictlr_wake_mask[i], ictlr + ICTLR_CPU_IER_SET);
|
||||||
|
}
|
||||||
|
local_irq_restore(flags);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void tegra_legacy_irq_resume(void)
|
||||||
|
{
|
||||||
|
unsigned long flags;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
local_irq_save(flags);
|
||||||
|
for (i = 0; i < num_ictlrs; i++) {
|
||||||
|
void __iomem *ictlr = ictlr_reg_base[i];
|
||||||
|
writel_relaxed(cpu_iep[i], ictlr + ICTLR_CPU_IEP_CLASS);
|
||||||
|
writel_relaxed(~0ul, ictlr + ICTLR_CPU_IER_CLR);
|
||||||
|
writel_relaxed(cpu_ier[i], ictlr + ICTLR_CPU_IER_SET);
|
||||||
|
writel_relaxed(cop_iep[i], ictlr + ICTLR_COP_IEP_CLASS);
|
||||||
|
writel_relaxed(~0ul, ictlr + ICTLR_COP_IER_CLR);
|
||||||
|
writel_relaxed(cop_ier[i], ictlr + ICTLR_COP_IER_SET);
|
||||||
|
}
|
||||||
|
local_irq_restore(flags);
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct syscore_ops tegra_legacy_irq_syscore_ops = {
|
||||||
|
.suspend = tegra_legacy_irq_suspend,
|
||||||
|
.resume = tegra_legacy_irq_resume,
|
||||||
|
};
|
||||||
|
|
||||||
|
int tegra_legacy_irq_syscore_init(void)
|
||||||
|
{
|
||||||
|
register_syscore_ops(&tegra_legacy_irq_syscore_ops);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
#define tegra_set_wake NULL
|
||||||
|
#endif
|
||||||
|
|
||||||
void __init tegra_init_irq(void)
|
void __init tegra_init_irq(void)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
|
@ -150,6 +242,8 @@ void __init tegra_init_irq(void)
|
||||||
gic_arch_extn.irq_mask = tegra_mask;
|
gic_arch_extn.irq_mask = tegra_mask;
|
||||||
gic_arch_extn.irq_unmask = tegra_unmask;
|
gic_arch_extn.irq_unmask = tegra_unmask;
|
||||||
gic_arch_extn.irq_retrigger = tegra_retrigger;
|
gic_arch_extn.irq_retrigger = tegra_retrigger;
|
||||||
|
gic_arch_extn.irq_set_wake = tegra_set_wake;
|
||||||
|
gic_arch_extn.flags = IRQCHIP_MASK_ON_SUSPEND;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Check if there is a devicetree present, since the GIC will be
|
* Check if there is a devicetree present, since the GIC will be
|
||||||
|
|
|
@ -19,4 +19,10 @@
|
||||||
|
|
||||||
bool tegra_pending_sgi(void);
|
bool tegra_pending_sgi(void);
|
||||||
|
|
||||||
|
#ifdef CONFIG_PM_SLEEP
|
||||||
|
int tegra_legacy_irq_syscore_init(void);
|
||||||
|
#else
|
||||||
|
static inline int tegra_legacy_irq_syscore_init(void) { return 0; }
|
||||||
|
#endif
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
Loading…
Reference in New Issue