x86: Enable PCIe controller on quark/galileo
authorBin Meng <bmeng.cn@gmail.com>
Thu, 3 Sep 2015 12:37:25 +0000 (05:37 -0700)
committerSimon Glass <sjg@chromium.org>
Wed, 9 Sep 2015 13:48:03 +0000 (07:48 -0600)
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@gmail.com>
Acked-by: Simon Glass <sjg@chromium.org>
arch/x86/cpu/quark/quark.c
arch/x86/include/asm/arch-quark/quark.h
board/intel/galileo/galileo.c

index 2688a70..7c55d9e 100644 (file)
@@ -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();
 
index 1ce5693..aad7fbe 100644 (file)
@@ -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 */
 #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_ */
index 746ab27..c1087ac 100644 (file)
@@ -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;