/** Set the I2C controller bus clock frequency. @param[in] This Address of the library's I2C context structure @param[in] PlatformData Address of the platform configuration data @param[in] BusClockHertz New I2C bus clock frequency in Hertz @retval RETURN_SUCCESS The bus frequency was set successfully. @retval RETURN_UNSUPPORTED The controller does not support this frequency. **/ EFI_STATUS I2cBusFrequencySet ( IN UINTN I2CBaseAddress, IN UINTN BusClockHertz, IN UINT16 *I2cMode ) { DEBUG((EFI_D_INFO,"InputFreq BusClockHertz: %d\r\n",BusClockHertz)); *I2cMode = B_IC_RESTART_EN | B_IC_SLAVE_DISABLE | B_MASTER_MODE; // // Set the 100 KHz clock divider // // From Table 10 of the I2C specification // // High: 4.00 uS // Low: 4.70 uS // I2CLibPeiMmioWrite16 ( I2CBaseAddress + R_IC_SS_SCL_HCNT, (UINT16)0x214 ); I2CLibPeiMmioWrite16 ( I2CBaseAddress + R_IC_SS_SCL_LCNT, (UINT16)0x272 ); // // Set the 400 KHz clock divider // // From Table 10 of the I2C specification // // High: 0.60 uS // Low: 1.30 uS // I2CLibPeiMmioWrite16 ( I2CBaseAddress + R_IC_FS_SCL_HCNT, (UINT16)0x50 ); I2CLibPeiMmioWrite16 ( I2CBaseAddress + R_IC_FS_SCL_LCNT, (UINT16)0xAD ); switch ( BusClockHertz ) { case 100 * 1000: I2CLibPeiMmioWrite32 ( I2CBaseAddress + R_IC_SDA_HOLD, (UINT16)0x40);//100K *I2cMode |= V_SPEED_STANDARD; break; case 400 * 1000: I2CLibPeiMmioWrite32 ( I2CBaseAddress + R_IC_SDA_HOLD, (UINT16)0x32);//400K *I2cMode |= V_SPEED_FAST; break; default: I2CLibPeiMmioWrite32 ( I2CBaseAddress + R_IC_SDA_HOLD, (UINT16)0x09);//3.4M *I2cMode |= V_SPEED_HIGH; } return EFI_SUCCESS; }
/** OR a 32-bit MMIO register. OR the 32-bit MMIO register specified by Address with the value specified by Value and returns Value. This function must guarantee that all MMIO read and write operations are serialized. If 32-bit MMIO register operations are not supported, then ASSERT(). If Address is not aligned on a 32-bit boundary, then ASSERT(). @param Address The MMIO register to write OR. @param Value The value to OR to the MMIO register. @return Value. **/ UINT32 EFIAPI I2CLibPeiMmioOr32 ( IN UINTN Address, IN UINT32 OrData ) { return I2CLibPeiMmioWrite32 (Address, I2CLibPeiMmioRead32(Address) | OrData); }
/** Constructor of this library. @param VOID @return EFI_SUCCESS **/ EFI_STATUS EFIAPI IntelI2CPeiLibConstructor ( IN EFI_PEI_FILE_HANDLE FileHandle, IN CONST EFI_PEI_SERVICES **PeiServices ) { UINTN Index; for (Index = 0; Index < sizeof(I2CGPIO)/sizeof(UINT16); Index ++) { I2CLibPeiMmioWrite32(IO_BASE_ADDRESS+I2CGPIO[Index], 0x2003CC81); } return EFI_SUCCESS; }
/** Programe all I2C controllers on LPSS. I2C0 is function 1 of LPSS. I2C1 is function 2 of LPSS, etc.. @param VOID @return EFI_SUCCESS **/ EFI_STATUS ProgramPciLpssI2C ( VOID ) { UINT32 PmcBase; UINT32 DevID; UINTN PciMmBase=0; UINTN Index; UINTN Bar0; UINTN Bar1; DEBUG ((EFI_D_INFO, "Pei ProgramPciLpssI2C() Start\n")); // // Set the VLV Function Disable Register to ZERO // PmcBase = I2CLibPeiMmioRead32(PciD31F0RegBase + R_PCH_LPC_PMC_BASE) & B_PCH_LPC_PMC_BASE_BAR; if(I2CLibPeiMmioRead32(PmcBase + R_PCH_PMC_FUNC_DIS)& (B_PCH_PMC_FUNC_DIS_LPSS2_FUNC1 | B_PCH_PMC_FUNC_DIS_LPSS2_FUNC2 | B_PCH_PMC_FUNC_DIS_LPSS2_FUNC3 | B_PCH_PMC_FUNC_DIS_LPSS2_FUNC4 | B_PCH_PMC_FUNC_DIS_LPSS2_FUNC5 | B_PCH_PMC_FUNC_DIS_LPSS2_FUNC6 | B_PCH_PMC_FUNC_DIS_LPSS2_FUNC7)) { I2CLibPeiMmioWrite32( PmcBase+R_PCH_PMC_FUNC_DIS, I2CLibPeiMmioRead32(PmcBase + R_PCH_PMC_FUNC_DIS)& \ ~(B_PCH_PMC_FUNC_DIS_LPSS2_FUNC1 | B_PCH_PMC_FUNC_DIS_LPSS2_FUNC2 \ | B_PCH_PMC_FUNC_DIS_LPSS2_FUNC3 | B_PCH_PMC_FUNC_DIS_LPSS2_FUNC4 \ | B_PCH_PMC_FUNC_DIS_LPSS2_FUNC5 | B_PCH_PMC_FUNC_DIS_LPSS2_FUNC6|B_PCH_PMC_FUNC_DIS_LPSS2_FUNC7) ); DEBUG ((EFI_D_INFO, "ProgramPciLpssI2C() enable all I2C controllers\n")); } for(Index = 0; Index < LPSS_PCI_DEVICE_NUMBER; Index ++) { PciMmBase = MmPciAddress ( 0, DEFAULT_PCI_BUS_NUMBER_PCH, PCI_DEVICE_NUMBER_PCH_LPSS_I2C, Index, 0 ); DevID = I2CLibPeiMmioRead32(PciMmBase); Bar0 = PEI_TEPM_LPSS_DMA_BAR + (Index * PCI_CONFIG_SPACE_SIZE); Bar1 = Bar0 + 0x8000; DEBUG((EFI_D_ERROR, "Program Pci Lpss I2C Device Function=%x DevID=%08x\n", Index, DevID)); // // Check if device present // if (DevID != 0xFFFFFFFF) { if(!(I2CLibPeiMmioRead32 (PciMmBase + R_PCH_LPSS_I2C_STSCMD) & B_PCH_LPSS_I2C_STSCMD_MSE)) { // // Program BAR 0 // I2CLibPeiMmioWrite32((UINTN) (PciMmBase + R_PCH_LPSS_I2C_BAR), (UINT32)(Bar0 & B_PCH_LPSS_I2C_BAR_BA)); DEBUG ((EFI_D_ERROR, "I2CBaseAddress1 = 0x%x \n",I2CLibPeiMmioRead32 (PciMmBase+R_PCH_LPSS_I2C_BAR))); // // Program BAR 1 // I2CLibPeiMmioWrite32 ((UINTN)(PciMmBase + R_PCH_LPSS_I2C_BAR1), (UINT32)(Bar1 & B_PCH_LPSS_I2C_BAR1_BA)); DEBUG ((EFI_D_ERROR, "I2CBaseAddress1 = 0x%x \n",I2CLibPeiMmioRead32(PciMmBase+R_PCH_LPSS_I2C_BAR1))); // // Bus Master Enable & Memory Space Enable // I2CLibPeiMmioWrite32((UINTN) (PciMmBase + R_PCH_LPSS_I2C_STSCMD), (UINT32)(B_PCH_LPSS_I2C_STSCMD_BME | B_PCH_LPSS_I2C_STSCMD_MSE)); } // // Release Resets // I2CLibPeiMmioWrite32 (Bar0 + R_PCH_LPIO_I2C_MEM_RESETS, (B_PCH_LPIO_I2C_MEM_RESETS_FUNC | B_PCH_LPIO_I2C_MEM_RESETS_APB)); // // Activate Clocks // I2CLibPeiMmioWrite32 (Bar0 + R_PCH_LPSS_I2C_MEM_PCP, 0x80020003);//No use for A0 DEBUG ((EFI_D_INFO, "ProgramPciLpssI2C() Programmed()\n")); } } DEBUG ((EFI_D_INFO, "Pei ProgramPciLpssI2C() End\n")); return EFI_SUCCESS; }