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