]>
Commit | Line | Data |
---|---|---|
1dbae815 | 1 | /* |
0f622e8c | 2 | * linux/arch/arm/mach-omap2/timer.c |
1dbae815 TL |
3 | * |
4 | * OMAP2 GP timer support. | |
5 | * | |
f248076c PW |
6 | * Copyright (C) 2009 Nokia Corporation |
7 | * | |
5a3a388f KH |
8 | * Update to use new clocksource/clockevent layers |
9 | * Author: Kevin Hilman, MontaVista Software, Inc. <source@mvista.com> | |
10 | * Copyright (C) 2007 MontaVista Software, Inc. | |
11 | * | |
12 | * Original driver: | |
1dbae815 TL |
13 | * Copyright (C) 2005 Nokia Corporation |
14 | * Author: Paul Mundt <paul.mundt@nokia.com> | |
96de0e25 | 15 | * Juha Yrjölä <juha.yrjola@nokia.com> |
77900a2f | 16 | * OMAP Dual-mode timer framework support by Timo Teras |
1dbae815 TL |
17 | * |
18 | * Some parts based off of TI's 24xx code: | |
19 | * | |
44169075 | 20 | * Copyright (C) 2004-2009 Texas Instruments, Inc. |
1dbae815 TL |
21 | * |
22 | * Roughly modelled after the OMAP1 MPU timer code. | |
44169075 | 23 | * Added OMAP4 support - Santosh Shilimkar <santosh.shilimkar@ti.com> |
1dbae815 TL |
24 | * |
25 | * This file is subject to the terms and conditions of the GNU General Public | |
26 | * License. See the file "COPYING" in the main directory of this archive | |
27 | * for more details. | |
28 | */ | |
f8ce2547 | 29 | #include <linux/clk.h> |
5a3a388f | 30 | #include <linux/clocksource.h> |
b481113a | 31 | |
dbc04161 | 32 | #include "soc.h" |
7d7e1eba | 33 | #include "common.h" |
afc9d590 | 34 | #include "control.h" |
5523e409 | 35 | #include "omap-secure.h" |
1dbae815 | 36 | |
fa6d79d2 SS |
37 | #define REALTIME_COUNTER_BASE 0x48243200 |
38 | #define INCREMENTER_NUMERATOR_OFFSET 0x10 | |
39 | #define INCREMENTER_DENUMERATOR_RELOAD_OFFSET 0x14 | |
40 | #define NUMERATOR_DENUMERATOR_MASK 0xfffff000 | |
41 | ||
5523e409 S |
42 | static unsigned long arch_timer_freq; |
43 | ||
44 | void set_cntfreq(void) | |
45 | { | |
46 | omap_smc1(OMAP5_DRA7_MON_SET_CNTFRQ_INDEX, arch_timer_freq); | |
47 | } | |
f248076c | 48 | |
fa6d79d2 SS |
49 | /* |
50 | * The realtime counter also called master counter, is a free-running | |
51 | * counter, which is related to real time. It produces the count used | |
52 | * by the CPU local timer peripherals in the MPU cluster. The timer counts | |
53 | * at a rate of 6.144 MHz. Because the device operates on different clocks | |
54 | * in different power modes, the master counter shifts operation between | |
55 | * clocks, adjusting the increment per clock in hardware accordingly to | |
56 | * maintain a constant count rate. | |
57 | */ | |
58 | static void __init realtime_counter_init(void) | |
59 | { | |
60 | void __iomem *base; | |
61 | static struct clk *sys_clk; | |
62 | unsigned long rate; | |
afc9d590 LS |
63 | unsigned int reg; |
64 | unsigned long long num, den; | |
fa6d79d2 SS |
65 | |
66 | base = ioremap(REALTIME_COUNTER_BASE, SZ_32); | |
67 | if (!base) { | |
68 | pr_err("%s: ioremap failed\n", __func__); | |
69 | return; | |
70 | } | |
7f585bbf | 71 | sys_clk = clk_get(NULL, "sys_clkin"); |
533b2981 | 72 | if (IS_ERR(sys_clk)) { |
fa6d79d2 SS |
73 | pr_err("%s: failed to get system clock handle\n", __func__); |
74 | iounmap(base); | |
75 | return; | |
76 | } | |
77 | ||
78 | rate = clk_get_rate(sys_clk); | |
afc9d590 LS |
79 | |
80 | if (soc_is_dra7xx()) { | |
81 | /* | |
82 | * Errata i856 says the 32.768KHz crystal does not start at | |
83 | * power on, so the CPU falls back to an emulated 32KHz clock | |
84 | * based on sysclk / 610 instead. This causes the master counter | |
85 | * frequency to not be 6.144MHz but at sysclk / 610 * 375 / 2 | |
86 | * (OR sysclk * 75 / 244) | |
87 | * | |
88 | * This affects at least the DRA7/AM572x 1.0, 1.1 revisions. | |
89 | * Of course any board built without a populated 32.768KHz | |
90 | * crystal would also need this fix even if the CPU is fixed | |
91 | * later. | |
92 | * | |
93 | * Either case can be detected by using the two speedselect bits | |
94 | * If they are not 0, then the 32.768KHz clock driving the | |
95 | * coarse counter that corrects the fine counter every time it | |
96 | * ticks is actually rate/610 rather than 32.768KHz and we | |
97 | * should compensate to avoid the 570ppm (at 20MHz, much worse | |
98 | * at other rates) too fast system time. | |
99 | */ | |
100 | reg = omap_ctrl_readl(DRA7_CTRL_CORE_BOOTSTRAP); | |
101 | if (reg & DRA7_SPEEDSELECT_MASK) { | |
102 | num = 75; | |
103 | den = 244; | |
104 | goto sysclk1_based; | |
105 | } | |
106 | } | |
107 | ||
fa6d79d2 SS |
108 | /* Numerator/denumerator values refer TRM Realtime Counter section */ |
109 | switch (rate) { | |
572b24e6 | 110 | case 12000000: |
fa6d79d2 SS |
111 | num = 64; |
112 | den = 125; | |
113 | break; | |
572b24e6 | 114 | case 13000000: |
fa6d79d2 SS |
115 | num = 768; |
116 | den = 1625; | |
117 | break; | |
118 | case 19200000: | |
119 | num = 8; | |
120 | den = 25; | |
121 | break; | |
38a1981c S |
122 | case 20000000: |
123 | num = 192; | |
124 | den = 625; | |
125 | break; | |
572b24e6 | 126 | case 26000000: |
fa6d79d2 SS |
127 | num = 384; |
128 | den = 1625; | |
129 | break; | |
572b24e6 | 130 | case 27000000: |
fa6d79d2 SS |
131 | num = 256; |
132 | den = 1125; | |
133 | break; | |
134 | case 38400000: | |
135 | default: | |
136 | /* Program it for 38.4 MHz */ | |
137 | num = 4; | |
138 | den = 25; | |
139 | break; | |
140 | } | |
141 | ||
afc9d590 | 142 | sysclk1_based: |
fa6d79d2 | 143 | /* Program numerator and denumerator registers */ |
edfaf05c | 144 | reg = readl_relaxed(base + INCREMENTER_NUMERATOR_OFFSET) & |
fa6d79d2 SS |
145 | NUMERATOR_DENUMERATOR_MASK; |
146 | reg |= num; | |
edfaf05c | 147 | writel_relaxed(reg, base + INCREMENTER_NUMERATOR_OFFSET); |
fa6d79d2 | 148 | |
edfaf05c | 149 | reg = readl_relaxed(base + INCREMENTER_DENUMERATOR_RELOAD_OFFSET) & |
fa6d79d2 SS |
150 | NUMERATOR_DENUMERATOR_MASK; |
151 | reg |= den; | |
edfaf05c | 152 | writel_relaxed(reg, base + INCREMENTER_DENUMERATOR_RELOAD_OFFSET); |
fa6d79d2 | 153 | |
afc9d590 | 154 | arch_timer_freq = DIV_ROUND_UP_ULL(rate * num, den); |
5523e409 S |
155 | set_cntfreq(); |
156 | ||
fa6d79d2 | 157 | iounmap(base); |
6f80b3bb IG |
158 | } |
159 | ||
6bb27d73 | 160 | void __init omap5_realtime_timer_init(void) |
fa6d79d2 | 161 | { |
036a3d42 | 162 | omap_clk_init(); |
fa6d79d2 | 163 | realtime_counter_init(); |
3c7c5dab | 164 | |
ba5d08c0 | 165 | timer_probe(); |
fa6d79d2 | 166 | } |