標籤

2014年10月27日 星期一

How to use RTC reigister to set wake up time

From EDKII, It is simple but useful. If your BIOS vendor not provide the items in setup menu, you may give it a try.

1. Check your RTC_EN at PCH.
2. Refer to http://stanislavs.org/helppc/cmos_ram.html, set your alarm time, don't forget to set update enable/disable and AIE bit.

That's all,  EDKII sample code as below

LibSetWakeupTime (
  IN BOOLEAN      Enabled,
  OUT EFI_TIME    *Time
  )
{
  EFI_STATUS            Status;
  EFI_TIME              RtcTime;
  RTC_REGISTER_B        RegisterB;
  UINT8                 Century;
  EFI_TIME_CAPABILITIES Capabilities;

  if (Enabled) {

    if (Time == NULL) {
      return EFI_INVALID_PARAMETER;
    }
    //
    // Make sure that the time fields are valid
    //
    Status = RtcTimeFieldsValid (Time);
    if (EFI_ERROR (Status)) {
      return EFI_INVALID_PARAMETER;
    }
    //
    // Just support set alarm time within 24 hours
    //
    LibGetTime (&RtcTime, &Capabilities);
    if (Time->Year != RtcTime.Year ||
        Time->Month != RtcTime.Month ||
        (Time->Day != RtcTime.Day && Time->Day != (RtcTime.Day + 1))
        ) {
      return EFI_UNSUPPORTED;
    }
    //
    // Make a local copy of the time and date
    //
    CopyMem (&RtcTime, Time, sizeof (EFI_TIME));

  }
  //
  // Acquire RTC Lock to make access to RTC atomic
  //
  EfiAcquireLock (&mRtc.RtcLock);

  //
  // Wait for up to 0.1 seconds for the RTC to be updated
  //
  Status = RtcWaitToUpdate (100000);
  if (EFI_ERROR (Status)) {
    EfiReleaseLock (&mRtc.RtcLock);
    return EFI_DEVICE_ERROR;
  }
  //
  // Read Register B, and inhibit updates of the RTC
  //
  RegisterB.Data      = RtcRead (RTC_ADDRESS_REGISTER_B);

  RegisterB.Bits.SET  = 1;
  RtcWrite (RTC_ADDRESS_REGISTER_B, RegisterB.Data);

  if (Enabled) {
    ConvertEfiTimeToRtcTime (&RtcTime, RegisterB, &Century);

    //
    // Set RTC alarm time
    //
    RtcWrite (RTC_ADDRESS_SECONDS_ALARM, RtcTime.Second);
    RtcWrite (RTC_ADDRESS_MINUTES_ALARM, RtcTime.Minute);
    RtcWrite (RTC_ADDRESS_HOURS_ALARM, RtcTime.Hour);

    RegisterB.Bits.AIE = 1;

  } else {
    RegisterB.Bits.AIE = 0;
  }
  //
  // Allow updates of the RTC registers
  //
  RegisterB.Bits.SET = 0;
  RtcWrite (RTC_ADDRESS_REGISTER_B, RegisterB.Data);

  //
  // Release RTC Lock.
  //
  EfiReleaseLock (&mRtc.RtcLock);

  return EFI_SUCCESS;
}