X-Git-Url: https://git.sur5r.net/?a=blobdiff_plain;f=drivers%2Fpci%2Fpcie_imx.c;h=fcc4ab713923aec381fc97cf053e54f17101205d;hb=5b2c9a6ce3ce66796e8c375133da8340c7ab2adc;hp=1568f20c1a060bfd28e633088acc1644fa51b571;hpb=850f788709cef8f7d53d571aec3bfb73b14c5531;p=u-boot diff --git a/drivers/pci/pcie_imx.c b/drivers/pci/pcie_imx.c index 1568f20c1a..fcc4ab7139 100644 --- a/drivers/pci/pcie_imx.c +++ b/drivers/pci/pcie_imx.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0 /* * Freescale i.MX6 PCI Express Root-Complex driver * @@ -6,8 +7,6 @@ * Based on upstream Linux kernel driver: * pci-imx6.c: Sean Cross * pcie-designware.c: Jingoo Han - * - * SPDX-License-Identifier: GPL-2.0 */ #include @@ -19,6 +18,7 @@ #include #include #include +#include #define PCI_ACCESS_READ 0 #define PCI_ACCESS_WRITE 1 @@ -41,6 +41,9 @@ /* PCIe Port Logic registers (memory-mapped) */ #define PL_OFFSET 0x700 +#define PCIE_PL_PFLR (PL_OFFSET + 0x08) +#define PCIE_PL_PFLR_LINK_STATE_MASK (0x3f << 16) +#define PCIE_PL_PFLR_FORCE_LINK (1 << 15) #define PCIE_PHY_DEBUG_R0 (PL_OFFSET + 0x28) #define PCIE_PHY_DEBUG_R1 (PL_OFFSET + 0x2c) #define PCIE_PHY_DEBUG_R1_LINK_UP (1 << 4) @@ -380,7 +383,7 @@ static int imx_pcie_read_config(struct pci_controller *hose, pci_dev_t d, ret = imx_pcie_addr_valid(d); if (ret) { *val = 0xffffffff; - return ret; + return 0; } va_address = get_bus_address(d, where); @@ -427,9 +430,13 @@ static int imx_pcie_write_config(struct pci_controller *hose, pci_dev_t d, /* * Initial bus setup */ -static int imx6_pcie_assert_core_reset(void) +static int imx6_pcie_assert_core_reset(bool prepare_for_boot) { struct iomuxc *iomuxc_regs = (struct iomuxc *)IOMUXC_BASE_ADDR; + + if (is_mx6dqp()) + setbits_le32(&iomuxc_regs->gpr[1], IOMUXC_GPR1_PCIE_SW_RST); + #if defined(CONFIG_MX6SX) struct gpc *gpc_regs = (struct gpc *)GPC_BASE_ADDR; @@ -440,6 +447,36 @@ static int imx6_pcie_assert_core_reset(void) /* Power up PCIe PHY */ setbits_le32(&gpc_regs->cntr, PCIE_PHY_PUP_REQ); #else + /* + * If the bootloader already enabled the link we need some special + * handling to get the core back into a state where it is safe to + * touch it for configuration. As there is no dedicated reset signal + * wired up for MX6QDL, we need to manually force LTSSM into "detect" + * state before completely disabling LTSSM, which is a prerequisite + * for core configuration. + * + * If both LTSSM_ENABLE and REF_SSP_ENABLE are active we have a strong + * indication that the bootloader activated the link. + */ + if (is_mx6dq() && prepare_for_boot) { + u32 val, gpr1, gpr12; + + gpr1 = readl(&iomuxc_regs->gpr[1]); + gpr12 = readl(&iomuxc_regs->gpr[12]); + if ((gpr1 & IOMUXC_GPR1_PCIE_REF_CLK_EN) && + (gpr12 & IOMUXC_GPR12_PCIE_CTL_2)) { + val = readl(MX6_DBI_ADDR + PCIE_PL_PFLR); + val &= ~PCIE_PL_PFLR_LINK_STATE_MASK; + val |= PCIE_PL_PFLR_FORCE_LINK; + + imx_pcie_fix_dabt_handler(true); + writel(val, MX6_DBI_ADDR + PCIE_PL_PFLR); + imx_pcie_fix_dabt_handler(false); + + gpr12 &= ~IOMUXC_GPR12_PCIE_CTL_2; + writel(val, &iomuxc_regs->gpr[12]); + } + } setbits_le32(&iomuxc_regs->gpr[1], IOMUXC_GPR1_TEST_POWERDOWN); clrbits_le32(&iomuxc_regs->gpr[1], IOMUXC_GPR1_REF_SSP_EN); #endif @@ -479,10 +516,12 @@ static int imx6_pcie_init_phy(void) __weak int imx6_pcie_toggle_power(void) { #ifdef CONFIG_PCIE_IMX_POWER_GPIO + gpio_request(CONFIG_PCIE_IMX_POWER_GPIO, "pcie_power"); gpio_direction_output(CONFIG_PCIE_IMX_POWER_GPIO, 0); mdelay(20); gpio_set_value(CONFIG_PCIE_IMX_POWER_GPIO, 1); mdelay(20); + gpio_free(CONFIG_PCIE_IMX_POWER_GPIO); #endif return 0; } @@ -518,10 +557,12 @@ __weak int imx6_pcie_toggle_reset(void) * state due to being previously used in U-Boot. */ #ifdef CONFIG_PCIE_IMX_PERST_GPIO + gpio_request(CONFIG_PCIE_IMX_PERST_GPIO, "pcie_reset"); gpio_direction_output(CONFIG_PCIE_IMX_PERST_GPIO, 0); mdelay(20); gpio_set_value(CONFIG_PCIE_IMX_PERST_GPIO, 1); mdelay(20); + gpio_free(CONFIG_PCIE_IMX_PERST_GPIO); #else puts("WARNING: Make sure the PCIe #PERST line is connected!\n"); #endif @@ -536,6 +577,9 @@ static int imx6_pcie_deassert_core_reset(void) enable_pcie_clock(); + if (is_mx6dqp()) + clrbits_le32(&iomuxc_regs->gpr[1], IOMUXC_GPR1_PCIE_SW_RST); + /* * Wait for the clock to settle a bit, when the clock are sourced * from the CPU, we need about 30 ms to settle. @@ -564,12 +608,23 @@ static int imx_pcie_link_up(void) uint32_t tmp; int count = 0; - imx6_pcie_assert_core_reset(); + imx6_pcie_assert_core_reset(false); imx6_pcie_init_phy(); imx6_pcie_deassert_core_reset(); imx_pcie_regions_setup(); + /* + * By default, the subordinate is set equally to the secondary + * bus (0x01) when the RC boots. + * This means that theoretically, only bus 1 is reachable from the RC. + * Force the PCIe RC subordinate to 0xff, otherwise no downstream + * devices will be detected if the enumeration is applied strictly. + */ + tmp = readl(MX6_DBI_ADDR + 0x18); + tmp |= (0xff << 16); + writel(tmp, MX6_DBI_ADDR + 0x18); + /* * FIXME: Force the PCIe RC to Gen1 operation * The RC must be forced into Gen1 mode before bringing the link @@ -587,7 +642,7 @@ static int imx_pcie_link_up(void) while (!imx6_pcie_link_up()) { udelay(10); count++; - if (count >= 2000) { + if (count >= 4000) { #ifdef CONFIG_PCI_SCAN_SHOW puts("PCI: pcie phy link never came up\n"); #endif @@ -644,6 +699,11 @@ void imx_pcie_init(void) } } +void imx_pcie_remove(void) +{ + imx6_pcie_assert_core_reset(true); +} + /* Probe function. */ void pci_init_board(void) {