1 | /*-------------------------------------------------------------------------+ |
---|
2 | | rtc.c v1.1 - PC386 BSP - 1997/08/07 |
---|
3 | +--------------------------------------------------------------------------+ |
---|
4 | | This file contains the real time clock manipulation package for the |
---|
5 | | PC386 board. |
---|
6 | +--------------------------------------------------------------------------+ |
---|
7 | | (C) Copyright 1997 - |
---|
8 | | - NavIST Group - Real-Time Distributed Systems and Industrial Automation |
---|
9 | | |
---|
10 | | http://pandora.ist.utl.pt |
---|
11 | | |
---|
12 | | Instituto Superior Tecnico * Lisboa * PORTUGAL |
---|
13 | +--------------------------------------------------------------------------+ |
---|
14 | | Disclaimer: |
---|
15 | | |
---|
16 | | This file is provided "AS IS" without warranty of any kind, either |
---|
17 | | expressed or implied. |
---|
18 | +--------------------------------------------------------------------------+ |
---|
19 | | This code is based on: |
---|
20 | | rtc.c,v 1.4 1995/12/19 20:07:15 joel Exp - go32 BSP |
---|
21 | | With the following copyright notice: |
---|
22 | | ************************************************************************** |
---|
23 | | * COPYRIGHT (c) 1989-1999. |
---|
24 | | * On-Line Applications Research Corporation (OAR). |
---|
25 | | * |
---|
26 | | * The license and distribution terms for this file may be |
---|
27 | | * found in the file LICENSE in this distribution or at |
---|
28 | | * http://www.rtems.com/license/LICENSE. |
---|
29 | | ************************************************************************** |
---|
30 | | |
---|
31 | | $Id$ |
---|
32 | +--------------------------------------------------------------------------*/ |
---|
33 | |
---|
34 | #include <string.h> |
---|
35 | |
---|
36 | #include <bsp.h> |
---|
37 | |
---|
38 | /*-------------------------------------------------------------------------+ |
---|
39 | | Constants |
---|
40 | +--------------------------------------------------------------------------*/ |
---|
41 | #define IO_RTC 0x70 /* RTC */ |
---|
42 | |
---|
43 | #define RTC_SEC 0x00 /* seconds */ |
---|
44 | #define RTC_SECALRM 0x01 /* seconds alarm */ |
---|
45 | #define RTC_MIN 0x02 /* minutes */ |
---|
46 | #define RTC_MINALRM 0x03 /* minutes alarm */ |
---|
47 | #define RTC_HRS 0x04 /* hours */ |
---|
48 | #define RTC_HRSALRM 0x05 /* hours alarm */ |
---|
49 | #define RTC_WDAY 0x06 /* week day */ |
---|
50 | #define RTC_DAY 0x07 /* day of month */ |
---|
51 | #define RTC_MONTH 0x08 /* month of year */ |
---|
52 | #define RTC_YEAR 0x09 /* month of year */ |
---|
53 | #define RTC_STATUSA 0x0a /* status register A */ |
---|
54 | #define RTCSA_TUP 0x80 /* time update, don't look now */ |
---|
55 | |
---|
56 | #define RTC_STATUSB 0x0b /* status register B */ |
---|
57 | |
---|
58 | #define RTC_INTR 0x0c /* status register C (R) interrupt source */ |
---|
59 | #define RTCIR_UPDATE 0x10 /* update intr */ |
---|
60 | #define RTCIR_ALARM 0x20 /* alarm intr */ |
---|
61 | #define RTCIR_PERIOD 0x40 /* periodic intr */ |
---|
62 | #define RTCIR_INT 0x80 /* interrupt output signal */ |
---|
63 | |
---|
64 | #define RTC_STATUSD 0x0d /* status register D (R) Lost Power */ |
---|
65 | #define RTCSD_PWR 0x80 /* clock lost power */ |
---|
66 | |
---|
67 | #define RTC_DIAG 0x0e /* status register E - bios diagnostic */ |
---|
68 | #define RTCDG_BITS "\020\010clock_battery\007ROM_cksum\006config_unit\005memory_size\004fixed_disk\003invalid_time" |
---|
69 | |
---|
70 | #define RTC_CENTURY 0x32 /* current century - increment in Dec99 */ |
---|
71 | |
---|
72 | /*-------------------------------------------------------------------------+ |
---|
73 | | Auxiliary Functions |
---|
74 | +--------------------------------------------------------------------------*/ |
---|
75 | /*-------------------------------------------------------------------------+ |
---|
76 | | Function: bcd |
---|
77 | | Description: Convert 2 digit number to its BCD representation. |
---|
78 | | Global Variables: None. |
---|
79 | | Arguments: i - Number to convert. |
---|
80 | | Returns: BCD representation of number. |
---|
81 | +--------------------------------------------------------------------------*/ |
---|
82 | static inline uint8_t |
---|
83 | bcd(uint8_t i) |
---|
84 | { |
---|
85 | return ((i / 16) * 10 + (i % 16)); |
---|
86 | } /* bcd */ |
---|
87 | |
---|
88 | #define QUICK_READ /* Quick read of the RTC: don't return number of seconds. */ |
---|
89 | |
---|
90 | #ifndef QUICK_READ |
---|
91 | |
---|
92 | #define SECS_PER_DAY (24 * 60 * 60) |
---|
93 | #define SECS_PER_REG_YEAR (365 * SECS_PER_DAY) |
---|
94 | |
---|
95 | /*-------------------------------------------------------------------------+ |
---|
96 | | Function: ytos |
---|
97 | | Description: Convert years to seconds (since 1970). |
---|
98 | | Global Variables: None. |
---|
99 | | Arguments: y - year to convert (1970 <= y <= 2100). |
---|
100 | | Returns: number of seconds since 1970. |
---|
101 | +--------------------------------------------------------------------------*/ |
---|
102 | static inline uint32_t |
---|
103 | ytos(uint16_t y) |
---|
104 | { /* v NUM LEAP YEARS v */ |
---|
105 | return ((y - 1970) * SECS_PER_REG_YEAR + (y - 1970 + 1) / 4 * SECS_PER_DAY); |
---|
106 | } /* ytos */ |
---|
107 | |
---|
108 | /*-------------------------------------------------------------------------+ |
---|
109 | | Function: mtos |
---|
110 | | Description: Convert months to seconds since January. |
---|
111 | | Global Variables: None. |
---|
112 | | Arguments: m - month to convert, leap - is this a month of a leap year. |
---|
113 | | Returns: number of seconds since January. |
---|
114 | +--------------------------------------------------------------------------*/ |
---|
115 | static inline uint32_t |
---|
116 | mtos(uint8_t m, bool leap) |
---|
117 | { |
---|
118 | static uint16_t daysMonth[] = { 0, 0, 31, 59, 90, 120, 151, 181, |
---|
119 | 212, 243, 273, 304, 334, 365 }; |
---|
120 | /* Days since beginning of year until beginning of month. */ |
---|
121 | |
---|
122 | return ((daysMonth[m] + (leap ? 1 : 0)) * SECS_PER_DAY); |
---|
123 | } /* mtos */ |
---|
124 | |
---|
125 | #endif /* QUICK_READ */ |
---|
126 | |
---|
127 | /*-------------------------------------------------------------------------+ |
---|
128 | | Function: rtcin |
---|
129 | | Description: Perform action on RTC and return its result. |
---|
130 | | Global Variables: None. |
---|
131 | | Arguments: what - what to write to RTC port (what to do). |
---|
132 | | Returns: result received from RTC port after action performed. |
---|
133 | +--------------------------------------------------------------------------*/ |
---|
134 | static inline uint8_t |
---|
135 | rtcin(uint8_t what) |
---|
136 | { |
---|
137 | uint8_t r; |
---|
138 | |
---|
139 | outport_byte(IO_RTC, what); |
---|
140 | inport_byte (IO_RTC+1, r); |
---|
141 | return r; |
---|
142 | } /* rtcin */ |
---|
143 | |
---|
144 | /*-------------------------------------------------------------------------+ |
---|
145 | | Functions |
---|
146 | +--------------------------------------------------------------------------*/ |
---|
147 | /*-------------------------------------------------------------------------+ |
---|
148 | | Function: init_rtc |
---|
149 | | Description: Initialize real-time clock (RTC). |
---|
150 | | Global Variables: None. |
---|
151 | | Arguments: None. |
---|
152 | | Returns: Nothing. |
---|
153 | +--------------------------------------------------------------------------*/ |
---|
154 | void |
---|
155 | init_rtc(void) |
---|
156 | { |
---|
157 | uint8_t s; |
---|
158 | |
---|
159 | /* initialize brain-dead battery powered clock */ |
---|
160 | outport_byte(IO_RTC, RTC_STATUSA); |
---|
161 | outport_byte(IO_RTC+1, 0x26); |
---|
162 | outport_byte(IO_RTC, RTC_STATUSB); |
---|
163 | outport_byte(IO_RTC+1, 2); |
---|
164 | |
---|
165 | outport_byte(IO_RTC, RTC_DIAG); |
---|
166 | inport_byte (IO_RTC+1, s); |
---|
167 | if (s) |
---|
168 | printk("RTC BIOS diagnostic error %b\n", s); |
---|
169 | |
---|
170 | /* FIXME: This was last line's original version. How was it supposed to work? |
---|
171 | printf("RTC BIOS diagnostic error %b\n", s, RTCDG_BITS); */ |
---|
172 | } /* init_rtc */ |
---|
173 | |
---|
174 | /*-------------------------------------------------------------------------+ |
---|
175 | | Function: rtc_read |
---|
176 | | Description: Read present time from RTC and return it. |
---|
177 | | Global Variables: None. |
---|
178 | | Arguments: tod - to return present time in 'rtems_time_of_day' format. |
---|
179 | | Returns: number of seconds from 1970/01/01 corresponding to 'tod'. |
---|
180 | +--------------------------------------------------------------------------*/ |
---|
181 | long int |
---|
182 | rtc_read(rtems_time_of_day *tod) |
---|
183 | { |
---|
184 | uint8_t sa; |
---|
185 | uint32_t sec = 0; |
---|
186 | |
---|
187 | memset(tod, 0, sizeof *tod); /* zero tod structure */ |
---|
188 | |
---|
189 | /* do we have a realtime clock present? (otherwise we loop below) */ |
---|
190 | sa = rtcin(RTC_STATUSA); |
---|
191 | if (sa == 0xff || sa == 0) |
---|
192 | return -1; |
---|
193 | |
---|
194 | /* ready for a read? */ |
---|
195 | while ((sa&RTCSA_TUP) == RTCSA_TUP) |
---|
196 | sa = rtcin(RTC_STATUSA); |
---|
197 | |
---|
198 | tod->year = bcd(rtcin(RTC_YEAR)) + 1900; /* year */ |
---|
199 | if (tod->year < 1970) tod->year += 100; |
---|
200 | tod->month = bcd(rtcin(RTC_MONTH)); /* month */ |
---|
201 | tod->day = bcd(rtcin(RTC_DAY)); /* day */ |
---|
202 | (void) bcd(rtcin(RTC_WDAY)); /* weekday */ |
---|
203 | tod->hour = bcd(rtcin(RTC_HRS)); /* hour */ |
---|
204 | tod->minute = bcd(rtcin(RTC_MIN)); /* minutes */ |
---|
205 | tod->second = bcd(rtcin(RTC_SEC)); /* seconds */ |
---|
206 | tod->ticks = 0; |
---|
207 | |
---|
208 | #ifndef QUICK_READ /* Quick read of the RTC: don't return number of seconds. */ |
---|
209 | sec = ytos(tod->year); |
---|
210 | sec += mtos(tod->month, (tod->year % 4) == 0); |
---|
211 | sec += tod->day * SECS_PER_DAY; |
---|
212 | sec += tod->hour * 60 * 60; /* hour */ |
---|
213 | sec += tod->minute * 60; /* minutes */ |
---|
214 | sec += tod->second; /* seconds */ |
---|
215 | #endif /* QUICK_READ */ |
---|
216 | |
---|
217 | return (long int)sec; |
---|
218 | } /* rtc_read */ |
---|