mirror of
				https://kernel.googlesource.com/pub/scm/linux/kernel/git/torvalds/linux
				synced 2025-11-04 16:52:06 +10:00 
			
		
		
		
	Merge branch 'irq-core-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip
Pull irq core updates from Thomas Gleixner:
 "This is the first (boring) part of irq updates:
   - support for big endian I/O accessors in the generic irq chip
   - cleanup of brcmstb/bcm7120 drivers so they can be reused for non
     ARM SoCs
   - the usual pile of fixes and updates for the various ARM irq chips"
* 'irq-core-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: (25 commits)
  irqchip: dw-apb-ictl: Add PM support
  irqchip: dw-apb-ictl: Enable IRQ_GC_MASK_CACHE_PER_TYPE
  irqchip: dw-apb-ictl: Always use use {readl|writel}_relaxed
  ARM: orion: convert the irq_reg_{readl,writel} calls to the new API
  irqchip: atmel-aic: Add missing entry for rm9200 irq fixups
  irqchip: atmel-aic: Rename at91sam9_aic_irq_fixup for naming consistency
  irqchip: atmel-aic: Add specific irq fixup function for sam9g45 and sam9rl
  irqchip: atmel-aic: Add irq fixups for at91sam926x SoCs
  irqchip: atmel-aic: Add irq fixup for RTT block
  irqchip: brcmstb-l2: Convert driver to use irq_reg_{readl,writel}
  irqchip: bcm7120-l2: Convert driver to use irq_reg_{readl,writel}
  irqchip: bcm7120-l2: Decouple driver from brcmstb-l2
  irqchip: bcm7120-l2: Extend driver to support 64+ bit controllers
  irqchip: bcm7120-l2: Use gc->mask_cache to simplify suspend/resume functions
  irqchip: bcm7120-l2: Fix missing nibble in gc->unused mask
  irqchip: bcm7120-l2: Make sure all register accesses use base+offset
  irqchip: bcm7120-l2, brcmstb-l2: Remove ARM Kconfig dependency
  irqchip: bcm7120-l2: Eliminate bad IRQ check
  irqchip: brcmstb-l2: Eliminate dependency on ARM code
  genirq: Generic chip: Add big endian I/O accessors
  ...
			
			
This commit is contained in:
		
						commit
						ecb50f0afd
					
				@ -13,7 +13,12 @@ Such an interrupt controller has the following hardware design:
 | 
			
		||||
  or if they will output an interrupt signal at this 2nd level interrupt
 | 
			
		||||
  controller, in particular for UARTs
 | 
			
		||||
 | 
			
		||||
- not all 32-bits within the interrupt controller actually map to an interrupt
 | 
			
		||||
- typically has one 32-bit enable word and one 32-bit status word, but on
 | 
			
		||||
  some hardware may have more than one enable/status pair
 | 
			
		||||
 | 
			
		||||
- no atomic set/clear operations
 | 
			
		||||
 | 
			
		||||
- not all bits within the interrupt controller actually map to an interrupt
 | 
			
		||||
 | 
			
		||||
The typical hardware layout for this controller is represented below:
 | 
			
		||||
 | 
			
		||||
@ -48,7 +53,9 @@ The typical hardware layout for this controller is represented below:
 | 
			
		||||
Required properties:
 | 
			
		||||
 | 
			
		||||
- compatible: should be "brcm,bcm7120-l2-intc"
 | 
			
		||||
- reg: specifies the base physical address and size of the registers
 | 
			
		||||
- reg: specifies the base physical address and size of the registers;
 | 
			
		||||
  multiple pairs may be specified, with the first pair handling IRQ offsets
 | 
			
		||||
  0..31 and the second pair handling 32..63
 | 
			
		||||
- interrupt-controller: identifies the node as an interrupt controller
 | 
			
		||||
- #interrupt-cells: specifies the number of cells needed to encode an interrupt
 | 
			
		||||
  source, should be 1.
 | 
			
		||||
@ -59,18 +66,21 @@ Required properties:
 | 
			
		||||
- brcm,int-map-mask: 32-bits bit mask describing how many and which interrupts
 | 
			
		||||
  are wired to this 2nd level interrupt controller, and how they match their
 | 
			
		||||
  respective interrupt parents. Should match exactly the number of interrupts
 | 
			
		||||
  specified in the 'interrupts' property.
 | 
			
		||||
  specified in the 'interrupts' property, multiplied by the number of
 | 
			
		||||
  enable/status register pairs implemented by this controller.  For
 | 
			
		||||
  multiple parent IRQs with multiple enable/status words, this looks like:
 | 
			
		||||
  <irq0_w0 irq0_w1 irq1_w0 irq1_w1 ...>
 | 
			
		||||
 | 
			
		||||
Optional properties:
 | 
			
		||||
 | 
			
		||||
- brcm,irq-can-wake: if present, this means the L2 controller can be used as a
 | 
			
		||||
  wakeup source for system suspend/resume.
 | 
			
		||||
 | 
			
		||||
- brcm,int-fwd-mask: if present, a 32-bits bit mask to configure for the
 | 
			
		||||
  interrupts which have a mux gate, typically UARTs. Setting these bits will
 | 
			
		||||
  make their respective interrupts outputs bypass this 2nd level interrupt
 | 
			
		||||
  controller completely, it completely transparent for the interrupt controller
 | 
			
		||||
  parent
 | 
			
		||||
- brcm,int-fwd-mask: if present, a bit mask to configure the interrupts which
 | 
			
		||||
  have a mux gate, typically UARTs. Setting these bits will make their
 | 
			
		||||
  respective interrupt outputs bypass this 2nd level interrupt controller
 | 
			
		||||
  completely; it is completely transparent for the interrupt controller
 | 
			
		||||
  parent. This should have one 32-bit word per enable/status pair.
 | 
			
		||||
 | 
			
		||||
Example:
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -143,6 +143,7 @@ config ARCH_BRCMSTB
 | 
			
		||||
	select HAVE_ARM_ARCH_TIMER
 | 
			
		||||
	select BRCMSTB_GISB_ARB
 | 
			
		||||
	select BRCMSTB_L2_IRQ
 | 
			
		||||
	select BCM7120_L2_IRQ
 | 
			
		||||
	help
 | 
			
		||||
	  Say Y if you intend to run the kernel on a Broadcom ARM-based STB
 | 
			
		||||
	  chipset.
 | 
			
		||||
 | 
			
		||||
@ -505,9 +505,9 @@ static void orion_gpio_unmask_irq(struct irq_data *d)
 | 
			
		||||
	u32 mask = d->mask;
 | 
			
		||||
 | 
			
		||||
	irq_gc_lock(gc);
 | 
			
		||||
	reg_val = irq_reg_readl(gc->reg_base + ct->regs.mask);
 | 
			
		||||
	reg_val = irq_reg_readl(gc, ct->regs.mask);
 | 
			
		||||
	reg_val |= mask;
 | 
			
		||||
	irq_reg_writel(reg_val, gc->reg_base + ct->regs.mask);
 | 
			
		||||
	irq_reg_writel(gc, reg_val, ct->regs.mask);
 | 
			
		||||
	irq_gc_unlock(gc);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -519,9 +519,9 @@ static void orion_gpio_mask_irq(struct irq_data *d)
 | 
			
		||||
	u32 reg_val;
 | 
			
		||||
 | 
			
		||||
	irq_gc_lock(gc);
 | 
			
		||||
	reg_val = irq_reg_readl(gc->reg_base + ct->regs.mask);
 | 
			
		||||
	reg_val = irq_reg_readl(gc, ct->regs.mask);
 | 
			
		||||
	reg_val &= ~mask;
 | 
			
		||||
	irq_reg_writel(reg_val, gc->reg_base + ct->regs.mask);
 | 
			
		||||
	irq_reg_writel(gc, reg_val, ct->regs.mask);
 | 
			
		||||
	irq_gc_unlock(gc);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -48,14 +48,19 @@ config ATMEL_AIC5_IRQ
 | 
			
		||||
	select MULTI_IRQ_HANDLER
 | 
			
		||||
	select SPARSE_IRQ
 | 
			
		||||
 | 
			
		||||
config BCM7120_L2_IRQ
 | 
			
		||||
	bool
 | 
			
		||||
	select GENERIC_IRQ_CHIP
 | 
			
		||||
	select IRQ_DOMAIN
 | 
			
		||||
 | 
			
		||||
config BRCMSTB_L2_IRQ
 | 
			
		||||
	bool
 | 
			
		||||
	depends on ARM
 | 
			
		||||
	select GENERIC_IRQ_CHIP
 | 
			
		||||
	select IRQ_DOMAIN
 | 
			
		||||
 | 
			
		||||
config DW_APB_ICTL
 | 
			
		||||
	bool
 | 
			
		||||
	select GENERIC_IRQ_CHIP
 | 
			
		||||
	select IRQ_DOMAIN
 | 
			
		||||
 | 
			
		||||
config IMGPDC_IRQ
 | 
			
		||||
 | 
			
		||||
@ -35,6 +35,6 @@ obj-$(CONFIG_TB10X_IRQC)		+= irq-tb10x.o
 | 
			
		||||
obj-$(CONFIG_XTENSA)			+= irq-xtensa-pic.o
 | 
			
		||||
obj-$(CONFIG_XTENSA_MX)			+= irq-xtensa-mx.o
 | 
			
		||||
obj-$(CONFIG_IRQ_CROSSBAR)		+= irq-crossbar.o
 | 
			
		||||
obj-$(CONFIG_BRCMSTB_L2_IRQ)		+= irq-brcmstb-l2.o \
 | 
			
		||||
					   irq-bcm7120-l2.o
 | 
			
		||||
obj-$(CONFIG_BCM7120_L2_IRQ)		+= irq-bcm7120-l2.o
 | 
			
		||||
obj-$(CONFIG_BRCMSTB_L2_IRQ)		+= irq-brcmstb-l2.o
 | 
			
		||||
