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

Commit 4ba9dcbe authored by Russell King's avatar Russell King Committed by Russell King
Browse files

Merge Realview GIC code

parents 382266ad 4b17244c
Loading
Loading
Loading
Loading
+95 −14
Original line number Original line Diff line number Diff line
@@ -14,7 +14,9 @@
 *
 *
 * o There is one CPU Interface per CPU, which sends interrupts sent
 * o There is one CPU Interface per CPU, which sends interrupts sent
 *   by the Distributor, and interrupts generated locally, to the
 *   by the Distributor, and interrupts generated locally, to the
 *   associated CPU.
 *   associated CPU. The base address of the CPU interface is usually
 *   aliased so that the same address points to different chips depending
 *   on the CPU it is accessed from.
 *
 *
 * Note that IRQs 0-31 are special - they are local to each CPU.
 * Note that IRQs 0-31 are special - they are local to each CPU.
 * As such, the enable set/clear, pending set/clear and active bit
 * As such, the enable set/clear, pending set/clear and active bit
@@ -31,10 +33,38 @@
#include <asm/mach/irq.h>
#include <asm/mach/irq.h>
#include <asm/hardware/gic.h>
#include <asm/hardware/gic.h>


static void __iomem *gic_dist_base;
static void __iomem *gic_cpu_base;
static DEFINE_SPINLOCK(irq_controller_lock);
static DEFINE_SPINLOCK(irq_controller_lock);


struct gic_chip_data {
	unsigned int irq_offset;
	void __iomem *dist_base;
	void __iomem *cpu_base;
};

#ifndef MAX_GIC_NR
#define MAX_GIC_NR	1
#endif

static struct gic_chip_data gic_data[MAX_GIC_NR];

static inline void __iomem *gic_dist_base(unsigned int irq)
{
	struct gic_chip_data *gic_data = get_irq_chip_data(irq);
	return gic_data->dist_base;
}

static inline void __iomem *gic_cpu_base(unsigned int irq)
{
	struct gic_chip_data *gic_data = get_irq_chip_data(irq);
	return gic_data->cpu_base;
}

static inline unsigned int gic_irq(unsigned int irq)
{
	struct gic_chip_data *gic_data = get_irq_chip_data(irq);
	return irq - gic_data->irq_offset;
}

