| 1 | |
| 2 | * Copyright (C) 2007-2013 Michal Simek <[email protected]>
|
| 3 | * Copyright (C) 2012-2013 Xilinx, Inc.
|
| 4 | * Copyright (C) 2007-2009 PetaLogix
|
| 5 | * Copyright (C) 2006 Atmark Techno, Inc.
|
| 6 | *
|
| 7 | * This file is subject to the terms and conditions of the GNU General Public
|
| 8 | * License. See the file "COPYING" in the main directory of this archive
|
| 9 | * for more details.
|
| 10 |
|
| 11 |
|
| 12 | #include <linux/interrupt.h>
|
| 13 | #include <linux/delay.h>
|
| 14 | #include <linux/sched.h>
|
| 15 | #include <linux/sched/clock.h>
|
| 16 | #include <linux/sched_clock.h>
|
| 17 | #include <linux/clk.h>
|
| 18 | #include <linux/clockchips.h>
|
| 19 | #include <linux/of_address.h>
|
| 20 | #include <linux/of_irq.h>
|
| 21 | #include <linux/timecounter.h>
|
| 22 | #include <asm/cpuinfo.h>
|
| 23 |
|
| 24 | static void __iomem *timer_baseaddr;
|
| 25 |
|
| 26 | static unsigned int freq_div_hz;
|
| 27 | static unsigned int timer_clock_freq;
|
| 28 |
|
| 29 | #define TCSR0 (0x00)
|
| 30 | #define TLR0 (0x04)
|
| 31 | #define TCR0 (0x08)
|
| 32 | #define TCSR1 (0x10)
|
| 33 | #define TLR1 (0x14)
|
| 34 | #define TCR1 (0x18)
|
| 35 |
|
| 36 | #define TCSR_MDT (1<<0)
|
| 37 | #define TCSR_UDT (1<<1)
|
| 38 | #define TCSR_GENT (1<<2)
|
| 39 | #define TCSR_CAPT (1<<3)
|
| 40 | #define TCSR_ARHT (1<<4)
|
| 41 | #define TCSR_LOAD (1<<5)
|
| 42 | #define TCSR_ENIT (1<<6)
|
| 43 | #define TCSR_ENT (1<<7)
|
| 44 | #define TCSR_TINT (1<<8)
|
| 45 | #define TCSR_PWMA (1<<9)
|
| 46 | #define TCSR_ENALL (1<<10)
|
| 47 |
|
| 48 | static unsigned int (*read_fn)(void __iomem *);
|
| 49 | static void (*write_fn)(u32, void __iomem *);
|
| 50 |
|
| 51 | static void timer_write32(u32 val, void __iomem *addr)
|
| 52 | {
|
| 53 | iowrite32(val, addr);
|
| 54 | }
|
| 55 |
|
| 56 | static unsigned int timer_read32(void __iomem *addr)
|
| 57 | {
|
| 58 | return ioread32(addr);
|
| 59 | }
|
| 60 |
|
| 61 | static void timer_write32_be(u32 val, void __iomem *addr)
|
| 62 | {
|
| 63 | iowrite32be(val, addr);
|
| 64 | }
|
| 65 |
|
| 66 | static unsigned int timer_read32_be(void __iomem *addr)
|
| 67 | {
|
| 68 | return ioread32be(addr);
|
| 69 | }
|
| 70 |
|
| 71 | static inline void xilinx_timer0_stop(void)
|
| 72 | {
|
| 73 | write_fn(read_fn(timer_baseaddr + TCSR0) & ~TCSR_ENT,
|
| 74 | timer_baseaddr + TCSR0);
|
| 75 | }
|
| 76 |
|
| 77 | static inline void xilinx_timer0_start_periodic(unsigned long load_val)
|
| 78 | {
|
| 79 | if (!load_val)
|
| 80 | load_val = 1;
|
| 81 |
|
| 82 | write_fn(load_val, timer_baseaddr + TLR0);
|
| 83 |
|
| 84 |
|
| 85 | write_fn(TCSR_LOAD, timer_baseaddr + TCSR0);
|
| 86 |
|
| 87 | |
| 88 | * !ENALL - don't enable 'em all
|
| 89 | * !PWMA - disable pwm
|
| 90 | * TINT - clear interrupt status
|
| 91 | * ENT- enable timer itself
|
| 92 | * ENIT - enable interrupt
|
| 93 | * !LOAD - clear the bit to let go
|
| 94 | * ARHT - auto reload
|
| 95 | * !CAPT - no external trigger
|
| 96 | * !GENT - no external signal
|
| 97 | * UDT - set the timer as down counter
|
| 98 | * !MDT0 - generate mode
|
| 99 |
|
| 100 | write_fn(TCSR_TINT|TCSR_ENIT|TCSR_ENT|TCSR_ARHT|TCSR_UDT,
|
| 101 | timer_baseaddr + TCSR0);
|
| 102 | }
|
| 103 |
|
| 104 | static inline void xilinx_timer0_start_oneshot(unsigned long load_val)
|
| 105 | {
|
| 106 | if (!load_val)
|
| 107 | load_val = 1;
|
| 108 |
|
| 109 | write_fn(load_val, timer_baseaddr + TLR0);
|
| 110 |
|
| 111 |
|
| 112 | write_fn(TCSR_LOAD, timer_baseaddr + TCSR0);
|
| 113 |
|
| 114 | write_fn(TCSR_TINT|TCSR_ENIT|TCSR_ENT|TCSR_ARHT|TCSR_UDT,
|
| 115 | timer_baseaddr + TCSR0);
|
| 116 | }
|
| 117 |
|
| 118 | static int xilinx_timer_set_next_event(unsigned long delta,
|
| 119 | struct clock_event_device *dev)
|
| 120 | {
|
| 121 | pr_debug("%s: next event, delta %x\n", __func__, (u32)delta);
|
| 122 | xilinx_timer0_start_oneshot(delta);
|
| 123 | return 0;
|
| 124 | }
|
| 125 |
|
| 126 | static int xilinx_timer_shutdown(struct clock_event_device *evt)
|
| 127 | {
|
| 128 | pr_info("%s\n", __func__);
|
| 129 | xilinx_timer0_stop();
|
| 130 | return 0;
|
| 131 | }
|
| 132 |
|
| 133 | static int xilinx_timer_set_periodic(struct clock_event_device *evt)
|
| 134 | {
|
| 135 | pr_info("%s\n", __func__);
|
| 136 | xilinx_timer0_start_periodic(freq_div_hz);
|
| 137 | return 0;
|
| 138 | }
|
| 139 |
|
| 140 | static struct clock_event_device clockevent_xilinx_timer = {
|
| 141 | .name = "xilinx_clockevent",
|
| 142 | .features = CLOCK_EVT_FEAT_ONESHOT |
|
| 143 | CLOCK_EVT_FEAT_PERIODIC,
|
| 144 | .shift = 8,
|
| 145 | .rating = 300,
|
| 146 | .set_next_event = xilinx_timer_set_next_event,
|
| 147 | .set_state_shutdown = xilinx_timer_shutdown,
|
| 148 | .set_state_periodic = xilinx_timer_set_periodic,
|
| 149 | };
|
| 150 |
|
| 151 | static inline void timer_ack(void)
|
| 152 | {
|
| 153 | write_fn(read_fn(timer_baseaddr + TCSR0), timer_baseaddr + TCSR0);
|
| 154 | }
|
| 155 |
|
| 156 | static irqreturn_t timer_interrupt(int irq, void *dev_id)
|
| 157 | {
|
| 158 | struct clock_event_device *evt = &clockevent_xilinx_timer;
|
| 159 | timer_ack();
|
| 160 | evt->event_handler(evt);
|
| 161 | return IRQ_HANDLED;
|
| 162 | }
|
| 163 |
|
| 164 | static __init int xilinx_clockevent_init(void)
|
| 165 | {
|
| 166 | clockevent_xilinx_timer.mult =
|
| 167 | div_sc(timer_clock_freq, NSEC_PER_SEC,
|
| 168 | clockevent_xilinx_timer.shift);
|
| 169 | clockevent_xilinx_timer.max_delta_ns =
|
| 170 | clockevent_delta2ns((u32)~0, &clockevent_xilinx_timer);
|
| 171 | clockevent_xilinx_timer.max_delta_ticks = (u32)~0;
|
| 172 | clockevent_xilinx_timer.min_delta_ns =
|
| 173 | clockevent_delta2ns(1, &clockevent_xilinx_timer);
|
| 174 | clockevent_xilinx_timer.min_delta_ticks = 1;
|
| 175 | clockevent_xilinx_timer.cpumask = cpumask_of(0);
|
| 176 | clockevents_register_device(&clockevent_xilinx_timer);
|
| 177 |
|
| 178 | return 0;
|
| 179 | }
|
| 180 |
|
| 181 | static u64 xilinx_clock_read(void)
|
| 182 | {
|
| 183 | return read_fn(timer_baseaddr + TCR1);
|
| 184 | }
|
| 185 |
|
| 186 | static u64 xilinx_read(struct clocksource *cs)
|
| 187 | {
|
| 188 |
|
| 189 | return (u64)xilinx_clock_read();
|
| 190 | }
|
| 191 |
|
| 192 | static struct timecounter xilinx_tc = {
|
| 193 | .cc = NULL,
|
| 194 | };
|
| 195 |
|
| 196 | static u64 xilinx_cc_read(struct cyclecounter *cc)
|
| 197 | {
|
| 198 | return xilinx_read(NULL);
|
| 199 | }
|
| 200 |
|
| 201 | static struct cyclecounter xilinx_cc = {
|
| 202 | .read = xilinx_cc_read,
|
| 203 | .mask = CLOCKSOURCE_MASK(32),
|
| 204 | .shift = 8,
|
| 205 | };
|
| 206 |
|
| 207 | static int __init init_xilinx_timecounter(void)
|
| 208 | {
|
| 209 | xilinx_cc.mult = div_sc(timer_clock_freq, NSEC_PER_SEC,
|
| 210 | xilinx_cc.shift);
|
| 211 |
|
| 212 | timecounter_init(&xilinx_tc, &xilinx_cc, sched_clock());
|
| 213 |
|
| 214 | return 0;
|
| 215 | }
|
| 216 |
|
| 217 | static struct clocksource clocksource_microblaze = {
|
| 218 | .name = "xilinx_clocksource",
|
| 219 | .rating = 300,
|
| 220 | .read = xilinx_read,
|
| 221 | .mask = CLOCKSOURCE_MASK(32),
|
| 222 | .flags = CLOCK_SOURCE_IS_CONTINUOUS,
|
| 223 | };
|
| 224 |
|
| 225 | static int __init xilinx_clocksource_init(void)
|
| 226 | {
|
| 227 | int ret;
|
| 228 |
|
| 229 | ret = clocksource_register_hz(&clocksource_microblaze,
|
| 230 | timer_clock_freq);
|
| 231 | if (ret) {
|
| 232 | pr_err("failed to register clocksource");
|
| 233 | return ret;
|
| 234 | }
|
| 235 |
|
| 236 |
|
| 237 | write_fn(read_fn(timer_baseaddr + TCSR1) & ~TCSR_ENT,
|
| 238 | timer_baseaddr + TCSR1);
|
| 239 |
|
| 240 | write_fn(TCSR_TINT|TCSR_ENT|TCSR_ARHT, timer_baseaddr + TCSR1);
|
| 241 |
|
| 242 |
|
| 243 | return init_xilinx_timecounter();
|
| 244 | }
|
| 245 |
|
| 246 | static int __init xilinx_timer_init(struct device_node *timer)
|
| 247 | {
|
| 248 | struct clk *clk;
|
| 249 | static int initialized;
|
| 250 | u32 irq;
|
| 251 | u32 timer_num = 1;
|
| 252 | int ret;
|
| 253 |
|
| 254 |
|
| 255 | if (of_property_present(timer, "#pwm-cells"))
|
| 256 | return 0;
|
| 257 |
|
| 258 | if (initialized)
|
| 259 | return -EINVAL;
|
| 260 |
|
| 261 | initialized = 1;
|
| 262 |
|
| 263 | timer_baseaddr = of_iomap(timer, 0);
|
| 264 | if (!timer_baseaddr) {
|
| 265 | pr_err("ERROR: invalid timer base address\n");
|
| 266 | return -ENXIO;
|
| 267 | }
|
| 268 |
|
| 269 | write_fn = timer_write32;
|
| 270 | read_fn = timer_read32;
|
| 271 |
|
| 272 | write_fn(TCSR_MDT, timer_baseaddr + TCSR0);
|
| 273 | if (!(read_fn(timer_baseaddr + TCSR0) & TCSR_MDT)) {
|
| 274 | write_fn = timer_write32_be;
|
| 275 | read_fn = timer_read32_be;
|
| 276 | }
|
| 277 |
|
| 278 | irq = irq_of_parse_and_map(timer, 0);
|
| 279 | if (irq <= 0) {
|
| 280 | pr_err("Failed to parse and map irq");
|
| 281 | return -EINVAL;
|
| 282 | }
|
| 283 |
|
| 284 | of_property_read_u32(timer, "xlnx,one-timer-only", &timer_num);
|
| 285 | if (timer_num) {
|
| 286 | pr_err("Please enable two timers in HW\n");
|
| 287 | return -EINVAL;
|
| 288 | }
|
| 289 |
|
| 290 | pr_info("%pOF: irq=%d\n", timer, irq);
|
| 291 |
|
| 292 | clk = of_clk_get(timer, 0);
|
| 293 | if (IS_ERR(clk)) {
|
| 294 | pr_err("ERROR: timer CCF input clock not found\n");
|
| 295 |
|
| 296 | of_property_read_u32(timer, "clock-frequency",
|
| 297 | &timer_clock_freq);
|
| 298 | } else {
|
| 299 | timer_clock_freq = clk_get_rate(clk);
|
| 300 | }
|
| 301 |
|
| 302 | if (!timer_clock_freq) {
|
| 303 | pr_err("ERROR: Using CPU clock frequency\n");
|
| 304 | timer_clock_freq = cpuinfo.cpu_clock_freq;
|
| 305 | }
|
| 306 |
|
| 307 | freq_div_hz = timer_clock_freq / HZ;
|
| 308 |
|
| 309 | ret = request_irq(irq, timer_interrupt, IRQF_TIMER, "timer",
|
| 310 | &clockevent_xilinx_timer);
|
| 311 | if (ret) {
|
| 312 | pr_err("Failed to setup IRQ");
|
| 313 | return ret;
|
| 314 | }
|
| 315 |
|
| 316 | ret = xilinx_clocksource_init();
|
| 317 | if (ret)
|
| 318 | return ret;
|
| 319 |
|
| 320 | ret = xilinx_clockevent_init();
|
| 321 | if (ret)
|
| 322 | return ret;
|
| 323 |
|
| 324 | sched_clock_register(xilinx_clock_read, 32, timer_clock_freq);
|
| 325 |
|
| 326 | return 0;
|
| 327 | }
|
| 328 |
|
| 329 | TIMER_OF_DECLARE(xilinx_timer, "xlnx,xps-timer-1.00.a",
|
| 330 | xilinx_timer_init);
|