diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2014-01-23 21:40:49 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2014-01-23 21:40:49 -0500 |
commit | dfd10e7ae60c6c1b24b5d601744b4fd1ecab2f31 (patch) | |
tree | 59fc5ee5877a4dcb4bd56d2e0d0272089496dba1 /drivers | |
parent | f2c73464d7b399cf4e0c601c1c7d7b079080fa52 (diff) | |
parent | 6373bb71875b3f9f73f375952f92e68140b75657 (diff) |
Merge tag 'soc-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/arm/arm-soc
Pull ARM SoC platform changes from Olof Johansson:
"New core SoC-specific changes.
New platforms:
* Introduction of a vendor, Hisilicon, and one of their SoCs with
some random numerical product name.
* Introduction of EFM32, embedded platform from Silicon Labs (ARMv7m,
i.e. !MMU).
* Marvell Berlin series of SoCs, which include the one in Chromecast.
* MOXA platform support, ARM9-based platform used mostly in
industrial products
* Support for Freescale's i.MX50 SoC.
Other work:
* Renesas work for new platforms and drivers, and conversion over to
more multiplatform-friendly device registration schemes.
* SMP support for Allwinner sunxi platforms.
* ... plus a bunch of other stuff across various platforms"
* tag 'soc-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/arm/arm-soc: (201 commits)
ARM: tegra: fix tegra_powergate_sequence_power_up() inline
ARM: msm_defconfig: Update for multi-platform
ARM: msm: Move MSM's DT based hardware to multi-platform support
ARM: msm: Only build timer.c if required
ARM: msm: Only build clock.c on proc_comm based platforms
ARM: ux500: Enable system suspend with WFI support
ARM: ux500: turn on PRINTK_TIME in u8500_defconfig
ARM: shmobile: r8a7790: Fix I2C controller names
ARM: msm: Simplify ARCH_MSM_DT config
ARM: msm: Add support for MSM8974 SoC
ARM: sunxi: select ARM_PSCI
MAINTAINERS: Update Allwinner sunXi maintainer files
ARM: sunxi: Select RESET_CONTROLLER
ARM: imx: improve the comment of CCM lpm SW workaround
ARM: imx: improve status check of clock gate
ARM: imx: add necessary interface for pfd
ARM: imx_v6_v7_defconfig: Select CONFIG_REGULATOR_PFUZE100
ARM: imx_v6_v7_defconfig: Select MX35 and MX50 device tree support
ARM: imx: Add cpu frequency scaling support
ARM i.MX35: Add devicetree support.
...
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/Makefile | 2 | ||||
-rw-r--r-- | drivers/clocksource/Makefile | 2 | ||||
-rw-r--r-- | drivers/irqchip/Kconfig | 4 | ||||
-rw-r--r-- | drivers/irqchip/Makefile | 1 | ||||
-rw-r--r-- | drivers/irqchip/irq-dw-apb-ictl.c | 150 | ||||
-rw-r--r-- | drivers/reset/Makefile | 1 | ||||
-rw-r--r-- | drivers/reset/reset-sunxi.c | 175 |
7 files changed, 333 insertions, 2 deletions
diff --git a/drivers/Makefile b/drivers/Makefile index 3cc8214f9b26..8e3b8b06c0b2 100644 --- a/drivers/Makefile +++ b/drivers/Makefile | |||
@@ -118,7 +118,7 @@ obj-$(CONFIG_SGI_SN) += sn/ | |||
118 | obj-y += firmware/ | 118 | obj-y += firmware/ |
119 | obj-$(CONFIG_CRYPTO) += crypto/ | 119 | obj-$(CONFIG_CRYPTO) += crypto/ |
120 | obj-$(CONFIG_SUPERH) += sh/ | 120 | obj-$(CONFIG_SUPERH) += sh/ |
121 | obj-$(CONFIG_ARCH_SHMOBILE) += sh/ | 121 | obj-$(CONFIG_ARCH_SHMOBILE_LEGACY) += sh/ |
122 | ifndef CONFIG_ARCH_USES_GETTIMEOFFSET | 122 | ifndef CONFIG_ARCH_USES_GETTIMEOFFSET |
123 | obj-y += clocksource/ | 123 | obj-y += clocksource/ |
124 | endif | 124 | endif |
diff --git a/drivers/clocksource/Makefile b/drivers/clocksource/Makefile index 358358d87b6d..c7ca50a9c232 100644 --- a/drivers/clocksource/Makefile +++ b/drivers/clocksource/Makefile | |||
@@ -26,7 +26,7 @@ obj-$(CONFIG_SUN5I_HSTIMER) += timer-sun5i.o | |||
26 | obj-$(CONFIG_ARCH_TEGRA) += tegra20_timer.o | 26 | obj-$(CONFIG_ARCH_TEGRA) += tegra20_timer.o |
27 | obj-$(CONFIG_VT8500_TIMER) += vt8500_timer.o | 27 | obj-$(CONFIG_VT8500_TIMER) += vt8500_timer.o |
28 | obj-$(CONFIG_ARCH_NSPIRE) += zevio-timer.o | 28 | obj-$(CONFIG_ARCH_NSPIRE) += zevio-timer.o |
29 | obj-$(CONFIG_ARCH_BCM) += bcm_kona_timer.o | 29 | obj-$(CONFIG_ARCH_BCM_MOBILE) += bcm_kona_timer.o |
30 | obj-$(CONFIG_CADENCE_TTC_TIMER) += cadence_ttc_timer.o | 30 | obj-$(CONFIG_CADENCE_TTC_TIMER) += cadence_ttc_timer.o |
31 | obj-$(CONFIG_CLKSRC_EFM32) += time-efm32.o | 31 | obj-$(CONFIG_CLKSRC_EFM32) += time-efm32.o |
32 | obj-$(CONFIG_CLKSRC_EXYNOS_MCT) += exynos_mct.o | 32 | obj-$(CONFIG_CLKSRC_EXYNOS_MCT) += exynos_mct.o |
diff --git a/drivers/irqchip/Kconfig b/drivers/irqchip/Kconfig index 3792a1aa52b8..940638ddc982 100644 --- a/drivers/irqchip/Kconfig +++ b/drivers/irqchip/Kconfig | |||
@@ -30,6 +30,10 @@ config ARM_VIC_NR | |||
30 | The maximum number of VICs available in the system, for | 30 | The maximum number of VICs available in the system, for |
31 | power management. | 31 | power management. |
32 | 32 | ||
33 | config DW_APB_ICTL | ||
34 | bool | ||
35 | select IRQ_DOMAIN | ||
36 | |||
33 | config IMGPDC_IRQ | 37 | config IMGPDC_IRQ |
34 | bool | 38 | bool |
35 | select GENERIC_IRQ_CHIP | 39 | select GENERIC_IRQ_CHIP |
diff --git a/drivers/irqchip/Makefile b/drivers/irqchip/Makefile index c60b9010b152..6427323af4c3 100644 --- a/drivers/irqchip/Makefile +++ b/drivers/irqchip/Makefile | |||
@@ -6,6 +6,7 @@ obj-$(CONFIG_ARCH_MMP) += irq-mmp.o | |||
6 | obj-$(CONFIG_ARCH_MVEBU) += irq-armada-370-xp.o | 6 | obj-$(CONFIG_ARCH_MVEBU) += irq-armada-370-xp.o |
7 | obj-$(CONFIG_ARCH_MXS) += irq-mxs.o | 7 | obj-$(CONFIG_ARCH_MXS) += irq-mxs.o |
8 | obj-$(CONFIG_ARCH_S3C24XX) += irq-s3c24xx.o | 8 | obj-$(CONFIG_ARCH_S3C24XX) += irq-s3c24xx.o |
9 | obj-$(CONFIG_DW_APB_ICTL) += irq-dw-apb-ictl.o | ||
9 | obj-$(CONFIG_METAG) += irq-metag-ext.o | 10 | obj-$(CONFIG_METAG) += irq-metag-ext.o |
10 | obj-$(CONFIG_METAG_PERFCOUNTER_IRQS) += irq-metag.o | 11 | obj-$(CONFIG_METAG_PERFCOUNTER_IRQS) += irq-metag.o |
11 | obj-$(CONFIG_ARCH_MOXART) += irq-moxart.o | 12 | obj-$(CONFIG_ARCH_MOXART) += irq-moxart.o |
diff --git a/drivers/irqchip/irq-dw-apb-ictl.c b/drivers/irqchip/irq-dw-apb-ictl.c new file mode 100644 index 000000000000..31e231e1f566 --- /dev/null +++ b/drivers/irqchip/irq-dw-apb-ictl.c | |||
@@ -0,0 +1,150 @@ | |||
1 | /* | ||
2 | * Synopsys DW APB ICTL irqchip driver. | ||
3 | * | ||
4 | * Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com> | ||
5 | * | ||
6 | * based on GPL'ed 2.6 kernel sources | ||
7 | * (c) Marvell International Ltd. | ||
8 | * | ||
9 | * This file is licensed under the terms of the GNU General Public | ||
10 | * License version 2. This program is licensed "as is" without any | ||
11 | * warranty of any kind, whether express or implied. | ||
12 | */ | ||
13 | |||
14 | #include <linux/io.h> | ||
15 | #include <linux/irq.h> | ||
16 | #include <linux/irqchip/chained_irq.h> | ||
17 | #include <linux/of_address.h> | ||
18 | #include <linux/of_irq.h> | ||
19 | |||
20 | #include "irqchip.h" | ||
21 | |||
22 | #define APB_INT_ENABLE_L 0x00 | ||
23 | #define APB_INT_ENABLE_H 0x04 | ||
24 | #define APB_INT_MASK_L 0x08 | ||
25 | #define APB_INT_MASK_H 0x0c | ||
26 | #define APB_INT_FINALSTATUS_L 0x30 | ||
27 | #define APB_INT_FINALSTATUS_H 0x34 | ||
28 | |||
29 | static void dw_apb_ictl_handler(unsigned int irq, struct irq_desc *desc) | ||
30 | { | ||
31 | struct irq_chip *chip = irq_get_chip(irq); | ||
32 | struct irq_chip_generic *gc = irq_get_handler_data(irq); | ||
33 | struct irq_domain *d = gc->private; | ||
34 | u32 stat; | ||
35 | int n; | ||
36 | |||
37 | chained_irq_enter(chip, desc); | ||
38 | |||
39 | for (n = 0; n < gc->num_ct; n++) { | ||
40 | stat = readl_relaxed(gc->reg_base + | ||
41 | APB_INT_FINALSTATUS_L + 4 * n); | ||
42 | while (stat) { | ||
43 | u32 hwirq = ffs(stat) - 1; | ||
44 | generic_handle_irq(irq_find_mapping(d, | ||
45 | gc->irq_base + hwirq + 32 * n)); | ||
46 | stat &= ~(1 << hwirq); | ||
47 | } | ||
48 | } | ||
49 | |||
50 | chained_irq_exit(chip, desc); | ||
51 | } | ||
52 | |||
53 | static int __init dw_apb_ictl_init(struct device_node *np, | ||
54 | struct device_node *parent) | ||
55 | { | ||
56 | unsigned int clr = IRQ_NOREQUEST | IRQ_NOPROBE | IRQ_NOAUTOEN; | ||
57 | struct resource r; | ||
58 | struct irq_domain *domain; | ||
59 | struct irq_chip_generic *gc; | ||
60 | void __iomem *iobase; | ||
61 | int ret, nrirqs, irq; | ||
62 | u32 reg; | ||
63 | |||
64 | /* Map the parent interrupt for the chained handler */ | ||
65 | irq = irq_of_parse_and_map(np, 0); | ||
66 | if (irq <= 0) { | ||
67 | pr_err("%s: unable to parse irq\n", np->full_name); | ||
68 | return -EINVAL; | ||
69 | } | ||
70 | |||
71 | ret = of_address_to_resource(np, 0, &r); | ||
72 | if (ret) { | ||
73 | pr_err("%s: unable to get resource\n", np->full_name); | ||
74 | return ret; | ||
75 | } | ||
76 | |||
77 | if (!request_mem_region(r.start, resource_size(&r), np->full_name)) { | ||
78 | pr_err("%s: unable to request mem region\n", np->full_name); | ||
79 | return -ENOMEM; | ||
80 | } | ||
81 | |||
82 | iobase = ioremap(r.start, resource_size(&r)); | ||
83 | if (!iobase) { | ||
84 | pr_err("%s: unable to map resource\n", np->full_name); | ||
85 | ret = -ENOMEM; | ||
86 | goto err_release; | ||
87 | } | ||
88 | |||
89 | /* | ||
90 | * DW IP can be configured to allow 2-64 irqs. We can determine | ||
91 | * the number of irqs supported by writing into enable register | ||
92 | * and look for bits not set, as corresponding flip-flops will | ||
93 | * have been removed by sythesis tool. | ||
94 | */ | ||
95 | |||
96 | /* mask and enable all interrupts */ | ||
97 | writel(~0, iobase + APB_INT_MASK_L); | ||
98 | writel(~0, iobase + APB_INT_MASK_H); | ||
99 | writel(~0, iobase + APB_INT_ENABLE_L); | ||
100 | writel(~0, iobase + APB_INT_ENABLE_H); | ||
101 | |||
102 | reg = readl(iobase + APB_INT_ENABLE_H); | ||
103 | if (reg) | ||
104 | nrirqs = 32 + fls(reg); | ||
105 | else | ||
106 | nrirqs = fls(readl(iobase + APB_INT_ENABLE_L)); | ||
107 | |||
108 | domain = irq_domain_add_linear(np, nrirqs, | ||
109 | &irq_generic_chip_ops, NULL); | ||
110 | if (!domain) { | ||
111 | pr_err("%s: unable to add irq domain\n", np->full_name); | ||
112 | ret = -ENOMEM; | ||
113 | goto err_unmap; | ||
114 | } | ||
115 | |||
116 | ret = irq_alloc_domain_generic_chips(domain, 32, (nrirqs > 32) ? 2 : 1, | ||
117 | np->name, handle_level_irq, clr, 0, | ||
118 | IRQ_GC_INIT_MASK_CACHE); | ||
119 | if (ret) { | ||
120 | pr_err("%s: unable to alloc irq domain gc\n", np->full_name); | ||
121 | goto err_unmap; | ||
122 | } | ||
123 | |||
124 | gc = irq_get_domain_generic_chip(domain, 0); | ||
125 | gc->private = domain; | ||
126 | gc->reg_base = iobase; | ||
127 | |||
128 | gc->chip_types[0].regs.mask = APB_INT_MASK_L; | ||
129 | gc->chip_types[0].chip.irq_mask = irq_gc_mask_set_bit; | ||
130 | gc->chip_types[0].chip.irq_unmask = irq_gc_mask_clr_bit; | ||
131 | |||
132 | if (nrirqs > 32) { | ||
133 | gc->chip_types[1].regs.mask = APB_INT_MASK_H; | ||
134 | gc->chip_types[1].chip.irq_mask = irq_gc_mask_set_bit; | ||
135 | gc->chip_types[1].chip.irq_unmask = irq_gc_mask_clr_bit; | ||
136 | } | ||
137 | |||
138 | irq_set_handler_data(irq, gc); | ||
139 | irq_set_chained_handler(irq, dw_apb_ictl_handler); | ||
140 | |||
141 | return 0; | ||
142 | |||
143 | err_unmap: | ||
144 | iounmap(iobase); | ||
145 | err_release: | ||
146 | release_mem_region(r.start, resource_size(&r)); | ||
147 | return ret; | ||
148 | } | ||
149 | IRQCHIP_DECLARE(dw_apb_ictl, | ||
150 | "snps,dw-apb-ictl", dw_apb_ictl_init); | ||
diff --git a/drivers/reset/Makefile b/drivers/reset/Makefile index 1e2d83f2b995..cc29832c9638 100644 --- a/drivers/reset/Makefile +++ b/drivers/reset/Makefile | |||
@@ -1 +1,2 @@ | |||
1 | obj-$(CONFIG_RESET_CONTROLLER) += core.o | 1 | obj-$(CONFIG_RESET_CONTROLLER) += core.o |
2 | obj-$(CONFIG_ARCH_SUNXI) += reset-sunxi.o | ||
diff --git a/drivers/reset/reset-sunxi.c b/drivers/reset/reset-sunxi.c new file mode 100644 index 000000000000..695bd3496eba --- /dev/null +++ b/drivers/reset/reset-sunxi.c | |||
@@ -0,0 +1,175 @@ | |||
1 | /* | ||
2 | * Allwinner SoCs Reset Controller driver | ||
3 | * | ||
4 | * Copyright 2013 Maxime Ripard | ||
5 | * | ||
6 | * Maxime Ripard <maxime.ripard@free-electrons.com> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License as published by | ||
10 | * the Free Software Foundation; either version 2 of the License, or | ||
11 | * (at your option) any later version. | ||
12 | */ | ||
13 | |||
14 | #include <linux/err.h> | ||
15 | #include <linux/io.h> | ||
16 | #include <linux/module.h> | ||
17 | #include <linux/of.h> | ||
18 | #include <linux/of_address.h> | ||
19 | #include <linux/platform_device.h> | ||
20 | #include <linux/reset-controller.h> | ||
21 | #include <linux/slab.h> | ||
22 | #include <linux/spinlock.h> | ||
23 | #include <linux/types.h> | ||
24 | |||
25 | struct sunxi_reset_data { | ||
26 | spinlock_t lock; | ||
27 | void __iomem *membase; | ||
28 | struct reset_controller_dev rcdev; | ||
29 | }; | ||
30 | |||
31 | static int sunxi_reset_assert(struct reset_controller_dev *rcdev, | ||
32 | unsigned long id) | ||
33 | { | ||
34 | struct sunxi_reset_data *data = container_of(rcdev, | ||
35 | struct sunxi_reset_data, | ||
36 | rcdev); | ||
37 | int bank = id / BITS_PER_LONG; | ||
38 | int offset = id % BITS_PER_LONG; | ||
39 | unsigned long flags; | ||
40 | u32 reg; | ||
41 | |||
42 | spin_lock_irqsave(&data->lock, flags); | ||
43 | |||
44 | reg = readl(data->membase + (bank * 4)); | ||
45 | writel(reg & ~BIT(offset), data->membase + (bank * 4)); | ||
46 | |||
47 | spin_unlock_irqrestore(&data->lock, flags); | ||
48 | |||
49 | return 0; | ||
50 | } | ||
51 | |||
52 | static int sunxi_reset_deassert(struct reset_controller_dev *rcdev, | ||
53 | unsigned long id) | ||
54 | { | ||
55 | struct sunxi_reset_data *data = container_of(rcdev, | ||
56 | struct sunxi_reset_data, | ||
57 | rcdev); | ||
58 | int bank = id / BITS_PER_LONG; | ||
59 | int offset = id % BITS_PER_LONG; | ||
60 | unsigned long flags; | ||
61 | u32 reg; | ||
62 | |||
63 | spin_lock_irqsave(&data->lock, flags); | ||
64 | |||
65 | reg = readl(data->membase + (bank * 4)); | ||
66 | writel(reg | BIT(offset), data->membase + (bank * 4)); | ||
67 | |||
68 | spin_unlock_irqrestore(&data->lock, flags); | ||
69 | |||
70 | return 0; | ||
71 | } | ||
72 | |||
73 | static struct reset_control_ops sunxi_reset_ops = { | ||
74 | .assert = sunxi_reset_assert, | ||
75 | .deassert = sunxi_reset_deassert, | ||
76 | }; | ||
77 | |||
78 | static int sunxi_reset_init(struct device_node *np) | ||
79 | { | ||
80 | struct sunxi_reset_data *data; | ||
81 | struct resource res; | ||
82 | resource_size_t size; | ||
83 | int ret; | ||
84 | |||
85 | data = kzalloc(sizeof(*data), GFP_KERNEL); | ||
86 | if (!data) | ||
87 | return -ENOMEM; | ||
88 | |||
89 | ret = of_address_to_resource(np, 0, &res); | ||
90 | if (ret) | ||
91 | goto err_alloc; | ||
92 | |||
93 | size = resource_size(&res); | ||
94 | if (!request_mem_region(res.start, size, np->name)) { | ||
95 | ret = -EBUSY; | ||
96 | goto err_alloc; | ||
97 | } | ||
98 | |||
99 | data->membase = ioremap(res.start, size); | ||
100 | if (!data->membase) { | ||
101 | ret = -ENOMEM; | ||
102 | goto err_alloc; | ||
103 | } | ||
104 | |||
105 | data->rcdev.owner = THIS_MODULE; | ||
106 | data->rcdev.nr_resets = size * 32; | ||
107 | data->rcdev.ops = &sunxi_reset_ops; | ||
108 | data->rcdev.of_node = np; | ||
109 | reset_controller_register(&data->rcdev); | ||
110 | |||
111 | return 0; | ||
112 | |||
113 | err_alloc: | ||
114 | kfree(data); | ||
115 | return ret; | ||
116 | }; | ||
117 | |||
118 | /* | ||
119 | * These are the reset controller we need to initialize early on in | ||
120 | * our system, before we can even think of using a regular device | ||
121 | * driver for it. | ||
122 | */ | ||
123 | static const struct of_device_id sunxi_early_reset_dt_ids[] __initdata = { | ||
124 | { .compatible = "allwinner,sun6i-a31-ahb1-reset", }, | ||
125 | { /* sentinel */ }, | ||
126 | }; | ||
127 | |||
128 | void __init sun6i_reset_init(void) | ||
129 | { | ||
130 | struct device_node *np; | ||
131 | |||
132 | for_each_matching_node(np, sunxi_early_reset_dt_ids) | ||
133 | sunxi_reset_init(np); | ||
134 | } | ||
135 | |||
136 | /* | ||
137 | * And these are the controllers we can register through the regular | ||
138 | * device model. | ||
139 | */ | ||
140 | static const struct of_device_id sunxi_reset_dt_ids[] = { | ||
141 | { .compatible = "allwinner,sun6i-a31-clock-reset", }, | ||
142 | { /* sentinel */ }, | ||
143 | }; | ||
144 | MODULE_DEVICE_TABLE(of, sunxi_reset_dt_ids); | ||
145 | |||
146 | static int sunxi_reset_probe(struct platform_device *pdev) | ||
147 | { | ||
148 | return sunxi_reset_init(pdev->dev.of_node); | ||
149 | } | ||
150 | |||
151 | static int sunxi_reset_remove(struct platform_device *pdev) | ||
152 | { | ||
153 | struct sunxi_reset_data *data = platform_get_drvdata(pdev); | ||
154 | |||
155 | reset_controller_unregister(&data->rcdev); | ||
156 | iounmap(data->membase); | ||
157 | kfree(data); | ||
158 | |||
159 | return 0; | ||
160 | } | ||
161 | |||
162 | static struct platform_driver sunxi_reset_driver = { | ||
163 | .probe = sunxi_reset_probe, | ||
164 | .remove = sunxi_reset_remove, | ||
165 | .driver = { | ||
166 | .name = "sunxi-reset", | ||
167 | .owner = THIS_MODULE, | ||
168 | .of_match_table = sunxi_reset_dt_ids, | ||
169 | }, | ||
170 | }; | ||
171 | module_platform_driver(sunxi_reset_driver); | ||
172 | |||
173 | MODULE_AUTHOR("Maxime Ripard <maxime.ripard@free-electrons.com"); | ||
174 | MODULE_DESCRIPTION("Allwinner SoCs Reset Controller Driver"); | ||
175 | MODULE_LICENSE("GPL"); | ||