/*
/*
 * Routines to acknowledge, disable and enable interrupts
 * Routines to acknowledge, disable and enable interrupts
 *
 *
@@ -55,8 +85,8 @@ static void gic_ack_irq(unsigned int irq)
	u32 mask = 1 << (irq % 32);
	u32 mask = 1 << (irq % 32);


	spin_lock(&irq_controller_lock);
	spin_lock(&irq_controller_lock);
	writel(mask, gic_dist_base + GIC_DIST_ENABLE_CLEAR + (irq / 32) * 4);
	writel(mask, gic_dist_base(irq) + GIC_DIST_ENABLE_CLEAR + (gic_irq(irq) / 32) * 4);
	writel(irq, gic_cpu_base + GIC_CPU_EOI);
	writel(gic_irq(irq), gic_cpu_base(irq) + GIC_CPU_EOI);
	spin_unlock(&irq_controller_lock);
	spin_unlock(&irq_controller_lock);
}
}


@@ -65,7 +95,7 @@ static void gic_mask_irq(unsigned int irq)
	u32 mask = 1 << (irq % 32);
	u32 mask = 1 << (irq % 32);


	spin_lock(&irq_controller_lock);
	spin_lock(&irq_controller_lock);
	writel(mask, gic_dist_base + GIC_DIST_ENABLE_CLEAR + (irq / 32) * 4);
	writel(mask, gic_dist_base(irq) + GIC_DIST_ENABLE_CLEAR + (gic_irq(irq) / 32) * 4);
	spin_unlock(&irq_controller_lock);
	spin_unlock(&irq_controller_lock);
}
}


@@ -74,14 +104,14 @@ static void gic_unmask_irq(unsigned int irq)
	u32 mask = 1 << (irq % 32);
	u32 mask = 1 << (irq % 32);


	spin_lock(&irq_controller_lock);
	spin_lock(&irq_controller_lock);
	writel(mask, gic_dist_base + GIC_DIST_ENABLE_SET + (irq / 32) * 4);
	writel(mask, gic_dist_base(irq) + GIC_DIST_ENABLE_SET + (gic_irq(irq) / 32) * 4);
	spin_unlock(&irq_controller_lock);
	spin_unlock(&irq_controller_lock);
}
}


#ifdef CONFIG_SMP
#ifdef CONFIG_SMP
static void gic_set_cpu(unsigned int irq, cpumask_t mask_val)
static void gic_set_cpu(unsigned int irq, cpumask_t mask_val)
{
{
	void __iomem *reg = gic_dist_base + GIC_DIST_TARGET + (irq & ~3);
	void __iomem *reg = gic_dist_base(irq) + GIC_DIST_TARGET + (gic_irq(irq) & ~3);
	unsigned int shift = (irq % 4) * 8;
	unsigned int shift = (irq % 4) * 8;
	unsigned int cpu = first_cpu(mask_val);
	unsigned int cpu = first_cpu(mask_val);
	u32 val;
	u32 val;
@@ -95,6 +125,37 @@ static void gic_set_cpu(unsigned int irq, cpumask_t mask_val)
}
}
#endif
#endif


static void fastcall gic_handle_cascade_irq(unsigned int irq,
					    struct irq_desc *desc)
{
	struct gic_chip_data *chip_data = get_irq_data(irq);
	struct irq_chip *chip = get_irq_chip(irq);
	unsigned int cascade_irq;
	unsigned long status;

	/* primary controller ack'ing */
	chip->ack(irq);

	spin_lock(&irq_controller_lock);
	status = readl(chip_data->cpu_base + GIC_CPU_INTACK);
	spin_unlock(&irq_controller_lock);

	cascade_irq = (status & 0x3ff);
	if (cascade_irq > 1020)
		goto out;
	if (cascade_irq < 32 || cascade_irq >= NR_IRQS) {
		do_bad_IRQ(cascade_irq, desc);
		goto out;
	}

	cascade_irq += chip_data->irq_offset;
	generic_handle_irq(cascade_irq);

 out:
	/* primary controller unmasking */
	chip->unmask(irq);
}

