Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /*
0003  * Allwinner A1X SoCs timer handling.
0004  *
0005  * Copyright (C) 2012 Maxime Ripard
0006  *
0007  * Maxime Ripard <maxime.ripard@free-electrons.com>
0008  *
0009  * Based on code from
0010  * Allwinner Technology Co., Ltd. <www.allwinnertech.com>
0011  * Benn Huang <benn@allwinnertech.com>
0012  */
0013 
0014 #include <linux/clk.h>
0015 #include <linux/clockchips.h>
0016 #include <linux/interrupt.h>
0017 #include <linux/irq.h>
0018 #include <linux/irqreturn.h>
0019 #include <linux/sched_clock.h>
0020 #include <linux/of.h>
0021 #include <linux/of_address.h>
0022 #include <linux/of_irq.h>
0023 
0024 #include "timer-of.h"
0025 
0026 #define TIMER_IRQ_EN_REG    0x00
0027 #define TIMER_IRQ_EN(val)       BIT(val)
0028 #define TIMER_IRQ_ST_REG    0x04
0029 #define TIMER_CTL_REG(val)  (0x10 * val + 0x10)
0030 #define TIMER_CTL_ENABLE        BIT(0)
0031 #define TIMER_CTL_RELOAD        BIT(1)
0032 #define TIMER_CTL_CLK_SRC(val)      (((val) & 0x3) << 2)
0033 #define TIMER_CTL_CLK_SRC_OSC24M        (1)
0034 #define TIMER_CTL_CLK_PRES(val)     (((val) & 0x7) << 4)
0035 #define TIMER_CTL_ONESHOT       BIT(7)
0036 #define TIMER_INTVAL_REG(val)   (0x10 * (val) + 0x14)
0037 #define TIMER_CNTVAL_REG(val)   (0x10 * (val) + 0x18)
0038 
0039 #define TIMER_SYNC_TICKS    3
0040 
0041 /*
0042  * When we disable a timer, we need to wait at least for 2 cycles of
0043  * the timer source clock. We will use for that the clocksource timer
0044  * that is already setup and runs at the same frequency than the other
0045  * timers, and we never will be disabled.
0046  */
0047 static void sun4i_clkevt_sync(void __iomem *base)
0048 {
0049     u32 old = readl(base + TIMER_CNTVAL_REG(1));
0050 
0051     while ((old - readl(base + TIMER_CNTVAL_REG(1))) < TIMER_SYNC_TICKS)
0052         cpu_relax();
0053 }
0054 
0055 static void sun4i_clkevt_time_stop(void __iomem *base, u8 timer)
0056 {
0057     u32 val = readl(base + TIMER_CTL_REG(timer));
0058     writel(val & ~TIMER_CTL_ENABLE, base + TIMER_CTL_REG(timer));
0059     sun4i_clkevt_sync(base);
0060 }
0061 
0062 static void sun4i_clkevt_time_setup(void __iomem *base, u8 timer,
0063                     unsigned long delay)
0064 {
0065     writel(delay, base + TIMER_INTVAL_REG(timer));
0066 }
0067 
0068 static void sun4i_clkevt_time_start(void __iomem *base, u8 timer,
0069                     bool periodic)
0070 {
0071     u32 val = readl(base + TIMER_CTL_REG(timer));
0072 
0073     if (periodic)
0074         val &= ~TIMER_CTL_ONESHOT;
0075     else
0076         val |= TIMER_CTL_ONESHOT;
0077 
0078     writel(val | TIMER_CTL_ENABLE | TIMER_CTL_RELOAD,
0079            base + TIMER_CTL_REG(timer));
0080 }
0081 
0082 static int sun4i_clkevt_shutdown(struct clock_event_device *evt)
0083 {
0084     struct timer_of *to = to_timer_of(evt);
0085 
0086     sun4i_clkevt_time_stop(timer_of_base(to), 0);
0087 
0088     return 0;
0089 }
0090 
0091 static int sun4i_clkevt_set_oneshot(struct clock_event_device *evt)
0092 {
0093     struct timer_of *to = to_timer_of(evt);
0094 
0095     sun4i_clkevt_time_stop(timer_of_base(to), 0);
0096     sun4i_clkevt_time_start(timer_of_base(to), 0, false);
0097 
0098     return 0;
0099 }
0100 
0101 static int sun4i_clkevt_set_periodic(struct clock_event_device *evt)
0102 {
0103     struct timer_of *to = to_timer_of(evt);
0104 
0105     sun4i_clkevt_time_stop(timer_of_base(to), 0);
0106     sun4i_clkevt_time_setup(timer_of_base(to), 0, timer_of_period(to));
0107     sun4i_clkevt_time_start(timer_of_base(to), 0, true);
0108 
0109     return 0;
0110 }
0111 
0112 static int sun4i_clkevt_next_event(unsigned long evt,
0113                    struct clock_event_device *clkevt)
0114 {
0115     struct timer_of *to = to_timer_of(clkevt);
0116 
0117     sun4i_clkevt_time_stop(timer_of_base(to), 0);
0118     sun4i_clkevt_time_setup(timer_of_base(to), 0, evt - TIMER_SYNC_TICKS);
0119     sun4i_clkevt_time_start(timer_of_base(to), 0, false);
0120 
0121     return 0;
0122 }
0123 
0124 static void sun4i_timer_clear_interrupt(void __iomem *base)
0125 {
0126     writel(TIMER_IRQ_EN(0), base + TIMER_IRQ_ST_REG);
0127 }
0128 
0129 static irqreturn_t sun4i_timer_interrupt(int irq, void *dev_id)
0130 {
0131     struct clock_event_device *evt = dev_id;
0132     struct timer_of *to = to_timer_of(evt);
0133 
0134     sun4i_timer_clear_interrupt(timer_of_base(to));
0135     evt->event_handler(evt);
0136 
0137     return IRQ_HANDLED;
0138 }
0139 
0140 static struct timer_of to = {
0141     .flags = TIMER_OF_IRQ | TIMER_OF_CLOCK | TIMER_OF_BASE,
0142 
0143     .clkevt = {
0144         .name = "sun4i_tick",
0145         .rating = 350,
0146         .features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT,
0147         .set_state_shutdown = sun4i_clkevt_shutdown,
0148         .set_state_periodic = sun4i_clkevt_set_periodic,
0149         .set_state_oneshot = sun4i_clkevt_set_oneshot,
0150         .tick_resume = sun4i_clkevt_shutdown,
0151         .set_next_event = sun4i_clkevt_next_event,
0152         .cpumask = cpu_possible_mask,
0153     },
0154 
0155     .of_irq = {
0156         .handler = sun4i_timer_interrupt,
0157         .flags = IRQF_TIMER | IRQF_IRQPOLL,
0158     },
0159 };
0160 
0161 static u64 notrace sun4i_timer_sched_read(void)
0162 {
0163     return ~readl(timer_of_base(&to) + TIMER_CNTVAL_REG(1));
0164 }
0165 
0166 static int __init sun4i_timer_init(struct device_node *node)
0167 {
0168     int ret;
0169     u32 val;
0170 
0171     ret = timer_of_init(node, &to);
0172     if (ret)
0173         return ret;
0174 
0175     writel(~0, timer_of_base(&to) + TIMER_INTVAL_REG(1));
0176     writel(TIMER_CTL_ENABLE | TIMER_CTL_RELOAD |
0177            TIMER_CTL_CLK_SRC(TIMER_CTL_CLK_SRC_OSC24M),
0178            timer_of_base(&to) + TIMER_CTL_REG(1));
0179 
0180     /*
0181      * sched_clock_register does not have priorities, and on sun6i and
0182      * later there is a better sched_clock registered by arm_arch_timer.c
0183      */
0184     if (of_machine_is_compatible("allwinner,sun4i-a10") ||
0185         of_machine_is_compatible("allwinner,sun5i-a13") ||
0186         of_machine_is_compatible("allwinner,sun5i-a10s") ||
0187         of_machine_is_compatible("allwinner,suniv-f1c100s"))
0188         sched_clock_register(sun4i_timer_sched_read, 32,
0189                      timer_of_rate(&to));
0190 
0191     ret = clocksource_mmio_init(timer_of_base(&to) + TIMER_CNTVAL_REG(1),
0192                     node->name, timer_of_rate(&to), 350, 32,
0193                     clocksource_mmio_readl_down);
0194     if (ret) {
0195         pr_err("Failed to register clocksource\n");
0196         return ret;
0197     }
0198 
0199     writel(TIMER_CTL_CLK_SRC(TIMER_CTL_CLK_SRC_OSC24M),
0200            timer_of_base(&to) + TIMER_CTL_REG(0));
0201 
0202     /* Make sure timer is stopped before playing with interrupts */
0203     sun4i_clkevt_time_stop(timer_of_base(&to), 0);
0204 
0205     /* clear timer0 interrupt */
0206     sun4i_timer_clear_interrupt(timer_of_base(&to));
0207 
0208     clockevents_config_and_register(&to.clkevt, timer_of_rate(&to),
0209                     TIMER_SYNC_TICKS, 0xffffffff);
0210 
0211     /* Enable timer0 interrupt */
0212     val = readl(timer_of_base(&to) + TIMER_IRQ_EN_REG);
0213     writel(val | TIMER_IRQ_EN(0), timer_of_base(&to) + TIMER_IRQ_EN_REG);
0214 
0215     return ret;
0216 }
0217 TIMER_OF_DECLARE(sun4i, "allwinner,sun4i-a10-timer",
0218                sun4i_timer_init);
0219 TIMER_OF_DECLARE(sun8i_a23, "allwinner,sun8i-a23-timer",
0220          sun4i_timer_init);
0221 TIMER_OF_DECLARE(sun8i_v3s, "allwinner,sun8i-v3s-timer",
0222          sun4i_timer_init);
0223 TIMER_OF_DECLARE(suniv, "allwinner,suniv-f1c100s-timer",
0224                sun4i_timer_init);