BaseEcLib.c 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332
  1. /** @file
  2. Base EC library implementation for H/W layer.
  3. Copyright (c) 2019, Intel Corporation. All rights reserved.<BR>
  4. SPDX-License-Identifier: BSD-2-Clause-Patent
  5. **/
  6. #include <Base.h>
  7. #include <Uefi.h>
  8. #include <Library/EcLib.h>
  9. #include <Library/IoLib.h>
  10. #include <Library/TimerLib.h>
  11. #include <Library/DebugLib.h>
  12. #ifndef STALL_ONE_MICRO_SECOND
  13. #define STALL_ONE_MICRO_SECOND 1
  14. #endif
  15. #ifndef STALL_ONE_MILLI_SECOND
  16. #define STALL_ONE_MILLI_SECOND 1000
  17. #endif
  18. #ifndef EC_INIT_TIME_OUT
  19. #define EC_INIT_TIME_OUT 0x200
  20. #endif
  21. typedef struct {
  22. UINT8 CommandNumber;
  23. UINT8 NumberOfSendData;
  24. UINT8 NumberOfReceiveData;
  25. BOOLEAN CommandImplemented;
  26. } EC_COMMAND_TABLE;
  27. EC_COMMAND_TABLE mEcCommand[] = {
  28. {EC_C_FAB_ID , 0, 2, TRUE}, // Get the board fab ID in the lower 3 bits
  29. {EC_C_ACPI_READ , 1, 1, TRUE}, // Read a byte of EC RAM
  30. {EC_C_ACPI_WRITE , 2, 0, TRUE} // Write a byte of EC RAM
  31. };
  32. //
  33. // Function implementations
  34. //
  35. /**
  36. Sends command to EC.
  37. @param[in] Command Command byte to send
  38. @param[in] Timeout Timeout in microseonds
  39. @retval EFI_SUCCESS Command success
  40. @retval EFI_DEVICE_ERROR Command error
  41. @retval EFI_TIMEOUT Command timeout
  42. **/
  43. EFI_STATUS
  44. SendEcCommandTimeout (
  45. IN UINT8 Command,
  46. IN UINT32 Timeout
  47. )
  48. {
  49. UINTN Index;
  50. UINT8 EcStatus;
  51. UINT8 DiscardData;
  52. Index = 0;
  53. EcStatus = 0;
  54. DiscardData = 0;
  55. //
  56. // Wait for EC to be ready (with a timeout)
  57. //
  58. ReceiveEcStatus (&EcStatus);
  59. //
  60. // Check if output buffer bit(OBF) is set.
  61. // Read and discard the output buffer data so that next BIOS-EC cmd is in sync
  62. // OBF is cleared by h/w after all data in output buffer is read by BIOS.
  63. //
  64. while ((EcStatus & EC_S_OBF) != 0) {
  65. //
  66. // Read EC data
  67. //
  68. DiscardData = IoRead8 (EC_D_PORT);
  69. DEBUG ((DEBUG_INFO, "OBF is Set!! DiscardData Read 0x%02X\n", DiscardData));
  70. ReceiveEcStatus (&EcStatus);
  71. }
  72. while (((EcStatus & EC_S_IBF) != 0) && (Index < Timeout)) {
  73. MicroSecondDelay (15 * STALL_ONE_MICRO_SECOND);
  74. ReceiveEcStatus (&EcStatus);
  75. Index++;
  76. }
  77. if (Index >= Timeout) {
  78. return EFI_TIMEOUT;
  79. }
  80. //Printing EC Command Sent
  81. DEBUG ((DEBUG_INFO, "Sending EC Command: %02X\n", Command));
  82. //
  83. // Send the EC command
  84. //
  85. IoWrite8 (EC_C_PORT, Command);
  86. return EFI_SUCCESS;
  87. }
  88. /**
  89. Sends command to EC.
  90. @param[in] Command Command byte to send
  91. @retval EFI_SUCCESS Command success
  92. @retval EFI_DEVICE_ERROR Command error
  93. @retval EFI_TIMEOUT Command timeout
  94. **/
  95. EFI_STATUS
  96. SendEcCommand (
  97. IN UINT8 Command
  98. )
  99. {
  100. return SendEcCommandTimeout (Command, EC_TIME_OUT);
  101. }
  102. /**
  103. Receives status from EC.
  104. @param[out] EcStatus Status byte to receive
  105. @retval EFI_SUCCESS
  106. @retval EFI_DEVICE_ERROR
  107. **/
  108. EFI_STATUS
  109. ReceiveEcStatus (
  110. OUT UINT8 *EcStatus
  111. )
  112. {
  113. //
  114. // Read and return the status
  115. //
  116. *EcStatus = IoRead8 (EC_C_PORT);
  117. return EFI_SUCCESS;
  118. }
  119. /**
  120. Sends data to EC.
  121. @param[in] Data Data byte to send
  122. @retval EFI_SUCCESS
  123. @retval EFI_DEVICE_ERROR
  124. **/
  125. EFI_STATUS
  126. SendEcData (
  127. IN UINT8 Data
  128. )
  129. {
  130. UINTN Index;
  131. UINT8 EcStatus;
  132. Index = 0;
  133. //
  134. // Wait for EC to be ready (with a timeout)
  135. //
  136. ReceiveEcStatus (&EcStatus);
  137. while (((EcStatus & EC_S_IBF) != 0) && (Index < EC_TIME_OUT)) {
  138. MicroSecondDelay (15);
  139. ReceiveEcStatus (&EcStatus);
  140. Index++;
  141. }
  142. if (Index >= EC_TIME_OUT) {
  143. return EFI_DEVICE_ERROR;
  144. }
  145. //
  146. //Printing EC Data Sent
  147. //
  148. DEBUG ((DEBUG_INFO, "Sending EC Data: %02X\n", Data));
  149. //
  150. // Send the data and return
  151. //
  152. IoWrite8 (EC_D_PORT, Data);
  153. return EFI_SUCCESS;
  154. }
  155. /**
  156. Receives data from EC.
  157. @param[out] Data Data byte received
  158. @param[in] Timeout Timeout in microseonds
  159. @retval EFI_SUCCESS Read success
  160. @retval EFI_DEVICE_ERROR Read error
  161. @retval EFI_TIMEOUT Command timeout
  162. --*/
  163. EFI_STATUS
  164. ReceiveEcDataTimeout (
  165. OUT UINT8 *Data,
  166. IN UINT32 Timeout
  167. )
  168. {
  169. UINTN Index;
  170. UINT8 EcStatus;
  171. Index = 0;
  172. //
  173. // Wait for EC to be ready (with a timeout)
  174. //
  175. ReceiveEcStatus (&EcStatus);
  176. while (((EcStatus & EC_S_OBF) == 0) && (Index < Timeout)) {
  177. MicroSecondDelay (15 * STALL_ONE_MICRO_SECOND);
  178. ReceiveEcStatus (&EcStatus);
  179. Index++;
  180. }
  181. if (Index >= Timeout) {
  182. return EFI_TIMEOUT;
  183. }
  184. //
  185. // Read EC data and return
  186. //
  187. *Data = IoRead8 (EC_D_PORT);
  188. //Printing EC Data Received
  189. DEBUG ((DEBUG_INFO, "Receiving EC Data: %02X\n", *Data));
  190. return EFI_SUCCESS;
  191. }
  192. /**
  193. Receives data from EC.
  194. @param[out] Data Data byte received
  195. @retval EFI_SUCCESS Read success
  196. @retval EFI_DEVICE_ERROR Read error
  197. @retval EFI_TIMEOUT Command timeout
  198. **/
  199. EFI_STATUS
  200. ReceiveEcData (
  201. OUT UINT8 *Data
  202. )
  203. {
  204. return ReceiveEcDataTimeout (Data, EC_TIME_OUT);
  205. }
  206. /**
  207. Send data to EC through LPC interface.
  208. @param[in] Command Command value to send to the EC
  209. @param[in][out] DataSize Size of data to send to the EC.
  210. If the command retuned data - size of buffer returned by the EC.
  211. Be aware of the DataSize must euqal to size of DataBuffer and cannot smaller
  212. than number of send data or number of receive data, whichever is the grater.
  213. @param[in][out] DataBuffer Pointer to the data buffer including data to be sent to the EC.
  214. If the command returned data - pointer to the buffer including the data.
  215. The buffer size should be the max of receive and transmit data.
  216. @retval EFI_SUCCESS Success
  217. @retval Other Failed - EFI_TIMEOUT, EFI_INVALID_PARAMETER, EFI_UNSUPPORTED,
  218. EFI_BUFFER_TOO_SMALL, etc.
  219. **/
  220. EFI_STATUS
  221. LpcEcInterface (
  222. IN UINT8 Command,
  223. IN OUT UINT8 *DataSize,
  224. IN OUT UINT8 *DataBuffer
  225. )
  226. {
  227. EFI_STATUS Status;
  228. UINT8 NumberOfEcCommands;
  229. UINT8 Index;
  230. UINT8 TxDataIndex;
  231. UINT8 RxDataIndex;
  232. UINT8 MaxValue;
  233. Status = EFI_SUCCESS;
  234. NumberOfEcCommands = sizeof (mEcCommand) / sizeof (EC_COMMAND_TABLE);
  235. for (Index = 0; Index < NumberOfEcCommands; Index++) {
  236. if (Command != mEcCommand[Index].CommandNumber) {
  237. continue;
  238. }
  239. if (mEcCommand[Index].CommandImplemented != TRUE) {
  240. Status = EFI_UNSUPPORTED;
  241. break;
  242. }
  243. if ((mEcCommand[Index].NumberOfSendData != 0) || (mEcCommand[Index].NumberOfReceiveData != 0)) {
  244. if (DataSize == NULL || DataBuffer == NULL) {
  245. Status = EFI_INVALID_PARAMETER;
  246. break;
  247. } else {
  248. MaxValue = MAX (mEcCommand[Index].NumberOfSendData, mEcCommand[Index].NumberOfReceiveData);
  249. if (*DataSize < MaxValue) {
  250. Status = EFI_BUFFER_TOO_SMALL;
  251. *DataSize = MaxValue;
  252. break;
  253. }
  254. }
  255. }
  256. Status = SendEcCommand (Command);
  257. if (EFI_ERROR (Status)) {
  258. break;
  259. }
  260. if (mEcCommand[Index].NumberOfSendData != 0) {
  261. for (TxDataIndex = 0; TxDataIndex < mEcCommand[Index].NumberOfSendData; TxDataIndex++) {
  262. Status = SendEcData (DataBuffer[TxDataIndex]);
  263. if (EFI_ERROR (Status)) {
  264. break;
  265. }
  266. }
  267. }
  268. if (mEcCommand[Index].NumberOfReceiveData != 0) {
  269. for (RxDataIndex = 0; RxDataIndex < mEcCommand[Index].NumberOfReceiveData; RxDataIndex++) {
  270. Status = ReceiveEcData (&DataBuffer[RxDataIndex]);
  271. if (EFI_ERROR (Status)) {
  272. break;
  273. }
  274. *DataSize = RxDataIndex + 1;
  275. }
  276. }
  277. break;
  278. }
  279. return Status;
  280. }