static struct irq_chip gic_chip = {
static struct irq_chip gic_chip = {
	.name		= "GIC",
	.name		= "GIC",
	.ack		= gic_ack_irq,
	.ack		= gic_ack_irq,
@@ -105,15 +166,29 @@ static struct irq_chip gic_chip = {
#endif
#endif
};
};


void __init gic_dist_init(void __iomem *base)
void __init gic_cascade_irq(unsigned int gic_nr, unsigned int irq)
{
	if (gic_nr >= MAX_GIC_NR)
		BUG();
	if (set_irq_data(irq, &gic_data[gic_nr]) != 0)
		BUG();
	set_irq_chained_handler(irq, gic_handle_cascade_irq);
}

void __init gic_dist_init(unsigned int gic_nr, void __iomem *base,
			  unsigned int irq_start)
{
{
	unsigned int max_irq, i;
	unsigned int max_irq, i;
	u32 cpumask = 1 << smp_processor_id();
	u32 cpumask = 1 << smp_processor_id();


	if (gic_nr >= MAX_GIC_NR)
		BUG();

	cpumask |= cpumask << 8;
	cpumask |= cpumask << 8;
	cpumask |= cpumask << 16;
	cpumask |= cpumask << 16;


	gic_dist_base = base;
	gic_data[gic_nr].dist_base = base;
	gic_data[gic_nr].irq_offset = (irq_start - 1) & ~31;


	writel(0, base + GIC_DIST_CTRL);
	writel(0, base + GIC_DIST_CTRL);


@@ -158,8 +233,9 @@ void __init gic_dist_init(void __iomem *base)
	/*
	/*
	 * Setup the Linux IRQ subsystem.
	 * Setup the Linux IRQ subsystem.
	 */
	 */
	for (i = 29; i < max_irq; i++) {
	for (i = irq_start; i < gic_data[gic_nr].irq_offset + max_irq; i++) {
		set_irq_chip(i, &gic_chip);
		set_irq_chip(i, &gic_chip);
		set_irq_chip_data(i, &gic_data[gic_nr]);
		set_irq_handler(i, handle_level_irq);
		set_irq_handler(i, handle_level_irq);
		set_irq_flags(i, IRQF_VALID | IRQF_PROBE);
		set_irq_flags(i, IRQF_VALID | IRQF_PROBE);
	}
	}
@@ -167,9 +243,13 @@ void __init gic_dist_init(void __iomem *base)
	writel(1, base + GIC_DIST_CTRL);
	writel(1, base + GIC_DIST_CTRL);
}
}


void __cpuinit gic_cpu_init(void __iomem *base)
void __cpuinit gic_cpu_init(unsigned int gic_nr, void __iomem *base)
{
{
	gic_cpu_base = base;
	if (gic_nr >= MAX_GIC_NR)
		BUG();

	gic_data[gic_nr].cpu_base = base;

	writel(0xf0, base + GIC_CPU_PRIMASK);
	writel(0xf0, base + GIC_CPU_PRIMASK);
	writel(1, base + GIC_CPU_CTRL);
	writel(1, base + GIC_CPU_CTRL);
}
}
@@ -179,6 +259,7 @@ void gic_raise_softirq(cpumask_t cpumask, unsigned int irq)
{
{
	unsigned long map = *cpus_addr(cpumask);
	unsigned long map = *cpus_addr(cpumask);


	writel(map << 16 | irq, gic_dist_base + GIC_DIST_SOFTINT);
	/* this always happens on GIC0 */
	writel(map << 16 | irq, gic_data[0].dist_base + GIC_DIST_SOFTINT);
}
}
#endif
#endif
+10 −0
Original line number Original line Diff line number Diff line
@@ -16,4 +16,14 @@ config REALVIEW_MPCORE
	  kernel built with this option enabled is not compatible with
	  kernel built with this option enabled is not compatible with
	  other tiles.
	  other tiles.


config REALVIEW_MPCORE_REVB
	bool "Support MPcore RevB tile"
	depends on REALVIEW_MPCORE
	default n
	help
	  Enable support for the MPCore RevB tile on the Realview platform.
	  Since there are device address differences, a
	  kernel built with this option enabled is not compatible with
	  other tiles.

endmenu
endmenu
+1 −1
Original line number Original line Diff line number Diff line
@@ -52,7 +52,7 @@ void __cpuinit platform_secondary_init(unsigned int cpu)
	 * core (e.g. timer irq), then they will not have been enabled
	 * core (e.g. timer irq), then they will not have been enabled
	 * for us: do so
	 * for us: do so
	 */
	 */
	gic_cpu_init(__io_address(REALVIEW_GIC_CPU_BASE));
	gic_cpu_init(0, __io_address(REALVIEW_GIC_CPU_BASE));


