Gmbus.c 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760
  1. /** @file
  2. GMBUS I/O Implementation
  3. Copyright (c) 2022, Intel Corporation. All rights reserved.<BR>
  4. SPDX-License-Identifier: BSD-2-Clause-Patent
  5. **/
  6. #include <Uefi.h>
  7. #include <Library/BaseLib.h>
  8. #include <Library/DebugLib.h>
  9. #include <Library/PcdLib.h>
  10. #include <Library/IoLib.h>
  11. #include <Library/PciLib.h>
  12. #include <IgfxI2c.h>
  13. #include <Gmbus.h>
  14. /**
  15. Gets the GttMmAdr BAR value
  16. @retval The current value of the GTTMMADR BAR
  17. **/
  18. UINTN
  19. GmbusGetGttMmAdr (
  20. VOID
  21. )
  22. {
  23. UINTN GttMmPciAddress;
  24. UINT32 GttMmAdr;
  25. //
  26. // Check if GTT Memory Mapped BAR has been already assigned, initialize if not
  27. //
  28. GttMmPciAddress = PCI_LIB_ADDRESS (SA_IGD_BUS, SA_IGD_DEV, SA_IGD_FUN_0, R_SA_IGD_GTTMMADR);
  29. GttMmAdr = PciRead32 (GttMmPciAddress) & 0xFFFFFFF0;
  30. if (GttMmAdr == 0) {
  31. GttMmAdr = (UINT32) FixedPcdGet32 (PcdGttMmAddress);
  32. if (GttMmAdr == 0) {
  33. return 0;
  34. }
  35. //
  36. // Program and read back GTT Memory Mapped BAR
  37. //
  38. PciWrite32 (GttMmPciAddress, (UINT32) (GttMmAdr & 0xFF000000));
  39. GttMmAdr = PciRead32 (GttMmPciAddress) & 0xFFFFFFF0;
  40. }
  41. //
  42. // Check if Bus Master and Memory access on 0:2:0 is enabled, enable it if not
  43. //
  44. if ((PciRead16 (
  45. PCI_LIB_ADDRESS (SA_IGD_BUS, SA_IGD_DEV, SA_IGD_FUN_0, R_SA_IGD_CMD)
  46. )
  47. & (BIT2 | BIT1)) != (BIT2 | BIT1)) {
  48. //
  49. // Enable Bus Master and Memory access on 0:2:0
  50. //
  51. PciOr16 (PCI_LIB_ADDRESS (SA_IGD_BUS, SA_IGD_DEV, SA_IGD_FUN_0, R_SA_IGD_CMD), (BIT2 | BIT1));
  52. //
  53. // Set the Reset Bus Master flag so that it will be disabled when the current transaction is done
  54. //
  55. SetIgdBusMasterReset (TRUE);
  56. }
  57. return GttMmAdr;
  58. }
  59. /**
  60. Reset Bus Master and Memory access on the IGD device to the initial state at
  61. the start of the current transaction.
  62. **/
  63. VOID
  64. GmbusResetBusMaster (
  65. VOID
  66. )
  67. {
  68. if (GetIgdBusMasterReset ()) {
  69. //
  70. // Check if Bus Master and Memory access on 0:2:0 is enabled, disable it if so
  71. //
  72. if ((PciRead16 (
  73. PCI_LIB_ADDRESS (SA_IGD_BUS, SA_IGD_DEV, SA_IGD_FUN_0, R_SA_IGD_CMD)
  74. )
  75. & (BIT2 | BIT1)) != 0) {
  76. //
  77. // Disable Bus Master and Memory access on 0:2:0
  78. //
  79. PciAnd16 (PCI_LIB_ADDRESS (SA_IGD_BUS, SA_IGD_DEV, SA_IGD_FUN_0, R_SA_IGD_CMD), (UINT16) ~(BIT2 | BIT1));
  80. }
  81. //
  82. // Clear the Reset Bus Master flag
  83. //
  84. SetIgdBusMasterReset (FALSE);
  85. }
  86. }
  87. /**
  88. Writes to the GMBUS0 register (Clock/Port Select)
  89. @param[in] GmbusClkPrtSel - The value to write to GMBUS0
  90. @retval EFI_SUCCESS - GMBUS0 was successfully written.
  91. @retval EFI_DEVICE_ERROR - An error occurred while writting to GMBUS0
  92. **/
  93. EFI_STATUS
  94. SetGmbus0ClockPortSelect (
  95. IN UINT32 GmbusClkPrtSel
  96. )
  97. {
  98. UINTN GttMmAdr;
  99. GttMmAdr = GmbusGetGttMmAdr ();
  100. MmioWrite32 (GttMmAdr + R_SA_GTTMMADR_GMBUS0_CLKPRTSEL, GmbusClkPrtSel);
  101. return EFI_SUCCESS;
  102. }
  103. /**
  104. Writes to the GMBUS1 register (Command/Status)
  105. @param[in] GmbusCmdSts - The value to write to GMBUS1
  106. @retval EFI_SUCCESS - GMBUS1 was successfully written.
  107. @retval EFI_DEVICE_ERROR - An error occurred while writting to GMBUS1
  108. **/
  109. EFI_STATUS
  110. SetGmbus1Command (
  111. IN UINT32 GmbusCmdSts
  112. )
  113. {
  114. UINTN GttMmAdr;
  115. GttMmAdr = GmbusGetGttMmAdr ();
  116. MmioWrite32 (GttMmAdr + R_SA_GTTMMADR_GMBUS1_CMDSTS, GmbusCmdSts);
  117. return EFI_SUCCESS;
  118. }
  119. /**
  120. Reads from the GMBUS2 register (GMBUS Status)
  121. @param[out] GmbusStatus - The value read from GMBUS2
  122. @retval EFI_SUCCESS - GMBUS2 was successfully read.
  123. @retval EFI_DEVICE_ERROR - An error occurred while reading from GMBUS2
  124. **/
  125. EFI_STATUS
  126. GetGmbus2Status (
  127. OUT UINT32 *GmbusStatus
  128. )
  129. {
  130. UINTN GttMmAdr;
  131. GttMmAdr = GmbusGetGttMmAdr ();
  132. if (GttMmAdr == 0) {
  133. return EFI_UNSUPPORTED;
  134. }
  135. *GmbusStatus = MmioRead32 (GttMmAdr + R_SA_GTTMMADR_GMBUS2_STATUS);
  136. return EFI_SUCCESS;
  137. }
  138. /**
  139. Writes to the GMBUS2 register (GMBUS Status)
  140. @param[in] GmbusStatus - The value to write to GMBUS2
  141. @retval EFI_SUCCESS - GMBUS2 was successfully written.
  142. @retval EFI_DEVICE_ERROR - An error occurred while writting to GMBUS2
  143. **/
  144. EFI_STATUS
  145. SetGmbus2Status (
  146. IN UINT32 GmbusStatus
  147. )
  148. {
  149. UINTN GttMmAdr;
  150. GttMmAdr = GmbusGetGttMmAdr ();
  151. if (GttMmAdr == 0) {
  152. return EFI_UNSUPPORTED;
  153. }
  154. MmioWrite32 (GttMmAdr + R_SA_GTTMMADR_GMBUS2_STATUS, GmbusStatus);
  155. return EFI_SUCCESS;
  156. }
  157. /**
  158. Reads from the GMBUS3 register (GMBUS Data Buffer)
  159. @param[out] GmbusData - The value read from GMBUS3
  160. @retval EFI_SUCCESS - GMBUS2 was successfully read.
  161. @retval EFI_DEVICE_ERROR - An error occurred while reading from GMBUS2
  162. **/
  163. EFI_STATUS
  164. GetGmbus3Data (
  165. OUT UINT32 *GmbusData
  166. )
  167. {
  168. UINTN GttMmAdr;
  169. GttMmAdr = GmbusGetGttMmAdr ();
  170. if (GttMmAdr == 0) {
  171. return EFI_UNSUPPORTED;
  172. }
  173. *GmbusData = MmioRead32 (GttMmAdr + R_SA_GTTMMADR_GMBUS3_DATA);
  174. return EFI_SUCCESS;
  175. }
  176. /**
  177. Writes to the GMBUS3 register (GMBUS Data Buffer)
  178. @param[in] GmbusData - The value to write to GMBUS3
  179. @retval EFI_SUCCESS - GMBUS3 was successfully written.
  180. @retval EFI_DEVICE_ERROR - An error occurred while writting to GMBUS3
  181. **/
  182. EFI_STATUS
  183. SetGmbus3Data (
  184. IN UINT32 GmbusData
  185. )
  186. {
  187. UINTN GttMmAdr;
  188. GttMmAdr = GmbusGetGttMmAdr ();
  189. if (GttMmAdr == 0) {
  190. return EFI_UNSUPPORTED;
  191. }
  192. MmioWrite32 (GttMmAdr + R_SA_GTTMMADR_GMBUS3_DATA, GmbusData);
  193. return EFI_SUCCESS;
  194. }
  195. /**
  196. Set and clear the software clear interrupt bit. This causes a local reset on the GMBUS controller.
  197. @retval EFI_SUCCESS - The GMBUS error was successfully cleared.
  198. @retval EFI_TIMEOUT - The GMBUS I2C controller did not respond within the required timeout period.
  199. @retval EFI_DEVICE_ERROR - An error occurred while accessing the GMBUS I2C controller.
  200. **/
  201. EFI_STATUS
  202. GmbusRecoverError (
  203. VOID
  204. )
  205. {
  206. EFI_STATUS Status;
  207. //
  208. // Setting B_SA_GTTMMADR_GMBUS1_SW_CLR_INT
  209. // causes a local reset on the GMBUS controller
  210. //
  211. Status = SetGmbus1Command ((UINT32) B_SA_GTTMMADR_GMBUS1_SW_CLR_INT);
  212. if (EFI_ERROR (Status)) {
  213. return Status;
  214. }
  215. Status = SetGmbus1Command (0);
  216. if (EFI_ERROR (Status)) {
  217. return Status;
  218. }
  219. //
  220. // Wait for reset to complete
  221. //
  222. Status = GmbusWaitForReady (B_SA_GTTMMADR_GMBUS2_BUS_ACTIVE, FALSE);
  223. if (EFI_ERROR (Status)) {
  224. return Status;
  225. }
  226. return Status;
  227. }
  228. /**
  229. Wait for a given bitmask of status bits to de-assert to zero.
  230. @param[in] StatusBitMask - A bitmask of status bits to be compared to the present value of GMBUS2
  231. @param[in] WaitForAssertion - If TRUE, the Status Bit indicated must be 1, otherwise it must be 0.
  232. @retval EFI_SUCCESS - The GMBUS controller has cleared all of the bits in the bitmask.
  233. @retval EFI_TIMEOUT - The GMBUS controller did not clear all of the bits in the bitmask
  234. within the required timeout period.
  235. @retval EFI_DEVICE_ERROR - An error occurred while accessing the GMBUS I2C controller.
  236. **/
  237. EFI_STATUS
  238. GmbusWaitForReady (
  239. IN UINT32 StatusBitMask,
  240. IN BOOLEAN WaitForAssertion
  241. )
  242. {
  243. EFI_STATUS Status;
  244. EFI_STATUS Status2;
  245. UINTN Index;
  246. UINT32 GmbusStatus;
  247. Status = EFI_TIMEOUT;
  248. for (Index = 0; Index < GMBUS_TIMEOUT; Index++) {
  249. Status2 = GetGmbus2Status (&GmbusStatus);
  250. if (EFI_ERROR (Status2)) {
  251. return Status2;
  252. }
  253. if (WaitForAssertion) {
  254. if (GmbusStatus & StatusBitMask) {
  255. Status = EFI_SUCCESS;
  256. break;
  257. }
  258. } else {
  259. if (!(GmbusStatus & StatusBitMask)) {
  260. Status = EFI_SUCCESS;
  261. break;
  262. }
  263. }
  264. }
  265. return Status;
  266. }
  267. /**
  268. Initialize the GMBUS to use a given GPIO pin pair and clock speed in preparation
  269. for sending a I2C command to the GMBUS controller.
  270. @param[in] BusSpeed - The clock rate for the I2C bus.
  271. @param[in] DdcBusPinPair - The GPIO pin pair the GMBUS controller should use.
  272. @retval EFI_SUCCESS - The GMBUS has been initialized successfully.
  273. @retval EFI_INVALID_PARAMETER - The given BusSpeed does not match a valid clock rate value.
  274. @retval EFI_TIMEOUT - The GMBUS I2C controller did not respond within the required timeout period.
  275. @retval EFI_DEVICE_ERROR - An error occurred while accessing the GMBUS I2C controller.
  276. **/
  277. EFI_STATUS
  278. GmbusPrepare (
  279. IN UINT8 BusSpeed,
  280. IN UINT8 DdcBusPinPair
  281. )
  282. {
  283. EFI_STATUS Status;
  284. UINT32 GmbusClkPrtSel;
  285. UINT32 GmbusStatus;
  286. //
  287. // Check that the user provided a valid bus speed
  288. //
  289. if ((BusSpeed != GMBUS_CLOCK_RATE_100K) && (BusSpeed != GMBUS_CLOCK_RATE_50K) &&
  290. (BusSpeed != GMBUS_CLOCK_RATE_400K) && (BusSpeed != GMBUS_CLOCK_RATE_1M)) {
  291. return EFI_INVALID_PARAMETER;
  292. }
  293. //
  294. // Wait for GMBUS to complete any pending commands
  295. //
  296. Status = GmbusWaitForReady (B_SA_GTTMMADR_GMBUS2_INUSE, FALSE);
  297. if (EFI_ERROR (Status)) {
  298. return Status;
  299. }
  300. //
  301. // Program the GMBUS Port and Clock
  302. //
  303. GmbusClkPrtSel = (BusSpeed << 8) | DdcBusPinPair;
  304. Status = SetGmbus0ClockPortSelect (GmbusClkPrtSel);
  305. if (EFI_ERROR (Status)) {
  306. return Status;
  307. }
  308. //
  309. // Check for a NACK that has not been cleared yet. Clear it if found.
  310. //
  311. Status = GetGmbus2Status (&GmbusStatus);
  312. if (EFI_ERROR (Status)) {
  313. return Status;
  314. }
  315. if (GmbusStatus & B_SA_GTTMMADR_GMBUS2_NACK_INDICATOR) {
  316. Status = GmbusRecoverError ();
  317. if (EFI_ERROR (Status)) {
  318. return Status;
  319. }
  320. }
  321. return Status;
  322. }
  323. /**
  324. Release the GMBUS controller
  325. @retval EFI_SUCCESS - The GMBUS has been released successfully.
  326. @retval EFI_DEVICE_ERROR - An error occurred while accessing the GMBUS I2C controller.
  327. **/
  328. EFI_STATUS
  329. GmbusRelease (
  330. VOID
  331. )
  332. {
  333. EFI_STATUS Status;
  334. //
  335. // Clear the GMBUS Port and Clock
  336. //
  337. Status = SetGmbus0ClockPortSelect (0);
  338. if (EFI_ERROR (Status)) {
  339. return Status;
  340. }
  341. //
  342. // Setting the INUSE bit to 1 indicates that software has released the GMBUS resource.
  343. // The GMBUS controller will then reset the INUSE bit to 0.
  344. //
  345. Status = SetGmbus2Status (B_SA_GTTMMADR_GMBUS2_INUSE);
  346. if (EFI_ERROR (Status)) {
  347. }
  348. return Status;
  349. }
  350. /**
  351. Reads data from the I2C bus using the GMBUS I2C controller
  352. @param[in] DdcBusPinPair - The GPIO pin pair to use for the read operation
  353. @param[in] SlaveAddress - The I2C device address to read data from
  354. @param[in] SendStopCondition - TRUE: After the read is complete, send a STOP condition to the I2C bus
  355. FALSE: Don't send a STOP after the read is complete, this allows one to
  356. immediately send a repeated START condition to the I2C bus after
  357. GmbusRead() exits by calling either GmbusRead() or GmbusWrite()
  358. immediately after this function returns.
  359. @param[in] SendIndexBeforeRead - TRUE: Before executing the read on the I2C bus, first send a WRITE to the
  360. I2C bus using the same SlaveAddress (but with BIT0 set to 0 because
  361. the operation is a write) the write will contain a single byte, that
  362. byte is the data given in the IndexData parameter.
  363. FALSE: Just send a read to the I2C bus, the IndexData parameter is ignored.
  364. @param[in] IndexData - If SendIndexBeforeRead is TRUE, this byte of data will be written to the I2C
  365. bus before the I2C bus is read. If SendIndexBeforeRead is FALSE, this
  366. parameter is ignored.
  367. @param[in, out] ByteCount - The number of bytes to read from the I2C bus. On output, the number of bytes
  368. actually read.
  369. @param[out] ReadBuffer - The memory buffer to return the read data.
  370. @retval EFI_SUCCESS - The data was successfully read.
  371. @retval EFI_INVALID_PARAMETER - One of the following conditions:
  372. * ByteCount is 0 or >GMBUS_MAX_BYTES.
  373. * ReadBuffer is NULL
  374. * SlaveAddress does not have BIT0 set (required for reads.)
  375. @retval EFI_TIMEOUT - The GMBUS I2C controller did not respond within the required timeout period.
  376. @retval EFI_DEVICE_ERROR - An error occurred while accessing the GMBUS I2C controller.
  377. **/
  378. EFI_STATUS
  379. GmbusRead (
  380. IN UINT8 DdcBusPinPair,
  381. IN UINT8 SlaveAddress,
  382. IN BOOLEAN SendStopCondition,
  383. IN BOOLEAN SendIndexBeforeRead,
  384. IN UINT8 IndexData,
  385. IN OUT UINT32 *ByteCount,
  386. OUT UINT8 *ReadBuffer
  387. )
  388. {
  389. EFI_STATUS Status;
  390. EFI_STATUS Status2;
  391. UINT8 GmbusClockRate;
  392. UINT32 Index;
  393. UINT32 GmbusCmdSts;
  394. UINT32 GmbusStatus;
  395. UINT32 GmbusData;
  396. UINT32 BytesRead;
  397. Status = EFI_SUCCESS;
  398. BytesRead = 0;
  399. GmbusStatus = 0;
  400. //
  401. // Input Validation
  402. //
  403. if ((*ByteCount) <= 0) {
  404. return EFI_INVALID_PARAMETER;
  405. }
  406. if ((*ByteCount) > GMBUS_MAX_BYTES) {
  407. return EFI_INVALID_PARAMETER;
  408. }
  409. if (ReadBuffer == NULL) {
  410. return EFI_INVALID_PARAMETER;
  411. }
  412. if ((SlaveAddress & BIT0) != BIT0) {
  413. return EFI_INVALID_PARAMETER;
  414. }
  415. //
  416. // Configure Gmbus port and clock speed
  417. //
  418. GmbusClockRate = FixedPcdGet8 (PcdI2cHdmiDebugPortGmbusClockRate);
  419. Status = GmbusPrepare (GmbusClockRate, (DdcBusPinPair & B_SA_GTTMMADR_GMBUS0_PIN_PAIR_MASK));
  420. if (EFI_ERROR (Status)) {
  421. goto Done;
  422. }
  423. //
  424. // Construct the command for the GMBUS controller
  425. //
  426. GmbusCmdSts = ((UINT32) SlaveAddress) |
  427. B_SA_GTTMMADR_GMBUS1_BUS_CYCLE_SEL_START |
  428. B_SA_GTTMMADR_GMBUS1_SW_RDY |
  429. B_SA_GTTMMADR_GMBUS1_EN_TIMEOUT;
  430. GmbusCmdSts |= (((*ByteCount) << N_SA_GTTMMADR_GMBUS1_TOTAL_BYTE_COUNT) & B_SA_GTTMMADR_GMBUS1_TOTAL_BYTE_COUNT_MASK);
  431. if (SendStopCondition) {
  432. GmbusCmdSts |= B_SA_GTTMMADR_GMBUS1_BUS_CYCLE_SEL_STOP;
  433. }
  434. if (SendIndexBeforeRead) {
  435. GmbusCmdSts |= B_SA_GTTMMADR_GMBUS1_BUS_CYCLE_SEL_INDEX;
  436. GmbusCmdSts |= ((IndexData << N_SA_GTTMMADR_GMBUS1_INDEX) & B_SA_GTTMMADR_GMBUS1_INDEX_MASK);
  437. }
  438. //
  439. // Send the command to the GMBUS controller, this will cause the I2C transaction to begin immediately
  440. //
  441. Status = SetGmbus1Command (GmbusCmdSts);
  442. if (EFI_ERROR (Status)) {
  443. goto Done;
  444. }
  445. //
  446. // Read the data from the GMBUS controller as it arrives
  447. //
  448. while (BytesRead < (*ByteCount)) {
  449. //
  450. // Wait for the GMBUS controller to set the HW_RDY bit to 1
  451. //
  452. // The HW_RDY bit is set under the following conditions:
  453. //
  454. // * After a reset
  455. // * When a transaction is aborted by the setting the SW_CLR_INT bit in the GMBUS1 register
  456. // * When an active GMBUS cycle has terminated with a STOP condition
  457. // * During a GMBUS write transaction, when the data register can accept another four bytes of data
  458. // * During a GMBUS read transaction, when the data register has four bytes of new data or when the read
  459. // transaction DATA phase is complete and the data register contains all remaining data.
  460. //
  461. Status = GmbusWaitForReady (B_SA_GTTMMADR_GMBUS2_HW_RDY, TRUE);
  462. //
  463. // Check the GMBUS2 register for error conditions (NACK or Slave Stall Timeout)
  464. //
  465. Status2 = GetGmbus2Status (&GmbusStatus);
  466. if (EFI_ERROR (Status2)) {
  467. Status = Status2;
  468. goto Done;
  469. }
  470. if (EFI_ERROR (Status) && ((GmbusStatus & B_SA_GTTMMADR_GMBUS2_NACK_INDICATOR) == 0)) {
  471. Status = EFI_DEVICE_ERROR;
  472. goto Done;
  473. }
  474. if (((GmbusStatus & B_SA_GTTMMADR_GMBUS2_NACK_INDICATOR) != 0) ||
  475. ((GmbusStatus & B_SA_GTTMMADR_GMBUS2_SLAVE_STALL_TIMEOUT_ERROR) != 0)) {
  476. //
  477. // If a NACK or Slave Stall Timeout occurs, then a bus error has occurred.
  478. // In the event of a bus error, one must reset the GMBUS controller to resume normal operation.
  479. //
  480. Status = GmbusRecoverError ();
  481. if (EFI_ERROR (Status)) {
  482. goto Done;
  483. }
  484. Status = EFI_DEVICE_ERROR;
  485. goto Done;
  486. }
  487. //
  488. // No error conditions were encountered, read the data and write it to the data buffer
  489. //
  490. Status = GetGmbus3Data (&GmbusData);
  491. if (EFI_ERROR (Status)) {
  492. goto Done;
  493. }
  494. for (Index = 0; (Index < sizeof (UINT32)) && (BytesRead < (*ByteCount)); Index++) {
  495. ReadBuffer[BytesRead] = (GmbusData >> (Index * 8)) & 0xFF;
  496. BytesRead++;
  497. }
  498. }
  499. //
  500. // Wait for the GMBUS controller to enter the IDLE state
  501. //
  502. Status = GmbusWaitForReady (B_SA_GTTMMADR_GMBUS2_BUS_ACTIVE, FALSE);
  503. if (EFI_ERROR (Status)) {
  504. return Status;
  505. }
  506. Done:
  507. Status2 = GmbusRelease ();
  508. if (EFI_ERROR (Status2)) {
  509. Status = Status2;
  510. }
  511. GmbusResetBusMaster ();
  512. (*ByteCount) = BytesRead;
  513. return Status;
  514. }
  515. /**
  516. Writes data to the I2C bus using the GMBUS I2C controller
  517. @param[in] DdcBusPinPair - The GPIO pin pair to use for the write operation
  518. @param[in] SlaveAddress - The I2C device address to write data to
  519. @param[in] SendStopCondition - TRUE: After the write is complete, send a STOP condition to the I2C bus
  520. FALSE: Don't send a STOP after the write is complete, this allows one to
  521. immediately send a repeated START condition to the I2C bus after
  522. GmbusRead() exits by calling either GmbusRead() or GmbusWrite()
  523. immediately after this function returns.
  524. @param[in] ByteCount - The number of bytes to write to the I2C bus.
  525. @param[in] WriteBuffer - The data to be written to the I2C bus.
  526. @retval EFI_SUCCESS - The data was successfully written.
  527. @retval EFI_INVALID_PARAMETER - One of the following conditions:
  528. * ByteCount is 0 or >GMBUS_MAX_BYTES.
  529. * WriteBuffer is NULL
  530. * SlaveAddress does not have BIT0 cleared (required for writes.)
  531. @retval EFI_TIMEOUT - The GMBUS I2C controller did not respond within the required timeout period.
  532. @retval EFI_DEVICE_ERROR - An error occurred while accessing the GMBUS I2C controller.
  533. **/
  534. EFI_STATUS
  535. GmbusWrite (
  536. IN UINT8 DdcBusPinPair,
  537. IN UINT8 SlaveAddress,
  538. IN BOOLEAN SendStopCondition,
  539. IN UINT32 ByteCount,
  540. IN UINT8 *WriteBuffer
  541. )
  542. {
  543. EFI_STATUS Status;
  544. EFI_STATUS Status2;
  545. UINT8 GmbusClockRate;
  546. UINT32 Index;
  547. UINT32 GmbusCmdSts;
  548. UINT32 GmbusStatus;
  549. UINT32 GmbusData;
  550. UINT32 BytesWritten;
  551. BOOLEAN FirstLoop;
  552. Status = EFI_SUCCESS;
  553. BytesWritten = 0;
  554. GmbusStatus = 0;
  555. FirstLoop = TRUE;
  556. //
  557. // Input Validation
  558. //
  559. if (ByteCount <= 0) {
  560. return EFI_INVALID_PARAMETER;
  561. }
  562. if (ByteCount > GMBUS_MAX_BYTES) {
  563. return EFI_INVALID_PARAMETER;
  564. }
  565. if (WriteBuffer == NULL) {
  566. return EFI_INVALID_PARAMETER;
  567. }
  568. if ((SlaveAddress & BIT0) != 0) {
  569. return EFI_INVALID_PARAMETER;
  570. }
  571. //
  572. // Configure Gmbus port and clock speed
  573. //
  574. GmbusClockRate = FixedPcdGet8 (PcdI2cHdmiDebugPortGmbusClockRate);
  575. Status = GmbusPrepare (GmbusClockRate, (DdcBusPinPair & B_SA_GTTMMADR_GMBUS0_PIN_PAIR_MASK));
  576. if (EFI_ERROR (Status)) {
  577. goto Done;
  578. }
  579. //
  580. // Construct the command for the GMBUS controller
  581. //
  582. GmbusCmdSts = ((UINT32) SlaveAddress) |
  583. B_SA_GTTMMADR_GMBUS1_BUS_CYCLE_SEL_START |
  584. B_SA_GTTMMADR_GMBUS1_SW_RDY |
  585. B_SA_GTTMMADR_GMBUS1_EN_TIMEOUT;
  586. GmbusCmdSts |= ((ByteCount << N_SA_GTTMMADR_GMBUS1_TOTAL_BYTE_COUNT) & B_SA_GTTMMADR_GMBUS1_TOTAL_BYTE_COUNT_MASK);
  587. if (SendStopCondition) {
  588. GmbusCmdSts |= B_SA_GTTMMADR_GMBUS1_BUS_CYCLE_SEL_STOP;
  589. }
  590. //
  591. // Preload the first 4 bytes of data so that when we send the command to the GMBUS
  592. // controller the first 4 bytes of data are ready for transmission. The GMBUS controller requires this.
  593. //
  594. GmbusData = 0;
  595. for (Index = 0; (Index < sizeof (UINT32)) && (BytesWritten < ByteCount); Index++) {
  596. GmbusData |= (WriteBuffer[BytesWritten] << (Index * 8));
  597. BytesWritten++;
  598. }
  599. Status = SetGmbus3Data (GmbusData);
  600. if (EFI_ERROR (Status)) {
  601. goto Done;
  602. }
  603. //
  604. // Send the command to the GMBUS controller, this will cause the I2C transaction to begin immediately
  605. //
  606. Status = SetGmbus1Command (GmbusCmdSts);
  607. if (EFI_ERROR (Status)) {
  608. goto Done;
  609. }
  610. while ((BytesWritten < ByteCount) || FirstLoop) {
  611. //
  612. // If this is not the first loop, load the next 4 bytes of data into the
  613. // GMBUS controller's data buffer.
  614. //
  615. if(!FirstLoop) {
  616. GmbusData = 0;
  617. for (Index = 0; (Index < sizeof (UINT32)) && (BytesWritten < ByteCount); Index++) {
  618. GmbusData |= (WriteBuffer[BytesWritten] << (Index * 8));
  619. BytesWritten++;
  620. }
  621. Status = SetGmbus3Data (GmbusData);
  622. if (EFI_ERROR (Status)) {
  623. goto Done;
  624. }
  625. }
  626. FirstLoop = FALSE;
  627. //
  628. // Wait for the GMBUS controller to set the HW_RDY bit to 1
  629. //
  630. // The HW_RDY bit is set under the following conditions:
  631. //
  632. // * After a reset
  633. // * When a transaction is aborted by the setting the SW_CLR_INT bit in the GMBUS1 register
  634. // * When an active GMBUS cycle has terminated with a STOP condition
  635. // * During a GMBUS write transaction, when the data register can accept another four bytes of data
  636. // * During a GMBUS read transaction, when the data register has four bytes of new data or when the read
  637. // transaction DATA phase is complete and the data register contains all remaining data.
  638. //
  639. Status = GmbusWaitForReady (B_SA_GTTMMADR_GMBUS2_HW_RDY, TRUE);
  640. if (EFI_ERROR (Status)) {
  641. }
  642. //
  643. // Check the GMBUS2 register for error conditions (NACK or Slave Stall Timeout)
  644. //
  645. Status2 = GetGmbus2Status (&GmbusStatus);
  646. if (EFI_ERROR (Status2)) {
  647. Status = Status2;
  648. goto Done;
  649. }
  650. if (EFI_ERROR (Status) && ((GmbusStatus & B_SA_GTTMMADR_GMBUS2_NACK_INDICATOR) == 0)) {
  651. Status = EFI_DEVICE_ERROR;
  652. goto Done;
  653. }
  654. if (((GmbusStatus & B_SA_GTTMMADR_GMBUS2_NACK_INDICATOR) != 0) ||
  655. ((GmbusStatus & B_SA_GTTMMADR_GMBUS2_SLAVE_STALL_TIMEOUT_ERROR) != 0)) {
  656. //
  657. // If a NACK or Slave Stall Timeout occurs, then a bus error has occurred.
  658. // In the event of a bus error, one must reset the GMBUS controller to resume normal operation.
  659. //
  660. Status = GmbusRecoverError ();
  661. if (EFI_ERROR (Status)) {
  662. goto Done;
  663. }
  664. Status = EFI_DEVICE_ERROR;
  665. goto Done;
  666. }
  667. }
  668. //
  669. // Wait for the GMBUS controller to enter the IDLE state
  670. //
  671. Status = GmbusWaitForReady (B_SA_GTTMMADR_GMBUS2_BUS_ACTIVE, FALSE);
  672. if (EFI_ERROR (Status)) {
  673. return Status;
  674. }
  675. Done:
  676. Status2 = GmbusRelease ();
  677. if (EFI_ERROR (Status2)) {
  678. Status = Status2;
  679. }
  680. GmbusResetBusMaster ();
  681. return Status;
  682. }