]> git.proxmox.com Git - mirror_edk2.git/blobdiff - Omap35xxPkg/Library/RealTimeClockLib/RealTimeClockLib.c
Omap35xxPkg/Library/RealTimeClockLib: Add RTC Support
[mirror_edk2.git] / Omap35xxPkg / Library / RealTimeClockLib / RealTimeClockLib.c
diff --git a/Omap35xxPkg/Library/RealTimeClockLib/RealTimeClockLib.c b/Omap35xxPkg/Library/RealTimeClockLib/RealTimeClockLib.c
new file mode 100755 (executable)
index 0000000..e1d5c9c
--- /dev/null
@@ -0,0 +1,297 @@
+/** @file
+*
+*  Copyright (c) 2011, ARM Limited. All rights reserved.
+*  
+*  This program and the accompanying materials                          
+*  are licensed and made available under the terms and conditions of the BSD License         
+*  which accompanies this distribution.  The full text of the license may be found at        
+*  http://opensource.org/licenses/bsd-license.php                                            
+*
+*  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,                     
+*  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.             
+*
+**/
+
+#include <Uefi.h>
+
+#include <Library/BaseMemoryLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiRuntimeServicesTableLib.h>
+#include <Library/DebugLib.h>
+#include <Library/IoLib.h>
+
+#include <Protocol/RealTimeClock.h>
+#include <Protocol/EmbeddedExternalDevice.h>
+
+#include <Omap3530/Omap3530.h>
+#include <TPS65950.h>
+
+
+EMBEDDED_EXTERNAL_DEVICE   *gTPS65950;
+INT16                      TimeZone = EFI_UNSPECIFIED_TIMEZONE;
+
+/**
+  Returns the current time and date information, and the time-keeping capabilities
+  of the hardware platform.
+
+  @param  Time                  A pointer to storage to receive a snapshot of the current time.
+  @param  Capabilities          An optional pointer to a buffer to receive the real time clock
+                                device's capabilities.
+
+  @retval EFI_SUCCESS           The operation completed successfully.
+  @retval EFI_INVALID_PARAMETER Time is NULL.
+  @retval EFI_DEVICE_ERROR      The time could not be retrieved due to hardware error.
+
+**/
+EFI_STATUS
+EFIAPI
+LibGetTime (
+  OUT EFI_TIME                *Time,
+  OUT EFI_TIME_CAPABILITIES   *Capabilities
+  )
+{
+  EFI_STATUS            Status;
+  UINT8                 Data;
+  EFI_TPL               OldTpl;
+
+  if (Time == NULL) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  OldTpl = gBS->RaiseTPL(TPL_NOTIFY);
+
+  /* Get time and date */
+  ZeroMem(Time, sizeof(EFI_TIME));
+
+  // Latch values
+  Status = gTPS65950->Read (gTPS65950, EXTERNAL_DEVICE_REGISTER(I2C_ADDR_GRP_ID4, RTC_CTRL_REG), 1, &Data);
+  if (Status != EFI_SUCCESS) goto EXIT;
+  Data |= BIT6;
+  Status = gTPS65950->Write (gTPS65950, EXTERNAL_DEVICE_REGISTER(I2C_ADDR_GRP_ID4, RTC_CTRL_REG), 1, &Data);
+  if (Status != EFI_SUCCESS) goto EXIT;
+
+  // Read registers
+  Status = gTPS65950->Read (gTPS65950, EXTERNAL_DEVICE_REGISTER(I2C_ADDR_GRP_ID4, YEARS_REG), 1, &Data);
+  if (Status != EFI_SUCCESS) goto EXIT;
+  Time->Year = 2000 + ((Data >> 4) & 0xF) * 10 + (Data & 0xF);
+
+  Status = gTPS65950->Read (gTPS65950, EXTERNAL_DEVICE_REGISTER(I2C_ADDR_GRP_ID4, MONTHS_REG), 1, &Data);
+  if (Status != EFI_SUCCESS) goto EXIT;
+  Time->Month = ((Data >> 4) & 0x1) * 10 + (Data & 0xF);
+
+  Status = gTPS65950->Read (gTPS65950, EXTERNAL_DEVICE_REGISTER(I2C_ADDR_GRP_ID4, DAYS_REG), 1, &Data);
+  if (Status != EFI_SUCCESS) goto EXIT;
+  Time->Day = ((Data >> 4) & 0x3) * 10 + (Data & 0xF);
+
+  Status = gTPS65950->Read (gTPS65950, EXTERNAL_DEVICE_REGISTER(I2C_ADDR_GRP_ID4, HOURS_REG), 1, &Data);
+  if (Status != EFI_SUCCESS) goto EXIT;
+  Time->Hour = ((Data >> 4) & 0x3) * 10 + (Data & 0xF);
+
+  Status = gTPS65950->Read (gTPS65950, EXTERNAL_DEVICE_REGISTER(I2C_ADDR_GRP_ID4, MINUTES_REG), 1, &Data);
+  if (Status != EFI_SUCCESS) goto EXIT;
+  Time->Minute = ((Data >> 4) & 0x7) * 10 + (Data & 0xF);
+
+  Status = gTPS65950->Read (gTPS65950, EXTERNAL_DEVICE_REGISTER(I2C_ADDR_GRP_ID4, SECONDS_REG), 1, &Data);
+  if (Status != EFI_SUCCESS) goto EXIT;
+  Time->Second = ((Data >> 4) & 0x7) * 10 + (Data & 0xF);
+
+  Time->TimeZone = TimeZone;
+  // TODO: check what to use here
+  Time->Daylight = EFI_TIME_ADJUST_DAYLIGHT;
+
+  // Set capabilities
+
+  // TODO: Set real capabilities
+  if (Capabilities != NULL) {
+    Capabilities->Resolution = 1;
+    Capabilities->Accuracy = 50000000;
+    Capabilities->SetsToZero = FALSE;
+  }
+
+EXIT:
+  gBS->RestoreTPL(OldTpl);
+
+  return (Status == EFI_SUCCESS) ? Status : EFI_DEVICE_ERROR;
+}
+
+/**
+  Sets the current local time and date information.
+
+  @param  Time                  A pointer to the current time.
+
+  @retval EFI_SUCCESS           The operation completed successfully.
+  @retval EFI_INVALID_PARAMETER A time field is out of range.
+  @retval EFI_DEVICE_ERROR      The time could not be set due due to hardware error.
+
+**/
+EFI_STATUS
+EFIAPI
+LibSetTime (
+  IN EFI_TIME                *Time
+  )
+{
+  EFI_STATUS Status;
+  UINT8      Data;
+  UINT8      MonthDayCount[12] = { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
+  EFI_TPL    OldTpl;
+
+  // Input validation according both to UEFI spec and hardware constraints
+  // UEFI spec says valid year range is 1900-9999 but TPS only supports 2000-2099
+  if ( (Time == NULL)
+    || (Time->Year < 2000 || Time->Year > 2099)
+    || (Time->Month < 1 || Time->Month > 12)
+    || (Time->Day < 1 || Time->Day > MonthDayCount[Time->Month])
+    || (Time->Hour > 23)
+    || (Time->Minute > 59)
+    || (Time->Second > 59)
+    || (Time->Nanosecond > 999999999)
+    || ((Time->TimeZone < -1440 || Time->TimeZone > 1440) && Time->TimeZone != 2047)
+  ) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  OldTpl = gBS->RaiseTPL(TPL_NOTIFY);
+
+  Data = Time->Year - 2000;
+  Status = gTPS65950->Write (gTPS65950, EXTERNAL_DEVICE_REGISTER(I2C_ADDR_GRP_ID4, YEARS_REG), 1, &Data);
+  if (Status != EFI_SUCCESS) goto EXIT;
+
+  Data = ((Time->Month / 10) << 4) | (Time->Month % 10);
+  Status = gTPS65950->Write (gTPS65950, EXTERNAL_DEVICE_REGISTER(I2C_ADDR_GRP_ID4, MONTHS_REG), 1, &Data);
+  if (Status != EFI_SUCCESS) goto EXIT;
+
+  Data = ((Time->Day / 10) << 4) | (Time->Day % 10);
+  Status = gTPS65950->Write (gTPS65950, EXTERNAL_DEVICE_REGISTER(I2C_ADDR_GRP_ID4, DAYS_REG), 1, &Data);
+  if (Status != EFI_SUCCESS) goto EXIT;
+
+  Data = ((Time->Hour / 10) << 4) | (Time->Hour % 10);
+  Status = gTPS65950->Write (gTPS65950, EXTERNAL_DEVICE_REGISTER(I2C_ADDR_GRP_ID4, HOURS_REG), 1, &Data);
+  if (Status != EFI_SUCCESS) goto EXIT;
+
+  Data = ((Time->Minute / 10) << 4) | (Time->Minute % 10);
+  Status = gTPS65950->Write (gTPS65950, EXTERNAL_DEVICE_REGISTER(I2C_ADDR_GRP_ID4, MINUTES_REG), 1, &Data);
+  if (Status != EFI_SUCCESS) goto EXIT;
+
+  Data = ((Time->Second / 10) << 4) | (Time->Second % 10);
+  Status = gTPS65950->Write (gTPS65950, EXTERNAL_DEVICE_REGISTER(I2C_ADDR_GRP_ID4, SECONDS_REG), 1, &Data);
+  if (Status != EFI_SUCCESS) goto EXIT;
+
+  TimeZone = Time->TimeZone;
+
+EXIT:
+  gBS->RestoreTPL(OldTpl);
+
+  return (Status == EFI_SUCCESS) ? Status : EFI_DEVICE_ERROR;
+}
+
+/**
+  Returns the current wakeup alarm clock setting.
+
+  @param  Enabled               Indicates if the alarm is currently enabled or disabled.
+  @param  Pending               Indicates if the alarm signal is pending and requires acknowledgement.
+  @param  Time                  The current alarm setting.
+
+  @retval EFI_SUCCESS           The alarm settings were returned.
+  @retval EFI_INVALID_PARAMETER Any parameter is NULL.
+  @retval EFI_DEVICE_ERROR      The wakeup time could not be retrieved due to a hardware error.
+
+**/
+EFI_STATUS
+EFIAPI
+LibGetWakeupTime (
+  OUT BOOLEAN     *Enabled,
+  OUT BOOLEAN     *Pending,
+  OUT EFI_TIME    *Time
+  )
+{
+  return EFI_UNSUPPORTED;
+}
+
+/**
+  Sets the system wakeup alarm clock time.
+
+  @param  Enabled               Enable or disable the wakeup alarm.
+  @param  Time                  If Enable is TRUE, the time to set the wakeup alarm for.
+
+  @retval EFI_SUCCESS           If Enable is TRUE, then the wakeup alarm was enabled. If
+                                Enable is FALSE, then the wakeup alarm was disabled.
+  @retval EFI_INVALID_PARAMETER A time field is out of range.
+  @retval EFI_DEVICE_ERROR      The wakeup time could not be set due to a hardware error.
+  @retval EFI_UNSUPPORTED       A wakeup timer is not supported on this platform.
+
+**/
+EFI_STATUS
+EFIAPI
+LibSetWakeupTime (
+  IN BOOLEAN      Enabled,
+  OUT EFI_TIME    *Time
+  )
+{
+  return EFI_UNSUPPORTED;
+}
+
+/**
+  This is the declaration of an EFI image entry point. This can be the entry point to an application
+  written to this specification, an EFI boot service driver, or an EFI runtime driver.
+
+  @param  ImageHandle           Handle that identifies the loaded image.
+  @param  SystemTable           System Table for this image.
+
+  @retval EFI_SUCCESS           The operation completed successfully.
+
+**/
+EFI_STATUS
+EFIAPI
+LibRtcInitialize (
+  IN EFI_HANDLE                            ImageHandle,
+  IN EFI_SYSTEM_TABLE                      *SystemTable
+  )
+{
+  EFI_STATUS    Status;
+  EFI_HANDLE    Handle;
+  UINT8         Data;
+  EFI_TPL       OldTpl;
+
+  Status = gBS->LocateProtocol (&gEmbeddedExternalDeviceProtocolGuid, NULL, (VOID **)&gTPS65950);
+  ASSERT_EFI_ERROR(Status);
+
+  OldTpl = gBS->RaiseTPL(TPL_NOTIFY);
+  Data = 1;
+  Status = gTPS65950->Write (gTPS65950, EXTERNAL_DEVICE_REGISTER(I2C_ADDR_GRP_ID4, RTC_CTRL_REG), 1, &Data);
+  ASSERT_EFI_ERROR(Status);
+  gBS->RestoreTPL(OldTpl);
+
+  // Setup the setters and getters
+  gRT->GetTime       = LibGetTime;
+  gRT->SetTime       = LibSetTime;
+  gRT->GetWakeupTime = LibGetWakeupTime;
+  gRT->SetWakeupTime = LibSetWakeupTime;
+
+  // Install the protocol
+  Handle = NULL;
+  Status = gBS->InstallMultipleProtocolInterfaces (
+                  &Handle,
+                  &gEfiRealTimeClockArchProtocolGuid,  NULL,
+                  NULL
+                 );
+
+  return Status;
+}
+
+/**
+  Fixup internal data so that EFI can be call in virtual mode.
+  Call the passed in Child Notify event and convert any pointers in
+  lib to virtual mode.
+
+  @param[in]    Event   The Event that is being processed
+  @param[in]    Context Event Context
+**/
+VOID
+EFIAPI
+LibRtcVirtualNotifyEvent (
+  IN EFI_EVENT        Event,
+  IN VOID             *Context
+  )
+{
+  return;
+}