Home | History | Annotate | Download | only in RealTimeClockLib
      1 /** @file
      2 *
      3 *  Copyright (c) 2011, ARM Limited. All rights reserved.
      4 *
      5 *  This program and the accompanying materials
      6 *  are licensed and made available under the terms and conditions of the BSD License
      7 *  which accompanies this distribution.  The full text of the license may be found at
      8 *  http://opensource.org/licenses/bsd-license.php
      9 *
     10 *  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
     11 *  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
     12 *
     13 **/
     14 
     15 #include <Uefi.h>
     16 
     17 #include <Library/BaseMemoryLib.h>
     18 #include <Library/UefiBootServicesTableLib.h>
     19 #include <Library/UefiRuntimeServicesTableLib.h>
     20 #include <Library/DebugLib.h>
     21 #include <Library/IoLib.h>
     22 
     23 #include <Protocol/RealTimeClock.h>
     24 #include <Protocol/EmbeddedExternalDevice.h>
     25 
     26 #include <Omap3530/Omap3530.h>
     27 #include <TPS65950.h>
     28 
     29 
     30 EMBEDDED_EXTERNAL_DEVICE   *gTPS65950;
     31 INT16                      TimeZone = EFI_UNSPECIFIED_TIMEZONE;
     32 
     33 /**
     34   Returns the current time and date information, and the time-keeping capabilities
     35   of the hardware platform.
     36 
     37   @param  Time                  A pointer to storage to receive a snapshot of the current time.
     38   @param  Capabilities          An optional pointer to a buffer to receive the real time clock
     39                                 device's capabilities.
     40 
     41   @retval EFI_SUCCESS           The operation completed successfully.
     42   @retval EFI_INVALID_PARAMETER Time is NULL.
     43   @retval EFI_DEVICE_ERROR      The time could not be retrieved due to hardware error.
     44 
     45 **/
     46 EFI_STATUS
     47 EFIAPI
     48 LibGetTime (
     49   OUT EFI_TIME                *Time,
     50   OUT EFI_TIME_CAPABILITIES   *Capabilities
     51   )
     52 {
     53   EFI_STATUS            Status;
     54   UINT8                 Data;
     55   EFI_TPL               OldTpl;
     56 
     57   if (Time == NULL) {
     58     return EFI_INVALID_PARAMETER;
     59   }
     60 
     61   OldTpl = gBS->RaiseTPL(TPL_NOTIFY);
     62 
     63   /* Get time and date */
     64   ZeroMem(Time, sizeof(EFI_TIME));
     65 
     66   // Latch values
     67   Status = gTPS65950->Read (gTPS65950, EXTERNAL_DEVICE_REGISTER(I2C_ADDR_GRP_ID4, RTC_CTRL_REG), 1, &Data);
     68   if (Status != EFI_SUCCESS) goto EXIT;
     69   Data |= BIT6;
     70   Status = gTPS65950->Write (gTPS65950, EXTERNAL_DEVICE_REGISTER(I2C_ADDR_GRP_ID4, RTC_CTRL_REG), 1, &Data);
     71   if (Status != EFI_SUCCESS) goto EXIT;
     72 
     73   // Read registers
     74   Status = gTPS65950->Read (gTPS65950, EXTERNAL_DEVICE_REGISTER(I2C_ADDR_GRP_ID4, YEARS_REG), 1, &Data);
     75   if (Status != EFI_SUCCESS) goto EXIT;
     76   Time->Year = 2000 + ((Data >> 4) & 0xF) * 10 + (Data & 0xF);
     77 
     78   Status = gTPS65950->Read (gTPS65950, EXTERNAL_DEVICE_REGISTER(I2C_ADDR_GRP_ID4, MONTHS_REG), 1, &Data);
     79   if (Status != EFI_SUCCESS) goto EXIT;
     80   Time->Month = ((Data >> 4) & 0x1) * 10 + (Data & 0xF);
     81 
     82   Status = gTPS65950->Read (gTPS65950, EXTERNAL_DEVICE_REGISTER(I2C_ADDR_GRP_ID4, DAYS_REG), 1, &Data);
     83   if (Status != EFI_SUCCESS) goto EXIT;
     84   Time->Day = ((Data >> 4) & 0x3) * 10 + (Data & 0xF);
     85 
     86   Status = gTPS65950->Read (gTPS65950, EXTERNAL_DEVICE_REGISTER(I2C_ADDR_GRP_ID4, HOURS_REG), 1, &Data);
     87   if (Status != EFI_SUCCESS) goto EXIT;
     88   Time->Hour = ((Data >> 4) & 0x3) * 10 + (Data & 0xF);
     89 
     90   Status = gTPS65950->Read (gTPS65950, EXTERNAL_DEVICE_REGISTER(I2C_ADDR_GRP_ID4, MINUTES_REG), 1, &Data);
     91   if (Status != EFI_SUCCESS) goto EXIT;
     92   Time->Minute = ((Data >> 4) & 0x7) * 10 + (Data & 0xF);
     93 
     94   Status = gTPS65950->Read (gTPS65950, EXTERNAL_DEVICE_REGISTER(I2C_ADDR_GRP_ID4, SECONDS_REG), 1, &Data);
     95   if (Status != EFI_SUCCESS) goto EXIT;
     96   Time->Second = ((Data >> 4) & 0x7) * 10 + (Data & 0xF);
     97 
     98   Time->TimeZone = TimeZone;
     99   // TODO: check what to use here
    100   Time->Daylight = EFI_TIME_ADJUST_DAYLIGHT;
    101 
    102   // Set capabilities
    103 
    104   // TODO: Set real capabilities
    105   if (Capabilities != NULL) {
    106     Capabilities->Resolution = 1;
    107     Capabilities->Accuracy = 50000000;
    108     Capabilities->SetsToZero = FALSE;
    109   }
    110 
    111 EXIT:
    112   gBS->RestoreTPL(OldTpl);
    113 
    114   return (Status == EFI_SUCCESS) ? Status : EFI_DEVICE_ERROR;
    115 }
    116 
    117 /**
    118   Sets the current local time and date information.
    119 
    120   @param  Time                  A pointer to the current time.
    121 
    122   @retval EFI_SUCCESS           The operation completed successfully.
    123   @retval EFI_INVALID_PARAMETER A time field is out of range.
    124   @retval EFI_DEVICE_ERROR      The time could not be set due due to hardware error.
    125 
    126 **/
    127 EFI_STATUS
    128 EFIAPI
    129 LibSetTime (
    130   IN EFI_TIME                *Time
    131   )
    132 {
    133   EFI_STATUS Status;
    134   UINT8      Data;
    135   UINT8      MonthDayCount[12] = { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
    136   EFI_TPL    OldTpl;
    137 
    138   // Input validation according both to UEFI spec and hardware constraints
    139   // UEFI spec says valid year range is 1900-9999 but TPS only supports 2000-2099
    140   if ( (Time == NULL)
    141     || (Time->Year < 2000 || Time->Year > 2099)
    142     || (Time->Month < 1 || Time->Month > 12)
    143     || (Time->Day < 1 || Time->Day > MonthDayCount[Time->Month])
    144     || (Time->Hour > 23)
    145     || (Time->Minute > 59)
    146     || (Time->Second > 59)
    147     || (Time->Nanosecond > 999999999)
    148     || ((Time->TimeZone < -1440 || Time->TimeZone > 1440) && Time->TimeZone != 2047)
    149   ) {
    150     return EFI_INVALID_PARAMETER;
    151   }
    152 
    153   OldTpl = gBS->RaiseTPL(TPL_NOTIFY);
    154 
    155   Data = Time->Year - 2000;
    156   Status = gTPS65950->Write (gTPS65950, EXTERNAL_DEVICE_REGISTER(I2C_ADDR_GRP_ID4, YEARS_REG), 1, &Data);
    157   if (Status != EFI_SUCCESS) goto EXIT;
    158 
    159   Data = ((Time->Month / 10) << 4) | (Time->Month % 10);
    160   Status = gTPS65950->Write (gTPS65950, EXTERNAL_DEVICE_REGISTER(I2C_ADDR_GRP_ID4, MONTHS_REG), 1, &Data);
    161   if (Status != EFI_SUCCESS) goto EXIT;
    162 
    163   Data = ((Time->Day / 10) << 4) | (Time->Day % 10);
    164   Status = gTPS65950->Write (gTPS65950, EXTERNAL_DEVICE_REGISTER(I2C_ADDR_GRP_ID4, DAYS_REG), 1, &Data);
    165   if (Status != EFI_SUCCESS) goto EXIT;
    166 
    167   Data = ((Time->Hour / 10) << 4) | (Time->Hour % 10);
    168   Status = gTPS65950->Write (gTPS65950, EXTERNAL_DEVICE_REGISTER(I2C_ADDR_GRP_ID4, HOURS_REG), 1, &Data);
    169   if (Status != EFI_SUCCESS) goto EXIT;
    170 
    171   Data = ((Time->Minute / 10) << 4) | (Time->Minute % 10);
    172   Status = gTPS65950->Write (gTPS65950, EXTERNAL_DEVICE_REGISTER(I2C_ADDR_GRP_ID4, MINUTES_REG), 1, &Data);
    173   if (Status != EFI_SUCCESS) goto EXIT;
    174 
    175   Data = ((Time->Second / 10) << 4) | (Time->Second % 10);
    176   Status = gTPS65950->Write (gTPS65950, EXTERNAL_DEVICE_REGISTER(I2C_ADDR_GRP_ID4, SECONDS_REG), 1, &Data);
    177   if (Status != EFI_SUCCESS) goto EXIT;
    178 
    179   TimeZone = Time->TimeZone;
    180 
    181 EXIT:
    182   gBS->RestoreTPL(OldTpl);
    183 
    184   return (Status == EFI_SUCCESS) ? Status : EFI_DEVICE_ERROR;
    185 }
    186 
    187 /**
    188   Returns the current wakeup alarm clock setting.
    189 
    190   @param  Enabled               Indicates if the alarm is currently enabled or disabled.
    191   @param  Pending               Indicates if the alarm signal is pending and requires acknowledgement.
    192   @param  Time                  The current alarm setting.
    193 
    194   @retval EFI_SUCCESS           The alarm settings were returned.
    195   @retval EFI_INVALID_PARAMETER Any parameter is NULL.
    196   @retval EFI_DEVICE_ERROR      The wakeup time could not be retrieved due to a hardware error.
    197 
    198 **/
    199 EFI_STATUS
    200 EFIAPI
    201 LibGetWakeupTime (
    202   OUT BOOLEAN     *Enabled,
    203   OUT BOOLEAN     *Pending,
    204   OUT EFI_TIME    *Time
    205   )
    206 {
    207   return EFI_UNSUPPORTED;
    208 }
    209 
    210 /**
    211   Sets the system wakeup alarm clock time.
    212 
    213   @param  Enabled               Enable or disable the wakeup alarm.
    214   @param  Time                  If Enable is TRUE, the time to set the wakeup alarm for.
    215 
    216   @retval EFI_SUCCESS           If Enable is TRUE, then the wakeup alarm was enabled. If
    217                                 Enable is FALSE, then the wakeup alarm was disabled.
    218   @retval EFI_INVALID_PARAMETER A time field is out of range.
    219   @retval EFI_DEVICE_ERROR      The wakeup time could not be set due to a hardware error.
    220   @retval EFI_UNSUPPORTED       A wakeup timer is not supported on this platform.
    221 
    222 **/
    223 EFI_STATUS
    224 EFIAPI
    225 LibSetWakeupTime (
    226   IN BOOLEAN      Enabled,
    227   OUT EFI_TIME    *Time
    228   )
    229 {
    230   return EFI_UNSUPPORTED;
    231 }
    232 
    233 /**
    234   This is the declaration of an EFI image entry point. This can be the entry point to an application
    235   written to this specification, an EFI boot service driver, or an EFI runtime driver.
    236 
    237   @param  ImageHandle           Handle that identifies the loaded image.
    238   @param  SystemTable           System Table for this image.
    239 
    240   @retval EFI_SUCCESS           The operation completed successfully.
    241 
    242 **/
    243 EFI_STATUS
    244 EFIAPI
    245 LibRtcInitialize (
    246   IN EFI_HANDLE                            ImageHandle,
    247   IN EFI_SYSTEM_TABLE                      *SystemTable
    248   )
    249 {
    250   EFI_STATUS    Status;
    251   EFI_HANDLE    Handle;
    252   UINT8         Data;
    253   EFI_TPL       OldTpl;
    254 
    255   Status = gBS->LocateProtocol (&gEmbeddedExternalDeviceProtocolGuid, NULL, (VOID **)&gTPS65950);
    256   ASSERT_EFI_ERROR(Status);
    257 
    258   OldTpl = gBS->RaiseTPL(TPL_NOTIFY);
    259   Data = 1;
    260   Status = gTPS65950->Write (gTPS65950, EXTERNAL_DEVICE_REGISTER(I2C_ADDR_GRP_ID4, RTC_CTRL_REG), 1, &Data);
    261   ASSERT_EFI_ERROR(Status);
    262   gBS->RestoreTPL(OldTpl);
    263 
    264   // Setup the setters and getters
    265   gRT->GetTime       = LibGetTime;
    266   gRT->SetTime       = LibSetTime;
    267   gRT->GetWakeupTime = LibGetWakeupTime;
    268   gRT->SetWakeupTime = LibSetWakeupTime;
    269 
    270   // Install the protocol
    271   Handle = NULL;
    272   Status = gBS->InstallMultipleProtocolInterfaces (
    273                   &Handle,
    274                   &gEfiRealTimeClockArchProtocolGuid,  NULL,
    275                   NULL
    276                  );
    277 
    278   return Status;
    279 }
    280 
    281 /**
    282   Fixup internal data so that EFI can be call in virtual mode.
    283   Call the passed in Child Notify event and convert any pointers in
    284   lib to virtual mode.
    285 
    286   @param[in]    Event   The Event that is being processed
    287   @param[in]    Context Event Context
    288 **/
    289 VOID
    290 EFIAPI
    291 LibRtcVirtualNotifyEvent (
    292   IN EFI_EVENT        Event,
    293   IN VOID             *Context
    294   )
    295 {
    296   return;
    297 }
    298