obj-$(CONFIG_KEYSTONE_IRQ)		+= irq-keystone.o
 | 
			
		||||
 | 
			
		||||
@ -268,7 +268,7 @@ static int armada_xp_set_affinity(struct irq_data *d,
 | 
			
		||||
	writel(reg, main_int_base + ARMADA_370_XP_INT_SOURCE_CTL(hwirq));
 | 
			
		||||
	raw_spin_unlock(&irq_controller_lock);
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
	return IRQ_SET_MASK_OK;
 | 
			
		||||
}
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -167,6 +167,32 @@ void __init aic_common_rtc_irq_fixup(struct device_node *root)
 | 
			
		||||
	iounmap(regs);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#define AT91_RTT_MR		0x00			/* Real-time Mode Register */
 | 
			
		||||
#define AT91_RTT_ALMIEN		(1 << 16)		/* Alarm Interrupt Enable */
 | 
			
		||||
#define AT91_RTT_RTTINCIEN	(1 << 17)		/* Real Time Timer Increment Interrupt Enable */
 | 
			
		||||
 | 
			
		||||
void __init aic_common_rtt_irq_fixup(struct device_node *root)
 | 
			
		||||
{
 | 
			
		||||
	struct device_node *np;
 | 
			
		||||
	void __iomem *regs;
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
	 * The at91sam9263 SoC has 2 instances of the RTT block, hence we
 | 
			
		||||
	 * iterate over the DT to find each occurrence.
 | 
			
		||||
	 */
 | 
			
		||||
	for_each_compatible_node(np, NULL, "atmel,at91sam9260-rtt") {
 | 
			
		||||
		regs = of_iomap(np, 0);
 | 
			
		||||
		if (!regs)
 | 
			
		||||
			continue;
 | 
			
		||||
 | 
			
		||||
		writel(readl(regs + AT91_RTT_MR) &
 | 
			
		||||
		       ~(AT91_RTT_ALMIEN | AT91_RTT_RTTINCIEN),
 | 
			
		||||
		       regs + AT91_RTT_MR);
 | 
			
		||||
 | 
			
		||||
		iounmap(regs);
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void __init aic_common_irq_fixup(const struct of_device_id *matches)
 | 
			
		||||
{
 | 
			
		||||
	struct device_node *root = of_find_node_by_path("/");
 | 
			
		||||
 | 
			
		||||
@ -34,6 +34,8 @@ struct irq_domain *__init aic_common_of_init(struct device_node *node,
 | 
			
		||||
 | 
			
		||||
void __init aic_common_rtc_irq_fixup(struct device_node *root);
 | 
			
		||||
 | 
			
		||||
void __init aic_common_rtt_irq_fixup(struct device_node *root);
 | 
			
		||||
 | 
			
		||||
void __init aic_common_irq_fixup(const struct of_device_id *matches);
 | 
			
		||||
 | 
			
		||||
#endif /* __IRQ_ATMEL_AIC_COMMON_H */
 | 
			
		||||
 | 
			
		||||
@ -65,11 +65,11 @@ aic_handle(struct pt_regs *regs)
 | 
			
		||||
	u32 irqnr;
 | 
			
		||||
	u32 irqstat;
 | 
			
		||||
 | 
			
		||||
	irqnr = irq_reg_readl(gc->reg_base + AT91_AIC_IVR);
 | 
			
		||||
	irqstat = irq_reg_readl(gc->reg_base + AT91_AIC_ISR);
 | 
			
		||||
	irqnr = irq_reg_readl(gc, AT91_AIC_IVR);
 | 
			
		||||
	irqstat = irq_reg_readl(gc, AT91_AIC_ISR);
 | 
			
		||||
 | 
			
		||||
	if (!irqstat)
 | 
			
		||||
		irq_reg_writel(0, gc->reg_base + AT91_AIC_EOICR);
 | 
			
		||||
		irq_reg_writel(gc, 0, AT91_AIC_EOICR);
 | 
			
		||||
	else
 | 
			
		||||
		handle_domain_irq(aic_domain, irqnr, regs);
 | 
			
		||||
}
 | 
			
		||||
@ -80,7 +80,7 @@ static int aic_retrigger(struct irq_data *d)
 | 
			
		||||
 | 
			
		||||
	/* Enable interrupt on AIC5 */
 | 
			
		||||
	irq_gc_lock(gc);
 | 
			
		||||
	irq_reg_writel(d->mask, gc->reg_base + AT91_AIC_ISCR);
 | 
			
		||||
	irq_reg_writel(gc, d->mask, AT91_AIC_ISCR);
 | 
			
		||||
	irq_gc_unlock(gc);
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
@ -92,12 +92,12 @@ static int aic_set_type(struct irq_data *d, unsigned type)
 | 
			
		||||
	unsigned int smr;
 | 
			
		||||
	int ret;
 | 
			
		||||
 | 
			
		||||
	smr = irq_reg_readl(gc->reg_base + AT91_AIC_SMR(d->hwirq));
 | 
			
		||||
	smr = irq_reg_readl(gc, AT91_AIC_SMR(d->hwirq));
 | 
			
		||||
	ret = aic_common_set_type(d, type, &smr);
 | 
			
		||||
	if (ret)
 | 
			
		||||
		return ret;
 | 
			
		||||
 | 
			
		||||
	irq_reg_writel(smr, gc->reg_base + AT91_AIC_SMR(d->hwirq));
 | 
			
		||||
	irq_reg_writel(gc, smr, AT91_AIC_SMR(d->hwirq));
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
@ -108,8 +108,8 @@ static void aic_suspend(struct irq_data *d)
 | 
			
		||||
	struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d);
 | 
			
		||||
 | 
			
		||||
	irq_gc_lock(gc);
 | 
			
		||||
	irq_reg_writel(gc->mask_cache, gc->reg_base + AT91_AIC_IDCR);
 | 
			
		||||
	irq_reg_writel(gc->wake_active, gc->reg_base + AT91_AIC_IECR);
 | 
			
		||||
	irq_reg_writel(gc, gc->mask_cache, AT91_AIC_IDCR);
 | 
			
		||||
	irq_reg_writel(gc, gc->wake_active, AT91_AIC_IECR);
 | 
			
		||||
	irq_gc_unlock(gc);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -118,8 +118,8 @@ static void aic_resume(struct irq_data *d)
 | 
			
		||||
	struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d);
 | 
			
		||||
 | 
			
		||||
	irq_gc_lock(gc);
 | 
			
		||||
	irq_reg_writel(gc->wake_active, gc->reg_base + AT91_AIC_IDCR);
 | 
			
		||||
	irq_reg_writel(gc->mask_cache, gc->reg_base + AT91_AIC_IECR);
 | 
			
		||||
	irq_reg_writel(gc, gc->wake_active, AT91_AIC_IDCR);
 | 
			
		||||
	irq_reg_writel(gc, gc->mask_cache, AT91_AIC_IECR);
 | 
			
		||||
	irq_gc_unlock(gc);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -128,8 +128,8 @@ static void aic_pm_shutdown(struct irq_data *d)
 | 
			
		||||
	struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d);
 | 
			
		||||
 | 
			
		||||
	irq_gc_lock(gc);
 | 
			
		||||
	irq_reg_writel(0xffffffff, gc->reg_base + AT91_AIC_IDCR);
 | 
			
		||||
	irq_reg_writel(0xffffffff, gc->reg_base + AT91_AIC_ICCR);
 | 
			
		||||
	irq_reg_writel(gc, 0xffffffff, AT91_AIC_IDCR);
 | 
			
		||||
	irq_reg_writel(gc, 0xffffffff, AT91_AIC_ICCR);
 | 
			
		||||
	irq_gc_unlock(gc);
 | 
			
		||||
}
 | 
			
		||||
#else
 | 
			
		||||
