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

Commit 94314a40 authored by Arnd Bergmann's avatar Arnd Bergmann
Browse files

Merge branch 'dt/gic' into imx/imx6q

parents 929f58ae f37a53cc
Loading
Loading
Loading
Loading
+55 −0
Original line number Diff line number Diff line
* ARM Generic Interrupt Controller

ARM SMP cores are often associated with a GIC, providing per processor
interrupts (PPI), shared processor interrupts (SPI) and software
generated interrupts (SGI).

Primary GIC is attached directly to the CPU and typically has PPIs and SGIs.
Secondary GICs are cascaded into the upward interrupt controller and do not
have PPIs or SGIs.

Main node required properties:

- compatible : should be one of:
	"arm,cortex-a9-gic"
	"arm,arm11mp-gic"
- interrupt-controller : Identifies the node as an interrupt controller
- #interrupt-cells : Specifies the number of cells needed to encode an
  interrupt source.  The type shall be a <u32> and the value shall be 3.

  The 1st cell is the interrupt type; 0 for SPI interrupts, 1 for PPI
  interrupts.

  The 2nd cell contains the interrupt number for the interrupt type.
  SPI interrupts are in the range [0-987].  PPI interrupts are in the
  range [0-15].

  The 3rd cell is the flags, encoded as follows:
	bits[3:0] trigger type and level flags.
		1 = low-to-high edge triggered
		2 = high-to-low edge triggered
		4 = active high level-sensitive
		8 = active low level-sensitive
	bits[15:8] PPI interrupt cpu mask.  Each bit corresponds to each of
	the 8 possible cpus attached to the GIC.  A bit set to '1' indicated
	the interrupt is wired to that CPU.  Only valid for PPI interrupts.

- reg : Specifies base physical address(s) and size of the GIC registers. The
  first region is the GIC distributor register base and size. The 2nd region is
  the GIC cpu interface register base and size.

Optional
- interrupts	: Interrupt source of the parent interrupt controller. Only
  present on secondary GICs.

Example:

	intc: interrupt-controller@fff11000 {
		compatible = "arm,cortex-a9-gic";
		#interrupt-cells = <3>;
		#address-cells = <1>;
		interrupt-controller;
		reg = <0xfff11000 0x1000>,
		      <0xfff10100 0x100>;
	};
+36 −10
Original line number Diff line number Diff line
@@ -196,7 +196,8 @@ config VECTORS_BASE
	  The base address of exception vectors.

config ARM_PATCH_PHYS_VIRT
	bool "Patch physical to virtual translations at runtime"
	bool "Patch physical to virtual translations at runtime" if EMBEDDED
	default y
	depends on !XIP_KERNEL && MMU
	depends on !ARCH_REALVIEW || !SPARSEMEM
	help
@@ -205,16 +206,25 @@ config ARM_PATCH_PHYS_VIRT
	  kernel in system memory.

	  This can only be used with non-XIP MMU kernels where the base
	  of physical memory is at a 16MB boundary, or theoretically 64K
	  for the MSM machine class.
	  of physical memory is at a 16MB boundary.

config ARM_PATCH_PHYS_VIRT_16BIT
	def_bool y
	depends on ARM_PATCH_PHYS_VIRT && ARCH_MSM
	  Only disable this option if you know that you do not require
	  this feature (eg, building a kernel for a single machine) and
	  you need to shrink the kernel to the minimal size.

config NEED_MACH_MEMORY_H
	bool
	help
	  Select this when mach/memory.h is required to provide special
	  definitions for this platform.  The need for mach/memory.h should
	  be avoided when possible.

config PHYS_OFFSET
	hex "Physical address of main memory"
	depends on !ARM_PATCH_PHYS_VIRT && !NEED_MACH_MEMORY_H
	help
	  This option extends the physical to virtual translation patching
	  to allow physical memory down to a theoretical minimum of 64K
	  boundaries.
	  Please provide the physical address corresponding to the
	  location of main memory in your system.

source "init/Kconfig"

@@ -247,6 +257,7 @@ config ARCH_INTEGRATOR
	select GENERIC_CLOCKEVENTS
	select PLAT_VERSATILE
	select PLAT_VERSATILE_FPGA_IRQ
	select NEED_MACH_MEMORY_H
	help
	  Support for ARM's Integrator platform.

