summaryrefslogtreecommitdiff
path: root/drivers/pci
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/pci')
-rw-r--r--drivers/pci/host/pci-imx6.c41
-rw-r--r--drivers/pci/quirks.c24
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.
*/