[coreboot-gerrit] New patch to review for coreboot: DO NOT MERGE: PCIe reset not working

Leroy P Leahy (leroy.p.leahy@intel.com) gerrit at coreboot.org
Tue May 17 18:33:35 CEST 2016


Leroy P Leahy (leroy.p.leahy at intel.com) just uploaded a new patch set to gerrit, which you can find at https://review.coreboot.org/14874

-gerrit

commit ad3768df9f026ded7b6969ddef9b8043bc00a505
Author: Lee Leahy <leroy.p.leahy at intel.com>
Date:   Fri Apr 29 15:16:54 2016 -0700

    DO NOT MERGE: PCIe reset not working
    
    Migrate PlatformPciHelperLib from QuarkFspPkg into coreboot.
    Writing to resume well GPIO is failing!
    
    Change-Id: I10f052704d7bbb3440fc6c7aeb9fb4f801238e6e
---
 src/mainboard/intel/galileo/gen1.h           |    3 +
 src/mainboard/intel/galileo/gen2.h           |    3 +
 src/mainboard/intel/galileo/gpio.c           |   12 +
 src/mainboard/intel/galileo/spd/mt41k128m8.c |   21 +
 src/soc/intel/quark/Makefile.inc             |    1 +
 src/soc/intel/quark/chip.c                   |    3 +
 src/soc/intel/quark/i2c.c                    | 1302 ++++++++++++++++++++++++++
 src/soc/intel/quark/include/soc/pci_devs.h   |    5 +-
 src/soc/intel/quark/include/soc/ramstage.h   |    5 +-
 src/soc/intel/quark/include/soc/reg_access.h |   31 +
 src/soc/intel/quark/pci.c                    |  131 +++
 src/soc/intel/quark/reg_access.c             |   38 +-
 src/soc/intel/quark/romstage/romstage.c      |    2 +
 src/soc/intel/quark/romstage/uart.c          |    8 +-
 14 files changed, 1556 insertions(+), 9 deletions(-)

diff --git a/src/mainboard/intel/galileo/gen1.h b/src/mainboard/intel/galileo/gen1.h
index 9ddec8f..bff3d6e 100644
--- a/src/mainboard/intel/galileo/gen1.h
+++ b/src/mainboard/intel/galileo/gen1.h
@@ -17,6 +17,9 @@
 
 #include "reg_access.h"
 
+/* PCIe reset pin */
+#define PCI_RESET_RESUMEWELL_GPIO	3
+
 /* Jumper J2 determines the slave address of Cypress I/O GPIO expander */
 #define GALILEO_DETERMINE_IOEXP_SLA_RESUMEWELL_GPIO     5
 
diff --git a/src/mainboard/intel/galileo/gen2.h b/src/mainboard/intel/galileo/gen2.h
index dcc057a..f11717f 100644
--- a/src/mainboard/intel/galileo/gen2.h
+++ b/src/mainboard/intel/galileo/gen2.h
@@ -17,6 +17,9 @@
 
 #include "reg_access.h"
 
+/* PCIe reset pin */
+#define PCI_RESET_RESUMEWELL_GPIO	0
+
 static const struct reg_script gpio_init[] = {
 	/* Initialize the legacy GPIO controller */
 	REG_LEG_GPIO_WRITE(R_QNC_GPIO_CGEN_CORE_WELL, 0x03),
diff --git a/src/mainboard/intel/galileo/gpio.c b/src/mainboard/intel/galileo/gpio.c
index 6d51d44..9c6048c 100644
--- a/src/mainboard/intel/galileo/gpio.c
+++ b/src/mainboard/intel/galileo/gpio.c
@@ -34,3 +34,15 @@ void mainboard_gpio_init(void)
 {
 	reg_script_run(gpio_init);
 }
+
+void mainboard_gpio_pcie_reset(uint32_t pin_value)
+{
+	uint32_t pin_number;
+	uint32_t value;
+
+	/* Update the PCIe reset value */
+	pin_number = PCI_RESET_RESUMEWELL_GPIO;
+	value = reg_legacy_gpio_read(R_QNC_GPIO_RGLVL_RESUME_WELL);
+	value = (value & ~(1 << pin_number)) | pin_value;
+	reg_legacy_gpio_write(R_QNC_GPIO_RGLVL_RESUME_WELL, value);
+}
diff --git a/src/mainboard/intel/galileo/spd/mt41k128m8.c b/src/mainboard/intel/galileo/spd/mt41k128m8.c
new file mode 100644
index 0000000..efefbf8
--- /dev/null
+++ b/src/mainboard/intel/galileo/spd/mt41k128m8.c
@@ -0,0 +1,21 @@
+uint8_t spd_data[] = {
+	sizeof(spd_data),	/* 0x00: Total bytes */
+	0x10,			/* 0x01: Revision 1.0 */
+	15,			/* 0x02: DRAM Type: LPDDR3 */
+	0x0e,			/* 0x03: Soldered down memory */
+	0x12,			/* 0x04: 1 Gbit, 8 banks */
+	0x11,			/* 0x05: 14 Row and 10 Column address bits */
+	1,			/* 0x06: 1 die/package, 1 channel, matrix 1 */
+	0,			/* 0x07: Untested MAC */
+	0,			/* 0x08: Reserved */
+	0,			/* 0x09: Per Package Repair not supported */
+	0,			/* 0x0a: Reserved */
+	0,			/* 0x0b: Reserved */
+	1,			/* 0x0c: 8-bits per device */
+	1,			/* 0x0d: 1 16-bit channel */
+	0,			/* 0x0e: No thermal sensor */
+	0,			/* 0x0f: Reserved */
+	0x49,			/* 0x10: 2 loads on all lines */
+
+};
+
diff --git a/src/soc/intel/quark/Makefile.inc b/src/soc/intel/quark/Makefile.inc
index b63e613..ec45a61 100644
--- a/src/soc/intel/quark/Makefile.inc
+++ b/src/soc/intel/quark/Makefile.inc
@@ -28,6 +28,7 @@ ramstage-y += chip.c
 ramstage-y += gpio_i2c.c
 ramstage-y += memmap.c
 ramstage-y += northcluster.c
+#ramstage-y += pci.c
 ramstage-y += pmc.c
 ramstage-y += reg_access.c
 ramstage-y += tsc_freq.c
diff --git a/src/soc/intel/quark/chip.c b/src/soc/intel/quark/chip.c
index 090d6a0..21f09c9 100644
--- a/src/soc/intel/quark/chip.c
+++ b/src/soc/intel/quark/chip.c
@@ -115,6 +115,9 @@ static void chip_init(void *chip_info)
 		== (TS_LOCK_THRM_CTRL_REGS_ENABLE
 			| TS_LOCK_AUX_TRIP_PT_REGS_ENABLE));
 
+	/* Initialize the PCIe bridges */
+//	reg_script_run(pcie_init_script);
+
 	/* Perform silicon specific init. */
 	if (IS_ENABLED(CONFIG_RELOCATE_FSP_INTO_DRAM))
 		intel_silicon_init();
