PCI: tegra: Fix host link initialization
[linux-2.6-microblaze.git] / drivers / pci / controller / dwc / pcie-tegra194.c
index f920e7e..6fa216e 100644 (file)
@@ -765,8 +765,6 @@ static void tegra_pcie_enable_msi_interrupts(struct pcie_port *pp)
        struct tegra_pcie_dw *pcie = to_tegra_pcie(pci);
        u32 val;
 
-       dw_pcie_msi_init(pp);
-
        /* Enable MSI interrupt generation */
        val = appl_readl(pcie, APPL_INTR_EN_L0_0);
        val |= APPL_INTR_EN_L0_0_SYS_MSI_INTR_EN;
@@ -855,12 +853,18 @@ static void config_gen3_gen4_eq_presets(struct tegra_pcie_dw *pcie)
        dw_pcie_writel_dbi(pci, GEN3_RELATED_OFF, val);
 }
 
-static void tegra_pcie_prepare_host(struct pcie_port *pp)
+static int tegra_pcie_dw_host_init(struct pcie_port *pp)
 {
        struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
        struct tegra_pcie_dw *pcie = to_tegra_pcie(pci);
        u32 val;
 
+       pp->bridge->ops = &tegra_pci_ops;
+
+       if (!pcie->pcie_cap_base)
+               pcie->pcie_cap_base = dw_pcie_find_capability(&pcie->pci,
+                                                             PCI_CAP_ID_EXP);
+
        val = dw_pcie_readl_dbi(pci, PCI_IO_BASE);
        val &= ~(IO_BASE_IO_DECODE | IO_BASE_IO_DECODE_BIT8);
        dw_pcie_writel_dbi(pci, PCI_IO_BASE, val);
@@ -889,6 +893,12 @@ static void tegra_pcie_prepare_host(struct pcie_port *pp)
 
        init_host_aspm(pcie);
 
+       /* Disable ASPM-L1SS advertisement if there is no CLKREQ routing */
+       if (!pcie->supports_clkreq) {
+               disable_aspm_l11(pcie);
+               disable_aspm_l12(pcie);
+       }
+
        val = dw_pcie_readl_dbi(pci, GEN3_RELATED_OFF);
        val &= ~GEN3_RELATED_OFF_GEN3_ZRXDC_NONCOMPL;
        dw_pcie_writel_dbi(pci, GEN3_RELATED_OFF, val);
@@ -899,10 +909,24 @@ static void tegra_pcie_prepare_host(struct pcie_port *pp)
                dw_pcie_writel_dbi(pci, CFG_TIMER_CTRL_MAX_FUNC_NUM_OFF, val);
        }
 
-       dw_pcie_setup_rc(pp);
-
        clk_set_rate(pcie->core_clk, GEN4_CORE_CLK_FREQ);
 
