clockevents for 4.1
Subsystems (5)
Hi Thomas, Ingo,
this pull request contains the following changes for 4.1:
- Made IO endian agnostic for at91 and dw apb timers (Ben Dooks)
- Maintained tegra endianess (Dmitry Osipenko)
- Enabled the sun4i / sun5i timer for sched_clock, all others winner
boards have the arch arm timer which is more accurate (Hans de Goede)
- Renamed the arch arm timer function name to reflect better its
purpose (Laurent Pinchart)
- Cleaned up the sun5i timer code, replaced the setup_irq by therequest_irq function and handled the parent clock frequency change with the frequency notifiers (Maxime Ripard)
- Fixed features declaration for the efm32 timer (Viresh Kumar)
Thanks !
-- Daniel
The following changes since commit 2557d215a36d18c8bbaa35f65749349ac603360b:
Merge branch 'timers/urgent' into timers/core, to pick up fixes
before applying new changes (2015-03-17 11:11:24 +0100)
are available in the git repository at:
http://git.linaro.org/people/daniel.lezcano/linux.git clockevents/4.1
for you to fetch changes up to 0bb4ef6f7c56cdf606a5e501cf1597f40c9028eb
clocksource: efm32: Use CLOCK_EVT_FEAT_PERIODIC for defining features
(2015-03-30 15:27:24 +0200)
----------------------------------------------------------------
Ben Dooks (2):
clocksource: at91: Make IO endian agnostic
clocksource: dw_apb_timer_of: Make IO endian agnostic
Dmitry Osipenko (1):
clocksource: tegra: Maintain CPU endianness
Hans de Goede (1):
clocksource: sun4i-timer: Only register a sched_clock on sun4i
and sun5i
Laurent Pinchart (1):
clocksource: arm_arch_timer: Rename arch_timer_probed to reflect
behaviour
Maxime Ripard (5):
clocksource: sun5i: Switch to request_irq
clocksource: sun5i: Use of_io_request_and_map
clocksource: sun5i: Remove sched_clock
clocksource: sun5i: Refactor the current code
clocksource: sun5i: Add clock notifiers
Viresh Kumar (1):
clocksource: efm32: Use CLOCK_EVT_FEAT_PERIODIC for defining features
drivers/clocksource/arm_arch_timer.c | 13 +++++----- drivers/clocksource/dw_apb_timer_of.c | 2 +- drivers/clocksource/sun4i_timer.c | 10 +++++++- drivers/clocksource/tegra20_timer.c | 4 ++-- drivers/clocksource/time-efm32.c | 2 +- drivers/clocksource/timer-atmel-pit.c | 4 ++-- drivers/clocksource/timer-sun5i.c | 302 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-------------------------------------------------------- 7 files changed, 250 insertions(+), 87 deletions(-)
Signature · 5 lines
<http://www.linaro.org/> Linaro.org ? Open source software for ARM SoCs Follow Linaro: <http://www.facebook.com/pages/Linaro> Facebook | <http://twitter.com/#!/linaroorg> Twitter | <http://www.linaro.org/linaro-blog/> Blog
PATCH 1/11 clocksource: arm_arch_timer: Rename arch_timer_probed to reflect behaviour
From: Laurent Pinchart <[email protected]>
The arch_timer_probed function returns whether the given time doesn't need to be probed. This can be the case when the timer has been probed already, but also when it has no corresponding enabled node in DT.
Rename the function to arch_timer_need_probe and invert its return value to better reflect the function's purpose and behaviour.
--- drivers/clocksource/arm_arch_timer.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-)
drivers/clocksource/arm_arch_timer.c +7 -6
@@ -661,17 +661,17 @@ static const struct of_device_id arch_timer_mem_of_match[] __initconst = { };static bool __init -arch_timer_probed (int type,const struct of_device_id *matches) +arch_timer_need_probe (int type,const struct of_device_id *matches) {struct device_node *dn; -bool probed = true; +bool need_probe = false; dn =of_find_matching_node (NULL , matches);if (dn &&of_device_is_available (dn) && !(arch_timers_present & type)) - probed = false; + need_probe = true;of_node_put (dn); -return probed; +return need_probe; }static void __init arch_timer_common_init (void )
@@ -680,9 +680,10 @@ static void __init arch_timer_common_init(void)/* Wait until both nodes are probed if we have two timers */ if ((arch_timers_present & mask) != mask) { -if (!arch_timer_probed (ARCH_MEM_TIMER , arch_timer_mem_of_match)) +if (arch_timer_need_probe (ARCH_MEM_TIMER , + arch_timer_mem_of_match))return ; -if (!arch_timer_probed (ARCH_CP15_TIMER , arch_timer_of_match)) +if (arch_timer_need_probe (ARCH_CP15_TIMER , arch_timer_of_match))return ; }
Signature · 1 line
1.9.1
PATCH 2/11 clocksource: sun5i: Switch to request_irq
From: Maxime Ripard <[email protected]>
The current code uses setup_irq, while it could perfectly use the much simpler request_irq. Switch to that.
--- drivers/clocksource/timer-sun5i.c | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-)
drivers/clocksource/timer-sun5i.c +2 -8
@@ -130,13 +130,6 @@ static irqreturn_t sun5i_timer_interrupt(int irq, void *dev_id)return IRQ_HANDLED ; } -static struct irqaction sun5i_timer_irq = { - .name ="sun5i_timer0" , - .flags =IRQF_TIMER |IRQF_IRQPOLL , - .handler = sun5i_timer_interrupt, - .dev_id = &sun5i_clockevent, -}; -static u64 sun5i_timer_sched_read (void ) {return ~readl (timer_base +TIMER_CNTVAL_LO_REG (1 ));
@@ -188,7 +181,8 @@ static void __init sun5i_timer_init(struct device_node *node)clockevents_config_and_register (&sun5i_clockevent, rate,TIMER_SYNC_TICKS ,0xffffffff ); - ret =setup_irq (irq, &sun5i_timer_irq); + ret =request_irq (irq, sun5i_timer_interrupt,IRQF_TIMER |IRQF_IRQPOLL , +"sun5i_timer0" , &sun5i_clockevent);if (ret)pr_warn ("failed to setup irq %d\n" , irq); }
Signature · 1 line
1.9.1
PATCH 3/11 clocksource: sun5i: Use of_io_request_and_map
In reply to Daniel LezcanoFrom: Maxime Ripard <[email protected]>
of_iomap doesn't do a request_mem_region on the memory area defined in the DT it maps. Switch to of_io_request_and_map to make sure we're the only users.
--- drivers/clocksource/timer-sun5i.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
drivers/clocksource/timer-sun5i.c +2 -1
@@ -143,7 +143,8 @@ static void __init sun5i_timer_init(struct device_node *node)int ret, irq;u32 val; - timer_base =of_iomap (node,0 ); + timer_base =of_io_request_and_map (node,0 , +of_node_full_name (node));if (!timer_base)panic ("Can't map registers" );
Signature · 1 line
1.9.1
PATCH 4/11 clocksource: sun5i: Remove sched_clock
In reply to Daniel LezcanoFrom: Maxime Ripard <[email protected]>
It's not possible to remove a sched_clock once it has been added, nor is it possible to change its rate.
Since we will need to support a rate change, and that we have other sched_clocks in the system anyway, remove it.
--- drivers/clocksource/timer-sun5i.c | 6 ------ 1 file changed, 6 deletions(-)
drivers/clocksource/timer-sun5i.c +0 -6
@@ -130,11 +130,6 @@ static irqreturn_t sun5i_timer_interrupt(int irq, void *dev_id)return IRQ_HANDLED ; } -static u64 sun5i_timer_sched_read (void ) -{ -return ~readl (timer_base +TIMER_CNTVAL_LO_REG (1 )); -} -static void __init sun5i_timer_init (struct device_node *node) {struct reset_control *rstc;
@@ -166,7 +161,6 @@ static void __init sun5i_timer_init(struct device_node *node)writel (TIMER_CTL_ENABLE |TIMER_CTL_RELOAD , timer_base +TIMER_CTL_REG (1 )); -sched_clock_register (sun5i_timer_sched_read,32 , rate);clocksource_mmio_init (timer_base +TIMER_CNTVAL_LO_REG (1 ), node->name, rate,340 ,32 , clocksource_mmio_readl_down);
Signature · 1 line
1.9.1
PATCH 5/11 clocksource: sun5i: Refactor the current code
In reply to Daniel LezcanoFrom: Maxime Ripard <[email protected]>
Refactor the code in order to remove the global variables and split the clock source and clock events registration in order to ease the addition of the clock notifiers needed to handle the parent clock rate changes.
[dlezcano] : Fixed conflict with commit 1096be084ac59927158ce80ff1d31c33eed0e565
--- drivers/clocksource/timer-sun5i.c | 231 +++++++++++++++++++++++++++----------- 1 file changed, 166 insertions(+), 65 deletions(-)
drivers/clocksource/timer-sun5i.c +166 -65
@@ -18,6 +18,7 @@#include <linux/irqreturn.h> #include <linux/reset.h> #include <linux/sched_clock.h> +#include <linux/slab.h> #include <linux/of.h> #include <linux/of_address.h> #include <linux/of_irq.h>
@@ -37,8 +38,27 @@#define TIMER_SYNC_TICKS 3 -static void __iomem *timer_base; -static u32 ticks_per_jiffy; +struct sun5i_timer { +void __iomem *base; +struct clk *clk; +u32 ticks_per_jiffy; +}; + +struct sun5i_timer_clksrc { +struct sun5i_timer timer; +struct clocksource clksrc; +}; + +#define to_sun5i_timer_clksrc (x) \ + container_of(x, struct sun5i_timer_clksrc, clksrc) + +struct sun5i_timer_clkevt { +struct sun5i_timer timer; +struct clock_event_device clkevt; +}; + +#define to_sun5i_timer_clkevt (x) \ + container_of(x, struct sun5i_timer_clkevt, clkevt)/* * When we disable a timer, we need to wait at least for 2 cycles of
@@ -46,30 +66,30 @@ static u32 ticks_per_jiffy;* that is already setup and runs at the same frequency than the other * timers, and we never will be disabled. */ -static void sun5i_clkevt_sync (void ) +static void sun5i_clkevt_sync (struct sun5i_timer_clkevt *ce) { -u32 old =readl (timer_base +TIMER_CNTVAL_LO_REG (1 )); +u32 old =readl (ce->timer.base +TIMER_CNTVAL_LO_REG (1 )); -while ((old -readl (timer_base +TIMER_CNTVAL_LO_REG (1 ))) <TIMER_SYNC_TICKS ) +while ((old -readl (ce->timer.base +TIMER_CNTVAL_LO_REG (1 ))) <TIMER_SYNC_TICKS )cpu_relax (); } -static void sun5i_clkevt_time_stop (u8 timer) +static void sun5i_clkevt_time_stop (struct sun5i_timer_clkevt *ce,u8 timer) { -u32 val =readl (timer_base +TIMER_CTL_REG (timer)); -writel (val & ~TIMER_CTL_ENABLE , timer_base +TIMER_CTL_REG (timer)); +u32 val =readl (ce->timer.base +TIMER_CTL_REG (timer)); +writel (val & ~TIMER_CTL_ENABLE , ce->timer.base +TIMER_CTL_REG (timer)); -sun5i_clkevt_sync (); +sun5i_clkevt_sync (ce); } -static void sun5i_clkevt_time_setup (u8 timer,u32 delay) +static void sun5i_clkevt_time_setup (struct sun5i_timer_clkevt *ce,u8 timer,u32 delay) { -writel (delay, timer_base +TIMER_INTVAL_LO_REG (timer)); +writel (delay, ce->timer.base +TIMER_INTVAL_LO_REG (timer)); } -static void sun5i_clkevt_time_start (u8 timer,bool periodic) +static void sun5i_clkevt_time_start (struct sun5i_timer_clkevt *ce,u8 timer,bool periodic) { -u32 val =readl (timer_base +TIMER_CTL_REG (timer)); +u32 val =readl (ce->timer.base +TIMER_CTL_REG (timer));if (periodic) val &= ~TIMER_CTL_ONESHOT ;
@@ -77,66 +97,170 @@ static void sun5i_clkevt_time_start(u8 timer, bool periodic) val |=TIMER_CTL_ONESHOT ;writel (val |TIMER_CTL_ENABLE |TIMER_CTL_RELOAD , - timer_base +TIMER_CTL_REG (timer)); + ce->timer.base +TIMER_CTL_REG (timer)); }static void sun5i_clkevt_mode (enum clock_event_mode mode, -struct clock_event_device *clk) +struct clock_event_device *clkevt) { +struct sun5i_timer_clkevt *ce =to_sun5i_timer_clkevt (clkevt); +switch (mode) {case CLOCK_EVT_MODE_PERIODIC : -sun5i_clkevt_time_stop (0 ); -sun5i_clkevt_time_setup (0 , ticks_per_jiffy); -sun5i_clkevt_time_start (0 , true); +sun5i_clkevt_time_stop (ce,0 ); +sun5i_clkevt_time_setup (ce,0 , ce->timer.ticks_per_jiffy); +sun5i_clkevt_time_start (ce,0 , true);break ;case CLOCK_EVT_MODE_ONESHOT : -sun5i_clkevt_time_stop (0 ); -sun5i_clkevt_time_start (0 , false); +sun5i_clkevt_time_stop (ce,0 ); +sun5i_clkevt_time_start (ce,0 , false);break ;case CLOCK_EVT_MODE_UNUSED :case CLOCK_EVT_MODE_SHUTDOWN :default : -sun5i_clkevt_time_stop (0 ); +sun5i_clkevt_time_stop (ce,0 );break ; } }static int sun5i_clkevt_next_event (unsigned long evt, -struct clock_event_device *unused) +struct clock_event_device *clkevt) { -sun5i_clkevt_time_stop (0 ); -sun5i_clkevt_time_setup (0 , evt -TIMER_SYNC_TICKS ); -sun5i_clkevt_time_start (0 , false); +struct sun5i_timer_clkevt *ce =to_sun5i_timer_clkevt (clkevt); + +sun5i_clkevt_time_stop (ce,0 ); +sun5i_clkevt_time_setup (ce,0 , evt -TIMER_SYNC_TICKS ); +sun5i_clkevt_time_start (ce,0 , false);return 0 ; } -static struct clock_event_device sun5i_clockevent = { - .name ="sun5i_tick" , - .rating =340 , - .features =CLOCK_EVT_FEAT_PERIODIC |CLOCK_EVT_FEAT_ONESHOT , - .set_mode = sun5i_clkevt_mode, - .set_next_event = sun5i_clkevt_next_event, -}; - -static irqreturn_t sun5i_timer_interrupt (int irq,void *dev_id) { -struct clock_event_device *evt = (struct clock_event_device *)dev_id; +struct sun5i_timer_clkevt *ce = (struct sun5i_timer_clkevt *)dev_id; -writel (0x1 , timer_base +TIMER_IRQ_ST_REG ); - evt->event_handler (evt); +writel (0x1 , ce->timer.base +TIMER_IRQ_ST_REG ); + ce->clkevt.event_handler (&ce->clkevt);return IRQ_HANDLED ; } +static cycle_t sun5i_clksrc_read (struct clocksource *clksrc) +{ +struct sun5i_timer_clksrc *cs =to_sun5i_timer_clksrc (clksrc); + +return ~readl (cs->timer.base +TIMER_CNTVAL_LO_REG (1 )); +} + +static int __init sun5i_setup_clocksource (struct device_node *node, +void __iomem *base, +struct clk *clk,int irq) +{ +struct sun5i_timer_clksrc *cs; +unsigned long rate; +int ret; + + cs =kzalloc (sizeof (*cs),GFP_KERNEL ); +if (!cs) +return -ENOMEM ; + + ret =clk_prepare_enable (clk); +if (ret) { +pr_err ("Couldn't enable parent clock\n" ); + goto err_free; + } + + rate =clk_get_rate (clk); + + cs->timer.base = base; + cs->timer.clk = clk; + +writel (~0 , base +TIMER_INTVAL_LO_REG (1 )); +writel (TIMER_CTL_ENABLE |TIMER_CTL_RELOAD , + base +TIMER_CTL_REG (1 )); + + cs->clksrc.name = node->name; + cs->clksrc.rating =340 ; + cs->clksrc.read = sun5i_clksrc_read; + cs->clksrc.mask =CLOCKSOURCE_MASK (32 ); + cs->clksrc.flags =CLOCK_SOURCE_IS_CONTINUOUS ; + + ret =clocksource_register_hz (&cs->clksrc, rate); +if (ret) { +pr_err ("Couldn't register clock source.\n" ); + goto err_disable_clk; + } + +return 0 ; + +err_disable_clk: +clk_disable_unprepare (clk); +err_free: +kfree (cs); +return ret; +} + +static int __init sun5i_setup_clockevent (struct device_node *node,void __iomem *base, +struct clk *clk,int irq) +{ +struct sun5i_timer_clkevt *ce; +unsigned long rate; +int ret; +u32 val; + + ce =kzalloc (sizeof (*ce),GFP_KERNEL ); +if (!ce) +return -ENOMEM ; + + ret =clk_prepare_enable (clk); +if (ret) { +pr_err ("Couldn't enable parent clock\n" ); + goto err_free; + } + + rate =clk_get_rate (clk); + + ce->timer.base = base; + ce->timer.ticks_per_jiffy =DIV_ROUND_UP (rate,HZ ); + ce->timer.clk = clk; + + ce->clkevt.name = node->name; + ce->clkevt.features =CLOCK_EVT_FEAT_PERIODIC |CLOCK_EVT_FEAT_ONESHOT ; + ce->clkevt.set_next_event = sun5i_clkevt_next_event; + ce->clkevt.set_mode = sun5i_clkevt_mode; + ce->clkevt.rating =340 ; + ce->clkevt.irq = irq; + ce->clkevt.cpumask = cpu_possible_mask; + +/* Enable timer0 interrupt */ + val =readl (base +TIMER_IRQ_EN_REG ); +writel (val |TIMER_IRQ_EN (0 ), base +TIMER_IRQ_EN_REG ); + +clockevents_config_and_register (&ce->clkevt, rate, +TIMER_SYNC_TICKS ,0xffffffff ); + + ret =request_irq (irq, sun5i_timer_interrupt,IRQF_TIMER |IRQF_IRQPOLL , +"sun5i_timer0" , ce); +if (ret) { +pr_err ("Unable to register interrupt\n" ); + goto err_disable_clk; + } + +return 0 ; + +err_disable_clk: +clk_disable_unprepare (clk); +err_free: +kfree (ce); +return ret; +} +static void __init sun5i_timer_init (struct device_node *node) {struct reset_control *rstc; -unsigned long rate; +void __iomem *timer_base;struct clk *clk; -int ret, irq; -u32 val; +int irq; timer_base =of_io_request_and_map (node,0 ,of_node_full_name (node));
@@ -150,36 +274,13 @@ static void __init sun5i_timer_init(struct device_node *node) clk =of_clk_get (node,0 );if (IS_ERR (clk))panic ("Can't get timer clock" ); -clk_prepare_enable (clk); - rate =clk_get_rate (clk); rstc =of_reset_control_get (node,NULL );if (!IS_ERR (rstc))reset_control_deassert (rstc); -writel (~0 , timer_base +TIMER_INTVAL_LO_REG (1 )); -writel (TIMER_CTL_ENABLE |TIMER_CTL_RELOAD , - timer_base +TIMER_CTL_REG (1 )); - -clocksource_mmio_init (timer_base +TIMER_CNTVAL_LO_REG (1 ), node->name, - rate,340 ,32 , clocksource_mmio_readl_down); - - ticks_per_jiffy =DIV_ROUND_UP (rate,HZ ); - -/* Enable timer0 interrupt */ - val =readl (timer_base +TIMER_IRQ_EN_REG ); -writel (val |TIMER_IRQ_EN (0 ), timer_base +TIMER_IRQ_EN_REG ); - - sun5i_clockevent.cpumask = cpu_possible_mask; - sun5i_clockevent.irq = irq; - -clockevents_config_and_register (&sun5i_clockevent, rate, -TIMER_SYNC_TICKS ,0xffffffff ); - - ret =request_irq (irq, sun5i_timer_interrupt,IRQF_TIMER |IRQF_IRQPOLL , -"sun5i_timer0" , &sun5i_clockevent); -if (ret) -pr_warn ("failed to setup irq %d\n" , irq); +sun5i_setup_clocksource (node, timer_base, clk, irq); +sun5i_setup_clockevent (node, timer_base, clk, irq); }CLOCKSOURCE_OF_DECLARE (sun5i_a13,"allwinner,sun5i-a13-hstimer" , sun5i_timer_init);
Signature · 1 line
1.9.1
PATCH 6/11 clocksource: sun5i: Add clock notifiers
In reply to Daniel LezcanoFrom: Maxime Ripard <[email protected]>
The parent clock of the sun5i timer is the AHB clock, which rate might change because of other devices requirements.
This is for example the case on the Allwinner A31, where the DMA controller needs a minimum rate higher than the default, that is enforced after the timer driver has probed.
Add clock notifiers to make sure we reflect the clock rate changes in the timer rates.
--- drivers/clocksource/timer-sun5i.c | 68 +++++++++++++++++++++++++++++++++++++-- 1 file changed, 66 insertions(+), 2 deletions(-)
drivers/clocksource/timer-sun5i.c +66 -2
@@ -41,9 +41,13 @@struct sun5i_timer {void __iomem *base;struct clk *clk; +struct notifier_block clk_rate_cb;u32 ticks_per_jiffy; }; +#define to_sun5i_timer (x) \ + container_of(x, struct sun5i_timer, clk_rate_cb) +struct sun5i_timer_clksrc {struct sun5i_timer timer;struct clocksource clksrc;
@@ -152,6 +156,30 @@ static cycle_t sun5i_clksrc_read(struct clocksource *clksrc)return ~readl (cs->timer.base +TIMER_CNTVAL_LO_REG (1 )); } +static int sun5i_rate_cb_clksrc (struct notifier_block *nb, +unsigned long event,void *data) +{ +struct clk_notifier_data *ndata = data; +struct sun5i_timer *timer =to_sun5i_timer (nb); +struct sun5i_timer_clksrc *cs =container_of (timer, + struct sun5i_timer_clksrc, timer); + +switch (event) { +case PRE_RATE_CHANGE : +clocksource_unregister (&cs->clksrc); +break ; + +case POST_RATE_CHANGE : +clocksource_register_hz (&cs->clksrc, ndata->new_rate); +break ; + +default : +break ; + } + +return NOTIFY_DONE ; +} +static int __init sun5i_setup_clocksource (struct device_node *node,void __iomem *base,struct clk *clk,int irq)
@@ -174,6 +202,14 @@ static int __init sun5i_setup_clocksource(struct device_node *node, cs->timer.base = base; cs->timer.clk = clk; + cs->timer.clk_rate_cb.notifier_call = sun5i_rate_cb_clksrc; + cs->timer.clk_rate_cb.next =NULL ; + + ret =clk_notifier_register (clk, &cs->timer.clk_rate_cb); +if (ret) { +pr_err ("Unable to register clock notifier.\n" ); + goto err_disable_clk; + }writel (~0 , base +TIMER_INTVAL_LO_REG (1 )); writel(TIMER_CTL_ENABLE | TIMER_CTL_RELOAD,
@@ -188,11 +224,13 @@ static int __init sun5i_setup_clocksource(struct device_node *node, ret =clocksource_register_hz (&cs->clksrc, rate);if (ret) {pr_err ("Couldn't register clock source.\n" ); - goto err_disable_clk; + goto err_remove_notifier; }return 0 ; +err_remove_notifier: +clk_notifier_unregister (clk, &cs->timer.clk_rate_cb); err_disable_clk:clk_disable_unprepare (clk); err_free:
@@ -200,6 +238,22 @@ err_free:return ret; } +static int sun5i_rate_cb_clkevt (struct notifier_block *nb, +unsigned long event,void *data) +{ +struct clk_notifier_data *ndata = data; +struct sun5i_timer *timer =to_sun5i_timer (nb); +struct sun5i_timer_clkevt *ce =container_of (timer, + struct sun5i_timer_clkevt, timer); + +if (event ==POST_RATE_CHANGE ) { +clockevents_update_freq (&ce->clkevt, ndata->new_rate); + ce->timer.ticks_per_jiffy =DIV_ROUND_UP (ndata->new_rate,HZ ); + } + +return NOTIFY_DONE ; +} +static int __init sun5i_setup_clockevent (struct device_node *node,void __iomem *base,struct clk *clk,int irq) {
@@ -223,6 +277,14 @@ static int __init sun5i_setup_clockevent(struct device_node *node, void __iomem ce->timer.base = base; ce->timer.ticks_per_jiffy =DIV_ROUND_UP (rate,HZ ); ce->timer.clk = clk; + ce->timer.clk_rate_cb.notifier_call = sun5i_rate_cb_clkevt; + ce->timer.clk_rate_cb.next =NULL ; + + ret =clk_notifier_register (clk, &ce->timer.clk_rate_cb); +if (ret) { +pr_err ("Unable to register clock notifier.\n" ); + goto err_disable_clk; + } ce->clkevt.name = node->name; ce->clkevt.features =CLOCK_EVT_FEAT_PERIODIC |CLOCK_EVT_FEAT_ONESHOT ;
@@ -243,11 +305,13 @@ static int __init sun5i_setup_clockevent(struct device_node *node, void __iomem "sun5i_timer0", ce);if (ret) {pr_err ("Unable to register interrupt\n" ); - goto err_disable_clk; + goto err_remove_notifier; }return 0 ; +err_remove_notifier: +clk_notifier_unregister (clk, &ce->timer.clk_rate_cb); err_disable_clk:clk_disable_unprepare (clk); err_free:
Signature · 1 line
1.9.1
PATCH 7/11 clocksource: at91: Make IO endian agnostic
In reply to Daniel LezcanoFrom: Ben Dooks <[email protected]>
Fix the use of __raw IO accessor with the readl/writel_relaxed versions to allow the code to be used on a system running in big endian.
--- drivers/clocksource/timer-atmel-pit.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
drivers/clocksource/timer-atmel-pit.c +2 -2
@@ -61,12 +61,12 @@ static inline struct pit_data *clkevt_to_pit_data(struct clock_event_device *clkstatic inline unsigned int pit_read (void __iomem *base,unsigned int reg_offset) { -return __raw_readl (base + reg_offset); +return readl_relaxed (base + reg_offset); }static inline void pit_write (void __iomem *base,unsigned int reg_offset,unsigned long value) { -__raw_writel (value, base + reg_offset); +writel_relaxed (value, base + reg_offset); }/*
Signature · 1 line
1.9.1
tip-bot for Ben Dooks
merge bot[tip:timers/core] clocksource/drivers/at91: Fix IO endianness
clocksource/drivers/at91: Fix IO endianness
Commit-ID: 4806c87f017d8a7003ad34886f58c3b9e023df6a Gitweb: http://git.kernel.org/tip/4806c87f017d8a7003ad34886f58c3b9e023df6a Author: Ben Dooks <[email protected]> AuthorDate: Mon, 30 Mar 2015 22:17:09 +0200 Committer: Ingo Molnar <[email protected]> CommitDate: Tue, 31 Mar 2015 09:15:58 +0200
clocksource/drivers/at91: Fix IO endianness
Fix the use of __raw IO accessor with the readl/writel_relaxed() versions to allow the code to be used on a system running in big endian mode.
--- drivers/clocksource/timer-atmel-pit.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
drivers/clocksource/timer-atmel-pit.c +2 -2
@@ -61,12 +61,12 @@ static inline struct pit_data *clkevt_to_pit_data(struct clock_event_device *clkstatic inline unsigned int pit_read (void __iomem *base,unsigned int reg_offset) { -return __raw_readl (base + reg_offset); +return readl_relaxed (base + reg_offset); }static inline void pit_write (void __iomem *base,unsigned int reg_offset,unsigned long value) { -__raw_writel (value, base + reg_offset); +writel_relaxed (value, base + reg_offset); }/*
PATCH 8/11 clocksource: sun4i-timer: Only register a sched_clock on sun4i and sun5i
In reply to Daniel LezcanoFrom: Hans de Goede <[email protected]>
sun6i and newer have an arm arch timer which is a better sched_clock source then the sun4i-timer, and sched_clock does not have priorities, so do not register the sun4i-timer sched_clock at all on sun6i and newer.
--- drivers/clocksource/sun4i_timer.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-)
drivers/clocksource/sun4i_timer.c +9 -1
@@ -170,7 +170,15 @@ static void __init sun4i_timer_init(struct device_node *node)TIMER_CTL_CLK_SRC (TIMER_CTL_CLK_SRC_OSC24M ), timer_base + TIMER_CTL_REG(1)); -sched_clock_register (sun4i_timer_sched_read,32 , rate); +/* +* sched_clock_register does not have priorities, and on sun6i and +* later there is a better sched_clock registered by arm_arch_timer.c +*/ +if (of_machine_is_compatible ("allwinner,sun4i-a10" ) || +of_machine_is_compatible ("allwinner,sun5i-a13" ) || +of_machine_is_compatible ("allwinner,sun5i-a10s" )) +sched_clock_register (sun4i_timer_sched_read,32 , rate); +clocksource_mmio_init (timer_base +TIMER_CNTVAL_REG (1 ), node->name, rate,350 ,32 , clocksource_mmio_readl_down);
Signature · 1 line
1.9.1
tip-bot for Hans de Goede
merge bot[tip:timers/core] clocksource/drivers/sun4i-timer: Only register a sched_clock on sun4i and sun5i
clocksource/drivers/sun4i-timer: Only register a sched_clock on sun4i and sun5i
Commit-ID: 37b8b003c483191a327a740fc32c1993959e7ae9 Gitweb: http://git.kernel.org/tip/37b8b003c483191a327a740fc32c1993959e7ae9 Author: Hans de Goede <[email protected]> AuthorDate: Mon, 30 Mar 2015 22:17:10 +0200 Committer: Ingo Molnar <[email protected]> CommitDate: Tue, 31 Mar 2015 09:15:58 +0200
clocksource/drivers/sun4i-timer: Only register a sched_clock on sun4i and sun5i
sun6i and newer have an arm arch timer which is a better sched_clock source then the sun4i-timer, and sched_clock does not have priorities, so do not register the sun4i-timer sched_clock at all on sun6i and newer.
--- drivers/clocksource/sun4i_timer.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-)
drivers/clocksource/sun4i_timer.c +9 -1
@@ -170,7 +170,15 @@ static void __init sun4i_timer_init(struct device_node *node)TIMER_CTL_CLK_SRC (TIMER_CTL_CLK_SRC_OSC24M ), timer_base + TIMER_CTL_REG(1)); -sched_clock_register (sun4i_timer_sched_read,32 , rate); +/* +* sched_clock_register does not have priorities, and on sun6i and +* later there is a better sched_clock registered by arm_arch_timer.c +*/ +if (of_machine_is_compatible ("allwinner,sun4i-a10" ) || +of_machine_is_compatible ("allwinner,sun5i-a13" ) || +of_machine_is_compatible ("allwinner,sun5i-a10s" )) +sched_clock_register (sun4i_timer_sched_read,32 , rate); +clocksource_mmio_init (timer_base +TIMER_CNTVAL_REG (1 ), node->name, rate,350 ,32 , clocksource_mmio_readl_down);
PATCH 9/11 clocksource: tegra: Maintain CPU endianness
In reply to Daniel LezcanoFrom: Dmitry Osipenko <[email protected]>
Support big-endian kernel by using endian-aware register access functions.
--- drivers/clocksource/tegra20_timer.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
drivers/clocksource/tegra20_timer.c +2 -2
@@ -57,9 +57,9 @@ static u64 persistent_ms, last_persistent_ms;static struct delay_timer tegra_delay_timer;#define timer_writel (value, reg) \ - __raw_writel(value, timer_reg_base + (reg)) + writel_relaxed(value, timer_reg_base + (reg))#define timer_readl (reg) \ - __raw_readl(timer_reg_base + (reg)) + readl_relaxed(timer_reg_base + (reg))static int tegra_timer_set_next_event (unsigned long cycles,struct clock_event_device *evt)
Signature · 1 line
1.9.1
tip-bot for Dmitry Osipenko
merge bot[tip:timers/core] clocksource/drivers/tegra: Fix IO endianness
clocksource/drivers/tegra: Fix IO endianness
Commit-ID: 59196bcef5c1034f020fe5bf3579f89767537246 Gitweb: http://git.kernel.org/tip/59196bcef5c1034f020fe5bf3579f89767537246 Author: Dmitry Osipenko <[email protected]> AuthorDate: Mon, 30 Mar 2015 22:17:11 +0200 Committer: Ingo Molnar <[email protected]> CommitDate: Tue, 31 Mar 2015 09:15:58 +0200
clocksource/drivers/tegra: Fix IO endianness
Support big-endian kernel by using endian-aware register access functions.
--- drivers/clocksource/tegra20_timer.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
drivers/clocksource/tegra20_timer.c +2 -2
@@ -57,9 +57,9 @@ static u64 persistent_ms, last_persistent_ms;static struct delay_timer tegra_delay_timer;#define timer_writel (value, reg) \ - __raw_writel(value, timer_reg_base + (reg)) + writel_relaxed(value, timer_reg_base + (reg))#define timer_readl (reg) \ - __raw_readl(timer_reg_base + (reg)) + readl_relaxed(timer_reg_base + (reg))static int tegra_timer_set_next_event (unsigned long cycles,struct clock_event_device *evt)
PATCH 10/11 clocksource: dw_apb_timer_of: Make IO endian agnostic
In reply to Daniel LezcanoFrom: Ben Dooks <[email protected]>
The dw_apb_timer_of timer is using __raw_readl to access the timer register, which is causing issues when the system is running in big endian mode. Fix this by using readl_relaxed() which should account for the endian settings.
This fixes issues where the time jumps around in the dmesg output due to returnling __le32 values.
For an example, these two console lines show time running backwards:
[ 49.882572] CPU1: failed to come online [ 43.282457] Brought up 1 CPUs
--- drivers/clocksource/dw_apb_timer_of.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/clocksource/dw_apb_timer_of.c +1 -1
@@ -108,7 +108,7 @@ static void __init add_clocksource(struct device_node *source_timer) static u64 notrace read_sched_clock(void) { -return ~__raw_readl (sched_io_base); +return ~readl_relaxed (sched_io_base); }static const struct of_device_id sptimer_ids[]__initconst = {
Signature · 1 line
1.9.1
tip-bot for Ben Dooks
merge bot[tip:timers/core] clocksource/drivers/dw_apb_timers_of: Fix IO endianness causing time jumps
clocksource/drivers/dw_apb_timers_of: Fix IO endianness causing time jumps
Commit-ID: 3a10013b6a5975346fe5a8db59500a8d176d64e0 Gitweb: http://git.kernel.org/tip/3a10013b6a5975346fe5a8db59500a8d176d64e0 Author: Ben Dooks <[email protected]> AuthorDate: Mon, 30 Mar 2015 22:17:12 +0200 Committer: Ingo Molnar <[email protected]> CommitDate: Tue, 31 Mar 2015 09:15:57 +0200
clocksource/drivers/dw_apb_timers_of: Fix IO endianness causing time jumps
The dw_apb_timer_of timer is using __raw_readl() to access the timer register, which is causing issues when the system is running in big endian mode. Fix this by using readl_relaxed() which should account for the endian settings.
This fixes issues where the time jumps around in the dmesg output due to returnling __le32 values.
For an example, these two console lines show time running backwards:
[ 49.882572] CPU1: failed to come online [ 43.282457] Brought up 1 CPUs
--- drivers/clocksource/dw_apb_timer_of.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/clocksource/dw_apb_timer_of.c +1 -1
@@ -108,7 +108,7 @@ static void __init add_clocksource(struct device_node *source_timer) static u64 notrace read_sched_clock(void) { -return ~__raw_readl (sched_io_base); +return ~readl_relaxed (sched_io_base); }static const struct of_device_id sptimer_ids[]__initconst = {
PATCH 11/11 clocksource: efm32: Use CLOCK_EVT_FEAT_PERIODIC for defining features
In reply to Daniel LezcanoFrom: Viresh Kumar <[email protected]>
We have used CLOCK_EVT_MODE_PERIODIC instead of CLOCK_EVT_FEAT_PERIODIC while defining features. Fix it.
--- drivers/clocksource/time-efm32.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/clocksource/time-efm32.c +1 -1
@@ -111,7 +111,7 @@ static irqreturn_t efm32_clock_event_handler(int irq, void *dev_id)static struct efm32_clock_event_ddata clock_event_ddata = { .evtdev = { .name ="efm32 clockevent" , - .features =CLOCK_EVT_FEAT_ONESHOT |CLOCK_EVT_MODE_PERIODIC , + .features =CLOCK_EVT_FEAT_ONESHOT |CLOCK_EVT_FEAT_PERIODIC , .set_mode = efm32_clock_event_set_mode, .set_next_event = efm32_clock_event_set_next_event, .rating =200 ,
Signature · 1 line
1.9.1
tip-bot for Viresh Kumar
merge bot[tip:timers/core] clocksource/drivers/efm32: Use CLOCK_EVT_FEAT_PERIODIC for defining features
clocksource/drivers/efm32: Use CLOCK_EVT_FEAT_PERIODIC for defining features
Commit-ID: ad834a346853b7ee7c684efa56b1d415a850a710 Gitweb: http://git.kernel.org/tip/ad834a346853b7ee7c684efa56b1d415a850a710 Author: Viresh Kumar <[email protected]> AuthorDate: Mon, 30 Mar 2015 22:17:13 +0200 Committer: Ingo Molnar <[email protected]> CommitDate: Tue, 31 Mar 2015 09:15:57 +0200
clocksource/drivers/efm32: Use CLOCK_EVT_FEAT_PERIODIC for defining features
We have used CLOCK_EVT_MODE_PERIODIC instead of CLOCK_EVT_FEAT_PERIODIC while defining features. Fix it.
--- drivers/clocksource/time-efm32.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/clocksource/time-efm32.c +1 -1
@@ -111,7 +111,7 @@ static irqreturn_t efm32_clock_event_handler(int irq, void *dev_id)static struct efm32_clock_event_ddata clock_event_ddata = { .evtdev = { .name ="efm32 clockevent" , - .features =CLOCK_EVT_FEAT_ONESHOT |CLOCK_EVT_MODE_PERIODIC , + .features =CLOCK_EVT_FEAT_ONESHOT |CLOCK_EVT_FEAT_PERIODIC , .set_mode = efm32_clock_event_set_mode, .set_next_event = efm32_clock_event_set_next_event, .rating =200 ,
Re: [PATCH 01/11] clocksource: arm_arch_timer: Rename arch_timer_probed to reflect behaviour
In reply to Daniel LezcanoQuoted 21 lines · Daniel Lezcano
From: Laurent Pinchart <[email protected]>
The
arch_timer_probedfunction returns whether the given time doesn't need to be probed. This can be the case when the timer has been probed already, but also when it has no corresponding enabled node in DT.Rename the function to
arch_timer_need_probeand invert its return value to better reflect the function's purpose and behaviour.Acked-by Sudeep Holla <[email protected]>Signed-off-by Laurent Pinchart <[email protected]>Signed-off-by Daniel Lezcano <[email protected]>--- drivers/clocksource/arm_arch_timer.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-)drivers/clocksource/arm_arch_timer.c +0
-0
drivers/clocksource/arm_arch_timer.c static const struct of_device_id arch_timer_mem_of_match[] __initconst = { · line 664
Quoted 5 lines
drivers/clocksource/arm_arch_timer.c +1
-1@@ -661,17 +661,17 @@ static const struct of_device_id arch_timer_mem_of_match[] __initconst = { };static bool __init -arch_timer_probed (int type,const struct of_device_id *matches) +arch_timer_need_probe (int type,const struct of_device_id *matches)
If we do a rename we might as well use valid English spelling such as 'arch_timer_needs_probing()'?
Thanks,
Ingo
Re: [PATCH 01/11] clocksource: arm_arch_timer: Rename arch_timer_probed to reflect behaviour
Hi Ingo,
Quoted 27 lines · On Tuesday 31 March 2015 09:14:52 Ingo Molnar wrote:
Quoted 26 lines · Daniel Lezcano
From: Laurent Pinchart <[email protected]>
The
arch_timer_probedfunction returns whether the given time doesn't need to be probed. This can be the case when the timer has been probed already, but also when it has no corresponding enabled node in DT.Rename the function to
arch_timer_need_probeand invert its return value to better reflect the function's purpose and behaviour.Acked-by Sudeep Holla <[email protected]>Signed-off-by Laurent PinchartSigned-off-by Daniel Lezcano <[email protected]>---
drivers/clocksource/arm_arch_timer.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-)(quoted diff) +0
-0
b/drivers/clocksource/arm_arch_timer.cindex a3025e7..50bb7f2 100644drivers/clocksource/arm_arch_timer.c +0
-0@@ -661,17 +661,17 @@ static const struct of_device_idarch_timer_mem_of_match[]
__initconst= {>
};
Quoted 7 lines
drivers/clocksource/arm_arch_timer.c static const struct of_device_id arch_timer_mem_of_match[] __initconst = { · line 664
Quoted 4 lines
static bool
__initdrivers/clocksource/arm_arch_timer.c +1
-1-arch_timer_probed(int type, const struct of_device_id *matches) +arch_timer_need_probe(int type, const struct of_device_id *matches)If we do a rename we might as well use valid English spelling such as '
arch_timer_needs_probing()'?
Of course. Should I resend the patch or can you fix that while applying it ?
Signature · 3 lines
Regards, Laurent Pinchart
Re: [PATCH 01/11] clocksource: arm_arch_timer: Rename arch_timer_probed to reflect behaviour
Quoted 32 lines · Laurent Pinchart
Hi Ingo,
Quoted 29 lines · On Tuesday 31 March 2015 09:14:52 Ingo Molnar wrote:
Quoted 28 lines · Daniel Lezcano
From: Laurent Pinchart <[email protected]>
The
arch_timer_probedfunction returns whether the given time doesn't need to be probed. This can be the case when the timer has been probed already, but also when it has no corresponding enabled node in DT.Rename the function to
arch_timer_need_probeand invert its return value to better reflect the function's purpose and behaviour.Acked-by Sudeep Holla <[email protected]>Signed-off-by Laurent PinchartSigned-off-by Daniel Lezcano <[email protected]>---
drivers/clocksource/arm_arch_timer.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-)(quoted diff) +0
-0
b/drivers/clocksource/arm_arch_timer.cindex a3025e7..50bb7f2 100644drivers/clocksource/arm_arch_timer.c +0
-0@@ -661,17 +661,17 @@ static const struct of_device_idarch_timer_mem_of_match[]
__initconst= {>
};static bool
__init
Quoted 7 lines
Quoted 5 lines
drivers/clocksource/arm_arch_timer.c static const struct of_device_id arch_timer_mem_of_match[] __initconst = { · line 664
Quoted 2 lines
drivers/clocksource/arm_arch_timer.c +1
-1-arch_timer_probed(int type, const struct of_device_id *matches) +arch_timer_need_probe(int type, const struct of_device_id *matches)If we do a rename we might as well use valid English spelling such as '
arch_timer_needs_probing()'?Of course. Should I resend the patch or can you fix that while applying it ?
No need to resend, I've done the rename in the patch.
Thanks,
Ingo
Quoted 15 lines · Daniel Lezcano
Hi Thomas, Ingo,
this pull request contains the following changes for 4.1:
- Made IO endian agnostic for at91 and dw apb timers (Ben Dooks)
- Maintained tegra endianess (Dmitry Osipenko)
- Enabled the sun4i / sun5i timer for
sched_clock, all others winner boards
have the arch arm timer which is more accurate (Hans de Goede)- Renamed the arch arm timer function name to reflect better its purpose
(Laurent Pinchart)
Quoted 7 lines
- Cleaned up the sun5i timer code, replaced the
setup_irqby therequest_irqfunction and handled the parent clock frequency change with the frequency notifiers (Maxime Ripard)- Fixed features declaration for the efm32 timer (Viresh Kumar)
Thanks !
So I had some comments about one of the patches, and fixes to changelogs, so I've applied all but the sun4/5i patches from email to move things forward.
The sun4/5i patches conflicted - mind reposting those merged on top of the latest tip:timers:core tree?
Thanks!
Ingo
Quoted 22 lines · Ingo Molnar
Quoted 19 lines · Daniel Lezcano
Hi Thomas, Ingo,
this pull request contains the following changes for 4.1:
- Made IO endian agnostic for at91 and dw apb timers (Ben Dooks)
- Maintained tegra endianess (Dmitry Osipenko)
- Enabled the sun4i / sun5i timer for
sched_clock, all others winner boards
have the arch arm timer which is more accurate (Hans de Goede)- Renamed the arch arm timer function name to reflect better its purpose
(Laurent Pinchart)- Cleaned up the sun5i timer code, replaced the
setup_irqby therequest_irqfunction and handled the parent clock frequency change with the frequency notifiers (Maxime Ripard)
Quoted 7 lines
Quoted 3 lines
- Fixed features declaration for the efm32 timer (Viresh Kumar)
Thanks !
So I had some comments about one of the patches, and fixes to changelogs, so I've applied all but the sun4/5i patches from email to move things forward.
The subsystem prefix is now 'clocksource/drivers/<name>' ?
Quoted 2 lines
The sun4/5i patches conflicted - mind reposting those merged on top of the latest tip:timers:core tree?
Yes, sure. No problem.
Thanks !
-- Daniel
Signature · 5 lines
<http://www.linaro.org/> Linaro.org ? Open source software for ARM SoCs Follow Linaro: <http://www.facebook.com/pages/Linaro> Facebook | <http://twitter.com/#!/linaroorg> Twitter | <http://www.linaro.org/linaro-blog/> Blog
Quoted 25 lines · Daniel Lezcano
Quoted 24 lines · Ingo Molnar
Quoted 21 lines · Daniel Lezcano
Hi Thomas, Ingo,
this pull request contains the following changes for 4.1:
- Made IO endian agnostic for at91 and dw apb timers (Ben Dooks)
- Maintained tegra endianess (Dmitry Osipenko)
- Enabled the sun4i / sun5i timer for
sched_clock, all others winner boards
have the arch arm timer which is more accurate (Hans de Goede)- Renamed the arch arm timer function name to reflect better its purpose
(Laurent Pinchart)- Cleaned up the sun5i timer code, replaced the
setup_irqby therequest_irqfunction and handled the parent clock frequency change with the frequency notifiers (Maxime Ripard)- Fixed features declaration for the efm32 timer (Viresh Kumar)
Quoted 7 lines
Quoted 5 lines
Quoted 1 line
Thanks !
So I had some comments about one of the patches, and fixes to changelogs, so I've applied all but the sun4/5i patches from email to move things forward.
The subsystem prefix is now 'clocksource/drivers/<name>' ?
At least now that we have a good number of clocksource drivers, for such pure driver changes that's the logical prefix and makes it easier to tell apart clocksource core changes from driver changes.
Quoted 4 lines
Quoted 2 lines
The sun4/5i patches conflicted - mind reposting those merged on top of the latest tip:timers:core tree?
Yes, sure. No problem.
Thanks!
Ingo