* [PATCH v2 0/8] PCI: Enable Power and configure the QPS615 PCIe switch
@ 2024-08-03 3:22 Krishna chaitanya chundru
2024-08-03 3:22 ` [PATCH v2 1/8] dt-bindings: PCI: Add binding for qps615 Krishna chaitanya chundru
` (12 more replies)
0 siblings, 13 replies; 77+ messages in thread
From: Krishna chaitanya chundru @ 2024-08-03 3:22 UTC (permalink / raw)
To: Lorenzo Pieralisi, Krzysztof Wilczyński, Rob Herring,
Bjorn Helgaas, Krzysztof Kozlowski, Conor Dooley, Konrad Dybcio,
cros-qcom-dts-watchers, Bartosz Golaszewski, Jingoo Han,
Manivannan Sadhasivam
Cc: andersson, quic_vbadigan, linux-arm-msm, linux-pci, devicetree,
linux-kernel, Bartosz Golaszewski, Krishna chaitanya chundru
QPS615 is the PCIe switch which has one upstream and three downstream
ports. One of the downstream ports is used as endpoint device of Ethernet
MAC. Other two downstream ports are supposed to connect to external
device. One Host can connect to QPS615 by upstream port.
QPS615 switch power is controlled by the GPIO's. After powering on
the switch will immediately participate in the link training. if the
host is also ready by that time PCIe link will established.
The QPS615 needs to configured certain parameters like de-emphasis,
disable unused port etc before link is established.
The device tree properties are parsed per node under pci-pci bridge in the
devicetree. Each node has unique bdf value in the reg property, driver
uses this bdf to differentiate ports, as there are certain i2c writes to
select particulat port.
As the controller starts link training before the probe of pwrctl driver,
the PCIe link may come up before configuring the switch itself.
To avoid this introduce two functions in pci_ops to start_link() &
stop_link() which will disable the link training if the PCIe link is
not up yet.
Now PCI pwrctl device is the child of the pci-pcie bridge, if we want
to enable the suspend resume for pwrctl device there may be issues
since pci bridge will try to access some registers in the config which
may cause timeouts or Un clocked access as the power can be removed in
the suspend of pwrctl driver.
To solve this make PCIe controller as parent to the pci pwr ctrl driver
and create devlink between host bridge and pci pwrctl driver so that
pci pwrctl driver will go suspend only after all the PCIe devices went
to suspend.
Signed-off-by: Krishna chaitanya chundru <quic_krichai@quicinc.com>
---
Changes in V1:
- Fix the code as per the comments given.
- Removed D3cold D0 sequence in suspend resume for now as it needs
seperate discussion.
- change to dt approach for configuring the switch instead of request_firmware() approach
- Link to v1: https://lore.kernel.org/linux-pci/20240626-qps615-v1-4-2ade7bd91e02@quicinc.com/T/
---
---
Krishna chaitanya chundru (8):
dt-bindings: PCI: Add binding for qps615
dt-bindings: trivial-devices: Add qcom,qps615
arm64: dts: qcom: qcs6490-rb3gen2: Add node for qps615
PCI: Change the parent to correctly represent pcie hierarchy
PCI: Add new start_link() & stop_link function ops
PCI: dwc: Add support for new pci function op
PCI: qcom: Add support for host_stop_link() & host_start_link()
PCI: pwrctl: Add power control driver for qps615
.../devicetree/bindings/pci/qcom,qps615.yaml | 191 ++++++
.../devicetree/bindings/trivial-devices.yaml | 2 +
arch/arm64/boot/dts/qcom/qcs6490-rb3gen2.dts | 121 ++++
arch/arm64/boot/dts/qcom/sc7280.dtsi | 2 +-
drivers/pci/bus.c | 3 +-
drivers/pci/controller/dwc/pcie-designware-host.c | 18 +
drivers/pci/controller/dwc/pcie-designware.h | 16 +
drivers/pci/controller/dwc/pcie-qcom.c | 39 ++
drivers/pci/pwrctl/Kconfig | 7 +
drivers/pci/pwrctl/Makefile | 1 +
drivers/pci/pwrctl/core.c | 9 +-
drivers/pci/pwrctl/pci-pwrctl-qps615.c | 638 +++++++++++++++++++++
include/linux/pci.h | 2 +
13 files changed, 1046 insertions(+), 3 deletions(-)
---
base-commit: 1722389b0d863056d78287a120a1d6cadb8d4f7b
change-id: 20240727-qps615-e2894a38d36f
Best regards,
--
Krishna chaitanya chundru <quic_krichai@quicinc.com>
^ permalink raw reply [flat|nested] 77+ messages in thread
* [PATCH v2 1/8] dt-bindings: PCI: Add binding for qps615
2024-08-03 3:22 [PATCH v2 0/8] PCI: Enable Power and configure the QPS615 PCIe switch Krishna chaitanya chundru
@ 2024-08-03 3:22 ` Krishna chaitanya chundru
2024-08-03 4:33 ` Rob Herring (Arm)
` (3 more replies)
2024-08-03 3:22 ` [PATCH v2 2/8] dt-bindings: trivial-devices: Add qcom,qps615 Krishna chaitanya chundru
` (11 subsequent siblings)
12 siblings, 4 replies; 77+ messages in thread
From: Krishna chaitanya chundru @ 2024-08-03 3:22 UTC (permalink / raw)
To: Lorenzo Pieralisi, Krzysztof Wilczyński, Rob Herring,
Bjorn Helgaas, Krzysztof Kozlowski, Conor Dooley, Konrad Dybcio,
cros-qcom-dts-watchers, Bartosz Golaszewski, Jingoo Han,
Manivannan Sadhasivam
Cc: andersson, quic_vbadigan, linux-arm-msm, linux-pci, devicetree,
linux-kernel, Bartosz Golaszewski, Krishna chaitanya chundru
Add binding describing the Qualcomm PCIe switch, QPS615,
which provides Ethernet MAC integrated to the 3rd downstream port
and two downstream PCIe ports.
Signed-off-by: Krishna chaitanya chundru <quic_krichai@quicinc.com>
---
.../devicetree/bindings/pci/qcom,qps615.yaml | 191 +++++++++++++++++++++
1 file changed, 191 insertions(+)
diff --git a/Documentation/devicetree/bindings/pci/qcom,qps615.yaml b/Documentation/devicetree/bindings/pci/qcom,qps615.yaml
new file mode 100644
index 000000000000..ea0c953ee56f
--- /dev/null
+++ b/Documentation/devicetree/bindings/pci/qcom,qps615.yaml
@@ -0,0 +1,191 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/pci/qcom,qps615.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Qualcomm QPS615 PCIe switch
+
+maintainers:
+ - Krishna chaitanya chundru <quic_krichai@quicinc.com>
+
+description: |
+ Qualcomm QPS615 PCIe switch has one upstream and three downstream
+ ports. The 3rd downstream port has integrated endpoint device of
+ Ethernet MAC. Other two downstream ports are supposed to connect
+ to external device.
+
+ The QPS615 PCIe switch can be configured through I2C interface before
+ PCIe link is established to change FTS, ASPM related entry delays,
+ tx amplitude etc for better power efficiency and functionality.
+
+properties:
+ compatible:
+ enum:
+ - pci1179,0623
+
+ reg:
+ maxItems: 1
+
+ qcom,qps615-controller:
+ $ref: /schemas/types.yaml#/definitions/phandle
+ description:
+ Reference to the I2C client used to do configure qps615
+
+ vdd18-supply: true
+
+ vdd09-supply: true
+
+ vddc-supply: true
+
+ vddio1-supply: true
+
+ vddio2-supply: true
+
+ vddio18-supply: true
+
+ reset-gpios:
+ maxItems: 1
+ description:
+ GPIO controlling the RESX# pin.
+
+ qps615,axi-clk-freq-hz:
+ description:
+ AXI clock which internal bus of the switch.
+
+ qcom,l0s-entry-delay-ns:
+ description: Aspm l0s entry delay in nanoseconds.
+
+ qcom,l1-entry-delay-ns:
+ description: Aspm l1 entry delay in nanoseconds.
+
+ qcom,tx-amplitude-millivolt:
+ $ref: /schemas/types.yaml#/definitions/uint32
+ description: Change Tx Margin setting for low power consumption.
+
+ qcom,no-dfe:
+ type: boolean
+ description: Disables DFE (Decision Feedback Equalizer).
+
+ qcom,nfts:
+ $ref: /schemas/types.yaml#/definitions/uint8
+ description:
+ Fast Training Sequence (FTS) is the mechanism that
+ is used for bit and Symbol lock.
+
+allOf:
+ - $ref: /schemas/pci/pci-bus-common.yaml#
+ - if:
+ properties:
+ compatible:
+ contains:
+ const: pci1179,0623
+ required:
+ - compatible
+ then:
+ required:
+ - vdd18-supply
+ - vdd09-supply
+ - vddc-supply
+ - vddio1-supply
+ - vddio2-supply
+ - vddio18-supply
+ - qcom,qps615-controller
+ - reset-gpios
+
+patternProperties:
+ "@1?[0-9a-f](,[0-7])?$":
+ type: object
+ $ref: qcom,qps615.yaml#
+ additionalProperties: true
+
+additionalProperties: true
+
+examples:
+ - |
+
+ #include <dt-bindings/gpio/gpio.h>
+
+ pcie {
+ #address-cells = <3>;
+ #size-cells = <2>;
+
+ pcie@0 {
+ device_type = "pci";
+ reg = <0x0 0x0 0x0 0x0 0x0>;
+
+ #address-cells = <3>;
+ #size-cells = <2>;
+ ranges;
+
+ pcie@0,0 {
+ compatible = "pci1179,0623";
+ reg = <0x10000 0x0 0x0 0x0 0x0>;
+ device_type = "pci";
+ #address-cells = <3>;
+ #size-cells = <2>;
+ ranges;
+
+ qcom,qps615-controller = <&qps615_controller>;
+
+ vdd18-supply = <&vdd>;
+ vdd09-supply = <&vdd>;
+ vddc-supply = <&vdd>;
+ vddio1-supply = <&vdd>;
+ vddio2-supply = <&vdd>;
+ vddio18-supply = <&vdd>;
+
+ reset-gpios = <&gpio 1 GPIO_ACTIVE_LOW>;
+
+ pcie@1,0 {
+ reg = <0x20800 0x0 0x0 0x0 0x0>;
+ #address-cells = <3>;
+ #size-cells = <2>;
+ device_type = "pci";
+ ranges;
+
+ qcom,no-dfe;
+ };
+
+ pcie@2,0 {
+ reg = <0x21000 0x0 0x0 0x0 0x0>;
+ #address-cells = <3>;
+ #size-cells = <2>;
+ device_type = "pci";
+ ranges;
+
+ qcom,nfts = /bits/ 8 <10>;
+ };
+
+ pcie@3,0 {
+ reg = <0x21800 0x0 0x0 0x0 0x0>;
+ #address-cells = <3>;
+ #size-cells = <2>;
+ device_type = "pci";
+ ranges;
+
+ qcom,tx-amplitude-millivolt = <10>;
+
+ pcie@0,0 {
+ reg = <0x40000 0x0 0x0 0x0 0x0>;
+ #address-cells = <3>;
+ #size-cells = <2>;
+ device_type = "pci";
+ ranges;
+
+ qcom,l1-entry-delay-ns = <10>;
+ };
+
+ pcie@0,1 {
+ reg = <0x40100 0x0 0x0 0x0 0x0>;
+ #address-cells = <3>;
+ #size-cells = <2>;
+ device_type = "pci";
+ ranges;
+
+ qcom,l0s-entry-delay-ns = <10>;
+ };
+ };
+ };
+ };
+ };
--
2.34.1
^ permalink raw reply related [flat|nested] 77+ messages in thread
* [PATCH v2 2/8] dt-bindings: trivial-devices: Add qcom,qps615
2024-08-03 3:22 [PATCH v2 0/8] PCI: Enable Power and configure the QPS615 PCIe switch Krishna chaitanya chundru
2024-08-03 3:22 ` [PATCH v2 1/8] dt-bindings: PCI: Add binding for qps615 Krishna chaitanya chundru
@ 2024-08-03 3:22 ` Krishna chaitanya chundru
2024-08-04 8:50 ` Krzysztof Kozlowski
2024-08-03 3:22 ` [PATCH v2 3/8] arm64: dts: qcom: qcs6490-rb3gen2: Add node for qps615 Krishna chaitanya chundru
` (10 subsequent siblings)
12 siblings, 1 reply; 77+ messages in thread
From: Krishna chaitanya chundru @ 2024-08-03 3:22 UTC (permalink / raw)
To: Lorenzo Pieralisi, Krzysztof Wilczyński, Rob Herring,
Bjorn Helgaas, Krzysztof Kozlowski, Conor Dooley, Konrad Dybcio,
cros-qcom-dts-watchers, Bartosz Golaszewski, Jingoo Han,
Manivannan Sadhasivam
Cc: andersson, quic_vbadigan, linux-arm-msm, linux-pci, devicetree,
linux-kernel, Bartosz Golaszewski, Krishna chaitanya chundru
qps615 is a PCIe switch which is configured through i2c.
Signed-off-by: Krishna chaitanya chundru <quic_krichai@quicinc.com>
---
Documentation/devicetree/bindings/trivial-devices.yaml | 2 ++
1 file changed, 2 insertions(+)
diff --git a/Documentation/devicetree/bindings/trivial-devices.yaml b/Documentation/devicetree/bindings/trivial-devices.yaml
index 5d3dc952770d..7f44add21bf6 100644
--- a/Documentation/devicetree/bindings/trivial-devices.yaml
+++ b/Documentation/devicetree/bindings/trivial-devices.yaml
@@ -330,6 +330,8 @@ properties:
- renesas,isl29501
# Rohm DH2228FV
- rohm,dh2228fv
+ # Qualcomm QPS615 PCIe switch control
+ - qcom,qps615
# S524AD0XF1 (128K/256K-bit Serial EEPROM for Low Power)
- samsung,24ad0xd1
# Samsung Exynos SoC SATA PHY I2C device
--
2.34.1
^ permalink raw reply related [flat|nested] 77+ messages in thread
* [PATCH v2 3/8] arm64: dts: qcom: qcs6490-rb3gen2: Add node for qps615
2024-08-03 3:22 [PATCH v2 0/8] PCI: Enable Power and configure the QPS615 PCIe switch Krishna chaitanya chundru
2024-08-03 3:22 ` [PATCH v2 1/8] dt-bindings: PCI: Add binding for qps615 Krishna chaitanya chundru
2024-08-03 3:22 ` [PATCH v2 2/8] dt-bindings: trivial-devices: Add qcom,qps615 Krishna chaitanya chundru
@ 2024-08-03 3:22 ` Krishna chaitanya chundru
2024-08-04 8:54 ` Krzysztof Kozlowski
2024-09-09 11:29 ` Caleb Connolly
2024-08-03 3:22 ` [PATCH v2 4/8] PCI: Change the parent to correctly represent pcie hierarchy Krishna chaitanya chundru
` (9 subsequent siblings)
12 siblings, 2 replies; 77+ messages in thread
From: Krishna chaitanya chundru @ 2024-08-03 3:22 UTC (permalink / raw)
To: Lorenzo Pieralisi, Krzysztof Wilczyński, Rob Herring,
Bjorn Helgaas, Krzysztof Kozlowski, Conor Dooley, Konrad Dybcio,
cros-qcom-dts-watchers, Bartosz Golaszewski, Jingoo Han,
Manivannan Sadhasivam
Cc: andersson, quic_vbadigan, linux-arm-msm, linux-pci, devicetree,
linux-kernel, Bartosz Golaszewski, Krishna chaitanya chundru
Add QPS615 PCIe switch node which has 3 downstream ports and in one
downstream port two embedded ethernet devices are present.
Power to the QPS615 is supplied through two LDO regulators, controlled
by two GPIOs, these are added as fixed regulators.
Add i2c device node which is used to configure the switch.
Signed-off-by: Krishna chaitanya chundru <quic_krichai@quicinc.com>
---
arch/arm64/boot/dts/qcom/qcs6490-rb3gen2.dts | 121 +++++++++++++++++++++++++++
arch/arm64/boot/dts/qcom/sc7280.dtsi | 2 +-
2 files changed, 122 insertions(+), 1 deletion(-)
diff --git a/arch/arm64/boot/dts/qcom/qcs6490-rb3gen2.dts b/arch/arm64/boot/dts/qcom/qcs6490-rb3gen2.dts
index 0d45662b8028..59d209768636 100644
--- a/arch/arm64/boot/dts/qcom/qcs6490-rb3gen2.dts
+++ b/arch/arm64/boot/dts/qcom/qcs6490-rb3gen2.dts
@@ -202,6 +202,30 @@ vph_pwr: vph-pwr-regulator {
regulator-min-microvolt = <3700000>;
regulator-max-microvolt = <3700000>;
};
+
+ vdd_ntn_0p9: regulator-vdd-ntn-0p9 {
+ compatible = "regulator-fixed";
+ regulator-name = "VDD_NTN_0P9";
+ gpio = <&pm8350c_gpios 2 GPIO_ACTIVE_HIGH>;
+ regulator-min-microvolt = <899400>;
+ regulator-max-microvolt = <899400>;
+ enable-active-high;
+ pinctrl-0 = <&ntn_0p9_en>;
+ pinctrl-names = "default";
+ regulator-enable-ramp-delay = <4300>;
+ };
+
+ vdd_ntn_1p8: regulator-vdd-ntn-1p8 {
+ compatible = "regulator-fixed";
+ regulator-name = "VDD_NTN_1P8";
+ gpio = <&pm8350c_gpios 3 GPIO_ACTIVE_HIGH>;
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ enable-active-high;
+ pinctrl-0 = <&ntn_1p8_en>;
+ pinctrl-names = "default";
+ regulator-enable-ramp-delay = <10000>;
+ };
};
&apps_rsc {
@@ -595,6 +619,12 @@ lt9611_out: endpoint {
};
};
};
+
+ qps615_switch: pcie-switch@77 {
+ compatible = "qcom,qps615";
+ reg = <0x77>;
+ status = "okay";
+ };
};
&i2c1 {
@@ -688,6 +718,75 @@ &pmk8350_rtc {
status = "okay";
};
+&pcie1 {
+ status = "okay";
+};
+
+&pcieport {
+ pcie@0,0 {
+ compatible = "pci1179,0623";
+ reg = <0x10000 0x0 0x0 0x0 0x0>;
+ #address-cells = <3>;
+ #size-cells = <2>;
+
+ device_type = "pci";
+ ranges;
+
+ vddc-supply = <&vdd_ntn_0p9>;
+ vdd18-supply = <&vdd_ntn_1p8>;
+ vdd09-supply = <&vdd_ntn_0p9>;
+ vddio1-supply = <&vdd_ntn_1p8>;
+ vddio2-supply = <&vdd_ntn_1p8>;
+ vddio18-supply = <&vdd_ntn_1p8>;
+
+ qcom,qps615-controller = <&qps615_switch>;
+
+ reset-gpios = <&pm8350c_gpios 1 GPIO_ACTIVE_LOW>;
+
+ pcie@1,0 {
+ reg = <0x20800 0x0 0x0 0x0 0x0>;
+ #address-cells = <3>;
+ #size-cells = <2>;
+
+ device_type = "pci";
+ ranges;
+ };
+
+ pcie@2,0 {
+ reg = <0x21000 0x0 0x0 0x0 0x0>;
+ #address-cells = <3>;
+ #size-cells = <2>;
+
+ device_type = "pci";
+ ranges;
+ };
+
+ pcie@3,0 {
+ reg = <0x21800 0x0 0x0 0x0 0x0>;
+ #address-cells = <3>;
+ #size-cells = <2>;
+ device_type = "pci";
+ ranges;
+
+ pcie@0,0 {
+ reg = <0x50000 0x0 0x0 0x0 0x0>;
+ #address-cells = <3>;
+ #size-cells = <2>;
+ device_type = "pci";
+ ranges;
+ };
+
+ pcie@0,1 {
+ reg = <0x50100 0x0 0x0 0x0 0x0>;
+ #address-cells = <3>;
+ #size-cells = <2>;
+ device_type = "pci";
+ ranges;
+ };
+ };
+ };
+};
+
&qupv3_id_0 {
status = "okay";
};
@@ -812,6 +911,28 @@ lt9611_rst_pin: lt9611-rst-state {
};
};
+&pm8350c_gpios {
+ ntn_0p9_en: ntn-0p9-en-state {
+ pins = "gpio2";
+ function = "normal";
+
+ bias-disable;
+ input-disable;
+ output-enable;
+ power-source = <0>;
+ };
+
+ ntn_1p8_en: ntn-1p8-en-state {
+ pins = "gpio3";
+ function = "normal";
+
+ bias-disable;
+ input-disable;
+ output-enable;
+ power-source = <0>;
+ };
+};
+
&tlmm {
lt9611_irq_pin: lt9611-irq-state {
pins = "gpio24";
diff --git a/arch/arm64/boot/dts/qcom/sc7280.dtsi b/arch/arm64/boot/dts/qcom/sc7280.dtsi
index 3d8410683402..3840f056b7f2 100644
--- a/arch/arm64/boot/dts/qcom/sc7280.dtsi
+++ b/arch/arm64/boot/dts/qcom/sc7280.dtsi
@@ -2279,7 +2279,7 @@ pcie1: pcie@1c08000 {
status = "disabled";
- pcie@0 {
+ pcieport: pcie@0 {
device_type = "pci";
reg = <0x0 0x0 0x0 0x0 0x0>;
bus-range = <0x01 0xff>;
--
2.34.1
^ permalink raw reply related [flat|nested] 77+ messages in thread
* [PATCH v2 4/8] PCI: Change the parent to correctly represent pcie hierarchy
2024-08-03 3:22 [PATCH v2 0/8] PCI: Enable Power and configure the QPS615 PCIe switch Krishna chaitanya chundru
` (2 preceding siblings ...)
2024-08-03 3:22 ` [PATCH v2 3/8] arm64: dts: qcom: qcs6490-rb3gen2: Add node for qps615 Krishna chaitanya chundru
@ 2024-08-03 3:22 ` Krishna chaitanya chundru
2024-08-06 19:07 ` Bjorn Helgaas
` (2 more replies)
2024-08-03 3:22 ` [PATCH v2 5/8] PCI: Add new start_link() & stop_link function ops Krishna chaitanya chundru
` (8 subsequent siblings)
12 siblings, 3 replies; 77+ messages in thread
From: Krishna chaitanya chundru @ 2024-08-03 3:22 UTC (permalink / raw)
To: Lorenzo Pieralisi, Krzysztof Wilczyński, Rob Herring,
Bjorn Helgaas, Krzysztof Kozlowski, Conor Dooley, Konrad Dybcio,
cros-qcom-dts-watchers, Bartosz Golaszewski, Jingoo Han,
Manivannan Sadhasivam
Cc: andersson, quic_vbadigan, linux-arm-msm, linux-pci, devicetree,
linux-kernel, Bartosz Golaszewski, Krishna chaitanya chundru
Currently the pwrctl driver is child of pci-pci bridge driver,
this will cause issue when suspend resume is introduced in the pwr
control driver. If the supply is removed to the endpoint in the
power control driver then the config space access by the
pci-pci bridge driver can cause issues like Timeouts.
For this reason change the parent to controller from pci-pci bridge.
Fixes: 4565d2652a37 ("PCI/pwrctl: Add PCI power control core code")
Signed-off-by: Krishna chaitanya chundru <quic_krichai@quicinc.com>
---
drivers/pci/bus.c | 3 ++-
drivers/pci/pwrctl/core.c | 9 ++++++++-
2 files changed, 10 insertions(+), 2 deletions(-)
diff --git a/drivers/pci/bus.c b/drivers/pci/bus.c
index 55c853686051..15b42f0f588f 100644
--- a/drivers/pci/bus.c
+++ b/drivers/pci/bus.c
@@ -328,6 +328,7 @@ void __weak pcibios_bus_add_device(struct pci_dev *pdev) { }
*/
void pci_bus_add_device(struct pci_dev *dev)
{
+ struct pci_host_bridge *host = pci_find_host_bridge(dev->bus);
struct device_node *dn = dev->dev.of_node;
int retval;
@@ -352,7 +353,7 @@ void pci_bus_add_device(struct pci_dev *dev)
if (dev_of_node(&dev->dev) && pci_is_bridge(dev)) {
retval = of_platform_populate(dev_of_node(&dev->dev), NULL, NULL,
- &dev->dev);
+ host->dev.parent);
if (retval)
pci_err(dev, "failed to populate child OF nodes (%d)\n",
retval);
diff --git a/drivers/pci/pwrctl/core.c b/drivers/pci/pwrctl/core.c
index feca26ad2f6a..4f2ffa0b0a5f 100644
--- a/drivers/pci/pwrctl/core.c
+++ b/drivers/pci/pwrctl/core.c
@@ -11,6 +11,8 @@
#include <linux/property.h>
#include <linux/slab.h>
+#include "../pci.h"
+
static int pci_pwrctl_notify(struct notifier_block *nb, unsigned long action,
void *data)
{
@@ -64,18 +66,23 @@ static int pci_pwrctl_notify(struct notifier_block *nb, unsigned long action,
*/
int pci_pwrctl_device_set_ready(struct pci_pwrctl *pwrctl)
{
+ struct pci_bus *bus;
int ret;
if (!pwrctl->dev)
return -ENODEV;
+ bus = pci_find_bus(of_get_pci_domain_nr(pwrctl->dev->parent->of_node), 0);
+ if (!bus)
+ return -ENODEV;
+
pwrctl->nb.notifier_call = pci_pwrctl_notify;
ret = bus_register_notifier(&pci_bus_type, &pwrctl->nb);
if (ret)
return ret;
pci_lock_rescan_remove();
- pci_rescan_bus(to_pci_dev(pwrctl->dev->parent)->bus);
+ pci_rescan_bus(bus);
pci_unlock_rescan_remove();
return 0;
--
2.34.1
^ permalink raw reply related [flat|nested] 77+ messages in thread
* [PATCH v2 5/8] PCI: Add new start_link() & stop_link function ops
2024-08-03 3:22 [PATCH v2 0/8] PCI: Enable Power and configure the QPS615 PCIe switch Krishna chaitanya chundru
` (3 preceding siblings ...)
2024-08-03 3:22 ` [PATCH v2 4/8] PCI: Change the parent to correctly represent pcie hierarchy Krishna chaitanya chundru
@ 2024-08-03 3:22 ` Krishna chaitanya chundru
2024-08-03 3:22 ` [PATCH v2 6/8] PCI: dwc: Add support for new pci function op Krishna chaitanya chundru
` (7 subsequent siblings)
12 siblings, 0 replies; 77+ messages in thread
From: Krishna chaitanya chundru @ 2024-08-03 3:22 UTC (permalink / raw)
To: Lorenzo Pieralisi, Krzysztof Wilczyński, Rob Herring,
Bjorn Helgaas, Krzysztof Kozlowski, Conor Dooley, Konrad Dybcio,
cros-qcom-dts-watchers, Bartosz Golaszewski, Jingoo Han,
Manivannan Sadhasivam
Cc: andersson, quic_vbadigan, linux-arm-msm, linux-pci, devicetree,
linux-kernel, Bartosz Golaszewski, Krishna chaitanya chundru
Certain devices like QPS615 which uses PCI pwrctl framework
needs to configure the device before PCI link is up.
If the controller driver already enables link training as part of
its probe, after the device is powered on, controller and device
participates in the link training and link can come up immediately
and maynot have time to configure the device.
So we need to stop the link training by using stop_link() and enable
them back after device is configured by using start_link().
Signed-off-by: Krishna chaitanya chundru <quic_krichai@quicinc.com>
---
include/linux/pci.h | 2 ++
1 file changed, 2 insertions(+)
diff --git a/include/linux/pci.h b/include/linux/pci.h
index 4cf89a4b4cbc..0791d74951e9 100644
--- a/include/linux/pci.h
+++ b/include/linux/pci.h
@@ -802,6 +802,8 @@ struct pci_ops {
void __iomem *(*map_bus)(struct pci_bus *bus, unsigned int devfn, int where);
int (*read)(struct pci_bus *bus, unsigned int devfn, int where, int size, u32 *val);
int (*write)(struct pci_bus *bus, unsigned int devfn, int where, int size, u32 val);
+ int (*start_link)(struct pci_bus *bus);
+ void (*stop_link)(struct pci_bus *bus);
};
/*
--
2.34.1
^ permalink raw reply related [flat|nested] 77+ messages in thread
* [PATCH v2 6/8] PCI: dwc: Add support for new pci function op
2024-08-03 3:22 [PATCH v2 0/8] PCI: Enable Power and configure the QPS615 PCIe switch Krishna chaitanya chundru
` (4 preceding siblings ...)
2024-08-03 3:22 ` [PATCH v2 5/8] PCI: Add new start_link() & stop_link function ops Krishna chaitanya chundru
@ 2024-08-03 3:22 ` Krishna chaitanya chundru
2024-08-03 3:22 ` [PATCH v2 7/8] PCI: qcom: Add support for host_stop_link() & host_start_link() Krishna chaitanya chundru
` (6 subsequent siblings)
12 siblings, 0 replies; 77+ messages in thread
From: Krishna chaitanya chundru @ 2024-08-03 3:22 UTC (permalink / raw)
To: Lorenzo Pieralisi, Krzysztof Wilczyński, Rob Herring,
Bjorn Helgaas, Krzysztof Kozlowski, Conor Dooley, Konrad Dybcio,
cros-qcom-dts-watchers, Bartosz Golaszewski, Jingoo Han,
Manivannan Sadhasivam
Cc: andersson, quic_vbadigan, linux-arm-msm, linux-pci, devicetree,
linux-kernel, Bartosz Golaszewski, Krishna chaitanya chundru
Add the support for stop_link() and start_link() function op.
Signed-off-by: Krishna chaitanya chundru <quic_krichai@quicinc.com>
---
drivers/pci/controller/dwc/pcie-designware-host.c | 18 ++++++++++++++++++
drivers/pci/controller/dwc/pcie-designware.h | 16 ++++++++++++++++
2 files changed, 34 insertions(+)
diff --git a/drivers/pci/controller/dwc/pcie-designware-host.c b/drivers/pci/controller/dwc/pcie-designware-host.c
index a0822d5371bc..a1d994334ca5 100644
--- a/drivers/pci/controller/dwc/pcie-designware-host.c
+++ b/drivers/pci/controller/dwc/pcie-designware-host.c
@@ -697,10 +697,28 @@ void __iomem *dw_pcie_own_conf_map_bus(struct pci_bus *bus, unsigned int devfn,
}
EXPORT_SYMBOL_GPL(dw_pcie_own_conf_map_bus);
+static int dw_pcie_op_start_link(struct pci_bus *bus)
+{
+ struct dw_pcie_rp *pp = bus->sysdata;
+ struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
+
+ return dw_pcie_host_start_link(pci);
+}
+
+static void dw_pcie_op_stop_link(struct pci_bus *bus)
+{
+ struct dw_pcie_rp *pp = bus->sysdata;
+ struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
+
+ dw_pcie_host_stop_link(pci);
+}
+
static struct pci_ops dw_pcie_ops = {
.map_bus = dw_pcie_own_conf_map_bus,
.read = pci_generic_config_read,
.write = pci_generic_config_write,
+ .start_link = dw_pcie_op_start_link,
+ .stop_link = dw_pcie_op_stop_link,
};
static int dw_pcie_iatu_setup(struct dw_pcie_rp *pp)
diff --git a/drivers/pci/controller/dwc/pcie-designware.h b/drivers/pci/controller/dwc/pcie-designware.h
index 53c4c8f399c8..1aa1f8be8bda 100644
--- a/drivers/pci/controller/dwc/pcie-designware.h
+++ b/drivers/pci/controller/dwc/pcie-designware.h
@@ -402,6 +402,8 @@ struct dw_pcie_ops {
enum dw_pcie_ltssm (*get_ltssm)(struct dw_pcie *pcie);
int (*start_link)(struct dw_pcie *pcie);
void (*stop_link)(struct dw_pcie *pcie);
+ int (*host_start_link)(struct dw_pcie *pcie);
+ void (*host_stop_link)(struct dw_pcie *pcie);
};
struct dw_pcie {
@@ -632,6 +634,20 @@ static inline void dw_pcie_stop_link(struct dw_pcie *pci)
pci->ops->stop_link(pci);
}
+static inline int dw_pcie_host_start_link(struct dw_pcie *pci)
+{
+ if (pci->ops && pci->ops->host_start_link)
+ return pci->ops->host_start_link(pci);
+
+ return 0;
+}
+
+static inline void dw_pcie_host_stop_link(struct dw_pcie *pci)
+{
+ if (pci->ops && pci->ops->host_stop_link)
+ pci->ops->host_stop_link(pci);
+}
+
static inline enum dw_pcie_ltssm dw_pcie_get_ltssm(struct dw_pcie *pci)
{
u32 val;
--
2.34.1
^ permalink raw reply related [flat|nested] 77+ messages in thread
* [PATCH v2 7/8] PCI: qcom: Add support for host_stop_link() & host_start_link()
2024-08-03 3:22 [PATCH v2 0/8] PCI: Enable Power and configure the QPS615 PCIe switch Krishna chaitanya chundru
` (5 preceding siblings ...)
2024-08-03 3:22 ` [PATCH v2 6/8] PCI: dwc: Add support for new pci function op Krishna chaitanya chundru
@ 2024-08-03 3:22 ` Krishna chaitanya chundru
2024-08-06 19:12 ` Bjorn Helgaas
2024-08-03 3:22 ` [PATCH v2 8/8] PCI: pwrctl: Add power control driver for qps615 Krishna chaitanya chundru
` (5 subsequent siblings)
12 siblings, 1 reply; 77+ messages in thread
From: Krishna chaitanya chundru @ 2024-08-03 3:22 UTC (permalink / raw)
To: Lorenzo Pieralisi, Krzysztof Wilczyński, Rob Herring,
Bjorn Helgaas, Krzysztof Kozlowski, Conor Dooley, Konrad Dybcio,
cros-qcom-dts-watchers, Bartosz Golaszewski, Jingoo Han,
Manivannan Sadhasivam
Cc: andersson, quic_vbadigan, linux-arm-msm, linux-pci, devicetree,
linux-kernel, Bartosz Golaszewski, Krishna chaitanya chundru
For the switches like QPS615 which needs to configure it before
the PCIe link is established.
if the link is not up assert the PERST# and disable LTSSM bit so
that PCIe controller will not participate in the link training
as part of host_stop_link().
De-assert the PERST# and enable LTSSM bit back in host_start_link().
Introduce ltssm_disable function op to stop the link training.
Signed-off-by: Krishna chaitanya chundru <quic_krichai@quicinc.com>
---
drivers/pci/controller/dwc/pcie-qcom.c | 39 ++++++++++++++++++++++++++++++++++
1 file changed, 39 insertions(+)
diff --git a/drivers/pci/controller/dwc/pcie-qcom.c b/drivers/pci/controller/dwc/pcie-qcom.c
index 0180edf3310e..f4a6df53139c 100644
--- a/drivers/pci/controller/dwc/pcie-qcom.c
+++ b/drivers/pci/controller/dwc/pcie-qcom.c
@@ -233,6 +233,7 @@ struct qcom_pcie_ops {
void (*host_post_init)(struct qcom_pcie *pcie);
void (*deinit)(struct qcom_pcie *pcie);
void (*ltssm_enable)(struct qcom_pcie *pcie);
+ void (*ltssm_disable)(struct qcom_pcie *pcie);
int (*config_sid)(struct qcom_pcie *pcie);
};
@@ -555,6 +556,41 @@ static int qcom_pcie_post_init_1_0_0(struct qcom_pcie *pcie)
return 0;
}
+static int qcom_pcie_host_start_link(struct dw_pcie *pci)
+{
+ struct qcom_pcie *pcie = to_qcom_pcie(pci);
+
+ if (!dw_pcie_link_up(pcie->pci)) {
+ qcom_ep_reset_deassert(pcie);
+
+ if (pcie->cfg->ops->ltssm_enable)
+ pcie->cfg->ops->ltssm_enable(pcie);
+ }
+
+ return 0;
+}
+
+static void qcom_pcie_host_stop_link(struct dw_pcie *pci)
+{
+ struct qcom_pcie *pcie = to_qcom_pcie(pci);
+
+ if (!dw_pcie_link_up(pcie->pci)) {
+ qcom_ep_reset_assert(pcie);
+
+ if (pcie->cfg->ops->ltssm_disable)
+ pcie->cfg->ops->ltssm_disable(pcie);
+ }
+}
+
+static void qcom_pcie_2_3_2_ltssm_disable(struct qcom_pcie *pcie)
+{
+ u32 val;
+
+ val = readl(pcie->parf + PARF_LTSSM);
+ val &= ~LTSSM_EN;
+ writel(val, pcie->parf + PARF_LTSSM);
+}
+
static void qcom_pcie_2_3_2_ltssm_enable(struct qcom_pcie *pcie)
{
u32 val;
@@ -1306,6 +1342,7 @@ static const struct qcom_pcie_ops ops_1_9_0 = {
.host_post_init = qcom_pcie_host_post_init_2_7_0,
.deinit = qcom_pcie_deinit_2_7_0,
.ltssm_enable = qcom_pcie_2_3_2_ltssm_enable,
+ .ltssm_disable = qcom_pcie_2_3_2_ltssm_disable,
.config_sid = qcom_pcie_config_sid_1_9_0,
};
@@ -1363,6 +1400,8 @@ static const struct qcom_pcie_cfg cfg_sc8280xp = {
static const struct dw_pcie_ops dw_pcie_ops = {
.link_up = qcom_pcie_link_up,
.start_link = qcom_pcie_start_link,
+ .host_start_link = qcom_pcie_host_start_link,
+ .host_stop_link = qcom_pcie_host_stop_link,
};
static int qcom_pcie_icc_init(struct qcom_pcie *pcie)
--
2.34.1
^ permalink raw reply related [flat|nested] 77+ messages in thread
* [PATCH v2 8/8] PCI: pwrctl: Add power control driver for qps615
2024-08-03 3:22 [PATCH v2 0/8] PCI: Enable Power and configure the QPS615 PCIe switch Krishna chaitanya chundru
` (6 preceding siblings ...)
2024-08-03 3:22 ` [PATCH v2 7/8] PCI: qcom: Add support for host_stop_link() & host_start_link() Krishna chaitanya chundru
@ 2024-08-03 3:22 ` Krishna chaitanya chundru
2024-08-03 11:34 ` Dmitry Baryshkov
2024-08-03 10:56 ` [PATCH v2 0/8] PCI: Enable Power and configure the QPS615 PCIe switch Dmitry Baryshkov
` (4 subsequent siblings)
12 siblings, 1 reply; 77+ messages in thread
From: Krishna chaitanya chundru @ 2024-08-03 3:22 UTC (permalink / raw)
To: Lorenzo Pieralisi, Krzysztof Wilczyński, Rob Herring,
Bjorn Helgaas, Krzysztof Kozlowski, Conor Dooley, Konrad Dybcio,
cros-qcom-dts-watchers, Bartosz Golaszewski, Jingoo Han,
Manivannan Sadhasivam
Cc: andersson, quic_vbadigan, linux-arm-msm, linux-pci, devicetree,
linux-kernel, Bartosz Golaszewski, Krishna chaitanya chundru
QPS615 switch needs to be configured after powering on and before
PCIe link was up.
As the PCIe controller driver already enables the PCIe link training
at the host side, stop the link training. Otherwise the moment we turn
on the switch it will participate in the link training and link may come
up before switch is configured through i2c.
The device tree properties are parsed per node under pci-pci bridge in the
driver. Each node has unique bdf value in the reg property, driver
uses this bdf to differentiate ports, as there are certain i2c writes to
select particular port.
Based up on dt property and port, qps615 is configured through i2c.
Signed-off-by: Krishna chaitanya chundru <quic_krichai@quicinc.com>
---
drivers/pci/pwrctl/Kconfig | 7 +
drivers/pci/pwrctl/Makefile | 1 +
drivers/pci/pwrctl/pci-pwrctl-qps615.c | 638 +++++++++++++++++++++++++++++++++
3 files changed, 646 insertions(+)
diff --git a/drivers/pci/pwrctl/Kconfig b/drivers/pci/pwrctl/Kconfig
index 54589bb2403b..6a1352af918c 100644
--- a/drivers/pci/pwrctl/Kconfig
+++ b/drivers/pci/pwrctl/Kconfig
@@ -10,3 +10,10 @@ config PCI_PWRCTL_PWRSEQ
tristate
select POWER_SEQUENCING
select PCI_PWRCTL
+
+config PCI_PWRCTL_QPS615
+ tristate "PCI Power Control driver for QPS615"
+ select PCI_PWRCTL
+ help
+ Say Y here to enable the pwrctl driver for Qualcomm
+ QPS615 PCIe switch.
diff --git a/drivers/pci/pwrctl/Makefile b/drivers/pci/pwrctl/Makefile
index d308aae4800c..ac563a70c023 100644
--- a/drivers/pci/pwrctl/Makefile
+++ b/drivers/pci/pwrctl/Makefile
@@ -4,3 +4,4 @@ obj-$(CONFIG_PCI_PWRCTL) += pci-pwrctl-core.o
pci-pwrctl-core-y := core.o
obj-$(CONFIG_PCI_PWRCTL_PWRSEQ) += pci-pwrctl-pwrseq.o
+obj-$(CONFIG_PCI_PWRCTL_QPS615) += pci-pwrctl-qps615.o
diff --git a/drivers/pci/pwrctl/pci-pwrctl-qps615.c b/drivers/pci/pwrctl/pci-pwrctl-qps615.c
new file mode 100644
index 000000000000..9dabb82787d5
--- /dev/null
+++ b/drivers/pci/pwrctl/pci-pwrctl-qps615.c
@@ -0,0 +1,638 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (c) 2024 Qualcomm Innovation Center, Inc. All rights reserved.
+ */
+
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/firmware.h>
+#include <linux/i2c.h>
+#include <linux/mod_devicetable.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/pci.h>
+#include <linux/pci-pwrctl.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/consumer.h>
+#include <linux/string.h>
+#include <linux/types.h>
+
+#include "../pci.h"
+
+#define QPS615_GPIO_CONFIG 0x801208
+#define QPS615_RESET_GPIO 0x801210
+
+#define QPS615_BUS_CONTROL 0x801014
+
+#define QPS615_PORT_L0S_DELAY 0x82496c
+#define QPS615_PORT_L1_DELAY 0x824970
+
+#define QPS615_EMBEDDED_ETH_DELAY 0x8200d8
+#define QPS615_ETH_L1_DELAY_MASK GENMASK(27, 18)
+#define QPS615_ETH_L1_DELAY_VALUE(x) FIELD_PREP(QPS615_ETH_L1_DELAY_MASK, x)
+#define QPS615_ETH_L0S_DELAY_MASK GENMASK(17, 13)
+#define QPS615_ETH_L0S_DELAY_VALUE(x) FIELD_PREP(QPS615_ETH_L0S_DELAY_MASK, x)
+
+#define QPS615_NFTS_2_5_GT 0x824978
+#define QPS615_NFTS_5_GT 0x82497c
+
+#define QPS615_PORT_LANE_ACCESS_ENABLE 0x828000
+
+#define QPS615_PHY_RATE_CHANGE_OVERRIDE 0x828040
+#define QPS615_PHY_RATE_CHANGE 0x828050
+
+#define QPS615_TX_MARGIN 0x828234
+
+#define QPS615_DFE_ENABLE 0x828a04
+#define QPS615_DFE_EQ0_MODE 0x828a08
+#define QPS615_DFE_EQ1_MODE 0x828a0c
+#define QPS615_DFE_EQ2_MODE 0x828a14
+#define QPS615_DFE_PD_MASK 0x828254
+
+#define QPS615_PORT_SELECT 0x82c02c
+#define QPS615_PORT_ACCESS_ENABLE 0x82c030
+
+#define QPS615_POWER_CONTROL 0x82b09c
+#define QPS615_POWER_CONTROL_OVREN 0x82b2c8
+
+#define QPS615_AXI_CLK_FREQ_MHZ 125
+
+struct qps615_pwrctl_reg_setting {
+ unsigned int offset;
+ unsigned int val;
+};
+
+struct qps615_pwrctl_bdf_info {
+ u16 usp_bdf;
+ u16 dsp1_bdf;
+ u16 dsp2_bdf;
+ u16 dsp3_bdf;
+};
+
+enum qps615_pwrctl_ports {
+ QPS615_USP,
+ QPS615_DSP1,
+ QPS615_DSP2,
+ QPS615_DSP3,
+ QPS615_ETHERNET,
+ QPS615_MAX
+};
+
+struct qps615_pwrctl_cfg {
+ u32 l0s_delay;
+ u32 l1_delay;
+ u32 tx_amp;
+ u32 axi_freq;
+ u8 nfts;
+ bool disable_dfe;
+ bool disable_port;
+};
+
+#define QPS615_PWRCTL_MAX_SUPPLY 6
+
+struct qps615_pwrctl_ctx {
+ struct regulator_bulk_data supplies[QPS615_PWRCTL_MAX_SUPPLY];
+ const struct qps615_pwrctl_bdf_info *bdf;
+ struct qps615_pwrctl_cfg cfg[QPS615_MAX];
+ struct gpio_desc *reset_gpio;
+ struct i2c_client *client;
+ struct pci_pwrctl pwrctl;
+ struct device_link *link;
+};
+
+/*
+ * downstream port power off sequence, hardcoding the address
+ * as we don't know register names for these register offsets.
+ */
+static const struct qps615_pwrctl_reg_setting common_pwroff_seq[] = {
+ {0x82900c, 0x1},
+ {0x829010, 0x1},
+ {0x829018, 0x0},
+ {0x829020, 0x1},
+ {0x82902c, 0x1},
+ {0x829030, 0x1},
+ {0x82903c, 0x1},
+ {0x829058, 0x0},
+ {0x82905c, 0x1},
+ {0x829060, 0x1},
+ {0x8290cc, 0x1},
+ {0x8290d0, 0x1},
+ {0x8290d8, 0x1},
+ {0x8290e0, 0x1},
+ {0x8290e8, 0x1},
+ {0x8290ec, 0x1},
+ {0x8290f4, 0x1},
+ {0x82910c, 0x1},
+ {0x829110, 0x1},
+ {0x829114, 0x1},
+};
+
+static const struct qps615_pwrctl_reg_setting dsp1_pwroff_seq[] = {
+ {QPS615_PORT_ACCESS_ENABLE, 0x2},
+ {QPS615_PORT_LANE_ACCESS_ENABLE, 0x3},
+ {QPS615_POWER_CONTROL, 0x014f4804},
+ {QPS615_POWER_CONTROL_OVREN, 0x1},
+ {QPS615_PORT_ACCESS_ENABLE, 0x4},
+};
+
+static const struct qps615_pwrctl_reg_setting dsp2_pwroff_seq[] = {
+ {QPS615_PORT_ACCESS_ENABLE, 0x8},
+ {QPS615_PORT_LANE_ACCESS_ENABLE, 0x1},
+ {QPS615_POWER_CONTROL, 0x014f4804},
+ {QPS615_POWER_CONTROL_OVREN, 0x1},
+ {QPS615_PORT_ACCESS_ENABLE, 0x8},
+};
+
+static int qps615_pwrctl_i2c_write(struct i2c_client *client,
+ u32 reg_addr, u32 reg_val)
+{
+ struct i2c_msg msg;
+ u8 msg_buf[7];
+ int ret;
+
+ msg.addr = client->addr;
+ msg.len = 7;
+ msg.flags = 0;
+
+ /* Big Endian for reg addr */
+ reg_addr = cpu_to_be32(reg_addr);
+
+ msg_buf[0] = (u8)(reg_addr >> 8);
+ msg_buf[1] = (u8)(reg_addr >> 16);
+ msg_buf[2] = (u8)(reg_addr >> 24);
+
+ /* Little Endian for reg val */
+ reg_val = cpu_to_le32(reg_val);
+
+ msg_buf[3] = (u8)(reg_val);
+ msg_buf[4] = (u8)(reg_val >> 8);
+ msg_buf[5] = (u8)(reg_val >> 16);
+ msg_buf[6] = (u8)(reg_val >> 24);
+
+ msg.buf = msg_buf;
+ ret = i2c_transfer(client->adapter, &msg, 1);
+ return ret == 1 ? 0 : ret;
+}
+
+static int qps615_pwrctl_i2c_read(struct i2c_client *client,
+ u32 reg_addr, u32 *reg_val)
+{
+ struct i2c_msg msg[2];
+ u8 wr_data[3];
+ u32 rd_data;
+ int ret;
+
+ msg[0].addr = client->addr;
+ msg[0].len = 3;
+ msg[0].flags = 0;
+
+ /* Big Endian for reg addr */
+ reg_addr = cpu_to_be32(reg_addr);
+
+ wr_data[0] = (u8)(reg_addr >> 8);
+ wr_data[1] = (u8)(reg_addr >> 16);
+ wr_data[2] = (u8)(reg_addr >> 24);
+
+ msg[0].buf = wr_data;
+
+ msg[1].addr = client->addr;
+ msg[1].len = 4;
+ msg[1].flags = I2C_M_RD;
+
+ msg[1].buf = (u8 *)&rd_data;
+
+ ret = i2c_transfer(client->adapter, &msg[0], 2);
+ if (ret == 2) {
+ *reg_val = le32_to_cpu(rd_data);
+ return 0;
+ }
+
+ /* If only one message successfully completed, return -ENODEV */
+ return ret == 1 ? -ENODEV : ret;
+}
+
+static int qps615_pwrctl_i2c_bulk_write(struct i2c_client *client,
+ const struct qps615_pwrctl_reg_setting *seq, int len)
+{
+ int ret, i;
+
+ for (i = 0; i < len; i++) {
+ ret = qps615_pwrctl_i2c_write(client, seq[i].offset, seq[i].val);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+static int of_pci_get_bdf(struct device_node *np)
+{
+ u32 reg[5];
+ int error;
+
+ error = of_property_read_u32_array(np, "reg", reg, ARRAY_SIZE(reg));
+ if (error)
+ return error;
+
+ return (reg[0] >> 8) & 0xffff;
+}
+
+static int qps615_pwrctl_disable_port(struct qps615_pwrctl_ctx *ctx,
+ enum qps615_pwrctl_ports port)
+{
+ const struct qps615_pwrctl_reg_setting *seq;
+ int ret, len;
+
+ seq = (port == QPS615_DSP1) ? dsp1_pwroff_seq : dsp2_pwroff_seq;
+ len = (port == QPS615_DSP1) ? ARRAY_SIZE(dsp1_pwroff_seq) : ARRAY_SIZE(dsp2_pwroff_seq);
+
+ ret = qps615_pwrctl_i2c_bulk_write(ctx->client, seq, len);
+ if (ret)
+ return ret;
+
+ return qps615_pwrctl_i2c_bulk_write(ctx->client,
+ common_pwroff_seq, ARRAY_SIZE(common_pwroff_seq));
+}
+
+static int qps615_pwrctl_set_l0s_l1_entry_delay(struct qps615_pwrctl_ctx *ctx,
+ enum qps615_pwrctl_ports port, bool is_l1, u32 ns)
+{
+ u32 rd_val, units;
+ int ret;
+
+ /* convert to units of 256ns */
+ units = ns / 256;
+
+ if (port == QPS615_ETHERNET) {
+ ret = qps615_pwrctl_i2c_read(ctx->client, QPS615_EMBEDDED_ETH_DELAY, &rd_val);
+ if (ret)
+ return ret;
+ rd_val = u32_replace_bits(rd_val, units,
+ is_l1 ?
+ QPS615_ETH_L1_DELAY_MASK : QPS615_ETH_L0S_DELAY_MASK);
+ return qps615_pwrctl_i2c_write(ctx->client, QPS615_EMBEDDED_ETH_DELAY, rd_val);
+ }
+
+ ret = qps615_pwrctl_i2c_write(ctx->client, QPS615_PORT_SELECT, BIT(port));
+ if (ret)
+ return ret;
+
+ return qps615_pwrctl_i2c_write(ctx->client,
+ is_l1 ? QPS615_PORT_L1_DELAY : QPS615_PORT_L0S_DELAY, units);
+}
+
+static int qps615_pwrctl_set_tx_amplitude(struct qps615_pwrctl_ctx *ctx,
+ enum qps615_pwrctl_ports port, u32 amp)
+{
+ int port_access;
+
+ switch (port) {
+ case QPS615_USP:
+ port_access = 0x1;
+ break;
+ case QPS615_DSP1:
+ port_access = 0x2;
+ break;
+ case QPS615_DSP2:
+ port_access = 0x8;
+ break;
+ default:
+ return -EINVAL;
+ };
+
+ struct qps615_pwrctl_reg_setting tx_amp_seq[] = {
+ {QPS615_PORT_ACCESS_ENABLE, port_access},
+ {QPS615_PORT_LANE_ACCESS_ENABLE, 0x3},
+ {QPS615_TX_MARGIN, amp},
+ };
+
+ return qps615_pwrctl_i2c_bulk_write(ctx->client, tx_amp_seq, ARRAY_SIZE(tx_amp_seq));
+}
+
+static int qps615_pwrctl_disable_dfe(struct qps615_pwrctl_ctx *ctx,
+ enum qps615_pwrctl_ports port)
+{
+ int port_access, lane_access = 0x3;
+ u32 phy_rate = 0x21;
+
+ switch (port) {
+ case QPS615_USP:
+ phy_rate = 0x1;
+ port_access = 0x1;
+ break;
+ case QPS615_DSP1:
+ port_access = 0x2;
+ break;
+ case QPS615_DSP2:
+ port_access = 0x8;
+ lane_access = 0x1;
+ break;
+ default:
+ return -EINVAL;
+ };
+
+ struct qps615_pwrctl_reg_setting disable_dfe_seq[] = {
+ {QPS615_PORT_ACCESS_ENABLE, port_access},
+ {QPS615_PORT_LANE_ACCESS_ENABLE, lane_access},
+ {QPS615_DFE_ENABLE, 0x0},
+ {QPS615_DFE_EQ0_MODE, 0x411},
+ {QPS615_DFE_EQ1_MODE, 0x11},
+ {QPS615_DFE_EQ2_MODE, 0x11},
+ {QPS615_DFE_PD_MASK, 0x7},
+ {QPS615_PHY_RATE_CHANGE_OVERRIDE, 0x10},
+ {QPS615_PHY_RATE_CHANGE, phy_rate},
+ {QPS615_PHY_RATE_CHANGE, 0x0},
+ {QPS615_PHY_RATE_CHANGE_OVERRIDE, 0x0},
+
+ };
+
+ return qps615_pwrctl_i2c_bulk_write(ctx->client,
+ disable_dfe_seq, ARRAY_SIZE(disable_dfe_seq));
+}
+
+static int qps615_pwrctl_set_nfts(struct qps615_pwrctl_ctx *ctx,
+ enum qps615_pwrctl_ports port, u32 nfts)
+{
+ int ret;
+ struct qps615_pwrctl_reg_setting nfts_seq[] = {
+ {QPS615_NFTS_2_5_GT, nfts},
+ {QPS615_NFTS_5_GT, nfts},
+ };
+
+ ret = qps615_pwrctl_i2c_write(ctx->client, QPS615_PORT_SELECT, BIT(port));
+ if (ret)
+ return ret;
+
+ return qps615_pwrctl_i2c_bulk_write(ctx->client, nfts_seq, ARRAY_SIZE(nfts_seq));
+}
+
+static int qps615_pwrctl_assert_deassert_reset(struct qps615_pwrctl_ctx *ctx, bool deassert)
+{
+ int ret, val = 0;
+
+ if (deassert)
+ val = 0xc;
+
+ ret = qps615_pwrctl_i2c_write(ctx->client, QPS615_GPIO_CONFIG, 0xfffffff3);
+ if (ret)
+ return ret;
+
+ return qps615_pwrctl_i2c_write(ctx->client, QPS615_RESET_GPIO, val);
+}
+
+static int qps615_pwrctl_parse_device_dt(struct qps615_pwrctl_ctx *ctx, struct device_node *node)
+{
+ enum qps615_pwrctl_ports port;
+ struct qps615_pwrctl_cfg *cfg;
+ struct device_node *np;
+ int bdf, fun_no;
+
+ bdf = of_pci_get_bdf(node);
+ if (bdf < 0) {
+ dev_err(ctx->pwrctl.dev, "Getting BDF failed\n");
+ return 0;
+ }
+
+ fun_no = bdf & 0x7;
+
+ /* In multi function node, ignore function 1 node */
+ if (of_pci_get_bdf(of_get_parent(node)) == ctx->bdf->dsp3_bdf && !fun_no)
+ port = QPS615_ETHERNET;
+ else if (bdf == ctx->bdf->usp_bdf)
+ port = QPS615_USP;
+ else if (bdf == ctx->bdf->dsp1_bdf)
+ port = QPS615_DSP1;
+ else if (bdf == ctx->bdf->dsp2_bdf)
+ port = QPS615_DSP2;
+ else if (bdf == ctx->bdf->dsp3_bdf)
+ port = QPS615_DSP3;
+ else
+ return 0;
+
+ cfg = &ctx->cfg[port];
+
+ if (!of_device_is_available(node)) {
+ cfg->disable_port = true;
+ return 0;
+ };
+
+ of_property_read_u32(node, "qcom,axi-clk-freq-hz", &cfg->axi_freq);
+
+ of_property_read_u32(node, "qcom,l0s-entry-delay-ns", &cfg->l0s_delay);
+
+ of_property_read_u32(node, "qcom,l1-entry-delay-ns", &cfg->l1_delay);
+
+ of_property_read_u32(node, "qcom,tx-amplitude-millivolt", &cfg->tx_amp);
+
+ cfg->disable_dfe = of_property_read_bool(node, "qcom,no-dfe");
+
+ of_property_read_u8(node, "qcom,nfts", &cfg->nfts);
+
+ for_each_child_of_node(node, np)
+ qps615_pwrctl_parse_device_dt(ctx, np);
+
+ of_node_put(np);
+ return 0;
+}
+
+static void qps615_pwrctl_power_off(struct qps615_pwrctl_ctx *ctx)
+{
+ gpiod_set_value(ctx->reset_gpio, 1);
+
+ regulator_bulk_disable(ARRAY_SIZE(ctx->supplies), ctx->supplies);
+}
+
+static int qps615_pwrctl_power_on(struct qps615_pwrctl_ctx *ctx)
+{
+ struct qps615_pwrctl_cfg *cfg;
+ int ret, i;
+
+ ret = regulator_bulk_enable(ARRAY_SIZE(ctx->supplies), ctx->supplies);
+ if (ret < 0)
+ return dev_err_probe(ctx->pwrctl.dev, ret, "cannot enable regulators\n");
+
+ gpiod_set_value(ctx->reset_gpio, 0);
+
+ if (!ctx->client)
+ return 0;
+
+ /*
+ * Don't have a way to see if the reset has completed.
+ * Wait for some time.
+ */
+ usleep_range(1000, 1001);
+
+ ret = qps615_pwrctl_assert_deassert_reset(ctx, false);
+ if (ret)
+ goto out;
+
+ if (ctx->cfg[QPS615_USP].axi_freq == QPS615_AXI_CLK_FREQ_MHZ) {
+ ret = qps615_pwrctl_i2c_write(ctx->client, QPS615_BUS_CONTROL, BIT(16));
+ if (ret)
+ dev_err(ctx->pwrctl.dev, "Setting axi clk freq failed %d\n", ret);
+ }
+
+ for (i = 0; i < QPS615_MAX; i++) {
+ cfg = &ctx->cfg[i];
+ if (cfg->disable_port) {
+ ret = qps615_pwrctl_disable_port(ctx, i);
+ if (ret) {
+ dev_err(ctx->pwrctl.dev, "Disabling port failed\n");
+ goto out;
+ }
+ }
+
+ if (cfg->l0s_delay) {
+ ret = qps615_pwrctl_set_l0s_l1_entry_delay(ctx, i, false, cfg->l0s_delay);
+ if (ret) {
+ dev_err(ctx->pwrctl.dev, "Setting L0s entry delay failed\n");
+ goto out;
+ }
+ }
+
+ if (cfg->l1_delay) {
+ ret = qps615_pwrctl_set_l0s_l1_entry_delay(ctx, i, true, cfg->l1_delay);
+ if (ret) {
+ dev_err(ctx->pwrctl.dev, "Setting L1 entry delay failed\n");
+ goto out;
+ }
+ }
+
+ if (cfg->tx_amp) {
+ ret = qps615_pwrctl_set_tx_amplitude(ctx, i, cfg->tx_amp);
+ if (ret) {
+ dev_err(ctx->pwrctl.dev, "Setting Tx amplitube failed\n");
+ goto out;
+ }
+ }
+
+ if (cfg->nfts) {
+ ret = qps615_pwrctl_set_nfts(ctx, i, cfg->nfts);
+ if (ret) {
+ dev_err(ctx->pwrctl.dev, "Setting nfts failed\n");
+ goto out;
+ }
+ }
+
+ if (cfg->disable_dfe) {
+ ret = qps615_pwrctl_disable_dfe(ctx, i);
+ if (ret) {
+ dev_err(ctx->pwrctl.dev, "Disabling DFE failed\n");
+ goto out;
+ }
+ }
+ }
+
+ ret = qps615_pwrctl_assert_deassert_reset(ctx, true);
+ if (!ret)
+ return 0;
+
+out:
+ qps615_pwrctl_power_off(ctx);
+ return ret;
+}
+
+static int qps615_pwrctl_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct pci_host_bridge *bridge;
+ struct qps615_pwrctl_ctx *ctx;
+ struct device_node *node;
+ struct pci_bus *bus;
+ int ret;
+
+ bus = pci_find_bus(of_get_pci_domain_nr(dev->parent->of_node), 0);
+ if (!bus)
+ return -ENODEV;
+
+ bridge = pci_find_host_bridge(bus);
+
+ ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL);
+ if (!ctx)
+ return -ENOMEM;
+
+ node = of_parse_phandle(pdev->dev.of_node, "qcom,qps615-controller", 0);
+ if (node) {
+ ctx->client = of_find_i2c_device_by_node(node);
+ of_node_put(node);
+ if (!ctx->client)
+ return dev_err_probe(dev, -EPROBE_DEFER,
+ "failed to parse qcom,qps615-controller\n");
+ }
+
+ ctx->bdf = of_device_get_match_data(dev);
+ ctx->pwrctl.dev = dev;
+
+ ctx->supplies[0].supply = "vddc";
+ ctx->supplies[1].supply = "vdd18";
+ ctx->supplies[2].supply = "vdd09";
+ ctx->supplies[3].supply = "vddio1";
+ ctx->supplies[4].supply = "vddio2";
+ ctx->supplies[5].supply = "vddio18";
+ ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(ctx->supplies), ctx->supplies);
+ if (ret)
+ return dev_err_probe(dev, ret,
+ "failed to get supply regulator\n");
+
+ ctx->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_ASIS);
+ if (IS_ERR(ctx->reset_gpio))
+ return dev_err_probe(dev, PTR_ERR(ctx->reset_gpio), "failed to get reset GPIO\n");
+
+ ctx->link = device_link_add(&bridge->dev, dev, DL_FLAG_AUTOREMOVE_CONSUMER);
+
+ platform_set_drvdata(pdev, ctx);
+
+ qps615_pwrctl_parse_device_dt(ctx, pdev->dev.of_node);
+
+ if (bridge->ops->stop_link)
+ bridge->ops->stop_link(bus);
+
+ ret = qps615_pwrctl_power_on(ctx);
+ if (ret)
+ return ret;
+
+ if (bridge->ops->start_link) {
+ ret = bridge->ops->start_link(bus);
+ if (ret)
+ return ret;
+ }
+
+ return devm_pci_pwrctl_device_set_ready(dev, &ctx->pwrctl);
+}
+
+static void qps615_pwrctl_remove(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct qps615_pwrctl_ctx *ctx = dev_get_drvdata(dev);
+
+ device_link_del(ctx->link);
+ qps615_pwrctl_power_off(ctx);
+}
+
+static const struct qps615_pwrctl_bdf_info bdf_info = {
+ .usp_bdf = 0x100,
+ .dsp1_bdf = 0x208,
+ .dsp2_bdf = 0x210,
+ .dsp3_bdf = 0x218,
+};
+
+static const struct of_device_id qps615_pwrctl_of_match[] = {
+ { .compatible = "pci1179,0623", .data = &bdf_info },
+ { }
+};
+MODULE_DEVICE_TABLE(of, qps615_pwrctl_of_match);
+
+static struct platform_driver qps615_pwrctl_driver = {
+ .driver = {
+ .name = "pwrctl-qps615",
+ .of_match_table = qps615_pwrctl_of_match,
+ .probe_type = PROBE_PREFER_ASYNCHRONOUS,
+ },
+ .probe = qps615_pwrctl_probe,
+ .remove_new = qps615_pwrctl_remove,
+};
+module_platform_driver(qps615_pwrctl_driver);
+
+MODULE_AUTHOR("Krishna chaitanya chundru <quic_krichai@quicinc.com>");
+MODULE_DESCRIPTION("Qualcomm QPS615 power control driver");
+MODULE_LICENSE("GPL");
--
2.34.1
^ permalink raw reply related [flat|nested] 77+ messages in thread
* Re: [PATCH v2 1/8] dt-bindings: PCI: Add binding for qps615
2024-08-03 3:22 ` [PATCH v2 1/8] dt-bindings: PCI: Add binding for qps615 Krishna chaitanya chundru
@ 2024-08-03 4:33 ` Rob Herring (Arm)
2024-08-03 11:00 ` Dmitry Baryshkov
` (2 subsequent siblings)
3 siblings, 0 replies; 77+ messages in thread
From: Rob Herring (Arm) @ 2024-08-03 4:33 UTC (permalink / raw)
To: Krishna chaitanya chundru
Cc: cros-qcom-dts-watchers, Bjorn Helgaas, Krzysztof Kozlowski,
Jingoo Han, Konrad Dybcio, quic_vbadigan,
Krzysztof Wilczyński, andersson, linux-kernel, Conor Dooley,
linux-arm-msm, Bartosz Golaszewski, linux-pci, Lorenzo Pieralisi,
Manivannan Sadhasivam, Bartosz Golaszewski, devicetree
On Sat, 03 Aug 2024 08:52:47 +0530, Krishna chaitanya chundru wrote:
> Add binding describing the Qualcomm PCIe switch, QPS615,
> which provides Ethernet MAC integrated to the 3rd downstream port
> and two downstream PCIe ports.
>
> Signed-off-by: Krishna chaitanya chundru <quic_krichai@quicinc.com>
> ---
> .../devicetree/bindings/pci/qcom,qps615.yaml | 191 +++++++++++++++++++++
> 1 file changed, 191 insertions(+)
>
My bot found errors running 'make dt_binding_check' on your patch:
yamllint warnings/errors:
dtschema/dtc warnings/errors:
Documentation/devicetree/bindings/pci/qcom,qps615.example.dts:33.26-101.19: Warning (pci_device_bus_num): /example-0/pcie/pcie@0/pcie@0,0: PCI bus number 1 out of range, expected (0 - 0)
Documentation/devicetree/bindings/pci/qcom,qps615.example.dts:52.30-60.23: Warning (pci_device_bus_num): /example-0/pcie/pcie@0/pcie@0,0/pcie@1,0: PCI bus number 2 out of range, expected (0 - 0)
Documentation/devicetree/bindings/pci/qcom,qps615.example.dts:62.30-70.23: Warning (pci_device_bus_num): /example-0/pcie/pcie@0/pcie@0,0/pcie@2,0: PCI bus number 2 out of range, expected (0 - 0)
Documentation/devicetree/bindings/pci/qcom,qps615.example.dts:72.30-100.23: Warning (pci_device_bus_num): /example-0/pcie/pcie@0/pcie@0,0/pcie@3,0: PCI bus number 2 out of range, expected (0 - 0)
Documentation/devicetree/bindings/pci/qcom,qps615.example.dts:81.39-89.32: Warning (pci_device_bus_num): /example-0/pcie/pcie@0/pcie@0,0/pcie@3,0/pcie@0,0: PCI bus number 4 out of range, expected (0 - 0)
Documentation/devicetree/bindings/pci/qcom,qps615.example.dts:91.39-99.32: Warning (pci_device_bus_num): /example-0/pcie/pcie@0/pcie@0,0/pcie@3,0/pcie@0,1: PCI bus number 4 out of range, expected (0 - 0)
doc reference errors (make refcheckdocs):
See https://patchwork.ozlabs.org/project/devicetree-bindings/patch/20240803-qps615-v2-1-9560b7c71369@quicinc.com
The base for the series is generally the latest rc1. A different dependency
should be noted in *this* patch.
If you already ran 'make dt_binding_check' and didn't see the above
error(s), then make sure 'yamllint' is installed and dt-schema is up to
date:
pip3 install dtschema --upgrade
Please check and re-submit after running the above command yourself. Note
that DT_SCHEMA_FILES can be set to your schema file to speed up checking
your schema. However, it must be unset to test all examples with your schema.
^ permalink raw reply [flat|nested] 77+ messages in thread
* Re: [PATCH v2 0/8] PCI: Enable Power and configure the QPS615 PCIe switch
2024-08-03 3:22 [PATCH v2 0/8] PCI: Enable Power and configure the QPS615 PCIe switch Krishna chaitanya chundru
` (7 preceding siblings ...)
2024-08-03 3:22 ` [PATCH v2 8/8] PCI: pwrctl: Add power control driver for qps615 Krishna chaitanya chundru
@ 2024-08-03 10:56 ` Dmitry Baryshkov
2024-08-05 4:19 ` Krishna Chaitanya Chundru
2024-08-04 8:57 ` Krzysztof Kozlowski
` (3 subsequent siblings)
12 siblings, 1 reply; 77+ messages in thread
From: Dmitry Baryshkov @ 2024-08-03 10:56 UTC (permalink / raw)
To: Krishna chaitanya chundru
Cc: Lorenzo Pieralisi, Krzysztof Wilczyński, Rob Herring,
Bjorn Helgaas, Krzysztof Kozlowski, Conor Dooley, Konrad Dybcio,
cros-qcom-dts-watchers, Bartosz Golaszewski, Jingoo Han,
Manivannan Sadhasivam, andersson, quic_vbadigan, linux-arm-msm,
linux-pci, devicetree, linux-kernel, Bartosz Golaszewski
On Sat, Aug 03, 2024 at 08:52:46AM GMT, Krishna chaitanya chundru wrote:
> QPS615 is the PCIe switch which has one upstream and three downstream
> ports. One of the downstream ports is used as endpoint device of Ethernet
> MAC. Other two downstream ports are supposed to connect to external
> device. One Host can connect to QPS615 by upstream port.
>
> QPS615 switch power is controlled by the GPIO's. After powering on
> the switch will immediately participate in the link training. if the
> host is also ready by that time PCIe link will established.
>
> The QPS615 needs to configured certain parameters like de-emphasis,
> disable unused port etc before link is established.
>
> The device tree properties are parsed per node under pci-pci bridge in the
> devicetree. Each node has unique bdf value in the reg property, driver
> uses this bdf to differentiate ports, as there are certain i2c writes to
> select particulat port.
>
> As the controller starts link training before the probe of pwrctl driver,
> the PCIe link may come up before configuring the switch itself.
> To avoid this introduce two functions in pci_ops to start_link() &
> stop_link() which will disable the link training if the PCIe link is
> not up yet.
>
> Now PCI pwrctl device is the child of the pci-pcie bridge, if we want
> to enable the suspend resume for pwrctl device there may be issues
> since pci bridge will try to access some registers in the config which
> may cause timeouts or Un clocked access as the power can be removed in
> the suspend of pwrctl driver.
>
> To solve this make PCIe controller as parent to the pci pwr ctrl driver
> and create devlink between host bridge and pci pwrctl driver so that
> pci pwrctl driver will go suspend only after all the PCIe devices went
> to suspend.
>
> Signed-off-by: Krishna chaitanya chundru <quic_krichai@quicinc.com>
> ---
> Changes in V1:
> - Fix the code as per the comments given.
This is not a proper changelog entry. It doesn't allow reviewers to
understand what actually happened. Could you please list your actual
changes in a reply and also include them in a changelog if there is a
need for v3.
> - Removed D3cold D0 sequence in suspend resume for now as it needs
> seperate discussion.
> - change to dt approach for configuring the switch instead of request_firmware() approach
> - Link to v1: https://lore.kernel.org/linux-pci/20240626-qps615-v1-4-2ade7bd91e02@quicinc.com/T/
> ---
>
--
With best wishes
Dmitry
^ permalink raw reply [flat|nested] 77+ messages in thread
* Re: [PATCH v2 1/8] dt-bindings: PCI: Add binding for qps615
2024-08-03 3:22 ` [PATCH v2 1/8] dt-bindings: PCI: Add binding for qps615 Krishna chaitanya chundru
2024-08-03 4:33 ` Rob Herring (Arm)
@ 2024-08-03 11:00 ` Dmitry Baryshkov
2024-08-05 4:16 ` Krishna Chaitanya Chundru
2024-08-04 8:53 ` Krzysztof Kozlowski
2024-08-04 8:56 ` Krzysztof Kozlowski
3 siblings, 1 reply; 77+ messages in thread
From: Dmitry Baryshkov @ 2024-08-03 11:00 UTC (permalink / raw)
To: Krishna chaitanya chundru
Cc: Lorenzo Pieralisi, Krzysztof Wilczyński, Rob Herring,
Bjorn Helgaas, Krzysztof Kozlowski, Conor Dooley, Konrad Dybcio,
cros-qcom-dts-watchers, Bartosz Golaszewski, Jingoo Han,
Manivannan Sadhasivam, andersson, quic_vbadigan, linux-arm-msm,
linux-pci, devicetree, linux-kernel, Bartosz Golaszewski
On Sat, Aug 03, 2024 at 08:52:47AM GMT, Krishna chaitanya chundru wrote:
> Add binding describing the Qualcomm PCIe switch, QPS615,
> which provides Ethernet MAC integrated to the 3rd downstream port
> and two downstream PCIe ports.
>
> Signed-off-by: Krishna chaitanya chundru <quic_krichai@quicinc.com>
> ---
> .../devicetree/bindings/pci/qcom,qps615.yaml | 191 +++++++++++++++++++++
> 1 file changed, 191 insertions(+)
>
> diff --git a/Documentation/devicetree/bindings/pci/qcom,qps615.yaml b/Documentation/devicetree/bindings/pci/qcom,qps615.yaml
> new file mode 100644
> index 000000000000..ea0c953ee56f
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/pci/qcom,qps615.yaml
> @@ -0,0 +1,191 @@
> +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
> +%YAML 1.2
> +---
> +$id: http://devicetree.org/schemas/pci/qcom,qps615.yaml#
> +$schema: http://devicetree.org/meta-schemas/core.yaml#
> +
> +title: Qualcomm QPS615 PCIe switch
> +
> +maintainers:
> + - Krishna chaitanya chundru <quic_krichai@quicinc.com>
> +
> +description: |
> + Qualcomm QPS615 PCIe switch has one upstream and three downstream
> + ports. The 3rd downstream port has integrated endpoint device of
> + Ethernet MAC. Other two downstream ports are supposed to connect
> + to external device.
> +
> + The QPS615 PCIe switch can be configured through I2C interface before
> + PCIe link is established to change FTS, ASPM related entry delays,
> + tx amplitude etc for better power efficiency and functionality.
> +
> +properties:
> + compatible:
> + enum:
> + - pci1179,0623
> +
> + reg:
> + maxItems: 1
> +
> + qcom,qps615-controller:
> + $ref: /schemas/types.yaml#/definitions/phandle
> + description:
> + Reference to the I2C client used to do configure qps615
> +
> + vdd18-supply: true
> +
> + vdd09-supply: true
> +
> + vddc-supply: true
> +
> + vddio1-supply: true
> +
> + vddio2-supply: true
> +
> + vddio18-supply: true
> +
> + reset-gpios:
> + maxItems: 1
> + description:
> + GPIO controlling the RESX# pin.
> +
> + qps615,axi-clk-freq-hz:
> + description:
> + AXI clock which internal bus of the switch.
Is it a clock or clock rate?
> +
> + qcom,l0s-entry-delay-ns:
> + description: Aspm l0s entry delay in nanoseconds.
I'd say, from the property name it is obvious that it comes in
nanoseconds.
> +
> + qcom,l1-entry-delay-ns:
> + description: Aspm l1 entry delay in nanoseconds.
> +
> + qcom,tx-amplitude-millivolt:
> + $ref: /schemas/types.yaml#/definitions/uint32
> + description: Change Tx Margin setting for low power consumption.
> +
> + qcom,no-dfe:
> + type: boolean
> + description: Disables DFE (Decision Feedback Equalizer).
> +
> + qcom,nfts:
> + $ref: /schemas/types.yaml#/definitions/uint8
> + description:
> + Fast Training Sequence (FTS) is the mechanism that
> + is used for bit and Symbol lock.
Doesn't help to understand what it is and what the value means.
> +
> +allOf:
> + - $ref: /schemas/pci/pci-bus-common.yaml#
> + - if:
> + properties:
> + compatible:
> + contains:
> + const: pci1179,0623
> + required:
> + - compatible
> + then:
> + required:
> + - vdd18-supply
> + - vdd09-supply
> + - vddc-supply
> + - vddio1-supply
> + - vddio2-supply
> + - vddio18-supply
> + - qcom,qps615-controller
> + - reset-gpios
> +
> +patternProperties:
> + "@1?[0-9a-f](,[0-7])?$":
> + type: object
> + $ref: qcom,qps615.yaml#
> + additionalProperties: true
> +
> +additionalProperties: true
> +
> +examples:
> + - |
> +
> + #include <dt-bindings/gpio/gpio.h>
> +
> + pcie {
> + #address-cells = <3>;
> + #size-cells = <2>;
> +
> + pcie@0 {
> + device_type = "pci";
> + reg = <0x0 0x0 0x0 0x0 0x0>;
> +
> + #address-cells = <3>;
> + #size-cells = <2>;
> + ranges;
> +
> + pcie@0,0 {
> + compatible = "pci1179,0623";
> + reg = <0x10000 0x0 0x0 0x0 0x0>;
> + device_type = "pci";
> + #address-cells = <3>;
> + #size-cells = <2>;
> + ranges;
> +
> + qcom,qps615-controller = <&qps615_controller>;
Where is the corresponding device?
> +
> + vdd18-supply = <&vdd>;
> + vdd09-supply = <&vdd>;
> + vddc-supply = <&vdd>;
> + vddio1-supply = <&vdd>;
> + vddio2-supply = <&vdd>;
> + vddio18-supply = <&vdd>;
> +
> + reset-gpios = <&gpio 1 GPIO_ACTIVE_LOW>;
> +
> + pcie@1,0 {
> + reg = <0x20800 0x0 0x0 0x0 0x0>;
> + #address-cells = <3>;
> + #size-cells = <2>;
> + device_type = "pci";
> + ranges;
> +
> + qcom,no-dfe;
> + };
> +
> + pcie@2,0 {
> + reg = <0x21000 0x0 0x0 0x0 0x0>;
> + #address-cells = <3>;
> + #size-cells = <2>;
> + device_type = "pci";
> + ranges;
> +
> + qcom,nfts = /bits/ 8 <10>;
> + };
> +
> + pcie@3,0 {
> + reg = <0x21800 0x0 0x0 0x0 0x0>;
> + #address-cells = <3>;
> + #size-cells = <2>;
> + device_type = "pci";
> + ranges;
> +
> + qcom,tx-amplitude-millivolt = <10>;
> +
> + pcie@0,0 {
Wrong indentation.
> + reg = <0x40000 0x0 0x0 0x0 0x0>;
> + #address-cells = <3>;
> + #size-cells = <2>;
> + device_type = "pci";
> + ranges;
> +
> + qcom,l1-entry-delay-ns = <10>;
> + };
> +
> + pcie@0,1 {
> + reg = <0x40100 0x0 0x0 0x0 0x0>;
> + #address-cells = <3>;
> + #size-cells = <2>;
> + device_type = "pci";
> + ranges;
> +
> + qcom,l0s-entry-delay-ns = <10>;
> + };
> + };
> + };
> + };
> + };
>
> --
> 2.34.1
>
--
With best wishes
Dmitry
^ permalink raw reply [flat|nested] 77+ messages in thread
* Re: [PATCH v2 8/8] PCI: pwrctl: Add power control driver for qps615
2024-08-03 3:22 ` [PATCH v2 8/8] PCI: pwrctl: Add power control driver for qps615 Krishna chaitanya chundru
@ 2024-08-03 11:34 ` Dmitry Baryshkov
2024-08-05 6:14 ` Krishna Chaitanya Chundru
0 siblings, 1 reply; 77+ messages in thread
From: Dmitry Baryshkov @ 2024-08-03 11:34 UTC (permalink / raw)
To: Krishna chaitanya chundru
Cc: Lorenzo Pieralisi, Krzysztof Wilczyński, Rob Herring,
Bjorn Helgaas, Krzysztof Kozlowski, Conor Dooley, Konrad Dybcio,
cros-qcom-dts-watchers, Bartosz Golaszewski, Jingoo Han,
Manivannan Sadhasivam, andersson, quic_vbadigan, linux-arm-msm,
linux-pci, devicetree, linux-kernel, Bartosz Golaszewski
On Sat, Aug 03, 2024 at 08:52:54AM GMT, Krishna chaitanya chundru wrote:
> QPS615 switch needs to be configured after powering on and before
> PCIe link was up.
>
> As the PCIe controller driver already enables the PCIe link training
> at the host side, stop the link training. Otherwise the moment we turn
> on the switch it will participate in the link training and link may come
> up before switch is configured through i2c.
>
> The device tree properties are parsed per node under pci-pci bridge in the
> driver. Each node has unique bdf value in the reg property, driver
> uses this bdf to differentiate ports, as there are certain i2c writes to
> select particular port.
>
> Based up on dt property and port, qps615 is configured through i2c.
>
> Signed-off-by: Krishna chaitanya chundru <quic_krichai@quicinc.com>
> ---
> drivers/pci/pwrctl/Kconfig | 7 +
> drivers/pci/pwrctl/Makefile | 1 +
> drivers/pci/pwrctl/pci-pwrctl-qps615.c | 638 +++++++++++++++++++++++++++++++++
> 3 files changed, 646 insertions(+)
>
> diff --git a/drivers/pci/pwrctl/Kconfig b/drivers/pci/pwrctl/Kconfig
> index 54589bb2403b..6a1352af918c 100644
> --- a/drivers/pci/pwrctl/Kconfig
> +++ b/drivers/pci/pwrctl/Kconfig
> @@ -10,3 +10,10 @@ config PCI_PWRCTL_PWRSEQ
> tristate
> select POWER_SEQUENCING
> select PCI_PWRCTL
> +
> +config PCI_PWRCTL_QPS615
> + tristate "PCI Power Control driver for QPS615"
> + select PCI_PWRCTL
> + help
> + Say Y here to enable the pwrctl driver for Qualcomm
> + QPS615 PCIe switch.
> diff --git a/drivers/pci/pwrctl/Makefile b/drivers/pci/pwrctl/Makefile
> index d308aae4800c..ac563a70c023 100644
> --- a/drivers/pci/pwrctl/Makefile
> +++ b/drivers/pci/pwrctl/Makefile
> @@ -4,3 +4,4 @@ obj-$(CONFIG_PCI_PWRCTL) += pci-pwrctl-core.o
> pci-pwrctl-core-y := core.o
>
> obj-$(CONFIG_PCI_PWRCTL_PWRSEQ) += pci-pwrctl-pwrseq.o
> +obj-$(CONFIG_PCI_PWRCTL_QPS615) += pci-pwrctl-qps615.o
> diff --git a/drivers/pci/pwrctl/pci-pwrctl-qps615.c b/drivers/pci/pwrctl/pci-pwrctl-qps615.c
> new file mode 100644
> index 000000000000..9dabb82787d5
> --- /dev/null
> +++ b/drivers/pci/pwrctl/pci-pwrctl-qps615.c
> @@ -0,0 +1,638 @@
> +// SPDX-License-Identifier: GPL-2.0-only
> +/*
> + * Copyright (c) 2024 Qualcomm Innovation Center, Inc. All rights reserved.
> + */
> +
> +#include <linux/delay.h>
> +#include <linux/device.h>
> +#include <linux/firmware.h>
> +#include <linux/i2c.h>
> +#include <linux/mod_devicetable.h>
> +#include <linux/module.h>
> +#include <linux/of.h>
> +#include <linux/pci.h>
> +#include <linux/pci-pwrctl.h>
> +#include <linux/platform_device.h>
> +#include <linux/regulator/consumer.h>
> +#include <linux/string.h>
> +#include <linux/types.h>
> +
> +#include "../pci.h"
> +
> +#define QPS615_GPIO_CONFIG 0x801208
> +#define QPS615_RESET_GPIO 0x801210
> +
> +#define QPS615_BUS_CONTROL 0x801014
> +
> +#define QPS615_PORT_L0S_DELAY 0x82496c
> +#define QPS615_PORT_L1_DELAY 0x824970
> +
> +#define QPS615_EMBEDDED_ETH_DELAY 0x8200d8
> +#define QPS615_ETH_L1_DELAY_MASK GENMASK(27, 18)
> +#define QPS615_ETH_L1_DELAY_VALUE(x) FIELD_PREP(QPS615_ETH_L1_DELAY_MASK, x)
> +#define QPS615_ETH_L0S_DELAY_MASK GENMASK(17, 13)
> +#define QPS615_ETH_L0S_DELAY_VALUE(x) FIELD_PREP(QPS615_ETH_L0S_DELAY_MASK, x)
> +
> +#define QPS615_NFTS_2_5_GT 0x824978
> +#define QPS615_NFTS_5_GT 0x82497c
> +
> +#define QPS615_PORT_LANE_ACCESS_ENABLE 0x828000
> +
> +#define QPS615_PHY_RATE_CHANGE_OVERRIDE 0x828040
> +#define QPS615_PHY_RATE_CHANGE 0x828050
> +
> +#define QPS615_TX_MARGIN 0x828234
> +
> +#define QPS615_DFE_ENABLE 0x828a04
> +#define QPS615_DFE_EQ0_MODE 0x828a08
> +#define QPS615_DFE_EQ1_MODE 0x828a0c
> +#define QPS615_DFE_EQ2_MODE 0x828a14
> +#define QPS615_DFE_PD_MASK 0x828254
> +
> +#define QPS615_PORT_SELECT 0x82c02c
> +#define QPS615_PORT_ACCESS_ENABLE 0x82c030
> +
> +#define QPS615_POWER_CONTROL 0x82b09c
> +#define QPS615_POWER_CONTROL_OVREN 0x82b2c8
> +
> +#define QPS615_AXI_CLK_FREQ_MHZ 125
> +
> +struct qps615_pwrctl_reg_setting {
> + unsigned int offset;
> + unsigned int val;
> +};
> +
> +struct qps615_pwrctl_bdf_info {
> + u16 usp_bdf;
> + u16 dsp1_bdf;
> + u16 dsp2_bdf;
> + u16 dsp3_bdf;
Why are these values dynamic? Please use #define's for now. If there
ever comes a similar bridge, it most likely will have a different ports
configuration, so it will need additional changes anyway.
> +};
> +
> +enum qps615_pwrctl_ports {
> + QPS615_USP,
> + QPS615_DSP1,
> + QPS615_DSP2,
> + QPS615_DSP3,
> + QPS615_ETHERNET,
> + QPS615_MAX
> +};
> +
> +struct qps615_pwrctl_cfg {
> + u32 l0s_delay;
> + u32 l1_delay;
> + u32 tx_amp;
> + u32 axi_freq;
> + u8 nfts;
> + bool disable_dfe;
> + bool disable_port;
> +};
> +
> +#define QPS615_PWRCTL_MAX_SUPPLY 6
> +
> +struct qps615_pwrctl_ctx {
> + struct regulator_bulk_data supplies[QPS615_PWRCTL_MAX_SUPPLY];
> + const struct qps615_pwrctl_bdf_info *bdf;
> + struct qps615_pwrctl_cfg cfg[QPS615_MAX];
> + struct gpio_desc *reset_gpio;
> + struct i2c_client *client;
> + struct pci_pwrctl pwrctl;
> + struct device_link *link;
> +};
> +
> +/*
> + * downstream port power off sequence, hardcoding the address
> + * as we don't know register names for these register offsets.
It is hard to believe that Qualcomm engineers don't know register names
for the Qualcomm device.
> + */
> +static const struct qps615_pwrctl_reg_setting common_pwroff_seq[] = {
> + {0x82900c, 0x1},
> + {0x829010, 0x1},
> + {0x829018, 0x0},
> + {0x829020, 0x1},
> + {0x82902c, 0x1},
> + {0x829030, 0x1},
> + {0x82903c, 0x1},
> + {0x829058, 0x0},
> + {0x82905c, 0x1},
> + {0x829060, 0x1},
> + {0x8290cc, 0x1},
> + {0x8290d0, 0x1},
> + {0x8290d8, 0x1},
> + {0x8290e0, 0x1},
> + {0x8290e8, 0x1},
> + {0x8290ec, 0x1},
> + {0x8290f4, 0x1},
> + {0x82910c, 0x1},
> + {0x829110, 0x1},
> + {0x829114, 0x1},
> +};
> +
> +static const struct qps615_pwrctl_reg_setting dsp1_pwroff_seq[] = {
> + {QPS615_PORT_ACCESS_ENABLE, 0x2},
> + {QPS615_PORT_LANE_ACCESS_ENABLE, 0x3},
> + {QPS615_POWER_CONTROL, 0x014f4804},
> + {QPS615_POWER_CONTROL_OVREN, 0x1},
> + {QPS615_PORT_ACCESS_ENABLE, 0x4},
> +};
> +
> +static const struct qps615_pwrctl_reg_setting dsp2_pwroff_seq[] = {
> + {QPS615_PORT_ACCESS_ENABLE, 0x8},
> + {QPS615_PORT_LANE_ACCESS_ENABLE, 0x1},
> + {QPS615_POWER_CONTROL, 0x014f4804},
> + {QPS615_POWER_CONTROL_OVREN, 0x1},
> + {QPS615_PORT_ACCESS_ENABLE, 0x8},
> +};
> +
> +static int qps615_pwrctl_i2c_write(struct i2c_client *client,
> + u32 reg_addr, u32 reg_val)
> +{
> + struct i2c_msg msg;
> + u8 msg_buf[7];
> + int ret;
> +
> + msg.addr = client->addr;
> + msg.len = 7;
> + msg.flags = 0;
> +
> + /* Big Endian for reg addr */
> + reg_addr = cpu_to_be32(reg_addr);
This is incorrect. After cpu_to_be32() the value depends on the CPU
endianness. So reg_addr >> 8 will return different values for LE and BE
CPUs.
> +
> + msg_buf[0] = (u8)(reg_addr >> 8);
> + msg_buf[1] = (u8)(reg_addr >> 16);
> + msg_buf[2] = (u8)(reg_addr >> 24);
> +
> + /* Little Endian for reg val */
> + reg_val = cpu_to_le32(reg_val);
> +
> + msg_buf[3] = (u8)(reg_val);
> + msg_buf[4] = (u8)(reg_val >> 8);
> + msg_buf[5] = (u8)(reg_val >> 16);
> + msg_buf[6] = (u8)(reg_val >> 24);
Same issue here.
> +
> + msg.buf = msg_buf;
> + ret = i2c_transfer(client->adapter, &msg, 1);
> + return ret == 1 ? 0 : ret;
> +}
> +
> +static int qps615_pwrctl_i2c_read(struct i2c_client *client,
> + u32 reg_addr, u32 *reg_val)
> +{
> + struct i2c_msg msg[2];
> + u8 wr_data[3];
> + u32 rd_data;
> + int ret;
> +
> + msg[0].addr = client->addr;
> + msg[0].len = 3;
> + msg[0].flags = 0;
> +
> + /* Big Endian for reg addr */
> + reg_addr = cpu_to_be32(reg_addr);
> +
> + wr_data[0] = (u8)(reg_addr >> 8);
> + wr_data[1] = (u8)(reg_addr >> 16);
> + wr_data[2] = (u8)(reg_addr >> 24);
And here.
> +
> + msg[0].buf = wr_data;
> +
> + msg[1].addr = client->addr;
> + msg[1].len = 4;
> + msg[1].flags = I2C_M_RD;
> +
> + msg[1].buf = (u8 *)&rd_data;
> +
> + ret = i2c_transfer(client->adapter, &msg[0], 2);
> + if (ret == 2) {
> + *reg_val = le32_to_cpu(rd_data);
> + return 0;
> + }
> +
> + /* If only one message successfully completed, return -ENODEV */
> + return ret == 1 ? -ENODEV : ret;
> +}
> +
> +static int qps615_pwrctl_i2c_bulk_write(struct i2c_client *client,
> + const struct qps615_pwrctl_reg_setting *seq, int len)
> +{
> + int ret, i;
> +
> + for (i = 0; i < len; i++) {
> + ret = qps615_pwrctl_i2c_write(client, seq[i].offset, seq[i].val);
> + if (ret)
> + return ret;
> + }
> +
> + return 0;
> +}
> +
> +static int of_pci_get_bdf(struct device_node *np)
> +{
> + u32 reg[5];
> + int error;
> +
> + error = of_property_read_u32_array(np, "reg", reg, ARRAY_SIZE(reg));
Please use of_property_read_u32_index() instead.
> + if (error)
> + return error;
> +
> + return (reg[0] >> 8) & 0xffff;
> +}
> +
> +static int qps615_pwrctl_disable_port(struct qps615_pwrctl_ctx *ctx,
> + enum qps615_pwrctl_ports port)
> +{
> + const struct qps615_pwrctl_reg_setting *seq;
> + int ret, len;
> +
> + seq = (port == QPS615_DSP1) ? dsp1_pwroff_seq : dsp2_pwroff_seq;
> + len = (port == QPS615_DSP1) ? ARRAY_SIZE(dsp1_pwroff_seq) : ARRAY_SIZE(dsp2_pwroff_seq);
> +
> + ret = qps615_pwrctl_i2c_bulk_write(ctx->client, seq, len);
> + if (ret)
> + return ret;
> +
> + return qps615_pwrctl_i2c_bulk_write(ctx->client,
> + common_pwroff_seq, ARRAY_SIZE(common_pwroff_seq));
> +}
> +
> +static int qps615_pwrctl_set_l0s_l1_entry_delay(struct qps615_pwrctl_ctx *ctx,
> + enum qps615_pwrctl_ports port, bool is_l1, u32 ns)
> +{
> + u32 rd_val, units;
> + int ret;
> +
> + /* convert to units of 256ns */
> + units = ns / 256;
> +
> + if (port == QPS615_ETHERNET) {
> + ret = qps615_pwrctl_i2c_read(ctx->client, QPS615_EMBEDDED_ETH_DELAY, &rd_val);
> + if (ret)
> + return ret;
> + rd_val = u32_replace_bits(rd_val, units,
> + is_l1 ?
> + QPS615_ETH_L1_DELAY_MASK : QPS615_ETH_L0S_DELAY_MASK);
> + return qps615_pwrctl_i2c_write(ctx->client, QPS615_EMBEDDED_ETH_DELAY, rd_val);
> + }
> +
> + ret = qps615_pwrctl_i2c_write(ctx->client, QPS615_PORT_SELECT, BIT(port));
> + if (ret)
> + return ret;
What if there is a concurrent call? The port_select / write_value
statements should use a lock to remove the possible race condition.
> +
> + return qps615_pwrctl_i2c_write(ctx->client,
> + is_l1 ? QPS615_PORT_L1_DELAY : QPS615_PORT_L0S_DELAY, units);
> +}
> +
> +static int qps615_pwrctl_set_tx_amplitude(struct qps615_pwrctl_ctx *ctx,
> + enum qps615_pwrctl_ports port, u32 amp)
> +{
> + int port_access;
> +
> + switch (port) {
> + case QPS615_USP:
> + port_access = 0x1;
> + break;
> + case QPS615_DSP1:
> + port_access = 0x2;
> + break;
> + case QPS615_DSP2:
> + port_access = 0x8;
> + break;
> + default:
> + return -EINVAL;
> + };
> +
> + struct qps615_pwrctl_reg_setting tx_amp_seq[] = {
> + {QPS615_PORT_ACCESS_ENABLE, port_access},
Hmm, this looks like another port selection, so most likely it should
also be under the same lock.
> + {QPS615_PORT_LANE_ACCESS_ENABLE, 0x3},
> + {QPS615_TX_MARGIN, amp},
> + };
> +
> + return qps615_pwrctl_i2c_bulk_write(ctx->client, tx_amp_seq, ARRAY_SIZE(tx_amp_seq));
> +}
> +
> +static int qps615_pwrctl_disable_dfe(struct qps615_pwrctl_ctx *ctx,
> + enum qps615_pwrctl_ports port)
> +{
> + int port_access, lane_access = 0x3;
> + u32 phy_rate = 0x21;
> +
> + switch (port) {
> + case QPS615_USP:
> + phy_rate = 0x1;
> + port_access = 0x1;
> + break;
> + case QPS615_DSP1:
> + port_access = 0x2;
> + break;
> + case QPS615_DSP2:
> + port_access = 0x8;
> + lane_access = 0x1;
> + break;
> + default:
> + return -EINVAL;
> + };
> +
> + struct qps615_pwrctl_reg_setting disable_dfe_seq[] = {
> + {QPS615_PORT_ACCESS_ENABLE, port_access},
> + {QPS615_PORT_LANE_ACCESS_ENABLE, lane_access},
> + {QPS615_DFE_ENABLE, 0x0},
> + {QPS615_DFE_EQ0_MODE, 0x411},
> + {QPS615_DFE_EQ1_MODE, 0x11},
> + {QPS615_DFE_EQ2_MODE, 0x11},
> + {QPS615_DFE_PD_MASK, 0x7},
> + {QPS615_PHY_RATE_CHANGE_OVERRIDE, 0x10},
> + {QPS615_PHY_RATE_CHANGE, phy_rate},
> + {QPS615_PHY_RATE_CHANGE, 0x0},
> + {QPS615_PHY_RATE_CHANGE_OVERRIDE, 0x0},
> +
> + };
> +
> + return qps615_pwrctl_i2c_bulk_write(ctx->client,
> + disable_dfe_seq, ARRAY_SIZE(disable_dfe_seq));
> +}
> +
> +static int qps615_pwrctl_set_nfts(struct qps615_pwrctl_ctx *ctx,
> + enum qps615_pwrctl_ports port, u32 nfts)
> +{
> + int ret;
> + struct qps615_pwrctl_reg_setting nfts_seq[] = {
> + {QPS615_NFTS_2_5_GT, nfts},
> + {QPS615_NFTS_5_GT, nfts},
> + };
> +
> + ret = qps615_pwrctl_i2c_write(ctx->client, QPS615_PORT_SELECT, BIT(port));
> + if (ret)
> + return ret;
> +
> + return qps615_pwrctl_i2c_bulk_write(ctx->client, nfts_seq, ARRAY_SIZE(nfts_seq));
> +}
> +
> +static int qps615_pwrctl_assert_deassert_reset(struct qps615_pwrctl_ctx *ctx, bool deassert)
> +{
> + int ret, val = 0;
> +
> + if (deassert)
> + val = 0xc;
> +
> + ret = qps615_pwrctl_i2c_write(ctx->client, QPS615_GPIO_CONFIG, 0xfffffff3);
It's a kind of magic
> + if (ret)
> + return ret;
> +
> + return qps615_pwrctl_i2c_write(ctx->client, QPS615_RESET_GPIO, val);
> +}
> +
> +static int qps615_pwrctl_parse_device_dt(struct qps615_pwrctl_ctx *ctx, struct device_node *node)
> +{
> + enum qps615_pwrctl_ports port;
> + struct qps615_pwrctl_cfg *cfg;
> + struct device_node *np;
> + int bdf, fun_no;
> +
> + bdf = of_pci_get_bdf(node);
> + if (bdf < 0) {
This is incorrect, it will fail if at any point BDF uses the most
significant bit (which is permitted by the spec, if I'm not mistaken).
> + dev_err(ctx->pwrctl.dev, "Getting BDF failed\n");
> + return 0;
> + }
> +
> + fun_no = bdf & 0x7;
I assume that ARI is not supported?
> +
> + /* In multi function node, ignore function 1 node */
> + if (of_pci_get_bdf(of_get_parent(node)) == ctx->bdf->dsp3_bdf && !fun_no)
> + port = QPS615_ETHERNET;
> + else if (bdf == ctx->bdf->usp_bdf)
> + port = QPS615_USP;
The function is being called for child device nodes. Thus upstream
facing port (I assume that this is what USP means) can not be enumerated
in this way.
> + else if (bdf == ctx->bdf->dsp1_bdf)
> + port = QPS615_DSP1;
> + else if (bdf == ctx->bdf->dsp2_bdf)
> + port = QPS615_DSP2;
> + else if (bdf == ctx->bdf->dsp3_bdf)
> + port = QPS615_DSP3;
> + else
> + return 0;
-EINVAL
> +
> + cfg = &ctx->cfg[port];
> +
> + if (!of_device_is_available(node)) {
> + cfg->disable_port = true;
> + return 0;
> + };
> +
> + of_property_read_u32(node, "qcom,axi-clk-freq-hz", &cfg->axi_freq);
> +
> + of_property_read_u32(node, "qcom,l0s-entry-delay-ns", &cfg->l0s_delay);
> +
> + of_property_read_u32(node, "qcom,l1-entry-delay-ns", &cfg->l1_delay);
> +
> + of_property_read_u32(node, "qcom,tx-amplitude-millivolt", &cfg->tx_amp);
> +
> + cfg->disable_dfe = of_property_read_bool(node, "qcom,no-dfe");
> +
> + of_property_read_u8(node, "qcom,nfts", &cfg->nfts);
> +
> + for_each_child_of_node(node, np)
> + qps615_pwrctl_parse_device_dt(ctx, np);
> +
> + of_node_put(np);
> + return 0;
> +}
> +
> +static void qps615_pwrctl_power_off(struct qps615_pwrctl_ctx *ctx)
> +{
> + gpiod_set_value(ctx->reset_gpio, 1);
> +
> + regulator_bulk_disable(ARRAY_SIZE(ctx->supplies), ctx->supplies);
> +}
> +
> +static int qps615_pwrctl_power_on(struct qps615_pwrctl_ctx *ctx)
> +{
> + struct qps615_pwrctl_cfg *cfg;
> + int ret, i;
> +
> + ret = regulator_bulk_enable(ARRAY_SIZE(ctx->supplies), ctx->supplies);
> + if (ret < 0)
> + return dev_err_probe(ctx->pwrctl.dev, ret, "cannot enable regulators\n");
> +
> + gpiod_set_value(ctx->reset_gpio, 0);
> +
> + if (!ctx->client)
> + return 0;
really?
> +
> + /*
> + * Don't have a way to see if the reset has completed.
> + * Wait for some time.
> + */
> + usleep_range(1000, 1001);
> +
> + ret = qps615_pwrctl_assert_deassert_reset(ctx, false);
> + if (ret)
> + goto out;
> +
> + if (ctx->cfg[QPS615_USP].axi_freq == QPS615_AXI_CLK_FREQ_MHZ) {
> + ret = qps615_pwrctl_i2c_write(ctx->client, QPS615_BUS_CONTROL, BIT(16));
> + if (ret)
> + dev_err(ctx->pwrctl.dev, "Setting axi clk freq failed %d\n", ret);
AXI, not axi
> + }
> +
> + for (i = 0; i < QPS615_MAX; i++) {
> + cfg = &ctx->cfg[i];
> + if (cfg->disable_port) {
> + ret = qps615_pwrctl_disable_port(ctx, i);
> + if (ret) {
> + dev_err(ctx->pwrctl.dev, "Disabling port failed\n");
> + goto out;
> + }
> + }
> +
> + if (cfg->l0s_delay) {
> + ret = qps615_pwrctl_set_l0s_l1_entry_delay(ctx, i, false, cfg->l0s_delay);
> + if (ret) {
> + dev_err(ctx->pwrctl.dev, "Setting L0s entry delay failed\n");
> + goto out;
> + }
> + }
> +
> + if (cfg->l1_delay) {
> + ret = qps615_pwrctl_set_l0s_l1_entry_delay(ctx, i, true, cfg->l1_delay);
> + if (ret) {
> + dev_err(ctx->pwrctl.dev, "Setting L1 entry delay failed\n");
> + goto out;
> + }
> + }
> +
> + if (cfg->tx_amp) {
> + ret = qps615_pwrctl_set_tx_amplitude(ctx, i, cfg->tx_amp);
> + if (ret) {
> + dev_err(ctx->pwrctl.dev, "Setting Tx amplitube failed\n");
> + goto out;
> + }
> + }
> +
> + if (cfg->nfts) {
> + ret = qps615_pwrctl_set_nfts(ctx, i, cfg->nfts);
> + if (ret) {
> + dev_err(ctx->pwrctl.dev, "Setting nfts failed\n");
> + goto out;
> + }
> + }
> +
> + if (cfg->disable_dfe) {
> + ret = qps615_pwrctl_disable_dfe(ctx, i);
> + if (ret) {
> + dev_err(ctx->pwrctl.dev, "Disabling DFE failed\n");
> + goto out;
> + }
> + }
> + }
> +
> + ret = qps615_pwrctl_assert_deassert_reset(ctx, true);
> + if (!ret)
> + return 0;
> +
> +out:
> + qps615_pwrctl_power_off(ctx);
> + return ret;
> +}
> +
> +static int qps615_pwrctl_probe(struct platform_device *pdev)
> +{
> + struct device *dev = &pdev->dev;
> + struct pci_host_bridge *bridge;
> + struct qps615_pwrctl_ctx *ctx;
> + struct device_node *node;
> + struct pci_bus *bus;
> + int ret;
> +
> + bus = pci_find_bus(of_get_pci_domain_nr(dev->parent->of_node), 0);
> + if (!bus)
> + return -ENODEV;
> +
> + bridge = pci_find_host_bridge(bus);
> +
> + ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL);
> + if (!ctx)
> + return -ENOMEM;
> +
> + node = of_parse_phandle(pdev->dev.of_node, "qcom,qps615-controller", 0);
> + if (node) {
And if !node?
> + ctx->client = of_find_i2c_device_by_node(node);
Leaks the reference count, see the comment at the function definition.
Also what if the I2C bus gets unbound? Will it crash the driver?
> + of_node_put(node);
> + if (!ctx->client)
> + return dev_err_probe(dev, -EPROBE_DEFER,
> + "failed to parse qcom,qps615-controller\n");
> + }
> +
> + ctx->bdf = of_device_get_match_data(dev);
> + ctx->pwrctl.dev = dev;
> +
> + ctx->supplies[0].supply = "vddc";
> + ctx->supplies[1].supply = "vdd18";
> + ctx->supplies[2].supply = "vdd09";
> + ctx->supplies[3].supply = "vddio1";
> + ctx->supplies[4].supply = "vddio2";
> + ctx->supplies[5].supply = "vddio18";
> + ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(ctx->supplies), ctx->supplies);
> + if (ret)
> + return dev_err_probe(dev, ret,
> + "failed to get supply regulator\n");
> +
> + ctx->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_ASIS);
> + if (IS_ERR(ctx->reset_gpio))
> + return dev_err_probe(dev, PTR_ERR(ctx->reset_gpio), "failed to get reset GPIO\n");
> +
> + ctx->link = device_link_add(&bridge->dev, dev, DL_FLAG_AUTOREMOVE_CONSUMER);
> +
> + platform_set_drvdata(pdev, ctx);
> +
> + qps615_pwrctl_parse_device_dt(ctx, pdev->dev.of_node);
> +
> + if (bridge->ops->stop_link)
> + bridge->ops->stop_link(bus);
> +
> + ret = qps615_pwrctl_power_on(ctx);
> + if (ret)
> + return ret;
> +
> + if (bridge->ops->start_link) {
> + ret = bridge->ops->start_link(bus);
> + if (ret)
> + return ret;
> + }
> +
> + return devm_pci_pwrctl_device_set_ready(dev, &ctx->pwrctl);
> +}
> +
> +static void qps615_pwrctl_remove(struct platform_device *pdev)
> +{
> + struct device *dev = &pdev->dev;
> + struct qps615_pwrctl_ctx *ctx = dev_get_drvdata(dev);
> +
> + device_link_del(ctx->link);
> + qps615_pwrctl_power_off(ctx);
> +}
> +
> +static const struct qps615_pwrctl_bdf_info bdf_info = {
> + .usp_bdf = 0x100,
> + .dsp1_bdf = 0x208,
> + .dsp2_bdf = 0x210,
> + .dsp3_bdf = 0x218,
> +};
> +
> +static const struct of_device_id qps615_pwrctl_of_match[] = {
> + { .compatible = "pci1179,0623", .data = &bdf_info },
> + { }
> +};
> +MODULE_DEVICE_TABLE(of, qps615_pwrctl_of_match);
> +
> +static struct platform_driver qps615_pwrctl_driver = {
> + .driver = {
> + .name = "pwrctl-qps615",
> + .of_match_table = qps615_pwrctl_of_match,
> + .probe_type = PROBE_PREFER_ASYNCHRONOUS,
> + },
> + .probe = qps615_pwrctl_probe,
> + .remove_new = qps615_pwrctl_remove,
> +};
> +module_platform_driver(qps615_pwrctl_driver);
> +
> +MODULE_AUTHOR("Krishna chaitanya chundru <quic_krichai@quicinc.com>");
> +MODULE_DESCRIPTION("Qualcomm QPS615 power control driver");
> +MODULE_LICENSE("GPL");
>
> --
> 2.34.1
>
--
With best wishes
Dmitry
^ permalink raw reply [flat|nested] 77+ messages in thread
* Re: [PATCH v2 2/8] dt-bindings: trivial-devices: Add qcom,qps615
2024-08-03 3:22 ` [PATCH v2 2/8] dt-bindings: trivial-devices: Add qcom,qps615 Krishna chaitanya chundru
@ 2024-08-04 8:50 ` Krzysztof Kozlowski
2024-08-05 4:11 ` Krishna Chaitanya Chundru
0 siblings, 1 reply; 77+ messages in thread
From: Krzysztof Kozlowski @ 2024-08-04 8:50 UTC (permalink / raw)
To: Krishna chaitanya chundru, Lorenzo Pieralisi,
Krzysztof Wilczyński, Rob Herring, Bjorn Helgaas,
Krzysztof Kozlowski, Conor Dooley, Konrad Dybcio,
cros-qcom-dts-watchers, Bartosz Golaszewski, Jingoo Han,
Manivannan Sadhasivam
Cc: andersson, quic_vbadigan, linux-arm-msm, linux-pci, devicetree,
linux-kernel, Bartosz Golaszewski
On 03/08/2024 05:22, Krishna chaitanya chundru wrote:
> qps615 is a PCIe switch which is configured through i2c.
>
> Signed-off-by: Krishna chaitanya chundru <quic_krichai@quicinc.com>
> ---
> Documentation/devicetree/bindings/trivial-devices.yaml | 2 ++
> 1 file changed, 2 insertions(+)
>
> diff --git a/Documentation/devicetree/bindings/trivial-devices.yaml b/Documentation/devicetree/bindings/trivial-devices.yaml
> index 5d3dc952770d..7f44add21bf6 100644
> --- a/Documentation/devicetree/bindings/trivial-devices.yaml
> +++ b/Documentation/devicetree/bindings/trivial-devices.yaml
> @@ -330,6 +330,8 @@ properties:
> - renesas,isl29501
> # Rohm DH2228FV
> - rohm,dh2228fv
> + # Qualcomm QPS615 PCIe switch control
> + - qcom,qps615
Don't place entries in random order. The list is alohabetically ordered.
Best regards,
Krzysztof
^ permalink raw reply [flat|nested] 77+ messages in thread
* Re: [PATCH v2 1/8] dt-bindings: PCI: Add binding for qps615
2024-08-03 3:22 ` [PATCH v2 1/8] dt-bindings: PCI: Add binding for qps615 Krishna chaitanya chundru
2024-08-03 4:33 ` Rob Herring (Arm)
2024-08-03 11:00 ` Dmitry Baryshkov
@ 2024-08-04 8:53 ` Krzysztof Kozlowski
2024-08-05 4:11 ` Krishna Chaitanya Chundru
2024-08-04 8:56 ` Krzysztof Kozlowski
3 siblings, 1 reply; 77+ messages in thread
From: Krzysztof Kozlowski @ 2024-08-04 8:53 UTC (permalink / raw)
To: Krishna chaitanya chundru, Lorenzo Pieralisi,
Krzysztof Wilczyński, Rob Herring, Bjorn Helgaas,
Krzysztof Kozlowski, Conor Dooley, Konrad Dybcio,
cros-qcom-dts-watchers, Bartosz Golaszewski, Jingoo Han,
Manivannan Sadhasivam
Cc: andersson, quic_vbadigan, linux-arm-msm, linux-pci, devicetree,
linux-kernel, Bartosz Golaszewski
On 03/08/2024 05:22, Krishna chaitanya chundru wrote:
> Add binding describing the Qualcomm PCIe switch, QPS615,
> which provides Ethernet MAC integrated to the 3rd downstream port
> and two downstream PCIe ports.
>
> Signed-off-by: Krishna chaitanya chundru <quic_krichai@quicinc.com>
> ---
> .../devicetree/bindings/pci/qcom,qps615.yaml | 191 +++++++++++++++++++++
> 1 file changed, 191 insertions(+)
>
> diff --git a/Documentation/devicetree/bindings/pci/qcom,qps615.yaml b/Documentation/devicetree/bindings/pci/qcom,qps615.yaml
> new file mode 100644
> index 000000000000..ea0c953ee56f
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/pci/qcom,qps615.yaml
> @@ -0,0 +1,191 @@
> +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
> +%YAML 1.2
> +---
> +$id: http://devicetree.org/schemas/pci/qcom,qps615.yaml#
> +$schema: http://devicetree.org/meta-schemas/core.yaml#
> +
> +title: Qualcomm QPS615 PCIe switch
> +
> +maintainers:
> + - Krishna chaitanya chundru <quic_krichai@quicinc.com>
> +
> +description: |
> + Qualcomm QPS615 PCIe switch has one upstream and three downstream
> + ports. The 3rd downstream port has integrated endpoint device of
> + Ethernet MAC. Other two downstream ports are supposed to connect
> + to external device.
> +
> + The QPS615 PCIe switch can be configured through I2C interface before
> + PCIe link is established to change FTS, ASPM related entry delays,
> + tx amplitude etc for better power efficiency and functionality.
> +
> +properties:
> + compatible:
> + enum:
> + - pci1179,0623
> +
> + reg:
> + maxItems: 1
> +
> + qcom,qps615-controller:
> + $ref: /schemas/types.yaml#/definitions/phandle
> + description:
> + Reference to the I2C client used to do configure qps615
Why?
> +
> + vdd18-supply: true
> +
> + vdd09-supply: true
> +
> + vddc-supply: true
> +
> + vddio1-supply: true
> +
> + vddio2-supply: true
> +
> + vddio18-supply: true
> +
> + reset-gpios:
> + maxItems: 1
> + description:
> + GPIO controlling the RESX# pin.
> +
> + qps615,axi-clk-freq-hz:
> + description:
> + AXI clock which internal bus of the switch.
No need, use CCF.
> +
> + qcom,l0s-entry-delay-ns:
> + description: Aspm l0s entry delay in nanoseconds.
> +
> + qcom,l1-entry-delay-ns:
> + description: Aspm l1 entry delay in nanoseconds.
> +
> + qcom,tx-amplitude-millivolt:
> + $ref: /schemas/types.yaml#/definitions/uint32
> + description: Change Tx Margin setting for low power consumption.
> +
> + qcom,no-dfe:
> + type: boolean
> + description: Disables DFE (Decision Feedback Equalizer).
You described the desired Linux feature or behavior, not the actual
hardware. The bindings are about the latter, so instead you need to
rephrase the property and its description to match actual hardware
capabilities/features/configuration etc.
> +
> + qcom,nfts:
> + $ref: /schemas/types.yaml#/definitions/uint8
> + description:
> + Fast Training Sequence (FTS) is the mechanism that
> + is used for bit and Symbol lock.
What are the values? Why this is uint8?
You described the desired Linux feature or behavior, not the actual
hardware. The bindings are about the latter, so instead you need to
rephrase the property and its description to match actual hardware
capabilities/features/configuration etc.
> +
> +allOf:
> + - $ref: /schemas/pci/pci-bus-common.yaml#
> + - if:
> + properties:
> + compatible:
> + contains:
> + const: pci1179,0623
> + required:
> + - compatible
Why do you have entire if? You do not have multiple variants, drop.
> + then:
> + required:
> + - vdd18-supply
> + - vdd09-supply
> + - vddc-supply
> + - vddio1-supply
> + - vddio2-supply
> + - vddio18-supply
> + - qcom,qps615-controller
> + - reset-gpios
> +
> +patternProperties:
> + "@1?[0-9a-f](,[0-7])?$":
> + type: object
> + $ref: qcom,qps615.yaml#
> + additionalProperties: true
Nope, drop pattern Properties or explain what is this.
> +
> +additionalProperties: true
This cannot be true,
> +
> +examples:
> + - |
> +
> + #include <dt-bindings/gpio/gpio.h>
> +
> + pcie {
> + #address-cells = <3>;
> + #size-cells = <2>;
> +
> + pcie@0 {
> + device_type = "pci";
> + reg = <0x0 0x0 0x0 0x0 0x0>;
> +
> + #address-cells = <3>;
> + #size-cells = <2>;
> + ranges;
> +
> + pcie@0,0 {
> + compatible = "pci1179,0623";
> + reg = <0x10000 0x0 0x0 0x0 0x0>;
> + device_type = "pci";
> + #address-cells = <3>;
> + #size-cells = <2>;
> + ranges;
> +
> + qcom,qps615-controller = <&qps615_controller>;
> +
> + vdd18-supply = <&vdd>;
> + vdd09-supply = <&vdd>;
> + vddc-supply = <&vdd>;
> + vddio1-supply = <&vdd>;
> + vddio2-supply = <&vdd>;
> + vddio18-supply = <&vdd>;
> +
> + reset-gpios = <&gpio 1 GPIO_ACTIVE_LOW>;
> +
> + pcie@1,0 {
> + reg = <0x20800 0x0 0x0 0x0 0x0>;
Where is the compatible? You claim this is the same device as child?
> + #address-cells = <3>;
> + #size-cells = <2>;
> + device_type = "pci";
> + ranges;
> +
> + qcom,no-dfe;
> + };
> +
> + pcie@2,0 {
> + reg = <0x21000 0x0 0x0 0x0 0x0>;
> + #address-cells = <3>;
> + #size-cells = <2>;
> + device_type = "pci";
> + ranges;
> +
> + qcom,nfts = /bits/ 8 <10>;
> + };
> +
> + pcie@3,0 {
> + reg = <0x21800 0x0 0x0 0x0 0x0>;
> + #address-cells = <3>;
> + #size-cells = <2>;
> + device_type = "pci";
> + ranges;
> +
> + qcom,tx-amplitude-millivolt = <10>;
> +
> + pcie@0,0 {
Total mess in indentation.
Best regards,
Krzysztof
^ permalink raw reply [flat|nested] 77+ messages in thread
* Re: [PATCH v2 3/8] arm64: dts: qcom: qcs6490-rb3gen2: Add node for qps615
2024-08-03 3:22 ` [PATCH v2 3/8] arm64: dts: qcom: qcs6490-rb3gen2: Add node for qps615 Krishna chaitanya chundru
@ 2024-08-04 8:54 ` Krzysztof Kozlowski
2024-08-05 4:14 ` Krishna Chaitanya Chundru
2024-09-09 11:29 ` Caleb Connolly
1 sibling, 1 reply; 77+ messages in thread
From: Krzysztof Kozlowski @ 2024-08-04 8:54 UTC (permalink / raw)
To: Krishna chaitanya chundru, Lorenzo Pieralisi,
Krzysztof Wilczyński, Rob Herring, Bjorn Helgaas,
Krzysztof Kozlowski, Conor Dooley, Konrad Dybcio,
cros-qcom-dts-watchers, Bartosz Golaszewski, Jingoo Han,
Manivannan Sadhasivam
Cc: andersson, quic_vbadigan, linux-arm-msm, linux-pci, devicetree,
linux-kernel, Bartosz Golaszewski
On 03/08/2024 05:22, Krishna chaitanya chundru wrote:
> Add QPS615 PCIe switch node which has 3 downstream ports and in one
> downstream port two embedded ethernet devices are present.
>
> Power to the QPS615 is supplied through two LDO regulators, controlled
> by two GPIOs, these are added as fixed regulators.
>
> Add i2c device node which is used to configure the switch.
>
> Signed-off-by: Krishna chaitanya chundru <quic_krichai@quicinc.com>
> ---
> arch/arm64/boot/dts/qcom/qcs6490-rb3gen2.dts | 121 +++++++++++++++++++++++++++
> arch/arm64/boot/dts/qcom/sc7280.dtsi | 2 +-
> 2 files changed, 122 insertions(+), 1 deletion(-)
>
> diff --git a/arch/arm64/boot/dts/qcom/qcs6490-rb3gen2.dts b/arch/arm64/boot/dts/qcom/qcs6490-rb3gen2.dts
> index 0d45662b8028..59d209768636 100644
> --- a/arch/arm64/boot/dts/qcom/qcs6490-rb3gen2.dts
> +++ b/arch/arm64/boot/dts/qcom/qcs6490-rb3gen2.dts
> @@ -202,6 +202,30 @@ vph_pwr: vph-pwr-regulator {
> regulator-min-microvolt = <3700000>;
> regulator-max-microvolt = <3700000>;
> };
> +
> + vdd_ntn_0p9: regulator-vdd-ntn-0p9 {
> + compatible = "regulator-fixed";
> + regulator-name = "VDD_NTN_0P9";
> + gpio = <&pm8350c_gpios 2 GPIO_ACTIVE_HIGH>;
> + regulator-min-microvolt = <899400>;
> + regulator-max-microvolt = <899400>;
> + enable-active-high;
> + pinctrl-0 = <&ntn_0p9_en>;
> + pinctrl-names = "default";
> + regulator-enable-ramp-delay = <4300>;
> + };
> +
> + vdd_ntn_1p8: regulator-vdd-ntn-1p8 {
> + compatible = "regulator-fixed";
> + regulator-name = "VDD_NTN_1P8";
> + gpio = <&pm8350c_gpios 3 GPIO_ACTIVE_HIGH>;
> + regulator-min-microvolt = <1800000>;
> + regulator-max-microvolt = <1800000>;
> + enable-active-high;
> + pinctrl-0 = <&ntn_1p8_en>;
> + pinctrl-names = "default";
> + regulator-enable-ramp-delay = <10000>;
> + };
> };
>
> &apps_rsc {
> @@ -595,6 +619,12 @@ lt9611_out: endpoint {
> };
> };
> };
> +
> + qps615_switch: pcie-switch@77 {
> + compatible = "qcom,qps615";
> + reg = <0x77>;
> + status = "okay";
Where is it disabled?
> + };
> };
>
> &i2c1 {
> @@ -688,6 +718,75 @@ &pmk8350_rtc {
> status = "okay";
> };
>
> +&pcie1 {
Entries are ordered.
> + status = "okay";
> +};
>
Best regards,
Krzysztof
^ permalink raw reply [flat|nested] 77+ messages in thread
* Re: [PATCH v2 1/8] dt-bindings: PCI: Add binding for qps615
2024-08-03 3:22 ` [PATCH v2 1/8] dt-bindings: PCI: Add binding for qps615 Krishna chaitanya chundru
` (2 preceding siblings ...)
2024-08-04 8:53 ` Krzysztof Kozlowski
@ 2024-08-04 8:56 ` Krzysztof Kozlowski
2024-08-05 4:02 ` Krishna Chaitanya Chundru
3 siblings, 1 reply; 77+ messages in thread
From: Krzysztof Kozlowski @ 2024-08-04 8:56 UTC (permalink / raw)
To: Krishna chaitanya chundru, Lorenzo Pieralisi,
Krzysztof Wilczyński, Rob Herring, Bjorn Helgaas,
Krzysztof Kozlowski, Conor Dooley, Konrad Dybcio,
cros-qcom-dts-watchers, Bartosz Golaszewski, Jingoo Han,
Manivannan Sadhasivam
Cc: andersson, quic_vbadigan, linux-arm-msm, linux-pci, devicetree,
linux-kernel, Bartosz Golaszewski
On 03/08/2024 05:22, Krishna chaitanya chundru wrote:
> Add binding describing the Qualcomm PCIe switch, QPS615,
> which provides Ethernet MAC integrated to the 3rd downstream port
> and two downstream PCIe ports.
>
> Signed-off-by: Krishna chaitanya chundru <quic_krichai@quicinc.com>
> ---
> .../devicetree/bindings/pci/qcom,qps615.yaml | 191 +++++++++++++++++++++
> 1 file changed, 191 insertions(+)
>
> diff --git a/Documentation/devicetree/bindings/pci/qcom,qps615.yaml b/Documentation/devicetree/bindings/pci/qcom,qps615.yaml
> new file mode 100644
> index 000000000000..ea0c953ee56f
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/pci/qcom,qps615.yaml
> @@ -0,0 +1,191 @@
> +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
> +%YAML 1.2
> +---
> +$id: http://devicetree.org/schemas/pci/qcom,qps615.yaml#
> +$schema: http://devicetree.org/meta-schemas/core.yaml#
> +
> +title: Qualcomm QPS615 PCIe switch
> +
> +maintainers:
> + - Krishna chaitanya chundru <quic_krichai@quicinc.com>
> +
> +description: |
> + Qualcomm QPS615 PCIe switch has one upstream and three downstream
> + ports. The 3rd downstream port has integrated endpoint device of
> + Ethernet MAC. Other two downstream ports are supposed to connect
> + to external device.
> +
> + The QPS615 PCIe switch can be configured through I2C interface before
> + PCIe link is established to change FTS, ASPM related entry delays,
> + tx amplitude etc for better power efficiency and functionality.
> +
> +properties:
> + compatible:
> + enum:
> + - pci1179,0623
> +
> + reg:
> + maxItems: 1
> +
> + qcom,qps615-controller:
and now I see that you totally ignored comments. Repeating the same over
and over is a waste of time.
<form letter>
This is a friendly reminder during the review process.
It seems my or other reviewer's previous comments were not fully
addressed. Maybe the feedback got lost between the quotes, maybe you
just forgot to apply it. Please go back to the previous discussion and
either implement all requested changes or keep discussing them.
Thank you.
</form letter>
Best regards,
Krzysztof
^ permalink raw reply [flat|nested] 77+ messages in thread
* Re: [PATCH v2 0/8] PCI: Enable Power and configure the QPS615 PCIe switch
2024-08-03 3:22 [PATCH v2 0/8] PCI: Enable Power and configure the QPS615 PCIe switch Krishna chaitanya chundru
` (8 preceding siblings ...)
2024-08-03 10:56 ` [PATCH v2 0/8] PCI: Enable Power and configure the QPS615 PCIe switch Dmitry Baryshkov
@ 2024-08-04 8:57 ` Krzysztof Kozlowski
2024-08-05 4:18 ` Krishna Chaitanya Chundru
2024-08-05 4:34 ` Krishna Chaitanya Chundru
` (2 subsequent siblings)
12 siblings, 1 reply; 77+ messages in thread
From: Krzysztof Kozlowski @ 2024-08-04 8:57 UTC (permalink / raw)
To: Krishna chaitanya chundru, Lorenzo Pieralisi,
Krzysztof Wilczyński, Rob Herring, Bjorn Helgaas,
Krzysztof Kozlowski, Conor Dooley, Konrad Dybcio,
cros-qcom-dts-watchers, Bartosz Golaszewski, Jingoo Han,
Manivannan Sadhasivam
Cc: andersson, quic_vbadigan, linux-arm-msm, linux-pci, devicetree,
linux-kernel, Bartosz Golaszewski
On 03/08/2024 05:22, Krishna chaitanya chundru wrote:
> QPS615 is the PCIe switch which has one upstream and three downstream
> ports. One of the downstream ports is used as endpoint device of Ethernet
> MAC. Other two downstream ports are supposed to connect to external
> device. One Host can connect to QPS615 by upstream port.
>
> QPS615 switch power is controlled by the GPIO's. After powering on
> the switch will immediately participate in the link training. if the
> host is also ready by that time PCIe link will established.
>
> The QPS615 needs to configured certain parameters like de-emphasis,
> disable unused port etc before link is established.
>
> The device tree properties are parsed per node under pci-pci bridge in the
> devicetree. Each node has unique bdf value in the reg property, driver
> uses this bdf to differentiate ports, as there are certain i2c writes to
> select particulat port.
>
> As the controller starts link training before the probe of pwrctl driver,
> the PCIe link may come up before configuring the switch itself.
> To avoid this introduce two functions in pci_ops to start_link() &
> stop_link() which will disable the link training if the PCIe link is
> not up yet.
>
> Now PCI pwrctl device is the child of the pci-pcie bridge, if we want
> to enable the suspend resume for pwrctl device there may be issues
> since pci bridge will try to access some registers in the config which
> may cause timeouts or Un clocked access as the power can be removed in
> the suspend of pwrctl driver.
>
> To solve this make PCIe controller as parent to the pci pwr ctrl driver
> and create devlink between host bridge and pci pwrctl driver so that
> pci pwrctl driver will go suspend only after all the PCIe devices went
> to suspend.
>
> Signed-off-by: Krishna chaitanya chundru <quic_krichai@quicinc.com>
> ---
> Changes in V1:
> - Fix the code as per the comments given.
You did not implement the comments so such changelog is rather a joke.
Respond to each comment from v1 and acknowledge it.
Then write detailed changelog.
Best regards,
Krzysztof
^ permalink raw reply [flat|nested] 77+ messages in thread
* Re: [PATCH v2 1/8] dt-bindings: PCI: Add binding for qps615
2024-08-04 8:56 ` Krzysztof Kozlowski
@ 2024-08-05 4:02 ` Krishna Chaitanya Chundru
2024-08-05 5:12 ` Krzysztof Kozlowski
0 siblings, 1 reply; 77+ messages in thread
From: Krishna Chaitanya Chundru @ 2024-08-05 4:02 UTC (permalink / raw)
To: Krzysztof Kozlowski, Lorenzo Pieralisi, Krzysztof Wilczyński,
Rob Herring, Bjorn Helgaas, Krzysztof Kozlowski, Conor Dooley,
Konrad Dybcio, cros-qcom-dts-watchers, Bartosz Golaszewski,
Jingoo Han, Manivannan Sadhasivam
Cc: andersson, quic_vbadigan, linux-arm-msm, linux-pci, devicetree,
linux-kernel, Bartosz Golaszewski
On 8/4/2024 2:26 PM, Krzysztof Kozlowski wrote:
> On 03/08/2024 05:22, Krishna chaitanya chundru wrote:
>> Add binding describing the Qualcomm PCIe switch, QPS615,
>> which provides Ethernet MAC integrated to the 3rd downstream port
>> and two downstream PCIe ports.
>>
>> Signed-off-by: Krishna chaitanya chundru <quic_krichai@quicinc.com>
>> ---
>> .../devicetree/bindings/pci/qcom,qps615.yaml | 191 +++++++++++++++++++++
>> 1 file changed, 191 insertions(+)
>>
>> diff --git a/Documentation/devicetree/bindings/pci/qcom,qps615.yaml b/Documentation/devicetree/bindings/pci/qcom,qps615.yaml
>> new file mode 100644
>> index 000000000000..ea0c953ee56f
>> --- /dev/null
>> +++ b/Documentation/devicetree/bindings/pci/qcom,qps615.yaml
>> @@ -0,0 +1,191 @@
>> +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
>> +%YAML 1.2
>> +---
>> +$id: http://devicetree.org/schemas/pci/qcom,qps615.yaml#
>> +$schema: http://devicetree.org/meta-schemas/core.yaml#
>> +
>> +title: Qualcomm QPS615 PCIe switch
>> +
>> +maintainers:
>> + - Krishna chaitanya chundru <quic_krichai@quicinc.com>
>> +
>> +description: |
>> + Qualcomm QPS615 PCIe switch has one upstream and three downstream
>> + ports. The 3rd downstream port has integrated endpoint device of
>> + Ethernet MAC. Other two downstream ports are supposed to connect
>> + to external device.
>> +
>> + The QPS615 PCIe switch can be configured through I2C interface before
>> + PCIe link is established to change FTS, ASPM related entry delays,
>> + tx amplitude etc for better power efficiency and functionality.
>> +
>> +properties:
>> + compatible:
>> + enum:
>> + - pci1179,0623
>> +
>> + reg:
>> + maxItems: 1
>> +
>> + qcom,qps615-controller:
>
> and now I see that you totally ignored comments. Repeating the same over
> and over is a waste of time.
>
> <form letter>
> This is a friendly reminder during the review process.
>
> It seems my or other reviewer's previous comments were not fully
> addressed. Maybe the feedback got lost between the quotes, maybe you
> just forgot to apply it. Please go back to the previous discussion and
> either implement all requested changes or keep discussing them.
>
> Thank you.
> </form letter>
>
>
> Best regards,
> Krzysztof
>
Hi Krzysztof,
In patch1 we are trying to add reference of i2c-adapter, you suggested
to use i2c-bus for that. we got comments on the driver code not to use
adapter and instead use i2c client reference. I felt i2c-bus is not
ideal to represent i2c client device so used this name.
I should have mentioned all these details in the change log for all
these changes. Next time onwards I will give detailed change log for
the changes between two versions.
- Krishna Chaitanya.
^ permalink raw reply [flat|nested] 77+ messages in thread
* Re: [PATCH v2 1/8] dt-bindings: PCI: Add binding for qps615
2024-08-04 8:53 ` Krzysztof Kozlowski
@ 2024-08-05 4:11 ` Krishna Chaitanya Chundru
2024-08-05 5:14 ` Krzysztof Kozlowski
2024-08-05 17:07 ` Bjorn Andersson
0 siblings, 2 replies; 77+ messages in thread
From: Krishna Chaitanya Chundru @ 2024-08-05 4:11 UTC (permalink / raw)
To: Krzysztof Kozlowski, Lorenzo Pieralisi, Krzysztof Wilczyński,
Rob Herring, Bjorn Helgaas, Krzysztof Kozlowski, Conor Dooley,
Konrad Dybcio, cros-qcom-dts-watchers, Bartosz Golaszewski,
Jingoo Han, Manivannan Sadhasivam
Cc: andersson, quic_vbadigan, linux-arm-msm, linux-pci, devicetree,
linux-kernel, Bartosz Golaszewski
On 8/4/2024 2:23 PM, Krzysztof Kozlowski wrote:
> On 03/08/2024 05:22, Krishna chaitanya chundru wrote:
>> Add binding describing the Qualcomm PCIe switch, QPS615,
>> which provides Ethernet MAC integrated to the 3rd downstream port
>> and two downstream PCIe ports.
>>
>> Signed-off-by: Krishna chaitanya chundru <quic_krichai@quicinc.com>
>> ---
>> .../devicetree/bindings/pci/qcom,qps615.yaml | 191 +++++++++++++++++++++
>> 1 file changed, 191 insertions(+)
>>
>> diff --git a/Documentation/devicetree/bindings/pci/qcom,qps615.yaml b/Documentation/devicetree/bindings/pci/qcom,qps615.yaml
>> new file mode 100644
>> index 000000000000..ea0c953ee56f
>> --- /dev/null
>> +++ b/Documentation/devicetree/bindings/pci/qcom,qps615.yaml
>> @@ -0,0 +1,191 @@
>> +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
>> +%YAML 1.2
>> +---
>> +$id: http://devicetree.org/schemas/pci/qcom,qps615.yaml#
>> +$schema: http://devicetree.org/meta-schemas/core.yaml#
>> +
>> +title: Qualcomm QPS615 PCIe switch
>> +
>> +maintainers:
>> + - Krishna chaitanya chundru <quic_krichai@quicinc.com>
>> +
>> +description: |
>> + Qualcomm QPS615 PCIe switch has one upstream and three downstream
>> + ports. The 3rd downstream port has integrated endpoint device of
>> + Ethernet MAC. Other two downstream ports are supposed to connect
>> + to external device.
>> +
>> + The QPS615 PCIe switch can be configured through I2C interface before
>> + PCIe link is established to change FTS, ASPM related entry delays,
>> + tx amplitude etc for better power efficiency and functionality.
>> +
>> +properties:
>> + compatible:
>> + enum:
>> + - pci1179,0623
>> +
>> + reg:
>> + maxItems: 1
>> +
>> + qcom,qps615-controller:
>> + $ref: /schemas/types.yaml#/definitions/phandle
>> + description:
>> + Reference to the I2C client used to do configure qps615
>
> Why?
>
>> +
>> + vdd18-supply: true
>> +
>> + vdd09-supply: true
>> +
>> + vddc-supply: true
>> +
>> + vddio1-supply: true
>> +
>> + vddio2-supply: true
>> +
>> + vddio18-supply: true
>> +
>> + reset-gpios:
>> + maxItems: 1
>> + description:
>> + GPIO controlling the RESX# pin.
>> +
>> + qps615,axi-clk-freq-hz:
>> + description:
>> + AXI clock which internal bus of the switch.
>
> No need, use CCF.
>
ack
>> +
>> + qcom,l0s-entry-delay-ns:
>> + description: Aspm l0s entry delay in nanoseconds.
>> +
>> + qcom,l1-entry-delay-ns:
>> + description: Aspm l1 entry delay in nanoseconds.
>> +
>> + qcom,tx-amplitude-millivolt:
>> + $ref: /schemas/types.yaml#/definitions/uint32
>> + description: Change Tx Margin setting for low power consumption.
>> +
>> + qcom,no-dfe:
>> + type: boolean
>> + description: Disables DFE (Decision Feedback Equalizer).
>
> You described the desired Linux feature or behavior, not the actual
> hardware. The bindings are about the latter, so instead you need to
> rephrase the property and its description to match actual hardware
> capabilities/features/configuration etc.
>
ack
>> +
>> + qcom,nfts:
>> + $ref: /schemas/types.yaml#/definitions/uint8
>> + description:
>> + Fast Training Sequence (FTS) is the mechanism that
>> + is used for bit and Symbol lock.
>
> What are the values? Why this is uint8?
>
These represents number of fast training sequence and doesn't have
any units and the maximum value for this is 0xFF only so we used
uint8.
> You described the desired Linux feature or behavior, not the actual
> hardware. The bindings are about the latter, so instead you need to
> rephrase the property and its description to match actual hardware
> capabilities/features/configuration etc.
ack.
>
>> +
>> +allOf:
>> + - $ref: /schemas/pci/pci-bus-common.yaml#
>> + - if:
>> + properties:
>> + compatible:
>> + contains:
>> + const: pci1179,0623
>> + required:
>> + - compatible
>
> Why do you have entire if? You do not have multiple variants, drop.
>
The child nodes also referencing the qcom,qps615.yaml# node, I tried
to use this way to say "the below properties are for the required for
parent and optional for child".
>> + then:
>> + required:
>> + - vdd18-supply
>> + - vdd09-supply
>> + - vddc-supply
>> + - vddio1-supply
>> + - vddio2-supply
>> + - vddio18-supply
>> + - qcom,qps615-controller
>> + - reset-gpios
>> +
>> +patternProperties:
>> + "@1?[0-9a-f](,[0-7])?$":
>> + type: object
>> + $ref: qcom,qps615.yaml#
>> + additionalProperties: true
>
> Nope, drop pattern Properties or explain what is this.
>
the child nodes represent the downstream ports of the PCIe
switch which wants to use same properties that is why
I tried to use this pattern properties.
>> +
>> +additionalProperties: true
>
> This cannot be true,
>
Let me check on this correct in next versions.
>> +
>> +examples:
>> + - |
>> +
>> + #include <dt-bindings/gpio/gpio.h>
>> +
>> + pcie {
>> + #address-cells = <3>;
>> + #size-cells = <2>;
>> +
>> + pcie@0 {
>> + device_type = "pci";
>> + reg = <0x0 0x0 0x0 0x0 0x0>;
>> +
>> + #address-cells = <3>;
>> + #size-cells = <2>;
>> + ranges;
>> +
>> + pcie@0,0 {
>> + compatible = "pci1179,0623";
>> + reg = <0x10000 0x0 0x0 0x0 0x0>;
>> + device_type = "pci";
>> + #address-cells = <3>;
>> + #size-cells = <2>;
>> + ranges;
>> +
>> + qcom,qps615-controller = <&qps615_controller>;
>> +
>> + vdd18-supply = <&vdd>;
>> + vdd09-supply = <&vdd>;
>> + vddc-supply = <&vdd>;
>> + vddio1-supply = <&vdd>;
>> + vddio2-supply = <&vdd>;
>> + vddio18-supply = <&vdd>;
>> +
>> + reset-gpios = <&gpio 1 GPIO_ACTIVE_LOW>;
>> +
>> + pcie@1,0 {
>> + reg = <0x20800 0x0 0x0 0x0 0x0>;
>
> Where is the compatible? You claim this is the same device as child?
>
These all the PCIe downstream nodes and compatible is optional for the
PCIe nodes.
>> + #address-cells = <3>;
>> + #size-cells = <2>;
>> + device_type = "pci";
>> + ranges;
>> +
>> + qcom,no-dfe;
>> + };
>> +
>> + pcie@2,0 {
>> + reg = <0x21000 0x0 0x0 0x0 0x0>;
>> + #address-cells = <3>;
>> + #size-cells = <2>;
>> + device_type = "pci";
>> + ranges;
>> +
>> + qcom,nfts = /bits/ 8 <10>;
>> + };
>> +
>> + pcie@3,0 {
>> + reg = <0x21800 0x0 0x0 0x0 0x0>;
>> + #address-cells = <3>;
>> + #size-cells = <2>;
>> + device_type = "pci";
>> + ranges;
>> +
>> + qcom,tx-amplitude-millivolt = <10>;
>> +
>> + pcie@0,0 {
>
> Total mess in indentation.
>
Let me correct in next version.
- Krishna Chaitanya.
>
>
> Best regards,
> Krzysztof
>
^ permalink raw reply [flat|nested] 77+ messages in thread
* Re: [PATCH v2 2/8] dt-bindings: trivial-devices: Add qcom,qps615
2024-08-04 8:50 ` Krzysztof Kozlowski
@ 2024-08-05 4:11 ` Krishna Chaitanya Chundru
0 siblings, 0 replies; 77+ messages in thread
From: Krishna Chaitanya Chundru @ 2024-08-05 4:11 UTC (permalink / raw)
To: Krzysztof Kozlowski, Lorenzo Pieralisi, Krzysztof Wilczyński,
Rob Herring, Bjorn Helgaas, Krzysztof Kozlowski, Conor Dooley,
Konrad Dybcio, cros-qcom-dts-watchers, Bartosz Golaszewski,
Jingoo Han, Manivannan Sadhasivam
Cc: andersson, quic_vbadigan, linux-arm-msm, linux-pci, devicetree,
linux-kernel, Bartosz Golaszewski
On 8/4/2024 2:20 PM, Krzysztof Kozlowski wrote:
> On 03/08/2024 05:22, Krishna chaitanya chundru wrote:
>> qps615 is a PCIe switch which is configured through i2c.
>>
>> Signed-off-by: Krishna chaitanya chundru <quic_krichai@quicinc.com>
>> ---
>> Documentation/devicetree/bindings/trivial-devices.yaml | 2 ++
>> 1 file changed, 2 insertions(+)
>>
>> diff --git a/Documentation/devicetree/bindings/trivial-devices.yaml b/Documentation/devicetree/bindings/trivial-devices.yaml
>> index 5d3dc952770d..7f44add21bf6 100644
>> --- a/Documentation/devicetree/bindings/trivial-devices.yaml
>> +++ b/Documentation/devicetree/bindings/trivial-devices.yaml
>> @@ -330,6 +330,8 @@ properties:
>> - renesas,isl29501
>> # Rohm DH2228FV
>> - rohm,dh2228fv
>> + # Qualcomm QPS615 PCIe switch control
>> + - qcom,qps615
>
> Don't place entries in random order. The list is alohabetically ordered.
>
> Best regards,
> Krzysztof
>
Ack
- krishna Chaitanya.
^ permalink raw reply [flat|nested] 77+ messages in thread
* Re: [PATCH v2 3/8] arm64: dts: qcom: qcs6490-rb3gen2: Add node for qps615
2024-08-04 8:54 ` Krzysztof Kozlowski
@ 2024-08-05 4:14 ` Krishna Chaitanya Chundru
0 siblings, 0 replies; 77+ messages in thread
From: Krishna Chaitanya Chundru @ 2024-08-05 4:14 UTC (permalink / raw)
To: Krzysztof Kozlowski, Lorenzo Pieralisi, Krzysztof Wilczyński,
Rob Herring, Bjorn Helgaas, Krzysztof Kozlowski, Conor Dooley,
Konrad Dybcio, cros-qcom-dts-watchers, Bartosz Golaszewski,
Jingoo Han, Manivannan Sadhasivam
Cc: andersson, quic_vbadigan, linux-arm-msm, linux-pci, devicetree,
linux-kernel, Bartosz Golaszewski
On 8/4/2024 2:24 PM, Krzysztof Kozlowski wrote:
> On 03/08/2024 05:22, Krishna chaitanya chundru wrote:
>> Add QPS615 PCIe switch node which has 3 downstream ports and in one
>> downstream port two embedded ethernet devices are present.
>>
>> Power to the QPS615 is supplied through two LDO regulators, controlled
>> by two GPIOs, these are added as fixed regulators.
>>
>> Add i2c device node which is used to configure the switch.
>>
>> Signed-off-by: Krishna chaitanya chundru <quic_krichai@quicinc.com>
>> ---
>> arch/arm64/boot/dts/qcom/qcs6490-rb3gen2.dts | 121 +++++++++++++++++++++++++++
>> arch/arm64/boot/dts/qcom/sc7280.dtsi | 2 +-
>> 2 files changed, 122 insertions(+), 1 deletion(-)
>>
>> diff --git a/arch/arm64/boot/dts/qcom/qcs6490-rb3gen2.dts b/arch/arm64/boot/dts/qcom/qcs6490-rb3gen2.dts
>> index 0d45662b8028..59d209768636 100644
>> --- a/arch/arm64/boot/dts/qcom/qcs6490-rb3gen2.dts
>> +++ b/arch/arm64/boot/dts/qcom/qcs6490-rb3gen2.dts
>> @@ -202,6 +202,30 @@ vph_pwr: vph-pwr-regulator {
>> regulator-min-microvolt = <3700000>;
>> regulator-max-microvolt = <3700000>;
>> };
>> +
>> + vdd_ntn_0p9: regulator-vdd-ntn-0p9 {
>> + compatible = "regulator-fixed";
>> + regulator-name = "VDD_NTN_0P9";
>> + gpio = <&pm8350c_gpios 2 GPIO_ACTIVE_HIGH>;
>> + regulator-min-microvolt = <899400>;
>> + regulator-max-microvolt = <899400>;
>> + enable-active-high;
>> + pinctrl-0 = <&ntn_0p9_en>;
>> + pinctrl-names = "default";
>> + regulator-enable-ramp-delay = <4300>;
>> + };
>> +
>> + vdd_ntn_1p8: regulator-vdd-ntn-1p8 {
>> + compatible = "regulator-fixed";
>> + regulator-name = "VDD_NTN_1P8";
>> + gpio = <&pm8350c_gpios 3 GPIO_ACTIVE_HIGH>;
>> + regulator-min-microvolt = <1800000>;
>> + regulator-max-microvolt = <1800000>;
>> + enable-active-high;
>> + pinctrl-0 = <&ntn_1p8_en>;
>> + pinctrl-names = "default";
>> + regulator-enable-ramp-delay = <10000>;
>> + };
>> };
>>
>> &apps_rsc {
>> @@ -595,6 +619,12 @@ lt9611_out: endpoint {
>> };
>> };
>> };
>> +
>> + qps615_switch: pcie-switch@77 {
>> + compatible = "qcom,qps615";
>> + reg = <0x77>;
>> + status = "okay";
>
> Where is it disabled?
>
let me check this, I taught if we are using a
phandle it should be enabled, if not the case
I will make it as disabled only.
>> + };
>> };
>>
>> &i2c1 {
>> @@ -688,6 +718,75 @@ &pmk8350_rtc {
>> status = "okay";
>> };
>>
>> +&pcie1 {
>
> Entries are ordered.
>
ack.
-- Krishna Chaitanya.
>> + status = "okay";
>> +};
>
>
>>
>
> Best regards,
> Krzysztof
>
^ permalink raw reply [flat|nested] 77+ messages in thread
* Re: [PATCH v2 1/8] dt-bindings: PCI: Add binding for qps615
2024-08-03 11:00 ` Dmitry Baryshkov
@ 2024-08-05 4:16 ` Krishna Chaitanya Chundru
0 siblings, 0 replies; 77+ messages in thread
From: Krishna Chaitanya Chundru @ 2024-08-05 4:16 UTC (permalink / raw)
To: Dmitry Baryshkov
Cc: Lorenzo Pieralisi, Krzysztof Wilczyński, Rob Herring,
Bjorn Helgaas, Krzysztof Kozlowski, Conor Dooley, Konrad Dybcio,
cros-qcom-dts-watchers, Bartosz Golaszewski, Jingoo Han,
Manivannan Sadhasivam, andersson, quic_vbadigan, linux-arm-msm,
linux-pci, devicetree, linux-kernel, Bartosz Golaszewski
On 8/3/2024 4:30 PM, Dmitry Baryshkov wrote:
> On Sat, Aug 03, 2024 at 08:52:47AM GMT, Krishna chaitanya chundru wrote:
>> Add binding describing the Qualcomm PCIe switch, QPS615,
>> which provides Ethernet MAC integrated to the 3rd downstream port
>> and two downstream PCIe ports.
>>
>> Signed-off-by: Krishna chaitanya chundru <quic_krichai@quicinc.com>
>> ---
>> .../devicetree/bindings/pci/qcom,qps615.yaml | 191 +++++++++++++++++++++
>> 1 file changed, 191 insertions(+)
>>
>> diff --git a/Documentation/devicetree/bindings/pci/qcom,qps615.yaml b/Documentation/devicetree/bindings/pci/qcom,qps615.yaml
>> new file mode 100644
>> index 000000000000..ea0c953ee56f
>> --- /dev/null
>> +++ b/Documentation/devicetree/bindings/pci/qcom,qps615.yaml
>> @@ -0,0 +1,191 @@
>> +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
>> +%YAML 1.2
>> +---
>> +$id: http://devicetree.org/schemas/pci/qcom,qps615.yaml#
>> +$schema: http://devicetree.org/meta-schemas/core.yaml#
>> +
>> +title: Qualcomm QPS615 PCIe switch
>> +
>> +maintainers:
>> + - Krishna chaitanya chundru <quic_krichai@quicinc.com>
>> +
>> +description: |
>> + Qualcomm QPS615 PCIe switch has one upstream and three downstream
>> + ports. The 3rd downstream port has integrated endpoint device of
>> + Ethernet MAC. Other two downstream ports are supposed to connect
>> + to external device.
>> +
>> + The QPS615 PCIe switch can be configured through I2C interface before
>> + PCIe link is established to change FTS, ASPM related entry delays,
>> + tx amplitude etc for better power efficiency and functionality.
>> +
>> +properties:
>> + compatible:
>> + enum:
>> + - pci1179,0623
>> +
>> + reg:
>> + maxItems: 1
>> +
>> + qcom,qps615-controller:
>> + $ref: /schemas/types.yaml#/definitions/phandle
>> + description:
>> + Reference to the I2C client used to do configure qps615
>> +
>> + vdd18-supply: true
>> +
>> + vdd09-supply: true
>> +
>> + vddc-supply: true
>> +
>> + vddio1-supply: true
>> +
>> + vddio2-supply: true
>> +
>> + vddio18-supply: true
>> +
>> + reset-gpios:
>> + maxItems: 1
>> + description:
>> + GPIO controlling the RESX# pin.
>> +
>> + qps615,axi-clk-freq-hz:
>> + description:
>> + AXI clock which internal bus of the switch.
>
> Is it a clock or clock rate?
It is clock ony.
>
>> +
>> + qcom,l0s-entry-delay-ns:
>> + description: Aspm l0s entry delay in nanoseconds.
>
> I'd say, from the property name it is obvious that it comes in
> nanoseconds.
>
I will remove the description from these properties.
>> +
>> + qcom,l1-entry-delay-ns:
>> + description: Aspm l1 entry delay in nanoseconds.
>> +
>> + qcom,tx-amplitude-millivolt:
>> + $ref: /schemas/types.yaml#/definitions/uint32
>> + description: Change Tx Margin setting for low power consumption.
>> +
>> + qcom,no-dfe:
>> + type: boolean
>> + description: Disables DFE (Decision Feedback Equalizer).
>> +
>> + qcom,nfts:
>> + $ref: /schemas/types.yaml#/definitions/uint8
>> + description:
>> + Fast Training Sequence (FTS) is the mechanism that
>> + is used for bit and Symbol lock.
>
> Doesn't help to understand what it is and what the value means.
>
I will update the description, this property represents number
of fast training sequence needs to be used for link transition
from L0s to L0.
- Krishna Chaitanya.
>> >> +allOf:
>> + - $ref: /schemas/pci/pci-bus-common.yaml#
>> + - if:
>> + properties:
>> + compatible:
>> + contains:
>> + const: pci1179,0623
>> + required:
>> + - compatible
>> + then:
>> + required:
>> + - vdd18-supply
>> + - vdd09-supply
>> + - vddc-supply
>> + - vddio1-supply
>> + - vddio2-supply
>> + - vddio18-supply
>> + - qcom,qps615-controller
>> + - reset-gpios
>> +
>> +patternProperties:
>> + "@1?[0-9a-f](,[0-7])?$":
>> + type: object
>> + $ref: qcom,qps615.yaml#
>> + additionalProperties: true
>> +
>> +additionalProperties: true
>> +
>> +examples:
>> + - |
>> +
>> + #include <dt-bindings/gpio/gpio.h>
>> +
>> + pcie {
>> + #address-cells = <3>;
>> + #size-cells = <2>;
>> +
>> + pcie@0 {
>> + device_type = "pci";
>> + reg = <0x0 0x0 0x0 0x0 0x0>;
>> +
>> + #address-cells = <3>;
>> + #size-cells = <2>;
>> + ranges;
>> +
>> + pcie@0,0 {
>> + compatible = "pci1179,0623";
>> + reg = <0x10000 0x0 0x0 0x0 0x0>;
>> + device_type = "pci";
>> + #address-cells = <3>;
>> + #size-cells = <2>;
>> + ranges;
>> +
>> + qcom,qps615-controller = <&qps615_controller>;
>
> Where is the corresponding device?
>
>> +
>> + vdd18-supply = <&vdd>;
>> + vdd09-supply = <&vdd>;
>> + vddc-supply = <&vdd>;
>> + vddio1-supply = <&vdd>;
>> + vddio2-supply = <&vdd>;
>> + vddio18-supply = <&vdd>;
>> +
>> + reset-gpios = <&gpio 1 GPIO_ACTIVE_LOW>;
>> +
>> + pcie@1,0 {
>> + reg = <0x20800 0x0 0x0 0x0 0x0>;
>> + #address-cells = <3>;
>> + #size-cells = <2>;
>> + device_type = "pci";
>> + ranges;
>> +
>> + qcom,no-dfe;
>> + };
>> +
>> + pcie@2,0 {
>> + reg = <0x21000 0x0 0x0 0x0 0x0>;
>> + #address-cells = <3>;
>> + #size-cells = <2>;
>> + device_type = "pci";
>> + ranges;
>> +
>> + qcom,nfts = /bits/ 8 <10>;
>> + };
>> +
>> + pcie@3,0 {
>> + reg = <0x21800 0x0 0x0 0x0 0x0>;
>> + #address-cells = <3>;
>> + #size-cells = <2>;
>> + device_type = "pci";
>> + ranges;
>> +
>> + qcom,tx-amplitude-millivolt = <10>;
>> +
>> + pcie@0,0 {
>
> Wrong indentation.
>
>> + reg = <0x40000 0x0 0x0 0x0 0x0>;
>> + #address-cells = <3>;
>> + #size-cells = <2>;
>> + device_type = "pci";
>> + ranges;
>> +
>> + qcom,l1-entry-delay-ns = <10>;
>> + };
>> +
>> + pcie@0,1 {
>> + reg = <0x40100 0x0 0x0 0x0 0x0>;
>> + #address-cells = <3>;
>> + #size-cells = <2>;
>> + device_type = "pci";
>> + ranges;
>> +
>> + qcom,l0s-entry-delay-ns = <10>;
>> + };
>> + };
>> + };
>> + };
>> + };
>>
>> --
>> 2.34.1
>>
>
^ permalink raw reply [flat|nested] 77+ messages in thread
* Re: [PATCH v2 0/8] PCI: Enable Power and configure the QPS615 PCIe switch
2024-08-04 8:57 ` Krzysztof Kozlowski
@ 2024-08-05 4:18 ` Krishna Chaitanya Chundru
0 siblings, 0 replies; 77+ messages in thread
From: Krishna Chaitanya Chundru @ 2024-08-05 4:18 UTC (permalink / raw)
To: Krzysztof Kozlowski, Lorenzo Pieralisi, Krzysztof Wilczyński,
Rob Herring, Bjorn Helgaas, Krzysztof Kozlowski, Conor Dooley,
Konrad Dybcio, cros-qcom-dts-watchers, Bartosz Golaszewski,
Jingoo Han, Manivannan Sadhasivam
Cc: andersson, quic_vbadigan, linux-arm-msm, linux-pci, devicetree,
linux-kernel, Bartosz Golaszewski
On 8/4/2024 2:27 PM, Krzysztof Kozlowski wrote:
> On 03/08/2024 05:22, Krishna chaitanya chundru wrote:
>> QPS615 is the PCIe switch which has one upstream and three downstream
>> ports. One of the downstream ports is used as endpoint device of Ethernet
>> MAC. Other two downstream ports are supposed to connect to external
>> device. One Host can connect to QPS615 by upstream port.
>>
>> QPS615 switch power is controlled by the GPIO's. After powering on
>> the switch will immediately participate in the link training. if the
>> host is also ready by that time PCIe link will established.
>>
>> The QPS615 needs to configured certain parameters like de-emphasis,
>> disable unused port etc before link is established.
>>
>> The device tree properties are parsed per node under pci-pci bridge in the
>> devicetree. Each node has unique bdf value in the reg property, driver
>> uses this bdf to differentiate ports, as there are certain i2c writes to
>> select particulat port.
>>
>> As the controller starts link training before the probe of pwrctl driver,
>> the PCIe link may come up before configuring the switch itself.
>> To avoid this introduce two functions in pci_ops to start_link() &
>> stop_link() which will disable the link training if the PCIe link is
>> not up yet.
>>
>> Now PCI pwrctl device is the child of the pci-pcie bridge, if we want
>> to enable the suspend resume for pwrctl device there may be issues
>> since pci bridge will try to access some registers in the config which
>> may cause timeouts or Un clocked access as the power can be removed in
>> the suspend of pwrctl driver.
>>
>> To solve this make PCIe controller as parent to the pci pwr ctrl driver
>> and create devlink between host bridge and pci pwrctl driver so that
>> pci pwrctl driver will go suspend only after all the PCIe devices went
>> to suspend.
>>
>> Signed-off-by: Krishna chaitanya chundru <quic_krichai@quicinc.com>
>> ---
>> Changes in V1:
>> - Fix the code as per the comments given.
>
> You did not implement the comments so such changelog is rather a joke.
> Respond to each comment from v1 and acknowledge it.
>
> Then write detailed changelog.
>
> Best regards,
> Krzysztof
>
I will write a detailed changelog from v3 onwards spare me for this time.
- Krishna Chaitanya.
^ permalink raw reply [flat|nested] 77+ messages in thread
* Re: [PATCH v2 0/8] PCI: Enable Power and configure the QPS615 PCIe switch
2024-08-03 10:56 ` [PATCH v2 0/8] PCI: Enable Power and configure the QPS615 PCIe switch Dmitry Baryshkov
@ 2024-08-05 4:19 ` Krishna Chaitanya Chundru
0 siblings, 0 replies; 77+ messages in thread
From: Krishna Chaitanya Chundru @ 2024-08-05 4:19 UTC (permalink / raw)
To: Dmitry Baryshkov
Cc: Lorenzo Pieralisi, Krzysztof Wilczyński, Rob Herring,
Bjorn Helgaas, Krzysztof Kozlowski, Conor Dooley, Konrad Dybcio,
cros-qcom-dts-watchers, Bartosz Golaszewski, Jingoo Han,
Manivannan Sadhasivam, andersson, quic_vbadigan, linux-arm-msm,
linux-pci, devicetree, linux-kernel, Bartosz Golaszewski
On 8/3/2024 4:26 PM, Dmitry Baryshkov wrote:
> On Sat, Aug 03, 2024 at 08:52:46AM GMT, Krishna chaitanya chundru wrote:
>> QPS615 is the PCIe switch which has one upstream and three downstream
>> ports. One of the downstream ports is used as endpoint device of Ethernet
>> MAC. Other two downstream ports are supposed to connect to external
>> device. One Host can connect to QPS615 by upstream port.
>>
>> QPS615 switch power is controlled by the GPIO's. After powering on
>> the switch will immediately participate in the link training. if the
>> host is also ready by that time PCIe link will established.
>>
>> The QPS615 needs to configured certain parameters like de-emphasis,
>> disable unused port etc before link is established.
>>
>> The device tree properties are parsed per node under pci-pci bridge in the
>> devicetree. Each node has unique bdf value in the reg property, driver
>> uses this bdf to differentiate ports, as there are certain i2c writes to
>> select particulat port.
>>
>> As the controller starts link training before the probe of pwrctl driver,
>> the PCIe link may come up before configuring the switch itself.
>> To avoid this introduce two functions in pci_ops to start_link() &
>> stop_link() which will disable the link training if the PCIe link is
>> not up yet.
>>
>> Now PCI pwrctl device is the child of the pci-pcie bridge, if we want
>> to enable the suspend resume for pwrctl device there may be issues
>> since pci bridge will try to access some registers in the config which
>> may cause timeouts or Un clocked access as the power can be removed in
>> the suspend of pwrctl driver.
>>
>> To solve this make PCIe controller as parent to the pci pwr ctrl driver
>> and create devlink between host bridge and pci pwrctl driver so that
>> pci pwrctl driver will go suspend only after all the PCIe devices went
>> to suspend.
>>
>> Signed-off-by: Krishna chaitanya chundru <quic_krichai@quicinc.com>
>> ---
>> Changes in V1:
>> - Fix the code as per the comments given.
>
> This is not a proper changelog entry. It doesn't allow reviewers to
> understand what actually happened. Could you please list your actual
> changes in a reply and also include them in a changelog if there is a
> need for v3.
>
ack
- Krishna Chaitanya.
>> - Removed D3cold D0 sequence in suspend resume for now as it needs
>> seperate discussion.
>> - change to dt approach for configuring the switch instead of request_firmware() approach
>> - Link to v1: https://lore.kernel.org/linux-pci/20240626-qps615-v1-4-2ade7bd91e02@quicinc.com/T/
>> ---
>>
>
^ permalink raw reply [flat|nested] 77+ messages in thread
* Re: [PATCH v2 0/8] PCI: Enable Power and configure the QPS615 PCIe switch
2024-08-03 3:22 [PATCH v2 0/8] PCI: Enable Power and configure the QPS615 PCIe switch Krishna chaitanya chundru
` (9 preceding siblings ...)
2024-08-04 8:57 ` Krzysztof Kozlowski
@ 2024-08-05 4:34 ` Krishna Chaitanya Chundru
2024-08-05 15:00 ` Rob Herring (Arm)
2024-08-06 15:24 ` Ilpo Järvinen
12 siblings, 0 replies; 77+ messages in thread
From: Krishna Chaitanya Chundru @ 2024-08-05 4:34 UTC (permalink / raw)
To: Lorenzo Pieralisi, Krzysztof Wilczyński, Rob Herring,
Bjorn Helgaas, Krzysztof Kozlowski, Conor Dooley, Konrad Dybcio,
cros-qcom-dts-watchers, Bartosz Golaszewski, Jingoo Han,
Manivannan Sadhasivam
Cc: andersson, quic_vbadigan, linux-arm-msm, linux-pci, devicetree,
linux-kernel, Bartosz Golaszewski
On 8/3/2024 8:52 AM, Krishna chaitanya chundru wrote:
> QPS615 is the PCIe switch which has one upstream and three downstream
> ports. One of the downstream ports is used as endpoint device of Ethernet
> MAC. Other two downstream ports are supposed to connect to external
> device. One Host can connect to QPS615 by upstream port.
>
> QPS615 switch power is controlled by the GPIO's. After powering on
> the switch will immediately participate in the link training. if the
> host is also ready by that time PCIe link will established.
>
> The QPS615 needs to configured certain parameters like de-emphasis,
> disable unused port etc before link is established.
>
> The device tree properties are parsed per node under pci-pci bridge in the
> devicetree. Each node has unique bdf value in the reg property, driver
> uses this bdf to differentiate ports, as there are certain i2c writes to
> select particulat port.
>
> As the controller starts link training before the probe of pwrctl driver,
> the PCIe link may come up before configuring the switch itself.
> To avoid this introduce two functions in pci_ops to start_link() &
> stop_link() which will disable the link training if the PCIe link is
> not up yet.
>
> Now PCI pwrctl device is the child of the pci-pcie bridge, if we want
> to enable the suspend resume for pwrctl device there may be issues
> since pci bridge will try to access some registers in the config which
> may cause timeouts or Un clocked access as the power can be removed in
> the suspend of pwrctl driver.
>
> To solve this make PCIe controller as parent to the pci pwr ctrl driver
> and create devlink between host bridge and pci pwrctl driver so that
> pci pwrctl driver will go suspend only after all the PCIe devices went
> to suspend.
>
> Signed-off-by: Krishna chaitanya chundru <quic_krichai@quicinc.com>
> ---
> Changes in V1:
> - Fix the code as per the comments given.
changes in v1:
- Instead of referencing whole i2c-bus add i2c-client node and reference
it (Dmitry)
- Change the regulator's as per the schematics as per offline review
(bjorn Andresson)
- Remove additional host check in bus.c (Bart)
- For stop_link op change return type from int to void (Bart)
- Remove firmware based approach for configuring sequence as suggested
by multiple reviewers.
- Introduce new dt-properties for the switch to configure the switch
as we are replacing the firmware based approach.
- The downstream ports add properties in the child nodes which will
represented in PCIe hierarchy format.
- Removed D3cold D0 sequence in suspend resume for now as it needs
separate discussion.
- Krishna Chaitanya.
> - Removed D3cold D0 sequence in suspend resume for now as it needs
> seperate discussion.
> - change to dt approach for configuring the switch instead of request_firmware() approach
> - Link to v1: https://lore.kernel.org/linux-pci/20240626-qps615-v1-4-2ade7bd91e02@quicinc.com/T/
> ---
>
> ---
> Krishna chaitanya chundru (8):
> dt-bindings: PCI: Add binding for qps615
> dt-bindings: trivial-devices: Add qcom,qps615
> arm64: dts: qcom: qcs6490-rb3gen2: Add node for qps615
> PCI: Change the parent to correctly represent pcie hierarchy
> PCI: Add new start_link() & stop_link function ops
> PCI: dwc: Add support for new pci function op
> PCI: qcom: Add support for host_stop_link() & host_start_link()
> PCI: pwrctl: Add power control driver for qps615
>
> .../devicetree/bindings/pci/qcom,qps615.yaml | 191 ++++++
> .../devicetree/bindings/trivial-devices.yaml | 2 +
> arch/arm64/boot/dts/qcom/qcs6490-rb3gen2.dts | 121 ++++
> arch/arm64/boot/dts/qcom/sc7280.dtsi | 2 +-
> drivers/pci/bus.c | 3 +-
> drivers/pci/controller/dwc/pcie-designware-host.c | 18 +
> drivers/pci/controller/dwc/pcie-designware.h | 16 +
> drivers/pci/controller/dwc/pcie-qcom.c | 39 ++
> drivers/pci/pwrctl/Kconfig | 7 +
> drivers/pci/pwrctl/Makefile | 1 +
> drivers/pci/pwrctl/core.c | 9 +-
> drivers/pci/pwrctl/pci-pwrctl-qps615.c | 638 +++++++++++++++++++++
> include/linux/pci.h | 2 +
> 13 files changed, 1046 insertions(+), 3 deletions(-)
> ---
> base-commit: 1722389b0d863056d78287a120a1d6cadb8d4f7b
> change-id: 20240727-qps615-e2894a38d36f
>
> Best regards,
^ permalink raw reply [flat|nested] 77+ messages in thread
* Re: [PATCH v2 1/8] dt-bindings: PCI: Add binding for qps615
2024-08-05 4:02 ` Krishna Chaitanya Chundru
@ 2024-08-05 5:12 ` Krzysztof Kozlowski
2024-08-05 5:33 ` Krishna Chaitanya Chundru
2024-08-05 16:39 ` Bjorn Andersson
0 siblings, 2 replies; 77+ messages in thread
From: Krzysztof Kozlowski @ 2024-08-05 5:12 UTC (permalink / raw)
To: Krishna Chaitanya Chundru, Lorenzo Pieralisi,
Krzysztof Wilczyński, Rob Herring, Bjorn Helgaas,
Krzysztof Kozlowski, Conor Dooley, Konrad Dybcio,
cros-qcom-dts-watchers, Bartosz Golaszewski, Jingoo Han,
Manivannan Sadhasivam
Cc: andersson, quic_vbadigan, linux-arm-msm, linux-pci, devicetree,
linux-kernel, Bartosz Golaszewski
On 05/08/2024 06:02, Krishna Chaitanya Chundru wrote:
>
>
> On 8/4/2024 2:26 PM, Krzysztof Kozlowski wrote:
>> On 03/08/2024 05:22, Krishna chaitanya chundru wrote:
>>> Add binding describing the Qualcomm PCIe switch, QPS615,
>>> which provides Ethernet MAC integrated to the 3rd downstream port
>>> and two downstream PCIe ports.
>>>
>>> Signed-off-by: Krishna chaitanya chundru <quic_krichai@quicinc.com>
>>> ---
>>> .../devicetree/bindings/pci/qcom,qps615.yaml | 191 +++++++++++++++++++++
>>> 1 file changed, 191 insertions(+)
>>>
>>> diff --git a/Documentation/devicetree/bindings/pci/qcom,qps615.yaml b/Documentation/devicetree/bindings/pci/qcom,qps615.yaml
>>> new file mode 100644
>>> index 000000000000..ea0c953ee56f
>>> --- /dev/null
>>> +++ b/Documentation/devicetree/bindings/pci/qcom,qps615.yaml
>>> @@ -0,0 +1,191 @@
>>> +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
>>> +%YAML 1.2
>>> +---
>>> +$id: http://devicetree.org/schemas/pci/qcom,qps615.yaml#
>>> +$schema: http://devicetree.org/meta-schemas/core.yaml#
>>> +
>>> +title: Qualcomm QPS615 PCIe switch
>>> +
>>> +maintainers:
>>> + - Krishna chaitanya chundru <quic_krichai@quicinc.com>
>>> +
>>> +description: |
>>> + Qualcomm QPS615 PCIe switch has one upstream and three downstream
>>> + ports. The 3rd downstream port has integrated endpoint device of
>>> + Ethernet MAC. Other two downstream ports are supposed to connect
>>> + to external device.
>>> +
>>> + The QPS615 PCIe switch can be configured through I2C interface before
>>> + PCIe link is established to change FTS, ASPM related entry delays,
>>> + tx amplitude etc for better power efficiency and functionality.
>>> +
>>> +properties:
>>> + compatible:
>>> + enum:
>>> + - pci1179,0623
>>> +
>>> + reg:
>>> + maxItems: 1
>>> +
>>> + qcom,qps615-controller:
>>
>> and now I see that you totally ignored comments. Repeating the same over
>> and over is a waste of time.
>>
>> <form letter>
>> This is a friendly reminder during the review process.
>>
>> It seems my or other reviewer's previous comments were not fully
>> addressed. Maybe the feedback got lost between the quotes, maybe you
>> just forgot to apply it. Please go back to the previous discussion and
>> either implement all requested changes or keep discussing them.
>>
>> Thank you.
>> </form letter>
>>
>>
>> Best regards,
>> Krzysztof
>>
> Hi Krzysztof,
>
> In patch1 we are trying to add reference of i2c-adapter, you suggested
> to use i2c-bus for that. we got comments on the driver code not to use
> adapter and instead use i2c client reference. I felt i2c-bus is not
> ideal to represent i2c client device so used this name.
You did not respond to comment of using i2c-bus, just silently decided
to implement other property.
Anyway, why i2c-bus is not suitable here? I am quite surprised...
Best regards,
Krzysztof
^ permalink raw reply [flat|nested] 77+ messages in thread
* Re: [PATCH v2 1/8] dt-bindings: PCI: Add binding for qps615
2024-08-05 4:11 ` Krishna Chaitanya Chundru
@ 2024-08-05 5:14 ` Krzysztof Kozlowski
2024-08-05 5:26 ` Krishna Chaitanya Chundru
2024-08-05 17:07 ` Bjorn Andersson
1 sibling, 1 reply; 77+ messages in thread
From: Krzysztof Kozlowski @ 2024-08-05 5:14 UTC (permalink / raw)
To: Krishna Chaitanya Chundru, Lorenzo Pieralisi,
Krzysztof Wilczyński, Rob Herring, Bjorn Helgaas,
Krzysztof Kozlowski, Conor Dooley, Konrad Dybcio,
cros-qcom-dts-watchers, Bartosz Golaszewski, Jingoo Han,
Manivannan Sadhasivam
Cc: andersson, quic_vbadigan, linux-arm-msm, linux-pci, devicetree,
linux-kernel, Bartosz Golaszewski
On 05/08/2024 06:11, Krishna Chaitanya Chundru wrote:
>>> +
>>> + qcom,nfts:
>>> + $ref: /schemas/types.yaml#/definitions/uint8
>>> + description:
>>> + Fast Training Sequence (FTS) is the mechanism that
>>> + is used for bit and Symbol lock.
>>
>> What are the values? Why this is uint8?
>>
> These represents number of fast training sequence and doesn't have
> any units and the maximum value for this is 0xFF only so we used
> uint8.
>> You described the desired Linux feature or behavior, not the actual
>> hardware. The bindings are about the latter, so instead you need to
>> rephrase the property and its description to match actual hardware
>> capabilities/features/configuration etc.
> ack.
>>
>>> +
>>> +allOf:
>>> + - $ref: /schemas/pci/pci-bus-common.yaml#
>>> + - if:
>>> + properties:
>>> + compatible:
>>> + contains:
>>> + const: pci1179,0623
>>> + required:
>>> + - compatible
>>
>> Why do you have entire if? You do not have multiple variants, drop.
>>
> The child nodes also referencing the qcom,qps615.yaml# node, I tried
> to use this way to say "the below properties are for the required for
> parent and optional for child".
I don't understand how child device can be exactly the same as parent
device. How does it look in terms of hardware? Pins and supplies?
>>> + then:
>>> + required:
>>> + - vdd18-supply
>>> + - vdd09-supply
>>> + - vddc-supply
>>> + - vddio1-supply
>>> + - vddio2-supply
>>> + - vddio18-supply
>>> + - qcom,qps615-controller
>>> + - reset-gpios
>>> +
>>> +patternProperties:
>>> + "@1?[0-9a-f](,[0-7])?$":
>>> + type: object
>>> + $ref: qcom,qps615.yaml#
>>> + additionalProperties: true
>>
>> Nope, drop pattern Properties or explain what is this.
>>
> the child nodes represent the downstream ports of the PCIe
> switch which wants to use same properties that is why
> I tried to use this pattern properties.
Downstream port is not the same as device. Why downstream port has the
same supplies? To which pins are they connected?
Best regards,
Krzysztof
^ permalink raw reply [flat|nested] 77+ messages in thread
* Re: [PATCH v2 1/8] dt-bindings: PCI: Add binding for qps615
2024-08-05 5:14 ` Krzysztof Kozlowski
@ 2024-08-05 5:26 ` Krishna Chaitanya Chundru
2024-08-05 5:28 ` Krzysztof Kozlowski
0 siblings, 1 reply; 77+ messages in thread
From: Krishna Chaitanya Chundru @ 2024-08-05 5:26 UTC (permalink / raw)
To: Krzysztof Kozlowski, Lorenzo Pieralisi, Krzysztof Wilczyński,
Rob Herring, Bjorn Helgaas, Krzysztof Kozlowski, Conor Dooley,
Konrad Dybcio, cros-qcom-dts-watchers, Bartosz Golaszewski,
Jingoo Han, Manivannan Sadhasivam
Cc: andersson, quic_vbadigan, linux-arm-msm, linux-pci, devicetree,
linux-kernel, Bartosz Golaszewski
On 8/5/2024 10:44 AM, Krzysztof Kozlowski wrote:
> On 05/08/2024 06:11, Krishna Chaitanya Chundru wrote:
>
>
>>>> +
>>>> + qcom,nfts:
>>>> + $ref: /schemas/types.yaml#/definitions/uint8
>>>> + description:
>>>> + Fast Training Sequence (FTS) is the mechanism that
>>>> + is used for bit and Symbol lock.
>>>
>>> What are the values? Why this is uint8?
>>>
>> These represents number of fast training sequence and doesn't have
>> any units and the maximum value for this is 0xFF only so we used
>> uint8.
>>> You described the desired Linux feature or behavior, not the actual
>>> hardware. The bindings are about the latter, so instead you need to
>>> rephrase the property and its description to match actual hardware
>>> capabilities/features/configuration etc.
>> ack.
>>>
>>>> +
>>>> +allOf:
>>>> + - $ref: /schemas/pci/pci-bus-common.yaml#
>>>> + - if:
>>>> + properties:
>>>> + compatible:
>>>> + contains:
>>>> + const: pci1179,0623
>>>> + required:
>>>> + - compatible
>>>
>>> Why do you have entire if? You do not have multiple variants, drop.
>>>
>> The child nodes also referencing the qcom,qps615.yaml# node, I tried
>> to use this way to say "the below properties are for the required for
>> parent and optional for child".
>
> I don't understand how child device can be exactly the same as parent
> device. How does it look in terms of hardware? Pins and supplies?
>
>>>> + then:
>>>> + required:
>>>> + - vdd18-supply
>>>> + - vdd09-supply
>>>> + - vddc-supply
>>>> + - vddio1-supply
>>>> + - vddio2-supply
>>>> + - vddio18-supply
>>>> + - qcom,qps615-controller
>>>> + - reset-gpios
>>>> +
>>>> +patternProperties:
>>>> + "@1?[0-9a-f](,[0-7])?$":
>>>> + type: object
>>>> + $ref: qcom,qps615.yaml#
>>>> + additionalProperties: true
>>>
>>> Nope, drop pattern Properties or explain what is this.
>>>
>> the child nodes represent the downstream ports of the PCIe
>> switch which wants to use same properties that is why
>> I tried to use this pattern properties.
>
> Downstream port is not the same as device. Why downstream port has the
> same supplies? To which pins are they connected?
>
>
Hi Krzysztof,
Downstream ports dosen't have pins or supplies to power on.
But there are properties like qcom,l0s-entry-delay-ns,
qcom,l1-entry-delay-ns, qcom,tx-amplitude-millivolt etc which
applicable for child nodes also. Instead of re-declaring the
these properties again I tried to use pattern properties.
- krishna Chaitanya.
>
>
> Best regards,
> Krzysztof
>
^ permalink raw reply [flat|nested] 77+ messages in thread
* Re: [PATCH v2 1/8] dt-bindings: PCI: Add binding for qps615
2024-08-05 5:26 ` Krishna Chaitanya Chundru
@ 2024-08-05 5:28 ` Krzysztof Kozlowski
2024-08-05 5:57 ` Krishna Chaitanya Chundru
0 siblings, 1 reply; 77+ messages in thread
From: Krzysztof Kozlowski @ 2024-08-05 5:28 UTC (permalink / raw)
To: Krishna Chaitanya Chundru, Lorenzo Pieralisi,
Krzysztof Wilczyński, Rob Herring, Bjorn Helgaas,
Krzysztof Kozlowski, Conor Dooley, Konrad Dybcio,
cros-qcom-dts-watchers, Bartosz Golaszewski, Jingoo Han,
Manivannan Sadhasivam
Cc: andersson, quic_vbadigan, linux-arm-msm, linux-pci, devicetree,
linux-kernel, Bartosz Golaszewski
On 05/08/2024 07:26, Krishna Chaitanya Chundru wrote:
>
>
> On 8/5/2024 10:44 AM, Krzysztof Kozlowski wrote:
>> On 05/08/2024 06:11, Krishna Chaitanya Chundru wrote:
>>
>>
>>>>> +
>>>>> + qcom,nfts:
>>>>> + $ref: /schemas/types.yaml#/definitions/uint8
>>>>> + description:
>>>>> + Fast Training Sequence (FTS) is the mechanism that
>>>>> + is used for bit and Symbol lock.
>>>>
>>>> What are the values? Why this is uint8?
>>>>
>>> These represents number of fast training sequence and doesn't have
>>> any units and the maximum value for this is 0xFF only so we used
>>> uint8.
>>>> You described the desired Linux feature or behavior, not the actual
>>>> hardware. The bindings are about the latter, so instead you need to
>>>> rephrase the property and its description to match actual hardware
>>>> capabilities/features/configuration etc.
>>> ack.
>>>>
>>>>> +
>>>>> +allOf:
>>>>> + - $ref: /schemas/pci/pci-bus-common.yaml#
>>>>> + - if:
>>>>> + properties:
>>>>> + compatible:
>>>>> + contains:
>>>>> + const: pci1179,0623
>>>>> + required:
>>>>> + - compatible
>>>>
>>>> Why do you have entire if? You do not have multiple variants, drop.
>>>>
>>> The child nodes also referencing the qcom,qps615.yaml# node, I tried
>>> to use this way to say "the below properties are for the required for
>>> parent and optional for child".
>>
>> I don't understand how child device can be exactly the same as parent
>> device. How does it look in terms of hardware? Pins and supplies?
>>
>>>>> + then:
>>>>> + required:
>>>>> + - vdd18-supply
>>>>> + - vdd09-supply
>>>>> + - vddc-supply
>>>>> + - vddio1-supply
>>>>> + - vddio2-supply
>>>>> + - vddio18-supply
>>>>> + - qcom,qps615-controller
>>>>> + - reset-gpios
>>>>> +
>>>>> +patternProperties:
>>>>> + "@1?[0-9a-f](,[0-7])?$":
>>>>> + type: object
>>>>> + $ref: qcom,qps615.yaml#
>>>>> + additionalProperties: true
>>>>
>>>> Nope, drop pattern Properties or explain what is this.
>>>>
>>> the child nodes represent the downstream ports of the PCIe
>>> switch which wants to use same properties that is why
>>> I tried to use this pattern properties.
>>
>> Downstream port is not the same as device. Why downstream port has the
>> same supplies? To which pins are they connected?
>>
>>
> Hi Krzysztof,
>
> Downstream ports dosen't have pins or supplies to power on.
>
> But there are properties like qcom,l0s-entry-delay-ns,
> qcom,l1-entry-delay-ns, qcom,tx-amplitude-millivolt etc which
> applicable for child nodes also. Instead of re-declaring the
> these properties again I tried to use pattern properties.
You could use $defs for them, but I don't understand how does these
properties apply for both main device and ports. It seems you are
writing binding to match some driver behavior. Let's start from basics -
describe the hardware.
Best regards,
Krzysztof
^ permalink raw reply [flat|nested] 77+ messages in thread
* Re: [PATCH v2 1/8] dt-bindings: PCI: Add binding for qps615
2024-08-05 5:12 ` Krzysztof Kozlowski
@ 2024-08-05 5:33 ` Krishna Chaitanya Chundru
2024-08-05 16:39 ` Bjorn Andersson
1 sibling, 0 replies; 77+ messages in thread
From: Krishna Chaitanya Chundru @ 2024-08-05 5:33 UTC (permalink / raw)
To: Krzysztof Kozlowski, Lorenzo Pieralisi, Krzysztof Wilczyński,
Rob Herring, Bjorn Helgaas, Krzysztof Kozlowski, Conor Dooley,
Konrad Dybcio, cros-qcom-dts-watchers, Bartosz Golaszewski,
Jingoo Han, Manivannan Sadhasivam
Cc: andersson, quic_vbadigan, linux-arm-msm, linux-pci, devicetree,
linux-kernel, Bartosz Golaszewski
On 8/5/2024 10:42 AM, Krzysztof Kozlowski wrote:
> On 05/08/2024 06:02, Krishna Chaitanya Chundru wrote:
>>
>>
>> On 8/4/2024 2:26 PM, Krzysztof Kozlowski wrote:
>>> On 03/08/2024 05:22, Krishna chaitanya chundru wrote:
>>>> Add binding describing the Qualcomm PCIe switch, QPS615,
>>>> which provides Ethernet MAC integrated to the 3rd downstream port
>>>> and two downstream PCIe ports.
>>>>
>>>> Signed-off-by: Krishna chaitanya chundru <quic_krichai@quicinc.com>
>>>> ---
>>>> .../devicetree/bindings/pci/qcom,qps615.yaml | 191 +++++++++++++++++++++
>>>> 1 file changed, 191 insertions(+)
>>>>
>>>> diff --git a/Documentation/devicetree/bindings/pci/qcom,qps615.yaml b/Documentation/devicetree/bindings/pci/qcom,qps615.yaml
>>>> new file mode 100644
>>>> index 000000000000..ea0c953ee56f
>>>> --- /dev/null
>>>> +++ b/Documentation/devicetree/bindings/pci/qcom,qps615.yaml
>>>> @@ -0,0 +1,191 @@
>>>> +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
>>>> +%YAML 1.2
>>>> +---
>>>> +$id: http://devicetree.org/schemas/pci/qcom,qps615.yaml#
>>>> +$schema: http://devicetree.org/meta-schemas/core.yaml#
>>>> +
>>>> +title: Qualcomm QPS615 PCIe switch
>>>> +
>>>> +maintainers:
>>>> + - Krishna chaitanya chundru <quic_krichai@quicinc.com>
>>>> +
>>>> +description: |
>>>> + Qualcomm QPS615 PCIe switch has one upstream and three downstream
>>>> + ports. The 3rd downstream port has integrated endpoint device of
>>>> + Ethernet MAC. Other two downstream ports are supposed to connect
>>>> + to external device.
>>>> +
>>>> + The QPS615 PCIe switch can be configured through I2C interface before
>>>> + PCIe link is established to change FTS, ASPM related entry delays,
>>>> + tx amplitude etc for better power efficiency and functionality.
>>>> +
>>>> +properties:
>>>> + compatible:
>>>> + enum:
>>>> + - pci1179,0623
>>>> +
>>>> + reg:
>>>> + maxItems: 1
>>>> +
>>>> + qcom,qps615-controller:
>>>
>>> and now I see that you totally ignored comments. Repeating the same over
>>> and over is a waste of time.
>>>
>>> <form letter>
>>> This is a friendly reminder during the review process.
>>>
>>> It seems my or other reviewer's previous comments were not fully
>>> addressed. Maybe the feedback got lost between the quotes, maybe you
>>> just forgot to apply it. Please go back to the previous discussion and
>>> either implement all requested changes or keep discussing them.
>>>
>>> Thank you.
>>> </form letter>
>>>
>>>
>>> Best regards,
>>> Krzysztof
>>>
>> Hi Krzysztof,
>>
>> In patch1 we are trying to add reference of i2c-adapter, you suggested
>> to use i2c-bus for that. we got comments on the driver code not to use
>> adapter and instead use i2c client reference. I felt i2c-bus is not
>> ideal to represent i2c client device so used this name.
>
> You did not respond to comment of using i2c-bus, just silently decided
> to implement other property.
>
I should have replied to v1 why we are not using this suggested way,
next time onwards I will fallow that.
> Anyway, why i2c-bus is not suitable here? I am quite surprised...
>
It was suggested by bjorn andresson in the offline review, I will check
this and get back.
- Krishna Chaitanya.
>
>
> Best regards,
> Krzysztof
>
^ permalink raw reply [flat|nested] 77+ messages in thread
* Re: [PATCH v2 1/8] dt-bindings: PCI: Add binding for qps615
2024-08-05 5:28 ` Krzysztof Kozlowski
@ 2024-08-05 5:57 ` Krishna Chaitanya Chundru
2024-08-05 14:43 ` Krzysztof Kozlowski
0 siblings, 1 reply; 77+ messages in thread
From: Krishna Chaitanya Chundru @ 2024-08-05 5:57 UTC (permalink / raw)
To: Krzysztof Kozlowski, Lorenzo Pieralisi, Krzysztof Wilczyński,
Rob Herring, Bjorn Helgaas, Krzysztof Kozlowski, Conor Dooley,
Konrad Dybcio, cros-qcom-dts-watchers, Bartosz Golaszewski,
Jingoo Han, Manivannan Sadhasivam
Cc: andersson, quic_vbadigan, linux-arm-msm, linux-pci, devicetree,
linux-kernel, Bartosz Golaszewski
On 8/5/2024 10:58 AM, Krzysztof Kozlowski wrote:
> On 05/08/2024 07:26, Krishna Chaitanya Chundru wrote:
>>
>>
>> On 8/5/2024 10:44 AM, Krzysztof Kozlowski wrote:
>>> On 05/08/2024 06:11, Krishna Chaitanya Chundru wrote:
>>>
>>>
>>>>>> +
>>>>>> + qcom,nfts:
>>>>>> + $ref: /schemas/types.yaml#/definitions/uint8
>>>>>> + description:
>>>>>> + Fast Training Sequence (FTS) is the mechanism that
>>>>>> + is used for bit and Symbol lock.
>>>>>
>>>>> What are the values? Why this is uint8?
>>>>>
>>>> These represents number of fast training sequence and doesn't have
>>>> any units and the maximum value for this is 0xFF only so we used
>>>> uint8.
>>>>> You described the desired Linux feature or behavior, not the actual
>>>>> hardware. The bindings are about the latter, so instead you need to
>>>>> rephrase the property and its description to match actual hardware
>>>>> capabilities/features/configuration etc.
>>>> ack.
>>>>>
>>>>>> +
>>>>>> +allOf:
>>>>>> + - $ref: /schemas/pci/pci-bus-common.yaml#
>>>>>> + - if:
>>>>>> + properties:
>>>>>> + compatible:
>>>>>> + contains:
>>>>>> + const: pci1179,0623
>>>>>> + required:
>>>>>> + - compatible
>>>>>
>>>>> Why do you have entire if? You do not have multiple variants, drop.
>>>>>
>>>> The child nodes also referencing the qcom,qps615.yaml# node, I tried
>>>> to use this way to say "the below properties are for the required for
>>>> parent and optional for child".
>>>
>>> I don't understand how child device can be exactly the same as parent
>>> device. How does it look in terms of hardware? Pins and supplies?
>>>
>>>>>> + then:
>>>>>> + required:
>>>>>> + - vdd18-supply
>>>>>> + - vdd09-supply
>>>>>> + - vddc-supply
>>>>>> + - vddio1-supply
>>>>>> + - vddio2-supply
>>>>>> + - vddio18-supply
>>>>>> + - qcom,qps615-controller
>>>>>> + - reset-gpios
>>>>>> +
>>>>>> +patternProperties:
>>>>>> + "@1?[0-9a-f](,[0-7])?$":
>>>>>> + type: object
>>>>>> + $ref: qcom,qps615.yaml#
>>>>>> + additionalProperties: true
>>>>>
>>>>> Nope, drop pattern Properties or explain what is this.
>>>>>
>>>> the child nodes represent the downstream ports of the PCIe
>>>> switch which wants to use same properties that is why
>>>> I tried to use this pattern properties.
>>>
>>> Downstream port is not the same as device. Why downstream port has the
>>> same supplies? To which pins are they connected?
>>>
>>>
>> Hi Krzysztof,
>>
>> Downstream ports dosen't have pins or supplies to power on.
>>
>> But there are properties like qcom,l0s-entry-delay-ns,
>> qcom,l1-entry-delay-ns, qcom,tx-amplitude-millivolt etc which
>> applicable for child nodes also. Instead of re-declaring the
>> these properties again I tried to use pattern properties.
>
> You could use $defs for them, but I don't understand how does these
> properties apply for both main device and ports. It seems you are
> writing binding to match some driver behavior. Let's start from basics -
> describe the hardware.
>
Hi Krzysztof,
QPS615 has a 3 downstream ports and 1 upstream port as described below
diagram.
For this entire switch there are some supplies which we described in the
dt-binding (vdd18-supply, vdd09-supply etc) and one GPIO which controls
reset of the switch (reset-gpio). The switch hardware can configure the
individual ports DSP0, DSP1, DSP2, upstream port and also one integrated
ethernet endpoint which is connected to DSP2(I didn't mentioned in the
diagram) through I2C.
The properties other than supplies,i2c client, reset gpio which
are added will be applicable for all the ports.
_______________________________________________________________
| |i2c| QPS615 |Supplies||Resx gpio |
| |___| _________________ |________||__________|
| ________________| Upstream port |_____________ |
| | |_______________| | |
| | | | |
| | | | |
| ____|_____ ____|_____ ___|____ |
| |DSP 0 | | DSP 1 | | DSP 2| |
| |________| |________| |______| |
|_____________________________________________________________|
- Krishna Chaitanya.
> Best regards,
> Krzysztof
>
^ permalink raw reply [flat|nested] 77+ messages in thread
* Re: [PATCH v2 8/8] PCI: pwrctl: Add power control driver for qps615
2024-08-03 11:34 ` Dmitry Baryshkov
@ 2024-08-05 6:14 ` Krishna Chaitanya Chundru
2024-08-08 3:30 ` Dmitry Baryshkov
0 siblings, 1 reply; 77+ messages in thread
From: Krishna Chaitanya Chundru @ 2024-08-05 6:14 UTC (permalink / raw)
To: Dmitry Baryshkov
Cc: Lorenzo Pieralisi, Krzysztof Wilczyński, Rob Herring,
Bjorn Helgaas, Krzysztof Kozlowski, Conor Dooley, Konrad Dybcio,
cros-qcom-dts-watchers, Bartosz Golaszewski, Jingoo Han,
Manivannan Sadhasivam, andersson, quic_vbadigan, linux-arm-msm,
linux-pci, devicetree, linux-kernel, Bartosz Golaszewski
On 8/3/2024 5:04 PM, Dmitry Baryshkov wrote:
> On Sat, Aug 03, 2024 at 08:52:54AM GMT, Krishna chaitanya chundru wrote:
>> QPS615 switch needs to be configured after powering on and before
>> PCIe link was up.
>>
>> As the PCIe controller driver already enables the PCIe link training
>> at the host side, stop the link training. Otherwise the moment we turn
>> on the switch it will participate in the link training and link may come
>> up before switch is configured through i2c.
>>
>> The device tree properties are parsed per node under pci-pci bridge in the
>> driver. Each node has unique bdf value in the reg property, driver
>> uses this bdf to differentiate ports, as there are certain i2c writes to
>> select particular port.
>>
>> Based up on dt property and port, qps615 is configured through i2c.
>>
>> Signed-off-by: Krishna chaitanya chundru <quic_krichai@quicinc.com>
>> ---
>> drivers/pci/pwrctl/Kconfig | 7 +
>> drivers/pci/pwrctl/Makefile | 1 +
>> drivers/pci/pwrctl/pci-pwrctl-qps615.c | 638 +++++++++++++++++++++++++++++++++
>> 3 files changed, 646 insertions(+)
>>
>> diff --git a/drivers/pci/pwrctl/Kconfig b/drivers/pci/pwrctl/Kconfig
>> index 54589bb2403b..6a1352af918c 100644
>> --- a/drivers/pci/pwrctl/Kconfig
>> +++ b/drivers/pci/pwrctl/Kconfig
>> @@ -10,3 +10,10 @@ config PCI_PWRCTL_PWRSEQ
>> tristate
>> select POWER_SEQUENCING
>> select PCI_PWRCTL
>> +
>> +config PCI_PWRCTL_QPS615
>> + tristate "PCI Power Control driver for QPS615"
>> + select PCI_PWRCTL
>> + help
>> + Say Y here to enable the pwrctl driver for Qualcomm
>> + QPS615 PCIe switch.
>> diff --git a/drivers/pci/pwrctl/Makefile b/drivers/pci/pwrctl/Makefile
>> index d308aae4800c..ac563a70c023 100644
>> --- a/drivers/pci/pwrctl/Makefile
>> +++ b/drivers/pci/pwrctl/Makefile
>> @@ -4,3 +4,4 @@ obj-$(CONFIG_PCI_PWRCTL) += pci-pwrctl-core.o
>> pci-pwrctl-core-y := core.o
>>
>> obj-$(CONFIG_PCI_PWRCTL_PWRSEQ) += pci-pwrctl-pwrseq.o
>> +obj-$(CONFIG_PCI_PWRCTL_QPS615) += pci-pwrctl-qps615.o
>> diff --git a/drivers/pci/pwrctl/pci-pwrctl-qps615.c b/drivers/pci/pwrctl/pci-pwrctl-qps615.c
>> new file mode 100644
>> index 000000000000..9dabb82787d5
>> --- /dev/null
>> +++ b/drivers/pci/pwrctl/pci-pwrctl-qps615.c
>> @@ -0,0 +1,638 @@
>> +// SPDX-License-Identifier: GPL-2.0-only
>> +/*
>> + * Copyright (c) 2024 Qualcomm Innovation Center, Inc. All rights reserved.
>> + */
>> +
>> +#include <linux/delay.h>
>> +#include <linux/device.h>
>> +#include <linux/firmware.h>
>> +#include <linux/i2c.h>
>> +#include <linux/mod_devicetable.h>
>> +#include <linux/module.h>
>> +#include <linux/of.h>
>> +#include <linux/pci.h>
>> +#include <linux/pci-pwrctl.h>
>> +#include <linux/platform_device.h>
>> +#include <linux/regulator/consumer.h>
>> +#include <linux/string.h>
>> +#include <linux/types.h>
>> +
>> +#include "../pci.h"
>> +
>> +#define QPS615_GPIO_CONFIG 0x801208
>> +#define QPS615_RESET_GPIO 0x801210
>> +
>> +#define QPS615_BUS_CONTROL 0x801014
>> +
>> +#define QPS615_PORT_L0S_DELAY 0x82496c
>> +#define QPS615_PORT_L1_DELAY 0x824970
>> +
>> +#define QPS615_EMBEDDED_ETH_DELAY 0x8200d8
>> +#define QPS615_ETH_L1_DELAY_MASK GENMASK(27, 18)
>> +#define QPS615_ETH_L1_DELAY_VALUE(x) FIELD_PREP(QPS615_ETH_L1_DELAY_MASK, x)
>> +#define QPS615_ETH_L0S_DELAY_MASK GENMASK(17, 13)
>> +#define QPS615_ETH_L0S_DELAY_VALUE(x) FIELD_PREP(QPS615_ETH_L0S_DELAY_MASK, x)
>> +
>> +#define QPS615_NFTS_2_5_GT 0x824978
>> +#define QPS615_NFTS_5_GT 0x82497c
>> +
>> +#define QPS615_PORT_LANE_ACCESS_ENABLE 0x828000
>> +
>> +#define QPS615_PHY_RATE_CHANGE_OVERRIDE 0x828040
>> +#define QPS615_PHY_RATE_CHANGE 0x828050
>> +
>> +#define QPS615_TX_MARGIN 0x828234
>> +
>> +#define QPS615_DFE_ENABLE 0x828a04
>> +#define QPS615_DFE_EQ0_MODE 0x828a08
>> +#define QPS615_DFE_EQ1_MODE 0x828a0c
>> +#define QPS615_DFE_EQ2_MODE 0x828a14
>> +#define QPS615_DFE_PD_MASK 0x828254
>> +
>> +#define QPS615_PORT_SELECT 0x82c02c
>> +#define QPS615_PORT_ACCESS_ENABLE 0x82c030
>> +
>> +#define QPS615_POWER_CONTROL 0x82b09c
>> +#define QPS615_POWER_CONTROL_OVREN 0x82b2c8
>> +
>> +#define QPS615_AXI_CLK_FREQ_MHZ 125
>> +
>> +struct qps615_pwrctl_reg_setting {
>> + unsigned int offset;
>> + unsigned int val;
>> +};
>> +
>> +struct qps615_pwrctl_bdf_info {
>> + u16 usp_bdf;
>> + u16 dsp1_bdf;
>> + u16 dsp2_bdf;
>> + u16 dsp3_bdf;
>
> Why are these values dynamic? Please use #define's for now. If there
> ever comes a similar bridge, it most likely will have a different ports
> configuration, so it will need additional changes anyway.
>
We added this for future use case only, we felt it is easier to support
at the time if we add this way.
>> +};
>> +
>> +enum qps615_pwrctl_ports {
>> + QPS615_USP,
>> + QPS615_DSP1,
>> + QPS615_DSP2,
>> + QPS615_DSP3,
>> + QPS615_ETHERNET,
>> + QPS615_MAX
>> +};
>> +
>> +struct qps615_pwrctl_cfg {
>> + u32 l0s_delay;
>> + u32 l1_delay;
>> + u32 tx_amp;
>> + u32 axi_freq;
>> + u8 nfts;
>> + bool disable_dfe;
>> + bool disable_port;
>> +};
>> +
>> +#define QPS615_PWRCTL_MAX_SUPPLY 6
>> +
>> +struct qps615_pwrctl_ctx {
>> + struct regulator_bulk_data supplies[QPS615_PWRCTL_MAX_SUPPLY];
>> + const struct qps615_pwrctl_bdf_info *bdf;
>> + struct qps615_pwrctl_cfg cfg[QPS615_MAX];
>> + struct gpio_desc *reset_gpio;
>> + struct i2c_client *client;
>> + struct pci_pwrctl pwrctl;
>> + struct device_link *link;
>> +};
>> +
>> +/*
>> + * downstream port power off sequence, hardcoding the address
>> + * as we don't know register names for these register offsets.
>
> It is hard to believe that Qualcomm engineers don't know register names
> for the Qualcomm device.
>
The switch IP is from the another vendor and the vendor provided these
settings. The databook doesn't have the register names in it.
>> + */
>> +static const struct qps615_pwrctl_reg_setting common_pwroff_seq[] = {
>> + {0x82900c, 0x1},
>> + {0x829010, 0x1},
>> + {0x829018, 0x0},
>> + {0x829020, 0x1},
>> + {0x82902c, 0x1},
>> + {0x829030, 0x1},
>> + {0x82903c, 0x1},
>> + {0x829058, 0x0},
>> + {0x82905c, 0x1},
>> + {0x829060, 0x1},
>> + {0x8290cc, 0x1},
>> + {0x8290d0, 0x1},
>> + {0x8290d8, 0x1},
>> + {0x8290e0, 0x1},
>> + {0x8290e8, 0x1},
>> + {0x8290ec, 0x1},
>> + {0x8290f4, 0x1},
>> + {0x82910c, 0x1},
>> + {0x829110, 0x1},
>> + {0x829114, 0x1},
>> +};
>> +
>> +static const struct qps615_pwrctl_reg_setting dsp1_pwroff_seq[] = {
>> + {QPS615_PORT_ACCESS_ENABLE, 0x2},
>> + {QPS615_PORT_LANE_ACCESS_ENABLE, 0x3},
>> + {QPS615_POWER_CONTROL, 0x014f4804},
>> + {QPS615_POWER_CONTROL_OVREN, 0x1},
>> + {QPS615_PORT_ACCESS_ENABLE, 0x4},
>> +};
>> +
>> +static const struct qps615_pwrctl_reg_setting dsp2_pwroff_seq[] = {
>> + {QPS615_PORT_ACCESS_ENABLE, 0x8},
>> + {QPS615_PORT_LANE_ACCESS_ENABLE, 0x1},
>> + {QPS615_POWER_CONTROL, 0x014f4804},
>> + {QPS615_POWER_CONTROL_OVREN, 0x1},
>> + {QPS615_PORT_ACCESS_ENABLE, 0x8},
>> +};
>> +
>> +static int qps615_pwrctl_i2c_write(struct i2c_client *client,
>> + u32 reg_addr, u32 reg_val)
>> +{
>> + struct i2c_msg msg;
>> + u8 msg_buf[7];
>> + int ret;
>> +
>> + msg.addr = client->addr;
>> + msg.len = 7;
>> + msg.flags = 0;
>> +
>> + /* Big Endian for reg addr */
>> + reg_addr = cpu_to_be32(reg_addr);
>
> This is incorrect. After cpu_to_be32() the value depends on the CPU
> endianness. So reg_addr >> 8 will return different values for LE and BE
> CPUs.
> I had following impression
If reg address is 0x828a0c in big endian sytem it will be 0c8a8200
and in litte endian it will be 0x828a0c only.
If cpu uses big endian cpu_to_be32 will not change this value
and in little endian case cpu_to_be32 will convert 0x828a0c to 0c8a8200.
Now the output is same for both the systems I tried to use
(reg_addr >> 8) directly.
Are you saying (reg_addr >> 8) output will be different based upon
LE and BE ? If that is the case I will remove the conversions
in next patch.
>> +
>> + msg_buf[0] = (u8)(reg_addr >> 8);
>> + msg_buf[1] = (u8)(reg_addr >> 16);
>> + msg_buf[2] = (u8)(reg_addr >> 24);
>> +
>> + /* Little Endian for reg val */
>> + reg_val = cpu_to_le32(reg_val);
>> +
>> + msg_buf[3] = (u8)(reg_val);
>> + msg_buf[4] = (u8)(reg_val >> 8);
>> + msg_buf[5] = (u8)(reg_val >> 16);
>> + msg_buf[6] = (u8)(reg_val >> 24);
>
> Same issue here.
>
>> +
>> + msg.buf = msg_buf;
>> + ret = i2c_transfer(client->adapter, &msg, 1);
>> + return ret == 1 ? 0 : ret;
>> +}
>> +
>> +static int qps615_pwrctl_i2c_read(struct i2c_client *client,
>> + u32 reg_addr, u32 *reg_val)
>> +{
>> + struct i2c_msg msg[2];
>> + u8 wr_data[3];
>> + u32 rd_data;
>> + int ret;
>> +
>> + msg[0].addr = client->addr;
>> + msg[0].len = 3;
>> + msg[0].flags = 0;
>> +
>> + /* Big Endian for reg addr */
>> + reg_addr = cpu_to_be32(reg_addr);
>> +
>> + wr_data[0] = (u8)(reg_addr >> 8);
>> + wr_data[1] = (u8)(reg_addr >> 16);
>> + wr_data[2] = (u8)(reg_addr >> 24);
>
> And here.
>
>> +
>> + msg[0].buf = wr_data;
>> +
>> + msg[1].addr = client->addr;
>> + msg[1].len = 4;
>> + msg[1].flags = I2C_M_RD;
>> +
>> + msg[1].buf = (u8 *)&rd_data;
>> +
>> + ret = i2c_transfer(client->adapter, &msg[0], 2);
>> + if (ret == 2) {
>> + *reg_val = le32_to_cpu(rd_data);
>> + return 0;
>> + }
>> +
>> + /* If only one message successfully completed, return -ENODEV */
>> + return ret == 1 ? -ENODEV : ret;
>> +}
>> +
>> +static int qps615_pwrctl_i2c_bulk_write(struct i2c_client *client,
>> + const struct qps615_pwrctl_reg_setting *seq, int len)
>> +{
>> + int ret, i;
>> +
>> + for (i = 0; i < len; i++) {
>> + ret = qps615_pwrctl_i2c_write(client, seq[i].offset, seq[i].val);
>> + if (ret)
>> + return ret;
>> + }
>> +
>> + return 0;
>> +}
>> +
>> +static int of_pci_get_bdf(struct device_node *np)
>> +{
>> + u32 reg[5];
>> + int error;
>> +
>> + error = of_property_read_u32_array(np, "reg", reg, ARRAY_SIZE(reg));
>
> Please use of_property_read_u32_index() instead.
>
ack.
>> + if (error)
>> + return error;
>> +
>> + return (reg[0] >> 8) & 0xffff;
>> +}
>> +
>> +static int qps615_pwrctl_disable_port(struct qps615_pwrctl_ctx *ctx,
>> + enum qps615_pwrctl_ports port)
>> +{
>> + const struct qps615_pwrctl_reg_setting *seq;
>> + int ret, len;
>> +
>> + seq = (port == QPS615_DSP1) ? dsp1_pwroff_seq : dsp2_pwroff_seq;
>> + len = (port == QPS615_DSP1) ? ARRAY_SIZE(dsp1_pwroff_seq) : ARRAY_SIZE(dsp2_pwroff_seq);
>> +
>> + ret = qps615_pwrctl_i2c_bulk_write(ctx->client, seq, len);
>> + if (ret)
>> + return ret;
>> +
>> + return qps615_pwrctl_i2c_bulk_write(ctx->client,
>> + common_pwroff_seq, ARRAY_SIZE(common_pwroff_seq));
>> +}
>> +
>> +static int qps615_pwrctl_set_l0s_l1_entry_delay(struct qps615_pwrctl_ctx *ctx,
>> + enum qps615_pwrctl_ports port, bool is_l1, u32 ns)
>> +{
>> + u32 rd_val, units;
>> + int ret;
>> +
>> + /* convert to units of 256ns */
>> + units = ns / 256;
>> +
>> + if (port == QPS615_ETHERNET) {
>> + ret = qps615_pwrctl_i2c_read(ctx->client, QPS615_EMBEDDED_ETH_DELAY, &rd_val);
>> + if (ret)
>> + return ret;
>> + rd_val = u32_replace_bits(rd_val, units,
>> + is_l1 ?
>> + QPS615_ETH_L1_DELAY_MASK : QPS615_ETH_L0S_DELAY_MASK);
>> + return qps615_pwrctl_i2c_write(ctx->client, QPS615_EMBEDDED_ETH_DELAY, rd_val);
>> + }
>> +
>> + ret = qps615_pwrctl_i2c_write(ctx->client, QPS615_PORT_SELECT, BIT(port));
>> + if (ret)
>> + return ret;
>
> What if there is a concurrent call? The port_select / write_value
> statements should use a lock to remove the possible race condition.
>
There should not be any concurrent calls since all calls come from the
probe itself.
>> +
>> + return qps615_pwrctl_i2c_write(ctx->client,
>> + is_l1 ? QPS615_PORT_L1_DELAY : QPS615_PORT_L0S_DELAY, units);
>> +}
>> +
>> +static int qps615_pwrctl_set_tx_amplitude(struct qps615_pwrctl_ctx *ctx,
>> + enum qps615_pwrctl_ports port, u32 amp)
>> +{
>> + int port_access;
>> +
>> + switch (port) {
>> + case QPS615_USP:
>> + port_access = 0x1;
>> + break;
>> + case QPS615_DSP1:
>> + port_access = 0x2;
>> + break;
>> + case QPS615_DSP2:
>> + port_access = 0x8;
>> + break;
>> + default:
>> + return -EINVAL;
>> + };
>> +
>> + struct qps615_pwrctl_reg_setting tx_amp_seq[] = {
>> + {QPS615_PORT_ACCESS_ENABLE, port_access},
>
> Hmm, this looks like another port selection, so most likely it should
> also be under the same lock.
>
>> + {QPS615_PORT_LANE_ACCESS_ENABLE, 0x3},
>> + {QPS615_TX_MARGIN, amp},
>> + };
>> +
>> + return qps615_pwrctl_i2c_bulk_write(ctx->client, tx_amp_seq, ARRAY_SIZE(tx_amp_seq));
>> +}
>> +
>> +static int qps615_pwrctl_disable_dfe(struct qps615_pwrctl_ctx *ctx,
>> + enum qps615_pwrctl_ports port)
>> +{
>> + int port_access, lane_access = 0x3;
>> + u32 phy_rate = 0x21;
>> +
>> + switch (port) {
>> + case QPS615_USP:
>> + phy_rate = 0x1;
>> + port_access = 0x1;
>> + break;
>> + case QPS615_DSP1:
>> + port_access = 0x2;
>> + break;
>> + case QPS615_DSP2:
>> + port_access = 0x8;
>> + lane_access = 0x1;
>> + break;
>> + default:
>> + return -EINVAL;
>> + };
>> +
>> + struct qps615_pwrctl_reg_setting disable_dfe_seq[] = {
>> + {QPS615_PORT_ACCESS_ENABLE, port_access},
>> + {QPS615_PORT_LANE_ACCESS_ENABLE, lane_access},
>> + {QPS615_DFE_ENABLE, 0x0},
>> + {QPS615_DFE_EQ0_MODE, 0x411},
>> + {QPS615_DFE_EQ1_MODE, 0x11},
>> + {QPS615_DFE_EQ2_MODE, 0x11},
>> + {QPS615_DFE_PD_MASK, 0x7},
>> + {QPS615_PHY_RATE_CHANGE_OVERRIDE, 0x10},
>> + {QPS615_PHY_RATE_CHANGE, phy_rate},
>> + {QPS615_PHY_RATE_CHANGE, 0x0},
>> + {QPS615_PHY_RATE_CHANGE_OVERRIDE, 0x0},
>> +
>> + };
>> +
>> + return qps615_pwrctl_i2c_bulk_write(ctx->client,
>> + disable_dfe_seq, ARRAY_SIZE(disable_dfe_seq));
>> +}
>> +
>> +static int qps615_pwrctl_set_nfts(struct qps615_pwrctl_ctx *ctx,
>> + enum qps615_pwrctl_ports port, u32 nfts)
>> +{
>> + int ret;
>> + struct qps615_pwrctl_reg_setting nfts_seq[] = {
>> + {QPS615_NFTS_2_5_GT, nfts},
>> + {QPS615_NFTS_5_GT, nfts},
>> + };
>> +
>> + ret = qps615_pwrctl_i2c_write(ctx->client, QPS615_PORT_SELECT, BIT(port));
>> + if (ret)
>> + return ret;
>> +
>> + return qps615_pwrctl_i2c_bulk_write(ctx->client, nfts_seq, ARRAY_SIZE(nfts_seq));
>> +}
>> +
>> +static int qps615_pwrctl_assert_deassert_reset(struct qps615_pwrctl_ctx *ctx, bool deassert)
>> +{
>> + int ret, val = 0;
>> +
>> + if (deassert)
>> + val = 0xc;
>> +
>> + ret = qps615_pwrctl_i2c_write(ctx->client, QPS615_GPIO_CONFIG, 0xfffffff3);
>
> It's a kind of magic
>
I will add a macro in next patch.
>> + if (ret)
>> + return ret;
>> +
>> + return qps615_pwrctl_i2c_write(ctx->client, QPS615_RESET_GPIO, val);
>> +}
>> +
>> +static int qps615_pwrctl_parse_device_dt(struct qps615_pwrctl_ctx *ctx, struct device_node *node)
>> +{
>> + enum qps615_pwrctl_ports port;
>> + struct qps615_pwrctl_cfg *cfg;
>> + struct device_node *np;
>> + int bdf, fun_no;
>> +
>> + bdf = of_pci_get_bdf(node);
>> + if (bdf < 0) {
>
> This is incorrect, it will fail if at any point BDF uses the most
> significant bit (which is permitted by the spec, if I'm not mistaken).
>
As per the reg property as described in the binding document we are not
expecting any change here.
https://elixir.bootlin.com/linux/v6.10.3/source/Documentation/devicetree/bindings/pci/pci.txt#L50.
>> + dev_err(ctx->pwrctl.dev, "Getting BDF failed\n");
>> + return 0;
>> + }
>> +
>> + fun_no = bdf & 0x7;
>
> I assume that ARI is not supported?
>
Yes this doesn't support ARI.
>> +
>> + /* In multi function node, ignore function 1 node */
>> + if (of_pci_get_bdf(of_get_parent(node)) == ctx->bdf->dsp3_bdf && !fun_no)
>> + port = QPS615_ETHERNET;
>> + else if (bdf == ctx->bdf->usp_bdf)
>> + port = QPS615_USP;
>
> The function is being called for child device nodes. Thus upstream
> facing port (I assume that this is what USP means) can not be enumerated
> in this way.
Sorry, but I didn't your question.
These settings will not affect the enumeration sequence these are
for configuring ports only.
>
>> + else if (bdf == ctx->bdf->dsp1_bdf)
>> + port = QPS615_DSP1;
>> + else if (bdf == ctx->bdf->dsp2_bdf)
>> + port = QPS615_DSP2;
>> + else if (bdf == ctx->bdf->dsp3_bdf)
>> + port = QPS615_DSP3;
>> + else
>> + return 0;
>
> -EINVAL >
There are can be nodes describing endpoints also,
for those nodes bdf will not match and we are not
returning since it is expected for endpoint nodes.
>> +
>> + cfg = &ctx->cfg[port];
>> +
>> + if (!of_device_is_available(node)) {
>> + cfg->disable_port = true;
>> + return 0;
>> + };
>> +
>> + of_property_read_u32(node, "qcom,axi-clk-freq-hz", &cfg->axi_freq);
>> +
>> + of_property_read_u32(node, "qcom,l0s-entry-delay-ns", &cfg->l0s_delay);
>> +
>> + of_property_read_u32(node, "qcom,l1-entry-delay-ns", &cfg->l1_delay);
>> +
>> + of_property_read_u32(node, "qcom,tx-amplitude-millivolt", &cfg->tx_amp);
>> +
>> + cfg->disable_dfe = of_property_read_bool(node, "qcom,no-dfe");
>> +
>> + of_property_read_u8(node, "qcom,nfts", &cfg->nfts);
>> +
>> + for_each_child_of_node(node, np)
>> + qps615_pwrctl_parse_device_dt(ctx, np);
>> +
>> + of_node_put(np);
>> + return 0;
>> +}
>> +
>> +static void qps615_pwrctl_power_off(struct qps615_pwrctl_ctx *ctx)
>> +{
>> + gpiod_set_value(ctx->reset_gpio, 1);
>> +
>> + regulator_bulk_disable(ARRAY_SIZE(ctx->supplies), ctx->supplies);
>> +}
>> +
>> +static int qps615_pwrctl_power_on(struct qps615_pwrctl_ctx *ctx)
>> +{
>> + struct qps615_pwrctl_cfg *cfg;
>> + int ret, i;
>> +
>> + ret = regulator_bulk_enable(ARRAY_SIZE(ctx->supplies), ctx->supplies);
>> + if (ret < 0)
>> + return dev_err_probe(ctx->pwrctl.dev, ret, "cannot enable regulators\n");
>> +
>> + gpiod_set_value(ctx->reset_gpio, 0);
>> +
>> + if (!ctx->client)
>> + return 0;
>
> really?
>
Even if we don't do i2c configuration PCIe enumeration will happen, for
some reason i2c client is not found, driver ignores the error and return
since basic functionality will work.
>> +
>> + /*
>> + * Don't have a way to see if the reset has completed.
>> + * Wait for some time.
>> + */
>> + usleep_range(1000, 1001);
>> +
>> + ret = qps615_pwrctl_assert_deassert_reset(ctx, false);
>> + if (ret)
>> + goto out;
>> +
>> + if (ctx->cfg[QPS615_USP].axi_freq == QPS615_AXI_CLK_FREQ_MHZ) {
>> + ret = qps615_pwrctl_i2c_write(ctx->client, QPS615_BUS_CONTROL, BIT(16));
>> + if (ret)
>> + dev_err(ctx->pwrctl.dev, "Setting axi clk freq failed %d\n", ret);
>
> AXI, not axi
>
ack.
>> + }
>> +
>> + for (i = 0; i < QPS615_MAX; i++) {
>> + cfg = &ctx->cfg[i];
>> + if (cfg->disable_port) {
>> + ret = qps615_pwrctl_disable_port(ctx, i);
>> + if (ret) {
>> + dev_err(ctx->pwrctl.dev, "Disabling port failed\n");
>> + goto out;
>> + }
>> + }
>> +
>> + if (cfg->l0s_delay) {
>> + ret = qps615_pwrctl_set_l0s_l1_entry_delay(ctx, i, false, cfg->l0s_delay);
>> + if (ret) {
>> + dev_err(ctx->pwrctl.dev, "Setting L0s entry delay failed\n");
>> + goto out;
>> + }
>> + }
>> +
>> + if (cfg->l1_delay) {
>> + ret = qps615_pwrctl_set_l0s_l1_entry_delay(ctx, i, true, cfg->l1_delay);
>> + if (ret) {
>> + dev_err(ctx->pwrctl.dev, "Setting L1 entry delay failed\n");
>> + goto out;
>> + }
>> + }
>> +
>> + if (cfg->tx_amp) {
>> + ret = qps615_pwrctl_set_tx_amplitude(ctx, i, cfg->tx_amp);
>> + if (ret) {
>> + dev_err(ctx->pwrctl.dev, "Setting Tx amplitube failed\n");
>> + goto out;
>> + }
>> + }
>> +
>> + if (cfg->nfts) {
>> + ret = qps615_pwrctl_set_nfts(ctx, i, cfg->nfts);
>> + if (ret) {
>> + dev_err(ctx->pwrctl.dev, "Setting nfts failed\n");
>> + goto out;
>> + }
>> + }
>> +
>> + if (cfg->disable_dfe) {
>> + ret = qps615_pwrctl_disable_dfe(ctx, i);
>> + if (ret) {
>> + dev_err(ctx->pwrctl.dev, "Disabling DFE failed\n");
>> + goto out;
>> + }
>> + }
>> + }
>> +
>> + ret = qps615_pwrctl_assert_deassert_reset(ctx, true);
>> + if (!ret)
>> + return 0;
>> +
>> +out:
>> + qps615_pwrctl_power_off(ctx);
>> + return ret;
>> +}
>> +
>> +static int qps615_pwrctl_probe(struct platform_device *pdev)
>> +{
>> + struct device *dev = &pdev->dev;
>> + struct pci_host_bridge *bridge;
>> + struct qps615_pwrctl_ctx *ctx;
>> + struct device_node *node;
>> + struct pci_bus *bus;
>> + int ret;
>> +
>> + bus = pci_find_bus(of_get_pci_domain_nr(dev->parent->of_node), 0);
>> + if (!bus)
>> + return -ENODEV;
>> +
>> + bridge = pci_find_host_bridge(bus);
>> +
>> + ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL);
>> + if (!ctx)
>> + return -ENOMEM;
>> +
>> + node = of_parse_phandle(pdev->dev.of_node, "qcom,qps615-controller", 0);
>> + if (node) {
>
> And if !node?
>
>> + ctx->client = of_find_i2c_device_by_node(node);
>
> Leaks the reference count, see the comment at the function definition.
> Also what if the I2C bus gets unbound? Will it crash the driver?
>
I will fix in next patch.
Driver is not expected to crash when i2c bus gets unbound.
It should be properly handled in i2c driver.
- Krishna Chaitanya.
>> + of_node_put(node);
>> + if (!ctx->client)
>> + return dev_err_probe(dev, -EPROBE_DEFER,
>> + "failed to parse qcom,qps615-controller\n");
>> + }
>> +
>> + ctx->bdf = of_device_get_match_data(dev);
>> + ctx->pwrctl.dev = dev;
>> +
>> + ctx->supplies[0].supply = "vddc";
>> + ctx->supplies[1].supply = "vdd18";
>> + ctx->supplies[2].supply = "vdd09";
>> + ctx->supplies[3].supply = "vddio1";
>> + ctx->supplies[4].supply = "vddio2";
>> + ctx->supplies[5].supply = "vddio18";
>> + ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(ctx->supplies), ctx->supplies);
>> + if (ret)
>> + return dev_err_probe(dev, ret,
>> + "failed to get supply regulator\n");
>> +
>> + ctx->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_ASIS);
>> + if (IS_ERR(ctx->reset_gpio))
>> + return dev_err_probe(dev, PTR_ERR(ctx->reset_gpio), "failed to get reset GPIO\n");
>> +
>> + ctx->link = device_link_add(&bridge->dev, dev, DL_FLAG_AUTOREMOVE_CONSUMER);
>> +
>> + platform_set_drvdata(pdev, ctx);
>> +
>> + qps615_pwrctl_parse_device_dt(ctx, pdev->dev.of_node);
>> +
>> + if (bridge->ops->stop_link)
>> + bridge->ops->stop_link(bus);
>> +
>> + ret = qps615_pwrctl_power_on(ctx);
>> + if (ret)
>> + return ret;
>> +
>> + if (bridge->ops->start_link) {
>> + ret = bridge->ops->start_link(bus);
>> + if (ret)
>> + return ret;
>> + }
>> +
>> + return devm_pci_pwrctl_device_set_ready(dev, &ctx->pwrctl);
>> +}
>> +
>> +static void qps615_pwrctl_remove(struct platform_device *pdev)
>> +{
>> + struct device *dev = &pdev->dev;
>> + struct qps615_pwrctl_ctx *ctx = dev_get_drvdata(dev);
>> +
>> + device_link_del(ctx->link);
>> + qps615_pwrctl_power_off(ctx);
>> +}
>> +
>> +static const struct qps615_pwrctl_bdf_info bdf_info = {
>> + .usp_bdf = 0x100,
>> + .dsp1_bdf = 0x208,
>> + .dsp2_bdf = 0x210,
>> + .dsp3_bdf = 0x218,
>> +};
>> +
>> +static const struct of_device_id qps615_pwrctl_of_match[] = {
>> + { .compatible = "pci1179,0623", .data = &bdf_info },
>> + { }
>> +};
>> +MODULE_DEVICE_TABLE(of, qps615_pwrctl_of_match);
>> +
>> +static struct platform_driver qps615_pwrctl_driver = {
>> + .driver = {
>> + .name = "pwrctl-qps615",
>> + .of_match_table = qps615_pwrctl_of_match,
>> + .probe_type = PROBE_PREFER_ASYNCHRONOUS,
>> + },
>> + .probe = qps615_pwrctl_probe,
>> + .remove_new = qps615_pwrctl_remove,
>> +};
>> +module_platform_driver(qps615_pwrctl_driver);
>> +
>> +MODULE_AUTHOR("Krishna chaitanya chundru <quic_krichai@quicinc.com>");
>> +MODULE_DESCRIPTION("Qualcomm QPS615 power control driver");
>> +MODULE_LICENSE("GPL");
>>
>> --
>> 2.34.1
>>
>
^ permalink raw reply [flat|nested] 77+ messages in thread
* Re: [PATCH v2 1/8] dt-bindings: PCI: Add binding for qps615
2024-08-05 5:57 ` Krishna Chaitanya Chundru
@ 2024-08-05 14:43 ` Krzysztof Kozlowski
2024-08-22 14:16 ` Manivannan Sadhasivam
0 siblings, 1 reply; 77+ messages in thread
From: Krzysztof Kozlowski @ 2024-08-05 14:43 UTC (permalink / raw)
To: Krishna Chaitanya Chundru, Lorenzo Pieralisi,
Krzysztof Wilczyński, Rob Herring, Bjorn Helgaas,
Krzysztof Kozlowski, Conor Dooley, Konrad Dybcio,
cros-qcom-dts-watchers, Bartosz Golaszewski, Jingoo Han,
Manivannan Sadhasivam
Cc: andersson, quic_vbadigan, linux-arm-msm, linux-pci, devicetree,
linux-kernel, Bartosz Golaszewski
On 05/08/2024 07:57, Krishna Chaitanya Chundru wrote:
>>
> Hi Krzysztof,
>
> QPS615 has a 3 downstream ports and 1 upstream port as described below
> diagram.
> For this entire switch there are some supplies which we described in the
> dt-binding (vdd18-supply, vdd09-supply etc) and one GPIO which controls
> reset of the switch (reset-gpio). The switch hardware can configure the
> individual ports DSP0, DSP1, DSP2, upstream port and also one integrated
> ethernet endpoint which is connected to DSP2(I didn't mentioned in the
> diagram) through I2C.
>
> The properties other than supplies,i2c client, reset gpio which
> are added will be applicable for all the ports.
> _______________________________________________________________
> | |i2c| QPS615 |Supplies||Resx gpio |
> | |___| _________________ |________||__________|
> | ________________| Upstream port |_____________ |
> | | |_______________| | |
> | | | | |
> | | | | |
> | ____|_____ ____|_____ ___|____ |
> | |DSP 0 | | DSP 1 | | DSP 2| |
> | |________| |________| |______| |
> |_____________________________________________________________|
>
I don't get why then properties should apply to main device node.
Best regards,
Krzysztof
^ permalink raw reply [flat|nested] 77+ messages in thread
* Re: [PATCH v2 0/8] PCI: Enable Power and configure the QPS615 PCIe switch
2024-08-03 3:22 [PATCH v2 0/8] PCI: Enable Power and configure the QPS615 PCIe switch Krishna chaitanya chundru
` (10 preceding siblings ...)
2024-08-05 4:34 ` Krishna Chaitanya Chundru
@ 2024-08-05 15:00 ` Rob Herring (Arm)
2024-08-06 15:24 ` Ilpo Järvinen
12 siblings, 0 replies; 77+ messages in thread
From: Rob Herring (Arm) @ 2024-08-05 15:00 UTC (permalink / raw)
To: Krishna chaitanya chundru
Cc: Conor Dooley, linux-kernel, Bartosz Golaszewski,
Krzysztof Kozlowski, Konrad Dybcio, Jingoo Han, Bjorn Helgaas,
Lorenzo Pieralisi, quic_vbadigan, linux-arm-msm,
Krzysztof Wilczyński, linux-pci, andersson, devicetree,
cros-qcom-dts-watchers, Manivannan Sadhasivam,
Bartosz Golaszewski
On Sat, 03 Aug 2024 08:52:46 +0530, Krishna chaitanya chundru wrote:
> QPS615 is the PCIe switch which has one upstream and three downstream
> ports. One of the downstream ports is used as endpoint device of Ethernet
> MAC. Other two downstream ports are supposed to connect to external
> device. One Host can connect to QPS615 by upstream port.
>
> QPS615 switch power is controlled by the GPIO's. After powering on
> the switch will immediately participate in the link training. if the
> host is also ready by that time PCIe link will established.
>
> The QPS615 needs to configured certain parameters like de-emphasis,
> disable unused port etc before link is established.
>
> The device tree properties are parsed per node under pci-pci bridge in the
> devicetree. Each node has unique bdf value in the reg property, driver
> uses this bdf to differentiate ports, as there are certain i2c writes to
> select particulat port.
>
> As the controller starts link training before the probe of pwrctl driver,
> the PCIe link may come up before configuring the switch itself.
> To avoid this introduce two functions in pci_ops to start_link() &
> stop_link() which will disable the link training if the PCIe link is
> not up yet.
>
> Now PCI pwrctl device is the child of the pci-pcie bridge, if we want
> to enable the suspend resume for pwrctl device there may be issues
> since pci bridge will try to access some registers in the config which
> may cause timeouts or Un clocked access as the power can be removed in
> the suspend of pwrctl driver.
>
> To solve this make PCIe controller as parent to the pci pwr ctrl driver
> and create devlink between host bridge and pci pwrctl driver so that
> pci pwrctl driver will go suspend only after all the PCIe devices went
> to suspend.
>
> Signed-off-by: Krishna chaitanya chundru <quic_krichai@quicinc.com>
> ---
> Changes in V1:
> - Fix the code as per the comments given.
> - Removed D3cold D0 sequence in suspend resume for now as it needs
> seperate discussion.
> - change to dt approach for configuring the switch instead of request_firmware() approach
> - Link to v1: https://lore.kernel.org/linux-pci/20240626-qps615-v1-4-2ade7bd91e02@quicinc.com/T/
> ---
>
> ---
> Krishna chaitanya chundru (8):
> dt-bindings: PCI: Add binding for qps615
> dt-bindings: trivial-devices: Add qcom,qps615
> arm64: dts: qcom: qcs6490-rb3gen2: Add node for qps615
> PCI: Change the parent to correctly represent pcie hierarchy
> PCI: Add new start_link() & stop_link function ops
> PCI: dwc: Add support for new pci function op
> PCI: qcom: Add support for host_stop_link() & host_start_link()
> PCI: pwrctl: Add power control driver for qps615
>
> .../devicetree/bindings/pci/qcom,qps615.yaml | 191 ++++++
> .../devicetree/bindings/trivial-devices.yaml | 2 +
> arch/arm64/boot/dts/qcom/qcs6490-rb3gen2.dts | 121 ++++
> arch/arm64/boot/dts/qcom/sc7280.dtsi | 2 +-
> drivers/pci/bus.c | 3 +-
> drivers/pci/controller/dwc/pcie-designware-host.c | 18 +
> drivers/pci/controller/dwc/pcie-designware.h | 16 +
> drivers/pci/controller/dwc/pcie-qcom.c | 39 ++
> drivers/pci/pwrctl/Kconfig | 7 +
> drivers/pci/pwrctl/Makefile | 1 +
> drivers/pci/pwrctl/core.c | 9 +-
> drivers/pci/pwrctl/pci-pwrctl-qps615.c | 638 +++++++++++++++++++++
> include/linux/pci.h | 2 +
> 13 files changed, 1046 insertions(+), 3 deletions(-)
> ---
> base-commit: 1722389b0d863056d78287a120a1d6cadb8d4f7b
> change-id: 20240727-qps615-e2894a38d36f
>
> Best regards,
> --
> Krishna chaitanya chundru <quic_krichai@quicinc.com>
>
>
>
My bot found new DTB warnings on the .dts files added or changed in this
series.
Some warnings may be from an existing SoC .dtsi. Or perhaps the warnings
are fixed by another series. Ultimately, it is up to the platform
maintainer whether these warnings are acceptable or not. No need to reply
unless the platform maintainer has comments.
If you already ran DT checks and didn't see these error(s), then
make sure dt-schema is up to date:
pip3 install dtschema --upgrade
New warnings running 'make CHECK_DTBS=y qcom/qcs6490-rb3gen2.dtb' for 20240803-qps615-v2-0-9560b7c71369@quicinc.com:
arch/arm64/boot/dts/qcom/qcs6490-rb3gen2.dts:746.12-753.5: Warning (pci_device_bus_num): /soc@0/pcie@1c08000/pcie@0/pcie@0,0/pcie@1,0: PCI bus number 2 out of range, expected (0 - 0)
arch/arm64/boot/dts/qcom/qcs6490-rb3gen2.dts:755.12-762.5: Warning (pci_device_bus_num): /soc@0/pcie@1c08000/pcie@0/pcie@0,0/pcie@2,0: PCI bus number 2 out of range, expected (0 - 0)
arch/arm64/boot/dts/qcom/qcs6490-rb3gen2.dts:764.12-786.5: Warning (pci_device_bus_num): /soc@0/pcie@1c08000/pcie@0/pcie@0,0/pcie@3,0: PCI bus number 2 out of range, expected (0 - 0)
arch/arm64/boot/dts/qcom/qcs6490-rb3gen2.dts:771.13-777.6: Warning (pci_device_bus_num): /soc@0/pcie@1c08000/pcie@0/pcie@0,0/pcie@3,0/pcie@0,0: PCI bus number 5 out of range, expected (0 - 0)
arch/arm64/boot/dts/qcom/qcs6490-rb3gen2.dts:779.13-785.6: Warning (pci_device_bus_num): /soc@0/pcie@1c08000/pcie@0/pcie@0,0/pcie@3,0/pcie@0,1: PCI bus number 5 out of range, expected (0 - 0)
^ permalink raw reply [flat|nested] 77+ messages in thread
* Re: [PATCH v2 1/8] dt-bindings: PCI: Add binding for qps615
2024-08-05 5:12 ` Krzysztof Kozlowski
2024-08-05 5:33 ` Krishna Chaitanya Chundru
@ 2024-08-05 16:39 ` Bjorn Andersson
2024-08-05 16:58 ` Krzysztof Kozlowski
1 sibling, 1 reply; 77+ messages in thread
From: Bjorn Andersson @ 2024-08-05 16:39 UTC (permalink / raw)
To: Krzysztof Kozlowski
Cc: Krishna Chaitanya Chundru, Lorenzo Pieralisi,
Krzysztof Wilczyński, Rob Herring, Bjorn Helgaas,
Krzysztof Kozlowski, Conor Dooley, Konrad Dybcio,
cros-qcom-dts-watchers, Bartosz Golaszewski, Jingoo Han,
Manivannan Sadhasivam, andersson, quic_vbadigan, linux-arm-msm,
linux-pci, devicetree, linux-kernel, Bartosz Golaszewski
On Mon, Aug 05, 2024 at 07:12:34AM +0200, Krzysztof Kozlowski wrote:
> On 05/08/2024 06:02, Krishna Chaitanya Chundru wrote:
> >
> >
> > On 8/4/2024 2:26 PM, Krzysztof Kozlowski wrote:
> >> On 03/08/2024 05:22, Krishna chaitanya chundru wrote:
> >>> Add binding describing the Qualcomm PCIe switch, QPS615,
> >>> which provides Ethernet MAC integrated to the 3rd downstream port
> >>> and two downstream PCIe ports.
> >>>
> >>> Signed-off-by: Krishna chaitanya chundru <quic_krichai@quicinc.com>
> >>> ---
> >>> .../devicetree/bindings/pci/qcom,qps615.yaml | 191 +++++++++++++++++++++
> >>> 1 file changed, 191 insertions(+)
> >>>
> >>> diff --git a/Documentation/devicetree/bindings/pci/qcom,qps615.yaml b/Documentation/devicetree/bindings/pci/qcom,qps615.yaml
> >>> new file mode 100644
> >>> index 000000000000..ea0c953ee56f
> >>> --- /dev/null
> >>> +++ b/Documentation/devicetree/bindings/pci/qcom,qps615.yaml
> >>> @@ -0,0 +1,191 @@
> >>> +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
> >>> +%YAML 1.2
> >>> +---
> >>> +$id: http://devicetree.org/schemas/pci/qcom,qps615.yaml#
> >>> +$schema: http://devicetree.org/meta-schemas/core.yaml#
> >>> +
> >>> +title: Qualcomm QPS615 PCIe switch
> >>> +
> >>> +maintainers:
> >>> + - Krishna chaitanya chundru <quic_krichai@quicinc.com>
> >>> +
> >>> +description: |
> >>> + Qualcomm QPS615 PCIe switch has one upstream and three downstream
> >>> + ports. The 3rd downstream port has integrated endpoint device of
> >>> + Ethernet MAC. Other two downstream ports are supposed to connect
> >>> + to external device.
> >>> +
> >>> + The QPS615 PCIe switch can be configured through I2C interface before
> >>> + PCIe link is established to change FTS, ASPM related entry delays,
> >>> + tx amplitude etc for better power efficiency and functionality.
> >>> +
> >>> +properties:
> >>> + compatible:
> >>> + enum:
> >>> + - pci1179,0623
> >>> +
> >>> + reg:
> >>> + maxItems: 1
> >>> +
> >>> + qcom,qps615-controller:
> >>
> >> and now I see that you totally ignored comments. Repeating the same over
> >> and over is a waste of time.
> >>
> >> <form letter>
> >> This is a friendly reminder during the review process.
> >>
> >> It seems my or other reviewer's previous comments were not fully
> >> addressed. Maybe the feedback got lost between the quotes, maybe you
> >> just forgot to apply it. Please go back to the previous discussion and
> >> either implement all requested changes or keep discussing them.
> >>
> >> Thank you.
Well, thank you for the rant. Very helpful indeed.
> >> </form letter>
> >>
> >>
> >> Best regards,
> >> Krzysztof
> >>
> > Hi Krzysztof,
> >
> > In patch1 we are trying to add reference of i2c-adapter, you suggested
> > to use i2c-bus for that. we got comments on the driver code not to use
> > adapter and instead use i2c client reference. I felt i2c-bus is not
> > ideal to represent i2c client device so used this name.
>
> You did not respond to comment of using i2c-bus, just silently decided
> to implement other property.
>
I guess you totally ignored my comment when you reviewed the previous
version, where I asked him to represent the device on said bus.
> Anyway, why i2c-bus is not suitable here? I am quite surprised...
>
I was not aware that i2c-bus was an acceptable solution, sorry for my
bad suggestion and guidance here.
Regards,
Bjorn
>
>
> Best regards,
> Krzysztof
>
>
^ permalink raw reply [flat|nested] 77+ messages in thread
* Re: [PATCH v2 1/8] dt-bindings: PCI: Add binding for qps615
2024-08-05 16:39 ` Bjorn Andersson
@ 2024-08-05 16:58 ` Krzysztof Kozlowski
0 siblings, 0 replies; 77+ messages in thread
From: Krzysztof Kozlowski @ 2024-08-05 16:58 UTC (permalink / raw)
To: Bjorn Andersson
Cc: Krishna Chaitanya Chundru, Lorenzo Pieralisi,
Krzysztof Wilczyński, Rob Herring, Bjorn Helgaas,
Krzysztof Kozlowski, Conor Dooley, Konrad Dybcio,
cros-qcom-dts-watchers, Bartosz Golaszewski, Jingoo Han,
Manivannan Sadhasivam, andersson, quic_vbadigan, linux-arm-msm,
linux-pci, devicetree, linux-kernel, Bartosz Golaszewski
On 05/08/2024 18:39, Bjorn Andersson wrote:
>>>
>>> In patch1 we are trying to add reference of i2c-adapter, you suggested
>>> to use i2c-bus for that. we got comments on the driver code not to use
>>> adapter and instead use i2c client reference. I felt i2c-bus is not
>>> ideal to represent i2c client device so used this name.
>>
>> You did not respond to comment of using i2c-bus, just silently decided
>> to implement other property.
>>
>
> I guess you totally ignored my comment when you reviewed the previous
> version, where I asked him to represent the device on said bus.
Hm, Rob suggested i2c-bus, you as well:
<<I'd prefer you call it "i2c-adapter" or perhaps "i2c-bus", because
it's not "the switch controller".>>
and there was no response to any of these comments.
>
>> Anyway, why i2c-bus is not suitable here? I am quite surprised...
>>
>
> I was not aware that i2c-bus was an acceptable solution, sorry for my
> bad suggestion and guidance here.
I think you suggested i2c-bus as well, but regardless what did you agree
internally, response to Rob was expected.
Best regards,
Krzysztof
^ permalink raw reply [flat|nested] 77+ messages in thread
* Re: [PATCH v2 1/8] dt-bindings: PCI: Add binding for qps615
2024-08-05 4:11 ` Krishna Chaitanya Chundru
2024-08-05 5:14 ` Krzysztof Kozlowski
@ 2024-08-05 17:07 ` Bjorn Andersson
2024-08-05 17:18 ` Krzysztof Kozlowski
1 sibling, 1 reply; 77+ messages in thread
From: Bjorn Andersson @ 2024-08-05 17:07 UTC (permalink / raw)
To: Krishna Chaitanya Chundru
Cc: Krzysztof Kozlowski, Lorenzo Pieralisi, Krzysztof Wilczyński,
Rob Herring, Bjorn Helgaas, Krzysztof Kozlowski, Conor Dooley,
Konrad Dybcio, cros-qcom-dts-watchers, Bartosz Golaszewski,
Jingoo Han, Manivannan Sadhasivam, andersson, quic_vbadigan,
linux-arm-msm, linux-pci, devicetree, linux-kernel,
Bartosz Golaszewski
On Mon, Aug 05, 2024 at 09:41:26AM +0530, Krishna Chaitanya Chundru wrote:
> On 8/4/2024 2:23 PM, Krzysztof Kozlowski wrote:
> > On 03/08/2024 05:22, Krishna chaitanya chundru wrote:
> > > diff --git a/Documentation/devicetree/bindings/pci/qcom,qps615.yaml b/Documentation/devicetree/bindings/pci/qcom,qps615.yaml
[..]
> > > + qps615,axi-clk-freq-hz:
> > > + description:
> > > + AXI clock which internal bus of the switch.
> >
> > No need, use CCF.
> >
> ack
This is a clock that's internal to the QPS615, so there's no clock
controller involved and hence I don't think CCF is applicable.
Regards,
Bjorn
^ permalink raw reply [flat|nested] 77+ messages in thread
* Re: [PATCH v2 1/8] dt-bindings: PCI: Add binding for qps615
2024-08-05 17:07 ` Bjorn Andersson
@ 2024-08-05 17:18 ` Krzysztof Kozlowski
2024-08-08 12:01 ` Manivannan Sadhasivam
0 siblings, 1 reply; 77+ messages in thread
From: Krzysztof Kozlowski @ 2024-08-05 17:18 UTC (permalink / raw)
To: Bjorn Andersson, Krishna Chaitanya Chundru
Cc: Lorenzo Pieralisi, Krzysztof Wilczyński, Rob Herring,
Bjorn Helgaas, Krzysztof Kozlowski, Conor Dooley, Konrad Dybcio,
cros-qcom-dts-watchers, Bartosz Golaszewski, Jingoo Han,
Manivannan Sadhasivam, andersson, quic_vbadigan, linux-arm-msm,
linux-pci, devicetree, linux-kernel, Bartosz Golaszewski
On 05/08/2024 19:07, Bjorn Andersson wrote:
> On Mon, Aug 05, 2024 at 09:41:26AM +0530, Krishna Chaitanya Chundru wrote:
>> On 8/4/2024 2:23 PM, Krzysztof Kozlowski wrote:
>>> On 03/08/2024 05:22, Krishna chaitanya chundru wrote:
>>>> diff --git a/Documentation/devicetree/bindings/pci/qcom,qps615.yaml b/Documentation/devicetree/bindings/pci/qcom,qps615.yaml
> [..]
>>>> + qps615,axi-clk-freq-hz:
>>>> + description:
>>>> + AXI clock which internal bus of the switch.
>>>
>>> No need, use CCF.
>>>
>> ack
>
> This is a clock that's internal to the QPS615, so there's no clock
> controller involved and hence I don't think CCF is applicable.
AXI does not sound that internal. DT rarely needs to specify internal
clock rates. What if you want to define rates for 20 clocks? Even
clock-frequency is deprecated, so why this would be allowed?
bus-frequency is allowed for buses, but that's not the case here, I guess?
Best regards,
Krzysztof
^ permalink raw reply [flat|nested] 77+ messages in thread
* Re: [PATCH v2 0/8] PCI: Enable Power and configure the QPS615 PCIe switch
2024-08-03 3:22 [PATCH v2 0/8] PCI: Enable Power and configure the QPS615 PCIe switch Krishna chaitanya chundru
` (11 preceding siblings ...)
2024-08-05 15:00 ` Rob Herring (Arm)
@ 2024-08-06 15:24 ` Ilpo Järvinen
12 siblings, 0 replies; 77+ messages in thread
From: Ilpo Järvinen @ 2024-08-06 15:24 UTC (permalink / raw)
To: Krishna chaitanya chundru
Cc: Lorenzo Pieralisi, Krzysztof Wilczyński, Rob Herring,
Bjorn Helgaas, Krzysztof Kozlowski, Conor Dooley, Konrad Dybcio,
cros-qcom-dts-watchers, Bartosz Golaszewski, Jingoo Han,
Manivannan Sadhasivam, andersson, quic_vbadigan, linux-arm-msm,
linux-pci, devicetree, LKML, Bartosz Golaszewski
On Sat, 3 Aug 2024, Krishna chaitanya chundru wrote:
> QPS615 is the PCIe switch which has one upstream and three downstream
> ports. One of the downstream ports is used as endpoint device of Ethernet
> MAC. Other two downstream ports are supposed to connect to external
> device. One Host can connect to QPS615 by upstream port.
>
> QPS615 switch power is controlled by the GPIO's. After powering on
> the switch will immediately participate in the link training. if the
> host is also ready by that time PCIe link will established.
>
> The QPS615 needs to configured certain parameters like de-emphasis,
> disable unused port etc before link is established.
>
> The device tree properties are parsed per node under pci-pci bridge in the
> devicetree. Each node has unique bdf value in the reg property, driver
> uses this bdf to differentiate ports, as there are certain i2c writes to
> select particulat port.
>
> As the controller starts link training before the probe of pwrctl driver,
> the PCIe link may come up before configuring the switch itself.
> To avoid this introduce two functions in pci_ops to start_link() &
> stop_link() which will disable the link training if the PCIe link is
> not up yet.
???
This paragraph contradicts with itself. First it says link training starts
and the link may come up, and then it says opposite, that is, disable the
link training if the link is not up yet. So which way it is?
If link can come up, why do you need to disable link training at all?
Cannot you just trigger another link training after the configuration has
been done so the new configuration is captured? If not, why?
--
i.
> Now PCI pwrctl device is the child of the pci-pcie bridge, if we want
> to enable the suspend resume for pwrctl device there may be issues
> since pci bridge will try to access some registers in the config which
> may cause timeouts or Un clocked access as the power can be removed in
> the suspend of pwrctl driver.
>
> To solve this make PCIe controller as parent to the pci pwr ctrl driver
> and create devlink between host bridge and pci pwrctl driver so that
> pci pwrctl driver will go suspend only after all the PCIe devices went
> to suspend.
>
> Signed-off-by: Krishna chaitanya chundru <quic_krichai@quicinc.com>
> ---
> Changes in V1:
> - Fix the code as per the comments given.
> - Removed D3cold D0 sequence in suspend resume for now as it needs
> seperate discussion.
> - change to dt approach for configuring the switch instead of request_firmware() approach
> - Link to v1: https://lore.kernel.org/linux-pci/20240626-qps615-v1-4-2ade7bd91e02@quicinc.com/T/
> ---
>
> ---
> Krishna chaitanya chundru (8):
> dt-bindings: PCI: Add binding for qps615
> dt-bindings: trivial-devices: Add qcom,qps615
> arm64: dts: qcom: qcs6490-rb3gen2: Add node for qps615
> PCI: Change the parent to correctly represent pcie hierarchy
> PCI: Add new start_link() & stop_link function ops
> PCI: dwc: Add support for new pci function op
> PCI: qcom: Add support for host_stop_link() & host_start_link()
> PCI: pwrctl: Add power control driver for qps615
>
> .../devicetree/bindings/pci/qcom,qps615.yaml | 191 ++++++
> .../devicetree/bindings/trivial-devices.yaml | 2 +
> arch/arm64/boot/dts/qcom/qcs6490-rb3gen2.dts | 121 ++++
> arch/arm64/boot/dts/qcom/sc7280.dtsi | 2 +-
> drivers/pci/bus.c | 3 +-
> drivers/pci/controller/dwc/pcie-designware-host.c | 18 +
> drivers/pci/controller/dwc/pcie-designware.h | 16 +
> drivers/pci/controller/dwc/pcie-qcom.c | 39 ++
> drivers/pci/pwrctl/Kconfig | 7 +
> drivers/pci/pwrctl/Makefile | 1 +
> drivers/pci/pwrctl/core.c | 9 +-
> drivers/pci/pwrctl/pci-pwrctl-qps615.c | 638 +++++++++++++++++++++
> include/linux/pci.h | 2 +
> 13 files changed, 1046 insertions(+), 3 deletions(-)
> ---
> base-commit: 1722389b0d863056d78287a120a1d6cadb8d4f7b
> change-id: 20240727-qps615-e2894a38d36f
>
> Best regards,
>
^ permalink raw reply [flat|nested] 77+ messages in thread
* Re: [PATCH v2 4/8] PCI: Change the parent to correctly represent pcie hierarchy
2024-08-03 3:22 ` [PATCH v2 4/8] PCI: Change the parent to correctly represent pcie hierarchy Krishna chaitanya chundru
@ 2024-08-06 19:07 ` Bjorn Helgaas
2024-08-06 20:06 ` Bartosz Golaszewski
2024-08-13 19:15 ` Bartosz Golaszewski
2024-08-23 7:23 ` Manivannan Sadhasivam
2 siblings, 1 reply; 77+ messages in thread
From: Bjorn Helgaas @ 2024-08-06 19:07 UTC (permalink / raw)
To: Krishna chaitanya chundru, Bartosz Golaszewski
Cc: Lorenzo Pieralisi, Krzysztof Wilczyński, Rob Herring,
Bjorn Helgaas, Krzysztof Kozlowski, Conor Dooley, Konrad Dybcio,
cros-qcom-dts-watchers, Bartosz Golaszewski, Jingoo Han,
Manivannan Sadhasivam, andersson, quic_vbadigan, linux-arm-msm,
linux-pci, devicetree, linux-kernel
On Sat, Aug 03, 2024 at 08:52:50AM +0530, Krishna chaitanya chundru wrote:
> Currently the pwrctl driver is child of pci-pci bridge driver,
> this will cause issue when suspend resume is introduced in the pwr
> control driver. If the supply is removed to the endpoint in the
> power control driver then the config space access by the
> pci-pci bridge driver can cause issues like Timeouts.
If "pci-pci bridge driver" refers to portdrv, please use "portdrv" to
avoid confusion.
Can you be a little more specific about config accesses by the bridge
driver? Generally portdrv wouldn't touch devices below the bridge.
It sounds like you've tripped over something here, so you probably
have an example of a timeout.
s/pcie/PCIe/ in subject, although it'd be nice if the whole subject
could be a little more specific. I don't think pwrctl is directly
part of the PCIe hierarchy, so I don't quite understand what you're
saying there.
> For this reason change the parent to controller from pci-pci bridge.
>
> Fixes: 4565d2652a37 ("PCI/pwrctl: Add PCI power control core code")
Will need an ack from Bartosz, of course, since he added this. Moved
from cc: to to: list to make sure he sees this.
> Signed-off-by: Krishna chaitanya chundru <quic_krichai@quicinc.com>
> ---
> drivers/pci/bus.c | 3 ++-
> drivers/pci/pwrctl/core.c | 9 ++++++++-
> 2 files changed, 10 insertions(+), 2 deletions(-)
>
> diff --git a/drivers/pci/bus.c b/drivers/pci/bus.c
> index 55c853686051..15b42f0f588f 100644
> --- a/drivers/pci/bus.c
> +++ b/drivers/pci/bus.c
> @@ -328,6 +328,7 @@ void __weak pcibios_bus_add_device(struct pci_dev *pdev) { }
> */
> void pci_bus_add_device(struct pci_dev *dev)
> {
> + struct pci_host_bridge *host = pci_find_host_bridge(dev->bus);
> struct device_node *dn = dev->dev.of_node;
> int retval;
>
> @@ -352,7 +353,7 @@ void pci_bus_add_device(struct pci_dev *dev)
>
> if (dev_of_node(&dev->dev) && pci_is_bridge(dev)) {
> retval = of_platform_populate(dev_of_node(&dev->dev), NULL, NULL,
> - &dev->dev);
> + host->dev.parent);
I'm not sure host->dev.parent is always valid. There are
pci_create_root_bus() callers that supply a NULL parent pointer.
> if (retval)
> pci_err(dev, "failed to populate child OF nodes (%d)\n",
> retval);
> diff --git a/drivers/pci/pwrctl/core.c b/drivers/pci/pwrctl/core.c
> index feca26ad2f6a..4f2ffa0b0a5f 100644
> --- a/drivers/pci/pwrctl/core.c
> +++ b/drivers/pci/pwrctl/core.c
> @@ -11,6 +11,8 @@
> #include <linux/property.h>
> #include <linux/slab.h>
>
> +#include "../pci.h"
> +
> static int pci_pwrctl_notify(struct notifier_block *nb, unsigned long action,
> void *data)
> {
> @@ -64,18 +66,23 @@ static int pci_pwrctl_notify(struct notifier_block *nb, unsigned long action,
> */
> int pci_pwrctl_device_set_ready(struct pci_pwrctl *pwrctl)
> {
> + struct pci_bus *bus;
> int ret;
>
> if (!pwrctl->dev)
> return -ENODEV;
>
> + bus = pci_find_bus(of_get_pci_domain_nr(pwrctl->dev->parent->of_node), 0);
> + if (!bus)
> + return -ENODEV;
> +
> pwrctl->nb.notifier_call = pci_pwrctl_notify;
> ret = bus_register_notifier(&pci_bus_type, &pwrctl->nb);
> if (ret)
> return ret;
>
> pci_lock_rescan_remove();
> - pci_rescan_bus(to_pci_dev(pwrctl->dev->parent)->bus);
> + pci_rescan_bus(bus);
> pci_unlock_rescan_remove();
>
> return 0;
>
> --
> 2.34.1
>
^ permalink raw reply [flat|nested] 77+ messages in thread
* Re: [PATCH v2 7/8] PCI: qcom: Add support for host_stop_link() & host_start_link()
2024-08-03 3:22 ` [PATCH v2 7/8] PCI: qcom: Add support for host_stop_link() & host_start_link() Krishna chaitanya chundru
@ 2024-08-06 19:12 ` Bjorn Helgaas
2024-09-02 6:51 ` Krishna Chaitanya Chundru
0 siblings, 1 reply; 77+ messages in thread
From: Bjorn Helgaas @ 2024-08-06 19:12 UTC (permalink / raw)
To: Krishna chaitanya chundru
Cc: Lorenzo Pieralisi, Krzysztof Wilczyński, Rob Herring,
Bjorn Helgaas, Krzysztof Kozlowski, Conor Dooley, Konrad Dybcio,
cros-qcom-dts-watchers, Bartosz Golaszewski, Jingoo Han,
Manivannan Sadhasivam, andersson, quic_vbadigan, linux-arm-msm,
linux-pci, devicetree, linux-kernel, Bartosz Golaszewski
On Sat, Aug 03, 2024 at 08:52:53AM +0530, Krishna chaitanya chundru wrote:
> For the switches like QPS615 which needs to configure it before
> the PCIe link is established.
>
> if the link is not up assert the PERST# and disable LTSSM bit so
> that PCIe controller will not participate in the link training
> as part of host_stop_link().
>
> De-assert the PERST# and enable LTSSM bit back in host_start_link().
>
> Introduce ltssm_disable function op to stop the link training.
pcie-qcom.c is a driver for a PCIe host controller. Apparently QPS615
is a switch in a hierarchy that could be below any PCIe host
controller, so I'm missing the connection with pcie-qcom.c.
Does this fix a problem that only occurs with pcie-qcom.c? What
happens if you put a QPS615 below some other controller?
> Signed-off-by: Krishna chaitanya chundru <quic_krichai@quicinc.com>
> ---
> drivers/pci/controller/dwc/pcie-qcom.c | 39 ++++++++++++++++++++++++++++++++++
> 1 file changed, 39 insertions(+)
>
> diff --git a/drivers/pci/controller/dwc/pcie-qcom.c b/drivers/pci/controller/dwc/pcie-qcom.c
> index 0180edf3310e..f4a6df53139c 100644
> --- a/drivers/pci/controller/dwc/pcie-qcom.c
> +++ b/drivers/pci/controller/dwc/pcie-qcom.c
> @@ -233,6 +233,7 @@ struct qcom_pcie_ops {
> void (*host_post_init)(struct qcom_pcie *pcie);
> void (*deinit)(struct qcom_pcie *pcie);
> void (*ltssm_enable)(struct qcom_pcie *pcie);
> + void (*ltssm_disable)(struct qcom_pcie *pcie);
> int (*config_sid)(struct qcom_pcie *pcie);
> };
>
> @@ -555,6 +556,41 @@ static int qcom_pcie_post_init_1_0_0(struct qcom_pcie *pcie)
> return 0;
> }
>
> +static int qcom_pcie_host_start_link(struct dw_pcie *pci)
> +{
> + struct qcom_pcie *pcie = to_qcom_pcie(pci);
> +
> + if (!dw_pcie_link_up(pcie->pci)) {
> + qcom_ep_reset_deassert(pcie);
> +
> + if (pcie->cfg->ops->ltssm_enable)
> + pcie->cfg->ops->ltssm_enable(pcie);
> + }
> +
> + return 0;
> +}
> +
> +static void qcom_pcie_host_stop_link(struct dw_pcie *pci)
> +{
> + struct qcom_pcie *pcie = to_qcom_pcie(pci);
> +
> + if (!dw_pcie_link_up(pcie->pci)) {
> + qcom_ep_reset_assert(pcie);
> +
> + if (pcie->cfg->ops->ltssm_disable)
> + pcie->cfg->ops->ltssm_disable(pcie);
> + }
> +}
> +
> +static void qcom_pcie_2_3_2_ltssm_disable(struct qcom_pcie *pcie)
> +{
> + u32 val;
> +
> + val = readl(pcie->parf + PARF_LTSSM);
> + val &= ~LTSSM_EN;
> + writel(val, pcie->parf + PARF_LTSSM);
> +}
> +
> static void qcom_pcie_2_3_2_ltssm_enable(struct qcom_pcie *pcie)
> {
> u32 val;
> @@ -1306,6 +1342,7 @@ static const struct qcom_pcie_ops ops_1_9_0 = {
> .host_post_init = qcom_pcie_host_post_init_2_7_0,
> .deinit = qcom_pcie_deinit_2_7_0,
> .ltssm_enable = qcom_pcie_2_3_2_ltssm_enable,
> + .ltssm_disable = qcom_pcie_2_3_2_ltssm_disable,
> .config_sid = qcom_pcie_config_sid_1_9_0,
> };
>
> @@ -1363,6 +1400,8 @@ static const struct qcom_pcie_cfg cfg_sc8280xp = {
> static const struct dw_pcie_ops dw_pcie_ops = {
> .link_up = qcom_pcie_link_up,
> .start_link = qcom_pcie_start_link,
> + .host_start_link = qcom_pcie_host_start_link,
> + .host_stop_link = qcom_pcie_host_stop_link,
> };
>
> static int qcom_pcie_icc_init(struct qcom_pcie *pcie)
>
> --
> 2.34.1
>
^ permalink raw reply [flat|nested] 77+ messages in thread
* Re: [PATCH v2 4/8] PCI: Change the parent to correctly represent pcie hierarchy
2024-08-06 19:07 ` Bjorn Helgaas
@ 2024-08-06 20:06 ` Bartosz Golaszewski
0 siblings, 0 replies; 77+ messages in thread
From: Bartosz Golaszewski @ 2024-08-06 20:06 UTC (permalink / raw)
To: Bjorn Helgaas
Cc: Krishna chaitanya chundru, Bartosz Golaszewski, Lorenzo Pieralisi,
Krzysztof Wilczyński, Rob Herring, Bjorn Helgaas,
Krzysztof Kozlowski, Conor Dooley, Konrad Dybcio,
cros-qcom-dts-watchers, Jingoo Han, Manivannan Sadhasivam,
andersson, quic_vbadigan, linux-arm-msm, linux-pci, devicetree,
linux-kernel
On Tue, Aug 6, 2024 at 9:07 PM Bjorn Helgaas <helgaas@kernel.org> wrote:
>
> On Sat, Aug 03, 2024 at 08:52:50AM +0530, Krishna chaitanya chundru wrote:
> > Currently the pwrctl driver is child of pci-pci bridge driver,
> > this will cause issue when suspend resume is introduced in the pwr
> > control driver. If the supply is removed to the endpoint in the
> > power control driver then the config space access by the
> > pci-pci bridge driver can cause issues like Timeouts.
>
> If "pci-pci bridge driver" refers to portdrv, please use "portdrv" to
> avoid confusion.
>
> Can you be a little more specific about config accesses by the bridge
> driver? Generally portdrv wouldn't touch devices below the bridge.
> It sounds like you've tripped over something here, so you probably
> have an example of a timeout.
>
> s/pcie/PCIe/ in subject, although it'd be nice if the whole subject
> could be a little more specific. I don't think pwrctl is directly
> part of the PCIe hierarchy, so I don't quite understand what you're
> saying there.
>
> > For this reason change the parent to controller from pci-pci bridge.
> >
> > Fixes: 4565d2652a37 ("PCI/pwrctl: Add PCI power control core code")
>
> Will need an ack from Bartosz, of course, since he added this. Moved
> from cc: to to: list to make sure he sees this.
>
I would drop the Fixes tag altogether. This is a change in
implementation but it doesn't really fix a bug or regression.
Other than that: please feel free to add
Acked-by: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>
I will also review the pwrctl part of the series shortly.
Bart
> > Signed-off-by: Krishna chaitanya chundru <quic_krichai@quicinc.com>
> > ---
> > drivers/pci/bus.c | 3 ++-
> > drivers/pci/pwrctl/core.c | 9 ++++++++-
> > 2 files changed, 10 insertions(+), 2 deletions(-)
> >
> > diff --git a/drivers/pci/bus.c b/drivers/pci/bus.c
> > index 55c853686051..15b42f0f588f 100644
> > --- a/drivers/pci/bus.c
> > +++ b/drivers/pci/bus.c
> > @@ -328,6 +328,7 @@ void __weak pcibios_bus_add_device(struct pci_dev *pdev) { }
> > */
> > void pci_bus_add_device(struct pci_dev *dev)
> > {
> > + struct pci_host_bridge *host = pci_find_host_bridge(dev->bus);
> > struct device_node *dn = dev->dev.of_node;
> > int retval;
> >
> > @@ -352,7 +353,7 @@ void pci_bus_add_device(struct pci_dev *dev)
> >
> > if (dev_of_node(&dev->dev) && pci_is_bridge(dev)) {
> > retval = of_platform_populate(dev_of_node(&dev->dev), NULL, NULL,
> > - &dev->dev);
> > + host->dev.parent);
>
> I'm not sure host->dev.parent is always valid. There are
> pci_create_root_bus() callers that supply a NULL parent pointer.
>
> > if (retval)
> > pci_err(dev, "failed to populate child OF nodes (%d)\n",
> > retval);
> > diff --git a/drivers/pci/pwrctl/core.c b/drivers/pci/pwrctl/core.c
> > index feca26ad2f6a..4f2ffa0b0a5f 100644
> > --- a/drivers/pci/pwrctl/core.c
> > +++ b/drivers/pci/pwrctl/core.c
> > @@ -11,6 +11,8 @@
> > #include <linux/property.h>
> > #include <linux/slab.h>
> >
> > +#include "../pci.h"
> > +
> > static int pci_pwrctl_notify(struct notifier_block *nb, unsigned long action,
> > void *data)
> > {
> > @@ -64,18 +66,23 @@ static int pci_pwrctl_notify(struct notifier_block *nb, unsigned long action,
> > */
> > int pci_pwrctl_device_set_ready(struct pci_pwrctl *pwrctl)
> > {
> > + struct pci_bus *bus;
> > int ret;
> >
> > if (!pwrctl->dev)
> > return -ENODEV;
> >
> > + bus = pci_find_bus(of_get_pci_domain_nr(pwrctl->dev->parent->of_node), 0);
> > + if (!bus)
> > + return -ENODEV;
> > +
> > pwrctl->nb.notifier_call = pci_pwrctl_notify;
> > ret = bus_register_notifier(&pci_bus_type, &pwrctl->nb);
> > if (ret)
> > return ret;
> >
> > pci_lock_rescan_remove();
> > - pci_rescan_bus(to_pci_dev(pwrctl->dev->parent)->bus);
> > + pci_rescan_bus(bus);
> > pci_unlock_rescan_remove();
> >
> > return 0;
> >
> > --
> > 2.34.1
> >
^ permalink raw reply [flat|nested] 77+ messages in thread
* Re: [PATCH v2 8/8] PCI: pwrctl: Add power control driver for qps615
2024-08-05 6:14 ` Krishna Chaitanya Chundru
@ 2024-08-08 3:30 ` Dmitry Baryshkov
2024-09-02 7:12 ` Krishna Chaitanya Chundru
0 siblings, 1 reply; 77+ messages in thread
From: Dmitry Baryshkov @ 2024-08-08 3:30 UTC (permalink / raw)
To: Krishna Chaitanya Chundru
Cc: Lorenzo Pieralisi, Krzysztof Wilczyński, Rob Herring,
Bjorn Helgaas, Krzysztof Kozlowski, Conor Dooley, Konrad Dybcio,
cros-qcom-dts-watchers, Bartosz Golaszewski, Jingoo Han,
Manivannan Sadhasivam, andersson, quic_vbadigan, linux-arm-msm,
linux-pci, devicetree, linux-kernel, Bartosz Golaszewski
On August 5, 2024 1:14:47 PM GMT+07:00, Krishna Chaitanya Chundru <quic_krichai@quicinc.com> wrote:
>
>
>On 8/3/2024 5:04 PM, Dmitry Baryshkov wrote:
>> On Sat, Aug 03, 2024 at 08:52:54AM GMT, Krishna chaitanya chundru wrote:
>>> QPS615 switch needs to be configured after powering on and before
>>> PCIe link was up.
>>>
>>> As the PCIe controller driver already enables the PCIe link training
>>> at the host side, stop the link training. Otherwise the moment we turn
>>> on the switch it will participate in the link training and link may come
>>> up before switch is configured through i2c.
>>>
>>> The device tree properties are parsed per node under pci-pci bridge in the
>>> driver. Each node has unique bdf value in the reg property, driver
>>> uses this bdf to differentiate ports, as there are certain i2c writes to
>>> select particular port.
>>>
>>> Based up on dt property and port, qps615 is configured through i2c.
>>>
>>> Signed-off-by: Krishna chaitanya chundru <quic_krichai@quicinc.com>
>>> ---
>>> drivers/pci/pwrctl/Kconfig | 7 +
>>> drivers/pci/pwrctl/Makefile | 1 +
>>> drivers/pci/pwrctl/pci-pwrctl-qps615.c | 638 +++++++++++++++++++++++++++++++++
>>> 3 files changed, 646 insertions(+)
>>>
>>> diff --git a/drivers/pci/pwrctl/Kconfig b/drivers/pci/pwrctl/Kconfig
>>> index 54589bb2403b..6a1352af918c 100644
>>> --- a/drivers/pci/pwrctl/Kconfig
>>> +++ b/drivers/pci/pwrctl/Kconfig
>>> @@ -10,3 +10,10 @@ config PCI_PWRCTL_PWRSEQ
>>> tristate
>>> select POWER_SEQUENCING
>>> select PCI_PWRCTL
>>> +
>>> +config PCI_PWRCTL_QPS615
>>> + tristate "PCI Power Control driver for QPS615"
>>> + select PCI_PWRCTL
>>> + help
>>> + Say Y here to enable the pwrctl driver for Qualcomm
>>> + QPS615 PCIe switch.
>>> diff --git a/drivers/pci/pwrctl/Makefile b/drivers/pci/pwrctl/Makefile
>>> index d308aae4800c..ac563a70c023 100644
>>> --- a/drivers/pci/pwrctl/Makefile
>>> +++ b/drivers/pci/pwrctl/Makefile
>>> @@ -4,3 +4,4 @@ obj-$(CONFIG_PCI_PWRCTL) += pci-pwrctl-core.o
>>> pci-pwrctl-core-y := core.o
>>> obj-$(CONFIG_PCI_PWRCTL_PWRSEQ) += pci-pwrctl-pwrseq.o
>>> +obj-$(CONFIG_PCI_PWRCTL_QPS615) += pci-pwrctl-qps615.o
>>> diff --git a/drivers/pci/pwrctl/pci-pwrctl-qps615.c b/drivers/pci/pwrctl/pci-pwrctl-qps615.c
>>> new file mode 100644
>>> index 000000000000..9dabb82787d5
>>> --- /dev/null
>>> +++ b/drivers/pci/pwrctl/pci-pwrctl-qps615.c
>>> @@ -0,0 +1,638 @@
>>> +// SPDX-License-Identifier: GPL-2.0-only
>>> +/*
>>> + * Copyright (c) 2024 Qualcomm Innovation Center, Inc. All rights reserved.
>>> + */
>>> +
>>> +#include <linux/delay.h>
>>> +#include <linux/device.h>
>>> +#include <linux/firmware.h>
>>> +#include <linux/i2c.h>
>>> +#include <linux/mod_devicetable.h>
>>> +#include <linux/module.h>
>>> +#include <linux/of.h>
>>> +#include <linux/pci.h>
>>> +#include <linux/pci-pwrctl.h>
>>> +#include <linux/platform_device.h>
>>> +#include <linux/regulator/consumer.h>
>>> +#include <linux/string.h>
>>> +#include <linux/types.h>
>>> +
>>> +#include "../pci.h"
>>> +
>>> +#define QPS615_GPIO_CONFIG 0x801208
>>> +#define QPS615_RESET_GPIO 0x801210
>>> +
>>> +#define QPS615_BUS_CONTROL 0x801014
>>> +
>>> +#define QPS615_PORT_L0S_DELAY 0x82496c
>>> +#define QPS615_PORT_L1_DELAY 0x824970
>>> +
>>> +#define QPS615_EMBEDDED_ETH_DELAY 0x8200d8
>>> +#define QPS615_ETH_L1_DELAY_MASK GENMASK(27, 18)
>>> +#define QPS615_ETH_L1_DELAY_VALUE(x) FIELD_PREP(QPS615_ETH_L1_DELAY_MASK, x)
>>> +#define QPS615_ETH_L0S_DELAY_MASK GENMASK(17, 13)
>>> +#define QPS615_ETH_L0S_DELAY_VALUE(x) FIELD_PREP(QPS615_ETH_L0S_DELAY_MASK, x)
>>> +
>>> +#define QPS615_NFTS_2_5_GT 0x824978
>>> +#define QPS615_NFTS_5_GT 0x82497c
>>> +
>>> +#define QPS615_PORT_LANE_ACCESS_ENABLE 0x828000
>>> +
>>> +#define QPS615_PHY_RATE_CHANGE_OVERRIDE 0x828040
>>> +#define QPS615_PHY_RATE_CHANGE 0x828050
>>> +
>>> +#define QPS615_TX_MARGIN 0x828234
>>> +
>>> +#define QPS615_DFE_ENABLE 0x828a04
>>> +#define QPS615_DFE_EQ0_MODE 0x828a08
>>> +#define QPS615_DFE_EQ1_MODE 0x828a0c
>>> +#define QPS615_DFE_EQ2_MODE 0x828a14
>>> +#define QPS615_DFE_PD_MASK 0x828254
>>> +
>>> +#define QPS615_PORT_SELECT 0x82c02c
>>> +#define QPS615_PORT_ACCESS_ENABLE 0x82c030
>>> +
>>> +#define QPS615_POWER_CONTROL 0x82b09c
>>> +#define QPS615_POWER_CONTROL_OVREN 0x82b2c8
>>> +
>>> +#define QPS615_AXI_CLK_FREQ_MHZ 125
>>> +
>>> +struct qps615_pwrctl_reg_setting {
>>> + unsigned int offset;
>>> + unsigned int val;
>>> +};
>>> +
>>> +struct qps615_pwrctl_bdf_info {
>>> + u16 usp_bdf;
>>> + u16 dsp1_bdf;
>>> + u16 dsp2_bdf;
>>> + u16 dsp3_bdf;
>>
>> Why are these values dynamic? Please use #define's for now. If there
>> ever comes a similar bridge, it most likely will have a different ports
>> configuration, so it will need additional changes anyway.
>>
>We added this for future use case only, we felt it is easier to support
>at the time if we add this way.
Please don't. You are hardcoding distinct roles into the structure that is supposed to be generic. Possible future use cases might have different number of ports or different port roles.
>
>>> +};
>>> +
>>> +enum qps615_pwrctl_ports {
>>> + QPS615_USP,
>>> + QPS615_DSP1,
>>> + QPS615_DSP2,
>>> + QPS615_DSP3,
>>> + QPS615_ETHERNET,
>>> + QPS615_MAX
>>> +};
>>> +
>>> +struct qps615_pwrctl_cfg {
>>> + u32 l0s_delay;
>>> + u32 l1_delay;
>>> + u32 tx_amp;
>>> + u32 axi_freq;
>>> + u8 nfts;
>>> + bool disable_dfe;
>>> + bool disable_port;
>>> +};
>>> +
>>> +#define QPS615_PWRCTL_MAX_SUPPLY 6
>>> +
>>> +struct qps615_pwrctl_ctx {
>>> + struct regulator_bulk_data supplies[QPS615_PWRCTL_MAX_SUPPLY];
>>> + const struct qps615_pwrctl_bdf_info *bdf;
>>> + struct qps615_pwrctl_cfg cfg[QPS615_MAX];
>>> + struct gpio_desc *reset_gpio;
>>> + struct i2c_client *client;
>>> + struct pci_pwrctl pwrctl;
>>> + struct device_link *link;
>>> +};
>>> +
>>> +/*
>>> + * downstream port power off sequence, hardcoding the address
>>> + * as we don't know register names for these register offsets.
>>
>> It is hard to believe that Qualcomm engineers don't know register names
>> for the Qualcomm device.
>>
>The switch IP is from the another vendor and the vendor provided these
>settings. The databook doesn't have the register names in it.
>>> + */
>>> +static const struct qps615_pwrctl_reg_setting common_pwroff_seq[] = {
>>> + {0x82900c, 0x1},
>>> + {0x829010, 0x1},
>>> + {0x829018, 0x0},
>>> + {0x829020, 0x1},
>>> + {0x82902c, 0x1},
>>> + {0x829030, 0x1},
>>> + {0x82903c, 0x1},
>>> + {0x829058, 0x0},
>>> + {0x82905c, 0x1},
>>> + {0x829060, 0x1},
>>> + {0x8290cc, 0x1},
>>> + {0x8290d0, 0x1},
>>> + {0x8290d8, 0x1},
>>> + {0x8290e0, 0x1},
>>> + {0x8290e8, 0x1},
>>> + {0x8290ec, 0x1},
>>> + {0x8290f4, 0x1},
>>> + {0x82910c, 0x1},
>>> + {0x829110, 0x1},
>>> + {0x829114, 0x1},
>>> +};
>>> +
>>> +static const struct qps615_pwrctl_reg_setting dsp1_pwroff_seq[] = {
>>> + {QPS615_PORT_ACCESS_ENABLE, 0x2},
>>> + {QPS615_PORT_LANE_ACCESS_ENABLE, 0x3},
>>> + {QPS615_POWER_CONTROL, 0x014f4804},
>>> + {QPS615_POWER_CONTROL_OVREN, 0x1},
>>> + {QPS615_PORT_ACCESS_ENABLE, 0x4},
>>> +};
>>> +
>>> +static const struct qps615_pwrctl_reg_setting dsp2_pwroff_seq[] = {
>>> + {QPS615_PORT_ACCESS_ENABLE, 0x8},
>>> + {QPS615_PORT_LANE_ACCESS_ENABLE, 0x1},
>>> + {QPS615_POWER_CONTROL, 0x014f4804},
>>> + {QPS615_POWER_CONTROL_OVREN, 0x1},
>>> + {QPS615_PORT_ACCESS_ENABLE, 0x8},
>>> +};
>>> +
>>> +static int qps615_pwrctl_i2c_write(struct i2c_client *client,
>>> + u32 reg_addr, u32 reg_val)
>>> +{
>>> + struct i2c_msg msg;
>>> + u8 msg_buf[7];
>>> + int ret;
>>> +
>>> + msg.addr = client->addr;
>>> + msg.len = 7;
>>> + msg.flags = 0;
>>> +
>>> + /* Big Endian for reg addr */
>>> + reg_addr = cpu_to_be32(reg_addr);
>>
>> This is incorrect. After cpu_to_be32() the value depends on the CPU
>> endianness. So reg_addr >> 8 will return different values for LE and BE
>> CPUs.
>> I had following impression
>If reg address is 0x828a0c in big endian sytem it will be 0c8a8200
>and in litte endian it will be 0x828a0c only.
>If cpu uses big endian cpu_to_be32 will not change this value
>and in little endian case cpu_to_be32 will convert 0x828a0c to 0c8a8200.
>
>Now the output is same for both the systems I tried to use
>(reg_addr >> 8) directly.
>
>Are you saying (reg_addr >> 8) output will be different based upon
>LE and BE ? If that is the case I will remove the conversions
>in next patch.
Reg address is always 0x00828a0c. Then on little-endian system you convert it to to BE32, which results in the value 0x0c8a8200. Finally you use shifts to get {0x82, 0x8a, 0x0c}, which is supposedly correct.
On big-endian system cpu_to_be32 returns the same value, 0x00828a0c, since it is BE32 already. So after shifts msg_buf will get {0x8a, 0x82, 0x00}, which is obviously incorrect.
>>> +
>>> + msg_buf[0] = (u8)(reg_addr >> 8);
>>> + msg_buf[1] = (u8)(reg_addr >> 16);
>>> + msg_buf[2] = (u8)(reg_addr >> 24);
>>> +
>>> + /* Little Endian for reg val */
>>> + reg_val = cpu_to_le32(reg_val);
>>> +
>>> + msg_buf[3] = (u8)(reg_val);
>>> + msg_buf[4] = (u8)(reg_val >> 8);
>>> + msg_buf[5] = (u8)(reg_val >> 16);
>>> + msg_buf[6] = (u8)(reg_val >> 24);
>>
>> Same issue here.
>>
>>> +
>>> + msg.buf = msg_buf;
>>> + ret = i2c_transfer(client->adapter, &msg, 1);
>>> + return ret == 1 ? 0 : ret;
>>> +}
>>> +
>>> +static int qps615_pwrctl_i2c_read(struct i2c_client *client,
>>> + u32 reg_addr, u32 *reg_val)
>>> +{
>>> + struct i2c_msg msg[2];
>>> + u8 wr_data[3];
>>> + u32 rd_data;
>>> + int ret;
>>> +
>>> + msg[0].addr = client->addr;
>>> + msg[0].len = 3;
>>> + msg[0].flags = 0;
>>> +
>>> + /* Big Endian for reg addr */
>>> + reg_addr = cpu_to_be32(reg_addr);
>>> +
>>> + wr_data[0] = (u8)(reg_addr >> 8);
>>> + wr_data[1] = (u8)(reg_addr >> 16);
>>> + wr_data[2] = (u8)(reg_addr >> 24);
>>
>> And here.
>>
>>> +
>>> + msg[0].buf = wr_data;
>>> +
>>> + msg[1].addr = client->addr;
>>> + msg[1].len = 4;
>>> + msg[1].flags = I2C_M_RD;
>>> +
>>> + msg[1].buf = (u8 *)&rd_data;
>>> +
>>> + ret = i2c_transfer(client->adapter, &msg[0], 2);
>>> + if (ret == 2) {
>>> + *reg_val = le32_to_cpu(rd_data);
>>> + return 0;
>>> + }
>>> +
>>> + /* If only one message successfully completed, return -ENODEV */
>>> + return ret == 1 ? -ENODEV : ret;
>>> +}
>>> +
>>> +static int qps615_pwrctl_i2c_bulk_write(struct i2c_client *client,
>>> + const struct qps615_pwrctl_reg_setting *seq, int len)
>>> +{
>>> + int ret, i;
>>> +
>>> + for (i = 0; i < len; i++) {
>>> + ret = qps615_pwrctl_i2c_write(client, seq[i].offset, seq[i].val);
>>> + if (ret)
>>> + return ret;
>>> + }
>>> +
>>> + return 0;
>>> +}
>>> +
>>> +static int of_pci_get_bdf(struct device_node *np)
>>> +{
>>> + u32 reg[5];
>>> + int error;
>>> +
>>> + error = of_property_read_u32_array(np, "reg", reg, ARRAY_SIZE(reg));
>>
>> Please use of_property_read_u32_index() instead.
>>
>ack.
>>> + if (error)
>>> + return error;
>>> +
>>> + return (reg[0] >> 8) & 0xffff;
>>> +}
>>> +
>>> +static int qps615_pwrctl_disable_port(struct qps615_pwrctl_ctx *ctx,
>>> + enum qps615_pwrctl_ports port)
>>> +{
>>> + const struct qps615_pwrctl_reg_setting *seq;
>>> + int ret, len;
>>> +
>>> + seq = (port == QPS615_DSP1) ? dsp1_pwroff_seq : dsp2_pwroff_seq;
>>> + len = (port == QPS615_DSP1) ? ARRAY_SIZE(dsp1_pwroff_seq) : ARRAY_SIZE(dsp2_pwroff_seq);
>>> +
>>> + ret = qps615_pwrctl_i2c_bulk_write(ctx->client, seq, len);
>>> + if (ret)
>>> + return ret;
>>> +
>>> + return qps615_pwrctl_i2c_bulk_write(ctx->client,
>>> + common_pwroff_seq, ARRAY_SIZE(common_pwroff_seq));
>>> +}
>>> +
>>> +static int qps615_pwrctl_set_l0s_l1_entry_delay(struct qps615_pwrctl_ctx *ctx,
>>> + enum qps615_pwrctl_ports port, bool is_l1, u32 ns)
>>> +{
>>> + u32 rd_val, units;
>>> + int ret;
>>> +
>>> + /* convert to units of 256ns */
>>> + units = ns / 256;
>>> +
>>> + if (port == QPS615_ETHERNET) {
>>> + ret = qps615_pwrctl_i2c_read(ctx->client, QPS615_EMBEDDED_ETH_DELAY, &rd_val);
>>> + if (ret)
>>> + return ret;
>>> + rd_val = u32_replace_bits(rd_val, units,
>>> + is_l1 ?
>>> + QPS615_ETH_L1_DELAY_MASK : QPS615_ETH_L0S_DELAY_MASK);
>>> + return qps615_pwrctl_i2c_write(ctx->client, QPS615_EMBEDDED_ETH_DELAY, rd_val);
>>> + }
>>> +
>>> + ret = qps615_pwrctl_i2c_write(ctx->client, QPS615_PORT_SELECT, BIT(port));
>>> + if (ret)
>>> + return ret;
>>
>> What if there is a concurrent call? The port_select / write_value
>> statements should use a lock to remove the possible race condition.
>>
>There should not be any concurrent calls since all calls come from the
>probe itself.
Comment this in the driver, since somebody might decide to call the function later
>>> +
>>> + return qps615_pwrctl_i2c_write(ctx->client,
>>> + is_l1 ? QPS615_PORT_L1_DELAY : QPS615_PORT_L0S_DELAY, units);
>>> +}
>>> +
>>> +static int qps615_pwrctl_set_tx_amplitude(struct qps615_pwrctl_ctx *ctx,
>>> + enum qps615_pwrctl_ports port, u32 amp)
>>> +{
>>> + int port_access;
>>> +
>>> + switch (port) {
>>> + case QPS615_USP:
>>> + port_access = 0x1;
>>> + break;
>>> + case QPS615_DSP1:
>>> + port_access = 0x2;
>>> + break;
>>> + case QPS615_DSP2:
>>> + port_access = 0x8;
>>> + break;
>>> + default:
>>> + return -EINVAL;
>>> + };
>>> +
>>> + struct qps615_pwrctl_reg_setting tx_amp_seq[] = {
>>> + {QPS615_PORT_ACCESS_ENABLE, port_access},
>>
>> Hmm, this looks like another port selection, so most likely it should
>> also be under the same lock.
>>
>>> + {QPS615_PORT_LANE_ACCESS_ENABLE, 0x3},
>>> + {QPS615_TX_MARGIN, amp},
>>> + };
>>> +
>>> + return qps615_pwrctl_i2c_bulk_write(ctx->client, tx_amp_seq, ARRAY_SIZE(tx_amp_seq));
>>> +}
>>> +
>>> +static int qps615_pwrctl_disable_dfe(struct qps615_pwrctl_ctx *ctx,
>>> + enum qps615_pwrctl_ports port)
>>> +{
>>> + int port_access, lane_access = 0x3;
>>> + u32 phy_rate = 0x21;
>>> +
>>> + switch (port) {
>>> + case QPS615_USP:
>>> + phy_rate = 0x1;
>>> + port_access = 0x1;
>>> + break;
>>> + case QPS615_DSP1:
>>> + port_access = 0x2;
>>> + break;
>>> + case QPS615_DSP2:
>>> + port_access = 0x8;
>>> + lane_access = 0x1;
>>> + break;
>>> + default:
>>> + return -EINVAL;
>>> + };
>>> +
>>> + struct qps615_pwrctl_reg_setting disable_dfe_seq[] = {
>>> + {QPS615_PORT_ACCESS_ENABLE, port_access},
>>> + {QPS615_PORT_LANE_ACCESS_ENABLE, lane_access},
>>> + {QPS615_DFE_ENABLE, 0x0},
>>> + {QPS615_DFE_EQ0_MODE, 0x411},
>>> + {QPS615_DFE_EQ1_MODE, 0x11},
>>> + {QPS615_DFE_EQ2_MODE, 0x11},
>>> + {QPS615_DFE_PD_MASK, 0x7},
>>> + {QPS615_PHY_RATE_CHANGE_OVERRIDE, 0x10},
>>> + {QPS615_PHY_RATE_CHANGE, phy_rate},
>>> + {QPS615_PHY_RATE_CHANGE, 0x0},
>>> + {QPS615_PHY_RATE_CHANGE_OVERRIDE, 0x0},
>>> +
>>> + };
>>> +
>>> + return qps615_pwrctl_i2c_bulk_write(ctx->client,
>>> + disable_dfe_seq, ARRAY_SIZE(disable_dfe_seq));
>>> +}
>>> +
>>> +static int qps615_pwrctl_set_nfts(struct qps615_pwrctl_ctx *ctx,
>>> + enum qps615_pwrctl_ports port, u32 nfts)
>>> +{
>>> + int ret;
>>> + struct qps615_pwrctl_reg_setting nfts_seq[] = {
>>> + {QPS615_NFTS_2_5_GT, nfts},
>>> + {QPS615_NFTS_5_GT, nfts},
>>> + };
>>> +
>>> + ret = qps615_pwrctl_i2c_write(ctx->client, QPS615_PORT_SELECT, BIT(port));
>>> + if (ret)
>>> + return ret;
>>> +
>>> + return qps615_pwrctl_i2c_bulk_write(ctx->client, nfts_seq, ARRAY_SIZE(nfts_seq));
>>> +}
>>> +
>>> +static int qps615_pwrctl_assert_deassert_reset(struct qps615_pwrctl_ctx *ctx, bool deassert)
>>> +{
>>> + int ret, val = 0;
>>> +
>>> + if (deassert)
>>> + val = 0xc;
>>> +
>>> + ret = qps615_pwrctl_i2c_write(ctx->client, QPS615_GPIO_CONFIG, 0xfffffff3);
>>
>> It's a kind of magic
>>
>I will add a macro in next patch.
>>> + if (ret)
>>> + return ret;
>>> +
>>> + return qps615_pwrctl_i2c_write(ctx->client, QPS615_RESET_GPIO, val);
>>> +}
>>> +
>>> +static int qps615_pwrctl_parse_device_dt(struct qps615_pwrctl_ctx *ctx, struct device_node *node)
>>> +{
>>> + enum qps615_pwrctl_ports port;
>>> + struct qps615_pwrctl_cfg *cfg;
>>> + struct device_node *np;
>>> + int bdf, fun_no;
>>> +
>>> + bdf = of_pci_get_bdf(node);
>>> + if (bdf < 0) {
>>
>> This is incorrect, it will fail if at any point BDF uses the most
>> significant bit (which is permitted by the spec, if I'm not mistaken).
>>
>As per the reg property as described in the binding document we are not
>expecting any change here.
>https://elixir.bootlin.com/linux/v6.10.3/source/Documentation/devicetree/bindings/pci/pci.txt#L50.
What will this function return if the bus no is 256?
Also please either move the function to the generic PCI code is change its name to match the rest of the driver. The of_pci_ prefix is reserved for the generic code.
>>> + dev_err(ctx->pwrctl.dev, "Getting BDF failed\n");
>>> + return 0;
>>> + }
>>> +
>>> + fun_no = bdf & 0x7;
>>
>> I assume that ARI is not supported?
>>
>Yes this doesn't support ARI.
>>> +
>>> + /* In multi function node, ignore function 1 node */
>>> + if (of_pci_get_bdf(of_get_parent(node)) == ctx->bdf->dsp3_bdf && !fun_no)
>>> + port = QPS615_ETHERNET;
>>> + else if (bdf == ctx->bdf->usp_bdf)
>>> + port = QPS615_USP;
>>
>> The function is being called for child device nodes. Thus upstream
>> facing port (I assume that this is what USP means) can not be enumerated
>> in this way.
>Sorry, but I didn't your question.
>
>These settings will not affect the enumeration sequence these are
>for configuring ports only.
You are handling the case of bdf equal to the USP. Is it possible at all?
>>
>>> + else if (bdf == ctx->bdf->dsp1_bdf)
>>> + port = QPS615_DSP1;
>>> + else if (bdf == ctx->bdf->dsp2_bdf)
>>> + port = QPS615_DSP2;
>>> + else if (bdf == ctx->bdf->dsp3_bdf)
>>> + port = QPS615_DSP3;
>>> + else
>>> + return 0;
>>
>> -EINVAL >
>There are can be nodes describing endpoints also,
>for those nodes bdf will not match and we are not
>returning since it is expected for endpoint nodes.
Which endpoints? Bindings don't describe them.
>
>>> +
>>> + cfg = &ctx->cfg[port];
>>> +
>>> + if (!of_device_is_available(node)) {
>>> + cfg->disable_port = true;
>>> + return 0;
>>> + };
>>> +
>>> + of_property_read_u32(node, "qcom,axi-clk-freq-hz", &cfg->axi_freq);
>>> +
>>> + of_property_read_u32(node, "qcom,l0s-entry-delay-ns", &cfg->l0s_delay);
>>> +
>>> + of_property_read_u32(node, "qcom,l1-entry-delay-ns", &cfg->l1_delay);
>>> +
>>> + of_property_read_u32(node, "qcom,tx-amplitude-millivolt", &cfg->tx_amp);
>>> +
>>> + cfg->disable_dfe = of_property_read_bool(node, "qcom,no-dfe");
>>> +
>>> + of_property_read_u8(node, "qcom,nfts", &cfg->nfts);
>>> +
>>> + for_each_child_of_node(node, np)
>>> + qps615_pwrctl_parse_device_dt(ctx, np);
>>> +
>>> + of_node_put(np);
>>> + return 0;
>>> +}
>>> +
>>> +static void qps615_pwrctl_power_off(struct qps615_pwrctl_ctx *ctx)
>>> +{
>>> + gpiod_set_value(ctx->reset_gpio, 1);
>>> +
>>> + regulator_bulk_disable(ARRAY_SIZE(ctx->supplies), ctx->supplies);
>>> +}
>>> +
>>> +static int qps615_pwrctl_power_on(struct qps615_pwrctl_ctx *ctx)
>>> +{
>>> + struct qps615_pwrctl_cfg *cfg;
>>> + int ret, i;
>>> +
>>> + ret = regulator_bulk_enable(ARRAY_SIZE(ctx->supplies), ctx->supplies);
>>> + if (ret < 0)
>>> + return dev_err_probe(ctx->pwrctl.dev, ret, "cannot enable regulators\n");
>>> +
>>> + gpiod_set_value(ctx->reset_gpio, 0);
>>> +
>>> + if (!ctx->client)
>>> + return 0;
>>
>> really?
>>
>Even if we don't do i2c configuration PCIe enumeration will happen, for
>some reason i2c client is not found, driver ignores the error and return
>since basic functionality will work.
So what is the point of such misconfiguration? If "something works" even in the default case, then we don't need this driver at all, do we?
Even worse. With the modular kernels you can not guarantee probe order. However the user expects that if the driver is probed, it has configured the hardware correctly.
Linux has special return value for such cases, please return it instead if 0.
>>> +
>>> + /*
>>> + * Don't have a way to see if the reset has completed.
>>> + * Wait for some time.
>>> + */
>>> + usleep_range(1000, 1001);
>>> +
>>> + ret = qps615_pwrctl_assert_deassert_reset(ctx, false);
>>> + if (ret)
>>> + goto out;
>>> +
>>> + if (ctx->cfg[QPS615_USP].axi_freq == QPS615_AXI_CLK_FREQ_MHZ) {
>>> + ret = qps615_pwrctl_i2c_write(ctx->client, QPS615_BUS_CONTROL, BIT(16));
>>> + if (ret)
>>> + dev_err(ctx->pwrctl.dev, "Setting axi clk freq failed %d\n", ret);
>>
>> AXI, not axi
>>
>ack.
>>> + }
>>> +
>>> + for (i = 0; i < QPS615_MAX; i++) {
>>> + cfg = &ctx->cfg[i];
>>> + if (cfg->disable_port) {
>>> + ret = qps615_pwrctl_disable_port(ctx, i);
>>> + if (ret) {
>>> + dev_err(ctx->pwrctl.dev, "Disabling port failed\n");
>>> + goto out;
>>> + }
>>> + }
>>> +
>>> + if (cfg->l0s_delay) {
>>> + ret = qps615_pwrctl_set_l0s_l1_entry_delay(ctx, i, false, cfg->l0s_delay);
>>> + if (ret) {
>>> + dev_err(ctx->pwrctl.dev, "Setting L0s entry delay failed\n");
>>> + goto out;
>>> + }
>>> + }
>>> +
>>> + if (cfg->l1_delay) {
>>> + ret = qps615_pwrctl_set_l0s_l1_entry_delay(ctx, i, true, cfg->l1_delay);
>>> + if (ret) {
>>> + dev_err(ctx->pwrctl.dev, "Setting L1 entry delay failed\n");
>>> + goto out;
>>> + }
>>> + }
>>> +
>>> + if (cfg->tx_amp) {
>>> + ret = qps615_pwrctl_set_tx_amplitude(ctx, i, cfg->tx_amp);
>>> + if (ret) {
>>> + dev_err(ctx->pwrctl.dev, "Setting Tx amplitube failed\n");
>>> + goto out;
>>> + }
>>> + }
>>> +
>>> + if (cfg->nfts) {
>>> + ret = qps615_pwrctl_set_nfts(ctx, i, cfg->nfts);
>>> + if (ret) {
>>> + dev_err(ctx->pwrctl.dev, "Setting nfts failed\n");
>>> + goto out;
>>> + }
>>> + }
>>> +
>>> + if (cfg->disable_dfe) {
>>> + ret = qps615_pwrctl_disable_dfe(ctx, i);
>>> + if (ret) {
>>> + dev_err(ctx->pwrctl.dev, "Disabling DFE failed\n");
>>> + goto out;
>>> + }
>>> + }
>>> + }
>>> +
>>> + ret = qps615_pwrctl_assert_deassert_reset(ctx, true);
>>> + if (!ret)
>>> + return 0;
>>> +
>>> +out:
>>> + qps615_pwrctl_power_off(ctx);
>>> + return ret;
>>> +}
>>> +
>>> +static int qps615_pwrctl_probe(struct platform_device *pdev)
>>> +{
>>> + struct device *dev = &pdev->dev;
>>> + struct pci_host_bridge *bridge;
>>> + struct qps615_pwrctl_ctx *ctx;
>>> + struct device_node *node;
>>> + struct pci_bus *bus;
>>> + int ret;
>>> +
>>> + bus = pci_find_bus(of_get_pci_domain_nr(dev->parent->of_node), 0);
>>> + if (!bus)
>>> + return -ENODEV;
>>> +
>>> + bridge = pci_find_host_bridge(bus);
>>> +
>>> + ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL);
>>> + if (!ctx)
>>> + return -ENOMEM;
>>> +
>>> + node = of_parse_phandle(pdev->dev.of_node, "qcom,qps615-controller", 0);
>>> + if (node) {
>>
>> And if !node?
>>
>>> + ctx->client = of_find_i2c_device_by_node(node);
>>
>> Leaks the reference count, see the comment at the function definition.
>> Also what if the I2C bus gets unbound? Will it crash the driver?
>>
>I will fix in next patch.
>
>Driver is not expected to crash when i2c bus gets unbound.
>It should be properly handled in i2c driver.
Please verify it.
>
>- Krishna Chaitanya.
>>> + of_node_put(node);
>>> + if (!ctx->client)
>>> + return dev_err_probe(dev, -EPROBE_DEFER,
>>> + "failed to parse qcom,qps615-controller\n");
>>> + }
>>> +
>>> + ctx->bdf = of_device_get_match_data(dev);
>>> + ctx->pwrctl.dev = dev;
>>> +
>>> + ctx->supplies[0].supply = "vddc";
>>> + ctx->supplies[1].supply = "vdd18";
>>> + ctx->supplies[2].supply = "vdd09";
>>> + ctx->supplies[3].supply = "vddio1";
>>> + ctx->supplies[4].supply = "vddio2";
>>> + ctx->supplies[5].supply = "vddio18";
>>> + ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(ctx->supplies), ctx->supplies);
>>> + if (ret)
>>> + return dev_err_probe(dev, ret,
>>> + "failed to get supply regulator\n");
>>> +
>>> + ctx->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_ASIS);
>>> + if (IS_ERR(ctx->reset_gpio))
>>> + return dev_err_probe(dev, PTR_ERR(ctx->reset_gpio), "failed to get reset GPIO\n");
>>> +
>>> + ctx->link = device_link_add(&bridge->dev, dev, DL_FLAG_AUTOREMOVE_CONSUMER);
>>> +
>>> + platform_set_drvdata(pdev, ctx);
>>> +
>>> + qps615_pwrctl_parse_device_dt(ctx, pdev->dev.of_node);
>>> +
>>> + if (bridge->ops->stop_link)
>>> + bridge->ops->stop_link(bus);
>>> +
>>> + ret = qps615_pwrctl_power_on(ctx);
>>> + if (ret)
>>> + return ret;
>>> +
>>> + if (bridge->ops->start_link) {
>>> + ret = bridge->ops->start_link(bus);
>>> + if (ret)
>>> + return ret;
>>> + }
>>> +
>>> + return devm_pci_pwrctl_device_set_ready(dev, &ctx->pwrctl);
>>> +}
>>> +
>>> +static void qps615_pwrctl_remove(struct platform_device *pdev)
>>> +{
>>> + struct device *dev = &pdev->dev;
>>> + struct qps615_pwrctl_ctx *ctx = dev_get_drvdata(dev);
>>> +
>>> + device_link_del(ctx->link);
>>> + qps615_pwrctl_power_off(ctx);
>>> +}
>>> +
>>> +static const struct qps615_pwrctl_bdf_info bdf_info = {
>>> + .usp_bdf = 0x100,
>>> + .dsp1_bdf = 0x208,
>>> + .dsp2_bdf = 0x210,
>>> + .dsp3_bdf = 0x218,
>>> +};
>>> +
>>> +static const struct of_device_id qps615_pwrctl_of_match[] = {
>>> + { .compatible = "pci1179,0623", .data = &bdf_info },
>>> + { }
>>> +};
>>> +MODULE_DEVICE_TABLE(of, qps615_pwrctl_of_match);
>>> +
>>> +static struct platform_driver qps615_pwrctl_driver = {
>>> + .driver = {
>>> + .name = "pwrctl-qps615",
>>> + .of_match_table = qps615_pwrctl_of_match,
>>> + .probe_type = PROBE_PREFER_ASYNCHRONOUS,
>>> + },
>>> + .probe = qps615_pwrctl_probe,
>>> + .remove_new = qps615_pwrctl_remove,
>>> +};
>>> +module_platform_driver(qps615_pwrctl_driver);
>>> +
>>> +MODULE_AUTHOR("Krishna chaitanya chundru <quic_krichai@quicinc.com>");
>>> +MODULE_DESCRIPTION("Qualcomm QPS615 power control driver");
>>> +MODULE_LICENSE("GPL");
>>>
>>> --
>>> 2.34.1
>>>
>>
--
With best wishes
Dmitry
^ permalink raw reply [flat|nested] 77+ messages in thread
* Re: [PATCH v2 1/8] dt-bindings: PCI: Add binding for qps615
2024-08-05 17:18 ` Krzysztof Kozlowski
@ 2024-08-08 12:01 ` Manivannan Sadhasivam
2024-08-08 12:13 ` Krzysztof Kozlowski
0 siblings, 1 reply; 77+ messages in thread
From: Manivannan Sadhasivam @ 2024-08-08 12:01 UTC (permalink / raw)
To: Krzysztof Kozlowski
Cc: Bjorn Andersson, Krishna Chaitanya Chundru, Lorenzo Pieralisi,
Krzysztof Wilczyński, Rob Herring, Bjorn Helgaas,
Krzysztof Kozlowski, Conor Dooley, Konrad Dybcio,
cros-qcom-dts-watchers, Bartosz Golaszewski, Jingoo Han,
andersson, quic_vbadigan, linux-arm-msm, linux-pci, devicetree,
linux-kernel, Bartosz Golaszewski
On Mon, Aug 05, 2024 at 07:18:04PM +0200, Krzysztof Kozlowski wrote:
> On 05/08/2024 19:07, Bjorn Andersson wrote:
> > On Mon, Aug 05, 2024 at 09:41:26AM +0530, Krishna Chaitanya Chundru wrote:
> >> On 8/4/2024 2:23 PM, Krzysztof Kozlowski wrote:
> >>> On 03/08/2024 05:22, Krishna chaitanya chundru wrote:
> >>>> diff --git a/Documentation/devicetree/bindings/pci/qcom,qps615.yaml b/Documentation/devicetree/bindings/pci/qcom,qps615.yaml
> > [..]
> >>>> + qps615,axi-clk-freq-hz:
> >>>> + description:
> >>>> + AXI clock which internal bus of the switch.
> >>>
> >>> No need, use CCF.
> >>>
> >> ack
> >
> > This is a clock that's internal to the QPS615, so there's no clock
> > controller involved and hence I don't think CCF is applicable.
>
> AXI does not sound that internal.
Well, AXI is applicable to whatever entity that implements it. We mostly seen it
in ARM SoCs (host), but in this case the PCIe switch also has a microcontroller
/processor of some sort, so AXI is indeed relevant for it. The naming actually
comes from the switch's i2c register name that is being configured in the driver
based on this property value.
> DT rarely needs to specify internal
> clock rates. What if you want to define rates for 20 clocks? Even
> clock-frequency is deprecated, so why this would be allowed?
> bus-frequency is allowed for buses, but that's not the case here, I guess?
>
This clock frequency is for the switch's internal AXI bus that runs at default
200MHz. And this property is used to specify a frequency that is configured over
the i2c interface so that the switch's AXI bus can operate in a low frequency
there by reducing the power consumption of the switch.
It is not strictly needed for the switch operation, but for power optimization.
So this property can also be dropped for the initial submission and added later
if you prefer.
- Mani
--
மணிவண்ணன் சதாசிவம்
^ permalink raw reply [flat|nested] 77+ messages in thread
* Re: [PATCH v2 1/8] dt-bindings: PCI: Add binding for qps615
2024-08-08 12:01 ` Manivannan Sadhasivam
@ 2024-08-08 12:13 ` Krzysztof Kozlowski
2024-08-08 12:41 ` Manivannan Sadhasivam
0 siblings, 1 reply; 77+ messages in thread
From: Krzysztof Kozlowski @ 2024-08-08 12:13 UTC (permalink / raw)
To: Manivannan Sadhasivam
Cc: Bjorn Andersson, Krishna Chaitanya Chundru, Lorenzo Pieralisi,
Krzysztof Wilczyński, Rob Herring, Bjorn Helgaas,
Krzysztof Kozlowski, Conor Dooley, Konrad Dybcio,
cros-qcom-dts-watchers, Bartosz Golaszewski, Jingoo Han,
andersson, quic_vbadigan, linux-arm-msm, linux-pci, devicetree,
linux-kernel, Bartosz Golaszewski
On 08/08/2024 14:01, Manivannan Sadhasivam wrote:
> On Mon, Aug 05, 2024 at 07:18:04PM +0200, Krzysztof Kozlowski wrote:
>> On 05/08/2024 19:07, Bjorn Andersson wrote:
>>> On Mon, Aug 05, 2024 at 09:41:26AM +0530, Krishna Chaitanya Chundru wrote:
>>>> On 8/4/2024 2:23 PM, Krzysztof Kozlowski wrote:
>>>>> On 03/08/2024 05:22, Krishna chaitanya chundru wrote:
>>>>>> diff --git a/Documentation/devicetree/bindings/pci/qcom,qps615.yaml b/Documentation/devicetree/bindings/pci/qcom,qps615.yaml
>>> [..]
>>>>>> + qps615,axi-clk-freq-hz:
>>>>>> + description:
>>>>>> + AXI clock which internal bus of the switch.
>>>>>
>>>>> No need, use CCF.
>>>>>
>>>> ack
>>>
>>> This is a clock that's internal to the QPS615, so there's no clock
>>> controller involved and hence I don't think CCF is applicable.
>>
>> AXI does not sound that internal.
>
> Well, AXI is applicable to whatever entity that implements it. We mostly seen it
> in ARM SoCs (host), but in this case the PCIe switch also has a microcontroller
> /processor of some sort, so AXI is indeed relevant for it. The naming actually
> comes from the switch's i2c register name that is being configured in the driver
> based on this property value.
>
>> DT rarely needs to specify internal
>> clock rates. What if you want to define rates for 20 clocks? Even
>> clock-frequency is deprecated, so why this would be allowed?
>> bus-frequency is allowed for buses, but that's not the case here, I guess?
>>
>
> This clock frequency is for the switch's internal AXI bus that runs at default
> 200MHz. And this property is used to specify a frequency that is configured over
> the i2c interface so that the switch's AXI bus can operate in a low frequency
> there by reducing the power consumption of the switch.
>
> It is not strictly needed for the switch operation, but for power optimization.
> So this property can also be dropped for the initial submission and added later
> if you prefer.
So if the clock rate can change, why this is static in DTB? Or why this
is configurable per-board?
There is a reason why clock-frequency property is not welcomed and you
are re-implementing it.
Best regards,
Krzysztof
^ permalink raw reply [flat|nested] 77+ messages in thread
* Re: [PATCH v2 1/8] dt-bindings: PCI: Add binding for qps615
2024-08-08 12:13 ` Krzysztof Kozlowski
@ 2024-08-08 12:41 ` Manivannan Sadhasivam
2024-08-08 13:06 ` Krzysztof Kozlowski
0 siblings, 1 reply; 77+ messages in thread
From: Manivannan Sadhasivam @ 2024-08-08 12:41 UTC (permalink / raw)
To: Krzysztof Kozlowski
Cc: Bjorn Andersson, Krishna Chaitanya Chundru, Lorenzo Pieralisi,
Krzysztof Wilczyński, Rob Herring, Bjorn Helgaas,
Krzysztof Kozlowski, Conor Dooley, Konrad Dybcio,
cros-qcom-dts-watchers, Bartosz Golaszewski, Jingoo Han,
andersson, quic_vbadigan, linux-arm-msm, linux-pci, devicetree,
linux-kernel, Bartosz Golaszewski
On Thu, Aug 08, 2024 at 02:13:01PM +0200, Krzysztof Kozlowski wrote:
> On 08/08/2024 14:01, Manivannan Sadhasivam wrote:
> > On Mon, Aug 05, 2024 at 07:18:04PM +0200, Krzysztof Kozlowski wrote:
> >> On 05/08/2024 19:07, Bjorn Andersson wrote:
> >>> On Mon, Aug 05, 2024 at 09:41:26AM +0530, Krishna Chaitanya Chundru wrote:
> >>>> On 8/4/2024 2:23 PM, Krzysztof Kozlowski wrote:
> >>>>> On 03/08/2024 05:22, Krishna chaitanya chundru wrote:
> >>>>>> diff --git a/Documentation/devicetree/bindings/pci/qcom,qps615.yaml b/Documentation/devicetree/bindings/pci/qcom,qps615.yaml
> >>> [..]
> >>>>>> + qps615,axi-clk-freq-hz:
> >>>>>> + description:
> >>>>>> + AXI clock which internal bus of the switch.
> >>>>>
> >>>>> No need, use CCF.
> >>>>>
> >>>> ack
> >>>
> >>> This is a clock that's internal to the QPS615, so there's no clock
> >>> controller involved and hence I don't think CCF is applicable.
> >>
> >> AXI does not sound that internal.
> >
> > Well, AXI is applicable to whatever entity that implements it. We mostly seen it
> > in ARM SoCs (host), but in this case the PCIe switch also has a microcontroller
> > /processor of some sort, so AXI is indeed relevant for it. The naming actually
> > comes from the switch's i2c register name that is being configured in the driver
> > based on this property value.
> >
> >> DT rarely needs to specify internal
> >> clock rates. What if you want to define rates for 20 clocks? Even
> >> clock-frequency is deprecated, so why this would be allowed?
> >> bus-frequency is allowed for buses, but that's not the case here, I guess?
> >>
> >
> > This clock frequency is for the switch's internal AXI bus that runs at default
> > 200MHz. And this property is used to specify a frequency that is configured over
> > the i2c interface so that the switch's AXI bus can operate in a low frequency
> > there by reducing the power consumption of the switch.
> >
> > It is not strictly needed for the switch operation, but for power optimization.
> > So this property can also be dropped for the initial submission and added later
> > if you prefer.
>
> So if the clock rate can change, why this is static in DTB? Or why this
> is configurable per-board?
>
Because, board manufacturers can change the frequency depending on the switch
configuration (enablement of DSP's etc...)
> There is a reason why clock-frequency property is not welcomed and you
> are re-implementing it.
>
Hmm, I'm not aware that 'clock-frequency' is not encouraged these days. So you
are suggesting to change the rate in the driver itself based on the switch
configuration? If so, what difference does it make?
And no more *-freq properties are allowed?
- Mani
--
மணிவண்ணன் சதாசிவம்
^ permalink raw reply [flat|nested] 77+ messages in thread
* Re: [PATCH v2 1/8] dt-bindings: PCI: Add binding for qps615
2024-08-08 12:41 ` Manivannan Sadhasivam
@ 2024-08-08 13:06 ` Krzysztof Kozlowski
2024-08-08 13:29 ` Manivannan Sadhasivam
2024-08-22 14:09 ` Manivannan Sadhasivam
0 siblings, 2 replies; 77+ messages in thread
From: Krzysztof Kozlowski @ 2024-08-08 13:06 UTC (permalink / raw)
To: Manivannan Sadhasivam
Cc: Bjorn Andersson, Krishna Chaitanya Chundru, Lorenzo Pieralisi,
Krzysztof Wilczyński, Rob Herring, Bjorn Helgaas,
Krzysztof Kozlowski, Conor Dooley, Konrad Dybcio,
cros-qcom-dts-watchers, Bartosz Golaszewski, Jingoo Han,
andersson, quic_vbadigan, linux-arm-msm, linux-pci, devicetree,
linux-kernel, Bartosz Golaszewski
On 08/08/2024 14:41, Manivannan Sadhasivam wrote:
> On Thu, Aug 08, 2024 at 02:13:01PM +0200, Krzysztof Kozlowski wrote:
>> On 08/08/2024 14:01, Manivannan Sadhasivam wrote:
>>> On Mon, Aug 05, 2024 at 07:18:04PM +0200, Krzysztof Kozlowski wrote:
>>>> On 05/08/2024 19:07, Bjorn Andersson wrote:
>>>>> On Mon, Aug 05, 2024 at 09:41:26AM +0530, Krishna Chaitanya Chundru wrote:
>>>>>> On 8/4/2024 2:23 PM, Krzysztof Kozlowski wrote:
>>>>>>> On 03/08/2024 05:22, Krishna chaitanya chundru wrote:
>>>>>>>> diff --git a/Documentation/devicetree/bindings/pci/qcom,qps615.yaml b/Documentation/devicetree/bindings/pci/qcom,qps615.yaml
>>>>> [..]
>>>>>>>> + qps615,axi-clk-freq-hz:
>>>>>>>> + description:
>>>>>>>> + AXI clock which internal bus of the switch.
>>>>>>>
>>>>>>> No need, use CCF.
>>>>>>>
>>>>>> ack
>>>>>
>>>>> This is a clock that's internal to the QPS615, so there's no clock
>>>>> controller involved and hence I don't think CCF is applicable.
>>>>
>>>> AXI does not sound that internal.
>>>
>>> Well, AXI is applicable to whatever entity that implements it. We mostly seen it
>>> in ARM SoCs (host), but in this case the PCIe switch also has a microcontroller
>>> /processor of some sort, so AXI is indeed relevant for it. The naming actually
>>> comes from the switch's i2c register name that is being configured in the driver
>>> based on this property value.
>>>
>>>> DT rarely needs to specify internal
>>>> clock rates. What if you want to define rates for 20 clocks? Even
>>>> clock-frequency is deprecated, so why this would be allowed?
>>>> bus-frequency is allowed for buses, but that's not the case here, I guess?
>>>>
>>>
>>> This clock frequency is for the switch's internal AXI bus that runs at default
>>> 200MHz. And this property is used to specify a frequency that is configured over
>>> the i2c interface so that the switch's AXI bus can operate in a low frequency
>>> there by reducing the power consumption of the switch.
>>>
>>> It is not strictly needed for the switch operation, but for power optimization.
>>> So this property can also be dropped for the initial submission and added later
>>> if you prefer.
>>
>> So if the clock rate can change, why this is static in DTB? Or why this
>> is configurable per-board?
>>
>
> Because, board manufacturers can change the frequency depending on the switch
> configuration (enablement of DSP's etc...)
>
>> There is a reason why clock-frequency property is not welcomed and you
>> are re-implementing it.
>>
>
> Hmm, I'm not aware that 'clock-frequency' is not encouraged these days. So you
> are suggesting to change the rate in the driver itself based on the switch
> configuration? If so, what difference does it make?
Based on the switch, other clocks, votes etc. whatever is reasonable
there. In most cases, not sure if this one here as well, devices can
operate on different clock frequencies thus specifying fixed frequency
in the DTS is simplification and lack of flexibility. It is chosen by
people only because it is easier for them but then they come back with
ABI issues when it turns out they need to switch to some dynamic control.
>
> And no more *-freq properties are allowed?
bus-frequency is allowed for busses.
Best regards,
Krzysztof
^ permalink raw reply [flat|nested] 77+ messages in thread
* Re: [PATCH v2 1/8] dt-bindings: PCI: Add binding for qps615
2024-08-08 13:06 ` Krzysztof Kozlowski
@ 2024-08-08 13:29 ` Manivannan Sadhasivam
2024-08-22 14:09 ` Manivannan Sadhasivam
1 sibling, 0 replies; 77+ messages in thread
From: Manivannan Sadhasivam @ 2024-08-08 13:29 UTC (permalink / raw)
To: Krzysztof Kozlowski, Krishna Chaitanya Chundru
Cc: Bjorn Andersson, Krishna Chaitanya Chundru, Lorenzo Pieralisi,
Krzysztof Wilczyński, Rob Herring, Bjorn Helgaas,
Krzysztof Kozlowski, Conor Dooley, Konrad Dybcio,
cros-qcom-dts-watchers, Bartosz Golaszewski, Jingoo Han,
andersson, quic_vbadigan, linux-arm-msm, linux-pci, devicetree,
linux-kernel, Bartosz Golaszewski
On Thu, Aug 08, 2024 at 03:06:28PM +0200, Krzysztof Kozlowski wrote:
> On 08/08/2024 14:41, Manivannan Sadhasivam wrote:
> > On Thu, Aug 08, 2024 at 02:13:01PM +0200, Krzysztof Kozlowski wrote:
> >> On 08/08/2024 14:01, Manivannan Sadhasivam wrote:
> >>> On Mon, Aug 05, 2024 at 07:18:04PM +0200, Krzysztof Kozlowski wrote:
> >>>> On 05/08/2024 19:07, Bjorn Andersson wrote:
> >>>>> On Mon, Aug 05, 2024 at 09:41:26AM +0530, Krishna Chaitanya Chundru wrote:
> >>>>>> On 8/4/2024 2:23 PM, Krzysztof Kozlowski wrote:
> >>>>>>> On 03/08/2024 05:22, Krishna chaitanya chundru wrote:
> >>>>>>>> diff --git a/Documentation/devicetree/bindings/pci/qcom,qps615.yaml b/Documentation/devicetree/bindings/pci/qcom,qps615.yaml
> >>>>> [..]
> >>>>>>>> + qps615,axi-clk-freq-hz:
> >>>>>>>> + description:
> >>>>>>>> + AXI clock which internal bus of the switch.
> >>>>>>>
> >>>>>>> No need, use CCF.
> >>>>>>>
> >>>>>> ack
> >>>>>
> >>>>> This is a clock that's internal to the QPS615, so there's no clock
> >>>>> controller involved and hence I don't think CCF is applicable.
> >>>>
> >>>> AXI does not sound that internal.
> >>>
> >>> Well, AXI is applicable to whatever entity that implements it. We mostly seen it
> >>> in ARM SoCs (host), but in this case the PCIe switch also has a microcontroller
> >>> /processor of some sort, so AXI is indeed relevant for it. The naming actually
> >>> comes from the switch's i2c register name that is being configured in the driver
> >>> based on this property value.
> >>>
> >>>> DT rarely needs to specify internal
> >>>> clock rates. What if you want to define rates for 20 clocks? Even
> >>>> clock-frequency is deprecated, so why this would be allowed?
> >>>> bus-frequency is allowed for buses, but that's not the case here, I guess?
> >>>>
> >>>
> >>> This clock frequency is for the switch's internal AXI bus that runs at default
> >>> 200MHz. And this property is used to specify a frequency that is configured over
> >>> the i2c interface so that the switch's AXI bus can operate in a low frequency
> >>> there by reducing the power consumption of the switch.
> >>>
> >>> It is not strictly needed for the switch operation, but for power optimization.
> >>> So this property can also be dropped for the initial submission and added later
> >>> if you prefer.
> >>
> >> So if the clock rate can change, why this is static in DTB? Or why this
> >> is configurable per-board?
> >>
> >
> > Because, board manufacturers can change the frequency depending on the switch
> > configuration (enablement of DSP's etc...)
> >
> >> There is a reason why clock-frequency property is not welcomed and you
> >> are re-implementing it.
> >>
> >
> > Hmm, I'm not aware that 'clock-frequency' is not encouraged these days. So you
> > are suggesting to change the rate in the driver itself based on the switch
> > configuration? If so, what difference does it make?
>
> Based on the switch, other clocks, votes etc. whatever is reasonable
> there. In most cases, not sure if this one here as well, devices can
> operate on different clock frequencies thus specifying fixed frequency
> in the DTS is simplification and lack of flexibility. It is chosen by
> people only because it is easier for them but then they come back with
> ABI issues when it turns out they need to switch to some dynamic control.
>
Atleast in this case, the requirement is to just set the frequency based on
switch configuration and not change it dynamically.
Krishna, is it possible to set the freq in driver by detecting the switch
configuration? I believe the freq is based on number of DSPs enabled?
> >
> > And no more *-freq properties are allowed?
>
> bus-frequency is allowed for busses.
>
Okay.
- Mani
--
மணிவண்ணன் சதாசிவம்
^ permalink raw reply [flat|nested] 77+ messages in thread
* Re: [PATCH v2 4/8] PCI: Change the parent to correctly represent pcie hierarchy
2024-08-03 3:22 ` [PATCH v2 4/8] PCI: Change the parent to correctly represent pcie hierarchy Krishna chaitanya chundru
2024-08-06 19:07 ` Bjorn Helgaas
@ 2024-08-13 19:15 ` Bartosz Golaszewski
2024-08-22 19:28 ` Bjorn Helgaas
2024-08-23 7:23 ` Manivannan Sadhasivam
2 siblings, 1 reply; 77+ messages in thread
From: Bartosz Golaszewski @ 2024-08-13 19:15 UTC (permalink / raw)
To: Krishna chaitanya chundru
Cc: Lorenzo Pieralisi, Krzysztof Wilczyński, Rob Herring,
Bjorn Helgaas, Krzysztof Kozlowski, Conor Dooley, Konrad Dybcio,
cros-qcom-dts-watchers, Jingoo Han, Manivannan Sadhasivam,
andersson, quic_vbadigan, linux-arm-msm, linux-pci, devicetree,
linux-kernel, Bartosz Golaszewski
On Sat, Aug 3, 2024 at 5:23 AM Krishna chaitanya chundru
<quic_krichai@quicinc.com> wrote:
>
> Currently the pwrctl driver is child of pci-pci bridge driver,
> this will cause issue when suspend resume is introduced in the pwr
> control driver. If the supply is removed to the endpoint in the
> power control driver then the config space access by the
> pci-pci bridge driver can cause issues like Timeouts.
>
> For this reason change the parent to controller from pci-pci bridge.
>
> Fixes: 4565d2652a37 ("PCI/pwrctl: Add PCI power control core code")
> Signed-off-by: Krishna chaitanya chundru <quic_krichai@quicinc.com>
> ---
Tested-by: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>
Bjorn,
I think this should go into v6.11 as it does indeed better represent
the underlying logic.
Bart
^ permalink raw reply [flat|nested] 77+ messages in thread
* Re: [PATCH v2 1/8] dt-bindings: PCI: Add binding for qps615
2024-08-08 13:06 ` Krzysztof Kozlowski
2024-08-08 13:29 ` Manivannan Sadhasivam
@ 2024-08-22 14:09 ` Manivannan Sadhasivam
2024-08-23 9:06 ` Krzysztof Kozlowski
1 sibling, 1 reply; 77+ messages in thread
From: Manivannan Sadhasivam @ 2024-08-22 14:09 UTC (permalink / raw)
To: Krzysztof Kozlowski
Cc: Bjorn Andersson, Krishna Chaitanya Chundru, Lorenzo Pieralisi,
Krzysztof Wilczyński, Rob Herring, Bjorn Helgaas,
Krzysztof Kozlowski, Conor Dooley, Konrad Dybcio,
cros-qcom-dts-watchers, Bartosz Golaszewski, Jingoo Han,
andersson, quic_vbadigan, linux-arm-msm, linux-pci, devicetree,
linux-kernel, Bartosz Golaszewski
On Thu, Aug 08, 2024 at 03:06:28PM +0200, Krzysztof Kozlowski wrote:
> On 08/08/2024 14:41, Manivannan Sadhasivam wrote:
> > On Thu, Aug 08, 2024 at 02:13:01PM +0200, Krzysztof Kozlowski wrote:
> >> On 08/08/2024 14:01, Manivannan Sadhasivam wrote:
> >>> On Mon, Aug 05, 2024 at 07:18:04PM +0200, Krzysztof Kozlowski wrote:
> >>>> On 05/08/2024 19:07, Bjorn Andersson wrote:
> >>>>> On Mon, Aug 05, 2024 at 09:41:26AM +0530, Krishna Chaitanya Chundru wrote:
> >>>>>> On 8/4/2024 2:23 PM, Krzysztof Kozlowski wrote:
> >>>>>>> On 03/08/2024 05:22, Krishna chaitanya chundru wrote:
> >>>>>>>> diff --git a/Documentation/devicetree/bindings/pci/qcom,qps615.yaml b/Documentation/devicetree/bindings/pci/qcom,qps615.yaml
> >>>>> [..]
> >>>>>>>> + qps615,axi-clk-freq-hz:
> >>>>>>>> + description:
> >>>>>>>> + AXI clock which internal bus of the switch.
> >>>>>>>
> >>>>>>> No need, use CCF.
> >>>>>>>
> >>>>>> ack
> >>>>>
> >>>>> This is a clock that's internal to the QPS615, so there's no clock
> >>>>> controller involved and hence I don't think CCF is applicable.
> >>>>
> >>>> AXI does not sound that internal.
> >>>
> >>> Well, AXI is applicable to whatever entity that implements it. We mostly seen it
> >>> in ARM SoCs (host), but in this case the PCIe switch also has a microcontroller
> >>> /processor of some sort, so AXI is indeed relevant for it. The naming actually
> >>> comes from the switch's i2c register name that is being configured in the driver
> >>> based on this property value.
> >>>
> >>>> DT rarely needs to specify internal
> >>>> clock rates. What if you want to define rates for 20 clocks? Even
> >>>> clock-frequency is deprecated, so why this would be allowed?
> >>>> bus-frequency is allowed for buses, but that's not the case here, I guess?
> >>>>
> >>>
> >>> This clock frequency is for the switch's internal AXI bus that runs at default
> >>> 200MHz. And this property is used to specify a frequency that is configured over
> >>> the i2c interface so that the switch's AXI bus can operate in a low frequency
> >>> there by reducing the power consumption of the switch.
> >>>
> >>> It is not strictly needed for the switch operation, but for power optimization.
> >>> So this property can also be dropped for the initial submission and added later
> >>> if you prefer.
> >>
> >> So if the clock rate can change, why this is static in DTB? Or why this
> >> is configurable per-board?
> >>
> >
> > Because, board manufacturers can change the frequency depending on the switch
> > configuration (enablement of DSP's etc...)
> >
> >> There is a reason why clock-frequency property is not welcomed and you
> >> are re-implementing it.
> >>
> >
> > Hmm, I'm not aware that 'clock-frequency' is not encouraged these days. So you
> > are suggesting to change the rate in the driver itself based on the switch
> > configuration? If so, what difference does it make?
>
> Based on the switch, other clocks, votes etc. whatever is reasonable
> there. In most cases, not sure if this one here as well, devices can
> operate on different clock frequencies thus specifying fixed frequency
> in the DTS is simplification and lack of flexibility. It is chosen by
> people only because it is easier for them but then they come back with
> ABI issues when it turns out they need to switch to some dynamic control.
>
Atleast for this device, this frequency is going to be static. Because, the
device itself cannot change the frequency, only the host driver can. That too is
only possible before enumerating the device. So there is no way the frequency is
going to change dynamically.
- Mani
--
மணிவண்ணன் சதாசிவம்
^ permalink raw reply [flat|nested] 77+ messages in thread
* Re: [PATCH v2 1/8] dt-bindings: PCI: Add binding for qps615
2024-08-05 14:43 ` Krzysztof Kozlowski
@ 2024-08-22 14:16 ` Manivannan Sadhasivam
2024-08-23 9:01 ` Krzysztof Kozlowski
0 siblings, 1 reply; 77+ messages in thread
From: Manivannan Sadhasivam @ 2024-08-22 14:16 UTC (permalink / raw)
To: Krzysztof Kozlowski
Cc: Krishna Chaitanya Chundru, Lorenzo Pieralisi,
Krzysztof Wilczyński, Rob Herring, Bjorn Helgaas,
Krzysztof Kozlowski, Conor Dooley, Konrad Dybcio,
cros-qcom-dts-watchers, Bartosz Golaszewski, Jingoo Han,
andersson, quic_vbadigan, linux-arm-msm, linux-pci, devicetree,
linux-kernel, Bartosz Golaszewski
On Mon, Aug 05, 2024 at 04:43:47PM +0200, Krzysztof Kozlowski wrote:
> On 05/08/2024 07:57, Krishna Chaitanya Chundru wrote:
> >>
> > Hi Krzysztof,
> >
> > QPS615 has a 3 downstream ports and 1 upstream port as described below
> > diagram.
> > For this entire switch there are some supplies which we described in the
> > dt-binding (vdd18-supply, vdd09-supply etc) and one GPIO which controls
> > reset of the switch (reset-gpio). The switch hardware can configure the
> > individual ports DSP0, DSP1, DSP2, upstream port and also one integrated
> > ethernet endpoint which is connected to DSP2(I didn't mentioned in the
> > diagram) through I2C.
> >
> > The properties other than supplies,i2c client, reset gpio which
> > are added will be applicable for all the ports.
> > _______________________________________________________________
> > | |i2c| QPS615 |Supplies||Resx gpio |
> > | |___| _________________ |________||__________|
> > | ________________| Upstream port |_____________ |
> > | | |_______________| | |
> > | | | | |
> > | | | | |
> > | ____|_____ ____|_____ ___|____ |
> > | |DSP 0 | | DSP 1 | | DSP 2| |
> > | |________| |________| |______| |
> > |_____________________________________________________________|
> >
>
> I don't get why then properties should apply to main device node.
>
The problem here is, we cannot differentiate between main device node and the
upstream node. Typically the differentiation is not needed because no one cared
about configuring the upstream port. But this PCIe switch is special (as like
most of the Qcom peripherals).
I agree that if we don't differentiate then it also implies that all main node
properties are applicable to upstream port and vice versa. But AFAIK, upstream
port is often considered as the _device_ itself as it shares the same bus
number.
- Mani
--
மணிவண்ணன் சதாசிவம்
^ permalink raw reply [flat|nested] 77+ messages in thread
* Re: [PATCH v2 4/8] PCI: Change the parent to correctly represent pcie hierarchy
2024-08-13 19:15 ` Bartosz Golaszewski
@ 2024-08-22 19:28 ` Bjorn Helgaas
2024-08-22 20:01 ` Bartosz Golaszewski
0 siblings, 1 reply; 77+ messages in thread
From: Bjorn Helgaas @ 2024-08-22 19:28 UTC (permalink / raw)
To: Bartosz Golaszewski
Cc: Krishna chaitanya chundru, Lorenzo Pieralisi,
Krzysztof Wilczyński, Rob Herring, Bjorn Helgaas,
Krzysztof Kozlowski, Conor Dooley, Konrad Dybcio,
cros-qcom-dts-watchers, Jingoo Han, Manivannan Sadhasivam,
andersson, quic_vbadigan, linux-arm-msm, linux-pci, devicetree,
linux-kernel, Bartosz Golaszewski
On Tue, Aug 13, 2024 at 09:15:06PM +0200, Bartosz Golaszewski wrote:
> On Sat, Aug 3, 2024 at 5:23 AM Krishna chaitanya chundru
> <quic_krichai@quicinc.com> wrote:
> >
> > Currently the pwrctl driver is child of pci-pci bridge driver,
> > this will cause issue when suspend resume is introduced in the pwr
> > control driver. If the supply is removed to the endpoint in the
> > power control driver then the config space access by the
> > pci-pci bridge driver can cause issues like Timeouts.
> >
> > For this reason change the parent to controller from pci-pci bridge.
> >
> > Fixes: 4565d2652a37 ("PCI/pwrctl: Add PCI power control core code")
> > Signed-off-by: Krishna chaitanya chundru <quic_krichai@quicinc.com>
> > ---
>
> Tested-by: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>
>
> Bjorn,
>
> I think this should go into v6.11 as it does indeed better represent
> the underlying logic.
Is this patch independent of the rest? I don't think the whole series
looks like v6.11 material, but if this patch can be applied
independently, *and* we can make a case in the commit log for why it
is v6.11 material, we can do that.
Right now the commit log doesn't tell me enough to justify a
post-merge window change.
Bjorn
^ permalink raw reply [flat|nested] 77+ messages in thread
* Re: [PATCH v2 4/8] PCI: Change the parent to correctly represent pcie hierarchy
2024-08-22 19:28 ` Bjorn Helgaas
@ 2024-08-22 20:01 ` Bartosz Golaszewski
2024-08-22 21:13 ` Bjorn Helgaas
0 siblings, 1 reply; 77+ messages in thread
From: Bartosz Golaszewski @ 2024-08-22 20:01 UTC (permalink / raw)
To: Bjorn Helgaas
Cc: Krishna chaitanya chundru, Lorenzo Pieralisi,
Krzysztof Wilczyński, Rob Herring, Bjorn Helgaas,
Krzysztof Kozlowski, Conor Dooley, Konrad Dybcio,
cros-qcom-dts-watchers, Jingoo Han, Manivannan Sadhasivam,
andersson, quic_vbadigan, linux-arm-msm, linux-pci, devicetree,
linux-kernel, Bartosz Golaszewski
On Thu, Aug 22, 2024 at 9:28 PM Bjorn Helgaas <helgaas@kernel.org> wrote:
>
> On Tue, Aug 13, 2024 at 09:15:06PM +0200, Bartosz Golaszewski wrote:
> > On Sat, Aug 3, 2024 at 5:23 AM Krishna chaitanya chundru
> > <quic_krichai@quicinc.com> wrote:
> > >
> > > Currently the pwrctl driver is child of pci-pci bridge driver,
> > > this will cause issue when suspend resume is introduced in the pwr
> > > control driver. If the supply is removed to the endpoint in the
> > > power control driver then the config space access by the
> > > pci-pci bridge driver can cause issues like Timeouts.
> > >
> > > For this reason change the parent to controller from pci-pci bridge.
> > >
> > > Fixes: 4565d2652a37 ("PCI/pwrctl: Add PCI power control core code")
> > > Signed-off-by: Krishna chaitanya chundru <quic_krichai@quicinc.com>
> > > ---
> >
> > Tested-by: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>
> >
> > Bjorn,
> >
> > I think this should go into v6.11 as it does indeed better represent
> > the underlying logic.
>
> Is this patch independent of the rest? I don't think the whole series
> looks like v6.11 material, but if this patch can be applied
> independently, *and* we can make a case in the commit log for why it
> is v6.11 material, we can do that.
>
> Right now the commit log doesn't tell me enough to justify a
> post-merge window change.
>
> Bjorn
Please, apply this patch independently. FYI I have a WiP branch[1]
with a v3 of the fixes series rebased on top of this one. Manivannan
and I are working on fixing one last remaining issue and I'll resend
it. This should go into v6.11.
Bart
[1] https://git.codelinaro.org/bartosz_golaszewski/linux/-/tree/topic/pci-pwrctl-fixes
^ permalink raw reply [flat|nested] 77+ messages in thread
* Re: [PATCH v2 4/8] PCI: Change the parent to correctly represent pcie hierarchy
2024-08-22 20:01 ` Bartosz Golaszewski
@ 2024-08-22 21:13 ` Bjorn Helgaas
2024-08-23 8:30 ` Manivannan Sadhasivam
0 siblings, 1 reply; 77+ messages in thread
From: Bjorn Helgaas @ 2024-08-22 21:13 UTC (permalink / raw)
To: Bartosz Golaszewski
Cc: Krishna chaitanya chundru, Lorenzo Pieralisi,
Krzysztof Wilczyński, Rob Herring, Bjorn Helgaas,
Krzysztof Kozlowski, Conor Dooley, Konrad Dybcio,
cros-qcom-dts-watchers, Jingoo Han, Manivannan Sadhasivam,
andersson, quic_vbadigan, linux-arm-msm, linux-pci, devicetree,
linux-kernel, Bartosz Golaszewski
On Thu, Aug 22, 2024 at 10:01:04PM +0200, Bartosz Golaszewski wrote:
> On Thu, Aug 22, 2024 at 9:28 PM Bjorn Helgaas <helgaas@kernel.org> wrote:
> >
> > On Tue, Aug 13, 2024 at 09:15:06PM +0200, Bartosz Golaszewski wrote:
> > > On Sat, Aug 3, 2024 at 5:23 AM Krishna chaitanya chundru
> > > <quic_krichai@quicinc.com> wrote:
> > > >
> > > > Currently the pwrctl driver is child of pci-pci bridge driver,
> > > > this will cause issue when suspend resume is introduced in the pwr
> > > > control driver. If the supply is removed to the endpoint in the
> > > > power control driver then the config space access by the
> > > > pci-pci bridge driver can cause issues like Timeouts.
> > > >
> > > > For this reason change the parent to controller from pci-pci bridge.
> > > >
> > > > Fixes: 4565d2652a37 ("PCI/pwrctl: Add PCI power control core code")
> > > > Signed-off-by: Krishna chaitanya chundru <quic_krichai@quicinc.com>
> > > > ---
> > >
> > > Tested-by: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>
> > >
> > > Bjorn,
> > >
> > > I think this should go into v6.11 as it does indeed better represent
> > > the underlying logic.
> >
> > Is this patch independent of the rest? I don't think the whole series
> > looks like v6.11 material, but if this patch can be applied
> > independently, *and* we can make a case in the commit log for why it
> > is v6.11 material, we can do that.
> >
> > Right now the commit log doesn't tell me enough to justify a
> > post-merge window change.
>
> Please, apply this patch independently. FYI I have a WiP branch[1]
> with a v3 of the fixes series rebased on top of this one. Manivannan
> and I are working on fixing one last remaining issue and I'll resend
> it. This should go into v6.11.
OK. I just need to be able to justify *why* we need it in v6.11, so I
can apply it as soon as somebody supplies that kind of text for the
commit log. I.e., what is broken without this change? What bad
things happen if we defer it to v6.12?
> [1] https://git.codelinaro.org/bartosz_golaszewski/linux/-/tree/topic/pci-pwrctl-fixes
^ permalink raw reply [flat|nested] 77+ messages in thread
* Re: [PATCH v2 4/8] PCI: Change the parent to correctly represent pcie hierarchy
2024-08-03 3:22 ` [PATCH v2 4/8] PCI: Change the parent to correctly represent pcie hierarchy Krishna chaitanya chundru
2024-08-06 19:07 ` Bjorn Helgaas
2024-08-13 19:15 ` Bartosz Golaszewski
@ 2024-08-23 7:23 ` Manivannan Sadhasivam
2 siblings, 0 replies; 77+ messages in thread
From: Manivannan Sadhasivam @ 2024-08-23 7:23 UTC (permalink / raw)
To: Krishna chaitanya chundru
Cc: Lorenzo Pieralisi, Krzysztof Wilczyński, Rob Herring,
Bjorn Helgaas, Krzysztof Kozlowski, Conor Dooley, Konrad Dybcio,
cros-qcom-dts-watchers, Bartosz Golaszewski, Jingoo Han,
andersson, quic_vbadigan, linux-arm-msm, linux-pci, devicetree,
linux-kernel, Bartosz Golaszewski
On Sat, Aug 03, 2024 at 08:52:50AM +0530, Krishna chaitanya chundru wrote:
> Currently the pwrctl driver is child of pci-pci bridge driver,
> this will cause issue when suspend resume is introduced in the pwr
> control driver. If the supply is removed to the endpoint in the
> power control driver then the config space access by the
> pci-pci bridge driver can cause issues like Timeouts.
>
> For this reason change the parent to controller from pci-pci bridge.
>
Also, what if the PCIe controller driver tries to access the device? Like for
sending PME_Turn_Off etc... during suspend? I think you should also make sure
that the suspend callback of the pwrctl driver has to happen _after_ the
controller driver.
Still the parent-child hierarchy is not going to change, but only the devlink
part.
- Mani
> Fixes: 4565d2652a37 ("PCI/pwrctl: Add PCI power control core code")
> Signed-off-by: Krishna chaitanya chundru <quic_krichai@quicinc.com>
> ---
> drivers/pci/bus.c | 3 ++-
> drivers/pci/pwrctl/core.c | 9 ++++++++-
> 2 files changed, 10 insertions(+), 2 deletions(-)
>
> diff --git a/drivers/pci/bus.c b/drivers/pci/bus.c
> index 55c853686051..15b42f0f588f 100644
> --- a/drivers/pci/bus.c
> +++ b/drivers/pci/bus.c
> @@ -328,6 +328,7 @@ void __weak pcibios_bus_add_device(struct pci_dev *pdev) { }
> */
> void pci_bus_add_device(struct pci_dev *dev)
> {
> + struct pci_host_bridge *host = pci_find_host_bridge(dev->bus);
> struct device_node *dn = dev->dev.of_node;
> int retval;
>
> @@ -352,7 +353,7 @@ void pci_bus_add_device(struct pci_dev *dev)
>
> if (dev_of_node(&dev->dev) && pci_is_bridge(dev)) {
> retval = of_platform_populate(dev_of_node(&dev->dev), NULL, NULL,
> - &dev->dev);
> + host->dev.parent);
> if (retval)
> pci_err(dev, "failed to populate child OF nodes (%d)\n",
> retval);
> diff --git a/drivers/pci/pwrctl/core.c b/drivers/pci/pwrctl/core.c
> index feca26ad2f6a..4f2ffa0b0a5f 100644
> --- a/drivers/pci/pwrctl/core.c
> +++ b/drivers/pci/pwrctl/core.c
> @@ -11,6 +11,8 @@
> #include <linux/property.h>
> #include <linux/slab.h>
>
> +#include "../pci.h"
> +
> static int pci_pwrctl_notify(struct notifier_block *nb, unsigned long action,
> void *data)
> {
> @@ -64,18 +66,23 @@ static int pci_pwrctl_notify(struct notifier_block *nb, unsigned long action,
> */
> int pci_pwrctl_device_set_ready(struct pci_pwrctl *pwrctl)
> {
> + struct pci_bus *bus;
> int ret;
>
> if (!pwrctl->dev)
> return -ENODEV;
>
> + bus = pci_find_bus(of_get_pci_domain_nr(pwrctl->dev->parent->of_node), 0);
> + if (!bus)
> + return -ENODEV;
> +
> pwrctl->nb.notifier_call = pci_pwrctl_notify;
> ret = bus_register_notifier(&pci_bus_type, &pwrctl->nb);
> if (ret)
> return ret;
>
> pci_lock_rescan_remove();
> - pci_rescan_bus(to_pci_dev(pwrctl->dev->parent)->bus);
> + pci_rescan_bus(bus);
> pci_unlock_rescan_remove();
>
> return 0;
>
> --
> 2.34.1
>
--
மணிவண்ணன் சதாசிவம்
^ permalink raw reply [flat|nested] 77+ messages in thread
* Re: [PATCH v2 4/8] PCI: Change the parent to correctly represent pcie hierarchy
2024-08-22 21:13 ` Bjorn Helgaas
@ 2024-08-23 8:30 ` Manivannan Sadhasivam
2024-08-23 8:31 ` Bartosz Golaszewski
0 siblings, 1 reply; 77+ messages in thread
From: Manivannan Sadhasivam @ 2024-08-23 8:30 UTC (permalink / raw)
To: Bjorn Helgaas
Cc: Bartosz Golaszewski, Krishna chaitanya chundru, Lorenzo Pieralisi,
Krzysztof Wilczyński, Rob Herring, Bjorn Helgaas,
Krzysztof Kozlowski, Conor Dooley, Konrad Dybcio,
cros-qcom-dts-watchers, Jingoo Han, andersson, quic_vbadigan,
linux-arm-msm, linux-pci, devicetree, linux-kernel,
Bartosz Golaszewski
On Thu, Aug 22, 2024 at 04:13:36PM -0500, Bjorn Helgaas wrote:
> On Thu, Aug 22, 2024 at 10:01:04PM +0200, Bartosz Golaszewski wrote:
> > On Thu, Aug 22, 2024 at 9:28 PM Bjorn Helgaas <helgaas@kernel.org> wrote:
> > >
> > > On Tue, Aug 13, 2024 at 09:15:06PM +0200, Bartosz Golaszewski wrote:
> > > > On Sat, Aug 3, 2024 at 5:23 AM Krishna chaitanya chundru
> > > > <quic_krichai@quicinc.com> wrote:
> > > > >
> > > > > Currently the pwrctl driver is child of pci-pci bridge driver,
> > > > > this will cause issue when suspend resume is introduced in the pwr
> > > > > control driver. If the supply is removed to the endpoint in the
> > > > > power control driver then the config space access by the
> > > > > pci-pci bridge driver can cause issues like Timeouts.
> > > > >
> > > > > For this reason change the parent to controller from pci-pci bridge.
> > > > >
> > > > > Fixes: 4565d2652a37 ("PCI/pwrctl: Add PCI power control core code")
> > > > > Signed-off-by: Krishna chaitanya chundru <quic_krichai@quicinc.com>
> > > > > ---
> > > >
> > > > Tested-by: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>
> > > >
> > > > Bjorn,
> > > >
> > > > I think this should go into v6.11 as it does indeed better represent
> > > > the underlying logic.
> > >
> > > Is this patch independent of the rest? I don't think the whole series
> > > looks like v6.11 material, but if this patch can be applied
> > > independently, *and* we can make a case in the commit log for why it
> > > is v6.11 material, we can do that.
> > >
> > > Right now the commit log doesn't tell me enough to justify a
> > > post-merge window change.
> >
> > Please, apply this patch independently. FYI I have a WiP branch[1]
> > with a v3 of the fixes series rebased on top of this one. Manivannan
> > and I are working on fixing one last remaining issue and I'll resend
> > it. This should go into v6.11.
>
> OK. I just need to be able to justify *why* we need it in v6.11, so I
> can apply it as soon as somebody supplies that kind of text for the
> commit log. I.e., what is broken without this change? What bad
> things happen if we defer it to v6.12?
>
I'm not sure if this is a 6.11 material as this patch is not fixing any crash or
potential breakage in 6.11. This patch changes the hierarchy in such a way that
the suspend/resume could work fine once added in the pwrctl drivers.
At the same time, I'd like to get it merged separately for 6.12 instead of
bundling it in this same series.
- Mani
--
மணிவண்ணன் சதாசிவம்
^ permalink raw reply [flat|nested] 77+ messages in thread
* Re: [PATCH v2 4/8] PCI: Change the parent to correctly represent pcie hierarchy
2024-08-23 8:30 ` Manivannan Sadhasivam
@ 2024-08-23 8:31 ` Bartosz Golaszewski
0 siblings, 0 replies; 77+ messages in thread
From: Bartosz Golaszewski @ 2024-08-23 8:31 UTC (permalink / raw)
To: Manivannan Sadhasivam
Cc: Bjorn Helgaas, Bartosz Golaszewski, Krishna chaitanya chundru,
Lorenzo Pieralisi, Krzysztof Wilczyński, Rob Herring,
Bjorn Helgaas, Krzysztof Kozlowski, Conor Dooley, Konrad Dybcio,
cros-qcom-dts-watchers, Jingoo Han, andersson, quic_vbadigan,
linux-arm-msm, linux-pci, devicetree, linux-kernel
On Fri, 23 Aug 2024 at 10:30, Manivannan Sadhasivam
<manivannan.sadhasivam@linaro.org> wrote:
>
> > > >
> > > > Right now the commit log doesn't tell me enough to justify a
> > > > post-merge window change.
> > >
> > > Please, apply this patch independently. FYI I have a WiP branch[1]
> > > with a v3 of the fixes series rebased on top of this one. Manivannan
> > > and I are working on fixing one last remaining issue and I'll resend
> > > it. This should go into v6.11.
> >
> > OK. I just need to be able to justify *why* we need it in v6.11, so I
> > can apply it as soon as somebody supplies that kind of text for the
> > commit log. I.e., what is broken without this change? What bad
> > things happen if we defer it to v6.12?
> >
>
> I'm not sure if this is a 6.11 material as this patch is not fixing any crash or
> potential breakage in 6.11. This patch changes the hierarchy in such a way that
> the suspend/resume could work fine once added in the pwrctl drivers.
>
> At the same time, I'd like to get it merged separately for 6.12 instead of
> bundling it in this same series.
>
Ok, I'll find a way to rework my patches so that this one's not needed.
Bart
^ permalink raw reply [flat|nested] 77+ messages in thread
* Re: [PATCH v2 1/8] dt-bindings: PCI: Add binding for qps615
2024-08-22 14:16 ` Manivannan Sadhasivam
@ 2024-08-23 9:01 ` Krzysztof Kozlowski
2024-08-23 9:44 ` Manivannan Sadhasivam
0 siblings, 1 reply; 77+ messages in thread
From: Krzysztof Kozlowski @ 2024-08-23 9:01 UTC (permalink / raw)
To: Manivannan Sadhasivam
Cc: Krishna Chaitanya Chundru, Lorenzo Pieralisi,
Krzysztof Wilczyński, Rob Herring, Bjorn Helgaas,
Krzysztof Kozlowski, Conor Dooley, Konrad Dybcio,
cros-qcom-dts-watchers, Bartosz Golaszewski, Jingoo Han,
andersson, quic_vbadigan, linux-arm-msm, linux-pci, devicetree,
linux-kernel, Bartosz Golaszewski
On 22/08/2024 16:16, Manivannan Sadhasivam wrote:
> On Mon, Aug 05, 2024 at 04:43:47PM +0200, Krzysztof Kozlowski wrote:
>> On 05/08/2024 07:57, Krishna Chaitanya Chundru wrote:
>>>>
>>> Hi Krzysztof,
>>>
>>> QPS615 has a 3 downstream ports and 1 upstream port as described below
>>> diagram.
>>> For this entire switch there are some supplies which we described in the
>>> dt-binding (vdd18-supply, vdd09-supply etc) and one GPIO which controls
>>> reset of the switch (reset-gpio). The switch hardware can configure the
>>> individual ports DSP0, DSP1, DSP2, upstream port and also one integrated
>>> ethernet endpoint which is connected to DSP2(I didn't mentioned in the
>>> diagram) through I2C.
>>>
>>> The properties other than supplies,i2c client, reset gpio which
>>> are added will be applicable for all the ports.
>>> _______________________________________________________________
>>> | |i2c| QPS615 |Supplies||Resx gpio |
>>> | |___| _________________ |________||__________|
>>> | ________________| Upstream port |_____________ |
>>> | | |_______________| | |
>>> | | | | |
>>> | | | | |
>>> | ____|_____ ____|_____ ___|____ |
>>> | |DSP 0 | | DSP 1 | | DSP 2| |
>>> | |________| |________| |______| |
>>> |_____________________________________________________________|
>>>
>>
>> I don't get why then properties should apply to main device node.
>>
>
> The problem here is, we cannot differentiate between main device node and the
> upstream node. Typically the differentiation is not needed because no one cared
> about configuring the upstream port. But this PCIe switch is special (as like
> most of the Qcom peripherals).
>
> I agree that if we don't differentiate then it also implies that all main node
> properties are applicable to upstream port and vice versa. But AFAIK, upstream
> port is often considered as the _device_ itself as it shares the same bus
> number.
Well, above diagram shows supplies being part of the entire device, not
each port. That's confusing. Based on diagram, downstream ports do not
have any supplies... and what exactly do they supply? Let's look at
vdd18 and vdd09 which sound main supplies of the entire device. In
context of port: what exactly do they power? Which part of the port?
Best regards,
Krzysztof
^ permalink raw reply [flat|nested] 77+ messages in thread
* Re: [PATCH v2 1/8] dt-bindings: PCI: Add binding for qps615
2024-08-22 14:09 ` Manivannan Sadhasivam
@ 2024-08-23 9:06 ` Krzysztof Kozlowski
2024-08-23 9:40 ` Manivannan Sadhasivam
0 siblings, 1 reply; 77+ messages in thread
From: Krzysztof Kozlowski @ 2024-08-23 9:06 UTC (permalink / raw)
To: Manivannan Sadhasivam
Cc: Bjorn Andersson, Krishna Chaitanya Chundru, Lorenzo Pieralisi,
Krzysztof Wilczyński, Rob Herring, Bjorn Helgaas,
Krzysztof Kozlowski, Conor Dooley, Konrad Dybcio,
cros-qcom-dts-watchers, Bartosz Golaszewski, Jingoo Han,
andersson, quic_vbadigan, linux-arm-msm, linux-pci, devicetree,
linux-kernel, Bartosz Golaszewski
On 22/08/2024 16:09, Manivannan Sadhasivam wrote:
> On Thu, Aug 08, 2024 at 03:06:28PM +0200, Krzysztof Kozlowski wrote:
>> On 08/08/2024 14:41, Manivannan Sadhasivam wrote:
>>> On Thu, Aug 08, 2024 at 02:13:01PM +0200, Krzysztof Kozlowski wrote:
>>>> On 08/08/2024 14:01, Manivannan Sadhasivam wrote:
>>>>> On Mon, Aug 05, 2024 at 07:18:04PM +0200, Krzysztof Kozlowski wrote:
>>>>>> On 05/08/2024 19:07, Bjorn Andersson wrote:
>>>>>>> On Mon, Aug 05, 2024 at 09:41:26AM +0530, Krishna Chaitanya Chundru wrote:
>>>>>>>> On 8/4/2024 2:23 PM, Krzysztof Kozlowski wrote:
>>>>>>>>> On 03/08/2024 05:22, Krishna chaitanya chundru wrote:
>>>>>>>>>> diff --git a/Documentation/devicetree/bindings/pci/qcom,qps615.yaml b/Documentation/devicetree/bindings/pci/qcom,qps615.yaml
>>>>>>> [..]
>>>>>>>>>> + qps615,axi-clk-freq-hz:
>>>>>>>>>> + description:
>>>>>>>>>> + AXI clock which internal bus of the switch.
>>>>>>>>>
>>>>>>>>> No need, use CCF.
>>>>>>>>>
>>>>>>>> ack
>>>>>>>
>>>>>>> This is a clock that's internal to the QPS615, so there's no clock
>>>>>>> controller involved and hence I don't think CCF is applicable.
>>>>>>
>>>>>> AXI does not sound that internal.
>>>>>
>>>>> Well, AXI is applicable to whatever entity that implements it. We mostly seen it
>>>>> in ARM SoCs (host), but in this case the PCIe switch also has a microcontroller
>>>>> /processor of some sort, so AXI is indeed relevant for it. The naming actually
>>>>> comes from the switch's i2c register name that is being configured in the driver
>>>>> based on this property value.
>>>>>
>>>>>> DT rarely needs to specify internal
>>>>>> clock rates. What if you want to define rates for 20 clocks? Even
>>>>>> clock-frequency is deprecated, so why this would be allowed?
>>>>>> bus-frequency is allowed for buses, but that's not the case here, I guess?
>>>>>>
>>>>>
>>>>> This clock frequency is for the switch's internal AXI bus that runs at default
>>>>> 200MHz. And this property is used to specify a frequency that is configured over
>>>>> the i2c interface so that the switch's AXI bus can operate in a low frequency
>>>>> there by reducing the power consumption of the switch.
>>>>>
>>>>> It is not strictly needed for the switch operation, but for power optimization.
>>>>> So this property can also be dropped for the initial submission and added later
>>>>> if you prefer.
>>>>
>>>> So if the clock rate can change, why this is static in DTB? Or why this
>>>> is configurable per-board?
>>>>
>>>
>>> Because, board manufacturers can change the frequency depending on the switch
>>> configuration (enablement of DSP's etc...)
>>>
>>>> There is a reason why clock-frequency property is not welcomed and you
>>>> are re-implementing it.
>>>>
>>>
>>> Hmm, I'm not aware that 'clock-frequency' is not encouraged these days. So you
>>> are suggesting to change the rate in the driver itself based on the switch
>>> configuration? If so, what difference does it make?
>>
>> Based on the switch, other clocks, votes etc. whatever is reasonable
>> there. In most cases, not sure if this one here as well, devices can
>> operate on different clock frequencies thus specifying fixed frequency
>> in the DTS is simplification and lack of flexibility. It is chosen by
>> people only because it is easier for them but then they come back with
>> ABI issues when it turns out they need to switch to some dynamic control.
>>
>
> Atleast for this device, this frequency is going to be static. Because, the
> device itself cannot change the frequency, only the host driver can. That too is
> only possible before enumerating the device. So there is no way the frequency is
> going to change dynamically.
We have assigned-clocks properties for this... but there are no clock
inputs here, so maybe it is not applicable? What generates this internal
AXI clock? Does it have internal oscillator?
So many questions and nothing in the property description helps to
understand this.
Best regards,
Krzysztof
^ permalink raw reply [flat|nested] 77+ messages in thread
* Re: [PATCH v2 1/8] dt-bindings: PCI: Add binding for qps615
2024-08-23 9:06 ` Krzysztof Kozlowski
@ 2024-08-23 9:40 ` Manivannan Sadhasivam
0 siblings, 0 replies; 77+ messages in thread
From: Manivannan Sadhasivam @ 2024-08-23 9:40 UTC (permalink / raw)
To: Krzysztof Kozlowski
Cc: Bjorn Andersson, Krishna Chaitanya Chundru, Lorenzo Pieralisi,
Krzysztof Wilczyński, Rob Herring, Bjorn Helgaas,
Krzysztof Kozlowski, Conor Dooley, Konrad Dybcio,
cros-qcom-dts-watchers, Bartosz Golaszewski, Jingoo Han,
andersson, quic_vbadigan, linux-arm-msm, linux-pci, devicetree,
linux-kernel, Bartosz Golaszewski
On Fri, Aug 23, 2024 at 11:06:28AM +0200, Krzysztof Kozlowski wrote:
> On 22/08/2024 16:09, Manivannan Sadhasivam wrote:
> > On Thu, Aug 08, 2024 at 03:06:28PM +0200, Krzysztof Kozlowski wrote:
> >> On 08/08/2024 14:41, Manivannan Sadhasivam wrote:
> >>> On Thu, Aug 08, 2024 at 02:13:01PM +0200, Krzysztof Kozlowski wrote:
> >>>> On 08/08/2024 14:01, Manivannan Sadhasivam wrote:
> >>>>> On Mon, Aug 05, 2024 at 07:18:04PM +0200, Krzysztof Kozlowski wrote:
> >>>>>> On 05/08/2024 19:07, Bjorn Andersson wrote:
> >>>>>>> On Mon, Aug 05, 2024 at 09:41:26AM +0530, Krishna Chaitanya Chundru wrote:
> >>>>>>>> On 8/4/2024 2:23 PM, Krzysztof Kozlowski wrote:
> >>>>>>>>> On 03/08/2024 05:22, Krishna chaitanya chundru wrote:
> >>>>>>>>>> diff --git a/Documentation/devicetree/bindings/pci/qcom,qps615.yaml b/Documentation/devicetree/bindings/pci/qcom,qps615.yaml
> >>>>>>> [..]
> >>>>>>>>>> + qps615,axi-clk-freq-hz:
> >>>>>>>>>> + description:
> >>>>>>>>>> + AXI clock which internal bus of the switch.
> >>>>>>>>>
> >>>>>>>>> No need, use CCF.
> >>>>>>>>>
> >>>>>>>> ack
> >>>>>>>
> >>>>>>> This is a clock that's internal to the QPS615, so there's no clock
> >>>>>>> controller involved and hence I don't think CCF is applicable.
> >>>>>>
> >>>>>> AXI does not sound that internal.
> >>>>>
> >>>>> Well, AXI is applicable to whatever entity that implements it. We mostly seen it
> >>>>> in ARM SoCs (host), but in this case the PCIe switch also has a microcontroller
> >>>>> /processor of some sort, so AXI is indeed relevant for it. The naming actually
> >>>>> comes from the switch's i2c register name that is being configured in the driver
> >>>>> based on this property value.
> >>>>>
> >>>>>> DT rarely needs to specify internal
> >>>>>> clock rates. What if you want to define rates for 20 clocks? Even
> >>>>>> clock-frequency is deprecated, so why this would be allowed?
> >>>>>> bus-frequency is allowed for buses, but that's not the case here, I guess?
> >>>>>>
> >>>>>
> >>>>> This clock frequency is for the switch's internal AXI bus that runs at default
> >>>>> 200MHz. And this property is used to specify a frequency that is configured over
> >>>>> the i2c interface so that the switch's AXI bus can operate in a low frequency
> >>>>> there by reducing the power consumption of the switch.
> >>>>>
> >>>>> It is not strictly needed for the switch operation, but for power optimization.
> >>>>> So this property can also be dropped for the initial submission and added later
> >>>>> if you prefer.
> >>>>
> >>>> So if the clock rate can change, why this is static in DTB? Or why this
> >>>> is configurable per-board?
> >>>>
> >>>
> >>> Because, board manufacturers can change the frequency depending on the switch
> >>> configuration (enablement of DSP's etc...)
> >>>
> >>>> There is a reason why clock-frequency property is not welcomed and you
> >>>> are re-implementing it.
> >>>>
> >>>
> >>> Hmm, I'm not aware that 'clock-frequency' is not encouraged these days. So you
> >>> are suggesting to change the rate in the driver itself based on the switch
> >>> configuration? If so, what difference does it make?
> >>
> >> Based on the switch, other clocks, votes etc. whatever is reasonable
> >> there. In most cases, not sure if this one here as well, devices can
> >> operate on different clock frequencies thus specifying fixed frequency
> >> in the DTS is simplification and lack of flexibility. It is chosen by
> >> people only because it is easier for them but then they come back with
> >> ABI issues when it turns out they need to switch to some dynamic control.
> >>
> >
> > Atleast for this device, this frequency is going to be static. Because, the
> > device itself cannot change the frequency, only the host driver can. That too is
> > only possible before enumerating the device. So there is no way the frequency is
> > going to change dynamically.
>
> We have assigned-clocks properties for this... but there are no clock
> inputs here, so maybe it is not applicable? What generates this internal
> AXI clock? Does it have internal oscillator?
>
I do not have access to the device schematics, but based on my knowledge there
should be an internal oscillator for the device. But the device also gets the
refclk from PCIe bus, but I don't know if that is somehow used as a parent of
AXI bus or not.
Going by the AXI bus terminology, I would assume that the frequency of this come
from the internal oscillator in the device.
And this is common on many PCIe devices, but they never mentioned in DT (well we
do not define PCIe devices in DT usually), but Qcom wants to control the
frequency of the device's internal clock to optimize the power consumption of
the device. Unfortunately, the device firmware is not doing its job as expected.
- Mani
--
மணிவண்ணன் சதாசிவம்
^ permalink raw reply [flat|nested] 77+ messages in thread
* Re: [PATCH v2 1/8] dt-bindings: PCI: Add binding for qps615
2024-08-23 9:01 ` Krzysztof Kozlowski
@ 2024-08-23 9:44 ` Manivannan Sadhasivam
2024-08-23 13:51 ` Krzysztof Kozlowski
0 siblings, 1 reply; 77+ messages in thread
From: Manivannan Sadhasivam @ 2024-08-23 9:44 UTC (permalink / raw)
To: Krzysztof Kozlowski
Cc: Krishna Chaitanya Chundru, Lorenzo Pieralisi,
Krzysztof Wilczyński, Rob Herring, Bjorn Helgaas,
Krzysztof Kozlowski, Conor Dooley, Konrad Dybcio,
cros-qcom-dts-watchers, Bartosz Golaszewski, Jingoo Han,
andersson, quic_vbadigan, linux-arm-msm, linux-pci, devicetree,
linux-kernel, Bartosz Golaszewski
On Fri, Aug 23, 2024 at 11:01:37AM +0200, Krzysztof Kozlowski wrote:
> On 22/08/2024 16:16, Manivannan Sadhasivam wrote:
> > On Mon, Aug 05, 2024 at 04:43:47PM +0200, Krzysztof Kozlowski wrote:
> >> On 05/08/2024 07:57, Krishna Chaitanya Chundru wrote:
> >>>>
> >>> Hi Krzysztof,
> >>>
> >>> QPS615 has a 3 downstream ports and 1 upstream port as described below
> >>> diagram.
> >>> For this entire switch there are some supplies which we described in the
> >>> dt-binding (vdd18-supply, vdd09-supply etc) and one GPIO which controls
> >>> reset of the switch (reset-gpio). The switch hardware can configure the
> >>> individual ports DSP0, DSP1, DSP2, upstream port and also one integrated
> >>> ethernet endpoint which is connected to DSP2(I didn't mentioned in the
> >>> diagram) through I2C.
> >>>
> >>> The properties other than supplies,i2c client, reset gpio which
> >>> are added will be applicable for all the ports.
> >>> _______________________________________________________________
> >>> | |i2c| QPS615 |Supplies||Resx gpio |
> >>> | |___| _________________ |________||__________|
> >>> | ________________| Upstream port |_____________ |
> >>> | | |_______________| | |
> >>> | | | | |
> >>> | | | | |
> >>> | ____|_____ ____|_____ ___|____ |
> >>> | |DSP 0 | | DSP 1 | | DSP 2| |
> >>> | |________| |________| |______| |
> >>> |_____________________________________________________________|
> >>>
> >>
> >> I don't get why then properties should apply to main device node.
> >>
> >
> > The problem here is, we cannot differentiate between main device node and the
> > upstream node. Typically the differentiation is not needed because no one cared
> > about configuring the upstream port. But this PCIe switch is special (as like
> > most of the Qcom peripherals).
> >
> > I agree that if we don't differentiate then it also implies that all main node
> > properties are applicable to upstream port and vice versa. But AFAIK, upstream
> > port is often considered as the _device_ itself as it shares the same bus
> > number.
>
> Well, above diagram shows supplies being part of the entire device, not
> each port. That's confusing. Based on diagram, downstream ports do not
> have any supplies... and what exactly do they supply? Let's look at
> vdd18 and vdd09 which sound main supplies of the entire device. In
> context of port: what exactly do they power? Which part of the port?
>
The supplies for the downstream ports are derived from the switch power supply
only. There is no way we can describe them as the port suppliers are internal to
the device.
- Mani
--
மணிவண்ணன் சதாசிவம்
^ permalink raw reply [flat|nested] 77+ messages in thread
* Re: [PATCH v2 1/8] dt-bindings: PCI: Add binding for qps615
2024-08-23 9:44 ` Manivannan Sadhasivam
@ 2024-08-23 13:51 ` Krzysztof Kozlowski
2024-08-23 15:11 ` Manivannan Sadhasivam
0 siblings, 1 reply; 77+ messages in thread
From: Krzysztof Kozlowski @ 2024-08-23 13:51 UTC (permalink / raw)
To: Manivannan Sadhasivam
Cc: Krishna Chaitanya Chundru, Lorenzo Pieralisi,
Krzysztof Wilczyński, Rob Herring, Bjorn Helgaas,
Krzysztof Kozlowski, Conor Dooley, Konrad Dybcio,
cros-qcom-dts-watchers, Bartosz Golaszewski, Jingoo Han,
andersson, quic_vbadigan, linux-arm-msm, linux-pci, devicetree,
linux-kernel, Bartosz Golaszewski
On 23/08/2024 11:44, Manivannan Sadhasivam wrote:
> On Fri, Aug 23, 2024 at 11:01:37AM +0200, Krzysztof Kozlowski wrote:
>> On 22/08/2024 16:16, Manivannan Sadhasivam wrote:
>>> On Mon, Aug 05, 2024 at 04:43:47PM +0200, Krzysztof Kozlowski wrote:
>>>> On 05/08/2024 07:57, Krishna Chaitanya Chundru wrote:
>>>>>>
>>>>> Hi Krzysztof,
>>>>>
>>>>> QPS615 has a 3 downstream ports and 1 upstream port as described below
>>>>> diagram.
>>>>> For this entire switch there are some supplies which we described in the
>>>>> dt-binding (vdd18-supply, vdd09-supply etc) and one GPIO which controls
>>>>> reset of the switch (reset-gpio). The switch hardware can configure the
>>>>> individual ports DSP0, DSP1, DSP2, upstream port and also one integrated
>>>>> ethernet endpoint which is connected to DSP2(I didn't mentioned in the
>>>>> diagram) through I2C.
>>>>>
>>>>> The properties other than supplies,i2c client, reset gpio which
>>>>> are added will be applicable for all the ports.
>>>>> _______________________________________________________________
>>>>> | |i2c| QPS615 |Supplies||Resx gpio |
>>>>> | |___| _________________ |________||__________|
>>>>> | ________________| Upstream port |_____________ |
>>>>> | | |_______________| | |
>>>>> | | | | |
>>>>> | | | | |
>>>>> | ____|_____ ____|_____ ___|____ |
>>>>> | |DSP 0 | | DSP 1 | | DSP 2| |
>>>>> | |________| |________| |______| |
>>>>> |_____________________________________________________________|
>>>>>
>>>>
>>>> I don't get why then properties should apply to main device node.
>>>>
>>>
>>> The problem here is, we cannot differentiate between main device node and the
>>> upstream node. Typically the differentiation is not needed because no one cared
>>> about configuring the upstream port. But this PCIe switch is special (as like
>>> most of the Qcom peripherals).
>>>
>>> I agree that if we don't differentiate then it also implies that all main node
>>> properties are applicable to upstream port and vice versa. But AFAIK, upstream
>>> port is often considered as the _device_ itself as it shares the same bus
>>> number.
>>
>> Well, above diagram shows supplies being part of the entire device, not
>> each port. That's confusing. Based on diagram, downstream ports do not
>> have any supplies... and what exactly do they supply? Let's look at
>> vdd18 and vdd09 which sound main supplies of the entire device. In
>> context of port: what exactly do they power? Which part of the port?
>>
>
> The supplies for the downstream ports are derived from the switch power supply
> only. There is no way we can describe them as the port suppliers are internal to
> the device.
IIUC, this means supplies are not valid for downstream ports, so it is a
proof that binding is not correct. I don't get why we keep poking this
and get to the same conclusions I had 3 weeks ago.
Basically the binding is saying that downstream ports are identical to
the device. Including the aspect of having more downstream ports (so
device -> downstream ports -> downstream ports -> downstream ports ...
infinite). To remind that was my conclusion:
"Downstream port is not the same as device. Why downstream port has the
same supplies? To which pins are they connected?"
Best regards,
Krzysztof
^ permalink raw reply [flat|nested] 77+ messages in thread
* Re: [PATCH v2 1/8] dt-bindings: PCI: Add binding for qps615
2024-08-23 13:51 ` Krzysztof Kozlowski
@ 2024-08-23 15:11 ` Manivannan Sadhasivam
0 siblings, 0 replies; 77+ messages in thread
From: Manivannan Sadhasivam @ 2024-08-23 15:11 UTC (permalink / raw)
To: Krzysztof Kozlowski
Cc: Krishna Chaitanya Chundru, Lorenzo Pieralisi,
Krzysztof Wilczyński, Rob Herring, Bjorn Helgaas,
Krzysztof Kozlowski, Conor Dooley, Konrad Dybcio,
cros-qcom-dts-watchers, Bartosz Golaszewski, Jingoo Han,
andersson, quic_vbadigan, linux-arm-msm, linux-pci, devicetree,
linux-kernel, Bartosz Golaszewski
On Fri, Aug 23, 2024 at 03:51:25PM +0200, Krzysztof Kozlowski wrote:
> On 23/08/2024 11:44, Manivannan Sadhasivam wrote:
> > On Fri, Aug 23, 2024 at 11:01:37AM +0200, Krzysztof Kozlowski wrote:
> >> On 22/08/2024 16:16, Manivannan Sadhasivam wrote:
> >>> On Mon, Aug 05, 2024 at 04:43:47PM +0200, Krzysztof Kozlowski wrote:
> >>>> On 05/08/2024 07:57, Krishna Chaitanya Chundru wrote:
> >>>>>>
> >>>>> Hi Krzysztof,
> >>>>>
> >>>>> QPS615 has a 3 downstream ports and 1 upstream port as described below
> >>>>> diagram.
> >>>>> For this entire switch there are some supplies which we described in the
> >>>>> dt-binding (vdd18-supply, vdd09-supply etc) and one GPIO which controls
> >>>>> reset of the switch (reset-gpio). The switch hardware can configure the
> >>>>> individual ports DSP0, DSP1, DSP2, upstream port and also one integrated
> >>>>> ethernet endpoint which is connected to DSP2(I didn't mentioned in the
> >>>>> diagram) through I2C.
> >>>>>
> >>>>> The properties other than supplies,i2c client, reset gpio which
> >>>>> are added will be applicable for all the ports.
> >>>>> _______________________________________________________________
> >>>>> | |i2c| QPS615 |Supplies||Resx gpio |
> >>>>> | |___| _________________ |________||__________|
> >>>>> | ________________| Upstream port |_____________ |
> >>>>> | | |_______________| | |
> >>>>> | | | | |
> >>>>> | | | | |
> >>>>> | ____|_____ ____|_____ ___|____ |
> >>>>> | |DSP 0 | | DSP 1 | | DSP 2| |
> >>>>> | |________| |________| |______| |
> >>>>> |_____________________________________________________________|
> >>>>>
> >>>>
> >>>> I don't get why then properties should apply to main device node.
> >>>>
> >>>
> >>> The problem here is, we cannot differentiate between main device node and the
> >>> upstream node. Typically the differentiation is not needed because no one cared
> >>> about configuring the upstream port. But this PCIe switch is special (as like
> >>> most of the Qcom peripherals).
> >>>
> >>> I agree that if we don't differentiate then it also implies that all main node
> >>> properties are applicable to upstream port and vice versa. But AFAIK, upstream
> >>> port is often considered as the _device_ itself as it shares the same bus
> >>> number.
> >>
> >> Well, above diagram shows supplies being part of the entire device, not
> >> each port. That's confusing. Based on diagram, downstream ports do not
> >> have any supplies... and what exactly do they supply? Let's look at
> >> vdd18 and vdd09 which sound main supplies of the entire device. In
> >> context of port: what exactly do they power? Which part of the port?
> >>
> >
> > The supplies for the downstream ports are derived from the switch power supply
> > only. There is no way we can describe them as the port suppliers are internal to
> > the device.
>
> IIUC, this means supplies are not valid for downstream ports, so it is a
> proof that binding is not correct. I don't get why we keep poking this
> and get to the same conclusions I had 3 weeks ago.
>
> Basically the binding is saying that downstream ports are identical to
> the device. Including the aspect of having more downstream ports (so
> device -> downstream ports -> downstream ports -> downstream ports ...
> infinite). To remind that was my conclusion:
>
> "Downstream port is not the same as device. Why downstream port has the
> same supplies? To which pins are they connected?"
>
Ok. I seem to have missed your above comment and you are right. I was just
clarifying the upstream port discussion as we cannot differentiate between
upstream port and main device node.
For downstream port, I hope Krishna will fix the binding.
- Mani
--
மணிவண்ணன் சதாசிவம்
^ permalink raw reply [flat|nested] 77+ messages in thread
* Re: [PATCH v2 7/8] PCI: qcom: Add support for host_stop_link() & host_start_link()
2024-08-06 19:12 ` Bjorn Helgaas
@ 2024-09-02 6:51 ` Krishna Chaitanya Chundru
2024-09-02 18:32 ` Dmitry Baryshkov
0 siblings, 1 reply; 77+ messages in thread
From: Krishna Chaitanya Chundru @ 2024-09-02 6:51 UTC (permalink / raw)
To: Bjorn Helgaas
Cc: Lorenzo Pieralisi, Krzysztof Wilczyński, Rob Herring,
Bjorn Helgaas, Krzysztof Kozlowski, Conor Dooley, Konrad Dybcio,
cros-qcom-dts-watchers, Bartosz Golaszewski, Jingoo Han,
Manivannan Sadhasivam, andersson, quic_vbadigan, linux-arm-msm,
linux-pci, devicetree, linux-kernel, Bartosz Golaszewski
On 8/7/2024 12:42 AM, Bjorn Helgaas wrote:
> On Sat, Aug 03, 2024 at 08:52:53AM +0530, Krishna chaitanya chundru wrote:
>> For the switches like QPS615 which needs to configure it before
>> the PCIe link is established.
>>
>> if the link is not up assert the PERST# and disable LTSSM bit so
>> that PCIe controller will not participate in the link training
>> as part of host_stop_link().
>>
>> De-assert the PERST# and enable LTSSM bit back in host_start_link().
>>
>> Introduce ltssm_disable function op to stop the link training.
>
> pcie-qcom.c is a driver for a PCIe host controller. Apparently QPS615
> is a switch in a hierarchy that could be below any PCIe host
> controller, so I'm missing the connection with pcie-qcom.c.
>
> Does this fix a problem that only occurs with pcie-qcom.c? What
> happens if you put a QPS615 below some other controller?
>
Hi Bjorn,
The qps615 is the qualcomm in-house PCIe switch it is not available to
others. so we are trying to add for qualcomm soc's only.
- Krishna chaitanya.
>> Signed-off-by: Krishna chaitanya chundru <quic_krichai@quicinc.com>
>> ---
>> drivers/pci/controller/dwc/pcie-qcom.c | 39 ++++++++++++++++++++++++++++++++++
>> 1 file changed, 39 insertions(+)
>>
>> diff --git a/drivers/pci/controller/dwc/pcie-qcom.c b/drivers/pci/controller/dwc/pcie-qcom.c
>> index 0180edf3310e..f4a6df53139c 100644
>> --- a/drivers/pci/controller/dwc/pcie-qcom.c
>> +++ b/drivers/pci/controller/dwc/pcie-qcom.c
>> @@ -233,6 +233,7 @@ struct qcom_pcie_ops {
>> void (*host_post_init)(struct qcom_pcie *pcie);
>> void (*deinit)(struct qcom_pcie *pcie);
>> void (*ltssm_enable)(struct qcom_pcie *pcie);
>> + void (*ltssm_disable)(struct qcom_pcie *pcie);
>> int (*config_sid)(struct qcom_pcie *pcie);
>> };
>>
>> @@ -555,6 +556,41 @@ static int qcom_pcie_post_init_1_0_0(struct qcom_pcie *pcie)
>> return 0;
>> }
>>
>> +static int qcom_pcie_host_start_link(struct dw_pcie *pci)
>> +{
>> + struct qcom_pcie *pcie = to_qcom_pcie(pci);
>> +
>> + if (!dw_pcie_link_up(pcie->pci)) {
>> + qcom_ep_reset_deassert(pcie);
>> +
>> + if (pcie->cfg->ops->ltssm_enable)
>> + pcie->cfg->ops->ltssm_enable(pcie);
>> + }
>> +
>> + return 0;
>> +}
>> +
>> +static void qcom_pcie_host_stop_link(struct dw_pcie *pci)
>> +{
>> + struct qcom_pcie *pcie = to_qcom_pcie(pci);
>> +
>> + if (!dw_pcie_link_up(pcie->pci)) {
>> + qcom_ep_reset_assert(pcie);
>> +
>> + if (pcie->cfg->ops->ltssm_disable)
>> + pcie->cfg->ops->ltssm_disable(pcie);
>> + }
>> +}
>> +
>> +static void qcom_pcie_2_3_2_ltssm_disable(struct qcom_pcie *pcie)
>> +{
>> + u32 val;
>> +
>> + val = readl(pcie->parf + PARF_LTSSM);
>> + val &= ~LTSSM_EN;
>> + writel(val, pcie->parf + PARF_LTSSM);
>> +}
>> +
>> static void qcom_pcie_2_3_2_ltssm_enable(struct qcom_pcie *pcie)
>> {
>> u32 val;
>> @@ -1306,6 +1342,7 @@ static const struct qcom_pcie_ops ops_1_9_0 = {
>> .host_post_init = qcom_pcie_host_post_init_2_7_0,
>> .deinit = qcom_pcie_deinit_2_7_0,
>> .ltssm_enable = qcom_pcie_2_3_2_ltssm_enable,
>> + .ltssm_disable = qcom_pcie_2_3_2_ltssm_disable,
>> .config_sid = qcom_pcie_config_sid_1_9_0,
>> };
>>
>> @@ -1363,6 +1400,8 @@ static const struct qcom_pcie_cfg cfg_sc8280xp = {
>> static const struct dw_pcie_ops dw_pcie_ops = {
>> .link_up = qcom_pcie_link_up,
>> .start_link = qcom_pcie_start_link,
>> + .host_start_link = qcom_pcie_host_start_link,
>> + .host_stop_link = qcom_pcie_host_stop_link,
>> };
>>
>> static int qcom_pcie_icc_init(struct qcom_pcie *pcie)
>>
>> --
>> 2.34.1
>>
^ permalink raw reply [flat|nested] 77+ messages in thread
* Re: [PATCH v2 8/8] PCI: pwrctl: Add power control driver for qps615
2024-08-08 3:30 ` Dmitry Baryshkov
@ 2024-09-02 7:12 ` Krishna Chaitanya Chundru
2024-09-02 7:20 ` Dmitry Baryshkov
0 siblings, 1 reply; 77+ messages in thread
From: Krishna Chaitanya Chundru @ 2024-09-02 7:12 UTC (permalink / raw)
To: Dmitry Baryshkov
Cc: Lorenzo Pieralisi, Krzysztof Wilczyński, Rob Herring,
Bjorn Helgaas, Krzysztof Kozlowski, Conor Dooley, Konrad Dybcio,
cros-qcom-dts-watchers, Bartosz Golaszewski, Jingoo Han,
Manivannan Sadhasivam, andersson, quic_vbadigan, linux-arm-msm,
linux-pci, devicetree, linux-kernel, Bartosz Golaszewski
On 8/8/2024 9:00 AM, Dmitry Baryshkov wrote:
> On August 5, 2024 1:14:47 PM GMT+07:00, Krishna Chaitanya Chundru <quic_krichai@quicinc.com> wrote:
>>
>>
>> On 8/3/2024 5:04 PM, Dmitry Baryshkov wrote:
>>> On Sat, Aug 03, 2024 at 08:52:54AM GMT, Krishna chaitanya chundru wrote:
>>>> QPS615 switch needs to be configured after powering on and before
>>>> PCIe link was up.
>>>>
>>>> As the PCIe controller driver already enables the PCIe link training
>>>> at the host side, stop the link training. Otherwise the moment we turn
>>>> on the switch it will participate in the link training and link may come
>>>> up before switch is configured through i2c.
>>>>
>>>> The device tree properties are parsed per node under pci-pci bridge in the
>>>> driver. Each node has unique bdf value in the reg property, driver
>>>> uses this bdf to differentiate ports, as there are certain i2c writes to
>>>> select particular port.
>>>>
>>>> Based up on dt property and port, qps615 is configured through i2c.
>>>>
>>>> Signed-off-by: Krishna chaitanya chundru <quic_krichai@quicinc.com>
>>>> ---
>>>> drivers/pci/pwrctl/Kconfig | 7 +
>>>> drivers/pci/pwrctl/Makefile | 1 +
>>>> drivers/pci/pwrctl/pci-pwrctl-qps615.c | 638 +++++++++++++++++++++++++++++++++
>>>> 3 files changed, 646 insertions(+)
>>>>
>>>> diff --git a/drivers/pci/pwrctl/Kconfig b/drivers/pci/pwrctl/Kconfig
>>>> index 54589bb2403b..6a1352af918c 100644
>>>> --- a/drivers/pci/pwrctl/Kconfig
>>>> +++ b/drivers/pci/pwrctl/Kconfig
>>>> @@ -10,3 +10,10 @@ config PCI_PWRCTL_PWRSEQ
>>>> tristate
>>>> select POWER_SEQUENCING
>>>> select PCI_PWRCTL
>>>> +
>>>> +config PCI_PWRCTL_QPS615
>>>> + tristate "PCI Power Control driver for QPS615"
>>>> + select PCI_PWRCTL
>>>> + help
>>>> + Say Y here to enable the pwrctl driver for Qualcomm
>>>> + QPS615 PCIe switch.
>>>> diff --git a/drivers/pci/pwrctl/Makefile b/drivers/pci/pwrctl/Makefile
>>>> index d308aae4800c..ac563a70c023 100644
>>>> --- a/drivers/pci/pwrctl/Makefile
>>>> +++ b/drivers/pci/pwrctl/Makefile
>>>> @@ -4,3 +4,4 @@ obj-$(CONFIG_PCI_PWRCTL) += pci-pwrctl-core.o
>>>> pci-pwrctl-core-y := core.o
>>>> obj-$(CONFIG_PCI_PWRCTL_PWRSEQ) += pci-pwrctl-pwrseq.o
>>>> +obj-$(CONFIG_PCI_PWRCTL_QPS615) += pci-pwrctl-qps615.o
>>>> diff --git a/drivers/pci/pwrctl/pci-pwrctl-qps615.c b/drivers/pci/pwrctl/pci-pwrctl-qps615.c
>>>> new file mode 100644
>>>> index 000000000000..9dabb82787d5
>>>> --- /dev/null
>>>> +++ b/drivers/pci/pwrctl/pci-pwrctl-qps615.c
>>>> @@ -0,0 +1,638 @@
>>>> +// SPDX-License-Identifier: GPL-2.0-only
>>>> +/*
>>>> + * Copyright (c) 2024 Qualcomm Innovation Center, Inc. All rights reserved.
>>>> + */
>>>> +
>>>> +#include <linux/delay.h>
>>>> +#include <linux/device.h>
>>>> +#include <linux/firmware.h>
>>>> +#include <linux/i2c.h>
>>>> +#include <linux/mod_devicetable.h>
>>>> +#include <linux/module.h>
>>>> +#include <linux/of.h>
>>>> +#include <linux/pci.h>
>>>> +#include <linux/pci-pwrctl.h>
>>>> +#include <linux/platform_device.h>
>>>> +#include <linux/regulator/consumer.h>
>>>> +#include <linux/string.h>
>>>> +#include <linux/types.h>
>>>> +
>>>> +#include "../pci.h"
>>>> +
>>>> +#define QPS615_GPIO_CONFIG 0x801208
>>>> +#define QPS615_RESET_GPIO 0x801210
>>>> +
>>>> +#define QPS615_BUS_CONTROL 0x801014
>>>> +
>>>> +#define QPS615_PORT_L0S_DELAY 0x82496c
>>>> +#define QPS615_PORT_L1_DELAY 0x824970
>>>> +
>>>> +#define QPS615_EMBEDDED_ETH_DELAY 0x8200d8
>>>> +#define QPS615_ETH_L1_DELAY_MASK GENMASK(27, 18)
>>>> +#define QPS615_ETH_L1_DELAY_VALUE(x) FIELD_PREP(QPS615_ETH_L1_DELAY_MASK, x)
>>>> +#define QPS615_ETH_L0S_DELAY_MASK GENMASK(17, 13)
>>>> +#define QPS615_ETH_L0S_DELAY_VALUE(x) FIELD_PREP(QPS615_ETH_L0S_DELAY_MASK, x)
>>>> +
>>>> +#define QPS615_NFTS_2_5_GT 0x824978
>>>> +#define QPS615_NFTS_5_GT 0x82497c
>>>> +
>>>> +#define QPS615_PORT_LANE_ACCESS_ENABLE 0x828000
>>>> +
>>>> +#define QPS615_PHY_RATE_CHANGE_OVERRIDE 0x828040
>>>> +#define QPS615_PHY_RATE_CHANGE 0x828050
>>>> +
>>>> +#define QPS615_TX_MARGIN 0x828234
>>>> +
>>>> +#define QPS615_DFE_ENABLE 0x828a04
>>>> +#define QPS615_DFE_EQ0_MODE 0x828a08
>>>> +#define QPS615_DFE_EQ1_MODE 0x828a0c
>>>> +#define QPS615_DFE_EQ2_MODE 0x828a14
>>>> +#define QPS615_DFE_PD_MASK 0x828254
>>>> +
>>>> +#define QPS615_PORT_SELECT 0x82c02c
>>>> +#define QPS615_PORT_ACCESS_ENABLE 0x82c030
>>>> +
>>>> +#define QPS615_POWER_CONTROL 0x82b09c
>>>> +#define QPS615_POWER_CONTROL_OVREN 0x82b2c8
>>>> +
>>>> +#define QPS615_AXI_CLK_FREQ_MHZ 125
>>>> +
>>>> +struct qps615_pwrctl_reg_setting {
>>>> + unsigned int offset;
>>>> + unsigned int val;
>>>> +};
>>>> +
>>>> +struct qps615_pwrctl_bdf_info {
>>>> + u16 usp_bdf;
>>>> + u16 dsp1_bdf;
>>>> + u16 dsp2_bdf;
>>>> + u16 dsp3_bdf;
>>>
>>> Why are these values dynamic? Please use #define's for now. If there
>>> ever comes a similar bridge, it most likely will have a different ports
>>> configuration, so it will need additional changes anyway.
>>>
>> We added this for future use case only, we felt it is easier to support
>> at the time if we add this way.
>
> Please don't. You are hardcoding distinct roles into the structure that is supposed to be generic. Possible future use cases might have different number of ports or different port roles.
>
ok.
>>
>>>> +};
>>>> +
>>>> +enum qps615_pwrctl_ports {
>>>> + QPS615_USP,
>>>> + QPS615_DSP1,
>>>> + QPS615_DSP2,
>>>> + QPS615_DSP3,
>>>> + QPS615_ETHERNET,
>>>> + QPS615_MAX
>>>> +};
>>>> +
>>>> +struct qps615_pwrctl_cfg {
>>>> + u32 l0s_delay;
>>>> + u32 l1_delay;
>>>> + u32 tx_amp;
>>>> + u32 axi_freq;
>>>> + u8 nfts;
>>>> + bool disable_dfe;
>>>> + bool disable_port;
>>>> +};
>>>> +
>>>> +#define QPS615_PWRCTL_MAX_SUPPLY 6
>>>> +
>>>> +struct qps615_pwrctl_ctx {
>>>> + struct regulator_bulk_data supplies[QPS615_PWRCTL_MAX_SUPPLY];
>>>> + const struct qps615_pwrctl_bdf_info *bdf;
>>>> + struct qps615_pwrctl_cfg cfg[QPS615_MAX];
>>>> + struct gpio_desc *reset_gpio;
>>>> + struct i2c_client *client;
>>>> + struct pci_pwrctl pwrctl;
>>>> + struct device_link *link;
>>>> +};
>>>> +
>>>> +/*
>>>> + * downstream port power off sequence, hardcoding the address
>>>> + * as we don't know register names for these register offsets.
>>>
>>> It is hard to believe that Qualcomm engineers don't know register names
>>> for the Qualcomm device.
>>>
>> The switch IP is from the another vendor and the vendor provided these
>> settings. The databook doesn't have the register names in it.
>>>> + */
>>>> +static const struct qps615_pwrctl_reg_setting common_pwroff_seq[] = {
>>>> + {0x82900c, 0x1},
>>>> + {0x829010, 0x1},
>>>> + {0x829018, 0x0},
>>>> + {0x829020, 0x1},
>>>> + {0x82902c, 0x1},
>>>> + {0x829030, 0x1},
>>>> + {0x82903c, 0x1},
>>>> + {0x829058, 0x0},
>>>> + {0x82905c, 0x1},
>>>> + {0x829060, 0x1},
>>>> + {0x8290cc, 0x1},
>>>> + {0x8290d0, 0x1},
>>>> + {0x8290d8, 0x1},
>>>> + {0x8290e0, 0x1},
>>>> + {0x8290e8, 0x1},
>>>> + {0x8290ec, 0x1},
>>>> + {0x8290f4, 0x1},
>>>> + {0x82910c, 0x1},
>>>> + {0x829110, 0x1},
>>>> + {0x829114, 0x1},
>>>> +};
>>>> +
>>>> +static const struct qps615_pwrctl_reg_setting dsp1_pwroff_seq[] = {
>>>> + {QPS615_PORT_ACCESS_ENABLE, 0x2},
>>>> + {QPS615_PORT_LANE_ACCESS_ENABLE, 0x3},
>>>> + {QPS615_POWER_CONTROL, 0x014f4804},
>>>> + {QPS615_POWER_CONTROL_OVREN, 0x1},
>>>> + {QPS615_PORT_ACCESS_ENABLE, 0x4},
>>>> +};
>>>> +
>>>> +static const struct qps615_pwrctl_reg_setting dsp2_pwroff_seq[] = {
>>>> + {QPS615_PORT_ACCESS_ENABLE, 0x8},
>>>> + {QPS615_PORT_LANE_ACCESS_ENABLE, 0x1},
>>>> + {QPS615_POWER_CONTROL, 0x014f4804},
>>>> + {QPS615_POWER_CONTROL_OVREN, 0x1},
>>>> + {QPS615_PORT_ACCESS_ENABLE, 0x8},
>>>> +};
>>>> +
>>>> +static int qps615_pwrctl_i2c_write(struct i2c_client *client,
>>>> + u32 reg_addr, u32 reg_val)
>>>> +{
>>>> + struct i2c_msg msg;
>>>> + u8 msg_buf[7];
>>>> + int ret;
>>>> +
>>>> + msg.addr = client->addr;
>>>> + msg.len = 7;
>>>> + msg.flags = 0;
>>>> +
>>>> + /* Big Endian for reg addr */
>>>> + reg_addr = cpu_to_be32(reg_addr);
>>>
>>> This is incorrect. After cpu_to_be32() the value depends on the CPU
>>> endianness. So reg_addr >> 8 will return different values for LE and BE
>>> CPUs.
>>> I had following impression
>> If reg address is 0x828a0c in big endian sytem it will be 0c8a8200
>> and in litte endian it will be 0x828a0c only.
>> If cpu uses big endian cpu_to_be32 will not change this value
>> and in little endian case cpu_to_be32 will convert 0x828a0c to 0c8a8200.
>>
>> Now the output is same for both the systems I tried to use
>> (reg_addr >> 8) directly.
>>
>> Are you saying (reg_addr >> 8) output will be different based upon
>> LE and BE ? If that is the case I will remove the conversions
>> in next patch.
>
> Reg address is always 0x00828a0c. Then on little-endian system you convert it to to BE32, which results in the value 0x0c8a8200. Finally you use shifts to get {0x82, 0x8a, 0x0c}, which is supposedly correct.
>
> On big-endian system cpu_to_be32 returns the same value, 0x00828a0c, since it is BE32 already. So after shifts msg_buf will get {0x8a, 0x82, 0x00}, which is obviously incorrect.
>
ack, I will fix them.
>>>> +
>>>> + msg_buf[0] = (u8)(reg_addr >> 8);
>>>> + msg_buf[1] = (u8)(reg_addr >> 16);
>>>> + msg_buf[2] = (u8)(reg_addr >> 24);
>>>> +
>>>> + /* Little Endian for reg val */
>>>> + reg_val = cpu_to_le32(reg_val);
>>>> +
>>>> + msg_buf[3] = (u8)(reg_val);
>>>> + msg_buf[4] = (u8)(reg_val >> 8);
>>>> + msg_buf[5] = (u8)(reg_val >> 16);
>>>> + msg_buf[6] = (u8)(reg_val >> 24);
>>>
>>> Same issue here.
>>>
>>>> +
>>>> + msg.buf = msg_buf;
>>>> + ret = i2c_transfer(client->adapter, &msg, 1);
>>>> + return ret == 1 ? 0 : ret;
>>>> +}
>>>> +
>>>> +static int qps615_pwrctl_i2c_read(struct i2c_client *client,
>>>> + u32 reg_addr, u32 *reg_val)
>>>> +{
>>>> + struct i2c_msg msg[2];
>>>> + u8 wr_data[3];
>>>> + u32 rd_data;
>>>> + int ret;
>>>> +
>>>> + msg[0].addr = client->addr;
>>>> + msg[0].len = 3;
>>>> + msg[0].flags = 0;
>>>> +
>>>> + /* Big Endian for reg addr */
>>>> + reg_addr = cpu_to_be32(reg_addr);
>>>> +
>>>> + wr_data[0] = (u8)(reg_addr >> 8);
>>>> + wr_data[1] = (u8)(reg_addr >> 16);
>>>> + wr_data[2] = (u8)(reg_addr >> 24);
>>>
>>> And here.
>>>
>>>> +
>>>> + msg[0].buf = wr_data;
>>>> +
>>>> + msg[1].addr = client->addr;
>>>> + msg[1].len = 4;
>>>> + msg[1].flags = I2C_M_RD;
>>>> +
>>>> + msg[1].buf = (u8 *)&rd_data;
>>>> +
>>>> + ret = i2c_transfer(client->adapter, &msg[0], 2);
>>>> + if (ret == 2) {
>>>> + *reg_val = le32_to_cpu(rd_data);
>>>> + return 0;
>>>> + }
>>>> +
>>>> + /* If only one message successfully completed, return -ENODEV */
>>>> + return ret == 1 ? -ENODEV : ret;
>>>> +}
>>>> +
>>>> +static int qps615_pwrctl_i2c_bulk_write(struct i2c_client *client,
>>>> + const struct qps615_pwrctl_reg_setting *seq, int len)
>>>> +{
>>>> + int ret, i;
>>>> +
>>>> + for (i = 0; i < len; i++) {
>>>> + ret = qps615_pwrctl_i2c_write(client, seq[i].offset, seq[i].val);
>>>> + if (ret)
>>>> + return ret;
>>>> + }
>>>> +
>>>> + return 0;
>>>> +}
>>>> +
>>>> +static int of_pci_get_bdf(struct device_node *np)
>>>> +{
>>>> + u32 reg[5];
>>>> + int error;
>>>> +
>>>> + error = of_property_read_u32_array(np, "reg", reg, ARRAY_SIZE(reg));
>>>
>>> Please use of_property_read_u32_index() instead.
>>>
>> ack.
>>>> + if (error)
>>>> + return error;
>>>> +
>>>> + return (reg[0] >> 8) & 0xffff;
>>>> +}
>>>> +
>>>> +static int qps615_pwrctl_disable_port(struct qps615_pwrctl_ctx *ctx,
>>>> + enum qps615_pwrctl_ports port)
>>>> +{
>>>> + const struct qps615_pwrctl_reg_setting *seq;
>>>> + int ret, len;
>>>> +
>>>> + seq = (port == QPS615_DSP1) ? dsp1_pwroff_seq : dsp2_pwroff_seq;
>>>> + len = (port == QPS615_DSP1) ? ARRAY_SIZE(dsp1_pwroff_seq) : ARRAY_SIZE(dsp2_pwroff_seq);
>>>> +
>>>> + ret = qps615_pwrctl_i2c_bulk_write(ctx->client, seq, len);
>>>> + if (ret)
>>>> + return ret;
>>>> +
>>>> + return qps615_pwrctl_i2c_bulk_write(ctx->client,
>>>> + common_pwroff_seq, ARRAY_SIZE(common_pwroff_seq));
>>>> +}
>>>> +
>>>> +static int qps615_pwrctl_set_l0s_l1_entry_delay(struct qps615_pwrctl_ctx *ctx,
>>>> + enum qps615_pwrctl_ports port, bool is_l1, u32 ns)
>>>> +{
>>>> + u32 rd_val, units;
>>>> + int ret;
>>>> +
>>>> + /* convert to units of 256ns */
>>>> + units = ns / 256;
>>>> +
>>>> + if (port == QPS615_ETHERNET) {
>>>> + ret = qps615_pwrctl_i2c_read(ctx->client, QPS615_EMBEDDED_ETH_DELAY, &rd_val);
>>>> + if (ret)
>>>> + return ret;
>>>> + rd_val = u32_replace_bits(rd_val, units,
>>>> + is_l1 ?
>>>> + QPS615_ETH_L1_DELAY_MASK : QPS615_ETH_L0S_DELAY_MASK);
>>>> + return qps615_pwrctl_i2c_write(ctx->client, QPS615_EMBEDDED_ETH_DELAY, rd_val);
>>>> + }
>>>> +
>>>> + ret = qps615_pwrctl_i2c_write(ctx->client, QPS615_PORT_SELECT, BIT(port));
>>>> + if (ret)
>>>> + return ret;
>>>
>>> What if there is a concurrent call? The port_select / write_value
>>> statements should use a lock to remove the possible race condition.
>>>
>> There should not be any concurrent calls since all calls come from the
>> probe itself.
>
> Comment this in the driver, since somebody might decide to call the function later
ack
>
>>>> +
>>>> + return qps615_pwrctl_i2c_write(ctx->client,
>>>> + is_l1 ? QPS615_PORT_L1_DELAY : QPS615_PORT_L0S_DELAY, units);
>>>> +}
>>>> +
>>>> +static int qps615_pwrctl_set_tx_amplitude(struct qps615_pwrctl_ctx *ctx,
>>>> + enum qps615_pwrctl_ports port, u32 amp)
>>>> +{
>>>> + int port_access;
>>>> +
>>>> + switch (port) {
>>>> + case QPS615_USP:
>>>> + port_access = 0x1;
>>>> + break;
>>>> + case QPS615_DSP1:
>>>> + port_access = 0x2;
>>>> + break;
>>>> + case QPS615_DSP2:
>>>> + port_access = 0x8;
>>>> + break;
>>>> + default:
>>>> + return -EINVAL;
>>>> + };
>>>> +
>>>> + struct qps615_pwrctl_reg_setting tx_amp_seq[] = {
>>>> + {QPS615_PORT_ACCESS_ENABLE, port_access},
>>>
>>> Hmm, this looks like another port selection, so most likely it should
>>> also be under the same lock.
>>>
>>>> + {QPS615_PORT_LANE_ACCESS_ENABLE, 0x3},
>>>> + {QPS615_TX_MARGIN, amp},
>>>> + };
>>>> +
>>>> + return qps615_pwrctl_i2c_bulk_write(ctx->client, tx_amp_seq, ARRAY_SIZE(tx_amp_seq));
>>>> +}
>>>> +
>>>> +static int qps615_pwrctl_disable_dfe(struct qps615_pwrctl_ctx *ctx,
>>>> + enum qps615_pwrctl_ports port)
>>>> +{
>>>> + int port_access, lane_access = 0x3;
>>>> + u32 phy_rate = 0x21;
>>>> +
>>>> + switch (port) {
>>>> + case QPS615_USP:
>>>> + phy_rate = 0x1;
>>>> + port_access = 0x1;
>>>> + break;
>>>> + case QPS615_DSP1:
>>>> + port_access = 0x2;
>>>> + break;
>>>> + case QPS615_DSP2:
>>>> + port_access = 0x8;
>>>> + lane_access = 0x1;
>>>> + break;
>>>> + default:
>>>> + return -EINVAL;
>>>> + };
>>>> +
>>>> + struct qps615_pwrctl_reg_setting disable_dfe_seq[] = {
>>>> + {QPS615_PORT_ACCESS_ENABLE, port_access},
>>>> + {QPS615_PORT_LANE_ACCESS_ENABLE, lane_access},
>>>> + {QPS615_DFE_ENABLE, 0x0},
>>>> + {QPS615_DFE_EQ0_MODE, 0x411},
>>>> + {QPS615_DFE_EQ1_MODE, 0x11},
>>>> + {QPS615_DFE_EQ2_MODE, 0x11},
>>>> + {QPS615_DFE_PD_MASK, 0x7},
>>>> + {QPS615_PHY_RATE_CHANGE_OVERRIDE, 0x10},
>>>> + {QPS615_PHY_RATE_CHANGE, phy_rate},
>>>> + {QPS615_PHY_RATE_CHANGE, 0x0},
>>>> + {QPS615_PHY_RATE_CHANGE_OVERRIDE, 0x0},
>>>> +
>>>> + };
>>>> +
>>>> + return qps615_pwrctl_i2c_bulk_write(ctx->client,
>>>> + disable_dfe_seq, ARRAY_SIZE(disable_dfe_seq));
>>>> +}
>>>> +
>>>> +static int qps615_pwrctl_set_nfts(struct qps615_pwrctl_ctx *ctx,
>>>> + enum qps615_pwrctl_ports port, u32 nfts)
>>>> +{
>>>> + int ret;
>>>> + struct qps615_pwrctl_reg_setting nfts_seq[] = {
>>>> + {QPS615_NFTS_2_5_GT, nfts},
>>>> + {QPS615_NFTS_5_GT, nfts},
>>>> + };
>>>> +
>>>> + ret = qps615_pwrctl_i2c_write(ctx->client, QPS615_PORT_SELECT, BIT(port));
>>>> + if (ret)
>>>> + return ret;
>>>> +
>>>> + return qps615_pwrctl_i2c_bulk_write(ctx->client, nfts_seq, ARRAY_SIZE(nfts_seq));
>>>> +}
>>>> +
>>>> +static int qps615_pwrctl_assert_deassert_reset(struct qps615_pwrctl_ctx *ctx, bool deassert)
>>>> +{
>>>> + int ret, val = 0;
>>>> +
>>>> + if (deassert)
>>>> + val = 0xc;
>>>> +
>>>> + ret = qps615_pwrctl_i2c_write(ctx->client, QPS615_GPIO_CONFIG, 0xfffffff3);
>>>
>>> It's a kind of magic
>>>
>> I will add a macro in next patch.
>>>> + if (ret)
>>>> + return ret;
>>>> +
>>>> + return qps615_pwrctl_i2c_write(ctx->client, QPS615_RESET_GPIO, val);
>>>> +}
>>>> +
>>>> +static int qps615_pwrctl_parse_device_dt(struct qps615_pwrctl_ctx *ctx, struct device_node *node)
>>>> +{
>>>> + enum qps615_pwrctl_ports port;
>>>> + struct qps615_pwrctl_cfg *cfg;
>>>> + struct device_node *np;
>>>> + int bdf, fun_no;
>>>> +
>>>> + bdf = of_pci_get_bdf(node);
>>>> + if (bdf < 0) {
>>>
>>> This is incorrect, it will fail if at any point BDF uses the most
>>> significant bit (which is permitted by the spec, if I'm not mistaken).
>>>
>> As per the reg property as described in the binding document we are not
>> expecting any change here.
>> https://elixir.bootlin.com/linux/v6.10.3/source/Documentation/devicetree/bindings/pci/pci.txt#L50.
>
> What will this function return if the bus no is 256?
> The supported PCI bus number is from 0x0 to 0xff only. so we
are not expecting any numbers greater than 0xff.
> Also please either move the function to the generic PCI code is change its name to match the rest of the driver. The of_pci_ prefix is reserved for the generic code.
>
ack.
>
>>>> + dev_err(ctx->pwrctl.dev, "Getting BDF failed\n");
>>>> + return 0;
>>>> + }
>>>> +
>>>> + fun_no = bdf & 0x7;
>>>
>>> I assume that ARI is not supported?
>>>
>> Yes this doesn't support ARI.
>>>> +
>>>> + /* In multi function node, ignore function 1 node */
>>>> + if (of_pci_get_bdf(of_get_parent(node)) == ctx->bdf->dsp3_bdf && !fun_no)
>>>> + port = QPS615_ETHERNET;
>>>> + else if (bdf == ctx->bdf->usp_bdf)
>>>> + port = QPS615_USP;
>>>
>>> The function is being called for child device nodes. Thus upstream
>>> facing port (I assume that this is what USP means) can not be enumerated
>>> in this way.
>> Sorry, but I didn't your question.
>>
>> These settings will not affect the enumeration sequence these are
>> for configuring ports only.
>
> You are handling the case of bdf equal to the USP. Is it possible at all?
>
at the time of the configuration the PCI link is not enabled yet,
once we are done with the configurations only we are resumeing the link
training. so when we start this configuration the link is not up yet.
>
>>>
>>>> + else if (bdf == ctx->bdf->dsp1_bdf)
>>>> + port = QPS615_DSP1;
>>>> + else if (bdf == ctx->bdf->dsp2_bdf)
>>>> + port = QPS615_DSP2;
>>>> + else if (bdf == ctx->bdf->dsp3_bdf)
>>>> + port = QPS615_DSP3;
>>>> + else
>>>> + return 0;
>>>
>>> -EINVAL >
>> There are can be nodes describing endpoints also,
>> for those nodes bdf will not match and we are not
>> returning since it is expected for endpoint nodes.
>
> Which endpoints? Bindings don't describe them.
>
The client drivers like ethernet will add them once
this series is merged. Their drivers are not present
in the linux as of now.
>
>>
>>>> +
>>>> + cfg = &ctx->cfg[port];
>>>> +
>>>> + if (!of_device_is_available(node)) {
>>>> + cfg->disable_port = true;
>>>> + return 0;
>>>> + };
>>>> +
>>>> + of_property_read_u32(node, "qcom,axi-clk-freq-hz", &cfg->axi_freq);
>>>> +
>>>> + of_property_read_u32(node, "qcom,l0s-entry-delay-ns", &cfg->l0s_delay);
>>>> +
>>>> + of_property_read_u32(node, "qcom,l1-entry-delay-ns", &cfg->l1_delay);
>>>> +
>>>> + of_property_read_u32(node, "qcom,tx-amplitude-millivolt", &cfg->tx_amp);
>>>> +
>>>> + cfg->disable_dfe = of_property_read_bool(node, "qcom,no-dfe");
>>>> +
>>>> + of_property_read_u8(node, "qcom,nfts", &cfg->nfts);
>>>> +
>>>> + for_each_child_of_node(node, np)
>>>> + qps615_pwrctl_parse_device_dt(ctx, np);
>>>> +
>>>> + of_node_put(np);
>>>> + return 0;
>>>> +}
>>>> +
>>>> +static void qps615_pwrctl_power_off(struct qps615_pwrctl_ctx *ctx)
>>>> +{
>>>> + gpiod_set_value(ctx->reset_gpio, 1);
>>>> +
>>>> + regulator_bulk_disable(ARRAY_SIZE(ctx->supplies), ctx->supplies);
>>>> +}
>>>> +
>>>> +static int qps615_pwrctl_power_on(struct qps615_pwrctl_ctx *ctx)
>>>> +{
>>>> + struct qps615_pwrctl_cfg *cfg;
>>>> + int ret, i;
>>>> +
>>>> + ret = regulator_bulk_enable(ARRAY_SIZE(ctx->supplies), ctx->supplies);
>>>> + if (ret < 0)
>>>> + return dev_err_probe(ctx->pwrctl.dev, ret, "cannot enable regulators\n");
>>>> +
>>>> + gpiod_set_value(ctx->reset_gpio, 0);
>>>> +
>>>> + if (!ctx->client)
>>>> + return 0;
>>>
>>> really?
>>>
>> Even if we don't do i2c configuration PCIe enumeration will happen, for
>> some reason i2c client is not found, driver ignores the error and return
>> since basic functionality will work.
>
> So what is the point of such misconfiguration? If "something works" even in the default case, then we don't need this driver at all, do we?
>
we need this configuration for better power savings, reduce the AER
errors etc.. if there is no i2c client then that particular platform
doesn't need any configurations required.
> Even worse. With the modular kernels you can not guarantee probe order. However the user expects that if the driver is probed, it has configured the hardware correctly.
> > Linux has special return value for such cases, please return it
instead if 0.
>
ack we will check and return them instead of 0.
- Krishna chaitanya.
>
>>>> +
>>>> + /*
>>>> + * Don't have a way to see if the reset has completed.
>>>> + * Wait for some time.
>>>> + */
>>>> + usleep_range(1000, 1001);
>>>> +
>>>> + ret = qps615_pwrctl_assert_deassert_reset(ctx, false);
>>>> + if (ret)
>>>> + goto out;
>>>> +
>>>> + if (ctx->cfg[QPS615_USP].axi_freq == QPS615_AXI_CLK_FREQ_MHZ) {
>>>> + ret = qps615_pwrctl_i2c_write(ctx->client, QPS615_BUS_CONTROL, BIT(16));
>>>> + if (ret)
>>>> + dev_err(ctx->pwrctl.dev, "Setting axi clk freq failed %d\n", ret);
>>>
>>> AXI, not axi
>>>
>> ack.
>>>> + }
>>>> +
>>>> + for (i = 0; i < QPS615_MAX; i++) {
>>>> + cfg = &ctx->cfg[i];
>>>> + if (cfg->disable_port) {
>>>> + ret = qps615_pwrctl_disable_port(ctx, i);
>>>> + if (ret) {
>>>> + dev_err(ctx->pwrctl.dev, "Disabling port failed\n");
>>>> + goto out;
>>>> + }
>>>> + }
>>>> +
>>>> + if (cfg->l0s_delay) {
>>>> + ret = qps615_pwrctl_set_l0s_l1_entry_delay(ctx, i, false, cfg->l0s_delay);
>>>> + if (ret) {
>>>> + dev_err(ctx->pwrctl.dev, "Setting L0s entry delay failed\n");
>>>> + goto out;
>>>> + }
>>>> + }
>>>> +
>>>> + if (cfg->l1_delay) {
>>>> + ret = qps615_pwrctl_set_l0s_l1_entry_delay(ctx, i, true, cfg->l1_delay);
>>>> + if (ret) {
>>>> + dev_err(ctx->pwrctl.dev, "Setting L1 entry delay failed\n");
>>>> + goto out;
>>>> + }
>>>> + }
>>>> +
>>>> + if (cfg->tx_amp) {
>>>> + ret = qps615_pwrctl_set_tx_amplitude(ctx, i, cfg->tx_amp);
>>>> + if (ret) {
>>>> + dev_err(ctx->pwrctl.dev, "Setting Tx amplitube failed\n");
>>>> + goto out;
>>>> + }
>>>> + }
>>>> +
>>>> + if (cfg->nfts) {
>>>> + ret = qps615_pwrctl_set_nfts(ctx, i, cfg->nfts);
>>>> + if (ret) {
>>>> + dev_err(ctx->pwrctl.dev, "Setting nfts failed\n");
>>>> + goto out;
>>>> + }
>>>> + }
>>>> +
>>>> + if (cfg->disable_dfe) {
>>>> + ret = qps615_pwrctl_disable_dfe(ctx, i);
>>>> + if (ret) {
>>>> + dev_err(ctx->pwrctl.dev, "Disabling DFE failed\n");
>>>> + goto out;
>>>> + }
>>>> + }
>>>> + }
>>>> +
>>>> + ret = qps615_pwrctl_assert_deassert_reset(ctx, true);
>>>> + if (!ret)
>>>> + return 0;
>>>> +
>>>> +out:
>>>> + qps615_pwrctl_power_off(ctx);
>>>> + return ret;
>>>> +}
>>>> +
>>>> +static int qps615_pwrctl_probe(struct platform_device *pdev)
>>>> +{
>>>> + struct device *dev = &pdev->dev;
>>>> + struct pci_host_bridge *bridge;
>>>> + struct qps615_pwrctl_ctx *ctx;
>>>> + struct device_node *node;
>>>> + struct pci_bus *bus;
>>>> + int ret;
>>>> +
>>>> + bus = pci_find_bus(of_get_pci_domain_nr(dev->parent->of_node), 0);
>>>> + if (!bus)
>>>> + return -ENODEV;
>>>> +
>>>> + bridge = pci_find_host_bridge(bus);
>>>> +
>>>> + ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL);
>>>> + if (!ctx)
>>>> + return -ENOMEM;
>>>> +
>>>> + node = of_parse_phandle(pdev->dev.of_node, "qcom,qps615-controller", 0);
>>>> + if (node) {
>>>
>>> And if !node?
>>>
>>>> + ctx->client = of_find_i2c_device_by_node(node);
>>>
>>> Leaks the reference count, see the comment at the function definition.
>>> Also what if the I2C bus gets unbound? Will it crash the driver?
>>>
>> I will fix in next patch.
>>
>> Driver is not expected to crash when i2c bus gets unbound.
>> It should be properly handled in i2c driver.
>
> Please verify it.
>
>
>>
>> - Krishna Chaitanya.
>>>> + of_node_put(node);
>>>> + if (!ctx->client)
>>>> + return dev_err_probe(dev, -EPROBE_DEFER,
>>>> + "failed to parse qcom,qps615-controller\n");
>>>> + }
>>>> +
>>>> + ctx->bdf = of_device_get_match_data(dev);
>>>> + ctx->pwrctl.dev = dev;
>>>> +
>>>> + ctx->supplies[0].supply = "vddc";
>>>> + ctx->supplies[1].supply = "vdd18";
>>>> + ctx->supplies[2].supply = "vdd09";
>>>> + ctx->supplies[3].supply = "vddio1";
>>>> + ctx->supplies[4].supply = "vddio2";
>>>> + ctx->supplies[5].supply = "vddio18";
>>>> + ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(ctx->supplies), ctx->supplies);
>>>> + if (ret)
>>>> + return dev_err_probe(dev, ret,
>>>> + "failed to get supply regulator\n");
>>>> +
>>>> + ctx->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_ASIS);
>>>> + if (IS_ERR(ctx->reset_gpio))
>>>> + return dev_err_probe(dev, PTR_ERR(ctx->reset_gpio), "failed to get reset GPIO\n");
>>>> +
>>>> + ctx->link = device_link_add(&bridge->dev, dev, DL_FLAG_AUTOREMOVE_CONSUMER);
>>>> +
>>>> + platform_set_drvdata(pdev, ctx);
>>>> +
>>>> + qps615_pwrctl_parse_device_dt(ctx, pdev->dev.of_node);
>>>> +
>>>> + if (bridge->ops->stop_link)
>>>> + bridge->ops->stop_link(bus);
>>>> +
>>>> + ret = qps615_pwrctl_power_on(ctx);
>>>> + if (ret)
>>>> + return ret;
>>>> +
>>>> + if (bridge->ops->start_link) {
>>>> + ret = bridge->ops->start_link(bus);
>>>> + if (ret)
>>>> + return ret;
>>>> + }
>>>> +
>>>> + return devm_pci_pwrctl_device_set_ready(dev, &ctx->pwrctl);
>>>> +}
>>>> +
>>>> +static void qps615_pwrctl_remove(struct platform_device *pdev)
>>>> +{
>>>> + struct device *dev = &pdev->dev;
>>>> + struct qps615_pwrctl_ctx *ctx = dev_get_drvdata(dev);
>>>> +
>>>> + device_link_del(ctx->link);
>>>> + qps615_pwrctl_power_off(ctx);
>>>> +}
>>>> +
>>>> +static const struct qps615_pwrctl_bdf_info bdf_info = {
>>>> + .usp_bdf = 0x100,
>>>> + .dsp1_bdf = 0x208,
>>>> + .dsp2_bdf = 0x210,
>>>> + .dsp3_bdf = 0x218,
>>>> +};
>>>> +
>>>> +static const struct of_device_id qps615_pwrctl_of_match[] = {
>>>> + { .compatible = "pci1179,0623", .data = &bdf_info },
>>>> + { }
>>>> +};
>>>> +MODULE_DEVICE_TABLE(of, qps615_pwrctl_of_match);
>>>> +
>>>> +static struct platform_driver qps615_pwrctl_driver = {
>>>> + .driver = {
>>>> + .name = "pwrctl-qps615",
>>>> + .of_match_table = qps615_pwrctl_of_match,
>>>> + .probe_type = PROBE_PREFER_ASYNCHRONOUS,
>>>> + },
>>>> + .probe = qps615_pwrctl_probe,
>>>> + .remove_new = qps615_pwrctl_remove,
>>>> +};
>>>> +module_platform_driver(qps615_pwrctl_driver);
>>>> +
>>>> +MODULE_AUTHOR("Krishna chaitanya chundru <quic_krichai@quicinc.com>");
>>>> +MODULE_DESCRIPTION("Qualcomm QPS615 power control driver");
>>>> +MODULE_LICENSE("GPL");
>>>>
>>>> --
>>>> 2.34.1
>>>>
>>>
>
>
^ permalink raw reply [flat|nested] 77+ messages in thread
* Re: [PATCH v2 8/8] PCI: pwrctl: Add power control driver for qps615
2024-09-02 7:12 ` Krishna Chaitanya Chundru
@ 2024-09-02 7:20 ` Dmitry Baryshkov
2024-09-02 8:31 ` Krishna Chaitanya Chundru
0 siblings, 1 reply; 77+ messages in thread
From: Dmitry Baryshkov @ 2024-09-02 7:20 UTC (permalink / raw)
To: Krishna Chaitanya Chundru
Cc: Lorenzo Pieralisi, Krzysztof Wilczyński, Rob Herring,
Bjorn Helgaas, Krzysztof Kozlowski, Conor Dooley, Konrad Dybcio,
cros-qcom-dts-watchers, Bartosz Golaszewski, Jingoo Han,
Manivannan Sadhasivam, andersson, quic_vbadigan, linux-arm-msm,
linux-pci, devicetree, linux-kernel, Bartosz Golaszewski
On Mon, 2 Sept 2024 at 10:13, Krishna Chaitanya Chundru
<quic_krichai@quicinc.com> wrote:
>
>
>
> On 8/8/2024 9:00 AM, Dmitry Baryshkov wrote:
> > On August 5, 2024 1:14:47 PM GMT+07:00, Krishna Chaitanya Chundru <quic_krichai@quicinc.com> wrote:
> >>
> >>
> >> On 8/3/2024 5:04 PM, Dmitry Baryshkov wrote:
> >>> On Sat, Aug 03, 2024 at 08:52:54AM GMT, Krishna chaitanya chundru wrote:
> >>>> QPS615 switch needs to be configured after powering on and before
> >>>> PCIe link was up.
> >>>>
> >>>> As the PCIe controller driver already enables the PCIe link training
> >>>> at the host side, stop the link training. Otherwise the moment we turn
> >>>> on the switch it will participate in the link training and link may come
> >>>> up before switch is configured through i2c.
> >>>>
> >>>> The device tree properties are parsed per node under pci-pci bridge in the
> >>>> driver. Each node has unique bdf value in the reg property, driver
> >>>> uses this bdf to differentiate ports, as there are certain i2c writes to
> >>>> select particular port.
> >>>>
> >>>> Based up on dt property and port, qps615 is configured through i2c.
> >>>>
> >>>> Signed-off-by: Krishna chaitanya chundru <quic_krichai@quicinc.com>
> >>>> ---
> >>>> drivers/pci/pwrctl/Kconfig | 7 +
> >>>> drivers/pci/pwrctl/Makefile | 1 +
> >>>> drivers/pci/pwrctl/pci-pwrctl-qps615.c | 638 +++++++++++++++++++++++++++++++++
> >>>> 3 files changed, 646 insertions(+)
> >>>>
> >>>> diff --git a/drivers/pci/pwrctl/Kconfig b/drivers/pci/pwrctl/Kconfig
> >>>> index 54589bb2403b..6a1352af918c 100644
> >>>> --- a/drivers/pci/pwrctl/Kconfig
> >>>> +++ b/drivers/pci/pwrctl/Kconfig
> >>>> @@ -10,3 +10,10 @@ config PCI_PWRCTL_PWRSEQ
> >>>> tristate
> >>>> select POWER_SEQUENCING
> >>>> select PCI_PWRCTL
> >>>> +
> >>>> +config PCI_PWRCTL_QPS615
> >>>> + tristate "PCI Power Control driver for QPS615"
> >>>> + select PCI_PWRCTL
> >>>> + help
> >>>> + Say Y here to enable the pwrctl driver for Qualcomm
> >>>> + QPS615 PCIe switch.
> >>>> diff --git a/drivers/pci/pwrctl/Makefile b/drivers/pci/pwrctl/Makefile
> >>>> index d308aae4800c..ac563a70c023 100644
> >>>> --- a/drivers/pci/pwrctl/Makefile
> >>>> +++ b/drivers/pci/pwrctl/Makefile
> >>>> @@ -4,3 +4,4 @@ obj-$(CONFIG_PCI_PWRCTL) += pci-pwrctl-core.o
> >>>> pci-pwrctl-core-y := core.o
> >>>> obj-$(CONFIG_PCI_PWRCTL_PWRSEQ) += pci-pwrctl-pwrseq.o
> >>>> +obj-$(CONFIG_PCI_PWRCTL_QPS615) += pci-pwrctl-qps615.o
> >>>> diff --git a/drivers/pci/pwrctl/pci-pwrctl-qps615.c b/drivers/pci/pwrctl/pci-pwrctl-qps615.c
> >>>> new file mode 100644
> >>>> index 000000000000..9dabb82787d5
> >>>> --- /dev/null
> >>>> +++ b/drivers/pci/pwrctl/pci-pwrctl-qps615.c
> >>>> @@ -0,0 +1,638 @@
> >>>> +// SPDX-License-Identifier: GPL-2.0-only
> >>>> +/*
> >>>> + * Copyright (c) 2024 Qualcomm Innovation Center, Inc. All rights reserved.
> >>>> + */
> >>>> +
> >>>> +#include <linux/delay.h>
> >>>> +#include <linux/device.h>
> >>>> +#include <linux/firmware.h>
> >>>> +#include <linux/i2c.h>
> >>>> +#include <linux/mod_devicetable.h>
> >>>> +#include <linux/module.h>
> >>>> +#include <linux/of.h>
> >>>> +#include <linux/pci.h>
> >>>> +#include <linux/pci-pwrctl.h>
> >>>> +#include <linux/platform_device.h>
> >>>> +#include <linux/regulator/consumer.h>
> >>>> +#include <linux/string.h>
> >>>> +#include <linux/types.h>
> >>>> +
> >>>> +#include "../pci.h"
> >>>> +
> >>>> +#define QPS615_GPIO_CONFIG 0x801208
> >>>> +#define QPS615_RESET_GPIO 0x801210
> >>>> +
> >>>> +#define QPS615_BUS_CONTROL 0x801014
> >>>> +
> >>>> +#define QPS615_PORT_L0S_DELAY 0x82496c
> >>>> +#define QPS615_PORT_L1_DELAY 0x824970
> >>>> +
> >>>> +#define QPS615_EMBEDDED_ETH_DELAY 0x8200d8
> >>>> +#define QPS615_ETH_L1_DELAY_MASK GENMASK(27, 18)
> >>>> +#define QPS615_ETH_L1_DELAY_VALUE(x) FIELD_PREP(QPS615_ETH_L1_DELAY_MASK, x)
> >>>> +#define QPS615_ETH_L0S_DELAY_MASK GENMASK(17, 13)
> >>>> +#define QPS615_ETH_L0S_DELAY_VALUE(x) FIELD_PREP(QPS615_ETH_L0S_DELAY_MASK, x)
> >>>> +
> >>>> +#define QPS615_NFTS_2_5_GT 0x824978
> >>>> +#define QPS615_NFTS_5_GT 0x82497c
> >>>> +
> >>>> +#define QPS615_PORT_LANE_ACCESS_ENABLE 0x828000
> >>>> +
> >>>> +#define QPS615_PHY_RATE_CHANGE_OVERRIDE 0x828040
> >>>> +#define QPS615_PHY_RATE_CHANGE 0x828050
> >>>> +
> >>>> +#define QPS615_TX_MARGIN 0x828234
> >>>> +
> >>>> +#define QPS615_DFE_ENABLE 0x828a04
> >>>> +#define QPS615_DFE_EQ0_MODE 0x828a08
> >>>> +#define QPS615_DFE_EQ1_MODE 0x828a0c
> >>>> +#define QPS615_DFE_EQ2_MODE 0x828a14
> >>>> +#define QPS615_DFE_PD_MASK 0x828254
> >>>> +
> >>>> +#define QPS615_PORT_SELECT 0x82c02c
> >>>> +#define QPS615_PORT_ACCESS_ENABLE 0x82c030
> >>>> +
> >>>> +#define QPS615_POWER_CONTROL 0x82b09c
> >>>> +#define QPS615_POWER_CONTROL_OVREN 0x82b2c8
> >>>> +
> >>>> +#define QPS615_AXI_CLK_FREQ_MHZ 125
> >>>> +
> >>>> +struct qps615_pwrctl_reg_setting {
> >>>> + unsigned int offset;
> >>>> + unsigned int val;
> >>>> +};
> >>>> +
> >>>> +struct qps615_pwrctl_bdf_info {
> >>>> + u16 usp_bdf;
> >>>> + u16 dsp1_bdf;
> >>>> + u16 dsp2_bdf;
> >>>> + u16 dsp3_bdf;
> >>>
> >>> Why are these values dynamic? Please use #define's for now. If there
> >>> ever comes a similar bridge, it most likely will have a different ports
> >>> configuration, so it will need additional changes anyway.
> >>>
> >> We added this for future use case only, we felt it is easier to support
> >> at the time if we add this way.
> >
> > Please don't. You are hardcoding distinct roles into the structure that is supposed to be generic. Possible future use cases might have different number of ports or different port roles.
> >
> ok.
> >>
> >>>> +};
> >>>> +
> >>>> +enum qps615_pwrctl_ports {
> >>>> + QPS615_USP,
> >>>> + QPS615_DSP1,
> >>>> + QPS615_DSP2,
> >>>> + QPS615_DSP3,
> >>>> + QPS615_ETHERNET,
> >>>> + QPS615_MAX
> >>>> +};
> >>>> +
> >>>> +struct qps615_pwrctl_cfg {
> >>>> + u32 l0s_delay;
> >>>> + u32 l1_delay;
> >>>> + u32 tx_amp;
> >>>> + u32 axi_freq;
> >>>> + u8 nfts;
> >>>> + bool disable_dfe;
> >>>> + bool disable_port;
> >>>> +};
> >>>> +
> >>>> +#define QPS615_PWRCTL_MAX_SUPPLY 6
> >>>> +
> >>>> +struct qps615_pwrctl_ctx {
> >>>> + struct regulator_bulk_data supplies[QPS615_PWRCTL_MAX_SUPPLY];
> >>>> + const struct qps615_pwrctl_bdf_info *bdf;
> >>>> + struct qps615_pwrctl_cfg cfg[QPS615_MAX];
> >>>> + struct gpio_desc *reset_gpio;
> >>>> + struct i2c_client *client;
> >>>> + struct pci_pwrctl pwrctl;
> >>>> + struct device_link *link;
> >>>> +};
> >>>> +
> >>>> +/*
> >>>> + * downstream port power off sequence, hardcoding the address
> >>>> + * as we don't know register names for these register offsets.
> >>>
> >>> It is hard to believe that Qualcomm engineers don't know register names
> >>> for the Qualcomm device.
> >>>
> >> The switch IP is from the another vendor and the vendor provided these
> >> settings. The databook doesn't have the register names in it.
> >>>> + */
> >>>> +static const struct qps615_pwrctl_reg_setting common_pwroff_seq[] = {
> >>>> + {0x82900c, 0x1},
> >>>> + {0x829010, 0x1},
> >>>> + {0x829018, 0x0},
> >>>> + {0x829020, 0x1},
> >>>> + {0x82902c, 0x1},
> >>>> + {0x829030, 0x1},
> >>>> + {0x82903c, 0x1},
> >>>> + {0x829058, 0x0},
> >>>> + {0x82905c, 0x1},
> >>>> + {0x829060, 0x1},
> >>>> + {0x8290cc, 0x1},
> >>>> + {0x8290d0, 0x1},
> >>>> + {0x8290d8, 0x1},
> >>>> + {0x8290e0, 0x1},
> >>>> + {0x8290e8, 0x1},
> >>>> + {0x8290ec, 0x1},
> >>>> + {0x8290f4, 0x1},
> >>>> + {0x82910c, 0x1},
> >>>> + {0x829110, 0x1},
> >>>> + {0x829114, 0x1},
> >>>> +};
> >>>> +
> >>>> +static const struct qps615_pwrctl_reg_setting dsp1_pwroff_seq[] = {
> >>>> + {QPS615_PORT_ACCESS_ENABLE, 0x2},
> >>>> + {QPS615_PORT_LANE_ACCESS_ENABLE, 0x3},
> >>>> + {QPS615_POWER_CONTROL, 0x014f4804},
> >>>> + {QPS615_POWER_CONTROL_OVREN, 0x1},
> >>>> + {QPS615_PORT_ACCESS_ENABLE, 0x4},
> >>>> +};
> >>>> +
> >>>> +static const struct qps615_pwrctl_reg_setting dsp2_pwroff_seq[] = {
> >>>> + {QPS615_PORT_ACCESS_ENABLE, 0x8},
> >>>> + {QPS615_PORT_LANE_ACCESS_ENABLE, 0x1},
> >>>> + {QPS615_POWER_CONTROL, 0x014f4804},
> >>>> + {QPS615_POWER_CONTROL_OVREN, 0x1},
> >>>> + {QPS615_PORT_ACCESS_ENABLE, 0x8},
> >>>> +};
> >>>> +
> >>>> +static int qps615_pwrctl_i2c_write(struct i2c_client *client,
> >>>> + u32 reg_addr, u32 reg_val)
> >>>> +{
> >>>> + struct i2c_msg msg;
> >>>> + u8 msg_buf[7];
> >>>> + int ret;
> >>>> +
> >>>> + msg.addr = client->addr;
> >>>> + msg.len = 7;
> >>>> + msg.flags = 0;
> >>>> +
> >>>> + /* Big Endian for reg addr */
> >>>> + reg_addr = cpu_to_be32(reg_addr);
> >>>
> >>> This is incorrect. After cpu_to_be32() the value depends on the CPU
> >>> endianness. So reg_addr >> 8 will return different values for LE and BE
> >>> CPUs.
> >>> I had following impression
> >> If reg address is 0x828a0c in big endian sytem it will be 0c8a8200
> >> and in litte endian it will be 0x828a0c only.
> >> If cpu uses big endian cpu_to_be32 will not change this value
> >> and in little endian case cpu_to_be32 will convert 0x828a0c to 0c8a8200.
> >>
> >> Now the output is same for both the systems I tried to use
> >> (reg_addr >> 8) directly.
> >>
> >> Are you saying (reg_addr >> 8) output will be different based upon
> >> LE and BE ? If that is the case I will remove the conversions
> >> in next patch.
> >
> > Reg address is always 0x00828a0c. Then on little-endian system you convert it to to BE32, which results in the value 0x0c8a8200. Finally you use shifts to get {0x82, 0x8a, 0x0c}, which is supposedly correct.
> >
> > On big-endian system cpu_to_be32 returns the same value, 0x00828a0c, since it is BE32 already. So after shifts msg_buf will get {0x8a, 0x82, 0x00}, which is obviously incorrect.
> >
> ack, I will fix them.
> >>>> +
> >>>> + msg_buf[0] = (u8)(reg_addr >> 8);
> >>>> + msg_buf[1] = (u8)(reg_addr >> 16);
> >>>> + msg_buf[2] = (u8)(reg_addr >> 24);
> >>>> +
> >>>> + /* Little Endian for reg val */
> >>>> + reg_val = cpu_to_le32(reg_val);
> >>>> +
> >>>> + msg_buf[3] = (u8)(reg_val);
> >>>> + msg_buf[4] = (u8)(reg_val >> 8);
> >>>> + msg_buf[5] = (u8)(reg_val >> 16);
> >>>> + msg_buf[6] = (u8)(reg_val >> 24);
> >>>
> >>> Same issue here.
> >>>
> >>>> +
> >>>> + msg.buf = msg_buf;
> >>>> + ret = i2c_transfer(client->adapter, &msg, 1);
> >>>> + return ret == 1 ? 0 : ret;
> >>>> +}
> >>>> +
> >>>> +static int qps615_pwrctl_i2c_read(struct i2c_client *client,
> >>>> + u32 reg_addr, u32 *reg_val)
> >>>> +{
> >>>> + struct i2c_msg msg[2];
> >>>> + u8 wr_data[3];
> >>>> + u32 rd_data;
> >>>> + int ret;
> >>>> +
> >>>> + msg[0].addr = client->addr;
> >>>> + msg[0].len = 3;
> >>>> + msg[0].flags = 0;
> >>>> +
> >>>> + /* Big Endian for reg addr */
> >>>> + reg_addr = cpu_to_be32(reg_addr);
> >>>> +
> >>>> + wr_data[0] = (u8)(reg_addr >> 8);
> >>>> + wr_data[1] = (u8)(reg_addr >> 16);
> >>>> + wr_data[2] = (u8)(reg_addr >> 24);
> >>>
> >>> And here.
> >>>
> >>>> +
> >>>> + msg[0].buf = wr_data;
> >>>> +
> >>>> + msg[1].addr = client->addr;
> >>>> + msg[1].len = 4;
> >>>> + msg[1].flags = I2C_M_RD;
> >>>> +
> >>>> + msg[1].buf = (u8 *)&rd_data;
> >>>> +
> >>>> + ret = i2c_transfer(client->adapter, &msg[0], 2);
> >>>> + if (ret == 2) {
> >>>> + *reg_val = le32_to_cpu(rd_data);
> >>>> + return 0;
> >>>> + }
> >>>> +
> >>>> + /* If only one message successfully completed, return -ENODEV */
> >>>> + return ret == 1 ? -ENODEV : ret;
> >>>> +}
> >>>> +
> >>>> +static int qps615_pwrctl_i2c_bulk_write(struct i2c_client *client,
> >>>> + const struct qps615_pwrctl_reg_setting *seq, int len)
> >>>> +{
> >>>> + int ret, i;
> >>>> +
> >>>> + for (i = 0; i < len; i++) {
> >>>> + ret = qps615_pwrctl_i2c_write(client, seq[i].offset, seq[i].val);
> >>>> + if (ret)
> >>>> + return ret;
> >>>> + }
> >>>> +
> >>>> + return 0;
> >>>> +}
> >>>> +
> >>>> +static int of_pci_get_bdf(struct device_node *np)
> >>>> +{
> >>>> + u32 reg[5];
> >>>> + int error;
> >>>> +
> >>>> + error = of_property_read_u32_array(np, "reg", reg, ARRAY_SIZE(reg));
> >>>
> >>> Please use of_property_read_u32_index() instead.
> >>>
> >> ack.
> >>>> + if (error)
> >>>> + return error;
> >>>> +
> >>>> + return (reg[0] >> 8) & 0xffff;
> >>>> +}
> >>>> +
> >>>> +static int qps615_pwrctl_disable_port(struct qps615_pwrctl_ctx *ctx,
> >>>> + enum qps615_pwrctl_ports port)
> >>>> +{
> >>>> + const struct qps615_pwrctl_reg_setting *seq;
> >>>> + int ret, len;
> >>>> +
> >>>> + seq = (port == QPS615_DSP1) ? dsp1_pwroff_seq : dsp2_pwroff_seq;
> >>>> + len = (port == QPS615_DSP1) ? ARRAY_SIZE(dsp1_pwroff_seq) : ARRAY_SIZE(dsp2_pwroff_seq);
> >>>> +
> >>>> + ret = qps615_pwrctl_i2c_bulk_write(ctx->client, seq, len);
> >>>> + if (ret)
> >>>> + return ret;
> >>>> +
> >>>> + return qps615_pwrctl_i2c_bulk_write(ctx->client,
> >>>> + common_pwroff_seq, ARRAY_SIZE(common_pwroff_seq));
> >>>> +}
> >>>> +
> >>>> +static int qps615_pwrctl_set_l0s_l1_entry_delay(struct qps615_pwrctl_ctx *ctx,
> >>>> + enum qps615_pwrctl_ports port, bool is_l1, u32 ns)
> >>>> +{
> >>>> + u32 rd_val, units;
> >>>> + int ret;
> >>>> +
> >>>> + /* convert to units of 256ns */
> >>>> + units = ns / 256;
> >>>> +
> >>>> + if (port == QPS615_ETHERNET) {
> >>>> + ret = qps615_pwrctl_i2c_read(ctx->client, QPS615_EMBEDDED_ETH_DELAY, &rd_val);
> >>>> + if (ret)
> >>>> + return ret;
> >>>> + rd_val = u32_replace_bits(rd_val, units,
> >>>> + is_l1 ?
> >>>> + QPS615_ETH_L1_DELAY_MASK : QPS615_ETH_L0S_DELAY_MASK);
> >>>> + return qps615_pwrctl_i2c_write(ctx->client, QPS615_EMBEDDED_ETH_DELAY, rd_val);
> >>>> + }
> >>>> +
> >>>> + ret = qps615_pwrctl_i2c_write(ctx->client, QPS615_PORT_SELECT, BIT(port));
> >>>> + if (ret)
> >>>> + return ret;
> >>>
> >>> What if there is a concurrent call? The port_select / write_value
> >>> statements should use a lock to remove the possible race condition.
> >>>
> >> There should not be any concurrent calls since all calls come from the
> >> probe itself.
> >
> > Comment this in the driver, since somebody might decide to call the function later
> ack
> >
> >>>> +
> >>>> + return qps615_pwrctl_i2c_write(ctx->client,
> >>>> + is_l1 ? QPS615_PORT_L1_DELAY : QPS615_PORT_L0S_DELAY, units);
> >>>> +}
> >>>> +
> >>>> +static int qps615_pwrctl_set_tx_amplitude(struct qps615_pwrctl_ctx *ctx,
> >>>> + enum qps615_pwrctl_ports port, u32 amp)
> >>>> +{
> >>>> + int port_access;
> >>>> +
> >>>> + switch (port) {
> >>>> + case QPS615_USP:
> >>>> + port_access = 0x1;
> >>>> + break;
> >>>> + case QPS615_DSP1:
> >>>> + port_access = 0x2;
> >>>> + break;
> >>>> + case QPS615_DSP2:
> >>>> + port_access = 0x8;
> >>>> + break;
> >>>> + default:
> >>>> + return -EINVAL;
> >>>> + };
> >>>> +
> >>>> + struct qps615_pwrctl_reg_setting tx_amp_seq[] = {
> >>>> + {QPS615_PORT_ACCESS_ENABLE, port_access},
> >>>
> >>> Hmm, this looks like another port selection, so most likely it should
> >>> also be under the same lock.
> >>>
> >>>> + {QPS615_PORT_LANE_ACCESS_ENABLE, 0x3},
> >>>> + {QPS615_TX_MARGIN, amp},
> >>>> + };
> >>>> +
> >>>> + return qps615_pwrctl_i2c_bulk_write(ctx->client, tx_amp_seq, ARRAY_SIZE(tx_amp_seq));
> >>>> +}
> >>>> +
> >>>> +static int qps615_pwrctl_disable_dfe(struct qps615_pwrctl_ctx *ctx,
> >>>> + enum qps615_pwrctl_ports port)
> >>>> +{
> >>>> + int port_access, lane_access = 0x3;
> >>>> + u32 phy_rate = 0x21;
> >>>> +
> >>>> + switch (port) {
> >>>> + case QPS615_USP:
> >>>> + phy_rate = 0x1;
> >>>> + port_access = 0x1;
> >>>> + break;
> >>>> + case QPS615_DSP1:
> >>>> + port_access = 0x2;
> >>>> + break;
> >>>> + case QPS615_DSP2:
> >>>> + port_access = 0x8;
> >>>> + lane_access = 0x1;
> >>>> + break;
> >>>> + default:
> >>>> + return -EINVAL;
> >>>> + };
> >>>> +
> >>>> + struct qps615_pwrctl_reg_setting disable_dfe_seq[] = {
> >>>> + {QPS615_PORT_ACCESS_ENABLE, port_access},
> >>>> + {QPS615_PORT_LANE_ACCESS_ENABLE, lane_access},
> >>>> + {QPS615_DFE_ENABLE, 0x0},
> >>>> + {QPS615_DFE_EQ0_MODE, 0x411},
> >>>> + {QPS615_DFE_EQ1_MODE, 0x11},
> >>>> + {QPS615_DFE_EQ2_MODE, 0x11},
> >>>> + {QPS615_DFE_PD_MASK, 0x7},
> >>>> + {QPS615_PHY_RATE_CHANGE_OVERRIDE, 0x10},
> >>>> + {QPS615_PHY_RATE_CHANGE, phy_rate},
> >>>> + {QPS615_PHY_RATE_CHANGE, 0x0},
> >>>> + {QPS615_PHY_RATE_CHANGE_OVERRIDE, 0x0},
> >>>> +
> >>>> + };
> >>>> +
> >>>> + return qps615_pwrctl_i2c_bulk_write(ctx->client,
> >>>> + disable_dfe_seq, ARRAY_SIZE(disable_dfe_seq));
> >>>> +}
> >>>> +
> >>>> +static int qps615_pwrctl_set_nfts(struct qps615_pwrctl_ctx *ctx,
> >>>> + enum qps615_pwrctl_ports port, u32 nfts)
> >>>> +{
> >>>> + int ret;
> >>>> + struct qps615_pwrctl_reg_setting nfts_seq[] = {
> >>>> + {QPS615_NFTS_2_5_GT, nfts},
> >>>> + {QPS615_NFTS_5_GT, nfts},
> >>>> + };
> >>>> +
> >>>> + ret = qps615_pwrctl_i2c_write(ctx->client, QPS615_PORT_SELECT, BIT(port));
> >>>> + if (ret)
> >>>> + return ret;
> >>>> +
> >>>> + return qps615_pwrctl_i2c_bulk_write(ctx->client, nfts_seq, ARRAY_SIZE(nfts_seq));
> >>>> +}
> >>>> +
> >>>> +static int qps615_pwrctl_assert_deassert_reset(struct qps615_pwrctl_ctx *ctx, bool deassert)
> >>>> +{
> >>>> + int ret, val = 0;
> >>>> +
> >>>> + if (deassert)
> >>>> + val = 0xc;
> >>>> +
> >>>> + ret = qps615_pwrctl_i2c_write(ctx->client, QPS615_GPIO_CONFIG, 0xfffffff3);
> >>>
> >>> It's a kind of magic
> >>>
> >> I will add a macro in next patch.
> >>>> + if (ret)
> >>>> + return ret;
> >>>> +
> >>>> + return qps615_pwrctl_i2c_write(ctx->client, QPS615_RESET_GPIO, val);
> >>>> +}
> >>>> +
> >>>> +static int qps615_pwrctl_parse_device_dt(struct qps615_pwrctl_ctx *ctx, struct device_node *node)
> >>>> +{
> >>>> + enum qps615_pwrctl_ports port;
> >>>> + struct qps615_pwrctl_cfg *cfg;
> >>>> + struct device_node *np;
> >>>> + int bdf, fun_no;
> >>>> +
> >>>> + bdf = of_pci_get_bdf(node);
> >>>> + if (bdf < 0) {
> >>>
> >>> This is incorrect, it will fail if at any point BDF uses the most
> >>> significant bit (which is permitted by the spec, if I'm not mistaken).
> >>>
> >> As per the reg property as described in the binding document we are not
> >> expecting any change here.
> >> https://elixir.bootlin.com/linux/v6.10.3/source/Documentation/devicetree/bindings/pci/pci.txt#L50.
> >
> > What will this function return if the bus no is 256?
> > The supported PCI bus number is from 0x0 to 0xff only. so we
> are not expecting any numbers greater than 0xff.
> > Also please either move the function to the generic PCI code is change its name to match the rest of the driver. The of_pci_ prefix is reserved for the generic code.
> >
> ack.
> >
> >>>> + dev_err(ctx->pwrctl.dev, "Getting BDF failed\n");
> >>>> + return 0;
> >>>> + }
> >>>> +
> >>>> + fun_no = bdf & 0x7;
> >>>
> >>> I assume that ARI is not supported?
> >>>
> >> Yes this doesn't support ARI.
> >>>> +
> >>>> + /* In multi function node, ignore function 1 node */
> >>>> + if (of_pci_get_bdf(of_get_parent(node)) == ctx->bdf->dsp3_bdf && !fun_no)
> >>>> + port = QPS615_ETHERNET;
> >>>> + else if (bdf == ctx->bdf->usp_bdf)
> >>>> + port = QPS615_USP;
> >>>
> >>> The function is being called for child device nodes. Thus upstream
> >>> facing port (I assume that this is what USP means) can not be enumerated
> >>> in this way.
> >> Sorry, but I didn't your question.
> >>
> >> These settings will not affect the enumeration sequence these are
> >> for configuring ports only.
> >
> > You are handling the case of bdf equal to the USP. Is it possible at all?
> >
> at the time of the configuration the PCI link is not enabled yet,
> once we are done with the configurations only we are resumeing the link
> training. so when we start this configuration the link is not up yet.
Is your answer relevant to the question I have asked?
> >
> >>>
> >>>> + else if (bdf == ctx->bdf->dsp1_bdf)
> >>>> + port = QPS615_DSP1;
> >>>> + else if (bdf == ctx->bdf->dsp2_bdf)
> >>>> + port = QPS615_DSP2;
> >>>> + else if (bdf == ctx->bdf->dsp3_bdf)
> >>>> + port = QPS615_DSP3;
> >>>> + else
> >>>> + return 0;
> >>>
> >>> -EINVAL >
> >> There are can be nodes describing endpoints also,
> >> for those nodes bdf will not match and we are not
> >> returning since it is expected for endpoint nodes.
> >
> > Which endpoints? Bindings don't describe them.
> >
> The client drivers like ethernet will add them once
> this series is merged. Their drivers are not present
> in the linux as of now.
The bindings describe the hardware, not the drivers. Also the driver
should work with the bindings that you have submitted, not some
imaginary to-be-submitted state. Please either update the bindings
within the patchset or fix the driver to return -EINVAL.
> >
> >>
> >>>> +
> >>>> + cfg = &ctx->cfg[port];
> >>>> +
> >>>> + if (!of_device_is_available(node)) {
> >>>> + cfg->disable_port = true;
> >>>> + return 0;
> >>>> + };
> >>>> +
> >>>> + of_property_read_u32(node, "qcom,axi-clk-freq-hz", &cfg->axi_freq);
> >>>> +
> >>>> + of_property_read_u32(node, "qcom,l0s-entry-delay-ns", &cfg->l0s_delay);
> >>>> +
> >>>> + of_property_read_u32(node, "qcom,l1-entry-delay-ns", &cfg->l1_delay);
> >>>> +
> >>>> + of_property_read_u32(node, "qcom,tx-amplitude-millivolt", &cfg->tx_amp);
> >>>> +
> >>>> + cfg->disable_dfe = of_property_read_bool(node, "qcom,no-dfe");
> >>>> +
> >>>> + of_property_read_u8(node, "qcom,nfts", &cfg->nfts);
> >>>> +
> >>>> + for_each_child_of_node(node, np)
> >>>> + qps615_pwrctl_parse_device_dt(ctx, np);
> >>>> +
> >>>> + of_node_put(np);
> >>>> + return 0;
> >>>> +}
> >>>> +
> >>>> +static void qps615_pwrctl_power_off(struct qps615_pwrctl_ctx *ctx)
> >>>> +{
> >>>> + gpiod_set_value(ctx->reset_gpio, 1);
> >>>> +
> >>>> + regulator_bulk_disable(ARRAY_SIZE(ctx->supplies), ctx->supplies);
> >>>> +}
> >>>> +
> >>>> +static int qps615_pwrctl_power_on(struct qps615_pwrctl_ctx *ctx)
> >>>> +{
> >>>> + struct qps615_pwrctl_cfg *cfg;
> >>>> + int ret, i;
> >>>> +
> >>>> + ret = regulator_bulk_enable(ARRAY_SIZE(ctx->supplies), ctx->supplies);
> >>>> + if (ret < 0)
> >>>> + return dev_err_probe(ctx->pwrctl.dev, ret, "cannot enable regulators\n");
> >>>> +
> >>>> + gpiod_set_value(ctx->reset_gpio, 0);
> >>>> +
> >>>> + if (!ctx->client)
> >>>> + return 0;
> >>>
> >>> really?
> >>>
> >> Even if we don't do i2c configuration PCIe enumeration will happen, for
> >> some reason i2c client is not found, driver ignores the error and return
> >> since basic functionality will work.
> >
> > So what is the point of such misconfiguration? If "something works" even in the default case, then we don't need this driver at all, do we?
> >
> we need this configuration for better power savings, reduce the AER
> errors etc.. if there is no i2c client then that particular platform
> doesn't need any configurations required.
NAK. The i2c client is marked as required in the bindings. So there is
no way for the kernel to see the device with no qps615 controller
property.
> > Even worse. With the modular kernels you can not guarantee probe order. However the user expects that if the driver is probed, it has configured the hardware correctly.
> > > Linux has special return value for such cases, please return it
> instead if 0.
> >
> ack we will check and return them instead of 0.
> - Krishna chaitanya.
> >
> >>>> +
> >>>> + /*
> >>>> + * Don't have a way to see if the reset has completed.
> >>>> + * Wait for some time.
> >>>> + */
> >>>> + usleep_range(1000, 1001);
> >>>> +
> >>>> + ret = qps615_pwrctl_assert_deassert_reset(ctx, false);
> >>>> + if (ret)
> >>>> + goto out;
> >>>> +
> >>>> + if (ctx->cfg[QPS615_USP].axi_freq == QPS615_AXI_CLK_FREQ_MHZ) {
> >>>> + ret = qps615_pwrctl_i2c_write(ctx->client, QPS615_BUS_CONTROL, BIT(16));
> >>>> + if (ret)
> >>>> + dev_err(ctx->pwrctl.dev, "Setting axi clk freq failed %d\n", ret);
> >>>
> >>> AXI, not axi
> >>>
> >> ack.
> >>>> + }
> >>>> +
> >>>> + for (i = 0; i < QPS615_MAX; i++) {
> >>>> + cfg = &ctx->cfg[i];
> >>>> + if (cfg->disable_port) {
> >>>> + ret = qps615_pwrctl_disable_port(ctx, i);
> >>>> + if (ret) {
> >>>> + dev_err(ctx->pwrctl.dev, "Disabling port failed\n");
> >>>> + goto out;
> >>>> + }
> >>>> + }
> >>>> +
> >>>> + if (cfg->l0s_delay) {
> >>>> + ret = qps615_pwrctl_set_l0s_l1_entry_delay(ctx, i, false, cfg->l0s_delay);
> >>>> + if (ret) {
> >>>> + dev_err(ctx->pwrctl.dev, "Setting L0s entry delay failed\n");
> >>>> + goto out;
> >>>> + }
> >>>> + }
> >>>> +
> >>>> + if (cfg->l1_delay) {
> >>>> + ret = qps615_pwrctl_set_l0s_l1_entry_delay(ctx, i, true, cfg->l1_delay);
> >>>> + if (ret) {
> >>>> + dev_err(ctx->pwrctl.dev, "Setting L1 entry delay failed\n");
> >>>> + goto out;
> >>>> + }
> >>>> + }
> >>>> +
> >>>> + if (cfg->tx_amp) {
> >>>> + ret = qps615_pwrctl_set_tx_amplitude(ctx, i, cfg->tx_amp);
> >>>> + if (ret) {
> >>>> + dev_err(ctx->pwrctl.dev, "Setting Tx amplitube failed\n");
> >>>> + goto out;
> >>>> + }
> >>>> + }
> >>>> +
> >>>> + if (cfg->nfts) {
> >>>> + ret = qps615_pwrctl_set_nfts(ctx, i, cfg->nfts);
> >>>> + if (ret) {
> >>>> + dev_err(ctx->pwrctl.dev, "Setting nfts failed\n");
> >>>> + goto out;
> >>>> + }
> >>>> + }
> >>>> +
> >>>> + if (cfg->disable_dfe) {
> >>>> + ret = qps615_pwrctl_disable_dfe(ctx, i);
> >>>> + if (ret) {
> >>>> + dev_err(ctx->pwrctl.dev, "Disabling DFE failed\n");
> >>>> + goto out;
> >>>> + }
> >>>> + }
> >>>> + }
> >>>> +
> >>>> + ret = qps615_pwrctl_assert_deassert_reset(ctx, true);
> >>>> + if (!ret)
> >>>> + return 0;
> >>>> +
> >>>> +out:
> >>>> + qps615_pwrctl_power_off(ctx);
> >>>> + return ret;
> >>>> +}
> >>>> +
> >>>> +static int qps615_pwrctl_probe(struct platform_device *pdev)
> >>>> +{
> >>>> + struct device *dev = &pdev->dev;
> >>>> + struct pci_host_bridge *bridge;
> >>>> + struct qps615_pwrctl_ctx *ctx;
> >>>> + struct device_node *node;
> >>>> + struct pci_bus *bus;
> >>>> + int ret;
> >>>> +
> >>>> + bus = pci_find_bus(of_get_pci_domain_nr(dev->parent->of_node), 0);
> >>>> + if (!bus)
> >>>> + return -ENODEV;
> >>>> +
> >>>> + bridge = pci_find_host_bridge(bus);
> >>>> +
> >>>> + ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL);
> >>>> + if (!ctx)
> >>>> + return -ENOMEM;
> >>>> +
> >>>> + node = of_parse_phandle(pdev->dev.of_node, "qcom,qps615-controller", 0);
> >>>> + if (node) {
> >>>
> >>> And if !node?
> >>>
> >>>> + ctx->client = of_find_i2c_device_by_node(node);
> >>>
> >>> Leaks the reference count, see the comment at the function definition.
> >>> Also what if the I2C bus gets unbound? Will it crash the driver?
> >>>
> >> I will fix in next patch.
> >>
> >> Driver is not expected to crash when i2c bus gets unbound.
> >> It should be properly handled in i2c driver.
> >
> > Please verify it.
> >
> >
> >>
> >> - Krishna Chaitanya.
> >>>> + of_node_put(node);
> >>>> + if (!ctx->client)
> >>>> + return dev_err_probe(dev, -EPROBE_DEFER,
> >>>> + "failed to parse qcom,qps615-controller\n");
> >>>> + }
> >>>> +
> >>>> + ctx->bdf = of_device_get_match_data(dev);
> >>>> + ctx->pwrctl.dev = dev;
> >>>> +
> >>>> + ctx->supplies[0].supply = "vddc";
> >>>> + ctx->supplies[1].supply = "vdd18";
> >>>> + ctx->supplies[2].supply = "vdd09";
> >>>> + ctx->supplies[3].supply = "vddio1";
> >>>> + ctx->supplies[4].supply = "vddio2";
> >>>> + ctx->supplies[5].supply = "vddio18";
> >>>> + ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(ctx->supplies), ctx->supplies);
> >>>> + if (ret)
> >>>> + return dev_err_probe(dev, ret,
> >>>> + "failed to get supply regulator\n");
> >>>> +
> >>>> + ctx->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_ASIS);
> >>>> + if (IS_ERR(ctx->reset_gpio))
> >>>> + return dev_err_probe(dev, PTR_ERR(ctx->reset_gpio), "failed to get reset GPIO\n");
> >>>> +
> >>>> + ctx->link = device_link_add(&bridge->dev, dev, DL_FLAG_AUTOREMOVE_CONSUMER);
> >>>> +
> >>>> + platform_set_drvdata(pdev, ctx);
> >>>> +
> >>>> + qps615_pwrctl_parse_device_dt(ctx, pdev->dev.of_node);
> >>>> +
> >>>> + if (bridge->ops->stop_link)
> >>>> + bridge->ops->stop_link(bus);
> >>>> +
> >>>> + ret = qps615_pwrctl_power_on(ctx);
> >>>> + if (ret)
> >>>> + return ret;
> >>>> +
> >>>> + if (bridge->ops->start_link) {
> >>>> + ret = bridge->ops->start_link(bus);
> >>>> + if (ret)
> >>>> + return ret;
> >>>> + }
> >>>> +
> >>>> + return devm_pci_pwrctl_device_set_ready(dev, &ctx->pwrctl);
> >>>> +}
> >>>> +
> >>>> +static void qps615_pwrctl_remove(struct platform_device *pdev)
> >>>> +{
> >>>> + struct device *dev = &pdev->dev;
> >>>> + struct qps615_pwrctl_ctx *ctx = dev_get_drvdata(dev);
> >>>> +
> >>>> + device_link_del(ctx->link);
> >>>> + qps615_pwrctl_power_off(ctx);
> >>>> +}
> >>>> +
> >>>> +static const struct qps615_pwrctl_bdf_info bdf_info = {
> >>>> + .usp_bdf = 0x100,
> >>>> + .dsp1_bdf = 0x208,
> >>>> + .dsp2_bdf = 0x210,
> >>>> + .dsp3_bdf = 0x218,
> >>>> +};
> >>>> +
> >>>> +static const struct of_device_id qps615_pwrctl_of_match[] = {
> >>>> + { .compatible = "pci1179,0623", .data = &bdf_info },
> >>>> + { }
> >>>> +};
> >>>> +MODULE_DEVICE_TABLE(of, qps615_pwrctl_of_match);
> >>>> +
> >>>> +static struct platform_driver qps615_pwrctl_driver = {
> >>>> + .driver = {
> >>>> + .name = "pwrctl-qps615",
> >>>> + .of_match_table = qps615_pwrctl_of_match,
> >>>> + .probe_type = PROBE_PREFER_ASYNCHRONOUS,
> >>>> + },
> >>>> + .probe = qps615_pwrctl_probe,
> >>>> + .remove_new = qps615_pwrctl_remove,
> >>>> +};
> >>>> +module_platform_driver(qps615_pwrctl_driver);
> >>>> +
> >>>> +MODULE_AUTHOR("Krishna chaitanya chundru <quic_krichai@quicinc.com>");
> >>>> +MODULE_DESCRIPTION("Qualcomm QPS615 power control driver");
> >>>> +MODULE_LICENSE("GPL");
> >>>>
> >>>> --
> >>>> 2.34.1
> >>>>
> >>>
> >
> >
--
With best wishes
Dmitry
^ permalink raw reply [flat|nested] 77+ messages in thread
* Re: [PATCH v2 8/8] PCI: pwrctl: Add power control driver for qps615
2024-09-02 7:20 ` Dmitry Baryshkov
@ 2024-09-02 8:31 ` Krishna Chaitanya Chundru
2024-09-02 10:12 ` Dmitry Baryshkov
0 siblings, 1 reply; 77+ messages in thread
From: Krishna Chaitanya Chundru @ 2024-09-02 8:31 UTC (permalink / raw)
To: Dmitry Baryshkov
Cc: Lorenzo Pieralisi, Krzysztof Wilczyński, Rob Herring,
Bjorn Helgaas, Krzysztof Kozlowski, Conor Dooley, Konrad Dybcio,
cros-qcom-dts-watchers, Bartosz Golaszewski, Jingoo Han,
Manivannan Sadhasivam, andersson, quic_vbadigan, linux-arm-msm,
linux-pci, devicetree, linux-kernel, Bartosz Golaszewski
On 9/2/2024 12:50 PM, Dmitry Baryshkov wrote:
> On Mon, 2 Sept 2024 at 10:13, Krishna Chaitanya Chundru
> <quic_krichai@quicinc.com> wrote:
>>
>>
>>
>> On 8/8/2024 9:00 AM, Dmitry Baryshkov wrote:
>>> On August 5, 2024 1:14:47 PM GMT+07:00, Krishna Chaitanya Chundru <quic_krichai@quicinc.com> wrote:
>>>>
>>>>
>>>> On 8/3/2024 5:04 PM, Dmitry Baryshkov wrote:
>>>>> On Sat, Aug 03, 2024 at 08:52:54AM GMT, Krishna chaitanya chundru wrote:
>>>>>> QPS615 switch needs to be configured after powering on and before
>>>>>> PCIe link was up.
>>>>>>
>>>>>> As the PCIe controller driver already enables the PCIe link training
>>>>>> at the host side, stop the link training. Otherwise the moment we turn
>>>>>> on the switch it will participate in the link training and link may come
>>>>>> up before switch is configured through i2c.
>>>>>>
>>>>>> The device tree properties are parsed per node under pci-pci bridge in the
>>>>>> driver. Each node has unique bdf value in the reg property, driver
>>>>>> uses this bdf to differentiate ports, as there are certain i2c writes to
>>>>>> select particular port.
>>>>>>
>>>>>> Based up on dt property and port, qps615 is configured through i2c.
>>>>>>
>>>>>> Signed-off-by: Krishna chaitanya chundru <quic_krichai@quicinc.com>
>>>>>> ---
>>>>>> drivers/pci/pwrctl/Kconfig | 7 +
>>>>>> drivers/pci/pwrctl/Makefile | 1 +
>>>>>> drivers/pci/pwrctl/pci-pwrctl-qps615.c | 638 +++++++++++++++++++++++++++++++++
>>>>>> 3 files changed, 646 insertions(+)
>>>>>>
>>>>>> diff --git a/drivers/pci/pwrctl/Kconfig b/drivers/pci/pwrctl/Kconfig
>>>>>> index 54589bb2403b..6a1352af918c 100644
>>>>>> --- a/drivers/pci/pwrctl/Kconfig
>>>>>> +++ b/drivers/pci/pwrctl/Kconfig
>>>>>> @@ -10,3 +10,10 @@ config PCI_PWRCTL_PWRSEQ
>>>>>> tristate
>>>>>> select POWER_SEQUENCING
>>>>>> select PCI_PWRCTL
>>>>>> +
>>>>>> +config PCI_PWRCTL_QPS615
>>>>>> + tristate "PCI Power Control driver for QPS615"
>>>>>> + select PCI_PWRCTL
>>>>>> + help
>>>>>> + Say Y here to enable the pwrctl driver for Qualcomm
>>>>>> + QPS615 PCIe switch.
>>>>>> diff --git a/drivers/pci/pwrctl/Makefile b/drivers/pci/pwrctl/Makefile
>>>>>> index d308aae4800c..ac563a70c023 100644
>>>>>> --- a/drivers/pci/pwrctl/Makefile
>>>>>> +++ b/drivers/pci/pwrctl/Makefile
>>>>>> @@ -4,3 +4,4 @@ obj-$(CONFIG_PCI_PWRCTL) += pci-pwrctl-core.o
>>>>>> pci-pwrctl-core-y := core.o
>>>>>> obj-$(CONFIG_PCI_PWRCTL_PWRSEQ) += pci-pwrctl-pwrseq.o
>>>>>> +obj-$(CONFIG_PCI_PWRCTL_QPS615) += pci-pwrctl-qps615.o
>>>>>> diff --git a/drivers/pci/pwrctl/pci-pwrctl-qps615.c b/drivers/pci/pwrctl/pci-pwrctl-qps615.c
>>>>>> new file mode 100644
>>>>>> index 000000000000..9dabb82787d5
>>>>>> --- /dev/null
>>>>>> +++ b/drivers/pci/pwrctl/pci-pwrctl-qps615.c
>>>>>> @@ -0,0 +1,638 @@
>>>>>> +// SPDX-License-Identifier: GPL-2.0-only
>>>>>> +/*
>>>>>> + * Copyright (c) 2024 Qualcomm Innovation Center, Inc. All rights reserved.
>>>>>> + */
>>>>>> +
>>>>>> +#include <linux/delay.h>
>>>>>> +#include <linux/device.h>
>>>>>> +#include <linux/firmware.h>
>>>>>> +#include <linux/i2c.h>
>>>>>> +#include <linux/mod_devicetable.h>
>>>>>> +#include <linux/module.h>
>>>>>> +#include <linux/of.h>
>>>>>> +#include <linux/pci.h>
>>>>>> +#include <linux/pci-pwrctl.h>
>>>>>> +#include <linux/platform_device.h>
>>>>>> +#include <linux/regulator/consumer.h>
>>>>>> +#include <linux/string.h>
>>>>>> +#include <linux/types.h>
>>>>>> +
>>>>>> +#include "../pci.h"
>>>>>> +
>>>>>> +#define QPS615_GPIO_CONFIG 0x801208
>>>>>> +#define QPS615_RESET_GPIO 0x801210
>>>>>> +
>>>>>> +#define QPS615_BUS_CONTROL 0x801014
>>>>>> +
>>>>>> +#define QPS615_PORT_L0S_DELAY 0x82496c
>>>>>> +#define QPS615_PORT_L1_DELAY 0x824970
>>>>>> +
>>>>>> +#define QPS615_EMBEDDED_ETH_DELAY 0x8200d8
>>>>>> +#define QPS615_ETH_L1_DELAY_MASK GENMASK(27, 18)
>>>>>> +#define QPS615_ETH_L1_DELAY_VALUE(x) FIELD_PREP(QPS615_ETH_L1_DELAY_MASK, x)
>>>>>> +#define QPS615_ETH_L0S_DELAY_MASK GENMASK(17, 13)
>>>>>> +#define QPS615_ETH_L0S_DELAY_VALUE(x) FIELD_PREP(QPS615_ETH_L0S_DELAY_MASK, x)
>>>>>> +
>>>>>> +#define QPS615_NFTS_2_5_GT 0x824978
>>>>>> +#define QPS615_NFTS_5_GT 0x82497c
>>>>>> +
>>>>>> +#define QPS615_PORT_LANE_ACCESS_ENABLE 0x828000
>>>>>> +
>>>>>> +#define QPS615_PHY_RATE_CHANGE_OVERRIDE 0x828040
>>>>>> +#define QPS615_PHY_RATE_CHANGE 0x828050
>>>>>> +
>>>>>> +#define QPS615_TX_MARGIN 0x828234
>>>>>> +
>>>>>> +#define QPS615_DFE_ENABLE 0x828a04
>>>>>> +#define QPS615_DFE_EQ0_MODE 0x828a08
>>>>>> +#define QPS615_DFE_EQ1_MODE 0x828a0c
>>>>>> +#define QPS615_DFE_EQ2_MODE 0x828a14
>>>>>> +#define QPS615_DFE_PD_MASK 0x828254
>>>>>> +
>>>>>> +#define QPS615_PORT_SELECT 0x82c02c
>>>>>> +#define QPS615_PORT_ACCESS_ENABLE 0x82c030
>>>>>> +
>>>>>> +#define QPS615_POWER_CONTROL 0x82b09c
>>>>>> +#define QPS615_POWER_CONTROL_OVREN 0x82b2c8
>>>>>> +
>>>>>> +#define QPS615_AXI_CLK_FREQ_MHZ 125
>>>>>> +
>>>>>> +struct qps615_pwrctl_reg_setting {
>>>>>> + unsigned int offset;
>>>>>> + unsigned int val;
>>>>>> +};
>>>>>> +
>>>>>> +struct qps615_pwrctl_bdf_info {
>>>>>> + u16 usp_bdf;
>>>>>> + u16 dsp1_bdf;
>>>>>> + u16 dsp2_bdf;
>>>>>> + u16 dsp3_bdf;
>>>>>
>>>>> Why are these values dynamic? Please use #define's for now. If there
>>>>> ever comes a similar bridge, it most likely will have a different ports
>>>>> configuration, so it will need additional changes anyway.
>>>>>
>>>> We added this for future use case only, we felt it is easier to support
>>>> at the time if we add this way.
>>>
>>> Please don't. You are hardcoding distinct roles into the structure that is supposed to be generic. Possible future use cases might have different number of ports or different port roles.
>>>
>> ok.
>>>>
>>>>>> +};
>>>>>> +
>>>>>> +enum qps615_pwrctl_ports {
>>>>>> + QPS615_USP,
>>>>>> + QPS615_DSP1,
>>>>>> + QPS615_DSP2,
>>>>>> + QPS615_DSP3,
>>>>>> + QPS615_ETHERNET,
>>>>>> + QPS615_MAX
>>>>>> +};
>>>>>> +
>>>>>> +struct qps615_pwrctl_cfg {
>>>>>> + u32 l0s_delay;
>>>>>> + u32 l1_delay;
>>>>>> + u32 tx_amp;
>>>>>> + u32 axi_freq;
>>>>>> + u8 nfts;
>>>>>> + bool disable_dfe;
>>>>>> + bool disable_port;
>>>>>> +};
>>>>>> +
>>>>>> +#define QPS615_PWRCTL_MAX_SUPPLY 6
>>>>>> +
>>>>>> +struct qps615_pwrctl_ctx {
>>>>>> + struct regulator_bulk_data supplies[QPS615_PWRCTL_MAX_SUPPLY];
>>>>>> + const struct qps615_pwrctl_bdf_info *bdf;
>>>>>> + struct qps615_pwrctl_cfg cfg[QPS615_MAX];
>>>>>> + struct gpio_desc *reset_gpio;
>>>>>> + struct i2c_client *client;
>>>>>> + struct pci_pwrctl pwrctl;
>>>>>> + struct device_link *link;
>>>>>> +};
>>>>>> +
>>>>>> +/*
>>>>>> + * downstream port power off sequence, hardcoding the address
>>>>>> + * as we don't know register names for these register offsets.
>>>>>
>>>>> It is hard to believe that Qualcomm engineers don't know register names
>>>>> for the Qualcomm device.
>>>>>
>>>> The switch IP is from the another vendor and the vendor provided these
>>>> settings. The databook doesn't have the register names in it.
>>>>>> + */
>>>>>> +static const struct qps615_pwrctl_reg_setting common_pwroff_seq[] = {
>>>>>> + {0x82900c, 0x1},
>>>>>> + {0x829010, 0x1},
>>>>>> + {0x829018, 0x0},
>>>>>> + {0x829020, 0x1},
>>>>>> + {0x82902c, 0x1},
>>>>>> + {0x829030, 0x1},
>>>>>> + {0x82903c, 0x1},
>>>>>> + {0x829058, 0x0},
>>>>>> + {0x82905c, 0x1},
>>>>>> + {0x829060, 0x1},
>>>>>> + {0x8290cc, 0x1},
>>>>>> + {0x8290d0, 0x1},
>>>>>> + {0x8290d8, 0x1},
>>>>>> + {0x8290e0, 0x1},
>>>>>> + {0x8290e8, 0x1},
>>>>>> + {0x8290ec, 0x1},
>>>>>> + {0x8290f4, 0x1},
>>>>>> + {0x82910c, 0x1},
>>>>>> + {0x829110, 0x1},
>>>>>> + {0x829114, 0x1},
>>>>>> +};
>>>>>> +
>>>>>> +static const struct qps615_pwrctl_reg_setting dsp1_pwroff_seq[] = {
>>>>>> + {QPS615_PORT_ACCESS_ENABLE, 0x2},
>>>>>> + {QPS615_PORT_LANE_ACCESS_ENABLE, 0x3},
>>>>>> + {QPS615_POWER_CONTROL, 0x014f4804},
>>>>>> + {QPS615_POWER_CONTROL_OVREN, 0x1},
>>>>>> + {QPS615_PORT_ACCESS_ENABLE, 0x4},
>>>>>> +};
>>>>>> +
>>>>>> +static const struct qps615_pwrctl_reg_setting dsp2_pwroff_seq[] = {
>>>>>> + {QPS615_PORT_ACCESS_ENABLE, 0x8},
>>>>>> + {QPS615_PORT_LANE_ACCESS_ENABLE, 0x1},
>>>>>> + {QPS615_POWER_CONTROL, 0x014f4804},
>>>>>> + {QPS615_POWER_CONTROL_OVREN, 0x1},
>>>>>> + {QPS615_PORT_ACCESS_ENABLE, 0x8},
>>>>>> +};
>>>>>> +
>>>>>> +static int qps615_pwrctl_i2c_write(struct i2c_client *client,
>>>>>> + u32 reg_addr, u32 reg_val)
>>>>>> +{
>>>>>> + struct i2c_msg msg;
>>>>>> + u8 msg_buf[7];
>>>>>> + int ret;
>>>>>> +
>>>>>> + msg.addr = client->addr;
>>>>>> + msg.len = 7;
>>>>>> + msg.flags = 0;
>>>>>> +
>>>>>> + /* Big Endian for reg addr */
>>>>>> + reg_addr = cpu_to_be32(reg_addr);
>>>>>
>>>>> This is incorrect. After cpu_to_be32() the value depends on the CPU
>>>>> endianness. So reg_addr >> 8 will return different values for LE and BE
>>>>> CPUs.
>>>>> I had following impression
>>>> If reg address is 0x828a0c in big endian sytem it will be 0c8a8200
>>>> and in litte endian it will be 0x828a0c only.
>>>> If cpu uses big endian cpu_to_be32 will not change this value
>>>> and in little endian case cpu_to_be32 will convert 0x828a0c to 0c8a8200.
>>>>
>>>> Now the output is same for both the systems I tried to use
>>>> (reg_addr >> 8) directly.
>>>>
>>>> Are you saying (reg_addr >> 8) output will be different based upon
>>>> LE and BE ? If that is the case I will remove the conversions
>>>> in next patch.
>>>
>>> Reg address is always 0x00828a0c. Then on little-endian system you convert it to to BE32, which results in the value 0x0c8a8200. Finally you use shifts to get {0x82, 0x8a, 0x0c}, which is supposedly correct.
>>>
>>> On big-endian system cpu_to_be32 returns the same value, 0x00828a0c, since it is BE32 already. So after shifts msg_buf will get {0x8a, 0x82, 0x00}, which is obviously incorrect.
>>>
>> ack, I will fix them.
>>>>>> +
>>>>>> + msg_buf[0] = (u8)(reg_addr >> 8);
>>>>>> + msg_buf[1] = (u8)(reg_addr >> 16);
>>>>>> + msg_buf[2] = (u8)(reg_addr >> 24);
>>>>>> +
>>>>>> + /* Little Endian for reg val */
>>>>>> + reg_val = cpu_to_le32(reg_val);
>>>>>> +
>>>>>> + msg_buf[3] = (u8)(reg_val);
>>>>>> + msg_buf[4] = (u8)(reg_val >> 8);
>>>>>> + msg_buf[5] = (u8)(reg_val >> 16);
>>>>>> + msg_buf[6] = (u8)(reg_val >> 24);
>>>>>
>>>>> Same issue here.
>>>>>
>>>>>> +
>>>>>> + msg.buf = msg_buf;
>>>>>> + ret = i2c_transfer(client->adapter, &msg, 1);
>>>>>> + return ret == 1 ? 0 : ret;
>>>>>> +}
>>>>>> +
>>>>>> +static int qps615_pwrctl_i2c_read(struct i2c_client *client,
>>>>>> + u32 reg_addr, u32 *reg_val)
>>>>>> +{
>>>>>> + struct i2c_msg msg[2];
>>>>>> + u8 wr_data[3];
>>>>>> + u32 rd_data;
>>>>>> + int ret;
>>>>>> +
>>>>>> + msg[0].addr = client->addr;
>>>>>> + msg[0].len = 3;
>>>>>> + msg[0].flags = 0;
>>>>>> +
>>>>>> + /* Big Endian for reg addr */
>>>>>> + reg_addr = cpu_to_be32(reg_addr);
>>>>>> +
>>>>>> + wr_data[0] = (u8)(reg_addr >> 8);
>>>>>> + wr_data[1] = (u8)(reg_addr >> 16);
>>>>>> + wr_data[2] = (u8)(reg_addr >> 24);
>>>>>
>>>>> And here.
>>>>>
>>>>>> +
>>>>>> + msg[0].buf = wr_data;
>>>>>> +
>>>>>> + msg[1].addr = client->addr;
>>>>>> + msg[1].len = 4;
>>>>>> + msg[1].flags = I2C_M_RD;
>>>>>> +
>>>>>> + msg[1].buf = (u8 *)&rd_data;
>>>>>> +
>>>>>> + ret = i2c_transfer(client->adapter, &msg[0], 2);
>>>>>> + if (ret == 2) {
>>>>>> + *reg_val = le32_to_cpu(rd_data);
>>>>>> + return 0;
>>>>>> + }
>>>>>> +
>>>>>> + /* If only one message successfully completed, return -ENODEV */
>>>>>> + return ret == 1 ? -ENODEV : ret;
>>>>>> +}
>>>>>> +
>>>>>> +static int qps615_pwrctl_i2c_bulk_write(struct i2c_client *client,
>>>>>> + const struct qps615_pwrctl_reg_setting *seq, int len)
>>>>>> +{
>>>>>> + int ret, i;
>>>>>> +
>>>>>> + for (i = 0; i < len; i++) {
>>>>>> + ret = qps615_pwrctl_i2c_write(client, seq[i].offset, seq[i].val);
>>>>>> + if (ret)
>>>>>> + return ret;
>>>>>> + }
>>>>>> +
>>>>>> + return 0;
>>>>>> +}
>>>>>> +
>>>>>> +static int of_pci_get_bdf(struct device_node *np)
>>>>>> +{
>>>>>> + u32 reg[5];
>>>>>> + int error;
>>>>>> +
>>>>>> + error = of_property_read_u32_array(np, "reg", reg, ARRAY_SIZE(reg));
>>>>>
>>>>> Please use of_property_read_u32_index() instead.
>>>>>
>>>> ack.
>>>>>> + if (error)
>>>>>> + return error;
>>>>>> +
>>>>>> + return (reg[0] >> 8) & 0xffff;
>>>>>> +}
>>>>>> +
>>>>>> +static int qps615_pwrctl_disable_port(struct qps615_pwrctl_ctx *ctx,
>>>>>> + enum qps615_pwrctl_ports port)
>>>>>> +{
>>>>>> + const struct qps615_pwrctl_reg_setting *seq;
>>>>>> + int ret, len;
>>>>>> +
>>>>>> + seq = (port == QPS615_DSP1) ? dsp1_pwroff_seq : dsp2_pwroff_seq;
>>>>>> + len = (port == QPS615_DSP1) ? ARRAY_SIZE(dsp1_pwroff_seq) : ARRAY_SIZE(dsp2_pwroff_seq);
>>>>>> +
>>>>>> + ret = qps615_pwrctl_i2c_bulk_write(ctx->client, seq, len);
>>>>>> + if (ret)
>>>>>> + return ret;
>>>>>> +
>>>>>> + return qps615_pwrctl_i2c_bulk_write(ctx->client,
>>>>>> + common_pwroff_seq, ARRAY_SIZE(common_pwroff_seq));
>>>>>> +}
>>>>>> +
>>>>>> +static int qps615_pwrctl_set_l0s_l1_entry_delay(struct qps615_pwrctl_ctx *ctx,
>>>>>> + enum qps615_pwrctl_ports port, bool is_l1, u32 ns)
>>>>>> +{
>>>>>> + u32 rd_val, units;
>>>>>> + int ret;
>>>>>> +
>>>>>> + /* convert to units of 256ns */
>>>>>> + units = ns / 256;
>>>>>> +
>>>>>> + if (port == QPS615_ETHERNET) {
>>>>>> + ret = qps615_pwrctl_i2c_read(ctx->client, QPS615_EMBEDDED_ETH_DELAY, &rd_val);
>>>>>> + if (ret)
>>>>>> + return ret;
>>>>>> + rd_val = u32_replace_bits(rd_val, units,
>>>>>> + is_l1 ?
>>>>>> + QPS615_ETH_L1_DELAY_MASK : QPS615_ETH_L0S_DELAY_MASK);
>>>>>> + return qps615_pwrctl_i2c_write(ctx->client, QPS615_EMBEDDED_ETH_DELAY, rd_val);
>>>>>> + }
>>>>>> +
>>>>>> + ret = qps615_pwrctl_i2c_write(ctx->client, QPS615_PORT_SELECT, BIT(port));
>>>>>> + if (ret)
>>>>>> + return ret;
>>>>>
>>>>> What if there is a concurrent call? The port_select / write_value
>>>>> statements should use a lock to remove the possible race condition.
>>>>>
>>>> There should not be any concurrent calls since all calls come from the
>>>> probe itself.
>>>
>>> Comment this in the driver, since somebody might decide to call the function later
>> ack
>>>
>>>>>> +
>>>>>> + return qps615_pwrctl_i2c_write(ctx->client,
>>>>>> + is_l1 ? QPS615_PORT_L1_DELAY : QPS615_PORT_L0S_DELAY, units);
>>>>>> +}
>>>>>> +
>>>>>> +static int qps615_pwrctl_set_tx_amplitude(struct qps615_pwrctl_ctx *ctx,
>>>>>> + enum qps615_pwrctl_ports port, u32 amp)
>>>>>> +{
>>>>>> + int port_access;
>>>>>> +
>>>>>> + switch (port) {
>>>>>> + case QPS615_USP:
>>>>>> + port_access = 0x1;
>>>>>> + break;
>>>>>> + case QPS615_DSP1:
>>>>>> + port_access = 0x2;
>>>>>> + break;
>>>>>> + case QPS615_DSP2:
>>>>>> + port_access = 0x8;
>>>>>> + break;
>>>>>> + default:
>>>>>> + return -EINVAL;
>>>>>> + };
>>>>>> +
>>>>>> + struct qps615_pwrctl_reg_setting tx_amp_seq[] = {
>>>>>> + {QPS615_PORT_ACCESS_ENABLE, port_access},
>>>>>
>>>>> Hmm, this looks like another port selection, so most likely it should
>>>>> also be under the same lock.
>>>>>
>>>>>> + {QPS615_PORT_LANE_ACCESS_ENABLE, 0x3},
>>>>>> + {QPS615_TX_MARGIN, amp},
>>>>>> + };
>>>>>> +
>>>>>> + return qps615_pwrctl_i2c_bulk_write(ctx->client, tx_amp_seq, ARRAY_SIZE(tx_amp_seq));
>>>>>> +}
>>>>>> +
>>>>>> +static int qps615_pwrctl_disable_dfe(struct qps615_pwrctl_ctx *ctx,
>>>>>> + enum qps615_pwrctl_ports port)
>>>>>> +{
>>>>>> + int port_access, lane_access = 0x3;
>>>>>> + u32 phy_rate = 0x21;
>>>>>> +
>>>>>> + switch (port) {
>>>>>> + case QPS615_USP:
>>>>>> + phy_rate = 0x1;
>>>>>> + port_access = 0x1;
>>>>>> + break;
>>>>>> + case QPS615_DSP1:
>>>>>> + port_access = 0x2;
>>>>>> + break;
>>>>>> + case QPS615_DSP2:
>>>>>> + port_access = 0x8;
>>>>>> + lane_access = 0x1;
>>>>>> + break;
>>>>>> + default:
>>>>>> + return -EINVAL;
>>>>>> + };
>>>>>> +
>>>>>> + struct qps615_pwrctl_reg_setting disable_dfe_seq[] = {
>>>>>> + {QPS615_PORT_ACCESS_ENABLE, port_access},
>>>>>> + {QPS615_PORT_LANE_ACCESS_ENABLE, lane_access},
>>>>>> + {QPS615_DFE_ENABLE, 0x0},
>>>>>> + {QPS615_DFE_EQ0_MODE, 0x411},
>>>>>> + {QPS615_DFE_EQ1_MODE, 0x11},
>>>>>> + {QPS615_DFE_EQ2_MODE, 0x11},
>>>>>> + {QPS615_DFE_PD_MASK, 0x7},
>>>>>> + {QPS615_PHY_RATE_CHANGE_OVERRIDE, 0x10},
>>>>>> + {QPS615_PHY_RATE_CHANGE, phy_rate},
>>>>>> + {QPS615_PHY_RATE_CHANGE, 0x0},
>>>>>> + {QPS615_PHY_RATE_CHANGE_OVERRIDE, 0x0},
>>>>>> +
>>>>>> + };
>>>>>> +
>>>>>> + return qps615_pwrctl_i2c_bulk_write(ctx->client,
>>>>>> + disable_dfe_seq, ARRAY_SIZE(disable_dfe_seq));
>>>>>> +}
>>>>>> +
>>>>>> +static int qps615_pwrctl_set_nfts(struct qps615_pwrctl_ctx *ctx,
>>>>>> + enum qps615_pwrctl_ports port, u32 nfts)
>>>>>> +{
>>>>>> + int ret;
>>>>>> + struct qps615_pwrctl_reg_setting nfts_seq[] = {
>>>>>> + {QPS615_NFTS_2_5_GT, nfts},
>>>>>> + {QPS615_NFTS_5_GT, nfts},
>>>>>> + };
>>>>>> +
>>>>>> + ret = qps615_pwrctl_i2c_write(ctx->client, QPS615_PORT_SELECT, BIT(port));
>>>>>> + if (ret)
>>>>>> + return ret;
>>>>>> +
>>>>>> + return qps615_pwrctl_i2c_bulk_write(ctx->client, nfts_seq, ARRAY_SIZE(nfts_seq));
>>>>>> +}
>>>>>> +
>>>>>> +static int qps615_pwrctl_assert_deassert_reset(struct qps615_pwrctl_ctx *ctx, bool deassert)
>>>>>> +{
>>>>>> + int ret, val = 0;
>>>>>> +
>>>>>> + if (deassert)
>>>>>> + val = 0xc;
>>>>>> +
>>>>>> + ret = qps615_pwrctl_i2c_write(ctx->client, QPS615_GPIO_CONFIG, 0xfffffff3);
>>>>>
>>>>> It's a kind of magic
>>>>>
>>>> I will add a macro in next patch.
>>>>>> + if (ret)
>>>>>> + return ret;
>>>>>> +
>>>>>> + return qps615_pwrctl_i2c_write(ctx->client, QPS615_RESET_GPIO, val);
>>>>>> +}
>>>>>> +
>>>>>> +static int qps615_pwrctl_parse_device_dt(struct qps615_pwrctl_ctx *ctx, struct device_node *node)
>>>>>> +{
>>>>>> + enum qps615_pwrctl_ports port;
>>>>>> + struct qps615_pwrctl_cfg *cfg;
>>>>>> + struct device_node *np;
>>>>>> + int bdf, fun_no;
>>>>>> +
>>>>>> + bdf = of_pci_get_bdf(node);
>>>>>> + if (bdf < 0) {
>>>>>
>>>>> This is incorrect, it will fail if at any point BDF uses the most
>>>>> significant bit (which is permitted by the spec, if I'm not mistaken).
>>>>>
>>>> As per the reg property as described in the binding document we are not
>>>> expecting any change here.
>>>> https://elixir.bootlin.com/linux/v6.10.3/source/Documentation/devicetree/bindings/pci/pci.txt#L50.
>>>
>>> What will this function return if the bus no is 256?
>>> The supported PCI bus number is from 0x0 to 0xff only. so we
>> are not expecting any numbers greater than 0xff.
>>> Also please either move the function to the generic PCI code is change its name to match the rest of the driver. The of_pci_ prefix is reserved for the generic code.
>>>
>> ack.
>>>
>>>>>> + dev_err(ctx->pwrctl.dev, "Getting BDF failed\n");
>>>>>> + return 0;
>>>>>> + }
>>>>>> +
>>>>>> + fun_no = bdf & 0x7;
>>>>>
>>>>> I assume that ARI is not supported?
>>>>>
>>>> Yes this doesn't support ARI.
>>>>>> +
>>>>>> + /* In multi function node, ignore function 1 node */
>>>>>> + if (of_pci_get_bdf(of_get_parent(node)) == ctx->bdf->dsp3_bdf && !fun_no)
>>>>>> + port = QPS615_ETHERNET;
>>>>>> + else if (bdf == ctx->bdf->usp_bdf)
>>>>>> + port = QPS615_USP;
>>>>>
>>>>> The function is being called for child device nodes. Thus upstream
>>>>> facing port (I assume that this is what USP means) can not be enumerated
>>>>> in this way.
>>>> Sorry, but I didn't your question.
>>>>
>>>> These settings will not affect the enumeration sequence these are
>>>> for configuring ports only.
>>>
>>> You are handling the case of bdf equal to the USP. Is it possible at all?
>>>
>> at the time of the configuration the PCI link is not enabled yet,
>> once we are done with the configurations only we are resumeing the link
>> training. so when we start this configuration the link is not up yet.
>
> Is your answer relevant to the question I have asked?
>
sorry dmitry I might got your question wrong. what I understood is
"you are configuring USP port before the link is up, is that possible?"
I might read your statement wrongly.
If the question is "why do we need to configure USP?" I will try to
respond below.
"USP also will have l0s, L1 entry delays, nfts etc which can be
configured".
Sorry once again if your question doesn't fall in both can you tell
me your question.
>>>
>>>>>
>>>>>> + else if (bdf == ctx->bdf->dsp1_bdf)
>>>>>> + port = QPS615_DSP1;
>>>>>> + else if (bdf == ctx->bdf->dsp2_bdf)
>>>>>> + port = QPS615_DSP2;
>>>>>> + else if (bdf == ctx->bdf->dsp3_bdf)
>>>>>> + port = QPS615_DSP3;
>>>>>> + else
>>>>>> + return 0;
>>>>>
>>>>> -EINVAL >
>>>> There are can be nodes describing endpoints also,
>>>> for those nodes bdf will not match and we are not
>>>> returning since it is expected for endpoint nodes.
>>>
>>> Which endpoints? Bindings don't describe them.
>>>
>> The client drivers like ethernet will add them once
>> this series is merged. Their drivers are not present
>> in the linux as of now.
>
> The bindings describe the hardware, not the drivers. Also the driver
> should work with the bindings that you have submitted, not some
> imaginary to-be-submitted state. Please either update the bindings
> within the patchset or fix the driver to return -EINVAL.
>
The qps615 bindings describes only the PCIe switch part,
the endpoints binding connected to the switch should be described by the
respective clients like USB hub, NVMe, ethernet etc bindings should
describe their hardware and its properties. And these bindings will
defined in seperate bindinds file not in qps615 bindings.
for example:-
in the following example pcie@0,0 describes usp and
pcie@1,0 & pcie@2,0 describes dsp's of the switch.
now if we say usb hub is connected to dsp1 i.e to the
node pcie@1,0 there will be a child node to the pcie@1,0
to denote usb hub hardware.
And that node is external to the switch and we are not
configuring it through i2c. As these are pcie devices
representation is generic one we can't say if the client
nodes(in this case usb hub) will be present or not. if the child
node( for example usb hub) is present we can't return -EINVAL
because qps615 will not configure it.
&pcieport {
pcie@0,0 {
pcie@1,0 {
reg = <0x20800 0x0 0x0 0x0 0x0>;
#address-cells = <3>;
#size-cells = <2>;
device_type = "pci";
ranges;
usb_hub@0,0 {
//describes USB hub
};
};
pcie@2,0 {
reg = <0x21000 0x0 0x0 0x0 0x0>;
#address-cells = <3>;
#size-cells = <2>;
device_type = "pci";
ranges;
};
};
};
>>>
>>>>
>>>>>> +
>>>>>> + cfg = &ctx->cfg[port];
>>>>>> +
>>>>>> + if (!of_device_is_available(node)) {
>>>>>> + cfg->disable_port = true;
>>>>>> + return 0;
>>>>>> + };
>>>>>> +
>>>>>> + of_property_read_u32(node, "qcom,axi-clk-freq-hz", &cfg->axi_freq);
>>>>>> +
>>>>>> + of_property_read_u32(node, "qcom,l0s-entry-delay-ns", &cfg->l0s_delay);
>>>>>> +
>>>>>> + of_property_read_u32(node, "qcom,l1-entry-delay-ns", &cfg->l1_delay);
>>>>>> +
>>>>>> + of_property_read_u32(node, "qcom,tx-amplitude-millivolt", &cfg->tx_amp);
>>>>>> +
>>>>>> + cfg->disable_dfe = of_property_read_bool(node, "qcom,no-dfe");
>>>>>> +
>>>>>> + of_property_read_u8(node, "qcom,nfts", &cfg->nfts);
>>>>>> +
>>>>>> + for_each_child_of_node(node, np)
>>>>>> + qps615_pwrctl_parse_device_dt(ctx, np);
>>>>>> +
>>>>>> + of_node_put(np);
>>>>>> + return 0;
>>>>>> +}
>>>>>> +
>>>>>> +static void qps615_pwrctl_power_off(struct qps615_pwrctl_ctx *ctx)
>>>>>> +{
>>>>>> + gpiod_set_value(ctx->reset_gpio, 1);
>>>>>> +
>>>>>> + regulator_bulk_disable(ARRAY_SIZE(ctx->supplies), ctx->supplies);
>>>>>> +}
>>>>>> +
>>>>>> +static int qps615_pwrctl_power_on(struct qps615_pwrctl_ctx *ctx)
>>>>>> +{
>>>>>> + struct qps615_pwrctl_cfg *cfg;
>>>>>> + int ret, i;
>>>>>> +
>>>>>> + ret = regulator_bulk_enable(ARRAY_SIZE(ctx->supplies), ctx->supplies);
>>>>>> + if (ret < 0)
>>>>>> + return dev_err_probe(ctx->pwrctl.dev, ret, "cannot enable regulators\n");
>>>>>> +
>>>>>> + gpiod_set_value(ctx->reset_gpio, 0);
>>>>>> +
>>>>>> + if (!ctx->client)
>>>>>> + return 0;
>>>>>
>>>>> really?
>>>>>
>>>> Even if we don't do i2c configuration PCIe enumeration will happen, for
>>>> some reason i2c client is not found, driver ignores the error and return
>>>> since basic functionality will work.
>>>
>>> So what is the point of such misconfiguration? If "something works" even in the default case, then we don't need this driver at all, do we?
>>>
>> we need this configuration for better power savings, reduce the AER
>> errors etc.. if there is no i2c client then that particular platform
>> doesn't need any configurations required.
>
> NAK. The i2c client is marked as required in the bindings. So there is
> no way for the kernel to see the device with no qps615 controller
> property.
>
agree as it is a required property we should not return 0 here.
I will return proper error value here.
- Krishna chaitanya.
>>> Even worse. With the modular kernels you can not guarantee probe order. However the user expects that if the driver is probed, it has configured the hardware correctly.
>>>> Linux has special return value for such cases, please return it
>> instead if 0.
>>>
>> ack we will check and return them instead of 0.
>> - Krishna chaitanya.
>>>
>>>>>> +
>>>>>> + /*
>>>>>> + * Don't have a way to see if the reset has completed.
>>>>>> + * Wait for some time.
>>>>>> + */
>>>>>> + usleep_range(1000, 1001);
>>>>>> +
>>>>>> + ret = qps615_pwrctl_assert_deassert_reset(ctx, false);
>>>>>> + if (ret)
>>>>>> + goto out;
>>>>>> +
>>>>>> + if (ctx->cfg[QPS615_USP].axi_freq == QPS615_AXI_CLK_FREQ_MHZ) {
>>>>>> + ret = qps615_pwrctl_i2c_write(ctx->client, QPS615_BUS_CONTROL, BIT(16));
>>>>>> + if (ret)
>>>>>> + dev_err(ctx->pwrctl.dev, "Setting axi clk freq failed %d\n", ret);
>>>>>
>>>>> AXI, not axi
>>>>>
>>>> ack.
>>>>>> + }
>>>>>> +
>>>>>> + for (i = 0; i < QPS615_MAX; i++) {
>>>>>> + cfg = &ctx->cfg[i];
>>>>>> + if (cfg->disable_port) {
>>>>>> + ret = qps615_pwrctl_disable_port(ctx, i);
>>>>>> + if (ret) {
>>>>>> + dev_err(ctx->pwrctl.dev, "Disabling port failed\n");
>>>>>> + goto out;
>>>>>> + }
>>>>>> + }
>>>>>> +
>>>>>> + if (cfg->l0s_delay) {
>>>>>> + ret = qps615_pwrctl_set_l0s_l1_entry_delay(ctx, i, false, cfg->l0s_delay);
>>>>>> + if (ret) {
>>>>>> + dev_err(ctx->pwrctl.dev, "Setting L0s entry delay failed\n");
>>>>>> + goto out;
>>>>>> + }
>>>>>> + }
>>>>>> +
>>>>>> + if (cfg->l1_delay) {
>>>>>> + ret = qps615_pwrctl_set_l0s_l1_entry_delay(ctx, i, true, cfg->l1_delay);
>>>>>> + if (ret) {
>>>>>> + dev_err(ctx->pwrctl.dev, "Setting L1 entry delay failed\n");
>>>>>> + goto out;
>>>>>> + }
>>>>>> + }
>>>>>> +
>>>>>> + if (cfg->tx_amp) {
>>>>>> + ret = qps615_pwrctl_set_tx_amplitude(ctx, i, cfg->tx_amp);
>>>>>> + if (ret) {
>>>>>> + dev_err(ctx->pwrctl.dev, "Setting Tx amplitube failed\n");
>>>>>> + goto out;
>>>>>> + }
>>>>>> + }
>>>>>> +
>>>>>> + if (cfg->nfts) {
>>>>>> + ret = qps615_pwrctl_set_nfts(ctx, i, cfg->nfts);
>>>>>> + if (ret) {
>>>>>> + dev_err(ctx->pwrctl.dev, "Setting nfts failed\n");
>>>>>> + goto out;
>>>>>> + }
>>>>>> + }
>>>>>> +
>>>>>> + if (cfg->disable_dfe) {
>>>>>> + ret = qps615_pwrctl_disable_dfe(ctx, i);
>>>>>> + if (ret) {
>>>>>> + dev_err(ctx->pwrctl.dev, "Disabling DFE failed\n");
>>>>>> + goto out;
>>>>>> + }
>>>>>> + }
>>>>>> + }
>>>>>> +
>>>>>> + ret = qps615_pwrctl_assert_deassert_reset(ctx, true);
>>>>>> + if (!ret)
>>>>>> + return 0;
>>>>>> +
>>>>>> +out:
>>>>>> + qps615_pwrctl_power_off(ctx);
>>>>>> + return ret;
>>>>>> +}
>>>>>> +
>>>>>> +static int qps615_pwrctl_probe(struct platform_device *pdev)
>>>>>> +{
>>>>>> + struct device *dev = &pdev->dev;
>>>>>> + struct pci_host_bridge *bridge;
>>>>>> + struct qps615_pwrctl_ctx *ctx;
>>>>>> + struct device_node *node;
>>>>>> + struct pci_bus *bus;
>>>>>> + int ret;
>>>>>> +
>>>>>> + bus = pci_find_bus(of_get_pci_domain_nr(dev->parent->of_node), 0);
>>>>>> + if (!bus)
>>>>>> + return -ENODEV;
>>>>>> +
>>>>>> + bridge = pci_find_host_bridge(bus);
>>>>>> +
>>>>>> + ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL);
>>>>>> + if (!ctx)
>>>>>> + return -ENOMEM;
>>>>>> +
>>>>>> + node = of_parse_phandle(pdev->dev.of_node, "qcom,qps615-controller", 0);
>>>>>> + if (node) {
>>>>>
>>>>> And if !node?
>>>>>
>>>>>> + ctx->client = of_find_i2c_device_by_node(node);
>>>>>
>>>>> Leaks the reference count, see the comment at the function definition.
>>>>> Also what if the I2C bus gets unbound? Will it crash the driver?
>>>>>
>>>> I will fix in next patch.
>>>>
>>>> Driver is not expected to crash when i2c bus gets unbound.
>>>> It should be properly handled in i2c driver.
>>>
>>> Please verify it.
>>>
>>>
>>>>
>>>> - Krishna Chaitanya.
>>>>>> + of_node_put(node);
>>>>>> + if (!ctx->client)
>>>>>> + return dev_err_probe(dev, -EPROBE_DEFER,
>>>>>> + "failed to parse qcom,qps615-controller\n");
>>>>>> + }
>>>>>> +
>>>>>> + ctx->bdf = of_device_get_match_data(dev);
>>>>>> + ctx->pwrctl.dev = dev;
>>>>>> +
>>>>>> + ctx->supplies[0].supply = "vddc";
>>>>>> + ctx->supplies[1].supply = "vdd18";
>>>>>> + ctx->supplies[2].supply = "vdd09";
>>>>>> + ctx->supplies[3].supply = "vddio1";
>>>>>> + ctx->supplies[4].supply = "vddio2";
>>>>>> + ctx->supplies[5].supply = "vddio18";
>>>>>> + ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(ctx->supplies), ctx->supplies);
>>>>>> + if (ret)
>>>>>> + return dev_err_probe(dev, ret,
>>>>>> + "failed to get supply regulator\n");
>>>>>> +
>>>>>> + ctx->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_ASIS);
>>>>>> + if (IS_ERR(ctx->reset_gpio))
>>>>>> + return dev_err_probe(dev, PTR_ERR(ctx->reset_gpio), "failed to get reset GPIO\n");
>>>>>> +
>>>>>> + ctx->link = device_link_add(&bridge->dev, dev, DL_FLAG_AUTOREMOVE_CONSUMER);
>>>>>> +
>>>>>> + platform_set_drvdata(pdev, ctx);
>>>>>> +
>>>>>> + qps615_pwrctl_parse_device_dt(ctx, pdev->dev.of_node);
>>>>>> +
>>>>>> + if (bridge->ops->stop_link)
>>>>>> + bridge->ops->stop_link(bus);
>>>>>> +
>>>>>> + ret = qps615_pwrctl_power_on(ctx);
>>>>>> + if (ret)
>>>>>> + return ret;
>>>>>> +
>>>>>> + if (bridge->ops->start_link) {
>>>>>> + ret = bridge->ops->start_link(bus);
>>>>>> + if (ret)
>>>>>> + return ret;
>>>>>> + }
>>>>>> +
>>>>>> + return devm_pci_pwrctl_device_set_ready(dev, &ctx->pwrctl);
>>>>>> +}
>>>>>> +
>>>>>> +static void qps615_pwrctl_remove(struct platform_device *pdev)
>>>>>> +{
>>>>>> + struct device *dev = &pdev->dev;
>>>>>> + struct qps615_pwrctl_ctx *ctx = dev_get_drvdata(dev);
>>>>>> +
>>>>>> + device_link_del(ctx->link);
>>>>>> + qps615_pwrctl_power_off(ctx);
>>>>>> +}
>>>>>> +
>>>>>> +static const struct qps615_pwrctl_bdf_info bdf_info = {
>>>>>> + .usp_bdf = 0x100,
>>>>>> + .dsp1_bdf = 0x208,
>>>>>> + .dsp2_bdf = 0x210,
>>>>>> + .dsp3_bdf = 0x218,
>>>>>> +};
>>>>>> +
>>>>>> +static const struct of_device_id qps615_pwrctl_of_match[] = {
>>>>>> + { .compatible = "pci1179,0623", .data = &bdf_info },
>>>>>> + { }
>>>>>> +};
>>>>>> +MODULE_DEVICE_TABLE(of, qps615_pwrctl_of_match);
>>>>>> +
>>>>>> +static struct platform_driver qps615_pwrctl_driver = {
>>>>>> + .driver = {
>>>>>> + .name = "pwrctl-qps615",
>>>>>> + .of_match_table = qps615_pwrctl_of_match,
>>>>>> + .probe_type = PROBE_PREFER_ASYNCHRONOUS,
>>>>>> + },
>>>>>> + .probe = qps615_pwrctl_probe,
>>>>>> + .remove_new = qps615_pwrctl_remove,
>>>>>> +};
>>>>>> +module_platform_driver(qps615_pwrctl_driver);
>>>>>> +
>>>>>> +MODULE_AUTHOR("Krishna chaitanya chundru <quic_krichai@quicinc.com>");
>>>>>> +MODULE_DESCRIPTION("Qualcomm QPS615 power control driver");
>>>>>> +MODULE_LICENSE("GPL");
>>>>>>
>>>>>> --
>>>>>> 2.34.1
>>>>>>
>>>>>
>>>
>>>
>
>
>
^ permalink raw reply [flat|nested] 77+ messages in thread
* Re: [PATCH v2 8/8] PCI: pwrctl: Add power control driver for qps615
2024-09-02 8:31 ` Krishna Chaitanya Chundru
@ 2024-09-02 10:12 ` Dmitry Baryshkov
2024-09-02 10:47 ` Krishna Chaitanya Chundru
0 siblings, 1 reply; 77+ messages in thread
From: Dmitry Baryshkov @ 2024-09-02 10:12 UTC (permalink / raw)
To: Krishna Chaitanya Chundru
Cc: Lorenzo Pieralisi, Krzysztof Wilczyński, Rob Herring,
Bjorn Helgaas, Krzysztof Kozlowski, Conor Dooley, Konrad Dybcio,
cros-qcom-dts-watchers, Bartosz Golaszewski, Jingoo Han,
Manivannan Sadhasivam, andersson, quic_vbadigan, linux-arm-msm,
linux-pci, devicetree, linux-kernel, Bartosz Golaszewski
On Mon, 2 Sept 2024 at 11:32, Krishna Chaitanya Chundru
<quic_krichai@quicinc.com> wrote:
>
>
>
> On 9/2/2024 12:50 PM, Dmitry Baryshkov wrote:
> > On Mon, 2 Sept 2024 at 10:13, Krishna Chaitanya Chundru
> > <quic_krichai@quicinc.com> wrote:
> >>
> >>
> >>
> >> On 8/8/2024 9:00 AM, Dmitry Baryshkov wrote:
> >>> On August 5, 2024 1:14:47 PM GMT+07:00, Krishna Chaitanya Chundru <quic_krichai@quicinc.com> wrote:
> >>>>
> >>>>
> >>>> On 8/3/2024 5:04 PM, Dmitry Baryshkov wrote:
> >>>>> On Sat, Aug 03, 2024 at 08:52:54AM GMT, Krishna chaitanya chundru wrote:
> >>>>>> QPS615 switch needs to be configured after powering on and before
> >>>>>> PCIe link was up.
> >>>>>>
> >>>>>> As the PCIe controller driver already enables the PCIe link training
> >>>>>> at the host side, stop the link training. Otherwise the moment we turn
> >>>>>> on the switch it will participate in the link training and link may come
> >>>>>> up before switch is configured through i2c.
> >>>>>>
> >>>>>> The device tree properties are parsed per node under pci-pci bridge in the
> >>>>>> driver. Each node has unique bdf value in the reg property, driver
> >>>>>> uses this bdf to differentiate ports, as there are certain i2c writes to
> >>>>>> select particular port.
> >>>>>>
> >>>>>> Based up on dt property and port, qps615 is configured through i2c.
> >>>>>>
> >>>>>> Signed-off-by: Krishna chaitanya chundru <quic_krichai@quicinc.com>
> >>>>>> ---
> >>>>>> drivers/pci/pwrctl/Kconfig | 7 +
> >>>>>> drivers/pci/pwrctl/Makefile | 1 +
> >>>>>> drivers/pci/pwrctl/pci-pwrctl-qps615.c | 638 +++++++++++++++++++++++++++++++++
> >>>>>> 3 files changed, 646 insertions(+)
> >>>>>>
> >>>>>> diff --git a/drivers/pci/pwrctl/Kconfig b/drivers/pci/pwrctl/Kconfig
> >>>>>> index 54589bb2403b..6a1352af918c 100644
> >>>>>> --- a/drivers/pci/pwrctl/Kconfig
> >>>>>> +++ b/drivers/pci/pwrctl/Kconfig
> >>>>>> @@ -10,3 +10,10 @@ config PCI_PWRCTL_PWRSEQ
> >>>>>> tristate
> >>>>>> select POWER_SEQUENCING
> >>>>>> select PCI_PWRCTL
> >>>>>> +
> >>>>>> +config PCI_PWRCTL_QPS615
> >>>>>> + tristate "PCI Power Control driver for QPS615"
> >>>>>> + select PCI_PWRCTL
> >>>>>> + help
> >>>>>> + Say Y here to enable the pwrctl driver for Qualcomm
> >>>>>> + QPS615 PCIe switch.
> >>>>>> diff --git a/drivers/pci/pwrctl/Makefile b/drivers/pci/pwrctl/Makefile
> >>>>>> index d308aae4800c..ac563a70c023 100644
> >>>>>> --- a/drivers/pci/pwrctl/Makefile
> >>>>>> +++ b/drivers/pci/pwrctl/Makefile
> >>>>>> @@ -4,3 +4,4 @@ obj-$(CONFIG_PCI_PWRCTL) += pci-pwrctl-core.o
> >>>>>> pci-pwrctl-core-y := core.o
> >>>>>> obj-$(CONFIG_PCI_PWRCTL_PWRSEQ) += pci-pwrctl-pwrseq.o
> >>>>>> +obj-$(CONFIG_PCI_PWRCTL_QPS615) += pci-pwrctl-qps615.o
> >>>>>> diff --git a/drivers/pci/pwrctl/pci-pwrctl-qps615.c b/drivers/pci/pwrctl/pci-pwrctl-qps615.c
> >>>>>> new file mode 100644
> >>>>>> index 000000000000..9dabb82787d5
> >>>>>> --- /dev/null
> >>>>>> +++ b/drivers/pci/pwrctl/pci-pwrctl-qps615.c
> >>>>>> @@ -0,0 +1,638 @@
> >>>>>> +// SPDX-License-Identifier: GPL-2.0-only
> >>>>>> +/*
> >>>>>> + * Copyright (c) 2024 Qualcomm Innovation Center, Inc. All rights reserved.
> >>>>>> + */
> >>>>>> +
> >>>>>> +#include <linux/delay.h>
> >>>>>> +#include <linux/device.h>
> >>>>>> +#include <linux/firmware.h>
> >>>>>> +#include <linux/i2c.h>
> >>>>>> +#include <linux/mod_devicetable.h>
> >>>>>> +#include <linux/module.h>
> >>>>>> +#include <linux/of.h>
> >>>>>> +#include <linux/pci.h>
> >>>>>> +#include <linux/pci-pwrctl.h>
> >>>>>> +#include <linux/platform_device.h>
> >>>>>> +#include <linux/regulator/consumer.h>
> >>>>>> +#include <linux/string.h>
> >>>>>> +#include <linux/types.h>
> >>>>>> +
> >>>>>> +#include "../pci.h"
> >>>>>> +
> >>>>>> +#define QPS615_GPIO_CONFIG 0x801208
> >>>>>> +#define QPS615_RESET_GPIO 0x801210
> >>>>>> +
> >>>>>> +#define QPS615_BUS_CONTROL 0x801014
> >>>>>> +
> >>>>>> +#define QPS615_PORT_L0S_DELAY 0x82496c
> >>>>>> +#define QPS615_PORT_L1_DELAY 0x824970
> >>>>>> +
> >>>>>> +#define QPS615_EMBEDDED_ETH_DELAY 0x8200d8
> >>>>>> +#define QPS615_ETH_L1_DELAY_MASK GENMASK(27, 18)
> >>>>>> +#define QPS615_ETH_L1_DELAY_VALUE(x) FIELD_PREP(QPS615_ETH_L1_DELAY_MASK, x)
> >>>>>> +#define QPS615_ETH_L0S_DELAY_MASK GENMASK(17, 13)
> >>>>>> +#define QPS615_ETH_L0S_DELAY_VALUE(x) FIELD_PREP(QPS615_ETH_L0S_DELAY_MASK, x)
> >>>>>> +
> >>>>>> +#define QPS615_NFTS_2_5_GT 0x824978
> >>>>>> +#define QPS615_NFTS_5_GT 0x82497c
> >>>>>> +
> >>>>>> +#define QPS615_PORT_LANE_ACCESS_ENABLE 0x828000
> >>>>>> +
> >>>>>> +#define QPS615_PHY_RATE_CHANGE_OVERRIDE 0x828040
> >>>>>> +#define QPS615_PHY_RATE_CHANGE 0x828050
> >>>>>> +
> >>>>>> +#define QPS615_TX_MARGIN 0x828234
> >>>>>> +
> >>>>>> +#define QPS615_DFE_ENABLE 0x828a04
> >>>>>> +#define QPS615_DFE_EQ0_MODE 0x828a08
> >>>>>> +#define QPS615_DFE_EQ1_MODE 0x828a0c
> >>>>>> +#define QPS615_DFE_EQ2_MODE 0x828a14
> >>>>>> +#define QPS615_DFE_PD_MASK 0x828254
> >>>>>> +
> >>>>>> +#define QPS615_PORT_SELECT 0x82c02c
> >>>>>> +#define QPS615_PORT_ACCESS_ENABLE 0x82c030
> >>>>>> +
> >>>>>> +#define QPS615_POWER_CONTROL 0x82b09c
> >>>>>> +#define QPS615_POWER_CONTROL_OVREN 0x82b2c8
> >>>>>> +
> >>>>>> +#define QPS615_AXI_CLK_FREQ_MHZ 125
> >>>>>> +
> >>>>>> +struct qps615_pwrctl_reg_setting {
> >>>>>> + unsigned int offset;
> >>>>>> + unsigned int val;
> >>>>>> +};
> >>>>>> +
> >>>>>> +struct qps615_pwrctl_bdf_info {
> >>>>>> + u16 usp_bdf;
> >>>>>> + u16 dsp1_bdf;
> >>>>>> + u16 dsp2_bdf;
> >>>>>> + u16 dsp3_bdf;
> >>>>>
> >>>>> Why are these values dynamic? Please use #define's for now. If there
> >>>>> ever comes a similar bridge, it most likely will have a different ports
> >>>>> configuration, so it will need additional changes anyway.
> >>>>>
> >>>> We added this for future use case only, we felt it is easier to support
> >>>> at the time if we add this way.
> >>>
> >>> Please don't. You are hardcoding distinct roles into the structure that is supposed to be generic. Possible future use cases might have different number of ports or different port roles.
> >>>
> >> ok.
> >>>>
> >>>>>> +};
> >>>>>> +
> >>>>>> +enum qps615_pwrctl_ports {
> >>>>>> + QPS615_USP,
> >>>>>> + QPS615_DSP1,
> >>>>>> + QPS615_DSP2,
> >>>>>> + QPS615_DSP3,
> >>>>>> + QPS615_ETHERNET,
> >>>>>> + QPS615_MAX
> >>>>>> +};
> >>>>>> +
> >>>>>> +struct qps615_pwrctl_cfg {
> >>>>>> + u32 l0s_delay;
> >>>>>> + u32 l1_delay;
> >>>>>> + u32 tx_amp;
> >>>>>> + u32 axi_freq;
> >>>>>> + u8 nfts;
> >>>>>> + bool disable_dfe;
> >>>>>> + bool disable_port;
> >>>>>> +};
> >>>>>> +
> >>>>>> +#define QPS615_PWRCTL_MAX_SUPPLY 6
> >>>>>> +
> >>>>>> +struct qps615_pwrctl_ctx {
> >>>>>> + struct regulator_bulk_data supplies[QPS615_PWRCTL_MAX_SUPPLY];
> >>>>>> + const struct qps615_pwrctl_bdf_info *bdf;
> >>>>>> + struct qps615_pwrctl_cfg cfg[QPS615_MAX];
> >>>>>> + struct gpio_desc *reset_gpio;
> >>>>>> + struct i2c_client *client;
> >>>>>> + struct pci_pwrctl pwrctl;
> >>>>>> + struct device_link *link;
> >>>>>> +};
> >>>>>> +
> >>>>>> +/*
> >>>>>> + * downstream port power off sequence, hardcoding the address
> >>>>>> + * as we don't know register names for these register offsets.
> >>>>>
> >>>>> It is hard to believe that Qualcomm engineers don't know register names
> >>>>> for the Qualcomm device.
> >>>>>
> >>>> The switch IP is from the another vendor and the vendor provided these
> >>>> settings. The databook doesn't have the register names in it.
> >>>>>> + */
> >>>>>> +static const struct qps615_pwrctl_reg_setting common_pwroff_seq[] = {
> >>>>>> + {0x82900c, 0x1},
> >>>>>> + {0x829010, 0x1},
> >>>>>> + {0x829018, 0x0},
> >>>>>> + {0x829020, 0x1},
> >>>>>> + {0x82902c, 0x1},
> >>>>>> + {0x829030, 0x1},
> >>>>>> + {0x82903c, 0x1},
> >>>>>> + {0x829058, 0x0},
> >>>>>> + {0x82905c, 0x1},
> >>>>>> + {0x829060, 0x1},
> >>>>>> + {0x8290cc, 0x1},
> >>>>>> + {0x8290d0, 0x1},
> >>>>>> + {0x8290d8, 0x1},
> >>>>>> + {0x8290e0, 0x1},
> >>>>>> + {0x8290e8, 0x1},
> >>>>>> + {0x8290ec, 0x1},
> >>>>>> + {0x8290f4, 0x1},
> >>>>>> + {0x82910c, 0x1},
> >>>>>> + {0x829110, 0x1},
> >>>>>> + {0x829114, 0x1},
> >>>>>> +};
> >>>>>> +
> >>>>>> +static const struct qps615_pwrctl_reg_setting dsp1_pwroff_seq[] = {
> >>>>>> + {QPS615_PORT_ACCESS_ENABLE, 0x2},
> >>>>>> + {QPS615_PORT_LANE_ACCESS_ENABLE, 0x3},
> >>>>>> + {QPS615_POWER_CONTROL, 0x014f4804},
> >>>>>> + {QPS615_POWER_CONTROL_OVREN, 0x1},
> >>>>>> + {QPS615_PORT_ACCESS_ENABLE, 0x4},
> >>>>>> +};
> >>>>>> +
> >>>>>> +static const struct qps615_pwrctl_reg_setting dsp2_pwroff_seq[] = {
> >>>>>> + {QPS615_PORT_ACCESS_ENABLE, 0x8},
> >>>>>> + {QPS615_PORT_LANE_ACCESS_ENABLE, 0x1},
> >>>>>> + {QPS615_POWER_CONTROL, 0x014f4804},
> >>>>>> + {QPS615_POWER_CONTROL_OVREN, 0x1},
> >>>>>> + {QPS615_PORT_ACCESS_ENABLE, 0x8},
> >>>>>> +};
> >>>>>> +
> >>>>>> +static int qps615_pwrctl_i2c_write(struct i2c_client *client,
> >>>>>> + u32 reg_addr, u32 reg_val)
> >>>>>> +{
> >>>>>> + struct i2c_msg msg;
> >>>>>> + u8 msg_buf[7];
> >>>>>> + int ret;
> >>>>>> +
> >>>>>> + msg.addr = client->addr;
> >>>>>> + msg.len = 7;
> >>>>>> + msg.flags = 0;
> >>>>>> +
> >>>>>> + /* Big Endian for reg addr */
> >>>>>> + reg_addr = cpu_to_be32(reg_addr);
> >>>>>
> >>>>> This is incorrect. After cpu_to_be32() the value depends on the CPU
> >>>>> endianness. So reg_addr >> 8 will return different values for LE and BE
> >>>>> CPUs.
> >>>>> I had following impression
> >>>> If reg address is 0x828a0c in big endian sytem it will be 0c8a8200
> >>>> and in litte endian it will be 0x828a0c only.
> >>>> If cpu uses big endian cpu_to_be32 will not change this value
> >>>> and in little endian case cpu_to_be32 will convert 0x828a0c to 0c8a8200.
> >>>>
> >>>> Now the output is same for both the systems I tried to use
> >>>> (reg_addr >> 8) directly.
> >>>>
> >>>> Are you saying (reg_addr >> 8) output will be different based upon
> >>>> LE and BE ? If that is the case I will remove the conversions
> >>>> in next patch.
> >>>
> >>> Reg address is always 0x00828a0c. Then on little-endian system you convert it to to BE32, which results in the value 0x0c8a8200. Finally you use shifts to get {0x82, 0x8a, 0x0c}, which is supposedly correct.
> >>>
> >>> On big-endian system cpu_to_be32 returns the same value, 0x00828a0c, since it is BE32 already. So after shifts msg_buf will get {0x8a, 0x82, 0x00}, which is obviously incorrect.
> >>>
> >> ack, I will fix them.
> >>>>>> +
> >>>>>> + msg_buf[0] = (u8)(reg_addr >> 8);
> >>>>>> + msg_buf[1] = (u8)(reg_addr >> 16);
> >>>>>> + msg_buf[2] = (u8)(reg_addr >> 24);
> >>>>>> +
> >>>>>> + /* Little Endian for reg val */
> >>>>>> + reg_val = cpu_to_le32(reg_val);
> >>>>>> +
> >>>>>> + msg_buf[3] = (u8)(reg_val);
> >>>>>> + msg_buf[4] = (u8)(reg_val >> 8);
> >>>>>> + msg_buf[5] = (u8)(reg_val >> 16);
> >>>>>> + msg_buf[6] = (u8)(reg_val >> 24);
> >>>>>
> >>>>> Same issue here.
> >>>>>
> >>>>>> +
> >>>>>> + msg.buf = msg_buf;
> >>>>>> + ret = i2c_transfer(client->adapter, &msg, 1);
> >>>>>> + return ret == 1 ? 0 : ret;
> >>>>>> +}
> >>>>>> +
> >>>>>> +static int qps615_pwrctl_i2c_read(struct i2c_client *client,
> >>>>>> + u32 reg_addr, u32 *reg_val)
> >>>>>> +{
> >>>>>> + struct i2c_msg msg[2];
> >>>>>> + u8 wr_data[3];
> >>>>>> + u32 rd_data;
> >>>>>> + int ret;
> >>>>>> +
> >>>>>> + msg[0].addr = client->addr;
> >>>>>> + msg[0].len = 3;
> >>>>>> + msg[0].flags = 0;
> >>>>>> +
> >>>>>> + /* Big Endian for reg addr */
> >>>>>> + reg_addr = cpu_to_be32(reg_addr);
> >>>>>> +
> >>>>>> + wr_data[0] = (u8)(reg_addr >> 8);
> >>>>>> + wr_data[1] = (u8)(reg_addr >> 16);
> >>>>>> + wr_data[2] = (u8)(reg_addr >> 24);
> >>>>>
> >>>>> And here.
> >>>>>
> >>>>>> +
> >>>>>> + msg[0].buf = wr_data;
> >>>>>> +
> >>>>>> + msg[1].addr = client->addr;
> >>>>>> + msg[1].len = 4;
> >>>>>> + msg[1].flags = I2C_M_RD;
> >>>>>> +
> >>>>>> + msg[1].buf = (u8 *)&rd_data;
> >>>>>> +
> >>>>>> + ret = i2c_transfer(client->adapter, &msg[0], 2);
> >>>>>> + if (ret == 2) {
> >>>>>> + *reg_val = le32_to_cpu(rd_data);
> >>>>>> + return 0;
> >>>>>> + }
> >>>>>> +
> >>>>>> + /* If only one message successfully completed, return -ENODEV */
> >>>>>> + return ret == 1 ? -ENODEV : ret;
> >>>>>> +}
> >>>>>> +
> >>>>>> +static int qps615_pwrctl_i2c_bulk_write(struct i2c_client *client,
> >>>>>> + const struct qps615_pwrctl_reg_setting *seq, int len)
> >>>>>> +{
> >>>>>> + int ret, i;
> >>>>>> +
> >>>>>> + for (i = 0; i < len; i++) {
> >>>>>> + ret = qps615_pwrctl_i2c_write(client, seq[i].offset, seq[i].val);
> >>>>>> + if (ret)
> >>>>>> + return ret;
> >>>>>> + }
> >>>>>> +
> >>>>>> + return 0;
> >>>>>> +}
> >>>>>> +
> >>>>>> +static int of_pci_get_bdf(struct device_node *np)
> >>>>>> +{
> >>>>>> + u32 reg[5];
> >>>>>> + int error;
> >>>>>> +
> >>>>>> + error = of_property_read_u32_array(np, "reg", reg, ARRAY_SIZE(reg));
> >>>>>
> >>>>> Please use of_property_read_u32_index() instead.
> >>>>>
> >>>> ack.
> >>>>>> + if (error)
> >>>>>> + return error;
> >>>>>> +
> >>>>>> + return (reg[0] >> 8) & 0xffff;
> >>>>>> +}
> >>>>>> +
> >>>>>> +static int qps615_pwrctl_disable_port(struct qps615_pwrctl_ctx *ctx,
> >>>>>> + enum qps615_pwrctl_ports port)
> >>>>>> +{
> >>>>>> + const struct qps615_pwrctl_reg_setting *seq;
> >>>>>> + int ret, len;
> >>>>>> +
> >>>>>> + seq = (port == QPS615_DSP1) ? dsp1_pwroff_seq : dsp2_pwroff_seq;
> >>>>>> + len = (port == QPS615_DSP1) ? ARRAY_SIZE(dsp1_pwroff_seq) : ARRAY_SIZE(dsp2_pwroff_seq);
> >>>>>> +
> >>>>>> + ret = qps615_pwrctl_i2c_bulk_write(ctx->client, seq, len);
> >>>>>> + if (ret)
> >>>>>> + return ret;
> >>>>>> +
> >>>>>> + return qps615_pwrctl_i2c_bulk_write(ctx->client,
> >>>>>> + common_pwroff_seq, ARRAY_SIZE(common_pwroff_seq));
> >>>>>> +}
> >>>>>> +
> >>>>>> +static int qps615_pwrctl_set_l0s_l1_entry_delay(struct qps615_pwrctl_ctx *ctx,
> >>>>>> + enum qps615_pwrctl_ports port, bool is_l1, u32 ns)
> >>>>>> +{
> >>>>>> + u32 rd_val, units;
> >>>>>> + int ret;
> >>>>>> +
> >>>>>> + /* convert to units of 256ns */
> >>>>>> + units = ns / 256;
> >>>>>> +
> >>>>>> + if (port == QPS615_ETHERNET) {
> >>>>>> + ret = qps615_pwrctl_i2c_read(ctx->client, QPS615_EMBEDDED_ETH_DELAY, &rd_val);
> >>>>>> + if (ret)
> >>>>>> + return ret;
> >>>>>> + rd_val = u32_replace_bits(rd_val, units,
> >>>>>> + is_l1 ?
> >>>>>> + QPS615_ETH_L1_DELAY_MASK : QPS615_ETH_L0S_DELAY_MASK);
> >>>>>> + return qps615_pwrctl_i2c_write(ctx->client, QPS615_EMBEDDED_ETH_DELAY, rd_val);
> >>>>>> + }
> >>>>>> +
> >>>>>> + ret = qps615_pwrctl_i2c_write(ctx->client, QPS615_PORT_SELECT, BIT(port));
> >>>>>> + if (ret)
> >>>>>> + return ret;
> >>>>>
> >>>>> What if there is a concurrent call? The port_select / write_value
> >>>>> statements should use a lock to remove the possible race condition.
> >>>>>
> >>>> There should not be any concurrent calls since all calls come from the
> >>>> probe itself.
> >>>
> >>> Comment this in the driver, since somebody might decide to call the function later
> >> ack
> >>>
> >>>>>> +
> >>>>>> + return qps615_pwrctl_i2c_write(ctx->client,
> >>>>>> + is_l1 ? QPS615_PORT_L1_DELAY : QPS615_PORT_L0S_DELAY, units);
> >>>>>> +}
> >>>>>> +
> >>>>>> +static int qps615_pwrctl_set_tx_amplitude(struct qps615_pwrctl_ctx *ctx,
> >>>>>> + enum qps615_pwrctl_ports port, u32 amp)
> >>>>>> +{
> >>>>>> + int port_access;
> >>>>>> +
> >>>>>> + switch (port) {
> >>>>>> + case QPS615_USP:
> >>>>>> + port_access = 0x1;
> >>>>>> + break;
> >>>>>> + case QPS615_DSP1:
> >>>>>> + port_access = 0x2;
> >>>>>> + break;
> >>>>>> + case QPS615_DSP2:
> >>>>>> + port_access = 0x8;
> >>>>>> + break;
> >>>>>> + default:
> >>>>>> + return -EINVAL;
> >>>>>> + };
> >>>>>> +
> >>>>>> + struct qps615_pwrctl_reg_setting tx_amp_seq[] = {
> >>>>>> + {QPS615_PORT_ACCESS_ENABLE, port_access},
> >>>>>
> >>>>> Hmm, this looks like another port selection, so most likely it should
> >>>>> also be under the same lock.
> >>>>>
> >>>>>> + {QPS615_PORT_LANE_ACCESS_ENABLE, 0x3},
> >>>>>> + {QPS615_TX_MARGIN, amp},
> >>>>>> + };
> >>>>>> +
> >>>>>> + return qps615_pwrctl_i2c_bulk_write(ctx->client, tx_amp_seq, ARRAY_SIZE(tx_amp_seq));
> >>>>>> +}
> >>>>>> +
> >>>>>> +static int qps615_pwrctl_disable_dfe(struct qps615_pwrctl_ctx *ctx,
> >>>>>> + enum qps615_pwrctl_ports port)
> >>>>>> +{
> >>>>>> + int port_access, lane_access = 0x3;
> >>>>>> + u32 phy_rate = 0x21;
> >>>>>> +
> >>>>>> + switch (port) {
> >>>>>> + case QPS615_USP:
> >>>>>> + phy_rate = 0x1;
> >>>>>> + port_access = 0x1;
> >>>>>> + break;
> >>>>>> + case QPS615_DSP1:
> >>>>>> + port_access = 0x2;
> >>>>>> + break;
> >>>>>> + case QPS615_DSP2:
> >>>>>> + port_access = 0x8;
> >>>>>> + lane_access = 0x1;
> >>>>>> + break;
> >>>>>> + default:
> >>>>>> + return -EINVAL;
> >>>>>> + };
> >>>>>> +
> >>>>>> + struct qps615_pwrctl_reg_setting disable_dfe_seq[] = {
> >>>>>> + {QPS615_PORT_ACCESS_ENABLE, port_access},
> >>>>>> + {QPS615_PORT_LANE_ACCESS_ENABLE, lane_access},
> >>>>>> + {QPS615_DFE_ENABLE, 0x0},
> >>>>>> + {QPS615_DFE_EQ0_MODE, 0x411},
> >>>>>> + {QPS615_DFE_EQ1_MODE, 0x11},
> >>>>>> + {QPS615_DFE_EQ2_MODE, 0x11},
> >>>>>> + {QPS615_DFE_PD_MASK, 0x7},
> >>>>>> + {QPS615_PHY_RATE_CHANGE_OVERRIDE, 0x10},
> >>>>>> + {QPS615_PHY_RATE_CHANGE, phy_rate},
> >>>>>> + {QPS615_PHY_RATE_CHANGE, 0x0},
> >>>>>> + {QPS615_PHY_RATE_CHANGE_OVERRIDE, 0x0},
> >>>>>> +
> >>>>>> + };
> >>>>>> +
> >>>>>> + return qps615_pwrctl_i2c_bulk_write(ctx->client,
> >>>>>> + disable_dfe_seq, ARRAY_SIZE(disable_dfe_seq));
> >>>>>> +}
> >>>>>> +
> >>>>>> +static int qps615_pwrctl_set_nfts(struct qps615_pwrctl_ctx *ctx,
> >>>>>> + enum qps615_pwrctl_ports port, u32 nfts)
> >>>>>> +{
> >>>>>> + int ret;
> >>>>>> + struct qps615_pwrctl_reg_setting nfts_seq[] = {
> >>>>>> + {QPS615_NFTS_2_5_GT, nfts},
> >>>>>> + {QPS615_NFTS_5_GT, nfts},
> >>>>>> + };
> >>>>>> +
> >>>>>> + ret = qps615_pwrctl_i2c_write(ctx->client, QPS615_PORT_SELECT, BIT(port));
> >>>>>> + if (ret)
> >>>>>> + return ret;
> >>>>>> +
> >>>>>> + return qps615_pwrctl_i2c_bulk_write(ctx->client, nfts_seq, ARRAY_SIZE(nfts_seq));
> >>>>>> +}
> >>>>>> +
> >>>>>> +static int qps615_pwrctl_assert_deassert_reset(struct qps615_pwrctl_ctx *ctx, bool deassert)
> >>>>>> +{
> >>>>>> + int ret, val = 0;
> >>>>>> +
> >>>>>> + if (deassert)
> >>>>>> + val = 0xc;
> >>>>>> +
> >>>>>> + ret = qps615_pwrctl_i2c_write(ctx->client, QPS615_GPIO_CONFIG, 0xfffffff3);
> >>>>>
> >>>>> It's a kind of magic
> >>>>>
> >>>> I will add a macro in next patch.
> >>>>>> + if (ret)
> >>>>>> + return ret;
> >>>>>> +
> >>>>>> + return qps615_pwrctl_i2c_write(ctx->client, QPS615_RESET_GPIO, val);
> >>>>>> +}
> >>>>>> +
> >>>>>> +static int qps615_pwrctl_parse_device_dt(struct qps615_pwrctl_ctx *ctx, struct device_node *node)
> >>>>>> +{
> >>>>>> + enum qps615_pwrctl_ports port;
> >>>>>> + struct qps615_pwrctl_cfg *cfg;
> >>>>>> + struct device_node *np;
> >>>>>> + int bdf, fun_no;
> >>>>>> +
> >>>>>> + bdf = of_pci_get_bdf(node);
> >>>>>> + if (bdf < 0) {
> >>>>>
> >>>>> This is incorrect, it will fail if at any point BDF uses the most
> >>>>> significant bit (which is permitted by the spec, if I'm not mistaken).
> >>>>>
> >>>> As per the reg property as described in the binding document we are not
> >>>> expecting any change here.
> >>>> https://elixir.bootlin.com/linux/v6.10.3/source/Documentation/devicetree/bindings/pci/pci.txt#L50.
> >>>
> >>> What will this function return if the bus no is 256?
> >>> The supported PCI bus number is from 0x0 to 0xff only. so we
> >> are not expecting any numbers greater than 0xff.
> >>> Also please either move the function to the generic PCI code is change its name to match the rest of the driver. The of_pci_ prefix is reserved for the generic code.
> >>>
> >> ack.
> >>>
> >>>>>> + dev_err(ctx->pwrctl.dev, "Getting BDF failed\n");
> >>>>>> + return 0;
> >>>>>> + }
> >>>>>> +
> >>>>>> + fun_no = bdf & 0x7;
> >>>>>
> >>>>> I assume that ARI is not supported?
> >>>>>
> >>>> Yes this doesn't support ARI.
> >>>>>> +
> >>>>>> + /* In multi function node, ignore function 1 node */
> >>>>>> + if (of_pci_get_bdf(of_get_parent(node)) == ctx->bdf->dsp3_bdf && !fun_no)
> >>>>>> + port = QPS615_ETHERNET;
> >>>>>> + else if (bdf == ctx->bdf->usp_bdf)
> >>>>>> + port = QPS615_USP;
> >>>>>
> >>>>> The function is being called for child device nodes. Thus upstream
> >>>>> facing port (I assume that this is what USP means) can not be enumerated
> >>>>> in this way.
> >>>> Sorry, but I didn't your question.
> >>>>
> >>>> These settings will not affect the enumeration sequence these are
> >>>> for configuring ports only.
> >>>
> >>> You are handling the case of bdf equal to the USP. Is it possible at all?
> >>>
> >> at the time of the configuration the PCI link is not enabled yet,
> >> once we are done with the configurations only we are resumeing the link
> >> training. so when we start this configuration the link is not up yet.
> >
> > Is your answer relevant to the question I have asked?
> >
> sorry dmitry I might got your question wrong. what I understood is
> "you are configuring USP port before the link is up, is that possible?"
> I might read your statement wrongly.
>
> If the question is "why do we need to configure USP?" I will try to
> respond below.
> "USP also will have l0s, L1 entry delays, nfts etc which can be
> configured".
>
> Sorry once again if your question doesn't fall in both can you tell
> me your question.
My question was why the function gets executed for the root port. But
after reading the qps615_pwrctl_parse_device_dt() I have another
question: you are parsing DT nodes recursively. You should stop
parsing at the first level, so that grandchildren nodes can not
override your data (and so that the time isn't spent on parsing
useless data). Also I have the feeling that BDF parsing isn't so
correct. Will it work if QPS is sitting behind a PCI-PCI bridge?
> >>>
> >>>>>
> >>>>>> + else if (bdf == ctx->bdf->dsp1_bdf)
> >>>>>> + port = QPS615_DSP1;
> >>>>>> + else if (bdf == ctx->bdf->dsp2_bdf)
> >>>>>> + port = QPS615_DSP2;
> >>>>>> + else if (bdf == ctx->bdf->dsp3_bdf)
> >>>>>> + port = QPS615_DSP3;
> >>>>>> + else
> >>>>>> + return 0;
> >>>>>
> >>>>> -EINVAL >
> >>>> There are can be nodes describing endpoints also,
> >>>> for those nodes bdf will not match and we are not
> >>>> returning since it is expected for endpoint nodes.
> >>>
> >>> Which endpoints? Bindings don't describe them.
> >>>
> >> The client drivers like ethernet will add them once
> >> this series is merged. Their drivers are not present
> >> in the linux as of now.
> >
> > The bindings describe the hardware, not the drivers. Also the driver
> > should work with the bindings that you have submitted, not some
> > imaginary to-be-submitted state. Please either update the bindings
> > within the patchset or fix the driver to return -EINVAL.
> >
> The qps615 bindings describes only the PCIe switch part,
> the endpoints binding connected to the switch should be described by the
> respective clients like USB hub, NVMe, ethernet etc bindings should
> describe their hardware and its properties. And these bindings will
> defined in seperate bindinds file not in qps615 bindings.
>
> for example:-
>
> in the following example pcie@0,0 describes usp and
> pcie@1,0 & pcie@2,0 describes dsp's of the switch.
> now if we say usb hub is connected to dsp1 i.e to the
> node pcie@1,0 there will be a child node to the pcie@1,0
> to denote usb hub hardware.
> And that node is external to the switch and we are not
> configuring it through i2c. As these are pcie devices
> representation is generic one we can't say if the client
> nodes(in this case usb hub) will be present or not. if the child
> node( for example usb hub) is present we can't return -EINVAL
> because qps615 will not configure it.
>
> &pcieport {
> pcie@0,0 {
> pcie@1,0 {
> reg = <0x20800 0x0 0x0 0x0 0x0>;
> #address-cells = <3>;
> #size-cells = <2>;
>
> device_type = "pci";
> ranges;
> usb_hub@0,0 {
> //describes USB hub
> };
> };
>
> pcie@2,0 {
> reg = <0x21000 0x0 0x0 0x0 0x0>;
> #address-cells = <3>;
> #size-cells = <2>;
>
> device_type = "pci";
> ranges;
> };
> };
> };
> >>>
> >>>>
> >>>>>> +
> >>>>>> + cfg = &ctx->cfg[port];
> >>>>>> +
> >>>>>> + if (!of_device_is_available(node)) {
> >>>>>> + cfg->disable_port = true;
> >>>>>> + return 0;
> >>>>>> + };
> >>>>>> +
> >>>>>> + of_property_read_u32(node, "qcom,axi-clk-freq-hz", &cfg->axi_freq);
> >>>>>> +
> >>>>>> + of_property_read_u32(node, "qcom,l0s-entry-delay-ns", &cfg->l0s_delay);
> >>>>>> +
> >>>>>> + of_property_read_u32(node, "qcom,l1-entry-delay-ns", &cfg->l1_delay);
> >>>>>> +
> >>>>>> + of_property_read_u32(node, "qcom,tx-amplitude-millivolt", &cfg->tx_amp);
> >>>>>> +
> >>>>>> + cfg->disable_dfe = of_property_read_bool(node, "qcom,no-dfe");
> >>>>>> +
> >>>>>> + of_property_read_u8(node, "qcom,nfts", &cfg->nfts);
> >>>>>> +
> >>>>>> + for_each_child_of_node(node, np)
> >>>>>> + qps615_pwrctl_parse_device_dt(ctx, np);
> >>>>>> +
> >>>>>> + of_node_put(np);
> >>>>>> + return 0;
> >>>>>> +}
> >>>>>> +
> >>>>>> +static void qps615_pwrctl_power_off(struct qps615_pwrctl_ctx *ctx)
> >>>>>> +{
> >>>>>> + gpiod_set_value(ctx->reset_gpio, 1);
> >>>>>> +
> >>>>>> + regulator_bulk_disable(ARRAY_SIZE(ctx->supplies), ctx->supplies);
> >>>>>> +}
> >>>>>> +
> >>>>>> +static int qps615_pwrctl_power_on(struct qps615_pwrctl_ctx *ctx)
> >>>>>> +{
> >>>>>> + struct qps615_pwrctl_cfg *cfg;
> >>>>>> + int ret, i;
> >>>>>> +
> >>>>>> + ret = regulator_bulk_enable(ARRAY_SIZE(ctx->supplies), ctx->supplies);
> >>>>>> + if (ret < 0)
> >>>>>> + return dev_err_probe(ctx->pwrctl.dev, ret, "cannot enable regulators\n");
> >>>>>> +
> >>>>>> + gpiod_set_value(ctx->reset_gpio, 0);
> >>>>>> +
> >>>>>> + if (!ctx->client)
> >>>>>> + return 0;
> >>>>>
> >>>>> really?
> >>>>>
> >>>> Even if we don't do i2c configuration PCIe enumeration will happen, for
> >>>> some reason i2c client is not found, driver ignores the error and return
> >>>> since basic functionality will work.
> >>>
> >>> So what is the point of such misconfiguration? If "something works" even in the default case, then we don't need this driver at all, do we?
> >>>
> >> we need this configuration for better power savings, reduce the AER
> >> errors etc.. if there is no i2c client then that particular platform
> >> doesn't need any configurations required.
> >
> > NAK. The i2c client is marked as required in the bindings. So there is
> > no way for the kernel to see the device with no qps615 controller
> > property.
> >
> agree as it is a required property we should not return 0 here.
> I will return proper error value here.
>
> - Krishna chaitanya.
> >>> Even worse. With the modular kernels you can not guarantee probe order. However the user expects that if the driver is probed, it has configured the hardware correctly.
> >>>> Linux has special return value for such cases, please return it
> >> instead if 0.
> >>>
> >> ack we will check and return them instead of 0.
> >> - Krishna chaitanya.
> >>>
> >>>>>> +
> >>>>>> + /*
> >>>>>> + * Don't have a way to see if the reset has completed.
> >>>>>> + * Wait for some time.
> >>>>>> + */
> >>>>>> + usleep_range(1000, 1001);
> >>>>>> +
> >>>>>> + ret = qps615_pwrctl_assert_deassert_reset(ctx, false);
> >>>>>> + if (ret)
> >>>>>> + goto out;
> >>>>>> +
> >>>>>> + if (ctx->cfg[QPS615_USP].axi_freq == QPS615_AXI_CLK_FREQ_MHZ) {
> >>>>>> + ret = qps615_pwrctl_i2c_write(ctx->client, QPS615_BUS_CONTROL, BIT(16));
> >>>>>> + if (ret)
> >>>>>> + dev_err(ctx->pwrctl.dev, "Setting axi clk freq failed %d\n", ret);
> >>>>>
> >>>>> AXI, not axi
> >>>>>
> >>>> ack.
> >>>>>> + }
> >>>>>> +
> >>>>>> + for (i = 0; i < QPS615_MAX; i++) {
> >>>>>> + cfg = &ctx->cfg[i];
> >>>>>> + if (cfg->disable_port) {
> >>>>>> + ret = qps615_pwrctl_disable_port(ctx, i);
> >>>>>> + if (ret) {
> >>>>>> + dev_err(ctx->pwrctl.dev, "Disabling port failed\n");
> >>>>>> + goto out;
> >>>>>> + }
> >>>>>> + }
> >>>>>> +
> >>>>>> + if (cfg->l0s_delay) {
> >>>>>> + ret = qps615_pwrctl_set_l0s_l1_entry_delay(ctx, i, false, cfg->l0s_delay);
> >>>>>> + if (ret) {
> >>>>>> + dev_err(ctx->pwrctl.dev, "Setting L0s entry delay failed\n");
> >>>>>> + goto out;
> >>>>>> + }
> >>>>>> + }
> >>>>>> +
> >>>>>> + if (cfg->l1_delay) {
> >>>>>> + ret = qps615_pwrctl_set_l0s_l1_entry_delay(ctx, i, true, cfg->l1_delay);
> >>>>>> + if (ret) {
> >>>>>> + dev_err(ctx->pwrctl.dev, "Setting L1 entry delay failed\n");
> >>>>>> + goto out;
> >>>>>> + }
> >>>>>> + }
> >>>>>> +
> >>>>>> + if (cfg->tx_amp) {
> >>>>>> + ret = qps615_pwrctl_set_tx_amplitude(ctx, i, cfg->tx_amp);
> >>>>>> + if (ret) {
> >>>>>> + dev_err(ctx->pwrctl.dev, "Setting Tx amplitube failed\n");
> >>>>>> + goto out;
> >>>>>> + }
> >>>>>> + }
> >>>>>> +
> >>>>>> + if (cfg->nfts) {
> >>>>>> + ret = qps615_pwrctl_set_nfts(ctx, i, cfg->nfts);
> >>>>>> + if (ret) {
> >>>>>> + dev_err(ctx->pwrctl.dev, "Setting nfts failed\n");
> >>>>>> + goto out;
> >>>>>> + }
> >>>>>> + }
> >>>>>> +
> >>>>>> + if (cfg->disable_dfe) {
> >>>>>> + ret = qps615_pwrctl_disable_dfe(ctx, i);
> >>>>>> + if (ret) {
> >>>>>> + dev_err(ctx->pwrctl.dev, "Disabling DFE failed\n");
> >>>>>> + goto out;
> >>>>>> + }
> >>>>>> + }
> >>>>>> + }
> >>>>>> +
> >>>>>> + ret = qps615_pwrctl_assert_deassert_reset(ctx, true);
> >>>>>> + if (!ret)
> >>>>>> + return 0;
> >>>>>> +
> >>>>>> +out:
> >>>>>> + qps615_pwrctl_power_off(ctx);
> >>>>>> + return ret;
> >>>>>> +}
> >>>>>> +
> >>>>>> +static int qps615_pwrctl_probe(struct platform_device *pdev)
> >>>>>> +{
> >>>>>> + struct device *dev = &pdev->dev;
> >>>>>> + struct pci_host_bridge *bridge;
> >>>>>> + struct qps615_pwrctl_ctx *ctx;
> >>>>>> + struct device_node *node;
> >>>>>> + struct pci_bus *bus;
> >>>>>> + int ret;
> >>>>>> +
> >>>>>> + bus = pci_find_bus(of_get_pci_domain_nr(dev->parent->of_node), 0);
> >>>>>> + if (!bus)
> >>>>>> + return -ENODEV;
> >>>>>> +
> >>>>>> + bridge = pci_find_host_bridge(bus);
> >>>>>> +
> >>>>>> + ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL);
> >>>>>> + if (!ctx)
> >>>>>> + return -ENOMEM;
> >>>>>> +
> >>>>>> + node = of_parse_phandle(pdev->dev.of_node, "qcom,qps615-controller", 0);
> >>>>>> + if (node) {
> >>>>>
> >>>>> And if !node?
> >>>>>
> >>>>>> + ctx->client = of_find_i2c_device_by_node(node);
> >>>>>
> >>>>> Leaks the reference count, see the comment at the function definition.
> >>>>> Also what if the I2C bus gets unbound? Will it crash the driver?
> >>>>>
> >>>> I will fix in next patch.
> >>>>
> >>>> Driver is not expected to crash when i2c bus gets unbound.
> >>>> It should be properly handled in i2c driver.
> >>>
> >>> Please verify it.
> >>>
> >>>
> >>>>
> >>>> - Krishna Chaitanya.
> >>>>>> + of_node_put(node);
> >>>>>> + if (!ctx->client)
> >>>>>> + return dev_err_probe(dev, -EPROBE_DEFER,
> >>>>>> + "failed to parse qcom,qps615-controller\n");
> >>>>>> + }
> >>>>>> +
> >>>>>> + ctx->bdf = of_device_get_match_data(dev);
> >>>>>> + ctx->pwrctl.dev = dev;
> >>>>>> +
> >>>>>> + ctx->supplies[0].supply = "vddc";
> >>>>>> + ctx->supplies[1].supply = "vdd18";
> >>>>>> + ctx->supplies[2].supply = "vdd09";
> >>>>>> + ctx->supplies[3].supply = "vddio1";
> >>>>>> + ctx->supplies[4].supply = "vddio2";
> >>>>>> + ctx->supplies[5].supply = "vddio18";
> >>>>>> + ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(ctx->supplies), ctx->supplies);
> >>>>>> + if (ret)
> >>>>>> + return dev_err_probe(dev, ret,
> >>>>>> + "failed to get supply regulator\n");
> >>>>>> +
> >>>>>> + ctx->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_ASIS);
> >>>>>> + if (IS_ERR(ctx->reset_gpio))
> >>>>>> + return dev_err_probe(dev, PTR_ERR(ctx->reset_gpio), "failed to get reset GPIO\n");
> >>>>>> +
> >>>>>> + ctx->link = device_link_add(&bridge->dev, dev, DL_FLAG_AUTOREMOVE_CONSUMER);
> >>>>>> +
> >>>>>> + platform_set_drvdata(pdev, ctx);
> >>>>>> +
> >>>>>> + qps615_pwrctl_parse_device_dt(ctx, pdev->dev.of_node);
> >>>>>> +
> >>>>>> + if (bridge->ops->stop_link)
> >>>>>> + bridge->ops->stop_link(bus);
> >>>>>> +
> >>>>>> + ret = qps615_pwrctl_power_on(ctx);
> >>>>>> + if (ret)
> >>>>>> + return ret;
> >>>>>> +
> >>>>>> + if (bridge->ops->start_link) {
> >>>>>> + ret = bridge->ops->start_link(bus);
> >>>>>> + if (ret)
> >>>>>> + return ret;
> >>>>>> + }
> >>>>>> +
> >>>>>> + return devm_pci_pwrctl_device_set_ready(dev, &ctx->pwrctl);
> >>>>>> +}
> >>>>>> +
> >>>>>> +static void qps615_pwrctl_remove(struct platform_device *pdev)
> >>>>>> +{
> >>>>>> + struct device *dev = &pdev->dev;
> >>>>>> + struct qps615_pwrctl_ctx *ctx = dev_get_drvdata(dev);
> >>>>>> +
> >>>>>> + device_link_del(ctx->link);
> >>>>>> + qps615_pwrctl_power_off(ctx);
> >>>>>> +}
> >>>>>> +
> >>>>>> +static const struct qps615_pwrctl_bdf_info bdf_info = {
> >>>>>> + .usp_bdf = 0x100,
> >>>>>> + .dsp1_bdf = 0x208,
> >>>>>> + .dsp2_bdf = 0x210,
> >>>>>> + .dsp3_bdf = 0x218,
> >>>>>> +};
> >>>>>> +
> >>>>>> +static const struct of_device_id qps615_pwrctl_of_match[] = {
> >>>>>> + { .compatible = "pci1179,0623", .data = &bdf_info },
> >>>>>> + { }
> >>>>>> +};
> >>>>>> +MODULE_DEVICE_TABLE(of, qps615_pwrctl_of_match);
> >>>>>> +
> >>>>>> +static struct platform_driver qps615_pwrctl_driver = {
> >>>>>> + .driver = {
> >>>>>> + .name = "pwrctl-qps615",
> >>>>>> + .of_match_table = qps615_pwrctl_of_match,
> >>>>>> + .probe_type = PROBE_PREFER_ASYNCHRONOUS,
> >>>>>> + },
> >>>>>> + .probe = qps615_pwrctl_probe,
> >>>>>> + .remove_new = qps615_pwrctl_remove,
> >>>>>> +};
> >>>>>> +module_platform_driver(qps615_pwrctl_driver);
> >>>>>> +
> >>>>>> +MODULE_AUTHOR("Krishna chaitanya chundru <quic_krichai@quicinc.com>");
> >>>>>> +MODULE_DESCRIPTION("Qualcomm QPS615 power control driver");
> >>>>>> +MODULE_LICENSE("GPL");
> >>>>>>
> >>>>>> --
> >>>>>> 2.34.1
> >>>>>>
> >>>>>
> >>>
> >>>
> >
> >
> >
--
With best wishes
Dmitry
^ permalink raw reply [flat|nested] 77+ messages in thread
* Re: [PATCH v2 8/8] PCI: pwrctl: Add power control driver for qps615
2024-09-02 10:12 ` Dmitry Baryshkov
@ 2024-09-02 10:47 ` Krishna Chaitanya Chundru
2024-09-02 18:37 ` Dmitry Baryshkov
0 siblings, 1 reply; 77+ messages in thread
From: Krishna Chaitanya Chundru @ 2024-09-02 10:47 UTC (permalink / raw)
To: Dmitry Baryshkov
Cc: Lorenzo Pieralisi, Krzysztof Wilczyński, Rob Herring,
Bjorn Helgaas, Krzysztof Kozlowski, Conor Dooley, Konrad Dybcio,
cros-qcom-dts-watchers, Bartosz Golaszewski, Jingoo Han,
Manivannan Sadhasivam, andersson, quic_vbadigan, linux-arm-msm,
linux-pci, devicetree, linux-kernel, Bartosz Golaszewski
On 9/2/2024 3:42 PM, Dmitry Baryshkov wrote:
> On Mon, 2 Sept 2024 at 11:32, Krishna Chaitanya Chundru
> <quic_krichai@quicinc.com> wrote:
>>
>>
>>
>> On 9/2/2024 12:50 PM, Dmitry Baryshkov wrote:
>>> On Mon, 2 Sept 2024 at 10:13, Krishna Chaitanya Chundru
>>> <quic_krichai@quicinc.com> wrote:
>>>>
>>>>
>>>>
>>>> On 8/8/2024 9:00 AM, Dmitry Baryshkov wrote:
>>>>> On August 5, 2024 1:14:47 PM GMT+07:00, Krishna Chaitanya Chundru <quic_krichai@quicinc.com> wrote:
>>>>>>
>>>>>>
>>>>>> On 8/3/2024 5:04 PM, Dmitry Baryshkov wrote:
>>>>>>> On Sat, Aug 03, 2024 at 08:52:54AM GMT, Krishna chaitanya chundru wrote:
>>>>>>>> QPS615 switch needs to be configured after powering on and before
>>>>>>>> PCIe link was up.
>>>>>>>>
>>>>>>>> As the PCIe controller driver already enables the PCIe link training
>>>>>>>> at the host side, stop the link training. Otherwise the moment we turn
>>>>>>>> on the switch it will participate in the link training and link may come
>>>>>>>> up before switch is configured through i2c.
>>>>>>>>
>>>>>>>> The device tree properties are parsed per node under pci-pci bridge in the
>>>>>>>> driver. Each node has unique bdf value in the reg property, driver
>>>>>>>> uses this bdf to differentiate ports, as there are certain i2c writes to
>>>>>>>> select particular port.
>>>>>>>>
>>>>>>>> Based up on dt property and port, qps615 is configured through i2c.
>>>>>>>>
>>>>>>>> Signed-off-by: Krishna chaitanya chundru <quic_krichai@quicinc.com>
>>>>>>>> ---
>>>>>>>> drivers/pci/pwrctl/Kconfig | 7 +
>>>>>>>> drivers/pci/pwrctl/Makefile | 1 +
>>>>>>>> drivers/pci/pwrctl/pci-pwrctl-qps615.c | 638 +++++++++++++++++++++++++++++++++
>>>>>>>> 3 files changed, 646 insertions(+)
>>>>>>>>
>>>>>>>> diff --git a/drivers/pci/pwrctl/Kconfig b/drivers/pci/pwrctl/Kconfig
>>>>>>>> index 54589bb2403b..6a1352af918c 100644
>>>>>>>> --- a/drivers/pci/pwrctl/Kconfig
>>>>>>>> +++ b/drivers/pci/pwrctl/Kconfig
>>>>>>>> @@ -10,3 +10,10 @@ config PCI_PWRCTL_PWRSEQ
>>>>>>>> tristate
>>>>>>>> select POWER_SEQUENCING
>>>>>>>> select PCI_PWRCTL
>>>>>>>> +
>>>>>>>> +config PCI_PWRCTL_QPS615
>>>>>>>> + tristate "PCI Power Control driver for QPS615"
>>>>>>>> + select PCI_PWRCTL
>>>>>>>> + help
>>>>>>>> + Say Y here to enable the pwrctl driver for Qualcomm
>>>>>>>> + QPS615 PCIe switch.
>>>>>>>> diff --git a/drivers/pci/pwrctl/Makefile b/drivers/pci/pwrctl/Makefile
>>>>>>>> index d308aae4800c..ac563a70c023 100644
>>>>>>>> --- a/drivers/pci/pwrctl/Makefile
>>>>>>>> +++ b/drivers/pci/pwrctl/Makefile
>>>>>>>> @@ -4,3 +4,4 @@ obj-$(CONFIG_PCI_PWRCTL) += pci-pwrctl-core.o
>>>>>>>> pci-pwrctl-core-y := core.o
>>>>>>>> obj-$(CONFIG_PCI_PWRCTL_PWRSEQ) += pci-pwrctl-pwrseq.o
>>>>>>>> +obj-$(CONFIG_PCI_PWRCTL_QPS615) += pci-pwrctl-qps615.o
>>>>>>>> diff --git a/drivers/pci/pwrctl/pci-pwrctl-qps615.c b/drivers/pci/pwrctl/pci-pwrctl-qps615.c
>>>>>>>> new file mode 100644
>>>>>>>> index 000000000000..9dabb82787d5
>>>>>>>> --- /dev/null
>>>>>>>> +++ b/drivers/pci/pwrctl/pci-pwrctl-qps615.c
>>>>>>>> @@ -0,0 +1,638 @@
>>>>>>>> +// SPDX-License-Identifier: GPL-2.0-only
>>>>>>>> +/*
>>>>>>>> + * Copyright (c) 2024 Qualcomm Innovation Center, Inc. All rights reserved.
>>>>>>>> + */
>>>>>>>> +
>>>>>>>> +#include <linux/delay.h>
>>>>>>>> +#include <linux/device.h>
>>>>>>>> +#include <linux/firmware.h>
>>>>>>>> +#include <linux/i2c.h>
>>>>>>>> +#include <linux/mod_devicetable.h>
>>>>>>>> +#include <linux/module.h>
>>>>>>>> +#include <linux/of.h>
>>>>>>>> +#include <linux/pci.h>
>>>>>>>> +#include <linux/pci-pwrctl.h>
>>>>>>>> +#include <linux/platform_device.h>
>>>>>>>> +#include <linux/regulator/consumer.h>
>>>>>>>> +#include <linux/string.h>
>>>>>>>> +#include <linux/types.h>
>>>>>>>> +
>>>>>>>> +#include "../pci.h"
>>>>>>>> +
>>>>>>>> +#define QPS615_GPIO_CONFIG 0x801208
>>>>>>>> +#define QPS615_RESET_GPIO 0x801210
>>>>>>>> +
>>>>>>>> +#define QPS615_BUS_CONTROL 0x801014
>>>>>>>> +
>>>>>>>> +#define QPS615_PORT_L0S_DELAY 0x82496c
>>>>>>>> +#define QPS615_PORT_L1_DELAY 0x824970
>>>>>>>> +
>>>>>>>> +#define QPS615_EMBEDDED_ETH_DELAY 0x8200d8
>>>>>>>> +#define QPS615_ETH_L1_DELAY_MASK GENMASK(27, 18)
>>>>>>>> +#define QPS615_ETH_L1_DELAY_VALUE(x) FIELD_PREP(QPS615_ETH_L1_DELAY_MASK, x)
>>>>>>>> +#define QPS615_ETH_L0S_DELAY_MASK GENMASK(17, 13)
>>>>>>>> +#define QPS615_ETH_L0S_DELAY_VALUE(x) FIELD_PREP(QPS615_ETH_L0S_DELAY_MASK, x)
>>>>>>>> +
>>>>>>>> +#define QPS615_NFTS_2_5_GT 0x824978
>>>>>>>> +#define QPS615_NFTS_5_GT 0x82497c
>>>>>>>> +
>>>>>>>> +#define QPS615_PORT_LANE_ACCESS_ENABLE 0x828000
>>>>>>>> +
>>>>>>>> +#define QPS615_PHY_RATE_CHANGE_OVERRIDE 0x828040
>>>>>>>> +#define QPS615_PHY_RATE_CHANGE 0x828050
>>>>>>>> +
>>>>>>>> +#define QPS615_TX_MARGIN 0x828234
>>>>>>>> +
>>>>>>>> +#define QPS615_DFE_ENABLE 0x828a04
>>>>>>>> +#define QPS615_DFE_EQ0_MODE 0x828a08
>>>>>>>> +#define QPS615_DFE_EQ1_MODE 0x828a0c
>>>>>>>> +#define QPS615_DFE_EQ2_MODE 0x828a14
>>>>>>>> +#define QPS615_DFE_PD_MASK 0x828254
>>>>>>>> +
>>>>>>>> +#define QPS615_PORT_SELECT 0x82c02c
>>>>>>>> +#define QPS615_PORT_ACCESS_ENABLE 0x82c030
>>>>>>>> +
>>>>>>>> +#define QPS615_POWER_CONTROL 0x82b09c
>>>>>>>> +#define QPS615_POWER_CONTROL_OVREN 0x82b2c8
>>>>>>>> +
>>>>>>>> +#define QPS615_AXI_CLK_FREQ_MHZ 125
>>>>>>>> +
>>>>>>>> +struct qps615_pwrctl_reg_setting {
>>>>>>>> + unsigned int offset;
>>>>>>>> + unsigned int val;
>>>>>>>> +};
>>>>>>>> +
>>>>>>>> +struct qps615_pwrctl_bdf_info {
>>>>>>>> + u16 usp_bdf;
>>>>>>>> + u16 dsp1_bdf;
>>>>>>>> + u16 dsp2_bdf;
>>>>>>>> + u16 dsp3_bdf;
>>>>>>>
>>>>>>> Why are these values dynamic? Please use #define's for now. If there
>>>>>>> ever comes a similar bridge, it most likely will have a different ports
>>>>>>> configuration, so it will need additional changes anyway.
>>>>>>>
>>>>>> We added this for future use case only, we felt it is easier to support
>>>>>> at the time if we add this way.
>>>>>
>>>>> Please don't. You are hardcoding distinct roles into the structure that is supposed to be generic. Possible future use cases might have different number of ports or different port roles.
>>>>>
>>>> ok.
>>>>>>
>>>>>>>> +};
>>>>>>>> +
>>>>>>>> +enum qps615_pwrctl_ports {
>>>>>>>> + QPS615_USP,
>>>>>>>> + QPS615_DSP1,
>>>>>>>> + QPS615_DSP2,
>>>>>>>> + QPS615_DSP3,
>>>>>>>> + QPS615_ETHERNET,
>>>>>>>> + QPS615_MAX
>>>>>>>> +};
>>>>>>>> +
>>>>>>>> +struct qps615_pwrctl_cfg {
>>>>>>>> + u32 l0s_delay;
>>>>>>>> + u32 l1_delay;
>>>>>>>> + u32 tx_amp;
>>>>>>>> + u32 axi_freq;
>>>>>>>> + u8 nfts;
>>>>>>>> + bool disable_dfe;
>>>>>>>> + bool disable_port;
>>>>>>>> +};
>>>>>>>> +
>>>>>>>> +#define QPS615_PWRCTL_MAX_SUPPLY 6
>>>>>>>> +
>>>>>>>> +struct qps615_pwrctl_ctx {
>>>>>>>> + struct regulator_bulk_data supplies[QPS615_PWRCTL_MAX_SUPPLY];
>>>>>>>> + const struct qps615_pwrctl_bdf_info *bdf;
>>>>>>>> + struct qps615_pwrctl_cfg cfg[QPS615_MAX];
>>>>>>>> + struct gpio_desc *reset_gpio;
>>>>>>>> + struct i2c_client *client;
>>>>>>>> + struct pci_pwrctl pwrctl;
>>>>>>>> + struct device_link *link;
>>>>>>>> +};
>>>>>>>> +
>>>>>>>> +/*
>>>>>>>> + * downstream port power off sequence, hardcoding the address
>>>>>>>> + * as we don't know register names for these register offsets.
>>>>>>>
>>>>>>> It is hard to believe that Qualcomm engineers don't know register names
>>>>>>> for the Qualcomm device.
>>>>>>>
>>>>>> The switch IP is from the another vendor and the vendor provided these
>>>>>> settings. The databook doesn't have the register names in it.
>>>>>>>> + */
>>>>>>>> +static const struct qps615_pwrctl_reg_setting common_pwroff_seq[] = {
>>>>>>>> + {0x82900c, 0x1},
>>>>>>>> + {0x829010, 0x1},
>>>>>>>> + {0x829018, 0x0},
>>>>>>>> + {0x829020, 0x1},
>>>>>>>> + {0x82902c, 0x1},
>>>>>>>> + {0x829030, 0x1},
>>>>>>>> + {0x82903c, 0x1},
>>>>>>>> + {0x829058, 0x0},
>>>>>>>> + {0x82905c, 0x1},
>>>>>>>> + {0x829060, 0x1},
>>>>>>>> + {0x8290cc, 0x1},
>>>>>>>> + {0x8290d0, 0x1},
>>>>>>>> + {0x8290d8, 0x1},
>>>>>>>> + {0x8290e0, 0x1},
>>>>>>>> + {0x8290e8, 0x1},
>>>>>>>> + {0x8290ec, 0x1},
>>>>>>>> + {0x8290f4, 0x1},
>>>>>>>> + {0x82910c, 0x1},
>>>>>>>> + {0x829110, 0x1},
>>>>>>>> + {0x829114, 0x1},
>>>>>>>> +};
>>>>>>>> +
>>>>>>>> +static const struct qps615_pwrctl_reg_setting dsp1_pwroff_seq[] = {
>>>>>>>> + {QPS615_PORT_ACCESS_ENABLE, 0x2},
>>>>>>>> + {QPS615_PORT_LANE_ACCESS_ENABLE, 0x3},
>>>>>>>> + {QPS615_POWER_CONTROL, 0x014f4804},
>>>>>>>> + {QPS615_POWER_CONTROL_OVREN, 0x1},
>>>>>>>> + {QPS615_PORT_ACCESS_ENABLE, 0x4},
>>>>>>>> +};
>>>>>>>> +
>>>>>>>> +static const struct qps615_pwrctl_reg_setting dsp2_pwroff_seq[] = {
>>>>>>>> + {QPS615_PORT_ACCESS_ENABLE, 0x8},
>>>>>>>> + {QPS615_PORT_LANE_ACCESS_ENABLE, 0x1},
>>>>>>>> + {QPS615_POWER_CONTROL, 0x014f4804},
>>>>>>>> + {QPS615_POWER_CONTROL_OVREN, 0x1},
>>>>>>>> + {QPS615_PORT_ACCESS_ENABLE, 0x8},
>>>>>>>> +};
>>>>>>>> +
>>>>>>>> +static int qps615_pwrctl_i2c_write(struct i2c_client *client,
>>>>>>>> + u32 reg_addr, u32 reg_val)
>>>>>>>> +{
>>>>>>>> + struct i2c_msg msg;
>>>>>>>> + u8 msg_buf[7];
>>>>>>>> + int ret;
>>>>>>>> +
>>>>>>>> + msg.addr = client->addr;
>>>>>>>> + msg.len = 7;
>>>>>>>> + msg.flags = 0;
>>>>>>>> +
>>>>>>>> + /* Big Endian for reg addr */
>>>>>>>> + reg_addr = cpu_to_be32(reg_addr);
>>>>>>>
>>>>>>> This is incorrect. After cpu_to_be32() the value depends on the CPU
>>>>>>> endianness. So reg_addr >> 8 will return different values for LE and BE
>>>>>>> CPUs.
>>>>>>> I had following impression
>>>>>> If reg address is 0x828a0c in big endian sytem it will be 0c8a8200
>>>>>> and in litte endian it will be 0x828a0c only.
>>>>>> If cpu uses big endian cpu_to_be32 will not change this value
>>>>>> and in little endian case cpu_to_be32 will convert 0x828a0c to 0c8a8200.
>>>>>>
>>>>>> Now the output is same for both the systems I tried to use
>>>>>> (reg_addr >> 8) directly.
>>>>>>
>>>>>> Are you saying (reg_addr >> 8) output will be different based upon
>>>>>> LE and BE ? If that is the case I will remove the conversions
>>>>>> in next patch.
>>>>>
>>>>> Reg address is always 0x00828a0c. Then on little-endian system you convert it to to BE32, which results in the value 0x0c8a8200. Finally you use shifts to get {0x82, 0x8a, 0x0c}, which is supposedly correct.
>>>>>
>>>>> On big-endian system cpu_to_be32 returns the same value, 0x00828a0c, since it is BE32 already. So after shifts msg_buf will get {0x8a, 0x82, 0x00}, which is obviously incorrect.
>>>>>
>>>> ack, I will fix them.
>>>>>>>> +
>>>>>>>> + msg_buf[0] = (u8)(reg_addr >> 8);
>>>>>>>> + msg_buf[1] = (u8)(reg_addr >> 16);
>>>>>>>> + msg_buf[2] = (u8)(reg_addr >> 24);
>>>>>>>> +
>>>>>>>> + /* Little Endian for reg val */
>>>>>>>> + reg_val = cpu_to_le32(reg_val);
>>>>>>>> +
>>>>>>>> + msg_buf[3] = (u8)(reg_val);
>>>>>>>> + msg_buf[4] = (u8)(reg_val >> 8);
>>>>>>>> + msg_buf[5] = (u8)(reg_val >> 16);
>>>>>>>> + msg_buf[6] = (u8)(reg_val >> 24);
>>>>>>>
>>>>>>> Same issue here.
>>>>>>>
>>>>>>>> +
>>>>>>>> + msg.buf = msg_buf;
>>>>>>>> + ret = i2c_transfer(client->adapter, &msg, 1);
>>>>>>>> + return ret == 1 ? 0 : ret;
>>>>>>>> +}
>>>>>>>> +
>>>>>>>> +static int qps615_pwrctl_i2c_read(struct i2c_client *client,
>>>>>>>> + u32 reg_addr, u32 *reg_val)
>>>>>>>> +{
>>>>>>>> + struct i2c_msg msg[2];
>>>>>>>> + u8 wr_data[3];
>>>>>>>> + u32 rd_data;
>>>>>>>> + int ret;
>>>>>>>> +
>>>>>>>> + msg[0].addr = client->addr;
>>>>>>>> + msg[0].len = 3;
>>>>>>>> + msg[0].flags = 0;
>>>>>>>> +
>>>>>>>> + /* Big Endian for reg addr */
>>>>>>>> + reg_addr = cpu_to_be32(reg_addr);
>>>>>>>> +
>>>>>>>> + wr_data[0] = (u8)(reg_addr >> 8);
>>>>>>>> + wr_data[1] = (u8)(reg_addr >> 16);
>>>>>>>> + wr_data[2] = (u8)(reg_addr >> 24);
>>>>>>>
>>>>>>> And here.
>>>>>>>
>>>>>>>> +
>>>>>>>> + msg[0].buf = wr_data;
>>>>>>>> +
>>>>>>>> + msg[1].addr = client->addr;
>>>>>>>> + msg[1].len = 4;
>>>>>>>> + msg[1].flags = I2C_M_RD;
>>>>>>>> +
>>>>>>>> + msg[1].buf = (u8 *)&rd_data;
>>>>>>>> +
>>>>>>>> + ret = i2c_transfer(client->adapter, &msg[0], 2);
>>>>>>>> + if (ret == 2) {
>>>>>>>> + *reg_val = le32_to_cpu(rd_data);
>>>>>>>> + return 0;
>>>>>>>> + }
>>>>>>>> +
>>>>>>>> + /* If only one message successfully completed, return -ENODEV */
>>>>>>>> + return ret == 1 ? -ENODEV : ret;
>>>>>>>> +}
>>>>>>>> +
>>>>>>>> +static int qps615_pwrctl_i2c_bulk_write(struct i2c_client *client,
>>>>>>>> + const struct qps615_pwrctl_reg_setting *seq, int len)
>>>>>>>> +{
>>>>>>>> + int ret, i;
>>>>>>>> +
>>>>>>>> + for (i = 0; i < len; i++) {
>>>>>>>> + ret = qps615_pwrctl_i2c_write(client, seq[i].offset, seq[i].val);
>>>>>>>> + if (ret)
>>>>>>>> + return ret;
>>>>>>>> + }
>>>>>>>> +
>>>>>>>> + return 0;
>>>>>>>> +}
>>>>>>>> +
>>>>>>>> +static int of_pci_get_bdf(struct device_node *np)
>>>>>>>> +{
>>>>>>>> + u32 reg[5];
>>>>>>>> + int error;
>>>>>>>> +
>>>>>>>> + error = of_property_read_u32_array(np, "reg", reg, ARRAY_SIZE(reg));
>>>>>>>
>>>>>>> Please use of_property_read_u32_index() instead.
>>>>>>>
>>>>>> ack.
>>>>>>>> + if (error)
>>>>>>>> + return error;
>>>>>>>> +
>>>>>>>> + return (reg[0] >> 8) & 0xffff;
>>>>>>>> +}
>>>>>>>> +
>>>>>>>> +static int qps615_pwrctl_disable_port(struct qps615_pwrctl_ctx *ctx,
>>>>>>>> + enum qps615_pwrctl_ports port)
>>>>>>>> +{
>>>>>>>> + const struct qps615_pwrctl_reg_setting *seq;
>>>>>>>> + int ret, len;
>>>>>>>> +
>>>>>>>> + seq = (port == QPS615_DSP1) ? dsp1_pwroff_seq : dsp2_pwroff_seq;
>>>>>>>> + len = (port == QPS615_DSP1) ? ARRAY_SIZE(dsp1_pwroff_seq) : ARRAY_SIZE(dsp2_pwroff_seq);
>>>>>>>> +
>>>>>>>> + ret = qps615_pwrctl_i2c_bulk_write(ctx->client, seq, len);
>>>>>>>> + if (ret)
>>>>>>>> + return ret;
>>>>>>>> +
>>>>>>>> + return qps615_pwrctl_i2c_bulk_write(ctx->client,
>>>>>>>> + common_pwroff_seq, ARRAY_SIZE(common_pwroff_seq));
>>>>>>>> +}
>>>>>>>> +
>>>>>>>> +static int qps615_pwrctl_set_l0s_l1_entry_delay(struct qps615_pwrctl_ctx *ctx,
>>>>>>>> + enum qps615_pwrctl_ports port, bool is_l1, u32 ns)
>>>>>>>> +{
>>>>>>>> + u32 rd_val, units;
>>>>>>>> + int ret;
>>>>>>>> +
>>>>>>>> + /* convert to units of 256ns */
>>>>>>>> + units = ns / 256;
>>>>>>>> +
>>>>>>>> + if (port == QPS615_ETHERNET) {
>>>>>>>> + ret = qps615_pwrctl_i2c_read(ctx->client, QPS615_EMBEDDED_ETH_DELAY, &rd_val);
>>>>>>>> + if (ret)
>>>>>>>> + return ret;
>>>>>>>> + rd_val = u32_replace_bits(rd_val, units,
>>>>>>>> + is_l1 ?
>>>>>>>> + QPS615_ETH_L1_DELAY_MASK : QPS615_ETH_L0S_DELAY_MASK);
>>>>>>>> + return qps615_pwrctl_i2c_write(ctx->client, QPS615_EMBEDDED_ETH_DELAY, rd_val);
>>>>>>>> + }
>>>>>>>> +
>>>>>>>> + ret = qps615_pwrctl_i2c_write(ctx->client, QPS615_PORT_SELECT, BIT(port));
>>>>>>>> + if (ret)
>>>>>>>> + return ret;
>>>>>>>
>>>>>>> What if there is a concurrent call? The port_select / write_value
>>>>>>> statements should use a lock to remove the possible race condition.
>>>>>>>
>>>>>> There should not be any concurrent calls since all calls come from the
>>>>>> probe itself.
>>>>>
>>>>> Comment this in the driver, since somebody might decide to call the function later
>>>> ack
>>>>>
>>>>>>>> +
>>>>>>>> + return qps615_pwrctl_i2c_write(ctx->client,
>>>>>>>> + is_l1 ? QPS615_PORT_L1_DELAY : QPS615_PORT_L0S_DELAY, units);
>>>>>>>> +}
>>>>>>>> +
>>>>>>>> +static int qps615_pwrctl_set_tx_amplitude(struct qps615_pwrctl_ctx *ctx,
>>>>>>>> + enum qps615_pwrctl_ports port, u32 amp)
>>>>>>>> +{
>>>>>>>> + int port_access;
>>>>>>>> +
>>>>>>>> + switch (port) {
>>>>>>>> + case QPS615_USP:
>>>>>>>> + port_access = 0x1;
>>>>>>>> + break;
>>>>>>>> + case QPS615_DSP1:
>>>>>>>> + port_access = 0x2;
>>>>>>>> + break;
>>>>>>>> + case QPS615_DSP2:
>>>>>>>> + port_access = 0x8;
>>>>>>>> + break;
>>>>>>>> + default:
>>>>>>>> + return -EINVAL;
>>>>>>>> + };
>>>>>>>> +
>>>>>>>> + struct qps615_pwrctl_reg_setting tx_amp_seq[] = {
>>>>>>>> + {QPS615_PORT_ACCESS_ENABLE, port_access},
>>>>>>>
>>>>>>> Hmm, this looks like another port selection, so most likely it should
>>>>>>> also be under the same lock.
>>>>>>>
>>>>>>>> + {QPS615_PORT_LANE_ACCESS_ENABLE, 0x3},
>>>>>>>> + {QPS615_TX_MARGIN, amp},
>>>>>>>> + };
>>>>>>>> +
>>>>>>>> + return qps615_pwrctl_i2c_bulk_write(ctx->client, tx_amp_seq, ARRAY_SIZE(tx_amp_seq));
>>>>>>>> +}
>>>>>>>> +
>>>>>>>> +static int qps615_pwrctl_disable_dfe(struct qps615_pwrctl_ctx *ctx,
>>>>>>>> + enum qps615_pwrctl_ports port)
>>>>>>>> +{
>>>>>>>> + int port_access, lane_access = 0x3;
>>>>>>>> + u32 phy_rate = 0x21;
>>>>>>>> +
>>>>>>>> + switch (port) {
>>>>>>>> + case QPS615_USP:
>>>>>>>> + phy_rate = 0x1;
>>>>>>>> + port_access = 0x1;
>>>>>>>> + break;
>>>>>>>> + case QPS615_DSP1:
>>>>>>>> + port_access = 0x2;
>>>>>>>> + break;
>>>>>>>> + case QPS615_DSP2:
>>>>>>>> + port_access = 0x8;
>>>>>>>> + lane_access = 0x1;
>>>>>>>> + break;
>>>>>>>> + default:
>>>>>>>> + return -EINVAL;
>>>>>>>> + };
>>>>>>>> +
>>>>>>>> + struct qps615_pwrctl_reg_setting disable_dfe_seq[] = {
>>>>>>>> + {QPS615_PORT_ACCESS_ENABLE, port_access},
>>>>>>>> + {QPS615_PORT_LANE_ACCESS_ENABLE, lane_access},
>>>>>>>> + {QPS615_DFE_ENABLE, 0x0},
>>>>>>>> + {QPS615_DFE_EQ0_MODE, 0x411},
>>>>>>>> + {QPS615_DFE_EQ1_MODE, 0x11},
>>>>>>>> + {QPS615_DFE_EQ2_MODE, 0x11},
>>>>>>>> + {QPS615_DFE_PD_MASK, 0x7},
>>>>>>>> + {QPS615_PHY_RATE_CHANGE_OVERRIDE, 0x10},
>>>>>>>> + {QPS615_PHY_RATE_CHANGE, phy_rate},
>>>>>>>> + {QPS615_PHY_RATE_CHANGE, 0x0},
>>>>>>>> + {QPS615_PHY_RATE_CHANGE_OVERRIDE, 0x0},
>>>>>>>> +
>>>>>>>> + };
>>>>>>>> +
>>>>>>>> + return qps615_pwrctl_i2c_bulk_write(ctx->client,
>>>>>>>> + disable_dfe_seq, ARRAY_SIZE(disable_dfe_seq));
>>>>>>>> +}
>>>>>>>> +
>>>>>>>> +static int qps615_pwrctl_set_nfts(struct qps615_pwrctl_ctx *ctx,
>>>>>>>> + enum qps615_pwrctl_ports port, u32 nfts)
>>>>>>>> +{
>>>>>>>> + int ret;
>>>>>>>> + struct qps615_pwrctl_reg_setting nfts_seq[] = {
>>>>>>>> + {QPS615_NFTS_2_5_GT, nfts},
>>>>>>>> + {QPS615_NFTS_5_GT, nfts},
>>>>>>>> + };
>>>>>>>> +
>>>>>>>> + ret = qps615_pwrctl_i2c_write(ctx->client, QPS615_PORT_SELECT, BIT(port));
>>>>>>>> + if (ret)
>>>>>>>> + return ret;
>>>>>>>> +
>>>>>>>> + return qps615_pwrctl_i2c_bulk_write(ctx->client, nfts_seq, ARRAY_SIZE(nfts_seq));
>>>>>>>> +}
>>>>>>>> +
>>>>>>>> +static int qps615_pwrctl_assert_deassert_reset(struct qps615_pwrctl_ctx *ctx, bool deassert)
>>>>>>>> +{
>>>>>>>> + int ret, val = 0;
>>>>>>>> +
>>>>>>>> + if (deassert)
>>>>>>>> + val = 0xc;
>>>>>>>> +
>>>>>>>> + ret = qps615_pwrctl_i2c_write(ctx->client, QPS615_GPIO_CONFIG, 0xfffffff3);
>>>>>>>
>>>>>>> It's a kind of magic
>>>>>>>
>>>>>> I will add a macro in next patch.
>>>>>>>> + if (ret)
>>>>>>>> + return ret;
>>>>>>>> +
>>>>>>>> + return qps615_pwrctl_i2c_write(ctx->client, QPS615_RESET_GPIO, val);
>>>>>>>> +}
>>>>>>>> +
>>>>>>>> +static int qps615_pwrctl_parse_device_dt(struct qps615_pwrctl_ctx *ctx, struct device_node *node)
>>>>>>>> +{
>>>>>>>> + enum qps615_pwrctl_ports port;
>>>>>>>> + struct qps615_pwrctl_cfg *cfg;
>>>>>>>> + struct device_node *np;
>>>>>>>> + int bdf, fun_no;
>>>>>>>> +
>>>>>>>> + bdf = of_pci_get_bdf(node);
>>>>>>>> + if (bdf < 0) {
>>>>>>>
>>>>>>> This is incorrect, it will fail if at any point BDF uses the most
>>>>>>> significant bit (which is permitted by the spec, if I'm not mistaken).
>>>>>>>
>>>>>> As per the reg property as described in the binding document we are not
>>>>>> expecting any change here.
>>>>>> https://elixir.bootlin.com/linux/v6.10.3/source/Documentation/devicetree/bindings/pci/pci.txt#L50.
>>>>>
>>>>> What will this function return if the bus no is 256?
>>>>> The supported PCI bus number is from 0x0 to 0xff only. so we
>>>> are not expecting any numbers greater than 0xff.
>>>>> Also please either move the function to the generic PCI code is change its name to match the rest of the driver. The of_pci_ prefix is reserved for the generic code.
>>>>>
>>>> ack.
>>>>>
>>>>>>>> + dev_err(ctx->pwrctl.dev, "Getting BDF failed\n");
>>>>>>>> + return 0;
>>>>>>>> + }
>>>>>>>> +
>>>>>>>> + fun_no = bdf & 0x7;
>>>>>>>
>>>>>>> I assume that ARI is not supported?
>>>>>>>
>>>>>> Yes this doesn't support ARI.
>>>>>>>> +
>>>>>>>> + /* In multi function node, ignore function 1 node */
>>>>>>>> + if (of_pci_get_bdf(of_get_parent(node)) == ctx->bdf->dsp3_bdf && !fun_no)
>>>>>>>> + port = QPS615_ETHERNET;
>>>>>>>> + else if (bdf == ctx->bdf->usp_bdf)
>>>>>>>> + port = QPS615_USP;
>>>>>>>
>>>>>>> The function is being called for child device nodes. Thus upstream
>>>>>>> facing port (I assume that this is what USP means) can not be enumerated
>>>>>>> in this way.
>>>>>> Sorry, but I didn't your question.
>>>>>>
>>>>>> These settings will not affect the enumeration sequence these are
>>>>>> for configuring ports only.
>>>>>
>>>>> You are handling the case of bdf equal to the USP. Is it possible at all?
>>>>>
>>>> at the time of the configuration the PCI link is not enabled yet,
>>>> once we are done with the configurations only we are resumeing the link
>>>> training. so when we start this configuration the link is not up yet.
>>>
>>> Is your answer relevant to the question I have asked?
>>>
>> sorry dmitry I might got your question wrong. what I understood is
>> "you are configuring USP port before the link is up, is that possible?"
>> I might read your statement wrongly.
>>
>> If the question is "why do we need to configure USP?" I will try to
>> respond below.
>> "USP also will have l0s, L1 entry delays, nfts etc which can be
>> configured".
>>
>> Sorry once again if your question doesn't fall in both can you tell
>> me your question.
>
> My question was why the function gets executed for the root port. But
> after reading the qps615_pwrctl_parse_device_dt() I have another
> question: you are parsing DT nodes recursively. You should stop
> parsing at the first level, so that grandchildren nodes can not
> override your data (and so that the time isn't spent on parsing
> useless data). Also I have the feeling that BDF parsing isn't so
> correct. Will it work if QPS is sitting behind a PCI-PCI bridge?
>
we are not executing for root port. we are configuring for USP
since there are some features of USP which can be configured.
we are trying to store each configurations in below line.
cfg = &ctx->cfg[port];
port will have enum value based upon the bdf. after filling
the parent node we calling recursive function for child nodes.
As the BDF is unique value for each node we not expecting to get
same enum value for child or grand child nodes and there will
be no overwrite. If the BDF is not matched we are just returning
instead of looking for the properties.
QPS615 node is defined as child of the pci-pci bridge only.
The pwrctl framework is designed to work if the device
is represented as child node in the pci-pci bridge only.
Hope it clarifies all the queries.
- Krishna chaitanya.
>>>>>
>>>>>>>
>>>>>>>> + else if (bdf == ctx->bdf->dsp1_bdf)
>>>>>>>> + port = QPS615_DSP1;
>>>>>>>> + else if (bdf == ctx->bdf->dsp2_bdf)
>>>>>>>> + port = QPS615_DSP2;
>>>>>>>> + else if (bdf == ctx->bdf->dsp3_bdf)
>>>>>>>> + port = QPS615_DSP3;
>>>>>>>> + else
>>>>>>>> + return 0;
>>>>>>>
>>>>>>> -EINVAL >
>>>>>> There are can be nodes describing endpoints also,
>>>>>> for those nodes bdf will not match and we are not
>>>>>> returning since it is expected for endpoint nodes.
>>>>>
>>>>> Which endpoints? Bindings don't describe them.
>>>>>
>>>> The client drivers like ethernet will add them once
>>>> this series is merged. Their drivers are not present
>>>> in the linux as of now.
>>>
>>> The bindings describe the hardware, not the drivers. Also the driver
>>> should work with the bindings that you have submitted, not some
>>> imaginary to-be-submitted state. Please either update the bindings
>>> within the patchset or fix the driver to return -EINVAL.
>>>
>> The qps615 bindings describes only the PCIe switch part,
>> the endpoints binding connected to the switch should be described by the
>> respective clients like USB hub, NVMe, ethernet etc bindings should
>> describe their hardware and its properties. And these bindings will
>> defined in seperate bindinds file not in qps615 bindings.
>>
>> for example:-
>>
>> in the following example pcie@0,0 describes usp and
>> pcie@1,0 & pcie@2,0 describes dsp's of the switch.
>> now if we say usb hub is connected to dsp1 i.e to the
>> node pcie@1,0 there will be a child node to the pcie@1,0
>> to denote usb hub hardware.
>> And that node is external to the switch and we are not
>> configuring it through i2c. As these are pcie devices
>> representation is generic one we can't say if the client
>> nodes(in this case usb hub) will be present or not. if the child
>> node( for example usb hub) is present we can't return -EINVAL
>> because qps615 will not configure it.
>>
>> &pcieport {
>> pcie@0,0 {
>> pcie@1,0 {
>> reg = <0x20800 0x0 0x0 0x0 0x0>;
>> #address-cells = <3>;
>> #size-cells = <2>;
>>
>> device_type = "pci";
>> ranges;
>> usb_hub@0,0 {
>> //describes USB hub
>> };
>> };
>>
>> pcie@2,0 {
>> reg = <0x21000 0x0 0x0 0x0 0x0>;
>> #address-cells = <3>;
>> #size-cells = <2>;
>>
>> device_type = "pci";
>> ranges;
>> };
>> };
>> };
>>>>>
>>>>>>
>>>>>>>> +
>>>>>>>> + cfg = &ctx->cfg[port];
>>>>>>>> +
>>>>>>>> + if (!of_device_is_available(node)) {
>>>>>>>> + cfg->disable_port = true;
>>>>>>>> + return 0;
>>>>>>>> + };
>>>>>>>> +
>>>>>>>> + of_property_read_u32(node, "qcom,axi-clk-freq-hz", &cfg->axi_freq);
>>>>>>>> +
>>>>>>>> + of_property_read_u32(node, "qcom,l0s-entry-delay-ns", &cfg->l0s_delay);
>>>>>>>> +
>>>>>>>> + of_property_read_u32(node, "qcom,l1-entry-delay-ns", &cfg->l1_delay);
>>>>>>>> +
>>>>>>>> + of_property_read_u32(node, "qcom,tx-amplitude-millivolt", &cfg->tx_amp);
>>>>>>>> +
>>>>>>>> + cfg->disable_dfe = of_property_read_bool(node, "qcom,no-dfe");
>>>>>>>> +
>>>>>>>> + of_property_read_u8(node, "qcom,nfts", &cfg->nfts);
>>>>>>>> +
>>>>>>>> + for_each_child_of_node(node, np)
>>>>>>>> + qps615_pwrctl_parse_device_dt(ctx, np);
>>>>>>>> +
>>>>>>>> + of_node_put(np);
>>>>>>>> + return 0;
>>>>>>>> +}
>>>>>>>> +
>>>>>>>> +static void qps615_pwrctl_power_off(struct qps615_pwrctl_ctx *ctx)
>>>>>>>> +{
>>>>>>>> + gpiod_set_value(ctx->reset_gpio, 1);
>>>>>>>> +
>>>>>>>> + regulator_bulk_disable(ARRAY_SIZE(ctx->supplies), ctx->supplies);
>>>>>>>> +}
>>>>>>>> +
>>>>>>>> +static int qps615_pwrctl_power_on(struct qps615_pwrctl_ctx *ctx)
>>>>>>>> +{
>>>>>>>> + struct qps615_pwrctl_cfg *cfg;
>>>>>>>> + int ret, i;
>>>>>>>> +
>>>>>>>> + ret = regulator_bulk_enable(ARRAY_SIZE(ctx->supplies), ctx->supplies);
>>>>>>>> + if (ret < 0)
>>>>>>>> + return dev_err_probe(ctx->pwrctl.dev, ret, "cannot enable regulators\n");
>>>>>>>> +
>>>>>>>> + gpiod_set_value(ctx->reset_gpio, 0);
>>>>>>>> +
>>>>>>>> + if (!ctx->client)
>>>>>>>> + return 0;
>>>>>>>
>>>>>>> really?
>>>>>>>
>>>>>> Even if we don't do i2c configuration PCIe enumeration will happen, for
>>>>>> some reason i2c client is not found, driver ignores the error and return
>>>>>> since basic functionality will work.
>>>>>
>>>>> So what is the point of such misconfiguration? If "something works" even in the default case, then we don't need this driver at all, do we?
>>>>>
>>>> we need this configuration for better power savings, reduce the AER
>>>> errors etc.. if there is no i2c client then that particular platform
>>>> doesn't need any configurations required.
>>>
>>> NAK. The i2c client is marked as required in the bindings. So there is
>>> no way for the kernel to see the device with no qps615 controller
>>> property.
>>>
>> agree as it is a required property we should not return 0 here.
>> I will return proper error value here.
>>
>> - Krishna chaitanya.
>>>>> Even worse. With the modular kernels you can not guarantee probe order. However the user expects that if the driver is probed, it has configured the hardware correctly.
>>>>>> Linux has special return value for such cases, please return it
>>>> instead if 0.
>>>>>
>>>> ack we will check and return them instead of 0.
>>>> - Krishna chaitanya.
>>>>>
>>>>>>>> +
>>>>>>>> + /*
>>>>>>>> + * Don't have a way to see if the reset has completed.
>>>>>>>> + * Wait for some time.
>>>>>>>> + */
>>>>>>>> + usleep_range(1000, 1001);
>>>>>>>> +
>>>>>>>> + ret = qps615_pwrctl_assert_deassert_reset(ctx, false);
>>>>>>>> + if (ret)
>>>>>>>> + goto out;
>>>>>>>> +
>>>>>>>> + if (ctx->cfg[QPS615_USP].axi_freq == QPS615_AXI_CLK_FREQ_MHZ) {
>>>>>>>> + ret = qps615_pwrctl_i2c_write(ctx->client, QPS615_BUS_CONTROL, BIT(16));
>>>>>>>> + if (ret)
>>>>>>>> + dev_err(ctx->pwrctl.dev, "Setting axi clk freq failed %d\n", ret);
>>>>>>>
>>>>>>> AXI, not axi
>>>>>>>
>>>>>> ack.
>>>>>>>> + }
>>>>>>>> +
>>>>>>>> + for (i = 0; i < QPS615_MAX; i++) {
>>>>>>>> + cfg = &ctx->cfg[i];
>>>>>>>> + if (cfg->disable_port) {
>>>>>>>> + ret = qps615_pwrctl_disable_port(ctx, i);
>>>>>>>> + if (ret) {
>>>>>>>> + dev_err(ctx->pwrctl.dev, "Disabling port failed\n");
>>>>>>>> + goto out;
>>>>>>>> + }
>>>>>>>> + }
>>>>>>>> +
>>>>>>>> + if (cfg->l0s_delay) {
>>>>>>>> + ret = qps615_pwrctl_set_l0s_l1_entry_delay(ctx, i, false, cfg->l0s_delay);
>>>>>>>> + if (ret) {
>>>>>>>> + dev_err(ctx->pwrctl.dev, "Setting L0s entry delay failed\n");
>>>>>>>> + goto out;
>>>>>>>> + }
>>>>>>>> + }
>>>>>>>> +
>>>>>>>> + if (cfg->l1_delay) {
>>>>>>>> + ret = qps615_pwrctl_set_l0s_l1_entry_delay(ctx, i, true, cfg->l1_delay);
>>>>>>>> + if (ret) {
>>>>>>>> + dev_err(ctx->pwrctl.dev, "Setting L1 entry delay failed\n");
>>>>>>>> + goto out;
>>>>>>>> + }
>>>>>>>> + }
>>>>>>>> +
>>>>>>>> + if (cfg->tx_amp) {
>>>>>>>> + ret = qps615_pwrctl_set_tx_amplitude(ctx, i, cfg->tx_amp);
>>>>>>>> + if (ret) {
>>>>>>>> + dev_err(ctx->pwrctl.dev, "Setting Tx amplitube failed\n");
>>>>>>>> + goto out;
>>>>>>>> + }
>>>>>>>> + }
>>>>>>>> +
>>>>>>>> + if (cfg->nfts) {
>>>>>>>> + ret = qps615_pwrctl_set_nfts(ctx, i, cfg->nfts);
>>>>>>>> + if (ret) {
>>>>>>>> + dev_err(ctx->pwrctl.dev, "Setting nfts failed\n");
>>>>>>>> + goto out;
>>>>>>>> + }
>>>>>>>> + }
>>>>>>>> +
>>>>>>>> + if (cfg->disable_dfe) {
>>>>>>>> + ret = qps615_pwrctl_disable_dfe(ctx, i);
>>>>>>>> + if (ret) {
>>>>>>>> + dev_err(ctx->pwrctl.dev, "Disabling DFE failed\n");
>>>>>>>> + goto out;
>>>>>>>> + }
>>>>>>>> + }
>>>>>>>> + }
>>>>>>>> +
>>>>>>>> + ret = qps615_pwrctl_assert_deassert_reset(ctx, true);
>>>>>>>> + if (!ret)
>>>>>>>> + return 0;
>>>>>>>> +
>>>>>>>> +out:
>>>>>>>> + qps615_pwrctl_power_off(ctx);
>>>>>>>> + return ret;
>>>>>>>> +}
>>>>>>>> +
>>>>>>>> +static int qps615_pwrctl_probe(struct platform_device *pdev)
>>>>>>>> +{
>>>>>>>> + struct device *dev = &pdev->dev;
>>>>>>>> + struct pci_host_bridge *bridge;
>>>>>>>> + struct qps615_pwrctl_ctx *ctx;
>>>>>>>> + struct device_node *node;
>>>>>>>> + struct pci_bus *bus;
>>>>>>>> + int ret;
>>>>>>>> +
>>>>>>>> + bus = pci_find_bus(of_get_pci_domain_nr(dev->parent->of_node), 0);
>>>>>>>> + if (!bus)
>>>>>>>> + return -ENODEV;
>>>>>>>> +
>>>>>>>> + bridge = pci_find_host_bridge(bus);
>>>>>>>> +
>>>>>>>> + ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL);
>>>>>>>> + if (!ctx)
>>>>>>>> + return -ENOMEM;
>>>>>>>> +
>>>>>>>> + node = of_parse_phandle(pdev->dev.of_node, "qcom,qps615-controller", 0);
>>>>>>>> + if (node) {
>>>>>>>
>>>>>>> And if !node?
>>>>>>>
>>>>>>>> + ctx->client = of_find_i2c_device_by_node(node);
>>>>>>>
>>>>>>> Leaks the reference count, see the comment at the function definition.
>>>>>>> Also what if the I2C bus gets unbound? Will it crash the driver?
>>>>>>>
>>>>>> I will fix in next patch.
>>>>>>
>>>>>> Driver is not expected to crash when i2c bus gets unbound.
>>>>>> It should be properly handled in i2c driver.
>>>>>
>>>>> Please verify it.
>>>>>
>>>>>
>>>>>>
>>>>>> - Krishna Chaitanya.
>>>>>>>> + of_node_put(node);
>>>>>>>> + if (!ctx->client)
>>>>>>>> + return dev_err_probe(dev, -EPROBE_DEFER,
>>>>>>>> + "failed to parse qcom,qps615-controller\n");
>>>>>>>> + }
>>>>>>>> +
>>>>>>>> + ctx->bdf = of_device_get_match_data(dev);
>>>>>>>> + ctx->pwrctl.dev = dev;
>>>>>>>> +
>>>>>>>> + ctx->supplies[0].supply = "vddc";
>>>>>>>> + ctx->supplies[1].supply = "vdd18";
>>>>>>>> + ctx->supplies[2].supply = "vdd09";
>>>>>>>> + ctx->supplies[3].supply = "vddio1";
>>>>>>>> + ctx->supplies[4].supply = "vddio2";
>>>>>>>> + ctx->supplies[5].supply = "vddio18";
>>>>>>>> + ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(ctx->supplies), ctx->supplies);
>>>>>>>> + if (ret)
>>>>>>>> + return dev_err_probe(dev, ret,
>>>>>>>> + "failed to get supply regulator\n");
>>>>>>>> +
>>>>>>>> + ctx->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_ASIS);
>>>>>>>> + if (IS_ERR(ctx->reset_gpio))
>>>>>>>> + return dev_err_probe(dev, PTR_ERR(ctx->reset_gpio), "failed to get reset GPIO\n");
>>>>>>>> +
>>>>>>>> + ctx->link = device_link_add(&bridge->dev, dev, DL_FLAG_AUTOREMOVE_CONSUMER);
>>>>>>>> +
>>>>>>>> + platform_set_drvdata(pdev, ctx);
>>>>>>>> +
>>>>>>>> + qps615_pwrctl_parse_device_dt(ctx, pdev->dev.of_node);
>>>>>>>> +
>>>>>>>> + if (bridge->ops->stop_link)
>>>>>>>> + bridge->ops->stop_link(bus);
>>>>>>>> +
>>>>>>>> + ret = qps615_pwrctl_power_on(ctx);
>>>>>>>> + if (ret)
>>>>>>>> + return ret;
>>>>>>>> +
>>>>>>>> + if (bridge->ops->start_link) {
>>>>>>>> + ret = bridge->ops->start_link(bus);
>>>>>>>> + if (ret)
>>>>>>>> + return ret;
>>>>>>>> + }
>>>>>>>> +
>>>>>>>> + return devm_pci_pwrctl_device_set_ready(dev, &ctx->pwrctl);
>>>>>>>> +}
>>>>>>>> +
>>>>>>>> +static void qps615_pwrctl_remove(struct platform_device *pdev)
>>>>>>>> +{
>>>>>>>> + struct device *dev = &pdev->dev;
>>>>>>>> + struct qps615_pwrctl_ctx *ctx = dev_get_drvdata(dev);
>>>>>>>> +
>>>>>>>> + device_link_del(ctx->link);
>>>>>>>> + qps615_pwrctl_power_off(ctx);
>>>>>>>> +}
>>>>>>>> +
>>>>>>>> +static const struct qps615_pwrctl_bdf_info bdf_info = {
>>>>>>>> + .usp_bdf = 0x100,
>>>>>>>> + .dsp1_bdf = 0x208,
>>>>>>>> + .dsp2_bdf = 0x210,
>>>>>>>> + .dsp3_bdf = 0x218,
>>>>>>>> +};
>>>>>>>> +
>>>>>>>> +static const struct of_device_id qps615_pwrctl_of_match[] = {
>>>>>>>> + { .compatible = "pci1179,0623", .data = &bdf_info },
>>>>>>>> + { }
>>>>>>>> +};
>>>>>>>> +MODULE_DEVICE_TABLE(of, qps615_pwrctl_of_match);
>>>>>>>> +
>>>>>>>> +static struct platform_driver qps615_pwrctl_driver = {
>>>>>>>> + .driver = {
>>>>>>>> + .name = "pwrctl-qps615",
>>>>>>>> + .of_match_table = qps615_pwrctl_of_match,
>>>>>>>> + .probe_type = PROBE_PREFER_ASYNCHRONOUS,
>>>>>>>> + },
>>>>>>>> + .probe = qps615_pwrctl_probe,
>>>>>>>> + .remove_new = qps615_pwrctl_remove,
>>>>>>>> +};
>>>>>>>> +module_platform_driver(qps615_pwrctl_driver);
>>>>>>>> +
>>>>>>>> +MODULE_AUTHOR("Krishna chaitanya chundru <quic_krichai@quicinc.com>");
>>>>>>>> +MODULE_DESCRIPTION("Qualcomm QPS615 power control driver");
>>>>>>>> +MODULE_LICENSE("GPL");
>>>>>>>>
>>>>>>>> --
>>>>>>>> 2.34.1
>>>>>>>>
>>>>>>>
>>>>>
>>>>>
>>>
>>>
>>>
>
>
>
^ permalink raw reply [flat|nested] 77+ messages in thread
* Re: [PATCH v2 7/8] PCI: qcom: Add support for host_stop_link() & host_start_link()
2024-09-02 6:51 ` Krishna Chaitanya Chundru
@ 2024-09-02 18:32 ` Dmitry Baryshkov
0 siblings, 0 replies; 77+ messages in thread
From: Dmitry Baryshkov @ 2024-09-02 18:32 UTC (permalink / raw)
To: Krishna Chaitanya Chundru
Cc: Bjorn Helgaas, Lorenzo Pieralisi, Krzysztof Wilczyński,
Rob Herring, Bjorn Helgaas, Krzysztof Kozlowski, Conor Dooley,
Konrad Dybcio, cros-qcom-dts-watchers, Bartosz Golaszewski,
Jingoo Han, Manivannan Sadhasivam, andersson, quic_vbadigan,
linux-arm-msm, linux-pci, devicetree, linux-kernel,
Bartosz Golaszewski
On Mon, Sep 02, 2024 at 12:21:22PM GMT, Krishna Chaitanya Chundru wrote:
>
>
> On 8/7/2024 12:42 AM, Bjorn Helgaas wrote:
> > On Sat, Aug 03, 2024 at 08:52:53AM +0530, Krishna chaitanya chundru wrote:
> > > For the switches like QPS615 which needs to configure it before
> > > the PCIe link is established.
> > >
> > > if the link is not up assert the PERST# and disable LTSSM bit so
> > > that PCIe controller will not participate in the link training
> > > as part of host_stop_link().
> > >
> > > De-assert the PERST# and enable LTSSM bit back in host_start_link().
> > >
> > > Introduce ltssm_disable function op to stop the link training.
> >
> > pcie-qcom.c is a driver for a PCIe host controller. Apparently QPS615
> > is a switch in a hierarchy that could be below any PCIe host
> > controller, so I'm missing the connection with pcie-qcom.c.
> >
> > Does this fix a problem that only occurs with pcie-qcom.c? What
> > happens if you put a QPS615 below some other controller?
> >
> Hi Bjorn,
>
> The qps615 is the qualcomm in-house PCIe switch it is not available to
> others. so we are trying to add for qualcomm soc's only.
Any guarantee that the status quo will stay so in future? Or that it
won't appear on Qualcomm platform with the virtualized PCIe controller?
--
With best wishes
Dmitry
^ permalink raw reply [flat|nested] 77+ messages in thread
* Re: [PATCH v2 8/8] PCI: pwrctl: Add power control driver for qps615
2024-09-02 10:47 ` Krishna Chaitanya Chundru
@ 2024-09-02 18:37 ` Dmitry Baryshkov
2024-10-17 15:47 ` Krishna Chaitanya Chundru
0 siblings, 1 reply; 77+ messages in thread
From: Dmitry Baryshkov @ 2024-09-02 18:37 UTC (permalink / raw)
To: Krishna Chaitanya Chundru
Cc: Lorenzo Pieralisi, Krzysztof Wilczyński, Rob Herring,
Bjorn Helgaas, Krzysztof Kozlowski, Conor Dooley, Konrad Dybcio,
cros-qcom-dts-watchers, Bartosz Golaszewski, Jingoo Han,
Manivannan Sadhasivam, andersson, quic_vbadigan, linux-arm-msm,
linux-pci, devicetree, linux-kernel, Bartosz Golaszewski
On Mon, Sep 02, 2024 at 04:17:06PM GMT, Krishna Chaitanya Chundru wrote:
>
>
> On 9/2/2024 3:42 PM, Dmitry Baryshkov wrote:
> > On Mon, 2 Sept 2024 at 11:32, Krishna Chaitanya Chundru
> > <quic_krichai@quicinc.com> wrote:
> > >
> > >
> > >
> > > On 9/2/2024 12:50 PM, Dmitry Baryshkov wrote:
> > > > On Mon, 2 Sept 2024 at 10:13, Krishna Chaitanya Chundru
> > > > <quic_krichai@quicinc.com> wrote:
> > > > >
> > > > >
> > > > >
> > > > > On 8/8/2024 9:00 AM, Dmitry Baryshkov wrote:
> > > > > > On August 5, 2024 1:14:47 PM GMT+07:00, Krishna Chaitanya Chundru <quic_krichai@quicinc.com> wrote:
> > > > > > >
> > > > > > >
> > > > > > > On 8/3/2024 5:04 PM, Dmitry Baryshkov wrote:
> > > > > > > > On Sat, Aug 03, 2024 at 08:52:54AM GMT, Krishna chaitanya chundru wrote:
> > > > > > > > > QPS615 switch needs to be configured after powering on and before
> > > > > > > > > PCIe link was up.
> > > > > > > > >
> > > > > > > > > As the PCIe controller driver already enables the PCIe link training
> > > > > > > > > at the host side, stop the link training. Otherwise the moment we turn
> > > > > > > > > on the switch it will participate in the link training and link may come
> > > > > > > > > up before switch is configured through i2c.
> > > > > > > > >
> > > > > > > > > The device tree properties are parsed per node under pci-pci bridge in the
> > > > > > > > > driver. Each node has unique bdf value in the reg property, driver
> > > > > > > > > uses this bdf to differentiate ports, as there are certain i2c writes to
> > > > > > > > > select particular port.
> > > > > > > > >
> > > > > > > > > Based up on dt property and port, qps615 is configured through i2c.
> > > > > > > > >
> > > > > > > > > Signed-off-by: Krishna chaitanya chundru <quic_krichai@quicinc.com>
> > > > > > > > > ---
> > > > > > > > > drivers/pci/pwrctl/Kconfig | 7 +
> > > > > > > > > drivers/pci/pwrctl/Makefile | 1 +
> > > > > > > > > drivers/pci/pwrctl/pci-pwrctl-qps615.c | 638 +++++++++++++++++++++++++++++++++
> > > > > > > > > 3 files changed, 646 insertions(+)
> > > > > > > > >
> > > > > > > > > +
> > > > > > > > > + return qps615_pwrctl_i2c_write(ctx->client,
> > > > > > > > > + is_l1 ? QPS615_PORT_L1_DELAY : QPS615_PORT_L0S_DELAY, units);
> > > > > > > > > +}
> > > > > > > > > +
> > > > > > > > > +static int qps615_pwrctl_set_tx_amplitude(struct qps615_pwrctl_ctx *ctx,
> > > > > > > > > + enum qps615_pwrctl_ports port, u32 amp)
> > > > > > > > > +{
> > > > > > > > > + int port_access;
> > > > > > > > > +
> > > > > > > > > + switch (port) {
> > > > > > > > > + case QPS615_USP:
> > > > > > > > > + port_access = 0x1;
> > > > > > > > > + break;
> > > > > > > > > + case QPS615_DSP1:
> > > > > > > > > + port_access = 0x2;
> > > > > > > > > + break;
> > > > > > > > > + case QPS615_DSP2:
> > > > > > > > > + port_access = 0x8;
> > > > > > > > > + break;
> > > > > > > > > + default:
> > > > > > > > > + return -EINVAL;
> > > > > > > > > + };
> > > > > > > > > +
> > > > > > > > > + struct qps615_pwrctl_reg_setting tx_amp_seq[] = {
> > > > > > > > > + {QPS615_PORT_ACCESS_ENABLE, port_access},
> > > > > > > >
> > > > > > > > Hmm, this looks like another port selection, so most likely it should
> > > > > > > > also be under the same lock.
> > > > > > > >
> > > > > > > > > + {QPS615_PORT_LANE_ACCESS_ENABLE, 0x3},
> > > > > > > > > + {QPS615_TX_MARGIN, amp},
> > > > > > > > > + };
> > > > > > > > > +
> > > > > > > > > + return qps615_pwrctl_i2c_bulk_write(ctx->client, tx_amp_seq, ARRAY_SIZE(tx_amp_seq));
> > > > > > > > > +}
> > > > > > > > > +
> > > > > > > > > +static int qps615_pwrctl_disable_dfe(struct qps615_pwrctl_ctx *ctx,
> > > > > > > > > + enum qps615_pwrctl_ports port)
> > > > > > > > > +{
> > > > > > > > > + int port_access, lane_access = 0x3;
> > > > > > > > > + u32 phy_rate = 0x21;
> > > > > > > > > +
> > > > > > > > > + switch (port) {
> > > > > > > > > + case QPS615_USP:
> > > > > > > > > + phy_rate = 0x1;
> > > > > > > > > + port_access = 0x1;
> > > > > > > > > + break;
> > > > > > > > > + case QPS615_DSP1:
> > > > > > > > > + port_access = 0x2;
> > > > > > > > > + break;
> > > > > > > > > + case QPS615_DSP2:
> > > > > > > > > + port_access = 0x8;
> > > > > > > > > + lane_access = 0x1;
> > > > > > > > > + break;
> > > > > > > > > + default:
> > > > > > > > > + return -EINVAL;
> > > > > > > > > + };
> > > > > > > > > +
> > > > > > > > > + struct qps615_pwrctl_reg_setting disable_dfe_seq[] = {
> > > > > > > > > + {QPS615_PORT_ACCESS_ENABLE, port_access},
> > > > > > > > > + {QPS615_PORT_LANE_ACCESS_ENABLE, lane_access},
> > > > > > > > > + {QPS615_DFE_ENABLE, 0x0},
> > > > > > > > > + {QPS615_DFE_EQ0_MODE, 0x411},
> > > > > > > > > + {QPS615_DFE_EQ1_MODE, 0x11},
> > > > > > > > > + {QPS615_DFE_EQ2_MODE, 0x11},
> > > > > > > > > + {QPS615_DFE_PD_MASK, 0x7},
> > > > > > > > > + {QPS615_PHY_RATE_CHANGE_OVERRIDE, 0x10},
> > > > > > > > > + {QPS615_PHY_RATE_CHANGE, phy_rate},
> > > > > > > > > + {QPS615_PHY_RATE_CHANGE, 0x0},
> > > > > > > > > + {QPS615_PHY_RATE_CHANGE_OVERRIDE, 0x0},
> > > > > > > > > +
> > > > > > > > > + };
> > > > > > > > > +
> > > > > > > > > + return qps615_pwrctl_i2c_bulk_write(ctx->client,
> > > > > > > > > + disable_dfe_seq, ARRAY_SIZE(disable_dfe_seq));
> > > > > > > > > +}
> > > > > > > > > +
> > > > > > > > > +static int qps615_pwrctl_set_nfts(struct qps615_pwrctl_ctx *ctx,
> > > > > > > > > + enum qps615_pwrctl_ports port, u32 nfts)
> > > > > > > > > +{
> > > > > > > > > + int ret;
> > > > > > > > > + struct qps615_pwrctl_reg_setting nfts_seq[] = {
> > > > > > > > > + {QPS615_NFTS_2_5_GT, nfts},
> > > > > > > > > + {QPS615_NFTS_5_GT, nfts},
> > > > > > > > > + };
> > > > > > > > > +
> > > > > > > > > + ret = qps615_pwrctl_i2c_write(ctx->client, QPS615_PORT_SELECT, BIT(port));
> > > > > > > > > + if (ret)
> > > > > > > > > + return ret;
> > > > > > > > > +
> > > > > > > > > + return qps615_pwrctl_i2c_bulk_write(ctx->client, nfts_seq, ARRAY_SIZE(nfts_seq));
> > > > > > > > > +}
> > > > > > > > > +
> > > > > > > > > +static int qps615_pwrctl_assert_deassert_reset(struct qps615_pwrctl_ctx *ctx, bool deassert)
> > > > > > > > > +{
> > > > > > > > > + int ret, val = 0;
> > > > > > > > > +
> > > > > > > > > + if (deassert)
> > > > > > > > > + val = 0xc;
> > > > > > > > > +
> > > > > > > > > + ret = qps615_pwrctl_i2c_write(ctx->client, QPS615_GPIO_CONFIG, 0xfffffff3);
> > > > > > > >
> > > > > > > > It's a kind of magic
> > > > > > > >
> > > > > > > I will add a macro in next patch.
> > > > > > > > > + if (ret)
> > > > > > > > > + return ret;
> > > > > > > > > +
> > > > > > > > > + return qps615_pwrctl_i2c_write(ctx->client, QPS615_RESET_GPIO, val);
> > > > > > > > > +}
> > > > > > > > > +
> > > > > > > > > +static int qps615_pwrctl_parse_device_dt(struct qps615_pwrctl_ctx *ctx, struct device_node *node)
> > > > > > > > > +{
> > > > > > > > > + enum qps615_pwrctl_ports port;
> > > > > > > > > + struct qps615_pwrctl_cfg *cfg;
> > > > > > > > > + struct device_node *np;
> > > > > > > > > + int bdf, fun_no;
> > > > > > > > > +
> > > > > > > > > + bdf = of_pci_get_bdf(node);
> > > > > > > > > + if (bdf < 0) {
> > > > > > > >
> > > > > > > > This is incorrect, it will fail if at any point BDF uses the most
> > > > > > > > significant bit (which is permitted by the spec, if I'm not mistaken).
> > > > > > > >
> > > > > > > As per the reg property as described in the binding document we are not
> > > > > > > expecting any change here.
> > > > > > > https://elixir.bootlin.com/linux/v6.10.3/source/Documentation/devicetree/bindings/pci/pci.txt#L50.
> > > > > >
> > > > > > What will this function return if the bus no is 256?
> > > > > > The supported PCI bus number is from 0x0 to 0xff only. so we
> > > > > are not expecting any numbers greater than 0xff.
> > > > > > Also please either move the function to the generic PCI code is change its name to match the rest of the driver. The of_pci_ prefix is reserved for the generic code.
> > > > > >
> > > > > ack.
> > > > > >
> > > > > > > > > + dev_err(ctx->pwrctl.dev, "Getting BDF failed\n");
> > > > > > > > > + return 0;
> > > > > > > > > + }
> > > > > > > > > +
> > > > > > > > > + fun_no = bdf & 0x7;
> > > > > > > >
> > > > > > > > I assume that ARI is not supported?
> > > > > > > >
> > > > > > > Yes this doesn't support ARI.
> > > > > > > > > +
> > > > > > > > > + /* In multi function node, ignore function 1 node */
> > > > > > > > > + if (of_pci_get_bdf(of_get_parent(node)) == ctx->bdf->dsp3_bdf && !fun_no)
> > > > > > > > > + port = QPS615_ETHERNET;
> > > > > > > > > + else if (bdf == ctx->bdf->usp_bdf)
> > > > > > > > > + port = QPS615_USP;
> > > > > > > >
> > > > > > > > The function is being called for child device nodes. Thus upstream
> > > > > > > > facing port (I assume that this is what USP means) can not be enumerated
> > > > > > > > in this way.
> > > > > > > Sorry, but I didn't your question.
> > > > > > >
> > > > > > > These settings will not affect the enumeration sequence these are
> > > > > > > for configuring ports only.
> > > > > >
> > > > > > You are handling the case of bdf equal to the USP. Is it possible at all?
> > > > > >
> > > > > at the time of the configuration the PCI link is not enabled yet,
> > > > > once we are done with the configurations only we are resumeing the link
> > > > > training. so when we start this configuration the link is not up yet.
> > > >
> > > > Is your answer relevant to the question I have asked?
> > > >
> > > sorry dmitry I might got your question wrong. what I understood is
> > > "you are configuring USP port before the link is up, is that possible?"
> > > I might read your statement wrongly.
> > >
> > > If the question is "why do we need to configure USP?" I will try to
> > > respond below.
> > > "USP also will have l0s, L1 entry delays, nfts etc which can be
> > > configured".
> > >
> > > Sorry once again if your question doesn't fall in both can you tell
> > > me your question.
> >
> > My question was why the function gets executed for the root port. But
> > after reading the qps615_pwrctl_parse_device_dt() I have another
> > question: you are parsing DT nodes recursively. You should stop
> > parsing at the first level, so that grandchildren nodes can not
> > override your data (and so that the time isn't spent on parsing
> > useless data). Also I have the feeling that BDF parsing isn't so
> > correct. Will it work if QPS is sitting behind a PCI-PCI bridge?
> >
> we are not executing for root port. we are configuring for USP
> since there are some features of USP which can be configured.
What is USP? Upstream side port?
>
> we are trying to store each configurations in below line.
> cfg = &ctx->cfg[port];
>
> port will have enum value based upon the bdf. after filling
> the parent node we calling recursive function for child nodes.
> As the BDF is unique value for each node we not expecting to get
> same enum value for child or grand child nodes and there will
> be no overwrite. If the BDF is not matched we are just returning
> instead of looking for the properties.
>
> QPS615 node is defined as child of the pci-pci bridge only.
> The pwrctl framework is designed to work if the device
> is represented as child node in the pci-pci bridge only.
Of course. Each PCIe device is either a child of the root port or a
child of a pci-pci bridge. So are the BDFs specific to the case of
QPS615 being a child of the root PCIe bridge?
>
> Hope it clarifies all the queries.
Yes. Please drop recursive parsing and add explicit single
for_each_child_of_node().
>
> - Krishna chaitanya.
> > > > > >
> > > > > > > >
> > > > > > > > > + else if (bdf == ctx->bdf->dsp1_bdf)
> > > > > > > > > + port = QPS615_DSP1;
> > > > > > > > > + else if (bdf == ctx->bdf->dsp2_bdf)
> > > > > > > > > + port = QPS615_DSP2;
> > > > > > > > > + else if (bdf == ctx->bdf->dsp3_bdf)
> > > > > > > > > + port = QPS615_DSP3;
> > > > > > > > > + else
> > > > > > > > > + return 0;
> > > > > > > >
> > > > > > > > -EINVAL >
> > > > > > > There are can be nodes describing endpoints also,
> > > > > > > for those nodes bdf will not match and we are not
> > > > > > > returning since it is expected for endpoint nodes.
> > > > > >
> > > > > > Which endpoints? Bindings don't describe them.
> > > > > >
> > > > > The client drivers like ethernet will add them once
> > > > > this series is merged. Their drivers are not present
> > > > > in the linux as of now.
> > > >
> > > > The bindings describe the hardware, not the drivers. Also the driver
> > > > should work with the bindings that you have submitted, not some
> > > > imaginary to-be-submitted state. Please either update the bindings
> > > > within the patchset or fix the driver to return -EINVAL.
> > > >
> > > The qps615 bindings describes only the PCIe switch part,
> > > the endpoints binding connected to the switch should be described by the
> > > respective clients like USB hub, NVMe, ethernet etc bindings should
> > > describe their hardware and its properties. And these bindings will
> > > defined in seperate bindinds file not in qps615 bindings.
> > >
> > > for example:-
> > >
> > > in the following example pcie@0,0 describes usp and
> > > pcie@1,0 & pcie@2,0 describes dsp's of the switch.
> > > now if we say usb hub is connected to dsp1 i.e to the
> > > node pcie@1,0 there will be a child node to the pcie@1,0
> > > to denote usb hub hardware.
> > > And that node is external to the switch and we are not
> > > configuring it through i2c. As these are pcie devices
> > > representation is generic one we can't say if the client
> > > nodes(in this case usb hub) will be present or not. if the child
> > > node( for example usb hub) is present we can't return -EINVAL
> > > because qps615 will not configure it.
> > >
> > > &pcieport {
> > > pcie@0,0 {
> > > pcie@1,0 {
> > > reg = <0x20800 0x0 0x0 0x0 0x0>;
> > > #address-cells = <3>;
> > > #size-cells = <2>;
> > >
> > > device_type = "pci";
> > > ranges;
> > > usb_hub@0,0 {
> > > //describes USB hub
> > > };
> > > };
> > >
> > > pcie@2,0 {
> > > reg = <0x21000 0x0 0x0 0x0 0x0>;
> > > #address-cells = <3>;
> > > #size-cells = <2>;
> > >
> > > device_type = "pci";
> > > ranges;
> > > };
> > > };
> > > };
--
With best wishes
Dmitry
^ permalink raw reply [flat|nested] 77+ messages in thread
* Re: [PATCH v2 3/8] arm64: dts: qcom: qcs6490-rb3gen2: Add node for qps615
2024-08-03 3:22 ` [PATCH v2 3/8] arm64: dts: qcom: qcs6490-rb3gen2: Add node for qps615 Krishna chaitanya chundru
2024-08-04 8:54 ` Krzysztof Kozlowski
@ 2024-09-09 11:29 ` Caleb Connolly
2024-09-09 11:51 ` Krishna Chaitanya Chundru
1 sibling, 1 reply; 77+ messages in thread
From: Caleb Connolly @ 2024-09-09 11:29 UTC (permalink / raw)
To: Krishna chaitanya chundru, Lorenzo Pieralisi,
Krzysztof Wilczyński, Rob Herring, Bjorn Helgaas,
Krzysztof Kozlowski, Conor Dooley, Konrad Dybcio,
cros-qcom-dts-watchers, Bartosz Golaszewski, Jingoo Han,
Manivannan Sadhasivam
Cc: andersson, quic_vbadigan, linux-arm-msm, linux-pci, devicetree,
linux-kernel, Bartosz Golaszewski
Hi Krishna,
On 03/08/2024 05:22, Krishna chaitanya chundru wrote:
> Add QPS615 PCIe switch node which has 3 downstream ports and in one
> downstream port two embedded ethernet devices are present.
>
> Power to the QPS615 is supplied through two LDO regulators, controlled
> by two GPIOs, these are added as fixed regulators.
>
> Add i2c device node which is used to configure the switch.
>
> Signed-off-by: Krishna chaitanya chundru <quic_krichai@quicinc.com>
> ---
> arch/arm64/boot/dts/qcom/qcs6490-rb3gen2.dts | 121 +++++++++++++++++++++++++++
> arch/arm64/boot/dts/qcom/sc7280.dtsi | 2 +-
> 2 files changed, 122 insertions(+), 1 deletion(-)
>
> diff --git a/arch/arm64/boot/dts/qcom/qcs6490-rb3gen2.dts b/arch/arm64/boot/dts/qcom/qcs6490-rb3gen2.dts
> index 0d45662b8028..59d209768636 100644
> --- a/arch/arm64/boot/dts/qcom/qcs6490-rb3gen2.dts
> +++ b/arch/arm64/boot/dts/qcom/qcs6490-rb3gen2.dts
> @@ -202,6 +202,30 @@ vph_pwr: vph-pwr-regulator {
> regulator-min-microvolt = <3700000>;
> regulator-max-microvolt = <3700000>;
> };
> +
> + vdd_ntn_0p9: regulator-vdd-ntn-0p9 {
> + compatible = "regulator-fixed";
> + regulator-name = "VDD_NTN_0P9";
> + gpio = <&pm8350c_gpios 2 GPIO_ACTIVE_HIGH>;
> + regulator-min-microvolt = <899400>;
> + regulator-max-microvolt = <899400>;
> + enable-active-high;
> + pinctrl-0 = <&ntn_0p9_en>;
> + pinctrl-names = "default";
> + regulator-enable-ramp-delay = <4300>;
> + };
> +
> + vdd_ntn_1p8: regulator-vdd-ntn-1p8 {
> + compatible = "regulator-fixed";
> + regulator-name = "VDD_NTN_1P8";
> + gpio = <&pm8350c_gpios 3 GPIO_ACTIVE_HIGH>;
> + regulator-min-microvolt = <1800000>;
> + regulator-max-microvolt = <1800000>;
> + enable-active-high;
> + pinctrl-0 = <&ntn_1p8_en>;
> + pinctrl-names = "default";
> + regulator-enable-ramp-delay = <10000>;
> + };
> };
>
> &apps_rsc {
> @@ -595,6 +619,12 @@ lt9611_out: endpoint {
> };
> };
> };
> +
> + qps615_switch: pcie-switch@77 {
> + compatible = "qcom,qps615";
> + reg = <0x77>;
> + status = "okay";
> + };
> };
>
> &i2c1 {
> @@ -688,6 +718,75 @@ &pmk8350_rtc {
> status = "okay";
> };
>
> +&pcie1 {
> + status = "okay";
> +};
Isn't it also necessary to configure the phy as well? It's also default
disabled and has two regulators.
Kind regards,
> +
> +&pcieport {
> + pcie@0,0 {
> + compatible = "pci1179,0623";
> + reg = <0x10000 0x0 0x0 0x0 0x0>;
> + #address-cells = <3>;
> + #size-cells = <2>;
> +
> + device_type = "pci";
> + ranges;
> +
> + vddc-supply = <&vdd_ntn_0p9>;
> + vdd18-supply = <&vdd_ntn_1p8>;
> + vdd09-supply = <&vdd_ntn_0p9>;
> + vddio1-supply = <&vdd_ntn_1p8>;
> + vddio2-supply = <&vdd_ntn_1p8>;
> + vddio18-supply = <&vdd_ntn_1p8>;
> +
> + qcom,qps615-controller = <&qps615_switch>;
> +
> + reset-gpios = <&pm8350c_gpios 1 GPIO_ACTIVE_LOW>;
> +
> + pcie@1,0 {
> + reg = <0x20800 0x0 0x0 0x0 0x0>;
> + #address-cells = <3>;
> + #size-cells = <2>;
> +
> + device_type = "pci";
> + ranges;
> + };
> +
> + pcie@2,0 {
> + reg = <0x21000 0x0 0x0 0x0 0x0>;
> + #address-cells = <3>;
> + #size-cells = <2>;
> +
> + device_type = "pci";
> + ranges;
> + };
> +
> + pcie@3,0 {
> + reg = <0x21800 0x0 0x0 0x0 0x0>;
> + #address-cells = <3>;
> + #size-cells = <2>;
> + device_type = "pci";
> + ranges;
> +
> + pcie@0,0 {
> + reg = <0x50000 0x0 0x0 0x0 0x0>;
> + #address-cells = <3>;
> + #size-cells = <2>;
> + device_type = "pci";
> + ranges;
> + };
> +
> + pcie@0,1 {
> + reg = <0x50100 0x0 0x0 0x0 0x0>;
> + #address-cells = <3>;
> + #size-cells = <2>;
> + device_type = "pci";
> + ranges;
> + };
> + };
> + };
> +};
> +
> &qupv3_id_0 {
> status = "okay";
> };
> @@ -812,6 +911,28 @@ lt9611_rst_pin: lt9611-rst-state {
> };
> };
>
> +&pm8350c_gpios {
> + ntn_0p9_en: ntn-0p9-en-state {
> + pins = "gpio2";
> + function = "normal";
> +
> + bias-disable;
> + input-disable;
> + output-enable;
> + power-source = <0>;
> + };
> +
> + ntn_1p8_en: ntn-1p8-en-state {
> + pins = "gpio3";
> + function = "normal";
> +
> + bias-disable;
> + input-disable;
> + output-enable;
> + power-source = <0>;
> + };
> +};
> +
> &tlmm {
> lt9611_irq_pin: lt9611-irq-state {
> pins = "gpio24";
> diff --git a/arch/arm64/boot/dts/qcom/sc7280.dtsi b/arch/arm64/boot/dts/qcom/sc7280.dtsi
> index 3d8410683402..3840f056b7f2 100644
> --- a/arch/arm64/boot/dts/qcom/sc7280.dtsi
> +++ b/arch/arm64/boot/dts/qcom/sc7280.dtsi
> @@ -2279,7 +2279,7 @@ pcie1: pcie@1c08000 {
>
> status = "disabled";
>
> - pcie@0 {
> + pcieport: pcie@0 {
> device_type = "pci";
> reg = <0x0 0x0 0x0 0x0 0x0>;
> bus-range = <0x01 0xff>;
>
--
// Caleb (they/them)
^ permalink raw reply [flat|nested] 77+ messages in thread
* Re: [PATCH v2 3/8] arm64: dts: qcom: qcs6490-rb3gen2: Add node for qps615
2024-09-09 11:29 ` Caleb Connolly
@ 2024-09-09 11:51 ` Krishna Chaitanya Chundru
2024-09-09 12:54 ` Dmitry Baryshkov
0 siblings, 1 reply; 77+ messages in thread
From: Krishna Chaitanya Chundru @ 2024-09-09 11:51 UTC (permalink / raw)
To: Caleb Connolly, Lorenzo Pieralisi, Krzysztof Wilczyński,
Rob Herring, Bjorn Helgaas, Krzysztof Kozlowski, Conor Dooley,
Konrad Dybcio, cros-qcom-dts-watchers, Bartosz Golaszewski,
Jingoo Han, Manivannan Sadhasivam
Cc: andersson, quic_vbadigan, linux-arm-msm, linux-pci, devicetree,
linux-kernel, Bartosz Golaszewski
On 9/9/2024 4:59 PM, Caleb Connolly wrote:
> Hi Krishna,
>
> On 03/08/2024 05:22, Krishna chaitanya chundru wrote:
>> Add QPS615 PCIe switch node which has 3 downstream ports and in one
>> downstream port two embedded ethernet devices are present.
>>
>> Power to the QPS615 is supplied through two LDO regulators, controlled
>> by two GPIOs, these are added as fixed regulators.
>>
>> Add i2c device node which is used to configure the switch.
>>
>> Signed-off-by: Krishna chaitanya chundru <quic_krichai@quicinc.com>
>> ---
>> arch/arm64/boot/dts/qcom/qcs6490-rb3gen2.dts | 121 +++++++++++++++++++++++++++
>> arch/arm64/boot/dts/qcom/sc7280.dtsi | 2 +-
>> 2 files changed, 122 insertions(+), 1 deletion(-)
>>
>> diff --git a/arch/arm64/boot/dts/qcom/qcs6490-rb3gen2.dts b/arch/arm64/boot/dts/qcom/qcs6490-rb3gen2.dts
>> index 0d45662b8028..59d209768636 100644
>> --- a/arch/arm64/boot/dts/qcom/qcs6490-rb3gen2.dts
>> +++ b/arch/arm64/boot/dts/qcom/qcs6490-rb3gen2.dts
>> @@ -202,6 +202,30 @@ vph_pwr: vph-pwr-regulator {
>> regulator-min-microvolt = <3700000>;
>> regulator-max-microvolt = <3700000>;
>> };
>> +
>> + vdd_ntn_0p9: regulator-vdd-ntn-0p9 {
>> + compatible = "regulator-fixed";
>> + regulator-name = "VDD_NTN_0P9";
>> + gpio = <&pm8350c_gpios 2 GPIO_ACTIVE_HIGH>;
>> + regulator-min-microvolt = <899400>;
>> + regulator-max-microvolt = <899400>;
>> + enable-active-high;
>> + pinctrl-0 = <&ntn_0p9_en>;
>> + pinctrl-names = "default";
>> + regulator-enable-ramp-delay = <4300>;
>> + };
>> +
>> + vdd_ntn_1p8: regulator-vdd-ntn-1p8 {
>> + compatible = "regulator-fixed";
>> + regulator-name = "VDD_NTN_1P8";
>> + gpio = <&pm8350c_gpios 3 GPIO_ACTIVE_HIGH>;
>> + regulator-min-microvolt = <1800000>;
>> + regulator-max-microvolt = <1800000>;
>> + enable-active-high;
>> + pinctrl-0 = <&ntn_1p8_en>;
>> + pinctrl-names = "default";
>> + regulator-enable-ramp-delay = <10000>;
>> + };
>> };
>>
>> &apps_rsc {
>> @@ -595,6 +619,12 @@ lt9611_out: endpoint {
>> };
>> };
>> };
>> +
>> + qps615_switch: pcie-switch@77 {
>> + compatible = "qcom,qps615";
>> + reg = <0x77>;
>> + status = "okay";
>> + };
>> };
>>
>> &i2c1 {
>> @@ -688,6 +718,75 @@ &pmk8350_rtc {
>> status = "okay";
>> };
>>
>> +&pcie1 {
>> + status = "okay";
>> +};
>
> Isn't it also necessary to configure the phy as well? It's also default
> disabled and has two regulators.
>
There is one more patch series which does this.
https://lore.kernel.org/linux-arm-msm/20240207-enable_pcie-v1-1-b684afa6371c@quicinc.com/T/
sorry for this I should have included this in cover letter.
I will squash those changes to this series or will update the cover
letter.
- Krishna Chaitanya.
> Kind regards >> +
>> +&pcieport {
>> + pcie@0,0 {
>> + compatible = "pci1179,0623";
>> + reg = <0x10000 0x0 0x0 0x0 0x0>;
>> + #address-cells = <3>;
>> + #size-cells = <2>;
>> +
>> + device_type = "pci";
>> + ranges;
>> +
>> + vddc-supply = <&vdd_ntn_0p9>;
>> + vdd18-supply = <&vdd_ntn_1p8>;
>> + vdd09-supply = <&vdd_ntn_0p9>;
>> + vddio1-supply = <&vdd_ntn_1p8>;
>> + vddio2-supply = <&vdd_ntn_1p8>;
>> + vddio18-supply = <&vdd_ntn_1p8>;
>> +
>> + qcom,qps615-controller = <&qps615_switch>;
>> +
>> + reset-gpios = <&pm8350c_gpios 1 GPIO_ACTIVE_LOW>;
>> +
>> + pcie@1,0 {
>> + reg = <0x20800 0x0 0x0 0x0 0x0>;
>> + #address-cells = <3>;
>> + #size-cells = <2>;
>> +
>> + device_type = "pci";
>> + ranges;
>> + };
>> +
>> + pcie@2,0 {
>> + reg = <0x21000 0x0 0x0 0x0 0x0>;
>> + #address-cells = <3>;
>> + #size-cells = <2>;
>> +
>> + device_type = "pci";
>> + ranges;
>> + };
>> +
>> + pcie@3,0 {
>> + reg = <0x21800 0x0 0x0 0x0 0x0>;
>> + #address-cells = <3>;
>> + #size-cells = <2>;
>> + device_type = "pci";
>> + ranges;
>> +
>> + pcie@0,0 {
>> + reg = <0x50000 0x0 0x0 0x0 0x0>;
>> + #address-cells = <3>;
>> + #size-cells = <2>;
>> + device_type = "pci";
>> + ranges;
>> + };
>> +
>> + pcie@0,1 {
>> + reg = <0x50100 0x0 0x0 0x0 0x0>;
>> + #address-cells = <3>;
>> + #size-cells = <2>;
>> + device_type = "pci";
>> + ranges;
>> + };
>> + };
>> + };
>> +};
>> +
>> &qupv3_id_0 {
>> status = "okay";
>> };
>> @@ -812,6 +911,28 @@ lt9611_rst_pin: lt9611-rst-state {
>> };
>> };
>>
>> +&pm8350c_gpios {
>> + ntn_0p9_en: ntn-0p9-en-state {
>> + pins = "gpio2";
>> + function = "normal";
>> +
>> + bias-disable;
>> + input-disable;
>> + output-enable;
>> + power-source = <0>;
>> + };
>> +
>> + ntn_1p8_en: ntn-1p8-en-state {
>> + pins = "gpio3";
>> + function = "normal";
>> +
>> + bias-disable;
>> + input-disable;
>> + output-enable;
>> + power-source = <0>;
>> + };
>> +};
>> +
>> &tlmm {
>> lt9611_irq_pin: lt9611-irq-state {
>> pins = "gpio24";
>> diff --git a/arch/arm64/boot/dts/qcom/sc7280.dtsi b/arch/arm64/boot/dts/qcom/sc7280.dtsi
>> index 3d8410683402..3840f056b7f2 100644
>> --- a/arch/arm64/boot/dts/qcom/sc7280.dtsi
>> +++ b/arch/arm64/boot/dts/qcom/sc7280.dtsi
>> @@ -2279,7 +2279,7 @@ pcie1: pcie@1c08000 {
>>
>> status = "disabled";
>>
>> - pcie@0 {
>> + pcieport: pcie@0 {
>> device_type = "pci";
>> reg = <0x0 0x0 0x0 0x0 0x0>;
>> bus-range = <0x01 0xff>;
>>
>
^ permalink raw reply [flat|nested] 77+ messages in thread
* Re: [PATCH v2 3/8] arm64: dts: qcom: qcs6490-rb3gen2: Add node for qps615
2024-09-09 11:51 ` Krishna Chaitanya Chundru
@ 2024-09-09 12:54 ` Dmitry Baryshkov
0 siblings, 0 replies; 77+ messages in thread
From: Dmitry Baryshkov @ 2024-09-09 12:54 UTC (permalink / raw)
To: Krishna Chaitanya Chundru
Cc: Caleb Connolly, Lorenzo Pieralisi, Krzysztof Wilczyński,
Rob Herring, Bjorn Helgaas, Krzysztof Kozlowski, Conor Dooley,
Konrad Dybcio, cros-qcom-dts-watchers, Bartosz Golaszewski,
Jingoo Han, Manivannan Sadhasivam, andersson, quic_vbadigan,
linux-arm-msm, linux-pci, devicetree, linux-kernel,
Bartosz Golaszewski
On Mon, Sep 09, 2024 at 05:21:22PM GMT, Krishna Chaitanya Chundru wrote:
>
>
> On 9/9/2024 4:59 PM, Caleb Connolly wrote:
> > Hi Krishna,
> >
> > On 03/08/2024 05:22, Krishna chaitanya chundru wrote:
> > > Add QPS615 PCIe switch node which has 3 downstream ports and in one
> > > downstream port two embedded ethernet devices are present.
> > >
> > > Power to the QPS615 is supplied through two LDO regulators, controlled
> > > by two GPIOs, these are added as fixed regulators.
> > >
> > > Add i2c device node which is used to configure the switch.
> > >
> > > Signed-off-by: Krishna chaitanya chundru <quic_krichai@quicinc.com>
> > > ---
> > > arch/arm64/boot/dts/qcom/qcs6490-rb3gen2.dts | 121 +++++++++++++++++++++++++++
> > > arch/arm64/boot/dts/qcom/sc7280.dtsi | 2 +-
> > > 2 files changed, 122 insertions(+), 1 deletion(-)
> > >
> > > diff --git a/arch/arm64/boot/dts/qcom/qcs6490-rb3gen2.dts b/arch/arm64/boot/dts/qcom/qcs6490-rb3gen2.dts
> > > index 0d45662b8028..59d209768636 100644
> > > --- a/arch/arm64/boot/dts/qcom/qcs6490-rb3gen2.dts
> > > +++ b/arch/arm64/boot/dts/qcom/qcs6490-rb3gen2.dts
> > > @@ -202,6 +202,30 @@ vph_pwr: vph-pwr-regulator {
> > > regulator-min-microvolt = <3700000>;
> > > regulator-max-microvolt = <3700000>;
> > > };
> > > +
> > > + vdd_ntn_0p9: regulator-vdd-ntn-0p9 {
> > > + compatible = "regulator-fixed";
> > > + regulator-name = "VDD_NTN_0P9";
> > > + gpio = <&pm8350c_gpios 2 GPIO_ACTIVE_HIGH>;
> > > + regulator-min-microvolt = <899400>;
> > > + regulator-max-microvolt = <899400>;
> > > + enable-active-high;
> > > + pinctrl-0 = <&ntn_0p9_en>;
> > > + pinctrl-names = "default";
> > > + regulator-enable-ramp-delay = <4300>;
> > > + };
> > > +
> > > + vdd_ntn_1p8: regulator-vdd-ntn-1p8 {
> > > + compatible = "regulator-fixed";
> > > + regulator-name = "VDD_NTN_1P8";
> > > + gpio = <&pm8350c_gpios 3 GPIO_ACTIVE_HIGH>;
> > > + regulator-min-microvolt = <1800000>;
> > > + regulator-max-microvolt = <1800000>;
> > > + enable-active-high;
> > > + pinctrl-0 = <&ntn_1p8_en>;
> > > + pinctrl-names = "default";
> > > + regulator-enable-ramp-delay = <10000>;
> > > + };
> > > };
> > > &apps_rsc {
> > > @@ -595,6 +619,12 @@ lt9611_out: endpoint {
> > > };
> > > };
> > > };
> > > +
> > > + qps615_switch: pcie-switch@77 {
> > > + compatible = "qcom,qps615";
> > > + reg = <0x77>;
> > > + status = "okay";
> > > + };
> > > };
> > > &i2c1 {
> > > @@ -688,6 +718,75 @@ &pmk8350_rtc {
> > > status = "okay";
> > > };
> > > +&pcie1 {
> > > + status = "okay";
> > > +};
> >
> > Isn't it also necessary to configure the phy as well? It's also default
> > disabled and has two regulators.
> >
> There is one more patch series which does this.
>
> https://lore.kernel.org/linux-arm-msm/20240207-enable_pcie-v1-1-b684afa6371c@quicinc.com/T/
>
> sorry for this I should have included this in cover letter.
>
> I will squash those changes to this series or will update the cover
> letter.
It was sent in February, you have received feedback and several
suggestions on how to change it. After that you've never reposted it.
So, no, it is not possible to depend on that series or to include it in
this patchset. Please follow the thread and rework that patch.
> - Krishna Chaitanya.
>
--
With best wishes
Dmitry
^ permalink raw reply [flat|nested] 77+ messages in thread
* Re: [PATCH v2 8/8] PCI: pwrctl: Add power control driver for qps615
2024-09-02 18:37 ` Dmitry Baryshkov
@ 2024-10-17 15:47 ` Krishna Chaitanya Chundru
2024-10-17 16:24 ` Dmitry Baryshkov
0 siblings, 1 reply; 77+ messages in thread
From: Krishna Chaitanya Chundru @ 2024-10-17 15:47 UTC (permalink / raw)
To: Dmitry Baryshkov
Cc: Lorenzo Pieralisi, Krzysztof Wilczyński, Rob Herring,
Bjorn Helgaas, Krzysztof Kozlowski, Conor Dooley, Konrad Dybcio,
cros-qcom-dts-watchers, Bartosz Golaszewski, Jingoo Han,
Manivannan Sadhasivam, andersson, quic_vbadigan, linux-arm-msm,
linux-pci, devicetree, linux-kernel, Bartosz Golaszewski
On 9/3/2024 12:07 AM, Dmitry Baryshkov wrote:
> On Mon, Sep 02, 2024 at 04:17:06PM GMT, Krishna Chaitanya Chundru wrote:
>>
>>
>> On 9/2/2024 3:42 PM, Dmitry Baryshkov wrote:
>>> On Mon, 2 Sept 2024 at 11:32, Krishna Chaitanya Chundru
>>> <quic_krichai@quicinc.com> wrote:
>>>>
>>>>
>>>>
>>>> On 9/2/2024 12:50 PM, Dmitry Baryshkov wrote:
>>>>> On Mon, 2 Sept 2024 at 10:13, Krishna Chaitanya Chundru
>>>>> <quic_krichai@quicinc.com> wrote:
>>>>>>
>>>>>>
>>>>>>
>>>>>> On 8/8/2024 9:00 AM, Dmitry Baryshkov wrote:
>>>>>>> On August 5, 2024 1:14:47 PM GMT+07:00, Krishna Chaitanya Chundru <quic_krichai@quicinc.com> wrote:
>>>>>>>>
>>>>>>>>
>>>>>>>> On 8/3/2024 5:04 PM, Dmitry Baryshkov wrote:
>>>>>>>>> On Sat, Aug 03, 2024 at 08:52:54AM GMT, Krishna chaitanya chundru wrote:
>>>>>>>>>> QPS615 switch needs to be configured after powering on and before
>>>>>>>>>> PCIe link was up.
>>>>>>>>>>
>>>>>>>>>> As the PCIe controller driver already enables the PCIe link training
>>>>>>>>>> at the host side, stop the link training. Otherwise the moment we turn
>>>>>>>>>> on the switch it will participate in the link training and link may come
>>>>>>>>>> up before switch is configured through i2c.
>>>>>>>>>>
>>>>>>>>>> The device tree properties are parsed per node under pci-pci bridge in the
>>>>>>>>>> driver. Each node has unique bdf value in the reg property, driver
>>>>>>>>>> uses this bdf to differentiate ports, as there are certain i2c writes to
>>>>>>>>>> select particular port.
>>>>>>>>>>
>>>>>>>>>> Based up on dt property and port, qps615 is configured through i2c.
>>>>>>>>>>
>>>>>>>>>> Signed-off-by: Krishna chaitanya chundru <quic_krichai@quicinc.com>
>>>>>>>>>> ---
>>>>>>>>>> drivers/pci/pwrctl/Kconfig | 7 +
>>>>>>>>>> drivers/pci/pwrctl/Makefile | 1 +
>>>>>>>>>> drivers/pci/pwrctl/pci-pwrctl-qps615.c | 638 +++++++++++++++++++++++++++++++++
>>>>>>>>>> 3 files changed, 646 insertions(+)
>>>>>>>>>>
>
>>>>>>>>>> +
>>>>>>>>>> + return qps615_pwrctl_i2c_write(ctx->client,
>>>>>>>>>> + is_l1 ? QPS615_PORT_L1_DELAY : QPS615_PORT_L0S_DELAY, units);
>>>>>>>>>> +}
>>>>>>>>>> +
>>>>>>>>>> +static int qps615_pwrctl_set_tx_amplitude(struct qps615_pwrctl_ctx *ctx,
>>>>>>>>>> + enum qps615_pwrctl_ports port, u32 amp)
>>>>>>>>>> +{
>>>>>>>>>> + int port_access;
>>>>>>>>>> +
>>>>>>>>>> + switch (port) {
>>>>>>>>>> + case QPS615_USP:
>>>>>>>>>> + port_access = 0x1;
>>>>>>>>>> + break;
>>>>>>>>>> + case QPS615_DSP1:
>>>>>>>>>> + port_access = 0x2;
>>>>>>>>>> + break;
>>>>>>>>>> + case QPS615_DSP2:
>>>>>>>>>> + port_access = 0x8;
>>>>>>>>>> + break;
>>>>>>>>>> + default:
>>>>>>>>>> + return -EINVAL;
>>>>>>>>>> + };
>>>>>>>>>> +
>>>>>>>>>> + struct qps615_pwrctl_reg_setting tx_amp_seq[] = {
>>>>>>>>>> + {QPS615_PORT_ACCESS_ENABLE, port_access},
>>>>>>>>>
>>>>>>>>> Hmm, this looks like another port selection, so most likely it should
>>>>>>>>> also be under the same lock.
>>>>>>>>>
>>>>>>>>>> + {QPS615_PORT_LANE_ACCESS_ENABLE, 0x3},
>>>>>>>>>> + {QPS615_TX_MARGIN, amp},
>>>>>>>>>> + };
>>>>>>>>>> +
>>>>>>>>>> + return qps615_pwrctl_i2c_bulk_write(ctx->client, tx_amp_seq, ARRAY_SIZE(tx_amp_seq));
>>>>>>>>>> +}
>>>>>>>>>> +
>>>>>>>>>> +static int qps615_pwrctl_disable_dfe(struct qps615_pwrctl_ctx *ctx,
>>>>>>>>>> + enum qps615_pwrctl_ports port)
>>>>>>>>>> +{
>>>>>>>>>> + int port_access, lane_access = 0x3;
>>>>>>>>>> + u32 phy_rate = 0x21;
>>>>>>>>>> +
>>>>>>>>>> + switch (port) {
>>>>>>>>>> + case QPS615_USP:
>>>>>>>>>> + phy_rate = 0x1;
>>>>>>>>>> + port_access = 0x1;
>>>>>>>>>> + break;
>>>>>>>>>> + case QPS615_DSP1:
>>>>>>>>>> + port_access = 0x2;
>>>>>>>>>> + break;
>>>>>>>>>> + case QPS615_DSP2:
>>>>>>>>>> + port_access = 0x8;
>>>>>>>>>> + lane_access = 0x1;
>>>>>>>>>> + break;
>>>>>>>>>> + default:
>>>>>>>>>> + return -EINVAL;
>>>>>>>>>> + };
>>>>>>>>>> +
>>>>>>>>>> + struct qps615_pwrctl_reg_setting disable_dfe_seq[] = {
>>>>>>>>>> + {QPS615_PORT_ACCESS_ENABLE, port_access},
>>>>>>>>>> + {QPS615_PORT_LANE_ACCESS_ENABLE, lane_access},
>>>>>>>>>> + {QPS615_DFE_ENABLE, 0x0},
>>>>>>>>>> + {QPS615_DFE_EQ0_MODE, 0x411},
>>>>>>>>>> + {QPS615_DFE_EQ1_MODE, 0x11},
>>>>>>>>>> + {QPS615_DFE_EQ2_MODE, 0x11},
>>>>>>>>>> + {QPS615_DFE_PD_MASK, 0x7},
>>>>>>>>>> + {QPS615_PHY_RATE_CHANGE_OVERRIDE, 0x10},
>>>>>>>>>> + {QPS615_PHY_RATE_CHANGE, phy_rate},
>>>>>>>>>> + {QPS615_PHY_RATE_CHANGE, 0x0},
>>>>>>>>>> + {QPS615_PHY_RATE_CHANGE_OVERRIDE, 0x0},
>>>>>>>>>> +
>>>>>>>>>> + };
>>>>>>>>>> +
>>>>>>>>>> + return qps615_pwrctl_i2c_bulk_write(ctx->client,
>>>>>>>>>> + disable_dfe_seq, ARRAY_SIZE(disable_dfe_seq));
>>>>>>>>>> +}
>>>>>>>>>> +
>>>>>>>>>> +static int qps615_pwrctl_set_nfts(struct qps615_pwrctl_ctx *ctx,
>>>>>>>>>> + enum qps615_pwrctl_ports port, u32 nfts)
>>>>>>>>>> +{
>>>>>>>>>> + int ret;
>>>>>>>>>> + struct qps615_pwrctl_reg_setting nfts_seq[] = {
>>>>>>>>>> + {QPS615_NFTS_2_5_GT, nfts},
>>>>>>>>>> + {QPS615_NFTS_5_GT, nfts},
>>>>>>>>>> + };
>>>>>>>>>> +
>>>>>>>>>> + ret = qps615_pwrctl_i2c_write(ctx->client, QPS615_PORT_SELECT, BIT(port));
>>>>>>>>>> + if (ret)
>>>>>>>>>> + return ret;
>>>>>>>>>> +
>>>>>>>>>> + return qps615_pwrctl_i2c_bulk_write(ctx->client, nfts_seq, ARRAY_SIZE(nfts_seq));
>>>>>>>>>> +}
>>>>>>>>>> +
>>>>>>>>>> +static int qps615_pwrctl_assert_deassert_reset(struct qps615_pwrctl_ctx *ctx, bool deassert)
>>>>>>>>>> +{
>>>>>>>>>> + int ret, val = 0;
>>>>>>>>>> +
>>>>>>>>>> + if (deassert)
>>>>>>>>>> + val = 0xc;
>>>>>>>>>> +
>>>>>>>>>> + ret = qps615_pwrctl_i2c_write(ctx->client, QPS615_GPIO_CONFIG, 0xfffffff3);
>>>>>>>>>
>>>>>>>>> It's a kind of magic
>>>>>>>>>
>>>>>>>> I will add a macro in next patch.
>>>>>>>>>> + if (ret)
>>>>>>>>>> + return ret;
>>>>>>>>>> +
>>>>>>>>>> + return qps615_pwrctl_i2c_write(ctx->client, QPS615_RESET_GPIO, val);
>>>>>>>>>> +}
>>>>>>>>>> +
>>>>>>>>>> +static int qps615_pwrctl_parse_device_dt(struct qps615_pwrctl_ctx *ctx, struct device_node *node)
>>>>>>>>>> +{
>>>>>>>>>> + enum qps615_pwrctl_ports port;
>>>>>>>>>> + struct qps615_pwrctl_cfg *cfg;
>>>>>>>>>> + struct device_node *np;
>>>>>>>>>> + int bdf, fun_no;
>>>>>>>>>> +
>>>>>>>>>> + bdf = of_pci_get_bdf(node);
>>>>>>>>>> + if (bdf < 0) {
>>>>>>>>>
>>>>>>>>> This is incorrect, it will fail if at any point BDF uses the most
>>>>>>>>> significant bit (which is permitted by the spec, if I'm not mistaken).
>>>>>>>>>
>>>>>>>> As per the reg property as described in the binding document we are not
>>>>>>>> expecting any change here.
>>>>>>>> https://elixir.bootlin.com/linux/v6.10.3/source/Documentation/devicetree/bindings/pci/pci.txt#L50.
>>>>>>>
>>>>>>> What will this function return if the bus no is 256?
>>>>>>> The supported PCI bus number is from 0x0 to 0xff only. so we
>>>>>> are not expecting any numbers greater than 0xff.
>>>>>>> Also please either move the function to the generic PCI code is change its name to match the rest of the driver. The of_pci_ prefix is reserved for the generic code.
>>>>>>>
>>>>>> ack.
>>>>>>>
>>>>>>>>>> + dev_err(ctx->pwrctl.dev, "Getting BDF failed\n");
>>>>>>>>>> + return 0;
>>>>>>>>>> + }
>>>>>>>>>> +
>>>>>>>>>> + fun_no = bdf & 0x7;
>>>>>>>>>
>>>>>>>>> I assume that ARI is not supported?
>>>>>>>>>
>>>>>>>> Yes this doesn't support ARI.
>>>>>>>>>> +
>>>>>>>>>> + /* In multi function node, ignore function 1 node */
>>>>>>>>>> + if (of_pci_get_bdf(of_get_parent(node)) == ctx->bdf->dsp3_bdf && !fun_no)
>>>>>>>>>> + port = QPS615_ETHERNET;
>>>>>>>>>> + else if (bdf == ctx->bdf->usp_bdf)
>>>>>>>>>> + port = QPS615_USP;
>>>>>>>>>
>>>>>>>>> The function is being called for child device nodes. Thus upstream
>>>>>>>>> facing port (I assume that this is what USP means) can not be enumerated
>>>>>>>>> in this way.
>>>>>>>> Sorry, but I didn't your question.
>>>>>>>>
>>>>>>>> These settings will not affect the enumeration sequence these are
>>>>>>>> for configuring ports only.
>>>>>>>
>>>>>>> You are handling the case of bdf equal to the USP. Is it possible at all?
>>>>>>>
>>>>>> at the time of the configuration the PCI link is not enabled yet,
>>>>>> once we are done with the configurations only we are resumeing the link
>>>>>> training. so when we start this configuration the link is not up yet.
>>>>>
>>>>> Is your answer relevant to the question I have asked?
>>>>>
>>>> sorry dmitry I might got your question wrong. what I understood is
>>>> "you are configuring USP port before the link is up, is that possible?"
>>>> I might read your statement wrongly.
>>>>
>>>> If the question is "why do we need to configure USP?" I will try to
>>>> respond below.
>>>> "USP also will have l0s, L1 entry delays, nfts etc which can be
>>>> configured".
>>>>
>>>> Sorry once again if your question doesn't fall in both can you tell
>>>> me your question.
>>>
>>> My question was why the function gets executed for the root port. But
>>> after reading the qps615_pwrctl_parse_device_dt() I have another
>>> question: you are parsing DT nodes recursively. You should stop
>>> parsing at the first level, so that grandchildren nodes can not
>>> override your data (and so that the time isn't spent on parsing
>>> useless data). Also I have the feeling that BDF parsing isn't so
>>> correct. Will it work if QPS is sitting behind a PCI-PCI bridge?
>>>
>> we are not executing for root port. we are configuring for USP
>> since there are some features of USP which can be configured.
>
> What is USP? Upstream side port?
>
>>
>> we are trying to store each configurations in below line.
>> cfg = &ctx->cfg[port];
>>
>> port will have enum value based upon the bdf. after filling
>> the parent node we calling recursive function for child nodes.
>> As the BDF is unique value for each node we not expecting to get
>> same enum value for child or grand child nodes and there will
>> be no overwrite. If the BDF is not matched we are just returning
>> instead of looking for the properties.
>>
>> QPS615 node is defined as child of the pci-pci bridge only.
>> The pwrctl framework is designed to work if the device
>> is represented as child node in the pci-pci bridge only.
>
> Of course. Each PCIe device is either a child of the root port or a
> child of a pci-pci bridge. So are the BDFs specific to the case of
> QPS615 being a child of the root PCIe bridge?
>
yes these are specific to qps615 being a child of the root PCIe bridge.
>>
>> Hope it clarifies all the queries.
>
> Yes. Please drop recursive parsing and add explicit single
> for_each_child_of_node().
>
Dimitry, the ethernet nodes which are child of dsp3 need extra
for_each_child_of_node and also we are going to add support for cascade
switch once this patch lands, in that cascade switch one more QPS615
switch will be connected to the one of the downstream port of the first
switch in that case we might need to do for_each_child_of_node twice
from the dsp node where cascade switch is connected.
So it will good if we have this recursive parsing.
- Krishna Chaitanya.
>
>> - Krishna chaitanya.
>>>>>>>
>>>>>>>>>
>>>>>>>>>> + else if (bdf == ctx->bdf->dsp1_bdf)
>>>>>>>>>> + port = QPS615_DSP1;
>>>>>>>>>> + else if (bdf == ctx->bdf->dsp2_bdf)
>>>>>>>>>> + port = QPS615_DSP2;
>>>>>>>>>> + else if (bdf == ctx->bdf->dsp3_bdf)
>>>>>>>>>> + port = QPS615_DSP3;
>>>>>>>>>> + else
>>>>>>>>>> + return 0;
>>>>>>>>>
>>>>>>>>> -EINVAL >
>>>>>>>> There are can be nodes describing endpoints also,
>>>>>>>> for those nodes bdf will not match and we are not
>>>>>>>> returning since it is expected for endpoint nodes.
>>>>>>>
>>>>>>> Which endpoints? Bindings don't describe them.
>>>>>>>
>>>>>> The client drivers like ethernet will add them once
>>>>>> this series is merged. Their drivers are not present
>>>>>> in the linux as of now.
>>>>>
>>>>> The bindings describe the hardware, not the drivers. Also the driver
>>>>> should work with the bindings that you have submitted, not some
>>>>> imaginary to-be-submitted state. Please either update the bindings
>>>>> within the patchset or fix the driver to return -EINVAL.
>>>>>
>>>> The qps615 bindings describes only the PCIe switch part,
>>>> the endpoints binding connected to the switch should be described by the
>>>> respective clients like USB hub, NVMe, ethernet etc bindings should
>>>> describe their hardware and its properties. And these bindings will
>>>> defined in seperate bindinds file not in qps615 bindings.
>>>>
>>>> for example:-
>>>>
>>>> in the following example pcie@0,0 describes usp and
>>>> pcie@1,0 & pcie@2,0 describes dsp's of the switch.
>>>> now if we say usb hub is connected to dsp1 i.e to the
>>>> node pcie@1,0 there will be a child node to the pcie@1,0
>>>> to denote usb hub hardware.
>>>> And that node is external to the switch and we are not
>>>> configuring it through i2c. As these are pcie devices
>>>> representation is generic one we can't say if the client
>>>> nodes(in this case usb hub) will be present or not. if the child
>>>> node( for example usb hub) is present we can't return -EINVAL
>>>> because qps615 will not configure it.
>>>>
>>>> &pcieport {
>>>> pcie@0,0 {
>>>> pcie@1,0 {
>>>> reg = <0x20800 0x0 0x0 0x0 0x0>;
>>>> #address-cells = <3>;
>>>> #size-cells = <2>;
>>>>
>>>> device_type = "pci";
>>>> ranges;
>>>> usb_hub@0,0 {
>>>> //describes USB hub
>>>> };
>>>> };
>>>>
>>>> pcie@2,0 {
>>>> reg = <0x21000 0x0 0x0 0x0 0x0>;
>>>> #address-cells = <3>;
>>>> #size-cells = <2>;
>>>>
>>>> device_type = "pci";
>>>> ranges;
>>>> };
>>>> };
>>>> };
>
^ permalink raw reply [flat|nested] 77+ messages in thread
* Re: [PATCH v2 8/8] PCI: pwrctl: Add power control driver for qps615
2024-10-17 15:47 ` Krishna Chaitanya Chundru
@ 2024-10-17 16:24 ` Dmitry Baryshkov
0 siblings, 0 replies; 77+ messages in thread
From: Dmitry Baryshkov @ 2024-10-17 16:24 UTC (permalink / raw)
To: Krishna Chaitanya Chundru
Cc: Lorenzo Pieralisi, Krzysztof Wilczyński, Rob Herring,
Bjorn Helgaas, Krzysztof Kozlowski, Conor Dooley, Konrad Dybcio,
cros-qcom-dts-watchers, Bartosz Golaszewski, Jingoo Han,
Manivannan Sadhasivam, andersson, quic_vbadigan, linux-arm-msm,
linux-pci, devicetree, linux-kernel, Bartosz Golaszewski
On Thu, 17 Oct 2024 at 18:48, Krishna Chaitanya Chundru
<quic_krichai@quicinc.com> wrote:
>
>
>
> On 9/3/2024 12:07 AM, Dmitry Baryshkov wrote:
> > On Mon, Sep 02, 2024 at 04:17:06PM GMT, Krishna Chaitanya Chundru wrote:
> >>
> >>
> >> On 9/2/2024 3:42 PM, Dmitry Baryshkov wrote:
> >>> On Mon, 2 Sept 2024 at 11:32, Krishna Chaitanya Chundru
> >>> <quic_krichai@quicinc.com> wrote:
> >>>>
> >>>>
> >>>>
> >>>> On 9/2/2024 12:50 PM, Dmitry Baryshkov wrote:
> >>>>> On Mon, 2 Sept 2024 at 10:13, Krishna Chaitanya Chundru
> >>>>> <quic_krichai@quicinc.com> wrote:
> >>>>>>
> >>>>>>
> >>>>>>
> >>>>>> On 8/8/2024 9:00 AM, Dmitry Baryshkov wrote:
> >>>>>>> On August 5, 2024 1:14:47 PM GMT+07:00, Krishna Chaitanya Chundru <quic_krichai@quicinc.com> wrote:
> >>>>>>>>
> >>>>>>>>
> >>>>>>>> On 8/3/2024 5:04 PM, Dmitry Baryshkov wrote:
> >>>>>>>>> On Sat, Aug 03, 2024 at 08:52:54AM GMT, Krishna chaitanya chundru wrote:
> >>>>>>>>>> QPS615 switch needs to be configured after powering on and before
> >>>>>>>>>> PCIe link was up.
> >>>>>>>>>>
> >>>>>>>>>> As the PCIe controller driver already enables the PCIe link training
> >>>>>>>>>> at the host side, stop the link training. Otherwise the moment we turn
> >>>>>>>>>> on the switch it will participate in the link training and link may come
> >>>>>>>>>> up before switch is configured through i2c.
> >>>>>>>>>>
> >>>>>>>>>> The device tree properties are parsed per node under pci-pci bridge in the
> >>>>>>>>>> driver. Each node has unique bdf value in the reg property, driver
> >>>>>>>>>> uses this bdf to differentiate ports, as there are certain i2c writes to
> >>>>>>>>>> select particular port.
> >>>>>>>>>>
> >>>>>>>>>> Based up on dt property and port, qps615 is configured through i2c.
> >>>>>>>>>>
> >>>>>>>>>> Signed-off-by: Krishna chaitanya chundru <quic_krichai@quicinc.com>
> >>>>>>>>>> ---
> >>>>>>>>>> drivers/pci/pwrctl/Kconfig | 7 +
> >>>>>>>>>> drivers/pci/pwrctl/Makefile | 1 +
> >>>>>>>>>> drivers/pci/pwrctl/pci-pwrctl-qps615.c | 638 +++++++++++++++++++++++++++++++++
> >>>>>>>>>> 3 files changed, 646 insertions(+)
> >>>>>>>>>>
> >
> >>>>>>>>>> +
> >>>>>>>>>> + return qps615_pwrctl_i2c_write(ctx->client,
> >>>>>>>>>> + is_l1 ? QPS615_PORT_L1_DELAY : QPS615_PORT_L0S_DELAY, units);
> >>>>>>>>>> +}
> >>>>>>>>>> +
> >>>>>>>>>> +static int qps615_pwrctl_set_tx_amplitude(struct qps615_pwrctl_ctx *ctx,
> >>>>>>>>>> + enum qps615_pwrctl_ports port, u32 amp)
> >>>>>>>>>> +{
> >>>>>>>>>> + int port_access;
> >>>>>>>>>> +
> >>>>>>>>>> + switch (port) {
> >>>>>>>>>> + case QPS615_USP:
> >>>>>>>>>> + port_access = 0x1;
> >>>>>>>>>> + break;
> >>>>>>>>>> + case QPS615_DSP1:
> >>>>>>>>>> + port_access = 0x2;
> >>>>>>>>>> + break;
> >>>>>>>>>> + case QPS615_DSP2:
> >>>>>>>>>> + port_access = 0x8;
> >>>>>>>>>> + break;
> >>>>>>>>>> + default:
> >>>>>>>>>> + return -EINVAL;
> >>>>>>>>>> + };
> >>>>>>>>>> +
> >>>>>>>>>> + struct qps615_pwrctl_reg_setting tx_amp_seq[] = {
> >>>>>>>>>> + {QPS615_PORT_ACCESS_ENABLE, port_access},
> >>>>>>>>>
> >>>>>>>>> Hmm, this looks like another port selection, so most likely it should
> >>>>>>>>> also be under the same lock.
> >>>>>>>>>
> >>>>>>>>>> + {QPS615_PORT_LANE_ACCESS_ENABLE, 0x3},
> >>>>>>>>>> + {QPS615_TX_MARGIN, amp},
> >>>>>>>>>> + };
> >>>>>>>>>> +
> >>>>>>>>>> + return qps615_pwrctl_i2c_bulk_write(ctx->client, tx_amp_seq, ARRAY_SIZE(tx_amp_seq));
> >>>>>>>>>> +}
> >>>>>>>>>> +
> >>>>>>>>>> +static int qps615_pwrctl_disable_dfe(struct qps615_pwrctl_ctx *ctx,
> >>>>>>>>>> + enum qps615_pwrctl_ports port)
> >>>>>>>>>> +{
> >>>>>>>>>> + int port_access, lane_access = 0x3;
> >>>>>>>>>> + u32 phy_rate = 0x21;
> >>>>>>>>>> +
> >>>>>>>>>> + switch (port) {
> >>>>>>>>>> + case QPS615_USP:
> >>>>>>>>>> + phy_rate = 0x1;
> >>>>>>>>>> + port_access = 0x1;
> >>>>>>>>>> + break;
> >>>>>>>>>> + case QPS615_DSP1:
> >>>>>>>>>> + port_access = 0x2;
> >>>>>>>>>> + break;
> >>>>>>>>>> + case QPS615_DSP2:
> >>>>>>>>>> + port_access = 0x8;
> >>>>>>>>>> + lane_access = 0x1;
> >>>>>>>>>> + break;
> >>>>>>>>>> + default:
> >>>>>>>>>> + return -EINVAL;
> >>>>>>>>>> + };
> >>>>>>>>>> +
> >>>>>>>>>> + struct qps615_pwrctl_reg_setting disable_dfe_seq[] = {
> >>>>>>>>>> + {QPS615_PORT_ACCESS_ENABLE, port_access},
> >>>>>>>>>> + {QPS615_PORT_LANE_ACCESS_ENABLE, lane_access},
> >>>>>>>>>> + {QPS615_DFE_ENABLE, 0x0},
> >>>>>>>>>> + {QPS615_DFE_EQ0_MODE, 0x411},
> >>>>>>>>>> + {QPS615_DFE_EQ1_MODE, 0x11},
> >>>>>>>>>> + {QPS615_DFE_EQ2_MODE, 0x11},
> >>>>>>>>>> + {QPS615_DFE_PD_MASK, 0x7},
> >>>>>>>>>> + {QPS615_PHY_RATE_CHANGE_OVERRIDE, 0x10},
> >>>>>>>>>> + {QPS615_PHY_RATE_CHANGE, phy_rate},
> >>>>>>>>>> + {QPS615_PHY_RATE_CHANGE, 0x0},
> >>>>>>>>>> + {QPS615_PHY_RATE_CHANGE_OVERRIDE, 0x0},
> >>>>>>>>>> +
> >>>>>>>>>> + };
> >>>>>>>>>> +
> >>>>>>>>>> + return qps615_pwrctl_i2c_bulk_write(ctx->client,
> >>>>>>>>>> + disable_dfe_seq, ARRAY_SIZE(disable_dfe_seq));
> >>>>>>>>>> +}
> >>>>>>>>>> +
> >>>>>>>>>> +static int qps615_pwrctl_set_nfts(struct qps615_pwrctl_ctx *ctx,
> >>>>>>>>>> + enum qps615_pwrctl_ports port, u32 nfts)
> >>>>>>>>>> +{
> >>>>>>>>>> + int ret;
> >>>>>>>>>> + struct qps615_pwrctl_reg_setting nfts_seq[] = {
> >>>>>>>>>> + {QPS615_NFTS_2_5_GT, nfts},
> >>>>>>>>>> + {QPS615_NFTS_5_GT, nfts},
> >>>>>>>>>> + };
> >>>>>>>>>> +
> >>>>>>>>>> + ret = qps615_pwrctl_i2c_write(ctx->client, QPS615_PORT_SELECT, BIT(port));
> >>>>>>>>>> + if (ret)
> >>>>>>>>>> + return ret;
> >>>>>>>>>> +
> >>>>>>>>>> + return qps615_pwrctl_i2c_bulk_write(ctx->client, nfts_seq, ARRAY_SIZE(nfts_seq));
> >>>>>>>>>> +}
> >>>>>>>>>> +
> >>>>>>>>>> +static int qps615_pwrctl_assert_deassert_reset(struct qps615_pwrctl_ctx *ctx, bool deassert)
> >>>>>>>>>> +{
> >>>>>>>>>> + int ret, val = 0;
> >>>>>>>>>> +
> >>>>>>>>>> + if (deassert)
> >>>>>>>>>> + val = 0xc;
> >>>>>>>>>> +
> >>>>>>>>>> + ret = qps615_pwrctl_i2c_write(ctx->client, QPS615_GPIO_CONFIG, 0xfffffff3);
> >>>>>>>>>
> >>>>>>>>> It's a kind of magic
> >>>>>>>>>
> >>>>>>>> I will add a macro in next patch.
> >>>>>>>>>> + if (ret)
> >>>>>>>>>> + return ret;
> >>>>>>>>>> +
> >>>>>>>>>> + return qps615_pwrctl_i2c_write(ctx->client, QPS615_RESET_GPIO, val);
> >>>>>>>>>> +}
> >>>>>>>>>> +
> >>>>>>>>>> +static int qps615_pwrctl_parse_device_dt(struct qps615_pwrctl_ctx *ctx, struct device_node *node)
> >>>>>>>>>> +{
> >>>>>>>>>> + enum qps615_pwrctl_ports port;
> >>>>>>>>>> + struct qps615_pwrctl_cfg *cfg;
> >>>>>>>>>> + struct device_node *np;
> >>>>>>>>>> + int bdf, fun_no;
> >>>>>>>>>> +
> >>>>>>>>>> + bdf = of_pci_get_bdf(node);
> >>>>>>>>>> + if (bdf < 0) {
> >>>>>>>>>
> >>>>>>>>> This is incorrect, it will fail if at any point BDF uses the most
> >>>>>>>>> significant bit (which is permitted by the spec, if I'm not mistaken).
> >>>>>>>>>
> >>>>>>>> As per the reg property as described in the binding document we are not
> >>>>>>>> expecting any change here.
> >>>>>>>> https://elixir.bootlin.com/linux/v6.10.3/source/Documentation/devicetree/bindings/pci/pci.txt#L50.
> >>>>>>>
> >>>>>>> What will this function return if the bus no is 256?
> >>>>>>> The supported PCI bus number is from 0x0 to 0xff only. so we
> >>>>>> are not expecting any numbers greater than 0xff.
> >>>>>>> Also please either move the function to the generic PCI code is change its name to match the rest of the driver. The of_pci_ prefix is reserved for the generic code.
> >>>>>>>
> >>>>>> ack.
> >>>>>>>
> >>>>>>>>>> + dev_err(ctx->pwrctl.dev, "Getting BDF failed\n");
> >>>>>>>>>> + return 0;
> >>>>>>>>>> + }
> >>>>>>>>>> +
> >>>>>>>>>> + fun_no = bdf & 0x7;
> >>>>>>>>>
> >>>>>>>>> I assume that ARI is not supported?
> >>>>>>>>>
> >>>>>>>> Yes this doesn't support ARI.
> >>>>>>>>>> +
> >>>>>>>>>> + /* In multi function node, ignore function 1 node */
> >>>>>>>>>> + if (of_pci_get_bdf(of_get_parent(node)) == ctx->bdf->dsp3_bdf && !fun_no)
> >>>>>>>>>> + port = QPS615_ETHERNET;
> >>>>>>>>>> + else if (bdf == ctx->bdf->usp_bdf)
> >>>>>>>>>> + port = QPS615_USP;
> >>>>>>>>>
> >>>>>>>>> The function is being called for child device nodes. Thus upstream
> >>>>>>>>> facing port (I assume that this is what USP means) can not be enumerated
> >>>>>>>>> in this way.
> >>>>>>>> Sorry, but I didn't your question.
> >>>>>>>>
> >>>>>>>> These settings will not affect the enumeration sequence these are
> >>>>>>>> for configuring ports only.
> >>>>>>>
> >>>>>>> You are handling the case of bdf equal to the USP. Is it possible at all?
> >>>>>>>
> >>>>>> at the time of the configuration the PCI link is not enabled yet,
> >>>>>> once we are done with the configurations only we are resumeing the link
> >>>>>> training. so when we start this configuration the link is not up yet.
> >>>>>
> >>>>> Is your answer relevant to the question I have asked?
> >>>>>
> >>>> sorry dmitry I might got your question wrong. what I understood is
> >>>> "you are configuring USP port before the link is up, is that possible?"
> >>>> I might read your statement wrongly.
> >>>>
> >>>> If the question is "why do we need to configure USP?" I will try to
> >>>> respond below.
> >>>> "USP also will have l0s, L1 entry delays, nfts etc which can be
> >>>> configured".
> >>>>
> >>>> Sorry once again if your question doesn't fall in both can you tell
> >>>> me your question.
> >>>
> >>> My question was why the function gets executed for the root port. But
> >>> after reading the qps615_pwrctl_parse_device_dt() I have another
> >>> question: you are parsing DT nodes recursively. You should stop
> >>> parsing at the first level, so that grandchildren nodes can not
> >>> override your data (and so that the time isn't spent on parsing
> >>> useless data). Also I have the feeling that BDF parsing isn't so
> >>> correct. Will it work if QPS is sitting behind a PCI-PCI bridge?
> >>>
> >> we are not executing for root port. we are configuring for USP
> >> since there are some features of USP which can be configured.
> >
> > What is USP? Upstream side port?
> >
> >>
> >> we are trying to store each configurations in below line.
> >> cfg = &ctx->cfg[port];
> >>
> >> port will have enum value based upon the bdf. after filling
> >> the parent node we calling recursive function for child nodes.
> >> As the BDF is unique value for each node we not expecting to get
> >> same enum value for child or grand child nodes and there will
> >> be no overwrite. If the BDF is not matched we are just returning
> >> instead of looking for the properties.
> >>
> >> QPS615 node is defined as child of the pci-pci bridge only.
> >> The pwrctl framework is designed to work if the device
> >> is represented as child node in the pci-pci bridge only.
> >
> > Of course. Each PCIe device is either a child of the root port or a
> > child of a pci-pci bridge. So are the BDFs specific to the case of
> > QPS615 being a child of the root PCIe bridge?
> >
> yes these are specific to qps615 being a child of the root PCIe bridge.
Then your approach doesn't scale. Please reimplement it in a way that
doesn't require knowing what is the actual topology of the bus. The
driver must work with no changes if you have another PCI-to-PCI bridge
between RC and QPS615.
> >>
> >> Hope it clarifies all the queries.
> >
> > Yes. Please drop recursive parsing and add explicit single
> > for_each_child_of_node().
> >
> Dimitry, the ethernet nodes which are child of dsp3 need extra
> for_each_child_of_node and also we are going to add support for cascade
> switch once this patch lands, in that cascade switch one more QPS615
> switch will be connected to the one of the downstream port of the first
> switch in that case we might need to do for_each_child_of_node twice
> from the dsp node where cascade switch is connected.
> So it will good if we have this recursive parsing.
Well, unless I miss something, your child bridge should be handled by
the driver for that bridge, not by the driver for the root bridge. So
recursive parsing should not be necessary.
>
> - Krishna Chaitanya.
> >
> >> - Krishna chaitanya.
> >>>>>>>
> >>>>>>>>>
> >>>>>>>>>> + else if (bdf == ctx->bdf->dsp1_bdf)
> >>>>>>>>>> + port = QPS615_DSP1;
> >>>>>>>>>> + else if (bdf == ctx->bdf->dsp2_bdf)
> >>>>>>>>>> + port = QPS615_DSP2;
> >>>>>>>>>> + else if (bdf == ctx->bdf->dsp3_bdf)
> >>>>>>>>>> + port = QPS615_DSP3;
> >>>>>>>>>> + else
> >>>>>>>>>> + return 0;
> >>>>>>>>>
> >>>>>>>>> -EINVAL >
> >>>>>>>> There are can be nodes describing endpoints also,
> >>>>>>>> for those nodes bdf will not match and we are not
> >>>>>>>> returning since it is expected for endpoint nodes.
> >>>>>>>
> >>>>>>> Which endpoints? Bindings don't describe them.
> >>>>>>>
> >>>>>> The client drivers like ethernet will add them once
> >>>>>> this series is merged. Their drivers are not present
> >>>>>> in the linux as of now.
> >>>>>
> >>>>> The bindings describe the hardware, not the drivers. Also the driver
> >>>>> should work with the bindings that you have submitted, not some
> >>>>> imaginary to-be-submitted state. Please either update the bindings
> >>>>> within the patchset or fix the driver to return -EINVAL.
> >>>>>
> >>>> The qps615 bindings describes only the PCIe switch part,
> >>>> the endpoints binding connected to the switch should be described by the
> >>>> respective clients like USB hub, NVMe, ethernet etc bindings should
> >>>> describe their hardware and its properties. And these bindings will
> >>>> defined in seperate bindinds file not in qps615 bindings.
> >>>>
> >>>> for example:-
> >>>>
> >>>> in the following example pcie@0,0 describes usp and
> >>>> pcie@1,0 & pcie@2,0 describes dsp's of the switch.
> >>>> now if we say usb hub is connected to dsp1 i.e to the
> >>>> node pcie@1,0 there will be a child node to the pcie@1,0
> >>>> to denote usb hub hardware.
> >>>> And that node is external to the switch and we are not
> >>>> configuring it through i2c. As these are pcie devices
> >>>> representation is generic one we can't say if the client
> >>>> nodes(in this case usb hub) will be present or not. if the child
> >>>> node( for example usb hub) is present we can't return -EINVAL
> >>>> because qps615 will not configure it.
> >>>>
> >>>> &pcieport {
> >>>> pcie@0,0 {
> >>>> pcie@1,0 {
> >>>> reg = <0x20800 0x0 0x0 0x0 0x0>;
> >>>> #address-cells = <3>;
> >>>> #size-cells = <2>;
> >>>>
> >>>> device_type = "pci";
> >>>> ranges;
> >>>> usb_hub@0,0 {
> >>>> //describes USB hub
> >>>> };
> >>>> };
> >>>>
> >>>> pcie@2,0 {
> >>>> reg = <0x21000 0x0 0x0 0x0 0x0>;
> >>>> #address-cells = <3>;
> >>>> #size-cells = <2>;
> >>>>
> >>>> device_type = "pci";
> >>>> ranges;
> >>>> };
> >>>> };
> >>>> };
> >
--
With best wishes
Dmitry
^ permalink raw reply [flat|nested] 77+ messages in thread
end of thread, other threads:[~2024-10-17 16:25 UTC | newest]
Thread overview: 77+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2024-08-03 3:22 [PATCH v2 0/8] PCI: Enable Power and configure the QPS615 PCIe switch Krishna chaitanya chundru
2024-08-03 3:22 ` [PATCH v2 1/8] dt-bindings: PCI: Add binding for qps615 Krishna chaitanya chundru
2024-08-03 4:33 ` Rob Herring (Arm)
2024-08-03 11:00 ` Dmitry Baryshkov
2024-08-05 4:16 ` Krishna Chaitanya Chundru
2024-08-04 8:53 ` Krzysztof Kozlowski
2024-08-05 4:11 ` Krishna Chaitanya Chundru
2024-08-05 5:14 ` Krzysztof Kozlowski
2024-08-05 5:26 ` Krishna Chaitanya Chundru
2024-08-05 5:28 ` Krzysztof Kozlowski
2024-08-05 5:57 ` Krishna Chaitanya Chundru
2024-08-05 14:43 ` Krzysztof Kozlowski
2024-08-22 14:16 ` Manivannan Sadhasivam
2024-08-23 9:01 ` Krzysztof Kozlowski
2024-08-23 9:44 ` Manivannan Sadhasivam
2024-08-23 13:51 ` Krzysztof Kozlowski
2024-08-23 15:11 ` Manivannan Sadhasivam
2024-08-05 17:07 ` Bjorn Andersson
2024-08-05 17:18 ` Krzysztof Kozlowski
2024-08-08 12:01 ` Manivannan Sadhasivam
2024-08-08 12:13 ` Krzysztof Kozlowski
2024-08-08 12:41 ` Manivannan Sadhasivam
2024-08-08 13:06 ` Krzysztof Kozlowski
2024-08-08 13:29 ` Manivannan Sadhasivam
2024-08-22 14:09 ` Manivannan Sadhasivam
2024-08-23 9:06 ` Krzysztof Kozlowski
2024-08-23 9:40 ` Manivannan Sadhasivam
2024-08-04 8:56 ` Krzysztof Kozlowski
2024-08-05 4:02 ` Krishna Chaitanya Chundru
2024-08-05 5:12 ` Krzysztof Kozlowski
2024-08-05 5:33 ` Krishna Chaitanya Chundru
2024-08-05 16:39 ` Bjorn Andersson
2024-08-05 16:58 ` Krzysztof Kozlowski
2024-08-03 3:22 ` [PATCH v2 2/8] dt-bindings: trivial-devices: Add qcom,qps615 Krishna chaitanya chundru
2024-08-04 8:50 ` Krzysztof Kozlowski
2024-08-05 4:11 ` Krishna Chaitanya Chundru
2024-08-03 3:22 ` [PATCH v2 3/8] arm64: dts: qcom: qcs6490-rb3gen2: Add node for qps615 Krishna chaitanya chundru
2024-08-04 8:54 ` Krzysztof Kozlowski
2024-08-05 4:14 ` Krishna Chaitanya Chundru
2024-09-09 11:29 ` Caleb Connolly
2024-09-09 11:51 ` Krishna Chaitanya Chundru
2024-09-09 12:54 ` Dmitry Baryshkov
2024-08-03 3:22 ` [PATCH v2 4/8] PCI: Change the parent to correctly represent pcie hierarchy Krishna chaitanya chundru
2024-08-06 19:07 ` Bjorn Helgaas
2024-08-06 20:06 ` Bartosz Golaszewski
2024-08-13 19:15 ` Bartosz Golaszewski
2024-08-22 19:28 ` Bjorn Helgaas
2024-08-22 20:01 ` Bartosz Golaszewski
2024-08-22 21:13 ` Bjorn Helgaas
2024-08-23 8:30 ` Manivannan Sadhasivam
2024-08-23 8:31 ` Bartosz Golaszewski
2024-08-23 7:23 ` Manivannan Sadhasivam
2024-08-03 3:22 ` [PATCH v2 5/8] PCI: Add new start_link() & stop_link function ops Krishna chaitanya chundru
2024-08-03 3:22 ` [PATCH v2 6/8] PCI: dwc: Add support for new pci function op Krishna chaitanya chundru
2024-08-03 3:22 ` [PATCH v2 7/8] PCI: qcom: Add support for host_stop_link() & host_start_link() Krishna chaitanya chundru
2024-08-06 19:12 ` Bjorn Helgaas
2024-09-02 6:51 ` Krishna Chaitanya Chundru
2024-09-02 18:32 ` Dmitry Baryshkov
2024-08-03 3:22 ` [PATCH v2 8/8] PCI: pwrctl: Add power control driver for qps615 Krishna chaitanya chundru
2024-08-03 11:34 ` Dmitry Baryshkov
2024-08-05 6:14 ` Krishna Chaitanya Chundru
2024-08-08 3:30 ` Dmitry Baryshkov
2024-09-02 7:12 ` Krishna Chaitanya Chundru
2024-09-02 7:20 ` Dmitry Baryshkov
2024-09-02 8:31 ` Krishna Chaitanya Chundru
2024-09-02 10:12 ` Dmitry Baryshkov
2024-09-02 10:47 ` Krishna Chaitanya Chundru
2024-09-02 18:37 ` Dmitry Baryshkov
2024-10-17 15:47 ` Krishna Chaitanya Chundru
2024-10-17 16:24 ` Dmitry Baryshkov
2024-08-03 10:56 ` [PATCH v2 0/8] PCI: Enable Power and configure the QPS615 PCIe switch Dmitry Baryshkov
2024-08-05 4:19 ` Krishna Chaitanya Chundru
2024-08-04 8:57 ` Krzysztof Kozlowski
2024-08-05 4:18 ` Krishna Chaitanya Chundru
2024-08-05 4:34 ` Krishna Chaitanya Chundru
2024-08-05 15:00 ` Rob Herring (Arm)
2024-08-06 15:24 ` Ilpo Järvinen
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).