]> git.proxmox.com Git - mirror_edk2.git/blame - ArmPlatformPkg/Library/PL031RealTimeClockLib/PL031RealTimeClockLib.c
ArmPlatformPkg/PL180MciDxe: Fixed check for space in transmit FIFO
[mirror_edk2.git] / ArmPlatformPkg / Library / PL031RealTimeClockLib / PL031RealTimeClockLib.c
CommitLineData
1d5d0ae9 1/** @file\r
2 Implement EFI RealTimeClock runtime services via RTC Lib.\r
0f4386e7 3\r
1d5d0ae9 4 Currently this driver does not support runtime virtual calling.\r
5\r
6 Copyright (c) 2008 - 2010, Apple Inc. All rights reserved.<BR>\r
d5cd447b 7 Copyright (c) 2011-2013, ARM Ltd. All rights reserved.<BR>\r
0f4386e7 8\r
1d5d0ae9 9 This program and the accompanying materials\r
10 are licensed and made available under the terms and conditions of the BSD License\r
11 which accompanies this distribution. The full text of the license may be found at\r
12 http://opensource.org/licenses/bsd-license.php\r
13\r
14 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
15 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
16\r
17**/\r
18\r
0f4386e7 19#include <Uefi.h>\r
1d5d0ae9 20#include <PiDxe.h>\r
21#include <Library/BaseLib.h>\r
22#include <Library/DebugLib.h>\r
0f4386e7 23#include <Library/UefiLib.h>\r
1d5d0ae9 24#include <Library/IoLib.h>\r
25#include <Library/RealTimeClockLib.h>\r
0f4386e7 26#include <Library/MemoryAllocationLib.h>\r
5cc45b70 27#include <Library/PcdLib.h>\r
0f4386e7 28#include <Library/ArmPlatformSysConfigLib.h>\r
29#include <Library/UefiBootServicesTableLib.h>\r
30#include <Library/UefiRuntimeServicesTableLib.h>\r
31#include <Protocol/RealTimeClock.h>\r
32#include <Guid/GlobalVariable.h>\r
0f4386e7 33#include <Drivers/PL031RealTimeClock.h>\r
34\r
5cc45b70 35#include <ArmPlatform.h>\r
36\r
1e43cdfd 37STATIC CONST CHAR16 mTimeZoneVariableName[] = L"PL031RtcTimeZone";\r
38STATIC CONST CHAR16 mDaylightVariableName[] = L"PL031RtcDaylight";\r
39STATIC BOOLEAN mPL031Initialized = FALSE;\r
0f4386e7 40\r
41EFI_STATUS\r
42IdentifyPL031 (\r
43 VOID\r
44 )\r
45{\r
46 EFI_STATUS Status;\r
47\r
48 // Check if this is a PrimeCell Peripheral\r
5cc45b70 49 if ( (MmioRead8 (PL031_RTC_PCELL_ID0) != 0x0D)\r
50 || (MmioRead8 (PL031_RTC_PCELL_ID1) != 0xF0)\r
51 || (MmioRead8 (PL031_RTC_PCELL_ID2) != 0x05)\r
52 || (MmioRead8 (PL031_RTC_PCELL_ID3) != 0xB1)) {\r
0f4386e7 53 Status = EFI_NOT_FOUND;\r
54 goto EXIT;\r
55 }\r
56\r
0db25ccc 57 // Check if this PrimeCell Peripheral is the PL031 Real Time Clock\r
5cc45b70 58 if ( (MmioRead8 (PL031_RTC_PERIPH_ID0) != 0x31)\r
59 || (MmioRead8 (PL031_RTC_PERIPH_ID1) != 0x10)\r
60 || ((MmioRead8 (PL031_RTC_PERIPH_ID2) & 0xF) != 0x04)\r
61 || (MmioRead8 (PL031_RTC_PERIPH_ID3) != 0x00)) {\r
0f4386e7 62 Status = EFI_NOT_FOUND;\r
63 goto EXIT;\r
64 }\r
65\r
66 Status = EFI_SUCCESS;\r
67\r
68 EXIT:\r
69 return Status;\r
70}\r
71\r
72EFI_STATUS\r
73InitializePL031 (\r
74 VOID\r
75 )\r
76{\r
77 EFI_STATUS Status;\r
78\r
79 // Prepare the hardware\r
80 Status = IdentifyPL031();\r
81 if (EFI_ERROR (Status)) {\r
82 goto EXIT;\r
83 }\r
84\r
85 // Ensure interrupts are masked. We do not want RTC interrupts in UEFI\r
5cc45b70 86 if ((MmioRead32 (PL031_RTC_IMSC_IRQ_MASK_SET_CLEAR_REGISTER) & PL031_SET_IRQ_MASK) != PL031_SET_IRQ_MASK) {\r
87 MmioOr32 (PL031_RTC_IMSC_IRQ_MASK_SET_CLEAR_REGISTER, PL031_SET_IRQ_MASK);\r
0f4386e7 88 }\r
89\r
90 // Clear any existing interrupts\r
5cc45b70 91 if ((MmioRead32 (PL031_RTC_RIS_RAW_IRQ_STATUS_REGISTER) & PL031_IRQ_TRIGGERED) == PL031_IRQ_TRIGGERED) {\r
92 MmioOr32 (PL031_RTC_ICR_IRQ_CLEAR_REGISTER, PL031_CLEAR_IRQ);\r
0f4386e7 93 }\r
94\r
95 // Start the clock counter\r
5cc45b70 96 if ((MmioRead32 (PL031_RTC_CR_CONTROL_REGISTER) & PL031_RTC_ENABLED) != PL031_RTC_ENABLED) {\r
97 MmioOr32 (PL031_RTC_CR_CONTROL_REGISTER, PL031_RTC_ENABLED);\r
0f4386e7 98 }\r
99\r
100 mPL031Initialized = TRUE;\r
101\r
102 EXIT:\r
103 return Status;\r
104}\r
105\r
106/**\r
107 Converts Epoch seconds (elapsed since 1970 JANUARY 01, 00:00:00 UTC) to EFI_TIME\r
108 **/\r
109VOID\r
110EpochToEfiTime (\r
111 IN UINTN EpochSeconds,\r
112 OUT EFI_TIME *Time\r
113 )\r
114{\r
115 UINTN a;\r
116 UINTN b;\r
117 UINTN c;\r
118 UINTN d;\r
119 UINTN g;\r
120 UINTN j;\r
121 UINTN m;\r
122 UINTN y;\r
123 UINTN da;\r
124 UINTN db;\r
125 UINTN dc;\r
126 UINTN dg;\r
127 UINTN hh;\r
128 UINTN mm;\r
129 UINTN ss;\r
130 UINTN J;\r
131\r
0f4386e7 132 J = (EpochSeconds / 86400) + 2440588;\r
133 j = J + 32044;\r
134 g = j / 146097;\r
135 dg = j % 146097;\r
136 c = (((dg / 36524) + 1) * 3) / 4;\r
137 dc = dg - (c * 36524);\r
138 b = dc / 1461;\r
139 db = dc % 1461;\r
140 a = (((db / 365) + 1) * 3) / 4;\r
141 da = db - (a * 365);\r
142 y = (g * 400) + (c * 100) + (b * 4) + a;\r
143 m = (((da * 5) + 308) / 153) - 2;\r
144 d = da - (((m + 4) * 153) / 5) + 122;\r
145\r
146 Time->Year = y - 4800 + ((m + 2) / 12);\r
147 Time->Month = ((m + 2) % 12) + 1;\r
148 Time->Day = d + 1;\r
149\r
150 ss = EpochSeconds % 60;\r
151 a = (EpochSeconds - ss) / 60;\r
152 mm = a % 60;\r
153 b = (a - mm) / 60;\r
154 hh = b % 24;\r
155\r
156 Time->Hour = hh;\r
157 Time->Minute = mm;\r
158 Time->Second = ss;\r
159 Time->Nanosecond = 0;\r
160\r
161}\r
162\r
163/**\r
164 Converts EFI_TIME to Epoch seconds (elapsed since 1970 JANUARY 01, 00:00:00 UTC)\r
165 **/\r
166UINTN\r
167EfiTimeToEpoch (\r
168 IN EFI_TIME *Time\r
169 )\r
170{\r
171 UINTN a;\r
172 UINTN y;\r
173 UINTN m;\r
174 UINTN JulianDate; // Absolute Julian Date representation of the supplied Time\r
175 UINTN EpochDays; // Number of days elapsed since EPOCH_JULIAN_DAY\r
176 UINTN EpochSeconds;\r
177\r
178 a = (14 - Time->Month) / 12 ;\r
179 y = Time->Year + 4800 - a;\r
180 m = Time->Month + (12*a) - 3;\r
181\r
182 JulianDate = Time->Day + ((153*m + 2)/5) + (365*y) + (y/4) - (y/100) + (y/400) - 32045;\r
183\r
5cc45b70 184 ASSERT(JulianDate > EPOCH_JULIAN_DATE);\r
0f4386e7 185 EpochDays = JulianDate - EPOCH_JULIAN_DATE;\r
186\r
187 EpochSeconds = (EpochDays * SEC_PER_DAY) + ((UINTN)Time->Hour * SEC_PER_HOUR) + (Time->Minute * SEC_PER_MIN) + Time->Second;\r
188\r
189 return EpochSeconds;\r
190}\r
191\r
192BOOLEAN\r
193IsLeapYear (\r
194 IN EFI_TIME *Time\r
195 )\r
196{\r
197 if (Time->Year % 4 == 0) {\r
198 if (Time->Year % 100 == 0) {\r
199 if (Time->Year % 400 == 0) {\r
200 return TRUE;\r
201 } else {\r
202 return FALSE;\r
203 }\r
204 } else {\r
205 return TRUE;\r
206 }\r
207 } else {\r
208 return FALSE;\r
209 }\r
210}\r
211\r
212BOOLEAN\r
213DayValid (\r
214 IN EFI_TIME *Time\r
215 )\r
216{\r
217 INTN DayOfMonth[12] = { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };\r
1d5d0ae9 218\r
0f4386e7 219 if (Time->Day < 1 ||\r
220 Time->Day > DayOfMonth[Time->Month - 1] ||\r
221 (Time->Month == 2 && (!IsLeapYear (Time) && Time->Day > 28))\r
5cc45b70 222 ) {\r
0f4386e7 223 return FALSE;\r
224 }\r
225\r
226 return TRUE;\r
227}\r
1d5d0ae9 228\r
229/**\r
230 Returns the current time and date information, and the time-keeping capabilities\r
231 of the hardware platform.\r
232\r
1e43cdfd 233 @param Time A pointer to storage to receive a snapshot of the current time.\r
234 @param Capabilities An optional pointer to a buffer to receive the real time clock\r
235 device's capabilities.\r
1d5d0ae9 236\r
1e43cdfd 237 @retval EFI_SUCCESS The operation completed successfully.\r
238 @retval EFI_INVALID_PARAMETER Time is NULL.\r
239 @retval EFI_DEVICE_ERROR The time could not be retrieved due to hardware error.\r
240 @retval EFI_SECURITY_VIOLATION The time could not be retrieved due to an authentication failure.\r
1d5d0ae9 241\r
242**/\r
243EFI_STATUS\r
244EFIAPI\r
245LibGetTime (\r
246 OUT EFI_TIME *Time,\r
0f4386e7 247 OUT EFI_TIME_CAPABILITIES *Capabilities\r
1d5d0ae9 248 )\r
249{\r
0f4386e7 250 EFI_STATUS Status = EFI_SUCCESS;\r
d5cd447b 251 UINT32 EpochSeconds;\r
1e43cdfd 252 INT16 TimeZone;\r
253 UINT8 Daylight;\r
254 UINTN Size;\r
0f4386e7 255\r
256 // Initialize the hardware if not already done\r
5cc45b70 257 if (!mPL031Initialized) {\r
258 Status = InitializePL031 ();\r
0f4386e7 259 if (EFI_ERROR (Status)) {\r
260 goto EXIT;\r
261 }\r
262 }\r
263\r
264 // Snapshot the time as early in the function call as possible\r
265 // On some platforms we may have access to a battery backed up hardware clock.\r
266 // If such RTC exists try to use it first.\r
267 Status = ArmPlatformSysConfigGet (SYS_CFG_RTC, &EpochSeconds);\r
268 if (Status == EFI_UNSUPPORTED) {\r
269 // Battery backed up hardware RTC does not exist, revert to PL031\r
5cc45b70 270 EpochSeconds = MmioRead32 (PL031_RTC_DR_DATA_REGISTER);\r
0f4386e7 271 Status = EFI_SUCCESS;\r
272 } else if (EFI_ERROR (Status)) {\r
273 // Battery backed up hardware RTC exists but could not be read due to error. Abort.\r
274 goto EXIT;\r
275 } else {\r
276 // Battery backed up hardware RTC exists and we read the time correctly from it.\r
277 // Now sync the PL031 to the new time.\r
5cc45b70 278 MmioWrite32 (PL031_RTC_LR_LOAD_REGISTER, EpochSeconds);\r
0f4386e7 279 }\r
280\r
281 // Ensure Time is a valid pointer\r
5cc45b70 282 if (Time == NULL) {\r
0f4386e7 283 Status = EFI_INVALID_PARAMETER;\r
284 goto EXIT;\r
285 }\r
286\r
287 // Get the current time zone information from non-volatile storage\r
1e43cdfd 288 Size = sizeof (TimeZone);\r
289 Status = gRT->GetVariable (\r
290 (CHAR16 *)mTimeZoneVariableName,\r
291 &gEfiCallerIdGuid,\r
292 NULL,\r
293 &Size,\r
294 (VOID *)&TimeZone\r
295 );\r
296\r
297 if (EFI_ERROR (Status)) {\r
298 ASSERT(Status != EFI_INVALID_PARAMETER);\r
299 ASSERT(Status != EFI_BUFFER_TOO_SMALL);\r
300\r
301 if (Status != EFI_NOT_FOUND)\r
302 goto EXIT;\r
0f4386e7 303\r
0f4386e7 304 // The time zone variable does not exist in non-volatile storage, so create it.\r
305 Time->TimeZone = EFI_UNSPECIFIED_TIMEZONE;\r
306 // Store it\r
307 Status = gRT->SetVariable (\r
1e43cdfd 308 (CHAR16 *)mTimeZoneVariableName,\r
309 &gEfiCallerIdGuid,\r
310 EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,\r
311 Size,\r
312 (VOID *)&(Time->TimeZone)\r
313 );\r
0f4386e7 314 if (EFI_ERROR (Status)) {\r
1e43cdfd 315 DEBUG ((\r
316 EFI_D_ERROR,\r
317 "LibGetTime: Failed to save %s variable to non-volatile storage, Status = %r\n",\r
318 mTimeZoneVariableName,\r
319 Status\r
320 ));\r
0f4386e7 321 goto EXIT;\r
322 }\r
323 } else {\r
324 // Got the time zone\r
1e43cdfd 325 Time->TimeZone = TimeZone;\r
0f4386e7 326\r
327 // Check TimeZone bounds: -1440 to 1440 or 2047\r
5cc45b70 328 if (((Time->TimeZone < -1440) || (Time->TimeZone > 1440))\r
329 && (Time->TimeZone != EFI_UNSPECIFIED_TIMEZONE)) {\r
0f4386e7 330 Time->TimeZone = EFI_UNSPECIFIED_TIMEZONE;\r
331 }\r
332\r
333 // Adjust for the correct time zone\r
5cc45b70 334 if (Time->TimeZone != EFI_UNSPECIFIED_TIMEZONE) {\r
0f4386e7 335 EpochSeconds += Time->TimeZone * SEC_PER_MIN;\r
336 }\r
337 }\r
338\r
339 // Get the current daylight information from non-volatile storage\r
1e43cdfd 340 Size = sizeof (Daylight);\r
341 Status = gRT->GetVariable (\r
342 (CHAR16 *)mDaylightVariableName,\r
343 &gEfiCallerIdGuid,\r
344 NULL,\r
345 &Size,\r
346 (VOID *)&Daylight\r
347 );\r
348\r
349 if (EFI_ERROR (Status)) {\r
350 ASSERT(Status != EFI_INVALID_PARAMETER);\r
351 ASSERT(Status != EFI_BUFFER_TOO_SMALL);\r
352\r
353 if (Status != EFI_NOT_FOUND)\r
354 goto EXIT;\r
0f4386e7 355\r
0f4386e7 356 // The daylight variable does not exist in non-volatile storage, so create it.\r
357 Time->Daylight = 0;\r
358 // Store it\r
359 Status = gRT->SetVariable (\r
1e43cdfd 360 (CHAR16 *)mDaylightVariableName,\r
361 &gEfiCallerIdGuid,\r
362 EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,\r
363 Size,\r
364 (VOID *)&(Time->Daylight)\r
365 );\r
0f4386e7 366 if (EFI_ERROR (Status)) {\r
1e43cdfd 367 DEBUG ((\r
368 EFI_D_ERROR,\r
369 "LibGetTime: Failed to save %s variable to non-volatile storage, Status = %r\n",\r
370 mDaylightVariableName,\r
371 Status\r
372 ));\r
0f4386e7 373 goto EXIT;\r
374 }\r
375 } else {\r
376 // Got the daylight information\r
1e43cdfd 377 Time->Daylight = Daylight;\r
0f4386e7 378\r
379 // Adjust for the correct period\r
5cc45b70 380 if ((Time->Daylight & EFI_TIME_IN_DAYLIGHT) == EFI_TIME_IN_DAYLIGHT) {\r
0f4386e7 381 // Convert to adjusted time, i.e. spring forwards one hour\r
382 EpochSeconds += SEC_PER_HOUR;\r
383 }\r
384 }\r
385\r
386 // Convert from internal 32-bit time to UEFI time\r
5cc45b70 387 EpochToEfiTime (EpochSeconds, Time);\r
0f4386e7 388\r
389 // Update the Capabilities info\r
5cc45b70 390 if (Capabilities != NULL) {\r
391 // PL031 runs at frequency 1Hz\r
392 Capabilities->Resolution = PL031_COUNTS_PER_SECOND;\r
393 // Accuracy in ppm multiplied by 1,000,000, e.g. for 50ppm set 50,000,000\r
394 Capabilities->Accuracy = (UINT32)PcdGet32 (PcdPL031RtcPpmAccuracy);\r
395 // FALSE: Setting the time does not clear the values below the resolution level\r
396 Capabilities->SetsToZero = FALSE;\r
0f4386e7 397 }\r
398\r
399 EXIT:\r
400 return Status;\r
1d5d0ae9 401}\r
402\r
403\r
404/**\r
405 Sets the current local time and date information.\r
406\r
407 @param Time A pointer to the current time.\r
408\r
409 @retval EFI_SUCCESS The operation completed successfully.\r
410 @retval EFI_INVALID_PARAMETER A time field is out of range.\r
411 @retval EFI_DEVICE_ERROR The time could not be set due due to hardware error.\r
412\r
413**/\r
414EFI_STATUS\r
415EFIAPI\r
416LibSetTime (\r
0f4386e7 417 IN EFI_TIME *Time\r
1d5d0ae9 418 )\r
419{\r
0f4386e7 420 EFI_STATUS Status;\r
421 UINTN EpochSeconds;\r
422\r
423 // Because the PL031 is a 32-bit counter counting seconds,\r
424 // the maximum time span is just over 136 years.\r
425 // Time is stored in Unix Epoch format, so it starts in 1970,\r
426 // Therefore it can not exceed the year 2106.\r
427 // This is not a problem for UEFI, as the current spec limits the years\r
428 // to the range 1998 .. 2011\r
429\r
430 // Check the input parameters' range.\r
5cc45b70 431 if ((Time->Year < 1998) ||\r
432 (Time->Year > 2099) ||\r
433 (Time->Month < 1 ) ||\r
434 (Time->Month > 12 ) ||\r
435 (!DayValid (Time) ) ||\r
436 (Time->Hour > 23 ) ||\r
437 (Time->Minute > 59 ) ||\r
438 (Time->Second > 59 ) ||\r
439 (Time->Nanosecond > 999999999) ||\r
440 (!((Time->TimeZone == EFI_UNSPECIFIED_TIMEZONE) || ((Time->TimeZone >= -1440) && (Time->TimeZone <= 1440)))) ||\r
441 (Time->Daylight & (~(EFI_TIME_ADJUST_DAYLIGHT | EFI_TIME_IN_DAYLIGHT)))\r
442 ) {\r
0f4386e7 443 Status = EFI_INVALID_PARAMETER;\r
444 goto EXIT;\r
445 }\r
446\r
447 // Initialize the hardware if not already done\r
5cc45b70 448 if (!mPL031Initialized) {\r
449 Status = InitializePL031 ();\r
0f4386e7 450 if (EFI_ERROR (Status)) {\r
451 goto EXIT;\r
452 }\r
453 }\r
454\r
5cc45b70 455 EpochSeconds = EfiTimeToEpoch (Time);\r
0f4386e7 456\r
457 // Adjust for the correct time zone, i.e. convert to UTC time zone\r
5cc45b70 458 if (Time->TimeZone != EFI_UNSPECIFIED_TIMEZONE) {\r
0f4386e7 459 EpochSeconds -= Time->TimeZone * SEC_PER_MIN;\r
460 }\r
461\r
462 // TODO: Automatic Daylight activation\r
463\r
464 // Adjust for the correct period\r
5cc45b70 465 if ((Time->Daylight & EFI_TIME_IN_DAYLIGHT) == EFI_TIME_IN_DAYLIGHT) {\r
0f4386e7 466 // Convert to un-adjusted time, i.e. fall back one hour\r
467 EpochSeconds -= SEC_PER_HOUR;\r
468 }\r
469\r
470 // On some platforms we may have access to a battery backed up hardware clock.\r
1d5d0ae9 471 //\r
0f4386e7 472 // If such RTC exists then it must be updated first, before the PL031,\r
473 // to minimise any time drift. This is important because the battery backed-up\r
474 // RTC maintains the master time for the platform across reboots.\r
1d5d0ae9 475 //\r
0f4386e7 476 // If such RTC does not exist then the following function returns UNSUPPORTED.\r
477 Status = ArmPlatformSysConfigSet (SYS_CFG_RTC, EpochSeconds);\r
478 if ((EFI_ERROR (Status)) && (Status != EFI_UNSUPPORTED)){\r
479 // Any status message except SUCCESS and UNSUPPORTED indicates a hardware failure.\r
480 goto EXIT;\r
481 }\r
482\r
483\r
484 // Set the PL031\r
5cc45b70 485 MmioWrite32 (PL031_RTC_LR_LOAD_REGISTER, EpochSeconds);\r
0f4386e7 486\r
487 // The accesses to Variable Services can be very slow, because we may be writing to Flash.\r
488 // Do this after having set the RTC.\r
489\r
490 // Save the current time zone information into non-volatile storage\r
491 Status = gRT->SetVariable (\r
1e43cdfd 492 (CHAR16 *)mTimeZoneVariableName,\r
493 &gEfiCallerIdGuid,\r
494 EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,\r
495 sizeof (Time->TimeZone),\r
496 (VOID *)&(Time->TimeZone)\r
497 );\r
0f4386e7 498 if (EFI_ERROR (Status)) {\r
1e43cdfd 499 DEBUG ((\r
500 EFI_D_ERROR,\r
501 "LibSetTime: Failed to save %s variable to non-volatile storage, Status = %r\n",\r
502 mTimeZoneVariableName,\r
503 Status\r
504 ));\r
0f4386e7 505 goto EXIT;\r
506 }\r
507\r
508 // Save the current daylight information into non-volatile storage\r
509 Status = gRT->SetVariable (\r
1e43cdfd 510 (CHAR16 *)mDaylightVariableName,\r
511 &gEfiCallerIdGuid,\r
512 EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,\r
513 sizeof(Time->Daylight),\r
514 (VOID *)&(Time->Daylight)\r
515 );\r
0f4386e7 516 if (EFI_ERROR (Status)) {\r
1e43cdfd 517 DEBUG ((\r
518 EFI_D_ERROR,\r
519 "LibSetTime: Failed to save %s variable to non-volatile storage, Status = %r\n",\r
520 mDaylightVariableName,\r
521 Status\r
522 ));\r
0f4386e7 523 goto EXIT;\r
524 }\r
525\r
526 EXIT:\r
527 return Status;\r
1d5d0ae9 528}\r
529\r
530\r
531/**\r
532 Returns the current wakeup alarm clock setting.\r
533\r
534 @param Enabled Indicates if the alarm is currently enabled or disabled.\r
535 @param Pending Indicates if the alarm signal is pending and requires acknowledgement.\r
536 @param Time The current alarm setting.\r
537\r
538 @retval EFI_SUCCESS The alarm settings were returned.\r
539 @retval EFI_INVALID_PARAMETER Any parameter is NULL.\r
540 @retval EFI_DEVICE_ERROR The wakeup time could not be retrieved due to a hardware error.\r
541\r
542**/\r
543EFI_STATUS\r
544EFIAPI\r
545LibGetWakeupTime (\r
546 OUT BOOLEAN *Enabled,\r
547 OUT BOOLEAN *Pending,\r
548 OUT EFI_TIME *Time\r
549 )\r
550{\r
551 // Not a required feature\r
552 return EFI_UNSUPPORTED;\r
553}\r
554\r
555\r
556/**\r
557 Sets the system wakeup alarm clock time.\r
558\r
559 @param Enabled Enable or disable the wakeup alarm.\r
560 @param Time If Enable is TRUE, the time to set the wakeup alarm for.\r
561\r
562 @retval EFI_SUCCESS If Enable is TRUE, then the wakeup alarm was enabled. If\r
563 Enable is FALSE, then the wakeup alarm was disabled.\r
564 @retval EFI_INVALID_PARAMETER A time field is out of range.\r
565 @retval EFI_DEVICE_ERROR The wakeup time could not be set due to a hardware error.\r
566 @retval EFI_UNSUPPORTED A wakeup timer is not supported on this platform.\r
567\r
568**/\r
569EFI_STATUS\r
570EFIAPI\r
571LibSetWakeupTime (\r
572 IN BOOLEAN Enabled,\r
573 OUT EFI_TIME *Time\r
574 )\r
575{\r
576 // Not a required feature\r
577 return EFI_UNSUPPORTED;\r
578}\r
579\r
580\r
581\r
582/**\r
583 This is the declaration of an EFI image entry point. This can be the entry point to an application\r
584 written to this specification, an EFI boot service driver, or an EFI runtime driver.\r
585\r
586 @param ImageHandle Handle that identifies the loaded image.\r
587 @param SystemTable System Table for this image.\r
588\r
589 @retval EFI_SUCCESS The operation completed successfully.\r
590\r
591**/\r
592EFI_STATUS\r
593EFIAPI\r
594LibRtcInitialize (\r
595 IN EFI_HANDLE ImageHandle,\r
596 IN EFI_SYSTEM_TABLE *SystemTable\r
597 )\r
598{\r
0f4386e7 599 EFI_STATUS Status;\r
600 EFI_HANDLE Handle;\r
601\r
602 // Setup the setters and getters\r
603 gRT->GetTime = LibGetTime;\r
604 gRT->SetTime = LibSetTime;\r
605 gRT->GetWakeupTime = LibGetWakeupTime;\r
606 gRT->SetWakeupTime = LibSetWakeupTime;\r
607\r
608 // Install the protocol\r
609 Handle = NULL;\r
610 Status = gBS->InstallMultipleProtocolInterfaces (\r
611 &Handle,\r
612 &gEfiRealTimeClockArchProtocolGuid, NULL,\r
613 NULL\r
5cc45b70 614 );\r
0f4386e7 615\r
616 return Status;\r
1d5d0ae9 617}\r
618\r
619\r
620/**\r
621 Fixup internal data so that EFI can be call in virtual mode.\r
622 Call the passed in Child Notify event and convert any pointers in\r
623 lib to virtual mode.\r
624\r
625 @param[in] Event The Event that is being processed\r
626 @param[in] Context Event Context\r
627**/\r
628VOID\r
629EFIAPI\r
630LibRtcVirtualNotifyEvent (\r
631 IN EFI_EVENT Event,\r
632 IN VOID *Context\r
633 )\r
634{\r
635 //\r
636 // Only needed if you are going to support the OS calling RTC functions in virtual mode.\r
0f4386e7 637 // You will need to call EfiConvertPointer (). To convert any stored physical addresses\r
638 // to virtual address. After the OS transitions to calling in virtual mode, all future\r
1d5d0ae9 639 // runtime calls will be made in virtual mode.\r
640 //\r
641 return;\r
642}\r