@@ -262,6 +273,7 @@ config ARCH_REALVIEW
	select PLAT_VERSATILE_CLCD
	select ARM_TIMER_SP804
	select GPIO_PL061 if GPIOLIB
	select NEED_MACH_MEMORY_H
	help
	  This enables support for ARM Ltd RealView boards.

@@ -302,7 +314,6 @@ config ARCH_AT91
	select ARCH_REQUIRE_GPIOLIB
	select HAVE_CLK
	select CLKDEV_LOOKUP
	select ARM_PATCH_PHYS_VIRT if MMU
	help
	  This enables support for systems based on the Atmel AT91RM9200,
	  AT91SAM9 and AT91CAP9 processors.
@@ -323,6 +334,7 @@ config ARCH_CLPS711X
	bool "Cirrus Logic CLPS711x/EP721x-based"
	select CPU_ARM720T
	select ARCH_USES_GETTIMEOFFSET
	select NEED_MACH_MEMORY_H
	help
	  Support for Cirrus Logic 711x/721x based boards.

@@ -363,6 +375,7 @@ config ARCH_EBSA110
	select ISA
	select NO_IOPORT
	select ARCH_USES_GETTIMEOFFSET
	select NEED_MACH_MEMORY_H
	help
	  This is an evaluation board for the StrongARM processor available
	  from Digital. It has limited hardware on-board, including an
@@ -378,6 +391,7 @@ config ARCH_EP93XX
	select ARCH_REQUIRE_GPIOLIB
	select ARCH_HAS_HOLES_MEMORYMODEL
	select ARCH_USES_GETTIMEOFFSET
	select NEED_MEMORY_H
	help
	  This enables support for the Cirrus EP93xx series of CPUs.

@@ -386,6 +400,7 @@ config ARCH_FOOTBRIDGE
	select CPU_SA110
	select FOOTBRIDGE
	select GENERIC_CLOCKEVENTS
	select NEED_MACH_MEMORY_H
	help
	  Support for systems based on the DC21285 companion chip
	  ("FootBridge"), such as the Simtec CATS and the Rebel NetWinder.
@@ -435,6 +450,7 @@ config ARCH_IOP13XX
	select PCI
	select ARCH_SUPPORTS_MSI
	select VMSPLIT_1G
	select NEED_MACH_MEMORY_H
	help
	  Support for Intel's IOP13XX (XScale) family of processors.

@@ -465,6 +481,7 @@ config ARCH_IXP23XX
	select CPU_XSC3
 	select PCI
	select ARCH_USES_GETTIMEOFFSET
	select NEED_MACH_MEMORY_H
	help
	  Support for Intel's IXP23xx (XScale) family of processors.

@@ -474,6 +491,7 @@ config ARCH_IXP2000
	select CPU_XSCALE
	select PCI
	select ARCH_USES_GETTIMEOFFSET
	select NEED_MACH_MEMORY_H
	help
	  Support for Intel's IXP2400/2800 (XScale) family of processors.

@@ -567,6 +585,7 @@ config ARCH_KS8695
	select CPU_ARM922T
	select ARCH_REQUIRE_GPIOLIB
	select ARCH_USES_GETTIMEOFFSET
	select NEED_MACH_MEMORY_H
	help
	  Support for Micrel/Kendin KS8695 "Centaur" (ARM922T) based
	  System-on-Chip devices.
@@ -658,6 +677,7 @@ config ARCH_SHMOBILE
	select SPARSE_IRQ
	select MULTI_IRQ_HANDLER
	select PM_GENERIC_DOMAINS if PM
	select NEED_MACH_MEMORY_H
	help
	  Support for Renesas's SH-Mobile and R-Mobile ARM platforms.

@@ -672,6 +692,7 @@ config ARCH_RPC
	select NO_IOPORT
	select ARCH_SPARSEMEM_ENABLE
	select ARCH_USES_GETTIMEOFFSET
	select NEED_MACH_MEMORY_H
	help
	  On the Acorn Risc-PC, Linux can support the internal IDE disk and
	  CD-ROM interface, serial and parallel port, and the floppy drive.
