From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from inva020.nxp.com (inva020.nxp.com [92.121.34.13]) by mx.groups.io with SMTP id smtpd.web11.22090.1574332904503808670 for ; Thu, 21 Nov 2019 02:41:45 -0800 Authentication-Results: mx.groups.io; dkim=missing; spf=pass (domain: nxp.com, ip: 92.121.34.13, mailfrom: meenakshi.aggarwal@nxp.com) Received: from inva020.nxp.com (localhost [127.0.0.1]) by inva020.eu-rdc02.nxp.com (Postfix) with ESMTP id 174B01A0124; Thu, 21 Nov 2019 11:41:43 +0100 (CET) Received: from inv0113.in-blr01.nxp.com (inv0113.in-blr01.nxp.com [165.114.116.118]) by inva020.eu-rdc02.nxp.com (Postfix) with ESMTP id 949271A0A3D; Thu, 21 Nov 2019 11:41:42 +0100 (CET) Received: from uefi-OptiPlex-790.ap.freescale.net (uefi-OptiPlex-790.ap.freescale.net [10.232.132.78]) by inv0113.in-blr01.nxp.com (Postfix) with ESMTP id CE5EA366; Thu, 21 Nov 2019 16:11:41 +0530 (IST) From: "Meenakshi Aggarwal" To: ard.biesheuvel@linaro.org, leif.lindholm@linaro.org, michael.d.kinney@intel.com, devel@edk2.groups.io Cc: v.sethi@nxp.com, Meenakshi Aggarwal Subject: [edk2-platforms] [PATCH v2 06/11] Silicon/Maxim : Add support for DS1307 RTC library Date: Thu, 21 Nov 2019 21:55:09 +0530 Message-Id: <1574353514-23986-7-git-send-email-meenakshi.aggarwal@nxp.com> X-Mailer: git-send-email 1.9.1 In-Reply-To: <1574353514-23986-1-git-send-email-meenakshi.aggarwal@nxp.com> References: <1570639758-30355-1-git-send-email-meenakshi.aggarwal@nxp.com> <1574353514-23986-1-git-send-email-meenakshi.aggarwal@nxp.com> X-Virus-Scanned: ClamAV using ClamSMTP Real time clock Apis on top of I2C Apis Signed-off-by: Meenakshi Aggarwal Reviewed-by: Leif Lindholm --- Silicon/Maxim/Library/Ds1307RtcLib/Ds1307RtcLib.dec | 23 ++ Silicon/Maxim/Library/Ds1307RtcLib/Ds1307RtcLib.inf | 40 +++ Silicon/Maxim/Library/Ds1307RtcLib/Ds1307Rtc.h | 48 +++ Silicon/Maxim/Library/Ds1307RtcLib/Ds1307RtcLib.c | 372 ++++++++++++++++++++ 4 files changed, 483 insertions(+) diff --git a/Silicon/Maxim/Library/Ds1307RtcLib/Ds1307RtcLib.dec b/Silicon/Maxim/Library/Ds1307RtcLib/Ds1307RtcLib.dec new file mode 100644 index 000000000000..27283e714732 --- /dev/null +++ b/Silicon/Maxim/Library/Ds1307RtcLib/Ds1307RtcLib.dec @@ -0,0 +1,23 @@ +#/** @file +# +# Copyright 2017 NXP +# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +#**/ + +[Defines] + DEC_SPECIFICATION = 0x0001001A + PACKAGE_NAME = Ds1307RtcLib + PACKAGE_GUID = 0c095cf6-834d-4fa2-a5a0-31ac35591ad2 + PACKAGE_VERSION = 0.1 + +[Guids] + gDs1307RtcLibTokenSpaceGuid = { 0xd939eb84, 0xa95a, 0x46a0, { 0xa8, 0x2b, 0xb9, 0x64, 0x30, 0xcf, 0xf5, 0x99 }} + +[Protocols] + gDs1307RealTimeClockLibI2cMasterProtocolGuid = { 0xd37c4d54, 0x1bca, 0x49e0, { 0xa0, 0x4a, 0x5c, 0x37, 0x59, 0x38, 0xc7, 0xec}} + +[PcdsFixedAtBuild] + gDs1307RtcLibTokenSpaceGuid.PcdI2cSlaveAddress|0|UINT8|0x00000001 + gDs1307RtcLibTokenSpaceGuid.PcdI2cBusFrequency|0|UINT32|0x00000002 diff --git a/Silicon/Maxim/Library/Ds1307RtcLib/Ds1307RtcLib.inf b/Silicon/Maxim/Library/Ds1307RtcLib/Ds1307RtcLib.inf new file mode 100644 index 000000000000..b92f658bfc46 --- /dev/null +++ b/Silicon/Maxim/Library/Ds1307RtcLib/Ds1307RtcLib.inf @@ -0,0 +1,40 @@ +# @Ds1307RtcLib.inf +# +# Copyright (c) 2016, Freescale Semiconductor, Inc. All rights reserved. +# Copyright 2017 NXP +# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +# + +[Defines] + INF_VERSION = 0x0001001A + BASE_NAME = Ds1307RtcLib + FILE_GUID = 7112fb46-8dda-4a41-ac40-bf212fedfc08 + MODULE_TYPE = BASE + VERSION_STRING = 1.0 + LIBRARY_CLASS = RealTimeClockLib + +[Sources.common] + Ds1307RtcLib.c + +[Packages] + EmbeddedPkg/EmbeddedPkg.dec + MdePkg/MdePkg.dec + Silicon/Maxim/Library/Ds1307RtcLib/Ds1307RtcLib.dec + +[LibraryClasses] + DebugLib + UefiBootServicesTableLib + UefiLib + +[Protocols] + gEfiI2cMasterProtocolGuid ## CONSUMES + gDs1307RealTimeClockLibI2cMasterProtocolGuid ## CONSUMES + +[FixedPcd] + gDs1307RtcLibTokenSpaceGuid.PcdI2cSlaveAddress + gDs1307RtcLibTokenSpaceGuid.PcdI2cBusFrequency + +[Depex] + gDs1307RealTimeClockLibI2cMasterProtocolGuid diff --git a/Silicon/Maxim/Library/Ds1307RtcLib/Ds1307Rtc.h b/Silicon/Maxim/Library/Ds1307RtcLib/Ds1307Rtc.h new file mode 100644 index 000000000000..aa5b3583ec7e --- /dev/null +++ b/Silicon/Maxim/Library/Ds1307RtcLib/Ds1307Rtc.h @@ -0,0 +1,48 @@ +/** Ds1307Rtc.h +* +* Copyright 2017 NXP +* +* SPDX-License-Identifier: BSD-2-Clause-Patent +* +**/ + +#ifndef DS1307RTC_H_ +#define DS1307RTC_H_ + +/* + * RTC time register + */ +#define DS1307_SEC_REG_ADDR 0x00 +#define DS1307_MIN_REG_ADDR 0x01 +#define DS1307_HR_REG_ADDR 0x02 +#define DS1307_DAY_REG_ADDR 0x03 +#define DS1307_DATE_REG_ADDR 0x04 +#define DS1307_MON_REG_ADDR 0x05 +#define DS1307_YR_REG_ADDR 0x06 + +#define DS1307_SEC_BIT_CH 0x80 /* Clock Halt (in Register 0) */ + +/* + * RTC control register + */ +#define DS1307_CTL_REG_ADDR 0x07 + +#define START_YEAR 1970 +#define END_YEAR 2070 + +/* + * TIME MASKS + */ +#define MASK_SEC 0x7F +#define MASK_MIN 0x7F +#define MASK_HOUR 0x3F +#define MASK_DAY 0x3F +#define MASK_MONTH 0x1F + +typedef struct { + UINTN OperationCount; + EFI_I2C_OPERATION SetAddressOp; + EFI_I2C_OPERATION GetSetDateTimeOp; +} RTC_I2C_REQUEST; + +#endif // DS1307RTC_H_ diff --git a/Silicon/Maxim/Library/Ds1307RtcLib/Ds1307RtcLib.c b/Silicon/Maxim/Library/Ds1307RtcLib/Ds1307RtcLib.c new file mode 100644 index 000000000000..88dc198ffec8 --- /dev/null +++ b/Silicon/Maxim/Library/Ds1307RtcLib/Ds1307RtcLib.c @@ -0,0 +1,372 @@ +/** Ds1307RtcLib.c + Implement EFI RealTimeClock via RTC Lib for DS1307 RTC. + + Based on RTC implementation available in + EmbeddedPkg/Library/TemplateRealTimeClockLib/RealTimeClockLib.c + + Copyright (c) 2008 - 2009, Apple Inc. All rights reserved.
+ Copyright 2017 NXP + + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "Ds1307Rtc.h" + +STATIC VOID *mDriverEventRegistration; +STATIC EFI_HANDLE mI2cMasterHandle; +STATIC EFI_I2C_MASTER_PROTOCOL *mI2cMaster; + +/** + Read RTC register. + + @param RtcRegAddr Register offset of RTC to be read. + + @retval Register Value read + +**/ + +STATIC +UINT8 +RtcRead ( + IN UINT8 RtcRegAddr + ) +{ + RTC_I2C_REQUEST Req; + EFI_STATUS Status; + UINT8 Val; + + Val = 0; + + Req.OperationCount = 2; + + Req.SetAddressOp.Flags = 0; + Req.SetAddressOp.LengthInBytes = sizeof (RtcRegAddr); + Req.SetAddressOp.Buffer = &RtcRegAddr; + + Req.GetSetDateTimeOp.Flags = I2C_FLAG_READ; + Req.GetSetDateTimeOp.LengthInBytes = sizeof (Val); + Req.GetSetDateTimeOp.Buffer = &Val; + + Status = mI2cMaster->StartRequest (mI2cMaster, FixedPcdGet8 (PcdI2cSlaveAddress), + (VOID *)&Req, + NULL, NULL); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "RTC read error at Addr:0x%x\n", RtcRegAddr)); + } + + return Val; +} + +/** + Write RTC register. + + @param RtcRegAddr Register offset of RTC to write. + @param Val Value to be written + +**/ + +STATIC +VOID +RtcWrite ( + IN UINT8 RtcRegAddr, + IN UINT8 Val + ) +{ + RTC_I2C_REQUEST Req; + EFI_STATUS Status; + + Req.OperationCount = 2; + + Req.SetAddressOp.Flags = 0; + Req.SetAddressOp.LengthInBytes = sizeof (RtcRegAddr); + Req.SetAddressOp.Buffer = &RtcRegAddr; + + Req.GetSetDateTimeOp.Flags = 0; + Req.GetSetDateTimeOp.LengthInBytes = sizeof (Val); + Req.GetSetDateTimeOp.Buffer = &Val; + + Status = mI2cMaster->StartRequest (mI2cMaster, FixedPcdGet8 (PcdI2cSlaveAddress), + (VOID *)&Req, + NULL, NULL); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "RTC write error at Addr:0x%x\n", RtcRegAddr)); + } +} + +/** + 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 Second; + UINT8 Minute; + UINT8 Hour; + UINT8 Day; + UINT8 Month; + UINT8 Year; + + if (mI2cMaster == NULL) { + return EFI_DEVICE_ERROR; + } + + Status = EFI_SUCCESS; + + Second = RtcRead (DS1307_SEC_REG_ADDR); + Minute = RtcRead (DS1307_MIN_REG_ADDR); + Hour = RtcRead (DS1307_HR_REG_ADDR); + Day = RtcRead (DS1307_DATE_REG_ADDR); + Month = RtcRead (DS1307_MON_REG_ADDR); + Year = RtcRead (DS1307_YR_REG_ADDR); + + if (Second & DS1307_SEC_BIT_CH) { + DEBUG ((DEBUG_ERROR, "### Warning: RTC oscillator has stopped\n")); + /* clear the CH flag */ + RtcWrite (DS1307_SEC_REG_ADDR, + RtcRead (DS1307_SEC_REG_ADDR) & ~DS1307_SEC_BIT_CH); + Status = EFI_DEVICE_ERROR; + } + + Time->Second = BcdToDecimal8 (Second & MASK_SEC); + Time->Minute = BcdToDecimal8 (Minute & MASK_MIN); + Time->Hour = BcdToDecimal8 (Hour & MASK_HOUR); + Time->Day = BcdToDecimal8 (Day & MASK_DAY); + Time->Month = BcdToDecimal8 (Month & MASK_MONTH); + + // + // RTC can save year 1970 to 2069 + // On writing Year, save year % 100 + // On Reading reversing the operation e.g. 2012 + // write = 12 (2012 % 100) + // read = 2012 (12 + 2000) + // + Time->Year = BcdToDecimal8 (Year) + + (BcdToDecimal8 (Year) >= 70 ? START_YEAR - 70 : END_YEAR -70); + + return Status; +} + +/** + 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. + +**/ +EFI_STATUS +EFIAPI +LibSetTime ( + IN EFI_TIME *Time + ) +{ + if (mI2cMaster == NULL) { + return EFI_DEVICE_ERROR; + } + + if (Time->Year < START_YEAR || Time->Year >= END_YEAR){ + DEBUG ((DEBUG_ERROR, "WARNING: Year should be between 1970 and 2069!\n")); + return EFI_INVALID_PARAMETER; + } + + RtcWrite (DS1307_YR_REG_ADDR, DecimalToBcd8 (Time->Year % 100)); + RtcWrite (DS1307_MON_REG_ADDR, DecimalToBcd8 (Time->Month)); + RtcWrite (DS1307_DATE_REG_ADDR, DecimalToBcd8 (Time->Day)); + RtcWrite (DS1307_HR_REG_ADDR, DecimalToBcd8 (Time->Hour)); + RtcWrite (DS1307_MIN_REG_ADDR, DecimalToBcd8 (Time->Minute)); + RtcWrite (DS1307_SEC_REG_ADDR, DecimalToBcd8 (Time->Second)); + + return EFI_SUCCESS; +} + +/** + 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. + @retval EFI_UNSUPPORTED A wakeup timer is not supported on this + platform. + +**/ +EFI_STATUS +EFIAPI +LibGetWakeupTime ( + OUT BOOLEAN *Enabled, + OUT BOOLEAN *Pending, + OUT EFI_TIME *Time + ) +{ + // The DS1307 does not support setting the alarm + 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 + ) +{ + // The DS1307 does not support setting the alarm + return EFI_UNSUPPORTED; +} + +STATIC +VOID +I2cDriverRegistrationEvent ( + IN EFI_EVENT Event, + IN VOID *Context + ) +{ + EFI_STATUS Status; + EFI_I2C_MASTER_PROTOCOL *I2cMaster; + UINTN BusFrequency; + EFI_HANDLE Handle; + UINTN BufferSize; + + // + // Try to connect the newly registered driver to our handle. + // + do { + BufferSize = sizeof (EFI_HANDLE); + Status = gBS->LocateHandle (ByRegisterNotify, + &gEfiI2cMasterProtocolGuid, + mDriverEventRegistration, + &BufferSize, + &Handle); + if (EFI_ERROR (Status)) { + if (Status != EFI_NOT_FOUND) { + DEBUG ((DEBUG_WARN, "%a: gBS->LocateHandle () returned %r\n", + __FUNCTION__, Status)); + } + break; + } + + if (Handle != mI2cMasterHandle) { + continue; + } + + DEBUG ((DEBUG_INFO, "%a: found I2C master!\n", __FUNCTION__)); + + gBS->CloseEvent (Event); + + Status = gBS->OpenProtocol (mI2cMasterHandle, &gEfiI2cMasterProtocolGuid, + (VOID **)&I2cMaster, gImageHandle, NULL, + EFI_OPEN_PROTOCOL_EXCLUSIVE); + ASSERT_EFI_ERROR (Status); + + Status = I2cMaster->Reset (I2cMaster); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "%a: I2CMaster->Reset () failed - %r\n", + __FUNCTION__, Status)); + break; + } + + BusFrequency = FixedPcdGet16 (PcdI2cBusFrequency); + Status = I2cMaster->SetBusFrequency (I2cMaster, &BusFrequency); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "%a: I2CMaster->SetBusFrequency () failed - %r\n", + __FUNCTION__, Status)); + break; + } + + mI2cMaster = I2cMaster; + break; + } while (TRUE); + + return; +} + +/** + 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. + + @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; + UINTN BufferSize; + + // + // Find the handle that marks the controller + // that will provide the I2C master protocol. + // + BufferSize = sizeof (EFI_HANDLE); + Status = gBS->LocateHandle ( + ByProtocol, + &gDs1307RealTimeClockLibI2cMasterProtocolGuid, + NULL, + &BufferSize, + &mI2cMasterHandle + ); + ASSERT_EFI_ERROR (Status); + + // + // Register a protocol registration notification callback on the driver + // binding protocol so we can attempt to connect our I2C master to it + // as soon as it appears. + // + EfiCreateProtocolNotifyEvent ( + &gEfiI2cMasterProtocolGuid, + TPL_CALLBACK, + I2cDriverRegistrationEvent, + NULL, + &mDriverEventRegistration); + + return EFI_SUCCESS; +} -- 1.9.1