root/drivers/clocksource/dw_apb_timer_of.c

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

DEFINITIONS

This source file includes following definitions.
  1. timer_get_base_and_rate
  2. add_clockevent
  3. add_clocksource
  4. read_sched_clock
  5. init_sched_clock
  6. dw_apb_delay_timer_read
  7. dw_apb_timer_init

   1 // SPDX-License-Identifier: GPL-2.0-only
   2 /*
   3  * Copyright (C) 2012 Altera Corporation
   4  * Copyright (c) 2011 Picochip Ltd., Jamie Iles
   5  *
   6  * Modified from mach-picoxcell/time.c
   7  */
   8 #include <linux/delay.h>
   9 #include <linux/dw_apb_timer.h>
  10 #include <linux/of.h>
  11 #include <linux/of_address.h>
  12 #include <linux/of_irq.h>
  13 #include <linux/clk.h>
  14 #include <linux/reset.h>
  15 #include <linux/sched_clock.h>
  16 
  17 static void __init timer_get_base_and_rate(struct device_node *np,
  18                                     void __iomem **base, u32 *rate)
  19 {
  20         struct clk *timer_clk;
  21         struct clk *pclk;
  22         struct reset_control *rstc;
  23 
  24         *base = of_iomap(np, 0);
  25 
  26         if (!*base)
  27                 panic("Unable to map regs for %pOFn", np);
  28 
  29         /*
  30          * Reset the timer if the reset control is available, wiping
  31          * out the state the firmware may have left it
  32          */
  33         rstc = of_reset_control_get(np, NULL);
  34         if (!IS_ERR(rstc)) {
  35                 reset_control_assert(rstc);
  36                 reset_control_deassert(rstc);
  37         }
  38 
  39         /*
  40          * Not all implementations use a periphal clock, so don't panic
  41          * if it's not present
  42          */
  43         pclk = of_clk_get_by_name(np, "pclk");
  44         if (!IS_ERR(pclk))
  45                 if (clk_prepare_enable(pclk))
  46                         pr_warn("pclk for %pOFn is present, but could not be activated\n",
  47                                 np);
  48 
  49         timer_clk = of_clk_get_by_name(np, "timer");
  50         if (IS_ERR(timer_clk))
  51                 goto try_clock_freq;
  52 
  53         if (!clk_prepare_enable(timer_clk)) {
  54                 *rate = clk_get_rate(timer_clk);
  55                 return;
  56         }
  57 
  58 try_clock_freq:
  59         if (of_property_read_u32(np, "clock-freq", rate) &&
  60             of_property_read_u32(np, "clock-frequency", rate))
  61                 panic("No clock nor clock-frequency property for %pOFn", np);
  62 }
  63 
  64 static void __init add_clockevent(struct device_node *event_timer)
  65 {
  66         void __iomem *iobase;
  67         struct dw_apb_clock_event_device *ced;
  68         u32 irq, rate;
  69 
  70         irq = irq_of_parse_and_map(event_timer, 0);
  71         if (irq == 0)
  72                 panic("No IRQ for clock event timer");
  73 
  74         timer_get_base_and_rate(event_timer, &iobase, &rate);
  75 
  76         ced = dw_apb_clockevent_init(0, event_timer->name, 300, iobase, irq,
  77                                      rate);
  78         if (!ced)
  79                 panic("Unable to initialise clockevent device");
  80 
  81         dw_apb_clockevent_register(ced);
  82 }
  83 
  84 static void __iomem *sched_io_base;
  85 static u32 sched_rate;
  86 
  87 static void __init add_clocksource(struct device_node *source_timer)
  88 {
  89         void __iomem *iobase;
  90         struct dw_apb_clocksource *cs;
  91         u32 rate;
  92 
  93         timer_get_base_and_rate(source_timer, &iobase, &rate);
  94 
  95         cs = dw_apb_clocksource_init(300, source_timer->name, iobase, rate);
  96         if (!cs)
  97                 panic("Unable to initialise clocksource device");
  98 
  99         dw_apb_clocksource_start(cs);
 100         dw_apb_clocksource_register(cs);
 101 
 102         /*
 103          * Fallback to use the clocksource as sched_clock if no separate
 104          * timer is found. sched_io_base then points to the current_value
 105          * register of the clocksource timer.
 106          */
 107         sched_io_base = iobase + 0x04;
 108         sched_rate = rate;
 109 }
 110 
 111 static u64 notrace read_sched_clock(void)
 112 {
 113         return ~readl_relaxed(sched_io_base);
 114 }
 115 
 116 static const struct of_device_id sptimer_ids[] __initconst = {
 117         { .compatible = "picochip,pc3x2-rtc" },
 118         { /* Sentinel */ },
 119 };
 120 
 121 static void __init init_sched_clock(void)
 122 {
 123         struct device_node *sched_timer;
 124 
 125         sched_timer = of_find_matching_node(NULL, sptimer_ids);
 126         if (sched_timer) {
 127                 timer_get_base_and_rate(sched_timer, &sched_io_base,
 128                                         &sched_rate);
 129                 of_node_put(sched_timer);
 130         }
 131 
 132         sched_clock_register(read_sched_clock, 32, sched_rate);
 133 }
 134 
 135 #ifdef CONFIG_ARM
 136 static unsigned long dw_apb_delay_timer_read(void)
 137 {
 138         return ~readl_relaxed(sched_io_base);
 139 }
 140 
 141 static struct delay_timer dw_apb_delay_timer = {
 142         .read_current_timer     = dw_apb_delay_timer_read,
 143 };
 144 #endif
 145 
 146 static int num_called;
 147 static int __init dw_apb_timer_init(struct device_node *timer)
 148 {
 149         switch (num_called) {
 150         case 0:
 151                 pr_debug("%s: found clockevent timer\n", __func__);
 152                 add_clockevent(timer);
 153                 break;
 154         case 1:
 155                 pr_debug("%s: found clocksource timer\n", __func__);
 156                 add_clocksource(timer);
 157                 init_sched_clock();
 158 #ifdef CONFIG_ARM
 159                 dw_apb_delay_timer.freq = sched_rate;
 160                 register_current_timer_delay(&dw_apb_delay_timer);
 161 #endif
 162                 break;
 163         default:
 164                 break;
 165         }
 166 
 167         num_called++;
 168 
 169         return 0;
 170 }
 171 TIMER_OF_DECLARE(pc3x2_timer, "picochip,pc3x2-timer", dw_apb_timer_init);
 172 TIMER_OF_DECLARE(apb_timer_osc, "snps,dw-apb-timer-osc", dw_apb_timer_init);
 173 TIMER_OF_DECLARE(apb_timer_sp, "snps,dw-apb-timer-sp", dw_apb_timer_init);
 174 TIMER_OF_DECLARE(apb_timer, "snps,dw-apb-timer", dw_apb_timer_init);

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