	/*
	/*
	 * let the primary processor know we're out of the
	 * let the primary processor know we're out of the
+23 −4
Original line number Original line Diff line number Diff line
@@ -57,7 +57,21 @@ static struct map_desc realview_eb_io_desc[] __initdata = {
		.pfn		= __phys_to_pfn(REALVIEW_GIC_DIST_BASE),
		.pfn		= __phys_to_pfn(REALVIEW_GIC_DIST_BASE),
		.length		= SZ_4K,
		.length		= SZ_4K,
		.type		= MT_DEVICE,
		.type		= MT_DEVICE,
	},
#ifdef CONFIG_REALVIEW_MPCORE
	{
		.virtual	= IO_ADDRESS(REALVIEW_GIC1_CPU_BASE),
		.pfn		= __phys_to_pfn(REALVIEW_GIC1_CPU_BASE),
		.length		= SZ_4K,
		.type		= MT_DEVICE,
	}, {
	}, {
		.virtual	= IO_ADDRESS(REALVIEW_GIC1_DIST_BASE),
		.pfn		= __phys_to_pfn(REALVIEW_GIC1_DIST_BASE),
		.length		= SZ_4K,
		.type		= MT_DEVICE,
	},
#endif
	{
		.virtual	= IO_ADDRESS(REALVIEW_SCTL_BASE),
		.virtual	= IO_ADDRESS(REALVIEW_SCTL_BASE),
		.pfn		= __phys_to_pfn(REALVIEW_SCTL_BASE),
		.pfn		= __phys_to_pfn(REALVIEW_SCTL_BASE),
		.length		= SZ_4K,
		.length		= SZ_4K,
@@ -138,13 +152,18 @@ static void __init gic_init_irq(void)
#ifdef CONFIG_REALVIEW_MPCORE
#ifdef CONFIG_REALVIEW_MPCORE
	unsigned int pldctrl;
	unsigned int pldctrl;
	writel(0x0000a05f, __io_address(REALVIEW_SYS_LOCK));
	writel(0x0000a05f, __io_address(REALVIEW_SYS_LOCK));
	pldctrl = readl(__io_address(REALVIEW_SYS_BASE)	+ 0xd8);
	pldctrl = readl(__io_address(REALVIEW_SYS_BASE)	+ REALVIEW_MPCORE_SYS_PLD_CTRL1);
	pldctrl |= 0x00800000;	/* New irq mode */
	pldctrl |= 0x00800000;	/* New irq mode */
	writel(pldctrl, __io_address(REALVIEW_SYS_BASE) + 0xd8);
	writel(pldctrl, __io_address(REALVIEW_SYS_BASE) + REALVIEW_MPCORE_SYS_PLD_CTRL1);
	writel(0x00000000, __io_address(REALVIEW_SYS_LOCK));
	writel(0x00000000, __io_address(REALVIEW_SYS_LOCK));
#endif
#endif
	gic_dist_init(__io_address(REALVIEW_GIC_DIST_BASE));
	gic_dist_init(0, __io_address(REALVIEW_GIC_DIST_BASE), 29);
	gic_cpu_init(__io_address(REALVIEW_GIC_CPU_BASE));
	gic_cpu_init(0, __io_address(REALVIEW_GIC_CPU_BASE));
#ifdef CONFIG_REALVIEW_MPCORE
	gic_dist_init(1, __io_address(REALVIEW_GIC1_DIST_BASE), 64);
	gic_cpu_init(1, __io_address(REALVIEW_GIC1_CPU_BASE));
	gic_cascade_irq(1, IRQ_EB_IRQ1);
#endif
}
}


static void __init realview_eb_init(void)
static void __init realview_eb_init(void)
+5 −3
Original line number Original line Diff line number Diff line
@@ -14,10 +14,13 @@
#include <asm/assembler.h>
#include <asm/assembler.h>
#include <asm/asm-offsets.h>
#include <asm/asm-offsets.h>
#include <asm/elf.h>
#include <asm/elf.h>
#include <asm/hardware/arm_scu.h>
#include <asm/pgtable-hwdef.h>
#include <asm/pgtable-hwdef.h>
#include <asm/pgtable.h>
#include <asm/pgtable.h>


#ifdef CONFIG_SMP
#include <asm/hardware/arm_scu.h>
#endif

#include "proc-macros.S"
#include "proc-macros.S"


#define D_CACHE_LINE_SIZE	32
#define D_CACHE_LINE_SIZE	32
@@ -187,8 +190,7 @@ __v6_setup:
	/* Set up the SCU on core 0 only */
	/* Set up the SCU on core 0 only */
	mrc	p15, 0, r0, c0, c0, 5		@ CPU core number
	mrc	p15, 0, r0, c0, c0, 5		@ CPU core number
	ands	r0, r0, #15
	ands	r0, r0, #15
	moveq	r0, #0x10000000 @ SCU_BASE
	ldreq	r0, =SCU_BASE
	orreq	r0, r0, #0x00100000
	ldreq	r5, [r0, #SCU_CTRL]
	ldreq	r5, [r0, #SCU_CTRL]
	orreq	r5, r5, #1
	orreq	r5, r5, #1
	streq	r5, [r0, #SCU_CTRL]
	streq	r5, [r0, #SCU_CTRL]
Loading