EcCommands.c 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231
  1. /** @file
  2. Board-specific EC commands.
  3. Copyright (c) 2021, Baruch Binyamin Doron
  4. Copyright (c) 2021, Intel Corporation. All rights reserved.<BR>
  5. SPDX-License-Identifier: BSD-2-Clause-Patent
  6. **/
  7. #include <Base.h>
  8. #include <Uefi.h>
  9. #include <Library/DebugLib.h>
  10. #include <Library/EcLib.h>
  11. #include <Library/IoLib.h>
  12. /* Notes:
  13. * - ACPI "CMDB": Writing to this offset is equivalent to sending commands.
  14. * The CMDx bytes contain the command parameters.
  15. *
  16. * TODO - Implement:
  17. * - Commands: 0x58, 0xE1 and 0xE2
  18. * - 0x51, 0x52: EC flash write?
  19. * - ACPI CMDB: 0x63 and 0x64, 0xC7
  20. * - 0x0B: Flash write (Boolean argument? Set in offset 0x0B?)
  21. *
  22. * Reversing vendor's protocols:
  23. * - Only read and write are used.
  24. * - Query, ACPI "CMDB" processing and command 58 are unused.
  25. * - Equivalent KbcPeim is an unused PPI.
  26. *
  27. * NB: Also look for potential EC library
  28. */
  29. #define EC_INDEX_IO_PORT 0x1200
  30. #define EC_INDEX_IO_HIGH_ADDR_PORT EC_INDEX_IO_PORT+1
  31. #define EC_INDEX_IO_LOW_ADDR_PORT EC_INDEX_IO_PORT+2
  32. #define EC_INDEX_IO_DATA_PORT EC_INDEX_IO_PORT+3
  33. /**
  34. Reads a byte of EC RAM.
  35. @param[in] Address Address to read
  36. @param[out] Data Data received
  37. @retval EFI_SUCCESS Command success
  38. @retval EFI_INVALID_PARAMETER Data is NULL
  39. @retval EFI_DEVICE_ERROR Command error
  40. @retval EFI_TIMEOUT Command timeout
  41. **/
  42. EFI_STATUS
  43. EcCmd90Read (
  44. IN UINT8 Address,
  45. OUT UINT8 *Data
  46. )
  47. {
  48. EFI_STATUS Status;
  49. if (Data == NULL) {
  50. return EFI_INVALID_PARAMETER;
  51. }
  52. Status = SendEcCommand (0x90);
  53. if (EFI_ERROR (Status)) {
  54. DEBUG((DEBUG_ERROR, "%a(): SendEcCommand(0x90) failed!\n", __FUNCTION__));
  55. return Status;
  56. }
  57. Status = SendEcData (Address);
  58. if (EFI_ERROR (Status)) {
  59. DEBUG((DEBUG_ERROR, "%a(): SendEcData(Address) failed!\n", __FUNCTION__));
  60. return Status;
  61. }
  62. Status = ReceiveEcData (Data);
  63. if (EFI_ERROR (Status)) {
  64. DEBUG((DEBUG_ERROR, "%a(): ReceiveEcData(Data) failed!\n", __FUNCTION__));
  65. return Status;
  66. }
  67. return EFI_SUCCESS;
  68. }
  69. /**
  70. Writes a byte of EC RAM.
  71. @param[in] Address Address to write
  72. @param[in] Data Data to write
  73. @retval EFI_SUCCESS Command success
  74. @retval EFI_DEVICE_ERROR Command error
  75. @retval EFI_TIMEOUT Command timeout
  76. **/
  77. EFI_STATUS
  78. EcCmd91Write (
  79. IN UINT8 Address,
  80. IN UINT8 Data
  81. )
  82. {
  83. EFI_STATUS Status;
  84. Status = SendEcCommand (0x91);
  85. if (EFI_ERROR (Status)) {
  86. DEBUG((DEBUG_ERROR, "%a(): SendEcCommand(0x91) failed!\n", __FUNCTION__));
  87. return Status;
  88. }
  89. Status = SendEcData (Address);
  90. if (EFI_ERROR (Status)) {
  91. DEBUG((DEBUG_ERROR, "%a(): SendEcData(Address) failed!\n", __FUNCTION__));
  92. return Status;
  93. }
  94. Status = SendEcData (Data);
  95. if (EFI_ERROR (Status)) {
  96. DEBUG((DEBUG_ERROR, "%a(): SendEcData(Data) failed!\n", __FUNCTION__));
  97. return Status;
  98. }
  99. return EFI_SUCCESS;
  100. }
  101. /**
  102. Query the EC status.
  103. @param[out] Status EC status byte
  104. @retval EFI_SUCCESS Command success
  105. @retval EFI_INVALID_PARAMETER Data is NULL
  106. @retval EFI_DEVICE_ERROR Command error
  107. @retval EFI_TIMEOUT Command timeout
  108. **/
  109. EFI_STATUS
  110. EcCmd94Query (
  111. OUT UINT8 *Data
  112. )
  113. {
  114. EFI_STATUS Status;
  115. if (Data == NULL) {
  116. return EFI_INVALID_PARAMETER;
  117. }
  118. Status = SendEcCommand (0x94);
  119. if (EFI_ERROR (Status)) {
  120. DEBUG((DEBUG_ERROR, "%a(): SendEcCommand(0x94) failed!\n", __FUNCTION__));
  121. return Status;
  122. }
  123. Status = ReceiveEcData (Data);
  124. if (EFI_ERROR (Status)) {
  125. DEBUG((DEBUG_ERROR, "%a(): ReceiveEcData(Data) failed!\n", __FUNCTION__));
  126. return Status;
  127. }
  128. return EFI_SUCCESS;
  129. }
  130. /**
  131. Reads a byte of EC (index) RAM.
  132. @param[in] Address Address to read
  133. @param[out] Data Data received
  134. **/
  135. VOID
  136. EcIdxRead (
  137. IN UINT16 Address,
  138. OUT UINT8 *Data
  139. )
  140. {
  141. if (Data == NULL) {
  142. return;
  143. }
  144. IoWrite8 (EC_INDEX_IO_HIGH_ADDR_PORT, (UINT8) (Address >> 8));
  145. IoWrite8 (EC_INDEX_IO_LOW_ADDR_PORT, (UINT8) Address);
  146. *Data = IoRead8 (EC_INDEX_IO_DATA_PORT);
  147. }
  148. /**
  149. Writes a byte of EC (index) RAM.
  150. @param[in] Address Address to read
  151. @param[in] Data Data received
  152. **/
  153. VOID
  154. EcIdxWrite (
  155. IN UINT16 Address,
  156. IN UINT8 Data
  157. )
  158. {
  159. IoWrite8 (EC_INDEX_IO_HIGH_ADDR_PORT, (UINT8) (Address >> 8));
  160. IoWrite8 (EC_INDEX_IO_LOW_ADDR_PORT, (UINT8) Address);
  161. IoWrite8 (EC_INDEX_IO_DATA_PORT, Data);
  162. }
  163. /**
  164. Read EC analog-digital converter.
  165. TODO: Check if ADC is valid.
  166. @param[in] Adc
  167. @param[out] DataBuffer
  168. **/
  169. VOID
  170. ReadEcAdcConverter (
  171. IN UINT8 Adc,
  172. OUT UINT16 *DataBuffer
  173. )
  174. {
  175. UINT8 AdcConvertersEnabled; // Contains some ADCs and some DACs
  176. UINT8 IdxData;
  177. if (DataBuffer == NULL) {
  178. return;
  179. }
  180. // Backup enabled ADCs
  181. EcIdxRead (0xff15, &AdcConvertersEnabled); // ADDAEN
  182. // Enable desired ADC in bitmask (not enabled by EC FW, not used by vendor FW)
  183. EcIdxWrite (0xff15, AdcConvertersEnabled | ((1 << Adc) & 0xf)); // ADDAEN
  184. // Sample the desired ADC in binary field; OR the start bit
  185. EcIdxWrite (0xff18, ((Adc << 1) & 0xf) | 1); // ADCTRL
  186. // Read the desired ADC
  187. EcIdxRead (0xff19, &IdxData); // ADCDAT
  188. *DataBuffer = (IdxData << 2);
  189. // Lower 2-bits of 10-bit ADC are in high bits of next register
  190. EcIdxRead (0xff1a, &IdxData); // ECIF
  191. *DataBuffer |= ((IdxData & 0xc0) >> 6);
  192. // Restore enabled ADCs
  193. EcIdxWrite (0xff15, AdcConvertersEnabled); // ADDAEN
  194. }