Ds1307RtcLib.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371
  1. /** Ds1307RtcLib.c
  2. Implement EFI RealTimeClock via RTC Lib for DS1307 RTC.
  3. Based on RTC implementation available in
  4. EmbeddedPkg/Library/TemplateRealTimeClockLib/RealTimeClockLib.c
  5. Copyright (c) 2008 - 2009, Apple Inc. All rights reserved.<BR>
  6. Copyright 2017, 2020 NXP
  7. SPDX-License-Identifier: BSD-2-Clause-Patent
  8. **/
  9. #include <PiDxe.h>
  10. #include <Base.h>
  11. #include <Library/BaseLib.h>
  12. #include <Library/DebugLib.h>
  13. #include <Library/RealTimeClockLib.h>
  14. #include <Library/UefiBootServicesTableLib.h>
  15. #include <Library/UefiLib.h>
  16. #include <Protocol/I2cMaster.h>
  17. #include "Ds1307Rtc.h"
  18. STATIC VOID *mDriverEventRegistration;
  19. STATIC EFI_HANDLE mI2cMasterHandle;
  20. STATIC EFI_I2C_MASTER_PROTOCOL *mI2cMaster;
  21. /**
  22. Read RTC register.
  23. @param RtcRegAddr Register offset of RTC to be read.
  24. @retval Register Value read
  25. **/
  26. STATIC
  27. UINT8
  28. RtcRead (
  29. IN UINT8 RtcRegAddr
  30. )
  31. {
  32. RTC_I2C_REQUEST Req;
  33. EFI_STATUS Status;
  34. UINT8 Val;
  35. Val = 0;
  36. Req.OperationCount = 2;
  37. Req.SetAddressOp.Flags = 0;
  38. Req.SetAddressOp.LengthInBytes = sizeof (RtcRegAddr);
  39. Req.SetAddressOp.Buffer = &RtcRegAddr;
  40. Req.GetSetDateTimeOp.Flags = I2C_FLAG_READ;
  41. Req.GetSetDateTimeOp.LengthInBytes = sizeof (Val);
  42. Req.GetSetDateTimeOp.Buffer = &Val;
  43. Status = mI2cMaster->StartRequest (mI2cMaster, FixedPcdGet8 (PcdI2cSlaveAddress),
  44. (VOID *)&Req,
  45. NULL, NULL);
  46. if (EFI_ERROR (Status)) {
  47. DEBUG ((DEBUG_ERROR, "RTC read error at Addr:0x%x\n", RtcRegAddr));
  48. }
  49. return Val;
  50. }
  51. /**
  52. Write RTC register.
  53. @param RtcRegAddr Register offset of RTC to write.
  54. @param Val Value to be written
  55. **/
  56. STATIC
  57. VOID
  58. RtcWrite (
  59. IN UINT8 RtcRegAddr,
  60. IN UINT8 Val
  61. )
  62. {
  63. RTC_I2C_REQUEST Req;
  64. EFI_STATUS Status;
  65. UINT8 Buffer[2];
  66. Req.OperationCount = 1;
  67. Buffer[0] = RtcRegAddr;
  68. Buffer[1] = Val;
  69. Req.SetAddressOp.Flags = 0;
  70. Req.SetAddressOp.LengthInBytes = sizeof (Buffer);
  71. Req.SetAddressOp.Buffer = Buffer;
  72. Status = mI2cMaster->StartRequest (mI2cMaster, FixedPcdGet8 (PcdI2cSlaveAddress),
  73. (VOID *)&Req,
  74. NULL, NULL);
  75. if (EFI_ERROR (Status)) {
  76. DEBUG ((DEBUG_ERROR, "RTC write error at Addr:0x%x\n", RtcRegAddr));
  77. }
  78. }
  79. /**
  80. Returns the current time and date information, and the time-keeping capabilities
  81. of the hardware platform.
  82. @param Time A pointer to storage to receive a snapshot of the current time.
  83. @param Capabilities An optional pointer to a buffer to receive the real time clock
  84. device's capabilities.
  85. @retval EFI_SUCCESS The operation completed successfully.
  86. @retval EFI_INVALID_PARAMETER Time is NULL.
  87. @retval EFI_DEVICE_ERROR The time could not be retrieved due to hardware error.
  88. **/
  89. EFI_STATUS
  90. EFIAPI
  91. LibGetTime (
  92. OUT EFI_TIME *Time,
  93. OUT EFI_TIME_CAPABILITIES *Capabilities
  94. )
  95. {
  96. EFI_STATUS Status;
  97. UINT8 Second;
  98. UINT8 Minute;
  99. UINT8 Hour;
  100. UINT8 Day;
  101. UINT8 Month;
  102. UINT8 Year;
  103. if (mI2cMaster == NULL) {
  104. return EFI_DEVICE_ERROR;
  105. }
  106. Status = EFI_SUCCESS;
  107. Second = RtcRead (DS1307_SEC_REG_ADDR);
  108. Minute = RtcRead (DS1307_MIN_REG_ADDR);
  109. Hour = RtcRead (DS1307_HR_REG_ADDR);
  110. Day = RtcRead (DS1307_DATE_REG_ADDR);
  111. Month = RtcRead (DS1307_MON_REG_ADDR);
  112. Year = RtcRead (DS1307_YR_REG_ADDR);
  113. if (Second & DS1307_SEC_BIT_CH) {
  114. DEBUG ((DEBUG_ERROR, "### Warning: RTC oscillator has stopped\n"));
  115. /* clear the CH flag */
  116. RtcWrite (DS1307_SEC_REG_ADDR,
  117. RtcRead (DS1307_SEC_REG_ADDR) & ~DS1307_SEC_BIT_CH);
  118. Status = EFI_DEVICE_ERROR;
  119. }
  120. Time->Second = BcdToDecimal8 (Second & MASK_SEC);
  121. Time->Minute = BcdToDecimal8 (Minute & MASK_MIN);
  122. Time->Hour = BcdToDecimal8 (Hour & MASK_HOUR);
  123. Time->Day = BcdToDecimal8 (Day & MASK_DAY);
  124. Time->Month = BcdToDecimal8 (Month & MASK_MONTH);
  125. //
  126. // RTC can save year 1970 to 2069
  127. // On writing Year, save year % 100
  128. // On Reading reversing the operation e.g. 2012
  129. // write = 12 (2012 % 100)
  130. // read = 2012 (12 + 2000)
  131. //
  132. Time->Year = BcdToDecimal8 (Year) +
  133. (BcdToDecimal8 (Year) >= 70 ? START_YEAR - 70 : END_YEAR -70);
  134. return Status;
  135. }
  136. /**
  137. Sets the current local time and date information.
  138. @param Time A pointer to the current time.
  139. @retval EFI_SUCCESS The operation completed successfully.
  140. @retval EFI_INVALID_PARAMETER A time field is out of range.
  141. **/
  142. EFI_STATUS
  143. EFIAPI
  144. LibSetTime (
  145. IN EFI_TIME *Time
  146. )
  147. {
  148. if (mI2cMaster == NULL) {
  149. return EFI_DEVICE_ERROR;
  150. }
  151. if (Time->Year < START_YEAR || Time->Year >= END_YEAR){
  152. DEBUG ((DEBUG_ERROR, "WARNING: Year should be between 1970 and 2069!\n"));
  153. return EFI_INVALID_PARAMETER;
  154. }
  155. RtcWrite (DS1307_YR_REG_ADDR, DecimalToBcd8 (Time->Year % 100));
  156. RtcWrite (DS1307_MON_REG_ADDR, DecimalToBcd8 (Time->Month));
  157. RtcWrite (DS1307_DATE_REG_ADDR, DecimalToBcd8 (Time->Day));
  158. RtcWrite (DS1307_HR_REG_ADDR, DecimalToBcd8 (Time->Hour));
  159. RtcWrite (DS1307_MIN_REG_ADDR, DecimalToBcd8 (Time->Minute));
  160. RtcWrite (DS1307_SEC_REG_ADDR, DecimalToBcd8 (Time->Second));
  161. return EFI_SUCCESS;
  162. }
  163. /**
  164. Returns the current wakeup alarm clock setting.
  165. @param Enabled Indicates if the alarm is currently enabled or disabled.
  166. @param Pending Indicates if the alarm signal is pending and requires acknowledgement.
  167. @param Time The current alarm setting.
  168. @retval EFI_SUCCESS The alarm settings were returned.
  169. @retval EFI_INVALID_PARAMETER Any parameter is NULL.
  170. @retval EFI_DEVICE_ERROR The wakeup time could not be retrieved due to a hardware error.
  171. @retval EFI_UNSUPPORTED A wakeup timer is not supported on this
  172. platform.
  173. **/
  174. EFI_STATUS
  175. EFIAPI
  176. LibGetWakeupTime (
  177. OUT BOOLEAN *Enabled,
  178. OUT BOOLEAN *Pending,
  179. OUT EFI_TIME *Time
  180. )
  181. {
  182. // The DS1307 does not support setting the alarm
  183. return EFI_UNSUPPORTED;
  184. }
  185. /**
  186. Sets the system wakeup alarm clock time.
  187. @param Enabled Enable or disable the wakeup alarm.
  188. @param Time If Enable is TRUE, the time to set the wakeup alarm for.
  189. @retval EFI_SUCCESS If Enable is TRUE, then the wakeup alarm was enabled. If
  190. Enable is FALSE, then the wakeup alarm was disabled.
  191. @retval EFI_INVALID_PARAMETER A time field is out of range.
  192. @retval EFI_DEVICE_ERROR The wakeup time could not be set due to a hardware error.
  193. @retval EFI_UNSUPPORTED A wakeup timer is not supported on this platform.
  194. **/
  195. EFI_STATUS
  196. EFIAPI
  197. LibSetWakeupTime (
  198. IN BOOLEAN Enabled,
  199. OUT EFI_TIME *Time
  200. )
  201. {
  202. // The DS1307 does not support setting the alarm
  203. return EFI_UNSUPPORTED;
  204. }
  205. STATIC
  206. VOID
  207. I2cDriverRegistrationEvent (
  208. IN EFI_EVENT Event,
  209. IN VOID *Context
  210. )
  211. {
  212. EFI_STATUS Status;
  213. EFI_I2C_MASTER_PROTOCOL *I2cMaster;
  214. UINTN BusFrequency;
  215. EFI_HANDLE Handle;
  216. UINTN BufferSize;
  217. //
  218. // Try to connect the newly registered driver to our handle.
  219. //
  220. do {
  221. BufferSize = sizeof (EFI_HANDLE);
  222. Status = gBS->LocateHandle (ByRegisterNotify,
  223. &gEfiI2cMasterProtocolGuid,
  224. mDriverEventRegistration,
  225. &BufferSize,
  226. &Handle);
  227. if (EFI_ERROR (Status)) {
  228. if (Status != EFI_NOT_FOUND) {
  229. DEBUG ((DEBUG_WARN, "%a: gBS->LocateHandle () returned %r\n",
  230. __FUNCTION__, Status));
  231. }
  232. break;
  233. }
  234. if (Handle != mI2cMasterHandle) {
  235. continue;
  236. }
  237. DEBUG ((DEBUG_INFO, "%a: found I2C master!\n", __FUNCTION__));
  238. gBS->CloseEvent (Event);
  239. Status = gBS->OpenProtocol (mI2cMasterHandle, &gEfiI2cMasterProtocolGuid,
  240. (VOID **)&I2cMaster, gImageHandle, NULL,
  241. EFI_OPEN_PROTOCOL_EXCLUSIVE);
  242. ASSERT_EFI_ERROR (Status);
  243. Status = I2cMaster->Reset (I2cMaster);
  244. if (EFI_ERROR (Status)) {
  245. DEBUG ((DEBUG_ERROR, "%a: I2CMaster->Reset () failed - %r\n",
  246. __FUNCTION__, Status));
  247. break;
  248. }
  249. BusFrequency = FixedPcdGet16 (PcdI2cBusFrequency);
  250. Status = I2cMaster->SetBusFrequency (I2cMaster, &BusFrequency);
  251. if (EFI_ERROR (Status)) {
  252. DEBUG ((DEBUG_ERROR, "%a: I2CMaster->SetBusFrequency () failed - %r\n",
  253. __FUNCTION__, Status));
  254. break;
  255. }
  256. mI2cMaster = I2cMaster;
  257. break;
  258. } while (TRUE);
  259. return;
  260. }
  261. /**
  262. This is the declaration of an EFI image entry point. This can be the entry point to an application
  263. written to this specification, an EFI boot service driver.
  264. @param ImageHandle Handle that identifies the loaded image.
  265. @param SystemTable System Table for this image.
  266. @retval EFI_SUCCESS The operation completed successfully.
  267. **/
  268. EFI_STATUS
  269. EFIAPI
  270. LibRtcInitialize (
  271. IN EFI_HANDLE ImageHandle,
  272. IN EFI_SYSTEM_TABLE *SystemTable
  273. )
  274. {
  275. EFI_STATUS Status;
  276. UINTN BufferSize;
  277. //
  278. // Find the handle that marks the controller
  279. // that will provide the I2C master protocol.
  280. //
  281. BufferSize = sizeof (EFI_HANDLE);
  282. Status = gBS->LocateHandle (
  283. ByProtocol,
  284. &gDs1307RealTimeClockLibI2cMasterProtocolGuid,
  285. NULL,
  286. &BufferSize,
  287. &mI2cMasterHandle
  288. );
  289. ASSERT_EFI_ERROR (Status);
  290. //
  291. // Register a protocol registration notification callback on the driver
  292. // binding protocol so we can attempt to connect our I2C master to it
  293. // as soon as it appears.
  294. //
  295. EfiCreateProtocolNotifyEvent (
  296. &gEfiI2cMasterProtocolGuid,
  297. TPL_CALLBACK,
  298. I2cDriverRegistrationEvent,
  299. NULL,
  300. &mDriverEventRegistration);
  301. return EFI_SUCCESS;
  302. }