Skip to content

Commit

Permalink
Merge branch 'omap/omap4' into next/pm
Browse files Browse the repository at this point in the history
  • Loading branch information
Olof Johansson committed Dec 11, 2011
2 parents 5611cc4 + eb3e1d9 commit 05da34d
Show file tree
Hide file tree
Showing 362 changed files with 3,763 additions and 3,169 deletions.
11 changes: 5 additions & 6 deletions Documentation/arm/memory.txt
Original file line number Diff line number Diff line change
Expand Up @@ -51,15 +51,14 @@ ffc00000 ffefffff DMA memory mapping region. Memory returned
ff000000 ffbfffff Reserved for future expansion of DMA
mapping region.

VMALLOC_END feffffff Free for platform use, recommended.
VMALLOC_END must be aligned to a 2MB
boundary.

VMALLOC_START VMALLOC_END-1 vmalloc() / ioremap() space.
Memory returned by vmalloc/ioremap will
be dynamically placed in this region.
VMALLOC_START may be based upon the value
of the high_memory variable.
Machine specific static mappings are also
located here through iotable_init().
VMALLOC_START is based upon the value
of the high_memory variable, and VMALLOC_END
is equal to 0xff000000.

PAGE_OFFSET high_memory-1 Kernel direct-mapped RAM region.
This maps the platforms RAM, and typically
Expand Down
4 changes: 4 additions & 0 deletions Documentation/devicetree/bindings/arm/gic.txt
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,10 @@ Optional
- interrupts : Interrupt source of the parent interrupt controller. Only
present on secondary GICs.

- cpu-offset : per-cpu offset within the distributor and cpu interface
regions, used when the GIC doesn't have banked registers. The offset is
cpu-offset * cpu-nr.

Example:

