PeiI2cAccessLib.c 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115
  1. /** @file
  2. Copyright (c) 2020, Intel Corporation. All rights reserved.<BR>
  3. SPDX-License-Identifier: BSD-2-Clause-Patent
  4. **/
  5. #include <Library/I2cAccessLib.h>
  6. EFI_STATUS
  7. I2cWriteRead (
  8. IN UINTN MmioBase,
  9. IN UINT8 SlaveAddress,
  10. IN UINT8 WriteLength,
  11. IN UINT8 *WriteBuffer,
  12. IN UINT8 ReadLength,
  13. IN UINT8 *ReadBuffer,
  14. IN UINT64 TimeBudget
  15. //TODO: add Speed parameter
  16. )
  17. {
  18. UINT8 ReadsNeeded = ReadLength;
  19. UINT64 CutOffTime;
  20. if ((WriteLength == 0 && ReadLength == 0) ||
  21. (WriteLength != 0 && WriteBuffer == NULL) ||
  22. (ReadLength != 0 && ReadBuffer == NULL) ) {
  23. DEBUG ((DEBUG_ERROR, "I2cWR Invalid Parameters\n"));
  24. return EFI_INVALID_PARAMETER;
  25. }
  26. //
  27. // Sanity checks to verify the I2C controller is alive
  28. // Conveniently, ICON register's values of 0 or FFFFFFFF indicate
  29. // I2c controller is out-of-order: either disabled, in D3 or in reset.
  30. //
  31. if (MmioRead32(MmioBase+R_IC_CON) == 0xFFFFFFFF || MmioRead32(MmioBase+R_IC_CON) == 0x0) {
  32. DEBUG ((DEBUG_ERROR, "I2cWR Device Error\n"));
  33. return EFI_DEVICE_ERROR;
  34. }
  35. MmioWrite32(MmioBase+R_IC_ENABLE, 0x0);
  36. MmioRead32(MmioBase+0x40);
  37. MmioRead32(MmioBase+R_IC_CLR_TX_ABRT);
  38. MmioWrite32(MmioBase+R_IC_SDA_HOLD, 0x001C001C);
  39. //
  40. // Set I2C Bus Speed at 400 kHz for GPIO Expander
  41. //
  42. MmioWrite32(MmioBase + R_IC_FS_SCL_HCNT, 128);
  43. MmioWrite32(MmioBase + R_IC_FS_SCL_LCNT, 160);
  44. MmioWrite32(MmioBase + R_IC_TAR, SlaveAddress);
  45. MmioWrite32(MmioBase + R_IC_CON, B_IC_MASTER_MODE | V_IC_SPEED_FAST | B_IC_RESTART_EN | B_IC_SLAVE_DISABLE );
  46. MmioWrite32(MmioBase+R_IC_ENABLE, 0x1);
  47. CutOffTime = AsmReadTsc() + TimeBudget;
  48. while ( (MmioRead32(MmioBase+R_IC_ENABLE_STATUS) & 1)==0 ) {
  49. if (AsmReadTsc() > CutOffTime) {
  50. DEBUG ((DEBUG_ERROR, "I2cWR timeout\n"));
  51. return EFI_TIMEOUT;
  52. }
  53. }
  54. while(1) {
  55. if(MmioRead32(MmioBase+R_IC_INTR_STAT) & B_IC_INTR_TX_ABRT) {
  56. DEBUG ((DEBUG_ERROR, "I2cWR Transfer aborted, reason = 0x%08x\n",MmioRead32(MmioBase+R_IC_TX_ABRT_SOURCE)));
  57. MmioRead32(MmioBase+R_IC_CLR_TX_ABRT);
  58. MmioAnd32(MmioBase+R_IC_ENABLE, 0xFFFFFFFE);
  59. while ( (MmioRead32(MmioBase+R_IC_ENABLE_STATUS) & 1)==1 ) {}
  60. return EFI_DEVICE_ERROR;
  61. }
  62. if (MmioRead32(MmioBase+R_IC_STATUS) & B_IC_STATUS_TFNF) {
  63. if (WriteLength > 1) {
  64. MmioWrite32(MmioBase+R_IC_DATA_CMD, *WriteBuffer);
  65. WriteBuffer++;
  66. WriteLength--;
  67. } else if (WriteLength==1 && ReadLength != 0) {
  68. MmioWrite32(MmioBase+R_IC_DATA_CMD, *WriteBuffer);
  69. WriteBuffer++;
  70. WriteLength--;
  71. } else if (WriteLength==1 && ReadLength == 0) {
  72. MmioWrite32(MmioBase+R_IC_DATA_CMD, *WriteBuffer | B_IC_CMD_STOP);
  73. WriteBuffer++;
  74. WriteLength--;
  75. } else if (ReadLength > 1) {
  76. MmioWrite32(MmioBase+R_IC_DATA_CMD, B_IC_CMD_READ);
  77. ReadLength--;
  78. } else if (ReadLength == 1) {
  79. MmioWrite32(MmioBase+R_IC_DATA_CMD, B_IC_CMD_READ|B_IC_CMD_STOP);
  80. ReadLength--;
  81. }
  82. }
  83. if (ReadsNeeded) {
  84. if (MmioRead32(MmioBase+R_IC_STATUS) & B_IC_STATUS_RFNE) {
  85. *ReadBuffer = (UINT8)MmioRead32(MmioBase+R_IC_DATA_CMD);
  86. ReadBuffer++;
  87. ReadsNeeded--;
  88. }
  89. }
  90. if (WriteLength==0 && ReadsNeeded==0 && !(MmioRead32(MmioBase+R_IC_STATUS)&B_IC_STATUS_ACTIVITY)) {
  91. MmioAnd32(MmioBase+R_IC_ENABLE, 0xFFFFFFFE);
  92. while ( (MmioRead32(MmioBase+R_IC_ENABLE_STATUS) & 1)==1 ) {}
  93. DEBUG ((DEBUG_INFO, "I2cWR success\n"));
  94. return EFI_SUCCESS;
  95. }
  96. if (AsmReadTsc() > CutOffTime) {
  97. MmioAnd32(MmioBase+R_IC_ENABLE, 0xFFFFFFFE);
  98. while ( (MmioRead32(MmioBase+R_IC_ENABLE_STATUS) & 1)==1 ) {}
  99. DEBUG ((DEBUG_ERROR, "I2cWR wrong ENST value\n"));
  100. return EFI_TIMEOUT;
  101. }
  102. }
  103. }