18b5f79f9d7ee4f4edb0212886771c977476eb811Vitja Makarov/*
28b5f79f9d7ee4f4edb0212886771c977476eb811Vitja Makarov * Based on arm clockevents implementation and old bfin time tick.
38b5f79f9d7ee4f4edb0212886771c977476eb811Vitja Makarov *
496f1050d3df105c9ae6c6ac224f370199ea82fcdRobin Getz * Copyright 2008-2009 Analog Devics Inc.
596f1050d3df105c9ae6c6ac224f370199ea82fcdRobin Getz *                2008 GeoTechnologies
696f1050d3df105c9ae6c6ac224f370199ea82fcdRobin Getz *                     Vitja Makarov
78b5f79f9d7ee4f4edb0212886771c977476eb811Vitja Makarov *
896f1050d3df105c9ae6c6ac224f370199ea82fcdRobin Getz * Licensed under the GPL-2
98b5f79f9d7ee4f4edb0212886771c977476eb811Vitja Makarov */
1096f1050d3df105c9ae6c6ac224f370199ea82fcdRobin Getz
118b5f79f9d7ee4f4edb0212886771c977476eb811Vitja Makarov#include <linux/module.h>
128b5f79f9d7ee4f4edb0212886771c977476eb811Vitja Makarov#include <linux/profile.h>
138b5f79f9d7ee4f4edb0212886771c977476eb811Vitja Makarov#include <linux/interrupt.h>
148b5f79f9d7ee4f4edb0212886771c977476eb811Vitja Makarov#include <linux/time.h>
15764cb81cdc0620711d2cef5d06e9ef03c9d84184Mike Frysinger#include <linux/timex.h>
168b5f79f9d7ee4f4edb0212886771c977476eb811Vitja Makarov#include <linux/irq.h>
178b5f79f9d7ee4f4edb0212886771c977476eb811Vitja Makarov#include <linux/clocksource.h>
188b5f79f9d7ee4f4edb0212886771c977476eb811Vitja Makarov#include <linux/clockchips.h>
19e6c91b64dd6e4c3adf39483c85a936eef9465e19Michael Hennerich#include <linux/cpufreq.h>
208b5f79f9d7ee4f4edb0212886771c977476eb811Vitja Makarov
218b5f79f9d7ee4f4edb0212886771c977476eb811Vitja Makarov#include <asm/blackfin.h>
22e6c91b64dd6e4c3adf39483c85a936eef9465e19Michael Hennerich#include <asm/time.h>
231fa9be72b558c39459f98835eb86dbb4ef4da30bGraf Yang#include <asm/gptimers.h>
2460ffdb36547da2397d6cfefe9c752ebad16524f6Graf Yang#include <asm/nmi.h>
258b5f79f9d7ee4f4edb0212886771c977476eb811Vitja Makarov
268b5f79f9d7ee4f4edb0212886771c977476eb811Vitja Makarov
27ceb33be95afcfbc4079af334835a345288f9f6caYi Li#if defined(CONFIG_CYCLES_CLOCKSOURCE)
28ceb33be95afcfbc4079af334835a345288f9f6caYi Li
29ceb33be95afcfbc4079af334835a345288f9f6caYi Listatic notrace cycle_t bfin_read_cycles(struct clocksource *cs)
308b5f79f9d7ee4f4edb0212886771c977476eb811Vitja Makarov{
316c2b7072a7035837998da38809f98e4182e4c41cGraf Yang#ifdef CONFIG_CPU_FREQ
321bfb4b21c7c39295f5535c139f796df1d51ec009Vitja Makarov	return __bfin_cycles_off + (get_cycles() << __bfin_cycles_mod);
336c2b7072a7035837998da38809f98e4182e4c41cGraf Yang#else
346c2b7072a7035837998da38809f98e4182e4c41cGraf Yang	return get_cycles();
356c2b7072a7035837998da38809f98e4182e4c41cGraf Yang#endif
368b5f79f9d7ee4f4edb0212886771c977476eb811Vitja Makarov}
378b5f79f9d7ee4f4edb0212886771c977476eb811Vitja Makarov
381fa9be72b558c39459f98835eb86dbb4ef4da30bGraf Yangstatic struct clocksource bfin_cs_cycles = {
391fa9be72b558c39459f98835eb86dbb4ef4da30bGraf Yang	.name		= "bfin_cs_cycles",
40e78feaaeeb9bbf78f961917d72d692802ac110e8Graf Yang	.rating		= 400,
411fa9be72b558c39459f98835eb86dbb4ef4da30bGraf Yang	.read		= bfin_read_cycles,
428b5f79f9d7ee4f4edb0212886771c977476eb811Vitja Makarov	.mask		= CLOCKSOURCE_MASK(64),
438b5f79f9d7ee4f4edb0212886771c977476eb811Vitja Makarov	.flags		= CLOCK_SOURCE_IS_CONTINUOUS,
448b5f79f9d7ee4f4edb0212886771c977476eb811Vitja Makarov};
458b5f79f9d7ee4f4edb0212886771c977476eb811Vitja Makarov
46ceb33be95afcfbc4079af334835a345288f9f6caYi Listatic inline unsigned long long bfin_cs_cycles_sched_clock(void)
478e19608e8b5c001e4a66ce482edc474f05fb7355Magnus Damm{
48c768a943fd8f41f5f7ed33c91d50818b301f5635Mike Frysinger	return clocksource_cyc2ns(bfin_read_cycles(&bfin_cs_cycles),
49c768a943fd8f41f5f7ed33c91d50818b301f5635Mike Frysinger		bfin_cs_cycles.mult, bfin_cs_cycles.shift);
508e19608e8b5c001e4a66ce482edc474f05fb7355Magnus Damm}
518e19608e8b5c001e4a66ce482edc474f05fb7355Magnus Damm
521fa9be72b558c39459f98835eb86dbb4ef4da30bGraf Yangstatic int __init bfin_cs_cycles_init(void)
538b5f79f9d7ee4f4edb0212886771c977476eb811Vitja Makarov{
54a1c57e0fec53defe745e64417eacdbd3618c3e66John Stultz	if (clocksource_register_hz(&bfin_cs_cycles, get_cclk()))
558b5f79f9d7ee4f4edb0212886771c977476eb811Vitja Makarov		panic("failed to register clocksource");
568b5f79f9d7ee4f4edb0212886771c977476eb811Vitja Makarov
578b5f79f9d7ee4f4edb0212886771c977476eb811Vitja Makarov	return 0;
588b5f79f9d7ee4f4edb0212886771c977476eb811Vitja Makarov}
591fa9be72b558c39459f98835eb86dbb4ef4da30bGraf Yang#else
601fa9be72b558c39459f98835eb86dbb4ef4da30bGraf Yang# define bfin_cs_cycles_init()
611fa9be72b558c39459f98835eb86dbb4ef4da30bGraf Yang#endif
621fa9be72b558c39459f98835eb86dbb4ef4da30bGraf Yang
631fa9be72b558c39459f98835eb86dbb4ef4da30bGraf Yang#ifdef CONFIG_GPTMR0_CLOCKSOURCE
641fa9be72b558c39459f98835eb86dbb4ef4da30bGraf Yang
651fa9be72b558c39459f98835eb86dbb4ef4da30bGraf Yangvoid __init setup_gptimer0(void)
661fa9be72b558c39459f98835eb86dbb4ef4da30bGraf Yang{
671fa9be72b558c39459f98835eb86dbb4ef4da30bGraf Yang	disable_gptimers(TIMER0bit);
681fa9be72b558c39459f98835eb86dbb4ef4da30bGraf Yang
692879bb30d788bb3841e2f1675ea7af5204eb171cSteven Miao#ifdef CONFIG_BF60x
702879bb30d788bb3841e2f1675ea7af5204eb171cSteven Miao	bfin_write16(TIMER_DATA_IMSK, 0);
712879bb30d788bb3841e2f1675ea7af5204eb171cSteven Miao	set_gptimer_config(TIMER0_id,  TIMER_OUT_DIS
722879bb30d788bb3841e2f1675ea7af5204eb171cSteven Miao		| TIMER_MODE_PWM_CONT | TIMER_PULSE_HI | TIMER_IRQ_PER);
732879bb30d788bb3841e2f1675ea7af5204eb171cSteven Miao#else
741fa9be72b558c39459f98835eb86dbb4ef4da30bGraf Yang	set_gptimer_config(TIMER0_id, \
751fa9be72b558c39459f98835eb86dbb4ef4da30bGraf Yang		TIMER_OUT_DIS | TIMER_PERIOD_CNT | TIMER_MODE_PWM);
762879bb30d788bb3841e2f1675ea7af5204eb171cSteven Miao#endif
771fa9be72b558c39459f98835eb86dbb4ef4da30bGraf Yang	set_gptimer_period(TIMER0_id, -1);
781fa9be72b558c39459f98835eb86dbb4ef4da30bGraf Yang	set_gptimer_pwidth(TIMER0_id, -2);
791fa9be72b558c39459f98835eb86dbb4ef4da30bGraf Yang	SSYNC();
801fa9be72b558c39459f98835eb86dbb4ef4da30bGraf Yang	enable_gptimers(TIMER0bit);
811fa9be72b558c39459f98835eb86dbb4ef4da30bGraf Yang}
821fa9be72b558c39459f98835eb86dbb4ef4da30bGraf Yang
83f7036d649c88ad14b482b2787ffb1063c8a719d7Yi Listatic cycle_t bfin_read_gptimer0(struct clocksource *cs)
841fa9be72b558c39459f98835eb86dbb4ef4da30bGraf Yang{
851fa9be72b558c39459f98835eb86dbb4ef4da30bGraf Yang	return bfin_read_TIMER0_COUNTER();
861fa9be72b558c39459f98835eb86dbb4ef4da30bGraf Yang}
871fa9be72b558c39459f98835eb86dbb4ef4da30bGraf Yang
881fa9be72b558c39459f98835eb86dbb4ef4da30bGraf Yangstatic struct clocksource bfin_cs_gptimer0 = {
891fa9be72b558c39459f98835eb86dbb4ef4da30bGraf Yang	.name		= "bfin_cs_gptimer0",
90e78feaaeeb9bbf78f961917d72d692802ac110e8Graf Yang	.rating		= 350,
911fa9be72b558c39459f98835eb86dbb4ef4da30bGraf Yang	.read		= bfin_read_gptimer0,
921fa9be72b558c39459f98835eb86dbb4ef4da30bGraf Yang	.mask		= CLOCKSOURCE_MASK(32),
931fa9be72b558c39459f98835eb86dbb4ef4da30bGraf Yang	.flags		= CLOCK_SOURCE_IS_CONTINUOUS,
941fa9be72b558c39459f98835eb86dbb4ef4da30bGraf Yang};
951fa9be72b558c39459f98835eb86dbb4ef4da30bGraf Yang
96ceb33be95afcfbc4079af334835a345288f9f6caYi Listatic inline unsigned long long bfin_cs_gptimer0_sched_clock(void)
97ceb33be95afcfbc4079af334835a345288f9f6caYi Li{
98c768a943fd8f41f5f7ed33c91d50818b301f5635Mike Frysinger	return clocksource_cyc2ns(bfin_read_TIMER0_COUNTER(),
99c768a943fd8f41f5f7ed33c91d50818b301f5635Mike Frysinger		bfin_cs_gptimer0.mult, bfin_cs_gptimer0.shift);
100ceb33be95afcfbc4079af334835a345288f9f6caYi Li}
101ceb33be95afcfbc4079af334835a345288f9f6caYi Li
1021fa9be72b558c39459f98835eb86dbb4ef4da30bGraf Yangstatic int __init bfin_cs_gptimer0_init(void)
1031fa9be72b558c39459f98835eb86dbb4ef4da30bGraf Yang{
1041fa9be72b558c39459f98835eb86dbb4ef4da30bGraf Yang	setup_gptimer0();
1058b5f79f9d7ee4f4edb0212886771c977476eb811Vitja Makarov
106a1c57e0fec53defe745e64417eacdbd3618c3e66John Stultz	if (clocksource_register_hz(&bfin_cs_gptimer0, get_sclk()))
1071fa9be72b558c39459f98835eb86dbb4ef4da30bGraf Yang		panic("failed to register clocksource");
1081fa9be72b558c39459f98835eb86dbb4ef4da30bGraf Yang
1091fa9be72b558c39459f98835eb86dbb4ef4da30bGraf Yang	return 0;
1101fa9be72b558c39459f98835eb86dbb4ef4da30bGraf Yang}
1118b5f79f9d7ee4f4edb0212886771c977476eb811Vitja Makarov#else
1121fa9be72b558c39459f98835eb86dbb4ef4da30bGraf Yang# define bfin_cs_gptimer0_init()
1138b5f79f9d7ee4f4edb0212886771c977476eb811Vitja Makarov#endif
1148b5f79f9d7ee4f4edb0212886771c977476eb811Vitja Makarov
115ceb33be95afcfbc4079af334835a345288f9f6caYi Li#if defined(CONFIG_GPTMR0_CLOCKSOURCE) || defined(CONFIG_CYCLES_CLOCKSOURCE)
116ceb33be95afcfbc4079af334835a345288f9f6caYi Li/* prefer to use cycles since it has higher rating */
117ceb33be95afcfbc4079af334835a345288f9f6caYi Linotrace unsigned long long sched_clock(void)
118ceb33be95afcfbc4079af334835a345288f9f6caYi Li{
119ceb33be95afcfbc4079af334835a345288f9f6caYi Li#if defined(CONFIG_CYCLES_CLOCKSOURCE)
120ceb33be95afcfbc4079af334835a345288f9f6caYi Li	return bfin_cs_cycles_sched_clock();
121ceb33be95afcfbc4079af334835a345288f9f6caYi Li#else
122ceb33be95afcfbc4079af334835a345288f9f6caYi Li	return bfin_cs_gptimer0_sched_clock();
123ceb33be95afcfbc4079af334835a345288f9f6caYi Li#endif
124ceb33be95afcfbc4079af334835a345288f9f6caYi Li}
125ceb33be95afcfbc4079af334835a345288f9f6caYi Li#endif
126ceb33be95afcfbc4079af334835a345288f9f6caYi Li
1271fa9be72b558c39459f98835eb86dbb4ef4da30bGraf Yang#if defined(CONFIG_TICKSOURCE_GPTMR0)
1280d152c27e336b5fd777da7dd3e814617e7305afdYi Listatic int bfin_gptmr0_set_next_event(unsigned long cycles,
1298b5f79f9d7ee4f4edb0212886771c977476eb811Vitja Makarov                                     struct clock_event_device *evt)
1308b5f79f9d7ee4f4edb0212886771c977476eb811Vitja Makarov{
1311fa9be72b558c39459f98835eb86dbb4ef4da30bGraf Yang	disable_gptimers(TIMER0bit);
1321fa9be72b558c39459f98835eb86dbb4ef4da30bGraf Yang
1331fa9be72b558c39459f98835eb86dbb4ef4da30bGraf Yang	/* it starts counting three SCLK cycles after the TIMENx bit is set */
1341fa9be72b558c39459f98835eb86dbb4ef4da30bGraf Yang	set_gptimer_pwidth(TIMER0_id, cycles - 3);
1351fa9be72b558c39459f98835eb86dbb4ef4da30bGraf Yang	enable_gptimers(TIMER0bit);
1361fa9be72b558c39459f98835eb86dbb4ef4da30bGraf Yang	return 0;
1371fa9be72b558c39459f98835eb86dbb4ef4da30bGraf Yang}
1381fa9be72b558c39459f98835eb86dbb4ef4da30bGraf Yang
1390d152c27e336b5fd777da7dd3e814617e7305afdYi Listatic void bfin_gptmr0_set_mode(enum clock_event_mode mode,
1401fa9be72b558c39459f98835eb86dbb4ef4da30bGraf Yang				struct clock_event_device *evt)
1411fa9be72b558c39459f98835eb86dbb4ef4da30bGraf Yang{
1421fa9be72b558c39459f98835eb86dbb4ef4da30bGraf Yang	switch (mode) {
1431fa9be72b558c39459f98835eb86dbb4ef4da30bGraf Yang	case CLOCK_EVT_MODE_PERIODIC: {
1442879bb30d788bb3841e2f1675ea7af5204eb171cSteven Miao#ifndef CONFIG_BF60x
1451fa9be72b558c39459f98835eb86dbb4ef4da30bGraf Yang		set_gptimer_config(TIMER0_id, \
1461fa9be72b558c39459f98835eb86dbb4ef4da30bGraf Yang			TIMER_OUT_DIS | TIMER_IRQ_ENA | \
1471fa9be72b558c39459f98835eb86dbb4ef4da30bGraf Yang			TIMER_PERIOD_CNT | TIMER_MODE_PWM);
1482879bb30d788bb3841e2f1675ea7af5204eb171cSteven Miao#else
1492879bb30d788bb3841e2f1675ea7af5204eb171cSteven Miao		set_gptimer_config(TIMER0_id,  TIMER_OUT_DIS
1502879bb30d788bb3841e2f1675ea7af5204eb171cSteven Miao			| TIMER_MODE_PWM_CONT | TIMER_PULSE_HI | TIMER_IRQ_PER);
1512879bb30d788bb3841e2f1675ea7af5204eb171cSteven Miao#endif
1522879bb30d788bb3841e2f1675ea7af5204eb171cSteven Miao
1531fa9be72b558c39459f98835eb86dbb4ef4da30bGraf Yang		set_gptimer_period(TIMER0_id, get_sclk() / HZ);
1541fa9be72b558c39459f98835eb86dbb4ef4da30bGraf Yang		set_gptimer_pwidth(TIMER0_id, get_sclk() / HZ - 1);
1551fa9be72b558c39459f98835eb86dbb4ef4da30bGraf Yang		enable_gptimers(TIMER0bit);
1561fa9be72b558c39459f98835eb86dbb4ef4da30bGraf Yang		break;
1571fa9be72b558c39459f98835eb86dbb4ef4da30bGraf Yang	}
1581fa9be72b558c39459f98835eb86dbb4ef4da30bGraf Yang	case CLOCK_EVT_MODE_ONESHOT:
1591fa9be72b558c39459f98835eb86dbb4ef4da30bGraf Yang		disable_gptimers(TIMER0bit);
1602879bb30d788bb3841e2f1675ea7af5204eb171cSteven Miao#ifndef CONFIG_BF60x
1611fa9be72b558c39459f98835eb86dbb4ef4da30bGraf Yang		set_gptimer_config(TIMER0_id, \
1621fa9be72b558c39459f98835eb86dbb4ef4da30bGraf Yang			TIMER_OUT_DIS | TIMER_IRQ_ENA | TIMER_MODE_PWM);
1632879bb30d788bb3841e2f1675ea7af5204eb171cSteven Miao#else
1642879bb30d788bb3841e2f1675ea7af5204eb171cSteven Miao		set_gptimer_config(TIMER0_id, TIMER_OUT_DIS | TIMER_MODE_PWM
1652879bb30d788bb3841e2f1675ea7af5204eb171cSteven Miao			| TIMER_PULSE_HI | TIMER_IRQ_WID_DLY);
1662879bb30d788bb3841e2f1675ea7af5204eb171cSteven Miao#endif
1672879bb30d788bb3841e2f1675ea7af5204eb171cSteven Miao
1681fa9be72b558c39459f98835eb86dbb4ef4da30bGraf Yang		set_gptimer_period(TIMER0_id, 0);
1691fa9be72b558c39459f98835eb86dbb4ef4da30bGraf Yang		break;
1701fa9be72b558c39459f98835eb86dbb4ef4da30bGraf Yang	case CLOCK_EVT_MODE_UNUSED:
1711fa9be72b558c39459f98835eb86dbb4ef4da30bGraf Yang	case CLOCK_EVT_MODE_SHUTDOWN:
1721fa9be72b558c39459f98835eb86dbb4ef4da30bGraf Yang		disable_gptimers(TIMER0bit);
1731fa9be72b558c39459f98835eb86dbb4ef4da30bGraf Yang		break;
1741fa9be72b558c39459f98835eb86dbb4ef4da30bGraf Yang	case CLOCK_EVT_MODE_RESUME:
1751fa9be72b558c39459f98835eb86dbb4ef4da30bGraf Yang		break;
1761fa9be72b558c39459f98835eb86dbb4ef4da30bGraf Yang	}
1771fa9be72b558c39459f98835eb86dbb4ef4da30bGraf Yang}
1781fa9be72b558c39459f98835eb86dbb4ef4da30bGraf Yang
1790d152c27e336b5fd777da7dd3e814617e7305afdYi Listatic void bfin_gptmr0_ack(void)
1801fa9be72b558c39459f98835eb86dbb4ef4da30bGraf Yang{
1812879bb30d788bb3841e2f1675ea7af5204eb171cSteven Miao	clear_gptimer_intr(TIMER0_id);
1821fa9be72b558c39459f98835eb86dbb4ef4da30bGraf Yang}
1831fa9be72b558c39459f98835eb86dbb4ef4da30bGraf Yang
1840d152c27e336b5fd777da7dd3e814617e7305afdYi Listatic void __init bfin_gptmr0_init(void)
1851fa9be72b558c39459f98835eb86dbb4ef4da30bGraf Yang{
1861fa9be72b558c39459f98835eb86dbb4ef4da30bGraf Yang	disable_gptimers(TIMER0bit);
1871fa9be72b558c39459f98835eb86dbb4ef4da30bGraf Yang}
1881fa9be72b558c39459f98835eb86dbb4ef4da30bGraf Yang
1890d152c27e336b5fd777da7dd3e814617e7305afdYi Li#ifdef CONFIG_CORE_TIMER_IRQ_L1
1900d152c27e336b5fd777da7dd3e814617e7305afdYi Li__attribute__((l1_text))
1910d152c27e336b5fd777da7dd3e814617e7305afdYi Li#endif
1920d152c27e336b5fd777da7dd3e814617e7305afdYi Liirqreturn_t bfin_gptmr0_interrupt(int irq, void *dev_id)
1931fa9be72b558c39459f98835eb86dbb4ef4da30bGraf Yang{
1940d152c27e336b5fd777da7dd3e814617e7305afdYi Li	struct clock_event_device *evt = dev_id;
1950d152c27e336b5fd777da7dd3e814617e7305afdYi Li	smp_mb();
1960bf02ce605b8780223b10739ab7c533de9eb10ccMike Frysinger	/*
1970bf02ce605b8780223b10739ab7c533de9eb10ccMike Frysinger	 * We want to ACK before we handle so that we can handle smaller timer
1980bf02ce605b8780223b10739ab7c533de9eb10ccMike Frysinger	 * intervals.  This way if the timer expires again while we're handling
1990bf02ce605b8780223b10739ab7c533de9eb10ccMike Frysinger	 * things, we're more likely to see that 2nd int rather than swallowing
2000bf02ce605b8780223b10739ab7c533de9eb10ccMike Frysinger	 * it by ACKing the int at the end of this handler.
2010bf02ce605b8780223b10739ab7c533de9eb10ccMike Frysinger	 */
2020d152c27e336b5fd777da7dd3e814617e7305afdYi Li	bfin_gptmr0_ack();
2030bf02ce605b8780223b10739ab7c533de9eb10ccMike Frysinger	evt->event_handler(evt);
2040d152c27e336b5fd777da7dd3e814617e7305afdYi Li	return IRQ_HANDLED;
2051fa9be72b558c39459f98835eb86dbb4ef4da30bGraf Yang}
2061fa9be72b558c39459f98835eb86dbb4ef4da30bGraf Yang
2070d152c27e336b5fd777da7dd3e814617e7305afdYi Listatic struct irqaction gptmr0_irq = {
2080d152c27e336b5fd777da7dd3e814617e7305afdYi Li	.name		= "Blackfin GPTimer0",
2097832bb5d450aefa45b6dac3b3140eade66bb12adYong Zhang	.flags		= IRQF_TIMER | IRQF_IRQPOLL | IRQF_PERCPU,
2100d152c27e336b5fd777da7dd3e814617e7305afdYi Li	.handler	= bfin_gptmr0_interrupt,
2110d152c27e336b5fd777da7dd3e814617e7305afdYi Li};
2121fa9be72b558c39459f98835eb86dbb4ef4da30bGraf Yang
2130d152c27e336b5fd777da7dd3e814617e7305afdYi Listatic struct clock_event_device clockevent_gptmr0 = {
2140d152c27e336b5fd777da7dd3e814617e7305afdYi Li	.name		= "bfin_gptimer0",
2150d152c27e336b5fd777da7dd3e814617e7305afdYi Li	.rating		= 300,
2160d152c27e336b5fd777da7dd3e814617e7305afdYi Li	.irq		= IRQ_TIMER0,
2170d152c27e336b5fd777da7dd3e814617e7305afdYi Li	.shift		= 32,
2182879bb30d788bb3841e2f1675ea7af5204eb171cSteven Miao	.features 	= CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT,
2190d152c27e336b5fd777da7dd3e814617e7305afdYi Li	.set_next_event = bfin_gptmr0_set_next_event,
2200d152c27e336b5fd777da7dd3e814617e7305afdYi Li	.set_mode	= bfin_gptmr0_set_mode,
2210d152c27e336b5fd777da7dd3e814617e7305afdYi Li};
2220d152c27e336b5fd777da7dd3e814617e7305afdYi Li
2230d152c27e336b5fd777da7dd3e814617e7305afdYi Listatic void __init bfin_gptmr0_clockevent_init(struct clock_event_device *evt)
2240d152c27e336b5fd777da7dd3e814617e7305afdYi Li{
2250d152c27e336b5fd777da7dd3e814617e7305afdYi Li	unsigned long clock_tick;
2260d152c27e336b5fd777da7dd3e814617e7305afdYi Li
2270d152c27e336b5fd777da7dd3e814617e7305afdYi Li	clock_tick = get_sclk();
2280d152c27e336b5fd777da7dd3e814617e7305afdYi Li	evt->mult = div_sc(clock_tick, NSEC_PER_SEC, evt->shift);
2290d152c27e336b5fd777da7dd3e814617e7305afdYi Li	evt->max_delta_ns = clockevent_delta2ns(-1, evt);
2300d152c27e336b5fd777da7dd3e814617e7305afdYi Li	evt->min_delta_ns = clockevent_delta2ns(100, evt);
2310d152c27e336b5fd777da7dd3e814617e7305afdYi Li
2320d152c27e336b5fd777da7dd3e814617e7305afdYi Li	evt->cpumask = cpumask_of(0);
2330d152c27e336b5fd777da7dd3e814617e7305afdYi Li
2340d152c27e336b5fd777da7dd3e814617e7305afdYi Li	clockevents_register_device(evt);
2350d152c27e336b5fd777da7dd3e814617e7305afdYi Li}
2360d152c27e336b5fd777da7dd3e814617e7305afdYi Li#endif /* CONFIG_TICKSOURCE_GPTMR0 */
2370d152c27e336b5fd777da7dd3e814617e7305afdYi Li
2380d152c27e336b5fd777da7dd3e814617e7305afdYi Li#if defined(CONFIG_TICKSOURCE_CORETMR)
2390d152c27e336b5fd777da7dd3e814617e7305afdYi Li/* per-cpu local core timer */
240d0014be47dc90d15adf7d6e09031d06e2aa7ce79Bob LiuDEFINE_PER_CPU(struct clock_event_device, coretmr_events);
2410d152c27e336b5fd777da7dd3e814617e7305afdYi Li
2420d152c27e336b5fd777da7dd3e814617e7305afdYi Listatic int bfin_coretmr_set_next_event(unsigned long cycles,
2431fa9be72b558c39459f98835eb86dbb4ef4da30bGraf Yang				struct clock_event_device *evt)
2441fa9be72b558c39459f98835eb86dbb4ef4da30bGraf Yang{
2451fa9be72b558c39459f98835eb86dbb4ef4da30bGraf Yang	bfin_write_TCNTL(TMPWR);
2461fa9be72b558c39459f98835eb86dbb4ef4da30bGraf Yang	CSYNC();
2478b5f79f9d7ee4f4edb0212886771c977476eb811Vitja Makarov	bfin_write_TCOUNT(cycles);
2488b5f79f9d7ee4f4edb0212886771c977476eb811Vitja Makarov	CSYNC();
2491fa9be72b558c39459f98835eb86dbb4ef4da30bGraf Yang	bfin_write_TCNTL(TMPWR | TMREN);
2508b5f79f9d7ee4f4edb0212886771c977476eb811Vitja Makarov	return 0;
2518b5f79f9d7ee4f4edb0212886771c977476eb811Vitja Makarov}
2528b5f79f9d7ee4f4edb0212886771c977476eb811Vitja Makarov
2530d152c27e336b5fd777da7dd3e814617e7305afdYi Listatic void bfin_coretmr_set_mode(enum clock_event_mode mode,
2541fa9be72b558c39459f98835eb86dbb4ef4da30bGraf Yang				struct clock_event_device *evt)
2558b5f79f9d7ee4f4edb0212886771c977476eb811Vitja Makarov{
2568b5f79f9d7ee4f4edb0212886771c977476eb811Vitja Makarov	switch (mode) {
2578b5f79f9d7ee4f4edb0212886771c977476eb811Vitja Makarov	case CLOCK_EVT_MODE_PERIODIC: {
258e6c91b64dd6e4c3adf39483c85a936eef9465e19Michael Hennerich		unsigned long tcount = ((get_cclk() / (HZ * TIME_SCALE)) - 1);
2598b5f79f9d7ee4f4edb0212886771c977476eb811Vitja Makarov		bfin_write_TCNTL(TMPWR);
2608b5f79f9d7ee4f4edb0212886771c977476eb811Vitja Makarov		CSYNC();
2611fa9be72b558c39459f98835eb86dbb4ef4da30bGraf Yang		bfin_write_TSCALE(TIME_SCALE - 1);
2628b5f79f9d7ee4f4edb0212886771c977476eb811Vitja Makarov		bfin_write_TPERIOD(tcount);
2638b5f79f9d7ee4f4edb0212886771c977476eb811Vitja Makarov		bfin_write_TCOUNT(tcount);
2648b5f79f9d7ee4f4edb0212886771c977476eb811Vitja Makarov		CSYNC();
2651fa9be72b558c39459f98835eb86dbb4ef4da30bGraf Yang		bfin_write_TCNTL(TMPWR | TMREN | TAUTORLD);
2668b5f79f9d7ee4f4edb0212886771c977476eb811Vitja Makarov		break;
2678b5f79f9d7ee4f4edb0212886771c977476eb811Vitja Makarov	}
2688b5f79f9d7ee4f4edb0212886771c977476eb811Vitja Makarov	case CLOCK_EVT_MODE_ONESHOT:
2691fa9be72b558c39459f98835eb86dbb4ef4da30bGraf Yang		bfin_write_TCNTL(TMPWR);
2701fa9be72b558c39459f98835eb86dbb4ef4da30bGraf Yang		CSYNC();
2711bfb4b21c7c39295f5535c139f796df1d51ec009Vitja Makarov		bfin_write_TSCALE(TIME_SCALE - 1);
2721fa9be72b558c39459f98835eb86dbb4ef4da30bGraf Yang		bfin_write_TPERIOD(0);
2738b5f79f9d7ee4f4edb0212886771c977476eb811Vitja Makarov		bfin_write_TCOUNT(0);
2748b5f79f9d7ee4f4edb0212886771c977476eb811Vitja Makarov		break;
2758b5f79f9d7ee4f4edb0212886771c977476eb811Vitja Makarov	case CLOCK_EVT_MODE_UNUSED:
2768b5f79f9d7ee4f4edb0212886771c977476eb811Vitja Makarov	case CLOCK_EVT_MODE_SHUTDOWN:
2778b5f79f9d7ee4f4edb0212886771c977476eb811Vitja Makarov		bfin_write_TCNTL(0);
2788b5f79f9d7ee4f4edb0212886771c977476eb811Vitja Makarov		CSYNC();
2798b5f79f9d7ee4f4edb0212886771c977476eb811Vitja Makarov		break;
2808b5f79f9d7ee4f4edb0212886771c977476eb811Vitja Makarov	case CLOCK_EVT_MODE_RESUME:
2818b5f79f9d7ee4f4edb0212886771c977476eb811Vitja Makarov		break;
2828b5f79f9d7ee4f4edb0212886771c977476eb811Vitja Makarov	}
2838b5f79f9d7ee4f4edb0212886771c977476eb811Vitja Makarov}
2848b5f79f9d7ee4f4edb0212886771c977476eb811Vitja Makarov
2850d152c27e336b5fd777da7dd3e814617e7305afdYi Livoid bfin_coretmr_init(void)
2868b5f79f9d7ee4f4edb0212886771c977476eb811Vitja Makarov{
2878b5f79f9d7ee4f4edb0212886771c977476eb811Vitja Makarov	/* power up the timer, but don't enable it just yet */
2888b5f79f9d7ee4f4edb0212886771c977476eb811Vitja Makarov	bfin_write_TCNTL(TMPWR);
2898b5f79f9d7ee4f4edb0212886771c977476eb811Vitja Makarov	CSYNC();
2908b5f79f9d7ee4f4edb0212886771c977476eb811Vitja Makarov
2910d152c27e336b5fd777da7dd3e814617e7305afdYi Li	/* the TSCALE prescaler counter. */
292e6c91b64dd6e4c3adf39483c85a936eef9465e19Michael Hennerich	bfin_write_TSCALE(TIME_SCALE - 1);
2938b5f79f9d7ee4f4edb0212886771c977476eb811Vitja Makarov	bfin_write_TPERIOD(0);
2948b5f79f9d7ee4f4edb0212886771c977476eb811Vitja Makarov	bfin_write_TCOUNT(0);
2958b5f79f9d7ee4f4edb0212886771c977476eb811Vitja Makarov
2968b5f79f9d7ee4f4edb0212886771c977476eb811Vitja Makarov	CSYNC();
2978b5f79f9d7ee4f4edb0212886771c977476eb811Vitja Makarov}
2988b5f79f9d7ee4f4edb0212886771c977476eb811Vitja Makarov
2990d152c27e336b5fd777da7dd3e814617e7305afdYi Li#ifdef CONFIG_CORE_TIMER_IRQ_L1
3000d152c27e336b5fd777da7dd3e814617e7305afdYi Li__attribute__((l1_text))
3010d152c27e336b5fd777da7dd3e814617e7305afdYi Li#endif
302d0014be47dc90d15adf7d6e09031d06e2aa7ce79Bob Liu
3030d152c27e336b5fd777da7dd3e814617e7305afdYi Liirqreturn_t bfin_coretmr_interrupt(int irq, void *dev_id)
3041fa9be72b558c39459f98835eb86dbb4ef4da30bGraf Yang{
3050d152c27e336b5fd777da7dd3e814617e7305afdYi Li	int cpu = smp_processor_id();
3060d152c27e336b5fd777da7dd3e814617e7305afdYi Li	struct clock_event_device *evt = &per_cpu(coretmr_events, cpu);
3071fa9be72b558c39459f98835eb86dbb4ef4da30bGraf Yang
3081fa9be72b558c39459f98835eb86dbb4ef4da30bGraf Yang	smp_mb();
3098b5f79f9d7ee4f4edb0212886771c977476eb811Vitja Makarov	evt->event_handler(evt);
31060ffdb36547da2397d6cfefe9c752ebad16524f6Graf Yang
31160ffdb36547da2397d6cfefe9c752ebad16524f6Graf Yang	touch_nmi_watchdog();
31260ffdb36547da2397d6cfefe9c752ebad16524f6Graf Yang
3138b5f79f9d7ee4f4edb0212886771c977476eb811Vitja Makarov	return IRQ_HANDLED;
3148b5f79f9d7ee4f4edb0212886771c977476eb811Vitja Makarov}
3158b5f79f9d7ee4f4edb0212886771c977476eb811Vitja Makarov
3160d152c27e336b5fd777da7dd3e814617e7305afdYi Listatic struct irqaction coretmr_irq = {
3170d152c27e336b5fd777da7dd3e814617e7305afdYi Li	.name		= "Blackfin CoreTimer",
3187832bb5d450aefa45b6dac3b3140eade66bb12adYong Zhang	.flags		= IRQF_TIMER | IRQF_IRQPOLL | IRQF_PERCPU,
3190d152c27e336b5fd777da7dd3e814617e7305afdYi Li	.handler	= bfin_coretmr_interrupt,
3200d152c27e336b5fd777da7dd3e814617e7305afdYi Li};
3218b5f79f9d7ee4f4edb0212886771c977476eb811Vitja Makarov
3220d152c27e336b5fd777da7dd3e814617e7305afdYi Livoid bfin_coretmr_clockevent_init(void)
3230d152c27e336b5fd777da7dd3e814617e7305afdYi Li{
3240d152c27e336b5fd777da7dd3e814617e7305afdYi Li	unsigned long clock_tick;
3250d152c27e336b5fd777da7dd3e814617e7305afdYi Li	unsigned int cpu = smp_processor_id();
3260d152c27e336b5fd777da7dd3e814617e7305afdYi Li	struct clock_event_device *evt = &per_cpu(coretmr_events, cpu);
3270d152c27e336b5fd777da7dd3e814617e7305afdYi Li
328d0014be47dc90d15adf7d6e09031d06e2aa7ce79Bob Liu#ifdef CONFIG_SMP
329d0014be47dc90d15adf7d6e09031d06e2aa7ce79Bob Liu	evt->broadcast = smp_timer_broadcast;
330d0014be47dc90d15adf7d6e09031d06e2aa7ce79Bob Liu#endif
331d0014be47dc90d15adf7d6e09031d06e2aa7ce79Bob Liu
3320d152c27e336b5fd777da7dd3e814617e7305afdYi Li	evt->name = "bfin_core_timer";
3330d152c27e336b5fd777da7dd3e814617e7305afdYi Li	evt->rating = 350;
3340d152c27e336b5fd777da7dd3e814617e7305afdYi Li	evt->irq = -1;
3350d152c27e336b5fd777da7dd3e814617e7305afdYi Li	evt->shift = 32;
3360d152c27e336b5fd777da7dd3e814617e7305afdYi Li	evt->features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT;
3370d152c27e336b5fd777da7dd3e814617e7305afdYi Li	evt->set_next_event = bfin_coretmr_set_next_event;
3380d152c27e336b5fd777da7dd3e814617e7305afdYi Li	evt->set_mode = bfin_coretmr_set_mode;
3390d152c27e336b5fd777da7dd3e814617e7305afdYi Li
3400d152c27e336b5fd777da7dd3e814617e7305afdYi Li	clock_tick = get_cclk() / TIME_SCALE;
3410d152c27e336b5fd777da7dd3e814617e7305afdYi Li	evt->mult = div_sc(clock_tick, NSEC_PER_SEC, evt->shift);
3420d152c27e336b5fd777da7dd3e814617e7305afdYi Li	evt->max_delta_ns = clockevent_delta2ns(-1, evt);
3430d152c27e336b5fd777da7dd3e814617e7305afdYi Li	evt->min_delta_ns = clockevent_delta2ns(100, evt);
3440d152c27e336b5fd777da7dd3e814617e7305afdYi Li
3450d152c27e336b5fd777da7dd3e814617e7305afdYi Li	evt->cpumask = cpumask_of(cpu);
3460d152c27e336b5fd777da7dd3e814617e7305afdYi Li
3470d152c27e336b5fd777da7dd3e814617e7305afdYi Li	clockevents_register_device(evt);
3488b5f79f9d7ee4f4edb0212886771c977476eb811Vitja Makarov}
3490d152c27e336b5fd777da7dd3e814617e7305afdYi Li#endif /* CONFIG_TICKSOURCE_CORETMR */
3500d152c27e336b5fd777da7dd3e814617e7305afdYi Li
3518b5f79f9d7ee4f4edb0212886771c977476eb811Vitja Makarov
352cb0e996378900fa05d5c779d6bfa52d55ebc3407John Stultzvoid read_persistent_clock(struct timespec *ts)
3538b5f79f9d7ee4f4edb0212886771c977476eb811Vitja Makarov{
3548b5f79f9d7ee4f4edb0212886771c977476eb811Vitja Makarov	time_t secs_since_1970 = (365 * 37 + 9) * 24 * 60 * 60;	/* 1 Jan 2007 */
355cb0e996378900fa05d5c779d6bfa52d55ebc3407John Stultz	ts->tv_sec = secs_since_1970;
356cb0e996378900fa05d5c779d6bfa52d55ebc3407John Stultz	ts->tv_nsec = 0;
357cb0e996378900fa05d5c779d6bfa52d55ebc3407John Stultz}
358cb0e996378900fa05d5c779d6bfa52d55ebc3407John Stultz
359cb0e996378900fa05d5c779d6bfa52d55ebc3407John Stultzvoid __init time_init(void)
360cb0e996378900fa05d5c779d6bfa52d55ebc3407John Stultz{
3618b5f79f9d7ee4f4edb0212886771c977476eb811Vitja Makarov
3628b5f79f9d7ee4f4edb0212886771c977476eb811Vitja Makarov#ifdef CONFIG_RTC_DRV_BFIN
3638b5f79f9d7ee4f4edb0212886771c977476eb811Vitja Makarov	/* [#2663] hack to filter junk RTC values that would cause
3648b5f79f9d7ee4f4edb0212886771c977476eb811Vitja Makarov	 * userspace to have to deal with time values greater than
3658b5f79f9d7ee4f4edb0212886771c977476eb811Vitja Makarov	 * 2^31 seconds (which uClibc cannot cope with yet)
3668b5f79f9d7ee4f4edb0212886771c977476eb811Vitja Makarov	 */
3678b5f79f9d7ee4f4edb0212886771c977476eb811Vitja Makarov	if ((bfin_read_RTC_STAT() & 0xC0000000) == 0xC0000000) {
3688b5f79f9d7ee4f4edb0212886771c977476eb811Vitja Makarov		printk(KERN_NOTICE "bfin-rtc: invalid date; resetting\n");
3698b5f79f9d7ee4f4edb0212886771c977476eb811Vitja Makarov		bfin_write_RTC_STAT(0);
3708b5f79f9d7ee4f4edb0212886771c977476eb811Vitja Makarov	}
3718b5f79f9d7ee4f4edb0212886771c977476eb811Vitja Makarov#endif
3728b5f79f9d7ee4f4edb0212886771c977476eb811Vitja Makarov
3731fa9be72b558c39459f98835eb86dbb4ef4da30bGraf Yang	bfin_cs_cycles_init();
3741fa9be72b558c39459f98835eb86dbb4ef4da30bGraf Yang	bfin_cs_gptimer0_init();
3750d152c27e336b5fd777da7dd3e814617e7305afdYi Li
3760d152c27e336b5fd777da7dd3e814617e7305afdYi Li#if defined(CONFIG_TICKSOURCE_CORETMR)
3770d152c27e336b5fd777da7dd3e814617e7305afdYi Li	bfin_coretmr_init();
3780d152c27e336b5fd777da7dd3e814617e7305afdYi Li	setup_irq(IRQ_CORETMR, &coretmr_irq);
3790d152c27e336b5fd777da7dd3e814617e7305afdYi Li	bfin_coretmr_clockevent_init();
3800d152c27e336b5fd777da7dd3e814617e7305afdYi Li#endif
3810d152c27e336b5fd777da7dd3e814617e7305afdYi Li
3820d152c27e336b5fd777da7dd3e814617e7305afdYi Li#if defined(CONFIG_TICKSOURCE_GPTMR0)
3830d152c27e336b5fd777da7dd3e814617e7305afdYi Li	bfin_gptmr0_init();
3840d152c27e336b5fd777da7dd3e814617e7305afdYi Li	setup_irq(IRQ_TIMER0, &gptmr0_irq);
3850d152c27e336b5fd777da7dd3e814617e7305afdYi Li	gptmr0_irq.dev_id = &clockevent_gptmr0;
3860d152c27e336b5fd777da7dd3e814617e7305afdYi Li	bfin_gptmr0_clockevent_init(&clockevent_gptmr0);
3870d152c27e336b5fd777da7dd3e814617e7305afdYi Li#endif
3880d152c27e336b5fd777da7dd3e814617e7305afdYi Li
3890d152c27e336b5fd777da7dd3e814617e7305afdYi Li#if !defined(CONFIG_TICKSOURCE_CORETMR) && !defined(CONFIG_TICKSOURCE_GPTMR0)
3900d152c27e336b5fd777da7dd3e814617e7305afdYi Li# error at least one clock event device is required
3910d152c27e336b5fd777da7dd3e814617e7305afdYi Li#endif
3928b5f79f9d7ee4f4edb0212886771c977476eb811Vitja Makarov}
393