intc: interrupt-controller@fff11000 {
Expand Down
29 changes: 29 additions & 0 deletions Documentation/devicetree/bindings/arm/vic.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
* ARM Vectored Interrupt Controller

One or more Vectored Interrupt Controllers (VIC's) can be connected in an ARM
system for interrupt routing. For multiple controllers they can either be
nested or have the outputs wire-OR'd together.

Required properties:

- compatible : should be one of
"arm,pl190-vic"
"arm,pl192-vic"
- interrupt-controller : Identifies the node as an interrupt controller
- #interrupt-cells : The number of cells to define the interrupts. Must be 1 as
the VIC has no configuration options for interrupt sources. The cell is a u32
and defines the interrupt number.
- reg : The register bank for the VIC.

Optional properties:

- interrupts : Interrupt source for parent controllers if the VIC is nested.

Example:

vic0: interrupt-controller@60000 {
compatible = "arm,pl192-vic";
interrupt-controller;
#interrupt-cells = <1>;
reg = <0x60000 0x1000>;
};
6 changes: 6 additions & 0 deletions arch/arm/common/Kconfig
Original file line number Diff line number Diff line change
@@ -1,8 +1,14 @@
config ARM_GIC
select IRQ_DOMAIN
select MULTI_IRQ_HANDLER
bool

config GIC_NON_BANKED
bool

config ARM_VIC
select IRQ_DOMAIN
select MULTI_IRQ_HANDLER
bool

config ARM_VIC_NR
Expand Down
165 changes: 141 additions & 24 deletions arch/arm/common/gic.c
Original file line number Diff line number Diff line change
Expand Up @@ -40,13 +40,36 @@
#include <linux/slab.h>

#include <asm/irq.h>
#include <asm/exception.h>
#include <asm/mach/irq.h>
#include <asm/hardware/gic.h>

static DEFINE_RAW_SPINLOCK(irq_controller_lock);
union gic_base {
void __iomem *common_base;
void __percpu __iomem **percpu_base;
};

/* Address of GIC 0 CPU interface */
void __iomem *gic_cpu_base_addr __read_mostly;
struct gic_chip_data {
unsigned int irq_offset;
union gic_base dist_base;
union gic_base cpu_base;
#ifdef CONFIG_CPU_PM
u32 saved_spi_enable[DIV_ROUND_UP(1020, 32)];
u32 saved_spi_conf[DIV_ROUND_UP(1020, 16)];
u32 saved_spi_target[DIV_ROUND_UP(1020, 4)];
u32 __percpu *saved_ppi_enable;
u32 __percpu *saved_ppi_conf;
#endif
#ifdef CONFIG_IRQ_DOMAIN
struct irq_domain domain;
#endif
unsigned int gic_irqs;
#ifdef CONFIG_GIC_NON_BANKED
void __iomem *(*get_base)(union gic_base *);
#endif
};

static DEFINE_RAW_SPINLOCK(irq_controller_lock);

/*
* Supported arch specific GIC irq extension.
Expand All @@ -67,16 +90,48 @@ struct irq_chip gic_arch_extn = {

static struct gic_chip_data gic_data[MAX_GIC_NR] __read_mostly;

#ifdef CONFIG_GIC_NON_BANKED
static void __iomem *gic_get_percpu_base(union gic_base *base)
{
return *__this_cpu_ptr(base->percpu_base);
}

static void __iomem *gic_get_common_base(union gic_base *base)
{
return base->common_base;
}

static inline void __iomem *gic_data_dist_base(struct gic_chip_data *data)
{
return data->get_base(&data->dist_base);
}

static inline void __iomem *gic_data_cpu_base(struct gic_chip_data *data)
{
return data->get_base(&data->cpu_base);
}

static inline void gic_set_base_accessor(struct gic_chip_data *data,
void __iomem *(*f)(union gic_base *))
{
data->get_base = f;
}
#else
#define gic_data_dist_base(d) ((d)->dist_base.common_base)
#define gic_data_cpu_base(d) ((d)->cpu_base.common_base)
#define gic_set_base_accessor(d,f)
#endif

static inline void __iomem *gic_dist_base(struct irq_data *d)
{
struct gic_chip_data *gic_data = irq_data_get_irq_chip_data(d);
return gic_data->dist_base;
return gic_data_dist_base(gic_data);
}

static inline void __iomem *gic_cpu_base(struct irq_data *d)
{
struct gic_chip_data *gic_data = irq_data_get_irq_chip_data(d);
return gic_data->cpu_base;
return gic_data_cpu_base(gic_data);
}

static inline unsigned int gic_irq(struct irq_data *d)
Expand Down Expand Up @@ -215,6 +270,32 @@ static int gic_set_wake(struct irq_data *d, unsigned int on)
#define gic_set_wake NULL
#endif

asmlinkage void __exception_irq_entry gic_handle_irq(struct pt_regs *regs)
{
u32 irqstat, irqnr;
struct gic_chip_data *gic = &gic_data[0];
void __iomem *cpu_base = gic_data_cpu_base(gic);

do {
irqstat = readl_relaxed(cpu_base + GIC_CPU_INTACK);
irqnr = irqstat & ~0x1c00;

if (likely(irqnr > 15 && irqnr < 1021)) {
irqnr = irq_domain_to_irq(&gic->domain, irqnr);
handle_IRQ(irqnr, regs);
continue;
}
if (irqnr < 16) {
writel_relaxed(irqstat, cpu_base + GIC_CPU_EOI);
#ifdef CONFIG_SMP
handle_IPI(irqnr, regs);
#endif
continue;
}
break;
} while (1);
}

static void gic_handle_cascade_irq(unsigned int irq, struct irq_desc *desc)
{
struct gic_chip_data *chip_data = irq_get_handler_data(irq);
Expand All @@ -225,7 +306,7 @@ static void gic_handle_cascade_irq(unsigned int irq, struct irq_desc *desc)
chained_irq_enter(chip, desc);

raw_spin_lock(&irq_controller_lock);
status = readl_relaxed(chip_data->cpu_base + GIC_CPU_INTACK);
status = readl_relaxed(gic_data_cpu_base(chip_data) + GIC_CPU_INTACK);
raw_spin_unlock(&irq_controller_lock);

gic_irq = (status & 0x3ff);
Expand Down Expand Up @@ -270,7 +351,7 @@ static void __init gic_dist_init(struct gic_chip_data *gic)
u32 cpumask;
unsigned int gic_irqs = gic->gic_irqs;
struct irq_domain *domain = &gic->domain;
void __iomem *base = gic->dist_base;
void __iomem *base = gic_data_dist_base(gic);
u32 cpu = 0;

#ifdef CONFIG_SMP
Expand Down Expand Up @@ -330,8 +411,8 @@ static void __init gic_dist_init(struct gic_chip_data *gic)

static void __cpuinit gic_cpu_init(struct gic_chip_data *gic)
{
void __iomem *dist_base = gic->dist_base;
void __iomem *base = gic->cpu_base;
void __iomem *dist_base = gic_data_dist_base(gic);
void __iomem *base = gic_data_cpu_base(gic);
int i;

/*
Expand Down Expand Up @@ -368,7 +449,7 @@ static void gic_dist_save(unsigned int gic_nr)
BUG();

gic_irqs = gic_data[gic_nr].gic_irqs;
dist_base = gic_data[gic_nr].dist_base;
dist_base = gic_data_dist_base(&gic_data[gic_nr]);

if (!dist_base)
return;
Expand Down Expand Up @@ -403,7 +484,7 @@ static void gic_dist_restore(unsigned int gic_nr)
BUG();

gic_irqs = gic_data[gic_nr].gic_irqs;
dist_base = gic_data[gic_nr].dist_base;
dist_base = gic_data_dist_base(&gic_data[gic_nr]);

if (!dist_base)
return;
Expand Down Expand Up @@ -439,8 +520,8 @@ static void gic_cpu_save(unsigned int gic_nr)
if (gic_nr >= MAX_GIC_NR)
BUG();

dist_base = gic_data[gic_nr].dist_base;
cpu_base = gic_data[gic_nr].cpu_base;
dist_base = gic_data_dist_base(&gic_data[gic_nr]);
cpu_base = gic_data_cpu_base(&gic_data[gic_nr]);

if (!dist_base || !cpu_base)
return;
Expand All @@ -465,8 +546,8 @@ static void gic_cpu_restore(unsigned int gic_nr)
if (gic_nr >= MAX_GIC_NR)
BUG();

dist_base = gic_data[gic_nr].dist_base;
cpu_base = gic_data[gic_nr].cpu_base;
dist_base = gic_data_dist_base(&gic_data[gic_nr]);
cpu_base = gic_data_cpu_base(&gic_data[gic_nr]);

if (!dist_base || !cpu_base)
return;
Expand All @@ -491,6 +572,11 @@ static int gic_notifier(struct notifier_block *self, unsigned long cmd, void *v)
int i;

for (i = 0; i < MAX_GIC_NR; i++) {
#ifdef CONFIG_GIC_NON_BANKED
/* Skip over unused GICs */
if (!gic_data[i].get_base)
continue;
#endif
switch (cmd) {
case CPU_PM_ENTER:
gic_cpu_save(i);
Expand Down Expand Up @@ -564,8 +650,9 @@ const struct irq_domain_ops gic_irq_domain_ops = {
#endif
};

void __init gic_init(unsigned int gic_nr, int irq_start,
void __iomem *dist_base, void __iomem *cpu_base)
void __init gic_init_bases(unsigned int gic_nr, int irq_start,
void __iomem *dist_base, void __iomem *cpu_base,
u32 percpu_offset)
{
struct gic_chip_data *gic;
struct irq_domain *domain;
Expand All @@ -575,17 +662,43 @@ void __init gic_init(unsigned int gic_nr, int irq_start,

gic = &gic_data[gic_nr];
domain = &gic->domain;
gic->dist_base = dist_base;
gic->cpu_base = cpu_base;
#ifdef CONFIG_GIC_NON_BANKED
if (percpu_offset) { /* Frankein-GIC without banked registers... */
unsigned int cpu;

gic->dist_base.percpu_base = alloc_percpu(void __iomem *);
gic->cpu_base.percpu_base = alloc_percpu(void __iomem *);
if (WARN_ON(!gic->dist_base.percpu_base ||
!gic->cpu_base.percpu_base)) {
free_percpu(gic->dist_base.percpu_base);
free_percpu(gic->cpu_base.percpu_base);
return;
}

for_each_possible_cpu(cpu) {
unsigned long offset = percpu_offset * cpu_logical_map(cpu);
*per_cpu_ptr(gic->dist_base.percpu_base, cpu) = dist_base + offset;
*per_cpu_ptr(gic->cpu_base.percpu_base, cpu) = cpu_base + offset;
}

gic_set_base_accessor(gic, gic_get_percpu_base);
} else
#endif
{ /* Normal, sane GIC... */
WARN(percpu_offset,
"GIC_NON_BANKED not enabled, ignoring %08x offset!",
percpu_offset);
gic->dist_base.common_base = dist_base;
gic->cpu_base.common_base = cpu_base;
gic_set_base_accessor(gic, gic_get_common_base);
}

/*
* For primary GICs, skip over SGIs.
* For secondary GICs, skip over PPIs, too.
*/
domain->hwirq_base = 32;
if (gic_nr == 0) {
gic_cpu_base_addr = cpu_base;

if ((irq_start & 31) > 0) {
domain->hwirq_base = 16;
if (irq_start != -1)
Expand All @@ -597,7 +710,7 @@ void __init gic_init(unsigned int gic_nr, int irq_start,
* Find out how many interrupts are supported.
* The GIC only supports up to 1020 interrupt sources.
*/
gic_irqs = readl_relaxed(dist_base + GIC_DIST_CTR) & 0x1f;
gic_irqs = readl_relaxed(gic_data_dist_base(gic) + GIC_DIST_CTR) & 0x1f;
gic_irqs = (gic_irqs + 1) * 32;
if (gic_irqs > 1020)
gic_irqs = 1020;
Expand Down Expand Up @@ -645,7 +758,7 @@ void gic_raise_softirq(const struct cpumask *mask, unsigned int irq)
dsb();

/* this always happens on GIC0 */
writel_relaxed(map << 16 | irq, gic_data[0].dist_base + GIC_DIST_SOFTINT);
writel_relaxed(map << 16 | irq, gic_data_dist_base(&gic_data[0]) + GIC_DIST_SOFTINT);
}
#endif

Expand All @@ -656,6 +769,7 @@ int __init gic_of_init(struct device_node *node, struct device_node *parent)
{
void __iomem *cpu_base;
void __iomem *dist_base;
u32 percpu_offset;
int irq;
struct irq_domain *domain = &gic_data[gic_cnt].domain;

Expand All @@ -668,9 +782,12 @@ int __init gic_of_init(struct device_node *node, struct device_node *parent)
cpu_base = of_iomap(node, 1);
WARN(!cpu_base, "unable to map gic cpu registers\n");

if (of_property_read_u32(node, "cpu-offset", &percpu_offset))
percpu_offset = 0;

domain->of_node = of_node_get(node);

gic_init(gic_cnt, -1, dist_base, cpu_base);
gic_init_bases(gic_cnt, -1, dist_base, cpu_base, percpu_offset);

if (parent) {
irq = irq_of_parse_and_map(node, 0);
Expand Down
Loading

0 comments on commit 05da34d

Please sign in to comment.