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