From dbb279c54dbed80ec700cfbd61632a64c2c08b51 Mon Sep 17 00:00:00 2001 From: Guo Mang Date: Thu, 24 Aug 2017 18:55:21 +0800 Subject: BroxtonSiPkg: Add I2CLibPei Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Guo Mang --- .../SouthCluster/Include/Library/I2CLib.h | 106 +--- .../SouthCluster/Include/ScRegs/RegsI2c.h | 143 +++++ .../SouthCluster/Library/I2CLibPei/I2CAccess.h | 51 ++ .../SouthCluster/Library/I2CLibPei/I2CDelayPei.c | 49 ++ .../SouthCluster/Library/I2CLibPei/I2CDelayPei.h | 34 ++ .../SouthCluster/Library/I2CLibPei/I2CIoLibPei.c | 175 ++++++ .../SouthCluster/Library/I2CLibPei/I2CIoLibPei.h | 146 +++++ .../SouthCluster/Library/I2CLibPei/I2CLibPei.c | 665 +++++++++++++++++++++ .../SouthCluster/Library/I2CLibPei/I2CLibPei.inf | 51 ++ 9 files changed, 1321 insertions(+), 99 deletions(-) create mode 100644 Silicon/BroxtonSoC/BroxtonSiPkg/SouthCluster/Include/ScRegs/RegsI2c.h create mode 100644 Silicon/BroxtonSoC/BroxtonSiPkg/SouthCluster/Library/I2CLibPei/I2CAccess.h create mode 100644 Silicon/BroxtonSoC/BroxtonSiPkg/SouthCluster/Library/I2CLibPei/I2CDelayPei.c create mode 100644 Silicon/BroxtonSoC/BroxtonSiPkg/SouthCluster/Library/I2CLibPei/I2CDelayPei.h create mode 100644 Silicon/BroxtonSoC/BroxtonSiPkg/SouthCluster/Library/I2CLibPei/I2CIoLibPei.c create mode 100644 Silicon/BroxtonSoC/BroxtonSiPkg/SouthCluster/Library/I2CLibPei/I2CIoLibPei.h create mode 100644 Silicon/BroxtonSoC/BroxtonSiPkg/SouthCluster/Library/I2CLibPei/I2CLibPei.c create mode 100644 Silicon/BroxtonSoC/BroxtonSiPkg/SouthCluster/Library/I2CLibPei/I2CLibPei.inf (limited to 'Silicon/BroxtonSoC') diff --git a/Silicon/BroxtonSoC/BroxtonSiPkg/SouthCluster/Include/Library/I2CLib.h b/Silicon/BroxtonSoC/BroxtonSiPkg/SouthCluster/Include/Library/I2CLib.h index b593620106..b897cb9dc4 100644 --- a/Silicon/BroxtonSoC/BroxtonSiPkg/SouthCluster/Include/Library/I2CLib.h +++ b/Silicon/BroxtonSoC/BroxtonSiPkg/SouthCluster/Include/Library/I2CLib.h @@ -1,7 +1,7 @@ /** @file Register Definitions for I2C Library. - Copyright (c) 1999 - 2016, Intel Corporation. All rights reserved.
+ Copyright (c) 1999 - 2017, Intel Corporation. All rights reserved.
This program and the accompanying materials are licensed and made available under the terms and conditions of the BSD License @@ -18,111 +18,19 @@ #include #include - // // FIFO write workaround value. // #define FIFO_WRITE_DELAY 2 -// -// MMIO Register Definitions -// -#define R_IC_CON (0x00) ///< I2C Control -#define B_IC_RESTART_EN BIT5 -#define B_IC_SLAVE_DISABLE BIT6 -#define V_SPEED_STANDARD 0x02 -#define V_SPEED_FAST 0x04 -#define V_SPEED_HIGH 0x06 -#define B_MASTER_MODE BIT0 - -#define R_IC_TAR (0x04) ///< I2C Target Address -#define IC_TAR_10BITADDR_MASTER BIT12 - -#define R_IC_SAR (0x08) ///< I2C Slave Address -#define R_IC_HS_MADDR (0x0C) ///< I2C HS MasterMode Code Address -#define R_IC_DATA_CMD (0x10) ///< I2C Rx/Tx Data Buffer and Command - -#define B_READ_CMD BIT8 ///< 1 = read, 0 = write -#define B_CMD_STOP BIT9 ///< 1 = STOP -#define B_CMD_RESTART BIT10 ///< 1 = IC_RESTART_EN - -#define V_WRITE_CMD_MASK (0xFF) - -#define R_IC_SS_SCL_HCNT (0x14) ///< Standard Speed I2C Clock SCL High Count -#define R_IC_SS_SCL_LCNT (0x18) ///< Standard Speed I2C Clock SCL Low Count -#define R_IC_FS_SCL_HCNT (0x1C) ///< Full Speed I2C Clock SCL High Count -#define R_IC_FS_SCL_LCNT (0x20) ///< Full Speed I2C Clock SCL Low Count -#define R_IC_HS_SCL_HCNT (0x24) ///< High Speed I2C Clock SCL High Count -#define R_IC_HS_SCL_LCNT (0x28) ///< High Speed I2C Clock SCL Low Count -#define R_IC_INTR_STAT (0x2C) ///< I2C Inetrrupt Status -#define R_IC_INTR_MASK (0x30) ///< I2C Interrupt Mask -#define I2C_INTR_GEN_CALL BIT11 ///< General call received -#define I2C_INTR_START_DET BIT10 -#define I2C_INTR_STOP_DET BIT9 -#define I2C_INTR_ACTIVITY BIT8 -#define I2C_INTR_TX_ABRT BIT6 ///< Set on NACK -#define I2C_INTR_TX_EMPTY BIT4 -#define I2C_INTR_TX_OVER BIT3 -#define I2C_INTR_RX_FULL BIT2 ///< Data bytes in RX FIFO over threshold -#define I2C_INTR_RX_OVER BIT1 -#define I2C_INTR_RX_UNDER BIT0 -#define R_IC_RAW_INTR_STAT (0x34) ///< I2C Raw Interrupt Status -#define R_IC_RX_TL (0x38) ///< I2C Receive FIFO Threshold -#define R_IC_TX_TL (0x3C) ///< I2C Transmit FIFO Threshold -#define R_IC_CLR_INTR (0x40) ///< Clear Combined and Individual Interrupts -#define R_IC_CLR_RX_UNDER (0x44) ///< Clear RX_UNDER Interrupt -#define R_IC_CLR_RX_OVER (0x48) ///< Clear RX_OVERinterrupt -#define R_IC_CLR_TX_OVER (0x4C) ///< Clear TX_OVER interrupt -#define R_IC_CLR_RD_REQ (0x50) ///< Clear RD_REQ interrupt -#define R_IC_CLR_TX_ABRT (0x54) ///< Clear TX_ABRT interrupt -#define R_IC_CLR_RX_DONE (0x58) ///< Clear RX_DONE interrupt -#define R_IC_CLR_ACTIVITY (0x5C) ///< Clear ACTIVITY interrupt -#define R_IC_CLR_STOP_DET (0x60) ///< Clear STOP_DET interrupt -#define R_IC_CLR_START_DET (0x64) ///< Clear START_DET interrupt -#define R_IC_CLR_GEN_CALL (0x68) ///< Clear GEN_CALL interrupt -#define R_IC_ENABLE (0x6C) ///< I2C Enable -#define R_IC_STATUS (0x70) ///< I2C Status - -#define R_IC_SDA_HOLD (0x7C) ///< I2C IC_DEFAULT_SDA_HOLD//16bits - -#define STAT_MST_ACTIVITY BIT5 ///< Master FSM Activity Status. -#define STAT_RFF BIT4 ///< RX FIFO is completely full -#define STAT_RFNE BIT3 ///< RX FIFO is not empty -#define STAT_TFE BIT2 ///< TX FIFO is completely empty -#define STAT_TFNF BIT1 ///< TX FIFO is not full - -#define R_IC_TXFLR (0x74) ///< Transmit FIFO Level Register -#define R_IC_RXFLR (0x78) ///< Receive FIFO Level Register -#define R_IC_TX_ABRT_SOURCE (0x80) ///< I2C Transmit Abort Status Register -#define R_IC_SLV_DATA_NACK_ONLY (0x84) ///< Generate SLV_DATA_NACK Register -#define R_IC_DMA_CR (0x88) ///< DMA Control Register -#define R_IC_DMA_TDLR (0x8C) ///< DMA Transmit Data Level -#define R_IC_DMA_RDLR (0x90) ///< DMA Receive Data Level -#define R_IC_SDA_SETUP (0x94) ///< I2C SDA Setup Register -#define R_IC_ACK_GENERAL_CALL (0x98) ///< I2C ACK General Call Register -#define R_IC_ENABLE_STATUS (0x9C) ///< I2C Enable Status Register -#define R_IC_COMP_PARAM (0xF4) ///< Component Parameter Register -#define R_IC_COMP_VERSION (0xF8) ///< Component Version ID -#define R_IC_COMP_TYPE (0xFC) ///< Component Type - -#define R_IC_CLK_GATE (0xC0) ///< Clock Gate - -#define IC_TAR_10BITADDR_MASTER BIT12 -#define FIFO_SIZE 32 - - /** Program LPSS I2C PCI controller's BAR0 and enable memory decode. - @param[in] BusNo I2C Bus number to which the I2C device has been connected - - @retval EFI_SUCCESS I2C controller's BAR0 is programmed and memory decode enabled. - @retval EFI_NOT_READY I2C controller's is not exist or its function has been disabled. - + @retval EFI_SUCCESS - I2C controller's BAR0 is programmed and memory decode enabled. **/ EFI_STATUS ProgramPciLpssI2C ( - IN UINT8 BusNo + VOID ); /** @@ -130,7 +38,7 @@ ProgramPciLpssI2C ( This is actual I2C hardware operation function. @param[in] BusNo I2C Bus number to which the I2C device has been connected - @param[in] SlaveAddress Slave address of the I2C device + @param[in] SlaveAddress Slave address of the I2C device (7-bit) @param[in] ReadBytes Number of bytes to be read @param[out] ReadBuffer Address to which the value read has to be stored @param[in] Start It controls whether a RESTART is issued before the byte is sent or received. @@ -157,7 +65,7 @@ ByteReadI2C_Basic ( This is actual I2C hardware operation function. @param[in] BusNo I2C Bus number to which the I2C device has been connected - @param[in] SlaveAddress Slave address of the I2C device + @param[in] SlaveAddress Slave address of the I2C device (7-bit) @param[in] WriteBytes Number of bytes to be written @param[in] WriteBuffer Address to which the byte value has to be written @param[in] Start It controls whether a RESTART is issued before the byte is sent or received. @@ -183,7 +91,7 @@ ByteWriteI2C_Basic ( Read bytes from I2C Device @param[in] BusNo I2C Bus number to which the I2C device has been connected - @param[in] SlaveAddress Slave address of the I2C device + @param[in] SlaveAddress Slave address of the I2C device (7-bit) @param[in] Offset Register offset from which the data has to be read @param[in] ReadBytes Number of bytes to be read @param[out] ReadBuffer Address to which the value read has to be stored @@ -205,7 +113,7 @@ ByteReadI2C ( Write bytes to I2C Device @param[in] BusNo I2C Bus number to which the I2C device has been connected - @param[in] SlaveAddress Slave address of the I2C device + @param[in] SlaveAddress Slave address of the I2C device (7-bit) @param[in] Offset Register offset from which the data has to be read @param[in] WriteBytes Number of bytes to be written @param[in] WriteBuffer Address to which the byte value has to be written diff --git a/Silicon/BroxtonSoC/BroxtonSiPkg/SouthCluster/Include/ScRegs/RegsI2c.h b/Silicon/BroxtonSoC/BroxtonSiPkg/SouthCluster/Include/ScRegs/RegsI2c.h new file mode 100644 index 0000000000..5fc758dd07 --- /dev/null +++ b/Silicon/BroxtonSoC/BroxtonSiPkg/SouthCluster/Include/ScRegs/RegsI2c.h @@ -0,0 +1,143 @@ +/** @file + Register names for I2C device. + + Copyright (c) 2017, Intel Corporation. All rights reserved.
+ + This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php. + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#ifndef _REGS_I2C_H_ +#define _REGS_I2C_H_ + +#define DEFAULT_PCI_BUS_NUMBER_SC 0 +#define PCI_DEVICE_NUMBER_LPSS_I2C 30 + +#define R_LPSS_I2C_STSCMD 0x04 ///< Status & Command +#define B_LPSS_I2C_STSCMD_RMA BIT29 ///< RMA +#define B_LPSS_I2C_STSCMD_RCA BIT28 ///< RCA +#define B_LPSS_I2C_STSCMD_CAPLIST BIT20 ///< Capability List +#define B_LPSS_I2C_STSCMD_INTRSTS BIT19 ///< Interrupt Status +#define B_LPSS_I2C_STSCMD_INTRDIS BIT10 ///< Interrupt Disable +#define B_LPSS_I2C_STSCMD_SERREN BIT8 ///< SERR# Enable +#define B_LPSS_I2C_STSCMD_BME BIT2 ///< Bus Master Enable +#define B_LPSS_I2C_STSCMD_MSE BIT1 ///< Memory Space Enable + +#define R_LPSS_I2C_BAR 0x10 ///< BAR0 Low +#define B_LPSS_I2C_BAR_BA 0xFFFFF000 ///< Base Address +#define B_LPSS_I2C_BAR_SI 0x00000FF0 ///< Size Indicator +#define B_LPSS_I2C_BAR_PF BIT3 ///< Prefetchable +#define B_LPSS_I2C_BAR_TYPE (BIT2 | BIT1) ///< Type +#define B_LPSS_I2C_BAR_MS BIT0 ///< Message Space + +#define R_LPSS_I2C_BAR1 0x18 ///< BAR1 Low +#define B_LPSS_I2C_BAR1_BA 0xFFFFF000 ///< Base Address +#define B_LPSS_I2C_BAR1_SI 0x00000FF0 ///< Size Indicator +#define B_LPSS_I2C_BAR1_PF BIT3 ///< Prefetchable +#define B_LPSS_I2C_BAR1_TYPE (BIT2 | BIT1) ///< Type +#define B_LPSS_I2C_BAR1_MS BIT0 ///< Message Space + +#define NUM_RETRIES 0xFFFF + +#define bit(a) 1 << (a) + +/// +/// MMI/O Register Definitions +/// +#define I2C0_REG_SPACE_ADDR_BASE 0xFF138000 ///< 01K + +#define R_IC_CON (0x00) ///< I2C Control +#define B_IC_RESTART_EN BIT5 +#define B_IC_SLAVE_DISABLE BIT6 +#define V_SPEED_STANDARD 0x02 +#define V_SPEED_FAST 0x04 +#define V_SPEED_HIGH 0x06 +#define B_MASTER_MODE BIT0 + +#define R_IC_TAR (0x04) ///< I2C Target Address +#define IC_TAR_10BITADDR_MASTER BIT12 + +#define R_IC_SAR (0x08) ///< I2C Slave Address +#define R_IC_HS_MADDR (0x0C) ///< I2C HS MasterMode Code Address +#define R_IC_DATA_CMD (0x10) ///< I2C Rx/Tx Data Buffer and Command + +#define B_READ_CMD BIT8 ///< 1 = read, 0 = write +#define B_CMD_STOP BIT9 ///< 1 = STOP +#define B_CMD_RESTART BIT10 ///< 1 = IC_RESTART_EN + +#define V_WRITE_CMD_MASK (0xFF) + +#define R_IC_SS_SCL_HCNT (0x14) ///< Standard Speed I2C Clock SCL High Count +#define R_IC_SS_SCL_LCNT (0x18) ///< Standard Speed I2C Clock SCL Low Count +#define R_IC_FS_SCL_HCNT (0x1C) ///< Full Speed I2C Clock SCL High Count +#define R_IC_FS_SCL_LCNT (0x20) ///< Full Speed I2C Clock SCL Low Count +#define R_IC_HS_SCL_HCNT (0x24) ///< High Speed I2C Clock SCL High Count +#define R_IC_HS_SCL_LCNT (0x28) ///< High Speed I2C Clock SCL Low Count +#define R_IC_INTR_STAT (0x2C) ///< I2C Inetrrupt Status +#define R_IC_INTR_MASK (0x30) ///< I2C Interrupt Mask +#define I2C_INTR_GEN_CALL BIT11 ///< General call received +#define I2C_INTR_START_DET BIT10 +#define I2C_INTR_STOP_DET BIT9 +#define I2C_INTR_ACTIVITY BIT8 +#define I2C_INTR_TX_ABRT BIT6 ///< Set on NACK +#define I2C_INTR_TX_EMPTY BIT4 +#define I2C_INTR_TX_OVER BIT3 +#define I2C_INTR_RX_FULL BIT2 ///< Data bytes in RX FIFO over threshold +#define I2C_INTR_RX_OVER BIT1 +#define I2C_INTR_RX_UNDER BIT0 +#define R_IC_RAW_INTR_STAT (0x34) ///< I2C Raw Interrupt Status +#define R_IC_RX_TL (0x38) ///< I2C Receive FIFO Threshold +#define R_IC_TX_TL (0x3C) ///< I2C Transmit FIFO Threshold +#define R_IC_CLR_INTR (0x40) ///< Clear Combined and Individual Interrupts +#define R_IC_CLR_RX_UNDER (0x44) ///< Clear RX_UNDER Interrupt +#define R_IC_CLR_RX_OVER (0x48) ///< Clear RX_OVERinterrupt +#define R_IC_CLR_TX_OVER (0x4C) ///< Clear TX_OVER interrupt +#define R_IC_CLR_RD_REQ (0x50) ///< Clear RD_REQ interrupt +#define R_IC_CLR_TX_ABRT (0x54) ///< Clear TX_ABRT interrupt +#define R_IC_CLR_RX_DONE (0x58) ///< Clear RX_DONE interrupt +#define R_IC_CLR_ACTIVITY (0x5C) ///< Clear ACTIVITY interrupt +#define R_IC_CLR_STOP_DET (0x60) ///< Clear STOP_DET interrupt +#define R_IC_CLR_START_DET (0x64) ///< Clear START_DET interrupt +#define R_IC_CLR_GEN_CALL (0x68) ///< Clear GEN_CALL interrupt +#define R_IC_ENABLE (0x6C) ///< I2C Enable +#define R_IC_STATUS (0x70) ///< I2C Status + +#define R_IC_SDA_HOLD (0x7C) ///< I2C IC_DEFAULT_SDA_HOLD//16bits + +#define STAT_MST_ACTIVITY BIT5 ///< Master FSM Activity Status. +#define STAT_RFF BIT4 ///< RX FIFO is completely full +#define STAT_RFNE BIT3 ///< RX FIFO is not empty +#define STAT_TFE BIT2 ///< TX FIFO is completely empty +#define STAT_TFNF BIT1 ///< TX FIFO is not full + +#define R_IC_TXFLR (0x74) ///< Transmit FIFO Level Register +#define R_IC_RXFLR (0x78) ///< Receive FIFO Level Register +#define R_IC_TX_ABRT_SOURCE (0x80) ///< I2C Transmit Abort Status Register +#define R_IC_SLV_DATA_NACK_ONLY (0x84) ///< Generate SLV_DATA_NACK Register +#define R_IC_DMA_CR (0x88) ///< DMA Control Register +#define R_IC_DMA_TDLR (0x8C) ///< DMA Transmit Data Level +#define R_IC_DMA_RDLR (0x90) ///< DMA Receive Data Level +#define R_IC_SDA_SETUP (0x94) ///< I2C SDA Setup Register +#define R_IC_ACK_GENERAL_CALL (0x98) ///< I2C ACK General Call Register +#define R_IC_ENABLE_STATUS (0x9C) ///< I2C Enable Status Register +#define R_IC_COMP_PARAM (0xF4) ///< Component Parameter Register +#define R_IC_COMP_VERSION (0xF8) ///< Component Version ID +#define R_IC_COMP_TYPE (0xFC) ///< Component Type + +#define R_IC_CLK_GATE (0xC0) ///< Clock Gate + +#define I2C_SS_SCL_HCNT_VALUE_100M 0x1DD +#define I2C_SS_SCL_LCNT_VALUE_100M 0x1E4 +#define I2C_FS_SCL_HCNT_VALUE_100M 0x54 +#define I2C_FS_SCL_LCNT_VALUE_100M 0x9a +#define I2C_HS_SCL_HCNT_VALUE_100M 0x7 +#define I2C_HS_SCL_LCNT_VALUE_100M 0xE + +#endif + diff --git a/Silicon/BroxtonSoC/BroxtonSiPkg/SouthCluster/Library/I2CLibPei/I2CAccess.h b/Silicon/BroxtonSoC/BroxtonSiPkg/SouthCluster/Library/I2CLibPei/I2CAccess.h new file mode 100644 index 0000000000..792a4834f2 --- /dev/null +++ b/Silicon/BroxtonSoC/BroxtonSiPkg/SouthCluster/Library/I2CLibPei/I2CAccess.h @@ -0,0 +1,51 @@ + +/** @file + Macros that simplify accessing I2C device's registers. + + Copyright (c) 2014 - 2017, Intel Corporation. All rights reserved.
+ + This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php. + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#ifndef _I2C_ACCESS_H_ +#define _I2C_ACCESS_H_ + +/// +/// Memory Mapped PCI Access macros +/// + +#include "I2CIoLibPei.h" + +#define DEFAULT_PCI_BUS_NUMBER_SC 0 + +#define PCI_DEVICE_NUMBER_LPC 31 +#define PCI_FUNCTION_NUMBER_LPC 0 + +#define R_LPC_ACPI_BASE 0x40 ///< ABASE, 16bit +#define R_LPC_ACPI_BASEADR 0x400 ///< ABASE, 16bit +#define B_LPC_ACPI_BASE_EN BIT1 ///< Enable Bit +#define B_LPC_ACPI_BASE_BAR 0x0000FF80 ///< Base Address, 128 Bytes +#define V_ACPI_PM1_TMR_MAX_VAL 0x1000000 ///< The timer is 24 bit overflow +#define B_ACPI_PM1_TMR_VAL 0xFFFFFF ///< The timer value mask + +#define R_ACPI_PM1_TMR 0x08 ///< Power Management 1 Timer +#define V_ACPI_PM1_TMR_FREQUENCY 3579545 ///< Timer Frequency + + +#define ScLpcPciCfg8(Register) I2CLibPeiMmioRead8 (MmPciAddress (0, DEFAULT_PCI_BUS_NUMBER_SC, PCI_DEVICE_NUMBER_LPC, 0, Register)) + +#define MmPciAddress( Segment, Bus, Device, Function, Register ) \ + ( (UINTN)PcdGet64 (PcdPciExpressBaseAddress)+ \ + (UINTN)(Bus << 20) + \ + (UINTN)(Device << 15) + \ + (UINTN)(Function << 12) + \ + (UINTN)(Register) \ + ) +#endif diff --git a/Silicon/BroxtonSoC/BroxtonSiPkg/SouthCluster/Library/I2CLibPei/I2CDelayPei.c b/Silicon/BroxtonSoC/BroxtonSiPkg/SouthCluster/Library/I2CLibPei/I2CDelayPei.c new file mode 100644 index 0000000000..409376ad14 --- /dev/null +++ b/Silicon/BroxtonSoC/BroxtonSiPkg/SouthCluster/Library/I2CLibPei/I2CDelayPei.c @@ -0,0 +1,49 @@ +/** @file + Timer instance for I2C Pei Library. + + Copyright (c) 2014 - 2017, Intel Corporation. All rights reserved.
+ + This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php. + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#include +#include "I2CAccess.h" +#include "I2CDelayPei.h" +#include +#include +#include + +/** + Stalls the CPU for at least the given number of microseconds. + + @param[in] MicroSeconds The minimum number of microseconds to delay. + + @retval EFI_SUCCESS Time delay successfully +**/ +EFI_STATUS +EFIAPI +MicroSecondDelay ( + IN UINTN MicroSeconds + ) +{ + EFI_PEI_STALL_PPI *StallPpi; + EFI_STATUS Status; + CONST EFI_PEI_SERVICES **PeiServices; + + PeiServices = GetPeiServicesTablePointer (); + + Status = (**PeiServices).LocatePpi (PeiServices, &gEfiPeiStallPpiGuid, 0, NULL, (VOID **) &StallPpi); + ASSERT(!EFI_ERROR(Status)); + + StallPpi->Stall (PeiServices, StallPpi, MicroSeconds); + + return EFI_SUCCESS; + +} diff --git a/Silicon/BroxtonSoC/BroxtonSiPkg/SouthCluster/Library/I2CLibPei/I2CDelayPei.h b/Silicon/BroxtonSoC/BroxtonSiPkg/SouthCluster/Library/I2CLibPei/I2CDelayPei.h new file mode 100644 index 0000000000..53ab6e0079 --- /dev/null +++ b/Silicon/BroxtonSoC/BroxtonSiPkg/SouthCluster/Library/I2CLibPei/I2CDelayPei.h @@ -0,0 +1,34 @@ +/** @file + imer prototype for I2C Pei Library. + + Copyright (c) 2014 - 2017, Intel Corporation. All rights reserved.
+ + This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php. + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#ifndef _I2C_DELAY_PEI_ +#define _I2C_DELAY_PEI_ + +#include + +/** + Stalls the CPU for at least the given number of microseconds. + + @param[in] MicroSeconds The minimum number of microseconds to delay. + + @retval EFI_SUCCESS Time delay successfully +**/ +EFI_STATUS +EFIAPI +MicroSecondDelay ( + IN UINTN MicroSeconds + ); + +#endif diff --git a/Silicon/BroxtonSoC/BroxtonSiPkg/SouthCluster/Library/I2CLibPei/I2CIoLibPei.c b/Silicon/BroxtonSoC/BroxtonSiPkg/SouthCluster/Library/I2CLibPei/I2CIoLibPei.c new file mode 100644 index 0000000000..f4cc843b8a --- /dev/null +++ b/Silicon/BroxtonSoC/BroxtonSiPkg/SouthCluster/Library/I2CLibPei/I2CIoLibPei.c @@ -0,0 +1,175 @@ +/** @file + IO instance for I2C Pei Library. + + Copyright (c) 2014 - 2017, Intel Corporation. All rights reserved.
+ + This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php. + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#include +#include +#include + + +/** + Reads an 8-bit MMIO register. + + Reads the 8-bit MMIO register specified by Address. The 8-bit read value is + returned. This function must guarantee that all MMIO read and write + operations are serialized. + + If 8-bit MMIO register operations are not supported, then ASSERT(). + + @param[in] Address - The MMIO register to read. + + @retval UINT8 - The UINT8 value read. +**/ +UINT8 +EFIAPI +I2CLibPeiMmioRead8 ( + IN UINTN Address + ) +{ + UINT8 Value; + + Value = *(volatile UINT8*)Address; + return Value; +} + +/** + Reads a 16-bit MMIO register. + + Reads the 16-bit MMIO register specified by Address. The 16-bit read value is + returned. This function must guarantee that all MMIO read and write + operations are serialized. + + If 16-bit MMIO register operations are not supported, then ASSERT(). + If Address is not aligned on a 16-bit boundary, then ASSERT(). + + @param[in] Address - The MMIO register to read. + + @retval UINT16 - The UINT16 value read. +**/ +UINT16 +EFIAPI +I2CLibPeiMmioRead16 ( + IN UINTN Address + ) +{ + UINT16 Value; + + ASSERT ((Address & 1) == 0); + Value = *(volatile UINT16*)Address; + return Value; +} + +/** + Writes a 16-bit MMIO register. + + Writes the 16-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 16-bit MMIO register operations are not supported, then ASSERT(). + If Address is not aligned on a 16-bit boundary, then ASSERT(). + + @param[in] Address - The MMIO register to write. + @param[in] Value - The value to write to the MMIO register. + + @retval UINT16 - The UINT16 value written. +**/ +UINT16 +EFIAPI +I2CLibPeiMmioWrite16 ( + IN UINTN Address, + IN UINT16 Value + ) +{ + ASSERT ((Address & 1) == 0); + *(volatile UINT16*)Address = Value; + return Value; +} + +/** + Reads a 32-bit MMIO register. + + Reads the 32-bit MMIO register specified by Address. The 32-bit read value is + returned. 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[in] Address - The MMIO register to read. + + @retval UINT32 - The UINT32 value read. + +**/ +UINT32 +EFIAPI +I2CLibPeiMmioRead32 ( + IN UINTN Address + ) +{ + UINT32 Value; + + ASSERT ((Address & 3) == 0); + Value = *(volatile UINT32*)Address; + + return Value; +} + +/** + Writes a 32-bit MMIO register. + + Writes 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[in] Address - The MMIO register to write. + @param[in] Value - The value to write to the MMIO register. + + @retval UINT32 - The UINT32 value written. +**/ +UINT32 +EFIAPI +I2CLibPeiMmioWrite32 ( + IN UINTN Address, + IN UINT32 Value + ) +{ + ASSERT ((Address & 3) == 0); + *(volatile UINT32*)Address = Value; + return Value; +} + +/** + Do logical OR operation with the value read from the 32-bit MMIO register + and write it back to 32-bit MMIO register. + + @param[in] Address - The MMIO register to write. + @param[in] OrData - The value to do logical OR operation with the value read from the MMIO register. + + @retval UINT32 - The final value written to the MMIO register. +**/ +UINT32 +EFIAPI +I2CLibPeiMmioOr32 ( + IN UINTN Address, + IN UINT32 OrData + ) +{ + return I2CLibPeiMmioWrite32 (Address, I2CLibPeiMmioRead32 (Address) | OrData); +} + + diff --git a/Silicon/BroxtonSoC/BroxtonSiPkg/SouthCluster/Library/I2CLibPei/I2CIoLibPei.h b/Silicon/BroxtonSoC/BroxtonSiPkg/SouthCluster/Library/I2CLibPei/I2CIoLibPei.h new file mode 100644 index 0000000000..0ea17274c5 --- /dev/null +++ b/Silicon/BroxtonSoC/BroxtonSiPkg/SouthCluster/Library/I2CLibPei/I2CIoLibPei.h @@ -0,0 +1,146 @@ +/** @file + IO prototype for I2C Pei Library. + + Copyright (c) 2014 - 2017, Intel Corporation. All rights reserved.
+ + This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php. + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#ifndef _I2C_IOLIB_PEI_ +#define _I2C_IOLIB_PEI_ + +#include + +/** + Reads an 8-bit MMIO register. + + Reads the 8-bit MMIO register specified by Address. The 8-bit read value is + returned. This function must guarantee that all MMIO read and write + operations are serialized. + + If 8-bit MMIO register operations are not supported, then ASSERT(). + + @param[in] Address - The MMIO register to read. + + @retval UINT8 - The UINT8 value read. +**/ +UINT8 +EFIAPI +I2CLibPeiMmioRead8 ( + IN UINTN Address + ); + + +/** + Reads a 16-bit MMIO register. + + Reads the 16-bit MMIO register specified by Address. The 16-bit read value is + returned. This function must guarantee that all MMIO read and write + operations are serialized. + + If 16-bit MMIO register operations are not supported, then ASSERT(). + If Address is not aligned on a 16-bit boundary, then ASSERT(). + + @param[in] Address - The MMIO register to read. + + @retval UINT16 - The UINT16 value read. +**/ +UINT16 +EFIAPI +I2CLibPeiMmioRead16 ( + IN UINTN Address + ); + + +/** + Writes a 16-bit MMIO register. + + Writes the 16-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 16-bit MMIO register operations are not supported, then ASSERT(). + If Address is not aligned on a 16-bit boundary, then ASSERT(). + + @param[in] Address - The MMIO register to write. + @param[in] Value - The value to write to the MMIO register. + + @retval UINT16 - The UINT16 value written. +**/ +UINT16 +EFIAPI +I2CLibPeiMmioWrite16 ( + IN UINTN Address, + IN UINT16 Value + ); + + +/** + Reads a 32-bit MMIO register. + + Reads the 32-bit MMIO register specified by Address. The 32-bit read value is + returned. 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[in] Address - The MMIO register to read. + + @retval UINT32 - The UINT32 value read. + +**/ +UINT32 +EFIAPI +I2CLibPeiMmioRead32 ( + IN UINTN Address + ); + + +/** + Writes a 32-bit MMIO register. + + Writes 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[in] Address - The MMIO register to write. + @param[in] Value - The value to write to the MMIO register. + + @retval UINT32 - The UINT32 value written. +**/ +UINT32 +EFIAPI +I2CLibPeiMmioWrite32 ( + IN UINTN Address, + IN UINT32 Value + ); + + +/** + Do logical OR operation with the value read from the 32-bit MMIO register + and write it back to 32-bit MMIO register. + + @param[in] Address - The MMIO register to write. + @param[in] OrData - The value to do logical OR operation with the value read from the MMIO register. + + @retval UINT32 - The final value written to the MMIO register. +**/ +UINT32 +EFIAPI +I2CLibPeiMmioOr32 ( + IN UINTN Address, + IN UINT32 OrData + ); + +#endif diff --git a/Silicon/BroxtonSoC/BroxtonSiPkg/SouthCluster/Library/I2CLibPei/I2CLibPei.c b/Silicon/BroxtonSoC/BroxtonSiPkg/SouthCluster/Library/I2CLibPei/I2CLibPei.c new file mode 100644 index 0000000000..d15170a35c --- /dev/null +++ b/Silicon/BroxtonSoC/BroxtonSiPkg/SouthCluster/Library/I2CLibPei/I2CLibPei.c @@ -0,0 +1,665 @@ +/** @file + Pei library for I2C bus driver. + + Copyright (c) 2014 - 2017, Intel Corporation. All rights reserved.
+ + This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php. + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#include "I2CDelayPei.h" +#include "I2CIoLibPei.h" +#include "I2CAccess.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +EFI_GUID mI2CPeiInitGuid = { + 0x96DED71A, 0xB9E7, 0x4EAD, {0x96, 0x2C, 0x01, 0x69, 0x3C, 0xED, 0x2A, 0x64} +}; + + +#define LPSS_PCI_DEVICE_NUMBER 8 + + +#define GPIO_PAD_CFG_DW0_GPIO_124_OFFSET 0x400 ///< This is the first gpio pin of I2C0 + +/* Name Function Offset of GPIO WEST + GPIO_124 LPSS_I2C0_SDA 0x400 + 16*0 + GPIO_125 LPSS_I2C0_SCL + + GPIO_126 LPSS_I2C1_SDA 0x400 + 16*1 + GPIO_127 LPSS_I2C1_SCL + + GPIO_128 LPSS_I2C2_SDA + GPIO_129 LPSS_I2C2_SCL + + GPIO_130 LPSS_I2C3_SDA + GPIO_131 LPSS_I2C3_SCL + + GPIO_132 LPSS_I2C4_SDA + GPIO_133 LPSS_I2C4_SCL + + GPIO_134 LPSS_I2C5_SDA + GPIO_135 LPSS_I2C5_SCL + + GPIO_136 LPSS_I2C6_SDA + GPIO_137 LPSS_I2C6_SCL + + GPIO_138 LPSS_I2C7_SDA 0x400 + 16*7 + GPIO_139 LPSS_I2C7_SCL +*/ + +EFI_STATUS +EFIAPI +IntelI2CPeiLibConstructor ( + VOID + ) +{ + UINTN Index; +//UINT32 Value; + UINT32 gpio_pad_cfg_dw0_offset; + + // Program GPIO pins for I2C 0~7, need to set GPIO to Function 1 and misc settings. + for (Index = 0; Index < 8; Index ++) { + // Config I2C[Index] SDA pin DW0 + gpio_pad_cfg_dw0_offset = GPIO_PAD_CFG_DW0_GPIO_124_OFFSET + 16 * Index; + { + //Value = 0; // FIXME: the right GPIO setting, need to get updated from GPIO config owner. Dummy code here. + //SideBandCR32Write (SB_PORTID_GPIOW, gpio_pad_cfg_dw0_offset, Value); + } + + // Config I2C[Index] SDA pin DW1 + gpio_pad_cfg_dw0_offset += 4; + { + //Value = 0; // FIXME: the right GPIO setting, need to get updated from GPIO config owner. Dummy code here. + //SideBandCR32Write (SB_PORTID_GPIOW, gpio_pad_cfg_dw0_offset, Value); + } + + // Config I2C[Index] SCL pin DW0 + gpio_pad_cfg_dw0_offset += 4; + { + //Value = 0; // FIXME: the right GPIO setting, need to get updated from GPIO config owner. Dummy code here. + //SideBandCR32Write (SB_PORTID_GPIOW, gpio_pad_cfg_dw0_offset, Value); + } + + // Config I2C[Index] SCL pin DW1 + gpio_pad_cfg_dw0_offset += 4; + { + //Value = 0; // FIXME: the right GPIO setting, need to get updated from GPIO config owner. Dummy code here. + //SideBandCR32Write (SB_PORTID_GPIOW, gpio_pad_cfg_dw0_offset, Value); + } + } + + return EFI_SUCCESS; +} + +/** + Program LPSS I2C PCI controller's BAR0 and enable memory decode. + + @retval EFI_SUCCESS - I2C controller's BAR0 is programmed and memory decode enabled. +**/ +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 BXT Function Disable Register to ZERO + // + PmcBase = PMC_BASE_ADDRESS; + + if (I2CLibPeiMmioRead32 (PmcBase + R_PMC_FUNC_DIS) & + (B_PMC_FUNC_DIS_LPSS_I2C0 | B_PMC_FUNC_DIS_LPSS_I2C1 | B_PMC_FUNC_DIS_LPSS_I2C2 | B_PMC_FUNC_DIS_LPSS_I2C3| + B_PMC_FUNC_DIS_LPSS_I2C4 | B_PMC_FUNC_DIS_LPSS_I2C5 | B_PMC_FUNC_DIS_LPSS_I2C6 | B_PMC_FUNC_DIS_LPSS_I2C7)) { + I2CLibPeiMmioWrite32 ( + PmcBase + R_PMC_FUNC_DIS, + I2CLibPeiMmioRead32 (PmcBase + R_PMC_FUNC_DIS) & + ~(B_PMC_FUNC_DIS_LPSS_I2C0| B_PMC_FUNC_DIS_LPSS_I2C1|B_PMC_FUNC_DIS_LPSS_I2C2| B_PMC_FUNC_DIS_LPSS_I2C3| + B_PMC_FUNC_DIS_LPSS_I2C4| B_PMC_FUNC_DIS_LPSS_I2C5|B_PMC_FUNC_DIS_LPSS_I2C6| B_PMC_FUNC_DIS_LPSS_I2C7) + ); + + DEBUG ((EFI_D_INFO, "ProgramPciLpssI2C() enable all I2C controllers\n")); + } + + for (Index = 0; Index < LPSS_PCI_DEVICE_NUMBER; Index ++) { + if (Index < 4) { + PciMmBase = MmPciAddress ( + 0, + DEFAULT_PCI_BUS_NUMBER_SC, + PCI_DEVICE_NUMBER_LPSS_I2C0, + Index, + 0 + ); + } else { + PciMmBase = MmPciAddress ( + 0, + DEFAULT_PCI_BUS_NUMBER_SC, + PCI_DEVICE_NUMBER_LPSS_I2C1, + (Index - 4), + 0 + ); + } + + DevID = I2CLibPeiMmioRead32 (PciMmBase); + Bar0 = LPSS_I2C0_TMP_BAR0 + Index * LPSS_I2C_TMP_BAR0_DELTA; + Bar1 = Bar0 + LPSS_I2C_TMP_BAR1_OFFSET; + + // + // Check if device present + // + if (DevID != 0xFFFFFFFF) { + if ((I2CLibPeiMmioRead32 (PciMmBase + R_LPSS_I2C_STSCMD) & B_LPSS_I2C_STSCMD_MSE)) { + // + // In PEI stage, we always disable Bus master, and memory space enabling for BAR re-programming + // In DXE stage, will read existing BAR value instead of re-programming + // + I2CLibPeiMmioWrite32 ((UINTN) (PciMmBase + R_LPSS_I2C_STSCMD), 0); + } + // + // Program BAR 0 + // + I2CLibPeiMmioWrite32 ((UINTN) (PciMmBase + R_LPSS_I2C_BAR), (UINT32) (Bar0 & B_LPSS_I2C_BAR_BA)); + + // + // Program BAR 1 + // + I2CLibPeiMmioWrite32 ((UINTN) (PciMmBase + R_LPSS_I2C_BAR1), (UINT32) (Bar1 & B_LPSS_I2C_BAR1_BA)); + + // + // Bus Master Enable & Memory Space Enable + // + I2CLibPeiMmioWrite32 ((UINTN) (PciMmBase + R_LPSS_I2C_STSCMD), (UINT32) (B_LPSS_I2C_STSCMD_BME | B_LPSS_I2C_STSCMD_MSE)); + } + + // + // Release Resets + // + I2CLibPeiMmioWrite32 (Bar0 + R_LPSS_IO_MEM_RESETS, B_LPSS_IO_MEM_HC_RESET_REL | B_LPSS_IO_MEM_iDMA_RESET_REL); + } + + DEBUG ((EFI_D_INFO, "Pei ProgramPciLpssI2C() End\n")); + + return EFI_SUCCESS; +} + +/** + Disable I2C host controller + + @param[in] BusNo - I2C Bus number to which the I2C device has been connected + + @retval EFI_SUCCESS - I2C host controller is completely inactive. + @retval EFI_NOT_READY - I2C host controller is still in an enabled state. +**/ +EFI_STATUS +I2cDisable ( + IN UINT8 BusNo + ) +{ + UINTN I2CBaseAddress; + UINT32 NumTries = 10000; // 0.1 seconds + + I2CBaseAddress = (UINT32) LPSS_I2C0_TMP_BAR0 + (BusNo * LPSS_I2C_TMP_BAR0_DELTA); + I2CLibPeiMmioWrite16 (I2CBaseAddress + R_IC_ENABLE, 0); + while (0 != (I2CLibPeiMmioRead16 (I2CBaseAddress + R_IC_ENABLE) & 1)) { + MicroSecondDelay (10); + NumTries--; + if (NumTries == 0) return EFI_NOT_READY; + } + return EFI_SUCCESS; +} + + +/** + Enable I2C host controller + + @param[in] BusNo - I2C Bus number to which the I2C device has been connected + + @retval EFI_SUCCESS - I2C host controller is in an enabled state. + @retval EFI_NOT_READY - I2C host controller is still inactive. +**/ +EFI_STATUS +I2cEnable ( + IN UINT8 BusNo + ) +{ + UINTN I2CBaseAddress; + UINT32 NumTries = 10000; //0.1 seconds + + I2CBaseAddress = (UINT32) LPSS_I2C0_TMP_BAR0 + (BusNo * LPSS_I2C_TMP_BAR0_DELTA); + I2CLibPeiMmioWrite16 (I2CBaseAddress + R_IC_ENABLE, 1); + while (0 == (I2CLibPeiMmioRead16 (I2CBaseAddress + R_IC_ENABLE ) & 1)) { + MicroSecondDelay (10); + NumTries --; + if (NumTries == 0) return EFI_NOT_READY; + } + return EFI_SUCCESS; +} + + +/** + Set the I2C controller bus clock frequency. + + The software and controller do a best case effort of using the specified + frequency for the I2C bus. If the frequency does not match exactly then + the controller will use a slightly lower frequency for the I2C to avoid + exceeding the operating conditions for any of the I2C devices on the bus. + For example if 400 KHz was specified and the controller's divide network + only supports 402 KHz or 398 KHz then the controller would be set to 398 + KHz. However if the desired frequency is 400 KHz and the controller only + supports 1 MHz and 100 KHz then this routine would return EFI_UNSUPPORTED. + + @param[in] I2CBaseAddress - BAR0 address of I2C host controller + @param[in] BusClockHertz - New I2C bus clock frequency in Hertz + @param[out] I2cMode - I2C operation mode. + Standard Speed: 100 KHz + Fast Speed : 400 KHz + High Speed : 3.4 MHz + + @retval EFI_SUCCESS - The bus frequency was set successfully. +**/ + +EFI_STATUS +I2cBusFrequencySet ( + IN UINTN I2CBaseAddress, + IN UINTN BusClockHertz, + OUT UINT16 *I2cMode, + IN BOOLEAN DebugFlag + ) +{ + if (DebugFlag) 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; +} + +/** + Initializes the host controller to execute I2C commands. + + @param[in] BusNo - I2C Bus number to which the I2C device has been connected + @param[in] SlaveAddress - Slave address of the I2C device + + @retval EFI_SUCCESS - Opcode initialization on the I2C host controller completed. + @retval EFI_INVALID_PARAMETER - Invalid slave address + @retval EFI_DEVICE_ERROR - Operation failed, device error + @retval Others - Failed to initialize I2C host controller +**/ +EFI_STATUS +I2CInit ( + IN UINT8 BusNo, + IN UINT16 SlaveAddress + ) +{ + EFI_STATUS Status; + UINT32 NumTries = 0; + UINTN I2CBaseAddress; + UINT16 I2cMode; + UINTN PciMmBase = 0; + BOOLEAN DebugFlag = TRUE; + + if (BusNo < 4) { + PciMmBase = MmPciAddress ( + 0, + DEFAULT_PCI_BUS_NUMBER_SC, + PCI_DEVICE_NUMBER_LPSS_I2C0, + BusNo, + 0 + ); + } else { + PciMmBase = MmPciAddress ( + 0, + DEFAULT_PCI_BUS_NUMBER_SC, + PCI_DEVICE_NUMBER_LPSS_I2C1, + (BusNo - 4), + 0 + ); + } + + I2CBaseAddress = (I2CLibPeiMmioRead32 (PciMmBase + R_LPSS_I2C_BAR) & 0xFFFFFFF8); + + // + // Verify the parameters + // + if (1023 < SlaveAddress) { + Status = EFI_INVALID_PARAMETER; + if (DebugFlag) DEBUG ((DEBUG_ERROR, "I2cStartRequest Exit with Status %r\r\n", Status)); + return Status; + } + + if (I2CBaseAddress == (LPSS_I2C0_TMP_BAR0 + (BusNo * LPSS_I2C_TMP_BAR0_DELTA))) { + DebugFlag = FALSE; + } else { + // + // Need to enable the I2C PCI device + // + ProgramPciLpssI2C (); + + I2CBaseAddress = (UINT32) (LPSS_I2C0_TMP_BAR0 + (BusNo * LPSS_I2C_TMP_BAR0_DELTA)); + if (DebugFlag) DEBUG ((DEBUG_INFO, "I2CBaseAddress = 0x%x \n", I2CBaseAddress)); + } + + NumTries = 10000; // 1 seconds + while ((1 == (I2CLibPeiMmioRead32 (I2CBaseAddress + R_IC_STATUS) & STAT_MST_ACTIVITY ))) { + MicroSecondDelay (10); + NumTries --; + if (0 == NumTries) + return EFI_DEVICE_ERROR; + } + + Status = I2cDisable (BusNo); + if (DebugFlag) DEBUG ((DEBUG_INFO, "I2cDisable Status = %r\r\n", Status)); + + I2cBusFrequencySet (I2CBaseAddress, 400 * 1000, &I2cMode, DebugFlag); // Set I2cMode + + I2CLibPeiMmioWrite16 (I2CBaseAddress + R_IC_INTR_MASK, 0x0); + if (0x7F < SlaveAddress) { + SlaveAddress = (SlaveAddress & 0x3FF) | IC_TAR_10BITADDR_MASTER; + } + + I2CLibPeiMmioWrite16 (I2CBaseAddress + R_IC_TAR, (UINT16) SlaveAddress); + I2CLibPeiMmioWrite16 (I2CBaseAddress + R_IC_RX_TL, 0); + I2CLibPeiMmioWrite16 (I2CBaseAddress + R_IC_TX_TL, 0); + I2CLibPeiMmioWrite16 (I2CBaseAddress + R_IC_CON, I2cMode); + + Status = I2cEnable (BusNo); + if (DebugFlag) DEBUG ((DEBUG_INFO, "I2cEnable Status = %r\r\n", Status)); + + I2CLibPeiMmioRead16 (I2CBaseAddress + R_IC_CLR_TX_ABRT); + return EFI_SUCCESS; +} + +/** + Read bytes from I2C Device + This is actual I2C hardware operation function. + + @param[in] BusNo - I2C Bus number to which the I2C device has been connected + @param[in] SlaveAddress - Slave address of the I2C device (7-bit) + @param[in] ReadBytes - Number of bytes to be read + @param[out] ReadBuffer - Address to which the value read has to be stored + @param[in] Start - It controls whether a RESTART is issued before the byte is sent or received. + @param[in] End - It controls whether a STOP is issued after the byte is sent or received. + + @retval EFI_SUCCESS - The byte value read successfully + @retval EFI_DEVICE_ERROR - Operation failed + @retval EFI_TIMEOUT - Hardware retry timeout + @retval Others - Failed to read a byte via I2C +**/ +EFI_STATUS +ByteReadI2C_Basic ( + IN UINT8 BusNo, + IN UINT8 SlaveAddress, + IN UINTN ReadBytes, + OUT UINT8 *ReadBuffer, + IN UINT8 Start, + IN UINT8 End + ) +{ + EFI_STATUS Status; + UINT32 I2cStatus; + UINT16 ReceiveData; + UINT8 *ReceiveDataEnd; + UINT8 *ReceiveRequest; + UINT16 raw_intr_stat; + UINTN I2CBaseAddress; + + I2CBaseAddress = (UINT32) (LPSS_I2C0_TMP_BAR0 + (BusNo * LPSS_I2C_TMP_BAR0_DELTA)); + + Status = EFI_SUCCESS; + + I2CInit (BusNo, SlaveAddress); + + ReceiveDataEnd = &ReadBuffer [ReadBytes]; + if (ReadBytes) { + ReceiveRequest = ReadBuffer; + + while ((ReceiveDataEnd > ReceiveRequest) || + (ReceiveDataEnd > ReadBuffer)) { + // + // Check for NACK + // + raw_intr_stat = I2CLibPeiMmioRead16 (I2CBaseAddress + R_IC_RAW_INTR_STAT); + if (0 != (raw_intr_stat & I2C_INTR_TX_ABRT)) { + I2CLibPeiMmioRead16 (I2CBaseAddress + R_IC_CLR_TX_ABRT); + Status = RETURN_DEVICE_ERROR; + DEBUG ((DEBUG_INFO,"TX ABRT ,%d bytes hasn't been transferred\r\n", ReceiveDataEnd - ReceiveRequest)); + break; + } + + // + // Determine if another byte was received + // + I2cStatus = I2CLibPeiMmioRead16 (I2CBaseAddress + R_IC_STATUS); + if (0 != (I2cStatus & STAT_RFNE)) { + ReceiveData = I2CLibPeiMmioRead16 (I2CBaseAddress + R_IC_DATA_CMD); + *ReadBuffer++ = (UINT8)ReceiveData; + } + + if (ReceiveDataEnd == ReceiveRequest) { + continue; //Waiting the last request to get data and make (ReceiveDataEnd > ReadBuffer) =TRUE. + } + + // + // Wait until a read request will fit + // + if (0 == (I2cStatus & STAT_TFNF)) { + MicroSecondDelay (10); + continue; + } + + // + // Issue the next read request + // + if (End && Start) { + I2CLibPeiMmioWrite16 (I2CBaseAddress + R_IC_DATA_CMD, B_READ_CMD | B_CMD_RESTART | B_CMD_STOP); + } else if (!End && Start) { + I2CLibPeiMmioWrite16 (I2CBaseAddress + R_IC_DATA_CMD, B_READ_CMD | B_CMD_RESTART); + } else if (End && !Start) { + I2CLibPeiMmioWrite16 (I2CBaseAddress + R_IC_DATA_CMD, B_READ_CMD | B_CMD_STOP); + } else if (!End && !Start) { + I2CLibPeiMmioWrite16 (I2CBaseAddress + R_IC_DATA_CMD, B_READ_CMD); + } + ReceiveRequest += 1; + } + } + return Status; + +} + +/** + Write bytes to I2C Device + This is actual I2C hardware operation function. + + @param[in] BusNo - I2C Bus number to which the I2C device has been connected + @param[in] SlaveAddress - Slave address of the I2C device (7-bit) + @param[in] WriteBytes - Number of bytes to be written + @param[in] WriteBuffer - Address to which the byte value has to be written + @param[in] Start - It controls whether a RESTART is issued before the byte is sent or received. + @param[in] End - It controls whether a STOP is issued after the byte is sent or received. + + @retval EFI_SUCCESS - The byte value written successfully + @retval EFI_DEVICE_ERROR - Operation failed + @retval EFI_TIMEOUT - Hardware retry timeout + @retval Others - Failed to write a byte via I2C +**/ +EFI_STATUS +ByteWriteI2C_Basic ( + IN UINT8 BusNo, + IN UINT8 SlaveAddress, + IN UINTN WriteBytes, + IN UINT8 *WriteBuffer, + IN UINT8 Start, + IN UINT8 End + ) +{ + UINT16 Data16; + EFI_STATUS Status; + UINT32 I2cStatus; + UINT8 *TransmitPtr; + UINT8 *TransmitEnd; + UINT16 raw_intr_stat; + UINTN I2CBaseAddress; + + + I2CBaseAddress = (UINT32)LPSS_I2C0_TMP_BAR0 + (BusNo * LPSS_I2C_TMP_BAR0_DELTA); + Status = EFI_SUCCESS; + I2CInit (BusNo, SlaveAddress); + + TransmitPtr = WriteBuffer; + TransmitEnd = &WriteBuffer[WriteBytes]; + if (WriteBytes > 0x00) { + + + while (TransmitEnd > TransmitPtr) { + I2cStatus = I2CLibPeiMmioRead16 (I2CBaseAddress + R_IC_STATUS); + raw_intr_stat = I2CLibPeiMmioRead16 (I2CBaseAddress + R_IC_RAW_INTR_STAT); + if (0 != (raw_intr_stat & I2C_INTR_TX_ABRT)) { + I2CLibPeiMmioRead16 (I2CBaseAddress + R_IC_CLR_TX_ABRT); + Status = RETURN_DEVICE_ERROR; + DEBUG ((DEBUG_ERROR,"TX ABRT TransmitEnd:0x%x WritePtr:0x%x\r\n", TransmitEnd, TransmitPtr)); + break; + } + if (0 == (I2cStatus & STAT_TFNF)) { + DEBUG ((DEBUG_INFO,"%a(#%d) - 0 == (I2cStatus & STAT_TFNF)\n", __FUNCTION__, __LINE__)); + continue; + } + + Data16 = (UINT16) *TransmitPtr; + if (End && Start) { + Data16 |= (B_CMD_RESTART | B_CMD_STOP); + } else if (!End && Start) { + Data16 |= B_CMD_RESTART; + } else if (End && !Start) { + Data16 |= B_CMD_STOP; + } + Data16 = I2CLibPeiMmioWrite16 (I2CBaseAddress + R_IC_DATA_CMD, Data16); + TransmitPtr++; + + // + // Add a small delay to work around some odd behavior being seen. Without this delay bytes get dropped. + // + MicroSecondDelay (FIFO_WRITE_DELAY); + } + + } + + if (EFI_ERROR (Status)) + DEBUG ((EFI_D_INFO,"I2cStartRequest Exit with Status %r\r\n", Status)); + + return Status; +} + + +/** + Read bytes from I2C Device + + @param[in] BusNo - I2C Bus number to which the I2C device has been connected + @param[in] SlaveAddress - Slave address of the I2C device (7-bit) + @param[in] Offset - Register offset from which the data has to be read + @param[in] ReadBytes - Number of bytes to be read + @param[out] ReadBuffer - Address to which the value read has to be stored + + @retval EFI_SUCCESS - Read bytes from I2C device successfully + @retval Others - Return status depends on ByteReadI2C_Basic +**/ +EFI_STATUS +ByteReadI2C ( + IN UINT8 BusNo, + IN UINT8 SlaveAddress, + IN UINT8 Offset, + IN UINTN ReadBytes, + OUT UINT8 *ReadBuffer + ) +{ + EFI_STATUS Status; + + Status = ByteWriteI2C_Basic (BusNo, SlaveAddress, 1, &Offset, TRUE, FALSE); + if (EFI_ERROR (Status)) return Status; + Status = ByteReadI2C_Basic (BusNo, SlaveAddress, ReadBytes, ReadBuffer, TRUE, TRUE); + + return Status; +} + +/** + Write bytes to I2C Device + + @param[in] BusNo - I2C Bus number to which the I2C device has been connected + @param[in] SlaveAddress - Slave address of the I2C device (7-bit) + @param[in] Offset - Register offset from which the data has to be read + @param[in] WriteBytes - Number of bytes to be written + @param[in] WriteBuffer - Address to which the byte value has to be written + + @retval EFI_SUCCESS - Write bytes to I2C device successfully + @retval Others - Return status depends on ByteWriteI2C_Basic +**/ +EFI_STATUS +ByteWriteI2C ( + IN UINT8 BusNo, + IN UINT8 SlaveAddress, + IN UINT8 Offset, + IN UINTN WriteBytes, + IN UINT8 *WriteBuffer + ) +{ + EFI_STATUS Status; + + Status = ByteWriteI2C_Basic (BusNo, SlaveAddress, 1, &Offset, TRUE, FALSE); + if (EFI_ERROR (Status)) return Status; + Status = ByteWriteI2C_Basic (BusNo, SlaveAddress, WriteBytes, WriteBuffer, FALSE, TRUE); + + return Status; +} diff --git a/Silicon/BroxtonSoC/BroxtonSiPkg/SouthCluster/Library/I2CLibPei/I2CLibPei.inf b/Silicon/BroxtonSoC/BroxtonSiPkg/SouthCluster/Library/I2CLibPei/I2CLibPei.inf new file mode 100644 index 0000000000..1f920bb0a5 --- /dev/null +++ b/Silicon/BroxtonSoC/BroxtonSiPkg/SouthCluster/Library/I2CLibPei/I2CLibPei.inf @@ -0,0 +1,51 @@ +## @file +# Pei library for I2C bus driver. +# +# Copyright (c) 1999 - 2017, Intel Corporation. All rights reserved.
+# +# This program and the accompanying materials +# are licensed and made available under the terms and conditions of the BSD License +# which accompanies this distribution. The full text of the license may be found at +# http://opensource.org/licenses/bsd-license.php. +# +# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +# +## + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = I2CLibPei + FILE_GUID = 8EF61509-890B-4FF2-B352-1C0E9CDDEC8B + MODULE_TYPE = BASE + VERSION_STRING = 1.0 + LIBRARY_CLASS = I2CLibPei + + CONSTRUCTOR = IntelI2CPeiLibConstructor + +# +# The following information is for reference only and not required by the build tools. +# +# VALID_ARCHITECTURES = IA32 X64 IPF EBC +# + +[Sources.common] + I2CLibPei.c + I2CDelayPei.c + I2CIoLibPei.c + +[LibraryClasses] + +[PPIs] + gEfiPeiStallPpiGuid ## CONSUMES + +[Packages] + MdePkg/MdePkg.dec + BroxtonSiPkg/BroxtonSiPkg.dec + +[Pcd] + gEfiMdePkgTokenSpaceGuid.PcdPciExpressBaseAddress ## SOMETIMES_CONSUMES + gEfiBxtTokenSpaceGuid.PcdPmcGcrBaseAddress ## CONSUMES + + + -- cgit v1.2.3