]>
Commit | Line | Data |
---|---|---|
15647dc7 WD |
1 | /* |
2 | * board/eva/phantom.c | |
3 | * | |
4 | * Phantom RTC device driver for EVA | |
5 | * | |
6 | * Author: Sangmoon Kim | |
7 | * dogoil@etinsys.com | |
8 | * | |
9 | * Copyright 2002 Etinsys Inc. | |
10 | * | |
1a459660 | 11 | * SPDX-License-Identifier: GPL-2.0+ |
15647dc7 WD |
12 | */ |
13 | ||
14 | #include <common.h> | |
15 | #include <command.h> | |
16 | #include <rtc.h> | |
17 | ||
b9307262 | 18 | #if defined(CONFIG_CMD_DATE) |
15647dc7 | 19 | |
6d0f6bcf | 20 | #define RTC_BASE (CONFIG_SYS_NVRAM_BASE_ADDR + 0x7fff8) |
15647dc7 WD |
21 | |
22 | #define RTC_YEAR ( RTC_BASE + 7 ) | |
23 | #define RTC_MONTH ( RTC_BASE + 6 ) | |
24 | #define RTC_DAY_OF_MONTH ( RTC_BASE + 5 ) | |
25 | #define RTC_DAY_OF_WEEK ( RTC_BASE + 4 ) | |
26 | #define RTC_HOURS ( RTC_BASE + 3 ) | |
27 | #define RTC_MINUTES ( RTC_BASE + 2 ) | |
28 | #define RTC_SECONDS ( RTC_BASE + 1 ) | |
29 | #define RTC_CENTURY ( RTC_BASE + 0 ) | |
30 | ||
31 | #define RTC_CONTROLA RTC_CENTURY | |
32 | #define RTC_CONTROLB RTC_SECONDS | |
33 | #define RTC_CONTROLC RTC_DAY_OF_WEEK | |
34 | ||
35 | #define RTC_CA_WRITE 0x80 | |
36 | #define RTC_CA_READ 0x40 | |
37 | ||
38 | #define RTC_CB_OSC_DISABLE 0x80 | |
39 | ||
40 | #define RTC_CC_BATTERY_FLAG 0x80 | |
41 | #define RTC_CC_FREQ_TEST 0x40 | |
42 | ||
43 | ||
44 | static int phantom_flag = -1; | |
45 | static int century_flag = -1; | |
46 | ||
47 | static uchar rtc_read(unsigned int addr) | |
48 | { | |
49 | return *(volatile unsigned char *)(addr); | |
50 | } | |
51 | ||
52 | static void rtc_write(unsigned int addr, uchar val) | |
53 | { | |
54 | *(volatile unsigned char *)(addr) = val; | |
55 | } | |
56 | ||
57 | static unsigned char phantom_rtc_sequence[] = { | |
58 | 0xc5, 0x3a, 0xa3, 0x5c, 0xc5, 0x3a, 0xa3, 0x5c | |
59 | }; | |
60 | ||
61 | static unsigned char* phantom_rtc_read(int addr, unsigned char rtc[8]) | |
62 | { | |
63 | int i, j; | |
64 | unsigned char v; | |
65 | unsigned char save = rtc_read(addr); | |
66 | ||
67 | for (j = 0; j < 8; j++) { | |
68 | v = phantom_rtc_sequence[j]; | |
69 | for (i = 0; i < 8; i++) { | |
70 | rtc_write(addr, v & 1); | |
71 | v >>= 1; | |
72 | } | |
73 | } | |
74 | for (j = 0; j < 8; j++) { | |
75 | v = 0; | |
76 | for (i = 0; i < 8; i++) { | |
77 | if(rtc_read(addr) & 1) | |
78 | v |= 1 << i; | |
79 | } | |
80 | rtc[j] = v; | |
81 | } | |
82 | rtc_write(addr, save); | |
83 | return rtc; | |
84 | } | |
85 | ||
86 | static void phantom_rtc_write(int addr, unsigned char rtc[8]) | |
87 | { | |
88 | int i, j; | |
89 | unsigned char v; | |
90 | unsigned char save = rtc_read(addr); | |
91 | for (j = 0; j < 8; j++) { | |
92 | v = phantom_rtc_sequence[j]; | |
93 | for (i = 0; i < 8; i++) { | |
94 | rtc_write(addr, v & 1); | |
95 | v >>= 1; | |
96 | } | |
97 | } | |
98 | for (j = 0; j < 8; j++) { | |
99 | v = rtc[j]; | |
100 | for (i = 0; i < 8; i++) { | |
101 | rtc_write(addr, v & 1); | |
102 | v >>= 1; | |
103 | } | |
104 | } | |
105 | rtc_write(addr, save); | |
106 | } | |
107 | ||
108 | static int get_phantom_flag(void) | |
109 | { | |
110 | int i; | |
111 | unsigned char rtc[8]; | |
112 | ||
113 | phantom_rtc_read(RTC_BASE, rtc); | |
114 | ||
115 | for(i = 1; i < 8; i++) { | |
116 | if (rtc[i] != rtc[0]) | |
117 | return 1; | |
118 | } | |
119 | return 0; | |
120 | } | |
121 | ||
122 | void rtc_reset(void) | |
123 | { | |
124 | if (phantom_flag < 0) | |
125 | phantom_flag = get_phantom_flag(); | |
126 | ||
127 | if (phantom_flag) { | |
128 | unsigned char rtc[8]; | |
129 | phantom_rtc_read(RTC_BASE, rtc); | |
130 | if(rtc[4] & 0x30) { | |
131 | printf( "real-time-clock was stopped. Now starting...\n" ); | |
132 | rtc[4] &= 0x07; | |
133 | phantom_rtc_write(RTC_BASE, rtc); | |
134 | } | |
135 | } else { | |
136 | uchar reg_a, reg_b, reg_c; | |
137 | reg_a = rtc_read( RTC_CONTROLA ); | |
138 | reg_b = rtc_read( RTC_CONTROLB ); | |
139 | ||
140 | if ( reg_b & RTC_CB_OSC_DISABLE ) | |
141 | { | |
142 | printf( "real-time-clock was stopped. Now starting...\n" ); | |
143 | reg_a |= RTC_CA_WRITE; | |
144 | reg_b &= ~RTC_CB_OSC_DISABLE; | |
145 | rtc_write( RTC_CONTROLA, reg_a ); | |
146 | rtc_write( RTC_CONTROLB, reg_b ); | |
147 | } | |
148 | ||
149 | /* make sure read/write clock register bits are cleared */ | |
150 | reg_a &= ~( RTC_CA_WRITE | RTC_CA_READ ); | |
151 | rtc_write( RTC_CONTROLA, reg_a ); | |
152 | ||
153 | reg_c = rtc_read( RTC_CONTROLC ); | |
154 | if (( reg_c & RTC_CC_BATTERY_FLAG ) == 0 ) | |
155 | printf( "RTC battery low. Clock setting may not be reliable.\n"); | |
156 | } | |
157 | } | |
158 | ||
15647dc7 WD |
159 | static int get_century_flag(void) |
160 | { | |
161 | int flag = 0; | |
162 | int bcd, century; | |
163 | bcd = rtc_read( RTC_CENTURY ); | |
164 | century = bcd2bin( bcd & 0x3F ); | |
165 | rtc_write( RTC_CENTURY, bin2bcd(century+1)); | |
166 | if (bcd == rtc_read( RTC_CENTURY )) | |
167 | flag = 1; | |
168 | rtc_write( RTC_CENTURY, bcd); | |
169 | return flag; | |
170 | } | |
171 | ||
b73a19e1 | 172 | int rtc_get( struct rtc_time *tmp) |
15647dc7 WD |
173 | { |
174 | if (phantom_flag < 0) | |
175 | phantom_flag = get_phantom_flag(); | |
176 | ||
177 | if (phantom_flag) | |
178 | { | |
179 | unsigned char rtc[8]; | |
180 | ||
181 | phantom_rtc_read(RTC_BASE, rtc); | |
182 | ||
183 | tmp->tm_sec = bcd2bin(rtc[1] & 0x7f); | |
184 | tmp->tm_min = bcd2bin(rtc[2] & 0x7f); | |
185 | tmp->tm_hour = bcd2bin(rtc[3] & 0x1f); | |
186 | tmp->tm_wday = bcd2bin(rtc[4] & 0x7); | |
187 | tmp->tm_mday = bcd2bin(rtc[5] & 0x3f); | |
188 | tmp->tm_mon = bcd2bin(rtc[6] & 0x1f); | |
189 | tmp->tm_year = bcd2bin(rtc[7]) + 1900; | |
190 | tmp->tm_yday = 0; | |
191 | tmp->tm_isdst = 0; | |
192 | ||
193 | if( (rtc[3] & 0x80) && (rtc[3] & 0x40) ) tmp->tm_hour += 12; | |
194 | if (tmp->tm_year < 1970) tmp->tm_year += 100; | |
195 | } else { | |
196 | uchar sec, min, hour; | |
197 | uchar mday, wday, mon, year; | |
198 | ||
199 | int century; | |
200 | ||
201 | uchar reg_a; | |
202 | ||
203 | if (century_flag < 0) | |
204 | century_flag = get_century_flag(); | |
205 | ||
206 | reg_a = rtc_read( RTC_CONTROLA ); | |
207 | /* lock clock registers for read */ | |
208 | rtc_write( RTC_CONTROLA, ( reg_a | RTC_CA_READ )); | |
209 | ||
210 | sec = rtc_read( RTC_SECONDS ); | |
211 | min = rtc_read( RTC_MINUTES ); | |
212 | hour = rtc_read( RTC_HOURS ); | |
213 | mday = rtc_read( RTC_DAY_OF_MONTH ); | |
214 | wday = rtc_read( RTC_DAY_OF_WEEK ); | |
215 | mon = rtc_read( RTC_MONTH ); | |
216 | year = rtc_read( RTC_YEAR ); | |
217 | century = rtc_read( RTC_CENTURY ); | |
218 | ||
219 | /* unlock clock registers after read */ | |
220 | rtc_write( RTC_CONTROLA, ( reg_a & ~RTC_CA_READ )); | |
221 | ||
222 | tmp->tm_sec = bcd2bin( sec & 0x7F ); | |
223 | tmp->tm_min = bcd2bin( min & 0x7F ); | |
224 | tmp->tm_hour = bcd2bin( hour & 0x3F ); | |
225 | tmp->tm_mday = bcd2bin( mday & 0x3F ); | |
226 | tmp->tm_mon = bcd2bin( mon & 0x1F ); | |
227 | tmp->tm_wday = bcd2bin( wday & 0x07 ); | |
228 | ||
229 | if (century_flag) { | |
230 | tmp->tm_year = bcd2bin( year ) + | |
231 | ( bcd2bin( century & 0x3F ) * 100 ); | |
232 | } else { | |
233 | tmp->tm_year = bcd2bin( year ) + 1900; | |
234 | if (tmp->tm_year < 1970) tmp->tm_year += 100; | |
235 | } | |
236 | ||
237 | tmp->tm_yday = 0; | |
238 | tmp->tm_isdst= 0; | |
239 | } | |
b73a19e1 YT |
240 | |
241 | return 0; | |
15647dc7 WD |
242 | } |
243 | ||
d1e23194 | 244 | int rtc_set( struct rtc_time *tmp ) |
15647dc7 WD |
245 | { |
246 | if (phantom_flag < 0) | |
247 | phantom_flag = get_phantom_flag(); | |
248 | ||
249 | if (phantom_flag) { | |
250 | uint year; | |
251 | unsigned char rtc[8]; | |
252 | ||
253 | year = tmp->tm_year; | |
254 | year -= (year < 2000) ? 1900 : 2000; | |
255 | ||
256 | rtc[0] = bin2bcd(0); | |
257 | rtc[1] = bin2bcd(tmp->tm_sec); | |
258 | rtc[2] = bin2bcd(tmp->tm_min); | |
259 | rtc[3] = bin2bcd(tmp->tm_hour); | |
260 | rtc[4] = bin2bcd(tmp->tm_wday); | |
261 | rtc[5] = bin2bcd(tmp->tm_mday); | |
262 | rtc[6] = bin2bcd(tmp->tm_mon); | |
263 | rtc[7] = bin2bcd(year); | |
264 | ||
265 | phantom_rtc_write(RTC_BASE, rtc); | |
266 | } else { | |
267 | uchar reg_a; | |
268 | if (century_flag < 0) | |
269 | century_flag = get_century_flag(); | |
270 | ||
271 | /* lock clock registers for write */ | |
272 | reg_a = rtc_read( RTC_CONTROLA ); | |
273 | rtc_write( RTC_CONTROLA, ( reg_a | RTC_CA_WRITE )); | |
274 | ||
275 | rtc_write( RTC_MONTH, bin2bcd( tmp->tm_mon )); | |
276 | ||
277 | rtc_write( RTC_DAY_OF_WEEK, bin2bcd( tmp->tm_wday )); | |
278 | rtc_write( RTC_DAY_OF_MONTH, bin2bcd( tmp->tm_mday )); | |
279 | rtc_write( RTC_HOURS, bin2bcd( tmp->tm_hour )); | |
280 | rtc_write( RTC_MINUTES, bin2bcd( tmp->tm_min )); | |
281 | rtc_write( RTC_SECONDS, bin2bcd( tmp->tm_sec )); | |
282 | ||
283 | /* break year up into century and year in century */ | |
284 | if (century_flag) { | |
285 | rtc_write( RTC_YEAR, bin2bcd( tmp->tm_year % 100 )); | |
286 | rtc_write( RTC_CENTURY, bin2bcd( tmp->tm_year / 100 )); | |
287 | reg_a &= 0xc0; | |
288 | reg_a |= bin2bcd( tmp->tm_year / 100 ); | |
289 | } else { | |
290 | rtc_write(RTC_YEAR, bin2bcd(tmp->tm_year - | |
291 | ((tmp->tm_year < 2000) ? 1900 : 2000))); | |
292 | } | |
293 | ||
294 | /* unlock clock registers after read */ | |
295 | rtc_write( RTC_CONTROLA, ( reg_a & ~RTC_CA_WRITE )); | |
296 | } | |
d1e23194 JCPV |
297 | |
298 | return 0; | |
15647dc7 WD |
299 | } |
300 | ||
301 | #endif |