1
2
3
4
5
6
7
8
9
10
11
12
13
14#include <common.h>
15#include <command.h>
16#include <rtc.h>
17
18#if defined(CONFIG_CMD_DATE)
19
20#define RTC_BASE (CONFIG_SYS_NVRAM_BASE_ADDR + 0x7fff8)
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
44static int phantom_flag = -1;
45static int century_flag = -1;
46
47static uchar rtc_read(unsigned int addr)
48{
49 return *(volatile unsigned char *)(addr);
50}
51
52static void rtc_write(unsigned int addr, uchar val)
53{
54 *(volatile unsigned char *)(addr) = val;
55}
56
57static unsigned char phantom_rtc_sequence[] = {
58 0xc5, 0x3a, 0xa3, 0x5c, 0xc5, 0x3a, 0xa3, 0x5c
59};
60
61static 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
86static 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
108static 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
122void 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
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
159static 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
172int rtc_get( struct rtc_time *tmp)
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
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
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 }
240
241 return 0;
242}
243
244int rtc_set( struct rtc_time *tmp )
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
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
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
295 rtc_write( RTC_CONTROLA, ( reg_a & ~RTC_CA_WRITE ));
296 }
297
298 return 0;
299}
300
301#endif
302