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