This is the 2nd part of ARM timer clean-ups for 3.10. This series has
the following changes: - Add sched_clock selection logic to select the highest frequency clock - Use full 64-bit arch timer counter for sched_clock - Convert arch timer, sp804 and integrator-cp timers to CLKSRC_OF and adapt all users to use clocksource_of_init -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.11 (GNU/Linux) iQEcBAABAgAGBQJRZx0aAAoJEMhvYp4jgsXiB7MH/AutBUa40yuzTA1RzaDxYTX7 m1NrjmsTI8pFLX6VTvtwNXdT1AJ0JbzPxu35E1Y8xsu8tnx/RjG/hhqq8R2rXd5t oqilT46SPBZpKBSrPSuEQde5v8XlKT5kEcUlg47bHGB1JrI9Ip14okRcg5aCJJzu Pb25NqxTWS+vFTNV7C+UzuJ72lJ24FHQXK4AbZqaWcaokGCRLP1QE1s83jY7mpX7 zd5xWMPygKR8oYNPVhxoD1ajUo5cqVHtcXFRnWy1o/T/8ZPqCuSOsyJokScPHzwa vUwoAn2OQSFLJZgITu8+9JSlLxW40BdMHaJ+jTlOXMGDq6RHZY1FHAy8PTf43wU= =QjNu -----END PGP SIGNATURE----- Merge tag 'clksrc-cleanup-for-3.10-part2' of git://sources.calxeda.com/kernel/linux into late/clksrc This is the 2nd part of ARM timer clean-ups for 3.10. This series has the following changes: - Add sched_clock selection logic to select the highest frequency clock - Use full 64-bit arch timer counter for sched_clock - Convert arch timer, sp804 and integrator-cp timers to CLKSRC_OF and adapt all users to use clocksource_of_init * tag 'clksrc-cleanup-for-3.10-part2' of git://sources.calxeda.com/kernel/linux: devtree: add binding documentation for sp804 ARM: integrator-cp: convert use CLKSRC_OF for timer init ARM: versatile: use OF init for sp804 timer ARM: versatile: add versatile dtbs to dtbs target ARM: vexpress: remove extra timer-sp control register clearing ARM: dts: vexpress: disable CA9 core tile sp804 timer ARM: vexpress: remove sp804 OF init ARM: highbank: use OF init for sp804 timer ARM: timer-sp: convert to use CLKSRC_OF init OF: add empty of_device_is_available for !OF ARM: convert arm/arm64 arch timer to use CLKSRC_OF init ARM: make machine_desc->init_time default to clocksource_of_init ARM: arch_timer: use full 64-bit counter for sched_clock ARM: make sched_clock just call a function pointer ARM: sched_clock: allow changing to higher frequency counter Signed-off-by: Olof Johansson <olof@lixom.net> This has a nasty set of conflicts with the exynos MCT code, which was moved in a separate branch, and then fixed up when merged in, but still conflicts a bit here. It should have been sorted out by this merge though.
This commit is contained in:
commit
c3e0c873d0
29
Documentation/devicetree/bindings/timer/arm,sp804.txt
Normal file
29
Documentation/devicetree/bindings/timer/arm,sp804.txt
Normal file
@ -0,0 +1,29 @@
|
||||
ARM sp804 Dual Timers
|
||||
---------------------------------------
|
||||
|
||||
Required properties:
|
||||
- compatible: Should be "arm,sp804" & "arm,primecell"
|
||||
- interrupts: Should contain the list of Dual Timer interrupts. This is the
|
||||
interrupt for timer 1 and timer 2. In the case of a single entry, it is
|
||||
the combined interrupt or if "arm,sp804-has-irq" is present that
|
||||
specifies which timer interrupt is connected.
|
||||
- reg: Should contain location and length for dual timer register.
|
||||
- clocks: clocks driving the dual timer hardware. This list should be 1 or 3
|
||||
clocks. With 3 clocks, the order is timer0 clock, timer1 clock,
|
||||
apb_pclk. A single clock can also be specified if the same clock is
|
||||
used for all clock inputs.
|
||||
|
||||
Optional properties:
|
||||
- arm,sp804-has-irq = <#>: In the case of only 1 timer irq line connected, this
|
||||
specifies if the irq connection is for timer 1 or timer 2. A value of 1
|
||||
or 2 should be used.
|
||||
|
||||
Example:
|
||||
|
||||
timer0: timer@fc800000 {
|
||||
compatible = "arm,sp804", "arm,primecell";
|
||||
reg = <0xfc800000 0x1000>;
|
||||
interrupts = <0 0 4>, <0 1 4>;
|
||||
clocks = <&timclk1 &timclk2 &pclk>;
|
||||
clock-names = "timer1", "timer2", "apb_pclk";
|
||||
};
|
@ -1180,6 +1180,7 @@ config PLAT_VERSATILE
|
||||
config ARM_TIMER_SP804
|
||||
bool
|
||||
select CLKSRC_MMIO
|
||||
select CLKSRC_OF if OF
|
||||
select HAVE_SCHED_CLOCK
|
||||
|
||||
source arch/arm/mm/Kconfig
|
||||
|
@ -165,6 +165,8 @@ dtb-$(CONFIG_ARCH_TEGRA) += tegra20-harmony.dtb \
|
||||
tegra30-cardhu-a04.dtb \
|
||||
tegra114-dalmore.dtb \
|
||||
tegra114-pluto.dtb
|
||||
dtb-$(CONFIG_ARCH_VERSATILE) += versatile-ab.dtb \
|
||||
versatile-pb.dtb
|
||||
dtb-$(CONFIG_ARCH_VEXPRESS) += vexpress-v2p-ca5s.dtb \
|
||||
vexpress-v2p-ca9.dtb \
|
||||
vexpress-v2p-ca15-tc1.dtb \
|
||||
|
@ -24,15 +24,15 @@
|
||||
};
|
||||
|
||||
timer0: timer@13000000 {
|
||||
compatible = "arm,sp804", "arm,primecell";
|
||||
compatible = "arm,integrator-cp-timer";
|
||||
};
|
||||
|
||||
timer1: timer@13000100 {
|
||||
compatible = "arm,sp804", "arm,primecell";
|
||||
compatible = "arm,integrator-cp-timer";
|
||||
};
|
||||
|
||||
timer2: timer@13000200 {
|
||||
compatible = "arm,sp804", "arm,primecell";
|
||||
compatible = "arm,integrator-cp-timer";
|
||||
};
|
||||
|
||||
pic: pic@14000000 {
|
||||
|
@ -121,6 +121,18 @@
|
||||
interrupts = <0>;
|
||||
};
|
||||
|
||||
timer@101e2000 {
|
||||
compatible = "arm,sp804", "arm,primecell";
|
||||
reg = <0x101e2000 0x1000>;
|
||||
interrupts = <4>;
|
||||
};
|
||||
|
||||
timer@101e3000 {
|
||||
compatible = "arm,sp804", "arm,primecell";
|
||||
reg = <0x101e3000 0x1000>;
|
||||
interrupts = <5>;
|
||||
};
|
||||
|
||||
gpio0: gpio@101e4000 {
|
||||
compatible = "arm,pl061", "arm,primecell";
|
||||
reg = <0x101e4000 0x1000>;
|
||||
|
@ -98,6 +98,7 @@
|
||||
<0 49 4>;
|
||||
clocks = <&oscclk2>, <&oscclk2>;
|
||||
clock-names = "timclk", "apb_pclk";
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
watchdog@100e5000 {
|
||||
|
@ -25,33 +25,29 @@
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/irq.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_address.h>
|
||||
#include <linux/of_irq.h>
|
||||
|
||||
#include <asm/sched_clock.h>
|
||||
#include <asm/hardware/arm_timer.h>
|
||||
#include <asm/hardware/timer-sp.h>
|
||||
|
||||
static long __init sp804_get_clock_rate(const char *name)
|
||||
static long __init sp804_get_clock_rate(struct clk *clk)
|
||||
{
|
||||
struct clk *clk;
|
||||
long rate;
|
||||
int err;
|
||||
|
||||
clk = clk_get_sys("sp804", name);
|
||||
if (IS_ERR(clk)) {
|
||||
pr_err("sp804: %s clock not found: %d\n", name,
|
||||
(int)PTR_ERR(clk));
|
||||
return PTR_ERR(clk);
|
||||
}
|
||||
|
||||
err = clk_prepare(clk);
|
||||
if (err) {
|
||||
pr_err("sp804: %s clock failed to prepare: %d\n", name, err);
|
||||
pr_err("sp804: clock failed to prepare: %d\n", err);
|
||||
clk_put(clk);
|
||||
return err;
|
||||
}
|
||||
|
||||
err = clk_enable(clk);
|
||||
if (err) {
|
||||
pr_err("sp804: %s clock failed to enable: %d\n", name, err);
|
||||
pr_err("sp804: clock failed to enable: %d\n", err);
|
||||
clk_unprepare(clk);
|
||||
clk_put(clk);
|
||||
return err;
|
||||
@ -59,7 +55,7 @@ static long __init sp804_get_clock_rate(const char *name)
|
||||
|
||||
rate = clk_get_rate(clk);
|
||||
if (rate < 0) {
|
||||
pr_err("sp804: %s clock failed to get rate: %ld\n", name, rate);
|
||||
pr_err("sp804: clock failed to get rate: %ld\n", rate);
|
||||
clk_disable(clk);
|
||||
clk_unprepare(clk);
|
||||
clk_put(clk);
|
||||
@ -77,9 +73,21 @@ static u32 sp804_read(void)
|
||||
|
||||
void __init __sp804_clocksource_and_sched_clock_init(void __iomem *base,
|
||||
const char *name,
|
||||
struct clk *clk,
|
||||
int use_sched_clock)
|
||||
{
|
||||
long rate = sp804_get_clock_rate(name);
|
||||
long rate;
|
||||
|
||||
if (!clk) {
|
||||
clk = clk_get_sys("sp804", name);
|
||||
if (IS_ERR(clk)) {
|
||||
pr_err("sp804: clock not found: %d\n",
|
||||
(int)PTR_ERR(clk));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
rate = sp804_get_clock_rate(clk);
|
||||
|
||||
if (rate < 0)
|
||||
return;
|
||||
@ -171,12 +179,20 @@ static struct irqaction sp804_timer_irq = {
|
||||
.dev_id = &sp804_clockevent,
|
||||
};
|
||||
|
||||
void __init sp804_clockevents_init(void __iomem *base, unsigned int irq,
|
||||
const char *name)
|
||||
void __init __sp804_clockevents_init(void __iomem *base, unsigned int irq, struct clk *clk, const char *name)
|
||||
{
|
||||
struct clock_event_device *evt = &sp804_clockevent;
|
||||
long rate = sp804_get_clock_rate(name);
|
||||
long rate;
|
||||
|
||||
if (!clk)
|
||||
clk = clk_get_sys("sp804", name);
|
||||
if (IS_ERR(clk)) {
|
||||
pr_err("sp804: %s clock not found: %d\n", name,
|
||||
(int)PTR_ERR(clk));
|
||||
return;
|
||||
}
|
||||
|
||||
rate = sp804_get_clock_rate(clk);
|
||||
if (rate < 0)
|
||||
return;
|
||||
|
||||
@ -186,6 +202,98 @@ void __init sp804_clockevents_init(void __iomem *base, unsigned int irq,
|
||||
evt->irq = irq;
|
||||
evt->cpumask = cpu_possible_mask;
|
||||
|
||||
writel(0, base + TIMER_CTRL);
|
||||
|
||||
setup_irq(irq, &sp804_timer_irq);
|
||||
clockevents_config_and_register(evt, rate, 0xf, 0xffffffff);
|
||||
}
|
||||
|
||||
static void __init sp804_of_init(struct device_node *np)
|
||||
{
|
||||
static bool initialized = false;
|
||||
void __iomem *base;
|
||||
int irq;
|
||||
u32 irq_num = 0;
|
||||
struct clk *clk1, *clk2;
|
||||
const char *name = of_get_property(np, "compatible", NULL);
|
||||
|
||||
base = of_iomap(np, 0);
|
||||
if (WARN_ON(!base))
|
||||
return;
|
||||
|
||||
/* Ensure timers are disabled */
|
||||
writel(0, base + TIMER_CTRL);
|
||||
writel(0, base + TIMER_2_BASE + TIMER_CTRL);
|
||||
|
||||
if (initialized || !of_device_is_available(np))
|
||||
goto err;
|
||||
|
||||
clk1 = of_clk_get(np, 0);
|
||||
if (IS_ERR(clk1))
|
||||
clk1 = NULL;
|
||||
|
||||
/* Get the 2nd clock if the timer has 2 timer clocks */
|
||||
if (of_count_phandle_with_args(np, "clocks", "#clock-cells") == 3) {
|
||||
clk2 = of_clk_get(np, 1);
|
||||
if (IS_ERR(clk2)) {
|
||||
pr_err("sp804: %s clock not found: %d\n", np->name,
|
||||
(int)PTR_ERR(clk2));
|
||||
goto err;
|
||||
}
|
||||
} else
|
||||
clk2 = clk1;
|
||||
|
||||
irq = irq_of_parse_and_map(np, 0);
|
||||
if (irq <= 0)
|
||||
goto err;
|
||||
|
||||
of_property_read_u32(np, "arm,sp804-has-irq", &irq_num);
|
||||
if (irq_num == 2) {
|
||||
__sp804_clockevents_init(base + TIMER_2_BASE, irq, clk2, name);
|
||||
__sp804_clocksource_and_sched_clock_init(base, name, clk1, 1);
|
||||
} else {
|
||||
__sp804_clockevents_init(base, irq, clk1 , name);
|
||||
__sp804_clocksource_and_sched_clock_init(base + TIMER_2_BASE,
|
||||
name, clk2, 1);
|
||||
}
|
||||
initialized = true;
|
||||
|
||||
return;
|
||||
err:
|
||||
iounmap(base);
|
||||
}
|
||||
CLOCKSOURCE_OF_DECLARE(sp804, "arm,sp804", sp804_of_init);
|
||||
|
||||
static void __init integrator_cp_of_init(struct device_node *np)
|
||||
{
|
||||
static int init_count = 0;
|
||||
void __iomem *base;
|
||||
int irq;
|
||||
const char *name = of_get_property(np, "compatible", NULL);
|
||||
|
||||
base = of_iomap(np, 0);
|
||||
if (WARN_ON(!base))
|
||||
return;
|
||||
|
||||
/* Ensure timer is disabled */
|
||||
writel(0, base + TIMER_CTRL);
|
||||
|
||||
if (init_count == 2 || !of_device_is_available(np))
|
||||
goto err;
|
||||
|
||||
if (!init_count)
|
||||
sp804_clocksource_init(base, name);
|
||||
else {
|
||||
irq = irq_of_parse_and_map(np, 0);
|
||||
if (irq <= 0)
|
||||
goto err;
|
||||
|
||||
sp804_clockevents_init(base, irq, name);
|
||||
}
|
||||
|
||||
init_count++;
|
||||
return;
|
||||
err:
|
||||
iounmap(base);
|
||||
}
|
||||
CLOCKSOURCE_OF_DECLARE(intcp, "arm,integrator-cp-timer", integrator_cp_of_init);
|
||||
|
@ -10,8 +10,7 @@
|
||||
#include <clocksource/arm_arch_timer.h>
|
||||
|
||||
#ifdef CONFIG_ARM_ARCH_TIMER
|
||||
int arch_timer_of_register(void);
|
||||
int arch_timer_sched_clock_init(void);
|
||||
int arch_timer_arch_init(void);
|
||||
|
||||
/*
|
||||
* These register accessors are marked inline so the compiler can
|
||||
@ -110,16 +109,6 @@ static inline void __cpuinit arch_counter_set_user_access(void)
|
||||
|
||||
asm volatile("mcr p15, 0, %0, c14, c1, 0" : : "r" (cntkctl));
|
||||
}
|
||||
#else
|
||||
static inline int arch_timer_of_register(void)
|
||||
{
|
||||
return -ENXIO;
|
||||
}
|
||||
|
||||
static inline int arch_timer_sched_clock_init(void)
|
||||
{
|
||||
return -ENXIO;
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
@ -1,15 +1,23 @@
|
||||
struct clk;
|
||||
|
||||
void __sp804_clocksource_and_sched_clock_init(void __iomem *,
|
||||
const char *, int);
|
||||
const char *, struct clk *, int);
|
||||
void __sp804_clockevents_init(void __iomem *, unsigned int,
|
||||
struct clk *, const char *);
|
||||
|
||||
static inline void sp804_clocksource_init(void __iomem *base, const char *name)
|
||||
{
|
||||
__sp804_clocksource_and_sched_clock_init(base, name, 0);
|
||||
__sp804_clocksource_and_sched_clock_init(base, name, NULL, 0);
|
||||
}
|
||||
|
||||
static inline void sp804_clocksource_and_sched_clock_init(void __iomem *base,
|
||||
const char *name)
|
||||
{
|
||||
__sp804_clocksource_and_sched_clock_init(base, name, 1);
|
||||
__sp804_clocksource_and_sched_clock_init(base, name, NULL, 1);
|
||||
}
|
||||
|
||||
void sp804_clockevents_init(void __iomem *, unsigned int, const char *);
|
||||
static inline void sp804_clockevents_init(void __iomem *base, unsigned int irq, const char *name)
|
||||
{
|
||||
__sp804_clockevents_init(base, irq, NULL, name);
|
||||
|
||||
}
|
||||
|
@ -11,4 +11,6 @@
|
||||
extern void sched_clock_postinit(void);
|
||||
extern void setup_sched_clock(u32 (*read)(void), int bits, unsigned long rate);
|
||||
|
||||
extern unsigned long long (*sched_clock_func)(void);
|
||||
|
||||
#endif
|
||||
|
@ -22,9 +22,11 @@ static unsigned long arch_timer_read_counter_long(void)
|
||||
return arch_timer_read_counter();
|
||||
}
|
||||
|
||||
static u32 arch_timer_read_counter_u32(void)
|
||||
static u32 sched_clock_mult __read_mostly;
|
||||
|
||||
static unsigned long long notrace arch_timer_sched_clock(void)
|
||||
{
|
||||
return arch_timer_read_counter();
|
||||
return arch_timer_read_counter() * sched_clock_mult;
|
||||
}
|
||||
|
||||
static struct delay_timer arch_delay_timer;
|
||||
@ -37,25 +39,20 @@ static void __init arch_timer_delay_timer_register(void)
|
||||
register_current_timer_delay(&arch_delay_timer);
|
||||
}
|
||||
|
||||
int __init arch_timer_of_register(void)
|
||||
int __init arch_timer_arch_init(void)
|
||||
{
|
||||
int ret;
|
||||
u32 arch_timer_rate = arch_timer_get_rate();
|
||||
|
||||
ret = arch_timer_init();
|
||||
if (ret)
|
||||
return ret;
|
||||
if (arch_timer_rate == 0)
|
||||
return -ENXIO;
|
||||
|
||||
arch_timer_delay_timer_register();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int __init arch_timer_sched_clock_init(void)
|
||||
{
|
||||
if (arch_timer_get_rate() == 0)
|
||||
return -ENXIO;
|
||||
|
||||
setup_sched_clock(arch_timer_read_counter_u32,
|
||||
32, arch_timer_get_rate());
|
||||
/* Cache the sched_clock multiplier to save a divide in the hot path. */
|
||||
sched_clock_mult = NSEC_PER_SEC / arch_timer_rate;
|
||||
sched_clock_func = arch_timer_sched_clock;
|
||||
pr_info("sched_clock: ARM arch timer >56 bits at %ukHz, resolution %uns\n",
|
||||
arch_timer_rate / 1000, sched_clock_mult);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -20,6 +20,7 @@ struct clock_data {
|
||||
u64 epoch_ns;
|
||||
u32 epoch_cyc;
|
||||
u32 epoch_cyc_copy;
|
||||
unsigned long rate;
|
||||
u32 mult;
|
||||
u32 shift;
|
||||
bool suspended;
|
||||
@ -113,11 +114,14 @@ void __init setup_sched_clock(u32 (*read)(void), int bits, unsigned long rate)
|
||||
u64 res, wrap;
|
||||
char r_unit;
|
||||
|
||||
if (cd.rate > rate)
|
||||
return;
|
||||
|
||||
BUG_ON(bits > 32);
|
||||
WARN_ON(!irqs_disabled());
|
||||
WARN_ON(read_sched_clock != jiffy_sched_clock_read);
|
||||
read_sched_clock = read;
|
||||
sched_clock_mask = (1 << bits) - 1;
|
||||
cd.rate = rate;
|
||||
|
||||
/* calculate the mult/shift to convert counter ticks to ns. */
|
||||
clocks_calc_mult_shift(&cd.mult, &cd.shift, rate, NSEC_PER_SEC, 0);
|
||||
@ -161,12 +165,19 @@ void __init setup_sched_clock(u32 (*read)(void), int bits, unsigned long rate)
|
||||
pr_debug("Registered %pF as sched_clock source\n", read);
|
||||
}
|
||||
|
||||
unsigned long long notrace sched_clock(void)
|
||||
static unsigned long long notrace sched_clock_32(void)
|
||||
{
|
||||
u32 cyc = read_sched_clock();
|
||||
return cyc_to_sched_clock(cyc, sched_clock_mask);
|
||||
}
|
||||
|
||||
unsigned long long __read_mostly (*sched_clock_func)(void) = sched_clock_32;
|
||||
|
||||
unsigned long long notrace sched_clock(void)
|
||||
{
|
||||
return sched_clock_func();
|
||||
}
|
||||
|
||||
void __init sched_clock_postinit(void)
|
||||
{
|
||||
/*
|
||||
|
@ -22,6 +22,7 @@
|
||||
#include <linux/errno.h>
|
||||
#include <linux/profile.h>
|
||||
#include <linux/timer.h>
|
||||
#include <linux/clocksource.h>
|
||||
#include <linux/irq.h>
|
||||
|
||||
#include <asm/thread_info.h>
|
||||
@ -115,6 +116,10 @@ int __init register_persistent_clock(clock_access_fn read_boot,
|
||||
|
||||
void __init time_init(void)
|
||||
{
|
||||
machine_desc->init_time();
|
||||
if (machine_desc->init_time)
|
||||
machine_desc->init_time();
|
||||
else
|
||||
clocksource_of_init();
|
||||
|
||||
sched_clock_postinit();
|
||||
}
|
||||
|
@ -217,7 +217,6 @@ DT_MACHINE_START(EXYNOS5_DT, "SAMSUNG EXYNOS5 (Flattened Device Tree)")
|
||||
.map_io = exynos5_dt_map_io,
|
||||
.init_machine = exynos5_dt_machine_init,
|
||||
.init_late = exynos_init_late,
|
||||
.init_time = clocksource_of_init,
|
||||
.dt_compat = exynos5_dt_compat,
|
||||
.restart = exynos5_restart,
|
||||
.reserve = exynos5_reserve,
|
||||
|
@ -15,6 +15,7 @@
|
||||
*/
|
||||
#include <linux/clk.h>
|
||||
#include <linux/clkdev.h>
|
||||
#include <linux/clocksource.h>
|
||||
#include <linux/dma-mapping.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/irq.h>
|
||||
@ -28,12 +29,9 @@
|
||||
#include <linux/amba/bus.h>
|
||||
#include <linux/clk-provider.h>
|
||||
|
||||
#include <asm/arch_timer.h>
|
||||
#include <asm/cacheflush.h>
|
||||
#include <asm/cputype.h>
|
||||
#include <asm/smp_plat.h>
|
||||
#include <asm/hardware/arm_timer.h>
|
||||
#include <asm/hardware/timer-sp.h>
|
||||
#include <asm/hardware/cache-l2x0.h>
|
||||
#include <asm/mach/arch.h>
|
||||
#include <asm/mach/map.h>
|
||||
@ -90,36 +88,16 @@ static void __init highbank_init_irq(void)
|
||||
#endif
|
||||
}
|
||||
|
||||
static struct clk_lookup lookup = {
|
||||
.dev_id = "sp804",
|
||||
.con_id = NULL,
|
||||
};
|
||||
|
||||
static void __init highbank_timer_init(void)
|
||||
{
|
||||
int irq;
|
||||
struct device_node *np;
|
||||
void __iomem *timer_base;
|
||||
|
||||
/* Map system registers */
|
||||
np = of_find_compatible_node(NULL, NULL, "calxeda,hb-sregs");
|
||||
sregs_base = of_iomap(np, 0);
|
||||
WARN_ON(!sregs_base);
|
||||
|
||||
np = of_find_compatible_node(NULL, NULL, "arm,sp804");
|
||||
timer_base = of_iomap(np, 0);
|
||||
WARN_ON(!timer_base);
|
||||
irq = irq_of_parse_and_map(np, 0);
|
||||
|
||||
of_clk_init(NULL);
|
||||
lookup.clk = of_clk_get(np, 0);
|
||||
clkdev_add(&lookup);
|
||||
|
||||
sp804_clocksource_and_sched_clock_init(timer_base + 0x20, "timer1");
|
||||
sp804_clockevents_init(timer_base, irq, "timer0");
|
||||
|
||||
arch_timer_of_register();
|
||||
arch_timer_sched_clock_init();
|
||||
|
||||
clocksource_of_init();
|
||||
}
|
||||
|
@ -250,39 +250,6 @@ static void __init intcp_init_early(void)
|
||||
}
|
||||
|
||||
#ifdef CONFIG_OF
|
||||
|
||||
static void __init cp_of_timer_init(void)
|
||||
{
|
||||
struct device_node *node;
|
||||
const char *path;
|
||||
void __iomem *base;
|
||||
int err;
|
||||
int irq;
|
||||
|
||||
err = of_property_read_string(of_aliases,
|
||||
"arm,timer-primary", &path);
|
||||
if (WARN_ON(err))
|
||||
return;
|
||||
node = of_find_node_by_path(path);
|
||||
base = of_iomap(node, 0);
|
||||
if (WARN_ON(!base))
|
||||
return;
|
||||
writel(0, base + TIMER_CTRL);
|
||||
sp804_clocksource_init(base, node->name);
|
||||
|
||||
err = of_property_read_string(of_aliases,
|
||||
"arm,timer-secondary", &path);
|
||||
if (WARN_ON(err))
|
||||
return;
|
||||
node = of_find_node_by_path(path);
|
||||
base = of_iomap(node, 0);
|
||||
if (WARN_ON(!base))
|
||||
return;
|
||||
irq = irq_of_parse_and_map(node, 0);
|
||||
writel(0, base + TIMER_CTRL);
|
||||
sp804_clockevents_init(base, irq, node->name);
|
||||
}
|
||||
|
||||
static const struct of_device_id fpga_irq_of_match[] __initconst = {
|
||||
{ .compatible = "arm,versatile-fpga-irq", .data = fpga_irq_of_init, },
|
||||
{ /* Sentinel */ }
|
||||
@ -383,7 +350,6 @@ DT_MACHINE_START(INTEGRATOR_CP_DT, "ARM Integrator/CP (Device Tree)")
|
||||
.init_early = intcp_init_early,
|
||||
.init_irq = intcp_init_irq_of,
|
||||
.handle_irq = fpga_handle_irq,
|
||||
.init_time = cp_of_timer_init,
|
||||
.init_machine = intcp_init_of,
|
||||
.restart = integrator_restart,
|
||||
.dt_compat = intcp_dt_board_compat,
|
||||
|
@ -46,7 +46,6 @@
|
||||
#include <asm/smp_twd.h>
|
||||
#include <asm/sched_clock.h>
|
||||
|
||||
#include <asm/arch_timer.h>
|
||||
#include "omap_hwmod.h"
|
||||
#include "omap_device.h"
|
||||
#include <plat/counter-32k.h>
|
||||
@ -627,9 +626,7 @@ void __init omap5_realtime_timer_init(void)
|
||||
omap4_sync32k_timer_init();
|
||||
realtime_counter_init();
|
||||
|
||||
err = arch_timer_of_register();
|
||||
if (err)
|
||||
pr_err("%s: arch_timer_register failed %d\n", __func__, err);
|
||||
clocksource_of_init();
|
||||
}
|
||||
#endif /* CONFIG_SOC_OMAP5 */
|
||||
|
||||
|
@ -90,6 +90,5 @@ DT_MACHINE_START(KZM9D_DT, "kzm9d")
|
||||
.init_irq = emev2_init_irq,
|
||||
.init_machine = kzm9d_add_standard_devices,
|
||||
.init_late = shmobile_init_late,
|
||||
.init_time = shmobile_timer_init,
|
||||
.dt_compat = kzm9d_boards_compat_dt,
|
||||
MACHINE_END
|
||||
|
@ -456,7 +456,6 @@ DT_MACHINE_START(EMEV2_DT, "Generic Emma Mobile EV2 (Flattened Device Tree)")
|
||||
.nr_irqs = NR_IRQS_LEGACY,
|
||||
.init_irq = irqchip_init,
|
||||
.init_machine = emev2_add_standard_devices_dt,
|
||||
.init_time = shmobile_timer_init,
|
||||
.dt_compat = emev2_boards_compat_dt,
|
||||
MACHINE_END
|
||||
|
||||
|
@ -906,7 +906,6 @@ DT_MACHINE_START(R8A7740_DT, "Generic R8A7740 (Flattened Device Tree)")
|
||||
.init_irq = r8a7740_init_irq,
|
||||
.handle_irq = shmobile_handle_irq_intc,
|
||||
.init_machine = r8a7740_add_standard_devices_dt,
|
||||
.init_time = shmobile_timer_init,
|
||||
.dt_compat = r8a7740_boards_compat_dt,
|
||||
MACHINE_END
|
||||
|
||||
|
@ -1175,7 +1175,6 @@ DT_MACHINE_START(SH7372_DT, "Generic SH7372 (Flattened Device Tree)")
|
||||
.init_irq = sh7372_init_irq,
|
||||
.handle_irq = shmobile_handle_irq_intc,
|
||||
.init_machine = sh7372_add_standard_devices_dt,
|
||||
.init_time = shmobile_timer_init,
|
||||
.dt_compat = sh7372_boards_compat_dt,
|
||||
MACHINE_END
|
||||
|
||||
|
@ -1037,7 +1037,6 @@ DT_MACHINE_START(SH73A0_DT, "Generic SH73A0 (Flattened Device Tree)")
|
||||
.nr_irqs = NR_IRQS_LEGACY,
|
||||
.init_irq = irqchip_init,
|
||||
.init_machine = sh73a0_add_standard_devices_dt,
|
||||
.init_time = shmobile_timer_init,
|
||||
.dt_compat = sh73a0_boards_compat_dt,
|
||||
MACHINE_END
|
||||
#endif /* CONFIG_USE_OF */
|
||||
|
@ -19,10 +19,8 @@
|
||||
*
|
||||
*/
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/clocksource.h>
|
||||
#include <linux/delay.h>
|
||||
#include <asm/arch_timer.h>
|
||||
#include <asm/mach/time.h>
|
||||
#include <asm/smp_twd.h>
|
||||
|
||||
void __init shmobile_setup_delay(unsigned int max_cpu_core_mhz,
|
||||
unsigned int mult, unsigned int div)
|
||||
@ -63,6 +61,5 @@ void __init shmobile_earlytimer_init(void)
|
||||
|
||||
void __init shmobile_timer_init(void)
|
||||
{
|
||||
arch_timer_of_register();
|
||||
arch_timer_sched_clock_init();
|
||||
clocksource_of_init();
|
||||
}
|
||||
|
@ -749,12 +749,25 @@ void versatile_restart(char mode, const char *cmd)
|
||||
/* Early initializations */
|
||||
void __init versatile_init_early(void)
|
||||
{
|
||||
u32 val;
|
||||
void __iomem *sys = __io_address(VERSATILE_SYS_BASE);
|
||||
|
||||
osc4_clk.vcoreg = sys + VERSATILE_SYS_OSCCLCD_OFFSET;
|
||||
clkdev_add_table(lookups, ARRAY_SIZE(lookups));
|
||||
|
||||
versatile_sched_clock_init(sys + VERSATILE_SYS_24MHz_OFFSET, 24000000);
|
||||
|
||||
/*
|
||||
* set clock frequency:
|
||||
* VERSATILE_REFCLK is 32KHz
|
||||
* VERSATILE_TIMCLK is 1MHz
|
||||
*/
|
||||
val = readl(__io_address(VERSATILE_SCTL_BASE));
|
||||
writel((VERSATILE_TIMCLK << VERSATILE_TIMER1_EnSel) |
|
||||
(VERSATILE_TIMCLK << VERSATILE_TIMER2_EnSel) |
|
||||
(VERSATILE_TIMCLK << VERSATILE_TIMER3_EnSel) |
|
||||
(VERSATILE_TIMCLK << VERSATILE_TIMER4_EnSel) | val,
|
||||
__io_address(VERSATILE_SCTL_BASE));
|
||||
}
|
||||
|
||||
void __init versatile_init(void)
|
||||
@ -785,19 +798,6 @@ void __init versatile_init(void)
|
||||
*/
|
||||
void __init versatile_timer_init(void)
|
||||
{
|
||||
u32 val;
|
||||
|
||||
/*
|
||||
* set clock frequency:
|
||||
* VERSATILE_REFCLK is 32KHz
|
||||
* VERSATILE_TIMCLK is 1MHz
|
||||
*/
|
||||
val = readl(__io_address(VERSATILE_SCTL_BASE));
|
||||
writel((VERSATILE_TIMCLK << VERSATILE_TIMER1_EnSel) |
|
||||
(VERSATILE_TIMCLK << VERSATILE_TIMER2_EnSel) |
|
||||
(VERSATILE_TIMCLK << VERSATILE_TIMER3_EnSel) |
|
||||
(VERSATILE_TIMCLK << VERSATILE_TIMER4_EnSel) | val,
|
||||
__io_address(VERSATILE_SCTL_BASE));
|
||||
|
||||
/*
|
||||
* Initialise to a known state (all timers off)
|
||||
|
@ -45,7 +45,6 @@ DT_MACHINE_START(VERSATILE_PB, "ARM-Versatile (Device Tree Support)")
|
||||
.map_io = versatile_map_io,
|
||||
.init_early = versatile_init_early,
|
||||
.init_irq = versatile_init_irq,
|
||||
.init_time = versatile_timer_init,
|
||||
.init_machine = versatile_dt_init,
|
||||
.dt_compat = versatile_dt_match,
|
||||
.restart = versatile_restart,
|
||||
|
@ -1,6 +1,7 @@
|
||||
/*
|
||||
* Versatile Express V2M Motherboard Support
|
||||
*/
|
||||
#include <linux/clocksource.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/amba/bus.h>
|
||||
#include <linux/amba/mmci.h>
|
||||
@ -23,7 +24,6 @@
|
||||
#include <linux/regulator/machine.h>
|
||||
#include <linux/vexpress.h>
|
||||
|
||||
#include <asm/arch_timer.h>
|
||||
#include <asm/mach-types.h>
|
||||
#include <asm/sizes.h>
|
||||
#include <asm/mach/arch.h>
|
||||
@ -61,9 +61,6 @@ static void __init v2m_sp804_init(void __iomem *base, unsigned int irq)
|
||||
if (WARN_ON(!base || irq == NO_IRQ))
|
||||
return;
|
||||
|
||||
writel(0, base + TIMER_1_BASE + TIMER_CTRL);
|
||||
writel(0, base + TIMER_2_BASE + TIMER_CTRL);
|
||||
|
||||
sp804_clocksource_init(base + TIMER_2_BASE, "v2m-timer1");
|
||||
sp804_clockevents_init(base + TIMER_1_BASE, irq, "v2m-timer0");
|
||||
}
|
||||
@ -431,25 +428,11 @@ void __init v2m_dt_init_early(void)
|
||||
|
||||
static void __init v2m_dt_timer_init(void)
|
||||
{
|
||||
struct device_node *node = NULL;
|
||||
|
||||
vexpress_clk_of_init();
|
||||
|
||||
clocksource_of_init();
|
||||
do {
|
||||
node = of_find_compatible_node(node, NULL, "arm,sp804");
|
||||
} while (node && vexpress_get_site_by_node(node) != VEXPRESS_SITE_MB);
|
||||
if (node) {
|
||||
pr_info("Using SP804 '%s' as a clock & events source\n",
|
||||
node->full_name);
|
||||
v2m_sp804_init(of_iomap(node, 0),
|
||||
irq_of_parse_and_map(node, 0));
|
||||
}
|
||||
|
||||
arch_timer_of_register();
|
||||
|
||||
if (arch_timer_sched_clock_init() != 0)
|
||||
versatile_sched_clock_init(vexpress_get_24mhz_clock_base(),
|
||||
versatile_sched_clock_init(vexpress_get_24mhz_clock_base(),
|
||||
24000000);
|
||||
}
|
||||
|
||||
|
@ -23,21 +23,13 @@
|
||||
#include <linux/of_platform.h>
|
||||
#include <linux/smp.h>
|
||||
|
||||
#include <asm/arch_timer.h>
|
||||
#include <asm/mach/arch.h>
|
||||
#include <asm/mach/time.h>
|
||||
|
||||
static void __init virt_init(void)
|
||||
{
|
||||
of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL);
|
||||
}
|
||||
|
||||
static void __init virt_timer_init(void)
|
||||
{
|
||||
WARN_ON(arch_timer_of_register() != 0);
|
||||
WARN_ON(arch_timer_sched_clock_init() != 0);
|
||||
}
|
||||
|
||||
static const char *virt_dt_match[] = {
|
||||
"linux,dummy-virt",
|
||||
NULL
|
||||
@ -47,7 +39,6 @@ extern struct smp_operations virt_smp_ops;
|
||||
|
||||
DT_MACHINE_START(VIRT, "Dummy Virtual Machine")
|
||||
.init_irq = irqchip_init,
|
||||
.init_time = virt_timer_init,
|
||||
.init_machine = virt_init,
|
||||
.smp = smp_ops(virt_smp_ops),
|
||||
.dt_compat = virt_dt_match,
|
||||
|
@ -130,4 +130,9 @@ static inline u64 arch_counter_get_cntvct(void)
|
||||
return cval;
|
||||
}
|
||||
|
||||
static inline int arch_timer_arch_init(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@ -32,6 +32,7 @@
|
||||
#include <linux/timer.h>
|
||||
#include <linux/irq.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/clocksource.h>
|
||||
|
||||
#include <clocksource/arm_arch_timer.h>
|
||||
|
||||
@ -77,10 +78,11 @@ void __init time_init(void)
|
||||
{
|
||||
u32 arch_timer_rate;
|
||||
|
||||
if (arch_timer_init())
|
||||
panic("Unable to initialise architected timer.\n");
|
||||
clocksource_of_init();
|
||||
|
||||
arch_timer_rate = arch_timer_get_rate();
|
||||
if (!arch_timer_rate)
|
||||
panic("Unable to initialise architected timer.\n");
|
||||
|
||||
/* Cache the sched_clock multiplier to save a divide in the hot path. */
|
||||
sched_clock_mult = NSEC_PER_SEC / arch_timer_rate;
|
||||
|
@ -65,6 +65,7 @@ config CLKSRC_DBX500_PRCMU_SCHED_CLOCK
|
||||
|
||||
config ARM_ARCH_TIMER
|
||||
bool
|
||||
select CLKSRC_OF if OF
|
||||
|
||||
config CLKSRC_METAG_GENERIC
|
||||
def_bool y if METAG
|
||||
|
@ -337,22 +337,14 @@ out:
|
||||
return err;
|
||||
}
|
||||
|
||||
static const struct of_device_id arch_timer_of_match[] __initconst = {
|
||||
{ .compatible = "arm,armv7-timer", },
|
||||
{ .compatible = "arm,armv8-timer", },
|
||||
{},
|
||||
};
|
||||
|
||||
int __init arch_timer_init(void)
|
||||
static void __init arch_timer_init(struct device_node *np)
|
||||
{
|
||||
struct device_node *np;
|
||||
u32 freq;
|
||||
int i;
|
||||
|
||||
np = of_find_matching_node(NULL, arch_timer_of_match);
|
||||
if (!np) {
|
||||
pr_err("arch_timer: can't find DT node\n");
|
||||
return -ENODEV;
|
||||
if (arch_timer_get_rate()) {
|
||||
pr_warn("arch_timer: multiple nodes in dt, skipping\n");
|
||||
return;
|
||||
}
|
||||
|
||||
/* Try to determine the frequency from the device tree or CNTFRQ */
|
||||
@ -378,7 +370,7 @@ int __init arch_timer_init(void)
|
||||
if (!arch_timer_ppi[PHYS_SECURE_PPI] ||
|
||||
!arch_timer_ppi[PHYS_NONSECURE_PPI]) {
|
||||
pr_warn("arch_timer: No interrupt available, giving up\n");
|
||||
return -EINVAL;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
@ -387,5 +379,8 @@ int __init arch_timer_init(void)
|
||||
else
|
||||
arch_timer_read_counter = arch_counter_get_cntpct;
|
||||
|
||||
return arch_timer_register();
|
||||
arch_timer_register();
|
||||
arch_timer_arch_init();
|
||||
}
|
||||
CLOCKSOURCE_OF_DECLARE(armv7_arch_timer, "arm,armv7-timer", arch_timer_init);
|
||||
CLOCKSOURCE_OF_DECLARE(armv8_arch_timer, "arm,armv8-timer", arch_timer_init);
|
||||
|
@ -24,7 +24,6 @@
|
||||
#include <linux/of_address.h>
|
||||
#include <linux/clocksource.h>
|
||||
|
||||
#include <asm/arch_timer.h>
|
||||
#include <asm/localtimer.h>
|
||||
|
||||
#include <plat/cpu.h>
|
||||
|
@ -31,18 +31,12 @@
|
||||
|
||||
#ifdef CONFIG_ARM_ARCH_TIMER
|
||||
|
||||
extern int arch_timer_init(void);
|
||||
extern u32 arch_timer_get_rate(void);
|
||||
extern u64 (*arch_timer_read_counter)(void);
|
||||
extern struct timecounter *arch_timer_get_timecounter(void);
|
||||
|
||||
#else
|
||||
|
||||
static inline int arch_timer_init(void)
|
||||
{
|
||||
return -ENXIO;
|
||||
}
|
||||
|
||||
static inline u32 arch_timer_get_rate(void)
|
||||
{
|
||||
return 0;
|
||||
|
@ -382,6 +382,11 @@ static inline int of_device_is_compatible(const struct device_node *device,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int of_device_is_available(const struct device_node *device)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline struct property *of_find_property(const struct device_node *np,
|
||||
const char *name,
|
||||
int *lenp)
|
||||
|
Loading…
Reference in New Issue
Block a user