mirror of
https://github.com/Fishwaldo/linux-bl808.git
synced 2025-04-12 01:05:09 +00:00
ARM: ep93xx: switch to GENERIC_CLOCKEVENTS
This switches the EP93xx to use GENERIC_CLOCKEVENTS and CLKSRC_MMIO. Also implements a sched_clock() hook. Tested on the SIM.ONE. Use only oneshot events. Tested-by: H Hartley Sweeten <hsweeten@visionengravers.com> Reviewed-by: H Hartley Sweeten <hsweeten@visionengravers.com> Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
This commit is contained in:
parent
361c81f996
commit
000bc17817
2 changed files with 72 additions and 41 deletions
|
@ -418,11 +418,12 @@ config ARCH_EP93XX
|
||||||
bool "EP93xx-based"
|
bool "EP93xx-based"
|
||||||
select ARCH_HAS_HOLES_MEMORYMODEL
|
select ARCH_HAS_HOLES_MEMORYMODEL
|
||||||
select ARCH_REQUIRE_GPIOLIB
|
select ARCH_REQUIRE_GPIOLIB
|
||||||
select ARCH_USES_GETTIMEOFFSET
|
|
||||||
select ARM_AMBA
|
select ARM_AMBA
|
||||||
select ARM_VIC
|
select ARM_VIC
|
||||||
select CLKDEV_LOOKUP
|
select CLKDEV_LOOKUP
|
||||||
|
select CLKSRC_MMIO
|
||||||
select CPU_ARM920T
|
select CPU_ARM920T
|
||||||
|
select GENERIC_CLOCKEVENTS
|
||||||
help
|
help
|
||||||
This enables support for the Cirrus EP93xx series of CPUs.
|
This enables support for the Cirrus EP93xx series of CPUs.
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,8 @@
|
||||||
#include <linux/kernel.h>
|
#include <linux/kernel.h>
|
||||||
#include <linux/init.h>
|
#include <linux/init.h>
|
||||||
|
#include <linux/clocksource.h>
|
||||||
|
#include <linux/clockchips.h>
|
||||||
|
#include <linux/sched_clock.h>
|
||||||
#include <linux/interrupt.h>
|
#include <linux/interrupt.h>
|
||||||
#include <linux/irq.h>
|
#include <linux/irq.h>
|
||||||
#include <linux/io.h>
|
#include <linux/io.h>
|
||||||
|
@ -45,26 +48,68 @@
|
||||||
#define EP93XX_TIMER3_CONTROL EP93XX_TIMER_REG(0x88)
|
#define EP93XX_TIMER3_CONTROL EP93XX_TIMER_REG(0x88)
|
||||||
#define EP93XX_TIMER3_CLEAR EP93XX_TIMER_REG(0x8c)
|
#define EP93XX_TIMER3_CLEAR EP93XX_TIMER_REG(0x8c)
|
||||||
|
|
||||||
#define EP93XX_TIMER123_CLOCK 508469
|
#define EP93XX_TIMER123_RATE 508469
|
||||||
#define EP93XX_TIMER4_CLOCK 983040
|
#define EP93XX_TIMER4_RATE 983040
|
||||||
|
|
||||||
#define TIMER1_RELOAD ((EP93XX_TIMER123_CLOCK / HZ) - 1)
|
static u64 notrace ep93xx_read_sched_clock(void)
|
||||||
#define TIMER4_TICKS_PER_JIFFY DIV_ROUND_CLOSEST(EP93XX_TIMER4_CLOCK, HZ)
|
{
|
||||||
|
u64 ret;
|
||||||
|
|
||||||
static unsigned int last_jiffy_time;
|
ret = __raw_readl(EP93XX_TIMER4_VALUE_LOW);
|
||||||
|
ret |= ((u64) (__raw_readl(EP93XX_TIMER4_VALUE_HIGH) & 0xff) << 32);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
cycle_t ep93xx_clocksource_read(struct clocksource *c)
|
||||||
|
{
|
||||||
|
u64 ret;
|
||||||
|
|
||||||
|
ret = __raw_readl(EP93XX_TIMER4_VALUE_LOW);
|
||||||
|
ret |= ((u64) (__raw_readl(EP93XX_TIMER4_VALUE_HIGH) & 0xff) << 32);
|
||||||
|
return (cycle_t) ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int ep93xx_clkevt_set_next_event(unsigned long next,
|
||||||
|
struct clock_event_device *evt)
|
||||||
|
{
|
||||||
|
/* Default mode: periodic, off, 508 kHz */
|
||||||
|
u32 tmode = EP93XX_TIMER123_CONTROL_MODE |
|
||||||
|
EP93XX_TIMER123_CONTROL_CLKSEL;
|
||||||
|
|
||||||
|
/* Clear timer */
|
||||||
|
__raw_writel(tmode, EP93XX_TIMER1_CONTROL);
|
||||||
|
|
||||||
|
/* Set next event */
|
||||||
|
__raw_writel(next, EP93XX_TIMER1_LOAD);
|
||||||
|
__raw_writel(tmode | EP93XX_TIMER123_CONTROL_ENABLE,
|
||||||
|
EP93XX_TIMER1_CONTROL);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void ep93xx_clkevt_set_mode(enum clock_event_mode mode,
|
||||||
|
struct clock_event_device *evt)
|
||||||
|
{
|
||||||
|
/* Disable timer */
|
||||||
|
__raw_writel(0, EP93XX_TIMER1_CONTROL);
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct clock_event_device ep93xx_clockevent = {
|
||||||
|
.name = "timer1",
|
||||||
|
.features = CLOCK_EVT_FEAT_ONESHOT,
|
||||||
|
.set_mode = ep93xx_clkevt_set_mode,
|
||||||
|
.set_next_event = ep93xx_clkevt_set_next_event,
|
||||||
|
.rating = 300,
|
||||||
|
};
|
||||||
|
|
||||||
static irqreturn_t ep93xx_timer_interrupt(int irq, void *dev_id)
|
static irqreturn_t ep93xx_timer_interrupt(int irq, void *dev_id)
|
||||||
{
|
{
|
||||||
|
struct clock_event_device *evt = dev_id;
|
||||||
|
|
||||||
/* Writing any value clears the timer interrupt */
|
/* Writing any value clears the timer interrupt */
|
||||||
__raw_writel(1, EP93XX_TIMER1_CLEAR);
|
__raw_writel(1, EP93XX_TIMER1_CLEAR);
|
||||||
|
|
||||||
/* Recover lost jiffies */
|
evt->event_handler(evt);
|
||||||
while ((signed long)
|
|
||||||
(__raw_readl(EP93XX_TIMER4_VALUE_LOW) - last_jiffy_time)
|
|
||||||
>= TIMER4_TICKS_PER_JIFFY) {
|
|
||||||
last_jiffy_time += TIMER4_TICKS_PER_JIFFY;
|
|
||||||
timer_tick();
|
|
||||||
}
|
|
||||||
|
|
||||||
return IRQ_HANDLED;
|
return IRQ_HANDLED;
|
||||||
}
|
}
|
||||||
|
@ -73,40 +118,25 @@ static struct irqaction ep93xx_timer_irq = {
|
||||||
.name = "ep93xx timer",
|
.name = "ep93xx timer",
|
||||||
.flags = IRQF_TIMER | IRQF_IRQPOLL,
|
.flags = IRQF_TIMER | IRQF_IRQPOLL,
|
||||||
.handler = ep93xx_timer_interrupt,
|
.handler = ep93xx_timer_interrupt,
|
||||||
|
.dev_id = &ep93xx_clockevent,
|
||||||
};
|
};
|
||||||
|
|
||||||
static u32 ep93xx_gettimeoffset(void)
|
|
||||||
{
|
|
||||||
int offset;
|
|
||||||
|
|
||||||
offset = __raw_readl(EP93XX_TIMER4_VALUE_LOW) - last_jiffy_time;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Timer 4 is based on a 983.04 kHz reference clock,
|
|
||||||
* so dividing by 983040 gives the fraction of a second,
|
|
||||||
* so dividing by 0.983040 converts to uS.
|
|
||||||
* Refactor the calculation to avoid overflow.
|
|
||||||
* Finally, multiply by 1000 to give nS.
|
|
||||||
*/
|
|
||||||
return (offset + (53 * offset / 3072)) * 1000;
|
|
||||||
}
|
|
||||||
|
|
||||||
void __init ep93xx_timer_init(void)
|
void __init ep93xx_timer_init(void)
|
||||||
{
|
{
|
||||||
u32 tmode = EP93XX_TIMER123_CONTROL_MODE |
|
/* Enable and register clocksource and sched_clock on timer 4 */
|
||||||
EP93XX_TIMER123_CONTROL_CLKSEL;
|
|
||||||
|
|
||||||
arch_gettimeoffset = ep93xx_gettimeoffset;
|
|
||||||
|
|
||||||
/* Enable periodic HZ timer. */
|
|
||||||
__raw_writel(tmode, EP93XX_TIMER1_CONTROL);
|
|
||||||
__raw_writel(TIMER1_RELOAD, EP93XX_TIMER1_LOAD);
|
|
||||||
__raw_writel(tmode | EP93XX_TIMER123_CONTROL_ENABLE,
|
|
||||||
EP93XX_TIMER1_CONTROL);
|
|
||||||
|
|
||||||
/* Enable lost jiffy timer. */
|
|
||||||
__raw_writel(EP93XX_TIMER4_VALUE_HIGH_ENABLE,
|
__raw_writel(EP93XX_TIMER4_VALUE_HIGH_ENABLE,
|
||||||
EP93XX_TIMER4_VALUE_HIGH);
|
EP93XX_TIMER4_VALUE_HIGH);
|
||||||
|
clocksource_mmio_init(NULL, "timer4",
|
||||||
|
EP93XX_TIMER4_RATE, 200, 40,
|
||||||
|
ep93xx_clocksource_read);
|
||||||
|
sched_clock_register(ep93xx_read_sched_clock, 40,
|
||||||
|
EP93XX_TIMER4_RATE);
|
||||||
|
|
||||||
|
/* Set up clockevent on timer 1 */
|
||||||
setup_irq(IRQ_EP93XX_TIMER1, &ep93xx_timer_irq);
|
setup_irq(IRQ_EP93XX_TIMER1, &ep93xx_timer_irq);
|
||||||
|
// FIXME: timer one is 16 bits 1-ffff use timer 3 1-ffffffff */
|
||||||
|
clockevents_config_and_register(&ep93xx_clockevent,
|
||||||
|
EP93XX_TIMER123_RATE,
|
||||||
|
1,
|
||||||
|
0xffffU);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue