PCI: dwc/qcom: Use common PCI register definitions
[linux-2.6-microblaze.git] / drivers / pci / controller / dwc / pcie-qcom.c
index fa0bf65..d8d1fb7 100644 (file)
@@ -27,6 +27,7 @@
 #include <linux/slab.h>
 #include <linux/types.h>
 
+#include "../../pci.h"
 #include "pcie-designware.h"
 
 #define PCIE20_PARF_SYS_CTRL                   0x00
 #define L23_CLK_RMV_DIS                                BIT(2)
 #define L1_CLK_RMV_DIS                         BIT(1)
 
-#define PCIE20_COMMAND_STATUS                  0x04
-#define CMD_BME_VAL                            0x4
-#define PCIE20_DEVICE_CONTROL2_STATUS2         0x98
-#define PCIE_CAP_CPL_TIMEOUT_DISABLE           0x10
-
 #define PCIE20_PARF_PHY_CTRL                   0x40
+#define PHY_CTRL_PHY_TX0_TERM_OFFSET_MASK      GENMASK(20, 16)
+#define PHY_CTRL_PHY_TX0_TERM_OFFSET(x)                ((x) << 16)
+
 #define PCIE20_PARF_PHY_REFCLK                 0x4C
+#define PHY_REFCLK_SSP_EN                      BIT(16)
+#define PHY_REFCLK_USE_PAD                     BIT(12)
+
 #define PCIE20_PARF_DBI_BASE_ADDR              0x168
 #define PCIE20_PARF_SLV_ADDR_SPACE_SIZE                0x16C
 #define PCIE20_PARF_MHI_CLOCK_RESET_CTRL       0x174
 #define PCIE20_AXI_MSTR_RESP_COMP_CTRL1                0x81c
 #define CFG_BRIDGE_SB_INIT                     BIT(0)
 
-#define PCIE20_CAP                             0x70
-#define PCIE20_CAP_LINK_CAPABILITIES           (PCIE20_CAP + 0xC)
-#define PCIE20_CAP_ACTIVE_STATE_LINK_PM_SUPPORT        (BIT(10) | BIT(11))
-#define PCIE20_CAP_LINK_1                      (PCIE20_CAP + 0x14)
 #define PCIE_CAP_LINK1_VAL                     0x2FD7F
 
 #define PCIE20_PARF_Q2A_FLUSH                  0x1AC
 #define DBI_RO_WR_EN                           1
 
 #define PERST_DELAY_US                         1000
+/* PARF registers */
+#define PCIE20_PARF_PCS_DEEMPH                 0x34
+#define PCS_DEEMPH_TX_DEEMPH_GEN1(x)           ((x) << 16)
+#define PCS_DEEMPH_TX_DEEMPH_GEN2_3_5DB(x)     ((x) << 8)
+#define PCS_DEEMPH_TX_DEEMPH_GEN2_6DB(x)       ((x) << 0)
+
+#define PCIE20_PARF_PCS_SWING                  0x38
+#define PCS_SWING_TX_SWING_FULL(x)             ((x) << 8)
+#define PCS_SWING_TX_SWING_LOW(x)              ((x) << 0)
+
+#define PCIE20_PARF_CONFIG_BITS                0x50
+#define PHY_RX0_EQ(x)                          ((x) << 24)
 
 #define PCIE20_v3_PARF_SLV_ADDR_SPACE_SIZE     0x358
 #define SLV_ADDR_SPACE_SZ                      0x10000000
 
+#define PCIE20_LNK_CONTROL2_LINK_STATUS2       0xa0
+
 #define DEVICE_TYPE_RC                         0x4
 
 #define QCOM_PCIE_2_1_0_MAX_SUPPLY     3
+#define QCOM_PCIE_2_1_0_MAX_CLOCKS     5
 struct qcom_pcie_resources_2_1_0 {
-       struct clk *iface_clk;
-       struct clk *core_clk;
-       struct clk *phy_clk;
-       struct clk *aux_clk;
-       struct clk *ref_clk;
+       struct clk_bulk_data clks[QCOM_PCIE_2_1_0_MAX_CLOCKS];
        struct reset_control *pci_reset;
        struct reset_control *axi_reset;
        struct reset_control *ahb_reset;
        struct reset_control *por_reset;
        struct reset_control *phy_reset;
+       struct reset_control *ext_reset;
        struct regulator_bulk_data supplies[QCOM_PCIE_2_1_0_MAX_SUPPLY];
 };
 
@@ -179,6 +189,7 @@ struct qcom_pcie {
        struct phy *phy;
        struct gpio_desc *reset;
        const struct qcom_pcie_ops *ops;
+       int gen;
 };
 
 #define to_qcom_pcie(x)                dev_get_drvdata((x)->dev)
@@ -236,25 +247,21 @@ static int qcom_pcie_get_resources_2_1_0(struct qcom_pcie *pcie)
        if (ret)
                return ret;
 
-       res->iface_clk = devm_clk_get(dev, "iface");
-       if (IS_ERR(res->iface_clk))
-               return PTR_ERR(res->iface_clk);
-
-       res->core_clk = devm_clk_get(dev, "core");
-       if (IS_ERR(res->core_clk))
-               return PTR_ERR(res->core_clk);
-
-       res->phy_clk = devm_clk_get(dev, "phy");
-       if (IS_ERR(res->phy_clk))
-               return PTR_ERR(res->phy_clk);
+       res->clks[0].id = "iface";
+       res->clks[1].id = "core";
+       res->clks[2].id = "phy";
+       res->clks[3].id = "aux";
+       res->clks[4].id = "ref";
 
-       res->aux_clk = devm_clk_get_optional(dev, "aux");
-       if (IS_ERR(res->aux_clk))
-               return PTR_ERR(res->aux_clk);
+       /* iface, core, phy are required */
+       ret = devm_clk_bulk_get(dev, 3, res->clks);
+       if (ret < 0)
+               return ret;
 
-       res->ref_clk = devm_clk_get_optional(dev, "ref");
-       if (IS_ERR(res->ref_clk))
-               return PTR_ERR(res->ref_clk);
+       /* aux, ref are optional */
+       ret = devm_clk_bulk_get_optional(dev, 2, res->clks + 3);
+       if (ret < 0)
+               return ret;
 
        res->pci_reset = devm_reset_control_get_exclusive(dev, "pci");
        if (IS_ERR(res->pci_reset))
@@ -272,6 +279,10 @@ static int qcom_pcie_get_resources_2_1_0(struct qcom_pcie *pcie)
        if (IS_ERR(res->por_reset))
                return PTR_ERR(res->por_reset);
 
+       res->ext_reset = devm_reset_control_get_optional_exclusive(dev, "ext");
+       if (IS_ERR(res->ext_reset))
+               return PTR_ERR(res->ext_reset);
+
        res->phy_reset = devm_reset_control_get_exclusive(dev, "phy");
        return PTR_ERR_OR_ZERO(res->phy_reset);
 }
@@ -280,16 +291,13 @@ static void qcom_pcie_deinit_2_1_0(struct qcom_pcie *pcie)
 {
        struct qcom_pcie_resources_2_1_0 *res = &pcie->res.v2_1_0;
 
+       clk_bulk_disable_unprepare(ARRAY_SIZE(res->clks), res->clks);
        reset_control_assert(res->pci_reset);
        reset_control_assert(res->axi_reset);
        reset_control_assert(res->ahb_reset);
        reset_control_assert(res->por_reset);
-       reset_control_assert(res->pci_reset);
-       clk_disable_unprepare(res->iface_clk);
-       clk_disable_unprepare(res->core_clk);
-       clk_disable_unprepare(res->phy_clk);
-       clk_disable_unprepare(res->aux_clk);
-       clk_disable_unprepare(res->ref_clk);
+       reset_control_assert(res->ext_reset);
+       reset_control_assert(res->phy_reset);
        regulator_bulk_disable(ARRAY_SIZE(res->supplies), res->supplies);
 }
 
@@ -298,6 +306,7 @@ static int qcom_pcie_init_2_1_0(struct qcom_pcie *pcie)
        struct qcom_pcie_resources_2_1_0 *res = &pcie->res.v2_1_0;
        struct dw_pcie *pci = pcie->pci;
        struct device *dev = pci->dev;
+       struct device_node *node = dev->of_node;
        u32 val;
        int ret;
 
@@ -307,85 +316,85 @@ static int qcom_pcie_init_2_1_0(struct qcom_pcie *pcie)
                return ret;
        }
 
-       ret = reset_control_assert(res->ahb_reset);
+       ret = reset_control_deassert(res->ahb_reset);
        if (ret) {
-               dev_err(dev, "cannot assert ahb reset\n");
-               goto err_assert_ahb;
+               dev_err(dev, "cannot deassert ahb reset\n");
+               goto err_deassert_ahb;
        }
 
-       ret = clk_prepare_enable(res->iface_clk);
+       ret = reset_control_deassert(res->ext_reset);
        if (ret) {
-               dev_err(dev, "cannot prepare/enable iface clock\n");
-               goto err_assert_ahb;
+               dev_err(dev, "cannot deassert ext reset\n");
+               goto err_deassert_ext;
        }
 
-       ret = clk_prepare_enable(res->core_clk);
+       ret = reset_control_deassert(res->phy_reset);
        if (ret) {
-               dev_err(dev, "cannot prepare/enable core clock\n");
-               goto err_clk_core;
+               dev_err(dev, "cannot deassert phy reset\n");
+               goto err_deassert_phy;
        }
 
-       ret = clk_prepare_enable(res->phy_clk);
+       ret = reset_control_deassert(res->pci_reset);
        if (ret) {
-               dev_err(dev, "cannot prepare/enable phy clock\n");
-               goto err_clk_phy;
+               dev_err(dev, "cannot deassert pci reset\n");
+               goto err_deassert_pci;
        }
 
-       ret = clk_prepare_enable(res->aux_clk);
+       ret = reset_control_deassert(res->por_reset);
        if (ret) {
-               dev_err(dev, "cannot prepare/enable aux clock\n");
-               goto err_clk_aux;
+               dev_err(dev, "cannot deassert por reset\n");
+               goto err_deassert_por;
        }
 
-       ret = clk_prepare_enable(res->ref_clk);
+       ret = reset_control_deassert(res->axi_reset);
        if (ret) {
-               dev_err(dev, "cannot prepare/enable ref clock\n");
-               goto err_clk_ref;
+               dev_err(dev, "cannot deassert axi reset\n");
+               goto err_deassert_axi;
        }
 
-       ret = reset_control_deassert(res->ahb_reset);
-       if (ret) {
-               dev_err(dev, "cannot deassert ahb reset\n");
-               goto err_deassert_ahb;
-       }
+       ret = clk_bulk_prepare_enable(ARRAY_SIZE(res->clks), res->clks);
+       if (ret)
+               goto err_clks;
 
        /* enable PCIe clocks and resets */
        val = readl(pcie->parf + PCIE20_PARF_PHY_CTRL);
        val &= ~BIT(0);
        writel(val, pcie->parf + PCIE20_PARF_PHY_CTRL);
 
-       /* enable external reference clock */
-       val = readl(pcie->parf + PCIE20_PARF_PHY_REFCLK);
-       val |= BIT(16);
-       writel(val, pcie->parf + PCIE20_PARF_PHY_REFCLK);
-
-       ret = reset_control_deassert(res->phy_reset);
-       if (ret) {
-               dev_err(dev, "cannot deassert phy reset\n");
-               return ret;
-       }
-
-       ret = reset_control_deassert(res->pci_reset);
-       if (ret) {
-               dev_err(dev, "cannot deassert pci reset\n");
-               return ret;
+       if (of_device_is_compatible(node, "qcom,pcie-ipq8064") ||
+           of_device_is_compatible(node, "qcom,pcie-ipq8064-v2")) {
+               writel(PCS_DEEMPH_TX_DEEMPH_GEN1(24) |
+                              PCS_DEEMPH_TX_DEEMPH_GEN2_3_5DB(24) |
+                              PCS_DEEMPH_TX_DEEMPH_GEN2_6DB(34),
+                      pcie->parf + PCIE20_PARF_PCS_DEEMPH);
+               writel(PCS_SWING_TX_SWING_FULL(120) |
+                              PCS_SWING_TX_SWING_LOW(120),
+                      pcie->parf + PCIE20_PARF_PCS_SWING);
+               writel(PHY_RX0_EQ(4), pcie->parf + PCIE20_PARF_CONFIG_BITS);
        }
 
-       ret = reset_control_deassert(res->por_reset);
-       if (ret) {
-               dev_err(dev, "cannot deassert por reset\n");
-               return ret;
+       if (of_device_is_compatible(node, "qcom,pcie-ipq8064")) {
+               /* set TX termination offset */
+               val = readl(pcie->parf + PCIE20_PARF_PHY_CTRL);
+               val &= ~PHY_CTRL_PHY_TX0_TERM_OFFSET_MASK;
+               val |= PHY_CTRL_PHY_TX0_TERM_OFFSET(7);
+               writel(val, pcie->parf + PCIE20_PARF_PHY_CTRL);
        }
 
-       ret = reset_control_deassert(res->axi_reset);
-       if (ret) {
-               dev_err(dev, "cannot deassert axi reset\n");
-               return ret;
-       }
+       /* enable external reference clock */
+       val = readl(pcie->parf + PCIE20_PARF_PHY_REFCLK);
+       val &= ~PHY_REFCLK_USE_PAD;
+       val |= PHY_REFCLK_SSP_EN;
+       writel(val, pcie->parf + PCIE20_PARF_PHY_REFCLK);
 
        /* wait for clock acquisition */
        usleep_range(1000, 1500);
 
+       if (pcie->gen == 1) {
+               val = readl(pci->dbi_base + PCIE20_LNK_CONTROL2_LINK_STATUS2);
+               val |= PCI_EXP_LNKSTA_CLS_2_5GB;
+               writel(val, pci->dbi_base + PCIE20_LNK_CONTROL2_LINK_STATUS2);
+       }
 
        /* Set the Max TLP size to 2K, instead of using default of 4K */
        writel(CFG_REMOTE_RD_REQ_BRIDGE_SIZE_2K,
@@ -395,17 +404,19 @@ static int qcom_pcie_init_2_1_0(struct qcom_pcie *pcie)
 
        return 0;
 
+err_clks:
+       reset_control_assert(res->axi_reset);
+err_deassert_axi:
+       reset_control_assert(res->por_reset);
+err_deassert_por:
+       reset_control_assert(res->pci_reset);
+err_deassert_pci:
+       reset_control_assert(res->phy_reset);
+err_deassert_phy:
+       reset_control_assert(res->ext_reset);
+err_deassert_ext:
+       reset_control_assert(res->ahb_reset);
 err_deassert_ahb:
-       clk_disable_unprepare(res->ref_clk);
-err_clk_ref:
-       clk_disable_unprepare(res->aux_clk);
-err_clk_aux:
-       clk_disable_unprepare(res->phy_clk);
-err_clk_phy:
-       clk_disable_unprepare(res->core_clk);
-err_clk_core:
-       clk_disable_unprepare(res->iface_clk);
-err_assert_ahb:
        regulator_bulk_disable(ARRAY_SIZE(res->supplies), res->supplies);
 
        return ret;
@@ -1002,6 +1013,7 @@ static int qcom_pcie_init_2_3_3(struct qcom_pcie *pcie)
        struct qcom_pcie_resources_2_3_3 *res = &pcie->res.v2_3_3;
        struct dw_pcie *pci = pcie->pci;
        struct device *dev = pci->dev;
+       u16 offset = dw_pcie_find_capability(pci, PCI_CAP_ID_EXP);
        int i, ret;
        u32 val;
 
@@ -1075,16 +1087,16 @@ static int qcom_pcie_init_2_3_3(struct qcom_pcie *pcie)
                pcie->parf + PCIE20_PARF_SYS_CTRL);
        writel(0, pcie->parf + PCIE20_PARF_Q2A_FLUSH);
 
-       writel(CMD_BME_VAL, pci->dbi_base + PCIE20_COMMAND_STATUS);
+       writel(PCI_COMMAND_MASTER, pci->dbi_base + PCI_COMMAND);
        writel(DBI_RO_WR_EN, pci->dbi_base + PCIE20_MISC_CONTROL_1_REG);
-       writel(PCIE_CAP_LINK1_VAL, pci->dbi_base + PCIE20_CAP_LINK_1);
+       writel(PCIE_CAP_LINK1_VAL, pci->dbi_base + offset + PCI_EXP_SLTCAP);
 
-       val = readl(pci->dbi_base + PCIE20_CAP_LINK_CAPABILITIES);
-       val &= ~PCIE20_CAP_ACTIVE_STATE_LINK_PM_SUPPORT;
-       writel(val, pci->dbi_base + PCIE20_CAP_LINK_CAPABILITIES);
+       val = readl(pci->dbi_base + offset + PCI_EXP_LNKCAP);
+       val &= ~PCI_EXP_LNKCAP_ASPMS;
+       writel(val, pci->dbi_base + offset + PCI_EXP_LNKCAP);
 
-       writel(PCIE_CAP_CPL_TIMEOUT_DISABLE, pci->dbi_base +
-               PCIE20_DEVICE_CONTROL2_STATUS2);
+       writel(PCI_EXP_DEVCTL2_COMP_TMOUT_DIS, pci->dbi_base + offset +
+               PCI_EXP_DEVCTL2);
 
        return 0;
 
@@ -1237,7 +1249,8 @@ static void qcom_pcie_post_deinit_2_7_0(struct qcom_pcie *pcie)
 
 static int qcom_pcie_link_up(struct dw_pcie *pci)
 {
-       u16 val = readw(pci->dbi_base + PCIE20_CAP + PCI_EXP_LNKSTA);
+       u16 offset = dw_pcie_find_capability(pci, PCI_CAP_ID_EXP);
+       u16 val = readw(pci->dbi_base + offset + PCI_EXP_LNKSTA);
 
        return !!(val & PCI_EXP_LNKSTA_DLLLA);
 }
@@ -1265,9 +1278,7 @@ static int qcom_pcie_host_init(struct pcie_port *pp)
        }
 
        dw_pcie_setup_rc(pp);
-
-       if (IS_ENABLED(CONFIG_PCI_MSI))
-               dw_pcie_msi_init(pp);
+       dw_pcie_msi_init(pp);
 
        qcom_ep_reset_deassert(pcie);
 
@@ -1367,10 +1378,8 @@ static int qcom_pcie_probe(struct platform_device *pdev)
 
        pm_runtime_enable(dev);
        ret = pm_runtime_get_sync(dev);
-       if (ret < 0) {
-               pm_runtime_disable(dev);
-               return ret;
-       }
+       if (ret < 0)
+               goto err_pm_runtime_put;
 
        pci->dev = dev;
        pci->ops = &dw_pcie_ops;
@@ -1386,8 +1395,11 @@ static int qcom_pcie_probe(struct platform_device *pdev)
                goto err_pm_runtime_put;
        }
 
-       res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "parf");
-       pcie->parf = devm_ioremap_resource(dev, res);
+       pcie->gen = of_pci_get_max_link_speed(pdev->dev.of_node);
+       if (pcie->gen < 0)
+               pcie->gen = 2;
+
+       pcie->parf = devm_platform_ioremap_resource_byname(pdev, "parf");
        if (IS_ERR(pcie->parf)) {
                ret = PTR_ERR(pcie->parf);
                goto err_pm_runtime_put;
@@ -1400,8 +1412,7 @@ static int qcom_pcie_probe(struct platform_device *pdev)
                goto err_pm_runtime_put;
        }
 
-       res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "elbi");
-       pcie->elbi = devm_ioremap_resource(dev, res);
+       pcie->elbi = devm_platform_ioremap_resource_byname(pdev, "elbi");
        if (IS_ERR(pcie->elbi)) {
                ret = PTR_ERR(pcie->elbi);
                goto err_pm_runtime_put;
@@ -1454,6 +1465,7 @@ err_pm_runtime_put:
 static const struct of_device_id qcom_pcie_match[] = {
        { .compatible = "qcom,pcie-apq8084", .data = &ops_1_0_0 },
        { .compatible = "qcom,pcie-ipq8064", .data = &ops_2_1_0 },
+       { .compatible = "qcom,pcie-ipq8064-v2", .data = &ops_2_1_0 },
        { .compatible = "qcom,pcie-apq8064", .data = &ops_2_1_0 },
        { .compatible = "qcom,pcie-msm8996", .data = &ops_2_3_2 },
        { .compatible = "qcom,pcie-ipq8074", .data = &ops_2_3_3 },