]> git.kernelconcepts.de Git - karo-tx-uboot.git/blob - board/mousse/m48t59y.c
ARM: highbank: use default prompt
[karo-tx-uboot.git] / board / mousse / m48t59y.c
1 /*
2  * SGS M48-T59Y TOD/NVRAM Driver
3  *
4  * (C) Copyright 2000
5  * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
6  *
7  * (C) Copyright 1999, by Curt McDowell, 08-06-99, Broadcom Corp.
8  *
9  * (C) Copyright 2001, James Dougherty, 07/18/01, Broadcom Corp.
10  *
11  * SPDX-License-Identifier:     GPL-2.0+
12  */
13
14 /*
15  * SGS M48-T59Y TOD/NVRAM Driver
16  *
17  * The SGS M48 an 8K NVRAM starting at offset M48_BASE_ADDR and
18  * continuing for 8176 bytes. After that starts the Time-Of-Day (TOD)
19  * registers which are used to set/get the internal date/time functions.
20  *
21  * This module implements Y2K compliance by taking full year numbers
22  * and translating back and forth from the TOD 2-digit year.
23  *
24  * NOTE: for proper interaction with an operating system, the TOD should
25  * be used to store Universal Coordinated Time (GMT) and timezone
26  * conversions should be used.
27  *
28  * Here is a diagram of the memory layout:
29  *
30  * +---------------------------------------------+ 0xffe0a000
31  * | Non-volatile memory                         | .
32  * |                                             | .
33  * | (8176 bytes of Non-volatile memory)         | .
34  * |                                             | .
35  * +---------------------------------------------+ 0xffe0bff0
36  * | Flags                                       |
37  * +---------------------------------------------+ 0xffe0bff1
38  * | Unused                                      |
39  * +---------------------------------------------+ 0xffe0bff2
40  * | Alarm Seconds                               |
41  * +---------------------------------------------+ 0xffe0bff3
42  * | Alarm Minutes                               |
43  * +---------------------------------------------+ 0xffe0bff4
44  * | Alarm Date                                  |
45  * +---------------------------------------------+ 0xffe0bff5
46  * | Interrupts                                  |
47  * +---------------------------------------------+ 0xffe0bff6
48  * | WatchDog                                    |
49  * +---------------------------------------------+ 0xffe0bff7
50  * | Calibration                                 |
51  * +---------------------------------------------+ 0xffe0bff8
52  * | Seconds                                     |
53  * +---------------------------------------------+ 0xffe0bff9
54  * | Minutes                                     |
55  * +---------------------------------------------+ 0xffe0bffa
56  * | Hours                                       |
57  * +---------------------------------------------+ 0xffe0bffb
58  * | Day                                         |
59  * +---------------------------------------------+ 0xffe0bffc
60  * | Date                                        |
61  * +---------------------------------------------+ 0xffe0bffd
62  * | Month                                       |
63  * +---------------------------------------------+ 0xffe0bffe
64  * | Year (2 digits only)                        |
65  * +---------------------------------------------+ 0xffe0bfff
66  */
67 #include <common.h>
68 #include <rtc.h>
69 #include "mousse.h"
70
71 /*
72  * Imported from mousse.h:
73  *
74  *   TOD_REG_BASE               Base of m48t59y TOD registers
75  *   SYS_TOD_UNPROTECT()        Disable NVRAM write protect
76  *   SYS_TOD_PROTECT()          Re-enable NVRAM write protect
77  */
78
79 #define YEAR            0xf
80 #define MONTH           0xe
81 #define DAY             0xd
82 #define DAY_OF_WEEK     0xc
83 #define HOUR            0xb
84 #define MINUTE          0xa
85 #define SECOND          0x9
86 #define CONTROL         0x8
87 #define WATCH           0x7
88 #define INTCTL          0x6
89 #define WD_DATE         0x5
90 #define WD_HOUR         0x4
91 #define WD_MIN          0x3
92 #define WD_SEC          0x2
93 #define _UNUSED         0x1
94 #define FLAGS           0x0
95
96 #define M48_ADDR        ((volatile unsigned char *) TOD_REG_BASE)
97
98 int m48_tod_init(void)
99 {
100     SYS_TOD_UNPROTECT();
101
102     M48_ADDR[CONTROL] = 0;
103     M48_ADDR[WATCH] = 0;
104     M48_ADDR[INTCTL] = 0;
105
106     /*
107      * If the oscillator is currently stopped (as on a new part shipped
108      * from the factory), start it running.
109      *
110      * Here is an example of the TOD bytes on a brand new M48T59Y part:
111      *          00 00 00 00 00 00 00 00 00 88 8c c3 bf c8 f5 01
112      */
113
114     if (M48_ADDR[SECOND] & 0x80)
115         M48_ADDR[SECOND] = 0;
116
117     /* Is battery low */
118     if ( M48_ADDR[FLAGS] & 0x10) {
119          printf("NOTICE: Battery low on Real-Time Clock (replace SNAPHAT).\n");
120     }
121
122     SYS_TOD_PROTECT();
123
124     return 0;
125 }
126
127 /*
128  * m48_tod_set
129  */
130
131 static int to_bcd(int value)
132 {
133     return value / 10 * 16 + value % 10;
134 }
135
136 static int from_bcd(int value)
137 {
138     return value / 16 * 10 + value % 16;
139 }
140
141 static int day_of_week(int y, int m, int d)     /* 0-6 ==> Sun-Sat */
142 {
143     static int t[] = {0, 3, 2, 5, 0, 3, 5, 1, 4, 6, 2, 4};
144     y -= m < 3;
145     return (y + y/4 - y/100 + y/400 + t[m-1] + d) % 7;
146 }
147
148 /*
149  * Note: the TOD should store the current GMT
150  */
151
152 int m48_tod_set(int year,               /* 1980-2079 */
153                 int month,              /* 01-12 */
154                 int day,                /* 01-31 */
155                 int hour,               /* 00-23 */
156                 int minute,             /* 00-59 */
157                 int second)             /* 00-59 */
158
159 {
160     SYS_TOD_UNPROTECT();
161
162     M48_ADDR[CONTROL] |= 0x80;  /* Set WRITE bit */
163
164     M48_ADDR[YEAR] = to_bcd(year % 100);
165     M48_ADDR[MONTH] = to_bcd(month);
166     M48_ADDR[DAY] = to_bcd(day);
167     M48_ADDR[DAY_OF_WEEK] = day_of_week(year, month, day) + 1;
168     M48_ADDR[HOUR] = to_bcd(hour);
169     M48_ADDR[MINUTE] = to_bcd(minute);
170     M48_ADDR[SECOND] = to_bcd(second);
171
172     M48_ADDR[CONTROL] &= ~0x80; /* Clear WRITE bit */
173
174     SYS_TOD_PROTECT();
175
176     return 0;
177 }
178
179 /*
180  * Note: the TOD should store the current GMT
181  */
182
183 int m48_tod_get(int *year,              /* 1980-2079 */
184                 int *month,             /* 01-12 */
185                 int *day,               /* 01-31 */
186                 int *hour,              /* 00-23 */
187                 int *minute,            /* 00-59 */
188                 int *second)            /* 00-59 */
189 {
190     int y;
191
192     SYS_TOD_UNPROTECT();
193
194     M48_ADDR[CONTROL] |= 0x40;  /* Set READ bit */
195
196     y = from_bcd(M48_ADDR[YEAR]);
197     *year = y < 80 ? 2000 + y : 1900 + y;
198     *month = from_bcd(M48_ADDR[MONTH]);
199     *day = from_bcd(M48_ADDR[DAY]);
200     /* day_of_week = M48_ADDR[DAY_OF_WEEK] & 0xf; */
201     *hour = from_bcd(M48_ADDR[HOUR]);
202     *minute = from_bcd(M48_ADDR[MINUTE]);
203     *second = from_bcd(M48_ADDR[SECOND] & 0x7f);
204
205     M48_ADDR[CONTROL] &= ~0x40; /* Clear READ bit */
206
207     SYS_TOD_PROTECT();
208
209     return 0;
210 }
211
212 int m48_tod_get_second(void)
213 {
214     return from_bcd(M48_ADDR[SECOND] & 0x7f);
215 }
216
217 /*
218  * Watchdog function
219  *
220  *  If usec is 0, the watchdog timer is disarmed.
221  *
222  *  If usec is non-zero, the watchdog timer is armed (or re-armed) for
223  *    approximately usec microseconds (if the exact requested usec is
224  *    not supported by the chip, the next higher available value is used).
225  *
226  *  Minimum watchdog timeout = 62500 usec
227  *  Maximum watchdog timeout = 124 sec (124000000 usec)
228  */
229
230 void m48_watchdog_arm(int usec)
231 {
232     int         mpy, res;
233
234     SYS_TOD_UNPROTECT();
235
236     if (usec == 0) {
237         res = 0;
238         mpy = 0;
239     } else if (usec < 2000000) {        /* Resolution: 1/16s if below 2s */
240         res = 0;
241         mpy = (usec + 62499) / 62500;
242     } else if (usec < 8000000) {        /* Resolution: 1/4s if below 8s */
243         res = 1;
244         mpy = (usec + 249999) / 250000;
245     } else if (usec < 32000000) {       /* Resolution: 1s if below 32s */
246         res = 2;
247         mpy = (usec + 999999) / 1000000;
248     } else {                            /* Resolution: 4s up to 124s */
249         res = 3;
250         mpy = (usec + 3999999) / 4000000;
251         if (mpy > 31)
252             mpy = 31;
253     }
254
255     M48_ADDR[WATCH] = (0x80 |           /* Steer to RST signal (IRQ = N/C) */
256                        mpy << 2 |
257                        res);
258
259     SYS_TOD_PROTECT();
260 }
261
262 /*
263  * U-Boot RTC support.
264  */
265 int
266 rtc_get( struct rtc_time *tmp )
267 {
268         m48_tod_get(&tmp->tm_year,
269                     &tmp->tm_mon,
270                     &tmp->tm_mday,
271                     &tmp->tm_hour,
272                     &tmp->tm_min,
273                     &tmp->tm_sec);
274         tmp->tm_yday = 0;
275         tmp->tm_isdst= 0;
276
277 #ifdef RTC_DEBUG
278         printf( "Get DATE: %4d-%02d-%02d (wday=%d)  TIME: %2d:%02d:%02d\n",
279                 tmp->tm_year, tmp->tm_mon, tmp->tm_mday, tmp->tm_wday,
280                 tmp->tm_hour, tmp->tm_min, tmp->tm_sec );
281 #endif
282
283         return 0;
284 }
285
286 int rtc_set( struct rtc_time *tmp )
287 {
288         m48_tod_set(tmp->tm_year,               /* 1980-2079 */
289                     tmp->tm_mon,                /* 01-12 */
290                     tmp->tm_mday,              /* 01-31 */
291                     tmp->tm_hour,               /* 00-23 */
292                     tmp->tm_min,                /* 00-59 */
293                     tmp->tm_sec);               /* 00-59 */
294
295 #ifdef RTC_DEBUG
296         printf( "Set DATE: %4d-%02d-%02d (wday=%d)  TIME: %2d:%02d:%02d\n",
297                 tmp->tm_year, tmp->tm_mon, tmp->tm_mday, tmp->tm_wday,
298                 tmp->tm_hour, tmp->tm_min, tmp->tm_sec);
299 #endif
300
301         return 0;
302 }
303
304 void
305 rtc_reset (void)
306 {
307   m48_tod_init();
308 }