diff options
Diffstat (limited to 'drivers/pci')
-rw-r--r-- | drivers/pci/host/pci-imx6.c | 41 | ||||
-rw-r--r-- | drivers/pci/quirks.c | 24 |
2 files changed, 58 insertions, 7 deletions
diff --git a/drivers/pci/host/pci-imx6.c b/drivers/pci/host/pci-imx6.c index 1fb3ec9ecf71..55315e670e24 100644 --- a/drivers/pci/host/pci-imx6.c +++ b/drivers/pci/host/pci-imx6.c @@ -62,6 +62,7 @@ struct imx6_pcie { int power_on_gpio; int reset_gpio; bool gpio_active_high; + int reset_ep_gpio; struct clk *pcie_bus; struct clk *pcie_inbound_axi; struct clk *pcie_phy; @@ -80,6 +81,7 @@ struct imx6_pcie { void __iomem *phy_base; struct regulator *pcie_phy_regulator; struct regulator *pcie_bus_regulator; + int force_detect_state; }; /* PCIe Root Complex registers (memory-mapped) */ @@ -299,7 +301,7 @@ static int imx6q_pcie_abort_handler(unsigned long addr, static void imx6_pcie_assert_core_reset(struct imx6_pcie *imx6_pcie) { struct pcie_port *pp = &imx6_pcie->pp; - u32 val, gpr1, gpr12; + u32 gpr1, gpr12; switch (imx6_pcie->variant) { case IMX6SX: @@ -335,11 +337,7 @@ static void imx6_pcie_assert_core_reset(struct imx6_pcie *imx6_pcie) if ((gpr1 & IMX6Q_GPR1_PCIE_REF_CLK_EN) && (gpr12 & IMX6Q_GPR12_PCIE_CTL_2)) { - val = dw_pcie_readl_rc(pp, PCIE_PL_PFLR); - val &= ~PCIE_PL_PFLR_LINK_STATE_MASK; - val |= PCIE_PL_PFLR_FORCE_LINK; - dw_pcie_writel_rc(pp, PCIE_PL_PFLR, val); - + imx6_pcie->force_detect_state = 1; regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR12, IMX6Q_GPR12_PCIE_CTL_2, 0 << 10); } @@ -532,13 +530,22 @@ static void imx6_pcie_deassert_core_reset(struct imx6_pcie *imx6_pcie) /* Some boards don't have PCIe reset GPIO. */ if (gpio_is_valid(imx6_pcie->reset_gpio)) { + if (gpio_is_valid(imx6_pcie->reset_ep_gpio)) + gpio_set_value_cansleep(imx6_pcie->reset_ep_gpio, 1); gpio_set_value_cansleep(imx6_pcie->reset_gpio, imx6_pcie->gpio_active_high); mdelay(20); gpio_set_value_cansleep(imx6_pcie->reset_gpio, !imx6_pcie->gpio_active_high); - mdelay(20); + mdelay(1); + if (gpio_is_valid(imx6_pcie->reset_ep_gpio)) + gpio_set_value_cansleep(imx6_pcie->reset_ep_gpio, 0); + } else if (gpio_is_valid(imx6_pcie->reset_ep_gpio)) { + gpio_set_value_cansleep(imx6_pcie->reset_ep_gpio, 1); + mdelay(100); + gpio_set_value_cansleep(imx6_pcie->reset_ep_gpio, 0); } + mdelay(20); return; @@ -725,6 +732,15 @@ static int imx6_pcie_establish_link(struct imx6_pcie *imx6_pcie) goto out; } + if (imx6_pcie->force_detect_state) { + u32 val; + + imx6_pcie->force_detect_state = 0; + val = dw_pcie_readl_rc(pp, PCIE_PL_PFLR); + val &= ~PCIE_PL_PFLR_LINK_STATE_MASK; + val |= PCIE_PL_PFLR_FORCE_LINK; + dw_pcie_writel_rc(pp, PCIE_PL_PFLR, val); + } /* * Start Directed Speed Change so the best possible speed both link * partners support can be negotiated. @@ -1224,6 +1240,17 @@ static int imx6_pcie_probe(struct platform_device *pdev) return ret; } } + imx6_pcie->reset_ep_gpio = of_get_named_gpio(node, "reset-ep-gpio", 0); + if (gpio_is_valid(imx6_pcie->reset_ep_gpio)) { + ret = devm_gpio_request_one(&pdev->dev, + imx6_pcie->reset_ep_gpio, + GPIOF_OUT_INIT_HIGH, + "PCIe EP reset"); + if (ret) { + dev_err(&pdev->dev, "unable to get reset end point gpio\n"); + return ret; + } + } imx6_pcie->power_on_gpio = of_get_named_gpio(node, "power-on-gpio", 0); if (gpio_is_valid(imx6_pcie->power_on_gpio)) { diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c index 0c9edc9d7c44..d8b5f9c42439 100644 --- a/drivers/pci/quirks.c +++ b/drivers/pci/quirks.c @@ -2302,6 +2302,21 @@ static void quirk_tile_plx_gen1(struct pci_dev *dev) DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_PLX, 0x8624, quirk_tile_plx_gen1); #endif /* CONFIG_TILEPRO */ +#ifdef CONFIG_PCI_FORCE_GEN1 +/* + * The Apalis evaluation board needs to set the link speed to 2.5 GT/s (GEN1). + * The default link speed setting is 5 GT/s (GEN2). 0x98 is the Link Control 2 + * PCIe Capability Register of the PEX8605 PCIe switch. The switch supports + * link speed auto negotiation, but falsely sets the link speed to 5 GT/s. + */ +static void quirk_apalis_plx_gen1(struct pci_dev *dev) +{ + pci_write_config_dword(dev, 0x98, 0x1); + mdelay(50); +} +DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_PLX, 0x8605, quirk_apalis_plx_gen1); +#endif /* CONFIG_PCI_FORCE_GEN1 */ + #ifdef CONFIG_PCI_MSI /* Some chipsets do not support MSI. We cannot easily rely on setting * PCI_BUS_FLAGS_NO_MSI in its bus flags because there are actually @@ -2957,6 +2972,15 @@ static void fixup_ti816x_class(struct pci_dev *dev) DECLARE_PCI_FIXUP_CLASS_EARLY(PCI_VENDOR_ID_TI, 0xb800, PCI_CLASS_NOT_DEFINED, 8, fixup_ti816x_class); +/* TW6869 Frame grabber has same problem as ti816x */ +static void fixup_tw6869_class(struct pci_dev* dev) +{ + dev_info(&dev->dev, "Setting PCI class for tw6869 PCIe device\n"); + dev->class = PCI_CLASS_MULTIMEDIA_VIDEO; +} +DECLARE_PCI_FIXUP_CLASS_EARLY(0x1797, 0x6869, + PCI_CLASS_NOT_DEFINED, 0, fixup_tw6869_class); + /* Some PCIe devices do not work reliably with the claimed maximum * payload size supported. */ |