]>
Commit | Line | Data |
---|---|---|
896e2ca9 LW |
1 | /* |
2 | * (C) Copyright 2011 | |
3 | * Marvell Semiconductor <www.marvell.com> | |
4 | * Written-by: Lei Wen <leiwen@marvell.com> | |
5 | * | |
1a459660 | 6 | * SPDX-License-Identifier: GPL-2.0+ |
896e2ca9 LW |
7 | */ |
8 | ||
9 | #include <common.h> | |
0c0d9b70 | 10 | #include <asm/arch/cpu.h> |
896e2ca9 LW |
11 | #include <asm/arch/pantheon.h> |
12 | ||
13 | /* | |
14 | * Timer registers | |
15 | * Refer 6.2.9 in Datasheet | |
16 | */ | |
17 | struct panthtmr_registers { | |
18 | u32 clk_ctrl; /* Timer clk control reg */ | |
19 | u32 match[9]; /* Timer match registers */ | |
20 | u32 count[3]; /* Timer count registers */ | |
21 | u32 status[3]; | |
22 | u32 ie[3]; | |
23 | u32 preload[3]; /* Timer preload value */ | |
24 | u32 preload_ctrl[3]; | |
25 | u32 wdt_match_en; | |
26 | u32 wdt_match_r; | |
27 | u32 wdt_val; | |
28 | u32 wdt_sts; | |
29 | u32 icr[3]; | |
30 | u32 wdt_icr; | |
31 | u32 cer; /* Timer count enable reg */ | |
32 | u32 cmr; | |
33 | u32 ilr[3]; | |
34 | u32 wcr; | |
35 | u32 wfar; | |
36 | u32 wsar; | |
37 | u32 cvwr[3]; | |
38 | }; | |
39 | ||
40 | #define TIMER 0 /* Use TIMER 0 */ | |
41 | /* Each timer has 3 match registers */ | |
42 | #define MATCH_CMP(x) ((3 * TIMER) + x) | |
43 | #define TIMER_LOAD_VAL 0xffffffff | |
44 | #define COUNT_RD_REQ 0x1 | |
45 | ||
46 | DECLARE_GLOBAL_DATA_PTR; | |
66ee6923 | 47 | /* Using gd->arch.tbu from timestamp and gd->arch.tbl for lastdec */ |
896e2ca9 LW |
48 | |
49 | /* | |
50 | * For preventing risk of instability in reading counter value, | |
51 | * first set read request to register cvwr and then read same | |
52 | * register after it captures counter value. | |
53 | */ | |
54 | ulong read_timer(void) | |
55 | { | |
56 | struct panthtmr_registers *panthtimers = | |
57 | (struct panthtmr_registers *) PANTHEON_TIMER_BASE; | |
58 | volatile int loop=100; | |
59 | ulong val; | |
60 | ||
61 | writel(COUNT_RD_REQ, &panthtimers->cvwr); | |
62 | while (loop--) | |
63 | val = readl(&panthtimers->cvwr); | |
64 | ||
65 | /* | |
66 | * This stop gcc complain and prevent loop mistake init to 0 | |
67 | */ | |
68 | val = readl(&panthtimers->cvwr); | |
69 | ||
70 | return val; | |
71 | } | |
72 | ||
896e2ca9 LW |
73 | ulong get_timer_masked(void) |
74 | { | |
75 | ulong now = read_timer(); | |
76 | ||
66ee6923 | 77 | if (now >= gd->arch.tbl) { |
896e2ca9 | 78 | /* normal mode */ |
66ee6923 | 79 | gd->arch.tbu += now - gd->arch.tbl; |
896e2ca9 LW |
80 | } else { |
81 | /* we have an overflow ... */ | |
66ee6923 | 82 | gd->arch.tbu += now + TIMER_LOAD_VAL - gd->arch.tbl; |
896e2ca9 | 83 | } |
66ee6923 | 84 | gd->arch.tbl = now; |
896e2ca9 | 85 | |
8ff43b03 | 86 | return gd->arch.tbu; |
896e2ca9 LW |
87 | } |
88 | ||
896e2ca9 LW |
89 | ulong get_timer(ulong base) |
90 | { | |
91 | return ((get_timer_masked() / (CONFIG_SYS_HZ_CLOCK / 1000)) - | |
92 | base); | |
93 | } | |
94 | ||
896e2ca9 LW |
95 | void __udelay(unsigned long usec) |
96 | { | |
97 | ulong delayticks; | |
98 | ulong endtime; | |
99 | ||
100 | delayticks = (usec * (CONFIG_SYS_HZ_CLOCK / 1000000)); | |
101 | endtime = get_timer_masked() + delayticks; | |
102 | ||
103 | while (get_timer_masked() < endtime) | |
104 | ; | |
105 | } | |
106 | ||
107 | /* | |
108 | * init the Timer | |
109 | */ | |
110 | int timer_init(void) | |
111 | { | |
112 | struct panthapb_registers *apb1clkres = | |
113 | (struct panthapb_registers *) PANTHEON_APBC_BASE; | |
114 | struct panthtmr_registers *panthtimers = | |
115 | (struct panthtmr_registers *) PANTHEON_TIMER_BASE; | |
116 | ||
117 | /* Enable Timer clock at 3.25 MHZ */ | |
118 | writel(APBC_APBCLK | APBC_FNCLK | APBC_FNCLKSEL(3), &apb1clkres->timers); | |
119 | ||
120 | /* load value into timer */ | |
121 | writel(0x0, &panthtimers->clk_ctrl); | |
122 | /* Use Timer 0 Match Resiger 0 */ | |
123 | writel(TIMER_LOAD_VAL, &panthtimers->match[MATCH_CMP(0)]); | |
124 | /* Preload value is 0 */ | |
125 | writel(0x0, &panthtimers->preload[TIMER]); | |
126 | /* Enable match comparator 0 for Timer 0 */ | |
127 | writel(0x1, &panthtimers->preload_ctrl[TIMER]); | |
128 | ||
129 | /* Enable timer 0 */ | |
130 | writel(0x1, &panthtimers->cer); | |
66ee6923 SG |
131 | /* init the gd->arch.tbu and gd->arch.tbl value */ |
132 | gd->arch.tbl = read_timer(); | |
8ff43b03 | 133 | gd->arch.tbu = 0; |
896e2ca9 LW |
134 | |
135 | return 0; | |
136 | } | |
137 | ||
138 | #define MPMU_APRR_WDTR (1<<4) | |
139 | #define TMR_WFAR 0xbaba /* WDT Register First key */ | |
140 | #define TMP_WSAR 0xeb10 /* WDT Register Second key */ | |
141 | ||
142 | /* | |
143 | * This function uses internal Watchdog Timer | |
144 | * based reset mechanism. | |
145 | * Steps to write watchdog registers (protected access) | |
146 | * 1. Write key value to TMR_WFAR reg. | |
147 | * 2. Write key value to TMP_WSAR reg. | |
148 | * 3. Perform write operation. | |
149 | */ | |
150 | void reset_cpu (unsigned long ignored) | |
151 | { | |
152 | struct panthmpmu_registers *mpmu = | |
153 | (struct panthmpmu_registers *) PANTHEON_MPMU_BASE; | |
154 | struct panthtmr_registers *panthtimers = | |
155 | (struct panthtmr_registers *) PANTHEON_WD_TIMER_BASE; | |
156 | u32 val; | |
157 | ||
158 | /* negate hardware reset to the WDT after system reset */ | |
159 | val = readl(&mpmu->aprr); | |
160 | val = val | MPMU_APRR_WDTR; | |
161 | writel(val, &mpmu->aprr); | |
162 | ||
163 | /* reset/enable WDT clock */ | |
164 | writel(APBC_APBCLK, &mpmu->wdtpcr); | |
165 | ||
166 | /* clear previous WDT status */ | |
167 | writel(TMR_WFAR, &panthtimers->wfar); | |
168 | writel(TMP_WSAR, &panthtimers->wsar); | |
169 | writel(0, &panthtimers->wdt_sts); | |
170 | ||
171 | /* set match counter */ | |
172 | writel(TMR_WFAR, &panthtimers->wfar); | |
173 | writel(TMP_WSAR, &panthtimers->wsar); | |
174 | writel(0xf, &panthtimers->wdt_match_r); | |
175 | ||
176 | /* enable WDT reset */ | |
177 | writel(TMR_WFAR, &panthtimers->wfar); | |
178 | writel(TMP_WSAR, &panthtimers->wsar); | |
179 | writel(0x3, &panthtimers->wdt_match_en); | |
180 | ||
181 | /*enable functional WDT clock */ | |
182 | writel(APBC_APBCLK | APBC_FNCLK, &mpmu->wdtpcr); | |
183 | } | |
96f5c4b2 PW |
184 | |
185 | /* | |
186 | * This function is derived from PowerPC code (read timebase as long long). | |
187 | * On ARM it just returns the timer value. | |
188 | */ | |
189 | unsigned long long get_ticks(void) | |
190 | { | |
191 | return get_timer(0); | |
192 | } | |
193 | ||
194 | /* | |
195 | * This function is derived from PowerPC code (timebase clock frequency). | |
196 | * On ARM it returns the number of timer ticks per second. | |
197 | */ | |
198 | ulong get_tbclk (void) | |
199 | { | |
200 | return (ulong)CONFIG_SYS_HZ; | |
201 | } |