From nobody Thu Oct 2 19:01:31 2025 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 1414125C821; Fri, 12 Sep 2025 08:35:21 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1757666122; cv=none; b=omQ0pdXZ1QuTCZivzDGjQWgS38k2M/sR7Lo9nJoXgN2SjfoFEUX5flYTotY+FhCgHFo4LyJYxlt4l8s1iOQPnFCO8xjKGqkPdWDRKYmboiJhPM9pOUaqqh9l28E3lQWI7DJo+A2IaU14619ZV4L6edPHAFk9xLWZLf/TFKM69DU= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1757666122; c=relaxed/simple; bh=4e2GIu7b5fa+yMjLUHq3pmSOYoEdO+/TNGnDVcHo+r4=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=kCv3dX4t104v/wV/7uL3SnmgeoiBo8zIQwnvpG3bjGHT6MjkuW9JApIOetp7+Dj2zLPS8Z7BYlljcGYtzVhtvpzTDF/RQkoZQU0Fg9ex+YwvH7JZbgMBuBmJtad1Sp7ysXRA+J1cYS5TosTcJqEUcHT7GJHWNFQ1VvPtIIGMbzk= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=M7jY4Y0b; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="M7jY4Y0b" Received: by smtp.kernel.org (Postfix) with ESMTPS id A1909C4CEF8; Fri, 12 Sep 2025 08:35:21 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1757666121; bh=4e2GIu7b5fa+yMjLUHq3pmSOYoEdO+/TNGnDVcHo+r4=; h=From:Date:Subject:References:In-Reply-To:To:Cc:Reply-To:From; b=M7jY4Y0bkr5xzbRwpi66TXp6xpfyzGqMn4+f0/JkesPUp55lWlsGn2BYFhOdZu/TB ak7DgZ5UCtP+xbMOyWTM21ZTEO3L1e05fs+edGOiZLWSKnpQDNN96DHQuKn9ZzBQOp FhLtqg3vu0VR9PBDQ6oz+5Lvs+0Y8B4dMQyBiNrCSM6560vkcpIv++VyddP39VhkAk zBGybEVhbmJOfdlEqo4UdnFHBVnw25Vxm98TTx7vXY155TLJ7t0xrL9RI0F4LFZACI 3bcuVavpFSfVdAkyjRFhWhNOJKKCS/tXxA7TP5IWuhWD9avSPF1N+3+37cQZ/NVQYz b359YEJf5CHcw== Received: from aws-us-west-2-korg-lkml-1.web.codeaurora.org (localhost.localdomain [127.0.0.1]) by smtp.lore.kernel.org (Postfix) with ESMTP id 8F1A4CAC582; Fri, 12 Sep 2025 08:35:21 +0000 (UTC) From: Manivannan Sadhasivam via B4 Relay Date: Fri, 12 Sep 2025 14:05:01 +0530 Subject: [PATCH v3 1/4] PCI/pwrctrl: Add support for asserting/deasserting PERST# Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20250912-pci-pwrctrl-perst-v3-1-3c0ac62b032c@oss.qualcomm.com> References: <20250912-pci-pwrctrl-perst-v3-0-3c0ac62b032c@oss.qualcomm.com> In-Reply-To: <20250912-pci-pwrctrl-perst-v3-0-3c0ac62b032c@oss.qualcomm.com> To: Manivannan Sadhasivam , Lorenzo Pieralisi , =?utf-8?q?Krzysztof_Wilczy=C5=84ski?= , Rob Herring , Bjorn Helgaas , Bartosz Golaszewski , Saravana Kannan Cc: linux-pci@vger.kernel.org, linux-arm-msm@vger.kernel.org, linux-kernel@vger.kernel.org, devicetree@vger.kernel.org, Krishna Chaitanya Chundru , Brian Norris , Manivannan Sadhasivam X-Mailer: b4 0.14.2 X-Developer-Signature: v=1; a=openpgp-sha256; l=4251; i=manivannan.sadhasivam@oss.qualcomm.com; h=from:subject:message-id; bh=jCv+iKeOMcKQiy+sgTT5FskEFZPk4zscRN+1zwZTLe8=; b=owEBbQGS/pANAwAKAVWfEeb+kc71AcsmYgBow9tHNza8f0jG3b+AspCiBV7VAMWXAy5GxYIcV +W5YLUQLBWJATMEAAEKAB0WIQRnpUMqgUjL2KRYJ5dVnxHm/pHO9QUCaMPbRwAKCRBVnxHm/pHO 9TV+B/0Sb2Sb+ByTUWUhwh9Jb8VcxsX+SYLJX5HFb3MYZsh7tHjpaa+Q6rEIJq4+5aciNw4iOj5 v5FCy4gvVNsws1rRHvO9/lT+hav92CuRXJvDCiGfImYYLERBX2O4q5rn5l4Ms+r3BTMdUFZB2na zR+6Fqa3vKD3CjqSSbRB04VeBMT9HwmFamrMpDwDHh6r/alWJ+0F67epE0UJfFtO2dzcWCdeuji 6pZ7OoUMllq66vwvcgByO5hx8ntSpGfzO036H0CGBcJTKKEc8AdjddiLBLFKkYkNLqqRsJECb50 8CL6tomfbk7Pd+ZMZsSdVf8dxnZF4NVVPcZl4wStPvZTAID4 X-Developer-Key: i=manivannan.sadhasivam@oss.qualcomm.com; a=openpgp; fpr=C668AEC3C3188E4C611465E7488550E901166008 X-Endpoint-Received: by B4 Relay for manivannan.sadhasivam@oss.qualcomm.com/default with auth_id=461 X-Original-From: Manivannan Sadhasivam Reply-To: manivannan.sadhasivam@oss.qualcomm.com From: Manivannan Sadhasivam As per PCIe spec r6.0, sec 6.6.1, PERST# is an auxiliary signal provided by the system to a component as a Fundamental Reset. This signal if available, should conform to the rules defined by the Electromechanical form factor specifications like PCIe CEM spec r4.0, sec 2.2. Since pwrctrl driver is meant to control the power supplies to the PCI components, it should also control the PERST# signal if available. But traditionally, the host bridge (controller) drivers are the ones parsing and controlling the PERST# signal. They also sometimes need to assert PERST# during their own hardware initialization. So it is not possible to move the PERST# control away from the controller drivers and it must be shared logically. Hence, add a new callback 'pci_host_bridge::perst_assert', that allows the pwrctrl core to assert/deassert PERST# with the help of the controller drivers. But care must be taken care by the controller drivers to not deassert the PERST# signal if this callback is populated. This callback if available, will be called by the pwrctrl core during the device power up and power down scenarios. Controller drivers should identify the device using the 'struct device_node' passed during the callback and assert/deassert PERST# accordingly. Signed-off-by: Manivannan Sadhasivam --- drivers/pci/pwrctrl/core.c | 27 +++++++++++++++++++++++++++ include/linux/pci.h | 3 +++ 2 files changed, 30 insertions(+) diff --git a/drivers/pci/pwrctrl/core.c b/drivers/pci/pwrctrl/core.c index 6bdbfed584d6d79ce28ba9e384a596b065ca69a4..54d3dbc24020e979f668bb29444= 8e8429cd8bdd3 100644 --- a/drivers/pci/pwrctrl/core.c +++ b/drivers/pci/pwrctrl/core.c @@ -6,6 +6,7 @@ #include #include #include +#include #include #include #include @@ -61,6 +62,28 @@ void pci_pwrctrl_init(struct pci_pwrctrl *pwrctrl, struc= t device *dev) } EXPORT_SYMBOL_GPL(pci_pwrctrl_init); =20 +static void pci_pwrctrl_perst_deassert(struct pci_pwrctrl *pwrctrl) +{ + struct pci_host_bridge *host_bridge =3D to_pci_host_bridge(pwrctrl->dev->= parent); + struct device_node *np =3D dev_of_node(pwrctrl->dev); + + if (!host_bridge->perst_assert) + return; + + host_bridge->perst_assert(host_bridge, np, false); +} + +static void pci_pwrctrl_perst_assert(struct pci_pwrctrl *pwrctrl) +{ + struct pci_host_bridge *host_bridge =3D to_pci_host_bridge(pwrctrl->dev->= parent); + struct device_node *np =3D dev_of_node(pwrctrl->dev); + + if (!host_bridge->perst_assert) + return; + + host_bridge->perst_assert(host_bridge, np, true); +} + /** * pci_pwrctrl_device_set_ready() - Notify the pwrctrl subsystem that the = PCI * device is powered-up and ready to be detected. @@ -82,6 +105,8 @@ int pci_pwrctrl_device_set_ready(struct pci_pwrctrl *pwr= ctrl) if (!pwrctrl->dev) return -ENODEV; =20 + pci_pwrctrl_perst_deassert(pwrctrl); + pwrctrl->nb.notifier_call =3D pci_pwrctrl_notify; ret =3D bus_register_notifier(&pci_bus_type, &pwrctrl->nb); if (ret) @@ -103,6 +128,8 @@ void pci_pwrctrl_device_unset_ready(struct pci_pwrctrl = *pwrctrl) { cancel_work_sync(&pwrctrl->work); =20 + pci_pwrctrl_perst_assert(pwrctrl); + /* * We don't have to delete the link here. Typically, this function * is only called when the power control device is being detached. If diff --git a/include/linux/pci.h b/include/linux/pci.h index 59876de13860dbe50ee6c207cd57e54f51a11079..08007ef244c0a8bc2be27496bea= 7249ce3e00935 100644 --- a/include/linux/pci.h +++ b/include/linux/pci.h @@ -605,6 +605,9 @@ struct pci_host_bridge { void (*release_fn)(struct pci_host_bridge *); int (*enable_device)(struct pci_host_bridge *bridge, struct pci_dev *dev); void (*disable_device)(struct pci_host_bridge *bridge, struct pci_dev *de= v); +#if IS_ENABLED(CONFIG_PCI_PWRCTRL) + void (*perst_assert)(struct pci_host_bridge *bridge, struct device_node *= np, bool assert); +#endif void *release_data; unsigned int ignore_reset_delay:1; /* For entire hierarchy */ unsigned int no_ext_tags:1; /* No Extended Tags */ --=20 2.45.2 From nobody Thu Oct 2 19:01:31 2025 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 1409C253355; Fri, 12 Sep 2025 08:35:21 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1757666122; cv=none; b=dC3mxVczcXXV21khWDimrjWqLbgumxhoXLqB/b+hIQinStxM2dUCXGjCtlIajTdscBH8lXAJwSt3SaLtpycJ0c7wnDEmeowdAVmbio9zG/iSPjductr6mKlG3hYzPV7F02VOs5Psi7m39mxLJ4ta4gg0t89jtCTiewGerkQRiso= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1757666122; c=relaxed/simple; bh=FiyFCpJ0GFm7SsXs/IRm5ZXJOee0SMylXr70LVM4zbc=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=fZLDFmzgsz3lGIP+z2i6K1m8joBVA1cGq0/Neu9SCZdJ5UFFoFV8b+I/BJ8bIX3qQvP96QQXE0Jmzco7T0IkKmc/jv/opZGcvU1f79MZXHNL5/R+HfBLlgPK+blL1xbhxLHo5YTKx03RAyMnhCfnGknfOQ/fhhkmYPwh3X4Vf0I= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=umYDpvcP; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="umYDpvcP" Received: by smtp.kernel.org (Postfix) with ESMTPS id ACE02C4CEF7; Fri, 12 Sep 2025 08:35:21 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1757666121; bh=FiyFCpJ0GFm7SsXs/IRm5ZXJOee0SMylXr70LVM4zbc=; h=From:Date:Subject:References:In-Reply-To:To:Cc:Reply-To:From; b=umYDpvcPLwsOCsY3cFCDLwD7d2W4aJK8Ktmx7aDFCGY6PZxTvc+jYAocbluPpjE5w TsGGzjeDKa1IilexDNrEVj1rz+hxFR/W4h+wdFKNARIN1svcIomdfHaWQarppweR6m 1D3+Cfkp2rm+k6pTKWHsKuNMXnJW75dpTFgdBaAgzSn2x1reqA082+rULrY/kjdCiZ awY2pE7895eMPke3TGjgOEs+AFFHeb8zOqL2HcPUAG8AnPfwFtJxApQRtSM8ZHypFs 0km10TzdXFjH2wmfb2WxlEYwjQy9j6eUjKgw7jOkVib6aPcH9wkEqBWXveqyA4XPbp CrKUPpZWRaHpw== Received: from aws-us-west-2-korg-lkml-1.web.codeaurora.org (localhost.localdomain [127.0.0.1]) by smtp.lore.kernel.org (Postfix) with ESMTP id 9E890CA101F; Fri, 12 Sep 2025 08:35:21 +0000 (UTC) From: Manivannan Sadhasivam via B4 Relay Date: Fri, 12 Sep 2025 14:05:02 +0530 Subject: [PATCH v3 2/4] PCI: qcom: Move host bridge 'phy' and 'reset' pointers to struct qcom_pcie_port Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20250912-pci-pwrctrl-perst-v3-2-3c0ac62b032c@oss.qualcomm.com> References: <20250912-pci-pwrctrl-perst-v3-0-3c0ac62b032c@oss.qualcomm.com> In-Reply-To: <20250912-pci-pwrctrl-perst-v3-0-3c0ac62b032c@oss.qualcomm.com> To: Manivannan Sadhasivam , Lorenzo Pieralisi , =?utf-8?q?Krzysztof_Wilczy=C5=84ski?= , Rob Herring , Bjorn Helgaas , Bartosz Golaszewski , Saravana Kannan Cc: linux-pci@vger.kernel.org, linux-arm-msm@vger.kernel.org, linux-kernel@vger.kernel.org, devicetree@vger.kernel.org, Krishna Chaitanya Chundru , Brian Norris , Manivannan Sadhasivam , Bjorn Helgaas X-Mailer: b4 0.14.2 X-Developer-Signature: v=1; a=openpgp-sha256; l=5606; i=manivannan.sadhasivam@oss.qualcomm.com; h=from:subject:message-id; bh=ilMHp9ACJpgKD/1mza53pL/FtXeYmnYLmD/AOSCLn64=; b=owEBbQGS/pANAwAKAVWfEeb+kc71AcsmYgBow9tHlBV2ozXmZ6TcjJDPHdZiNQOTQ00RKlaJF sHK9ehx10GJATMEAAEKAB0WIQRnpUMqgUjL2KRYJ5dVnxHm/pHO9QUCaMPbRwAKCRBVnxHm/pHO 9V1iCACAudhIJ/fiXFFRAGifKsnk4g1c/W/IrhCfCqem/LRcwLkUitvhpk4zmwx9M9AJqJnraLS ZvjesBeeNaiyrZ4FWumDQ7ZcBIMsqjqNufSNqDdfW7ZexOWC/OEvao44/mhxH7s6k9KbOkBfUeD BEB/5tjyh8l+pgZg5uCbBuT/TOkiGxez5OcrkNrbNRrg+6q+6pKUCd7RRhdOvSCY8BOmQC4lOyt Pap3jdElUfWWADIwekhNA8Sma+b8dYj6m+GFl+dGC9MA7+wxeujJ7Hk6CxiO6djQE/GFjiyD0pj XDWLLBwjJ4h6mZ4OmZMabd93nQvozvz2VNVxSwl9Y2VNyG3q X-Developer-Key: i=manivannan.sadhasivam@oss.qualcomm.com; a=openpgp; fpr=C668AEC3C3188E4C611465E7488550E901166008 X-Endpoint-Received: by B4 Relay for manivannan.sadhasivam@oss.qualcomm.com/default with auth_id=461 X-Original-From: Manivannan Sadhasivam Reply-To: manivannan.sadhasivam@oss.qualcomm.com From: Manivannan Sadhasivam DT binding allows specifying 'phy' and 'reset' properties in both host bridge and Root Port nodes, though specifying in the host bridge node is marked as deprecated. Still, the pcie-qcom driver should support both combinations for maintaining the DT backwards compatibility. For this purpose, the driver is holding the relevant pointers of these properties in two structs: struct qcom_pcie_port and struct qcom_pcie. However, this causes confusion and increases the driver complexity. Hence, move the pointers from struct qcom_pcie to struct qcom_pcie_port. As a result, even if these properties are specified in the host bridge node, the pointers will be stored in struct qcom_pcie_port as if the properties are specified in a single Root Port node. This logic simplifies the driver a lot. Suggested-by: Bjorn Helgaas Signed-off-by: Manivannan Sadhasivam Reviewed-by: Bjorn Helgaas =20 --- drivers/pci/controller/dwc/pcie-qcom.c | 87 ++++++++++++++----------------= ---- 1 file changed, 36 insertions(+), 51 deletions(-) diff --git a/drivers/pci/controller/dwc/pcie-qcom.c b/drivers/pci/controlle= r/dwc/pcie-qcom.c index 294babe1816e4d0c2b2343fe22d89af72afcd6cd..6170c86f465f43f980f5b2f88bd= 8799c3c152e68 100644 --- a/drivers/pci/controller/dwc/pcie-qcom.c +++ b/drivers/pci/controller/dwc/pcie-qcom.c @@ -279,8 +279,6 @@ struct qcom_pcie { void __iomem *elbi; /* DT elbi */ void __iomem *mhi; union qcom_pcie_resources res; - struct phy *phy; - struct gpio_desc *reset; struct icc_path *icc_mem; struct icc_path *icc_cpu; const struct qcom_pcie_cfg *cfg; @@ -297,11 +295,8 @@ static void qcom_perst_assert(struct qcom_pcie *pcie, = bool assert) struct qcom_pcie_port *port; int val =3D assert ? 1 : 0; =20 - if (list_empty(&pcie->ports)) - gpiod_set_value_cansleep(pcie->reset, val); - else - list_for_each_entry(port, &pcie->ports, list) - gpiod_set_value_cansleep(port->reset, val); + list_for_each_entry(port, &pcie->ports, list) + gpiod_set_value_cansleep(port->reset, val); =20 usleep_range(PERST_DELAY_US, PERST_DELAY_US + 500); } @@ -1253,57 +1248,32 @@ static bool qcom_pcie_link_up(struct dw_pcie *pci) return val & PCI_EXP_LNKSTA_DLLLA; } =20 -static void qcom_pcie_phy_exit(struct qcom_pcie *pcie) -{ - struct qcom_pcie_port *port; - - if (list_empty(&pcie->ports)) - phy_exit(pcie->phy); - else - list_for_each_entry(port, &pcie->ports, list) - phy_exit(port->phy); -} - static void qcom_pcie_phy_power_off(struct qcom_pcie *pcie) { struct qcom_pcie_port *port; =20 - if (list_empty(&pcie->ports)) { - phy_power_off(pcie->phy); - } else { - list_for_each_entry(port, &pcie->ports, list) - phy_power_off(port->phy); - } + list_for_each_entry(port, &pcie->ports, list) + phy_power_off(port->phy); } =20 static int qcom_pcie_phy_power_on(struct qcom_pcie *pcie) { struct qcom_pcie_port *port; - int ret =3D 0; + int ret; =20 - if (list_empty(&pcie->ports)) { - ret =3D phy_set_mode_ext(pcie->phy, PHY_MODE_PCIE, PHY_MODE_PCIE_RC); + list_for_each_entry(port, &pcie->ports, list) { + ret =3D phy_set_mode_ext(port->phy, PHY_MODE_PCIE, PHY_MODE_PCIE_RC); if (ret) return ret; =20 - ret =3D phy_power_on(pcie->phy); - if (ret) + ret =3D phy_power_on(port->phy); + if (ret) { + qcom_pcie_phy_power_off(pcie); return ret; - } else { - list_for_each_entry(port, &pcie->ports, list) { - ret =3D phy_set_mode_ext(port->phy, PHY_MODE_PCIE, PHY_MODE_PCIE_RC); - if (ret) - return ret; - - ret =3D phy_power_on(port->phy); - if (ret) { - qcom_pcie_phy_power_off(pcie); - return ret; - } } } =20 - return ret; + return 0; } =20 static int qcom_pcie_host_init(struct dw_pcie_rp *pp) @@ -1748,8 +1718,10 @@ static int qcom_pcie_parse_ports(struct qcom_pcie *p= cie) return ret; =20 err_port_del: - list_for_each_entry_safe(port, tmp, &pcie->ports, list) + list_for_each_entry_safe(port, tmp, &pcie->ports, list) { + phy_exit(port->phy); list_del(&port->list); + } =20 return ret; } @@ -1757,20 +1729,32 @@ static int qcom_pcie_parse_ports(struct qcom_pcie *= pcie) static int qcom_pcie_parse_legacy_binding(struct qcom_pcie *pcie) { struct device *dev =3D pcie->pci->dev; + struct qcom_pcie_port *port; + struct gpio_desc *reset; + struct phy *phy; int ret; =20 - pcie->phy =3D devm_phy_optional_get(dev, "pciephy"); - if (IS_ERR(pcie->phy)) - return PTR_ERR(pcie->phy); + phy =3D devm_phy_optional_get(dev, "pciephy"); + if (IS_ERR(phy)) + return PTR_ERR(phy); =20 - pcie->reset =3D devm_gpiod_get_optional(dev, "perst", GPIOD_OUT_HIGH); - if (IS_ERR(pcie->reset)) - return PTR_ERR(pcie->reset); + reset =3D devm_gpiod_get_optional(dev, "perst", GPIOD_OUT_HIGH); + if (IS_ERR(reset)) + return PTR_ERR(reset); =20 - ret =3D phy_init(pcie->phy); + ret =3D phy_init(phy); if (ret) return ret; =20 + port =3D devm_kzalloc(dev, sizeof(*port), GFP_KERNEL); + if (!port) + return -ENOMEM; + + port->reset =3D reset; + port->phy =3D phy; + INIT_LIST_HEAD(&port->list); + list_add_tail(&port->list, &pcie->ports); + return 0; } =20 @@ -1984,9 +1968,10 @@ static int qcom_pcie_probe(struct platform_device *p= dev) err_host_deinit: dw_pcie_host_deinit(pp); err_phy_exit: - qcom_pcie_phy_exit(pcie); - list_for_each_entry_safe(port, tmp, &pcie->ports, list) + list_for_each_entry_safe(port, tmp, &pcie->ports, list) { + phy_exit(port->phy); list_del(&port->list); + } err_pm_runtime_put: pm_runtime_put(dev); pm_runtime_disable(dev); --=20 2.45.2 From nobody Thu Oct 2 19:01:31 2025 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 141A627055E; Fri, 12 Sep 2025 08:35:21 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1757666122; cv=none; b=VC2qIch1vZYyQ3bp4Ohs9teOdhyjaDT4piN7OPC8OkS0LaYkXi5xoY/gx+i9XUIwDOVluPbZd3FExJyRikpF6fuw+x4l3rrlLXEhBOLBvb0ZAfRysn5V9ZhN8Zqmuj2qERfY4Ohid92lrmYK8iEknu5nlPmRYKHawcEvrzAxH+g= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1757666122; c=relaxed/simple; bh=irNNqoocV6cMC8yPK5ktlURb049YO1Ahn2UHXklOw7o=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=iFVMGHbk/f+zxL91yr08bM70ZXpCv2a5bh5hezWYYUApec8j10ZanlEGkL73J1XCcxmceWbRk1b0mm+upvhVU3mdjjpHh9Thr/B20RWOa0s8EvpeN0KyqMJ1eSZD8As1GNlxg1OvykquEGOs7Fs1eU7SSdzm/YbE4zv+HinjYtY= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=i9FuGDll; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="i9FuGDll" Received: by smtp.kernel.org (Postfix) with ESMTPS id B988BC4CEFC; Fri, 12 Sep 2025 08:35:21 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1757666121; bh=irNNqoocV6cMC8yPK5ktlURb049YO1Ahn2UHXklOw7o=; h=From:Date:Subject:References:In-Reply-To:To:Cc:Reply-To:From; b=i9FuGDllDea4ls2ZkFk0fQrS1wfdIGd4MFBCynDwgVI0MdgYzV590dZE6vwlQuu6b 0m5x1Wsha5MiJHv87pcmKoGiYrXM4c2z3yx133AIvtYRRKpkr03iocErbZPllz96c2 xbDpjT+b3em8zni5sS1NqAKX5RFI4hd1r7DOdth7+v39n6xOmBOeIUPfduoKC31fYm dZoA2cLSb3oiV9Tu/g2Xpznp9uH1I5jL3Oz0D7t72hPiporWppVVjJi6HNobKBsNxB hoekRmnkCafG5nCY2ZXrUjELuOuSnMPMNXtIIzBEzSG/RU15UAy1QNp5UB50zSHjyC ri6o+eUqdH0Iw== Received: from aws-us-west-2-korg-lkml-1.web.codeaurora.org (localhost.localdomain [127.0.0.1]) by smtp.lore.kernel.org (Postfix) with ESMTP id AD430CAC593; Fri, 12 Sep 2025 08:35:21 +0000 (UTC) From: Manivannan Sadhasivam via B4 Relay Date: Fri, 12 Sep 2025 14:05:03 +0530 Subject: [PATCH v3 3/4] PCI: qcom: Parse PERST# from all PCIe bridge nodes Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20250912-pci-pwrctrl-perst-v3-3-3c0ac62b032c@oss.qualcomm.com> References: <20250912-pci-pwrctrl-perst-v3-0-3c0ac62b032c@oss.qualcomm.com> In-Reply-To: <20250912-pci-pwrctrl-perst-v3-0-3c0ac62b032c@oss.qualcomm.com> To: Manivannan Sadhasivam , Lorenzo Pieralisi , =?utf-8?q?Krzysztof_Wilczy=C5=84ski?= , Rob Herring , Bjorn Helgaas , Bartosz Golaszewski , Saravana Kannan Cc: linux-pci@vger.kernel.org, linux-arm-msm@vger.kernel.org, linux-kernel@vger.kernel.org, devicetree@vger.kernel.org, Krishna Chaitanya Chundru , Brian Norris , Manivannan Sadhasivam X-Mailer: b4 0.14.2 X-Developer-Signature: v=1; a=openpgp-sha256; l=7517; i=manivannan.sadhasivam@oss.qualcomm.com; h=from:subject:message-id; bh=QDTz7IBvhkzaQLzJmC1HhnHhUIFbQuOT+vlqUaWI56I=; b=owEBbQGS/pANAwAKAVWfEeb+kc71AcsmYgBow9tHdqO0cWoEnL+dc9JPuumW0+GrPh0TRFTHK nHsM+uxqZSJATMEAAEKAB0WIQRnpUMqgUjL2KRYJ5dVnxHm/pHO9QUCaMPbRwAKCRBVnxHm/pHO 9X4lB/9b2MmXoPDuYi8sObxLhnSPX7vSJwwBRAIjQxcji/pR9dJPZcp5R0Uv/Wc1VdZL4mgVnI9 YxRq3fSduNuxD2W1LHJSIL9jJw1bPyE6NwQaS6C4CFnUuWBvvq34q+KJX/022QsRBCaWc3b9EPU Ea5ifrCjwH08rU9hOT97u2Wf213kW+P3quMmQWgBmUUmXqnD7ySpEqGQDWy9LcNfl41Pmh93CDH mBXH/qkgxI9XlAf1Pmh3OBZA6HaFfcEH/YZPj7wrvcz19HxbcStiGXbXSd59OPQenoL2AEcN1rq 092ND0bw/+4uu7Y0jos8dXa8i1d8fL+OwCMvie7/W9IAHYM0 X-Developer-Key: i=manivannan.sadhasivam@oss.qualcomm.com; a=openpgp; fpr=C668AEC3C3188E4C611465E7488550E901166008 X-Endpoint-Received: by B4 Relay for manivannan.sadhasivam@oss.qualcomm.com/default with auth_id=461 X-Original-From: Manivannan Sadhasivam Reply-To: manivannan.sadhasivam@oss.qualcomm.com From: Manivannan Sadhasivam Devicetree schema allows the PERST# GPIO to be present in all PCIe bridge nodes, not just in Root Port node. But the current logic parses PERST# only from the Root Port nodes. Though it is not causing any issue on the current platforms, the upcoming platforms will have PERST# in PCIe switch downstream ports also. So this requires parsing all the PCIe bridge nodes for the PERST# GPIO. Hence, rework the parsing logic to extend to all PCIe bridge nodes starting from the Root Port node. If the 'reset-gpios' property is found for a PCI bridge node, the GPIO descriptor will be stored in qcom_pcie_perst::desc and added to the qcom_pcie_port::perst list. It should be noted that if more than one bridge node has the same GPIO for PERST# (shared PERST#), the driver will error out. This is due to the limitation in the GPIOLIB subsystem that allows only exclusive (non-shared) access to GPIOs from consumers. But this is soon going to get fixed. Once that happens, it will get incorporated in this driver. So for now, PERST# sharing is not supported. Signed-off-by: Manivannan Sadhasivam --- drivers/pci/controller/dwc/pcie-qcom.c | 102 +++++++++++++++++++++++++++--= ---- 1 file changed, 85 insertions(+), 17 deletions(-) diff --git a/drivers/pci/controller/dwc/pcie-qcom.c b/drivers/pci/controlle= r/dwc/pcie-qcom.c index 6170c86f465f43f980f5b2f88bd8799c3c152e68..ccff01c31898cdbc5634221e7f8= ef7e86469f5fd 100644 --- a/drivers/pci/controller/dwc/pcie-qcom.c +++ b/drivers/pci/controller/dwc/pcie-qcom.c @@ -267,10 +267,15 @@ struct qcom_pcie_cfg { bool no_l0s; }; =20 +struct qcom_pcie_perst { + struct list_head list; + struct gpio_desc *desc; +}; + struct qcom_pcie_port { struct list_head list; - struct gpio_desc *reset; struct phy *phy; + struct list_head perst; }; =20 struct qcom_pcie { @@ -292,11 +297,14 @@ struct qcom_pcie { =20 static void qcom_perst_assert(struct qcom_pcie *pcie, bool assert) { + struct qcom_pcie_perst *perst; struct qcom_pcie_port *port; int val =3D assert ? 1 : 0; =20 - list_for_each_entry(port, &pcie->ports, list) - gpiod_set_value_cansleep(port->reset, val); + list_for_each_entry(port, &pcie->ports, list) { + list_for_each_entry(perst, &port->perst, list) + gpiod_set_value_cansleep(perst->desc, val); + } =20 usleep_range(PERST_DELAY_US, PERST_DELAY_US + 500); } @@ -1670,18 +1678,58 @@ static const struct pci_ecam_ops pci_qcom_ecam_ops = =3D { } }; =20 -static int qcom_pcie_parse_port(struct qcom_pcie *pcie, struct device_node= *node) +/* Parse PERST# from all nodes in depth first manner starting from @np */ +static int qcom_pcie_parse_perst(struct qcom_pcie *pcie, + struct qcom_pcie_port *port, + struct device_node *np) { struct device *dev =3D pcie->pci->dev; - struct qcom_pcie_port *port; + struct qcom_pcie_perst *perst; struct gpio_desc *reset; - struct phy *phy; int ret; =20 - reset =3D devm_fwnode_gpiod_get(dev, of_fwnode_handle(node), - "reset", GPIOD_OUT_HIGH, "PERST#"); - if (IS_ERR(reset)) + if (!of_find_property(np, "reset-gpios", NULL)) + goto parse_child_node; + + reset =3D devm_fwnode_gpiod_get(dev, of_fwnode_handle(np), "reset", + GPIOD_OUT_HIGH, "PERST#"); + if (IS_ERR(reset)) { + /* + * FIXME: GPIOLIB currently supports exclusive GPIO access only. + * Non exclusive access is broken. But shared PERST# requires + * non-exclusive access. So once GPIOLIB properly supports it, + * implement it here. + */ + if (PTR_ERR(reset) =3D=3D -EBUSY) + dev_err(dev, "Shared PERST# is not supported\n"); + return PTR_ERR(reset); + } + + perst =3D devm_kzalloc(dev, sizeof(*perst), GFP_KERNEL); + if (!perst) + return -ENOMEM; + + INIT_LIST_HEAD(&perst->list); + perst->desc =3D reset; + list_add_tail(&perst->list, &port->perst); + +parse_child_node: + for_each_available_child_of_node_scoped(np, child) { + ret =3D qcom_pcie_parse_perst(pcie, port, child); + if (ret) + return ret; + } + + return 0; +} + +static int qcom_pcie_parse_port(struct qcom_pcie *pcie, struct device_node= *node) +{ + struct device *dev =3D pcie->pci->dev; + struct qcom_pcie_port *port; + struct phy *phy; + int ret; =20 phy =3D devm_of_phy_get(dev, node, NULL); if (IS_ERR(phy)) @@ -1695,7 +1743,12 @@ static int qcom_pcie_parse_port(struct qcom_pcie *pc= ie, struct device_node *node if (ret) return ret; =20 - port->reset =3D reset; + INIT_LIST_HEAD(&port->perst); + + ret =3D qcom_pcie_parse_perst(pcie, port, node); + if (ret) + return ret; + port->phy =3D phy; INIT_LIST_HEAD(&port->list); list_add_tail(&port->list, &pcie->ports); @@ -1705,9 +1758,10 @@ static int qcom_pcie_parse_port(struct qcom_pcie *pc= ie, struct device_node *node =20 static int qcom_pcie_parse_ports(struct qcom_pcie *pcie) { + struct qcom_pcie_perst *perst, *tmp_perst; + struct qcom_pcie_port *port, *tmp_port; struct device *dev =3D pcie->pci->dev; - struct qcom_pcie_port *port, *tmp; - int ret =3D -ENOENT; + int ret =3D -ENODEV; =20 for_each_available_child_of_node_scoped(dev->of_node, of_port) { ret =3D qcom_pcie_parse_port(pcie, of_port); @@ -1718,7 +1772,9 @@ static int qcom_pcie_parse_ports(struct qcom_pcie *pc= ie) return ret; =20 err_port_del: - list_for_each_entry_safe(port, tmp, &pcie->ports, list) { + list_for_each_entry_safe(port, tmp_port, &pcie->ports, list) { + list_for_each_entry_safe(perst, tmp_perst, &port->perst, list) + list_del(&perst->list); phy_exit(port->phy); list_del(&port->list); } @@ -1729,6 +1785,7 @@ static int qcom_pcie_parse_ports(struct qcom_pcie *pc= ie) static int qcom_pcie_parse_legacy_binding(struct qcom_pcie *pcie) { struct device *dev =3D pcie->pci->dev; + struct qcom_pcie_perst *perst; struct qcom_pcie_port *port; struct gpio_desc *reset; struct phy *phy; @@ -1750,19 +1807,28 @@ static int qcom_pcie_parse_legacy_binding(struct qc= om_pcie *pcie) if (!port) return -ENOMEM; =20 - port->reset =3D reset; + perst =3D devm_kzalloc(dev, sizeof(*perst), GFP_KERNEL); + if (!perst) + return -ENOMEM; + port->phy =3D phy; INIT_LIST_HEAD(&port->list); list_add_tail(&port->list, &pcie->ports); =20 + perst->desc =3D reset; + INIT_LIST_HEAD(&port->perst); + INIT_LIST_HEAD(&perst->list); + list_add_tail(&perst->list, &port->perst); + return 0; } =20 static int qcom_pcie_probe(struct platform_device *pdev) { + struct qcom_pcie_perst *perst, *tmp_perst; + struct qcom_pcie_port *port, *tmp_port; const struct qcom_pcie_cfg *pcie_cfg; unsigned long max_freq =3D ULONG_MAX; - struct qcom_pcie_port *port, *tmp; struct device *dev =3D &pdev->dev; struct dev_pm_opp *opp; struct qcom_pcie *pcie; @@ -1909,7 +1975,7 @@ static int qcom_pcie_probe(struct platform_device *pd= ev) =20 ret =3D qcom_pcie_parse_ports(pcie); if (ret) { - if (ret !=3D -ENOENT) { + if (ret !=3D -ENODEV) { dev_err_probe(pci->dev, ret, "Failed to parse Root Port: %d\n", ret); goto err_pm_runtime_put; @@ -1968,7 +2034,9 @@ static int qcom_pcie_probe(struct platform_device *pd= ev) err_host_deinit: dw_pcie_host_deinit(pp); err_phy_exit: - list_for_each_entry_safe(port, tmp, &pcie->ports, list) { + list_for_each_entry_safe(port, tmp_port, &pcie->ports, list) { + list_for_each_entry_safe(perst, tmp_perst, &port->perst, list) + list_del(&perst->list); phy_exit(port->phy); list_del(&port->list); } --=20 2.45.2 From nobody Thu Oct 2 19:01:31 2025 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 142BE272E7C; Fri, 12 Sep 2025 08:35:21 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1757666122; cv=none; b=lCbAUsWVEnJoNOxrCbxcosZlbaIGZhFarNYVjJHBNw2c+kz5v+JFPPpXAyT928SClNB2w+L701UwiNfXS/Tz+fsSSTiQTcRAnLyIH6EBjzUJmQ1f9rZwR+PGCach2pIiD6PuMP9ecv+VkcCzjf1FJdwXftrg9SWliyqVEXF5UQ0= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1757666122; c=relaxed/simple; bh=1BTnQcS0PWwb4QjaWMF5p9KA1L76JzP/XpMvIv4ZNs8=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=VLJ7xumnAJ3TRgscCwcoEV6jyHwCL2TbQVkDaCJcStkbDaOGfiPpikWCmR5J+9HMY22YUp3bXAm34WNoZN8BGyyzwbRWtr90HNHoi3a9yl7eoN6hor/nWMR6qjo24qVBLHm/W5QYaelzQNfhuglzZ9DUol7DG8IBUsktWxraGZk= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=anhO7Tf2; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="anhO7Tf2" Received: by smtp.kernel.org (Postfix) with ESMTPS id C5AA3C4CEFE; Fri, 12 Sep 2025 08:35:21 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1757666121; bh=1BTnQcS0PWwb4QjaWMF5p9KA1L76JzP/XpMvIv4ZNs8=; h=From:Date:Subject:References:In-Reply-To:To:Cc:Reply-To:From; b=anhO7Tf2AI5DffcZZh61WH9p7WR5PI3qlnWguxE5N4D1q8GslYcYtUB1492oSDdeW UBdR85dmUMsxIWdJnHxHG4bmE2pLEu5AuOP95iNvI0G6E98Dbk6w1CImn7m6YyOZIB ja9xyaE+R++TIOH9gNbAB8bQTyTjGxhHM5QF8vayBYyO9UeU+nlPc15I55bB9V/6eR E/1E5nhUzqBAWJKB0YENWkbulILA9zcxYuWAlk0SPB3qwwkSGR1Nl6BLk8WT56kM0c KsrtkYvnlpoFsJPhZj2idfkdP2R3OGKsfKPdJ/lf+1SH0+RRAySIypHddwQJwFKrj1 Gk9DBfeYzADDQ== Received: from aws-us-west-2-korg-lkml-1.web.codeaurora.org (localhost.localdomain [127.0.0.1]) by smtp.lore.kernel.org (Postfix) with ESMTP id BCAABCAC597; Fri, 12 Sep 2025 08:35:21 +0000 (UTC) From: Manivannan Sadhasivam via B4 Relay Date: Fri, 12 Sep 2025 14:05:04 +0530 Subject: [PATCH v3 4/4] PCI: qcom: Allow pwrctrl core to control PERST# if 'reset-gpios' property is available Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20250912-pci-pwrctrl-perst-v3-4-3c0ac62b032c@oss.qualcomm.com> References: <20250912-pci-pwrctrl-perst-v3-0-3c0ac62b032c@oss.qualcomm.com> In-Reply-To: <20250912-pci-pwrctrl-perst-v3-0-3c0ac62b032c@oss.qualcomm.com> To: Manivannan Sadhasivam , Lorenzo Pieralisi , =?utf-8?q?Krzysztof_Wilczy=C5=84ski?= , Rob Herring , Bjorn Helgaas , Bartosz Golaszewski , Saravana Kannan Cc: linux-pci@vger.kernel.org, linux-arm-msm@vger.kernel.org, linux-kernel@vger.kernel.org, devicetree@vger.kernel.org, Krishna Chaitanya Chundru , Brian Norris , Manivannan Sadhasivam X-Mailer: b4 0.14.2 X-Developer-Signature: v=1; a=openpgp-sha256; l=8784; i=manivannan.sadhasivam@oss.qualcomm.com; h=from:subject:message-id; bh=jUiH8ofsOtVd73Yic4FmsZWJD7S+z6vhnX9M4Wlf+90=; b=owEBbQGS/pANAwAKAVWfEeb+kc71AcsmYgBow9tH+At81n57kx2aXYHxHecTmrVvgsmFAxEgl cDyTBhZSX+JATMEAAEKAB0WIQRnpUMqgUjL2KRYJ5dVnxHm/pHO9QUCaMPbRwAKCRBVnxHm/pHO 9eJdCACQwOjXFTNJB91mqFNksQ8I944ZGZa+nhHqJblWwtHJ/n9vzmk6yoyd7OPe0VDuI7VyVFH OfLiHOHwL5HxRHZTYu3EVL8MhW11yxsmAGqH2PXgHCop1WRheY/nj/2IaC9SUyNyhfssZvhrjBx YbWgDRo0pgsfQY0AZFTBK9wRt77xl5Q/c5aJA/XWcUSWhCbe8vAsQ/PmDXSONHtmw9yWoqL3eSI /LTxiI1UcC/pogEE22NsDk8AD/WiLjafjpT/f4EYlzZj0WWrGXkfFz3JM5KfpbEnopmpPHvNxbt Icd1trZ6WUgPlMJp8Ebe9yJ9MRz2Zf89VGyNsz6V6pBGAh6q X-Developer-Key: i=manivannan.sadhasivam@oss.qualcomm.com; a=openpgp; fpr=C668AEC3C3188E4C611465E7488550E901166008 X-Endpoint-Received: by B4 Relay for manivannan.sadhasivam@oss.qualcomm.com/default with auth_id=461 X-Original-From: Manivannan Sadhasivam Reply-To: manivannan.sadhasivam@oss.qualcomm.com From: Manivannan Sadhasivam For historic reasons, the pcie-qcom driver was controlling the power supply and PERST# GPIO of the PCIe slot. This turned out to be an issue as the power supply requirements differ between components. For instance, some of the WLAN chipsets used in Qualcomm systems were connected to the Root Port in a non-standard way using their own connectors. This requires specific power sequencing mechanisms for controlling the WLAN chipsets. So the pwrctrl framework (CONFIG_PWRCTRL) was introduced to handle these custom and complex power supply requirements for components. Sooner, we realized that it would be best to let the pwrctrl driver control the supplies to the PCIe slots also. As it will allow us to consolidate all the power supply handling in one place instead of doing it in two. So the CONFIG_PWRCTRL_SLOT driver was introduced, that just parses the Root Port nodes representing slots and controls the standard power supplies like 3.3v, 3.3VAux etc... However, the control of the PERST# GPIOs was still within the controller drivers like pcie-qcom. So the controller drivers continued to assert/ deassert PERST# GPIOs independent of the power supplies to the components. This mostly went unnoticed as the components tolerated this non-standard PERST# assertion/deassertion. But this behavior completely goes against the PCIe Electromechanical specs like CEM, M.2, as these specs enforce strict control of PERST# signal together with the power supplies. So conform to these specs, allow the pwrctrl core to control PERST# for the slots if the 'reset-gpios' property is specified in the DT bridge nodes. This is achieved by populating the 'pci_host_bridge::perst_assert' callback with qcom_pcie_perst_assert() function, so that the pwrctrl core can control PERST# through this callback. qcom_pcie_perst_assert() will find the PERST# GPIO descriptor associated with the supplied 'device_node' of the component and asserts/deasserts PERST# as requested by the 'assert' parameter. If PERST# is not found in the supplied node of the component, the function will look for PERST# in the parent node as a fallback. This is needed since PERST# won't be available in the endpoint node as per the DT binding. Note that the driver still asserts PERST# during the controller initialization as it is needed as per the hardware documentation. For preserving the backward compatibility with older DTs that still specifies the Root Port resources in the host bridge DT node, the controller driver still controls power supplies and PERST# for them. For those cases, the 'qcom_pcie::legacy_binding' flag will be set and the driver will continue to control PERST# exclusively. If this flag is not set, then the pwrctrl driver will control PERST# through the callback. Signed-off-by: Manivannan Sadhasivam --- drivers/pci/controller/dwc/pcie-qcom.c | 94 ++++++++++++++++++++++++++++++= ---- 1 file changed, 83 insertions(+), 11 deletions(-) diff --git a/drivers/pci/controller/dwc/pcie-qcom.c b/drivers/pci/controlle= r/dwc/pcie-qcom.c index ccff01c31898cdbc5634221e7f8ef7e86469f5fd..f9a8908d6e5dc3e8dd9ab1c210b= fbc5cca1e5be9 100644 --- a/drivers/pci/controller/dwc/pcie-qcom.c +++ b/drivers/pci/controller/dwc/pcie-qcom.c @@ -270,6 +270,7 @@ struct qcom_pcie_cfg { struct qcom_pcie_perst { struct list_head list; struct gpio_desc *desc; + struct device_node *np; }; =20 struct qcom_pcie_port { @@ -291,34 +292,90 @@ struct qcom_pcie { struct list_head ports; bool suspended; bool use_pm_opp; + bool legacy_binding; }; =20 #define to_qcom_pcie(x) dev_get_drvdata((x)->dev) =20 -static void qcom_perst_assert(struct qcom_pcie *pcie, bool assert) +static struct gpio_desc *qcom_find_perst(struct qcom_pcie *pcie, struct de= vice_node *np) +{ + struct qcom_pcie_perst *perst; + struct qcom_pcie_port *port; + + list_for_each_entry(port, &pcie->ports, list) { + list_for_each_entry(perst, &port->perst, list) + if (np =3D=3D perst->np) + return perst->desc; + } + + return NULL; +} + +static void qcom_perst_reset_per_device(struct qcom_pcie *pcie, + struct device_node *np, int val) +{ + struct gpio_desc *perst; + + perst =3D qcom_find_perst(pcie, np); + if (perst) + goto perst_assert; + + /* + * If PERST# is not available in the current node, try the parent. This + * fallback is needed if the current node belongs to an endpoint or + * switch upstream port. + */ + if (np->parent) + perst =3D qcom_find_perst(pcie, np->parent); + +perst_assert: + /* gpiod* APIs handle NULL gpio_desc gracefully. So no need to check. */ + gpiod_set_value_cansleep(perst, val); +} + +static void qcom_perst_reset(struct qcom_pcie *pcie, struct device_node *n= p, + bool assert) { struct qcom_pcie_perst *perst; struct qcom_pcie_port *port; int val =3D assert ? 1 : 0; =20 + if (np) { + qcom_perst_reset_per_device(pcie, np, val); + goto perst_delay; + } + list_for_each_entry(port, &pcie->ports, list) { list_for_each_entry(perst, &port->perst, list) gpiod_set_value_cansleep(perst->desc, val); } =20 +perst_delay: usleep_range(PERST_DELAY_US, PERST_DELAY_US + 500); } =20 -static void qcom_ep_reset_assert(struct qcom_pcie *pcie) +static void qcom_ep_reset_assert(struct qcom_pcie *pcie, struct device_nod= e *np) { - qcom_perst_assert(pcie, true); + qcom_perst_reset(pcie, np, true); } =20 -static void qcom_ep_reset_deassert(struct qcom_pcie *pcie) +static void qcom_ep_reset_deassert(struct qcom_pcie *pcie, + struct device_node *np) { /* Ensure that PERST has been asserted for at least 100 ms */ msleep(PCIE_T_PVPERL_MS); - qcom_perst_assert(pcie, false); + qcom_perst_reset(pcie, np, false); +} + +static void qcom_pcie_perst_assert(struct pci_host_bridge *bridge, + struct device_node *np, bool assert) +{ + struct qcom_pcie *pcie =3D dev_get_drvdata(bridge->dev.parent); + + if (assert) + qcom_ep_reset_assert(pcie, np); + else + qcom_ep_reset_deassert(pcie, np); } =20 static int qcom_pcie_start_link(struct dw_pcie *pci) @@ -1290,7 +1347,7 @@ static int qcom_pcie_host_init(struct dw_pcie_rp *pp) struct qcom_pcie *pcie =3D to_qcom_pcie(pci); int ret; =20 - qcom_ep_reset_assert(pcie); + qcom_ep_reset_assert(pcie, NULL); =20 ret =3D pcie->cfg->ops->init(pcie); if (ret) @@ -1306,7 +1363,13 @@ static int qcom_pcie_host_init(struct dw_pcie_rp *pp) goto err_disable_phy; } =20 - qcom_ep_reset_deassert(pcie); + /* + * Only deassert PERST# for all devices here if legacy binding is used. + * For the new binding, pwrctrl driver is expected to toggle PERST# for + * individual devices. + */ + if (pcie->legacy_binding) + qcom_ep_reset_deassert(pcie, NULL); =20 if (pcie->cfg->ops->config_sid) { ret =3D pcie->cfg->ops->config_sid(pcie); @@ -1314,10 +1377,12 @@ static int qcom_pcie_host_init(struct dw_pcie_rp *p= p) goto err_assert_reset; } =20 + pci->pp.bridge->perst_assert =3D qcom_pcie_perst_assert; + return 0; =20 err_assert_reset: - qcom_ep_reset_assert(pcie); + qcom_ep_reset_assert(pcie, NULL); err_disable_phy: qcom_pcie_phy_power_off(pcie); err_deinit: @@ -1331,7 +1396,7 @@ static void qcom_pcie_host_deinit(struct dw_pcie_rp *= pp) struct dw_pcie *pci =3D to_dw_pcie_from_pp(pp); struct qcom_pcie *pcie =3D to_qcom_pcie(pci); =20 - qcom_ep_reset_assert(pcie); + qcom_ep_reset_assert(pcie, NULL); qcom_pcie_phy_power_off(pcie); pcie->cfg->ops->deinit(pcie); } @@ -1712,6 +1777,9 @@ static int qcom_pcie_parse_perst(struct qcom_pcie *pc= ie, =20 INIT_LIST_HEAD(&perst->list); perst->desc =3D reset; + /* Increase the refcount to make sure 'np' is valid till it is stored */ + of_node_get(np); + perst->np =3D np; list_add_tail(&perst->list, &port->perst); =20 parse_child_node: @@ -1773,8 +1841,10 @@ static int qcom_pcie_parse_ports(struct qcom_pcie *p= cie) =20 err_port_del: list_for_each_entry_safe(port, tmp_port, &pcie->ports, list) { - list_for_each_entry_safe(perst, tmp_perst, &port->perst, list) + list_for_each_entry_safe(perst, tmp_perst, &port->perst, list) { + of_node_put(perst->np); list_del(&perst->list); + } phy_exit(port->phy); list_del(&port->list); } @@ -2035,8 +2105,10 @@ static int qcom_pcie_probe(struct platform_device *p= dev) dw_pcie_host_deinit(pp); err_phy_exit: list_for_each_entry_safe(port, tmp_port, &pcie->ports, list) { - list_for_each_entry_safe(perst, tmp_perst, &port->perst, list) + list_for_each_entry_safe(perst, tmp_perst, &port->perst, list) { + of_node_put(perst->np); list_del(&perst->list); + } phy_exit(port->phy); list_del(&port->list); } --=20 2.45.2