diff --git a/src/soc/intel/quark/i2c.c b/src/soc/intel/quark/i2c.c
new file mode 100644
index 0000000..83e26e2
--- /dev/null
+++ b/src/soc/intel/quark/i2c.c
@@ -0,0 +1,1302 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright (C) 2016 Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <console/console.h>
+#include <device/device.h>
+#include <soc/ramstage.h>
+#include <soc/reg_access.h>
+
+/**
+  The Called to Common Service Entry.
+
+  @return None.
+
+**/
+
+#define IohMmioAddress( BaseAddr, Register ) \
+    ( (UINTN)BaseAddr + \
+      (UINTN)(Register) \
+    )
+
+//
+// UINT64
+//
+#define IohMmio64Ptr( BaseAddr, Register ) \
+    ( (volatile UINT64 *)IohMmioAddress( BaseAddr, Register ) )
+
+#define IohMmio64( BaseAddr, Register ) \
+    *IohMmio64Ptr( BaseAddr, Register )
+
+#define IohMmio64Or( BaseAddr, Register, OrData ) \
+    IohMmio64( BaseAddr, Register ) = \
+      (UINT64) ( \
+        IohMmio64( BaseAddr, Register ) | \
+        (UINT64)(OrData) \
+      )
+
+#define IohMmio64And( BaseAddr, Register, AndData ) \
+    IohMmio64( BaseAddr, Register ) = \
+      (UINT64) ( \
+        IohMmio64( BaseAddr, Register ) & \
+        (UINT64)(AndData) \
+      )
+
+#define IohMmio64AndThenOr( BaseAddr, Register, AndData, OrData ) \
+    IohMmio64( BaseAddr, Register ) = \
+      (UINT64) ( \
+        ( IohMmio64( BaseAddr, Register ) & \
+            (UINT64)(AndData) \
+        ) | \
+        (UINT64)(OrData) \
+      )
+
+//
+// UINT32
+//
+#define IohMmio32Ptr( BaseAddr, Register ) \
+    ( (volatile UINT32 *)IohMmioAddress( BaseAddr, Register ) )
+
+#define IohMmio32( BaseAddr, Register ) \
+    *IohMmio32Ptr( BaseAddr, Register )
+
+#define IohMmio32Or( BaseAddr, Register, OrData ) \
+    IohMmio32( BaseAddr, Register ) = \
+      (UINT32) ( \
+        IohMmio32( BaseAddr, Register ) | \
+        (UINT32)(OrData) \
+      )
+
+#define IohMmio32And( BaseAddr, Register, AndData ) \
+    IohMmio32( BaseAddr, Register ) = \
+      (UINT32) ( \
+        IohMmio32( BaseAddr, Register ) & \
+        (UINT32)(AndData) \
+      )
+
+#define IohMmio32AndThenOr( BaseAddr, Register, AndData, OrData ) \
+    IohMmio32( BaseAddr, Register ) = \
+      (UINT32) ( \
+        ( IohMmio32( BaseAddr, Register ) & \
+            (UINT32)(AndData) \
+        ) | \
+        (UINT32)(OrData) \
+      )
+//
+// UINT16
+//
+
+#define IohMmio16Ptr( BaseAddr, Register ) \
+    ( (volatile UINT16 *)IohMmioAddress( BaseAddr, Register ) )
+
+#define IohMmio16( BaseAddr, Register ) \
+    *IohMmio16Ptr( BaseAddr, Register )
+
+#define IohMmio16Or( BaseAddr, Register, OrData ) \
+    IohMmio16( BaseAddr, Register ) = \
+      (UINT16) ( \
+        IohMmio16( BaseAddr, Register ) | \
+        (UINT16)(OrData) \
+      )
+
+#define IohMmio16And( BaseAddr, Register, AndData ) \
+    IohMmio16( BaseAddr, Register ) = \
+      (UINT16) ( \
+        IohMmio16( BaseAddr, Register ) & \
+        (UINT16)(AndData) \
+      )
+
+#define IohMmio16AndThenOr( BaseAddr, Register, AndData, OrData ) \
+    IohMmio16( BaseAddr, Register ) = \
+      (UINT16) ( \
+        ( IohMmio16( BaseAddr, Register ) & \
+            (UINT16)(AndData) \
+        ) | \
+        (UINT16)(OrData) \
+      )
+//
+// UINT8
+//
+#define IohMmio8Ptr( BaseAddr, Register ) \
+    ( (volatile UINT8 *)IohMmioAddress( BaseAddr, Register ) )
+
+#define IohMmio8( BaseAddr, Register ) \
+    *IohMmio8Ptr( BaseAddr, Register )
+
+#define IohMmio8Or( BaseAddr, Register, OrData ) \
+    IohMmio8( BaseAddr, Register ) = \
+      (UINT8) ( \
+        IohMmio8( BaseAddr, Register ) | \
+        (UINT8)(OrData) \
+      )
+
+#define IohMmio8And( BaseAddr, Register, AndData ) \
+    IohMmio8( BaseAddr, Register ) = \
+      (UINT8) ( \
+        IohMmio8( BaseAddr, Register ) & \
+        (UINT8)(AndData) \
+      )
+
+#define IohMmio8AndThenOr( BaseAddr, Register, AndData, OrData ) \
+    IohMmio8( BaseAddr, Register ) = \
+      (UINT8) ( \
+        ( IohMmio8( BaseAddr, Register ) & \
+            (UINT8)(AndData) \
+          ) | \
+        (UINT8)(OrData) \
+      )
+
+//
+//  Common Memory mapped Pci access macros ------------------------------------------
+//
+#define Ioh_PCI_EXPRESS_BASE_ADDRESS  0xE0000000
+
+
+#define IohMmPciAddress( Segment, Bus, Device, Function, Register ) \
+  ( (UINTN)Ioh_PCI_EXPRESS_BASE_ADDRESS + \
+    (UINTN)(Bus << 20) + \
+    (UINTN)(Device << 15) + \
+    (UINTN)(Function << 12) + \
+    (UINTN)(Register) \
+  )
+
+//
+// UINT32
+//
+#define IohMmPci32Ptr( Segment, Bus, Device, Function, Register ) \
+  ( (volatile UINT32 *)IohMmPciAddress( Segment, Bus, Device, Function, Register ) )
+
+#define IohMmPci32( Segment, Bus, Device, Function, Register ) \
+  *IohMmPci32Ptr( Segment, Bus, Device, Function, Register )
+
+#define IohMmPci32Or( Segment, Bus, Device, Function, Register, OrData ) \
+  IohMmPci32( Segment, Bus, Device, Function, Register ) = \
+    (UINT32) ( \
+      IohMmPci32( Segment, Bus, Device, Function, Register ) | \
+      (UINT32)(OrData) \
+    )
+
+#define IohMmPci32And( Segment, Bus, Device, Function, Register, AndData ) \
+  IohMmPci32( Segment, Bus, Device, Function, Register ) = \
+    (UINT32) ( \
+      IohMmPci32( Segment, Bus, Device, Function, Register ) & \
+      (UINT32)(AndData) \
+    )
+
+#define IohMmPci32AndThenOr( Segment, Bus, Device, Function, Register, AndData, OrData ) \
+  IohMmPci32( Segment, Bus, Device, Function, Register ) = \
+    (UINT32) ( \
+      ( IohMmPci32( Segment, Bus, Device, Function, Register ) & \
+          (UINT32)(AndData) \
+      ) | \
+      (UINT32)(OrData) \
+    )
+//
+// UINT16
+//
+#define IohMmPci16Ptr( Segment, Bus, Device, Function, Register ) \
+  ( (volatile UINT16 *)IohMmPciAddress( Segment, Bus, Device, Function, Register ) )
+
+#define IohMmPci16( Segment, Bus, Device, Function, Register ) \
+  *IohMmPci16Ptr( Segment, Bus, Device, Function, Register )
+
+#define IohMmPci16Or( Segment, Bus, Device, Function, Register, OrData ) \
+  IohMmPci16( Segment, Bus, Device, Function, Register ) = \
+    (UINT16) ( \
+      IohMmPci16( Segment, Bus, Device, Function, Register ) | \
+      (UINT16)(OrData) \
+    )
+
+#define IohMmPci16And( Segment, Bus, Device, Function, Register, AndData ) \
+  IohMmPci16( Segment, Bus, Device, Function, Register ) = \
+    (UINT16) ( \
+      IohMmPci16( Segment, Bus, Device, Function, Register ) & \
+      (UINT16)(AndData) \
+    )
+
+#define IohMmPci16AndThenOr( Segment, Bus, Device, Function, Register, AndData, OrData ) \
+  IohMmPci16( Segment, Bus, Device, Function, Register ) = \
+    (UINT16) ( \
+      ( IohMmPci16( Segment, Bus, Device, Function, Register ) & \
+          (UINT16)(AndData) \
+      ) | \
+      (UINT16)(OrData) \
+    )
+//
+// UINT8
+//
+#define IohMmPci8Ptr( Segment, Bus, Device, Function, Register ) \
+  ( (volatile UINT8 *)IohMmPciAddress( Segment, Bus, Device, Function, Register ) )
+
+#define IohMmPci8( Segment, Bus, Device, Function, Register ) \
+  *IohMmPci8Ptr( Segment, Bus, Device, Function, Register )
+
+#define IohMmPci8Or( Segment, Bus, Device, Function, Register, OrData ) \
+  IohMmPci8( Segment, Bus, Device, Function, Register ) = \
+    (UINT8) ( \
+      IohMmPci8( Segment, Bus, Device, Function, Register ) | \
+      (UINT8)(OrData) \
+    )
+
+#define IohMmPci8And( Segment, Bus, Device, Function, Register, AndData ) \
+  IohMmPci8( Segment, Bus, Device, Function, Register ) = \
+    (UINT8) ( \
+      IohMmPci8( Segment, Bus, Device, Function, Register ) & \
+      (UINT8)(AndData) \
+    )
+
+#define IohMmPci8AndThenOr( Segment, Bus, Device, Function, Register, AndData, OrData ) \
+  IohMmPci8( Segment, Bus, Device, Function, Register ) = \
+    (UINT8) ( \
+      ( IohMmPci8( Segment, Bus, Device, Function, Register ) & \
+          (UINT8)(AndData) \
+        ) | \
+      (UINT8)(OrData) \
+    )
+
+
+VOID
+I2cCommonServiceEntry  (
+  OUT UINT16 *SaveCmdPtr,
+  OUT UINT32 *SaveBar0Ptr
+  )
+{
+  *SaveBar0Ptr = IohMmPci32 (0, I2C_Bus, I2C_Device, I2C_Func, PCI_BAR0);
+  if (((*SaveBar0Ptr) & B_IOH_I2C_GPIO_MEMBAR_ADDR_MASK) == 0) {
+
+    IohMmPci32(0, I2C_Bus, I2C_Device, I2C_Func, PCI_BAR0) =
+      FixedPcdGet32 (PcdIohI2cMmioBase) & B_IOH_I2C_GPIO_MEMBAR_ADDR_MASK;
+
+    //
+    // also Save Cmd Register, Setup by InitializeInternal later during xfers.
+    //
+    *SaveCmdPtr = IohMmPci16 (0, I2C_Bus, I2C_Device, I2C_Func, PCI_CMD);
+  }
+}
+
+/**
+  The Called on Common Service Exit.
+
+  @return None.
+
+**/
+VOID
+I2cCommonServiceExit  (
+  IN CONST UINT16 SaveCmd,
+  IN CONST UINT32 SaveBar0
+
+  )
+{
+  if ((SaveBar0 & B_IOH_I2C_GPIO_MEMBAR_ADDR_MASK) == 0) {
+    IohMmPci16 (0, I2C_Bus, I2C_Device, I2C_Func, PCI_CMD) = SaveCmd;
+    IohMmPci32 (0, I2C_Bus, I2C_Device, I2C_Func, PCI_BAR0) = SaveBar0;
+  }
+}
+
+
+/**
+  The GetI2CIoPortBaseAddress() function gets IO port base address of I2C Controller.
+
+  Always reads PCI configuration space to get MMIO base address of I2C Controller.
+
+  @return The IO port base address of I2C controller.
+
+**/
+UINTN
+GetI2CIoPortBaseAddress (
+  VOID
+  )
+{
+  UINTN     I2CIoPortBaseAddress;
+
+  //
+  // Get I2C Memory Mapped registers base address.
+  //
+  I2CIoPortBaseAddress = IohMmPci32(0, I2C_Bus, I2C_Device, I2C_Func, PCI_BAR0);
+
+  //
+  // Make sure that the IO port base address has been properly set.
+  //
+  ASSERT (I2CIoPortBaseAddress != 0);
+  ASSERT (I2CIoPortBaseAddress != 0xFF);
+
+  return I2CIoPortBaseAddress;
+}
+
+
+/**
+  The EnableI2CMmioSpace() function enables access to I2C MMIO space.
+
+**/
+VOID
+EnableI2CMmioSpace (
+  VOID
+  )
+{
+  UINT8 PciCmd;
+
+  //
+  // Read PCICMD.  Bus=0, Dev=0, Func=0, Reg=0x4
+  //
+  PciCmd = IohMmPci8(0, I2C_Bus, I2C_Device, I2C_Func, PCI_REG_PCICMD);
+
+  //
+  // Enable Bus Master(Bit2), MMIO Space(Bit1) & I/O Space(Bit0)
+  //
+  PciCmd |= 0x7;
+  IohMmPci8(0, I2C_Bus, I2C_Device, I2C_Func, PCI_REG_PCICMD) = PciCmd;
+
+}
+
+/**
+  The DisableI2CController() functions disables I2C Controller.
+
+**/
+VOID
+DisableI2CController (
+  VOID
+  )
+{
+  UINTN       I2CIoPortBaseAddress;
+  UINT32      Addr;
+  UINT32      Data;
+  UINT8       PollCount;
+
+  PollCount = 0;
+
+  //
+  // Get I2C Memory Mapped registers base address.
+  //
+  I2CIoPortBaseAddress = GetI2CIoPortBaseAddress ();
+
+  //
+  // Disable the I2C Controller by setting IC_ENABLE.ENABLE to zero
+  //
+  Addr = I2CIoPortBaseAddress + I2C_REG_ENABLE;
+  Data = *((volatile UINT32 *) (UINTN)(Addr));
+  Data &= ~B_I2C_REG_ENABLE;
+  *((volatile UINT32 *) (UINTN)(Addr)) = Data;
+
+  //
+  // Read the IC_ENABLE_STATUS.IC_EN Bit to check if Controller is disabled
+  //
+  Data = 0xFF;
+  Addr = I2CIoPortBaseAddress + I2C_REG_ENABLE_STATUS;
+  Data = *((volatile UINT32 *) (UINTN)(Addr)) & I2C_REG_ENABLE_STATUS;
+  while (Data != 0) {
+    //
+    // Poll the IC_ENABLE_STATUS.IC_EN Bit to check if Controller is disabled, until timeout (TI2C_POLL*MAX_T_POLL_COUNT).
+    //
+    PollCount++;
+    if (PollCount >= MAX_T_POLL_COUNT) {
+      break;
+    }
+    MicroSecondDelay(TI2C_POLL);
+    Data = *((volatile UINT32 *) (UINTN)(Addr));
+    Data &= I2C_REG_ENABLE_STATUS;
+  }
+
+  //
+  // Asset if controller does not enter Disabled state.
+  //
+  ASSERT (PollCount < MAX_T_POLL_COUNT);
+
+  //
+  // Read IC_CLR_INTR register to automatically clear the combined interrupt,
+  // all individual interrupts and the IC_TX_ABRT_SOURCE register.
+  //
+  Addr = I2CIoPortBaseAddress + I2C_REG_CLR_INT;
+  Data = *((volatile UINT32 *) (UINTN)(Addr));
+
+}
+
+/**
+  The EnableI2CController() function enables the I2C Controller.
+
+**/
+VOID
+EnableI2CController (
+  VOID
+  )
+{
+  UINTN   I2CIoPortBaseAddress;
+  UINT32  Addr;
+  UINT32  Data;
+
+  //
+  // Get I2C Memory Mapped registers base address.
+  //
+  I2CIoPortBaseAddress = GetI2CIoPortBaseAddress ();
+
+  //
+  // Enable the I2C Controller by setting IC_ENABLE.ENABLE to 1
+  //
+  Addr = I2CIoPortBaseAddress + I2C_REG_ENABLE;
+  Data = *((volatile UINT32 *) (UINTN)(Addr));
+  Data |= B_I2C_REG_ENABLE;
+  *((volatile UINT32 *) (UINTN)(Addr)) = Data;
+
+  //
+  // Clear overflow and abort error status bits before transactions.
+  //
+  Addr = I2CIoPortBaseAddress + I2C_REG_CLR_RX_OVER;
+  Data = *((volatile UINT32 *) (UINTN)(Addr));
+  Addr = I2CIoPortBaseAddress + I2C_REG_CLR_TX_OVER;
+  Data = *((volatile UINT32 *) (UINTN)(Addr));
+  Addr = I2CIoPortBaseAddress + I2C_REG_CLR_TX_ABRT;
+  Data = *((volatile UINT32 *) (UINTN)(Addr));
+
+}
+
+/**
+  The WaitForStopDet() function waits until I2C STOP Condition occurs,
+  indicating transfer completion.
+
+  @retval EFI_SUCCESS           Stop detected.
+  @retval EFI_TIMEOUT           Timeout while waiting for stop condition.
+  @retval EFI_ABORTED           Tx abort signaled in HW status register.
+  @retval EFI_DEVICE_ERROR      Tx or Rx overflow detected.
+
+**/
+EFI_STATUS
+WaitForStopDet (
+  VOID
+  )
+{
+  UINTN       I2CIoPortBaseAddress;
+  UINT32      Addr;
+  UINT32      Data;
+  UINT32      PollCount;
+  EFI_STATUS  Status;
+
+  Status = EFI_SUCCESS;
+
+  PollCount = 0;
+
+  //
+  // Get I2C Memory Mapped registers base address.
+  //
+  I2CIoPortBaseAddress = GetI2CIoPortBaseAddress ();
+
+  //
+  // Wait for STOP Detect.
+  //
+  Addr = I2CIoPortBaseAddress + I2C_REG_RAW_INTR_STAT;
+
+  do {
+    Data = *((volatile UINT32 *) (UINTN)(Addr));
+    if ((Data & I2C_REG_RAW_INTR_STAT_TX_ABRT) != 0) {
+      Status = EFI_ABORTED;
+      break;
+    }
+    if ((Data & I2C_REG_RAW_INTR_STAT_TX_OVER) != 0) {
+      Status = EFI_DEVICE_ERROR;
+      break;
+    }
+    if ((Data & I2C_REG_RAW_INTR_STAT_RX_OVER) != 0) {
+      Status = EFI_DEVICE_ERROR;
+      break;
+    }
+    if ((Data & I2C_REG_RAW_INTR_STAT_STOP_DET) != 0) {
+      Status = EFI_SUCCESS;
+      break;
+    }
+    MicroSecondDelay(TI2C_POLL);
+    PollCount++;
+    if (PollCount >= MAX_STOP_DET_POLL_COUNT) {
+      Status = EFI_TIMEOUT;
+      break;
+    }
+
+  } while (TRUE);
+
+  return Status;
+}
+
+/**
+
+  The InitializeInternal() function initialises internal I2C Controller
+  register values that are commonly required for I2C Write and Read transfers.
+
+  @param AddrMode     I2C Addressing Mode: 7-bit or 10-bit address.
+
+  @retval EFI_SUCCESS           I2C Operation completed successfully.
+
+**/
+EFI_STATUS
+InitializeInternal (
+  IN  EFI_I2C_ADDR_MODE  AddrMode
+  )
+{
+  UINTN       I2CIoPortBaseAddress;
+  UINTN       Addr;
+  UINT32      Data;
+  EFI_STATUS  Status;
+
+  Status = EFI_SUCCESS;
+
+  //
+  // Enable access to I2C Controller MMIO space.
+  //
+  EnableI2CMmioSpace ();
+
+  //
+  // Disable I2C Controller initially
+  //
+  DisableI2CController ();
+
+  //
+  // Get I2C Memory Mapped registers base address.
+  //
+  I2CIoPortBaseAddress = GetI2CIoPortBaseAddress ();
+
+  //
+  // Clear START_DET
+  //
+  Addr = I2CIoPortBaseAddress + I2C_REG_CLR_START_DET;
+  Data = *((volatile UINT32 *) (UINTN)(Addr));
+  Data &= ~B_I2C_REG_CLR_START_DET;
+  *((volatile UINT32 *) (UINTN)(Addr)) = Data;
+
+  //
+  // Clear STOP_DET
+  //
+  Addr = I2CIoPortBaseAddress + I2C_REG_CLR_STOP_DET;
+  Data = *((volatile UINT32 *) (UINTN)(Addr));
+  Data &= ~B_I2C_REG_CLR_STOP_DET;
+  *((volatile UINT32 *) (UINTN)(Addr)) = Data;
+
+  //
+  // Set addressing mode to user defined (7 or 10 bit) and
+  // speed mode to that defined by PCD (standard mode default).
+  //
+  Addr = I2CIoPortBaseAddress + I2C_REG_CON;
+  Data = *((volatile UINT32 *) (UINTN)(Addr));
+  // Set Addressing Mode
+  if (AddrMode == EfiI2CSevenBitAddrMode) {
+    Data &= ~B_I2C_REG_CON_10BITADD_MASTER;
+  } else {
+    Data |= B_I2C_REG_CON_10BITADD_MASTER;
+  }
+  // Set Speed Mode
+  Data &= ~B_I2C_REG_CON_SPEED;
+  if (FeaturePcdGet (PcdI2CFastModeEnabled)) {
+    Data |= BIT2;
+  } else {
+    Data |= BIT1;
+  }
+  *((volatile UINT32 *) (UINTN)(Addr)) = Data;
+
+  Data = *((volatile UINT32 *) (UINTN)(Addr));
+
+  return Status;
+
+}
+
+/**
+
+  The WriteByte() function provides a standard way to execute a
+  standard single byte write to an IC2 device (without accessing
+  sub-addresses), as defined in the I2C Specification.
+
+  @param  I2CAddress      I2C Slave device address
+  @param  Value           The 8-bit value to write.
+
+  @retval EFI_SUCCESS           Transfer success.
+  @retval EFI_UNSUPPORTED       Unsupported input param.
+  @retval EFI_TIMEOUT           Timeout while waiting xfer.
+  @retval EFI_ABORTED           Controller aborted xfer.
+  @retval EFI_DEVICE_ERROR      Device error detected by controller.
+
+**/
+EFI_STATUS
+EFIAPI
+WriteByte (
+  IN  UINTN          I2CAddress,
+  IN  UINT8          Value
+  )
+{
+  UINTN       I2CIoPortBaseAddress;
+  UINTN       Addr;
+  UINT32      Data;
+  EFI_STATUS  Status;
+
+  //
+  // Get I2C Memory Mapped registers base address
+  //
+  I2CIoPortBaseAddress = GetI2CIoPortBaseAddress ();
+
+  //
+  // Write to the IC_TAR register the address of the slave device to be addressed
+  //
+  Addr = I2CIoPortBaseAddress + I2C_REG_TAR;
+  Data = *((volatile UINT32 *) (UINTN)(Addr));
+  Data &= ~B_I2C_REG_TAR;
+  Data |= I2CAddress;
+  *((volatile UINT32 *) (UINTN)(Addr)) = Data;
+
+  //
+  // Enable the I2C Controller
+  //
+  EnableI2CController ();
+
+  //
+  // Write the data and transfer direction to the IC_DATA_CMD register.
+  // Also specify that transfer should be terminated by STOP condition.
+  //
+  Addr = I2CIoPortBaseAddress + I2C_REG_DATA_CMD;
+  Data = *((volatile UINT32 *) (UINTN)(Addr));
+  Data &= 0xFFFFFF00;
+  Data |= (UINT8)Value;
+  Data &= ~B_I2C_REG_DATA_CMD_RW;
+  Data |= B_I2C_REG_DATA_CMD_STOP;
+  *((volatile UINT32 *) (UINTN)(Addr)) = Data;
+
+  //
+  // Wait for transfer completion.
+  //
+  Status = WaitForStopDet ();
+
+  //
+  // Ensure I2C Controller disabled.
+  //
+  DisableI2CController();
+
+  return Status;
+}
+
+/**
+
+  The ReadByte() function provides a standard way to execute a
+  standard single byte read to an IC2 device (without accessing
+  sub-addresses), as defined in the I2C Specification.
+
+  @param  I2CAddress      I2C Slave device address
+  @param  ReturnDataPtr   Pointer to location to receive read byte.
+
+  @retval EFI_SUCCESS           Transfer success.
+  @retval EFI_UNSUPPORTED       Unsupported input param.
+  @retval EFI_TIMEOUT           Timeout while waiting xfer.
+  @retval EFI_ABORTED           Controller aborted xfer.
+  @retval EFI_DEVICE_ERROR      Device error detected by controller.
+
+**/
+EFI_STATUS
+EFIAPI
+ReadByte (
+  IN  UINTN          I2CAddress,
+  OUT UINT8          *ReturnDataPtr
+  )
+{
+  UINTN       I2CIoPortBaseAddress;
+  UINTN       Addr;
+  UINT32      Data;
+  EFI_STATUS  Status;
+
+  //
+  // Get I2C Memory Mapped registers base address.
+  //
+  I2CIoPortBaseAddress = GetI2CIoPortBaseAddress ();
+
+  //
+  // Write to the IC_TAR register the address of the slave device to be addressed
+  //
+  Addr = I2CIoPortBaseAddress + I2C_REG_TAR;
+  Data = *((volatile UINT32 *) (UINTN)(Addr));
+  Data &= ~B_I2C_REG_TAR;
+  Data |= I2CAddress;
+  *((volatile UINT32 *) (UINTN)(Addr)) = Data;
+
+  //
+  // Enable the I2C Controller
+  //
+  EnableI2CController ();
+
+  //
+  // Write transfer direction to the IC_DATA_CMD register and
+  // specify that transfer should be terminated by STOP condition.
+  //
+  Addr = I2CIoPortBaseAddress + I2C_REG_DATA_CMD;
+  Data = *((volatile UINT32 *) (UINTN)(Addr));
+  Data &= 0xFFFFFF00;
+  Data |= B_I2C_REG_DATA_CMD_RW;
+  Data |= B_I2C_REG_DATA_CMD_STOP;
+  *((volatile UINT32 *) (UINTN)(Addr)) = Data;
+
+  //
+  // Wait for transfer completion
+  //
+  Status = WaitForStopDet ();
+  if (!EFI_ERROR(Status)) {
+
+    //
+    // Clear RX underflow before reading IC_DATA_CMD.
+    //
+    Addr = I2CIoPortBaseAddress + I2C_REG_CLR_RX_UNDER;
+    Data = *((volatile UINT32 *) (UINTN)(Addr));
+
+    //
+    // Obtain and return read data byte from RX buffer (IC_DATA_CMD[7:0]).
+    //
+    Addr = I2CIoPortBaseAddress + I2C_REG_DATA_CMD;
+    Data = *((volatile UINT32 *) (UINTN)(Addr));
+    Data &= 0x000000FF;
+    *ReturnDataPtr = (UINT8) Data;
+
+    Addr = I2CIoPortBaseAddress + I2C_REG_RAW_INTR_STAT;
+    Data = *((volatile UINT32 *) (UINTN)(Addr));
+    Data &= I2C_REG_RAW_INTR_STAT_RX_UNDER;
+    if (Data != 0) {
+      Status = EFI_DEVICE_ERROR;
+    }
+  }
+
+  //
+  // Ensure I2C Controller disabled.
+  //
+  DisableI2CController ();
+
+  return Status;
+}
+
+/**
+
+  The WriteMultipleByte() function provides a standard way to execute
+  multiple byte writes to an IC2 device (e.g. when accessing sub-addresses or
+  when writing block of data), as defined in the I2C Specification.
+
+  @param I2CAddress   The I2C slave address of the device
+                      with which to communicate.
+
+  @param WriteBuffer  Contains the value of byte to be written to the
+                      I2C slave device.
+
+  @param Length       No. of bytes to be written.
+
+  @retval EFI_SUCCESS           Transfer success.
+  @retval EFI_UNSUPPORTED       Unsupported input param.
+  @retval EFI_TIMEOUT           Timeout while waiting xfer.
+  @retval EFI_ABORTED           Tx abort signaled in HW status register.
+  @retval EFI_DEVICE_ERROR      Tx overflow detected.
+
+**/
+EFI_STATUS
+EFIAPI
+WriteMultipleByte (
+  IN  UINTN          I2CAddress,
+  IN  UINT8          *WriteBuffer,
+  IN  UINTN          Length
+  )
+{
+  UINTN       I2CIoPortBaseAddress;
+  UINTN       Index;
+  UINTN       Addr;
+  UINT32      Data;
+  EFI_STATUS  Status;
+
+  if (Length > I2C_FIFO_SIZE) {
+    return EFI_UNSUPPORTED;  // Routine does not handle xfers > fifo size.
+  }
+
+  I2CIoPortBaseAddress = GetI2CIoPortBaseAddress ();
+
+  //
+  // Write to the IC_TAR register the address of the slave device to be addressed
+  //
+  Addr = I2CIoPortBaseAddress + I2C_REG_TAR;
+  Data = *((volatile UINT32 *) (UINTN)(Addr));
+  Data &= ~B_I2C_REG_TAR;
+  Data |= I2CAddress;
+  *((volatile UINT32 *) (UINTN)(Addr)) = Data;
+
+  //
+  // Enable the I2C Controller
+  //
+  EnableI2CController ();
+
+  //
+  // Write the data and transfer direction to the IC_DATA_CMD register.
+  // Also specify that transfer should be terminated by STOP condition.
+  //
+  Addr = I2CIoPortBaseAddress + I2C_REG_DATA_CMD;
+  for (Index = 0; Index < Length; Index++) {
+    Data = *((volatile UINT32 *) (UINTN)(Addr));
+    Data &= 0xFFFFFF00;
+    Data |= (UINT8)WriteBuffer[Index];
+    Data &= ~B_I2C_REG_DATA_CMD_RW;
+    if (Index == (Length-1)) {
+      Data |= B_I2C_REG_DATA_CMD_STOP;
+    }
+    *((volatile UINT32 *) (UINTN)(Addr)) = Data;
+  }
+
+  //
+  // Wait for transfer completion
+  //
+  Status = WaitForStopDet ();
+
+  //
+  // Ensure I2C Controller disabled.
+  //
+  DisableI2CController ();
+  return Status;
+}
+
+/**
+
+  The ReadMultipleByte() function provides a standard way to execute
+  multiple byte writes to an IC2 device (e.g. when accessing sub-addresses or
+  when reading block of data), as defined in the I2C Specification (I2C combined
+  write/read protocol).
+
+  @param I2CAddress   The I2C slave address of the device
+                      with which to communicate.
+
+  @param Buffer       Contains the value of byte data written or read from the
+                      I2C slave device.
+
+  @param WriteLength  No. of bytes to be written. In this case data
+                      written typically contains sub-address or sub-addresses
+                      in Hi-Lo format, that need to be read (I2C combined
+                      write/read protocol).
+
+  @param ReadLength   No. of bytes to be read from I2C slave device.
+
+  @retval EFI_SUCCESS           Transfer success.
+  @retval EFI_UNSUPPORTED       Unsupported input param.
+  @retval EFI_TIMEOUT           Timeout while waiting xfer.
+  @retval EFI_ABORTED           Tx abort signaled in HW status register.
+  @retval EFI_DEVICE_ERROR      Rx underflow or Rx/Tx overflow detected.
+
+**/
+EFI_STATUS
+EFIAPI
+ReadMultipleByte (
+  IN  UINTN          I2CAddress,
+  IN  OUT UINT8      *Buffer,
+  IN  UINTN          WriteLength,
+  IN  UINTN          ReadLength
+  )
+{
+  UINTN       I2CIoPortBaseAddress;
+  UINTN       Index;
+  UINTN       Addr;
+  UINT32      Data;
+  UINT8       PollCount;
+  EFI_STATUS  Status;
+
+  if (WriteLength > I2C_FIFO_SIZE || ReadLength > I2C_FIFO_SIZE) {
+    return EFI_UNSUPPORTED;  // Routine does not handle xfers > fifo size.
+  }
+
+  I2CIoPortBaseAddress = GetI2CIoPortBaseAddress ();
+
+  //
+  // Write to the IC_TAR register the address of the slave device to be addressed
+  //
+  Addr = I2CIoPortBaseAddress + I2C_REG_TAR;
+  Data = *((volatile UINT32 *) (UINTN)(Addr));
+  Data &= ~B_I2C_REG_TAR;
+  Data |= I2CAddress;
+  *((volatile UINT32 *) (UINTN)(Addr)) = Data;
+
+  //
+  // Enable the I2C Controller
+  //
+  EnableI2CController ();
+
+  //
+  // Write the data (sub-addresses) to the IC_DATA_CMD register.
+  //
+  Addr = I2CIoPortBaseAddress + I2C_REG_DATA_CMD;
+  for (Index = 0; Index < WriteLength; Index++) {
+    Data = *((volatile UINT32 *) (UINTN)(Addr));
+    Data &= 0xFFFFFF00;
+    Data |= (UINT8)Buffer[Index];
+    Data &= ~B_I2C_REG_DATA_CMD_RW;
+    *((volatile UINT32 *) (UINTN)(Addr)) = Data;
+  }
+
+  //
+  // Issue Read Transfers for each byte (Restart issued when write/read bit changed).
+  //
+  for (Index = 0; Index < ReadLength; Index++) {
+    Data = *((volatile UINT32 *) (UINTN)(Addr));
+    Data |= B_I2C_REG_DATA_CMD_RW;
+    // Issue a STOP for last read transfer.
+    if (Index == (ReadLength-1)) {
+      Data |= B_I2C_REG_DATA_CMD_STOP;
+    }
+    *((volatile UINT32 *) (UINTN)(Addr)) = Data;
+  }
+
+  //
+  // Wait for STOP condition.
+  //
+  Status = WaitForStopDet ();
+  if (!EFI_ERROR(Status)) {
+
+    //
+    // Poll Receive FIFO Buffer Level register until valid (upto MAX_T_POLL_COUNT times).
+    //
+    Data = 0;
+    PollCount = 0;
+    Addr = I2CIoPortBaseAddress + I2C_REG_RXFLR;
+    Data = *((volatile UINT32 *) (UINTN)(Addr));
+    while ((Data != ReadLength) && (PollCount < MAX_T_POLL_COUNT)) {
+      MicroSecondDelay(TI2C_POLL);
+      PollCount++;
+      Data = *((volatile UINT32 *) (UINTN)(Addr));
+    }
+
+    Addr = I2CIoPortBaseAddress + I2C_REG_RAW_INTR_STAT;
+    Data = *((volatile UINT32 *) (UINTN)(Addr));
+
+    //
+    // If no timeout or device error then read rx data.
+    //
+    if (PollCount == MAX_T_POLL_COUNT) {
+      Status = EFI_TIMEOUT;
+    } else if ((Data & I2C_REG_RAW_INTR_STAT_RX_OVER) != 0) {
+      Status = EFI_DEVICE_ERROR;
+    } else {
+
+      //
+      // Clear RX underflow before reading IC_DATA_CMD.
+      //
+      Addr = I2CIoPortBaseAddress + I2C_REG_CLR_RX_UNDER;
+      Data = *((volatile UINT32 *) (UINTN)(Addr));
+
+      //
+      // Read data.
+      //
+      Addr = I2CIoPortBaseAddress + I2C_REG_DATA_CMD;
+      for (Index = 0; Index < ReadLength; Index++) {
+        Data = *((volatile UINT32 *) (UINTN)(Addr));
+        Data &= 0x000000FF;
+        *(Buffer+Index) = (UINT8)Data;
+      }
+      Addr = I2CIoPortBaseAddress + I2C_REG_RAW_INTR_STAT;
+      Data = *((volatile UINT32 *) (UINTN)(Addr));
+      Data &= I2C_REG_RAW_INTR_STAT_RX_UNDER;
+      if (Data != 0) {
+        Status = EFI_DEVICE_ERROR;
+      } else {
+        Status = EFI_SUCCESS;
+      }
+    }
+  }
+
+  //
+  // Ensure I2C Controller disabled.
+  //
+  DisableI2CController ();
+
+  return Status;
+}
+
+/**
+
+  The I2cWriteByte() function is a wrapper function for the WriteByte function.
+  Provides a standard way to execute a standard single byte write to an IC2 device
+  (without accessing sub-addresses), as defined in the I2C Specification.
+
+  @param SlaveAddress The I2C slave address of the device
+                      with which to communicate.
+
+  @param AddrMode     I2C Addressing Mode: 7-bit or 10-bit address.
+
+  @param Buffer       Contains the value of byte data to execute to the
+                      I2C slave device.
+
+
+  @retval EFI_SUCCESS           Transfer success.
+  @retval EFI_INVALID_PARAMETER  This or Buffer pointers are invalid.
+  @retval EFI_UNSUPPORTED       Unsupported input param.
+  @retval EFI_TIMEOUT           Timeout while waiting xfer.
+  @retval EFI_ABORTED           Controller aborted xfer.
+  @retval EFI_DEVICE_ERROR      Device error detected by controller.
+
+**/
+EFI_STATUS
+EFIAPI
+I2cWriteByte (
+  IN        EFI_I2C_DEVICE_ADDRESS  SlaveAddress,
+  IN        EFI_I2C_ADDR_MODE       AddrMode,
+  IN OUT VOID                       *Buffer
+  )
+{
+  EFI_STATUS Status;
+  UINTN      I2CAddress;
+  UINT16            SaveCmd;
+  UINT32            SaveBar0;
+
+  if (Buffer == NULL) {
+    return EFI_INVALID_PARAMETER;
+  }
+  SaveCmd = 0;
+  SaveBar0 = 0;
+
+  I2cCommonServiceEntry (&SaveCmd, &SaveBar0);
+
+  Status = EFI_SUCCESS;
+
+  I2CAddress = SlaveAddress.I2CDeviceAddress;
+  Status = InitializeInternal (AddrMode);
+  if (!EFI_ERROR(Status)) {
+    Status = WriteByte (I2CAddress, *(UINT8 *) Buffer);
+  }
+
+  I2cCommonServiceExit (SaveCmd, SaveBar0);
+  return Status;
+}
+
+/**
+
+  The I2cReadByte() function is a wrapper function for the ReadByte function.
+  Provides a standard way to execute a standard single byte read to an I2C device
+  (without accessing sub-addresses), as defined in the I2C Specification.
+
+  @param SlaveAddress The I2C slave address of the device
+                      with which to communicate.
+
+  @param AddrMode     I2C Addressing Mode: 7-bit or 10-bit address.
+
+  @param Buffer       Contains the value of byte data read from the
+                      I2C slave device.
+
+
+  @retval EFI_SUCCESS           Transfer success.
+  @retval EFI_INVALID_PARAMETER This or Buffer pointers are invalid.
+  @retval EFI_TIMEOUT           Timeout while waiting xfer.
+  @retval EFI_ABORTED           Controller aborted xfer.
+  @retval EFI_DEVICE_ERROR      Device error detected by controller.
+
+
+**/
+EFI_STATUS
+EFIAPI
+I2cReadByte (
+  IN        EFI_I2C_DEVICE_ADDRESS  SlaveAddress,
+  IN        EFI_I2C_ADDR_MODE       AddrMode,
+  IN OUT    VOID                    *Buffer
+  )
+{
+  EFI_STATUS Status;
+  UINTN      I2CAddress;
+  UINT16     SaveCmd;
+  UINT32     SaveBar0;
+
+  if (Buffer == NULL) {
+    return EFI_INVALID_PARAMETER;
+  }
+  SaveCmd = 0;
+  SaveBar0 =0;
+
+  I2cCommonServiceEntry (&SaveCmd, &SaveBar0);
+
+  Status = EFI_SUCCESS;
+
+  I2CAddress = SlaveAddress.I2CDeviceAddress;
+
+  Status = InitializeInternal (AddrMode);
+  if (!EFI_ERROR(Status)) {
+    Status = ReadByte (I2CAddress, (UINT8 *) Buffer);
+  }
+  I2cCommonServiceExit (SaveCmd, SaveBar0);
+  return Status;
+}
+
+/**
+
+  The I2cWriteMultipleByte() function is a wrapper function for the
+  WriteMultipleByte() function. Provides a standard way to execute multiple
+  byte writes to an I2C device (e.g. when accessing sub-addresses or writing
+  block of data), as defined in the I2C Specification.
+
+  @param SlaveAddress The I2C slave address of the device
+                      with which to communicate.
+
+  @param AddrMode     I2C Addressing Mode: 7-bit or 10-bit address.
+
+  @param Length       No. of bytes to be written.
+
+  @param Buffer       Contains the value of byte to be written to the
+                      I2C slave device.
+
+  @retval EFI_SUCCESS            Transfer success.
+  @retval EFI_INVALID_PARAMETER  This, Length or Buffer pointers are invalid.
+  @retval EFI_UNSUPPORTED        Unsupported input param.
+  @retval EFI_TIMEOUT            Timeout while waiting xfer.
+  @retval EFI_ABORTED            Controller aborted xfer.
+  @retval EFI_DEVICE_ERROR       Device error detected by controller.
+
+**/
+EFI_STATUS
+EFIAPI
+I2cWriteMultipleByte (
+  IN        EFI_I2C_DEVICE_ADDRESS  SlaveAddress,
+  IN        EFI_I2C_ADDR_MODE       AddrMode,
+  IN UINTN                          *Length,
+  IN OUT    VOID                    *Buffer
+  )
+{
+  EFI_STATUS Status;
+  UINTN      I2CAddress;
+  UINT16     SaveCmd;
+  UINT32     SaveBar0;
+
+    if (Buffer == NULL || Length == NULL) {
+    return EFI_INVALID_PARAMETER;
+  }
+  SaveCmd = 0;
+  SaveBar0 =0;
+
+  I2cCommonServiceEntry (&SaveCmd, &SaveBar0);
+  Status = EFI_SUCCESS;
+
+  I2CAddress = SlaveAddress.I2CDeviceAddress;
+
+  Status = InitializeInternal (AddrMode);
+  if (!EFI_ERROR(Status)) {
+    Status = WriteMultipleByte (I2CAddress, Buffer, (*Length));
+  }
+
+  I2cCommonServiceExit (SaveCmd, SaveBar0);
+  return Status;
+}
+
+/**
+
+  The I2cReadMultipleByte() function is a wrapper function for the ReadMultipleByte() function.
+  Provides a standard way to execute multiple byte writes to an I2C device
+  (e.g. when accessing sub-addresses or when reading block of data), as defined
+  in the I2C Specification (I2C combined write/read protocol).
+
+  @param SlaveAddress The I2C slave address of the device
+                      with which to communicate.
+
+  @param AddrMode     I2C Addressing Mode: 7-bit or 10-bit address.
+
+  @param WriteLength  No. of bytes to be written. In this case data
+                      written typically contains sub-address or sub-addresses
+                      in Hi-Lo format, that need to be read (I2C combined
+                      write/read protocol).
+
+  @param ReadLength   No. of bytes to be read from I2C slave device.
+
+  @param Buffer       Contains the value of byte data read from the
+                      I2C slave device.
+
+  @retval EFI_SUCCESS            Transfer success.
+  @retval EFI_INVALID_PARAMETER  This, WriteLength, ReadLength or Buffer
+                                 pointers are invalid.
+  @retval EFI_UNSUPPORTED        Unsupported input param.
+  @retval EFI_TIMEOUT            Timeout while waiting xfer.
+  @retval EFI_ABORTED            Controller aborted xfer.
+  @retval EFI_DEVICE_ERROR       Device error detected by controller.
+
+**/
+EFI_STATUS
+EFIAPI
+I2cReadMultipleByte (
+  IN        EFI_I2C_DEVICE_ADDRESS  SlaveAddress,
+  IN        EFI_I2C_ADDR_MODE       AddrMode,
+  IN UINTN                          *WriteLength,
+  IN UINTN                          *ReadLength,
+  IN OUT    VOID                    *Buffer
+  )
+{
+  EFI_STATUS        Status;
+  UINTN             I2CAddress;
+  UINT16            SaveCmd;
+  UINT32            SaveBar0;
+
+  if (Buffer == NULL || WriteLength == NULL || ReadLength == NULL) {
+    return EFI_INVALID_PARAMETER;
+  }
+  SaveCmd = 0;
+  SaveBar0 =0;
+
+  I2cCommonServiceEntry (&SaveCmd, &SaveBar0);
+
+  Status = EFI_SUCCESS;
+
+  I2CAddress = SlaveAddress.I2CDeviceAddress;
+  Status = InitializeInternal (AddrMode);
+  if (!EFI_ERROR(Status)) {
+    Status = ReadMultipleByte (I2CAddress, Buffer, (*WriteLength), (*ReadLength));
+  }
+  I2cCommonServiceExit (SaveCmd, SaveBar0);
+  return Status;
+}
+
+static void i2c_init(void *chip_info)
+{
+}
+
+static void pci_domain_set_resources(device_t dev)
+{
+	assign_resources(dev->link_list);
+}
+
+static struct device_operations pci_domain_ops = {
+	.read_resources	= pci_domain_read_resources,
+	.set_resources	= pci_domain_set_resources,
+	.scan_bus	= pci_domain_scan_bus,
+	.ops_pci_bus	= pci_bus_default_ops,
+};
+
+static void chip_enable_dev(device_t dev)
+{
+	const char *type_name = dev_path_name(dev->path.type);
+
+	/* Set the operations if it is a special bus type */
+	printk(BIOS_DEBUG, "type: %s\n", type_name);
+	if (dev->path.type == DEVICE_PATH_DOMAIN)
+		dev->ops = &pci_domain_ops;
+}
+
+struct chip_operations soc_intel_quark_ops = {
+	CHIP_NAME("Intel Quark")
+	.init		= &chip_init,
+	.enable_dev	= chip_enable_dev,
+};
+
+static void pci_set_subsystem(device_t dev, unsigned vendor, unsigned device)
+{
+	if (!vendor || !device) {
+		vendor = pci_read_config32(dev, PCI_VENDOR_ID);
+		device = vendor >> 16;
+	}
+	printk(BIOS_SPEW,
+		"PCI: %02x:%02x:%d subsystem vendor: 0x%04x, device: 0x%04x\n",
+		0, PCI_SLOT(dev->path.pci.devfn), PCI_FUNC(dev->path.pci.devfn),
+		vendor & 0xffff, device);
+	pci_write_config32(dev, PCI_SUBSYSTEM_VENDOR_ID,
+			((device & 0xffff) << 16) | (vendor & 0xffff));
+}
+
+struct pci_operations chip_pci_ops = {
+	.set_subsystem = &pci_set_subsystem,
+};
+
+void soc_silicon_init_params(SILICON_INIT_UPD *upd)
+{
+}
+
+void soc_display_silicon_init_params(const SILICON_INIT_UPD *old,
+	SILICON_INIT_UPD *new)
+{
+}
diff --git a/src/soc/intel/quark/include/soc/pci_devs.h b/src/soc/intel/quark/include/soc/pci_devs.h
index 9d4e116..ba433e2 100644
--- a/src/soc/intel/quark/include/soc/pci_devs.h
+++ b/src/soc/intel/quark/include/soc/pci_devs.h
@@ -18,9 +18,8 @@
 #ifndef _QUARK_PCI_DEVS_H_
 #define _QUARK_PCI_DEVS_H_
 
