Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
at v4.13-rc7 268 lines 7.2 kB view raw
1/* 2 * Mediatek SoCs General-Purpose Timer handling. 3 * 4 * Copyright (C) 2014 Matthias Brugger 5 * 6 * Matthias Brugger <matthias.bgg@gmail.com> 7 * 8 * This program is free software; you can redistribute it and/or modify 9 * it under the terms of the GNU General Public License as published by 10 * the Free Software Foundation; either version 2 of the License, or 11 * (at your option) any later version. 12 * 13 * This program is distributed in the hope that it will be useful, 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 * GNU General Public License for more details. 17 */ 18 19#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 20 21#include <linux/clk.h> 22#include <linux/clockchips.h> 23#include <linux/interrupt.h> 24#include <linux/irq.h> 25#include <linux/irqreturn.h> 26#include <linux/of.h> 27#include <linux/of_address.h> 28#include <linux/of_irq.h> 29#include <linux/sched_clock.h> 30#include <linux/slab.h> 31 32#define GPT_IRQ_EN_REG 0x00 33#define GPT_IRQ_ENABLE(val) BIT((val) - 1) 34#define GPT_IRQ_ACK_REG 0x08 35#define GPT_IRQ_ACK(val) BIT((val) - 1) 36 37#define TIMER_CTRL_REG(val) (0x10 * (val)) 38#define TIMER_CTRL_OP(val) (((val) & 0x3) << 4) 39#define TIMER_CTRL_OP_ONESHOT (0) 40#define TIMER_CTRL_OP_REPEAT (1) 41#define TIMER_CTRL_OP_FREERUN (3) 42#define TIMER_CTRL_CLEAR (2) 43#define TIMER_CTRL_ENABLE (1) 44#define TIMER_CTRL_DISABLE (0) 45 46#define TIMER_CLK_REG(val) (0x04 + (0x10 * (val))) 47#define TIMER_CLK_SRC(val) (((val) & 0x1) << 4) 48#define TIMER_CLK_SRC_SYS13M (0) 49#define TIMER_CLK_SRC_RTC32K (1) 50#define TIMER_CLK_DIV1 (0x0) 51#define TIMER_CLK_DIV2 (0x1) 52 53#define TIMER_CNT_REG(val) (0x08 + (0x10 * (val))) 54#define TIMER_CMP_REG(val) (0x0C + (0x10 * (val))) 55 56#define GPT_CLK_EVT 1 57#define GPT_CLK_SRC 2 58 59struct mtk_clock_event_device { 60 void __iomem *gpt_base; 61 u32 ticks_per_jiffy; 62 struct clock_event_device dev; 63}; 64 65static void __iomem *gpt_sched_reg __read_mostly; 66 67static u64 notrace mtk_read_sched_clock(void) 68{ 69 return readl_relaxed(gpt_sched_reg); 70} 71 72static inline struct mtk_clock_event_device *to_mtk_clk( 73 struct clock_event_device *c) 74{ 75 return container_of(c, struct mtk_clock_event_device, dev); 76} 77 78static void mtk_clkevt_time_stop(struct mtk_clock_event_device *evt, u8 timer) 79{ 80 u32 val; 81 82 val = readl(evt->gpt_base + TIMER_CTRL_REG(timer)); 83 writel(val & ~TIMER_CTRL_ENABLE, evt->gpt_base + 84 TIMER_CTRL_REG(timer)); 85} 86 87static void mtk_clkevt_time_setup(struct mtk_clock_event_device *evt, 88 unsigned long delay, u8 timer) 89{ 90 writel(delay, evt->gpt_base + TIMER_CMP_REG(timer)); 91} 92 93static void mtk_clkevt_time_start(struct mtk_clock_event_device *evt, 94 bool periodic, u8 timer) 95{ 96 u32 val; 97 98 /* Acknowledge interrupt */ 99 writel(GPT_IRQ_ACK(timer), evt->gpt_base + GPT_IRQ_ACK_REG); 100 101 val = readl(evt->gpt_base + TIMER_CTRL_REG(timer)); 102 103 /* Clear 2 bit timer operation mode field */ 104 val &= ~TIMER_CTRL_OP(0x3); 105 106 if (periodic) 107 val |= TIMER_CTRL_OP(TIMER_CTRL_OP_REPEAT); 108 else 109 val |= TIMER_CTRL_OP(TIMER_CTRL_OP_ONESHOT); 110 111 writel(val | TIMER_CTRL_ENABLE | TIMER_CTRL_CLEAR, 112 evt->gpt_base + TIMER_CTRL_REG(timer)); 113} 114 115static int mtk_clkevt_shutdown(struct clock_event_device *clk) 116{ 117 mtk_clkevt_time_stop(to_mtk_clk(clk), GPT_CLK_EVT); 118 return 0; 119} 120 121static int mtk_clkevt_set_periodic(struct clock_event_device *clk) 122{ 123 struct mtk_clock_event_device *evt = to_mtk_clk(clk); 124 125 mtk_clkevt_time_stop(evt, GPT_CLK_EVT); 126 mtk_clkevt_time_setup(evt, evt->ticks_per_jiffy, GPT_CLK_EVT); 127 mtk_clkevt_time_start(evt, true, GPT_CLK_EVT); 128 return 0; 129} 130 131static int mtk_clkevt_next_event(unsigned long event, 132 struct clock_event_device *clk) 133{ 134 struct mtk_clock_event_device *evt = to_mtk_clk(clk); 135 136 mtk_clkevt_time_stop(evt, GPT_CLK_EVT); 137 mtk_clkevt_time_setup(evt, event, GPT_CLK_EVT); 138 mtk_clkevt_time_start(evt, false, GPT_CLK_EVT); 139 140 return 0; 141} 142 143static irqreturn_t mtk_timer_interrupt(int irq, void *dev_id) 144{ 145 struct mtk_clock_event_device *evt = dev_id; 146 147 /* Acknowledge timer0 irq */ 148 writel(GPT_IRQ_ACK(GPT_CLK_EVT), evt->gpt_base + GPT_IRQ_ACK_REG); 149 evt->dev.event_handler(&evt->dev); 150 151 return IRQ_HANDLED; 152} 153 154static void 155__init mtk_timer_setup(struct mtk_clock_event_device *evt, u8 timer, u8 option) 156{ 157 writel(TIMER_CTRL_CLEAR | TIMER_CTRL_DISABLE, 158 evt->gpt_base + TIMER_CTRL_REG(timer)); 159 160 writel(TIMER_CLK_SRC(TIMER_CLK_SRC_SYS13M) | TIMER_CLK_DIV1, 161 evt->gpt_base + TIMER_CLK_REG(timer)); 162 163 writel(0x0, evt->gpt_base + TIMER_CMP_REG(timer)); 164 165 writel(TIMER_CTRL_OP(option) | TIMER_CTRL_ENABLE, 166 evt->gpt_base + TIMER_CTRL_REG(timer)); 167} 168 169static void mtk_timer_enable_irq(struct mtk_clock_event_device *evt, u8 timer) 170{ 171 u32 val; 172 173 /* Disable all interrupts */ 174 writel(0x0, evt->gpt_base + GPT_IRQ_EN_REG); 175 176 /* Acknowledge all spurious pending interrupts */ 177 writel(0x3f, evt->gpt_base + GPT_IRQ_ACK_REG); 178 179 val = readl(evt->gpt_base + GPT_IRQ_EN_REG); 180 writel(val | GPT_IRQ_ENABLE(timer), 181 evt->gpt_base + GPT_IRQ_EN_REG); 182} 183 184static int __init mtk_timer_init(struct device_node *node) 185{ 186 struct mtk_clock_event_device *evt; 187 struct resource res; 188 unsigned long rate = 0; 189 struct clk *clk; 190 191 evt = kzalloc(sizeof(*evt), GFP_KERNEL); 192 if (!evt) 193 return -ENOMEM; 194 195 evt->dev.name = "mtk_tick"; 196 evt->dev.rating = 300; 197 evt->dev.features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT; 198 evt->dev.set_state_shutdown = mtk_clkevt_shutdown; 199 evt->dev.set_state_periodic = mtk_clkevt_set_periodic; 200 evt->dev.set_state_oneshot = mtk_clkevt_shutdown; 201 evt->dev.tick_resume = mtk_clkevt_shutdown; 202 evt->dev.set_next_event = mtk_clkevt_next_event; 203 evt->dev.cpumask = cpu_possible_mask; 204 205 evt->gpt_base = of_io_request_and_map(node, 0, "mtk-timer"); 206 if (IS_ERR(evt->gpt_base)) { 207 pr_err("Can't get resource\n"); 208 goto err_kzalloc; 209 } 210 211 evt->dev.irq = irq_of_parse_and_map(node, 0); 212 if (evt->dev.irq <= 0) { 213 pr_err("Can't parse IRQ\n"); 214 goto err_mem; 215 } 216 217 clk = of_clk_get(node, 0); 218 if (IS_ERR(clk)) { 219 pr_err("Can't get timer clock\n"); 220 goto err_irq; 221 } 222 223 if (clk_prepare_enable(clk)) { 224 pr_err("Can't prepare clock\n"); 225 goto err_clk_put; 226 } 227 rate = clk_get_rate(clk); 228 229 if (request_irq(evt->dev.irq, mtk_timer_interrupt, 230 IRQF_TIMER | IRQF_IRQPOLL, "mtk_timer", evt)) { 231 pr_err("failed to setup irq %d\n", evt->dev.irq); 232 goto err_clk_disable; 233 } 234 235 evt->ticks_per_jiffy = DIV_ROUND_UP(rate, HZ); 236 237 /* Configure clock source */ 238 mtk_timer_setup(evt, GPT_CLK_SRC, TIMER_CTRL_OP_FREERUN); 239 clocksource_mmio_init(evt->gpt_base + TIMER_CNT_REG(GPT_CLK_SRC), 240 node->name, rate, 300, 32, clocksource_mmio_readl_up); 241 gpt_sched_reg = evt->gpt_base + TIMER_CNT_REG(GPT_CLK_SRC); 242 sched_clock_register(mtk_read_sched_clock, 32, rate); 243 244 /* Configure clock event */ 245 mtk_timer_setup(evt, GPT_CLK_EVT, TIMER_CTRL_OP_REPEAT); 246 clockevents_config_and_register(&evt->dev, rate, 0x3, 247 0xffffffff); 248 249 mtk_timer_enable_irq(evt, GPT_CLK_EVT); 250 251 return 0; 252 253err_clk_disable: 254 clk_disable_unprepare(clk); 255err_clk_put: 256 clk_put(clk); 257err_irq: 258 irq_dispose_mapping(evt->dev.irq); 259err_mem: 260 iounmap(evt->gpt_base); 261 of_address_to_resource(node, 0, &res); 262 release_mem_region(res.start, resource_size(&res)); 263err_kzalloc: 264 kfree(evt); 265 266 return -EINVAL; 267} 268TIMER_OF_DECLARE(mtk_mt6577, "mediatek,mt6577-timer", mtk_timer_init);