Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit b46ad442 authored by Olof Johansson's avatar Olof Johansson
Browse files

Merge branch 'board' of...

Merge branch 'board' of git://git.kernel.org/pub/scm/linux/kernel/git/tmlind/linux-omap into omap/board
parents dc47ce90 a890b676
Loading
Loading
Loading
Loading
+5 −6
Original line number Original line Diff line number Diff line
@@ -51,15 +51,14 @@ ffc00000 ffefffff DMA memory mapping region. Memory returned
ff000000	ffbfffff	Reserved for future expansion of DMA
ff000000	ffbfffff	Reserved for future expansion of DMA
				mapping region.
				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.
VMALLOC_START	VMALLOC_END-1	vmalloc() / ioremap() space.
				Memory returned by vmalloc/ioremap will
				Memory returned by vmalloc/ioremap will
				be dynamically placed in this region.
				be dynamically placed in this region.
				VMALLOC_START may be based upon the value
				Machine specific static mappings are also
				of the high_memory variable.
				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.
PAGE_OFFSET	high_memory-1	Kernel direct-mapped RAM region.
				This maps the platforms RAM, and typically
				This maps the platforms RAM, and typically
+4 −0
Original line number Original line Diff line number Diff line
@@ -42,6 +42,10 @@ Optional
- interrupts	: Interrupt source of the parent interrupt controller. Only
- interrupts	: Interrupt source of the parent interrupt controller. Only
  present on secondary GICs.
  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:
Example:


	intc: interrupt-controller@fff11000 {
	intc: interrupt-controller@fff11000 {
+29 −0
Original line number Original line Diff line number Diff line
* 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 −0
Original line number Original line Diff line number Diff line
config ARM_GIC
config ARM_GIC
	select IRQ_DOMAIN
	select IRQ_DOMAIN
	select MULTI_IRQ_HANDLER
	bool

config GIC_NON_BANKED
	bool
	bool


config ARM_VIC
config ARM_VIC
	select IRQ_DOMAIN
	select MULTI_IRQ_HANDLER
	bool
	bool


config ARM_VIC_NR
config ARM_VIC_NR
+141 −24
Original line number Original line Diff line number Diff line
@@ -40,13 +40,36 @@
#include <linux/slab.h>
#include <linux/slab.h>


#include <asm/irq.h>
#include <asm/irq.h>
#include <asm/exception.h>
#include <asm/mach/irq.h>
#include <asm/mach/irq.h>
#include <asm/hardware/gic.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;
};

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
};


/* Address of GIC 0 CPU interface */
static DEFINE_RAW_SPINLOCK(irq_controller_lock);
void __iomem *gic_cpu_base_addr __read_mostly;


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


static struct gic_chip_data gic_data[MAX_GIC_NR] __read_mostly;
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)
static inline void __iomem *gic_dist_base(struct irq_data *d)
{
{
	struct gic_chip_data *gic_data = irq_data_get_irq_chip_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)
static inline void __iomem *gic_cpu_base(struct irq_data *d)
{
{
	struct gic_chip_data *gic_data = irq_data_get_irq_chip_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)
static inline unsigned int gic_irq(struct irq_data *d)
@@ -215,6 +270,32 @@ static int gic_set_wake(struct irq_data *d, unsigned int on)
#define gic_set_wake	NULL
#define gic_set_wake	NULL
#endif
#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)
static void gic_handle_cascade_irq(unsigned int irq, struct irq_desc *desc)
{
{
	struct gic_chip_data *chip_data = irq_get_handler_data(irq);
	struct gic_chip_data *chip_data = irq_get_handler_data(irq);
@@ -225,7 +306,7 @@ static void gic_handle_cascade_irq(unsigned int irq, struct irq_desc *desc)
	chained_irq_enter(chip, desc);
	chained_irq_enter(chip, desc);


	raw_spin_lock(&irq_controller_lock);
	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);
	raw_spin_unlock(&irq_controller_lock);


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


#ifdef CONFIG_SMP
#ifdef CONFIG_SMP
@@ -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)
static void __cpuinit gic_cpu_init(struct gic_chip_data *gic)
{
{
	void __iomem *dist_base = gic->dist_base;
	void __iomem *dist_base = gic_data_dist_base(gic);
	void __iomem *base = gic->cpu_base;
	void __iomem *base = gic_data_cpu_base(gic);
	int i;
	int i;


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


	gic_irqs = gic_data[gic_nr].gic_irqs;
	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)
	if (!dist_base)
		return;
		return;
@@ -403,7 +484,7 @@ static void gic_dist_restore(unsigned int gic_nr)
		BUG();
		BUG();


	gic_irqs = gic_data[gic_nr].gic_irqs;
	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)
	if (!dist_base)
		return;
		return;
@@ -439,8 +520,8 @@ static void gic_cpu_save(unsigned int gic_nr)
	if (gic_nr >= MAX_GIC_NR)
	if (gic_nr >= MAX_GIC_NR)
		BUG();
		BUG();


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


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


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


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


	for (i = 0; i < MAX_GIC_NR; 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) {
		switch (cmd) {
		case CPU_PM_ENTER:
		case CPU_PM_ENTER:
			gic_cpu_save(i);
			gic_cpu_save(i);
@@ -564,8 +650,9 @@ const struct irq_domain_ops gic_irq_domain_ops = {
#endif
#endif
};
};


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


	gic = &gic_data[gic_nr];
	gic = &gic_data[gic_nr];
	domain = &gic->domain;
	domain = &gic->domain;
	gic->dist_base = dist_base;
#ifdef CONFIG_GIC_NON_BANKED
	gic->cpu_base = cpu_base;
	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 primary GICs, skip over SGIs.
@@ -584,8 +699,6 @@ void __init gic_init(unsigned int gic_nr, int irq_start,
	 */
	 */
	domain->hwirq_base = 32;
	domain->hwirq_base = 32;
	if (gic_nr == 0) {
	if (gic_nr == 0) {
		gic_cpu_base_addr = cpu_base;

		if ((irq_start & 31) > 0) {
		if ((irq_start & 31) > 0) {
			domain->hwirq_base = 16;
			domain->hwirq_base = 16;
			if (irq_start != -1)
			if (irq_start != -1)
@@ -597,7 +710,7 @@ void __init gic_init(unsigned int gic_nr, int irq_start,
	 * Find out how many interrupts are supported.
	 * Find out how many interrupts are supported.
	 * The GIC only supports up to 1020 interrupt sources.
	 * 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;
	gic_irqs = (gic_irqs + 1) * 32;
	if (gic_irqs > 1020)
	if (gic_irqs > 1020)
		gic_irqs = 1020;
		gic_irqs = 1020;
@@ -645,7 +758,7 @@ void gic_raise_softirq(const struct cpumask *mask, unsigned int irq)
	dsb();
	dsb();


	/* this always happens on GIC0 */
	/* 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
#endif


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


@@ -668,9 +782,12 @@ int __init gic_of_init(struct device_node *node, struct device_node *parent)
	cpu_base = of_iomap(node, 1);
	cpu_base = of_iomap(node, 1);
	WARN(!cpu_base, "unable to map gic cpu registers\n");
	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);
	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) {
	if (parent) {
		irq = irq_of_parse_and_map(node, 0);
		irq = irq_of_parse_and_map(node, 0);
Loading