Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 326672
b: refs/heads/master
c: ee4af56
h: refs/heads/master
v: v3
  • Loading branch information
Simon Arlott authored and Stephen Warren committed Sep 20, 2012
1 parent d7ec195 commit 7688341
Show file tree
Hide file tree
Showing 7 changed files with 215 additions and 10 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: 89214f009c1d38568456dcf997d93977928fe2c3
refs/heads/master: ee4af5696720bb5b9de2e3b18be42089bed1e638
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
BCM2835 System Timer

The System Timer peripheral provides four 32-bit timer channels and a
single 64-bit free running counter. Each channel has an output compare
register, which is compared against the 32 least significant bits of the
free running counter values, and generates an interrupt.

Required properties:

- compatible : should be "brcm,bcm2835-system-timer.txt"
- reg : Specifies base physical address and size of the registers.
- interrupts : A list of 4 interrupt sinks; one per timer channel.
- clock-frequency : The frequency of the clock that drives the counter, in Hz.

Example:

timer {
compatible = "brcm,bcm2835-system-timer";
reg = <0x7e003000 0x1000>;
interrupts = <1 0>, <1 1>, <1 2>, <1 3>;
clock-frequency = <1000000>;
};
7 changes: 7 additions & 0 deletions trunk/arch/arm/boot/dts/bcm2835.dtsi
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,13 @@
#size-cells = <1>;
ranges = <0x7e000000 0x20000000 0x02000000>;

timer {
compatible = "brcm,bcm2835-system-timer";
reg = <0x7e003000 0x1000>;
interrupts = <1 0>, <1 1>, <1 2>, <1 3>;
clock-frequency = <1000000>;
};

intc: interrupt-controller {
compatible = "brcm,bcm2835-armctrl-ic";
reg = <0x7e00b200 0x200>;
Expand Down
10 changes: 1 addition & 9 deletions trunk/arch/arm/mach-bcm2835/bcm2835.c
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,10 @@
#include <linux/init.h>
#include <linux/irqchip/bcm2835.h>
#include <linux/of_platform.h>
#include <linux/bcm2835_timer.h>

#include <asm/mach/arch.h>
#include <asm/mach/map.h>
#include <asm/mach/time.h>

#include <mach/bcm2835_soc.h>

Expand Down Expand Up @@ -46,14 +46,6 @@ void __init bcm2835_init(void)
}
}

static void __init bcm2835_timer_init(void)
{
}

struct sys_timer bcm2835_timer = {
.init = bcm2835_timer_init
};

