Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /*
0003  * Marvell Orion SoC timer handling.
0004  *
0005  * Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com>
0006  *
0007  * Timer 0 is used as free-running clocksource, while timer 1 is
0008  * used as clock_event_device.
0009  */
0010 
0011 #include <linux/kernel.h>
0012 #include <linux/bitops.h>
0013 #include <linux/clk.h>
0014 #include <linux/clockchips.h>
0015 #include <linux/delay.h>
0016 #include <linux/interrupt.h>
0017 #include <linux/of_address.h>
0018 #include <linux/of_irq.h>
0019 #include <linux/spinlock.h>
0020 #include <linux/sched_clock.h>
0021 
0022 #define TIMER_CTRL      0x00
0023 #define  TIMER0_EN      BIT(0)
0024 #define  TIMER0_RELOAD_EN   BIT(1)
0025 #define  TIMER1_EN      BIT(2)
0026 #define  TIMER1_RELOAD_EN   BIT(3)
0027 #define TIMER0_RELOAD       0x10
0028 #define TIMER0_VAL      0x14
0029 #define TIMER1_RELOAD       0x18
0030 #define TIMER1_VAL      0x1c
0031 
0032 #define ORION_ONESHOT_MIN   1
0033 #define ORION_ONESHOT_MAX   0xfffffffe
0034 
0035 static void __iomem *timer_base;
0036 
0037 static unsigned long notrace orion_read_timer(void)
0038 {
0039     return ~readl(timer_base + TIMER0_VAL);
0040 }
0041 
0042 static struct delay_timer orion_delay_timer = {
0043     .read_current_timer = orion_read_timer,
0044 };
0045 
0046 static void orion_delay_timer_init(unsigned long rate)
0047 {
0048     orion_delay_timer.freq = rate;
0049     register_current_timer_delay(&orion_delay_timer);
0050 }
0051 
0052 /*
0053  * Free-running clocksource handling.
0054  */
0055 static u64 notrace orion_read_sched_clock(void)
0056 {
0057     return ~readl(timer_base + TIMER0_VAL);
0058 }
0059 
0060 /*
0061  * Clockevent handling.
0062  */
0063 static u32 ticks_per_jiffy;
0064 
0065 static int orion_clkevt_next_event(unsigned long delta,
0066                    struct clock_event_device *dev)
0067 {
0068     /* setup and enable one-shot timer */
0069     writel(delta, timer_base + TIMER1_VAL);
0070     atomic_io_modify(timer_base + TIMER_CTRL,
0071         TIMER1_RELOAD_EN | TIMER1_EN, TIMER1_EN);
0072 
0073     return 0;
0074 }
0075 
0076 static int orion_clkevt_shutdown(struct clock_event_device *dev)
0077 {
0078     /* disable timer */
0079     atomic_io_modify(timer_base + TIMER_CTRL,
0080              TIMER1_RELOAD_EN | TIMER1_EN, 0);
0081     return 0;
0082 }
0083 
0084 static int orion_clkevt_set_periodic(struct clock_event_device *dev)
0085 {
0086     /* setup and enable periodic timer at 1/HZ intervals */
0087     writel(ticks_per_jiffy - 1, timer_base + TIMER1_RELOAD);
0088     writel(ticks_per_jiffy - 1, timer_base + TIMER1_VAL);
0089     atomic_io_modify(timer_base + TIMER_CTRL,
0090              TIMER1_RELOAD_EN | TIMER1_EN,
0091              TIMER1_RELOAD_EN | TIMER1_EN);
0092     return 0;
0093 }
0094 
0095 static struct clock_event_device orion_clkevt = {
0096     .name           = "orion_event",
0097     .features       = CLOCK_EVT_FEAT_ONESHOT |
0098                   CLOCK_EVT_FEAT_PERIODIC,
0099     .shift          = 32,
0100     .rating         = 300,
0101     .set_next_event     = orion_clkevt_next_event,
0102     .set_state_shutdown = orion_clkevt_shutdown,
0103     .set_state_periodic = orion_clkevt_set_periodic,
0104     .set_state_oneshot  = orion_clkevt_shutdown,
0105     .tick_resume        = orion_clkevt_shutdown,
0106 };
0107 
0108 static irqreturn_t orion_clkevt_irq_handler(int irq, void *dev_id)
0109 {
0110     orion_clkevt.event_handler(&orion_clkevt);
0111     return IRQ_HANDLED;
0112 }
0113 
0114 static int __init orion_timer_init(struct device_node *np)
0115 {
0116     unsigned long rate;
0117     struct clk *clk;
0118     int irq, ret;
0119 
0120     /* timer registers are shared with watchdog timer */
0121     timer_base = of_iomap(np, 0);
0122     if (!timer_base) {
0123         pr_err("%pOFn: unable to map resource\n", np);
0124         return -ENXIO;
0125     }
0126 
0127     clk = of_clk_get(np, 0);
0128     if (IS_ERR(clk)) {
0129         pr_err("%pOFn: unable to get clk\n", np);
0130         return PTR_ERR(clk);
0131     }
0132 
0133     ret = clk_prepare_enable(clk);
0134     if (ret) {
0135         pr_err("Failed to prepare clock\n");
0136         return ret;
0137     }
0138 
0139     /* we are only interested in timer1 irq */
0140     irq = irq_of_parse_and_map(np, 1);
0141     if (irq <= 0) {
0142         pr_err("%pOFn: unable to parse timer1 irq\n", np);
0143         ret = -EINVAL;
0144         goto out_unprep_clk;
0145     }
0146 
0147     rate = clk_get_rate(clk);
0148 
0149     /* setup timer0 as free-running clocksource */
0150     writel(~0, timer_base + TIMER0_VAL);
0151     writel(~0, timer_base + TIMER0_RELOAD);
0152     atomic_io_modify(timer_base + TIMER_CTRL,
0153         TIMER0_RELOAD_EN | TIMER0_EN,
0154         TIMER0_RELOAD_EN | TIMER0_EN);
0155 
0156     ret = clocksource_mmio_init(timer_base + TIMER0_VAL,
0157                     "orion_clocksource", rate, 300, 32,
0158                     clocksource_mmio_readl_down);
0159     if (ret) {
0160         pr_err("Failed to initialize mmio timer\n");
0161         goto out_unprep_clk;
0162     }
0163 
0164     sched_clock_register(orion_read_sched_clock, 32, rate);
0165 
0166     /* setup timer1 as clockevent timer */
0167     ret = request_irq(irq, orion_clkevt_irq_handler, IRQF_TIMER,
0168               "orion_event", NULL);
0169     if (ret) {
0170         pr_err("%pOFn: unable to setup irq\n", np);
0171         goto out_unprep_clk;
0172     }
0173 
0174     ticks_per_jiffy = (clk_get_rate(clk) + HZ/2) / HZ;
0175     orion_clkevt.cpumask = cpumask_of(0);
0176     orion_clkevt.irq = irq;
0177     clockevents_config_and_register(&orion_clkevt, rate,
0178                     ORION_ONESHOT_MIN, ORION_ONESHOT_MAX);
0179 
0180 
0181     orion_delay_timer_init(rate);
0182 
0183     return 0;
0184 
0185 out_unprep_clk:
0186     clk_disable_unprepare(clk);
0187     return ret;
0188 }
0189 TIMER_OF_DECLARE(orion_timer, "marvell,orion-timer", orion_timer_init);