[U-Boot] [PATCH v4 03/11] x86: Enable PCIe controller on quark/galileo

Bin Meng bmeng.cn at gmail.com
Thu Sep 3 14:37:25 CEST 2015


Quark SoC holds the PCIe controller in reset following a power on.
U-Boot needs to release the PCIe controller from reset. The PCIe
controller (D23:F0/F1) will not be visible in PCI configuration
space and any access to its PCI configuration registers will cause
system hang while it is held in reset.

Enable PCIe controller per Quark firmware writer guide.

Signed-off-by: Bin Meng <bmeng.cn at gmail.com>
Acked-by: Simon Glass <sjg at chromium.org>

---

Changes in v4: None
Changes in v3: None
Changes in v2:
- New patch to enable PCIe controller on quark/galileo

 arch/x86/cpu/quark/quark.c              | 63 +++++++++++++++++++++++++++++++++
 arch/x86/include/asm/arch-quark/quark.h | 42 ++++++++++++++++++++++
 board/intel/galileo/galileo.c           | 56 +++++++++++++++++++++++++++++
 3 files changed, 161 insertions(+)

diff --git a/arch/x86/cpu/quark/quark.c b/arch/x86/cpu/quark/quark.c
index 2688a70..7c55d9e 100644
--- a/arch/x86/cpu/quark/quark.c
+++ b/arch/x86/cpu/quark/quark.c
@@ -73,6 +73,58 @@ static void quark_setup_bars(void)
 		       CONFIG_PCIE_ECAM_BASE | MEM_BAR_EN);
 }
 
