Commit 2f18d872 authored by Greg Gallagher's avatar Greg Gallagher Committed by Philippe Gerum

drivers/clocksource: ipipe: add support for BCM2835 chips

This change will add support for bcm2835 chips.  This includes the raspberry pi
0 and 1 family of boards.
parent d2404f5e
...@@ -29,6 +29,9 @@ ...@@ -29,6 +29,9 @@
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/string.h> #include <linux/string.h>
#include <linux/sched_clock.h> #include <linux/sched_clock.h>
#include <linux/ipipe.h>
#include <linux/ipipe_tickdev.h>
#include <linux/time.h>
#include <asm/irq.h> #include <asm/irq.h>
...@@ -39,6 +42,7 @@ ...@@ -39,6 +42,7 @@
#define MAX_TIMER 3 #define MAX_TIMER 3
#define DEFAULT_TIMER 3 #define DEFAULT_TIMER 3
struct bcm2835_timer { struct bcm2835_timer {
void __iomem *control; void __iomem *control;
void __iomem *compare; void __iomem *compare;
...@@ -46,9 +50,53 @@ struct bcm2835_timer { ...@@ -46,9 +50,53 @@ struct bcm2835_timer {
struct clock_event_device evt; struct clock_event_device evt;
struct irqaction act; struct irqaction act;
}; };
static void __iomem *system_clock __read_mostly; static void __iomem *system_clock __read_mostly;
#ifdef CONFIG_IPIPE
static void __iomem *t_base;
static unsigned long t_pbase;
static inline void bcm2835_ipipe_cs_setup(unsigned int freq)
{
struct __ipipe_tscinfo tsc_info = {
.type = IPIPE_TSC_TYPE_FREERUNNING,
.freq = freq,
.counter_vaddr = (unsigned long)t_base + 0x04,
.u = {
{
.counter_paddr = t_pbase + 0x04,
.mask = 0xffffffff,
}
},
};
__ipipe_tsc_register(&tsc_info);
}
static struct ipipe_timer bcm2835_itimer;
static void bcm2835_itimer_ack(void)
{
struct bcm2835_timer *timer = container_of(bcm2835_itimer.host_timer,
struct bcm2835_timer, evt);
writel(timer->match_mask, timer->control);
}
static inline void bcm2835_ipipe_evt_setup(struct clock_event_device *evt,
int freq)
{
evt->ipipe_timer = &bcm2835_itimer;
evt->ipipe_timer->irq = evt->irq;
evt->ipipe_timer->ack = bcm2835_itimer_ack;
evt->ipipe_timer->freq = freq;
}
#else
static inline void bcm2835_ipipe_cs_setup(void) { }
static inline void bcm2835_ipipe_evt_setup(struct clock_event_device *evt) { }
#endif /* CONFIG_IPIPE */
static u64 notrace bcm2835_sched_read(void) static u64 notrace bcm2835_sched_read(void)
{ {
return readl_relaxed(system_clock); return readl_relaxed(system_clock);
...@@ -59,8 +107,7 @@ static int bcm2835_time_set_next_event(unsigned long event, ...@@ -59,8 +107,7 @@ static int bcm2835_time_set_next_event(unsigned long event,
{ {
struct bcm2835_timer *timer = container_of(evt_dev, struct bcm2835_timer *timer = container_of(evt_dev,
struct bcm2835_timer, evt); struct bcm2835_timer, evt);
writel_relaxed(readl_relaxed(system_clock) + event, writel_relaxed(readl_relaxed(system_clock) + event, timer->compare);
timer->compare);
return 0; return 0;
} }
...@@ -68,16 +115,23 @@ static irqreturn_t bcm2835_time_interrupt(int irq, void *dev_id) ...@@ -68,16 +115,23 @@ static irqreturn_t bcm2835_time_interrupt(int irq, void *dev_id)
{ {
struct bcm2835_timer *timer = dev_id; struct bcm2835_timer *timer = dev_id;
void (*event_handler)(struct clock_event_device *); void (*event_handler)(struct clock_event_device *);
if (readl_relaxed(timer->control) & timer->match_mask) {
writel_relaxed(timer->match_mask, timer->control);
event_handler = ACCESS_ONCE(timer->evt.event_handler); if (clockevent_ipipe_stolen(&timer->evt)) {
if (event_handler) goto handle;
event_handler(&timer->evt); }
if (readl_relaxed(timer->control) & timer->match_mask) {
writel_relaxed(timer->match_mask, timer->control);
handle:
event_handler = ACCESS_ONCE(timer->evt.event_handler);
__ipipe_tsc_update();
if (event_handler) {
event_handler(&timer->evt);
}
return IRQ_HANDLED; return IRQ_HANDLED;
} else { } else {
return IRQ_NONE; return IRQ_NONE;
} }
} }
static int __init bcm2835_timer_init(struct device_node *node) static int __init bcm2835_timer_init(struct device_node *node)
...@@ -93,6 +147,17 @@ static int __init bcm2835_timer_init(struct device_node *node) ...@@ -93,6 +147,17 @@ static int __init bcm2835_timer_init(struct device_node *node)
return -ENXIO; return -ENXIO;
} }
if (IS_ENABLED(CONFIG_IPIPE)) {
struct resource res;
int ret;
ret = of_address_to_resource(node, 0, &res);
if (ret)
res.start = 0;
t_base = base;
t_pbase = res.start;
}
ret = of_property_read_u32(node, "clock-frequency", &freq); ret = of_property_read_u32(node, "clock-frequency", &freq);
if (ret) { if (ret) {
pr_err("Can't read clock-frequency\n"); pr_err("Can't read clock-frequency\n");
...@@ -127,11 +192,22 @@ static int __init bcm2835_timer_init(struct device_node *node) ...@@ -127,11 +192,22 @@ static int __init bcm2835_timer_init(struct device_node *node)
timer->evt.set_next_event = bcm2835_time_set_next_event; timer->evt.set_next_event = bcm2835_time_set_next_event;
timer->evt.cpumask = cpumask_of(0); timer->evt.cpumask = cpumask_of(0);
timer->act.name = node->name; timer->act.name = node->name;
timer->act.flags = IRQF_TIMER | IRQF_SHARED; timer->act.flags = IRQF_TIMER;
timer->act.dev_id = timer; timer->act.dev_id = timer;
timer->act.handler = bcm2835_time_interrupt; timer->act.handler = bcm2835_time_interrupt;
ret = setup_irq(irq, &timer->act); if (IS_ENABLED(CONFIG_IPIPE)) {
bcm2835_ipipe_cs_setup(freq);
bcm2835_ipipe_evt_setup(&timer->evt, freq);
timer->evt.ipipe_timer = &bcm2835_itimer;
timer->evt.ipipe_timer->irq = irq;
timer->evt.ipipe_timer->ack = bcm2835_itimer_ack;
timer->evt.ipipe_timer->freq = freq;
} else {
timer->act.flags |= IRQF_SHARED;
}
ret = setup_irq(irq, &timer->act);
if (ret) { if (ret) {
pr_err("Can't set up timer IRQ\n"); pr_err("Can't set up timer IRQ\n");
goto err_iounmap; goto err_iounmap;
......
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