Commit a4ae54f9 authored by Linus Torvalds's avatar Linus Torvalds

Merge branch 'timers/core' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip

Pull timer code update from Thomas Gleixner:
 - armada SoC clocksource overhaul with a trivial merge conflict
 - Minor improvements to various SoC clocksource drivers

* 'timers/core' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip:
  clocksource: armada-370-xp: Add detailed clock requirements in devicetree binding
  clocksource: armada-370-xp: Get reference fixed-clock by name
  clocksource: armada-370-xp: Replace WARN_ON with BUG_ON
  clocksource: armada-370-xp: Fix device-tree binding
  clocksource: armada-370-xp: Introduce new compatibles
  clocksource: armada-370-xp: Use CLOCKSOURCE_OF_DECLARE
  clocksource: armada-370-xp: Simplify TIMER_CTRL register access
  clocksource: armada-370-xp: Use BIT()
  ARM: timer-sp: Set dynamic irq affinity
  ARM: nomadik: add dynamic irq flag to the timer
  clocksource: sh_cmt: 32-bit control register support
  clocksource: em_sti: Convert to devm_* managed helpers
parents 3369d116 63ce2cc4
...@@ -2,14 +2,40 @@ Marvell Armada 370 and Armada XP Timers ...@@ -2,14 +2,40 @@ Marvell Armada 370 and Armada XP Timers
--------------------------------------- ---------------------------------------
Required properties: Required properties:
- compatible: Should be "marvell,armada-370-xp-timer" - compatible: Should be either "marvell,armada-370-timer" or
"marvell,armada-xp-timer" as appropriate.
- interrupts: Should contain the list of Global Timer interrupts and - interrupts: Should contain the list of Global Timer interrupts and
then local timer interrupts then local timer interrupts
- reg: Should contain location and length for timers register. First - reg: Should contain location and length for timers register. First
pair for the Global Timer registers, second pair for the pair for the Global Timer registers, second pair for the
local/private timers. local/private timers.
- clocks: clock driving the timer hardware
Optional properties: Clocks required for compatible = "marvell,armada-370-timer":
- marvell,timer-25Mhz: Tells whether the Global timer supports the 25 - clocks : Must contain a single entry describing the clock input
Mhz fixed mode (available on Armada XP and not on Armada 370)
Clocks required for compatible = "marvell,armada-xp-timer":
- clocks : Must contain an entry for each entry in clock-names.
- clock-names : Must include the following entries:
"nbclk" (L2/coherency fabric clock),
"fixed" (Reference 25 MHz fixed-clock).
Examples:
- Armada 370:
timer {
compatible = "marvell,armada-370-timer";
reg = <0x20300 0x30>, <0x21040 0x30>;
interrupts = <37>, <38>, <39>, <40>, <5>, <6>;
clocks = <&coreclk 2>;
};
- Armada XP:
timer {
compatible = "marvell,armada-xp-timer";
reg = <0x20300 0x30>, <0x21040 0x30>;
interrupts = <37>, <38>, <39>, <40>, <5>, <6>;
clocks = <&coreclk 2>, <&refclk>;
clock-names = "nbclk", "fixed";
};
...@@ -166,7 +166,8 @@ static int sp804_set_next_event(unsigned long next, ...@@ -166,7 +166,8 @@ static int sp804_set_next_event(unsigned long next,
} }
static struct clock_event_device sp804_clockevent = { static struct clock_event_device sp804_clockevent = {
.features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT, .features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT |
CLOCK_EVT_FEAT_DYNIRQ,
.set_mode = sp804_set_mode, .set_mode = sp804_set_mode,
.set_next_event = sp804_set_next_event, .set_next_event = sp804_set_next_event,
.rating = 300, .rating = 300,
......
...@@ -18,7 +18,7 @@ ...@@ -18,7 +18,7 @@
#include <linux/of_address.h> #include <linux/of_address.h>
#include <linux/of_platform.h> #include <linux/of_platform.h>
#include <linux/io.h> #include <linux/io.h>
#include <linux/time-armada-370-xp.h> #include <linux/clocksource.h>
#include <linux/dma-mapping.h> #include <linux/dma-mapping.h>
#include <linux/mbus.h> #include <linux/mbus.h>
#include <asm/hardware/cache-l2x0.h> #include <asm/hardware/cache-l2x0.h>
...@@ -37,7 +37,7 @@ static void __init armada_370_xp_map_io(void) ...@@ -37,7 +37,7 @@ static void __init armada_370_xp_map_io(void)
static void __init armada_370_xp_timer_and_clk_init(void) static void __init armada_370_xp_timer_and_clk_init(void)
{ {
of_clk_init(NULL); of_clk_init(NULL);
armada_370_xp_timer_init(); clocksource_of_init();
coherency_init(); coherency_init();
BUG_ON(mvebu_mbus_dt_init()); BUG_ON(mvebu_mbus_dt_init());
#ifdef CONFIG_CACHE_L2X0 #ifdef CONFIG_CACHE_L2X0
......
...@@ -315,68 +315,47 @@ static int em_sti_probe(struct platform_device *pdev) ...@@ -315,68 +315,47 @@ static int em_sti_probe(struct platform_device *pdev)
{ {
struct em_sti_priv *p; struct em_sti_priv *p;
struct resource *res; struct resource *res;
int irq, ret; int irq;
p = kzalloc(sizeof(*p), GFP_KERNEL); p = devm_kzalloc(&pdev->dev, sizeof(*p), GFP_KERNEL);
if (p == NULL) { if (p == NULL) {
dev_err(&pdev->dev, "failed to allocate driver data\n"); dev_err(&pdev->dev, "failed to allocate driver data\n");
ret = -ENOMEM; return -ENOMEM;
goto err0;
} }
p->pdev = pdev; p->pdev = pdev;
platform_set_drvdata(pdev, p); platform_set_drvdata(pdev, p);
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res) {
dev_err(&pdev->dev, "failed to get I/O memory\n");
ret = -EINVAL;
goto err0;
}
irq = platform_get_irq(pdev, 0); irq = platform_get_irq(pdev, 0);
if (irq < 0) { if (irq < 0) {
dev_err(&pdev->dev, "failed to get irq\n"); dev_err(&pdev->dev, "failed to get irq\n");
ret = -EINVAL; return -EINVAL;
goto err0;
} }
/* map memory, let base point to the STI instance */ /* map memory, let base point to the STI instance */
p->base = ioremap_nocache(res->start, resource_size(res)); res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (p->base == NULL) { p->base = devm_ioremap_resource(&pdev->dev, res);
dev_err(&pdev->dev, "failed to remap I/O memory\n"); if (IS_ERR(p->base))
ret = -ENXIO; return PTR_ERR(p->base);
goto err0;
}
/* get hold of clock */ /* get hold of clock */
p->clk = clk_get(&pdev->dev, "sclk"); p->clk = devm_clk_get(&pdev->dev, "sclk");
if (IS_ERR(p->clk)) { if (IS_ERR(p->clk)) {
dev_err(&pdev->dev, "cannot get clock\n"); dev_err(&pdev->dev, "cannot get clock\n");
ret = PTR_ERR(p->clk); return PTR_ERR(p->clk);
goto err1;
} }
if (request_irq(irq, em_sti_interrupt, if (devm_request_irq(&pdev->dev, irq, em_sti_interrupt,
IRQF_TIMER | IRQF_IRQPOLL | IRQF_NOBALANCING, IRQF_TIMER | IRQF_IRQPOLL | IRQF_NOBALANCING,
dev_name(&pdev->dev), p)) { dev_name(&pdev->dev), p)) {
dev_err(&pdev->dev, "failed to request low IRQ\n"); dev_err(&pdev->dev, "failed to request low IRQ\n");
ret = -ENOENT; return -ENOENT;
goto err2;
} }
raw_spin_lock_init(&p->lock); raw_spin_lock_init(&p->lock);
em_sti_register_clockevent(p); em_sti_register_clockevent(p);
em_sti_register_clocksource(p); em_sti_register_clocksource(p);
return 0; return 0;
err2:
clk_put(p->clk);
err1:
iounmap(p->base);
err0:
kfree(p);
return ret;
} }
static int em_sti_remove(struct platform_device *pdev) static int em_sti_remove(struct platform_device *pdev)
......
...@@ -165,7 +165,8 @@ static void nmdk_clkevt_resume(struct clock_event_device *cedev) ...@@ -165,7 +165,8 @@ static void nmdk_clkevt_resume(struct clock_event_device *cedev)
static struct clock_event_device nmdk_clkevt = { static struct clock_event_device nmdk_clkevt = {
.name = "mtu_1", .name = "mtu_1",
.features = CLOCK_EVT_FEAT_ONESHOT | CLOCK_EVT_FEAT_PERIODIC, .features = CLOCK_EVT_FEAT_ONESHOT | CLOCK_EVT_FEAT_PERIODIC |
CLOCK_EVT_FEAT_DYNIRQ,
.rating = 200, .rating = 200,
.set_mode = nmdk_clkevt_mode, .set_mode = nmdk_clkevt_mode,
.set_next_event = nmdk_clkevt_next, .set_next_event = nmdk_clkevt_next,
......
...@@ -37,6 +37,7 @@ ...@@ -37,6 +37,7 @@
struct sh_cmt_priv { struct sh_cmt_priv {
void __iomem *mapbase; void __iomem *mapbase;
void __iomem *mapbase_str;
struct clk *clk; struct clk *clk;
unsigned long width; /* 16 or 32 bit version of hardware block */ unsigned long width; /* 16 or 32 bit version of hardware block */
unsigned long overflow_bit; unsigned long overflow_bit;
...@@ -79,6 +80,12 @@ struct sh_cmt_priv { ...@@ -79,6 +80,12 @@ struct sh_cmt_priv {
* CMCSR 0xffca0060 16-bit * CMCSR 0xffca0060 16-bit
* CMCNT 0xffca0064 32-bit * CMCNT 0xffca0064 32-bit
* CMCOR 0xffca0068 32-bit * CMCOR 0xffca0068 32-bit
*
* "32-bit counter and 32-bit control" as found on r8a73a4 and r8a7790:
* CMSTR 0xffca0500 32-bit
* CMCSR 0xffca0510 32-bit
* CMCNT 0xffca0514 32-bit
* CMCOR 0xffca0518 32-bit
*/ */
static unsigned long sh_cmt_read16(void __iomem *base, unsigned long offs) static unsigned long sh_cmt_read16(void __iomem *base, unsigned long offs)
...@@ -109,9 +116,7 @@ static void sh_cmt_write32(void __iomem *base, unsigned long offs, ...@@ -109,9 +116,7 @@ static void sh_cmt_write32(void __iomem *base, unsigned long offs,
static inline unsigned long sh_cmt_read_cmstr(struct sh_cmt_priv *p) static inline unsigned long sh_cmt_read_cmstr(struct sh_cmt_priv *p)
{ {
struct sh_timer_config *cfg = p->pdev->dev.platform_data; return p->read_control(p->mapbase_str, 0);
return p->read_control(p->mapbase - cfg->channel_offset, 0);
} }
static inline unsigned long sh_cmt_read_cmcsr(struct sh_cmt_priv *p) static inline unsigned long sh_cmt_read_cmcsr(struct sh_cmt_priv *p)
...@@ -127,9 +132,7 @@ static inline unsigned long sh_cmt_read_cmcnt(struct sh_cmt_priv *p) ...@@ -127,9 +132,7 @@ static inline unsigned long sh_cmt_read_cmcnt(struct sh_cmt_priv *p)
static inline void sh_cmt_write_cmstr(struct sh_cmt_priv *p, static inline void sh_cmt_write_cmstr(struct sh_cmt_priv *p,
unsigned long value) unsigned long value)
{ {
struct sh_timer_config *cfg = p->pdev->dev.platform_data; p->write_control(p->mapbase_str, 0, value);
p->write_control(p->mapbase - cfg->channel_offset, 0, value);
} }
static inline void sh_cmt_write_cmcsr(struct sh_cmt_priv *p, static inline void sh_cmt_write_cmcsr(struct sh_cmt_priv *p,
...@@ -676,7 +679,7 @@ static int sh_cmt_register(struct sh_cmt_priv *p, char *name, ...@@ -676,7 +679,7 @@ static int sh_cmt_register(struct sh_cmt_priv *p, char *name,
static int sh_cmt_setup(struct sh_cmt_priv *p, struct platform_device *pdev) static int sh_cmt_setup(struct sh_cmt_priv *p, struct platform_device *pdev)
{ {
struct sh_timer_config *cfg = pdev->dev.platform_data; struct sh_timer_config *cfg = pdev->dev.platform_data;
struct resource *res; struct resource *res, *res2;
int irq, ret; int irq, ret;
ret = -ENXIO; ret = -ENXIO;
...@@ -694,6 +697,9 @@ static int sh_cmt_setup(struct sh_cmt_priv *p, struct platform_device *pdev) ...@@ -694,6 +697,9 @@ static int sh_cmt_setup(struct sh_cmt_priv *p, struct platform_device *pdev)
goto err0; goto err0;
} }
/* optional resource for the shared timer start/stop register */
res2 = platform_get_resource(p->pdev, IORESOURCE_MEM, 1);
irq = platform_get_irq(p->pdev, 0); irq = platform_get_irq(p->pdev, 0);
if (irq < 0) { if (irq < 0) {
dev_err(&p->pdev->dev, "failed to get irq\n"); dev_err(&p->pdev->dev, "failed to get irq\n");
...@@ -707,6 +713,15 @@ static int sh_cmt_setup(struct sh_cmt_priv *p, struct platform_device *pdev) ...@@ -707,6 +713,15 @@ static int sh_cmt_setup(struct sh_cmt_priv *p, struct platform_device *pdev)
goto err0; goto err0;
} }
/* map second resource for CMSTR */
p->mapbase_str = ioremap_nocache(res2 ? res2->start :
res->start - cfg->channel_offset,
res2 ? resource_size(res2) : 2);
if (p->mapbase_str == NULL) {
dev_err(&p->pdev->dev, "failed to remap I/O second memory\n");
goto err1;
}
/* request irq using setup_irq() (too early for request_irq()) */ /* request irq using setup_irq() (too early for request_irq()) */
p->irqaction.name = dev_name(&p->pdev->dev); p->irqaction.name = dev_name(&p->pdev->dev);
p->irqaction.handler = sh_cmt_interrupt; p->irqaction.handler = sh_cmt_interrupt;
...@@ -719,11 +734,17 @@ static int sh_cmt_setup(struct sh_cmt_priv *p, struct platform_device *pdev) ...@@ -719,11 +734,17 @@ static int sh_cmt_setup(struct sh_cmt_priv *p, struct platform_device *pdev)
if (IS_ERR(p->clk)) { if (IS_ERR(p->clk)) {
dev_err(&p->pdev->dev, "cannot get clock\n"); dev_err(&p->pdev->dev, "cannot get clock\n");
ret = PTR_ERR(p->clk); ret = PTR_ERR(p->clk);
goto err1; goto err2;
} }
p->read_control = sh_cmt_read16; if (res2 && (resource_size(res2) == 4)) {
p->write_control = sh_cmt_write16; /* assume both CMSTR and CMCSR to be 32-bit */
p->read_control = sh_cmt_read32;
p->write_control = sh_cmt_write32;
} else {
p->read_control = sh_cmt_read16;
p->write_control = sh_cmt_write16;
}
if (resource_size(res) == 6) { if (resource_size(res) == 6) {
p->width = 16; p->width = 16;
...@@ -752,22 +773,23 @@ static int sh_cmt_setup(struct sh_cmt_priv *p, struct platform_device *pdev) ...@@ -752,22 +773,23 @@ static int sh_cmt_setup(struct sh_cmt_priv *p, struct platform_device *pdev)
cfg->clocksource_rating); cfg->clocksource_rating);
if (ret) { if (ret) {
dev_err(&p->pdev->dev, "registration failed\n"); dev_err(&p->pdev->dev, "registration failed\n");
goto err2; goto err3;
} }
p->cs_enabled = false; p->cs_enabled = false;
ret = setup_irq(irq, &p->irqaction); ret = setup_irq(irq, &p->irqaction);
if (ret) { if (ret) {
dev_err(&p->pdev->dev, "failed to request irq %d\n", irq); dev_err(&p->pdev->dev, "failed to request irq %d\n", irq);
goto err2; goto err3;
} }
platform_set_drvdata(pdev, p); platform_set_drvdata(pdev, p);
return 0; return 0;
err2: err3:
clk_put(p->clk); clk_put(p->clk);
err2:
iounmap(p->mapbase_str);
err1: err1:
iounmap(p->mapbase); iounmap(p->mapbase);
err0: err0:
......
...@@ -13,6 +13,19 @@ ...@@ -13,6 +13,19 @@
* *
* Timer 0 is used as free-running clocksource, while timer 1 is * Timer 0 is used as free-running clocksource, while timer 1 is
* used as clock_event_device. * used as clock_event_device.
*
* ---
* Clocksource driver for Armada 370 and Armada XP SoC.
* This driver implements one compatible string for each SoC, given
* each has its own characteristics:
*
* * Armada 370 has no 25 MHz fixed timer.
*
* * Armada XP cannot work properly without such 25 MHz fixed timer as
* doing otherwise leads to using a clocksource whose frequency varies
* when doing cpufreq frequency changes.
*
* See Documentation/devicetree/bindings/timer/marvell,armada-370-xp-timer.txt
*/ */
#include <linux/init.h> #include <linux/init.h>
...@@ -30,19 +43,18 @@ ...@@ -30,19 +43,18 @@
#include <linux/module.h> #include <linux/module.h>
#include <linux/sched_clock.h> #include <linux/sched_clock.h>
#include <linux/percpu.h> #include <linux/percpu.h>
#include <linux/time-armada-370-xp.h>
/* /*
* Timer block registers. * Timer block registers.
*/ */
#define TIMER_CTRL_OFF 0x0000 #define TIMER_CTRL_OFF 0x0000
#define TIMER0_EN 0x0001 #define TIMER0_EN BIT(0)
#define TIMER0_RELOAD_EN 0x0002 #define TIMER0_RELOAD_EN BIT(1)
#define TIMER0_25MHZ 0x0800 #define TIMER0_25MHZ BIT(11)
#define TIMER0_DIV(div) ((div) << 19) #define TIMER0_DIV(div) ((div) << 19)
#define TIMER1_EN 0x0004 #define TIMER1_EN BIT(2)
#define TIMER1_RELOAD_EN 0x0008 #define TIMER1_RELOAD_EN BIT(3)
#define TIMER1_25MHZ 0x1000 #define TIMER1_25MHZ BIT(12)
#define TIMER1_DIV(div) ((div) << 22) #define TIMER1_DIV(div) ((div) << 22)
#define TIMER_EVENTS_STATUS 0x0004 #define TIMER_EVENTS_STATUS 0x0004
#define TIMER0_CLR_MASK (~0x1) #define TIMER0_CLR_MASK (~0x1)
...@@ -72,6 +84,18 @@ static u32 ticks_per_jiffy; ...@@ -72,6 +84,18 @@ static u32 ticks_per_jiffy;
static struct clock_event_device __percpu *armada_370_xp_evt; static struct clock_event_device __percpu *armada_370_xp_evt;
static void timer_ctrl_clrset(u32 clr, u32 set)
{
writel((readl(timer_base + TIMER_CTRL_OFF) & ~clr) | set,
timer_base + TIMER_CTRL_OFF);
}
static void local_timer_ctrl_clrset(u32 clr, u32 set)
{
writel((readl(local_base + TIMER_CTRL_OFF) & ~clr) | set,
local_base + TIMER_CTRL_OFF);
}
static u32 notrace armada_370_xp_read_sched_clock(void) static u32 notrace armada_370_xp_read_sched_clock(void)
{ {
return ~readl(timer_base + TIMER0_VAL_OFF); return ~readl(timer_base + TIMER0_VAL_OFF);
...@@ -84,7 +108,6 @@ static int ...@@ -84,7 +108,6 @@ static int
armada_370_xp_clkevt_next_event(unsigned long delta, armada_370_xp_clkevt_next_event(unsigned long delta,
struct clock_event_device *dev) struct clock_event_device *dev)
{ {
u32 u;
/* /*
* Clear clockevent timer interrupt. * Clear clockevent timer interrupt.
*/ */
...@@ -98,11 +121,8 @@ armada_370_xp_clkevt_next_event(unsigned long delta, ...@@ -98,11 +121,8 @@ armada_370_xp_clkevt_next_event(unsigned long delta,
/* /*
* Enable the timer. * Enable the timer.
*/ */
u = readl(local_base + TIMER_CTRL_OFF); local_timer_ctrl_clrset(TIMER0_RELOAD_EN,
u = ((u & ~TIMER0_RELOAD_EN) | TIMER0_EN | TIMER0_EN | TIMER0_DIV(TIMER_DIVIDER_SHIFT));
TIMER0_DIV(TIMER_DIVIDER_SHIFT));
writel(u, local_base + TIMER_CTRL_OFF);
return 0; return 0;
} }
...@@ -110,8 +130,6 @@ static void ...@@ -110,8 +130,6 @@ static void
armada_370_xp_clkevt_mode(enum clock_event_mode mode, armada_370_xp_clkevt_mode(enum clock_event_mode mode,
struct clock_event_device *dev) struct clock_event_device *dev)
{ {
u32 u;
if (mode == CLOCK_EVT_MODE_PERIODIC) { if (mode == CLOCK_EVT_MODE_PERIODIC) {
/* /*
...@@ -123,18 +141,14 @@ armada_370_xp_clkevt_mode(enum clock_event_mode mode, ...@@ -123,18 +141,14 @@ armada_370_xp_clkevt_mode(enum clock_event_mode mode,
/* /*
* Enable timer. * Enable timer.
*/ */
local_timer_ctrl_clrset(0, TIMER0_RELOAD_EN |
u = readl(local_base + TIMER_CTRL_OFF); TIMER0_EN |
TIMER0_DIV(TIMER_DIVIDER_SHIFT));
writel((u | TIMER0_EN | TIMER0_RELOAD_EN |
TIMER0_DIV(TIMER_DIVIDER_SHIFT)),
local_base + TIMER_CTRL_OFF);
} else { } else {
/* /*
* Disable timer. * Disable timer.
*/ */
u = readl(local_base + TIMER_CTRL_OFF); local_timer_ctrl_clrset(TIMER0_EN, 0);
writel(u & ~TIMER0_EN, local_base + TIMER_CTRL_OFF);
/* /*
* ACK pending timer interrupt. * ACK pending timer interrupt.
...@@ -163,14 +177,14 @@ static irqreturn_t armada_370_xp_timer_interrupt(int irq, void *dev_id) ...@@ -163,14 +177,14 @@ static irqreturn_t armada_370_xp_timer_interrupt(int irq, void *dev_id)
*/ */
static int armada_370_xp_timer_setup(struct clock_event_device *evt) static int armada_370_xp_timer_setup(struct clock_event_device *evt)
{ {
u32 u; u32 clr = 0, set = 0;
int cpu = smp_processor_id(); int cpu = smp_processor_id();
u = readl(local_base + TIMER_CTRL_OFF);
if (timer25Mhz) if (timer25Mhz)
writel(u | TIMER0_25MHZ, local_base + TIMER_CTRL_OFF); set = TIMER0_25MHZ;
else else
writel(u & ~TIMER0_25MHZ, local_base + TIMER_CTRL_OFF); clr = TIMER0_25MHZ;
local_timer_ctrl_clrset(clr, set);
evt->name = "armada_370_xp_per_cpu_tick", evt->name = "armada_370_xp_per_cpu_tick",
evt->features = CLOCK_EVT_FEAT_ONESHOT | evt->features = CLOCK_EVT_FEAT_ONESHOT |
...@@ -217,36 +231,21 @@ static struct notifier_block armada_370_xp_timer_cpu_nb = { ...@@ -217,36 +231,21 @@ static struct notifier_block armada_370_xp_timer_cpu_nb = {
.notifier_call = armada_370_xp_timer_cpu_notify, .notifier_call = armada_370_xp_timer_cpu_notify,
}; };
void __init armada_370_xp_timer_init(void) static void __init armada_370_xp_timer_common_init(struct device_node *np)
{ {
u32 u; u32 clr = 0, set = 0;
struct device_node *np;
int res; int res;
np = of_find_compatible_node(NULL, NULL, "marvell,armada-370-xp-timer");
timer_base = of_iomap(np, 0); timer_base = of_iomap(np, 0);
WARN_ON(!timer_base); WARN_ON(!timer_base);
local_base = of_iomap(np, 1); local_base = of_iomap(np, 1);
if (of_find_property(np, "marvell,timer-25Mhz", NULL)) { if (timer25Mhz)
/* The fixed 25MHz timer is available so let's use it */ set = TIMER0_25MHZ;
u = readl(timer_base + TIMER_CTRL_OFF); else
writel(u | TIMER0_25MHZ, clr = TIMER0_25MHZ;
timer_base + TIMER_CTRL_OFF); timer_ctrl_clrset(clr, set);
timer_clk = 25000000; local_timer_ctrl_clrset(clr, set);
} else {
unsigned long rate = 0;
struct clk *clk = of_clk_get(np, 0);
WARN_ON(IS_ERR(clk));
rate = clk_get_rate(clk);
u = readl(timer_base + TIMER_CTRL_OFF);
writel(u & ~(TIMER0_25MHZ),
timer_base + TIMER_CTRL_OFF);
timer_clk = rate / TIMER_DIVIDER;
timer25Mhz = false;
}
/* /*
* We use timer 0 as clocksource, and private(local) timer 0 * We use timer 0 as clocksource, and private(local) timer 0
...@@ -268,10 +267,8 @@ void __init armada_370_xp_timer_init(void) ...@@ -268,10 +267,8 @@ void __init armada_370_xp_timer_init(void)
writel(0xffffffff, timer_base + TIMER0_VAL_OFF); writel(0xffffffff, timer_base + TIMER0_VAL_OFF);
writel(0xffffffff, timer_base + TIMER0_RELOAD_OFF); writel(0xffffffff, timer_base + TIMER0_RELOAD_OFF);
u = readl(timer_base + TIMER_CTRL_OFF); timer_ctrl_clrset(0, TIMER0_EN | TIMER0_RELOAD_EN |
TIMER0_DIV(TIMER_DIVIDER_SHIFT));
writel((u | TIMER0_EN | TIMER0_RELOAD_EN |
TIMER0_DIV(TIMER_DIVIDER_SHIFT)), timer_base + TIMER_CTRL_OFF);
clocksource_mmio_init(timer_base + TIMER0_VAL_OFF, clocksource_mmio_init(timer_base + TIMER0_VAL_OFF,
"armada_370_xp_clocksource", "armada_370_xp_clocksource",
...@@ -293,3 +290,29 @@ void __init armada_370_xp_timer_init(void) ...@@ -293,3 +290,29 @@ void __init armada_370_xp_timer_init(void)
if (!res) if (!res)
armada_370_xp_timer_setup(this_cpu_ptr(armada_370_xp_evt)); armada_370_xp_timer_setup(this_cpu_ptr(armada_370_xp_evt));
} }
static void __init armada_xp_timer_init(struct device_node *np)
{
struct clk *clk = of_clk_get_by_name(np, "fixed");
/* The 25Mhz fixed clock is mandatory, and must always be available */
BUG_ON(IS_ERR(clk));
timer_clk = clk_get_rate(clk);
armada_370_xp_timer_common_init(np);
}
CLOCKSOURCE_OF_DECLARE(armada_xp, "marvell,armada-xp-timer",
armada_xp_timer_init);
static void __init armada_370_timer_init(struct device_node *np)
{
struct clk *clk = of_clk_get(np, 0);
BUG_ON(IS_ERR(clk));
timer_clk = clk_get_rate(clk) / TIMER_DIVIDER;
timer25Mhz = false;
armada_370_xp_timer_common_init(np);
}
CLOCKSOURCE_OF_DECLARE(armada_370, "marvell,armada-370-timer",
armada_370_timer_init);
/*
* Marvell Armada 370/XP SoC timer handling.
*
* Copyright (C) 2012 Marvell
*
* Lior Amsalem <alior@marvell.com>
* Gregory CLEMENT <gregory.clement@free-electrons.com>
* Thomas Petazzoni <thomas.petazzoni@free-electrons.com>
*
*/
#ifndef __TIME_ARMADA_370_XPPRCMU_H
#define __TIME_ARMADA_370_XPPRCMU_H
void armada_370_xp_timer_init(void);
#endif
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