14182de9eSLey Foon Tan /* 24182de9eSLey Foon Tan * Copyright (C) 2013-2014 Altera Corporation 34182de9eSLey Foon Tan * Copyright (C) 2010 Tobias Klauser <tklauser@distanz.ch> 44182de9eSLey Foon Tan * Copyright (C) 2004 Microtronix Datacom Ltd. 54182de9eSLey Foon Tan * 64182de9eSLey Foon Tan * This file is subject to the terms and conditions of the GNU General Public 74182de9eSLey Foon Tan * License. See the file "COPYING" in the main directory of this archive 84182de9eSLey Foon Tan * for more details. 94182de9eSLey Foon Tan */ 104182de9eSLey Foon Tan 1105dee9c7SHerbert Xu #include <linux/export.h> 124182de9eSLey Foon Tan #include <linux/interrupt.h> 134182de9eSLey Foon Tan #include <linux/clockchips.h> 144182de9eSLey Foon Tan #include <linux/clocksource.h> 154182de9eSLey Foon Tan #include <linux/delay.h> 164182de9eSLey Foon Tan #include <linux/of.h> 174182de9eSLey Foon Tan #include <linux/of_address.h> 184182de9eSLey Foon Tan #include <linux/of_irq.h> 194182de9eSLey Foon Tan #include <linux/io.h> 204182de9eSLey Foon Tan #include <linux/slab.h> 214182de9eSLey Foon Tan 22a8955cc3SLey Foon Tan #define ALTR_TIMER_COMPATIBLE "altr,timer-1.0" 23a8955cc3SLey Foon Tan 244182de9eSLey Foon Tan #define ALTERA_TIMER_STATUS_REG 0 254182de9eSLey Foon Tan #define ALTERA_TIMER_CONTROL_REG 4 264182de9eSLey Foon Tan #define ALTERA_TIMER_PERIODL_REG 8 274182de9eSLey Foon Tan #define ALTERA_TIMER_PERIODH_REG 12 284182de9eSLey Foon Tan #define ALTERA_TIMER_SNAPL_REG 16 294182de9eSLey Foon Tan #define ALTERA_TIMER_SNAPH_REG 20 304182de9eSLey Foon Tan 314182de9eSLey Foon Tan #define ALTERA_TIMER_CONTROL_ITO_MSK (0x1) 324182de9eSLey Foon Tan #define ALTERA_TIMER_CONTROL_CONT_MSK (0x2) 334182de9eSLey Foon Tan #define ALTERA_TIMER_CONTROL_START_MSK (0x4) 344182de9eSLey Foon Tan #define ALTERA_TIMER_CONTROL_STOP_MSK (0x8) 354182de9eSLey Foon Tan 364182de9eSLey Foon Tan struct nios2_timer { 374182de9eSLey Foon Tan void __iomem *base; 384182de9eSLey Foon Tan unsigned long freq; 394182de9eSLey Foon Tan }; 404182de9eSLey Foon Tan 414182de9eSLey Foon Tan struct nios2_clockevent_dev { 424182de9eSLey Foon Tan struct nios2_timer timer; 434182de9eSLey Foon Tan struct clock_event_device ced; 444182de9eSLey Foon Tan }; 454182de9eSLey Foon Tan 464182de9eSLey Foon Tan struct nios2_clocksource { 474182de9eSLey Foon Tan struct nios2_timer timer; 484182de9eSLey Foon Tan struct clocksource cs; 494182de9eSLey Foon Tan }; 504182de9eSLey Foon Tan 514182de9eSLey Foon Tan static inline struct nios2_clockevent_dev * 524182de9eSLey Foon Tan to_nios2_clkevent(struct clock_event_device *evt) 534182de9eSLey Foon Tan { 544182de9eSLey Foon Tan return container_of(evt, struct nios2_clockevent_dev, ced); 554182de9eSLey Foon Tan } 564182de9eSLey Foon Tan 574182de9eSLey Foon Tan static inline struct nios2_clocksource * 584182de9eSLey Foon Tan to_nios2_clksource(struct clocksource *cs) 594182de9eSLey Foon Tan { 604182de9eSLey Foon Tan return container_of(cs, struct nios2_clocksource, cs); 614182de9eSLey Foon Tan } 624182de9eSLey Foon Tan 634182de9eSLey Foon Tan static u16 timer_readw(struct nios2_timer *timer, u32 offs) 644182de9eSLey Foon Tan { 654182de9eSLey Foon Tan return readw(timer->base + offs); 664182de9eSLey Foon Tan } 674182de9eSLey Foon Tan 684182de9eSLey Foon Tan static void timer_writew(struct nios2_timer *timer, u16 val, u32 offs) 694182de9eSLey Foon Tan { 704182de9eSLey Foon Tan writew(val, timer->base + offs); 714182de9eSLey Foon Tan } 724182de9eSLey Foon Tan 734182de9eSLey Foon Tan static inline unsigned long read_timersnapshot(struct nios2_timer *timer) 744182de9eSLey Foon Tan { 754182de9eSLey Foon Tan unsigned long count; 764182de9eSLey Foon Tan 774182de9eSLey Foon Tan timer_writew(timer, 0, ALTERA_TIMER_SNAPL_REG); 784182de9eSLey Foon Tan count = timer_readw(timer, ALTERA_TIMER_SNAPH_REG) << 16 | 794182de9eSLey Foon Tan timer_readw(timer, ALTERA_TIMER_SNAPL_REG); 804182de9eSLey Foon Tan 814182de9eSLey Foon Tan return count; 824182de9eSLey Foon Tan } 834182de9eSLey Foon Tan 84a5a1d1c2SThomas Gleixner static u64 nios2_timer_read(struct clocksource *cs) 854182de9eSLey Foon Tan { 864182de9eSLey Foon Tan struct nios2_clocksource *nios2_cs = to_nios2_clksource(cs); 874182de9eSLey Foon Tan unsigned long flags; 884182de9eSLey Foon Tan u32 count; 894182de9eSLey Foon Tan 904182de9eSLey Foon Tan local_irq_save(flags); 914182de9eSLey Foon Tan count = read_timersnapshot(&nios2_cs->timer); 924182de9eSLey Foon Tan local_irq_restore(flags); 934182de9eSLey Foon Tan 944182de9eSLey Foon Tan /* Counter is counting down */ 954182de9eSLey Foon Tan return ~count; 964182de9eSLey Foon Tan } 974182de9eSLey Foon Tan 984182de9eSLey Foon Tan static struct nios2_clocksource nios2_cs = { 994182de9eSLey Foon Tan .cs = { 1004182de9eSLey Foon Tan .name = "nios2-clksrc", 1014182de9eSLey Foon Tan .rating = 250, 1024182de9eSLey Foon Tan .read = nios2_timer_read, 1034182de9eSLey Foon Tan .mask = CLOCKSOURCE_MASK(32), 1044182de9eSLey Foon Tan .flags = CLOCK_SOURCE_IS_CONTINUOUS, 1054182de9eSLey Foon Tan }, 1064182de9eSLey Foon Tan }; 1074182de9eSLey Foon Tan 1084182de9eSLey Foon Tan cycles_t get_cycles(void) 1094182de9eSLey Foon Tan { 11065d1e3ddSGuenter Roeck /* Only read timer if it has been initialized */ 11165d1e3ddSGuenter Roeck if (nios2_cs.timer.base) 1124182de9eSLey Foon Tan return nios2_timer_read(&nios2_cs.cs); 11365d1e3ddSGuenter Roeck return 0; 1144182de9eSLey Foon Tan } 11505dee9c7SHerbert Xu EXPORT_SYMBOL(get_cycles); 1164182de9eSLey Foon Tan 1174182de9eSLey Foon Tan static void nios2_timer_start(struct nios2_timer *timer) 1184182de9eSLey Foon Tan { 1194182de9eSLey Foon Tan u16 ctrl; 1204182de9eSLey Foon Tan 1214182de9eSLey Foon Tan ctrl = timer_readw(timer, ALTERA_TIMER_CONTROL_REG); 1224182de9eSLey Foon Tan ctrl |= ALTERA_TIMER_CONTROL_START_MSK; 1234182de9eSLey Foon Tan timer_writew(timer, ctrl, ALTERA_TIMER_CONTROL_REG); 1244182de9eSLey Foon Tan } 1254182de9eSLey Foon Tan 1264182de9eSLey Foon Tan static void nios2_timer_stop(struct nios2_timer *timer) 1274182de9eSLey Foon Tan { 1284182de9eSLey Foon Tan u16 ctrl; 1294182de9eSLey Foon Tan 1304182de9eSLey Foon Tan ctrl = timer_readw(timer, ALTERA_TIMER_CONTROL_REG); 1314182de9eSLey Foon Tan ctrl |= ALTERA_TIMER_CONTROL_STOP_MSK; 1324182de9eSLey Foon Tan timer_writew(timer, ctrl, ALTERA_TIMER_CONTROL_REG); 1334182de9eSLey Foon Tan } 1344182de9eSLey Foon Tan 1354182de9eSLey Foon Tan static void nios2_timer_config(struct nios2_timer *timer, unsigned long period, 136549a14c1SViresh Kumar bool periodic) 1374182de9eSLey Foon Tan { 1384182de9eSLey Foon Tan u16 ctrl; 1394182de9eSLey Foon Tan 1404182de9eSLey Foon Tan /* The timer's actual period is one cycle greater than the value 1414182de9eSLey Foon Tan * stored in the period register. */ 1424182de9eSLey Foon Tan period--; 1434182de9eSLey Foon Tan 1444182de9eSLey Foon Tan ctrl = timer_readw(timer, ALTERA_TIMER_CONTROL_REG); 1454182de9eSLey Foon Tan /* stop counter */ 1464182de9eSLey Foon Tan timer_writew(timer, ctrl | ALTERA_TIMER_CONTROL_STOP_MSK, 1474182de9eSLey Foon Tan ALTERA_TIMER_CONTROL_REG); 1484182de9eSLey Foon Tan 1494182de9eSLey Foon Tan /* write new count */ 1504182de9eSLey Foon Tan timer_writew(timer, period, ALTERA_TIMER_PERIODL_REG); 1514182de9eSLey Foon Tan timer_writew(timer, period >> 16, ALTERA_TIMER_PERIODH_REG); 1524182de9eSLey Foon Tan 1534182de9eSLey Foon Tan ctrl |= ALTERA_TIMER_CONTROL_START_MSK | ALTERA_TIMER_CONTROL_ITO_MSK; 154549a14c1SViresh Kumar if (periodic) 1554182de9eSLey Foon Tan ctrl |= ALTERA_TIMER_CONTROL_CONT_MSK; 1564182de9eSLey Foon Tan else 1574182de9eSLey Foon Tan ctrl &= ~ALTERA_TIMER_CONTROL_CONT_MSK; 1584182de9eSLey Foon Tan timer_writew(timer, ctrl, ALTERA_TIMER_CONTROL_REG); 1594182de9eSLey Foon Tan } 1604182de9eSLey Foon Tan 1614182de9eSLey Foon Tan static int nios2_timer_set_next_event(unsigned long delta, 1624182de9eSLey Foon Tan struct clock_event_device *evt) 1634182de9eSLey Foon Tan { 1644182de9eSLey Foon Tan struct nios2_clockevent_dev *nios2_ced = to_nios2_clkevent(evt); 1654182de9eSLey Foon Tan 166549a14c1SViresh Kumar nios2_timer_config(&nios2_ced->timer, delta, false); 1674182de9eSLey Foon Tan 1684182de9eSLey Foon Tan return 0; 1694182de9eSLey Foon Tan } 1704182de9eSLey Foon Tan 171549a14c1SViresh Kumar static int nios2_timer_shutdown(struct clock_event_device *evt) 172549a14c1SViresh Kumar { 173549a14c1SViresh Kumar struct nios2_clockevent_dev *nios2_ced = to_nios2_clkevent(evt); 174549a14c1SViresh Kumar struct nios2_timer *timer = &nios2_ced->timer; 175549a14c1SViresh Kumar 176549a14c1SViresh Kumar nios2_timer_stop(timer); 177549a14c1SViresh Kumar return 0; 178549a14c1SViresh Kumar } 179549a14c1SViresh Kumar 180549a14c1SViresh Kumar static int nios2_timer_set_periodic(struct clock_event_device *evt) 1814182de9eSLey Foon Tan { 1824182de9eSLey Foon Tan unsigned long period; 1834182de9eSLey Foon Tan struct nios2_clockevent_dev *nios2_ced = to_nios2_clkevent(evt); 1844182de9eSLey Foon Tan struct nios2_timer *timer = &nios2_ced->timer; 1854182de9eSLey Foon Tan 1864182de9eSLey Foon Tan period = DIV_ROUND_UP(timer->freq, HZ); 187549a14c1SViresh Kumar nios2_timer_config(timer, period, true); 188549a14c1SViresh Kumar return 0; 1894182de9eSLey Foon Tan } 190549a14c1SViresh Kumar 191549a14c1SViresh Kumar static int nios2_timer_resume(struct clock_event_device *evt) 192549a14c1SViresh Kumar { 193549a14c1SViresh Kumar struct nios2_clockevent_dev *nios2_ced = to_nios2_clkevent(evt); 194549a14c1SViresh Kumar struct nios2_timer *timer = &nios2_ced->timer; 195549a14c1SViresh Kumar 196549a14c1SViresh Kumar nios2_timer_start(timer); 197549a14c1SViresh Kumar return 0; 1984182de9eSLey Foon Tan } 1994182de9eSLey Foon Tan 2004182de9eSLey Foon Tan irqreturn_t timer_interrupt(int irq, void *dev_id) 2014182de9eSLey Foon Tan { 2024182de9eSLey Foon Tan struct clock_event_device *evt = (struct clock_event_device *) dev_id; 2034182de9eSLey Foon Tan struct nios2_clockevent_dev *nios2_ced = to_nios2_clkevent(evt); 2044182de9eSLey Foon Tan 2054182de9eSLey Foon Tan /* Clear the interrupt condition */ 2064182de9eSLey Foon Tan timer_writew(&nios2_ced->timer, 0, ALTERA_TIMER_STATUS_REG); 2074182de9eSLey Foon Tan evt->event_handler(evt); 2084182de9eSLey Foon Tan 2094182de9eSLey Foon Tan return IRQ_HANDLED; 2104182de9eSLey Foon Tan } 2114182de9eSLey Foon Tan 212dd1364a7SDaniel Lezcano static int __init nios2_timer_get_base_and_freq(struct device_node *np, 2134182de9eSLey Foon Tan void __iomem **base, u32 *freq) 2144182de9eSLey Foon Tan { 2154182de9eSLey Foon Tan *base = of_iomap(np, 0); 216dd1364a7SDaniel Lezcano if (!*base) { 217dd1364a7SDaniel Lezcano pr_crit("Unable to map reg for %s\n", np->name); 218dd1364a7SDaniel Lezcano return -ENXIO; 219dd1364a7SDaniel Lezcano } 2204182de9eSLey Foon Tan 221dd1364a7SDaniel Lezcano if (of_property_read_u32(np, "clock-frequency", freq)) { 222dd1364a7SDaniel Lezcano pr_crit("Unable to get %s clock frequency\n", np->name); 223dd1364a7SDaniel Lezcano return -EINVAL; 224dd1364a7SDaniel Lezcano } 225dd1364a7SDaniel Lezcano 226dd1364a7SDaniel Lezcano return 0; 2274182de9eSLey Foon Tan } 2284182de9eSLey Foon Tan 2294182de9eSLey Foon Tan static struct nios2_clockevent_dev nios2_ce = { 2304182de9eSLey Foon Tan .ced = { 2314182de9eSLey Foon Tan .name = "nios2-clkevent", 2324182de9eSLey Foon Tan .features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT, 2334182de9eSLey Foon Tan .rating = 250, 2344182de9eSLey Foon Tan .shift = 32, 2354182de9eSLey Foon Tan .set_next_event = nios2_timer_set_next_event, 236549a14c1SViresh Kumar .set_state_shutdown = nios2_timer_shutdown, 237549a14c1SViresh Kumar .set_state_periodic = nios2_timer_set_periodic, 238549a14c1SViresh Kumar .set_state_oneshot = nios2_timer_shutdown, 239549a14c1SViresh Kumar .tick_resume = nios2_timer_resume, 2404182de9eSLey Foon Tan }, 2414182de9eSLey Foon Tan }; 2424182de9eSLey Foon Tan 243dd1364a7SDaniel Lezcano static __init int nios2_clockevent_init(struct device_node *timer) 2444182de9eSLey Foon Tan { 2454182de9eSLey Foon Tan void __iomem *iobase; 2464182de9eSLey Foon Tan u32 freq; 247dd1364a7SDaniel Lezcano int irq, ret; 2484182de9eSLey Foon Tan 249dd1364a7SDaniel Lezcano ret = nios2_timer_get_base_and_freq(timer, &iobase, &freq); 250dd1364a7SDaniel Lezcano if (ret) 251dd1364a7SDaniel Lezcano return ret; 2524182de9eSLey Foon Tan 2534182de9eSLey Foon Tan irq = irq_of_parse_and_map(timer, 0); 254dd1364a7SDaniel Lezcano if (!irq) { 255dd1364a7SDaniel Lezcano pr_crit("Unable to parse timer irq\n"); 256dd1364a7SDaniel Lezcano return -EINVAL; 257dd1364a7SDaniel Lezcano } 2584182de9eSLey Foon Tan 2594182de9eSLey Foon Tan nios2_ce.timer.base = iobase; 2604182de9eSLey Foon Tan nios2_ce.timer.freq = freq; 2614182de9eSLey Foon Tan 2624182de9eSLey Foon Tan nios2_ce.ced.cpumask = cpumask_of(0); 2634182de9eSLey Foon Tan nios2_ce.ced.irq = irq; 2644182de9eSLey Foon Tan 2654182de9eSLey Foon Tan nios2_timer_stop(&nios2_ce.timer); 2664182de9eSLey Foon Tan /* clear pending interrupt */ 2674182de9eSLey Foon Tan timer_writew(&nios2_ce.timer, 0, ALTERA_TIMER_STATUS_REG); 2684182de9eSLey Foon Tan 269dd1364a7SDaniel Lezcano ret = request_irq(irq, timer_interrupt, IRQF_TIMER, timer->name, 270dd1364a7SDaniel Lezcano &nios2_ce.ced); 271dd1364a7SDaniel Lezcano if (ret) { 272dd1364a7SDaniel Lezcano pr_crit("Unable to setup timer irq\n"); 273dd1364a7SDaniel Lezcano return ret; 2744182de9eSLey Foon Tan } 2754182de9eSLey Foon Tan 276dd1364a7SDaniel Lezcano clockevents_config_and_register(&nios2_ce.ced, freq, 1, ULONG_MAX); 277dd1364a7SDaniel Lezcano 278dd1364a7SDaniel Lezcano return 0; 279dd1364a7SDaniel Lezcano } 280dd1364a7SDaniel Lezcano 281dd1364a7SDaniel Lezcano static __init int nios2_clocksource_init(struct device_node *timer) 2824182de9eSLey Foon Tan { 2834182de9eSLey Foon Tan unsigned int ctrl; 2844182de9eSLey Foon Tan void __iomem *iobase; 2854182de9eSLey Foon Tan u32 freq; 286dd1364a7SDaniel Lezcano int ret; 2874182de9eSLey Foon Tan 288dd1364a7SDaniel Lezcano ret = nios2_timer_get_base_and_freq(timer, &iobase, &freq); 289dd1364a7SDaniel Lezcano if (ret) 290dd1364a7SDaniel Lezcano return ret; 2914182de9eSLey Foon Tan 2924182de9eSLey Foon Tan nios2_cs.timer.base = iobase; 2934182de9eSLey Foon Tan nios2_cs.timer.freq = freq; 2944182de9eSLey Foon Tan 295dd1364a7SDaniel Lezcano ret = clocksource_register_hz(&nios2_cs.cs, freq); 296dd1364a7SDaniel Lezcano if (ret) 297dd1364a7SDaniel Lezcano return ret; 2984182de9eSLey Foon Tan 2994182de9eSLey Foon Tan timer_writew(&nios2_cs.timer, USHRT_MAX, ALTERA_TIMER_PERIODL_REG); 3004182de9eSLey Foon Tan timer_writew(&nios2_cs.timer, USHRT_MAX, ALTERA_TIMER_PERIODH_REG); 3014182de9eSLey Foon Tan 3024182de9eSLey Foon Tan /* interrupt disable + continuous + start */ 3034182de9eSLey Foon Tan ctrl = ALTERA_TIMER_CONTROL_CONT_MSK | ALTERA_TIMER_CONTROL_START_MSK; 3044182de9eSLey Foon Tan timer_writew(&nios2_cs.timer, ctrl, ALTERA_TIMER_CONTROL_REG); 3054182de9eSLey Foon Tan 3064182de9eSLey Foon Tan /* Calibrate the delay loop directly */ 3074182de9eSLey Foon Tan lpj_fine = freq / HZ; 308dd1364a7SDaniel Lezcano 309dd1364a7SDaniel Lezcano return 0; 3104182de9eSLey Foon Tan } 3114182de9eSLey Foon Tan 3124182de9eSLey Foon Tan /* 3134182de9eSLey Foon Tan * The first timer instance will use as a clockevent. If there are two or 3144182de9eSLey Foon Tan * more instances, the second one gets used as clocksource and all 3154182de9eSLey Foon Tan * others are unused. 3164182de9eSLey Foon Tan */ 317dd1364a7SDaniel Lezcano static int __init nios2_time_init(struct device_node *timer) 3184182de9eSLey Foon Tan { 3194182de9eSLey Foon Tan static int num_called; 320dd1364a7SDaniel Lezcano int ret; 3214182de9eSLey Foon Tan 3224182de9eSLey Foon Tan switch (num_called) { 3234182de9eSLey Foon Tan case 0: 324dd1364a7SDaniel Lezcano ret = nios2_clockevent_init(timer); 3254182de9eSLey Foon Tan break; 3264182de9eSLey Foon Tan case 1: 327dd1364a7SDaniel Lezcano ret = nios2_clocksource_init(timer); 3284182de9eSLey Foon Tan break; 3294182de9eSLey Foon Tan default: 330069013a9SArnd Bergmann ret = 0; 3314182de9eSLey Foon Tan break; 3324182de9eSLey Foon Tan } 3334182de9eSLey Foon Tan 3344182de9eSLey Foon Tan num_called++; 335dd1364a7SDaniel Lezcano 336dd1364a7SDaniel Lezcano return ret; 3374182de9eSLey Foon Tan } 3384182de9eSLey Foon Tan 3393d9644efSBaolin Wang void read_persistent_clock64(struct timespec64 *ts) 3404182de9eSLey Foon Tan { 3413d9644efSBaolin Wang ts->tv_sec = mktime64(2007, 1, 1, 0, 0, 0); 3424182de9eSLey Foon Tan ts->tv_nsec = 0; 3434182de9eSLey Foon Tan } 3444182de9eSLey Foon Tan 3454182de9eSLey Foon Tan void __init time_init(void) 3464182de9eSLey Foon Tan { 347a8955cc3SLey Foon Tan struct device_node *np; 348a8955cc3SLey Foon Tan int count = 0; 349a8955cc3SLey Foon Tan 350a8955cc3SLey Foon Tan for_each_compatible_node(np, NULL, ALTR_TIMER_COMPATIBLE) 351a8955cc3SLey Foon Tan count++; 352a8955cc3SLey Foon Tan 353a8955cc3SLey Foon Tan if (count < 2) 354a8955cc3SLey Foon Tan panic("%d timer is found, it needs 2 timers in system\n", count); 355a8955cc3SLey Foon Tan 356ba5d08c0SDaniel Lezcano timer_probe(); 3574182de9eSLey Foon Tan } 3584182de9eSLey Foon Tan 35917273395SDaniel Lezcano TIMER_OF_DECLARE(nios2_timer, ALTR_TIMER_COMPATIBLE, nios2_time_init); 360