-#include <arch/io.h>
 #include <device/pci.h>
-#include <soc/QuarkNcSocId.h>
+#include <soc/reg_access.h>
 
 /* DEVICE 0 (Memroy Controller Hub) */
 #define MC_BDF		PCI_DEV(PCI_BUS_NUMBER_QNC, MC_DEV, MC_FUN)
@@ -29,6 +28,8 @@
 #define I2CGPIO_DEVID		0x0934
 #define HSUART_DEVID		0x0936
 #define EHCI_DEVID		0x0939
+#define PCIE_PORT0_DEVID	0x11c3
+#define PCIE_PORT1_DEVID	0x11c4
 
 /* IO Fabric 1 */
 #define SIO1_DEV		0x14
diff --git a/src/soc/intel/quark/include/soc/ramstage.h b/src/soc/intel/quark/include/soc/ramstage.h
index abfb827..0ac49ef 100644
--- a/src/soc/intel/quark/include/soc/ramstage.h
+++ b/src/soc/intel/quark/include/soc/ramstage.h
@@ -20,9 +20,12 @@
 #include <chip.h>
 #include <device/device.h>
 #include <fsp/ramstage.h>
-#include <soc/QuarkNcSocId.h>
+#include <soc/reg_access.h>
 
 void mainboard_gpio_i2c_init(device_t dev);
 extern struct pci_operations chip_pci_ops;
 
