aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/clocksource
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2013-07-02 16:43:38 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2013-07-02 16:43:38 -0400
commit3883cbb6c1bda013a3ce2dbdab7dc97c52e4a232 (patch)
tree5b69f83b049d24ac81123ac954ca8c9128e48443 /drivers/clocksource
parentd2033f2c1d1de2239ded15e478ddb4028f192a15 (diff)
parent1eb92b24e243085d242cf5ffd64829bba70972e1 (diff)
Merge tag 'soc-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/arm/arm-soc
Pull ARM SoC specific changes from Arnd Bergmann: "These changes are all to SoC-specific code, a total of 33 branches on 17 platforms were pulled into this. Like last time, Renesas sh-mobile is now the platform with the most changes, followed by OMAP and EXYNOS. Two new platforms, TI Keystone and Rockchips RK3xxx are added in this branch, both containing almost no platform specific code at all, since they are using generic subsystem interfaces for clocks, pinctrl, interrupts etc. The device drivers are getting merged through the respective subsystem maintainer trees. One more SoC (u300) is now multiplatform capable and several others (shmobile, exynos, msm, integrator, kirkwood, clps711x) are moving towards that goal with this series but need more work. Also noteworthy is the work on PCI here, which is traditionally part of the SoC specific code. With the changes done by Thomas Petazzoni, we can now more easily have PCI host controller drivers as loadable modules and keep them separate from the platform code in drivers/pci/host. This has already led to the discovery that three platforms (exynos, spear and imx) are actually using an identical PCIe host controller and will be able to share a driver once support for spear and imx is added." * tag 'soc-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/arm/arm-soc: (480 commits) ARM: integrator: let pciv3 use mem/premem from device tree ARM: integrator: set local side PCI addresses right ARM: dts: Add pcie controller node for exynos5440-ssdk5440 ARM: dts: Add pcie controller node for Samsung EXYNOS5440 SoC ARM: EXYNOS: Enable PCIe support for Exynos5440 pci: Add PCIe driver for Samsung Exynos ARM: OMAP5: voltagedomain data: remove temporary OMAP4 voltage data ARM: keystone: Move CPU bringup code to dedicated asm file ARM: multiplatform: always pick one CPU type ARM: imx: select syscon for IMX6SL ARM: keystone: select ARM_ERRATA_798181 only for SMP ARM: imx: Synertronixx scb9328 needs to select SOC_IMX1 ARM: OMAP2+: AM43x: resolve SMP related build error dmaengine: edma: enable build for AM33XX ARM: edma: Add EDMA crossbar event mux support ARM: edma: Add DT and runtime PM support to the private EDMA API dmaengine: edma: Add TI EDMA device tree binding arm: add basic support for Rockchip RK3066a boards arm: add debug uarts for rockchip rk29xx and rk3xxx series arm: Add basic clocks for Rockchip rk3066a SoCs ...
Diffstat (limited to 'drivers/clocksource')
-rw-r--r--drivers/clocksource/Kconfig2
-rw-r--r--drivers/clocksource/cadence_ttc_timer.c23
-rw-r--r--drivers/clocksource/dw_apb_timer_of.c95
3 files changed, 83 insertions, 37 deletions
diff --git a/drivers/clocksource/Kconfig b/drivers/clocksource/Kconfig
index f151c6cf27c3..5871933c4e51 100644
--- a/drivers/clocksource/Kconfig
+++ b/drivers/clocksource/Kconfig
@@ -21,6 +21,8 @@ config DW_APB_TIMER
21 21
22config DW_APB_TIMER_OF 22config DW_APB_TIMER_OF
23 bool 23 bool
24 select DW_APB_TIMER
25 select CLKSRC_OF
24 26
25config ARMADA_370_XP_TIMER 27config ARMADA_370_XP_TIMER
26 bool 28 bool
diff --git a/drivers/clocksource/cadence_ttc_timer.c b/drivers/clocksource/cadence_ttc_timer.c
index 685bc60e210a..4cbe28c74631 100644
--- a/drivers/clocksource/cadence_ttc_timer.c
+++ b/drivers/clocksource/cadence_ttc_timer.c
@@ -51,6 +51,8 @@
51 51
52#define TTC_CNT_CNTRL_DISABLE_MASK 0x1 52#define TTC_CNT_CNTRL_DISABLE_MASK 0x1
53 53
54#define TTC_CLK_CNTRL_CSRC_MASK (1 << 5) /* clock source */
55
54/* 56/*
55 * Setup the timers to use pre-scaling, using a fixed value for now that will 57 * Setup the timers to use pre-scaling, using a fixed value for now that will
56 * work across most input frequency, but it may need to be more dynamic 58 * work across most input frequency, but it may need to be more dynamic
@@ -396,8 +398,9 @@ static void __init ttc_timer_init(struct device_node *timer)
396{ 398{
397 unsigned int irq; 399 unsigned int irq;
398 void __iomem *timer_baseaddr; 400 void __iomem *timer_baseaddr;
399 struct clk *clk; 401 struct clk *clk_cs, *clk_ce;
400 static int initialized; 402 static int initialized;
403 int clksel;
401 404
402 if (initialized) 405 if (initialized)
403 return; 406 return;
@@ -421,14 +424,24 @@ static void __init ttc_timer_init(struct device_node *timer)
421 BUG(); 424 BUG();
422 } 425 }
423 426
424 clk = of_clk_get_by_name(timer, "cpu_1x"); 427 clksel = __raw_readl(timer_baseaddr + TTC_CLK_CNTRL_OFFSET);
425 if (IS_ERR(clk)) { 428 clksel = !!(clksel & TTC_CLK_CNTRL_CSRC_MASK);
429 clk_cs = of_clk_get(timer, clksel);
430 if (IS_ERR(clk_cs)) {
431 pr_err("ERROR: timer input clock not found\n");
432 BUG();
433 }
434
435 clksel = __raw_readl(timer_baseaddr + 4 + TTC_CLK_CNTRL_OFFSET);
436 clksel = !!(clksel & TTC_CLK_CNTRL_CSRC_MASK);
437 clk_ce = of_clk_get(timer, clksel);
438 if (IS_ERR(clk_ce)) {
426 pr_err("ERROR: timer input clock not found\n"); 439 pr_err("ERROR: timer input clock not found\n");
427 BUG(); 440 BUG();
428 } 441 }
429 442
430 ttc_setup_clocksource(clk, timer_baseaddr); 443 ttc_setup_clocksource(clk_cs, timer_baseaddr);
431 ttc_setup_clockevent(clk, timer_baseaddr + 4, irq); 444 ttc_setup_clockevent(clk_ce, timer_baseaddr + 4, irq);
432 445
433 pr_info("%s #0 at %p, irq=%d\n", timer->name, timer_baseaddr, irq); 446 pr_info("%s #0 at %p, irq=%d\n", timer->name, timer_baseaddr, irq);
434} 447}
diff --git a/drivers/clocksource/dw_apb_timer_of.c b/drivers/clocksource/dw_apb_timer_of.c
index ab09ed3742ee..cef554432a33 100644
--- a/drivers/clocksource/dw_apb_timer_of.c
+++ b/drivers/clocksource/dw_apb_timer_of.c
@@ -20,6 +20,7 @@
20#include <linux/of.h> 20#include <linux/of.h>
21#include <linux/of_address.h> 21#include <linux/of_address.h>
22#include <linux/of_irq.h> 22#include <linux/of_irq.h>
23#include <linux/clk.h>
23 24
24#include <asm/mach/time.h> 25#include <asm/mach/time.h>
25#include <asm/sched_clock.h> 26#include <asm/sched_clock.h>
@@ -27,14 +28,37 @@
27static void timer_get_base_and_rate(struct device_node *np, 28static void timer_get_base_and_rate(struct device_node *np,
28 void __iomem **base, u32 *rate) 29 void __iomem **base, u32 *rate)
29{ 30{
31 struct clk *timer_clk;
32 struct clk *pclk;
33
30 *base = of_iomap(np, 0); 34 *base = of_iomap(np, 0);
31 35
32 if (!*base) 36 if (!*base)
33 panic("Unable to map regs for %s", np->name); 37 panic("Unable to map regs for %s", np->name);
34 38
39 /*
40 * Not all implementations use a periphal clock, so don't panic
41 * if it's not present
42 */
43 pclk = of_clk_get_by_name(np, "pclk");
44 if (!IS_ERR(pclk))
45 if (clk_prepare_enable(pclk))
46 pr_warn("pclk for %s is present, but could not be activated\n",
47 np->name);
48
49 timer_clk = of_clk_get_by_name(np, "timer");
50 if (IS_ERR(timer_clk))
51 goto try_clock_freq;
52
53 if (!clk_prepare_enable(timer_clk)) {
54 *rate = clk_get_rate(timer_clk);
55 return;
56 }
57
58try_clock_freq:
35 if (of_property_read_u32(np, "clock-freq", rate) && 59 if (of_property_read_u32(np, "clock-freq", rate) &&
36 of_property_read_u32(np, "clock-frequency", rate)) 60 of_property_read_u32(np, "clock-frequency", rate))
37 panic("No clock-frequency property for %s", np->name); 61 panic("No clock nor clock-frequency property for %s", np->name);
38} 62}
39 63
40static void add_clockevent(struct device_node *event_timer) 64static void add_clockevent(struct device_node *event_timer)
@@ -57,6 +81,9 @@ static void add_clockevent(struct device_node *event_timer)
57 dw_apb_clockevent_register(ced); 81 dw_apb_clockevent_register(ced);
58} 82}
59 83
84static void __iomem *sched_io_base;
85static u32 sched_rate;
86
60static void add_clocksource(struct device_node *source_timer) 87static void add_clocksource(struct device_node *source_timer)
61{ 88{
62 void __iomem *iobase; 89 void __iomem *iobase;
@@ -71,9 +98,15 @@ static void add_clocksource(struct device_node *source_timer)
71 98
72 dw_apb_clocksource_start(cs); 99 dw_apb_clocksource_start(cs);
73 dw_apb_clocksource_register(cs); 100 dw_apb_clocksource_register(cs);
74}
75 101
76static void __iomem *sched_io_base; 102 /*
103 * Fallback to use the clocksource as sched_clock if no separate
104 * timer is found. sched_io_base then points to the current_value
105 * register of the clocksource timer.
106 */
107 sched_io_base = iobase + 0x04;
108 sched_rate = rate;
109}
77 110
78static u32 read_sched_clock(void) 111static u32 read_sched_clock(void)
79{ 112{
@@ -89,39 +122,37 @@ static const struct of_device_id sptimer_ids[] __initconst = {
89static void init_sched_clock(void) 122static void init_sched_clock(void)
90{ 123{
91 struct device_node *sched_timer; 124 struct device_node *sched_timer;
92 u32 rate;
93 125
94 sched_timer = of_find_matching_node(NULL, sptimer_ids); 126 sched_timer = of_find_matching_node(NULL, sptimer_ids);
95 if (!sched_timer) 127 if (sched_timer) {
96 panic("No RTC for sched clock to use"); 128 timer_get_base_and_rate(sched_timer, &sched_io_base,
129 &sched_rate);
130 of_node_put(sched_timer);
131 }
97 132
98 timer_get_base_and_rate(sched_timer, &sched_io_base, &rate); 133 setup_sched_clock(read_sched_clock, 32, sched_rate);
99 of_node_put(sched_timer);
100
101 setup_sched_clock(read_sched_clock, 32, rate);
102} 134}
103 135
104static const struct of_device_id osctimer_ids[] __initconst = { 136static int num_called;
105 { .compatible = "picochip,pc3x2-timer" }, 137static void __init dw_apb_timer_init(struct device_node *timer)
106 { .compatible = "snps,dw-apb-timer-osc" },
107 {},
108};
109
110void __init dw_apb_timer_init(void)
111{ 138{
112 struct device_node *event_timer, *source_timer; 139 switch (num_called) {
113 140 case 0:
114 event_timer = of_find_matching_node(NULL, osctimer_ids); 141 pr_debug("%s: found clockevent timer\n", __func__);
115 if (!event_timer) 142 add_clockevent(timer);
116 panic("No timer for clockevent"); 143 of_node_put(timer);
117 add_clockevent(event_timer); 144 break;
118 145 case 1:
119 source_timer = of_find_matching_node(event_timer, osctimer_ids); 146 pr_debug("%s: found clocksource timer\n", __func__);
120 if (!source_timer) 147 add_clocksource(timer);
121 panic("No timer for clocksource"); 148 of_node_put(timer);
122 add_clocksource(source_timer); 149 init_sched_clock();
123 150 break;
124 of_node_put(source_timer); 151 default:
125 152 break;
126 init_sched_clock(); 153 }
154
155 num_called++;
127} 156}
157CLOCKSOURCE_OF_DECLARE(pc3x2_timer, "picochip,pc3x2-timer", dw_apb_timer_init);
158CLOCKSOURCE_OF_DECLARE(apb_timer, "snps,dw-apb-timer-osc", dw_apb_timer_init);