static const char * const bcm2835_compat[] = {
"brcm,bcm2835",
NULL
Expand Down
1 change: 1 addition & 0 deletions trunk/drivers/clocksource/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,4 @@ obj-$(CONFIG_DW_APB_TIMER) += dw_apb_timer.o
obj-$(CONFIG_DW_APB_TIMER_OF) += dw_apb_timer_of.o
obj-$(CONFIG_CLKSRC_DBX500_PRCMU) += clksrc-dbx500-prcmu.o
obj-$(CONFIG_ARMADA_370_XP_TIMER) += time-armada-370-xp.o
obj-$(CONFIG_ARCH_BCM2835) += bcm2835_timer.o
161 changes: 161 additions & 0 deletions trunk/drivers/clocksource/bcm2835_timer.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,161 @@
/*
* Copyright 2012 Simon Arlott
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/

#include <linux/bcm2835_timer.h>
#include <linux/bitops.h>
#include <linux/clockchips.h>
#include <linux/clocksource.h>
#include <linux/interrupt.h>
#include <linux/irqreturn.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/of_address.h>
#include <linux/of_irq.h>
#include <linux/of_platform.h>
#include <linux/slab.h>
#include <linux/string.h>

#include <asm/sched_clock.h>
#include <asm/irq.h>

#define REG_CONTROL 0x00
#define REG_COUNTER_LO 0x04
#define REG_COUNTER_HI 0x08
#define REG_COMPARE(n) (0x0c + (n) * 4)
#define MAX_TIMER 3
#define DEFAULT_TIMER 3

struct bcm2835_timer {
void __iomem *control;
void __iomem *compare;
int match_mask;
struct clock_event_device evt;
struct irqaction act;
};

static void __iomem *system_clock __read_mostly;

static u32 notrace bcm2835_sched_read(void)
{
return readl_relaxed(system_clock);
}

static void bcm2835_time_set_mode(enum clock_event_mode mode,
struct clock_event_device *evt_dev)
{
switch (mode) {
case CLOCK_EVT_MODE_ONESHOT:
case CLOCK_EVT_MODE_UNUSED:
case CLOCK_EVT_MODE_SHUTDOWN:
case CLOCK_EVT_MODE_RESUME:
break;
default:
WARN(1, "%s: unhandled event mode %d\n", __func__, mode);
break;
}
}

static int bcm2835_time_set_next_event(unsigned long event,
struct clock_event_device *evt_dev)
{
struct bcm2835_timer *timer = container_of(evt_dev,
struct bcm2835_timer, evt);
writel_relaxed(readl_relaxed(system_clock) + event,
timer->compare);
return 0;
}

static irqreturn_t bcm2835_time_interrupt(int irq, void *dev_id)
{
struct bcm2835_timer *timer = dev_id;
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 (event_handler)
event_handler(&timer->evt);
return IRQ_HANDLED;
} else {
return IRQ_NONE;
}
}

static struct of_device_id bcm2835_time_match[] __initconst = {
{ .compatible = "brcm,bcm2835-system-timer" },
{}
};

static void __init bcm2835_time_init(void)
{
struct device_node *node;
void __iomem *base;
u32 freq;
int irq;
struct bcm2835_timer *timer;

node = of_find_matching_node(NULL, bcm2835_time_match);
if (!node)
panic("No bcm2835 timer node");

base = of_iomap(node, 0);
if (!base)
panic("Can't remap registers");

if (of_property_read_u32(node, "clock-frequency", &freq))
panic("Can't read clock-frequency");

system_clock = base + REG_COUNTER_LO;
setup_sched_clock(bcm2835_sched_read, 32, freq);

clocksource_mmio_init(base + REG_COUNTER_LO, node->name,
freq, 300, 32, clocksource_mmio_readl_up);

irq = irq_of_parse_and_map(node, DEFAULT_TIMER);
if (irq <= 0)
panic("Can't parse IRQ");

timer = kzalloc(sizeof(*timer), GFP_KERNEL);
if (!timer)
panic("Can't allocate timer struct\n");

timer->control = base + REG_CONTROL;
timer->compare = base + REG_COMPARE(DEFAULT_TIMER);
timer->match_mask = BIT(DEFAULT_TIMER);
timer->evt.name = node->name;
timer->evt.rating = 300;
timer->evt.features = CLOCK_EVT_FEAT_ONESHOT;
timer->evt.set_mode = bcm2835_time_set_mode;
timer->evt.set_next_event = bcm2835_time_set_next_event;
timer->evt.cpumask = cpumask_of(0);
timer->act.name = node->name;
timer->act.flags = IRQF_TIMER | IRQF_SHARED;
timer->act.dev_id = timer;
timer->act.handler = bcm2835_time_interrupt;

if (setup_irq(irq, &timer->act))
panic("Can't set up timer IRQ\n");

clockevents_config_and_register(&timer->evt, freq, 0xf, 0xffffffff);

pr_info("bcm2835: system timer (irq = %d)\n", irq);
}

struct sys_timer bcm2835_timer = {
.init = bcm2835_time_init,
};
22 changes: 22 additions & 0 deletions trunk/include/linux/bcm2835_timer.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
/*
* Copyright 2012 Simon Arlott
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/

#ifndef __BCM2835_TIMER_H
#define __BCM2835_TIMER_H

#include <asm/mach/time.h>

extern struct sys_timer bcm2835_timer;

#endif

0 comments on commit 7688341

Please sign in to comment.