+       return 0;
+}
+
+static int tegra_pcie_dw_start_link(struct dw_pcie *pci)
+{
+       u32 val, offset, speed, tmp;
+       struct tegra_pcie_dw *pcie = to_tegra_pcie(pci);
+       struct pcie_port *pp = &pci->pp;
+       bool retry = true;
+
+       if (pcie->mode == DW_PCIE_EP_TYPE) {
+               enable_irq(pcie->pex_rst_irq);
+               return 0;
+       }
+
+retry_link:
        /* Assert RST */
        val = appl_readl(pcie, APPL_PINMUX);
        val &= ~APPL_PINMUX_PEX_RST;
@@ -921,19 +945,10 @@ static void tegra_pcie_prepare_host(struct pcie_port *pp)
        appl_writel(pcie, val, APPL_PINMUX);
 
        msleep(100);
-}
-
-static int tegra_pcie_dw_host_init(struct pcie_port *pp)
-{
-       struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
-       struct tegra_pcie_dw *pcie = to_tegra_pcie(pci);
-       u32 val, tmp, offset, speed;
-
-       pp->bridge->ops = &tegra_pci_ops;
-
-       tegra_pcie_prepare_host(pp);
 
        if (dw_pcie_wait_for_link(pci)) {
+               if (!retry)
+                       return 0;
                /*
                 * There are some endpoints which can't get the link up if
                 * root port has Data Link Feature (DLF) enabled.
@@ -967,10 +982,11 @@ static int tegra_pcie_dw_host_init(struct pcie_port *pp)
                val &= ~PCI_DLF_EXCHANGE_ENABLE;
                dw_pcie_writel_dbi(pci, offset, val);
 
-               tegra_pcie_prepare_host(pp);
+               tegra_pcie_dw_host_init(pp);
+               dw_pcie_setup_rc(pp);
 
-               if (dw_pcie_wait_for_link(pci))
-                       return 0;
+               retry = false;
+               goto retry_link;
        }
 
        speed = dw_pcie_readw_dbi(pci, pcie->pcie_cap_base + PCI_EXP_LNKSTA) &
@@ -990,20 +1006,6 @@ static int tegra_pcie_dw_link_up(struct dw_pcie *pci)
        return !!(val & PCI_EXP_LNKSTA_DLLLA);
 }
 
-static void tegra_pcie_set_msi_vec_num(struct pcie_port *pp)
-{
-       pp->num_vectors = MAX_MSI_IRQS;
-}
-
-static int tegra_pcie_dw_start_link(struct dw_pcie *pci)
-{
-       struct tegra_pcie_dw *pcie = to_tegra_pcie(pci);
-
-       enable_irq(pcie->pex_rst_irq);
-
-       return 0;
-}
-
 static void tegra_pcie_dw_stop_link(struct dw_pcie *pci)
 {
        struct tegra_pcie_dw *pcie = to_tegra_pcie(pci);
@@ -1019,7 +1021,6 @@ static const struct dw_pcie_ops tegra_dw_pcie_ops = {
 
 static struct dw_pcie_host_ops tegra_pcie_dw_host_ops = {
        .host_init = tegra_pcie_dw_host_init,
-       .set_num_vectors = tegra_pcie_set_msi_vec_num,
 };
 
 static void tegra_pcie_disable_phy(struct tegra_pcie_dw *pcie)
@@ -1061,9 +1062,16 @@ phy_exit:
 
 static int tegra_pcie_dw_parse_dt(struct tegra_pcie_dw *pcie)
 {
+       struct platform_device *pdev = to_platform_device(pcie->dev);
        struct device_node *np = pcie->dev->of_node;
        int ret;
 
+       pcie->dbi_res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "dbi");
+       if (!pcie->dbi_res) {
+               dev_err(pcie->dev, "Failed to find \"dbi\" region\n");
+               return -ENODEV;
+       }
+
        ret = of_property_read_u32(np, "nvidia,aspm-cmrt-us", &pcie->aspm_cmrt);
        if (ret < 0) {
                dev_info(pcie->dev, "Failed to read ASPM T_cmrt: %d\n", ret);
@@ -1390,15 +1398,6 @@ static int tegra_pcie_config_controller(struct tegra_pcie_dw *pcie,
 
        reset_control_deassert(pcie->core_rst);
 
-       pcie->pcie_cap_base = dw_pcie_find_capability(&pcie->pci,
-                                                     PCI_CAP_ID_EXP);
-
-       /* Disable ASPM-L1SS advertisement as there is no CLKREQ routing */
-       if (!pcie->supports_clkreq) {
-               disable_aspm_l11(pcie);
-               disable_aspm_l12(pcie);
-       }
-
        return ret;
 
 fail_phy:
@@ -1415,43 +1414,32 @@ fail_slot_reg_en:
        return ret;
 }
 
-static int __deinit_controller(struct tegra_pcie_dw *pcie)
+static void tegra_pcie_unconfig_controller(struct tegra_pcie_dw *pcie)
 {
        int ret;
 
        ret = reset_control_assert(pcie->core_rst);
-       if (ret) {
-               dev_err(pcie->dev, "Failed to assert \"core\" reset: %d\n",
-                       ret);
-               return ret;
-       }
+       if (ret)
+               dev_err(pcie->dev, "Failed to assert \"core\" reset: %d\n", ret);
 
        tegra_pcie_disable_phy(pcie);
 
        ret = reset_control_assert(pcie->core_apb_rst);
-       if (ret) {
+       if (ret)
                dev_err(pcie->dev, "Failed to assert APB reset: %d\n", ret);
-               return ret;
-       }
 
        clk_disable_unprepare(pcie->core_clk);
 
        ret = regulator_disable(pcie->pex_ctl_supply);
-       if (ret) {
+       if (ret)
                dev_err(pcie->dev, "Failed to disable regulator: %d\n", ret);
-               return ret;
-       }
 
        tegra_pcie_disable_slot_regulators(pcie);
 
        ret = tegra_pcie_bpmp_set_ctrl_state(pcie, false);
-       if (ret) {
+       if (ret)
                dev_err(pcie->dev, "Failed to disable controller %d: %d\n",
                        pcie->cid, ret);
-               return ret;
-       }
-
-       return ret;
 }
 
 static int tegra_pcie_init_controller(struct tegra_pcie_dw *pcie)
@@ -1475,7 +1463,8 @@ static int tegra_pcie_init_controller(struct tegra_pcie_dw *pcie)
        return 0;
 
 fail_host_init:
-       return __deinit_controller(pcie);
+       tegra_pcie_unconfig_controller(pcie);
+       return ret;
 }
 
 static int tegra_pcie_try_link_l2(struct tegra_pcie_dw *pcie)
