1 /* 2 * Marvell Orion SoC timer handling. 3 * 4 * Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com> 5 * 6 * This file is licensed under the terms of the GNU General Public 7 * License version 2. This program is licensed "as is" without any 8 * warranty of any kind, whether express or implied. 9 * 10 * Timer 0 is used as free-running clocksource, while timer 1 is 11 * used as clock_event_device. 12 */ 13 14 #include <linux/kernel.h> 15 #include <linux/bitops.h> 16 #include <linux/clk.h> 17 #include <linux/clockchips.h> 18 #include <linux/delay.h> 19 #include <linux/interrupt.h> 20 #include <linux/of_address.h> 21 #include <linux/of_irq.h> 22 #include <linux/spinlock.h> 23 #include <linux/sched_clock.h> 24 25 #define TIMER_CTRL 0x00 26 #define TIMER0_EN BIT(0) 27 #define TIMER0_RELOAD_EN BIT(1) 28 #define TIMER1_EN BIT(2) 29 #define TIMER1_RELOAD_EN BIT(3) 30 #define TIMER0_RELOAD 0x10 31 #define TIMER0_VAL 0x14 32 #define TIMER1_RELOAD 0x18 33 #define TIMER1_VAL 0x1c 34 35 #define ORION_ONESHOT_MIN 1 36 #define ORION_ONESHOT_MAX 0xfffffffe 37 38 static void __iomem *timer_base; 39 40 static unsigned long notrace orion_read_timer(void) 41 { 42 return ~readl(timer_base + TIMER0_VAL); 43 } 44 45 static struct delay_timer orion_delay_timer = { 46 .read_current_timer = orion_read_timer, 47 }; 48 49 static void orion_delay_timer_init(unsigned long rate) 50 { 51 orion_delay_timer.freq = rate; 52 register_current_timer_delay(&orion_delay_timer); 53 } 54 55 /* 56 * Free-running clocksource handling. 57 */ 58 static u64 notrace orion_read_sched_clock(void) 59 { 60 return ~readl(timer_base + TIMER0_VAL); 61 } 62 63 /* 64 * Clockevent handling. 65 */ 66 static u32 ticks_per_jiffy; 67 68 static int orion_clkevt_next_event(unsigned long delta, 69 struct clock_event_device *dev) 70 { 71 /* setup and enable one-shot timer */ 72 writel(delta, timer_base + TIMER1_VAL); 73 atomic_io_modify(timer_base + TIMER_CTRL, 74 TIMER1_RELOAD_EN | TIMER1_EN, TIMER1_EN); 75 76 return 0; 77 } 78 79 static int orion_clkevt_shutdown(struct clock_event_device *dev) 80 { 81 /* disable timer */ 82 atomic_io_modify(timer_base + TIMER_CTRL, 83 TIMER1_RELOAD_EN | TIMER1_EN, 0); 84 return 0; 85 } 86 87 static int orion_clkevt_set_periodic(struct clock_event_device *dev) 88 { 89 /* setup and enable periodic timer at 1/HZ intervals */ 90 writel(ticks_per_jiffy - 1, timer_base + TIMER1_RELOAD); 91 writel(ticks_per_jiffy - 1, timer_base + TIMER1_VAL); 92 atomic_io_modify(timer_base + TIMER_CTRL, 93 TIMER1_RELOAD_EN | TIMER1_EN, 94 TIMER1_RELOAD_EN | TIMER1_EN); 95 return 0; 96 } 97 98 static struct clock_event_device orion_clkevt = { 99 .name = "orion_event", 100 .features = CLOCK_EVT_FEAT_ONESHOT | 101 CLOCK_EVT_FEAT_PERIODIC, 102 .shift = 32, 103 .rating = 300, 104 .set_next_event = orion_clkevt_next_event, 105 .set_state_shutdown = orion_clkevt_shutdown, 106 .set_state_periodic = orion_clkevt_set_periodic, 107 .set_state_oneshot = orion_clkevt_shutdown, 108 .tick_resume = orion_clkevt_shutdown, 109 }; 110 111 static irqreturn_t orion_clkevt_irq_handler(int irq, void *dev_id) 112 { 113 orion_clkevt.event_handler(&orion_clkevt); 114 return IRQ_HANDLED; 115 } 116 117 static int __init orion_timer_init(struct device_node *np) 118 { 119 unsigned long rate; 120 struct clk *clk; 121 int irq, ret; 122 123 /* timer registers are shared with watchdog timer */ 124 timer_base = of_iomap(np, 0); 125 if (!timer_base) { 126 pr_err("%pOFn: unable to map resource\n", np); 127 return -ENXIO; 128 } 129 130 clk = of_clk_get(np, 0); 131 if (IS_ERR(clk)) { 132 pr_err("%pOFn: unable to get clk\n", np); 133 return PTR_ERR(clk); 134 } 135 136 ret = clk_prepare_enable(clk); 137 if (ret) { 138 pr_err("Failed to prepare clock\n"); 139 return ret; 140 } 141 142 /* we are only interested in timer1 irq */ 143 irq = irq_of_parse_and_map(np, 1); 144 if (irq <= 0) { 145 pr_err("%pOFn: unable to parse timer1 irq\n", np); 146 return -EINVAL; 147 } 148 149 rate = clk_get_rate(clk); 150 151 /* setup timer0 as free-running clocksource */ 152 writel(~0, timer_base + TIMER0_VAL); 153 writel(~0, timer_base + TIMER0_RELOAD); 154 atomic_io_modify(timer_base + TIMER_CTRL, 155 TIMER0_RELOAD_EN | TIMER0_EN, 156 TIMER0_RELOAD_EN | TIMER0_EN); 157 158 ret = clocksource_mmio_init(timer_base + TIMER0_VAL, 159 "orion_clocksource", rate, 300, 32, 160 clocksource_mmio_readl_down); 161 if (ret) { 162 pr_err("Failed to initialize mmio timer\n"); 163 return ret; 164 } 165 166 sched_clock_register(orion_read_sched_clock, 32, rate); 167 168 /* setup timer1 as clockevent timer */ 169 ret = request_irq(irq, orion_clkevt_irq_handler, IRQF_TIMER, 170 "orion_event", NULL); 171 if (ret) { 172 pr_err("%pOFn: unable to setup irq\n", np); 173 return ret; 174 } 175 176 ticks_per_jiffy = (clk_get_rate(clk) + HZ/2) / HZ; 177 orion_clkevt.cpumask = cpumask_of(0); 178 orion_clkevt.irq = irq; 179 clockevents_config_and_register(&orion_clkevt, rate, 180 ORION_ONESHOT_MIN, ORION_ONESHOT_MAX); 181 182 183 orion_delay_timer_init(rate); 184 185 return 0; 186 } 187 TIMER_OF_DECLARE(orion_timer, "marvell,orion-timer", orion_timer_init); 188