timer-rda.c (4749B)
1// SPDX-License-Identifier: GPL-2.0+ 2/* 3 * RDA8810PL SoC timer driver 4 * 5 * Copyright RDA Microelectronics Company Limited 6 * Copyright (c) 2017 Andreas Färber 7 * Copyright (c) 2018 Manivannan Sadhasivam 8 * 9 * RDA8810PL has two independent timers: OSTIMER (56 bit) and HWTIMER (64 bit). 10 * Each timer provides optional interrupt support. In this driver, OSTIMER is 11 * used for clockevents and HWTIMER is used for clocksource. 12 */ 13 14#include <linux/init.h> 15#include <linux/interrupt.h> 16 17#include "timer-of.h" 18 19#define RDA_OSTIMER_LOADVAL_L 0x000 20#define RDA_OSTIMER_CTRL 0x004 21#define RDA_HWTIMER_LOCKVAL_L 0x024 22#define RDA_HWTIMER_LOCKVAL_H 0x028 23#define RDA_TIMER_IRQ_MASK_SET 0x02c 24#define RDA_TIMER_IRQ_MASK_CLR 0x030 25#define RDA_TIMER_IRQ_CLR 0x034 26 27#define RDA_OSTIMER_CTRL_ENABLE BIT(24) 28#define RDA_OSTIMER_CTRL_REPEAT BIT(28) 29#define RDA_OSTIMER_CTRL_LOAD BIT(30) 30 31#define RDA_TIMER_IRQ_MASK_OSTIMER BIT(0) 32 33#define RDA_TIMER_IRQ_CLR_OSTIMER BIT(0) 34 35static int rda_ostimer_start(void __iomem *base, bool periodic, u64 cycles) 36{ 37 u32 ctrl, load_l; 38 39 load_l = (u32)cycles; 40 ctrl = ((cycles >> 32) & 0xffffff); 41 ctrl |= RDA_OSTIMER_CTRL_LOAD | RDA_OSTIMER_CTRL_ENABLE; 42 if (periodic) 43 ctrl |= RDA_OSTIMER_CTRL_REPEAT; 44 45 /* Enable ostimer interrupt first */ 46 writel_relaxed(RDA_TIMER_IRQ_MASK_OSTIMER, 47 base + RDA_TIMER_IRQ_MASK_SET); 48 49 /* Write low 32 bits first, high 24 bits are with ctrl */ 50 writel_relaxed(load_l, base + RDA_OSTIMER_LOADVAL_L); 51 writel_relaxed(ctrl, base + RDA_OSTIMER_CTRL); 52 53 return 0; 54} 55 56static int rda_ostimer_stop(void __iomem *base) 57{ 58 /* Disable ostimer interrupt first */ 59 writel_relaxed(RDA_TIMER_IRQ_MASK_OSTIMER, 60 base + RDA_TIMER_IRQ_MASK_CLR); 61 62 writel_relaxed(0, base + RDA_OSTIMER_CTRL); 63 64 return 0; 65} 66 67static int rda_ostimer_set_state_shutdown(struct clock_event_device *evt) 68{ 69 struct timer_of *to = to_timer_of(evt); 70 71 rda_ostimer_stop(timer_of_base(to)); 72 73 return 0; 74} 75 76static int rda_ostimer_set_state_oneshot(struct clock_event_device *evt) 77{ 78 struct timer_of *to = to_timer_of(evt); 79 80 rda_ostimer_stop(timer_of_base(to)); 81 82 return 0; 83} 84 85static int rda_ostimer_set_state_periodic(struct clock_event_device *evt) 86{ 87 struct timer_of *to = to_timer_of(evt); 88 unsigned long cycles_per_jiffy; 89 90 rda_ostimer_stop(timer_of_base(to)); 91 92 cycles_per_jiffy = ((unsigned long long)NSEC_PER_SEC / HZ * 93 evt->mult) >> evt->shift; 94 rda_ostimer_start(timer_of_base(to), true, cycles_per_jiffy); 95 96 return 0; 97} 98 99static int rda_ostimer_tick_resume(struct clock_event_device *evt) 100{ 101 return 0; 102} 103 104static int rda_ostimer_set_next_event(unsigned long evt, 105 struct clock_event_device *ev) 106{ 107 struct timer_of *to = to_timer_of(ev); 108 109 rda_ostimer_start(timer_of_base(to), false, evt); 110 111 return 0; 112} 113 114static irqreturn_t rda_ostimer_interrupt(int irq, void *dev_id) 115{ 116 struct clock_event_device *evt = dev_id; 117 struct timer_of *to = to_timer_of(evt); 118 119 /* clear timer int */ 120 writel_relaxed(RDA_TIMER_IRQ_CLR_OSTIMER, 121 timer_of_base(to) + RDA_TIMER_IRQ_CLR); 122 123 if (evt->event_handler) 124 evt->event_handler(evt); 125 126 return IRQ_HANDLED; 127} 128 129static struct timer_of rda_ostimer_of = { 130 .flags = TIMER_OF_IRQ | TIMER_OF_BASE, 131 132 .clkevt = { 133 .name = "rda-ostimer", 134 .rating = 250, 135 .features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT | 136 CLOCK_EVT_FEAT_DYNIRQ, 137 .set_state_shutdown = rda_ostimer_set_state_shutdown, 138 .set_state_oneshot = rda_ostimer_set_state_oneshot, 139 .set_state_periodic = rda_ostimer_set_state_periodic, 140 .tick_resume = rda_ostimer_tick_resume, 141 .set_next_event = rda_ostimer_set_next_event, 142 }, 143 144 .of_base = { 145 .name = "rda-timer", 146 .index = 0, 147 }, 148 149 .of_irq = { 150 .name = "ostimer", 151 .handler = rda_ostimer_interrupt, 152 .flags = IRQF_TIMER, 153 }, 154}; 155 156static u64 rda_hwtimer_read(struct clocksource *cs) 157{ 158 void __iomem *base = timer_of_base(&rda_ostimer_of); 159 u32 lo, hi; 160 161 /* Always read low 32 bits first */ 162 do { 163 lo = readl_relaxed(base + RDA_HWTIMER_LOCKVAL_L); 164 hi = readl_relaxed(base + RDA_HWTIMER_LOCKVAL_H); 165 } while (hi != readl_relaxed(base + RDA_HWTIMER_LOCKVAL_H)); 166 167 return ((u64)hi << 32) | lo; 168} 169 170static struct clocksource rda_hwtimer_clocksource = { 171 .name = "rda-timer", 172 .rating = 400, 173 .read = rda_hwtimer_read, 174 .mask = CLOCKSOURCE_MASK(64), 175 .flags = CLOCK_SOURCE_IS_CONTINUOUS, 176}; 177 178static int __init rda_timer_init(struct device_node *np) 179{ 180 unsigned long rate = 2000000; 181 int ret; 182 183 ret = timer_of_init(np, &rda_ostimer_of); 184 if (ret) 185 return ret; 186 187 clocksource_register_hz(&rda_hwtimer_clocksource, rate); 188 189 clockevents_config_and_register(&rda_ostimer_of.clkevt, rate, 190 0x2, UINT_MAX); 191 192 return 0; 193} 194 195TIMER_OF_DECLARE(rda8810pl, "rda,8810pl-timer", rda_timer_init);