diff options
Diffstat (limited to 'drivers/irqchip/exynos-combiner.c')
| -rw-r--r-- | drivers/irqchip/exynos-combiner.c | 80 | 
1 files changed, 62 insertions, 18 deletions
diff --git a/drivers/irqchip/exynos-combiner.c b/drivers/irqchip/exynos-combiner.c index 6a520135150..02492ab20d2 100644 --- a/drivers/irqchip/exynos-combiner.c +++ b/drivers/irqchip/exynos-combiner.c @@ -32,6 +32,7 @@ struct combiner_chip_data {  	unsigned int irq_offset;  	unsigned int irq_mask;  	void __iomem *base; +	unsigned int parent_irq;  };  static struct irq_domain *combiner_irq_domain; @@ -88,22 +89,46 @@ static void combiner_handle_cascade_irq(unsigned int irq, struct irq_desc *desc)  	chained_irq_exit(chip, desc);  } +#ifdef CONFIG_SMP +static int combiner_set_affinity(struct irq_data *d, +				 const struct cpumask *mask_val, bool force) +{ +	struct combiner_chip_data *chip_data = irq_data_get_irq_chip_data(d); +	struct irq_chip *chip = irq_get_chip(chip_data->parent_irq); +	struct irq_data *data = irq_get_irq_data(chip_data->parent_irq); + +	if (chip && chip->irq_set_affinity) +		return chip->irq_set_affinity(data, mask_val, force); +	else +		return -EINVAL; +} +#endif +  static struct irq_chip combiner_chip = { -	.name		= "COMBINER", -	.irq_mask	= combiner_mask_irq, -	.irq_unmask	= combiner_unmask_irq, +	.name			= "COMBINER", +	.irq_mask		= combiner_mask_irq, +	.irq_unmask		= combiner_unmask_irq, +#ifdef CONFIG_SMP +	.irq_set_affinity	= combiner_set_affinity, +#endif  }; -static void __init combiner_cascade_irq(unsigned int combiner_nr, unsigned int irq) +static unsigned int max_combiner_nr(void)  { -	unsigned int max_nr; -  	if (soc_is_exynos5250()) -		max_nr = EXYNOS5_MAX_COMBINER_NR; +		return EXYNOS5_MAX_COMBINER_NR; +	else if (soc_is_exynos4412()) +		return EXYNOS4412_MAX_COMBINER_NR; +	else if (soc_is_exynos4212()) +		return EXYNOS4212_MAX_COMBINER_NR;  	else -		max_nr = EXYNOS4_MAX_COMBINER_NR; +		return EXYNOS4210_MAX_COMBINER_NR; +} -	if (combiner_nr >= max_nr) +static void __init combiner_cascade_irq(unsigned int combiner_nr, +					unsigned int irq) +{ +	if (combiner_nr >= max_combiner_nr())  		BUG();  	if (irq_set_handler_data(irq, &combiner_data[combiner_nr]) != 0)  		BUG(); @@ -111,12 +136,13 @@ static void __init combiner_cascade_irq(unsigned int combiner_nr, unsigned int i  }  static void __init combiner_init_one(unsigned int combiner_nr, -				     void __iomem *base) +				     void __iomem *base, unsigned int irq)  {  	combiner_data[combiner_nr].base = base;  	combiner_data[combiner_nr].irq_offset = irq_find_mapping(  		combiner_irq_domain, combiner_nr * MAX_IRQ_IN_COMBINER);  	combiner_data[combiner_nr].irq_mask = 0xff << ((combiner_nr % 4) << 3); +	combiner_data[combiner_nr].parent_irq = irq;  	/* Disable all interrupts */  	__raw_writel(combiner_data[combiner_nr].irq_mask, @@ -167,23 +193,38 @@ static struct irq_domain_ops combiner_irq_domain_ops = {  	.map	= combiner_irq_domain_map,  }; +static unsigned int exynos4x12_combiner_extra_irq(int group) +{ +	switch (group) { +	case 16: +		return IRQ_SPI(107); +	case 17: +		return IRQ_SPI(108); +	case 18: +		return IRQ_SPI(48); +	case 19: +		return IRQ_SPI(42); +	default: +		return 0; +	} +} +  void __init combiner_init(void __iomem *combiner_base,  			  struct device_node *np)  {  	int i, irq, irq_base;  	unsigned int max_nr, nr_irq; +	max_nr = max_combiner_nr(); +  	if (np) {  		if (of_property_read_u32(np, "samsung,combiner-nr", &max_nr)) { -			pr_warning("%s: number of combiners not specified, " +			pr_info("%s: number of combiners not specified, "  				"setting default as %d.\n", -				__func__, EXYNOS4_MAX_COMBINER_NR); -			max_nr = EXYNOS4_MAX_COMBINER_NR; +				__func__, max_nr);  		} -	} else { -		max_nr = soc_is_exynos5250() ? EXYNOS5_MAX_COMBINER_NR : -						EXYNOS4_MAX_COMBINER_NR;  	} +  	nr_irq = max_nr * MAX_IRQ_IN_COMBINER;  	irq_base = irq_alloc_descs(COMBINER_IRQ(0, 0), 1, nr_irq, 0); @@ -200,12 +241,15 @@ void __init combiner_init(void __iomem *combiner_base,  	}  	for (i = 0; i < max_nr; i++) { -		combiner_init_one(i, combiner_base + (i >> 2) * 0x10); -		irq = IRQ_SPI(i); +		if (i < EXYNOS4210_MAX_COMBINER_NR || soc_is_exynos5250()) +			irq = IRQ_SPI(i); +		else +			irq = exynos4x12_combiner_extra_irq(i);  #ifdef CONFIG_OF  		if (np)  			irq = irq_of_parse_and_map(np, i);  #endif +		combiner_init_one(i, combiner_base + (i >> 2) * 0x10, irq);  		combiner_cascade_irq(i, irq);  	}  }  |