Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /*
0003  * Integrator/AP timer driver
0004  * Copyright (C) 2000-2003 Deep Blue Solutions Ltd
0005  * Copyright (c) 2014, Linaro Limited
0006  */
0007 
0008 #include <linux/clk.h>
0009 #include <linux/clocksource.h>
0010 #include <linux/of_irq.h>
0011 #include <linux/of_address.h>
0012 #include <linux/of_platform.h>
0013 #include <linux/clockchips.h>
0014 #include <linux/interrupt.h>
0015 #include <linux/sched_clock.h>
0016 
0017 #include "timer-sp.h"
0018 
0019 static void __iomem * sched_clk_base;
0020 
0021 static u64 notrace integrator_read_sched_clock(void)
0022 {
0023     return -readl(sched_clk_base + TIMER_VALUE);
0024 }
0025 
0026 static int __init integrator_clocksource_init(unsigned long inrate,
0027                           void __iomem *base)
0028 {
0029     u32 ctrl = TIMER_CTRL_ENABLE | TIMER_CTRL_PERIODIC;
0030     unsigned long rate = inrate;
0031     int ret;
0032 
0033     if (rate >= 1500000) {
0034         rate /= 16;
0035         ctrl |= TIMER_CTRL_DIV16;
0036     }
0037 
0038     writel(0xffff, base + TIMER_LOAD);
0039     writel(ctrl, base + TIMER_CTRL);
0040 
0041     ret = clocksource_mmio_init(base + TIMER_VALUE, "timer2",
0042                     rate, 200, 16, clocksource_mmio_readl_down);
0043     if (ret)
0044         return ret;
0045 
0046     sched_clk_base = base;
0047     sched_clock_register(integrator_read_sched_clock, 16, rate);
0048 
0049     return 0;
0050 }
0051 
0052 static unsigned long timer_reload;
0053 static void __iomem * clkevt_base;
0054 
0055 /*
0056  * IRQ handler for the timer
0057  */
0058 static irqreturn_t integrator_timer_interrupt(int irq, void *dev_id)
0059 {
0060     struct clock_event_device *evt = dev_id;
0061 
0062     /* clear the interrupt */
0063     writel(1, clkevt_base + TIMER_INTCLR);
0064 
0065     evt->event_handler(evt);
0066 
0067     return IRQ_HANDLED;
0068 }
0069 
0070 static int clkevt_shutdown(struct clock_event_device *evt)
0071 {
0072     u32 ctrl = readl(clkevt_base + TIMER_CTRL) & ~TIMER_CTRL_ENABLE;
0073 
0074     /* Disable timer */
0075     writel(ctrl, clkevt_base + TIMER_CTRL);
0076     return 0;
0077 }
0078 
0079 static int clkevt_set_oneshot(struct clock_event_device *evt)
0080 {
0081     u32 ctrl = readl(clkevt_base + TIMER_CTRL) &
0082            ~(TIMER_CTRL_ENABLE | TIMER_CTRL_PERIODIC);
0083 
0084     /* Leave the timer disabled, .set_next_event will enable it */
0085     writel(ctrl, clkevt_base + TIMER_CTRL);
0086     return 0;
0087 }
0088 
0089 static int clkevt_set_periodic(struct clock_event_device *evt)
0090 {
0091     u32 ctrl = readl(clkevt_base + TIMER_CTRL) & ~TIMER_CTRL_ENABLE;
0092 
0093     /* Disable timer */
0094     writel(ctrl, clkevt_base + TIMER_CTRL);
0095 
0096     /* Enable the timer and start the periodic tick */
0097     writel(timer_reload, clkevt_base + TIMER_LOAD);
0098     ctrl |= TIMER_CTRL_PERIODIC | TIMER_CTRL_ENABLE;
0099     writel(ctrl, clkevt_base + TIMER_CTRL);
0100     return 0;
0101 }
0102 
0103 static int clkevt_set_next_event(unsigned long next, struct clock_event_device *evt)
0104 {
0105     unsigned long ctrl = readl(clkevt_base + TIMER_CTRL);
0106 
0107     writel(ctrl & ~TIMER_CTRL_ENABLE, clkevt_base + TIMER_CTRL);
0108     writel(next, clkevt_base + TIMER_LOAD);
0109     writel(ctrl | TIMER_CTRL_ENABLE, clkevt_base + TIMER_CTRL);
0110 
0111     return 0;
0112 }
0113 
0114 static struct clock_event_device integrator_clockevent = {
0115     .name           = "timer1",
0116     .features       = CLOCK_EVT_FEAT_PERIODIC |
0117                   CLOCK_EVT_FEAT_ONESHOT,
0118     .set_state_shutdown = clkevt_shutdown,
0119     .set_state_periodic = clkevt_set_periodic,
0120     .set_state_oneshot  = clkevt_set_oneshot,
0121     .tick_resume        = clkevt_shutdown,
0122     .set_next_event     = clkevt_set_next_event,
0123     .rating         = 300,
0124 };
0125 
0126 static int integrator_clockevent_init(unsigned long inrate,
0127                       void __iomem *base, int irq)
0128 {
0129     unsigned long rate = inrate;
0130     unsigned int ctrl = 0;
0131     int ret;
0132 
0133     clkevt_base = base;
0134     /* Calculate and program a divisor */
0135     if (rate > 0x100000 * HZ) {
0136         rate /= 256;
0137         ctrl |= TIMER_CTRL_DIV256;
0138     } else if (rate > 0x10000 * HZ) {
0139         rate /= 16;
0140         ctrl |= TIMER_CTRL_DIV16;
0141     }
0142     timer_reload = rate / HZ;
0143     writel(ctrl, clkevt_base + TIMER_CTRL);
0144 
0145     ret = request_irq(irq, integrator_timer_interrupt,
0146               IRQF_TIMER | IRQF_IRQPOLL, "timer",
0147               &integrator_clockevent);
0148     if (ret)
0149         return ret;
0150 
0151     clockevents_config_and_register(&integrator_clockevent,
0152                     rate,
0153                     1,
0154                     0xffffU);
0155     return 0;
0156 }
0157 
0158 static int __init integrator_ap_timer_init_of(struct device_node *node)
0159 {
0160     const char *path;
0161     void __iomem *base;
0162     int err;
0163     int irq;
0164     struct clk *clk;
0165     unsigned long rate;
0166     struct device_node *alias_node;
0167 
0168     base = of_io_request_and_map(node, 0, "integrator-timer");
0169     if (IS_ERR(base))
0170         return PTR_ERR(base);
0171 
0172     clk = of_clk_get(node, 0);
0173     if (IS_ERR(clk)) {
0174         pr_err("No clock for %pOFn\n", node);
0175         return PTR_ERR(clk);
0176     }
0177     clk_prepare_enable(clk);
0178     rate = clk_get_rate(clk);
0179     writel(0, base + TIMER_CTRL);
0180 
0181     err = of_property_read_string(of_aliases,
0182                 "arm,timer-primary", &path);
0183     if (err) {
0184         pr_warn("Failed to read property\n");
0185         return err;
0186     }
0187 
0188     alias_node = of_find_node_by_path(path);
0189 
0190     /*
0191      * The pointer is used as an identifier not as a pointer, we
0192      * can drop the refcount on the of__node immediately after
0193      * getting it.
0194      */
0195     of_node_put(alias_node);
0196 
0197     if (node == alias_node)
0198         /* The primary timer lacks IRQ, use as clocksource */
0199         return integrator_clocksource_init(rate, base);
0200 
0201     err = of_property_read_string(of_aliases,
0202                 "arm,timer-secondary", &path);
0203     if (err) {
0204         pr_warn("Failed to read property\n");
0205         return err;
0206     }
0207 
0208     alias_node = of_find_node_by_path(path);
0209 
0210     of_node_put(alias_node);
0211 
0212     if (node == alias_node) {
0213         /* The secondary timer will drive the clock event */
0214         irq = irq_of_parse_and_map(node, 0);
0215         return integrator_clockevent_init(rate, base, irq);
0216     }
0217 
0218     pr_info("Timer @%p unused\n", base);
0219     clk_disable_unprepare(clk);
0220 
0221     return 0;
0222 }
0223 
0224 TIMER_OF_DECLARE(integrator_ap_timer, "arm,integrator-timer",
0225                integrator_ap_timer_init_of);