mirror of
https://github.com/torvalds/linux.git
synced 2026-09-23 22:14:03 +02:00
Merge branch 'pci/controller/dwc-imx6'
- Remove PERST# checking from pci_host_common_parse_port() so callers can decide whether to fall back to legacy DT binding with PERST# in the host bridge (Sherry Sun) - Fix build issues when PCI_PWRCTRL_GENERIC or PCI_HOST_COMMON is a module (Arnd Bergmann) - Create pwrctrl devices only once by doing it from imx_pcie_probe() instead of imx_pcie_host_init(), which is used during both probe and resume (Sherry Sun) - Use 'dw_pcie_rp->skip_pwrctrl_off' to avoid powering off devices during suspend to preserve wakeup capability (Sherry Sun) - Add runtime PM support for i.MX95 to allow dynamic power management when the link is idle (Richard Zhu) * pci/controller/dwc-imx6: PCI: imx6: Add runtime PM support for i.MX95 PCI: imx6: Add 'skip_pwrctrl_off' flag support PCI: imx6: Move pci_pwrctrl_create_devices() to imx_pcie_probe() PCI: imx6: Fix building against PCI_PWRCTRL_GENERIC PCI: imx6: Fix building against PCI_HOST_COMMON PCI: host-generic: Move legacy DT binding fallback decision to caller of pci_host_common_parse_ports()
This commit is contained in:
commit
3e01ebb619
|
|
@ -126,7 +126,9 @@ config PCI_IMX6_EP
|
|||
depends on ARCH_MXC || COMPILE_TEST
|
||||
depends on PCI_ENDPOINT
|
||||
select PCIE_DW_EP
|
||||
select PCI_HOST_COMMON
|
||||
select PCI_IMX6
|
||||
select PCI_PWRCTRL_GENERIC
|
||||
help
|
||||
Enables support for the PCIe controller in the i.MX SoCs to
|
||||
work in endpoint mode. The PCI controller on i.MX is based
|
||||
|
|
|
|||
|
|
@ -121,6 +121,7 @@ enum imx_pcie_variants {
|
|||
#define IMX_PCIE_FLAG_SKIP_L23_READY BIT(12)
|
||||
/* Preserve MSI capability for platforms that require it */
|
||||
#define IMX_PCIE_FLAG_KEEP_MSI_CAP BIT(13)
|
||||
#define IMX_PCIE_FLAG_PM_RUNTIME BIT(14)
|
||||
|
||||
#define imx_check_flag(pci, val) (pci->drvdata->flags & val)
|
||||
|
||||
|
|
@ -1318,6 +1319,18 @@ static void imx_pcie_assert_perst(struct imx_pcie *imx_pcie, bool assert)
|
|||
}
|
||||
}
|
||||
|
||||
static bool imx_pcie_perst_found(struct pci_host_bridge *bridge)
|
||||
{
|
||||
struct pci_host_port *port;
|
||||
|
||||
list_for_each_entry(port, &bridge->ports, list) {
|
||||
if (!list_empty(&port->perst))
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static int imx_pcie_host_init(struct dw_pcie_rp *pp)
|
||||
{
|
||||
struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
|
||||
|
|
@ -1330,15 +1343,12 @@ static int imx_pcie_host_init(struct dw_pcie_rp *pp)
|
|||
/* Parse Root Port nodes if present */
|
||||
ret = pci_host_common_parse_ports(dev, bridge);
|
||||
if (ret) {
|
||||
if (ret != -ENODEV) {
|
||||
dev_err(dev, "Failed to parse Root Port nodes: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
dev_err(dev, "Failed to parse Root Port nodes: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Fall back to legacy binding for DT backwards
|
||||
* compatibility
|
||||
*/
|
||||
/* Fall back to legacy binding for DT backwards compatibility */
|
||||
if (!imx_pcie_perst_found(bridge)) {
|
||||
ret = imx_pcie_parse_legacy_binding(imx_pcie);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
|
@ -1373,16 +1383,12 @@ static int imx_pcie_host_init(struct dw_pcie_rp *pp)
|
|||
}
|
||||
}
|
||||
|
||||
ret = pci_pwrctrl_create_devices(dev);
|
||||
if (ret) {
|
||||
dev_err(dev, "failed to create pwrctrl devices\n");
|
||||
goto err_reg_disable;
|
||||
}
|
||||
|
||||
ret = pci_pwrctrl_power_on_devices(dev);
|
||||
if (ret) {
|
||||
dev_err(dev, "failed to power on pwrctrl devices\n");
|
||||
goto err_pwrctrl_destroy;
|
||||
if (!pp->skip_pwrctrl_off) {
|
||||
ret = pci_pwrctrl_power_on_devices(dev);
|
||||
if (ret) {
|
||||
dev_err(dev, "failed to power on pwrctrl devices\n");
|
||||
goto err_reg_disable;
|
||||
}
|
||||
}
|
||||
|
||||
ret = imx_pcie_clk_enable(imx_pcie);
|
||||
|
|
@ -1451,10 +1457,8 @@ static int imx_pcie_host_init(struct dw_pcie_rp *pp)
|
|||
err_clk_disable:
|
||||
imx_pcie_clk_disable(imx_pcie);
|
||||
err_pwrctrl_power_off:
|
||||
pci_pwrctrl_power_off_devices(dev);
|
||||
err_pwrctrl_destroy:
|
||||
if (ret != -EPROBE_DEFER)
|
||||
pci_pwrctrl_destroy_devices(dev);
|
||||
if (!pp->skip_pwrctrl_off)
|
||||
pci_pwrctrl_power_off_devices(dev);
|
||||
err_reg_disable:
|
||||
if (imx_pcie->vpcie)
|
||||
regulator_disable(imx_pcie->vpcie);
|
||||
|
|
@ -1473,7 +1477,8 @@ static void imx_pcie_host_exit(struct dw_pcie_rp *pp)
|
|||
}
|
||||
imx_pcie_clk_disable(imx_pcie);
|
||||
|
||||
pci_pwrctrl_power_off_devices(pci->dev);
|
||||
if (!pci->pp.skip_pwrctrl_off)
|
||||
pci_pwrctrl_power_off_devices(pci->dev);
|
||||
if (imx_pcie->vpcie)
|
||||
regulator_disable(imx_pcie->vpcie);
|
||||
}
|
||||
|
|
@ -1945,11 +1950,15 @@ static int imx_pcie_probe(struct platform_device *pdev)
|
|||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = pci_pwrctrl_create_devices(dev);
|
||||
if (ret)
|
||||
return dev_err_probe(dev, ret, "failed to create pwrctrl devices\n");
|
||||
|
||||
pci->use_parent_dt_ranges = true;
|
||||
if (imx_pcie->drvdata->mode == DW_PCIE_EP_TYPE) {
|
||||
ret = imx_add_pcie_ep(imx_pcie, pdev);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
goto err_pwrctrl_destroy;
|
||||
|
||||
/*
|
||||
* FIXME: Only single Device (EPF) is supported due to the
|
||||
|
|
@ -1957,6 +1966,13 @@ static int imx_pcie_probe(struct platform_device *pdev)
|
|||
*/
|
||||
imx_pcie_add_lut_by_rid(imx_pcie, 0);
|
||||
} else {
|
||||
if (imx_pcie->drvdata->flags & IMX_PCIE_FLAG_PM_RUNTIME) {
|
||||
pm_runtime_no_callbacks(dev);
|
||||
ret = devm_pm_runtime_set_active_enabled(dev);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (imx_check_flag(imx_pcie, IMX_PCIE_FLAG_SKIP_L23_READY))
|
||||
pci->pp.skip_l23_ready = true;
|
||||
if (imx_check_flag(imx_pcie, IMX_PCIE_FLAG_KEEP_MSI_CAP))
|
||||
|
|
@ -1964,7 +1980,7 @@ static int imx_pcie_probe(struct platform_device *pdev)
|
|||
pci->pp.use_atu_msg = true;
|
||||
ret = dw_pcie_host_init(&pci->pp);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
goto err_pwrctrl_destroy;
|
||||
|
||||
if (pci_msi_enabled()) {
|
||||
u8 offset = dw_pcie_find_capability(pci, PCI_CAP_ID_MSI);
|
||||
|
|
@ -1976,6 +1992,11 @@ static int imx_pcie_probe(struct platform_device *pdev)
|
|||
}
|
||||
|
||||
return 0;
|
||||
|
||||
err_pwrctrl_destroy:
|
||||
if (ret != -EPROBE_DEFER)
|
||||
pci_pwrctrl_destroy_devices(dev);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void imx_pcie_shutdown(struct platform_device *pdev)
|
||||
|
|
@ -2100,6 +2121,7 @@ static const struct imx_pcie_drvdata drvdata[] = {
|
|||
.flags = IMX_PCIE_FLAG_HAS_SERDES |
|
||||
IMX_PCIE_FLAG_HAS_LUT |
|
||||
IMX_PCIE_FLAG_8GT_ECN_ERR051586 |
|
||||
IMX_PCIE_FLAG_PM_RUNTIME |
|
||||
IMX_PCIE_FLAG_SUPPORTS_SUSPEND,
|
||||
.ltssm_off = IMX95_PE0_GEN_CTRL_3,
|
||||
.ltssm_mask = IMX95_PCIE_LTSSM_EN,
|
||||
|
|
|
|||
|
|
@ -110,8 +110,7 @@ static int pci_host_common_parse_perst(struct device *dev,
|
|||
* dependencies and the driver may fail to operate if required resources
|
||||
* are missing.
|
||||
*
|
||||
* Return: 0 on success, -ENODEV if PERST# found in RC node (legacy binding
|
||||
* should be used), Other negative error codes on failure.
|
||||
* Return: 0 on success, negative error codes on failure.
|
||||
*/
|
||||
static int pci_host_common_parse_port(struct device *dev,
|
||||
struct pci_host_bridge *bridge,
|
||||
|
|
@ -130,22 +129,6 @@ static int pci_host_common_parse_port(struct device *dev,
|
|||
if (ret)
|
||||
return ret;
|
||||
|
||||
/*
|
||||
* 1. PERST# found in RP or its child nodes - list is not empty,
|
||||
* continue
|
||||
*
|
||||
* 2. PERST# not found in RP/children, but found in RC node -
|
||||
* return -ENODEV to fallback legacy binding
|
||||
*
|
||||
* 3. PERST# not found anywhere - list is empty, continue (optional
|
||||
* PERST#)
|
||||
*/
|
||||
if (list_empty(&port->perst)) {
|
||||
if (of_property_present(dev->of_node, "reset-gpios") ||
|
||||
of_property_present(dev->of_node, "reset-gpio"))
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
INIT_LIST_HEAD(&port->list);
|
||||
list_add_tail(&port->list, &bridge->ports);
|
||||
|
||||
|
|
@ -160,13 +143,11 @@ static int pci_host_common_parse_port(struct device *dev,
|
|||
* Iterate through child nodes of the host bridge and parse Root Port
|
||||
* properties (currently only reset GPIOs).
|
||||
*
|
||||
* Return: 0 on success, -ENODEV if no ports found or PERST# found in RC
|
||||
* node (legacy binding should be used), Other negative error codes on
|
||||
* failure.
|
||||
* Return: 0 on success or ports not found, negative error codes on failure.
|
||||
*/
|
||||
int pci_host_common_parse_ports(struct device *dev, struct pci_host_bridge *bridge)
|
||||
{
|
||||
int ret = -ENODEV;
|
||||
int ret = 0;
|
||||
|
||||
for_each_available_child_of_node_scoped(dev->of_node, of_port) {
|
||||
if (!of_node_is_type(of_port, "pci"))
|
||||
|
|
@ -176,8 +157,8 @@ int pci_host_common_parse_ports(struct device *dev, struct pci_host_bridge *brid
|
|||
goto err_cleanup;
|
||||
}
|
||||
|
||||
if (ret)
|
||||
return ret;
|
||||
if (list_empty(&bridge->ports))
|
||||
return 0;
|
||||
|
||||
return devm_add_action_or_reset(dev, pci_host_common_delete_ports,
|
||||
&bridge->ports);
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user