[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