@@ -690,6 +711,7 @@ config ARCH_SA1100
	select HAVE_SCHED_CLOCK
	select TICK_ONESHOT
	select ARCH_REQUIRE_GPIOLIB
	select NEED_MACH_MEMORY_H
	help
	  Support for StrongARM 11x0 based boards.

@@ -782,6 +804,7 @@ config ARCH_S5PV210
	select HAVE_S3C2410_I2C if I2C
	select HAVE_S3C_RTC if RTC_CLASS
	select HAVE_S3C2410_WATCHDOG if WATCHDOG
	select NEED_MACH_MEMORY_H
	help
	  Samsung S5PV210/S5PC110 series based systems

@@ -798,6 +821,7 @@ config ARCH_EXYNOS4
	select HAVE_S3C_RTC if RTC_CLASS
	select HAVE_S3C2410_I2C if I2C
	select HAVE_S3C2410_WATCHDOG if WATCHDOG
	select NEED_MACH_MEMORY_H
	help
	  Samsung EXYNOS4 series based systems

@@ -809,6 +833,7 @@ config ARCH_SHARK
	select ZONE_DMA
	select PCI
	select ARCH_USES_GETTIMEOFFSET
	select NEED_MACH_MEMORY_H
	help
	  Support for the StrongARM based Digital DNARD machine, also known
	  as "Shark" (<http://www.shark-linux.de/shark.html>).
@@ -836,6 +861,7 @@ config ARCH_U300
	select CLKDEV_LOOKUP
	select HAVE_MACH_CLKDEV
	select GENERIC_GPIO
	select NEED_MACH_MEMORY_H
	help
	  Support for ST-Ericsson U300 series mobile platforms.

+3 −0
Original line number Diff line number Diff line
@@ -128,6 +128,9 @@ textofs-$(CONFIG_PM_H1940) := 0x00108000
ifeq ($(CONFIG_ARCH_SA1100),y)
textofs-$(CONFIG_SA1111) := 0x00208000
endif
textofs-$(CONFIG_ARCH_MSM7X30) := 0x00208000
textofs-$(CONFIG_ARCH_MSM8X60) := 0x00208000
textofs-$(CONFIG_ARCH_MSM8960) := 0x00208000

# Machine directory name.  This list is sorted alphanumerically
# by CONFIG_* macro name.
+1 −0
Original line number Diff line number Diff line
config ARM_GIC
	select IRQ_DOMAIN
	bool

config ARM_VIC
+128 −45
Original line number Diff line number Diff line
@@ -24,11 +24,20 @@
 */
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/err.h>
#include <linux/export.h>
#include <linux/list.h>
#include <linux/smp.h>
#include <linux/cpu_pm.h>
#include <linux/cpumask.h>
#include <linux/io.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/of_irq.h>
#include <linux/irqdomain.h>
#include <linux/interrupt.h>
#include <linux/percpu.h>
#include <linux/slab.h>

#include <asm/irq.h>
#include <asm/mach/irq.h>
@@ -72,8 +81,7 @@ static inline void __iomem *gic_cpu_base(struct irq_data *d)

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

/*
@@ -81,7 +89,7 @@ static inline unsigned int gic_irq(struct irq_data *d)
 */
static void gic_mask_irq(struct irq_data *d)
{
	u32 mask = 1 << (d->irq % 32);
	u32 mask = 1 << (gic_irq(d) % 32);

	spin_lock(&irq_controller_lock);
	writel_relaxed(mask, gic_dist_base(d) + GIC_DIST_ENABLE_CLEAR + (gic_irq(d) / 32) * 4);
@@ -92,7 +100,7 @@ static void gic_mask_irq(struct irq_data *d)

static void gic_unmask_irq(struct irq_data *d)
{
	u32 mask = 1 << (d->irq % 32);
	u32 mask = 1 << (gic_irq(d) % 32);

	spin_lock(&irq_controller_lock);
	if (gic_arch_extn.irq_unmask)
@@ -173,7 +181,7 @@ static int gic_set_affinity(struct irq_data *d, const struct cpumask *mask_val,
			    bool force)
{
	void __iomem *reg = gic_dist_base(d) + GIC_DIST_TARGET + (gic_irq(d) & ~3);
	unsigned int shift = (d->irq % 4) * 8;
	unsigned int shift = (gic_irq(d) % 4) * 8;
	unsigned int cpu = cpumask_any_and(mask_val, cpu_online_mask);
	u32 val, mask, bit;

@@ -224,7 +232,7 @@ static void gic_handle_cascade_irq(unsigned int irq, struct irq_desc *desc)
	if (gic_irq == 1023)
		goto out;

	cascade_irq = gic_irq + chip_data->irq_offset;
	cascade_irq = irq_domain_to_irq(&chip_data->domain, gic_irq);
	if (unlikely(gic_irq < 32 || gic_irq > 1020 || cascade_irq >= NR_IRQS))
		do_bad_IRQ(cascade_irq, desc);
	else
@@ -256,11 +264,12 @@ void __init gic_cascade_irq(unsigned int gic_nr, unsigned int irq)
	irq_set_chained_handler(irq, gic_handle_cascade_irq);
}

static void __init gic_dist_init(struct gic_chip_data *gic,
	unsigned int irq_start)
static void __init gic_dist_init(struct gic_chip_data *gic)
{
	unsigned int gic_irqs, irq_limit, i;
	unsigned int i, irq;
	u32 cpumask;
	unsigned int gic_irqs = gic->gic_irqs;
	struct irq_domain *domain = &gic->domain;
	void __iomem *base = gic->dist_base;
	u32 cpu = 0;

@@ -274,17 +283,6 @@ static void __init gic_dist_init(struct gic_chip_data *gic,

	writel_relaxed(0, base + GIC_DIST_CTRL);

	/*
	 * Find out how many interrupts are supported.
	 * The GIC only supports up to 1020 interrupt sources.
	 */
	gic_irqs = readl_relaxed(base + GIC_DIST_CTR) & 0x1f;
	gic_irqs = (gic_irqs + 1) * 32;
	if (gic_irqs > 1020)
		gic_irqs = 1020;

	gic->gic_irqs = gic_irqs;

	/*
	 * Set all global interrupts to be level triggered, active low.
	 */
@@ -310,20 +308,21 @@ static void __init gic_dist_init(struct gic_chip_data *gic,
	for (i = 32; i < gic_irqs; i += 32)
		writel_relaxed(0xffffffff, base + GIC_DIST_ENABLE_CLEAR + i * 4 / 32);

	/*
	 * Limit number of interrupts registered to the platform maximum
	 */
	irq_limit = gic->irq_offset + gic_irqs;
	if (WARN_ON(irq_limit > NR_IRQS))
		irq_limit = NR_IRQS;

	/*
	 * Setup the Linux IRQ subsystem.
	 */
	for (i = irq_start; i < irq_limit; i++) {
		irq_set_chip_and_handler(i, &gic_chip, handle_fasteoi_irq);
		irq_set_chip_data(i, gic);
		set_irq_flags(i, IRQF_VALID | IRQF_PROBE);
	irq_domain_for_each_irq(domain, i, irq) {
		if (i < 32) {
			irq_set_percpu_devid(irq);
			irq_set_chip_and_handler(irq, &gic_chip,
						 handle_percpu_devid_irq);
			set_irq_flags(irq, IRQF_VALID | IRQF_NOAUTOEN);
		} else {
			irq_set_chip_and_handler(irq, &gic_chip,
						 handle_fasteoi_irq);
			set_irq_flags(irq, IRQF_VALID | IRQF_PROBE);
		}
		irq_set_chip_data(irq, gic);
	}

	writel_relaxed(1, base + GIC_DIST_CTRL);
@@ -535,23 +534,85 @@ static void __init gic_pm_init(struct gic_chip_data *gic)
}
#endif

void __init gic_init(unsigned int gic_nr, unsigned int irq_start,
#ifdef CONFIG_OF
static int gic_irq_domain_dt_translate(struct irq_domain *d,
				       struct device_node *controller,
				       const u32 *intspec, unsigned int intsize,
				       unsigned long *out_hwirq, unsigned int *out_type)
{
	if (d->of_node != controller)
		return -EINVAL;
	if (intsize < 3)
		return -EINVAL;

	/* Get the interrupt number and add 16 to skip over SGIs */
	*out_hwirq = intspec[1] + 16;

	/* For SPIs, we need to add 16 more to get the GIC irq ID number */
	if (!intspec[0])
		*out_hwirq += 16;

	*out_type = intspec[2] & IRQ_TYPE_SENSE_MASK;
	return 0;
}
#endif

const struct irq_domain_ops gic_irq_domain_ops = {
#ifdef CONFIG_OF
	.dt_translate = gic_irq_domain_dt_translate,
#endif
};

void __init gic_init(unsigned int gic_nr, int irq_start,
	void __iomem *dist_base, void __iomem *cpu_base)
{
	struct gic_chip_data *gic;
	struct irq_domain *domain;
	int gic_irqs;

	BUG_ON(gic_nr >= MAX_GIC_NR);

	gic = &gic_data[gic_nr];
	domain = &gic->domain;
	gic->dist_base = dist_base;
	gic->cpu_base = cpu_base;
	gic->irq_offset = (irq_start - 1) & ~31;

	if (gic_nr == 0)
	/*
	 * For primary GICs, skip over SGIs.
	 * For secondary GICs, skip over PPIs, too.
	 */
	if (gic_nr == 0) {
		gic_cpu_base_addr = cpu_base;
		domain->hwirq_base = 16;
		if (irq_start > 0)
			irq_start = (irq_start & ~31) + 16;
	} else
		domain->hwirq_base = 32;

	/*
	 * 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 = (gic_irqs + 1) * 32;
	if (gic_irqs > 1020)
		gic_irqs = 1020;
	gic->gic_irqs = gic_irqs;

	domain->nr_irq = gic_irqs - domain->hwirq_base;
	domain->irq_base = irq_alloc_descs(irq_start, 16, domain->nr_irq,
					   numa_node_id());
	if (IS_ERR_VALUE(domain->irq_base)) {
		WARN(1, "Cannot allocate irq_descs @ IRQ%d, assuming pre-allocated\n",
		     irq_start);
		domain->irq_base = irq_start;
	}
	domain->priv = gic;
	domain->ops = &gic_irq_domain_ops;
	irq_domain_add(domain);

	gic_chip.flags |= gic_arch_extn.flags;
	gic_dist_init(gic, irq_start);
	gic_dist_init(gic);
	gic_cpu_init(gic);
	gic_pm_init(gic);
}
@@ -563,16 +624,6 @@ void __cpuinit gic_secondary_init(unsigned int gic_nr)
	gic_cpu_init(&gic_data[gic_nr]);
}

void __cpuinit gic_enable_ppi(unsigned int irq)
{
	unsigned long flags;

	local_irq_save(flags);
	irq_set_status_flags(irq, IRQ_NOPROBE);
	gic_unmask_irq(irq_get_irq_data(irq));
	local_irq_restore(flags);
}

#ifdef CONFIG_SMP
void gic_raise_softirq(const struct cpumask *mask, unsigned int irq)
{
@@ -593,3 +644,35 @@ void gic_raise_softirq(const struct cpumask *mask, unsigned int irq)
	writel_relaxed(map << 16 | irq, gic_data[0].dist_base + GIC_DIST_SOFTINT);
}
#endif

#ifdef CONFIG_OF
static int gic_cnt __initdata = 0;

int __init gic_of_init(struct device_node *node, struct device_node *parent)
{
	void __iomem *cpu_base;
	void __iomem *dist_base;
	int irq;
	struct irq_domain *domain = &gic_data[gic_cnt].domain;

	if (WARN_ON(!node))
		return -ENODEV;

	dist_base = of_iomap(node, 0);
	WARN(!dist_base, "unable to map gic dist registers\n");

	cpu_base = of_iomap(node, 1);
	WARN(!cpu_base, "unable to map gic cpu registers\n");

	domain->of_node = of_node_get(node);

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

	if (parent) {
		irq = irq_of_parse_and_map(node, 0);
		gic_cascade_irq(gic_cnt, irq);
	}
	gic_cnt++;
	return 0;
}
#endif
Loading