Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /*
0003  * Amlogic Meson6 SoCs timer handling.
0004  *
0005  * Copyright (C) 2014 Carlo Caione <carlo@caione.org>
0006  *
0007  * Based on code from Amlogic, Inc
0008  */
0009 
0010 #include <linux/bitfield.h>
0011 #include <linux/bitops.h>
0012 #include <linux/clk.h>
0013 #include <linux/clockchips.h>
0014 #include <linux/interrupt.h>
0015 #include <linux/irq.h>
0016 #include <linux/irqreturn.h>
0017 #include <linux/sched_clock.h>
0018 #include <linux/of.h>
0019 #include <linux/of_address.h>
0020 #include <linux/of_irq.h>
0021 
0022 #ifdef CONFIG_ARM
0023 #include <linux/delay.h>
0024 #endif
0025 
0026 #define MESON_ISA_TIMER_MUX                 0x00
0027 #define MESON_ISA_TIMER_MUX_TIMERD_EN               BIT(19)
0028 #define MESON_ISA_TIMER_MUX_TIMERC_EN               BIT(18)
0029 #define MESON_ISA_TIMER_MUX_TIMERB_EN               BIT(17)
0030 #define MESON_ISA_TIMER_MUX_TIMERA_EN               BIT(16)
0031 #define MESON_ISA_TIMER_MUX_TIMERD_MODE             BIT(15)
0032 #define MESON_ISA_TIMER_MUX_TIMERC_MODE             BIT(14)
0033 #define MESON_ISA_TIMER_MUX_TIMERB_MODE             BIT(13)
0034 #define MESON_ISA_TIMER_MUX_TIMERA_MODE             BIT(12)
0035 #define MESON_ISA_TIMER_MUX_TIMERE_INPUT_CLOCK_MASK     GENMASK(10, 8)
0036 #define MESON_ISA_TIMER_MUX_TIMERE_INPUT_CLOCK_SYSTEM_CLOCK 0x0
0037 #define MESON_ISA_TIMER_MUX_TIMERE_INPUT_CLOCK_1US      0x1
0038 #define MESON_ISA_TIMER_MUX_TIMERE_INPUT_CLOCK_10US     0x2
0039 #define MESON_ISA_TIMER_MUX_TIMERE_INPUT_CLOCK_100US        0x3
0040 #define MESON_ISA_TIMER_MUX_TIMERE_INPUT_CLOCK_1MS      0x4
0041 #define MESON_ISA_TIMER_MUX_TIMERD_INPUT_CLOCK_MASK     GENMASK(7, 6)
0042 #define MESON_ISA_TIMER_MUX_TIMERC_INPUT_CLOCK_MASK     GENMASK(5, 4)
0043 #define MESON_ISA_TIMER_MUX_TIMERB_INPUT_CLOCK_MASK     GENMASK(3, 2)
0044 #define MESON_ISA_TIMER_MUX_TIMERA_INPUT_CLOCK_MASK     GENMASK(1, 0)
0045 #define MESON_ISA_TIMER_MUX_TIMERABCD_INPUT_CLOCK_1US       0x0
0046 #define MESON_ISA_TIMER_MUX_TIMERABCD_INPUT_CLOCK_10US      0x1
0047 #define MESON_ISA_TIMER_MUX_TIMERABCD_INPUT_CLOCK_100US     0x0
0048 #define MESON_ISA_TIMER_MUX_TIMERABCD_INPUT_CLOCK_1MS       0x3
0049 
0050 #define MESON_ISA_TIMERA                    0x04
0051 #define MESON_ISA_TIMERB                    0x08
0052 #define MESON_ISA_TIMERC                    0x0c
0053 #define MESON_ISA_TIMERD                    0x10
0054 #define MESON_ISA_TIMERE                    0x14
0055 
0056 static void __iomem *timer_base;
0057 
0058 #ifdef CONFIG_ARM
0059 static unsigned long meson6_read_current_timer(void)
0060 {
0061     return readl_relaxed(timer_base + MESON_ISA_TIMERE);
0062 }
0063 
0064 static struct delay_timer meson6_delay_timer = {
0065     .read_current_timer = meson6_read_current_timer,
0066     .freq = 1000 * 1000,
0067 };
0068 #endif
0069 
0070 static u64 notrace meson6_timer_sched_read(void)
0071 {
0072     return (u64)readl(timer_base + MESON_ISA_TIMERE);
0073 }
0074 
0075 static void meson6_clkevt_time_stop(void)
0076 {
0077     u32 val = readl(timer_base + MESON_ISA_TIMER_MUX);
0078 
0079     writel(val & ~MESON_ISA_TIMER_MUX_TIMERA_EN,
0080            timer_base + MESON_ISA_TIMER_MUX);
0081 }
0082 
0083 static void meson6_clkevt_time_setup(unsigned long delay)
0084 {
0085     writel(delay, timer_base + MESON_ISA_TIMERA);
0086 }
0087 
0088 static void meson6_clkevt_time_start(bool periodic)
0089 {
0090     u32 val = readl(timer_base + MESON_ISA_TIMER_MUX);
0091 
0092     if (periodic)
0093         val |= MESON_ISA_TIMER_MUX_TIMERA_MODE;
0094     else
0095         val &= ~MESON_ISA_TIMER_MUX_TIMERA_MODE;
0096 
0097     writel(val | MESON_ISA_TIMER_MUX_TIMERA_EN,
0098            timer_base + MESON_ISA_TIMER_MUX);
0099 }
0100 
0101 static int meson6_shutdown(struct clock_event_device *evt)
0102 {
0103     meson6_clkevt_time_stop();
0104     return 0;
0105 }
0106 
0107 static int meson6_set_oneshot(struct clock_event_device *evt)
0108 {
0109     meson6_clkevt_time_stop();
0110     meson6_clkevt_time_start(false);
0111     return 0;
0112 }
0113 
0114 static int meson6_set_periodic(struct clock_event_device *evt)
0115 {
0116     meson6_clkevt_time_stop();
0117     meson6_clkevt_time_setup(USEC_PER_SEC / HZ - 1);
0118     meson6_clkevt_time_start(true);
0119     return 0;
0120 }
0121 
0122 static int meson6_clkevt_next_event(unsigned long evt,
0123                     struct clock_event_device *unused)
0124 {
0125     meson6_clkevt_time_stop();
0126     meson6_clkevt_time_setup(evt);
0127     meson6_clkevt_time_start(false);
0128 
0129     return 0;
0130 }
0131 
0132 static struct clock_event_device meson6_clockevent = {
0133     .name           = "meson6_tick",
0134     .rating         = 400,
0135     .features       = CLOCK_EVT_FEAT_PERIODIC |
0136                   CLOCK_EVT_FEAT_ONESHOT,
0137     .set_state_shutdown = meson6_shutdown,
0138     .set_state_periodic = meson6_set_periodic,
0139     .set_state_oneshot  = meson6_set_oneshot,
0140     .tick_resume        = meson6_shutdown,
0141     .set_next_event     = meson6_clkevt_next_event,
0142 };
0143 
0144 static irqreturn_t meson6_timer_interrupt(int irq, void *dev_id)
0145 {
0146     struct clock_event_device *evt = (struct clock_event_device *)dev_id;
0147 
0148     evt->event_handler(evt);
0149 
0150     return IRQ_HANDLED;
0151 }
0152 
0153 static int __init meson6_timer_init(struct device_node *node)
0154 {
0155     u32 val;
0156     int ret, irq;
0157 
0158     timer_base = of_io_request_and_map(node, 0, "meson6-timer");
0159     if (IS_ERR(timer_base)) {
0160         pr_err("Can't map registers\n");
0161         return -ENXIO;
0162     }
0163 
0164     irq = irq_of_parse_and_map(node, 0);
0165     if (irq <= 0) {
0166         pr_err("Can't parse IRQ\n");
0167         return -EINVAL;
0168     }
0169 
0170     /* Set 1us for timer E */
0171     val = readl(timer_base + MESON_ISA_TIMER_MUX);
0172     val &= ~MESON_ISA_TIMER_MUX_TIMERE_INPUT_CLOCK_MASK;
0173     val |= FIELD_PREP(MESON_ISA_TIMER_MUX_TIMERE_INPUT_CLOCK_MASK,
0174               MESON_ISA_TIMER_MUX_TIMERE_INPUT_CLOCK_1US);
0175     writel(val, timer_base + MESON_ISA_TIMER_MUX);
0176 
0177     sched_clock_register(meson6_timer_sched_read, 32, USEC_PER_SEC);
0178     clocksource_mmio_init(timer_base + MESON_ISA_TIMERE, node->name,
0179                   1000 * 1000, 300, 32, clocksource_mmio_readl_up);
0180 
0181     /* Timer A base 1us */
0182     val &= ~MESON_ISA_TIMER_MUX_TIMERA_INPUT_CLOCK_MASK;
0183     val |= FIELD_PREP(MESON_ISA_TIMER_MUX_TIMERA_INPUT_CLOCK_MASK,
0184               MESON_ISA_TIMER_MUX_TIMERABCD_INPUT_CLOCK_1US);
0185     writel(val, timer_base + MESON_ISA_TIMER_MUX);
0186 
0187     /* Stop the timer A */
0188     meson6_clkevt_time_stop();
0189 
0190     ret = request_irq(irq, meson6_timer_interrupt,
0191               IRQF_TIMER | IRQF_IRQPOLL, "meson6_timer",
0192               &meson6_clockevent);
0193     if (ret) {
0194         pr_warn("failed to setup irq %d\n", irq);
0195         return ret;
0196     }
0197 
0198     meson6_clockevent.cpumask = cpu_possible_mask;
0199     meson6_clockevent.irq = irq;
0200 
0201     clockevents_config_and_register(&meson6_clockevent, USEC_PER_SEC,
0202                     1, 0xfffe);
0203 
0204 #ifdef CONFIG_ARM
0205     /* Also use MESON_ISA_TIMERE for delays */
0206     register_current_timer_delay(&meson6_delay_timer);
0207 #endif
0208 
0209     return 0;
0210 }
0211 TIMER_OF_DECLARE(meson6, "amlogic,meson6-timer",
0212                meson6_timer_init);