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