@ -148,24 +148,24 @@ static void __init aic_hw_init(struct irq_domain *domain)
 | 
			
		||||
	 * will not Lock out nIRQ
 | 
			
		||||
	 */
 | 
			
		||||
	for (i = 0; i < 8; i++)
 | 
			
		||||
		irq_reg_writel(0, gc->reg_base + AT91_AIC_EOICR);
 | 
			
		||||
		irq_reg_writel(gc, 0, AT91_AIC_EOICR);
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
	 * Spurious Interrupt ID in Spurious Vector Register.
 | 
			
		||||
	 * When there is no current interrupt, the IRQ Vector Register
 | 
			
		||||
	 * reads the value stored in AIC_SPU
 | 
			
		||||
	 */
 | 
			
		||||
	irq_reg_writel(0xffffffff, gc->reg_base + AT91_AIC_SPU);
 | 
			
		||||
	irq_reg_writel(gc, 0xffffffff, AT91_AIC_SPU);
 | 
			
		||||
 | 
			
		||||
	/* No debugging in AIC: Debug (Protect) Control Register */
 | 
			
		||||
	irq_reg_writel(0, gc->reg_base + AT91_AIC_DCR);
 | 
			
		||||
	irq_reg_writel(gc, 0, AT91_AIC_DCR);
 | 
			
		||||
 | 
			
		||||
	/* Disable and clear all interrupts initially */
 | 
			
		||||
	irq_reg_writel(0xffffffff, gc->reg_base + AT91_AIC_IDCR);
 | 
			
		||||
	irq_reg_writel(0xffffffff, gc->reg_base + AT91_AIC_ICCR);
 | 
			
		||||
	irq_reg_writel(gc, 0xffffffff, AT91_AIC_IDCR);
 | 
			
		||||
	irq_reg_writel(gc, 0xffffffff, AT91_AIC_ICCR);
 | 
			
		||||
 | 
			
		||||
	for (i = 0; i < 32; i++)
 | 
			
		||||
		irq_reg_writel(i, gc->reg_base + AT91_AIC_SVR(i));
 | 
			
		||||
		irq_reg_writel(gc, i, AT91_AIC_SVR(i));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int aic_irq_domain_xlate(struct irq_domain *d,
 | 
			
		||||
@ -195,10 +195,10 @@ static int aic_irq_domain_xlate(struct irq_domain *d,
 | 
			
		||||
	gc = dgc->gc[idx];
 | 
			
		||||
 | 
			
		||||
	irq_gc_lock(gc);
 | 
			
		||||
	smr = irq_reg_readl(gc->reg_base + AT91_AIC_SMR(*out_hwirq));
 | 
			
		||||
	smr = irq_reg_readl(gc, AT91_AIC_SMR(*out_hwirq));
 | 
			
		||||
	ret = aic_common_set_priority(intspec[2], &smr);
 | 
			
		||||
	if (!ret)
 | 
			
		||||
		irq_reg_writel(smr, gc->reg_base + AT91_AIC_SMR(*out_hwirq));
 | 
			
		||||
		irq_reg_writel(gc, smr, AT91_AIC_SMR(*out_hwirq));
 | 
			
		||||
	irq_gc_unlock(gc);
 | 
			
		||||
 | 
			
		||||
	return ret;
 | 
			
		||||
@ -209,16 +209,32 @@ static const struct irq_domain_ops aic_irq_ops = {
 | 
			
		||||
	.xlate	= aic_irq_domain_xlate,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static void __init at91sam9_aic_irq_fixup(struct device_node *root)
 | 
			
		||||
static void __init at91rm9200_aic_irq_fixup(struct device_node *root)
 | 
			
		||||
{
 | 
			
		||||
	aic_common_rtc_irq_fixup(root);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void __init at91sam9260_aic_irq_fixup(struct device_node *root)
 | 
			
		||||
{
 | 
			
		||||
	aic_common_rtt_irq_fixup(root);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void __init at91sam9g45_aic_irq_fixup(struct device_node *root)
 | 
			
		||||
{
 | 
			
		||||
	aic_common_rtc_irq_fixup(root);
 | 
			
		||||
	aic_common_rtt_irq_fixup(root);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static const struct of_device_id __initdata aic_irq_fixups[] = {
 | 
			
		||||
	{ .compatible = "atmel,at91sam9g45", .data = at91sam9_aic_irq_fixup },
 | 
			
		||||
	{ .compatible = "atmel,at91sam9n12", .data = at91sam9_aic_irq_fixup },
 | 
			
		||||
	{ .compatible = "atmel,at91sam9rl", .data = at91sam9_aic_irq_fixup },
 | 
			
		||||
	{ .compatible = "atmel,at91sam9x5", .data = at91sam9_aic_irq_fixup },
 | 
			
		||||
	{ .compatible = "atmel,at91rm9200", .data = at91rm9200_aic_irq_fixup },
 | 
			
		||||
	{ .compatible = "atmel,at91sam9g45", .data = at91sam9g45_aic_irq_fixup },
 | 
			
		||||
	{ .compatible = "atmel,at91sam9n12", .data = at91rm9200_aic_irq_fixup },
 | 
			
		||||
	{ .compatible = "atmel,at91sam9rl", .data = at91sam9g45_aic_irq_fixup },
 | 
			
		||||
	{ .compatible = "atmel,at91sam9x5", .data = at91rm9200_aic_irq_fixup },
 | 
			
		||||
	{ .compatible = "atmel,at91sam9260", .data = at91sam9260_aic_irq_fixup },
 | 
			
		||||
	{ .compatible = "atmel,at91sam9261", .data = at91sam9260_aic_irq_fixup },
 | 
			
		||||
	{ .compatible = "atmel,at91sam9263", .data = at91sam9260_aic_irq_fixup },
 | 
			
		||||
	{ .compatible = "atmel,at91sam9g20", .data = at91sam9260_aic_irq_fixup },
 | 
			
		||||
	{ /* sentinel */ },
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -75,11 +75,11 @@ aic5_handle(struct pt_regs *regs)
 | 
			
		||||
	u32 irqnr;
 | 
			
		||||
	u32 irqstat;
 | 
			
		||||
 | 
			
		||||
	irqnr = irq_reg_readl(gc->reg_base + AT91_AIC5_IVR);
 | 
			
		||||
	irqstat = irq_reg_readl(gc->reg_base + AT91_AIC5_ISR);
 | 
			
		||||
	irqnr = irq_reg_readl(gc, AT91_AIC5_IVR);
 | 
			
		||||
	irqstat = irq_reg_readl(gc, AT91_AIC5_ISR);
 | 
			
		||||
 | 
			
		||||
	if (!irqstat)
 | 
			
		||||
		irq_reg_writel(0, gc->reg_base + AT91_AIC5_EOICR);
 | 
			
		||||
		irq_reg_writel(gc, 0, AT91_AIC5_EOICR);
 | 
			
		||||
	else
 | 
			
		||||
		handle_domain_irq(aic5_domain, irqnr, regs);
 | 
			
		||||
}
 | 
			
		||||
@ -92,8 +92,8 @@ static void aic5_mask(struct irq_data *d)
 | 
			
		||||
 | 
			
		||||
	/* Disable interrupt on AIC5 */
 | 
			
		||||
	irq_gc_lock(gc);
 | 
			
		||||
	irq_reg_writel(d->hwirq, gc->reg_base + AT91_AIC5_SSR);
 | 
			
		||||
	irq_reg_writel(1, gc->reg_base + AT91_AIC5_IDCR);
 | 
			
		||||
	irq_reg_writel(gc, d->hwirq, AT91_AIC5_SSR);
 | 
			
		||||
	irq_reg_writel(gc, 1, AT91_AIC5_IDCR);
 | 
			
		||||
	gc->mask_cache &= ~d->mask;
 | 
			
		||||
	irq_gc_unlock(gc);
 | 
			
		||||
}
 | 
			
		||||
@ -106,8 +106,8 @@ static void aic5_unmask(struct irq_data *d)
 | 
			
		||||
 | 
			
		||||
	/* Enable interrupt on AIC5 */
 | 
			
		||||
	irq_gc_lock(gc);
 | 
			
		||||
	irq_reg_writel(d->hwirq, gc->reg_base + AT91_AIC5_SSR);
 | 
			
		||||
	irq_reg_writel(1, gc->reg_base + AT91_AIC5_IECR);
 | 
			
		||||
	irq_reg_writel(gc, d->hwirq, AT91_AIC5_SSR);
 | 
			
		||||
	irq_reg_writel(gc, 1, AT91_AIC5_IECR);
 | 
			
		||||
	gc->mask_cache |= d->mask;
 | 
			
		||||
	irq_gc_unlock(gc);
 | 
			
		||||
}
 | 
			
		||||
@ -120,8 +120,8 @@ static int aic5_retrigger(struct irq_data *d)
 | 
			
		||||
 | 
			
		||||
	/* Enable interrupt on AIC5 */
 | 
			
		||||
	irq_gc_lock(gc);
 | 
			
		||||
	irq_reg_writel(d->hwirq, gc->reg_base + AT91_AIC5_SSR);
 | 
			
		||||
	irq_reg_writel(1, gc->reg_base + AT91_AIC5_ISCR);
 | 
			
		||||
	irq_reg_writel(gc, d->hwirq, AT91_AIC5_SSR);
 | 
			
		||||
	irq_reg_writel(gc, 1, AT91_AIC5_ISCR);
 | 
			
		||||
	irq_gc_unlock(gc);
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
@ -136,11 +136,11 @@ static int aic5_set_type(struct irq_data *d, unsigned type)
 | 
			
		||||
	int ret;
 | 
			
		||||
 | 
			
		||||
	irq_gc_lock(gc);
 | 
			
		||||
	irq_reg_writel(d->hwirq, gc->reg_base + AT91_AIC5_SSR);
 | 
			
		||||
	smr = irq_reg_readl(gc->reg_base + AT91_AIC5_SMR);
 | 
			
		||||
	irq_reg_writel(gc, d->hwirq, AT91_AIC5_SSR);
 | 
			
		||||
	smr = irq_reg_readl(gc, AT91_AIC5_SMR);
 | 
			
		||||
	ret = aic_common_set_type(d, type, &smr);
 | 
			
		||||
	if (!ret)
 | 
			
		||||
		irq_reg_writel(smr, gc->reg_base + AT91_AIC5_SMR);
 | 
			
		||||
		irq_reg_writel(gc, smr, AT91_AIC5_SMR);
 | 
			
		||||
	irq_gc_unlock(gc);
 | 
			
		||||
 | 
			
		||||
	return ret;
 | 
			
		||||
@ -162,12 +162,11 @@ static void aic5_suspend(struct irq_data *d)
 | 
			
		||||
		if ((mask & gc->mask_cache) == (mask & gc->wake_active))
 | 
			
		||||
			continue;
 | 
			
		||||
 | 
			
		||||
		irq_reg_writel(i + gc->irq_base,
 | 
			
		||||
			       bgc->reg_base + AT91_AIC5_SSR);
 | 
			
		||||
		irq_reg_writel(bgc, i + gc->irq_base, AT91_AIC5_SSR);
 | 
			
		||||
		if (mask & gc->wake_active)
 | 
			
		||||
			irq_reg_writel(1, bgc->reg_base + AT91_AIC5_IECR);
 | 
			
		||||
			irq_reg_writel(bgc, 1, AT91_AIC5_IECR);
 | 
			
		||||
		else
 | 
			
		||||
			irq_reg_writel(1, bgc->reg_base + AT91_AIC5_IDCR);
 | 
			
		||||
			irq_reg_writel(bgc, 1, AT91_AIC5_IDCR);
 | 
			
		||||
	}
 | 
			
		||||
	irq_gc_unlock(bgc);
 | 
			
		||||
}
 | 
			
		||||
@ -187,12 +186,11 @@ static void aic5_resume(struct irq_data *d)
 | 
			
		||||
		if ((mask & gc->mask_cache) == (mask & gc->wake_active))
 | 
			
		||||
			continue;
 | 
			
		||||
 | 
			
		||||
		irq_reg_writel(i + gc->irq_base,
 | 
			
		||||
			       bgc->reg_base + AT91_AIC5_SSR);
 | 
			
		||||
		irq_reg_writel(bgc, i + gc->irq_base, AT91_AIC5_SSR);
 | 
			
		||||
		if (mask & gc->mask_cache)
 | 
			
		||||
			irq_reg_writel(1, bgc->reg_base + AT91_AIC5_IECR);
 | 
			
		||||
			irq_reg_writel(bgc, 1, AT91_AIC5_IECR);
 | 
			
		||||
		else
 | 
			
		||||
			irq_reg_writel(1, bgc->reg_base + AT91_AIC5_IDCR);
 | 
			
		||||
			irq_reg_writel(bgc, 1, AT91_AIC5_IDCR);
 | 
			
		||||
	}
 | 
			
		||||
	irq_gc_unlock(bgc);
 | 
			
		||||
}
 | 
			
		||||