@@ -1516,6 +1505,14 @@ static void tegra_pcie_dw_pme_turnoff(struct tegra_pcie_dw *pcie)
                data &= ~APPL_PINMUX_PEX_RST;
                appl_writel(pcie, data, APPL_PINMUX);
 
+               /*
+                * Some cards do not go to detect state even after de-asserting
+                * PERST#. So, de-assert LTSSM to bring link to detect state.
+                */
+               data = readl(pcie->appl_base + APPL_CTRL);
+               data &= ~APPL_CTRL_LTSSM_EN;
+               writel(data, pcie->appl_base + APPL_CTRL);
+
                err = readl_poll_timeout_atomic(pcie->appl_base + APPL_DEBUG,
                                                data,
                                                ((data &
@@ -1523,14 +1520,8 @@ static void tegra_pcie_dw_pme_turnoff(struct tegra_pcie_dw *pcie)
                                                APPL_DEBUG_LTSSM_STATE_SHIFT) ==
                                                LTSSM_STATE_PRE_DETECT,
                                                1, LTSSM_TIMEOUT);
-               if (err) {
+               if (err)
                        dev_info(pcie->dev, "Link didn't go to detect state\n");
-               } else {
-                       /* Disable LTSSM after link is in detect state */
-                       data = appl_readl(pcie, APPL_CTRL);
-                       data &= ~APPL_CTRL_LTSSM_EN;
-                       appl_writel(pcie, data, APPL_CTRL);
-               }
        }
        /*
         * DBI registers may not be accessible after this as PLL-E would be
@@ -1544,30 +1535,20 @@ static void tegra_pcie_dw_pme_turnoff(struct tegra_pcie_dw *pcie)
        appl_writel(pcie, data, APPL_PINMUX);
 }
 
-static int tegra_pcie_deinit_controller(struct tegra_pcie_dw *pcie)
+static void tegra_pcie_deinit_controller(struct tegra_pcie_dw *pcie)
 {
        tegra_pcie_downstream_dev_to_D0(pcie);
        dw_pcie_host_deinit(&pcie->pci.pp);
        tegra_pcie_dw_pme_turnoff(pcie);
-
-       return __deinit_controller(pcie);
+       tegra_pcie_unconfig_controller(pcie);
 }
 
 static int tegra_pcie_config_rp(struct tegra_pcie_dw *pcie)
 {
-       struct pcie_port *pp = &pcie->pci.pp;
        struct device *dev = pcie->dev;
        char *name;
        int ret;
 
-       if (IS_ENABLED(CONFIG_PCI_MSI)) {
-               pp->msi_irq = of_irq_get_byname(dev->of_node, "msi");
-               if (!pp->msi_irq) {
-                       dev_err(dev, "Failed to get MSI interrupt\n");
-                       return -ENODEV;
-               }
-       }
-
        pm_runtime_enable(dev);
 
        ret = pm_runtime_get_sync(dev);
@@ -1583,7 +1564,11 @@ static int tegra_pcie_config_rp(struct tegra_pcie_dw *pcie)
                goto fail_pm_get_sync;
        }
 
-       tegra_pcie_init_controller(pcie);
+       ret = tegra_pcie_init_controller(pcie);
+       if (ret < 0) {
+               dev_err(dev, "Failed to initialize controller: %d\n", ret);
+               goto fail_pm_get_sync;
+       }
 
        pcie->link_state = tegra_pcie_dw_link_up(&pcie->pci);
        if (!pcie->link_state) {
@@ -1907,19 +1892,12 @@ static int tegra_pcie_config_ep(struct tegra_pcie_dw *pcie,
        struct dw_pcie *pci = &pcie->pci;
        struct device *dev = pcie->dev;
        struct dw_pcie_ep *ep;
-       struct resource *res;
        char *name;
        int ret;
 
        ep = &pci->ep;
        ep->ops = &pcie_ep_ops;
 
-       res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "addr_space");
-       if (!res)
-               return -EINVAL;
-
-       ep->phys_base = res->start;
-       ep->addr_size = resource_size(res);
        ep->page_size = SZ_64K;
 
        ret = gpiod_set_debounce(pcie->pex_rst_gpiod, PERST_DEBOUNCE_TIME);
@@ -1982,7 +1960,6 @@ static int tegra_pcie_dw_probe(struct platform_device *pdev)
        struct device *dev = &pdev->dev;
        struct resource *atu_dma_res;
        struct tegra_pcie_dw *pcie;
-       struct resource *dbi_res;
        struct pcie_port *pp;
        struct dw_pcie *pci;
        struct phy **phys;
@@ -2001,8 +1978,10 @@ static int tegra_pcie_dw_probe(struct platform_device *pdev)
        pci->ops = &tegra_dw_pcie_ops;
        pci->n_fts[0] = N_FTS_VAL;
        pci->n_fts[1] = FTS_VAL;
+       pci->version = 0x490A;
 
        pp = &pci->pp;
+       pp->num_vectors = MAX_MSI_IRQS;
        pcie->dev = &pdev->dev;
        pcie->mode = (enum dw_pcie_device_mode)data->mode;
 
@@ -2091,20 +2070,6 @@ static int tegra_pcie_dw_probe(struct platform_device *pdev)
 
        pcie->phys = phys;
 
-       dbi_res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "dbi");
-       if (!dbi_res) {
-               dev_err(dev, "Failed to find \"dbi\" region\n");
-               return -ENODEV;
-       }
-       pcie->dbi_res = dbi_res;
-
-       pci->dbi_base = devm_ioremap_resource(dev, dbi_res);
-       if (IS_ERR(pci->dbi_base))
-               return PTR_ERR(pci->dbi_base);
-
-       /* Tegra HW locates DBI2 at a fixed offset from DBI */
-       pci->dbi_base2 = pci->dbi_base + 0x1000;
-
        atu_dma_res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
                                                   "atu_dma");
        if (!atu_dma_res) {
@@ -2113,6 +2078,7 @@ static int tegra_pcie_dw_probe(struct platform_device *pdev)
        }
        pcie->atu_dma_res = atu_dma_res;
 
