Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at v4.14-rc8 299 lines 7.4 kB view raw
1/* 2 * drivers/clocksource/timer-oxnas-rps.c 3 * 4 * Copyright (C) 2009 Oxford Semiconductor Ltd 5 * Copyright (C) 2013 Ma Haijun <mahaijuns@gmail.com> 6 * Copyright (C) 2016 Neil Armstrong <narmstrong@baylibre.com> 7 * 8 * This program is free software; you can redistribute it and/or modify it 9 * under the terms and conditions of the GNU General Public License, 10 * version 2, as published by the Free Software Foundation. 11 * 12 * This program is distributed in the hope it will be useful, but WITHOUT 13 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 14 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 15 * more details. 16 * 17 * You should have received a copy of the GNU General Public License 18 * along with this program. If not, see <http://www.gnu.org/licenses/>. 19 */ 20 21#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 22 23#include <linux/init.h> 24#include <linux/irq.h> 25#include <linux/io.h> 26#include <linux/clk.h> 27#include <linux/slab.h> 28#include <linux/interrupt.h> 29#include <linux/of_irq.h> 30#include <linux/of_address.h> 31#include <linux/clockchips.h> 32#include <linux/sched_clock.h> 33 34/* TIMER1 used as tick 35 * TIMER2 used as clocksource 36 */ 37 38/* Registers definitions */ 39 40#define TIMER_LOAD_REG 0x0 41#define TIMER_CURR_REG 0x4 42#define TIMER_CTRL_REG 0x8 43#define TIMER_CLRINT_REG 0xC 44 45#define TIMER_BITS 24 46 47#define TIMER_MAX_VAL (BIT(TIMER_BITS) - 1) 48 49#define TIMER_PERIODIC BIT(6) 50#define TIMER_ENABLE BIT(7) 51 52#define TIMER_DIV1 (0) 53#define TIMER_DIV16 (1 << 2) 54#define TIMER_DIV256 (2 << 2) 55 56#define TIMER1_REG_OFFSET 0 57#define TIMER2_REG_OFFSET 0x20 58 59/* Clockevent & Clocksource data */ 60 61struct oxnas_rps_timer { 62 struct clock_event_device clkevent; 63 void __iomem *clksrc_base; 64 void __iomem *clkevt_base; 65 unsigned long timer_period; 66 unsigned int timer_prescaler; 67 struct clk *clk; 68 int irq; 69}; 70 71static irqreturn_t oxnas_rps_timer_irq(int irq, void *dev_id) 72{ 73 struct oxnas_rps_timer *rps = dev_id; 74 75 writel_relaxed(0, rps->clkevt_base + TIMER_CLRINT_REG); 76 77 rps->clkevent.event_handler(&rps->clkevent); 78 79 return IRQ_HANDLED; 80} 81 82static void oxnas_rps_timer_config(struct oxnas_rps_timer *rps, 83 unsigned long period, 84 unsigned int periodic) 85{ 86 uint32_t cfg = rps->timer_prescaler; 87 88 if (period) 89 cfg |= TIMER_ENABLE; 90 91 if (periodic) 92 cfg |= TIMER_PERIODIC; 93 94 writel_relaxed(period, rps->clkevt_base + TIMER_LOAD_REG); 95 writel_relaxed(cfg, rps->clkevt_base + TIMER_CTRL_REG); 96} 97 98static int oxnas_rps_timer_shutdown(struct clock_event_device *evt) 99{ 100 struct oxnas_rps_timer *rps = 101 container_of(evt, struct oxnas_rps_timer, clkevent); 102 103 oxnas_rps_timer_config(rps, 0, 0); 104 105 return 0; 106} 107 108static int oxnas_rps_timer_set_periodic(struct clock_event_device *evt) 109{ 110 struct oxnas_rps_timer *rps = 111 container_of(evt, struct oxnas_rps_timer, clkevent); 112 113 oxnas_rps_timer_config(rps, rps->timer_period, 1); 114 115 return 0; 116} 117 118static int oxnas_rps_timer_set_oneshot(struct clock_event_device *evt) 119{ 120 struct oxnas_rps_timer *rps = 121 container_of(evt, struct oxnas_rps_timer, clkevent); 122 123 oxnas_rps_timer_config(rps, rps->timer_period, 0); 124 125 return 0; 126} 127 128static int oxnas_rps_timer_next_event(unsigned long delta, 129 struct clock_event_device *evt) 130{ 131 struct oxnas_rps_timer *rps = 132 container_of(evt, struct oxnas_rps_timer, clkevent); 133 134 oxnas_rps_timer_config(rps, delta, 0); 135 136 return 0; 137} 138 139static int __init oxnas_rps_clockevent_init(struct oxnas_rps_timer *rps) 140{ 141 ulong clk_rate = clk_get_rate(rps->clk); 142 ulong timer_rate; 143 144 /* Start with prescaler 1 */ 145 rps->timer_prescaler = TIMER_DIV1; 146 rps->timer_period = DIV_ROUND_UP(clk_rate, HZ); 147 timer_rate = clk_rate; 148 149 if (rps->timer_period > TIMER_MAX_VAL) { 150 rps->timer_prescaler = TIMER_DIV16; 151 timer_rate = clk_rate / 16; 152 rps->timer_period = DIV_ROUND_UP(timer_rate, HZ); 153 } 154 if (rps->timer_period > TIMER_MAX_VAL) { 155 rps->timer_prescaler = TIMER_DIV256; 156 timer_rate = clk_rate / 256; 157 rps->timer_period = DIV_ROUND_UP(timer_rate, HZ); 158 } 159 160 rps->clkevent.name = "oxnas-rps"; 161 rps->clkevent.features = CLOCK_EVT_FEAT_PERIODIC | 162 CLOCK_EVT_FEAT_ONESHOT | 163 CLOCK_EVT_FEAT_DYNIRQ; 164 rps->clkevent.tick_resume = oxnas_rps_timer_shutdown; 165 rps->clkevent.set_state_shutdown = oxnas_rps_timer_shutdown; 166 rps->clkevent.set_state_periodic = oxnas_rps_timer_set_periodic; 167 rps->clkevent.set_state_oneshot = oxnas_rps_timer_set_oneshot; 168 rps->clkevent.set_next_event = oxnas_rps_timer_next_event; 169 rps->clkevent.rating = 200; 170 rps->clkevent.cpumask = cpu_possible_mask; 171 rps->clkevent.irq = rps->irq; 172 clockevents_config_and_register(&rps->clkevent, 173 timer_rate, 174 1, 175 TIMER_MAX_VAL); 176 177 pr_info("Registered clock event rate %luHz prescaler %x period %lu\n", 178 clk_rate, 179 rps->timer_prescaler, 180 rps->timer_period); 181 182 return 0; 183} 184 185/* Clocksource */ 186 187static void __iomem *timer_sched_base; 188 189static u64 notrace oxnas_rps_read_sched_clock(void) 190{ 191 return ~readl_relaxed(timer_sched_base); 192} 193 194static int __init oxnas_rps_clocksource_init(struct oxnas_rps_timer *rps) 195{ 196 ulong clk_rate = clk_get_rate(rps->clk); 197 int ret; 198 199 /* use prescale 16 */ 200 clk_rate = clk_rate / 16; 201 202 writel_relaxed(TIMER_MAX_VAL, rps->clksrc_base + TIMER_LOAD_REG); 203 writel_relaxed(TIMER_PERIODIC | TIMER_ENABLE | TIMER_DIV16, 204 rps->clksrc_base + TIMER_CTRL_REG); 205 206 timer_sched_base = rps->clksrc_base + TIMER_CURR_REG; 207 sched_clock_register(oxnas_rps_read_sched_clock, 208 TIMER_BITS, clk_rate); 209 ret = clocksource_mmio_init(timer_sched_base, 210 "oxnas_rps_clocksource_timer", 211 clk_rate, 250, TIMER_BITS, 212 clocksource_mmio_readl_down); 213 if (WARN_ON(ret)) { 214 pr_err("can't register clocksource\n"); 215 return ret; 216 } 217 218 pr_info("Registered clocksource rate %luHz\n", clk_rate); 219 220 return 0; 221} 222 223static int __init oxnas_rps_timer_init(struct device_node *np) 224{ 225 struct oxnas_rps_timer *rps; 226 void __iomem *base; 227 int ret; 228 229 rps = kzalloc(sizeof(*rps), GFP_KERNEL); 230 if (!rps) 231 return -ENOMEM; 232 233 rps->clk = of_clk_get(np, 0); 234 if (IS_ERR(rps->clk)) { 235 ret = PTR_ERR(rps->clk); 236 goto err_alloc; 237 } 238 239 ret = clk_prepare_enable(rps->clk); 240 if (ret) 241 goto err_clk; 242 243 base = of_iomap(np, 0); 244 if (!base) { 245 ret = -ENXIO; 246 goto err_clk_prepare; 247 } 248 249 rps->irq = irq_of_parse_and_map(np, 0); 250 if (rps->irq < 0) { 251 ret = -EINVAL; 252 goto err_iomap; 253 } 254 255 rps->clkevt_base = base + TIMER1_REG_OFFSET; 256 rps->clksrc_base = base + TIMER2_REG_OFFSET; 257 258 /* Disable timers */ 259 writel_relaxed(0, rps->clkevt_base + TIMER_CTRL_REG); 260 writel_relaxed(0, rps->clksrc_base + TIMER_CTRL_REG); 261 writel_relaxed(0, rps->clkevt_base + TIMER_LOAD_REG); 262 writel_relaxed(0, rps->clksrc_base + TIMER_LOAD_REG); 263 writel_relaxed(0, rps->clkevt_base + TIMER_CLRINT_REG); 264 writel_relaxed(0, rps->clksrc_base + TIMER_CLRINT_REG); 265 266 ret = request_irq(rps->irq, oxnas_rps_timer_irq, 267 IRQF_TIMER | IRQF_IRQPOLL, 268 "rps-timer", rps); 269 if (ret) 270 goto err_iomap; 271 272 ret = oxnas_rps_clocksource_init(rps); 273 if (ret) 274 goto err_irqreq; 275 276 ret = oxnas_rps_clockevent_init(rps); 277 if (ret) 278 goto err_irqreq; 279 280 return 0; 281 282err_irqreq: 283 free_irq(rps->irq, rps); 284err_iomap: 285 iounmap(base); 286err_clk_prepare: 287 clk_disable_unprepare(rps->clk); 288err_clk: 289 clk_put(rps->clk); 290err_alloc: 291 kfree(rps); 292 293 return ret; 294} 295 296TIMER_OF_DECLARE(ox810se_rps, 297 "oxsemi,ox810se-rps-timer", oxnas_rps_timer_init); 298TIMER_OF_DECLARE(ox820_rps, 299 "oxsemi,ox820se-rps-timer", oxnas_rps_timer_init);