@ -207,10 +205,9 @@ static void aic5_pm_shutdown(struct irq_data *d)
 | 
			
		||||
 | 
			
		||||
	irq_gc_lock(bgc);
 | 
			
		||||
	for (i = 0; i < dgc->irqs_per_chip; i++) {
 | 
			
		||||
		irq_reg_writel(i + gc->irq_base,
 | 
			
		||||
			       bgc->reg_base + AT91_AIC5_SSR);
 | 
			
		||||
		irq_reg_writel(1, bgc->reg_base + AT91_AIC5_IDCR);
 | 
			
		||||
		irq_reg_writel(1, bgc->reg_base + AT91_AIC5_ICCR);
 | 
			
		||||
		irq_reg_writel(bgc, i + gc->irq_base, AT91_AIC5_SSR);
 | 
			
		||||
		irq_reg_writel(bgc, 1, AT91_AIC5_IDCR);
 | 
			
		||||
		irq_reg_writel(bgc, 1, AT91_AIC5_ICCR);
 | 
			
		||||
	}
 | 
			
		||||
	irq_gc_unlock(bgc);
 | 
			
		||||
}
 | 
			
		||||
@ -230,24 +227,24 @@ static void __init aic5_hw_init(struct irq_domain *domain)
 | 
			
		||||
	 * will not Lock out nIRQ
 | 
			
		||||
	 */
 | 
			
		||||
	for (i = 0; i < 8; i++)
 | 
			
		||||
		irq_reg_writel(0, gc->reg_base + AT91_AIC5_EOICR);
 | 
			
		||||
		irq_reg_writel(gc, 0, AT91_AIC5_EOICR);
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
	 * Spurious Interrupt ID in Spurious Vector Register.
 | 
			
		||||
	 * When there is no current interrupt, the IRQ Vector Register
 | 
			
		||||
	 * reads the value stored in AIC_SPU
 | 
			
		||||
	 */
 | 
			
		||||
	irq_reg_writel(0xffffffff, gc->reg_base + AT91_AIC5_SPU);
 | 
			
		||||
	irq_reg_writel(gc, 0xffffffff, AT91_AIC5_SPU);
 | 
			
		||||
 | 
			
		||||
	/* No debugging in AIC: Debug (Protect) Control Register */
 | 
			
		||||
	irq_reg_writel(0, gc->reg_base + AT91_AIC5_DCR);
 | 
			
		||||
	irq_reg_writel(gc, 0, AT91_AIC5_DCR);
 | 
			
		||||
 | 
			
		||||
	/* Disable and clear all interrupts initially */
 | 
			
		||||
	for (i = 0; i < domain->revmap_size; i++) {
 | 
			
		||||
		irq_reg_writel(i, gc->reg_base + AT91_AIC5_SSR);
 | 
			
		||||
		irq_reg_writel(i, gc->reg_base + AT91_AIC5_SVR);
 | 
			
		||||
		irq_reg_writel(1, gc->reg_base + AT91_AIC5_IDCR);
 | 
			
		||||
		irq_reg_writel(1, gc->reg_base + AT91_AIC5_ICCR);
 | 
			
		||||
		irq_reg_writel(gc, i, AT91_AIC5_SSR);
 | 
			
		||||
		irq_reg_writel(gc, i, AT91_AIC5_SVR);
 | 
			
		||||
		irq_reg_writel(gc, 1, AT91_AIC5_IDCR);
 | 
			
		||||
		irq_reg_writel(gc, 1, AT91_AIC5_ICCR);
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -273,11 +270,11 @@ static int aic5_irq_domain_xlate(struct irq_domain *d,
 | 
			
		||||
	gc = dgc->gc[0];
 | 
			
		||||
 | 
			
		||||
	irq_gc_lock(gc);
 | 
			
		||||
	irq_reg_writel(*out_hwirq, gc->reg_base + AT91_AIC5_SSR);
 | 
			
		||||
	smr = irq_reg_readl(gc->reg_base + AT91_AIC5_SMR);
 | 
			
		||||
	irq_reg_writel(gc, *out_hwirq, AT91_AIC5_SSR);
 | 
			
		||||
	smr = irq_reg_readl(gc, AT91_AIC5_SMR);
 | 
			
		||||
	ret = aic_common_set_priority(intspec[2], &smr);
 | 
			
		||||
	if (!ret)
 | 
			
		||||
		irq_reg_writel(intspec[2] | smr, gc->reg_base + AT91_AIC5_SMR);
 | 
			
		||||
		irq_reg_writel(gc, intspec[2] | smr, AT91_AIC5_SMR);
 | 
			
		||||
	irq_gc_unlock(gc);
 | 
			
		||||
 | 
			
		||||
	return ret;
 | 
			
		||||
 | 
			
		||||
@ -13,6 +13,7 @@
 | 
			
		||||
#include <linux/init.h>
 | 
			
		||||
#include <linux/slab.h>
 | 
			
		||||
#include <linux/module.h>
 | 
			
		||||
#include <linux/kconfig.h>
 | 
			
		||||
#include <linux/platform_device.h>
 | 
			
		||||
#include <linux/of.h>
 | 
			
		||||
#include <linux/of_irq.h>
 | 
			
		||||
@ -23,47 +24,52 @@
 | 
			
		||||
#include <linux/io.h>
 | 
			
		||||
#include <linux/irqdomain.h>
 | 
			
		||||
#include <linux/reboot.h>
 | 
			
		||||
#include <linux/bitops.h>
 | 
			
		||||
#include <linux/irqchip/chained_irq.h>
 | 
			
		||||
 | 
			
		||||
#include "irqchip.h"
 | 
			
		||||
 | 
			
		||||
#include <asm/mach/irq.h>
 | 
			
		||||
 | 
			
		||||
/* Register offset in the L2 interrupt controller */
 | 
			
		||||
#define IRQEN		0x00
 | 
			
		||||
#define IRQSTAT		0x04
 | 
			
		||||
 | 
			
		||||
#define MAX_WORDS	4
 | 
			
		||||
#define IRQS_PER_WORD	32
 | 
			
		||||
 | 
			
		||||
struct bcm7120_l2_intc_data {
 | 
			
		||||
	void __iomem *base;
 | 
			
		||||
	unsigned int n_words;
 | 
			
		||||
	void __iomem *base[MAX_WORDS];
 | 
			
		||||
	struct irq_domain *domain;
 | 
			
		||||
	bool can_wake;
 | 
			
		||||
	u32 irq_fwd_mask;
 | 
			
		||||
	u32 irq_map_mask;
 | 
			
		||||
	u32 saved_mask;
 | 
			
		||||
	u32 irq_fwd_mask[MAX_WORDS];
 | 
			
		||||
	u32 irq_map_mask[MAX_WORDS];
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static void bcm7120_l2_intc_irq_handle(unsigned int irq, struct irq_desc *desc)
 | 
			
		||||
{
 | 
			
		||||
	struct bcm7120_l2_intc_data *b = irq_desc_get_handler_data(desc);
 | 
			
		||||
	struct irq_chip *chip = irq_desc_get_chip(desc);
 | 
			
		||||
	u32 status;
 | 
			
		||||
	unsigned int idx;
 | 
			
		||||
 | 
			
		||||
	chained_irq_enter(chip, desc);
 | 
			
		||||
 | 
			
		||||
	status = __raw_readl(b->base + IRQSTAT);
 | 
			
		||||
	for (idx = 0; idx < b->n_words; idx++) {
 | 
			
		||||
		int base = idx * IRQS_PER_WORD;
 | 
			
		||||
		struct irq_chip_generic *gc =
 | 
			
		||||
			irq_get_domain_generic_chip(b->domain, base);
 | 
			
		||||
		unsigned long pending;
 | 
			
		||||
		int hwirq;
 | 
			
		||||
 | 
			
		||||
	if (status == 0) {
 | 
			
		||||
		do_bad_IRQ(irq, desc);
 | 
			
		||||
		goto out;
 | 
			
		||||
		irq_gc_lock(gc);
 | 
			
		||||
		pending = irq_reg_readl(gc, IRQSTAT) & gc->mask_cache;
 | 
			
		||||
		irq_gc_unlock(gc);
 | 
			
		||||
 | 
			
		||||
		for_each_set_bit(hwirq, &pending, IRQS_PER_WORD) {
 | 
			
		||||
			generic_handle_irq(irq_find_mapping(b->domain,
 | 
			
		||||
					   base + hwirq));
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	do {
 | 
			
		||||
		irq = ffs(status) - 1;
 | 
			
		||||
		status &= ~(1 << irq);
 | 
			
		||||
		generic_handle_irq(irq_find_mapping(b->domain, irq));
 | 
			
		||||
	} while (status);
 | 
			
		||||
 | 
			
		||||
out:
 | 
			
		||||
	chained_irq_exit(chip, desc);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -71,26 +77,20 @@ static void bcm7120_l2_intc_suspend(struct irq_data *d)
 | 
			
		||||
{
 | 
			
		||||
	struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d);
 | 
			
		||||
	struct bcm7120_l2_intc_data *b = gc->private;
 | 
			
		||||
	u32 reg;
 | 
			
		||||
 | 
			
		||||
	irq_gc_lock(gc);
 | 
			
		||||
	/* Save the current mask and the interrupt forward mask */
 | 
			
		||||
	b->saved_mask = __raw_readl(b->base) | b->irq_fwd_mask;
 | 
			
		||||
	if (b->can_wake) {
 | 
			
		||||
		reg = b->saved_mask | gc->wake_active;
 | 
			
		||||
		__raw_writel(reg, b->base);
 | 
			
		||||
	}
 | 
			
		||||
	if (b->can_wake)
 | 
			
		||||
		irq_reg_writel(gc, gc->mask_cache | gc->wake_active, IRQEN);
 | 
			
		||||
	irq_gc_unlock(gc);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void bcm7120_l2_intc_resume(struct irq_data *d)
 | 
			
		||||
{
 | 
			
		||||
	struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d);
 | 
			
		||||
	struct bcm7120_l2_intc_data *b = gc->private;
 | 
			
		||||
 | 
			
		||||
	/* Restore the saved mask */
 | 
			
		||||
	irq_gc_lock(gc);
 | 
			
		||||
	__raw_writel(b->saved_mask, b->base);
 | 
			
		||||
	irq_reg_writel(gc, gc->mask_cache, IRQEN);
 | 
			
		||||
	irq_gc_unlock(gc);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -99,6 +99,7 @@ static int bcm7120_l2_intc_init_one(struct device_node *dn,
 | 
			
		||||
					int irq, const __be32 *map_mask)
 | 
			
		||||
{
 | 
			
		||||
	int parent_irq;
 | 
			
		||||
	unsigned int idx;
 | 
			
		||||
 | 
			
		||||
	parent_irq = irq_of_parse_and_map(dn, irq);
 | 
			
		||||
	if (!parent_irq) {
 | 
			
		||||
@ -106,7 +107,12 @@ static int bcm7120_l2_intc_init_one(struct device_node *dn,
 | 
			
		||||
		return -EINVAL;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	data->irq_map_mask |= be32_to_cpup(map_mask + irq);
 | 
			
		||||
	/* For multiple parent IRQs with multiple words, this looks like:
 | 
			
		||||
	 * <irq0_w0 irq0_w1 irq1_w0 irq1_w1 ...>
 | 
			
		||||
	 */
 | 
			
		||||
	for (idx = 0; idx < data->n_words; idx++)
 | 
			
		||||
		data->irq_map_mask[idx] |=
 | 
			
		||||
			be32_to_cpup(map_mask + irq * data->n_words + idx);
 | 
			
		||||
 | 
			
		||||
	irq_set_handler_data(parent_irq, data);
 | 
			
		||||
	irq_set_chained_handler(parent_irq, bcm7120_l2_intc_irq_handle);
 | 
			
		||||
@ -123,26 +129,41 @@ int __init bcm7120_l2_intc_of_init(struct device_node *dn,
 | 
			
		||||
	struct irq_chip_type *ct;
 | 
			
		||||
	const __be32 *map_mask;
 | 
			
		||||
	int num_parent_irqs;
 | 
			
		||||
	int ret = 0, len, irq;
 | 
			
		||||
	int ret = 0, len;
 | 
			
		||||
	unsigned int idx, irq, flags;
 | 
			
		||||
 | 
			
		||||
	data = kzalloc(sizeof(*data), GFP_KERNEL);
 | 
			
		||||
	if (!data)
 | 
			
		||||
		return -ENOMEM;
 | 
			
		||||
 | 
			
		||||
	data->base = of_iomap(dn, 0);
 | 
			
		||||
	if (!data->base) {
 | 
			
		||||
	for (idx = 0; idx < MAX_WORDS; idx++) {
 | 
			
		||||
		data->base[idx] = of_iomap(dn, idx);
 | 
			
		||||
		if (!data->base[idx])
 | 
			
		||||
			break;
 | 
			
		||||
		data->n_words = idx + 1;
 | 
			
		||||
	}
 | 
			
		||||
	if (!data->n_words) {
 | 
			
		||||
		pr_err("failed to remap intc L2 registers\n");
 | 
			
		||||
		ret = -ENOMEM;
 | 
			
		||||
		goto out_free;
 | 
			
		||||
		goto out_unmap;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (of_property_read_u32(dn, "brcm,int-fwd-mask", &data->irq_fwd_mask))
 | 
			
		||||
		data->irq_fwd_mask = 0;
 | 
			
		||||
 | 
			
		||||
	/* Enable all interrupt specified in the interrupt forward mask and have
 | 
			
		||||
	 * the other disabled
 | 
			
		||||
	/* Enable all interrupts specified in the interrupt forward mask;
 | 
			
		||||
	 * disable all others.  If the property doesn't exist (-EINVAL),
 | 
			
		||||
	 * assume all zeroes.
 | 
			
		||||
	 */
 | 
			
		||||
	__raw_writel(data->irq_fwd_mask, data->base + IRQEN);
 | 
			
		||||
	ret = of_property_read_u32_array(dn, "brcm,int-fwd-mask",
 | 
			
		||||
					 data->irq_fwd_mask, data->n_words);
 | 
			
		||||
	if (ret == 0 || ret == -EINVAL) {
 | 
			
		||||
		for (idx = 0; idx < data->n_words; idx++)
 | 
			
		||||
			__raw_writel(data->irq_fwd_mask[idx],
 | 
			
		||||
				     data->base[idx] + IRQEN);
 | 
			
		||||
	} else {
 | 
			
		||||
		/* property exists but has the wrong number of words */
 | 
			
		||||
		pr_err("invalid int-fwd-mask property\n");
 | 
			
		||||
		ret = -EINVAL;
 | 
			
		||||
		goto out_unmap;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	num_parent_irqs = of_irq_count(dn);
 | 
			
		||||
	if (num_parent_irqs <= 0) {
 | 
			
		||||
@ -152,7 +173,8 @@ int __init bcm7120_l2_intc_of_init(struct device_node *dn,
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	map_mask = of_get_property(dn, "brcm,int-map-mask", &len);
 | 
			
		||||
	if (!map_mask || (len != (sizeof(*map_mask) * num_parent_irqs))) {
 | 
			
		||||
	if (!map_mask ||
 | 
			
		||||
	    (len != (sizeof(*map_mask) * num_parent_irqs * data->n_words))) {
 | 
			
		||||
		pr_err("invalid brcm,int-map-mask property\n");
 | 
			
		||||
		ret = -EINVAL;
 | 
			
		||||
		goto out_unmap;
 | 
			
		||||
@ -164,56 +186,70 @@ int __init bcm7120_l2_intc_of_init(struct device_node *dn,
 | 
			
		||||
			goto out_unmap;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	data->domain = irq_domain_add_linear(dn, 32,
 | 
			
		||||
					&irq_generic_chip_ops, NULL);
 | 
			
		||||
	data->domain = irq_domain_add_linear(dn, IRQS_PER_WORD * data->n_words,
 | 
			
		||||
					     &irq_generic_chip_ops, NULL);
 | 
			
		||||
	if (!data->domain) {
 | 
			
		||||
		ret = -ENOMEM;
 | 
			
		||||
		goto out_unmap;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	ret = irq_alloc_domain_generic_chips(data->domain, 32, 1,
 | 
			
		||||
				dn->full_name, handle_level_irq, clr, 0,
 | 
			
		||||
				IRQ_GC_INIT_MASK_CACHE);
 | 
			
		||||
	/* MIPS chips strapped for BE will automagically configure the
 | 
			
		||||
	 * peripheral registers for CPU-native byte order.
 | 
			
		||||
	 */
 | 
			
		||||
	flags = IRQ_GC_INIT_MASK_CACHE;
 | 
			
		||||
	if (IS_ENABLED(CONFIG_MIPS) && IS_ENABLED(CONFIG_CPU_BIG_ENDIAN))
 | 
			
		||||
		flags |= IRQ_GC_BE_IO;
 | 
			
		||||
 | 
			
		||||
	ret = irq_alloc_domain_generic_chips(data->domain, IRQS_PER_WORD, 1,
 | 
			
		||||
				dn->full_name, handle_level_irq, clr, 0, flags);
 | 
			
		||||
	if (ret) {
 | 
			
		||||
		pr_err("failed to allocate generic irq chip\n");
 | 
			
		||||
		goto out_free_domain;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	gc = irq_get_domain_generic_chip(data->domain, 0);
 | 
			
		||||
	gc->unused = 0xfffffff & ~data->irq_map_mask;
 | 
			
		||||
	gc->reg_base = data->base;
 | 
			
		||||
	gc->private = data;
 | 
			
		||||
	ct = gc->chip_types;
 | 
			
		||||
 | 
			
		||||
	ct->regs.mask = IRQEN;
 | 
			
		||||
	ct->chip.irq_mask = irq_gc_mask_clr_bit;
 | 
			
		||||
	ct->chip.irq_unmask = irq_gc_mask_set_bit;
 | 
			
		||||
	ct->chip.irq_ack = irq_gc_noop;
 | 
			
		||||
	ct->chip.irq_suspend = bcm7120_l2_intc_suspend;
 | 
			
		||||
	ct->chip.irq_resume = bcm7120_l2_intc_resume;
 | 
			
		||||
 | 
			
		||||
	if (of_property_read_bool(dn, "brcm,irq-can-wake")) {
 | 
			
		||||
	if (of_property_read_bool(dn, "brcm,irq-can-wake"))
 | 
			
		||||
		data->can_wake = true;
 | 
			
		||||
		/* This IRQ chip can wake the system, set all relevant child
 | 
			
		||||
		 * interupts in wake_enabled mask
 | 
			
		||||
		 */
 | 
			
		||||
		gc->wake_enabled = 0xffffffff;
 | 
			
		||||
		gc->wake_enabled &= ~gc->unused;
 | 
			
		||||
		ct->chip.irq_set_wake = irq_gc_set_wake;
 | 
			
		||||
 | 
			
		||||
	for (idx = 0; idx < data->n_words; idx++) {
 | 
			
		||||
		irq = idx * IRQS_PER_WORD;
 | 
			
		||||
		gc = irq_get_domain_generic_chip(data->domain, irq);
 | 
			
		||||
 | 
			
		||||
		gc->unused = 0xffffffff & ~data->irq_map_mask[idx];
 | 
			
		||||
		gc->reg_base = data->base[idx];
 | 
			
		||||
		gc->private = data;
 | 
			
		||||
		ct = gc->chip_types;
 | 
			
		||||
 | 
			
		||||
		ct->regs.mask = IRQEN;
 | 
			
		||||
		ct->chip.irq_mask = irq_gc_mask_clr_bit;
 | 
			
		||||
		ct->chip.irq_unmask = irq_gc_mask_set_bit;
 | 
			
		||||
		ct->chip.irq_ack = irq_gc_noop;
 | 
			
		||||
		ct->chip.irq_suspend = bcm7120_l2_intc_suspend;
 | 
			
		||||
		ct->chip.irq_resume = bcm7120_l2_intc_resume;
 | 
			
		||||
 | 
			
		||||
		if (data->can_wake) {
 | 
			
		||||
			/* This IRQ chip can wake the system, set all
 | 
			
		||||
			 * relevant child interupts in wake_enabled mask
 | 
			
		||||
			 */
 | 
			
		||||
			gc->wake_enabled = 0xffffffff;
 | 
			
		||||
			gc->wake_enabled &= ~gc->unused;
 | 
			
		||||
			ct->chip.irq_set_wake = irq_gc_set_wake;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	pr_info("registered BCM7120 L2 intc (mem: 0x%p, parent IRQ(s): %d)\n",
 | 
			
		||||
			data->base, num_parent_irqs);
 | 
			
		||||
			data->base[0], num_parent_irqs);
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
 | 
			
		||||
out_free_domain:
 | 
			
		||||
	irq_domain_remove(data->domain);
 | 
			
		||||
out_unmap:
 | 
			
		||||
	iounmap(data->base);
 | 
			
		||||
out_free:
 | 
			
		||||
	for (idx = 0; idx < MAX_WORDS; idx++) {
 | 
			
		||||
		if (data->base[idx])
 | 
			
		||||
			iounmap(data->base[idx]);
 | 
			
		||||
	}
 | 
			
		||||
	kfree(data);
 | 
			
		||||
	return ret;
 | 
			
		||||
}
 | 
			
		||||
IRQCHIP_DECLARE(brcmstb_l2_intc, "brcm,bcm7120-l2-intc",
 | 
			
		||||
IRQCHIP_DECLARE(bcm7120_l2_intc, "brcm,bcm7120-l2-intc",
 | 
			
		||||
		bcm7120_l2_intc_of_init);
 | 
			
		||||
 | 
			
		||||
@ -18,7 +18,9 @@
 | 
			
		||||
#include <linux/init.h>
 | 
			
		||||
#include <linux/slab.h>
 | 
			
		||||
#include <linux/module.h>
 | 
			
		||||
#include <linux/kconfig.h>
 | 
			
		||||
#include <linux/platform_device.h>
 | 
			
		||||
#include <linux/spinlock.h>
 | 
			
		||||
#include <linux/of.h>
 | 
			
		||||
#include <linux/of_irq.h>
 | 
			
		||||
#include <linux/of_address.h>
 | 
			
		||||
@ -30,8 +32,6 @@
 | 
			
		||||
#include <linux/irqchip.h>
 | 
			
		||||
#include <linux/irqchip/chained_irq.h>
 | 
			
		||||
 | 
			
		||||
#include <asm/mach/irq.h>
 | 
			
		||||
 | 
			
		||||
#include "irqchip.h"
 | 
			
		||||
 | 
			
		||||
/* Register offsets in the L2 interrupt controller */
 | 
			
		||||
@ -54,23 +54,26 @@ struct brcmstb_l2_intc_data {
 | 
			
		||||
static void brcmstb_l2_intc_irq_handle(unsigned int irq, struct irq_desc *desc)
 | 
			
		||||
{
 | 
			
		||||
	struct brcmstb_l2_intc_data *b = irq_desc_get_handler_data(desc);
 | 
			
		||||
	struct irq_chip_generic *gc = irq_get_domain_generic_chip(b->domain, 0);
 | 
			
		||||
	struct irq_chip *chip = irq_desc_get_chip(desc);
 | 
			
		||||
	u32 status;
 | 
			
		||||
 | 
			
		||||
	chained_irq_enter(chip, desc);
 | 
			
		||||
 | 
			
		||||
	status = __raw_readl(b->base + CPU_STATUS) &
 | 
			
		||||
		~(__raw_readl(b->base + CPU_MASK_STATUS));
 | 
			
		||||
	status = irq_reg_readl(gc, CPU_STATUS) &
 | 
			
		||||
		~(irq_reg_readl(gc, CPU_MASK_STATUS));
 | 
			
		||||
 | 
			
		||||
	if (status == 0) {
 | 
			
		||||
		do_bad_IRQ(irq, desc);
 | 
			
		||||
		raw_spin_lock(&desc->lock);
 | 
			
		||||
		handle_bad_irq(irq, desc);
 | 
			
		||||
		raw_spin_unlock(&desc->lock);
 | 
			
		||||
		goto out;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	do {
 | 
			
		||||
		irq = ffs(status) - 1;
 | 
			
		||||
		/* ack at our level */
 | 
			
		||||
		__raw_writel(1 << irq, b->base + CPU_CLEAR);
 | 
			
		||||
		irq_reg_writel(gc, 1 << irq, CPU_CLEAR);
 | 
			
		||||
		status &= ~(1 << irq);
 | 
			
		||||
		generic_handle_irq(irq_find_mapping(b->domain, irq));
 | 
			
		||||
	} while (status);
 | 
			
		||||
@ -85,12 +88,12 @@ static void brcmstb_l2_intc_suspend(struct irq_data *d)
 | 
			
		||||
 | 
			
		||||
	irq_gc_lock(gc);
 | 
			
		||||
	/* Save the current mask */
 | 
			
		||||
	b->saved_mask = __raw_readl(b->base + CPU_MASK_STATUS);
 | 
			
		||||
	b->saved_mask = irq_reg_readl(gc, CPU_MASK_STATUS);
 | 
			
		||||
 | 
			
		||||
	if (b->can_wake) {
 | 
			
		||||
		/* Program the wakeup mask */
 | 
			
		||||
		__raw_writel(~gc->wake_active, b->base + CPU_MASK_SET);
 | 
			
		||||
		__raw_writel(gc->wake_active, b->base + CPU_MASK_CLEAR);
 | 
			
		||||
		irq_reg_writel(gc, ~gc->wake_active, CPU_MASK_SET);
 | 
			
		||||
		irq_reg_writel(gc, gc->wake_active, CPU_MASK_CLEAR);
 | 
			
		||||
	}
 | 
			
		||||
	irq_gc_unlock(gc);
 | 
			
		||||
}
 | 
			
		||||
@ -102,11 +105,11 @@ static void brcmstb_l2_intc_resume(struct irq_data *d)
 | 
			
		||||
 | 
			
		||||
	irq_gc_lock(gc);
 | 
			
		||||
	/* Clear unmasked non-wakeup interrupts */
 | 
			
		||||
	__raw_writel(~b->saved_mask & ~gc->wake_active, b->base + CPU_CLEAR);
 | 
			
		||||
	irq_reg_writel(gc, ~b->saved_mask & ~gc->wake_active, CPU_CLEAR);
 | 
			
		||||
 | 
			
		||||
	/* Restore the saved mask */
 | 
			
		||||
	__raw_writel(b->saved_mask, b->base + CPU_MASK_SET);
 | 
			
		||||
	__raw_writel(~b->saved_mask, b->base + CPU_MASK_CLEAR);
 | 
			
		||||
	irq_reg_writel(gc, b->saved_mask, CPU_MASK_SET);
 | 
			
		||||
	irq_reg_writel(gc, ~b->saved_mask, CPU_MASK_CLEAR);
 | 
			
		||||
	irq_gc_unlock(gc);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -118,6 +121,7 @@ int __init brcmstb_l2_intc_of_init(struct device_node *np,
 | 
			
		||||
	struct irq_chip_generic *gc;
 | 
			
		||||
	struct irq_chip_type *ct;
 | 
			
		||||
	int ret;
 | 
			
		||||
	unsigned int flags;
 | 
			
		||||
 | 
			
		||||
	data = kzalloc(sizeof(*data), GFP_KERNEL);
 | 
			
		||||
	if (!data)
 | 
			
		||||
@ -131,8 +135,8 @@ int __init brcmstb_l2_intc_of_init(struct device_node *np,
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* Disable all interrupts by default */
 | 
			
		||||
	__raw_writel(0xffffffff, data->base + CPU_MASK_SET);
 | 
			
		||||
	__raw_writel(0xffffffff, data->base + CPU_CLEAR);
 | 
			
		||||
	writel(0xffffffff, data->base + CPU_MASK_SET);
 | 
			
		||||
	writel(0xffffffff, data->base + CPU_CLEAR);
 | 
			
		||||
 | 
			
		||||
	data->parent_irq = irq_of_parse_and_map(np, 0);
 | 
			
		||||
	if (!data->parent_irq) {
 | 
			
		||||
@ -148,9 +152,16 @@ int __init brcmstb_l2_intc_of_init(struct device_node *np,
 | 
			
		||||
		goto out_unmap;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* MIPS chips strapped for BE will automagically configure the
 | 
			
		||||
	 * peripheral registers for CPU-native byte order.
 | 
			
		||||
	 */
 | 
			
		||||
	flags = 0;
 | 
			
		||||
	if (IS_ENABLED(CONFIG_MIPS) && IS_ENABLED(CONFIG_CPU_BIG_ENDIAN))
 | 
			
		||||
		flags |= IRQ_GC_BE_IO;
 | 
			
		||||
 | 
			
		||||
	/* Allocate a single Generic IRQ chip for this node */
 | 
			
		||||
	ret = irq_alloc_domain_generic_chips(data->domain, 32, 1,
 | 
			
		||||
				np->full_name, handle_edge_irq, clr, 0, 0);
 | 
			
		||||
				np->full_name, handle_edge_irq, clr, 0, flags);
 | 
			
		||||
	if (ret) {
 | 
			
		||||
		pr_err("failed to allocate generic irq chip\n");
 | 
			
		||||
		goto out_free_domain;
 | 
			
		||||
 | 
			
		||||
@ -50,6 +50,21 @@ static void dw_apb_ictl_handler(unsigned int irq, struct irq_desc *desc)
 | 
			
		||||
	chained_irq_exit(chip, desc);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#ifdef CONFIG_PM
 | 
			
		||||
static void dw_apb_ictl_resume(struct irq_data *d)
 | 
			
		||||
{
 | 
			
		||||
	struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d);
 | 
			
		||||
	struct irq_chip_type *ct = irq_data_get_chip_type(d);
 | 
			
		||||
 | 
			
		||||
	irq_gc_lock(gc);
 | 
			
		||||
	writel_relaxed(~0, gc->reg_base + ct->regs.enable);
 | 
			
		||||
	writel_relaxed(*ct->mask_cache, gc->reg_base + ct->regs.mask);
 | 
			
		||||
	irq_gc_unlock(gc);
 | 
			
		||||
}
 | 
			
		||||
#else
 | 
			
		||||
#define dw_apb_ictl_resume	NULL
 | 
			
		||||
#endif /* CONFIG_PM */
 | 
			
		||||
 | 
			
		||||
static int __init dw_apb_ictl_init(struct device_node *np,
 | 
			
		||||
				   struct device_node *parent)
 | 
			
		||||
{
 | 
			
		||||
@ -94,16 +109,16 @@ static int __init dw_apb_ictl_init(struct device_node *np,
 | 
			
		||||
	 */
 | 
			
		||||
 | 
			
		||||
	/* mask and enable all interrupts */
 | 
			
		||||
	writel(~0, iobase + APB_INT_MASK_L);
 | 
			
		||||
	writel(~0, iobase + APB_INT_MASK_H);
 | 
			
		||||
	writel(~0, iobase + APB_INT_ENABLE_L);
 | 
			
		||||
	writel(~0, iobase + APB_INT_ENABLE_H);
 | 
			
		||||
	writel_relaxed(~0, iobase + APB_INT_MASK_L);
 | 
			
		||||
	writel_relaxed(~0, iobase + APB_INT_MASK_H);
 | 
			
		||||
	writel_relaxed(~0, iobase + APB_INT_ENABLE_L);
 | 
			
		||||
	writel_relaxed(~0, iobase + APB_INT_ENABLE_H);
 | 
			
		||||
 | 
			
		||||
	reg = readl(iobase + APB_INT_ENABLE_H);
 | 
			
		||||
	reg = readl_relaxed(iobase + APB_INT_ENABLE_H);
 | 
			
		||||
	if (reg)
 | 
			
		||||
		nrirqs = 32 + fls(reg);
 | 
			
		||||
	else
 | 
			
		||||
		nrirqs = fls(readl(iobase + APB_INT_ENABLE_L));
 | 
			
		||||
		nrirqs = fls(readl_relaxed(iobase + APB_INT_ENABLE_L));
 | 
			
		||||
 | 
			
		||||
	domain = irq_domain_add_linear(np, nrirqs,
 | 
			
		||||
				       &irq_generic_chip_ops, NULL);
 | 
			
		||||
@ -115,6 +130,7 @@ static int __init dw_apb_ictl_init(struct device_node *np,
 | 
			
		||||
 | 
			
		||||
	ret = irq_alloc_domain_generic_chips(domain, 32, (nrirqs > 32) ? 2 : 1,
 | 
			
		||||
					     np->name, handle_level_irq, clr, 0,
 | 
			
		||||
					     IRQ_GC_MASK_CACHE_PER_TYPE |
 | 
			
		||||
					     IRQ_GC_INIT_MASK_CACHE);
 | 
			
		||||
	if (ret) {
 | 
			
		||||
		pr_err("%s: unable to alloc irq domain gc\n", np->full_name);
 | 
			
		||||
@ -126,13 +142,17 @@ static int __init dw_apb_ictl_init(struct device_node *np,
 | 
			
		||||
	gc->reg_base = iobase;
 | 
			
		||||
 | 
			
		||||
	gc->chip_types[0].regs.mask = APB_INT_MASK_L;
 | 
			
		||||
	gc->chip_types[0].regs.enable = APB_INT_ENABLE_L;
 | 
			
		||||
	gc->chip_types[0].chip.irq_mask = irq_gc_mask_set_bit;
 | 
			
		||||
	gc->chip_types[0].chip.irq_unmask = irq_gc_mask_clr_bit;
 | 
			
		||||
	gc->chip_types[0].chip.irq_resume = dw_apb_ictl_resume;
 | 
			
		||||
 | 
			
		||||
	if (nrirqs > 32) {
 | 
			
		||||
		gc->chip_types[1].regs.mask = APB_INT_MASK_H;
 | 
			
		||||
		gc->chip_types[1].regs.enable = APB_INT_ENABLE_H;
 | 
			
		||||
		gc->chip_types[1].chip.irq_mask = irq_gc_mask_set_bit;
 | 
			
		||||
		gc->chip_types[1].chip.irq_unmask = irq_gc_mask_clr_bit;
 | 
			
		||||
		gc->chip_types[1].chip.irq_resume = dw_apb_ictl_resume;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	irq_set_handler_data(irq, gc);
 | 
			
		||||
 | 
			
		||||
@ -176,8 +176,7 @@ static void __exception_irq_entry hip04_handle_irq(struct pt_regs *regs)
 | 
			
		||||
		irqnr = irqstat & GICC_IAR_INT_ID_MASK;
 | 
			
		||||
 | 
			
		||||
		if (likely(irqnr > 15 && irqnr <= HIP04_MAX_IRQS)) {
 | 
			
		||||
			irqnr = irq_find_mapping(hip04_data.domain, irqnr);
 | 
			
		||||
			handle_IRQ(irqnr, regs);
 | 
			
		||||
			handle_domain_irq(hip04_data.domain, irqnr, regs);
 | 
			
		||||
			continue;
 | 
			
		||||
		}
 | 
			
		||||
		if (irqnr < 16) {
 | 
			
		||||
 | 
			
		||||
@ -50,12 +50,12 @@ static struct sunxi_sc_nmi_reg_offs sun6i_reg_offs = {
 | 
			
		||||
static inline void sunxi_sc_nmi_write(struct irq_chip_generic *gc, u32 off,
 | 
			
		||||
				      u32 val)
 | 
			
		||||
{
 | 
			
		||||
	irq_reg_writel(val, gc->reg_base + off);
 | 
			
		||||
	irq_reg_writel(gc, val, off);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline u32 sunxi_sc_nmi_read(struct irq_chip_generic *gc, u32 off)
 | 
			
		||||
{
 | 
			
		||||
	return irq_reg_readl(gc->reg_base + off);
 | 
			
		||||
	return irq_reg_readl(gc, off);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void sunxi_sc_nmi_handle_irq(unsigned int irq, struct irq_desc *desc)
 | 
			
		||||
 | 
			
		||||
@ -43,12 +43,12 @@
 | 
			
		||||
static inline void ab_irqctl_writereg(struct irq_chip_generic *gc, u32 reg,
 | 
			
		||||
	u32 val)
 | 
			
		||||
{
 | 
			
		||||
	irq_reg_writel(val, gc->reg_base + reg);
 | 
			
		||||
	irq_reg_writel(gc, val, reg);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline u32 ab_irqctl_readreg(struct irq_chip_generic *gc, u32 reg)
 | 
			
		||||
{
 | 
			
		||||
	return irq_reg_readl(gc->reg_base + reg);
 | 
			
		||||
	return irq_reg_readl(gc, reg);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int tb10x_irq_set_type(struct irq_data *data, unsigned int flow_type)
 | 
			
		||||
 | 
			
		||||
@ -20,6 +20,7 @@
 | 
			
		||||
#include <linux/errno.h>
 | 
			
		||||
#include <linux/topology.h>
 | 
			
		||||
#include <linux/wait.h>
 | 
			
		||||
#include <linux/io.h>
 | 
			
		||||
 | 
			
		||||
#include <asm/irq.h>
 | 
			
		||||
#include <asm/ptrace.h>
 | 
			
		||||
@ -639,13 +640,6 @@ void arch_teardown_hwirq(unsigned int irq);
 | 
			
		||||
void irq_init_desc(unsigned int irq);
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#ifndef irq_reg_writel
 | 
			
		||||
# define irq_reg_writel(val, addr)	writel(val, addr)
 | 
			
		||||
#endif
 | 
			
		||||
#ifndef irq_reg_readl
 | 
			
		||||
# define irq_reg_readl(addr)		readl(addr)
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * struct irq_chip_regs - register offsets for struct irq_gci
 | 
			
		||||
 * @enable:	Enable register offset to reg_base
 | 
			
		||||
@ -692,6 +686,8 @@ struct irq_chip_type {
 | 
			
		||||
 * struct irq_chip_generic - Generic irq chip data structure
 | 
			
		||||
 * @lock:		Lock to protect register and cache data access
 | 
			
		||||
 * @reg_base:		Register base address (virtual)
 | 
			
		||||
 * @reg_readl:		Alternate I/O accessor (defaults to readl if NULL)
 | 
			
		||||
 * @reg_writel:		Alternate I/O accessor (defaults to writel if NULL)
 | 
			
		||||
 * @irq_base:		Interrupt base nr for this chip
 | 
			
		||||
 * @irq_cnt:		Number of interrupts handled by this chip
 | 
			
		||||
 * @mask_cache:		Cached mask register shared between all chip types
 | 
			
		||||
@ -716,6 +712,8 @@ struct irq_chip_type {
 | 
			
		||||
struct irq_chip_generic {
 | 
			
		||||
	raw_spinlock_t		lock;
 | 
			
		||||
	void __iomem		*reg_base;
 | 
			
		||||
	u32			(*reg_readl)(void __iomem *addr);
 | 
			
		||||
	void			(*reg_writel)(u32 val, void __iomem *addr);
 | 
			
		||||
	unsigned int		irq_base;
 | 
			
		||||
	unsigned int		irq_cnt;
 | 
			
		||||
	u32			mask_cache;
 | 
			
		||||
@ -740,12 +738,14 @@ struct irq_chip_generic {
 | 
			
		||||
 *				the parent irq. Usually GPIO implementations
 | 
			
		||||
 * @IRQ_GC_MASK_CACHE_PER_TYPE:	Mask cache is chip type private
 | 
			
		||||
 * @IRQ_GC_NO_MASK:		Do not calculate irq_data->mask
 | 
			
		||||
 * @IRQ_GC_BE_IO:		Use big-endian register accesses (default: LE)
 | 
			
		||||
 */
 | 
			
		||||
enum irq_gc_flags {
 | 
			
		||||
	IRQ_GC_INIT_MASK_CACHE		= 1 << 0,
 | 
			
		||||
	IRQ_GC_INIT_NESTED_LOCK		= 1 << 1,
 | 
			
		||||
	IRQ_GC_MASK_CACHE_PER_TYPE	= 1 << 2,
 | 
			
		||||
	IRQ_GC_NO_MASK			= 1 << 3,
 | 
			
		||||
	IRQ_GC_BE_IO			= 1 << 4,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
@ -821,4 +821,22 @@ static inline void irq_gc_lock(struct irq_chip_generic *gc) { }
 | 
			
		||||
static inline void irq_gc_unlock(struct irq_chip_generic *gc) { }
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
static inline void irq_reg_writel(struct irq_chip_generic *gc,
 | 
			
		||||
				  u32 val, int reg_offset)
 | 
			
		||||
{
 | 
			
		||||
	if (gc->reg_writel)
 | 
			
		||||
		gc->reg_writel(val, gc->reg_base + reg_offset);
 | 
			
		||||
	else
 | 
			
		||||
		writel(val, gc->reg_base + reg_offset);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline u32 irq_reg_readl(struct irq_chip_generic *gc,
 | 
			
		||||
				int reg_offset)
 | 
			
		||||
{
 | 
			
		||||
	if (gc->reg_readl)
 | 
			
		||||
		return gc->reg_readl(gc->reg_base + reg_offset);
 | 
			
		||||
	else
 | 
			
		||||
		return readl(gc->reg_base + reg_offset);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#endif /* _LINUX_IRQ_H */
 | 
			
		||||
 | 
			
		||||
@ -39,7 +39,7 @@ void irq_gc_mask_disable_reg(struct irq_data *d)
 | 
			
		||||
	u32 mask = d->mask;
 | 
			
		||||
 | 
			
		||||
	irq_gc_lock(gc);
 | 
			
		||||
	irq_reg_writel(mask, gc->reg_base + ct->regs.disable);
 | 
			
		||||
	irq_reg_writel(gc, mask, ct->regs.disable);
 | 
			
		||||
	*ct->mask_cache &= ~mask;
 | 
			
		||||
	irq_gc_unlock(gc);
 | 
			
		||||
}
 | 
			
		||||
@ -59,7 +59,7 @@ void irq_gc_mask_set_bit(struct irq_data *d)
 | 
			
		||||
 | 
			
		||||
	irq_gc_lock(gc);
 | 
			
		||||
	*ct->mask_cache |= mask;
 | 
			
		||||
	irq_reg_writel(*ct->mask_cache, gc->reg_base + ct->regs.mask);
 | 
			
		||||
	irq_reg_writel(gc, *ct->mask_cache, ct->regs.mask);
 | 
			
		||||
	irq_gc_unlock(gc);
 | 
			
		||||
}
 | 
			
		||||
EXPORT_SYMBOL_GPL(irq_gc_mask_set_bit);
 | 
			
		||||
@ -79,7 +79,7 @@ void irq_gc_mask_clr_bit(struct irq_data *d)
 | 
			
		||||
 | 
			
		||||
	irq_gc_lock(gc);
 | 
			
		||||
	*ct->mask_cache &= ~mask;
 | 
			
		||||
	irq_reg_writel(*ct->mask_cache, gc->reg_base + ct->regs.mask);
 | 
			
		||||
	irq_reg_writel(gc, *ct->mask_cache, ct->regs.mask);
 | 
			
		||||
	irq_gc_unlock(gc);
 | 
			
		||||
}
 | 
			
		||||
EXPORT_SYMBOL_GPL(irq_gc_mask_clr_bit);
 | 
			
		||||
@ -98,7 +98,7 @@ void irq_gc_unmask_enable_reg(struct irq_data *d)
 | 
			
		||||
	u32 mask = d->mask;
 | 
			
		||||
 | 
			
		||||
	irq_gc_lock(gc);
 | 
			
		||||
	irq_reg_writel(mask, gc->reg_base + ct->regs.enable);
 | 
			
		||||
	irq_reg_writel(gc, mask, ct->regs.enable);
 | 
			
		||||
	*ct->mask_cache |= mask;
 | 
			
		||||
	irq_gc_unlock(gc);
 | 
			
		||||
}
 | 
			
		||||
@ -114,7 +114,7 @@ void irq_gc_ack_set_bit(struct irq_data *d)
 | 
			
		||||
	u32 mask = d->mask;
 | 
			
		||||
 | 
			
		||||
	irq_gc_lock(gc);
 | 
			
		||||
	irq_reg_writel(mask, gc->reg_base + ct->regs.ack);
 | 
			
		||||
	irq_reg_writel(gc, mask, ct->regs.ack);
 | 
			
		||||
	irq_gc_unlock(gc);
 | 
			
		||||
}
 | 
			
		||||
EXPORT_SYMBOL_GPL(irq_gc_ack_set_bit);
 | 
			
		||||
@ -130,7 +130,7 @@ void irq_gc_ack_clr_bit(struct irq_data *d)
 | 
			
		||||
	u32 mask = ~d->mask;
 | 
			
		||||
 | 
			
		||||
	irq_gc_lock(gc);
 | 
			
		||||
	irq_reg_writel(mask, gc->reg_base + ct->regs.ack);
 | 
			
		||||
	irq_reg_writel(gc, mask, ct->regs.ack);
 | 
			
		||||
	irq_gc_unlock(gc);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -145,8 +145,8 @@ void irq_gc_mask_disable_reg_and_ack(struct irq_data *d)
 | 
			
		||||
	u32 mask = d->mask;
 | 
			
		||||
 | 
			
		||||
	irq_gc_lock(gc);
 | 
			
		||||
	irq_reg_writel(mask, gc->reg_base + ct->regs.mask);
 | 
			
		||||
	irq_reg_writel(mask, gc->reg_base + ct->regs.ack);
 | 
			
		||||
	irq_reg_writel(gc, mask, ct->regs.mask);
 | 
			
		||||
	irq_reg_writel(gc, mask, ct->regs.ack);
 | 
			
		||||
	irq_gc_unlock(gc);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -161,7 +161,7 @@ void irq_gc_eoi(struct irq_data *d)
 | 
			
		||||
	u32 mask = d->mask;
 | 
			
		||||
 | 
			
		||||
	irq_gc_lock(gc);
 | 
			
		||||
	irq_reg_writel(mask, gc->reg_base + ct->regs.eoi);
 | 
			
		||||
	irq_reg_writel(gc, mask, ct->regs.eoi);
 | 
			
		||||
	irq_gc_unlock(gc);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -191,6 +191,16 @@ int irq_gc_set_wake(struct irq_data *d, unsigned int on)
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static u32 irq_readl_be(void __iomem *addr)
 | 
			
		||||
{
 | 
			
		||||
	return ioread32be(addr);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void irq_writel_be(u32 val, void __iomem *addr)
 | 
			
		||||
{
 | 
			
		||||
	iowrite32be(val, addr);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
irq_init_generic_chip(struct irq_chip_generic *gc, const char *name,
 | 
			
		||||
		      int num_ct, unsigned int irq_base,
 | 
			
		||||
@ -245,7 +255,7 @@ irq_gc_init_mask_cache(struct irq_chip_generic *gc, enum irq_gc_flags flags)
 | 
			
		||||
		}
 | 
			
		||||
		ct[i].mask_cache = mskptr;
 | 
			
		||||
		if (flags & IRQ_GC_INIT_MASK_CACHE)
 | 
			
		||||
			*mskptr = irq_reg_readl(gc->reg_base + mskreg);
 | 
			
		||||
			*mskptr = irq_reg_readl(gc, mskreg);
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -300,7 +310,13 @@ int irq_alloc_domain_generic_chips(struct irq_domain *d, int irqs_per_chip,
 | 
			
		||||
		dgc->gc[i] = gc = tmp;
 | 
			
		||||
		irq_init_generic_chip(gc, name, num_ct, i * irqs_per_chip,
 | 
			
		||||
				      NULL, handler);
 | 
			
		||||
 | 
			
		||||
		gc->domain = d;
 | 
			
		||||
		if (gcflags & IRQ_GC_BE_IO) {
 | 
			
		||||
			gc->reg_readl = &irq_readl_be;
 | 
			
		||||
			gc->reg_writel = &irq_writel_be;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		raw_spin_lock_irqsave(&gc_lock, flags);
 | 
			
		||||
		list_add_tail(&gc->list, &gc_list);
 | 
			
		||||
		raw_spin_unlock_irqrestore(&gc_lock, flags);
 | 
			
		||||
 | 
			
		||||
		Loading…
	
		Reference in New Issue
	
	Block a user