+static void quark_pcie_early_init(void)
+{
+	u32 pcie_cfg;
+
+	/*
+	 * Step1: Assert PCIe signal PERST#
+	 *
+	 * The CPU interface to the PERST# signal is platform dependent.
+	 * Call the board-specific codes to perform this task.
+	 */
+	board_assert_perst();
+
+	/* Step2: PHY common lane reset */
+	pcie_cfg = msg_port_alt_read(MSG_PORT_SOC_UNIT, PCIE_CFG);
+	pcie_cfg |= PCIE_PHY_LANE_RST;
+	msg_port_alt_write(MSG_PORT_SOC_UNIT, PCIE_CFG, pcie_cfg);
+	/* wait 1 ms for PHY common lane reset */
+	mdelay(1);
+
+	/* Step3: PHY sideband interface reset and controller main reset */
+	pcie_cfg = msg_port_alt_read(MSG_PORT_SOC_UNIT, PCIE_CFG);
+	pcie_cfg |= (PCIE_PHY_SB_RST | PCIE_CTLR_MAIN_RST);
+	msg_port_alt_write(MSG_PORT_SOC_UNIT, PCIE_CFG, pcie_cfg);
+	/* wait 80ms for PLL to lock */
+	mdelay(80);
+
+	/* Step4: Controller sideband interface reset */
+	pcie_cfg = msg_port_alt_read(MSG_PORT_SOC_UNIT, PCIE_CFG);
+	pcie_cfg |= PCIE_CTLR_SB_RST;
+	msg_port_alt_write(MSG_PORT_SOC_UNIT, PCIE_CFG, pcie_cfg);
+	/* wait 20ms for controller sideband interface reset */
+	mdelay(20);
+
+	/* Step5: De-assert PERST# */
+	board_deassert_perst();
+
+	/* Step6: Controller primary interface reset */
+	pcie_cfg = msg_port_alt_read(MSG_PORT_SOC_UNIT, PCIE_CFG);
+	pcie_cfg |= PCIE_CTLR_PRI_RST;
+	msg_port_alt_write(MSG_PORT_SOC_UNIT, PCIE_CFG, pcie_cfg);
+
+	/* Mixer Load Lane 0 */
+	pcie_cfg = msg_port_io_read(MSG_PORT_PCIE_AFE, PCIE_RXPICTRL0_L0);
+	pcie_cfg &= ~((1 << 6) | (1 << 7));
+	msg_port_io_write(MSG_PORT_PCIE_AFE, PCIE_RXPICTRL0_L0, pcie_cfg);
+
+	/* Mixer Load Lane 1 */
+	pcie_cfg = msg_port_io_read(MSG_PORT_PCIE_AFE, PCIE_RXPICTRL0_L1);
+	pcie_cfg &= ~((1 << 6) | (1 << 7));
+	msg_port_io_write(MSG_PORT_PCIE_AFE, PCIE_RXPICTRL0_L1, pcie_cfg);
+}
+
 static void quark_enable_legacy_seg(void)
 {
 	u32 hmisc2;
@@ -106,6 +158,17 @@ int arch_cpu_init(void)
 	 */
 	quark_setup_bars();
 
+	/*
+	 * Initialize PCIe controller
+	 *
+	 * Quark SoC holds the PCIe controller in reset following a power on.
+	 * U-Boot needs to release the PCIe controller from reset. The PCIe
+	 * controller (D23:F0/F1) will not be visible in PCI configuration
+	 * space and any access to its PCI configuration registers will cause
+	 * system hang while it is held in reset.
+	 */
+	quark_pcie_early_init();
+
 	/* Turn on legacy segments (A/B/E/F) decode to system RAM */
 	quark_enable_legacy_seg();
 
diff --git a/arch/x86/include/asm/arch-quark/quark.h b/arch/x86/include/asm/arch-quark/quark.h
index 1ce5693..aad7fbe 100644
--- a/arch/x86/include/asm/arch-quark/quark.h
+++ b/arch/x86/include/asm/arch-quark/quark.h
@@ -12,6 +12,7 @@
 #define MSG_PORT_HOST_BRIDGE	0x03
 #define MSG_PORT_RMU		0x04
 #define MSG_PORT_MEM_MGR	0x05
+#define MSG_PORT_PCIE_AFE	0x16
 #define MSG_PORT_SOC_UNIT	0x31
 
 /* Port 0x00: Memory Arbiter Message Port Registers */
@@ -48,6 +49,21 @@
 #define ESRAM_BLK_CTRL		0x82
 #define ESRAM_BLOCK_MODE	0x10000000
 
+/* Port 0x16: PCIe AFE Unit Port Registers */
+
+#define PCIE_RXPICTRL0_L0	0x2080
+#define PCIE_RXPICTRL0_L1	0x2180
+
+/* Port 0x31: SoC Unit Port Registers */
+
+/* PCIe Controller Config */
+#define PCIE_CFG		0x36
+#define PCIE_CTLR_PRI_RST	0x00010000
+#define PCIE_PHY_SB_RST		0x00020000
+#define PCIE_CTLR_SB_RST	0x00040000
+#define PCIE_PHY_LANE_RST	0x00090000
+#define PCIE_CTLR_MAIN_RST	0x00100000
+
 /* DRAM */
 #define DRAM_BASE		0x00000000
 #define DRAM_MAX_SIZE		0x80000000
@@ -124,6 +140,32 @@ static inline void qrk_pci_write_config_dword(pci_dev_t dev, int offset,
 	outl(value, PCI_REG_DATA);
 }
 
+/**
+ * board_assert_perst() - Assert the PERST# pin
+ *
+ * The CPU interface to the PERST# signal on Quark is platform dependent.
+ * Board-specific codes need supply this routine to assert PCIe slot reset.
+ *
+ * The tricky part in this routine is that any APIs that may trigger PCI
+ * enumeration process are strictly forbidden, as any access to PCIe root
+ * port's configuration registers will cause system hang while it is held
+ * in reset.
+ */
+void board_assert_perst(void);
+
+/**
+ * board_deassert_perst() - De-assert the PERST# pin
+ *
+ * The CPU interface to the PERST# signal on Quark is platform dependent.
+ * Board-specific codes need supply this routine to de-assert PCIe slot reset.
+ *
+ * The tricky part in this routine is that any APIs that may trigger PCI
+ * enumeration process are strictly forbidden, as any access to PCIe root
+ * port's configuration registers will cause system hang while it is held
+ * in reset.
+ */
+void board_deassert_perst(void);
+
 #endif /* __ASSEMBLY__ */
 
 #endif /* _QUARK_H_ */
diff --git a/board/intel/galileo/galileo.c b/board/intel/galileo/galileo.c
index 746ab27..c1087ac 100644
--- a/board/intel/galileo/galileo.c
+++ b/board/intel/galileo/galileo.c
@@ -5,12 +5,68 @@
  */
 
 #include <common.h>
+#include <asm/io.h>
+#include <asm/arch/device.h>
+#include <asm/arch/gpio.h>
+#include <asm/arch/quark.h>
 
 int board_early_init_f(void)
 {
 	return 0;
 }
 
+/*
+ * Intel Galileo gen2 board uses GPIO Resume Well bank pin0 as the PERST# pin.
+ *
+ * We cannot use any public GPIO APIs in <asm-generic/gpio.h> to control this
+ * pin, as these APIs will eventually call into gpio_ich6_ofdata_to_platdata()
+ * in the Intel ICH6 GPIO driver where it calls PCI configuration space access
+ * APIs which will trigger PCI enumeration process.
+ *
+ * Check <asm/arch-quark/quark.h> for more details.
+ */
+void board_assert_perst(void)
+{
+	u32 base, port, val;
+
+	/* retrieve the GPIO IO base */
+	qrk_pci_read_config_dword(QUARK_LEGACY_BRIDGE, PCI_CFG_GPIOBASE, &base);
+	base = (base & 0xffff) & ~0x7f;
+
+	/* enable the pin */
+	port = base + 0x20;
+	val = inl(port);
+	val |= (1 << 0);
+	outl(val, port);
+
+	/* configure the pin as output */
+	port = base + 0x24;
+	val = inl(port);
+	val &= ~(1 << 0);
+	outl(val, port);
+
+	/* pull it down (assert) */
+	port = base + 0x28;
+	val = inl(port);
+	val &= ~(1 << 0);
+	outl(val, port);
+}
+
+void board_deassert_perst(void)
+{
+	u32 base, port, val;
+
+	/* retrieve the GPIO IO base */
+	qrk_pci_read_config_dword(QUARK_LEGACY_BRIDGE, PCI_CFG_GPIOBASE, &base);
+	base = (base & 0xffff) & ~0x7f;
+
+	/* pull it up (de-assert) */
+	port = base + 0x28;
+	val = inl(port);
+	val |= (1 << 0);
+	outl(val, port);
+}
+
 void setup_pch_gpios(u16 gpiobase, const struct pch_gpio_map *gpio)
 {
 	return;
-- 
1.8.2.1



More information about the U-Boot mailing list