root/drivers/clocksource/timer-mediatek.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. mtk_syst_ack_irq
  2. mtk_syst_handler
  3. mtk_syst_clkevt_next_event
  4. mtk_syst_clkevt_shutdown
  5. mtk_syst_clkevt_resume
  6. mtk_syst_clkevt_oneshot
  7. mtk_gpt_read_sched_clock
  8. mtk_gpt_clkevt_time_stop
  9. mtk_gpt_clkevt_time_setup
  10. mtk_gpt_clkevt_time_start
  11. mtk_gpt_clkevt_shutdown
  12. mtk_gpt_clkevt_set_periodic
  13. mtk_gpt_clkevt_next_event
  14. mtk_gpt_interrupt
  15. mtk_gpt_setup
  16. mtk_gpt_enable_irq
  17. mtk_syst_init
  18. mtk_gpt_init

   1 // SPDX-License-Identifier: GPL-2.0-or-later
   2 /*
   3  * Mediatek SoCs General-Purpose Timer handling.
   4  *
   5  * Copyright (C) 2014 Matthias Brugger
   6  *
   7  * Matthias Brugger <matthias.bgg@gmail.com>
   8  */
   9 
  10 #define pr_fmt(fmt)     KBUILD_MODNAME ": " fmt
  11 
  12 #include <linux/clockchips.h>
  13 #include <linux/clocksource.h>
  14 #include <linux/interrupt.h>
  15 #include <linux/irqreturn.h>
  16 #include <linux/sched_clock.h>
  17 #include <linux/slab.h>
  18 #include "timer-of.h"
  19 
  20 #define TIMER_CLK_EVT           (1)
  21 #define TIMER_CLK_SRC           (2)
  22 
  23 #define TIMER_SYNC_TICKS        (3)
  24 
  25 /* gpt */
  26 #define GPT_IRQ_EN_REG          0x00
  27 #define GPT_IRQ_ENABLE(val)     BIT((val) - 1)
  28 #define GPT_IRQ_ACK_REG         0x08
  29 #define GPT_IRQ_ACK(val)        BIT((val) - 1)
  30 
  31 #define GPT_CTRL_REG(val)       (0x10 * (val))
  32 #define GPT_CTRL_OP(val)        (((val) & 0x3) << 4)
  33 #define GPT_CTRL_OP_ONESHOT     (0)
  34 #define GPT_CTRL_OP_REPEAT      (1)
  35 #define GPT_CTRL_OP_FREERUN     (3)
  36 #define GPT_CTRL_CLEAR          (2)
  37 #define GPT_CTRL_ENABLE         (1)
  38 #define GPT_CTRL_DISABLE        (0)
  39 
  40 #define GPT_CLK_REG(val)        (0x04 + (0x10 * (val)))
  41 #define GPT_CLK_SRC(val)        (((val) & 0x1) << 4)
  42 #define GPT_CLK_SRC_SYS13M      (0)
  43 #define GPT_CLK_SRC_RTC32K      (1)
  44 #define GPT_CLK_DIV1            (0x0)
  45 #define GPT_CLK_DIV2            (0x1)
  46 
  47 #define GPT_CNT_REG(val)        (0x08 + (0x10 * (val)))
  48 #define GPT_CMP_REG(val)        (0x0C + (0x10 * (val)))
  49 
  50 /* system timer */
  51 #define SYST_BASE               (0x40)
  52 
  53 #define SYST_CON                (SYST_BASE + 0x0)
  54 #define SYST_VAL                (SYST_BASE + 0x4)
  55 
  56 #define SYST_CON_REG(to)        (timer_of_base(to) + SYST_CON)
  57 #define SYST_VAL_REG(to)        (timer_of_base(to) + SYST_VAL)
  58 
  59 /*
  60  * SYST_CON_EN: Clock enable. Shall be set to
  61  *   - Start timer countdown.
  62  *   - Allow timeout ticks being updated.
  63  *   - Allow changing interrupt functions.
  64  *
  65  * SYST_CON_IRQ_EN: Set to allow interrupt.
  66  *
  67  * SYST_CON_IRQ_CLR: Set to clear interrupt.
  68  */
  69 #define SYST_CON_EN              BIT(0)
  70 #define SYST_CON_IRQ_EN          BIT(1)
  71 #define SYST_CON_IRQ_CLR         BIT(4)
  72 
  73 static void __iomem *gpt_sched_reg __read_mostly;
  74 
  75 static void mtk_syst_ack_irq(struct timer_of *to)
  76 {
  77         /* Clear and disable interrupt */
  78         writel(SYST_CON_IRQ_CLR | SYST_CON_EN, SYST_CON_REG(to));
  79 }
  80 
  81 static irqreturn_t mtk_syst_handler(int irq, void *dev_id)
  82 {
  83         struct clock_event_device *clkevt = dev_id;
  84         struct timer_of *to = to_timer_of(clkevt);
  85 
  86         mtk_syst_ack_irq(to);
  87         clkevt->event_handler(clkevt);
  88 
  89         return IRQ_HANDLED;
  90 }
  91 
  92 static int mtk_syst_clkevt_next_event(unsigned long ticks,
  93                                       struct clock_event_device *clkevt)
  94 {
  95         struct timer_of *to = to_timer_of(clkevt);
  96 
  97         /* Enable clock to allow timeout tick update later */
  98         writel(SYST_CON_EN, SYST_CON_REG(to));
  99 
 100         /*
 101          * Write new timeout ticks. Timer shall start countdown
 102          * after timeout ticks are updated.
 103          */
 104         writel(ticks, SYST_VAL_REG(to));
 105 
 106         /* Enable interrupt */
 107         writel(SYST_CON_EN | SYST_CON_IRQ_EN, SYST_CON_REG(to));
 108 
 109         return 0;
 110 }
 111 
 112 static int mtk_syst_clkevt_shutdown(struct clock_event_device *clkevt)
 113 {
 114         /* Disable timer */
 115         writel(0, SYST_CON_REG(to_timer_of(clkevt)));
 116 
 117         return 0;
 118 }
 119 
 120 static int mtk_syst_clkevt_resume(struct clock_event_device *clkevt)
 121 {
 122         return mtk_syst_clkevt_shutdown(clkevt);
 123 }
 124 
 125 static int mtk_syst_clkevt_oneshot(struct clock_event_device *clkevt)
 126 {
 127         return 0;
 128 }
 129 
 130 static u64 notrace mtk_gpt_read_sched_clock(void)
 131 {
 132         return readl_relaxed(gpt_sched_reg);
 133 }
 134 
 135 static void mtk_gpt_clkevt_time_stop(struct timer_of *to, u8 timer)
 136 {
 137         u32 val;
 138 
 139         val = readl(timer_of_base(to) + GPT_CTRL_REG(timer));
 140         writel(val & ~GPT_CTRL_ENABLE, timer_of_base(to) +
 141                GPT_CTRL_REG(timer));
 142 }
 143 
 144 static void mtk_gpt_clkevt_time_setup(struct timer_of *to,
 145                                       unsigned long delay, u8 timer)
 146 {
 147         writel(delay, timer_of_base(to) + GPT_CMP_REG(timer));
 148 }
 149 
 150 static void mtk_gpt_clkevt_time_start(struct timer_of *to,
 151                                       bool periodic, u8 timer)
 152 {
 153         u32 val;
 154 
 155         /* Acknowledge interrupt */
 156         writel(GPT_IRQ_ACK(timer), timer_of_base(to) + GPT_IRQ_ACK_REG);
 157 
 158         val = readl(timer_of_base(to) + GPT_CTRL_REG(timer));
 159 
 160         /* Clear 2 bit timer operation mode field */
 161         val &= ~GPT_CTRL_OP(0x3);
 162 
 163         if (periodic)
 164                 val |= GPT_CTRL_OP(GPT_CTRL_OP_REPEAT);
 165         else
 166                 val |= GPT_CTRL_OP(GPT_CTRL_OP_ONESHOT);
 167 
 168         writel(val | GPT_CTRL_ENABLE | GPT_CTRL_CLEAR,
 169                timer_of_base(to) + GPT_CTRL_REG(timer));
 170 }
 171 
 172 static int mtk_gpt_clkevt_shutdown(struct clock_event_device *clk)
 173 {
 174         mtk_gpt_clkevt_time_stop(to_timer_of(clk), TIMER_CLK_EVT);
 175 
 176         return 0;
 177 }
 178 
 179 static int mtk_gpt_clkevt_set_periodic(struct clock_event_device *clk)
 180 {
 181         struct timer_of *to = to_timer_of(clk);
 182 
 183         mtk_gpt_clkevt_time_stop(to, TIMER_CLK_EVT);
 184         mtk_gpt_clkevt_time_setup(to, to->of_clk.period, TIMER_CLK_EVT);
 185         mtk_gpt_clkevt_time_start(to, true, TIMER_CLK_EVT);
 186 
 187         return 0;
 188 }
 189 
 190 static int mtk_gpt_clkevt_next_event(unsigned long event,
 191                                      struct clock_event_device *clk)
 192 {
 193         struct timer_of *to = to_timer_of(clk);
 194 
 195         mtk_gpt_clkevt_time_stop(to, TIMER_CLK_EVT);
 196         mtk_gpt_clkevt_time_setup(to, event, TIMER_CLK_EVT);
 197         mtk_gpt_clkevt_time_start(to, false, TIMER_CLK_EVT);
 198 
 199         return 0;
 200 }
 201 
 202 static irqreturn_t mtk_gpt_interrupt(int irq, void *dev_id)
 203 {
 204         struct clock_event_device *clkevt = (struct clock_event_device *)dev_id;
 205         struct timer_of *to = to_timer_of(clkevt);
 206 
 207         /* Acknowledge timer0 irq */
 208         writel(GPT_IRQ_ACK(TIMER_CLK_EVT), timer_of_base(to) + GPT_IRQ_ACK_REG);
 209         clkevt->event_handler(clkevt);
 210 
 211         return IRQ_HANDLED;
 212 }
 213 
 214 static void
 215 __init mtk_gpt_setup(struct timer_of *to, u8 timer, u8 option)
 216 {
 217         writel(GPT_CTRL_CLEAR | GPT_CTRL_DISABLE,
 218                timer_of_base(to) + GPT_CTRL_REG(timer));
 219 
 220         writel(GPT_CLK_SRC(GPT_CLK_SRC_SYS13M) | GPT_CLK_DIV1,
 221                timer_of_base(to) + GPT_CLK_REG(timer));
 222 
 223         writel(0x0, timer_of_base(to) + GPT_CMP_REG(timer));
 224 
 225         writel(GPT_CTRL_OP(option) | GPT_CTRL_ENABLE,
 226                timer_of_base(to) + GPT_CTRL_REG(timer));
 227 }
 228 
 229 static void mtk_gpt_enable_irq(struct timer_of *to, u8 timer)
 230 {
 231         u32 val;
 232 
 233         /* Disable all interrupts */
 234         writel(0x0, timer_of_base(to) + GPT_IRQ_EN_REG);
 235 
 236         /* Acknowledge all spurious pending interrupts */
 237         writel(0x3f, timer_of_base(to) + GPT_IRQ_ACK_REG);
 238 
 239         val = readl(timer_of_base(to) + GPT_IRQ_EN_REG);
 240         writel(val | GPT_IRQ_ENABLE(timer),
 241                timer_of_base(to) + GPT_IRQ_EN_REG);
 242 }
 243 
 244 static struct timer_of to = {
 245         .flags = TIMER_OF_IRQ | TIMER_OF_BASE | TIMER_OF_CLOCK,
 246 
 247         .clkevt = {
 248                 .name = "mtk-clkevt",
 249                 .rating = 300,
 250                 .cpumask = cpu_possible_mask,
 251         },
 252 
 253         .of_irq = {
 254                 .flags = IRQF_TIMER | IRQF_IRQPOLL,
 255         },
 256 };
 257 
 258 static int __init mtk_syst_init(struct device_node *node)
 259 {
 260         int ret;
 261 
 262         to.clkevt.features = CLOCK_EVT_FEAT_DYNIRQ | CLOCK_EVT_FEAT_ONESHOT;
 263         to.clkevt.set_state_shutdown = mtk_syst_clkevt_shutdown;
 264         to.clkevt.set_state_oneshot = mtk_syst_clkevt_oneshot;
 265         to.clkevt.tick_resume = mtk_syst_clkevt_resume;
 266         to.clkevt.set_next_event = mtk_syst_clkevt_next_event;
 267         to.of_irq.handler = mtk_syst_handler;
 268 
 269         ret = timer_of_init(node, &to);
 270         if (ret)
 271                 return ret;
 272 
 273         clockevents_config_and_register(&to.clkevt, timer_of_rate(&to),
 274                                         TIMER_SYNC_TICKS, 0xffffffff);
 275 
 276         return 0;
 277 }
 278 
 279 static int __init mtk_gpt_init(struct device_node *node)
 280 {
 281         int ret;
 282 
 283         to.clkevt.features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT;
 284         to.clkevt.set_state_shutdown = mtk_gpt_clkevt_shutdown;
 285         to.clkevt.set_state_periodic = mtk_gpt_clkevt_set_periodic;
 286         to.clkevt.set_state_oneshot = mtk_gpt_clkevt_shutdown;
 287         to.clkevt.tick_resume = mtk_gpt_clkevt_shutdown;
 288         to.clkevt.set_next_event = mtk_gpt_clkevt_next_event;
 289         to.of_irq.handler = mtk_gpt_interrupt;
 290 
 291         ret = timer_of_init(node, &to);
 292         if (ret)
 293                 return ret;
 294 
 295         /* Configure clock source */
 296         mtk_gpt_setup(&to, TIMER_CLK_SRC, GPT_CTRL_OP_FREERUN);
 297         clocksource_mmio_init(timer_of_base(&to) + GPT_CNT_REG(TIMER_CLK_SRC),
 298                               node->name, timer_of_rate(&to), 300, 32,
 299                               clocksource_mmio_readl_up);
 300         gpt_sched_reg = timer_of_base(&to) + GPT_CNT_REG(TIMER_CLK_SRC);
 301         sched_clock_register(mtk_gpt_read_sched_clock, 32, timer_of_rate(&to));
 302 
 303         /* Configure clock event */
 304         mtk_gpt_setup(&to, TIMER_CLK_EVT, GPT_CTRL_OP_REPEAT);
 305         clockevents_config_and_register(&to.clkevt, timer_of_rate(&to),
 306                                         TIMER_SYNC_TICKS, 0xffffffff);
 307 
 308         mtk_gpt_enable_irq(&to, TIMER_CLK_EVT);
 309 
 310         return 0;
 311 }
 312 TIMER_OF_DECLARE(mtk_mt6577, "mediatek,mt6577-timer", mtk_gpt_init);
 313 TIMER_OF_DECLARE(mtk_mt6765, "mediatek,mt6765-timer", mtk_syst_init);

/* [<][>][^][v][top][bottom][index][help] */