aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'drivers')
-rw-r--r--drivers/bus/Kconfig7
-rw-r--r--drivers/bus/Makefile1
-rw-r--r--drivers/bus/ti-sysc.c583
-rw-r--r--drivers/clk/bcm/clk-bcm2835-aux.c1
-rw-r--r--drivers/clk/bcm/clk-bcm2835.c30
-rw-r--r--drivers/irqchip/irq-bcm2836.c79
6 files changed, 593 insertions, 108 deletions
diff --git a/drivers/bus/Kconfig b/drivers/bus/Kconfig
index 3e66f4cc1a59..fa94a85bf410 100644
--- a/drivers/bus/Kconfig
+++ b/drivers/bus/Kconfig
@@ -158,6 +158,13 @@ config TEGRA_GMI
158 Driver for the Tegra Generic Memory Interface bus which can be used 158 Driver for the Tegra Generic Memory Interface bus which can be used
159 to attach devices such as NOR, UART, FPGA and more. 159 to attach devices such as NOR, UART, FPGA and more.
160 160
161config TI_SYSC
162 bool "TI sysc interconnect target module driver"
163 depends on ARCH_OMAP2PLUS
164 help
165 Generic driver for Texas Instruments interconnect target module
166 found on many TI SoCs.
167
161config UNIPHIER_SYSTEM_BUS 168config UNIPHIER_SYSTEM_BUS
162 tristate "UniPhier System Bus driver" 169 tristate "UniPhier System Bus driver"
163 depends on ARCH_UNIPHIER && OF 170 depends on ARCH_UNIPHIER && OF
diff --git a/drivers/bus/Makefile b/drivers/bus/Makefile
index 3ae96cffabd5..94a079008cbe 100644
--- a/drivers/bus/Makefile
+++ b/drivers/bus/Makefile
@@ -21,6 +21,7 @@ obj-$(CONFIG_SUNXI_RSB) += sunxi-rsb.o
21obj-$(CONFIG_SIMPLE_PM_BUS) += simple-pm-bus.o 21obj-$(CONFIG_SIMPLE_PM_BUS) += simple-pm-bus.o
22obj-$(CONFIG_TEGRA_ACONNECT) += tegra-aconnect.o 22obj-$(CONFIG_TEGRA_ACONNECT) += tegra-aconnect.o
23obj-$(CONFIG_TEGRA_GMI) += tegra-gmi.o 23obj-$(CONFIG_TEGRA_GMI) += tegra-gmi.o
24obj-$(CONFIG_TI_SYSC) += ti-sysc.o
24obj-$(CONFIG_UNIPHIER_SYSTEM_BUS) += uniphier-system-bus.o 25obj-$(CONFIG_UNIPHIER_SYSTEM_BUS) += uniphier-system-bus.o
25obj-$(CONFIG_VEXPRESS_CONFIG) += vexpress-config.o 26obj-$(CONFIG_VEXPRESS_CONFIG) += vexpress-config.o
26 27
diff --git a/drivers/bus/ti-sysc.c b/drivers/bus/ti-sysc.c
new file mode 100644
index 000000000000..c3c76a1ea8a8
--- /dev/null
+++ b/drivers/bus/ti-sysc.c
@@ -0,0 +1,583 @@
1/*
2 * ti-sysc.c - Texas Instruments sysc interconnect target driver
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
7 *
8 * This program is distributed "as is" WITHOUT ANY WARRANTY of any
9 * kind, whether express or implied; without even the implied warranty
10 * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 */
13
14#include <linux/io.h>
15#include <linux/clk.h>
16#include <linux/module.h>
17#include <linux/platform_device.h>
18#include <linux/pm_runtime.h>
19#include <linux/of_address.h>
20#include <linux/of_platform.h>
21
22enum sysc_registers {
23 SYSC_REVISION,
24 SYSC_SYSCONFIG,
25 SYSC_SYSSTATUS,
26 SYSC_MAX_REGS,
27};
28
29static const char * const reg_names[] = { "rev", "sysc", "syss", };
30
31enum sysc_clocks {
32 SYSC_FCK,
33 SYSC_ICK,
34 SYSC_MAX_CLOCKS,
35};
36
37static const char * const clock_names[] = { "fck", "ick", };
38
39/**
40 * struct sysc - TI sysc interconnect target module registers and capabilities
41 * @dev: struct device pointer
42 * @module_pa: physical address of the interconnect target module
43 * @module_size: size of the interconnect target module
44 * @module_va: virtual address of the interconnect target module
45 * @offsets: register offsets from module base
46 * @clocks: clocks used by the interconnect target module
47 * @legacy_mode: configured for legacy mode if set
48 */
49struct sysc {
50 struct device *dev;
51 u64 module_pa;
52 u32 module_size;
53 void __iomem *module_va;
54 int offsets[SYSC_MAX_REGS];
55 struct clk *clocks[SYSC_MAX_CLOCKS];
56 const char *legacy_mode;
57};
58
59static u32 sysc_read_revision(struct sysc *ddata)
60{
61 return readl_relaxed(ddata->module_va +
62 ddata->offsets[SYSC_REVISION]);
63}
64
65static int sysc_get_one_clock(struct sysc *ddata,
66 enum sysc_clocks index)
67{
68 const char *name;
69 int error;
70
71 switch (index) {
72 case SYSC_FCK:
73 break;
74 case SYSC_ICK:
75 break;
76 default:
77 return -EINVAL;
78 }
79 name = clock_names[index];
80
81 ddata->clocks[index] = devm_clk_get(ddata->dev, name);
82 if (IS_ERR(ddata->clocks[index])) {
83 if (PTR_ERR(ddata->clocks[index]) == -ENOENT)
84 return 0;
85
86 dev_err(ddata->dev, "clock get error for %s: %li\n",
87 name, PTR_ERR(ddata->clocks[index]));
88
89 return PTR_ERR(ddata->clocks[index]);
90 }
91
92 error = clk_prepare(ddata->clocks[index]);
93 if (error) {
94 dev_err(ddata->dev, "clock prepare error for %s: %i\n",
95 name, error);
96
97 return error;
98 }
99
100 return 0;
101}
102
103static int sysc_get_clocks(struct sysc *ddata)
104{
105 int i, error;
106
107 if (ddata->legacy_mode)
108 return 0;
109
110 for (i = 0; i < SYSC_MAX_CLOCKS; i++) {
111 error = sysc_get_one_clock(ddata, i);
112 if (error && error != -ENOENT)
113 return error;
114 }
115
116 return 0;
117}
118
119/**
120 * sysc_parse_and_check_child_range - parses module IO region from ranges
121 * @ddata: device driver data
122 *
123 * In general we only need rev, syss, and sysc registers and not the whole
124 * module range. But we do want the offsets for these registers from the
125 * module base. This allows us to check them against the legacy hwmod
126 * platform data. Let's also check the ranges are configured properly.
127 */
128static int sysc_parse_and_check_child_range(struct sysc *ddata)
129{
130 struct device_node *np = ddata->dev->of_node;
131 const __be32 *ranges;
132 u32 nr_addr, nr_size;
133 int len, error;
134
135 ranges = of_get_property(np, "ranges", &len);
136 if (!ranges) {
137 dev_err(ddata->dev, "missing ranges for %pOF\n", np);
138
139 return -ENOENT;
140 }
141
142 len /= sizeof(*ranges);
143
144 if (len < 3) {
145 dev_err(ddata->dev, "incomplete ranges for %pOF\n", np);
146
147 return -EINVAL;
148 }
149
150 error = of_property_read_u32(np, "#address-cells", &nr_addr);
151 if (error)
152 return -ENOENT;
153
154 error = of_property_read_u32(np, "#size-cells", &nr_size);
155 if (error)
156 return -ENOENT;
157
158 if (nr_addr != 1 || nr_size != 1) {
159 dev_err(ddata->dev, "invalid ranges for %pOF\n", np);
160
161 return -EINVAL;
162 }
163
164 ranges++;
165 ddata->module_pa = of_translate_address(np, ranges++);
166 ddata->module_size = be32_to_cpup(ranges);
167
168 dev_dbg(ddata->dev, "interconnect target 0x%llx size 0x%x for %pOF\n",
169 ddata->module_pa, ddata->module_size, np);
170
171 return 0;
172}
173
174/**
175 * sysc_check_one_child - check child configuration
176 * @ddata: device driver data
177 * @np: child device node
178 *
179 * Let's avoid messy situations where we have new interconnect target
180 * node but children have "ti,hwmods". These belong to the interconnect
181 * target node and are managed by this driver.
182 */
183static int sysc_check_one_child(struct sysc *ddata,
184 struct device_node *np)
185{
186 const char *name;
187
188 name = of_get_property(np, "ti,hwmods", NULL);
189 if (name)
190 dev_warn(ddata->dev, "really a child ti,hwmods property?");
191
192 return 0;
193}
194
195static int sysc_check_children(struct sysc *ddata)
196{
197 struct device_node *child;
198 int error;
199
200 for_each_child_of_node(ddata->dev->of_node, child) {
201 error = sysc_check_one_child(ddata, child);
202 if (error)
203 return error;
204 }
205
206 return 0;
207}
208
209/**
210 * sysc_parse_one - parses the interconnect target module registers
211 * @ddata: device driver data
212 * @reg: register to parse
213 */
214static int sysc_parse_one(struct sysc *ddata, enum sysc_registers reg)
215{
216 struct resource *res;
217 const char *name;
218
219 switch (reg) {
220 case SYSC_REVISION:
221 case SYSC_SYSCONFIG:
222 case SYSC_SYSSTATUS:
223 name = reg_names[reg];
224 break;
225 default:
226 return -EINVAL;
227 }
228
229 res = platform_get_resource_byname(to_platform_device(ddata->dev),
230 IORESOURCE_MEM, name);
231 if (!res) {
232 dev_dbg(ddata->dev, "has no %s register\n", name);
233 ddata->offsets[reg] = -ENODEV;
234
235 return 0;
236 }
237
238 ddata->offsets[reg] = res->start - ddata->module_pa;
239
240 return 0;
241}
242
243static int sysc_parse_registers(struct sysc *ddata)
244{
245 int i, error;
246
247 for (i = 0; i < SYSC_MAX_REGS; i++) {
248 error = sysc_parse_one(ddata, i);
249 if (error)
250 return error;
251 }
252
253 return 0;
254}
255
256/**
257 * sysc_check_registers - check for misconfigured register overlaps
258 * @ddata: device driver data
259 */
260static int sysc_check_registers(struct sysc *ddata)
261{
262 int i, j, nr_regs = 0, nr_matches = 0;
263
264 for (i = 0; i < SYSC_MAX_REGS; i++) {
265 if (ddata->offsets[i] < 0)
266 continue;
267
268 if (ddata->offsets[i] > (ddata->module_size - 4)) {
269 dev_err(ddata->dev, "register outside module range");
270
271 return -EINVAL;
272 }
273
274 for (j = 0; j < SYSC_MAX_REGS; j++) {
275 if (ddata->offsets[j] < 0)
276 continue;
277
278 if (ddata->offsets[i] == ddata->offsets[j])
279 nr_matches++;
280 }
281 nr_regs++;
282 }
283
284 if (nr_regs < 1) {
285 dev_err(ddata->dev, "missing registers\n");
286
287 return -EINVAL;
288 }
289
290 if (nr_matches > nr_regs) {
291 dev_err(ddata->dev, "overlapping registers: (%i/%i)",
292 nr_regs, nr_matches);
293
294 return -EINVAL;
295 }
296
297 return 0;
298}
299
300/**
301 * syc_ioremap - ioremap register space for the interconnect target module
302 * @ddata: deviec driver data
303 *
304 * Note that the interconnect target module registers can be anywhere
305 * within the first child device address space. For example, SGX has
306 * them at offset 0x1fc00 in the 32MB module address space. We just
307 * what we need around the interconnect target module registers.
308 */
309static int sysc_ioremap(struct sysc *ddata)
310{
311 u32 size = 0;
312
313 if (ddata->offsets[SYSC_SYSSTATUS] >= 0)
314 size = ddata->offsets[SYSC_SYSSTATUS];
315 else if (ddata->offsets[SYSC_SYSCONFIG] >= 0)
316 size = ddata->offsets[SYSC_SYSCONFIG];
317 else if (ddata->offsets[SYSC_REVISION] >= 0)
318 size = ddata->offsets[SYSC_REVISION];
319 else
320 return -EINVAL;
321
322 size &= 0xfff00;
323 size += SZ_256;
324
325 ddata->module_va = devm_ioremap(ddata->dev,
326 ddata->module_pa,
327 size);
328 if (!ddata->module_va)
329 return -EIO;
330
331 return 0;
332}
333
334/**
335 * sysc_map_and_check_registers - ioremap and check device registers
336 * @ddata: device driver data
337 */
338static int sysc_map_and_check_registers(struct sysc *ddata)
339{
340 int error;
341
342 error = sysc_parse_and_check_child_range(ddata);
343 if (error)
344 return error;
345
346 error = sysc_check_children(ddata);
347 if (error)
348 return error;
349
350 error = sysc_parse_registers(ddata);
351 if (error)
352 return error;
353
354 error = sysc_ioremap(ddata);
355 if (error)
356 return error;
357
358 error = sysc_check_registers(ddata);
359 if (error)
360 return error;
361
362 return 0;
363}
364
365/**
366 * sysc_show_rev - read and show interconnect target module revision
367 * @bufp: buffer to print the information to
368 * @ddata: device driver data
369 */
370static int sysc_show_rev(char *bufp, struct sysc *ddata)
371{
372 int error, len;
373
374 if (ddata->offsets[SYSC_REVISION] < 0)
375 return sprintf(bufp, ":NA");
376
377 error = pm_runtime_get_sync(ddata->dev);
378 if (error < 0) {
379 pm_runtime_put_noidle(ddata->dev);
380
381 return 0;
382 }
383
384 len = sprintf(bufp, ":%08x", sysc_read_revision(ddata));
385
386 pm_runtime_mark_last_busy(ddata->dev);
387 pm_runtime_put_autosuspend(ddata->dev);
388
389 return len;
390}
391
392static int sysc_show_reg(struct sysc *ddata,
393 char *bufp, enum sysc_registers reg)
394{
395 if (ddata->offsets[reg] < 0)
396 return sprintf(bufp, ":NA");
397
398 return sprintf(bufp, ":%x", ddata->offsets[reg]);
399}
400
401/**
402 * sysc_show_registers - show information about interconnect target module
403 * @ddata: device driver data
404 */
405static void sysc_show_registers(struct sysc *ddata)
406{
407 char buf[128];
408 char *bufp = buf;
409 int i;
410
411 for (i = 0; i < SYSC_MAX_REGS; i++)
412 bufp += sysc_show_reg(ddata, bufp, i);
413
414 bufp += sysc_show_rev(bufp, ddata);
415
416 dev_dbg(ddata->dev, "%llx:%x%s\n",
417 ddata->module_pa, ddata->module_size,
418 buf);
419}
420
421static int __maybe_unused sysc_runtime_suspend(struct device *dev)
422{
423 struct sysc *ddata;
424 int i;
425
426 ddata = dev_get_drvdata(dev);
427
428 if (ddata->legacy_mode)
429 return 0;
430
431 for (i = 0; i < SYSC_MAX_CLOCKS; i++) {
432 if (IS_ERR_OR_NULL(ddata->clocks[i]))
433 continue;
434 clk_disable(ddata->clocks[i]);
435 }
436
437 return 0;
438}
439
440static int __maybe_unused sysc_runtime_resume(struct device *dev)
441{
442 struct sysc *ddata;
443 int i, error;
444
445 ddata = dev_get_drvdata(dev);
446
447 if (ddata->legacy_mode)
448 return 0;
449
450 for (i = 0; i < SYSC_MAX_CLOCKS; i++) {
451 if (IS_ERR_OR_NULL(ddata->clocks[i]))
452 continue;
453 error = clk_enable(ddata->clocks[i]);
454 if (error)
455 return error;
456 }
457
458 return 0;
459}
460
461static const struct dev_pm_ops sysc_pm_ops = {
462 SET_RUNTIME_PM_OPS(sysc_runtime_suspend,
463 sysc_runtime_resume,
464 NULL)
465};
466
467static void sysc_unprepare(struct sysc *ddata)
468{
469 int i;
470
471 for (i = 0; i < SYSC_MAX_CLOCKS; i++) {
472 if (!IS_ERR_OR_NULL(ddata->clocks[i]))
473 clk_unprepare(ddata->clocks[i]);
474 }
475}
476
477static int sysc_probe(struct platform_device *pdev)
478{
479 struct device_node *np = pdev->dev.of_node;
480 struct sysc *ddata;
481 int error;
482
483 ddata = devm_kzalloc(&pdev->dev, sizeof(*ddata), GFP_KERNEL);
484 if (!ddata)
485 return -ENOMEM;
486
487 ddata->dev = &pdev->dev;
488 ddata->legacy_mode = of_get_property(np, "ti,hwmods", NULL);
489
490 error = sysc_get_clocks(ddata);
491 if (error)
492 return error;
493
494 error = sysc_map_and_check_registers(ddata);
495 if (error)
496 goto unprepare;
497
498 platform_set_drvdata(pdev, ddata);
499
500 pm_runtime_enable(ddata->dev);
501 error = pm_runtime_get_sync(ddata->dev);
502 if (error < 0) {
503 pm_runtime_put_noidle(ddata->dev);
504 pm_runtime_disable(ddata->dev);
505 goto unprepare;
506 }
507
508 pm_runtime_use_autosuspend(ddata->dev);
509
510 sysc_show_registers(ddata);
511
512 error = of_platform_populate(ddata->dev->of_node,
513 NULL, NULL, ddata->dev);
514 if (error)
515 goto err;
516
517 pm_runtime_mark_last_busy(ddata->dev);
518 pm_runtime_put_autosuspend(ddata->dev);
519
520 return 0;
521
522err:
523 pm_runtime_dont_use_autosuspend(&pdev->dev);
524 pm_runtime_put_sync(&pdev->dev);
525 pm_runtime_disable(&pdev->dev);
526unprepare:
527 sysc_unprepare(ddata);
528
529 return error;
530}
531
532static int sysc_remove(struct platform_device *pdev)
533{
534 struct sysc *ddata = platform_get_drvdata(pdev);
535 int error;
536
537 error = pm_runtime_get_sync(ddata->dev);
538 if (error < 0) {
539 pm_runtime_put_noidle(ddata->dev);
540 pm_runtime_disable(ddata->dev);
541 goto unprepare;
542 }
543
544 of_platform_depopulate(&pdev->dev);
545
546 pm_runtime_dont_use_autosuspend(&pdev->dev);
547 pm_runtime_put_sync(&pdev->dev);
548 pm_runtime_disable(&pdev->dev);
549
550unprepare:
551 sysc_unprepare(ddata);
552
553 return 0;
554}
555
556static const struct of_device_id sysc_match[] = {
557 { .compatible = "ti,sysc-omap2" },
558 { .compatible = "ti,sysc-omap4" },
559 { .compatible = "ti,sysc-omap4-simple" },
560 { .compatible = "ti,sysc-omap3430-sr" },
561 { .compatible = "ti,sysc-omap3630-sr" },
562 { .compatible = "ti,sysc-omap4-sr" },
563 { .compatible = "ti,sysc-omap3-sham" },
564 { .compatible = "ti,sysc-omap-aes" },
565 { .compatible = "ti,sysc-mcasp" },
566 { .compatible = "ti,sysc-usb-host-fs" },
567 { },
568};
569MODULE_DEVICE_TABLE(of, sysc_match);
570
571static struct platform_driver sysc_driver = {
572 .probe = sysc_probe,
573 .remove = sysc_remove,
574 .driver = {
575 .name = "ti-sysc",
576 .of_match_table = sysc_match,
577 .pm = &sysc_pm_ops,
578 },
579};
580module_platform_driver(sysc_driver);
581
582MODULE_DESCRIPTION("TI sysc interconnect target driver");
583MODULE_LICENSE("GPL v2");
diff --git a/drivers/clk/bcm/clk-bcm2835-aux.c b/drivers/clk/bcm/clk-bcm2835-aux.c
index bd750cf2238d..77e276d61702 100644
--- a/drivers/clk/bcm/clk-bcm2835-aux.c
+++ b/drivers/clk/bcm/clk-bcm2835-aux.c
@@ -14,7 +14,6 @@
14 14
15#include <linux/clk.h> 15#include <linux/clk.h>
16#include <linux/clk-provider.h> 16#include <linux/clk-provider.h>
17#include <linux/clk/bcm2835.h>
18#include <linux/module.h> 17#include <linux/module.h>
19#include <linux/platform_device.h> 18#include <linux/platform_device.h>
20#include <dt-bindings/clock/bcm2835-aux.h> 19#include <dt-bindings/clock/bcm2835-aux.h>
diff --git a/drivers/clk/bcm/clk-bcm2835.c b/drivers/clk/bcm/clk-bcm2835.c
index 58ce6af8452d..44301a3d9963 100644
--- a/drivers/clk/bcm/clk-bcm2835.c
+++ b/drivers/clk/bcm/clk-bcm2835.c
@@ -37,7 +37,6 @@
37#include <linux/clk-provider.h> 37#include <linux/clk-provider.h>
38#include <linux/clkdev.h> 38#include <linux/clkdev.h>
39#include <linux/clk.h> 39#include <linux/clk.h>
40#include <linux/clk/bcm2835.h>
41#include <linux/debugfs.h> 40#include <linux/debugfs.h>
42#include <linux/delay.h> 41#include <linux/delay.h>
43#include <linux/module.h> 42#include <linux/module.h>
@@ -416,35 +415,6 @@ static int bcm2835_debugfs_regset(struct bcm2835_cprman *cprman, u32 base,
416 return regdump ? 0 : -ENOMEM; 415 return regdump ? 0 : -ENOMEM;
417} 416}
418 417
419/*
420 * These are fixed clocks. They're probably not all root clocks and it may
421 * be possible to turn them on and off but until this is mapped out better
422 * it's the only way they can be used.
423 */
424void __init bcm2835_init_clocks(void)
425{
426 struct clk_hw *hw;
427 int ret;
428
429 hw = clk_hw_register_fixed_rate(NULL, "apb_pclk", NULL, 0, 126000000);
430 if (IS_ERR(hw))
431 pr_err("apb_pclk not registered\n");
432
433 hw = clk_hw_register_fixed_rate(NULL, "uart0_pclk", NULL, 0, 3000000);
434 if (IS_ERR(hw))
435 pr_err("uart0_pclk not registered\n");
436 ret = clk_hw_register_clkdev(hw, NULL, "20201000.uart");
437 if (ret)
438 pr_err("uart0_pclk alias not registered\n");
439
440 hw = clk_hw_register_fixed_rate(NULL, "uart1_pclk", NULL, 0, 125000000);
441 if (IS_ERR(hw))
442 pr_err("uart1_pclk not registered\n");
443 ret = clk_hw_register_clkdev(hw, NULL, "20215000.uart");
444 if (ret)
445 pr_err("uart1_pclk alias not registered\n");
446}
447
448struct bcm2835_pll_data { 418struct bcm2835_pll_data {
449 const char *name; 419 const char *name;
450 u32 cm_ctrl_reg; 420 u32 cm_ctrl_reg;
diff --git a/drivers/irqchip/irq-bcm2836.c b/drivers/irqchip/irq-bcm2836.c
index dc8c1e3eafe7..667b9e14b032 100644
--- a/drivers/irqchip/irq-bcm2836.c
+++ b/drivers/irqchip/irq-bcm2836.c
@@ -19,62 +19,9 @@
19#include <linux/of_irq.h> 19#include <linux/of_irq.h>
20#include <linux/irqchip.h> 20#include <linux/irqchip.h>
21#include <linux/irqdomain.h> 21#include <linux/irqdomain.h>
22#include <asm/exception.h> 22#include <linux/irqchip/irq-bcm2836.h>
23
24#define LOCAL_CONTROL 0x000
25#define LOCAL_PRESCALER 0x008
26 23
27/* 24#include <asm/exception.h>
28 * The low 2 bits identify the CPU that the GPU IRQ goes to, and the
29 * next 2 bits identify the CPU that the GPU FIQ goes to.
30 */
31#define LOCAL_GPU_ROUTING 0x00c
32/* When setting bits 0-3, enables PMU interrupts on that CPU. */
33#define LOCAL_PM_ROUTING_SET 0x010
34/* When setting bits 0-3, disables PMU interrupts on that CPU. */
35#define LOCAL_PM_ROUTING_CLR 0x014
36/*
37 * The low 4 bits of this are the CPU's timer IRQ enables, and the
38 * next 4 bits are the CPU's timer FIQ enables (which override the IRQ
39 * bits).
40 */
41#define LOCAL_TIMER_INT_CONTROL0 0x040
42/*
43 * The low 4 bits of this are the CPU's per-mailbox IRQ enables, and
44 * the next 4 bits are the CPU's per-mailbox FIQ enables (which
45 * override the IRQ bits).
46 */
47#define LOCAL_MAILBOX_INT_CONTROL0 0x050
48/*
49 * The CPU's interrupt status register. Bits are defined by the the
50 * LOCAL_IRQ_* bits below.
51 */
52#define LOCAL_IRQ_PENDING0 0x060
53/* Same status bits as above, but for FIQ. */
54#define LOCAL_FIQ_PENDING0 0x070
55/*
56 * Mailbox write-to-set bits. There are 16 mailboxes, 4 per CPU, and
57 * these bits are organized by mailbox number and then CPU number. We
58 * use mailbox 0 for IPIs. The mailbox's interrupt is raised while
59 * any bit is set.
60 */
61#define LOCAL_MAILBOX0_SET0 0x080
62#define LOCAL_MAILBOX3_SET0 0x08c
63/* Mailbox write-to-clear bits. */
64#define LOCAL_MAILBOX0_CLR0 0x0c0
65#define LOCAL_MAILBOX3_CLR0 0x0cc
66
67#define LOCAL_IRQ_CNTPSIRQ 0
68#define LOCAL_IRQ_CNTPNSIRQ 1
69#define LOCAL_IRQ_CNTHPIRQ 2
70#define LOCAL_IRQ_CNTVIRQ 3
71#define LOCAL_IRQ_MAILBOX0 4
72#define LOCAL_IRQ_MAILBOX1 5
73#define LOCAL_IRQ_MAILBOX2 6
74#define LOCAL_IRQ_MAILBOX3 7
75#define LOCAL_IRQ_GPU_FAST 8
76#define LOCAL_IRQ_PMU_FAST 9
77#define LAST_IRQ LOCAL_IRQ_PMU_FAST
78 25
79struct bcm2836_arm_irqchip_intc { 26struct bcm2836_arm_irqchip_intc {
80 struct irq_domain *domain; 27 struct irq_domain *domain;
@@ -215,24 +162,6 @@ static int bcm2836_cpu_dying(unsigned int cpu)
215 cpu); 162 cpu);
216 return 0; 163 return 0;
217} 164}
218
219#ifdef CONFIG_ARM
220static int __init bcm2836_smp_boot_secondary(unsigned int cpu,
221 struct task_struct *idle)
222{
223 unsigned long secondary_startup_phys =
224 (unsigned long)virt_to_phys((void *)secondary_startup);
225
226 writel(secondary_startup_phys,
227 intc.base + LOCAL_MAILBOX3_SET0 + 16 * cpu);
228
229 return 0;
230}
231
232static const struct smp_operations bcm2836_smp_ops __initconst = {
233 .smp_boot_secondary = bcm2836_smp_boot_secondary,
234};
235#endif
236#endif 165#endif
237 166
238static const struct irq_domain_ops bcm2836_arm_irqchip_intc_ops = { 167static const struct irq_domain_ops bcm2836_arm_irqchip_intc_ops = {
@@ -249,10 +178,6 @@ bcm2836_arm_irqchip_smp_init(void)
249 bcm2836_cpu_dying); 178 bcm2836_cpu_dying);
250 179
251 set_smp_cross_call(bcm2836_arm_irqchip_send_ipi); 180 set_smp_cross_call(bcm2836_arm_irqchip_send_ipi);
252
253#ifdef CONFIG_ARM
254 smp_set_ops(&bcm2836_smp_ops);
255#endif
256#endif 181#endif
257} 182}
258 183