diff options
| author | Mark Brown <broonie@kernel.org> | 2020-12-28 17:20:00 +0300 | 
|---|---|---|
| committer | Mark Brown <broonie@kernel.org> | 2020-12-28 17:20:00 +0300 | 
| commit | 2ae6f64ce1ce304b502461fdfe0b96c8171ae2cc (patch) | |
| tree | 88e987c447daf2c29e2d4c15e58d1029b0cc78c2 /drivers/pci/controller/dwc/pcie-tegra194.c | |
| parent | 3b66e4a8e58a85af3212c7117d7a29c9ef6679a2 (diff) | |
| parent | 5c8fe583cce542aa0b84adc939ce85293de36e5e (diff) | |
| download | linux-2ae6f64ce1ce304b502461fdfe0b96c8171ae2cc.tar.xz | |
Merge tag 'v5.11-rc1' into regulator-5.11
Linux 5.11-rc1
Diffstat (limited to 'drivers/pci/controller/dwc/pcie-tegra194.c')
| -rw-r--r-- | drivers/pci/controller/dwc/pcie-tegra194.c | 184 | 
1 files changed, 78 insertions, 106 deletions
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 = {  | 
