X-Git-Url: http://git.monstr.eu/?a=blobdiff_plain;f=drivers%2Fpci%2Fcontroller%2Fdwc%2Fpcie-tegra194.c;h=6fa216e52d142c8045380a2c717d5794689c6e57;hb=275e88b06a277ccf89d9c471a777e9b4f8c552b0;hp=f920e7efe118f40fd4abbc6e2d5eecd0358b881a;hpb=746b25b1aa0f5736d585728ded70a8141da91edb;p=linux-2.6-microblaze.git diff --git a/drivers/pci/controller/dwc/pcie-tegra194.c b/drivers/pci/controller/dwc/pcie-tegra194.c index f920e7efe118..6fa216e52d14 100644 --- a/drivers/pci/controller/dwc/pcie-tegra194.c +++ b/drivers/pci/controller/dwc/pcie-tegra194.c @@ -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 = {