+       pci->atu_size = resource_size(atu_dma_res);
        pci->atu_base = devm_ioremap_resource(dev, atu_dma_res);
        if (IS_ERR(pci->atu_base))
                return PTR_ERR(pci->atu_base);
@@ -2225,8 +2191,9 @@ static int tegra_pcie_dw_suspend_noirq(struct device *dev)
                                               PORT_LOGIC_MSI_CTRL_INT_0_EN);
        tegra_pcie_downstream_dev_to_D0(pcie);
        tegra_pcie_dw_pme_turnoff(pcie);
+       tegra_pcie_unconfig_controller(pcie);
 
-       return __deinit_controller(pcie);
+       return 0;
 }
 
 static int tegra_pcie_dw_resume_noirq(struct device *dev)
@@ -2247,6 +2214,10 @@ static int tegra_pcie_dw_resume_noirq(struct device *dev)
                goto fail_host_init;
        }
 
+       ret = tegra_pcie_dw_start_link(&pcie->pci);
+       if (ret < 0)
+               goto fail_host_init;
+
        /* Restore MSI interrupt vector */
        dw_pcie_writel_dbi(&pcie->pci, PORT_LOGIC_MSI_CTRL_INT_0_EN,
                           pcie->msi_ctrl_int);
@@ -2254,7 +2225,8 @@ static int tegra_pcie_dw_resume_noirq(struct device *dev)
        return 0;
 
 fail_host_init:
-       return __deinit_controller(pcie);
+       tegra_pcie_unconfig_controller(pcie);
+       return ret;
 }
 
 static int tegra_pcie_dw_resume_early(struct device *dev)
@@ -2292,7 +2264,7 @@ static void tegra_pcie_dw_shutdown(struct platform_device *pdev)
                disable_irq(pcie->pci.pp.msi_irq);
 
        tegra_pcie_dw_pme_turnoff(pcie);
-       __deinit_controller(pcie);
+       tegra_pcie_unconfig_controller(pcie);
 }
 
 static const struct tegra_pcie_dw_of_data tegra_pcie_dw_rc_of_data = {