From ec78595a24b5ff1020baa97b6d6e79a3a3326307 Mon Sep 17 00:00:00 2001 From: Richard Zhu Date: Tue, 15 Jul 2014 14:19:03 +0800 Subject: ENGR00325255 pcie:enable pcie support on imx6sx sd Enable pcie support in uboot on imx6sx sd boards - enable_pcie_clock should be call before ssp_en is set, since that ssp_en control the phy_ref clk gate, turn on it after the source of the pcie clks are stable. - add debug info - add rx_eq of gpr12 on imx6sx - there are random link down issue on imx6sx. It's pcie ep reset issue. solution:reset ep, then retry link can fix it. Signed-off-by: Richard Zhu --- drivers/pci/pcie_imx.c | 139 ++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 132 insertions(+), 7 deletions(-) (limited to 'drivers/pci') diff --git a/drivers/pci/pcie_imx.c b/drivers/pci/pcie_imx.c index c48737e..0b5b886 100644 --- a/drivers/pci/pcie_imx.c +++ b/drivers/pci/pcie_imx.c @@ -23,13 +23,20 @@ #define PCI_ACCESS_READ 0 #define PCI_ACCESS_WRITE 1 +#ifdef CONFIG_MX6SX +#define MX6_DBI_ADDR 0x08ffc000 +#define MX6_IO_ADDR 0x08000000 +#define MX6_MEM_ADDR 0x08100000 +#define MX6_ROOT_ADDR 0x08f00000 +#else #define MX6_DBI_ADDR 0x01ffc000 -#define MX6_DBI_SIZE 0x4000 #define MX6_IO_ADDR 0x01000000 -#define MX6_IO_SIZE 0x100000 #define MX6_MEM_ADDR 0x01100000 -#define MX6_MEM_SIZE 0xe00000 #define MX6_ROOT_ADDR 0x01f00000 +#endif +#define MX6_DBI_SIZE 0x4000 +#define MX6_IO_SIZE 0x100000 +#define MX6_MEM_SIZE 0xe00000 #define MX6_ROOT_SIZE 0xfc000 /* PCIe Port Logic registers (memory-mapped) */ @@ -80,6 +87,46 @@ #define PCIE_ATU_FUNC(x) (((x) & 0x7) << 16) #define PCIE_ATU_UPPER_TARGET 0x91C +#ifdef DEBUG + +#ifdef DEBUG_STRESS_WR /* warm-reset stress tests */ +#define SNVS_LPGRP 0x020cc068 +#endif + +#define DBGF(x...) printf(x) + +static void print_regs(int contain_pcie_reg) +{ + u32 val; +#ifndef CONFIG_MX6SX + struct iomuxc *iomuxc_regs = (struct iomuxc *)IOMUXC_BASE_ADDR; +#else + struct iomuxc *iomuxc_regs = (struct iomuxc *)IOMUXC_GPR_BASE_ADDR; +#endif + val = readl(&iomuxc_regs->gpr[1]); + DBGF("GPR01 a:0x%08x v:0x%08x\n", (u32)&iomuxc_regs->gpr[1], val); + val = readl(&iomuxc_regs->gpr[5]); + DBGF("GPR05 a:0x%08x v:0x%08x\n", (u32)&iomuxc_regs->gpr[5], val); + val = readl(&iomuxc_regs->gpr[8]); + DBGF("GPR08 a:0x%08x v:0x%08x\n", (u32)&iomuxc_regs->gpr[8], val); + val = readl(&iomuxc_regs->gpr[12]); + DBGF("GPR12 a:0x%08x v:0x%08x\n", (u32)&iomuxc_regs->gpr[12], val); + val = readl(ANATOP_BASE_ADDR + 0xe0); + DBGF("PLL06 a:0x%08x v:0x%08x\n", ANATOP_BASE_ADDR + 0xe0, val); + val = readl(ANATOP_BASE_ADDR + 0x160); + DBGF("MISC1 a:0x%08x v:0x%08x\n", ANATOP_BASE_ADDR + 0x160, val); + if (contain_pcie_reg) { + val = readl(MX6_DBI_ADDR + 0x728); + DBGF("dbr0 offset 0x728 %08x\n", val); + val = readl(MX6_DBI_ADDR + 0x72c); + DBGF("dbr1 offset 0x72c %08x\n", val); + } +} +#else +#define DBGF(x...) +static void print_regs(int contain_pcie_reg) {} +#endif + /* * PHY access functions */ @@ -420,19 +467,43 @@ static int imx_pcie_write_config(struct pci_controller *hose, pci_dev_t d, */ static int imx6_pcie_assert_core_reset(void) { +#ifndef CONFIG_MX6SX struct iomuxc *iomuxc_regs = (struct iomuxc *)IOMUXC_BASE_ADDR; +#else + u32 val; + struct iomuxc *iomuxc_regs = (struct iomuxc *)IOMUXC_GPR_BASE_ADDR; +#endif +#if defined(CONFIG_MX6SX) + /* SSP_EN is not used on iMX6SX anymore */ + setbits_le32(&iomuxc_regs->gpr[12], IOMUXC_GPR12_TEST_POWERDOWN); + /* Force PCIe PHY reset */ + setbits_le32(&iomuxc_regs->gpr[5], IOMUXC_GPR5_PCIE_BTNRST); + + /* Power up PCIe PHY, ANATOP_REG_CORE offset 0x140, bit13-9 */ + val = readl(GPC_BASE_ADDR + 0); + val |= (0x1 << 7); + writel(val, GPC_BASE_ADDR + 0); + pcie_power_up(); +#else setbits_le32(&iomuxc_regs->gpr[1], IOMUXC_GPR1_TEST_POWERDOWN); clrbits_le32(&iomuxc_regs->gpr[1], IOMUXC_GPR1_REF_SSP_EN); +#endif return 0; } static int imx6_pcie_init_phy(void) { +#ifndef CONFIG_MX6SX struct iomuxc *iomuxc_regs = (struct iomuxc *)IOMUXC_BASE_ADDR; +#else + struct iomuxc *iomuxc_regs = (struct iomuxc *)IOMUXC_GPR_BASE_ADDR; +#endif +#ifndef DEBUG clrbits_le32(&iomuxc_regs->gpr[12], IOMUXC_GPR12_APPS_LTSSM_ENABLE); +#endif clrsetbits_le32(&iomuxc_regs->gpr[12], IOMUXC_GPR12_DEVICE_TYPE_MASK, @@ -440,6 +511,11 @@ static int imx6_pcie_init_phy(void) clrsetbits_le32(&iomuxc_regs->gpr[12], IOMUXC_GPR12_LOS_LEVEL_MASK, IOMUXC_GPR12_LOS_LEVEL_9); +#ifdef CONFIG_MX6SX + clrsetbits_le32(&iomuxc_regs->gpr[12], + IOMUXC_GPR12_RX_EQ_MASK, + IOMUXC_GPR12_RX_EQ_2); +#endif writel((0x0 << IOMUXC_GPR8_PCS_TX_DEEMPH_GEN1_OFFSET) | (0x0 << IOMUXC_GPR8_PCS_TX_DEEMPH_GEN2_3P5DB_OFFSET) | @@ -505,21 +581,38 @@ __weak int imx6_pcie_toggle_reset(void) static int imx6_pcie_deassert_core_reset(void) { +#ifndef CONFIG_MX6SX struct iomuxc *iomuxc_regs = (struct iomuxc *)IOMUXC_BASE_ADDR; +#else + struct iomuxc *iomuxc_regs = (struct iomuxc *)IOMUXC_GPR_BASE_ADDR; +#endif imx6_pcie_toggle_power(); + enable_pcie_clock(); + /* Enable PCIe */ +#if defined(CONFIG_MX6SX) + /* SSP_EN is not used on iMX6SX anymore */ + clrbits_le32(&iomuxc_regs->gpr[12], IOMUXC_GPR12_TEST_POWERDOWN); + /* + * iMX6SX PCIe has the stand-alone power domain. + * refer to the initialization for iMX6SX PCIe, + * release the PCIe PHY reset here, + * before LTSSM enable is set + * . + */ + clrbits_le32(&iomuxc_regs->gpr[5], IOMUXC_GPR5_PCIE_BTNRST); +#else clrbits_le32(&iomuxc_regs->gpr[1], IOMUXC_GPR1_TEST_POWERDOWN); setbits_le32(&iomuxc_regs->gpr[1], IOMUXC_GPR1_REF_SSP_EN); - enable_pcie_clock(); - /* * Wait for the clock to settle a bit, when the clock are sourced * from the CPU, we need about 30mS to settle. */ mdelay(50); +#endif imx6_pcie_toggle_reset(); @@ -528,7 +621,11 @@ static int imx6_pcie_deassert_core_reset(void) static int imx_pcie_link_up(void) { +#ifndef CONFIG_MX6SX struct iomuxc *iomuxc_regs = (struct iomuxc *)IOMUXC_BASE_ADDR; +#else + struct iomuxc *iomuxc_regs = (struct iomuxc *)IOMUXC_GPR_BASE_ADDR; +#endif uint32_t tmp; int count = 0; @@ -555,9 +652,25 @@ static int imx_pcie_link_up(void) while (!imx6_pcie_link_up()) { udelay(10); count++; + if (count == 1000) { + print_regs(1); + /* link down, try reset ep, and re-try link here */ + DBGF("pcie link is down, reset ep, then retry!\n"); + imx6_pcie_toggle_reset(); + continue; + } +#ifdef DEBUG + else if (count >= 2000) { + print_regs(1); + /* link is down, stop here */ + setenv("bootcmd", "sleep 2;"); + DBGF("pcie link is down, stop here!\n"); + return -EINVAL; + } +#endif if (count >= 2000) { - debug("phy link never came up\n"); - debug("DEBUG_R0: 0x%08x, DEBUG_R1: 0x%08x\n", + printf("phy link never came up\n"); + printf("DEBUG_R0: 0x%08x, DEBUG_R1: 0x%08x\n", readl(MX6_DBI_ADDR + PCIE_PHY_DEBUG_R0), readl(MX6_DBI_ADDR + PCIE_PHY_DEBUG_R1)); return -EINVAL; @@ -573,6 +686,10 @@ void imx_pcie_init(void) static struct pci_controller pcc; struct pci_controller *hose = &pcc; int ret; +#ifdef DEBUG_STRESS_WR + u32 dbg_reg_addr = SNVS_LPGRP; + u32 dbg_reg = readl(dbg_reg_addr) + 1; +#endif memset(&pcc, 0, sizeof(pcc)); @@ -607,7 +724,15 @@ void imx_pcie_init(void) if (!ret) { pci_register_hose(hose); hose->last_busno = pci_hose_scan(hose); +#ifdef DEBUG_STRESS_WR + dbg_reg += 1<<16; +#endif } +#ifdef DEBUG_STRESS_WR + writel(dbg_reg, dbg_reg_addr); + DBGF("PCIe Successes/Attempts: %d/%d\n", + dbg_reg >> 16, dbg_reg & 0xffff); +#endif } /* Probe function. */ -- cgit v1.1