Commit b8172a6d authored by Gilles Chanteperdrix's avatar Gilles Chanteperdrix Committed by Philippe Gerum

clocksource: dw_apb: ipipe: add support for user-visible TSC

Expose the clocksource to userland processes via the ARM-specific
user-TSC interface if enabled.
parent 3004a824
......@@ -15,6 +15,7 @@
#include <linux/kernel.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/ipipe.h>
#include <linux/io.h>
#include <linux/slab.h>
......@@ -384,7 +385,7 @@ static void apbt_restart_clocksource(struct clocksource *cs)
*/
struct dw_apb_clocksource *
dw_apb_clocksource_init(unsigned rating, const char *name, void __iomem *base,
unsigned long freq)
unsigned long phys, unsigned long freq)
{
struct dw_apb_clocksource *dw_cs = kzalloc(sizeof(*dw_cs), GFP_KERNEL);
......@@ -399,10 +400,22 @@ dw_apb_clocksource_init(unsigned rating, const char *name, void __iomem *base,
dw_cs->cs.mask = CLOCKSOURCE_MASK(32);
dw_cs->cs.flags = CLOCK_SOURCE_IS_CONTINUOUS;
dw_cs->cs.resume = apbt_restart_clocksource;
dw_cs->phys = phys;
return dw_cs;
}
#ifdef CONFIG_IPIPE
static struct __ipipe_tscinfo apb_tsc_info = {
.type = IPIPE_TSC_TYPE_FREERUNNING_COUNTDOWN,
.u = {
.dec = {
.mask = 0xffffffffU,
},
},
};
#endif
/**
* dw_apb_clocksource_register() - register the APB clocksource.
*
......@@ -411,6 +424,12 @@ dw_apb_clocksource_init(unsigned rating, const char *name, void __iomem *base,
void dw_apb_clocksource_register(struct dw_apb_clocksource *dw_cs)
{
clocksource_register_hz(&dw_cs->cs, dw_cs->timer.freq);
#ifdef CONFIG_IPIPE
apb_tsc_info.u.dec.counter = (void *)(dw_cs->phys + APBTMR_N_CURRENT_VALUE);
apb_tsc_info.counter_vaddr = (unsigned long)dw_cs->timer.base + APBTMR_N_CURRENT_VALUE;
apb_tsc_info.freq = dw_cs->timer.freq;
__ipipe_tsc_register(&apb_tsc_info);
#endif
}
/**
......
......@@ -25,16 +25,20 @@
#include <linux/sched_clock.h>
static void __init timer_get_base_and_rate(struct device_node *np,
void __iomem **base, u32 *rate)
void __iomem **base, unsigned long *phys,
u32 *rate)
{
struct clk *timer_clk;
struct resource res;
struct clk *pclk;
*base = of_iomap(np, 0);
if (!*base)
if (!*base || of_address_to_resource(np, 0, &res))
panic("Unable to map regs for %s", np->name);
*phys = res.start;
/*
* Not all implementations use a periphal clock, so don't panic
* if it's not present
......@@ -64,13 +68,14 @@ static void __init add_clockevent(struct device_node *event_timer)
{
void __iomem *iobase;
struct dw_apb_clock_event_device *ced;
unsigned long phys;
u32 irq, rate;
irq = irq_of_parse_and_map(event_timer, 0);
if (irq == 0)
panic("No IRQ for clock event timer");
timer_get_base_and_rate(event_timer, &iobase, &rate);
timer_get_base_and_rate(event_timer, &iobase, &phys, &rate);
ced = dw_apb_clockevent_init(0, event_timer->name, 300, iobase, irq,
rate);
......@@ -87,11 +92,12 @@ static void __init add_clocksource(struct device_node *source_timer)
{
void __iomem *iobase;
struct dw_apb_clocksource *cs;
unsigned long phys;
u32 rate;
timer_get_base_and_rate(source_timer, &iobase, &rate);
timer_get_base_and_rate(source_timer, &iobase, &phys, &rate);
cs = dw_apb_clocksource_init(300, source_timer->name, iobase, rate);
cs = dw_apb_clocksource_init(300, source_timer->name, iobase, phys, rate);
if (!cs)
panic("Unable to initialise clocksource device");
......@@ -120,11 +126,12 @@ static const struct of_device_id sptimer_ids[] __initconst = {
static void __init init_sched_clock(void)
{
struct device_node *sched_timer;
unsigned long phys;
sched_timer = of_find_matching_node(NULL, sptimer_ids);
if (sched_timer) {
timer_get_base_and_rate(sched_timer, &sched_io_base,
&sched_rate);
&phys, &sched_rate);
of_node_put(sched_timer);
}
......
......@@ -35,6 +35,7 @@ struct dw_apb_clock_event_device {
struct dw_apb_clocksource {
struct dw_apb_timer timer;
struct clocksource cs;
unsigned long phys;
};
void dw_apb_clockevent_register(struct dw_apb_clock_event_device *dw_ced);
......@@ -47,7 +48,7 @@ dw_apb_clockevent_init(int cpu, const char *name, unsigned rating,
void __iomem *base, int irq, unsigned long freq);
struct dw_apb_clocksource *
dw_apb_clocksource_init(unsigned rating, const char *name, void __iomem *base,
unsigned long freq);
unsigned long phys, unsigned long freq);
void dw_apb_clocksource_register(struct dw_apb_clocksource *dw_cs);
void dw_apb_clocksource_start(struct dw_apb_clocksource *dw_cs);
u64 dw_apb_clocksource_read(struct dw_apb_clocksource *dw_cs);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment