1 /** @file
2   Header file for real time clock driver.
3 
4 Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
5 Copyright (c) 2017, AMD Inc. All rights reserved.<BR>
6 
7 SPDX-License-Identifier: BSD-2-Clause-Patent
8 
9 **/
10 
11 
12 #ifndef _RTC_H_
13 #define _RTC_H_
14 
15 
16 #include <Uefi.h>
17 
18 #include <Guid/Acpi.h>
19 
20 #include <Protocol/RealTimeClock.h>
21 
22 #include <Library/BaseLib.h>
23 #include <Library/DebugLib.h>
24 #include <Library/UefiLib.h>
25 #include <Library/BaseMemoryLib.h>
26 #include <Library/IoLib.h>
27 #include <Library/TimerLib.h>
28 #include <Library/UefiDriverEntryPoint.h>
29 #include <Library/UefiBootServicesTableLib.h>
30 #include <Library/UefiRuntimeLib.h>
31 #include <Library/UefiRuntimeServicesTableLib.h>
32 #include <Library/PcdLib.h>
33 #include <Library/ReportStatusCodeLib.h>
34 
35 typedef struct {
36   EFI_LOCK  RtcLock;
37   INT16     SavedTimeZone;
38   UINT8     Daylight;
39   UINT8     CenturyRtcAddress;
40 } PC_RTC_MODULE_GLOBALS;
41 
42 extern PC_RTC_MODULE_GLOBALS  mModuleGlobal;
43 
44 //
45 // Dallas DS12C887 Real Time Clock
46 //
47 #define RTC_ADDRESS_SECONDS           0   // R/W  Range 0..59
48 #define RTC_ADDRESS_SECONDS_ALARM     1   // R/W  Range 0..59
49 #define RTC_ADDRESS_MINUTES           2   // R/W  Range 0..59
50 #define RTC_ADDRESS_MINUTES_ALARM     3   // R/W  Range 0..59
51 #define RTC_ADDRESS_HOURS             4   // R/W  Range 1..12 or 0..23 Bit 7 is AM/PM
52 #define RTC_ADDRESS_HOURS_ALARM       5   // R/W  Range 1..12 or 0..23 Bit 7 is AM/PM
53 #define RTC_ADDRESS_DAY_OF_THE_WEEK   6   // R/W  Range 1..7
54 #define RTC_ADDRESS_DAY_OF_THE_MONTH  7   // R/W  Range 1..31
55 #define RTC_ADDRESS_MONTH             8   // R/W  Range 1..12
56 #define RTC_ADDRESS_YEAR              9   // R/W  Range 0..99
57 #define RTC_ADDRESS_REGISTER_A        10  // R/W[0..6]  R0[7]
58 #define RTC_ADDRESS_REGISTER_B        11  // R/W
59 #define RTC_ADDRESS_REGISTER_C        12  // RO
60 #define RTC_ADDRESS_REGISTER_D        13  // RO
61 //
62 // Date and time initial values.
63 // They are used if the RTC values are invalid during driver initialization
64 //
65 #define RTC_INIT_SECOND 0
66 #define RTC_INIT_MINUTE 0
67 #define RTC_INIT_HOUR   0
68 #define RTC_INIT_DAY    1
69 #define RTC_INIT_MONTH  1
70 
71 #pragma pack(1)
72 //
73 // Register A
74 //
75 typedef struct {
76   UINT8 Rs : 4;   // Rate Selection Bits
77   UINT8 Dv : 3;   // Divisor
78   UINT8 Uip : 1;  // Update in progress
79 } RTC_REGISTER_A_BITS;
80 
81 typedef union {
82   RTC_REGISTER_A_BITS Bits;
83   UINT8               Data;
84 } RTC_REGISTER_A;
85 
86 //
87 // Register B
88 //
89 typedef struct {
90   UINT8 Dse : 1;  // 0 - Daylight saving disabled  1 - Daylight savings enabled
91   UINT8 Mil : 1;  // 0 - 12 hour mode              1 - 24 hour mode
92   UINT8 Dm : 1;   // 0 - BCD Format                1 - Binary Format
93   UINT8 Sqwe : 1; // 0 - Disable SQWE output       1 - Enable SQWE output
94   UINT8 Uie : 1;  // 0 - Update INT disabled       1 - Update INT enabled
95   UINT8 Aie : 1;  // 0 - Alarm INT disabled        1 - Alarm INT Enabled
96   UINT8 Pie : 1;  // 0 - Periodic INT disabled     1 - Periodic INT Enabled
97   UINT8 Set : 1;  // 0 - Normal operation.         1 - Updates inhibited
98 } RTC_REGISTER_B_BITS;
99 
100 typedef union {
101   RTC_REGISTER_B_BITS Bits;
102   UINT8               Data;
103 } RTC_REGISTER_B;
104 
105 //
106 // Register C
107 //
108 typedef struct {
109   UINT8 Reserved : 4; // Read as zero.  Can not be written.
110   UINT8 Uf : 1;       // Update End Interrupt Flag
111   UINT8 Af : 1;       // Alarm Interrupt Flag
112   UINT8 Pf : 1;       // Periodic Interrupt Flag
113   UINT8 Irqf : 1;     // Interrupt Request Flag = PF & PIE | AF & AIE | UF & UIE
114 } RTC_REGISTER_C_BITS;
115 
116 typedef union {
117   RTC_REGISTER_C_BITS Bits;
118   UINT8               Data;
119 } RTC_REGISTER_C;
120 
121 //
122 // Register D
123 //
124 typedef struct {
125   UINT8 Reserved : 7; // Read as zero.  Can not be written.
126   UINT8 Vrt : 1;      // Valid RAM and Time
127 } RTC_REGISTER_D_BITS;
128 
129 typedef union {
130   RTC_REGISTER_D_BITS Bits;
131   UINT8               Data;
132 } RTC_REGISTER_D;
133 
134 #pragma pack()
135 
136 /**
137   Initialize RTC.
138 
139   @param  Global            For global use inside this module.
140 
141   @retval EFI_DEVICE_ERROR  Initialization failed due to device error.
142   @retval EFI_SUCCESS       Initialization successful.
143 
144 **/
145 EFI_STATUS
146 PcRtcInit (
147   IN PC_RTC_MODULE_GLOBALS  *Global
148   );
149 
150 /**
151   Sets the current local time and date information.
152 
153   @param  Time                  A pointer to the current time.
154   @param  Global                For global use inside this module.
155 
156   @retval EFI_SUCCESS           The operation completed successfully.
157   @retval EFI_INVALID_PARAMETER A time field is out of range.
158   @retval EFI_DEVICE_ERROR      The time could not be set due due to hardware error.
159 
160 **/
161 EFI_STATUS
162 PcRtcSetTime (
163   IN EFI_TIME               *Time,
164   IN PC_RTC_MODULE_GLOBALS  *Global
165   );
166 
167 /**
168   Returns the current time and date information, and the time-keeping capabilities
169   of the hardware platform.
170 
171   @param  Time          A pointer to storage to receive a snapshot of the current time.
172   @param  Capabilities  An optional pointer to a buffer to receive the real time clock
173                         device's capabilities.
174   @param  Global        For global use inside this module.
175 
176   @retval EFI_SUCCESS            The operation completed successfully.
177   @retval EFI_INVALID_PARAMETER  Time is NULL.
178   @retval EFI_DEVICE_ERROR       The time could not be retrieved due to hardware error.
179 
180 **/
181 EFI_STATUS
182 PcRtcGetTime (
183   OUT EFI_TIME              *Time,
184   OUT EFI_TIME_CAPABILITIES *Capabilities, OPTIONAL
185   IN  PC_RTC_MODULE_GLOBALS *Global
186   );
187 
188 /**
189   Sets the system wakeup alarm clock time.
190 
191   @param  Enabled  Enable or disable the wakeup alarm.
192   @param  Time     If Enable is TRUE, the time to set the wakeup alarm for.
193                    If Enable is FALSE, then this parameter is optional, and may be NULL.
194   @param  Global   For global use inside this module.
195 
196   @retval EFI_SUCCESS           If Enable is TRUE, then the wakeup alarm was enabled.
197                                 If Enable is FALSE, then the wakeup alarm was disabled.
198   @retval EFI_INVALID_PARAMETER A time field is out of range.
199   @retval EFI_DEVICE_ERROR      The wakeup time could not be set due to a hardware error.
200   @retval EFI_UNSUPPORTED       A wakeup timer is not supported on this platform.
201 
202 **/
203 EFI_STATUS
204 PcRtcSetWakeupTime (
205   IN BOOLEAN                Enable,
206   IN EFI_TIME               *Time,  OPTIONAL
207   IN PC_RTC_MODULE_GLOBALS  *Global
208   );
209 
210 /**
211   Returns the current wakeup alarm clock setting.
212 
213   @param  Enabled  Indicates if the alarm is currently enabled or disabled.
214   @param  Pending  Indicates if the alarm signal is pending and requires acknowledgement.
215   @param  Time     The current alarm setting.
216   @param  Global   For global use inside this module.
217 
218   @retval EFI_SUCCESS           The alarm settings were returned.
219   @retval EFI_INVALID_PARAMETER Enabled is NULL.
220   @retval EFI_INVALID_PARAMETER Pending is NULL.
221   @retval EFI_INVALID_PARAMETER Time is NULL.
222   @retval EFI_DEVICE_ERROR      The wakeup time could not be retrieved due to a hardware error.
223   @retval EFI_UNSUPPORTED       A wakeup timer is not supported on this platform.
224 
225 **/
226 EFI_STATUS
227 PcRtcGetWakeupTime (
228   OUT BOOLEAN               *Enabled,
229   OUT BOOLEAN               *Pending,
230   OUT EFI_TIME              *Time,
231   IN  PC_RTC_MODULE_GLOBALS *Global
232   );
233 
234 /**
235   The user Entry Point for PcRTC module.
236 
237   This is the entry point for PcRTC module. It installs the UEFI runtime service
238   including GetTime(),SetTime(),GetWakeupTime(),and SetWakeupTime().
239 
240   @param  ImageHandle    The firmware allocated handle for the EFI image.
241   @param  SystemTable    A pointer to the EFI System Table.
242 
243   @retval EFI_SUCCESS    The entry point is executed successfully.
244   @retval Others         Some error occurs when executing this entry point.
245 
246 **/
247 EFI_STATUS
248 EFIAPI
249 InitializePcRtc (
250   IN EFI_HANDLE                            ImageHandle,
251   IN EFI_SYSTEM_TABLE                      *SystemTable
252   );
253 
254 /**
255   See if all fields of a variable of EFI_TIME type is correct.
256 
257   @param   Time   The time to be checked.
258 
259   @retval  EFI_INVALID_PARAMETER  Some fields of Time are not correct.
260   @retval  EFI_SUCCESS            Time is a valid EFI_TIME variable.
261 
262 **/
263 EFI_STATUS
264 RtcTimeFieldsValid (
265   IN EFI_TIME *Time
266   );
267 
268 /**
269   Converts time from EFI_TIME format defined by UEFI spec to RTC format.
270 
271   This function converts time from EFI_TIME format defined by UEFI spec to RTC format.
272   If data mode of RTC is BCD, then converts EFI_TIME to it.
273   If RTC is in 12-hour format, then converts EFI_TIME to it.
274 
275   @param   Time       On input, the time data read from UEFI to convert
276                       On output, the time converted to RTC format
277   @param   RegisterB  Value of Register B of RTC, indicating data mode
278 **/
279 VOID
280 ConvertEfiTimeToRtcTime (
281   IN OUT EFI_TIME        *Time,
282   IN     RTC_REGISTER_B  RegisterB
283   );
284 
285 
286 /**
287   Converts time read from RTC to EFI_TIME format defined by UEFI spec.
288 
289   This function converts raw time data read from RTC to the EFI_TIME format
290   defined by UEFI spec.
291   If data mode of RTC is BCD, then converts it to decimal,
292   If RTC is in 12-hour format, then converts it to 24-hour format.
293 
294   @param   Time       On input, the time data read from RTC to convert
295                       On output, the time converted to UEFI format
296   @param   RegisterB  Value of Register B of RTC, indicating data mode
297                       and hour format.
298 
299   @retval  EFI_INVALID_PARAMETER  Parameters passed in are invalid.
300   @retval  EFI_SUCCESS            Convert RTC time to EFI time successfully.
301 
302 **/
303 EFI_STATUS
304 ConvertRtcTimeToEfiTime (
305   IN OUT EFI_TIME        *Time,
306   IN     RTC_REGISTER_B  RegisterB
307   );
308 
309 /**
310   Wait for a period for the RTC to be ready.
311 
312   @param    Timeout  Tell how long it should take to wait.
313 
314   @retval   EFI_DEVICE_ERROR   RTC device error.
315   @retval   EFI_SUCCESS        RTC is updated and ready.
316 **/
317 EFI_STATUS
318 RtcWaitToUpdate (
319   UINTN Timeout
320   );
321 
322 /**
323   See if field Day of an EFI_TIME is correct.
324 
325   @param    Time   Its Day field is to be checked.
326 
327   @retval   TRUE   Day field of Time is correct.
328   @retval   FALSE  Day field of Time is NOT correct.
329 **/
330 BOOLEAN
331 DayValid (
332   IN  EFI_TIME  *Time
333   );
334 
335 /**
336   Check if it is a leapyear.
337 
338   @param    Time   The time to be checked.
339 
340   @retval   TRUE   It is a leapyear.
341   @retval   FALSE  It is NOT a leapyear.
342 **/
343 BOOLEAN
344 IsLeapYear (
345   IN EFI_TIME   *Time
346   );
347 
348 /**
349   Get the century RTC address from the ACPI FADT table.
350 
351   @return  The century RTC address or 0 if not found.
352 **/
353 UINT8
354 GetCenturyRtcAddress (
355   VOID
356   );
357 
358 /**
359   Notification function of ACPI Table change.
360 
361   This is a notification function registered on ACPI Table change event.
362   It saves the Century address stored in ACPI FADT table.
363 
364   @param  Event        Event whose notification function is being invoked.
365   @param  Context      Pointer to the notification function's context.
366 
367 **/
368 VOID
369 EFIAPI
370 PcRtcAcpiTableChangeCallback (
371   IN EFI_EVENT        Event,
372   IN VOID             *Context
373   );
374 #endif
375