diff options
author | Arnd Bergmann <arnd@arndb.de> | 2013-04-09 16:46:16 -0400 |
---|---|---|
committer | Arnd Bergmann <arnd@arndb.de> | 2013-04-09 16:46:16 -0400 |
commit | 0b8467ee39721340450482e87471ca4c0d6170f3 (patch) | |
tree | efabb381fdec807b3486c9bc8e93950c2d414b1c /drivers/irqchip | |
parent | 19ce4f4a03e52bc694dc837a4a832111cb4271b3 (diff) | |
parent | db35234ec7a7a10145cf472f68e1c73fbd48f79c (diff) |
Merge tag 'pmu-exynos-for-v3.10' of git://git.kernel.org/pub/scm/linux/kernel/git/kgene/linux-samsung into next/drivers
From Kukjin Kim <kgene.kim@samsung.com>:
add support arm-pmu for exynos4 and exynos5250
* tag 'pmu-exynos-for-v3.10' of git://git.kernel.org/pub/scm/linux/kernel/git/kgene/linux-samsung:
ARM: EXYNOS: Add arm-pmu DT binding for exynos421x
ARM: EXYNOS: Add arm-pmu DT binding for exynos5250
ARM: EXYNOS: Enable PMUs for exynos4
irqchip: exynos-combiner: Correct combined IRQs for exynos4
irqchip: exynos-combiner: Add set_irq_affinity function for combiner_irq
Signed-off-by: Arnd Bergmann <arnd@arndb.de>
Diffstat (limited to 'drivers/irqchip')
-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 04d86a9803f4..e8501dbaa0b7 100644 --- a/drivers/irqchip/exynos-combiner.c +++ b/drivers/irqchip/exynos-combiner.c | |||
@@ -31,6 +31,7 @@ struct combiner_chip_data { | |||
31 | unsigned int irq_offset; | 31 | unsigned int irq_offset; |
32 | unsigned int irq_mask; | 32 | unsigned int irq_mask; |
33 | void __iomem *base; | 33 | void __iomem *base; |
34 | unsigned int parent_irq; | ||
34 | }; | 35 | }; |
35 | 36 | ||
36 | static struct irq_domain *combiner_irq_domain; | 37 | static struct irq_domain *combiner_irq_domain; |
@@ -87,22 +88,46 @@ static void combiner_handle_cascade_irq(unsigned int irq, struct irq_desc *desc) | |||
87 | chained_irq_exit(chip, desc); | 88 | chained_irq_exit(chip, desc); |
88 | } | 89 | } |
89 | 90 | ||
91 | #ifdef CONFIG_SMP | ||
92 | static int combiner_set_affinity(struct irq_data *d, | ||
93 | const struct cpumask *mask_val, bool force) | ||
94 | { | ||
95 | struct combiner_chip_data *chip_data = irq_data_get_irq_chip_data(d); | ||
96 | struct irq_chip *chip = irq_get_chip(chip_data->parent_irq); | ||
97 | struct irq_data *data = irq_get_irq_data(chip_data->parent_irq); | ||
98 | |||
99 | if (chip && chip->irq_set_affinity) | ||
100 | return chip->irq_set_affinity(data, mask_val, force); | ||
101 | else | ||
102 | return -EINVAL; | ||
103 | } | ||
104 | #endif | ||
105 | |||
90 | static struct irq_chip combiner_chip = { | 106 | static struct irq_chip combiner_chip = { |
91 | .name = "COMBINER", | 107 | .name = "COMBINER", |
92 | .irq_mask = combiner_mask_irq, | 108 | .irq_mask = combiner_mask_irq, |
93 | .irq_unmask = combiner_unmask_irq, | 109 | .irq_unmask = combiner_unmask_irq, |
110 | #ifdef CONFIG_SMP | ||
111 | .irq_set_affinity = combiner_set_affinity, | ||
112 | #endif | ||
94 | }; | 113 | }; |
95 | 114 | ||
96 | static void __init combiner_cascade_irq(unsigned int combiner_nr, unsigned int irq) | 115 | static unsigned int max_combiner_nr(void) |
97 | { | 116 | { |
98 | unsigned int max_nr; | ||
99 | |||
100 | if (soc_is_exynos5250()) | 117 | if (soc_is_exynos5250()) |
101 | max_nr = EXYNOS5_MAX_COMBINER_NR; | 118 | return EXYNOS5_MAX_COMBINER_NR; |
119 | else if (soc_is_exynos4412()) | ||
120 | return EXYNOS4412_MAX_COMBINER_NR; | ||
121 | else if (soc_is_exynos4212()) | ||
122 | return EXYNOS4212_MAX_COMBINER_NR; | ||
102 | else | 123 | else |
103 | max_nr = EXYNOS4_MAX_COMBINER_NR; | 124 | return EXYNOS4210_MAX_COMBINER_NR; |
125 | } | ||
104 | 126 | ||
105 | if (combiner_nr >= max_nr) | 127 | static void __init combiner_cascade_irq(unsigned int combiner_nr, |
128 | unsigned int irq) | ||
129 | { | ||
130 | if (combiner_nr >= max_combiner_nr()) | ||
106 | BUG(); | 131 | BUG(); |
107 | if (irq_set_handler_data(irq, &combiner_data[combiner_nr]) != 0) | 132 | if (irq_set_handler_data(irq, &combiner_data[combiner_nr]) != 0) |
108 | BUG(); | 133 | BUG(); |
@@ -110,12 +135,13 @@ static void __init combiner_cascade_irq(unsigned int combiner_nr, unsigned int i | |||
110 | } | 135 | } |
111 | 136 | ||
112 | static void __init combiner_init_one(unsigned int combiner_nr, | 137 | static void __init combiner_init_one(unsigned int combiner_nr, |
113 | void __iomem *base) | 138 | void __iomem *base, unsigned int irq) |
114 | { | 139 | { |
115 | combiner_data[combiner_nr].base = base; | 140 | combiner_data[combiner_nr].base = base; |
116 | combiner_data[combiner_nr].irq_offset = irq_find_mapping( | 141 | combiner_data[combiner_nr].irq_offset = irq_find_mapping( |
117 | combiner_irq_domain, combiner_nr * MAX_IRQ_IN_COMBINER); | 142 | combiner_irq_domain, combiner_nr * MAX_IRQ_IN_COMBINER); |
118 | combiner_data[combiner_nr].irq_mask = 0xff << ((combiner_nr % 4) << 3); | 143 | combiner_data[combiner_nr].irq_mask = 0xff << ((combiner_nr % 4) << 3); |
144 | combiner_data[combiner_nr].parent_irq = irq; | ||
119 | 145 | ||
120 | /* Disable all interrupts */ | 146 | /* Disable all interrupts */ |
121 | __raw_writel(combiner_data[combiner_nr].irq_mask, | 147 | __raw_writel(combiner_data[combiner_nr].irq_mask, |
@@ -166,23 +192,38 @@ static struct irq_domain_ops combiner_irq_domain_ops = { | |||
166 | .map = combiner_irq_domain_map, | 192 | .map = combiner_irq_domain_map, |
167 | }; | 193 | }; |
168 | 194 | ||
195 | static unsigned int exynos4x12_combiner_extra_irq(int group) | ||
196 | { | ||
197 | switch (group) { | ||
198 | case 16: | ||
199 | return IRQ_SPI(107); | ||
200 | case 17: | ||
201 | return IRQ_SPI(108); | ||
202 | case 18: | ||
203 | return IRQ_SPI(48); | ||
204 | case 19: | ||
205 | return IRQ_SPI(42); | ||
206 | default: | ||
207 | return 0; | ||
208 | } | ||
209 | } | ||
210 | |||
169 | void __init combiner_init(void __iomem *combiner_base, | 211 | void __init combiner_init(void __iomem *combiner_base, |
170 | struct device_node *np) | 212 | struct device_node *np) |
171 | { | 213 | { |
172 | int i, irq, irq_base; | 214 | int i, irq, irq_base; |
173 | unsigned int max_nr, nr_irq; | 215 | unsigned int max_nr, nr_irq; |
174 | 216 | ||
217 | max_nr = max_combiner_nr(); | ||
218 | |||
175 | if (np) { | 219 | if (np) { |
176 | if (of_property_read_u32(np, "samsung,combiner-nr", &max_nr)) { | 220 | if (of_property_read_u32(np, "samsung,combiner-nr", &max_nr)) { |
177 | pr_warning("%s: number of combiners not specified, " | 221 | pr_info("%s: number of combiners not specified, " |
178 | "setting default as %d.\n", | 222 | "setting default as %d.\n", |
179 | __func__, EXYNOS4_MAX_COMBINER_NR); | 223 | __func__, max_nr); |
180 | max_nr = EXYNOS4_MAX_COMBINER_NR; | ||
181 | } | 224 | } |
182 | } else { | ||
183 | max_nr = soc_is_exynos5250() ? EXYNOS5_MAX_COMBINER_NR : | ||
184 | EXYNOS4_MAX_COMBINER_NR; | ||
185 | } | 225 | } |
226 | |||
186 | nr_irq = max_nr * MAX_IRQ_IN_COMBINER; | 227 | nr_irq = max_nr * MAX_IRQ_IN_COMBINER; |
187 | 228 | ||
188 | irq_base = irq_alloc_descs(COMBINER_IRQ(0, 0), 1, nr_irq, 0); | 229 | irq_base = irq_alloc_descs(COMBINER_IRQ(0, 0), 1, nr_irq, 0); |
@@ -199,12 +240,15 @@ void __init combiner_init(void __iomem *combiner_base, | |||
199 | } | 240 | } |
200 | 241 | ||
201 | for (i = 0; i < max_nr; i++) { | 242 | for (i = 0; i < max_nr; i++) { |
202 | combiner_init_one(i, combiner_base + (i >> 2) * 0x10); | 243 | if (i < EXYNOS4210_MAX_COMBINER_NR || soc_is_exynos5250()) |
203 | irq = IRQ_SPI(i); | 244 | irq = IRQ_SPI(i); |
245 | else | ||
246 | irq = exynos4x12_combiner_extra_irq(i); | ||
204 | #ifdef CONFIG_OF | 247 | #ifdef CONFIG_OF |
205 | if (np) | 248 | if (np) |
206 | irq = irq_of_parse_and_map(np, i); | 249 | irq = irq_of_parse_and_map(np, i); |
207 | #endif | 250 | #endif |
251 | combiner_init_one(i, combiner_base + (i >> 2) * 0x10, irq); | ||
208 | combiner_cascade_irq(i, irq); | 252 | combiner_cascade_irq(i, irq); |
209 | } | 253 | } |
210 | } | 254 | } |