+extern void mainboard_gpio_i2c_init(device_t dev);
+extern const struct reg_script pcie_init_script[];
+
 #endif /* _SOC_RAMSTAGE_H_ */
diff --git a/src/soc/intel/quark/include/soc/reg_access.h b/src/soc/intel/quark/include/soc/reg_access.h
index 66ab7b8..580400c 100644
--- a/src/soc/intel/quark/include/soc/reg_access.h
+++ b/src/soc/intel/quark/include/soc/reg_access.h
@@ -16,6 +16,9 @@
 #ifndef _QUARK_REG_ACCESS_H_
 #define _QUARK_REG_ACCESS_H_
 
+#define __SIMPLE_DEVICE__
+
+#include <arch/io.h>
 #include <delay.h>
 #include <fsp/util.h>
 #include <reg_script.h>
@@ -30,6 +33,8 @@ enum {
 	MICROSECOND_DELAY,
 	LEG_GPIO_REGS,
 	GPIO_REGS,
+	PCIE_AFE_REGS,
+	PCIE_RESET,
 };
 
 enum {
@@ -83,6 +88,31 @@ enum {
 #define REG_LEG_GPIO_XOR(reg_, value_) \
 	REG_LEG_GPIO_RXW(reg_, 0xffffffff, value_)
 
+/* PCIE AFE register access macros */
+#define REG_PCIE_AFE_ACCESS(cmd_, reg_, mask_, value_, timeout_) \
+	SOC_ACCESS(cmd_, reg_, REG_SCRIPT_SIZE_32, mask_, value_, timeout_, \
+		PCIE_AFE_REGS)
+#define REG_PCIE_AFE_READ(reg_) \
+	REG_PCIE_AFE_ACCESS(READ, reg_, 0, 0, 0)
+#define REG_PCIE_AFE_WRITE(reg_, value_) \
+	REG_PCIE_AFE_ACCESS(WRITE, reg_, 0, value_, 0)
+#define REG_PCIE_AFE_AND(reg_, value_) \
+	REG_PCIE_AFE_RMW(reg_, value_, 0)
+#define REG_PCIE_AFE_RMW(reg_, mask_, value_) \
+	REG_PCIE_AFE_ACCESS(RMW, reg_, mask_, value_, 0)
+#define REG_PCIE_AFE_RXW(reg_, mask_, value_) \
+	REG_PCIE_AFE_ACCESS(RXW, reg_, mask_, value_, 0)
+#define REG_PCIE_AFE_OR(reg_, value_) \
+	REG_PCIE_AFE_RMW(reg_, 0xffffffff, value_)
+#define REG_PCIE_AFE_POLL(reg_, mask_, value_, timeout_) \
+	REG_PCIE_AFE_ACCESS(POLL, reg_, mask_, value_, timeout_)
+#define REG_PCIE_AFE_XOR(reg_, value_) \
+	REG_PCIE_AFE_RXW(reg_, 0xffffffff, value_)
+
+/* PCIe reset */
+#define MAINBOARD_PCIE_RESET(pin_value_) \
+	SOC_ACCESS(WRITE, 0, REG_SCRIPT_SIZE_32, 1, pin_value_, 0, PCIE_RESET)
+
 /* RMU temperature register access macros */
 #define REG_RMU_TEMP_ACCESS(cmd_, reg_, mask_, value_, timeout_) \
 	SOC_ACCESS(cmd_, reg_, REG_SCRIPT_SIZE_32, mask_, value_, timeout_, \
@@ -152,6 +182,7 @@ enum {
 
 void *get_i2c_address(void);
 void mainboard_gpio_init(void);
+void mainboard_gpio_pcie_reset(uint32_t pin_value);
 void mcr_write(uint8_t opcode, uint8_t port, uint32_t reg_address);
 uint32_t mdr_read(void);
 void mdr_write(uint32_t value);
diff --git a/src/soc/intel/quark/pci.c b/src/soc/intel/quark/pci.c
new file mode 100644
index 0000000..86c64db
--- /dev/null
+++ b/src/soc/intel/quark/pci.c
@@ -0,0 +1,131 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright (C) 2016 Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <console/console.h>
+#include <delay.h>
+#include <device/device.h>
+#include <device/i2c.h>
+#include <device/pci_ids.h>
+#include <soc/i2c.h>
+#include <soc/ramstage.h>
+#include <soc/reg_access.h>
+
+/* Minimum time in microseconds for assertion of PERST# signal */
+#define PCIEXP_PERST_MIN_ASSERT_US		100
+
+/* Microsecond delay post issuing common lane reset */
+#define PCIEXP_DELAY_US_POST_CMNRESET_RESET	1
+
+/* Microsecond delay to wait for PLL to lock */
+#define PCIEXP_DELAY_US_WAIT_PLL_LOCK		80
+
+/* Microsecond delay post issuing sideband interface reset */
+#define PCIEXP_DELAY_US_POST_SBI_RESET		20
+
+/* Microsecond delay post deasserting PERST# */
+#define PCIEXP_DELAY_US_POST_PERST_DEASSERT	10
+
+const struct reg_script pcie_init_script[] = {
+	REG_SCRIPT_DISPLAY_ON,
+
+	/* Assert PCIe reset# */
+	MAINBOARD_PCIE_RESET(0),
+
+	/* PHY Common lane reset */
+	REG_SOC_UNIT_OR(QUARK_SCSS_SOC_UNIT_SOCCLKEN_CONFIG,
+		SOCCLKEN_CONFIG_PHY_I_CMNRESET_L),
+
+	/* Wait post common lane reset */
+	TIME_DELAY_USEC(PCIEXP_DELAY_US_POST_CMNRESET_RESET),
+
+	/* PHY Sideband interface reset.
+	 * Controller main reset
+	 */
+	REG_SOC_UNIT_OR(QUARK_SCSS_SOC_UNIT_SOCCLKEN_CONFIG,
+		SOCCLKEN_CONFIG_SBI_RST_100_CORE_B
+		| SOCCLKEN_CONFIG_PHY_I_SIDE_RST_L),
+	TIME_DELAY_USEC(PCIEXP_DELAY_US_WAIT_PLL_LOCK),
+
+	/* Controller sideband interface reset */
+	REG_SOC_UNIT_OR(QUARK_SCSS_SOC_UNIT_SOCCLKEN_CONFIG,
+		SOCCLKEN_CONFIG_SBI_BB_RST_B),
+
+	/* Wait post sideband interface reset */
+	TIME_DELAY_USEC(PCIEXP_DELAY_US_POST_SBI_RESET),
+
+	/* Deassert PCIe reset# */
+	MAINBOARD_PCIE_RESET(1),
+
+	/* Wait post de assert PERST#. */
+	TIME_DELAY_USEC(PCIEXP_DELAY_US_POST_PERST_DEASSERT),
+
+	/* Controller primary interface reset */
+	REG_SOC_UNIT_OR(QUARK_SCSS_SOC_UNIT_SOCCLKEN_CONFIG,
+		SOCCLKEN_CONFIG_BB_RST_B),
+
+	/* Set the mixer load resistance */
+	REG_PCIE_AFE_AND(QUARK_PCIE_AFE_PCIE_RXPICTRL0_L0,
+		OCFGPIMIXLOAD_1_0_MASK),
+	REG_PCIE_AFE_AND(QUARK_PCIE_AFE_PCIE_RXPICTRL0_L1,
+		OCFGPIMIXLOAD_1_0_MASK),
+	REG_SCRIPT_END
+};
+
+static const struct reg_script pcie_bus_init_script[] = {
+	REG_SCRIPT_DISPLAY_ON,
+	/* North cluster early PCIe init */
+
+	/* Setup Message Bus Idle Counter (SBIC) values */
+	REG_PCI_RMW8(R_QNC_PCIE_IOSFSBCTL, ~B_QNC_PCIE_IOSFSBCTL_SBIC_MASK,
+		V_PCIE_ROOT_PORT_SBIC_VALUE),
+	REG_PCI_READ8(R_QNC_PCIE_IOSFSBCTL),
+
+	/* Set the IPF bit in MCR2 */
+	REG_PCI_OR32(R_QNC_PCIE_MPC2, B_QNC_PCIE_MPC2_IPF),
+	REG_PCI_READ32(R_QNC_PCIE_MPC2),
+
+	/* Set up the Posted and Non Posted Request sizes for PCIe */
+	REG_PCI_RMW32(R_QNC_PCIE_CCFG, ~B_QNC_PCIE_CCFG_UPSD,
+		(B_QNC_PCIE_CCFG_UNRS | B_QNC_PCIE_CCFG_UPRS)),
+	REG_PCI_READ32(R_QNC_PCIE_CCFG),
+	REG_SCRIPT_END
+};
+
+static void read_resources(device_t dev)
+{
+printk(BIOS_INFO, "Running PCIe bus init script\n");
+	ASSERT (PCIEXP_PERST_MIN_ASSERT_US
+		<= (PCIEXP_DELAY_US_POST_CMNRESET_RESET
+			+ PCIEXP_DELAY_US_WAIT_PLL_LOCK
+			+ PCIEXP_DELAY_US_POST_SBI_RESET));
+	reg_script_run_on_dev(dev, pcie_bus_init_script);
+	pci_dev_read_resources(dev);
+}
+
+static struct device_operations device_ops = {
+	.read_resources		= read_resources,
+	.set_resources		= pci_dev_set_resources,
+	.enable_resources	= pci_dev_enable_resources,
+};
+
+static const unsigned short device_ids[] = {
+	PCIE_PORT0_DEVID, PCIE_PORT1_DEVID, 0
+};
+
+static const struct pci_driver gfx_driver __pci_driver = {
+	.ops     = &device_ops,
+	.vendor  = PCI_VENDOR_ID_INTEL,
+	.devices = device_ids,
+};
diff --git a/src/soc/intel/quark/reg_access.c b/src/soc/intel/quark/reg_access.c
index 4734135..f7820e9 100644
--- a/src/soc/intel/quark/reg_access.c
+++ b/src/soc/intel/quark/reg_access.c
@@ -15,10 +15,9 @@
 
 #define __SIMPLE_DEVICE__
 
-#include <arch/io.h>
 #include <console/console.h>
 #include <soc/pci_devs.h>
-#include <soc/reg_access.h>
+#include <soc/ramstage.h>
 
 static uint32_t *get_gpio_address(uint32_t reg_address)
 {
@@ -108,6 +107,24 @@ void reg_legacy_gpio_write(uint32_t reg_address, uint32_t value)
 	outl(value, get_legacy_gpio_address(reg_address));
 }
 
+static uint32_t reg_pcie_afe_read(uint32_t reg_address)
+{
+	/* Read the PCIE AFE register */
+	mea_write(reg_address);
+	mcr_write(QUARK_OPCODE_IO_READ, QUARK_SC_PCIE_AFE_SB_PORT_ID,
+		reg_address);
+	return mdr_read();
+}
+
+static void reg_pcie_afe_write(uint32_t reg_address, uint32_t value)
+{
+	/* Write the PCIE AFE register */
+	mea_write(reg_address);
+	mdr_write(value);
+	mcr_write(QUARK_OPCODE_IO_WRITE, QUARK_SC_PCIE_AFE_SB_PORT_ID,
+		reg_address);
+}
+
 uint32_t reg_rmu_temp_read(uint32_t reg_address)
 {
 	/* Read the RMU temperature register */
@@ -181,6 +198,10 @@ static uint64_t reg_read(struct reg_script_context *ctx)
 	case LEG_GPIO_REGS:
 		ctx->display_prefix = "Legacy GPIO: ";
 		value = reg_legacy_gpio_read(step->reg);
+
+	case PCIE_AFE_REGS:
+		ctx->display_prefix = "PCIe AFE: ";
+		value = reg_pcie_afe_read(step->reg);
 		break;
 
 	case RMU_TEMP_REGS:
@@ -223,6 +244,19 @@ static void reg_write(struct reg_script_context *ctx)
 		reg_legacy_gpio_write(step->reg, (uint32_t)step->value);
 		break;
 
+	case PCIE_AFE_REGS:
+		ctx->display_prefix = "PCIe AFE: ";
+		reg_pcie_afe_write(step->reg, (uint32_t)step->value);
+		break;
+
+	case PCIE_RESET:
+		if (ctx->display_features) {
+			ctx->display_prefix = "PCIe reset: ";
+			ctx->display_features &= ~REG_SCRIPT_DISPLAY_REGISTER;
+		}
+		mainboard_gpio_pcie_reset(step->value);
+		break;
+
 	case RMU_TEMP_REGS:
 		ctx->display_prefix = "RMU TEMP";
 		reg_rmu_temp_write(step->reg, (uint32_t)step->value);
diff --git a/src/soc/intel/quark/romstage/romstage.c b/src/soc/intel/quark/romstage/romstage.c
index f876d3e..7291d97 100644
--- a/src/soc/intel/quark/romstage/romstage.c
+++ b/src/soc/intel/quark/romstage/romstage.c
@@ -115,6 +115,7 @@ void soc_memory_init_params(struct romstage_params *params,
 	}
 	config = dev->chip_info;
 
+legacy_gpio_pin_value(0, 0);
 	/* Display the ROM shadow data */
 	hexdump((void *)0x000ffff0, 0x10);
 }
@@ -138,6 +139,7 @@ void soc_after_ram_init(struct romstage_params *params)
 
 	/* Display the DRAM data */
 	hexdump((void *)0x000ffff0, 0x10);
+legacy_gpio_pin_value(0, 0);
 }
 
 void soc_display_memory_init_params(const MEMORY_INIT_UPD *old,
diff --git a/src/soc/intel/quark/romstage/uart.c b/src/soc/intel/quark/romstage/uart.c
index 2d53a48..9e8f6c5 100644
--- a/src/soc/intel/quark/romstage/uart.c
+++ b/src/soc/intel/quark/romstage/uart.c
@@ -28,15 +28,15 @@ int set_base_address_and_enable_uart(u8 bus, u8 dev, u8 func, u32 mmio_base)
 	uint16_t reg16;
 
 	/* HSUART controller #1 (B0:D20:F5). */
-	device_t uart_dev = PCI_DEV(bus, dev, func);
+	pci_devfn_t uart_bdf = PCI_DEV(bus, dev, func);
 
 	/* Decode BAR0(offset 0x10). */
-	pci_write_config32(uart_dev, PCI_BASE_ADDRESS_0, mmio_base);
+	pci_write_config32(uart_bdf, PCI_BASE_ADDRESS_0, mmio_base);
 
 	/* Enable MEMBASE at CMD(offset 0x04). */
-	reg16 = pci_read_config16(uart_dev, PCI_COMMAND);
+	reg16 = pci_read_config16(uart_bdf, PCI_COMMAND);
 	reg16 |= PCI_COMMAND_MEMORY;
-	pci_write_config16(uart_dev, PCI_COMMAND, reg16);
+	pci_write_config16(uart_bdf, PCI_COMMAND, reg16);
 
 	return 0;
 }



More information about the coreboot-gerrit mailing list