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