blob: 63feb7c2c3564d80175c04f58ff3b565a91f576c [file] [log] [blame]
wdenk9f837932003-10-09 19:00:25 +00001/*
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
Jon Loeliger4ed9ed62007-07-09 18:24:55 -050021#if defined(CONFIG_CMD_DATE)
wdenk9f837932003-10-09 19:00:25 +000022
Jean-Christophe PLAGNIOL-VILLARD03836942008-10-16 15:01:15 +020023#define RTC_BASE (CONFIG_SYS_NVRAM_BASE_ADDR + 0x7fff8)
wdenk9f837932003-10-09 19:00:25 +000024
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
47static int phantom_flag = -1;
48static int century_flag = -1;
49
50static uchar rtc_read(unsigned int addr)
51{
52 return *(volatile unsigned char *)(addr);
53}
54
55static void rtc_write(unsigned int addr, uchar val)
56{
57 *(volatile unsigned char *)(addr) = val;
58}
59
60static unsigned char phantom_rtc_sequence[] = {
61 0xc5, 0x3a, 0xa3, 0x5c, 0xc5, 0x3a, 0xa3, 0x5c
62};
63
64static 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
89static 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
111static 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
125void 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
wdenk9f837932003-10-09 19:00:25 +0000162static int get_century_flag(void)
163{
164 int flag = 0;
165 int bcd, century;
166 bcd = rtc_read( RTC_CENTURY );
167 century = bcd2bin( bcd & 0x3F );
168 rtc_write( RTC_CENTURY, bin2bcd(century+1));
169 if (bcd == rtc_read( RTC_CENTURY ))
170 flag = 1;
171 rtc_write( RTC_CENTURY, bcd);
172 return flag;
173}
174
Yuri Tikhonov9bacd942008-03-20 17:56:04 +0300175int rtc_get( struct rtc_time *tmp)
wdenk9f837932003-10-09 19:00:25 +0000176{
177 if (phantom_flag < 0)
178 phantom_flag = get_phantom_flag();
179
180 if (phantom_flag)
181 {
182 unsigned char rtc[8];
183
184 phantom_rtc_read(RTC_BASE, rtc);
185
186 tmp->tm_sec = bcd2bin(rtc[1] & 0x7f);
187 tmp->tm_min = bcd2bin(rtc[2] & 0x7f);
188 tmp->tm_hour = bcd2bin(rtc[3] & 0x1f);
189 tmp->tm_wday = bcd2bin(rtc[4] & 0x7);
190 tmp->tm_mday = bcd2bin(rtc[5] & 0x3f);
191 tmp->tm_mon = bcd2bin(rtc[6] & 0x1f);
192 tmp->tm_year = bcd2bin(rtc[7]) + 1900;
193 tmp->tm_yday = 0;
194 tmp->tm_isdst = 0;
195
196 if( (rtc[3] & 0x80) && (rtc[3] & 0x40) ) tmp->tm_hour += 12;
197 if (tmp->tm_year < 1970) tmp->tm_year += 100;
198 } else {
199 uchar sec, min, hour;
200 uchar mday, wday, mon, year;
201
202 int century;
203
204 uchar reg_a;
205
206 if (century_flag < 0)
207 century_flag = get_century_flag();
208
209 reg_a = rtc_read( RTC_CONTROLA );
210 /* lock clock registers for read */
211 rtc_write( RTC_CONTROLA, ( reg_a | RTC_CA_READ ));
212
213 sec = rtc_read( RTC_SECONDS );
214 min = rtc_read( RTC_MINUTES );
215 hour = rtc_read( RTC_HOURS );
216 mday = rtc_read( RTC_DAY_OF_MONTH );
217 wday = rtc_read( RTC_DAY_OF_WEEK );
218 mon = rtc_read( RTC_MONTH );
219 year = rtc_read( RTC_YEAR );
220 century = rtc_read( RTC_CENTURY );
221
222 /* unlock clock registers after read */
223 rtc_write( RTC_CONTROLA, ( reg_a & ~RTC_CA_READ ));
224
225 tmp->tm_sec = bcd2bin( sec & 0x7F );
226 tmp->tm_min = bcd2bin( min & 0x7F );
227 tmp->tm_hour = bcd2bin( hour & 0x3F );
228 tmp->tm_mday = bcd2bin( mday & 0x3F );
229 tmp->tm_mon = bcd2bin( mon & 0x1F );
230 tmp->tm_wday = bcd2bin( wday & 0x07 );
231
232 if (century_flag) {
233 tmp->tm_year = bcd2bin( year ) +
234 ( bcd2bin( century & 0x3F ) * 100 );
235 } else {
236 tmp->tm_year = bcd2bin( year ) + 1900;
237 if (tmp->tm_year < 1970) tmp->tm_year += 100;
238 }
239
240 tmp->tm_yday = 0;
241 tmp->tm_isdst= 0;
242 }
Yuri Tikhonov9bacd942008-03-20 17:56:04 +0300243
244 return 0;
wdenk9f837932003-10-09 19:00:25 +0000245}
246
Jean-Christophe PLAGNIOL-VILLARD97a2e102008-09-01 23:06:23 +0200247int rtc_set( struct rtc_time *tmp )
wdenk9f837932003-10-09 19:00:25 +0000248{
249 if (phantom_flag < 0)
250 phantom_flag = get_phantom_flag();
251
252 if (phantom_flag) {
253 uint year;
254 unsigned char rtc[8];
255
256 year = tmp->tm_year;
257 year -= (year < 2000) ? 1900 : 2000;
258
259 rtc[0] = bin2bcd(0);
260 rtc[1] = bin2bcd(tmp->tm_sec);
261 rtc[2] = bin2bcd(tmp->tm_min);
262 rtc[3] = bin2bcd(tmp->tm_hour);
263 rtc[4] = bin2bcd(tmp->tm_wday);
264 rtc[5] = bin2bcd(tmp->tm_mday);
265 rtc[6] = bin2bcd(tmp->tm_mon);
266 rtc[7] = bin2bcd(year);
267
268 phantom_rtc_write(RTC_BASE, rtc);
269 } else {
270 uchar reg_a;
271 if (century_flag < 0)
272 century_flag = get_century_flag();
273
274 /* lock clock registers for write */
275 reg_a = rtc_read( RTC_CONTROLA );
276 rtc_write( RTC_CONTROLA, ( reg_a | RTC_CA_WRITE ));
277
278 rtc_write( RTC_MONTH, bin2bcd( tmp->tm_mon ));
279
280 rtc_write( RTC_DAY_OF_WEEK, bin2bcd( tmp->tm_wday ));
281 rtc_write( RTC_DAY_OF_MONTH, bin2bcd( tmp->tm_mday ));
282 rtc_write( RTC_HOURS, bin2bcd( tmp->tm_hour ));
283 rtc_write( RTC_MINUTES, bin2bcd( tmp->tm_min ));
284 rtc_write( RTC_SECONDS, bin2bcd( tmp->tm_sec ));
285
286 /* break year up into century and year in century */
287 if (century_flag) {
288 rtc_write( RTC_YEAR, bin2bcd( tmp->tm_year % 100 ));
289 rtc_write( RTC_CENTURY, bin2bcd( tmp->tm_year / 100 ));
290 reg_a &= 0xc0;
291 reg_a |= bin2bcd( tmp->tm_year / 100 );
292 } else {
293 rtc_write(RTC_YEAR, bin2bcd(tmp->tm_year -
294 ((tmp->tm_year < 2000) ? 1900 : 2000)));
295 }
296
297 /* unlock clock registers after read */
298 rtc_write( RTC_CONTROLA, ( reg_a & ~RTC_CA_WRITE ));
299 }
Jean-Christophe PLAGNIOL-VILLARD97a2e102008-09-01 23:06:23 +0200300
301 return 0;
wdenk9f837932003-10-09 19:00:25 +0000302}
303
304#endif