Skip to contentSkip to conversation

power: sequencing: implement the subsystem and add first users

RFC Superseded Bartosz Golaszewski 9 participants 46 messages Feb 1, 2024 – Feb 14, 2024

Subsystems (8)

v1 of 9 Superseded Latest is v9 →

lore
Share & tools
lore
#0 lore raw

cover power: sequencing: implement the subsystem and add first users

From: Bartosz Golaszewski <[email protected]>

I'd like to preface the cover letter by saying right away that this series is not complete. It's an RFC that presents my approach and is sent to the list for discussion. There are no DT bindings nor docs in Documentation/ yet. Please review it as an RFC and not an upstreambound series. If the approach is accepted as correct, I'll add missing bits.

The RFC[1] presenting my proposed device-tree representation of the QCA6391 package present on the RB5 board - while not really officially accepted - was not outright rejected which is a good sign.

This series incorporates it and builds a proposed power sequencing subsystem together with the first dedicated driver around it. Then it adds first two users: the Bluetooth and WLAN modules of the QCA6391.

The Bluetooth part is pretty straightforward. The WLAN however is a PCIe device and as such needs to be powered-up *before* it's detected on the PCI bus. To that end, we modify the PCI core to instantiate platform devices for existing DT child nodes of the PCIe ports. For those nodes for which a power-sequencing driver exists, we bind it and let it probe. The driver then triggers a rescan of the PCI bus with the aim of detecting the now powered-on device. The device will consume the same DT node as the platform, power-sequencing device. We use device links to make the latter become the parent of the former.

The main advantage of the above approach (both for PCI as well as generic power sequencers) is that we don't introduce significant changes in DT bindings and don't introduce new properties. We merely define new resources.

[1] https://lore.kernel.org/all/CAMRc=MckG32DQv7b1AQL-mbnYdx4fsdYWtLwCyXc5Ma7EeSAKw@mail.gmail.com/T/#md5dc62007d12f6833d4e51658b14e0493954ba68

Bartosz Golaszewski (9):
of: provide a cleanup helper for OF nodes
arm64: dts: qcom: qrb5165-rb5: model the PMU of the QCA6391
power: sequencing: new subsystem
power: pwrseq: add a driver for the QCA6390 PMU module
Bluetooth: qca: use the power sequencer for QCA6390
PCI: create platform devices for child OF nodes of the port node
PCI: hold the rescan mutex when scanning for the first time PCI/pwrctl: add PCI power control core code
PCI/pwrctl: add a PCI power control driver for power sequenced devices

 arch/arm64/boot/dts/qcom/qrb5165-rb5.dts  | 128 +++++-
 arch/arm64/boot/dts/qcom/sm8250.dtsi      |  10 +
 drivers/bluetooth/hci_qca.c               |  30 ++
 drivers/pci/Kconfig                       |   1 +
 drivers/pci/Makefile                      |   1 +
 drivers/pci/bus.c                         |   9 +-
 drivers/pci/probe.c                       |   2 +
 drivers/pci/pwrctl/Kconfig                |  17 +
 drivers/pci/pwrctl/Makefile               |   4 +
 drivers/pci/pwrctl/core.c                 |  82 ++++
 drivers/pci/pwrctl/pci-pwrctl-pwrseq.c    |  83 ++++
 drivers/pci/remove.c                      |   2 +
 drivers/power/Kconfig                     |   1 +
 drivers/power/Makefile                    |   1 +
 drivers/power/sequencing/Kconfig          |  28 ++
 drivers/power/sequencing/Makefile         |   6 +
 drivers/power/sequencing/core.c           | 482 ++++++++++++++++++++++
 drivers/power/sequencing/pwrseq-qca6390.c | 232 +++++++++++
 include/linux/of.h                        |   4 +
 include/linux/pci-pwrctl.h                |  24 ++
 include/linux/pwrseq/consumer.h           |  53 +++
 include/linux/pwrseq/provider.h           |  41 ++
 22 files changed, 1229 insertions(+), 12 deletions(-)
 create mode 100644 drivers/pci/pwrctl/Kconfig
 create mode 100644 drivers/pci/pwrctl/Makefile
 create mode 100644 drivers/pci/pwrctl/core.c
 create mode 100644 drivers/pci/pwrctl/pci-pwrctl-pwrseq.c
 create mode 100644 drivers/power/sequencing/Kconfig
 create mode 100644 drivers/power/sequencing/Makefile
 create mode 100644 drivers/power/sequencing/core.c
 create mode 100644 drivers/power/sequencing/pwrseq-qca6390.c
 create mode 100644 include/linux/pci-pwrctl.h
 create mode 100644 include/linux/pwrseq/consumer.h
 create mode 100644 include/linux/pwrseq/provider.h
Signature · 1 line
2.40.1
#1 lore raw

RFC 1/9 of: provide a cleanup helper for OF nodes

From: Bartosz Golaszewski <[email protected]>

Allow to use __free() to automatically put references to OF nodes.

---
 include/linux/of.h | 4 ++++
 1 file changed, 4 insertions(+)
include/linux/of.h +4 -0
index 331e05918f11..5462ed47f25b 100644
@@ -11,6 +11,8 @@
  * Updates for SPARC64 by David S. Miller
  * Derived from PowerPC and Sparc prom.h files by Stephen Rothwell, IBM Corp.
  */
+
+#include <linux/cleanup.h>
 #include <linux/types.h>
 #include <linux/bitops.h>
 #include <linux/errno.h>
@@ -887,6 +889,8 @@ static inline const void *of_device_get_match_data(const struct device *dev)
 #define of_match_node(_matches, _node)	NULL
 #endif /* CONFIG_OF */
 
+DEFINE_FREE(of_node, struct device_node *, if (_T) of_node_put(_T))
+
 /* Default string compare functions, Allow arch asm/prom.h to override */
 #if !defined(of_compat_cmp)
 #define of_compat_cmp(s1, s2, l)	strcasecmp((s1), (s2))
Signature · 1 line
2.40.1
#2 lore raw

This is an automated email and please do not reply to this email.

Dear Submitter,

Thank you for submitting the patches to the linux bluetooth mailing list.
While preparing the CI tests, the patches you submitted couldn't be applied to the current HEAD of the repository.

----- Output -----

error: patch failed: arch/arm64/boot/dts/qcom/qrb5165-rb5.dts:1303
error: arch/arm64/boot/dts/qcom/qrb5165-rb5.dts: patch does not apply
hint: Use 'git am --show-current-patch' to see the failed patch

Please resolve the issue and submit the patches again.

---
Regards,
Linux Bluetooth

#4 lore raw

Re: [RFC 1/9] of: provide a cleanup helper for OF nodes

Quoted 5 lines · Rob Herring
Quoted 3 lines · Bartosz Golaszewski

From: Bartosz Golaszewski <[email protected]>

Quoted 7 lines
Quoted 1 line

Allow to use __free() to automatically put references to OF nodes.

Jonathan has already been working on this[1].

Rob

[1] https://lore.kernel.org/all/[email protected]/

Thanks, I will watch this but for now I'll have to stick to carrying it in my series until it gets upstream.

Bart

#5 lore raw
In reply to Bartosz Golaszewski

This is automated email and please do not reply to this email!

Dear submitter,

Thank you for submitting the patches to the linux bluetooth mailing list. This is a CI test results with your patch series:
PW Link:https://patchwork.kernel.org/project/bluetooth/list/?series=822186

---Test result---

Test Summary:

CheckPatch                    FAIL      11.15 seconds
GitLint                       PASS      3.00 seconds
SubjectPrefix                 FAIL      1.39 seconds
BuildKernel                   PASS      27.79 seconds
CheckAllWarning               PASS      30.75 seconds
CheckSparse                   PASS      37.46 seconds
CheckSmatch                   PASS      99.82 seconds
BuildKernel32                 PASS      27.11 seconds
TestRunnerSetup               PASS      499.56 seconds
TestRunner_l2cap-tester       PASS      17.17 seconds
TestRunner_iso-tester         PASS      28.35 seconds
TestRunner_bnep-tester        PASS      4.85 seconds
TestRunner_mgmt-tester        FAIL      106.30 seconds
TestRunner_rfcomm-tester      PASS      7.42 seconds
TestRunner_sco-tester         PASS      13.23 seconds
TestRunner_ioctl-tester       PASS      7.87 seconds
TestRunner_mesh-tester        PASS      5.92 seconds
TestRunner_smp-tester         PASS      6.90 seconds
TestRunner_userchan-tester    PASS      5.00 seconds
IncrementalBuild              PASS      60.54 seconds

Details
##############################
Test: CheckPatch - FAIL
Desc: Run checkpatch.pl script
Output:
[RFC,2/9] arm64: dts: qcom: qrb5165-rb5: model the PMU of the QCA6391
WARNING: DT compatible string "qcom,qca6390-pmu" appears un-documented -- check ./Documentation/devicetree/bindings/ #138: FILE: arch/arm64/boot/dts/qcom/qrb5165-rb5.dts:112:
+ compatible = "qcom,qca6390-pmu";

WARNING: DT compatible string "pci17cb,1101" appears un-documented -- check ./Documentation/devicetree/bindings/ #227: FILE: arch/arm64/boot/dts/qcom/qrb5165-rb5.dts:820:
+ compatible = "pci17cb,1101";

WARNING: DT compatible string vendor "pci17cb" appears un-documented -- check ./Documentation/devicetree/bindings/vendor-prefixes.yaml #227: FILE: arch/arm64/boot/dts/qcom/qrb5165-rb5.dts:820:
+ compatible = "pci17cb,1101";

total: 0 errors, 3 warnings, 168 lines checked

NOTE: For some of the reported defects, checkpatch may be able to
mechanically convert to the typical style using --fix or --fix-inplace.

/github/workspace/src/src/13541336.patch has style problems, please review.

NOTE: Ignored message types: UNKNOWN_COMMIT_ID

NOTE: If any of the errors are false positives, please report
them to the maintainer, see CHECKPATCH in MAINTAINERS.

[RFC,3/9] power: sequencing: new subsystem
WARNING: added, moved or deleted file(s), does MAINTAINERS need updating? #158:
new file mode 100644

WARNING: ENOSYS means 'invalid syscall nr' and nothing else #706: FILE: include/linux/pwrseq/consumer.h:28:
+ return ERR_PTR(-ENOSYS);

WARNING: ENOSYS means 'invalid syscall nr' and nothing else #716: FILE: include/linux/pwrseq/consumer.h:38:
+ return ERR_PTR(-ENOSYS);

WARNING: ENOSYS means 'invalid syscall nr' and nothing else #721: FILE: include/linux/pwrseq/consumer.h:43:
+ return -ENOSYS;

WARNING: ENOSYS means 'invalid syscall nr' and nothing else #726: FILE: include/linux/pwrseq/consumer.h:48:
+ return -ENOSYS;

total: 0 errors, 5 warnings, 600 lines checked

NOTE: For some of the reported defects, checkpatch may be able to
mechanically convert to the typical style using --fix or --fix-inplace.

/github/workspace/src/src/13541337.patch has style problems, please review.

NOTE: Ignored message types: UNKNOWN_COMMIT_ID

NOTE: If any of the errors are false positives, please report
them to the maintainer, see CHECKPATCH in MAINTAINERS.

[RFC,4/9] power: pwrseq: add a driver for the QCA6390 PMU module
WARNING: added, moved or deleted file(s), does MAINTAINERS need updating? #165:
new file mode 100644

WARNING: DT compatible string "qcom,qca6390-pmu" appears un-documented -- check ./Documentation/devicetree/bindings/ #383: FILE: drivers/power/sequencing/pwrseq-qca6390.c:214:
+ .compatible = "qcom,qca6390-pmu",

total: 0 errors, 2 warnings, 256 lines checked

NOTE: For some of the reported defects, checkpatch may be able to
mechanically convert to the typical style using --fix or --fix-inplace.

/github/workspace/src/src/13541338.patch has style problems, please review.

NOTE: Ignored message types: UNKNOWN_COMMIT_ID

NOTE: If any of the errors are false positives, please report
them to the maintainer, see CHECKPATCH in MAINTAINERS.

[RFC,8/9] PCI/pwrctl: add PCI power control core code
WARNING: added, moved or deleted file(s), does MAINTAINERS need updating? #170:
new file mode 100644

total: 0 errors, 1 warnings, 130 lines checked

NOTE: For some of the reported defects, checkpatch may be able to
mechanically convert to the typical style using --fix or --fix-inplace.

/github/workspace/src/src/13541342.patch has style problems, please review.

NOTE: Ignored message types: UNKNOWN_COMMIT_ID

NOTE: If any of the errors are false positives, please report
them to the maintainer, see CHECKPATCH in MAINTAINERS.

[RFC,9/9] PCI/pwrctl: add a PCI power control driver for power sequenced devices
WARNING: please write a help paragraph that fully describes the config symbol #139: FILE: drivers/pci/pwrctl/Kconfig:8:
+config PCI_PWRCTL_PWRSEQ
+ tristate "PCI Power Control driver using the Power Sequencing subsystem"
+ select POWER_SEQUENCING
+ select PCI_PWRCTL
+ default m if (ATH11K_PCI && ARCH_QCOM)
+ help
+ Enable support for the PCI power control driver for device
+ drivers using the Power Sequencing subsystem.
+

WARNING: added, moved or deleted file(s), does MAINTAINERS need updating? #159:
new file mode 100644

WARNING: DT compatible string "pci17cb,1101" appears un-documented -- check ./Documentation/devicetree/bindings/ #229: FILE: drivers/pci/pwrctl/pci-pwrctl-pwrseq.c:66:
+ .compatible = "pci17cb,1101",

WARNING: DT compatible string vendor "pci17cb" appears un-documented -- check ./Documentation/devicetree/bindings/vendor-prefixes.yaml #229: FILE: drivers/pci/pwrctl/pci-pwrctl-pwrseq.c:66:
+ .compatible = "pci17cb,1101",

total: 0 errors, 4 warnings, 100 lines checked

NOTE: For some of the reported defects, checkpatch may be able to
mechanically convert to the typical style using --fix or --fix-inplace.

/github/workspace/src/src/13541343.patch has style problems, please review.

NOTE: Ignored message types: UNKNOWN_COMMIT_ID

NOTE: If any of the errors are false positives, please report
them to the maintainer, see CHECKPATCH in MAINTAINERS.

##############################
Test: SubjectPrefix - FAIL
Desc: Check subject contains "Bluetooth" prefix Output:
"Bluetooth: " prefix is not specified in the subject "Bluetooth: " prefix is not specified in the subject "Bluetooth: " prefix is not specified in the subject "Bluetooth: " prefix is not specified in the subject "Bluetooth: " prefix is not specified in the subject "Bluetooth: " prefix is not specified in the subject "Bluetooth: " prefix is not specified in the subject "Bluetooth: " prefix is not specified in the subject
##############################
Test: TestRunner_mgmt-tester - FAIL
Desc: Run mgmt-tester with test-runner Output:
Total: 497, Passed: 486 (97.8%), Failed: 5, Not Run: 6

Failed Test Cases

Read Ext Controller Info 1                           Failed       0.083 seconds
Read Ext Controller Info 2                           Failed       0.089 seconds
Read Ext Controller Info 3                           Failed       0.092 seconds
Read Ext Controller Info 4                           Failed       0.085 seconds
Read Ext Controller Info 5                           Failed       0.104 seconds

---
Regards,
Linux Bluetooth

#6 lore raw

RFC 2/9 arm64: dts: qcom: qrb5165-rb5: model the PMU of the QCA6391

In reply to Bartosz Golaszewski

From: Bartosz Golaszewski <[email protected]>

Add a node for the PMU module of the QCA6391 present on the RB5 board. Assign its LDO power outputs to the existing Bluetooth module. Add a node for the PCIe port to sm8250.dtsi and define the WLAN node on it in the board's .dts and also make it consume the power outputs of the PMU.

---
 arch/arm64/boot/dts/qcom/qrb5165-rb5.dts | 128 +++++++++++++++++++++--
 arch/arm64/boot/dts/qcom/sm8250.dtsi     |  10 ++
 2 files changed, 127 insertions(+), 11 deletions(-)
arch/arm64/boot/dts/qcom/qrb5165-rb5.dts +117 -11
index cd0db4f31d4a..fab5bebafbad 100644
@@ -108,6 +108,87 @@ lt9611_3v3: lt9611-3v3 {
 		regulator-always-on;
 	};
 
+	qca6390_pmu: pmu@0 {
+		compatible = "qcom,qca6390-pmu";
+
+		pinctrl-names = "default";
+		pinctrl-0 = <&bt_en_state>, <&wlan_en_state>;
+
+		vddaon-supply = <&vreg_s6a_0p95>;
+		vddpmu-supply = <&vreg_s2f_0p95>;
+		vddrfa1-supply = <&vreg_s2f_0p95>;
+		vddrfa2-supply = <&vreg_s8c_1p3>;
+		vddrfa3-supply = <&vreg_s5a_1p9>;
+		vddpcie1-supply = <&vreg_s8c_1p3>;
+		vddpcie2-supply = <&vreg_s5a_1p9>;
+		vddio-supply = <&vreg_s4a_1p8>;
+
+		wlan-enable-gpios = <&tlmm 20 GPIO_ACTIVE_HIGH>;
+		bt-enable-gpios = <&tlmm 21 GPIO_ACTIVE_HIGH>;
+
+		regulators {
+			vreg_pmu_rfa_cmn: ldo0 {
+				regulator-name = "vreg_pmu_rfa_cmn";
+				regulator-min-microvolt = <760000>;
+				regulator-max-microvolt = <840000>;
+			};
+
+			vreg_pmu_aon_0p59: ldo1 {
+				regulator-name = "vreg_pmu_aon_0p59";
+				regulator-min-microvolt = <540000>;
+				regulator-max-microvolt = <840000>;
+			};
+
+			vreg_pmu_wlcx_0p8: ldo2 {
+				regulator_name = "vreg_pmu_wlcx_0p8";
+				regulator-min-microvolt = <760000>;
+				regulator-max-microvolt = <840000>;
+			};
+
+			vreg_pmu_wlmx_0p85: ldo3 {
+				regulator-name = "vreg_pmu_wlmx_0p85";
+				regulator-min-microvolt = <810000>;
+				regulator-max-microvolt = <890000>;
+			};
+
+			vreg_pmu_btcmx_0p85: ldo4 {
+				regulator-name = "vreg_pmu_btcmx_0p85";
+				regulator-min-microvolt = <810000>;
+				regulator-max-microvolt = <890000>;
+			};
+
+			vreg_pmu_rfa_0p8: ldo5 {
+				regulator-name = "vreg_pmu_rfa_0p8";
+				regulator-min-microvolt = <760000>;
+				regulator-max-microvolt = <840000>;
+			};
+
+			vreg_pmu_rfa_1p2: ldo6 {
+				regulator-name = "vreg_pmu_rfa_1p2";
+				regulator-min-microvolt = <1187000>;
+				regulator-max-microvolt = <1313000>;
+			};
+
+			vreg_pmu_rfa_1p7: ldo7 {
+				regulator_name = "vreg_pmu_rfa_1p7";
+				regulator-min-microvolt = <1710000>;
+				regulator-max-microvolt = <1890000>;
+			};
+
+			vreg_pmu_pcie_0p9: ldo8 {
+				regulator_name = "vreg_pmu_pcie_0p9";
+				regulator-min-microvolt = <870000>;
+				regulator-max-microvolt = <970000>;
+			};
+
+			vreg_pmu_pcie_1p8: ldo9 {
+				regulator_name = "vreg_pmu_pcie_1p8";
+				regulator-min-microvolt = <1710000>;
+				regulator-max-microvolt = <1890000>;
+			};
+		};
+	};
+
 	thermal-zones {
 		conn-thermal {
 			polling-delay-passive = <0>;
@@ -734,6 +815,24 @@ &pcie0_phy {
 	vdda-pll-supply = <&vreg_l9a_1p2>;
 };
 
+&pcieport0 {
+	wifi@0 {
+		compatible = "pci17cb,1101";
+		reg = <0x10000 0x0 0x0 0x0 0x0>;
+
+		vddrfacmn-supply = <&vreg_pmu_rfa_cmn>;
+		vddaon-supply = <&vreg_pmu_aon_0p59>;
+		vddwlcx-supply = <&vreg_pmu_wlcx_0p8>;
+		vddwlmx-supply = <&vreg_pmu_wlmx_0p85>;
+		vddbtcmx-supply = <&vreg_pmu_btcmx_0p85>;
+		vddrfa0-supply = <&vreg_pmu_rfa_0p8>;
+		vddrfa1-supply = <&vreg_pmu_rfa_1p2>;
+		vddrfa2-supply = <&vreg_pmu_rfa_1p7>;
+		vddpcie0-supply = <&vreg_pmu_pcie_0p9>;
+		vddpcie1-supply = <&vreg_pmu_pcie_1p8>;
+	};
+};
+
 &pcie1 {
 	status = "okay";
 };
@@ -1303,6 +1402,14 @@ sdc2_card_det_n: sd-card-det-n-state {
 		function = "gpio";
 		bias-pull-up;
 	};
+
+	wlan_en_state: wlan-default-state {
+		pins = "gpio20";
+		function = "gpio";
+		drive-strength = <16>;
+		output-low;
+		bias-pull-up;
+	};
 };
 
 &uart6 {
@@ -1311,17 +1418,16 @@ &uart6 {
 	bluetooth {
 		compatible = "qcom,qca6390-bt";
 
-		pinctrl-names = "default";
-		pinctrl-0 = <&bt_en_state>;
-
-		enable-gpios = <&tlmm 21 GPIO_ACTIVE_HIGH>;
-
-		vddio-supply = <&vreg_s4a_1p8>;
-		vddpmu-supply = <&vreg_s2f_0p95>;
-		vddaon-supply = <&vreg_s6a_0p95>;
-		vddrfa0p9-supply = <&vreg_s2f_0p95>;
-		vddrfa1p3-supply = <&vreg_s8c_1p3>;
-		vddrfa1p9-supply = <&vreg_s5a_1p9>;
+		vddrfacmn-supply = <&vreg_pmu_rfa_cmn>;
+		vddaon-supply = <&vreg_pmu_aon_0p59>;
+		vddwlcx-supply = <&vreg_pmu_wlcx_0p8>;
+		vddwlmx-supply = <&vreg_pmu_wlmx_0p85>;
+		vddbtcmx-supply = <&vreg_pmu_btcmx_0p85>;
+		vddrfa0-supply = <&vreg_pmu_rfa_0p8>;
+		vddrfa1-supply = <&vreg_pmu_rfa_1p2>;
+		vddrfa2-supply = <&vreg_pmu_rfa_1p7>;
+		vddpcie0-supply = <&vreg_pmu_pcie_0p9>;
+		vddpcie1-supply = <&vreg_pmu_pcie_1p8>;
 	};
 };
 
arch/arm64/boot/dts/qcom/sm8250.dtsi +10 -0
index 4d849e98bf9b..7cd21d4e7278 100644
@@ -2203,6 +2203,16 @@ pcie0: pcie@1c00000 {
 			dma-coherent;
 
 			status = "disabled";
+
+			pcieport0: pcie@0 {
+				device_type = "pci";
+				reg = <0x0 0x0 0x0 0x0 0x0>;
+				#address-cells = <3>;
+				#size-cells = <2>;
+				ranges;
+
+				bus-range = <0x01 0xff>;
+			};
 		};
 
 		pcie0_phy: phy@1c06000 {
Signature · 1 line
2.40.1
maintainer
#7 lore raw

Re: [RFC 2/9] arm64: dts: qcom: qrb5165-rb5: model the PMU of the QCA6391

Quoted 34 lines · Bartosz Golaszewski

From: Bartosz Golaszewski <[email protected]>

Add a node for the PMU module of the QCA6391 present on the RB5 board. Assign its LDO power outputs to the existing Bluetooth module. Add a node for the PCIe port to sm8250.dtsi and define the WLAN node on it in the board's .dts and also make it consume the power outputs of the PMU.

---
 arch/arm64/boot/dts/qcom/qrb5165-rb5.dts | 128 +++++++++++++++++++++--
 arch/arm64/boot/dts/qcom/sm8250.dtsi     |  10 ++
 2 files changed, 127 insertions(+), 11 deletions(-)
arch/arm64/boot/dts/qcom/qrb5165-rb5.dts +13 -0
index cd0db4f31d4a..fab5bebafbad 100644
@@ -108,6 +108,87 @@ lt9611_3v3: lt9611-3v3 {
 		regulator-always-on;
 	};
 
+	qca6390_pmu: pmu@0 {
+		compatible = "qcom,qca6390-pmu";
+
+		pinctrl-names = "default";
+		pinctrl-0 = <&bt_en_state>, <&wlan_en_state>;
+
+		vddaon-supply = <&vreg_s6a_0p95>;
+		vddpmu-supply = <&vreg_s2f_0p95>;
+		vddrfa1-supply = <&vreg_s2f_0p95>;
+		vddrfa2-supply = <&vreg_s8c_1p3>;
+		vddrfa3-supply = <&vreg_s5a_1p9>;
+		vddpcie1-supply = <&vreg_s8c_1p3>;
+		vddpcie2-supply = <&vreg_s5a_1p9>;

arch/arm64/boot/dts/qcom/qrb5165-rb5.dts lt9611_3v3: lt9611-3v3 { · line 133

Quoted 10 lines
arch/arm64/boot/dts/qcom/qrb5165-rb5.dts +10 -0
+		vddio-supply = <&vreg_s4a_1p8>;
+
+		wlan-enable-gpios = <&tlmm 20 GPIO_ACTIVE_HIGH>;
+		bt-enable-gpios = <&tlmm 21 GPIO_ACTIVE_HIGH>;
+
+		regulators {
+			vreg_pmu_rfa_cmn: ldo0 {
+				regulator-name = "vreg_pmu_rfa_cmn";
+				regulator-min-microvolt = <760000>;
+				regulator-max-microvolt = <840000>;

I'm still not convinced that the PMU has a set of LDOs, and looking at your implementation you neither register these with the regulator framework, nor provide any means of controlling the state or voltage of these "regulators".

[..]

Quoted 17 lines
arch/arm64/boot/dts/qcom/qrb5165-rb5.dts +0 -11
 &uart6 {
@@ -1311,17 +1418,16 @@ &uart6 {
 	bluetooth {
 		compatible = "qcom,qca6390-bt";
 
-		pinctrl-names = "default";
-		pinctrl-0 = <&bt_en_state>;
-
-		enable-gpios = <&tlmm 21 GPIO_ACTIVE_HIGH>;
-
-		vddio-supply = <&vreg_s4a_1p8>;
-		vddpmu-supply = <&vreg_s2f_0p95>;
-		vddaon-supply = <&vreg_s6a_0p95>;
-		vddrfa0p9-supply = <&vreg_s2f_0p95>;
-		vddrfa1p3-supply = <&vreg_s8c_1p3>;
-		vddrfa1p9-supply = <&vreg_s5a_1p9>;

arch/arm64/boot/dts/qcom/qrb5165-rb5.dts &uart6 { · line 1430

Quoted 10 lines
arch/arm64/boot/dts/qcom/qrb5165-rb5.dts +10 -0
+		vddrfacmn-supply = <&vreg_pmu_rfa_cmn>;
+		vddaon-supply = <&vreg_pmu_aon_0p59>;
+		vddwlcx-supply = <&vreg_pmu_wlcx_0p8>;
+		vddwlmx-supply = <&vreg_pmu_wlmx_0p85>;
+		vddbtcmx-supply = <&vreg_pmu_btcmx_0p85>;
+		vddrfa0-supply = <&vreg_pmu_rfa_0p8>;
+		vddrfa1-supply = <&vreg_pmu_rfa_1p2>;
+		vddrfa2-supply = <&vreg_pmu_rfa_1p7>;
+		vddpcie0-supply = <&vreg_pmu_pcie_0p9>;
+		vddpcie1-supply = <&vreg_pmu_pcie_1p8>;

As I asked before, why does bluetooth suddenly care about PCIe supplies?

Regards,
Bjorn

Quoted 27 lines
arch/arm64/boot/dts/qcom/qrb5165-rb5.dts +0 -0
 	};
 };
 
arch/arm64/boot/dts/qcom/sm8250.dtsi +10 -0
index 4d849e98bf9b..7cd21d4e7278 100644
@@ -2203,6 +2203,16 @@ pcie0: pcie@1c00000 {
 			dma-coherent;
 
 			status = "disabled";
+
+			pcieport0: pcie@0 {
+				device_type = "pci";
+				reg = <0x0 0x0 0x0 0x0 0x0>;
+				#address-cells = <3>;
+				#size-cells = <2>;
+				ranges;
+
+				bus-range = <0x01 0xff>;
+			};
 		};
 
 		pcie0_phy: phy@1c06000 {
Signature · 1 line
2.40.1
#8 lore raw

Re: [RFC 2/9] arm64: dts: qcom: qrb5165-rb5: model the PMU of the QCA6391

Quoted 43 lines · Bjorn Andersson
Quoted 41 lines · Bartosz Golaszewski

From: Bartosz Golaszewski <[email protected]>

Add a node for the PMU module of the QCA6391 present on the RB5 board. Assign its LDO power outputs to the existing Bluetooth module. Add a node for the PCIe port to sm8250.dtsi and define the WLAN node on it in the board's .dts and also make it consume the power outputs of the PMU.

---
 arch/arm64/boot/dts/qcom/qrb5165-rb5.dts | 128 +++++++++++++++++++++--
 arch/arm64/boot/dts/qcom/sm8250.dtsi     |  10 ++
 2 files changed, 127 insertions(+), 11 deletions(-)
arch/arm64/boot/dts/qcom/qrb5165-rb5.dts +20 -0
index cd0db4f31d4a..fab5bebafbad 100644
@@ -108,6 +108,87 @@ lt9611_3v3: lt9611-3v3 {
              regulator-always-on;
      };
 
+     qca6390_pmu: pmu@0 {
+             compatible = "qcom,qca6390-pmu";
+
+             pinctrl-names = "default";
+             pinctrl-0 = <&bt_en_state>, <&wlan_en_state>;
+
+             vddaon-supply = <&vreg_s6a_0p95>;
+             vddpmu-supply = <&vreg_s2f_0p95>;
+             vddrfa1-supply = <&vreg_s2f_0p95>;
+             vddrfa2-supply = <&vreg_s8c_1p3>;
+             vddrfa3-supply = <&vreg_s5a_1p9>;
+             vddpcie1-supply = <&vreg_s8c_1p3>;
+             vddpcie2-supply = <&vreg_s5a_1p9>;
+             vddio-supply = <&vreg_s4a_1p8>;
+
+             wlan-enable-gpios = <&tlmm 20 GPIO_ACTIVE_HIGH>;
+             bt-enable-gpios = <&tlmm 21 GPIO_ACTIVE_HIGH>;
+
+             regulators {
+                     vreg_pmu_rfa_cmn: ldo0 {
Quoted 8 lines

arch/arm64/boot/dts/qcom/qrb5165-rb5.dts lt9611_3v3: lt9611-3v3 { · line 133

Quoted 3 lines
arch/arm64/boot/dts/qcom/qrb5165-rb5.dts +3 -0
+                             regulator-name = "vreg_pmu_rfa_cmn";
+                             regulator-min-microvolt = <760000>;
+                             regulator-max-microvolt = <840000>;

I'm still not convinced that the PMU has a set of LDOs, and looking at your implementation you neither register these with the regulator framework, nor provide any means of controlling the state or voltage of these "regulators".

Please take a look at the description of VDD08_PMU_RFA_CMN and VDD_PMU_AON_I pins in the spec (80-WL522-1, page 25). I'm not sure if I'm allowed to quote it, so I won't. But the spec clearly describes VDD_PMU_AON_I as 0.95V LDO input and VDD08_PMU_RFA_CMN as 0.8 LDO output generated using that input. I think this proves that the on-chip PMU has actual LDOs.

I must admit, I find this representation very verbose, but on the other hand Bartosz is right, it represents actual hardware. Maybe we can drop some of the properties of corresponding regulator blocks, as we don't actually need them and they are internal properties of the hardware.

Quoted 23 lines

[..]

Quoted 21 lines

&uart6 {

arch/arm64/boot/dts/qcom/qrb5165-rb5.dts +4 -11
@@ -1311,17 +1418,16 @@ &uart6 {
      bluetooth {
              compatible = "qcom,qca6390-bt";
 
-             pinctrl-names = "default";
-             pinctrl-0 = <&bt_en_state>;
-
-             enable-gpios = <&tlmm 21 GPIO_ACTIVE_HIGH>;
-
-             vddio-supply = <&vreg_s4a_1p8>;
-             vddpmu-supply = <&vreg_s2f_0p95>;
-             vddaon-supply = <&vreg_s6a_0p95>;
-             vddrfa0p9-supply = <&vreg_s2f_0p95>;
-             vddrfa1p3-supply = <&vreg_s8c_1p3>;
-             vddrfa1p9-supply = <&vreg_s5a_1p9>;
+             vddrfacmn-supply = <&vreg_pmu_rfa_cmn>;
+             vddaon-supply = <&vreg_pmu_aon_0p59>;
+             vddwlcx-supply = <&vreg_pmu_wlcx_0p8>;
+             vddwlmx-supply = <&vreg_pmu_wlmx_0p85>;
Quoted 8 lines

arch/arm64/boot/dts/qcom/qrb5165-rb5.dts &pcie0_phy { · line 832

Quoted 6 lines
arch/arm64/boot/dts/qcom/qrb5165-rb5.dts +6 -0
+             vddbtcmx-supply = <&vreg_pmu_btcmx_0p85>;
+             vddrfa0-supply = <&vreg_pmu_rfa_0p8>;
+             vddrfa1-supply = <&vreg_pmu_rfa_1p2>;
+             vddrfa2-supply = <&vreg_pmu_rfa_1p7>;
+             vddpcie0-supply = <&vreg_pmu_pcie_0p9>;
+             vddpcie1-supply = <&vreg_pmu_pcie_1p8>;

As I asked before, why does bluetooth suddenly care about PCIe supplies?

Power sequencing in the same spec describes that PCIe voltages should be up even if only BT is being brought up. PMU itself handles distributing voltages according to the actual load needs.

Quoted 32 lines

Regards,
Bjorn

Quoted 27 lines
arch/arm64/boot/dts/qcom/qrb5165-rb5.dts +0 -0
      };
 };
 
arch/arm64/boot/dts/qcom/sm8250.dtsi +10 -1
index 4d849e98bf9b..7cd21d4e7278 100644
@@ -2203,6 +2203,16 @@ pcie0: pcie@1c00000 {
                      dma-coherent;
 
                      status = "disabled";
+
+                     pcieport0: pcie@0 {
+                             device_type = "pci";
+                             reg = <0x0 0x0 0x0 0x0 0x0>;
+                             #address-cells = <3>;
+                             #size-cells = <2>;
+                             ranges;
+
+                             bus-range = <0x01 0xff>;
+                     };
              };
 
              pcie0_phy: phy@1c06000 {
--

2.40.1

Signature · 2 lines
With best wishes
Dmitry
maintainer
#9 lore raw

Re: Re: [RFC 2/9] arm64: dts: qcom: qrb5165-rb5: model the PMU of the QCA6391

Quoted 53 lines · Dmitry Baryshkov
Quoted 43 lines · Bjorn Andersson
Quoted 41 lines · Bartosz Golaszewski

From: Bartosz Golaszewski <[email protected]>

Add a node for the PMU module of the QCA6391 present on the RB5 board. Assign its LDO power outputs to the existing Bluetooth module. Add a node for the PCIe port to sm8250.dtsi and define the WLAN node on it in the board's .dts and also make it consume the power outputs of the PMU.

---
 arch/arm64/boot/dts/qcom/qrb5165-rb5.dts | 128 +++++++++++++++++++++--
 arch/arm64/boot/dts/qcom/sm8250.dtsi     |  10 ++
 2 files changed, 127 insertions(+), 11 deletions(-)
arch/arm64/boot/dts/qcom/qrb5165-rb5.dts +20 -0
index cd0db4f31d4a..fab5bebafbad 100644
@@ -108,6 +108,87 @@ lt9611_3v3: lt9611-3v3 {
              regulator-always-on;
      };
 
+     qca6390_pmu: pmu@0 {
+             compatible = "qcom,qca6390-pmu";
+
+             pinctrl-names = "default";
+             pinctrl-0 = <&bt_en_state>, <&wlan_en_state>;
+
+             vddaon-supply = <&vreg_s6a_0p95>;
+             vddpmu-supply = <&vreg_s2f_0p95>;
+             vddrfa1-supply = <&vreg_s2f_0p95>;
+             vddrfa2-supply = <&vreg_s8c_1p3>;
+             vddrfa3-supply = <&vreg_s5a_1p9>;
+             vddpcie1-supply = <&vreg_s8c_1p3>;
+             vddpcie2-supply = <&vreg_s5a_1p9>;
+             vddio-supply = <&vreg_s4a_1p8>;
+
+             wlan-enable-gpios = <&tlmm 20 GPIO_ACTIVE_HIGH>;
+             bt-enable-gpios = <&tlmm 21 GPIO_ACTIVE_HIGH>;
+
+             regulators {
+                     vreg_pmu_rfa_cmn: ldo0 {
Quoted 8 lines

arch/arm64/boot/dts/qcom/qrb5165-rb5.dts lt9611_3v3: lt9611-3v3 { · line 133

Quoted 3 lines
arch/arm64/boot/dts/qcom/qrb5165-rb5.dts +3 -0
+                             regulator-name = "vreg_pmu_rfa_cmn";
+                             regulator-min-microvolt = <760000>;
+                             regulator-max-microvolt = <840000>;

I'm still not convinced that the PMU has a set of LDOs, and looking at your implementation you neither register these with the regulator framework, nor provide any means of controlling the state or voltage of these "regulators".

Quoted 7 lines

Please take a look at the description of VDD08_PMU_RFA_CMN and VDD_PMU_AON_I pins in the spec (80-WL522-1, page 25). I'm not sure if I'm allowed to quote it, so I won't. But the spec clearly describes VDD_PMU_AON_I as 0.95V LDO input and VDD08_PMU_RFA_CMN as 0.8 LDO output generated using that input. I think this proves that the on-chip PMU has actual LDOs.

You're correct, thank you for the pointer and clarification. I now agree with you, the PMU consumes what I saw as the chip input supplies, and based on WL_EN and BT_EN will provide power on pads, which are then externally routed to respective block.

Quoted 2 lines

I must admit, I find this representation very verbose, but on the other hand Bartosz is right, it represents actual hardware.

I agree, this is actual hardware.

Quoted 5 lines

Maybe we
can drop some of the properties of corresponding regulator blocks, as we don't actually need them and they are internal properties of the hardware.

To me this really looks like a fancy "regulator-fixed" with multiple inputs, two gpios and multiple outputs.

This would also imply that we don't need to invent the power sequence framework to tie WiFi and BT to the PMU's state.

The PMU is a thing, so we can represent that in DeviceTree, it consumes M input power rails, and two gpios, it provides N WiFi supplies and O BT supplies (with some overlap between N and O). The WiFi node consumes its N supplies, the BT node consumes its O supplies.

If any of the N regulators are requested enabled the qca6390-pmu driver enables all M input rails, then enables WL_EN. If any of the O BT regulators are requested enabled, the driver enables all M input rails, then enables BT_EN.

Quoted 32 lines
Quoted 23 lines

[..]

Quoted 21 lines

&uart6 {

arch/arm64/boot/dts/qcom/qrb5165-rb5.dts +4 -11
@@ -1311,17 +1418,16 @@ &uart6 {
      bluetooth {
              compatible = "qcom,qca6390-bt";
 
-             pinctrl-names = "default";
-             pinctrl-0 = <&bt_en_state>;
-
-             enable-gpios = <&tlmm 21 GPIO_ACTIVE_HIGH>;
-
-             vddio-supply = <&vreg_s4a_1p8>;
-             vddpmu-supply = <&vreg_s2f_0p95>;
-             vddaon-supply = <&vreg_s6a_0p95>;
-             vddrfa0p9-supply = <&vreg_s2f_0p95>;
-             vddrfa1p3-supply = <&vreg_s8c_1p3>;
-             vddrfa1p9-supply = <&vreg_s5a_1p9>;
+             vddrfacmn-supply = <&vreg_pmu_rfa_cmn>;
+             vddaon-supply = <&vreg_pmu_aon_0p59>;
+             vddwlcx-supply = <&vreg_pmu_wlcx_0p8>;
+             vddwlmx-supply = <&vreg_pmu_wlmx_0p85>;
Quoted 8 lines

arch/arm64/boot/dts/qcom/qrb5165-rb5.dts &pcie0_phy { · line 832

Quoted 6 lines
arch/arm64/boot/dts/qcom/qrb5165-rb5.dts +6 -0
+             vddbtcmx-supply = <&vreg_pmu_btcmx_0p85>;
+             vddrfa0-supply = <&vreg_pmu_rfa_0p8>;
+             vddrfa1-supply = <&vreg_pmu_rfa_1p2>;
+             vddrfa2-supply = <&vreg_pmu_rfa_1p7>;
+             vddpcie0-supply = <&vreg_pmu_pcie_0p9>;
+             vddpcie1-supply = <&vreg_pmu_pcie_1p8>;

As I asked before, why does bluetooth suddenly care about PCIe supplies?

Quoted 4 lines

Power sequencing in the same spec describes that PCIe voltages should be up even if only BT is being brought up. PMU itself handles distributing voltages according to the actual load needs.

You're right, the power sequence diagram in the docs do indicate that VDD13_PMU_PCIE_I and VDD19_PMU_PCIE_I should be enabled before either WL_EN or BT_EN are driven high.

But I don't see anything stating that the output from the PMU (VDD09_PMU_PCIE) in turn is fed to the bluetooth block.

Regards,
Bjorn

Quoted 37 lines
Quoted 32 lines

Regards,
Bjorn

Quoted 27 lines
arch/arm64/boot/dts/qcom/qrb5165-rb5.dts +0 -0
      };
 };
 
arch/arm64/boot/dts/qcom/sm8250.dtsi +10 -1
index 4d849e98bf9b..7cd21d4e7278 100644
@@ -2203,6 +2203,16 @@ pcie0: pcie@1c00000 {
                      dma-coherent;
 
                      status = "disabled";
+
+                     pcieport0: pcie@0 {
+                             device_type = "pci";
+                             reg = <0x0 0x0 0x0 0x0 0x0>;
+                             #address-cells = <3>;
+                             #size-cells = <2>;
+                             ranges;
+
+                             bus-range = <0x01 0xff>;
+                     };
              };
 
              pcie0_phy: phy@1c06000 {
--

2.40.1

Signature · 2 lines
With best wishes
Dmitry
#10 lore raw

Re: [RFC 2/9] arm64: dts: qcom: qrb5165-rb5: model the PMU of the QCA6391

In reply to Bjorn Andersson
Quoted 1 line · Bjorn Andersson

[snip]

Quoted 6 lines
Quoted 6 lines
arch/arm64/boot/dts/qcom/qrb5165-rb5.dts +6 -0
+
+             wlan-enable-gpios = <&tlmm 20 GPIO_ACTIVE_HIGH>;
+             bt-enable-gpios = <&tlmm 21 GPIO_ACTIVE_HIGH>;
+
+             regulators {
+                     vreg_pmu_rfa_cmn: ldo0 {
Quoted 9 lines

arch/arm64/boot/dts/qcom/qrb5165-rb5.dts lt9611_3v3: lt9611-3v3 { · line 133

Quoted 3 lines
arch/arm64/boot/dts/qcom/qrb5165-rb5.dts +3 -0
+                             regulator-name = "vreg_pmu_rfa_cmn";
+                             regulator-min-microvolt = <760000>;
+                             regulator-max-microvolt = <840000>;

I'm still not convinced that the PMU has a set of LDOs, and looking at your implementation you neither register these with the regulator framework, nor provide any means of controlling the state or voltage of these "regulators".

Why are you so fixated on the driver implementation matching the device-tree 1:1? I asked that question before - what does it matter if we use the regulator subsystem or not? This is just what HW there is. What we do with that knowledge in C is irrelevant. Yes, I don't use the regulator subsystem because it's unnecessary and would actually get in the way of the power sequencing. But it doesn't change the fact that the regulators *are* there so let's show them.

What isn't there is a "power sequencer device". This was the main concern about Dmitry's implementation before. We must not have "bt-pwrseq = <&...>;" -like properties in device-tree because there is no device that this would represent. But there *are* LDO outputs of the PMU which can be modelled and then used in C to retrieve the power sequencer and this is what I'm proposing.

Bartosz

Quoted 22 lines

[..]

Quoted 21 lines

&uart6 {

arch/arm64/boot/dts/qcom/qrb5165-rb5.dts +4 -11
@@ -1311,17 +1418,16 @@ &uart6 {
      bluetooth {
              compatible = "qcom,qca6390-bt";
 
-             pinctrl-names = "default";
-             pinctrl-0 = <&bt_en_state>;
-
-             enable-gpios = <&tlmm 21 GPIO_ACTIVE_HIGH>;
-
-             vddio-supply = <&vreg_s4a_1p8>;
-             vddpmu-supply = <&vreg_s2f_0p95>;
-             vddaon-supply = <&vreg_s6a_0p95>;
-             vddrfa0p9-supply = <&vreg_s2f_0p95>;
-             vddrfa1p3-supply = <&vreg_s8c_1p3>;
-             vddrfa1p9-supply = <&vreg_s5a_1p9>;
+             vddrfacmn-supply = <&vreg_pmu_rfa_cmn>;
+             vddaon-supply = <&vreg_pmu_aon_0p59>;
+             vddwlcx-supply = <&vreg_pmu_wlcx_0p8>;
+             vddwlmx-supply = <&vreg_pmu_wlmx_0p85>;
Quoted 9 lines

arch/arm64/boot/dts/qcom/qrb5165-rb5.dts &pcie0_phy { · line 832

Quoted 6 lines
arch/arm64/boot/dts/qcom/qrb5165-rb5.dts +6 -0
+             vddbtcmx-supply = <&vreg_pmu_btcmx_0p85>;
+             vddrfa0-supply = <&vreg_pmu_rfa_0p8>;
+             vddrfa1-supply = <&vreg_pmu_rfa_1p2>;
+             vddrfa2-supply = <&vreg_pmu_rfa_1p7>;
+             vddpcie0-supply = <&vreg_pmu_pcie_0p9>;
+             vddpcie1-supply = <&vreg_pmu_pcie_1p8>;

As I asked before, why does bluetooth suddenly care about PCIe supplies?

Yes, I forgot to remove it, I'll do it next time.

Bartosz

[snip]

maintainer
#11 lore raw

Re: Re: [RFC 2/9] arm64: dts: qcom: qrb5165-rb5: model the PMU of the QCA6391

Quoted 21 lines · Bartosz Golaszewski
Quoted 1 line · Bjorn Andersson

[snip]

Quoted 6 lines
Quoted 6 lines
arch/arm64/boot/dts/qcom/qrb5165-rb5.dts +6 -0
+
+             wlan-enable-gpios = <&tlmm 20 GPIO_ACTIVE_HIGH>;
+             bt-enable-gpios = <&tlmm 21 GPIO_ACTIVE_HIGH>;
+
+             regulators {
+                     vreg_pmu_rfa_cmn: ldo0 {
Quoted 9 lines

arch/arm64/boot/dts/qcom/qrb5165-rb5.dts lt9611_3v3: lt9611-3v3 { · line 133

Quoted 3 lines
arch/arm64/boot/dts/qcom/qrb5165-rb5.dts +3 -0
+                             regulator-name = "vreg_pmu_rfa_cmn";
+                             regulator-min-microvolt = <760000>;
+                             regulator-max-microvolt = <840000>;

I'm still not convinced that the PMU has a set of LDOs, and looking at your implementation you neither register these with the regulator framework, nor provide any means of controlling the state or voltage of these "regulators".

Quoted 3 lines

Why are you so fixated on the driver implementation matching the device-tree 1:1? I asked that question before - what does it matter if we use the regulator subsystem or not?

I'm sorry, I must have missed this question. I'm not questioning why the DT needs to match the Linux implementation, I was really questioning if the hardware you describe here existed.

Quoted 4 lines

This is just what HW there is.
What we do with that knowledge in C is irrelevant. Yes, I don't use the regulator subsystem because it's unnecessary and would actually get in the way of the power sequencing.

Then describe that in your commit messages.

Quoted 5 lines

But it doesn't change the fact
that the regulators *are* there so let's show them.

What isn't there is a "power sequencer device". This was the main concern about Dmitry's implementation before.

I don't agree. The concerns that I saw being raised with Dmitry's proposed design was that he used connected the WiFi controller to the QCA6391 using power-domains, etc.

Quoted 6 lines

We must not have
"bt-pwrseq = <&...>;" -like properties in device-tree because there is no device that this would represent. But there *are* LDO outputs of the PMU which can be modelled and then used in C to retrieve the power sequencer and this is what I'm proposing.

Performing device-specific power sequences is extremely common, but we so far don't have a separate abstraction of this because it's generally not an matter external to any given device.

If we're going to introduce a power sequence framework, it needs to be made very clear that it is there to solve the problem that you have devices on separate busses that need to share that sequence.

This also implies that for most examples out there where we have a need for doing "PCI power sequencing", I don't think we would use the power-sequence framework.

Regards,
Bjorn

Quoted 39 lines

Bartosz

Quoted 22 lines

[..]

Quoted 21 lines

&uart6 {

arch/arm64/boot/dts/qcom/qrb5165-rb5.dts +4 -11
@@ -1311,17 +1418,16 @@ &uart6 {
      bluetooth {
              compatible = "qcom,qca6390-bt";
 
-             pinctrl-names = "default";
-             pinctrl-0 = <&bt_en_state>;
-
-             enable-gpios = <&tlmm 21 GPIO_ACTIVE_HIGH>;
-
-             vddio-supply = <&vreg_s4a_1p8>;
-             vddpmu-supply = <&vreg_s2f_0p95>;
-             vddaon-supply = <&vreg_s6a_0p95>;
-             vddrfa0p9-supply = <&vreg_s2f_0p95>;
-             vddrfa1p3-supply = <&vreg_s8c_1p3>;
-             vddrfa1p9-supply = <&vreg_s5a_1p9>;
+             vddrfacmn-supply = <&vreg_pmu_rfa_cmn>;
+             vddaon-supply = <&vreg_pmu_aon_0p59>;
+             vddwlcx-supply = <&vreg_pmu_wlcx_0p8>;
+             vddwlmx-supply = <&vreg_pmu_wlmx_0p85>;
Quoted 9 lines

arch/arm64/boot/dts/qcom/qrb5165-rb5.dts &pcie0_phy { · line 832

Quoted 6 lines
arch/arm64/boot/dts/qcom/qrb5165-rb5.dts +6 -0
+             vddbtcmx-supply = <&vreg_pmu_btcmx_0p85>;
+             vddrfa0-supply = <&vreg_pmu_rfa_0p8>;
+             vddrfa1-supply = <&vreg_pmu_rfa_1p2>;
+             vddrfa2-supply = <&vreg_pmu_rfa_1p7>;
+             vddpcie0-supply = <&vreg_pmu_pcie_0p9>;
+             vddpcie1-supply = <&vreg_pmu_pcie_1p8>;

As I asked before, why does bluetooth suddenly care about PCIe supplies?

Yes, I forgot to remove it, I'll do it next time.

Bartosz

[snip]

maintainer
#12 lore raw

Re: [RFC 2/9] arm64: dts: qcom: qrb5165-rb5: model the PMU of the QCA6391

In reply to Bartosz Golaszewski
Quoted 18 lines · Bartosz Golaszewski

From: Bartosz Golaszewski <[email protected]>

Add a node for the PMU module of the QCA6391 present on the RB5 board. Assign its LDO power outputs to the existing Bluetooth module. Add a node for the PCIe port to sm8250.dtsi and define the WLAN node on it in the board's .dts and also make it consume the power outputs of the PMU.

---
 arch/arm64/boot/dts/qcom/qrb5165-rb5.dts | 128 +++++++++++++++++++++--
 arch/arm64/boot/dts/qcom/sm8250.dtsi     |  10 ++
 2 files changed, 127 insertions(+), 11 deletions(-)
arch/arm64/boot/dts/qcom/qrb5165-rb5.dts +0 -0
index cd0db4f31d4a..fab5bebafbad 100644

arch/arm64/boot/dts/qcom/qrb5165-rb5.dts lt9611_3v3: lt9611-3v3 { · line 111

Quoted 4 lines
arch/arm64/boot/dts/qcom/qrb5165-rb5.dts +1 -0
@@ -108,6 +108,87 @@ lt9611_3v3: lt9611-3v3 {
 		regulator-always-on;
 	};
 
+	qca6390_pmu: pmu@0 {

The node doesn't have an address, so why does it have a unit address? Also, the node isn't referenced, so please skip the label.

arch/arm64/boot/dts/qcom/qrb5165-rb5.dts lt9611_3v3: lt9611-3v3 { · line 124

Quoted 13 lines
arch/arm64/boot/dts/qcom/qrb5165-rb5.dts +13 -0
+		compatible = "qcom,qca6390-pmu";
+
+		pinctrl-names = "default";
+		pinctrl-0 = <&bt_en_state>, <&wlan_en_state>;
+
+		vddaon-supply = <&vreg_s6a_0p95>;
+		vddpmu-supply = <&vreg_s2f_0p95>;
+		vddrfa1-supply = <&vreg_s2f_0p95>;
+		vddrfa2-supply = <&vreg_s8c_1p3>;
+		vddrfa3-supply = <&vreg_s5a_1p9>;
+		vddpcie1-supply = <&vreg_s8c_1p3>;
+		vddpcie2-supply = <&vreg_s5a_1p9>;
+		vddio-supply = <&vreg_s4a_1p8>;

So, after studying the datasheet for this. The names of the pins seems to come from the existing binding(s). As you're introducing a new binding (and driver) for qcom,qca6390-pmu, please use the pad names from qca6390.

arch/arm64/boot/dts/qcom/qrb5165-rb5.dts lt9611_3v3: lt9611-3v3 { · line 133

Quoted 9 lines
arch/arm64/boot/dts/qcom/qrb5165-rb5.dts +9 -0
+
+		wlan-enable-gpios = <&tlmm 20 GPIO_ACTIVE_HIGH>;
+		bt-enable-gpios = <&tlmm 21 GPIO_ACTIVE_HIGH>;
+
+		regulators {
+			vreg_pmu_rfa_cmn: ldo0 {
+				regulator-name = "vreg_pmu_rfa_cmn";
+				regulator-min-microvolt = <760000>;
+				regulator-max-microvolt = <840000>;

The min/max operating range of the regulator is something we provide in the implementation, in DeviceTree you should specify the expected operating voltage. Based on the TYP value this should be regulator-min-microvolt = regulator-max-microvolt = 0.8V.

Quoted 7 lines
arch/arm64/boot/dts/qcom/qrb5165-rb5.dts +7 -0
+			};
+
+			vreg_pmu_aon_0p59: ldo1 {
+				regulator-name = "vreg_pmu_aon_0p59";
+				regulator-min-microvolt = <540000>;
+				regulator-max-microvolt = <840000>;
+			};

[..]

arch/arm64/boot/dts/qcom/qrb5165-rb5.dts sdc2_card_det_n: sd-card-det-n-state { · line 1410

Quoted 10 lines
arch/arm64/boot/dts/qcom/qrb5165-rb5.dts +6 -0
@@ -1303,6 +1402,14 @@ sdc2_card_det_n: sd-card-det-n-state {
 		function = "gpio";
 		bias-pull-up;
 	};
+
+	wlan_en_state: wlan-default-state {
+		pins = "gpio20";
+		function = "gpio";
+		drive-strength = <16>;
+		output-low;

Please omit output-low here.

arch/arm64/boot/dts/qcom/qrb5165-rb5.dts sdc2_card_det_n: sd-card-det-n-state { · line 1411

Quoted 1 line
arch/arm64/boot/dts/qcom/qrb5165-rb5.dts +1 -0
+		bias-pull-up;

Why do you drive it low and pull it high? bias-disable sounds more appropriate.

Regards,
Bjorn

Quoted 56 lines
arch/arm64/boot/dts/qcom/qrb5165-rb5.dts +11 -11
+	};
 };
 
 &uart6 {
@@ -1311,17 +1418,16 @@ &uart6 {
 	bluetooth {
 		compatible = "qcom,qca6390-bt";
 
-		pinctrl-names = "default";
-		pinctrl-0 = <&bt_en_state>;
-
-		enable-gpios = <&tlmm 21 GPIO_ACTIVE_HIGH>;
-
-		vddio-supply = <&vreg_s4a_1p8>;
-		vddpmu-supply = <&vreg_s2f_0p95>;
-		vddaon-supply = <&vreg_s6a_0p95>;
-		vddrfa0p9-supply = <&vreg_s2f_0p95>;
-		vddrfa1p3-supply = <&vreg_s8c_1p3>;
-		vddrfa1p9-supply = <&vreg_s5a_1p9>;
+		vddrfacmn-supply = <&vreg_pmu_rfa_cmn>;
+		vddaon-supply = <&vreg_pmu_aon_0p59>;
+		vddwlcx-supply = <&vreg_pmu_wlcx_0p8>;
+		vddwlmx-supply = <&vreg_pmu_wlmx_0p85>;
+		vddbtcmx-supply = <&vreg_pmu_btcmx_0p85>;
+		vddrfa0-supply = <&vreg_pmu_rfa_0p8>;
+		vddrfa1-supply = <&vreg_pmu_rfa_1p2>;
+		vddrfa2-supply = <&vreg_pmu_rfa_1p7>;
+		vddpcie0-supply = <&vreg_pmu_pcie_0p9>;
+		vddpcie1-supply = <&vreg_pmu_pcie_1p8>;
 	};
 };
 
arch/arm64/boot/dts/qcom/sm8250.dtsi +10 -0
index 4d849e98bf9b..7cd21d4e7278 100644
@@ -2203,6 +2203,16 @@ pcie0: pcie@1c00000 {
 			dma-coherent;
 
 			status = "disabled";
+
+			pcieport0: pcie@0 {
+				device_type = "pci";
+				reg = <0x0 0x0 0x0 0x0 0x0>;
+				#address-cells = <3>;
+				#size-cells = <2>;
+				ranges;
+
+				bus-range = <0x01 0xff>;
+			};
 		};
 
 		pcie0_phy: phy@1c06000 {
Signature · 1 line
2.40.1
#13 lore raw

Re: [RFC 2/9] arm64: dts: qcom: qrb5165-rb5: model the PMU of the QCA6391

In reply to Bartosz Golaszewski
Quoted 18 lines · Bartosz Golaszewski

From: Bartosz Golaszewski <[email protected]>

Add a node for the PMU module of the QCA6391 present on the RB5 board. Assign its LDO power outputs to the existing Bluetooth module. Add a node for the PCIe port to sm8250.dtsi and define the WLAN node on it in the board's .dts and also make it consume the power outputs of the PMU.

---
 arch/arm64/boot/dts/qcom/qrb5165-rb5.dts | 128 +++++++++++++++++++++--
 arch/arm64/boot/dts/qcom/sm8250.dtsi     |  10 ++
 2 files changed, 127 insertions(+), 11 deletions(-)
arch/arm64/boot/dts/qcom/qrb5165-rb5.dts +0 -0
index cd0db4f31d4a..fab5bebafbad 100644

arch/arm64/boot/dts/qcom/qrb5165-rb5.dts lt9611_3v3: lt9611-3v3 { · line 111

Quoted 4 lines
arch/arm64/boot/dts/qcom/qrb5165-rb5.dts +1 -0
@@ -108,6 +108,87 @@ lt9611_3v3: lt9611-3v3 {
 		regulator-always-on;
 	};
 
+	qca6390_pmu: pmu@0 {

It does not look like you tested the DTS against bindings. Please run make dtbs_check W=1 (see Documentation/devicetree/bindings/writing-schema.rst or
https://www.linaro.org/blog/tips-and-tricks-for-validating-devicetree-sources-with-the-devicetree-schema/
for instructions).

Best regards,
Krzysztof

#14 lore raw

RFC 3/9 power: sequencing: new subsystem

In reply to Bartosz Golaszewski

From: Bartosz Golaszewski <[email protected]>

Implement the power sequencing subsystem allowing devices to share complex powering-up and down procedures. It's split into the consumer and provider parts but does not implement any new DT bindings so that the actual power sequencing is never revealed in the DT representation.

---
 drivers/power/Kconfig             |   1 +
 drivers/power/Makefile            |   1 +
 drivers/power/sequencing/Kconfig  |  12 +
 drivers/power/sequencing/Makefile |   4 +
 drivers/power/sequencing/core.c   | 482 ++++++++++++++++++++++++++++++
 include/linux/pwrseq/consumer.h   |  53 ++++
 include/linux/pwrseq/provider.h   |  41 +++
 7 files changed, 594 insertions(+)
 create mode 100644 drivers/power/sequencing/Kconfig
 create mode 100644 drivers/power/sequencing/Makefile
 create mode 100644 drivers/power/sequencing/core.c
 create mode 100644 include/linux/pwrseq/consumer.h
 create mode 100644 include/linux/pwrseq/provider.h
drivers/power/Kconfig +1 -0
index 696bf77a7042..9a8e44ca9ae4 100644
@@ -1,3 +1,4 @@
 # SPDX-License-Identifier: GPL-2.0-only
 source "drivers/power/reset/Kconfig"
+source "drivers/power/sequencing/Kconfig"
 source "drivers/power/supply/Kconfig"
drivers/power/Makefile +1 -0
index effbf0377f32..962a2cd30a51 100644
@@ -1,3 +1,4 @@
 # SPDX-License-Identifier: GPL-2.0-only
 obj-$(CONFIG_POWER_RESET)	+= reset/
+obj-$(CONFIG_POWER_SEQUENCING)	+= sequencing/
 obj-$(CONFIG_POWER_SUPPLY)	+= supply/
drivers/power/sequencing/Kconfig new file +12 -0
new file mode 100644
index 000000000000..ba5732b1dbf8
@@ -0,0 +1,12 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
+menuconfig POWER_SEQUENCING
+	tristate "Power Sequencing support"
+	help
+	  Say Y here to enable the Power Sequencing subsystem.
+
+	  This subsystem is designed to control power to devices that share
+	  complex resources and/or require specific power sequences to be run
+	  during power-up.
+
+	  If unsure, say no.
drivers/power/sequencing/Makefile new file +4 -0
new file mode 100644
index 000000000000..dcdf8c0c159e
@@ -0,0 +1,4 @@
+# SPDX-License-Identifier: GPL-2.0
+
+obj-$(CONFIG_POWER_SEQUENCING)		+= pwrseq-core.o
+pwrseq-core-y				:= core.o
drivers/power/sequencing/core.c new file +482 -0

482 lines not on this page · raw message

include/linux/pwrseq/consumer.h new file +53 -0

53 lines not on this page · raw message

include/linux/pwrseq/provider.h new file +41 -0

41 lines not on this page · raw message

Signature · 1 line
2.40.1
maintainer
#15 lore raw

Re: [RFC 3/9] power: sequencing: new subsystem

Quoted 21 lines · Bartosz Golaszewski

From: Bartosz Golaszewski <[email protected]>

Implement the power sequencing subsystem allowing devices to share complex powering-up and down procedures. It's split into the consumer and provider parts but does not implement any new DT bindings so that the actual power sequencing is never revealed in the DT representation.

+++ b/drivers/power/sequencing/Kconfig

drivers/power/sequencing/Kconfig new file +1 -0
@@ -0,0 +1,12 @@
+# SPDX-License-Identifier: GPL-2.0-only
drivers/power/sequencing/Makefile new file +0 -0
new file mode 100644
index 000000000000..dcdf8c0c159e

drivers/power/sequencing/Makefile line 1

Quoted 1 line
drivers/power/sequencing/Makefile new file +1 -0
@@ -0,0 +1,4 @@
+# SPDX-License-Identifier: GPL-2.0

GPL-2.0-only to be consistent.

drivers/power/sequencing/core.c line 1

Quoted 10 lines
drivers/power/sequencing/Makefile new file +3 -0
+
+obj-$(CONFIG_POWER_SEQUENCING)         += pwrseq-core.o
+pwrseq-core-y                          := core.o
drivers/power/sequencing/core.c new file +1 -0
new file mode 100644
index 000000000000..f035caed0e4e
@@ -0,0 +1,482 @@
+// SPDX-License-Identifier: GPL-2.0-or-later

Why the deviation from the kernel's default license?

Rob

#16 lore raw

Re: [RFC 3/9] power: sequencing: new subsystem

In reply to Bartosz Golaszewski
kernel test robot noticed the following build errors:

Hi Bartosz,

[This is a private test report for your RFC patch.] kernel test robot noticed the following build errors:

[auto build test ERROR on pci/next]
[also build test ERROR on pci/for-linus robh/for-next bluetooth-next/master bluetooth/master linus/master v6.8-rc2 next-20240202] [If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]

url:    https://github.com/intel-lab-lkp/linux/commits/Bartosz-Golaszewski/of-provide-a-cleanup-helper-for-OF-nodes/20240202-000307
base:   https://git.kernel.org/pub/scm/linux/kernel/git/pci/pci.git next
patch link:    https://lore.kernel.org/r/20240201155532.49707-4-brgl%40bgdev.pl
patch subject: [RFC 3/9] power: sequencing: new subsystem
config: m68k-allmodconfig (https://download.01.org/0day-ci/archive/20240203/[email protected]/config)
compiler: m68k-linux-gcc (GCC) 13.2.0
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20240203/[email protected]/reproduce)

If you fix the issue in a separate patch/commit (i.e. not just a new version of the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <[email protected]>
| Closes: https://lore.kernel.org/oe-kbuild-all/[email protected]/

All error/warnings (new ones prefixed by >>):

drivers/power/sequencing/core.c: In function 'pwrseq_release':

>> drivers/power/sequencing/core.c:91:9: error: implicit declaration of function 'kfree'; did you mean 'kvfree'? [-Werror=implicit-function-declaration]
      91 |         kfree(pwrseq);
         |         ^~~~~
         |         kvfree
   drivers/power/sequencing/core.c: In function 'pwrseq_device_register':
>> drivers/power/sequencing/core.c:123:18: error: implicit declaration of function 'kzalloc' [-Werror=implicit-function-declaration]
     123 |         pwrseq = kzalloc(sizeof(*pwrseq), GFP_KERNEL);
         |                  ^~~~~~~
>> drivers/power/sequencing/core.c:123:16: warning: assignment to 'struct pwrseq_device *' from 'int' makes pointer from integer without a cast [-Wint-conversion]
     123 |         pwrseq = kzalloc(sizeof(*pwrseq), GFP_KERNEL);
         |                ^
   drivers/power/sequencing/core.c: In function 'pwrseq_get':
>> drivers/power/sequencing/core.c:280:16: error: cleanup argument not a function
     280 |         struct pwrseq_desc *desc __free(kfree) = kzalloc(sizeof(*desc),
         |                ^~~~~~~~~~~
>> drivers/power/sequencing/core.c:280:50: warning: initialization of 'struct pwrseq_desc *' from 'int' makes pointer from integer without a cast [-Wint-conversion]

280 | struct pwrseq_desc *desc __free(kfree) = kzalloc(sizeof(*desc),
| ^~~~~~~
cc1: some warnings being treated as errors

vim +91 drivers/power/sequencing/core.c

    84	
    85	static void pwrseq_release(struct device *dev)
    86	{
    87		struct pwrseq_device *pwrseq = to_pwrseq_device(dev);
    88	
    89		mutex_destroy(&pwrseq->state_lock);
    90		ida_free(&pwrseq_ida, pwrseq->id);
  > 91		kfree(pwrseq);
    92	}
    93	
    94	static const struct device_type pwrseq_device_type = {
    95		.name = "power_sequencer",
    96		.release = pwrseq_release,
    97	};
    98	
    99	/**
   100	 * pwrseq_device_register() - Register a new power sequencer.
   101	 * @config: Configuration of the new power sequencing device.
   102	 *
   103	 * The config structure is only used during the call and can be freed after
   104	 * the function returns. The config structure *must* have the parent device
   105	 * as well as the match(), power_on() and power_off() callbacks registered.
   106	 *
   107	 * Returns:
   108	 * Returns the address of the new pwrseq device or ERR_PTR() on failure.
   109	 */
   110	struct pwrseq_device *pwrseq_device_register(struct pwrseq_config *config)
   111	{
   112		struct pwrseq_device *pwrseq;
   113		int ret;
   114	
   115		/*
   116		 * Power sequencer must have a parent device and at least the power-on,
   117		 * power-off and match callbacks.
   118		 */
   119		if (!config->parent || !config->match || !config->power_on ||
   120		    !config->power_off)
   121			return ERR_PTR(-EINVAL);
   122	
 > 123		pwrseq = kzalloc(sizeof(*pwrseq), GFP_KERNEL);
   124		if (!pwrseq)
   125			return ERR_PTR(-ENOMEM);
   126	
   127		pwrseq->dev.type = &pwrseq_device_type;
   128		pwrseq->dev.bus = &pwrseq_bus;
   129		pwrseq->dev.parent = config->parent;
   130		device_set_node(&pwrseq->dev, dev_fwnode(config->parent));
   131	
   132		pwrseq->id = ida_alloc(&pwrseq_ida, GFP_KERNEL);
   133		if (pwrseq->id < 0) {
   134			kfree(pwrseq);
   135			return ERR_PTR(pwrseq->id);
   136		}
   137	
   138		/*
   139		 * From this point onwards the device's release() callback is
   140		 * responsible for freeing resources.
   141		 */
   142		device_initialize(&pwrseq->dev);
   143	
   144		ret = dev_set_name(&pwrseq->dev, "pwrseq.%d", pwrseq->id);
   145		if (ret)
   146			goto err_put_pwrseq;
   147	
   148		pwrseq->owner = config->owner ?: THIS_MODULE;
   149		pwrseq->drvdata = config->drvdata;
   150		pwrseq->match = config->match;
   151		pwrseq->power_on = config->power_on;
   152		pwrseq->power_off = config->power_off;
   153	
   154		init_rwsem(&pwrseq->dev_sem);
   155		mutex_init(&pwrseq->state_lock);
   156	
   157		scoped_guard(rwsem_write, &pwrseq_sem) {
   158			ret = device_add(&pwrseq->dev);
   159			if (ret)
   160				goto err_put_pwrseq;
   161		}
   162	
   163		return pwrseq;
   164	
   165	err_put_pwrseq:
   166		pwrseq_device_put(pwrseq);
   167		return ERR_PTR(ret);
   168	}
   169	EXPORT_SYMBOL_GPL(pwrseq_device_register);
   170	
   171	/**
   172	 * pwrseq_device_unregister() - Unregister the power sequencer.
   173	 * @pwrseq: Power sequencer to unregister.
   174	 */
   175	void pwrseq_device_unregister(struct pwrseq_device *pwrseq)
   176	{
   177		struct device *dev = &pwrseq->dev;
   178	
   179		scoped_guard(mutex, &pwrseq->state_lock) {
   180			WARN_ONCE(pwrseq->pwrup_count > 0,
   181				  "%s: UNREGISTERING POWER SEQUENCER WITH ACTIVE USERS\n",
   182				  dev_name(&pwrseq->dev));
   183	
   184			scoped_guard(rwsem_write, &pwrseq_sem) {
   185				scoped_guard(rwsem_write, &pwrseq->dev_sem)
   186					device_del(dev);
   187			}
   188		}
   189	
   190		pwrseq_device_put(pwrseq);
   191	}
   192	EXPORT_SYMBOL_GPL(pwrseq_device_unregister);
   193	
   194	static void devm_pwrseq_device_unregister(void *data)
   195	{
   196		struct pwrseq_device *pwrseq = data;
   197	
   198		pwrseq_device_unregister(pwrseq);
   199	}
   200	
   201	/**
   202	 * devm_pwrseq_device_register() - Managed variant of pwrseq_device_register().
   203	 * @dev: Managing device.
   204	 * @config: Configuration of the new power sequencing device.
   205	 *
   206	 * Returns:
   207	 * Returns the address of the new pwrseq device or ERR_PTR() on failure.
   208	 */
   209	struct pwrseq_device *
   210	devm_pwrseq_device_register(struct device *dev, struct pwrseq_config *config)
   211	{
   212		struct pwrseq_device *pwrseq;
   213		int ret;
   214	
   215		pwrseq = pwrseq_device_register(config);
   216		if (IS_ERR(pwrseq))
   217			return pwrseq;
   218	
   219		ret = devm_add_action_or_reset(dev, devm_pwrseq_device_unregister,
   220					       pwrseq);
   221		if (ret)
   222			return ERR_PTR(ret);
   223	
   224		return pwrseq;
   225	}
   226	EXPORT_SYMBOL_GPL(devm_pwrseq_device_register);
   227	
   228	/**
   229	 * pwrseq_device_get_data() - Get the driver private data associated with this
   230	 *                            sequencer.
   231	 * @pwrseq: Power sequencer object.
   232	 *
   233	 * Returns:
   234	 * Address of the private driver data.
   235	 */
   236	void *pwrseq_device_get_data(struct pwrseq_device *pwrseq)
   237	{
   238		return pwrseq->drvdata;
   239	}
   240	EXPORT_SYMBOL_GPL(pwrseq_device_get_data);
   241	
   242	struct pwrseq_match_data {
   243		struct pwrseq_device *matched;
   244		struct device *dev;
   245	};
   246	
   247	static int pwrseq_match_device(struct device *pwrseq_dev, void *data)
   248	{
   249		struct pwrseq_device *pwrseq = to_pwrseq_device(pwrseq_dev);
   250		struct pwrseq_match_data *match_data = data;
   251		int ret;
   252	
   253		guard(rwsem_read)(&pwrseq->dev_sem);
   254		if (!device_is_registered(&pwrseq->dev))
   255			return 0;
   256	
   257		ret = pwrseq->match(pwrseq, match_data->dev);
   258		if (ret <= 0)
   259			return ret;
   260	
   261		match_data->matched = pwrseq;
   262	
   263		return 1;
   264	}
   265	
   266	/**
   267	 * pwrseq_get() - Get the power sequencer associated with this device.
   268	 * @dev: Device for which to get the sequencer.
   269	 *
   270	 * Returns:
   271	 * New power sequencer descriptor for use by the consumer driver or ERR_PTR()
   272	 * on failure.
   273	 */
   274	struct pwrseq_desc *pwrseq_get(struct device *dev)
   275	{
   276		struct pwrseq_match_data match_data;
   277		struct pwrseq_device *pwrseq;
   278		int ret;
   279	
 > 280		struct pwrseq_desc *desc __free(kfree) = kzalloc(sizeof(*desc),

281 GFP_KERNEL);
282 if (!desc)
283 return ERR_PTR(-ENOMEM);
284
285 match_data.matched = NULL;
286 match_data.dev = dev;
287
288 guard(rwsem_read)(&pwrseq_sem);
289
290 ret = bus_for_each_dev(&pwrseq_bus, NULL, &match_data,
291 pwrseq_match_device);
292 if (ret < 0)
293 return ERR_PTR(ret);
294 if (ret == 0)
295 /* No device matched. */
296 return ERR_PTR(-EPROBE_DEFER);
297
298 pwrseq = match_data.matched;
299
300 if (!try_module_get(pwrseq->owner))
301 return ERR_PTR(-EPROBE_DEFER);
302
303 desc->pwrseq = pwrseq_device_get(pwrseq);
304
305 return no_free_ptr(desc);
306 }
307 EXPORT_SYMBOL_GPL(pwrseq_get);
308

Signature · 2 lines
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki
#17 lore raw

Re: [RFC 3/9] power: sequencing: new subsystem

In reply to Bartosz Golaszewski
kernel test robot noticed the following build warnings:

Hi Bartosz,

[This is a private test report for your RFC patch.] kernel test robot noticed the following build warnings:

[auto build test WARNING on pci/next]
[also build test WARNING on pci/for-linus robh/for-next bluetooth-next/master bluetooth/master linus/master v6.8-rc2 next-20240202] [If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]

url:    https://github.com/intel-lab-lkp/linux/commits/Bartosz-Golaszewski/of-provide-a-cleanup-helper-for-OF-nodes/20240202-000307
base:   https://git.kernel.org/pub/scm/linux/kernel/git/pci/pci.git next
patch link:    https://lore.kernel.org/r/20240201155532.49707-4-brgl%40bgdev.pl
patch subject: [RFC 3/9] power: sequencing: new subsystem
config: loongarch-allmodconfig (https://download.01.org/0day-ci/archive/20240204/[email protected]/config)
compiler: loongarch64-linux-gcc (GCC) 13.2.0
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20240204/[email protected]/reproduce)

If you fix the issue in a separate patch/commit (i.e. not just a new version of the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <[email protected]>
| Closes: https://lore.kernel.org/oe-kbuild-all/[email protected]/

All warnings (new ones prefixed by >>):

>> drivers/power/sequencing/core.c:50: warning: Function parameter or struct member 'dev_sem' not described in 'pwrseq_device'
>> drivers/power/sequencing/core.c:50: warning: Function parameter or struct member 'state_lock' not described in 'pwrseq_device'
>> drivers/power/sequencing/core.c:50: warning: Excess struct member 'sem' description in 'pwrseq_device'

vim +50 drivers/power/sequencing/core.c

    26	
    27	/**
    28	 * struct pwrseq_device - Private power sequencing data.
    29	 * @dev: Device struct associated with this sequencer.
    30	 * @id: Device ID.
    31	 * @owner: Prevents removal of active power sequencing providers.
    32	 * @pwrup_count: Keeps track of power state change requests.
    33	 * @sem: Protects the device against being unregistered while in use.
    34	 * @drvdata: Provider driver private data.
    35	 * @match: Power sequencer matching callback.
    36	 * @power_on: Power-on callback.
    37	 * @power_off: Power-off callback.
    38	 */
    39	struct pwrseq_device {
    40		struct device dev;
    41		int id;
    42		struct module *owner;
    43		unsigned int pwrup_count;
    44		struct rw_semaphore dev_sem;
    45		struct mutex state_lock;
    46		void *drvdata;
    47		pwrseq_match_func match;
    48		pwrseq_power_state_func power_on;
    49		pwrseq_power_state_func power_off;
  > 50	};
    51	
Signature · 2 lines
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki
#18 lore raw

Re: [RFC 3/9] power: sequencing: new subsystem

In reply to Bartosz Golaszewski
kernel test robot noticed the following build errors:

Hi Bartosz,

[This is a private test report for your RFC patch.] kernel test robot noticed the following build errors:

[auto build test ERROR on pci/next]
[also build test ERROR on pci/for-linus robh/for-next bluetooth-next/master bluetooth/master linus/master v6.8-rc2 next-20240202] [If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]

url:    https://github.com/intel-lab-lkp/linux/commits/Bartosz-Golaszewski/of-provide-a-cleanup-helper-for-OF-nodes/20240202-000307
base:   https://git.kernel.org/pub/scm/linux/kernel/git/pci/pci.git next
patch link:    https://lore.kernel.org/r/20240201155532.49707-4-brgl%40bgdev.pl
patch subject: [RFC 3/9] power: sequencing: new subsystem
config: powerpc-allyesconfig (https://download.01.org/0day-ci/archive/20240204/[email protected]/config)
compiler: clang version 19.0.0git (https://github.com/llvm/llvm-project 7dd790db8b77c4a833c06632e903dc4f13877a64)
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20240204/[email protected]/reproduce)

If you fix the issue in a separate patch/commit (i.e. not just a new version of the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <[email protected]>
| Closes: https://lore.kernel.org/oe-kbuild-all/[email protected]/

All errors (new ones prefixed by >>):

>> drivers/power/sequencing/core.c:91:2: error: call to undeclared function 'kfree'; ISO C99 and later do not support implicit function declarations [-Wimplicit-function-declaration]
      91 |         kfree(pwrseq);
         |         ^
>> drivers/power/sequencing/core.c:123:11: error: call to undeclared function 'kzalloc'; ISO C99 and later do not support implicit function declarations [-Wimplicit-function-declaration]
     123 |         pwrseq = kzalloc(sizeof(*pwrseq), GFP_KERNEL);
         |                  ^
>> drivers/power/sequencing/core.c:123:9: error: incompatible integer to pointer conversion assigning to 'struct pwrseq_device *' from 'int' [-Wint-conversion]
     123 |         pwrseq = kzalloc(sizeof(*pwrseq), GFP_KERNEL);
         |                ^ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   drivers/power/sequencing/core.c:134:3: error: call to undeclared function 'kfree'; ISO C99 and later do not support implicit function declarations [-Wimplicit-function-declaration]
     134 |                 kfree(pwrseq);
         |                 ^
>> drivers/power/sequencing/core.c:280:27: error: use of undeclared identifier '__free_kfree'; did you mean '__free_pages'?
     280 |         struct pwrseq_desc *desc __free(kfree) = kzalloc(sizeof(*desc),
         |                                  ^
   include/linux/cleanup.h:64:33: note: expanded from macro '__free'
      64 | #define __free(_name)   __cleanup(__free_##_name)
         |                                   ^
   <scratch space>:13:1: note: expanded from here
      13 | __free_kfree
         | ^
   include/linux/gfp.h:310:13: note: '__free_pages' declared here
     310 | extern void __free_pages(struct page *page, unsigned int order);
         |             ^
>> drivers/power/sequencing/core.c:280:27: error: 'cleanup' function '__free_pages' must take 1 parameter
     280 |         struct pwrseq_desc *desc __free(kfree) = kzalloc(sizeof(*desc),
         |                                  ^
   include/linux/cleanup.h:64:33: note: expanded from macro '__free'
      64 | #define __free(_name)   __cleanup(__free_##_name)
         |                                   ^
   <scratch space>:13:1: note: expanded from here
      13 | __free_kfree
         | ^
   drivers/power/sequencing/core.c:280:43: error: call to undeclared function 'kzalloc'; ISO C99 and later do not support implicit function declarations [-Wimplicit-function-declaration]
     280 |         struct pwrseq_desc *desc __free(kfree) = kzalloc(sizeof(*desc),
         |                                                  ^
>> drivers/power/sequencing/core.c:280:22: error: incompatible integer to pointer conversion initializing 'struct pwrseq_desc *' with an expression of type 'int' [-Wint-conversion]
     280 |         struct pwrseq_desc *desc __free(kfree) = kzalloc(sizeof(*desc),
         |                             ^                    ~~~~~~~~~~~~~~~~~~~~~~
     281 |                                                          GFP_KERNEL);
         |                                                          ~~~~~~~~~~~
   drivers/power/sequencing/core.c:325:2: error: call to undeclared function 'kfree'; ISO C99 and later do not support implicit function declarations [-Wimplicit-function-declaration]
     325 |         kfree(desc);
         |         ^

9 errors generated.

vim +/kfree +91 drivers/power/sequencing/core.c

    84	
    85	static void pwrseq_release(struct device *dev)
    86	{
    87		struct pwrseq_device *pwrseq = to_pwrseq_device(dev);
    88	
    89		mutex_destroy(&pwrseq->state_lock);
    90		ida_free(&pwrseq_ida, pwrseq->id);
  > 91		kfree(pwrseq);
    92	}
    93	
    94	static const struct device_type pwrseq_device_type = {
    95		.name = "power_sequencer",
    96		.release = pwrseq_release,
    97	};
    98	
    99	/**
   100	 * pwrseq_device_register() - Register a new power sequencer.
   101	 * @config: Configuration of the new power sequencing device.
   102	 *
   103	 * The config structure is only used during the call and can be freed after
   104	 * the function returns. The config structure *must* have the parent device
   105	 * as well as the match(), power_on() and power_off() callbacks registered.
   106	 *
   107	 * Returns:
   108	 * Returns the address of the new pwrseq device or ERR_PTR() on failure.
   109	 */
   110	struct pwrseq_device *pwrseq_device_register(struct pwrseq_config *config)
   111	{
   112		struct pwrseq_device *pwrseq;
   113		int ret;
   114	
   115		/*
   116		 * Power sequencer must have a parent device and at least the power-on,
   117		 * power-off and match callbacks.
   118		 */
   119		if (!config->parent || !config->match || !config->power_on ||
   120		    !config->power_off)
   121			return ERR_PTR(-EINVAL);
   122	
 > 123		pwrseq = kzalloc(sizeof(*pwrseq), GFP_KERNEL);
   124		if (!pwrseq)
   125			return ERR_PTR(-ENOMEM);
   126	
   127		pwrseq->dev.type = &pwrseq_device_type;
   128		pwrseq->dev.bus = &pwrseq_bus;
   129		pwrseq->dev.parent = config->parent;
   130		device_set_node(&pwrseq->dev, dev_fwnode(config->parent));
   131	
   132		pwrseq->id = ida_alloc(&pwrseq_ida, GFP_KERNEL);
   133		if (pwrseq->id < 0) {
   134			kfree(pwrseq);
   135			return ERR_PTR(pwrseq->id);
   136		}
   137	
   138		/*
   139		 * From this point onwards the device's release() callback is
   140		 * responsible for freeing resources.
   141		 */
   142		device_initialize(&pwrseq->dev);
   143	
   144		ret = dev_set_name(&pwrseq->dev, "pwrseq.%d", pwrseq->id);
   145		if (ret)
   146			goto err_put_pwrseq;
   147	
   148		pwrseq->owner = config->owner ?: THIS_MODULE;
   149		pwrseq->drvdata = config->drvdata;
   150		pwrseq->match = config->match;
   151		pwrseq->power_on = config->power_on;
   152		pwrseq->power_off = config->power_off;
   153	
   154		init_rwsem(&pwrseq->dev_sem);
   155		mutex_init(&pwrseq->state_lock);
   156	
   157		scoped_guard(rwsem_write, &pwrseq_sem) {
   158			ret = device_add(&pwrseq->dev);
   159			if (ret)
   160				goto err_put_pwrseq;
   161		}
   162	
   163		return pwrseq;
   164	
   165	err_put_pwrseq:
   166		pwrseq_device_put(pwrseq);
   167		return ERR_PTR(ret);
   168	}
   169	EXPORT_SYMBOL_GPL(pwrseq_device_register);
   170	
   171	/**
   172	 * pwrseq_device_unregister() - Unregister the power sequencer.
   173	 * @pwrseq: Power sequencer to unregister.
   174	 */
   175	void pwrseq_device_unregister(struct pwrseq_device *pwrseq)
   176	{
   177		struct device *dev = &pwrseq->dev;
   178	
   179		scoped_guard(mutex, &pwrseq->state_lock) {
   180			WARN_ONCE(pwrseq->pwrup_count > 0,
   181				  "%s: UNREGISTERING POWER SEQUENCER WITH ACTIVE USERS\n",
   182				  dev_name(&pwrseq->dev));
   183	
   184			scoped_guard(rwsem_write, &pwrseq_sem) {
   185				scoped_guard(rwsem_write, &pwrseq->dev_sem)
   186					device_del(dev);
   187			}
   188		}
   189	
   190		pwrseq_device_put(pwrseq);
   191	}
   192	EXPORT_SYMBOL_GPL(pwrseq_device_unregister);
   193	
   194	static void devm_pwrseq_device_unregister(void *data)
   195	{
   196		struct pwrseq_device *pwrseq = data;
   197	
   198		pwrseq_device_unregister(pwrseq);
   199	}
   200	
   201	/**
   202	 * devm_pwrseq_device_register() - Managed variant of pwrseq_device_register().
   203	 * @dev: Managing device.
   204	 * @config: Configuration of the new power sequencing device.
   205	 *
   206	 * Returns:
   207	 * Returns the address of the new pwrseq device or ERR_PTR() on failure.
   208	 */
   209	struct pwrseq_device *
   210	devm_pwrseq_device_register(struct device *dev, struct pwrseq_config *config)
   211	{
   212		struct pwrseq_device *pwrseq;
   213		int ret;
   214	
   215		pwrseq = pwrseq_device_register(config);
   216		if (IS_ERR(pwrseq))
   217			return pwrseq;
   218	
   219		ret = devm_add_action_or_reset(dev, devm_pwrseq_device_unregister,
   220					       pwrseq);
   221		if (ret)
   222			return ERR_PTR(ret);
   223	
   224		return pwrseq;
   225	}
   226	EXPORT_SYMBOL_GPL(devm_pwrseq_device_register);
   227	
   228	/**
   229	 * pwrseq_device_get_data() - Get the driver private data associated with this
   230	 *                            sequencer.
   231	 * @pwrseq: Power sequencer object.
   232	 *
   233	 * Returns:
   234	 * Address of the private driver data.
   235	 */
   236	void *pwrseq_device_get_data(struct pwrseq_device *pwrseq)
   237	{
   238		return pwrseq->drvdata;
   239	}
   240	EXPORT_SYMBOL_GPL(pwrseq_device_get_data);
   241	
   242	struct pwrseq_match_data {
   243		struct pwrseq_device *matched;
   244		struct device *dev;
   245	};
   246	
   247	static int pwrseq_match_device(struct device *pwrseq_dev, void *data)
   248	{
   249		struct pwrseq_device *pwrseq = to_pwrseq_device(pwrseq_dev);
   250		struct pwrseq_match_data *match_data = data;
   251		int ret;
   252	
   253		guard(rwsem_read)(&pwrseq->dev_sem);
   254		if (!device_is_registered(&pwrseq->dev))
   255			return 0;
   256	
   257		ret = pwrseq->match(pwrseq, match_data->dev);
   258		if (ret <= 0)
   259			return ret;
   260	
   261		match_data->matched = pwrseq;
   262	
   263		return 1;
   264	}
   265	
   266	/**
   267	 * pwrseq_get() - Get the power sequencer associated with this device.
   268	 * @dev: Device for which to get the sequencer.
   269	 *
   270	 * Returns:
   271	 * New power sequencer descriptor for use by the consumer driver or ERR_PTR()
   272	 * on failure.
   273	 */
   274	struct pwrseq_desc *pwrseq_get(struct device *dev)
   275	{
   276		struct pwrseq_match_data match_data;
   277		struct pwrseq_device *pwrseq;
   278		int ret;
   279	
 > 280		struct pwrseq_desc *desc __free(kfree) = kzalloc(sizeof(*desc),

281 GFP_KERNEL);
282 if (!desc)
283 return ERR_PTR(-ENOMEM);
284
285 match_data.matched = NULL;
286 match_data.dev = dev;
287
288 guard(rwsem_read)(&pwrseq_sem);
289
290 ret = bus_for_each_dev(&pwrseq_bus, NULL, &match_data,
291 pwrseq_match_device);
292 if (ret < 0)
293 return ERR_PTR(ret);
294 if (ret == 0)
295 /* No device matched. */
296 return ERR_PTR(-EPROBE_DEFER);
297
298 pwrseq = match_data.matched;
299
300 if (!try_module_get(pwrseq->owner))
301 return ERR_PTR(-EPROBE_DEFER);
302
303 desc->pwrseq = pwrseq_device_get(pwrseq);
304
305 return no_free_ptr(desc);
306 }
307 EXPORT_SYMBOL_GPL(pwrseq_get);
308

Signature · 2 lines
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki
#19 lore raw

RFC 4/9 power: pwrseq: add a driver for the QCA6390 PMU module

In reply to Bartosz Golaszewski

From: Bartosz Golaszewski <[email protected]>

This adds the power sequencing driver for the QCA6390's PMU module. It uses the pwrseq subsystem and knows how to match the sequencer to the consumer device by verifying the relevant properties and DT layout.

---
 drivers/power/sequencing/Kconfig          |  16 ++
 drivers/power/sequencing/Makefile         |   2 +
 drivers/power/sequencing/pwrseq-qca6390.c | 232 ++++++++++++++++++++++
 3 files changed, 250 insertions(+)
 create mode 100644 drivers/power/sequencing/pwrseq-qca6390.c
drivers/power/sequencing/Kconfig +16 -0
index ba5732b1dbf8..84ddf3b4ae56 100644
@@ -10,3 +10,19 @@ menuconfig POWER_SEQUENCING
 	  during power-up.
 
 	  If unsure, say no.
+
+if POWER_SEQUENCING
+
+config POWER_SEQUENCING_QCA6390
+	tristate "QCA6390 PMU driver"
+	default m if ARCH_QCOM
+	help
+	  Say U here to enable the power sequencing driver for Qualcomm
+	  QCA6390.
+
+	  The QCA6390 package contains the BT and WLAN modules whose power
+	  is controlled by the PMU module. As the former two share the power-up
+	  sequence which is executed by the PMU, this driver is needed for
+	  correct power control.
+
+endif
drivers/power/sequencing/Makefile +2 -0
index dcdf8c0c159e..628345c4e7ae 100644
@@ -2,3 +2,5 @@
 
 obj-$(CONFIG_POWER_SEQUENCING)		+= pwrseq-core.o
 pwrseq-core-y				:= core.o
+
+obj-$(CONFIG_POWER_SEQUENCING_QCA6390)	+= pwrseq-qca6390.o
drivers/power/sequencing/pwrseq-qca6390.c new file +232 -0

232 lines not on this page · raw message

Signature · 1 line
2.40.1
maintainer
#20 lore raw

Re: [RFC 4/9] power: pwrseq: add a driver for the QCA6390 PMU module

Quoted 1 line · Bartosz Golaszewski
drivers/power/sequencing/pwrseq-qca6390.c +0 -0

[..]

drivers/power/sequencing/pwrseq-qca6390.c line 89

Quoted 11 lines
drivers/power/sequencing/pwrseq-qca6390.c +11 -0
+static int pwrseq_qca6390_power_on(struct pwrseq_device *pwrseq)
+{
+	struct pwrseq_qca6390_ctx *ctx = pwrseq_device_get_data(pwrseq);
+	int ret;
+
+	ret = regulator_bulk_enable(ctx->pdata->num_vregs, ctx->regs);
+	if (ret)
+		return ret;
+
+	gpiod_set_value_cansleep(ctx->bt_gpio, 1);
+	gpiod_set_value_cansleep(ctx->wlan_gpio, 1);

So it's no longer possible to power these independently?

Quoted 4 lines
drivers/power/sequencing/pwrseq-qca6390.c +4 -0
+
+	if (ctx->pdata->pwup_delay_msec)
+		msleep(ctx->pdata->pwup_delay_msec);
+

drivers/power/sequencing/pwrseq-qca6390.c line 103

Quoted 10 lines
drivers/power/sequencing/pwrseq-qca6390.c +10 -0
+	return 0;
+}
+
+static int pwrseq_qca6390_power_off(struct pwrseq_device *pwrseq)
+{
+	struct pwrseq_qca6390_ctx *ctx = pwrseq_device_get_data(pwrseq);
+
+	gpiod_set_value_cansleep(ctx->bt_gpio, 0);
+	gpiod_set_value_cansleep(ctx->wlan_gpio, 0);
+

The answer that was provided recently was that the WiFi and BT modules absolutely must be modelled together, because there must be a 100ms delay between bt_gpio going low and wlan_gpio going high.

If you're not going to address that concern, then I fail to see the reason for adding the power sequence framework - just let the BT and PCI power control (WiFi) do their thing independently.

Quoted 21 lines
drivers/power/sequencing/pwrseq-qca6390.c +21 -0
+	return regulator_bulk_disable(ctx->pdata->num_vregs, ctx->regs);
+}
+
+static int pwrseq_qca6390_match(struct pwrseq_device *pwrseq,
+				struct device *dev)
+{
+	struct pwrseq_qca6390_ctx *ctx = pwrseq_device_get_data(pwrseq);
+	struct device_node *dev_node = dev->of_node;
+
+	/*
+	 * The PMU supplies power to the Bluetooth and WLAN modules. both
+	 * consume the PMU AON output so check the presence of the
+	 * 'vddaon-supply' property and whether it leads us to the right
+	 * device.
+	 */
+	if (!of_property_present(dev_node, "vddaon-supply"))
+		return 0;
+
+	struct device_node *reg_node __free(of_node) =
+			of_parse_phandle(dev_node, "vddaon-supply", 0);
+	if (!reg_node)

drivers/power/sequencing/pwrseq-qca6390.c line 134

Quoted 10 lines
drivers/power/sequencing/pwrseq-qca6390.c +10 -0
+		return 0;
+
+	/*
+	 * `reg_node` is the PMU AON regulator, its parent is the `regulators`
+	 * node and finally its grandparent is the PMU device node that we're
+	 * looking for.
+	 */
+	if (!reg_node->parent || !reg_node->parent->parent ||
+	    reg_node->parent->parent != ctx->of_node)
+		return 0;

Your DeviceTree example gives a sense that a set of supplies feeds the PMU, which then supplies power to the BT and WiFi nodes through some entity that can switch power on and off, and adjust the voltage level.

Then comes this function, which indicates that the DeviceTree model was just for show.

Quoted 40 lines
drivers/power/sequencing/pwrseq-qca6390.c +40 -0
+
+	return 1;
+}
+
+static int pwrseq_qca6390_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct pwrseq_qca6390_ctx *ctx;
+	struct pwrseq_config config;
+	int ret, i;
+
+	ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL);
+	if (!ctx)
+		return -ENOMEM;
+
+	ctx->of_node = dev->of_node;
+
+	ctx->pdata = of_device_get_match_data(dev);
+	if (!ctx->pdata)
+		return dev_err_probe(dev, -ENODEV,
+				     "Failed to obtain platform data\n");
+
+	if (ctx->pdata->vregs) {
+		ctx->regs = devm_kcalloc(dev, ctx->pdata->num_vregs,
+					 sizeof(*ctx->regs), GFP_KERNEL);
+		if (!ctx->regs)
+			return -ENOMEM;
+
+		for (i = 0; i < ctx->pdata->num_vregs; i++)
+			ctx->regs[i].supply = ctx->pdata->vregs[i].name;
+
+		ret = devm_regulator_bulk_get(dev, ctx->pdata->num_vregs,
+					      ctx->regs);
+		if (ret < 0)
+			return dev_err_probe(dev, ret,
+					     "Failed to get all regulators\n");
+
+		for (i = 0; i < ctx->pdata->num_vregs; i++) {
+			if (!ctx->pdata->vregs[1].load_uA)
+				continue;

drivers/power/sequencing/pwrseq-qca6390.c line 184

Quoted 10 lines
drivers/power/sequencing/pwrseq-qca6390.c +10 -0
+
+			ret = regulator_set_load(ctx->regs[i].consumer,
+						 ctx->pdata->vregs[i].load_uA);
+			if (ret)
+				return dev_err_probe(dev, ret,
+						     "Failed to set vreg load\n");
+		}
+	}
+
+	ctx->bt_gpio = devm_gpiod_get_optional(dev, "bt-enable", GPIOD_OUT_LOW);

Why are these optional? Does it make sense to have a qca6390 without both of these gpios connected?

Regards,
Bjorn

Quoted 51 lines
drivers/power/sequencing/pwrseq-qca6390.c +48 -0
+	if (IS_ERR(ctx->bt_gpio))
+		return dev_err_probe(dev, PTR_ERR(ctx->bt_gpio),
+				     "Failed to get the Bluetooth enable GPIO\n");
+
+	ctx->wlan_gpio = devm_gpiod_get_optional(dev, "wlan-enable",
+						 GPIOD_OUT_LOW);
+	if (IS_ERR(ctx->wlan_gpio))
+		return dev_err_probe(dev, PTR_ERR(ctx->wlan_gpio),
+				     "Failed to get the WLAN enable GPIO\n");
+
+	memset(&config, 0, sizeof(config));
+
+	config.parent = dev;
+	config.owner = THIS_MODULE;
+	config.drvdata = ctx;
+	config.match = pwrseq_qca6390_match;
+	config.power_on = pwrseq_qca6390_power_on;
+	config.power_off = pwrseq_qca6390_power_off;
+
+	ctx->pwrseq = devm_pwrseq_device_register(dev, &config);
+	if (IS_ERR(ctx->pwrseq))
+		return dev_err_probe(dev, PTR_ERR(ctx->pwrseq),
+				     "Failed to register the power sequencer\n");
+
+	return 0;
+}
+
+static const struct of_device_id pwrseq_qca6390_of_match[] = {
+	{
+		.compatible = "qcom,qca6390-pmu",
+		.data = &pwrseq_qca6390_of_data,
+	},
+	{ }
+};
+MODULE_DEVICE_TABLE(of, pwrseq_qca6390_of_match);
+
+static struct platform_driver pwrseq_qca6390_driver = {
+	.driver = {
+		.name = "pwrseq-qca6390",
+		.of_match_table = pwrseq_qca6390_of_match,
+	},
+	.probe = pwrseq_qca6390_probe,
+};
+module_platform_driver(pwrseq_qca6390_driver);
+
+MODULE_AUTHOR("Bartosz Golaszewski <[email protected]>");
+MODULE_DESCRIPTION("QCA6390 PMU power sequencing driver");
+MODULE_LICENSE("GPL");
Signature · 1 line
2.40.1
#21 lore raw

Re: [RFC 4/9] power: pwrseq: add a driver for the QCA6390 PMU module

Quoted 4 lines · Bjorn Andersson
Quoted 1 line · Bartosz Golaszewski
drivers/power/sequencing/pwrseq-qca6390.c +0 -0

[..]

Quoted 13 lines

drivers/power/sequencing/pwrseq-qca6390.c line 89

Quoted 11 lines
drivers/power/sequencing/pwrseq-qca6390.c +11 -0
+static int pwrseq_qca6390_power_on(struct pwrseq_device *pwrseq)
+{
+     struct pwrseq_qca6390_ctx *ctx = pwrseq_device_get_data(pwrseq);
+     int ret;
+
+     ret = regulator_bulk_enable(ctx->pdata->num_vregs, ctx->regs);
+     if (ret)
+             return ret;
+
+     gpiod_set_value_cansleep(ctx->bt_gpio, 1);
+     gpiod_set_value_cansleep(ctx->wlan_gpio, 1);

So it's no longer possible to power these independently?

I'd second this, there must be a way to power them on and off separately. In the end, this provides a good way to restart the BT core if it gets sick.

Quoted 11 lines
Quoted 11 lines
drivers/power/sequencing/pwrseq-qca6390.c +10 -0
+
+     if (ctx->pdata->pwup_delay_msec)
+             msleep(ctx->pdata->pwup_delay_msec);
+
+     return 0;
+}
+
+static int pwrseq_qca6390_power_off(struct pwrseq_device *pwrseq)
+{
+     struct pwrseq_qca6390_ctx *ctx = pwrseq_device_get_data(pwrseq);
Quoted 8 lines

drivers/power/sequencing/pwrseq-qca6390.c line 103

Quoted 4 lines
drivers/power/sequencing/pwrseq-qca6390.c +4 -0
+
+     gpiod_set_value_cansleep(ctx->bt_gpio, 0);
+     gpiod_set_value_cansleep(ctx->wlan_gpio, 0);
+

The answer that was provided recently was that the WiFi and BT modules absolutely must be modelled together, because there must be a 100ms delay between bt_gpio going low and wlan_gpio going high.

For the reference, it was for the QCA6490 (not QCA6390, next revision), which maps to WCN6855.

Quoted 144 lines

If you're not going to address that concern, then I fail to see the reason for adding the power sequence framework - just let the BT and PCI power control (WiFi) do their thing independently.

Quoted 21 lines
drivers/power/sequencing/pwrseq-qca6390.c +21 -0
+     return regulator_bulk_disable(ctx->pdata->num_vregs, ctx->regs);
+}
+
+static int pwrseq_qca6390_match(struct pwrseq_device *pwrseq,
+                             struct device *dev)
+{
+     struct pwrseq_qca6390_ctx *ctx = pwrseq_device_get_data(pwrseq);
+     struct device_node *dev_node = dev->of_node;
+
+     /*
+      * The PMU supplies power to the Bluetooth and WLAN modules. both
+      * consume the PMU AON output so check the presence of the
+      * 'vddaon-supply' property and whether it leads us to the right
+      * device.
+      */
+     if (!of_property_present(dev_node, "vddaon-supply"))
+             return 0;
+
+     struct device_node *reg_node __free(of_node) =
+                     of_parse_phandle(dev_node, "vddaon-supply", 0);
+     if (!reg_node)

drivers/power/sequencing/pwrseq-qca6390.c line 134

Quoted 10 lines
drivers/power/sequencing/pwrseq-qca6390.c +10 -0
+             return 0;
+
+     /*
+      * `reg_node` is the PMU AON regulator, its parent is the `regulators`
+      * node and finally its grandparent is the PMU device node that we're
+      * looking for.
+      */
+     if (!reg_node->parent || !reg_node->parent->parent ||
+         reg_node->parent->parent != ctx->of_node)
+             return 0;

Your DeviceTree example gives a sense that a set of supplies feeds the PMU, which then supplies power to the BT and WiFi nodes through some entity that can switch power on and off, and adjust the voltage level.

Then comes this function, which indicates that the DeviceTree model was just for show.

Quoted 40 lines
drivers/power/sequencing/pwrseq-qca6390.c +40 -0
+
+     return 1;
+}
+
+static int pwrseq_qca6390_probe(struct platform_device *pdev)
+{
+     struct device *dev = &pdev->dev;
+     struct pwrseq_qca6390_ctx *ctx;
+     struct pwrseq_config config;
+     int ret, i;
+
+     ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL);
+     if (!ctx)
+             return -ENOMEM;
+
+     ctx->of_node = dev->of_node;
+
+     ctx->pdata = of_device_get_match_data(dev);
+     if (!ctx->pdata)
+             return dev_err_probe(dev, -ENODEV,
+                                  "Failed to obtain platform data\n");
+
+     if (ctx->pdata->vregs) {
+             ctx->regs = devm_kcalloc(dev, ctx->pdata->num_vregs,
+                                      sizeof(*ctx->regs), GFP_KERNEL);
+             if (!ctx->regs)
+                     return -ENOMEM;
+
+             for (i = 0; i < ctx->pdata->num_vregs; i++)
+                     ctx->regs[i].supply = ctx->pdata->vregs[i].name;
+
+             ret = devm_regulator_bulk_get(dev, ctx->pdata->num_vregs,
+                                           ctx->regs);
+             if (ret < 0)
+                     return dev_err_probe(dev, ret,
+                                          "Failed to get all regulators\n");
+
+             for (i = 0; i < ctx->pdata->num_vregs; i++) {
+                     if (!ctx->pdata->vregs[1].load_uA)
+                             continue;

drivers/power/sequencing/pwrseq-qca6390.c line 184

Quoted 10 lines
drivers/power/sequencing/pwrseq-qca6390.c +10 -0
+
+                     ret = regulator_set_load(ctx->regs[i].consumer,
+                                              ctx->pdata->vregs[i].load_uA);
+                     if (ret)
+                             return dev_err_probe(dev, ret,
+                                                  "Failed to set vreg load\n");
+             }
+     }
+
+     ctx->bt_gpio = devm_gpiod_get_optional(dev, "bt-enable", GPIOD_OUT_LOW);

Why are these optional? Does it make sense to have a qca6390 without both of these gpios connected?

Regards,
Bjorn

Quoted 43 lines
drivers/power/sequencing/pwrseq-qca6390.c +43 -0
+     if (IS_ERR(ctx->bt_gpio))
+             return dev_err_probe(dev, PTR_ERR(ctx->bt_gpio),
+                                  "Failed to get the Bluetooth enable GPIO\n");
+
+     ctx->wlan_gpio = devm_gpiod_get_optional(dev, "wlan-enable",
+                                              GPIOD_OUT_LOW);
+     if (IS_ERR(ctx->wlan_gpio))
+             return dev_err_probe(dev, PTR_ERR(ctx->wlan_gpio),
+                                  "Failed to get the WLAN enable GPIO\n");
+
+     memset(&config, 0, sizeof(config));
+
+     config.parent = dev;
+     config.owner = THIS_MODULE;
+     config.drvdata = ctx;
+     config.match = pwrseq_qca6390_match;
+     config.power_on = pwrseq_qca6390_power_on;
+     config.power_off = pwrseq_qca6390_power_off;
+
+     ctx->pwrseq = devm_pwrseq_device_register(dev, &config);
+     if (IS_ERR(ctx->pwrseq))
+             return dev_err_probe(dev, PTR_ERR(ctx->pwrseq),
+                                  "Failed to register the power sequencer\n");
+
+     return 0;
+}
+
+static const struct of_device_id pwrseq_qca6390_of_match[] = {
+     {
+             .compatible = "qcom,qca6390-pmu",
+             .data = &pwrseq_qca6390_of_data,
+     },
+     { }
+};
+MODULE_DEVICE_TABLE(of, pwrseq_qca6390_of_match);
+
+static struct platform_driver pwrseq_qca6390_driver = {
+     .driver = {
+             .name = "pwrseq-qca6390",
+             .of_match_table = pwrseq_qca6390_of_match,
+     },
+     .probe = pwrseq_qca6390_probe,
+};
Quoted 9 lines
Quoted 8 lines
drivers/power/sequencing/pwrseq-qca6390.c +5 -1
+module_platform_driver(pwrseq_qca6390_driver);
+
+MODULE_AUTHOR("Bartosz Golaszewski <[email protected]>");
+MODULE_DESCRIPTION("QCA6390 PMU power sequencing driver");
+MODULE_LICENSE("GPL");
--

2.40.1

--
With best wishes
Dmitry

#22 lore raw

Re: [RFC 4/9] power: pwrseq: add a driver for the QCA6390 PMU module

Quoted 20 lines · Dmitry Baryshkov
Quoted 4 lines · Bjorn Andersson
Quoted 1 line · Bartosz Golaszewski
drivers/power/sequencing/pwrseq-qca6390.c +0 -0

[..]

Quoted 13 lines

drivers/power/sequencing/pwrseq-qca6390.c line 89

Quoted 11 lines
drivers/power/sequencing/pwrseq-qca6390.c +11 -0
+static int pwrseq_qca6390_power_on(struct pwrseq_device *pwrseq)
+{
+     struct pwrseq_qca6390_ctx *ctx = pwrseq_device_get_data(pwrseq);
+     int ret;
+
+     ret = regulator_bulk_enable(ctx->pdata->num_vregs, ctx->regs);
+     if (ret)
+             return ret;
+
+     gpiod_set_value_cansleep(ctx->bt_gpio, 1);
+     gpiod_set_value_cansleep(ctx->wlan_gpio, 1);

So it's no longer possible to power these independently?

Quoted 4 lines

I'd second this, there must be a way to power them on and off separately. In the end, this provides a good way to restart the BT core if it gets sick.

Makes sense, I'll think about it. I'm thinking about adding a flags argument for this kind of switching.

Quoted 20 lines
Quoted 11 lines
Quoted 11 lines
drivers/power/sequencing/pwrseq-qca6390.c +10 -0
+
+     if (ctx->pdata->pwup_delay_msec)
+             msleep(ctx->pdata->pwup_delay_msec);
+
+     return 0;
+}
+
+static int pwrseq_qca6390_power_off(struct pwrseq_device *pwrseq)
+{
+     struct pwrseq_qca6390_ctx *ctx = pwrseq_device_get_data(pwrseq);
Quoted 8 lines

drivers/power/sequencing/pwrseq-qca6390.c line 103

Quoted 4 lines
drivers/power/sequencing/pwrseq-qca6390.c +4 -0
+
+     gpiod_set_value_cansleep(ctx->bt_gpio, 0);
+     gpiod_set_value_cansleep(ctx->wlan_gpio, 0);
+

The answer that was provided recently was that the WiFi and BT modules absolutely must be modelled together, because there must be a 100ms delay between bt_gpio going low and wlan_gpio going high.

Quoted 3 lines

For the reference, it was for the QCA6490 (not QCA6390, next revision), which maps to WCN6855.

The docs for QCA6390 also mention the 100ms delay but it doesn't seem to be necessary. But yes, this was done after Dmitry raised concerns about the QCA6490.

Bart

Quoted 159 lines
Quoted 145 lines

If you're not going to address that concern, then I fail to see the reason for adding the power sequence framework - just let the BT and PCI power control (WiFi) do their thing independently.

Quoted 21 lines
drivers/power/sequencing/pwrseq-qca6390.c +21 -0
+     return regulator_bulk_disable(ctx->pdata->num_vregs, ctx->regs);
+}
+
+static int pwrseq_qca6390_match(struct pwrseq_device *pwrseq,
+                             struct device *dev)
+{
+     struct pwrseq_qca6390_ctx *ctx = pwrseq_device_get_data(pwrseq);
+     struct device_node *dev_node = dev->of_node;
+
+     /*
+      * The PMU supplies power to the Bluetooth and WLAN modules. both
+      * consume the PMU AON output so check the presence of the
+      * 'vddaon-supply' property and whether it leads us to the right
+      * device.
+      */
+     if (!of_property_present(dev_node, "vddaon-supply"))
+             return 0;
+
+     struct device_node *reg_node __free(of_node) =
+                     of_parse_phandle(dev_node, "vddaon-supply", 0);
+     if (!reg_node)

drivers/power/sequencing/pwrseq-qca6390.c line 134

Quoted 10 lines
drivers/power/sequencing/pwrseq-qca6390.c +10 -0
+             return 0;
+
+     /*
+      * `reg_node` is the PMU AON regulator, its parent is the `regulators`
+      * node and finally its grandparent is the PMU device node that we're
+      * looking for.
+      */
+     if (!reg_node->parent || !reg_node->parent->parent ||
+         reg_node->parent->parent != ctx->of_node)
+             return 0;

Your DeviceTree example gives a sense that a set of supplies feeds the PMU, which then supplies power to the BT and WiFi nodes through some entity that can switch power on and off, and adjust the voltage level.

Then comes this function, which indicates that the DeviceTree model was just for show.

Quoted 40 lines
drivers/power/sequencing/pwrseq-qca6390.c +40 -0
+
+     return 1;
+}
+
+static int pwrseq_qca6390_probe(struct platform_device *pdev)
+{
+     struct device *dev = &pdev->dev;
+     struct pwrseq_qca6390_ctx *ctx;
+     struct pwrseq_config config;
+     int ret, i;
+
+     ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL);
+     if (!ctx)
+             return -ENOMEM;
+
+     ctx->of_node = dev->of_node;
+
+     ctx->pdata = of_device_get_match_data(dev);
+     if (!ctx->pdata)
+             return dev_err_probe(dev, -ENODEV,
+                                  "Failed to obtain platform data\n");
+
+     if (ctx->pdata->vregs) {
+             ctx->regs = devm_kcalloc(dev, ctx->pdata->num_vregs,
+                                      sizeof(*ctx->regs), GFP_KERNEL);
+             if (!ctx->regs)
+                     return -ENOMEM;
+
+             for (i = 0; i < ctx->pdata->num_vregs; i++)
+                     ctx->regs[i].supply = ctx->pdata->vregs[i].name;
+
+             ret = devm_regulator_bulk_get(dev, ctx->pdata->num_vregs,
+                                           ctx->regs);
+             if (ret < 0)
+                     return dev_err_probe(dev, ret,
+                                          "Failed to get all regulators\n");
+
+             for (i = 0; i < ctx->pdata->num_vregs; i++) {
+                     if (!ctx->pdata->vregs[1].load_uA)
+                             continue;

drivers/power/sequencing/pwrseq-qca6390.c line 184

Quoted 10 lines
drivers/power/sequencing/pwrseq-qca6390.c +10 -0
+
+                     ret = regulator_set_load(ctx->regs[i].consumer,
+                                              ctx->pdata->vregs[i].load_uA);
+                     if (ret)
+                             return dev_err_probe(dev, ret,
+                                                  "Failed to set vreg load\n");
+             }
+     }
+
+     ctx->bt_gpio = devm_gpiod_get_optional(dev, "bt-enable", GPIOD_OUT_LOW);

Why are these optional? Does it make sense to have a qca6390 without both of these gpios connected?

Regards,
Bjorn

Quoted 43 lines
drivers/power/sequencing/pwrseq-qca6390.c +43 -0
+     if (IS_ERR(ctx->bt_gpio))
+             return dev_err_probe(dev, PTR_ERR(ctx->bt_gpio),
+                                  "Failed to get the Bluetooth enable GPIO\n");
+
+     ctx->wlan_gpio = devm_gpiod_get_optional(dev, "wlan-enable",
+                                              GPIOD_OUT_LOW);
+     if (IS_ERR(ctx->wlan_gpio))
+             return dev_err_probe(dev, PTR_ERR(ctx->wlan_gpio),
+                                  "Failed to get the WLAN enable GPIO\n");
+
+     memset(&config, 0, sizeof(config));
+
+     config.parent = dev;
+     config.owner = THIS_MODULE;
+     config.drvdata = ctx;
+     config.match = pwrseq_qca6390_match;
+     config.power_on = pwrseq_qca6390_power_on;
+     config.power_off = pwrseq_qca6390_power_off;
+
+     ctx->pwrseq = devm_pwrseq_device_register(dev, &config);
+     if (IS_ERR(ctx->pwrseq))
+             return dev_err_probe(dev, PTR_ERR(ctx->pwrseq),
+                                  "Failed to register the power sequencer\n");
+
+     return 0;
+}
+
+static const struct of_device_id pwrseq_qca6390_of_match[] = {
+     {
+             .compatible = "qcom,qca6390-pmu",
+             .data = &pwrseq_qca6390_of_data,
+     },
+     { }
+};
+MODULE_DEVICE_TABLE(of, pwrseq_qca6390_of_match);
+
+static struct platform_driver pwrseq_qca6390_driver = {
+     .driver = {
+             .name = "pwrseq-qca6390",
+             .of_match_table = pwrseq_qca6390_of_match,
+     },
+     .probe = pwrseq_qca6390_probe,
+};
Quoted 9 lines
Quoted 8 lines
drivers/power/sequencing/pwrseq-qca6390.c +5 -1
+module_platform_driver(pwrseq_qca6390_driver);
+
+MODULE_AUTHOR("Bartosz Golaszewski <[email protected]>");
+MODULE_DESCRIPTION("QCA6390 PMU power sequencing driver");
+MODULE_LICENSE("GPL");
--

2.40.1

--
With best wishes
Dmitry

#23 lore raw

RFC 5/9 Bluetooth: qca: use the power sequencer for QCA6390

In reply to Bartosz Golaszewski

From: Bartosz Golaszewski <[email protected]>

Use the pwrseq subsystem's consumer API to run the power-up sequence for the Bluetooth module of the QCA6390 package.

---
 drivers/bluetooth/hci_qca.c | 30 ++++++++++++++++++++++++++++++
 1 file changed, 30 insertions(+)
drivers/bluetooth/hci_qca.c +30 -0
index 94b8c406f0c0..21c306caafbc 100644
@@ -28,6 +28,7 @@
 #include <linux/of.h>
 #include <linux/acpi.h>
 #include <linux/platform_device.h>
+#include <linux/pwrseq/consumer.h>
 #include <linux/regulator/consumer.h>
 #include <linux/serdev.h>
 #include <linux/mutex.h>
@@ -214,6 +215,7 @@ struct qca_power {
 	struct regulator_bulk_data *vreg_bulk;
 	int num_vregs;
 	bool vregs_on;
+	struct pwrseq_desc *pwrseq;
 };
 
 struct qca_serdev {
@@ -1791,6 +1793,11 @@ static int qca_power_on(struct hci_dev *hdev)
 		ret = qca_regulator_init(hu);
 		break;
 
+	case QCA_QCA6390:
+		qcadev = serdev_device_get_drvdata(hu->serdev);
+		ret = pwrseq_power_on(qcadev->bt_power->pwrseq);
+		break;
+
 	default:
 		qcadev = serdev_device_get_drvdata(hu->serdev);
 		if (qcadev->bt_en) {
@@ -2160,6 +2167,10 @@ static void qca_power_shutdown(struct hci_uart *hu)
 		}
 		break;
 
+	case QCA_QCA6390:
+		pwrseq_power_off(qcadev->bt_power->pwrseq);
+		break;
+
 	default:
 		gpiod_set_value_cansleep(qcadev->bt_en, 0);
 	}
@@ -2298,12 +2309,25 @@ static int qca_serdev_probe(struct serdev_device *serdev)
 	case QCA_WCN6750:
 	case QCA_WCN6855:
 	case QCA_WCN7850:
+	case QCA_QCA6390:
 		qcadev->bt_power = devm_kzalloc(&serdev->dev,
 						sizeof(struct qca_power),
 						GFP_KERNEL);
 		if (!qcadev->bt_power)
 			return -ENOMEM;
+		break;
+	default:
+		break;
+	}
 
+	switch (qcadev->btsoc_type) {
+	case QCA_WCN3988:
+	case QCA_WCN3990:
+	case QCA_WCN3991:
+	case QCA_WCN3998:
+	case QCA_WCN6750:
+	case QCA_WCN6855:
+	case QCA_WCN7850:
 		qcadev->bt_power->dev = &serdev->dev;
 		err = qca_init_regulators(qcadev->bt_power, data->vregs,
 					  data->num_vregs);
@@ -2344,6 +2368,12 @@ static int qca_serdev_probe(struct serdev_device *serdev)
 		}
 		break;
 
+	case QCA_QCA6390:
+		qcadev->bt_power->pwrseq = devm_pwrseq_get(&serdev->dev);
+		if (IS_ERR(qcadev->bt_power->pwrseq))
+			return PTR_ERR(qcadev->bt_power->pwrseq);
+		fallthrough;
+
 	default:
 		qcadev->bt_en = devm_gpiod_get_optional(&serdev->dev, "enable",
 					       GPIOD_OUT_LOW);
Signature · 1 line
2.40.1
#24 lore raw

RFC 6/9 PCI: create platform devices for child OF nodes of the port node

In reply to Bartosz Golaszewski

From: Bartosz Golaszewski <[email protected]>

In order to introduce PCI power-sequencing, we need to create platform devices for child nodes of the port node. They will get matched against the pwrseq drivers (if one exists) and then the actual PCI device will reuse the node once it's detected on the bus.

---
 drivers/pci/bus.c    | 9 ++++++++-
 drivers/pci/remove.c | 2 ++
 2 files changed, 10 insertions(+), 1 deletion(-)
drivers/pci/bus.c +8 -1
index 826b5016a101..17ab41094c4e 100644
@@ -12,6 +12,7 @@
 #include <linux/errno.h>
 #include <linux/ioport.h>
 #include <linux/of.h>
+#include <linux/of_platform.h>
 #include <linux/proc_fs.h>
 #include <linux/slab.h>
 
@@ -342,8 +343,14 @@ void pci_bus_add_device(struct pci_dev *dev)
 	 */
 	pcibios_bus_add_device(dev);
 	pci_fixup_device(pci_fixup_final, dev);
-	if (pci_is_bridge(dev))
+	if (pci_is_bridge(dev)) {
 		of_pci_make_dev_node(dev);
+		retval = of_platform_populate(dev->dev.of_node, NULL, NULL,
+					      &dev->dev);
+		if (retval)
+			pci_err(dev, "failed to populate child OF nodes (%d)\n",
+				retval);
+	}
 	pci_create_sysfs_dev_files(dev);
 	pci_proc_attach_device(dev);
 	pci_bridge_d3_update(dev);
drivers/pci/remove.c +2 -0
index d749ea8250d6..fc9db2805888 100644
@@ -1,6 +1,7 @@
 // SPDX-License-Identifier: GPL-2.0
 #include <linux/pci.h>
 #include <linux/module.h>
+#include <linux/of_platform.h>
 #include "pci.h"
 
 static void pci_free_resources(struct pci_dev *dev)
@@ -22,6 +23,7 @@ static void pci_stop_dev(struct pci_dev *dev)
 		device_release_driver(&dev->dev);
 		pci_proc_detach_device(dev);
 		pci_remove_sysfs_dev_files(dev);
+		of_platform_depopulate(&dev->dev);
 		of_pci_remove_node(dev);
 
 		pci_dev_assign_added(dev, false);
Signature · 1 line
2.40.1
maintainer
#25 lore raw

Re: [RFC 6/9] PCI: create platform devices for child OF nodes of the port node

Quoted 3 lines · Bartosz Golaszewski

From: Bartosz Golaszewski <[email protected]>

In order to introduce PCI power-sequencing,

Please provide a proper problem description.

Quoted 1 line

we need to create platform

And properly express why this is a "need".

Quoted 2 lines

devices for child nodes of the port node. They will get matched against the pwrseq drivers

That's not what happens in your code, the child nodes of the bridge node in DeviceTree will match against arbitrary platform_drivers.

I also would like this commit message to express that the job of the matched device is to:

1) power up said device, followed by triggering a scan on the parent PCI bus during it's probe function.

2) power down said device, during its remove function.

Quoted 2 lines

(if one exists) and then the actual PCI device will reuse the node once it's detected on the bus.

I think the "reuse" deserves to be clarified as there will be both a pci and a platform device associated with the same of_node.

Quoted 20 lines
---
 drivers/pci/bus.c    | 9 ++++++++-
 drivers/pci/remove.c | 2 ++
 2 files changed, 10 insertions(+), 1 deletion(-)
drivers/pci/bus.c +1 -0
index 826b5016a101..17ab41094c4e 100644
@@ -12,6 +12,7 @@
 #include <linux/errno.h>
 #include <linux/ioport.h>
 #include <linux/of.h>
+#include <linux/of_platform.h>
 #include <linux/proc_fs.h>
 #include <linux/slab.h>
 

drivers/pci/bus.c void pci_bus_add_device(struct pci_dev *dev) · line 349

Quoted 8 lines
drivers/pci/bus.c +3 -1
@@ -342,8 +343,14 @@ void pci_bus_add_device(struct pci_dev *dev)
 	 */
 	pcibios_bus_add_device(dev);
 	pci_fixup_device(pci_fixup_final, dev);
-	if (pci_is_bridge(dev))
+	if (pci_is_bridge(dev)) {
 		of_pci_make_dev_node(dev);
+		retval = of_platform_populate(dev->dev.of_node, NULL, NULL,
+					      &dev->dev);

I'm not familiar enough with the ins and outs of the PCI code. Can you confirm that there are no problems with this (possibly) calling pci_rescan_bus() before the bridge device is fully initialized below?

Regards,
Bjorn

Quoted 30 lines
drivers/pci/bus.c +4 -0
+		if (retval)
+			pci_err(dev, "failed to populate child OF nodes (%d)\n",
+				retval);
+	}
 	pci_create_sysfs_dev_files(dev);
 	pci_proc_attach_device(dev);
 	pci_bridge_d3_update(dev);
drivers/pci/remove.c +2 -0
index d749ea8250d6..fc9db2805888 100644
@@ -1,6 +1,7 @@
 // SPDX-License-Identifier: GPL-2.0
 #include <linux/pci.h>
 #include <linux/module.h>
+#include <linux/of_platform.h>
 #include "pci.h"
 
 static void pci_free_resources(struct pci_dev *dev)
@@ -22,6 +23,7 @@ static void pci_stop_dev(struct pci_dev *dev)
 		device_release_driver(&dev->dev);
 		pci_proc_detach_device(dev);
 		pci_remove_sysfs_dev_files(dev);
+		of_platform_depopulate(&dev->dev);
 		of_pci_remove_node(dev);
 
 		pci_dev_assign_added(dev, false);
Signature · 1 line
2.40.1
#26 lore raw

Re: [RFC 6/9] PCI: create platform devices for child OF nodes of the port node

Quoted 24 lines · Bjorn Andersson
Quoted 3 lines · Bartosz Golaszewski

From: Bartosz Golaszewski <[email protected]>

In order to introduce PCI power-sequencing,

Please provide a proper problem description.

Quoted 1 line

we need to create platform

And properly express why this is a "need".

Quoted 2 lines

devices for child nodes of the port node. They will get matched against the pwrseq drivers

That's not what happens in your code, the child nodes of the bridge node in DeviceTree will match against arbitrary platform_drivers.

I also would like this commit message to express that the job of the matched device is to:

1) power up said device, followed by triggering a scan on the parent PCI bus during it's probe function.

Quoted 8 lines

2) power down said device, during its remove function.

Quoted 2 lines

(if one exists) and then the actual PCI device will reuse the node once it's detected on the bus.

I think the "reuse" deserves to be clarified as there will be both a pci and a platform device associated with the same of_node.

Noted all of the above. Thanks!

Quoted 19 lines
Quoted 19 lines
---
 drivers/pci/bus.c    | 9 ++++++++-
 drivers/pci/remove.c | 2 ++
 2 files changed, 10 insertions(+), 1 deletion(-)
drivers/pci/bus.c +1 -0
index 826b5016a101..17ab41094c4e 100644
@@ -12,6 +12,7 @@
 #include <linux/errno.h>
 #include <linux/ioport.h>
 #include <linux/of.h>
+#include <linux/of_platform.h>
 #include <linux/proc_fs.h>
 #include <linux/slab.h>
 
Quoted 14 lines

drivers/pci/bus.c void pci_bus_add_device(struct pci_dev *dev) · line 349

Quoted 9 lines
drivers/pci/bus.c +3 -1
@@ -342,8 +343,14 @@ void pci_bus_add_device(struct pci_dev *dev)
       */
      pcibios_bus_add_device(dev);
      pci_fixup_device(pci_fixup_final, dev);
-     if (pci_is_bridge(dev))
+     if (pci_is_bridge(dev)) {
              of_pci_make_dev_node(dev);
+             retval = of_platform_populate(dev->dev.of_node, NULL, NULL,
+                                           &dev->dev);

I'm not familiar enough with the ins and outs of the PCI code. Can you confirm that there are no problems with this (possibly) calling pci_rescan_bus() before the bridge device is fully initialized below?

I'll clarify that. I'm not that well versed with PCI code either but will get help from the right people.

Bart

Quoted 33 lines

Regards,
Bjorn

Quoted 30 lines
drivers/pci/bus.c +4 -0
+             if (retval)
+                     pci_err(dev, "failed to populate child OF nodes (%d)\n",
+                             retval);
+     }
      pci_create_sysfs_dev_files(dev);
      pci_proc_attach_device(dev);
      pci_bridge_d3_update(dev);
drivers/pci/remove.c +2 -1
index d749ea8250d6..fc9db2805888 100644
@@ -1,6 +1,7 @@
 // SPDX-License-Identifier: GPL-2.0
 #include <linux/pci.h>
 #include <linux/module.h>
+#include <linux/of_platform.h>
 #include "pci.h"
 
 static void pci_free_resources(struct pci_dev *dev)
@@ -22,6 +23,7 @@ static void pci_stop_dev(struct pci_dev *dev)
              device_release_driver(&dev->dev);
              pci_proc_detach_device(dev);
              pci_remove_sysfs_dev_files(dev);
+             of_platform_depopulate(&dev->dev);
              of_pci_remove_node(dev);
 
              pci_dev_assign_added(dev, false);
--

2.40.1

#27 lore raw

RFC 7/9 PCI: hold the rescan mutex when scanning for the first time

In reply to Bartosz Golaszewski

From: Bartosz Golaszewski <[email protected]>

With the introduction of the power sequencing drivers that will be able to trigger the port rescan, we need to hold the rescan mutex during the initial pci_host_probe() too or the two could get in each other's way.

---
 drivers/pci/probe.c | 2 ++
 1 file changed, 2 insertions(+)
drivers/pci/probe.c +2 -0
index b7335be56008..957f7afee7ba 100644
@@ -3122,7 +3122,9 @@ int pci_host_probe(struct pci_host_bridge *bridge)
 	struct pci_bus *bus, *child;
 	int ret;
 
+	pci_lock_rescan_remove();
 	ret = pci_scan_root_bus_bridge(bridge);
+	pci_unlock_rescan_remove();
 	if (ret < 0) {
 		dev_err(bridge->dev.parent, "Scanning root bridge failed");
 		return ret;
Signature · 1 line
2.40.1
#28 lore raw

RFC 8/9 PCI/pwrctl: add PCI power control core code

In reply to Bartosz Golaszewski

From: Bartosz Golaszewski <[email protected]>

Some PCI devices must be powered-on before they can be detected on the bus. Introduce a simple framework reusing the existing PCI OF infrastructure.

The way this works is: a DT node representing a PCI device connected to the port can be matched against its power control platform driver. If the match succeeds, the driver is responsible for powering-up the device and calling pcie_pwrctl_device_enable() which will trigger a PCI bus rescan as well as subscribe to PCI bus notifications.

When the device is detected and created, we'll make it consume the same DT node that the platform device did. When the device is bound, we'll create a device link between it and the parent power control device.

---
 drivers/pci/Kconfig         |  1 +
 drivers/pci/Makefile        |  1 +
 drivers/pci/pwrctl/Kconfig  |  8 ++++
 drivers/pci/pwrctl/Makefile |  3 ++
 drivers/pci/pwrctl/core.c   | 82 +++++++++++++++++++++++++++++++++++++
 include/linux/pci-pwrctl.h  | 24 +++++++++++
 6 files changed, 119 insertions(+)
 create mode 100644 drivers/pci/pwrctl/Kconfig
 create mode 100644 drivers/pci/pwrctl/Makefile
 create mode 100644 drivers/pci/pwrctl/core.c
 create mode 100644 include/linux/pci-pwrctl.h
drivers/pci/Kconfig +1 -0
index 74147262625b..5b9b84f8774f 100644
@@ -291,5 +291,6 @@ source "drivers/pci/hotplug/Kconfig"
 source "drivers/pci/controller/Kconfig"
 source "drivers/pci/endpoint/Kconfig"
 source "drivers/pci/switch/Kconfig"
+source "drivers/pci/pwrctl/Kconfig"
 
 endif
drivers/pci/Makefile +1 -0
index cc8b4e01e29d..6ae202d950f8 100644
@@ -9,6 +9,7 @@ obj-$(CONFIG_PCI)		+= access.o bus.o probe.o host-bridge.o \
 
 obj-$(CONFIG_PCI)		+= msi/
 obj-$(CONFIG_PCI)		+= pcie/
+obj-$(CONFIG_PCI)		+= pwrctl/
 
 ifdef CONFIG_PCI
 obj-$(CONFIG_PROC_FS)		+= proc.o
drivers/pci/pwrctl/Kconfig new file +8 -0
new file mode 100644
index 000000000000..e2dc5e5d2af1
@@ -0,0 +1,8 @@
+# SPDX-License-Identifier: GPL-2.0
+
+menu "PCI Power control drivers"
+
+config PCI_PWRCTL
+	bool
+
+endmenu
drivers/pci/pwrctl/Makefile new file +3 -0
new file mode 100644
index 000000000000..4381cfbf3f21
@@ -0,0 +1,3 @@
+# SPDX-License-Identifier: GPL-2.0
+
+obj-$(CONFIG_PCI_PWRCTL)		+= core.o
drivers/pci/pwrctl/core.c new file +82 -0

82 lines not on this page · raw message

include/linux/pci-pwrctl.h new file +24 -0
new file mode 100644
index 000000000000..8d16d27cbfeb
@@ -0,0 +1,24 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * Copyright (C) 2024 Linaro Ltd.
+ */
+
+#ifndef __PCI_PWRCTL_H__
+#define __PCI_PWRCTL_H__
+
+#include <linux/notifier.h>
+
+struct device;
+
+struct pci_pwrctl {
+	struct notifier_block nb;
+	struct device *dev;
+	struct device_link *link;
+};
+
+int pci_pwrctl_device_enable(struct pci_pwrctl *pwrctl);
+void pci_pwrctl_device_disable(struct pci_pwrctl *pwrctl);
+int devm_pci_pwrctl_device_enable(struct device *dev,
+				  struct pci_pwrctl *pwrctl);
+
+#endif /* __PCI_PWRCTL_H__ */
Signature · 1 line
2.40.1
maintainer
#29 lore raw

Re: [RFC 8/9] PCI/pwrctl: add PCI power control core code

Quoted 97 lines · Bartosz Golaszewski

From: Bartosz Golaszewski <[email protected]>

Some PCI devices must be powered-on before they can be detected on the bus. Introduce a simple framework reusing the existing PCI OF infrastructure.

The way this works is: a DT node representing a PCI device connected to the port can be matched against its power control platform driver. If the match succeeds, the driver is responsible for powering-up the device and calling pcie_pwrctl_device_enable() which will trigger a PCI bus rescan as well as subscribe to PCI bus notifications.

When the device is detected and created, we'll make it consume the same DT node that the platform device did. When the device is bound, we'll create a device link between it and the parent power control device.

---
 drivers/pci/Kconfig         |  1 +
 drivers/pci/Makefile        |  1 +
 drivers/pci/pwrctl/Kconfig  |  8 ++++
 drivers/pci/pwrctl/Makefile |  3 ++
 drivers/pci/pwrctl/core.c   | 82 +++++++++++++++++++++++++++++++++++++
 include/linux/pci-pwrctl.h  | 24 +++++++++++
 6 files changed, 119 insertions(+)
 create mode 100644 drivers/pci/pwrctl/Kconfig
 create mode 100644 drivers/pci/pwrctl/Makefile
 create mode 100644 drivers/pci/pwrctl/core.c
 create mode 100644 include/linux/pci-pwrctl.h
drivers/pci/Kconfig +1 -0
index 74147262625b..5b9b84f8774f 100644
@@ -291,5 +291,6 @@ source "drivers/pci/hotplug/Kconfig"
 source "drivers/pci/controller/Kconfig"
 source "drivers/pci/endpoint/Kconfig"
 source "drivers/pci/switch/Kconfig"
+source "drivers/pci/pwrctl/Kconfig"
 
 endif
drivers/pci/Makefile +1 -0
index cc8b4e01e29d..6ae202d950f8 100644
@@ -9,6 +9,7 @@ obj-$(CONFIG_PCI)		+= access.o bus.o probe.o host-bridge.o \
 
 obj-$(CONFIG_PCI)		+= msi/
 obj-$(CONFIG_PCI)		+= pcie/
+obj-$(CONFIG_PCI)		+= pwrctl/
 
 ifdef CONFIG_PCI
 obj-$(CONFIG_PROC_FS)		+= proc.o
drivers/pci/pwrctl/Kconfig new file +8 -0
new file mode 100644
index 000000000000..e2dc5e5d2af1
@@ -0,0 +1,8 @@
+# SPDX-License-Identifier: GPL-2.0
+
+menu "PCI Power control drivers"
+
+config PCI_PWRCTL
+	bool
+
+endmenu
drivers/pci/pwrctl/Makefile new file +3 -0
new file mode 100644
index 000000000000..4381cfbf3f21
@@ -0,0 +1,3 @@
+# SPDX-License-Identifier: GPL-2.0
+
+obj-$(CONFIG_PCI_PWRCTL)		+= core.o
drivers/pci/pwrctl/core.c new file +15 -0
new file mode 100644
index 000000000000..312e6fe95c31
@@ -0,0 +1,82 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (C) 2024 Linaro Ltd.
+ */
+
+#include <linux/device.h>
+#include <linux/export.h>
+#include <linux/kernel.h>
+#include <linux/pci.h>
+#include <linux/pci-pwrctl.h>
+#include <linux/property.h>
+#include <linux/slab.h>
+
+static int pci_pwrctl_notify(struct notifier_block *nb, unsigned long action,
+			     void *data)

drivers/pci/pwrctl/core.c line 25

Quoted 10 lines
drivers/pci/pwrctl/core.c new file +10 -0
+{
+	struct pci_pwrctl *pwrctl = container_of(nb, struct pci_pwrctl, nb);
+	struct device *dev = data;
+
+	if (dev_fwnode(dev) != dev_fwnode(pwrctl->dev))
+		return NOTIFY_DONE;
+
+	switch (action) {
+	case BUS_NOTIFY_ADD_DEVICE:
+		device_set_of_node_from_dev(dev, pwrctl->dev);

What happens if the bootloader left the power on, and the of_platform_populate() got probe deferred because the pwrseq wasn't ready, so this happens after pci_set_of_node() has been called?

(I think dev->of_node will be put, then get and then node_reused assigned...but I'm not entirely sure)

drivers/pci/pwrctl/core.c line 34

Quoted 9 lines
drivers/pci/pwrctl/core.c new file +9 -0
+		break;
+	case BUS_NOTIFY_BOUND_DRIVER:
+		pwrctl->link = device_link_add(dev, pwrctl->dev,
+					       DL_FLAG_AUTOREMOVE_CONSUMER);
+		if (!pwrctl->link)
+			dev_err(pwrctl->dev, "Failed to add device link\n");
+		break;
+	case BUS_NOTIFY_UNBOUND_DRIVER:
+		device_link_del(pwrctl->link);

This might however become a NULL-pointer dereference, if dev was bound to its driver before the pci_pwrctl_notify() was registered for the pwrctl and then the PCI device is unbound.

This would also happen if device_link_add() failed when the PCI device was bound...

drivers/pci/pwrctl/core.c line 41

Quoted 7 lines
drivers/pci/pwrctl/core.c new file +7 -0
+		break;
+	}
+
+	return NOTIFY_DONE;
+}
+
+int pci_pwrctl_device_enable(struct pci_pwrctl *pwrctl)

This function doesn't really "enable the device", looking at the example driver it's rather "device_enabled" than "device_enable"...

Quoted 6 lines
drivers/pci/pwrctl/core.c new file +6 -0
+{
+	if (!pwrctl->dev)
+		return -ENODEV;
+
+	pwrctl->nb.notifier_call = pci_pwrctl_notify;
+	bus_register_notifier(&pci_bus_type, &pwrctl->nb);

drivers/pci/pwrctl/core.c line 57

Quoted 10 lines
drivers/pci/pwrctl/core.c new file +10 -0
+
+	pci_lock_rescan_remove();
+	pci_rescan_bus(to_pci_dev(pwrctl->dev->parent)->bus);
+	pci_unlock_rescan_remove();
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(pci_pwrctl_device_enable);
+
+void pci_pwrctl_device_disable(struct pci_pwrctl *pwrctl)

Similarly this doesn't disable the device, the code calling this is doing so...

Regards,
Bjorn

Quoted 58 lines
drivers/pci/pwrctl/core.c new file +25 -0
+{
+	bus_unregister_notifier(&pci_bus_type, &pwrctl->nb);
+}
+EXPORT_SYMBOL_GPL(pci_pwrctl_device_disable);
+
+static void devm_pci_pwrctl_device_disable(void *data)
+{
+	struct pci_pwrctl *pwrctl = data;
+
+	pci_pwrctl_device_disable(pwrctl);
+}
+
+int devm_pci_pwrctl_device_enable(struct device *dev,
+				  struct pci_pwrctl *pwrctl)
+{
+	int ret;
+
+	ret = pci_pwrctl_device_enable(pwrctl);
+	if (ret)
+		return ret;
+
+	return devm_add_action_or_reset(dev, devm_pci_pwrctl_device_disable,
+					pwrctl);
+}
+EXPORT_SYMBOL_GPL(devm_pci_pwrctl_device_enable);
include/linux/pci-pwrctl.h new file +24 -0
new file mode 100644
index 000000000000..8d16d27cbfeb
@@ -0,0 +1,24 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * Copyright (C) 2024 Linaro Ltd.
+ */
+
+#ifndef __PCI_PWRCTL_H__
+#define __PCI_PWRCTL_H__
+
+#include <linux/notifier.h>
+
+struct device;
+
+struct pci_pwrctl {
+	struct notifier_block nb;
+	struct device *dev;
+	struct device_link *link;
+};
+
+int pci_pwrctl_device_enable(struct pci_pwrctl *pwrctl);
+void pci_pwrctl_device_disable(struct pci_pwrctl *pwrctl);
+int devm_pci_pwrctl_device_enable(struct device *dev,
+				  struct pci_pwrctl *pwrctl);
+
+#endif /* __PCI_PWRCTL_H__ */
Signature · 1 line
2.40.1
#30 lore raw

Re: [RFC 8/9] PCI/pwrctl: add PCI power control core code

Quoted 1 line · Bjorn Andersson

[snip]

Quoted 18 lines

drivers/pci/pwrctl/core.c line 25

Quoted 13 lines
drivers/pci/pwrctl/core.c new file +13 -0
+
+static int pci_pwrctl_notify(struct notifier_block *nb, unsigned long action,
+                          void *data)
+{
+     struct pci_pwrctl *pwrctl = container_of(nb, struct pci_pwrctl, nb);
+     struct device *dev = data;
+
+     if (dev_fwnode(dev) != dev_fwnode(pwrctl->dev))
+             return NOTIFY_DONE;
+
+     switch (action) {
+     case BUS_NOTIFY_ADD_DEVICE:
+             device_set_of_node_from_dev(dev, pwrctl->dev);

What happens if the bootloader left the power on, and the of_platform_populate() got probe deferred because the pwrseq wasn't ready, so this happens after pci_set_of_node() has been called?

Quoted 2 lines

(I think dev->of_node will be put, then get and then node_reused assigned...but I'm not entirely sure)

That's exactly what will happen and the end result will be the same.

Quoted 11 lines

drivers/pci/pwrctl/core.c line 34

Quoted 10 lines
drivers/pci/pwrctl/core.c new file +9 -0
+             break;
+     case BUS_NOTIFY_BOUND_DRIVER:
+             pwrctl->link = device_link_add(dev, pwrctl->dev,
+                                            DL_FLAG_AUTOREMOVE_CONSUMER);
+             if (!pwrctl->link)
+                     dev_err(pwrctl->dev, "Failed to add device link\n");
+             break;
+     case BUS_NOTIFY_UNBOUND_DRIVER:
+             device_link_del(pwrctl->link);
Quoted 7 lines

This might however become a NULL-pointer dereference, if dev was bound to its driver before the pci_pwrctl_notify() was registered for the pwrctl and then the PCI device is unbound.

This would also happen if device_link_add() failed when the PCI device was bound...

Yes, I'll address it.

Quoted 11 lines

drivers/pci/pwrctl/core.c line 41

Quoted 7 lines
drivers/pci/pwrctl/core.c new file +7 -0
+             break;
+     }
+
+     return NOTIFY_DONE;
+}
+
+int pci_pwrctl_device_enable(struct pci_pwrctl *pwrctl)

This function doesn't really "enable the device", looking at the example driver it's rather "device_enabled" than "device_enable"...

I was also thinking about pci_pwrctl_device_ready() or pci_pwrctl_device_prepared().

Bart

[snip!]

maintainer
#31 lore raw

Re: Re: [RFC 8/9] PCI/pwrctl: add PCI power control core code

Quoted 1 line · Bartosz Golaszewski

On Fri, Feb 2, 2024 at 4:53 AM Bjorn Andersson <[email protected]> wrote:

[..]

Quoted 12 lines
Quoted 11 lines

drivers/pci/pwrctl/core.c line 41

Quoted 7 lines
drivers/pci/pwrctl/core.c new file +7 -0
+             break;
+     }
+
+     return NOTIFY_DONE;
+}
+
+int pci_pwrctl_device_enable(struct pci_pwrctl *pwrctl)

This function doesn't really "enable the device", looking at the example driver it's rather "device_enabled" than "device_enable"...

Quoted 2 lines

I was also thinking about pci_pwrctl_device_ready() or pci_pwrctl_device_prepared().

I like both of these.

I guess the bigger question is how the flow would look like in the event that we need to power-cycle the attached PCIe device, e.g. because firmware has gotten into a really bad state.

Will we need an operation that removes the device first, and then cut the power, or do we cut the power and then call unprepared()?

Regards,
Bjorn

Quoted 4 lines

Bart

[snip!]

#32 lore raw

Re: Re: [RFC 8/9] PCI/pwrctl: add PCI power control core code

Quoted 19 lines · Bjorn Andersson
Quoted 1 line · Bartosz Golaszewski

On Fri, Feb 2, 2024 at 4:53 AM Bjorn Andersson <[email protected]> wrote:

[..]

Quoted 12 lines
Quoted 11 lines

drivers/pci/pwrctl/core.c line 41

Quoted 7 lines
drivers/pci/pwrctl/core.c new file +7 -0
+             break;
+     }
+
+     return NOTIFY_DONE;
+}
+
+int pci_pwrctl_device_enable(struct pci_pwrctl *pwrctl)

This function doesn't really "enable the device", looking at the example driver it's rather "device_enabled" than "device_enable"...

Quoted 2 lines

I was also thinking about pci_pwrctl_device_ready() or pci_pwrctl_device_prepared().

Quoted 9 lines

I like both of these.

I guess the bigger question is how the flow would look like in the event that we need to power-cycle the attached PCIe device, e.g. because firmware has gotten into a really bad state.

Will we need an operation that removes the device first, and then cut the power, or do we cut the power and then call unprepared()?

How would the core be notified about this power-cycle from the PCI subsystem? I honestly don't know. Is there a notifier we could subscribe to? Is the device unbound and rebound in such case?

Bart

#33 lore raw

Re: Re: [RFC 8/9] PCI/pwrctl: add PCI power control core code

Quoted 11 lines · Bartosz Golaszewski
Quoted 10 lines · On Fri, Feb 2, 2024 at 5:52???PM Bjorn Andersson <[email protected]> wrote:
Quoted 2 lines · Bartosz Golaszewski

I was also thinking about pci_pwrctl_device_ready() or pci_pwrctl_device_prepared().

I like both of these.

I guess the bigger question is how the flow would look like in the event that we need to power-cycle the attached PCIe device, e.g. because firmware has gotten into a really bad state.

Quoted 6 lines
Quoted 2 lines

Will we need an operation that removes the device first, and then cut the power, or do we cut the power and then call unprepared()?

How would the core be notified about this power-cycle from the PCI subsystem? I honestly don't know. Is there a notifier we could subscribe to? Is the device unbound and rebound in such case?

To power-manage the PCI device for runtime PM (suspend to D3cold) or system sleep, you need to amend:

platform_pci_power_manageable()
platform_pci_set_power_state()
platform_pci_get_power_state()
platform_pci_refresh_power_state()
platform_pci_choose_state()

E.g. platform_pci_power_manageable() would check for presence of a regulator in the DT and platform_pci_set_power_state() would disable or enable the regulator.

To reset the device by power cycling it, amend pci_reset_fn_methods[] to provide a reset method which disables and re-enables the regulator. Then you can choose that reset method via sysfs and power-cycle the device. The PCI core will also automatically use that reset method if there's nothing else available (e.g. if no Secondary Bus Reset is available because the device has siblings or children, or if FLR is not supported).

Thanks,

Lukas

#34 lore raw

Re: Re: [RFC 8/9] PCI/pwrctl: add PCI power control core code

Quoted 28 lines · Lukas Wunner
Quoted 11 lines · Bartosz Golaszewski
Quoted 10 lines · On Fri, Feb 2, 2024 at 5:52???PM Bjorn Andersson <[email protected]> wrote:
Quoted 2 lines · Bartosz Golaszewski

I was also thinking about pci_pwrctl_device_ready() or pci_pwrctl_device_prepared().

I like both of these.

I guess the bigger question is how the flow would look like in the event that we need to power-cycle the attached PCIe device, e.g. because firmware has gotten into a really bad state.

Quoted 6 lines
Quoted 2 lines

Will we need an operation that removes the device first, and then cut the power, or do we cut the power and then call unprepared()?

How would the core be notified about this power-cycle from the PCI subsystem? I honestly don't know. Is there a notifier we could subscribe to? Is the device unbound and rebound in such case?

To power-manage the PCI device for runtime PM (suspend to D3cold) or system sleep, you need to amend:

platform_pci_power_manageable()
platform_pci_set_power_state()
platform_pci_get_power_state()
platform_pci_refresh_power_state()
platform_pci_choose_state()

Quoted 4 lines

E.g. platform_pci_power_manageable() would check for presence of a regulator in the DT and platform_pci_set_power_state() would disable or enable the regulator.

This will work if the sole control of the resources lies in these platform_*() APIs. But in reality, the controller drivers are the ones controlling the power supply to the devices and with this series, the control would be shifted partly to pwrctl driver.

I think what we need is to call in the callbacks of the drivers in a hierarchial order.

- Mani

Quoted 11 lines

To reset the device by power cycling it, amend pci_reset_fn_methods[] to provide a reset method which disables and re-enables the regulator. Then you can choose that reset method via sysfs and power-cycle the device. The PCI core will also automatically use that reset method if there's nothing else available (e.g. if no Secondary Bus Reset is available because the device has siblings or children, or if FLR is not supported).

Thanks,

Lukas

Signature · 1 line
மணிவண்ணன் சதாசிவம்
#35 lore raw

Re: Re: [RFC 8/9] PCI/pwrctl: add PCI power control core code

In reply to Bjorn Andersson
Quoted 18 lines · Bjorn Andersson
Quoted 1 line · Bartosz Golaszewski

On Fri, Feb 2, 2024 at 4:53 AM Bjorn Andersson <[email protected]> wrote:

[..]

Quoted 12 lines
Quoted 11 lines

drivers/pci/pwrctl/core.c line 41

Quoted 7 lines
drivers/pci/pwrctl/core.c new file +7 -0
+             break;
+     }
+
+     return NOTIFY_DONE;
+}
+
+int pci_pwrctl_device_enable(struct pci_pwrctl *pwrctl)

This function doesn't really "enable the device", looking at the example driver it's rather "device_enabled" than "device_enable"...

Quoted 2 lines

I was also thinking about pci_pwrctl_device_ready() or pci_pwrctl_device_prepared().

Quoted 9 lines

I like both of these.

I guess the bigger question is how the flow would look like in the event that we need to power-cycle the attached PCIe device, e.g. because firmware has gotten into a really bad state.

Will we need an operation that removes the device first, and then cut the power, or do we cut the power and then call unprepared()?

Currently, we don't power cycle while resetting the devices. Most of the drivers just do a software reset using some register writes. Part of the reason for that is, the drivers themselves don't control the power to the devices and there would be no way to let the parent know about the firmware crash.

- Mani

Signature · 1 line
மணிவண்ணன் சதாசிவம்
maintainer
#36 lore raw

Re: Re: Re: [RFC 8/9] PCI/pwrctl: add PCI power control core code

Quoted 25 lines · Manivannan Sadhasivam
Quoted 24 lines · Bjorn Andersson
Quoted 1 line · Bartosz Golaszewski

On Fri, Feb 2, 2024 at 4:53 AM Bjorn Andersson <[email protected]> wrote:

[..]

Quoted 12 lines
Quoted 11 lines

drivers/pci/pwrctl/core.c line 41

Quoted 7 lines
drivers/pci/pwrctl/core.c new file +7 -0
+             break;
+     }
+
+     return NOTIFY_DONE;
+}
+
+int pci_pwrctl_device_enable(struct pci_pwrctl *pwrctl)

This function doesn't really "enable the device", looking at the example driver it's rather "device_enabled" than "device_enable"...

Quoted 2 lines

I was also thinking about pci_pwrctl_device_ready() or pci_pwrctl_device_prepared().

I like both of these.

I guess the bigger question is how the flow would look like in the event that we need to power-cycle the attached PCIe device, e.g. because firmware has gotten into a really bad state.

Quoted 9 lines
Quoted 3 lines

Will we need an operation that removes the device first, and then cut the power, or do we cut the power and then call unprepared()?

Currently, we don't power cycle while resetting the devices. Most of the drivers just do a software reset using some register writes. Part of the reason for that is, the drivers themselves don't control the power to the devices and there would be no way to let the parent know about the firmware crash.

I don't know what the appropriate design for this is, but we do have a need for being able to recover from this state by the means of power-cycling the device.

If it's not possible to let the device do it (in any fashion), then perhaps a user-space-assisted model is needed?

Turning on power is an important first step, but please do consider the full scope of the known problem space.

Regards,
Bjorn

#37 lore raw

Re: Re: Re: [RFC 8/9] PCI/pwrctl: add PCI power control core code

Quoted 40 lines · Bjorn Andersson
Quoted 25 lines · Manivannan Sadhasivam
Quoted 24 lines · Bjorn Andersson
Quoted 1 line · Bartosz Golaszewski

On Fri, Feb 2, 2024 at 4:53 AM Bjorn Andersson <[email protected]> wrote:

[..]

Quoted 12 lines
Quoted 11 lines

drivers/pci/pwrctl/core.c line 41

Quoted 7 lines
drivers/pci/pwrctl/core.c new file +7 -0
+             break;
+     }
+
+     return NOTIFY_DONE;
+}
+
+int pci_pwrctl_device_enable(struct pci_pwrctl *pwrctl)

This function doesn't really "enable the device", looking at the example driver it's rather "device_enabled" than "device_enable"...

Quoted 2 lines

I was also thinking about pci_pwrctl_device_ready() or pci_pwrctl_device_prepared().

I like both of these.

I guess the bigger question is how the flow would look like in the event that we need to power-cycle the attached PCIe device, e.g. because firmware has gotten into a really bad state.

Quoted 9 lines
Quoted 3 lines

Will we need an operation that removes the device first, and then cut the power, or do we cut the power and then call unprepared()?

Currently, we don't power cycle while resetting the devices. Most of the drivers just do a software reset using some register writes. Part of the reason for that is, the drivers themselves don't control the power to the devices and there would be no way to let the parent know about the firmware crash.

I don't know what the appropriate design for this is, but we do have a need for being able to recover from this state by the means of power-cycling the device.

Quoted 6 lines

If it's not possible to let the device do it (in any fashion), then perhaps a user-space-assisted model is needed?

Turning on power is an important first step, but please do consider the full scope of the known problem space.

Agree. I'm not ignoring this issue, but this is a separate topic IMO (or an incremental change). Because, power cycling the device in the event of a firmware crash or even upon receiving AER Fatal errors is valid for platforms not making use of this driver and an existing issue.

For sure we can accomodate that functionality in this series itself, but that's going to drag this series to many releases (you already know how long it took for us to get to the current state). Instead, I'd recommend to merge it in its current form and have Bartosz or someone work on incremental features such as:

1. Runtime/System PM
2. Resetting the device in the event of fw crash etc...

Wdyt?

- Mani

Signature · 1 line
மணிவண்ணன் சதாசிவம்
#38 lore raw

Re: [RFC 8/9] PCI/pwrctl: add PCI power control core code

In reply to Bjorn Andersson
Quoted 1 line · Bjorn Andersson

[snip]

Quoted 11 lines

drivers/pci/pwrctl/core.c line 34

Quoted 10 lines
drivers/pci/pwrctl/core.c new file +9 -0
+             break;
+     case BUS_NOTIFY_BOUND_DRIVER:
+             pwrctl->link = device_link_add(dev, pwrctl->dev,
+                                            DL_FLAG_AUTOREMOVE_CONSUMER);
+             if (!pwrctl->link)
+                     dev_err(pwrctl->dev, "Failed to add device link\n");
+             break;
+     case BUS_NOTIFY_UNBOUND_DRIVER:
+             device_link_del(pwrctl->link);
Quoted 4 lines

This might however become a NULL-pointer dereference, if dev was bound to its driver before the pci_pwrctl_notify() was registered for the pwrctl and then the PCI device is unbound.

Right. And it also makes me think that right after registering with the notifier, we should iterate over the PCI bus devices and see if the relevant one is already there.

Quoted 3 lines

This would also happen if device_link_add() failed when the PCI device was bound...

Right.

Bart

[snip]

#39 lore raw

RFC 9/9 PCI/pwrctl: add a PCI power control driver for power sequenced devices

In reply to Bartosz Golaszewski

From: Bartosz Golaszewski <[email protected]>

Add a PCI power control driver that's capable of correctly powering up devices using the power sequencing subsystem. For now we support the ath11k module on QCA6390.

---
 drivers/pci/pwrctl/Kconfig             |  9 +++
 drivers/pci/pwrctl/Makefile            |  1 +
 drivers/pci/pwrctl/pci-pwrctl-pwrseq.c | 83 ++++++++++++++++++++++++++
 3 files changed, 93 insertions(+)
 create mode 100644 drivers/pci/pwrctl/pci-pwrctl-pwrseq.c
drivers/pci/pwrctl/Kconfig +9 -0
index e2dc5e5d2af1..bca72dc08e79 100644
@@ -5,4 +5,13 @@ menu "PCI Power control drivers"
 config PCI_PWRCTL
 	bool
 
+config PCI_PWRCTL_PWRSEQ
+	tristate "PCI Power Control driver using the Power Sequencing subsystem"
+	select POWER_SEQUENCING
+	select PCI_PWRCTL
+	default m if (ATH11K_PCI && ARCH_QCOM)
+	help
+	  Enable support for the PCI power control driver for device
+	  drivers using the Power Sequencing subsystem.
+
 endmenu
drivers/pci/pwrctl/Makefile +1 -0
index 4381cfbf3f21..919c0f704ee9 100644
@@ -1,3 +1,4 @@
 # SPDX-License-Identifier: GPL-2.0
 
 obj-$(CONFIG_PCI_PWRCTL)		+= core.o
+obj-$(CONFIG_PCI_PWRCTL_PWRSEQ)		+= pci-pwrctl-pwrseq.o
drivers/pci/pwrctl/pci-pwrctl-pwrseq.c new file +83 -0

83 lines not on this page · raw message

Signature · 1 line
2.40.1
maintainer
#40 lore raw

Re: [RFC 9/9] PCI/pwrctl: add a PCI power control driver for power sequenced devices

Quoted 6 lines · Bartosz Golaszewski

From: Bartosz Golaszewski <[email protected]>

Add a PCI power control driver that's capable of correctly powering up devices using the power sequencing subsystem. For now we support the ath11k module on QCA6390.

For a PCI device which doesn't share resources with something on another bus, the whole power sequencing would be implemented in a driver like this - without the involvement of the power sequence framework.

I think it would be nice to see this series introduce a simple pci_pwrctl driver, and then (in the same series) introduce the power sequence framework and your PMU driver.

One case where such model would be appropriate is the XHCI controller (uPD720201) on db845c. Today we describe vddpe-3p3-supply as a supply on the PCI controller, but it should have been vdd33-supply, vdd10-supply, avdd33-supply on the PCI device.

That would provide an example for how a simple PCI power control driver can/should look like, and we can discuss the PCI pieces separate from the introduction of the new power sequence framework (which is unrelated to PCI).

Regards,
Bjorn

Quoted 127 lines
---
 drivers/pci/pwrctl/Kconfig             |  9 +++
 drivers/pci/pwrctl/Makefile            |  1 +
 drivers/pci/pwrctl/pci-pwrctl-pwrseq.c | 83 ++++++++++++++++++++++++++
 3 files changed, 93 insertions(+)
 create mode 100644 drivers/pci/pwrctl/pci-pwrctl-pwrseq.c
drivers/pci/pwrctl/Kconfig +9 -0
index e2dc5e5d2af1..bca72dc08e79 100644
@@ -5,4 +5,13 @@ menu "PCI Power control drivers"
 config PCI_PWRCTL
 	bool
 
+config PCI_PWRCTL_PWRSEQ
+	tristate "PCI Power Control driver using the Power Sequencing subsystem"
+	select POWER_SEQUENCING
+	select PCI_PWRCTL
+	default m if (ATH11K_PCI && ARCH_QCOM)
+	help
+	  Enable support for the PCI power control driver for device
+	  drivers using the Power Sequencing subsystem.
+
 endmenu
drivers/pci/pwrctl/Makefile +1 -0
index 4381cfbf3f21..919c0f704ee9 100644
@@ -1,3 +1,4 @@
 # SPDX-License-Identifier: GPL-2.0
 
 obj-$(CONFIG_PCI_PWRCTL)		+= core.o
+obj-$(CONFIG_PCI_PWRCTL_PWRSEQ)		+= pci-pwrctl-pwrseq.o
drivers/pci/pwrctl/pci-pwrctl-pwrseq.c new file +83 -0
new file mode 100644
index 000000000000..510598c4edc4
@@ -0,0 +1,83 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (C) 2023-2024 Linaro Ltd.
+ */
+
+#include <linux/device.h>
+#include <linux/mod_devicetable.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/pci-pwrctl.h>
+#include <linux/platform_device.h>
+#include <linux/pwrseq/consumer.h>
+#include <linux/slab.h>
+#include <linux/types.h>
+
+struct pci_pwrctl_pwrseq_data {
+	struct pci_pwrctl ctx;
+	struct pwrseq_desc *pwrseq;
+};
+
+static void devm_pci_pwrctl_pwrseq_power_off(void *data)
+{
+	struct pwrseq_desc *pwrseq = data;
+
+	pwrseq_power_off(pwrseq);
+}
+
+static int pci_pwrctl_pwrseq_probe(struct platform_device *pdev)
+{
+	struct pci_pwrctl_pwrseq_data *data;
+	struct device *dev = &pdev->dev;
+	int ret;
+
+	data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
+	if (!data)
+		return -ENOMEM;
+
+	data->pwrseq = devm_pwrseq_get(dev);
+	if (IS_ERR(data->pwrseq))
+		return dev_err_probe(dev, PTR_ERR(data->pwrseq),
+				     "Failed to get the power sequencer\n");
+
+	ret = pwrseq_power_on(data->pwrseq);
+	if (ret)
+		return dev_err_probe(dev, ret,
+				     "Failed to power-on the device\n");
+
+	ret = devm_add_action_or_reset(dev, devm_pci_pwrctl_pwrseq_power_off,
+				       data->pwrseq);
+	if (ret)
+		return ret;
+
+	data->ctx.dev = dev;
+
+	ret = devm_pci_pwrctl_device_enable(dev, &data->ctx);
+	if (ret)
+		return dev_err_probe(dev, ret,
+				     "Failed to register the pwrctl wrapper\n");
+
+	return 0;
+}
+
+static const struct of_device_id pci_pwrctl_pwrseq_of_match[] = {
+	{
+		/* ATH11K in QCA6390 package. */
+		.compatible = "pci17cb,1101",
+	},
+	{ }
+};
+MODULE_DEVICE_TABLE(of, pci_pwrctl_pwrseq_of_match);
+
+static struct platform_driver pci_pwrctl_pwrseq_driver = {
+	.driver = {
+		.name = "pci-pwrctl-pwrseq",
+		.of_match_table = pci_pwrctl_pwrseq_of_match,
+	},
+	.probe = pci_pwrctl_pwrseq_probe,
+};
+module_platform_driver(pci_pwrctl_pwrseq_driver);
+
+MODULE_AUTHOR("Bartosz Golaszewski <[email protected]>");
+MODULE_DESCRIPTION("Generic PCI Power Control module for power sequenced devices");
+MODULE_LICENSE("GPL");
Signature · 1 line
2.40.1
#41 lore raw

Re: [RFC 9/9] PCI/pwrctl: add a PCI power control driver for power sequenced devices

Quoted 4 lines · Bjorn Andersson
Quoted 2 lines · Bartosz Golaszewski

From: Bartosz Golaszewski <[email protected]>

Quoted 9 lines
Quoted 4 lines

Add a PCI power control driver that's capable of correctly powering up devices using the power sequencing subsystem. For now we support the ath11k module on QCA6390.

For a PCI device which doesn't share resources with something on another bus, the whole power sequencing would be implemented in a driver like this - without the involvement of the power sequence framework.

Yes, this is what I did in the previous incarnation of this code[1].

(I know, I should have linked it here. My bad, I will do it next time).

Quoted 4 lines

I think it would be nice to see this series introduce a simple pci_pwrctl driver, and then (in the same series) introduce the power sequence framework and your PMU driver.

I disagree. I was initially annoyed by Dmitry asking me to do a lot more work than anticipated but he's right after all. WLAN and BT consuming what is really the PMU's inputs is simply not the actual representation. That's why we should make it a pwrseq user IMO.

Quoted 4 lines

One case where such model would be appropriate is the XHCI controller (uPD720201) on db845c. Today we describe vddpe-3p3-supply as a supply on the PCI controller, but it should have been vdd33-supply, vdd10-supply, avdd33-supply on the PCI device.

Sounds like a good second user then!

Quoted 5 lines

That would provide an example for how a simple PCI power control driver can/should look like, and we can discuss the PCI pieces separate from the introduction of the new power sequence framework (which is unrelated to PCI).

I agree it's unrelated and it could possibly go upstream separately but the particular use-case on RB5 (and other Qcom platforms) requires both the PCI and generic power sequencing to be addressed.

Bart

[snip]

[1] https://lore.kernel.org/netdev/[email protected]/T/#m72f52254a52fcb8a8a44de0702cad1087d4bcfa1

maintainer
#42 lore raw

Re: Re: [RFC 9/9] PCI/pwrctl: add a PCI power control driver for power sequenced devices

Quoted 24 lines · Bartosz Golaszewski
Quoted 4 lines · Bjorn Andersson
Quoted 2 lines · Bartosz Golaszewski

From: Bartosz Golaszewski <[email protected]>

Quoted 9 lines
Quoted 4 lines

Add a PCI power control driver that's capable of correctly powering up devices using the power sequencing subsystem. For now we support the ath11k module on QCA6390.

For a PCI device which doesn't share resources with something on another bus, the whole power sequencing would be implemented in a driver like this - without the involvement of the power sequence framework.

Yes, this is what I did in the previous incarnation of this code[1].

(I know, I should have linked it here. My bad, I will do it next time).

Quoted 4 lines

I think it would be nice to see this series introduce a simple pci_pwrctl driver, and then (in the same series) introduce the power sequence framework and your PMU driver.

Quoted 5 lines

I disagree. I was initially annoyed by Dmitry asking me to do a lot more work than anticipated but he's right after all. WLAN and BT consuming what is really the PMU's inputs is simply not the actual representation. That's why we should make it a pwrseq user IMO.

If the PMU registers the "internal" output regulators, then PCI device would consume the PCI outputs of the PMU, the BT device would consume the BT outputs of the PMU. The PMU requests inputs enabled and drives BT_EN and WLAN_EN according to which subset of these output regulators are enabled.

Pretty much exactly as "regulator-fixes" isn't a pwrseq device.

Regards,
Bjorn

Quoted 22 lines
Quoted 4 lines

One case where such model would be appropriate is the XHCI controller (uPD720201) on db845c. Today we describe vddpe-3p3-supply as a supply on the PCI controller, but it should have been vdd33-supply, vdd10-supply, avdd33-supply on the PCI device.

Sounds like a good second user then!

Quoted 5 lines

That would provide an example for how a simple PCI power control driver can/should look like, and we can discuss the PCI pieces separate from the introduction of the new power sequence framework (which is unrelated to PCI).

I agree it's unrelated and it could possibly go upstream separately but the particular use-case on RB5 (and other Qcom platforms) requires both the PCI and generic power sequencing to be addressed.

Bart

[snip]

[1] https://lore.kernel.org/netdev/[email protected]/T/#m72f52254a52fcb8a8a44de0702cad1087d4bcfa1

maintainer
#43 lore raw
In reply to Bartosz Golaszewski
Quoted 2 lines · Bartosz Golaszewski

From: Bartosz Golaszewski <[email protected]>

We now have 3 RFC and 1 PATCH versions of these patches on the list in under a month. Please at least add a version to your subject...

Quoted 24 lines

I'd like to preface the cover letter by saying right away that this series is not complete. It's an RFC that presents my approach and is sent to the list for discussion. There are no DT bindings nor docs in Documentation/ yet. Please review it as an RFC and not an upstreambound series. If the approach is accepted as correct, I'll add missing bits.

The RFC[1] presenting my proposed device-tree representation of the QCA6391 package present on the RB5 board - while not really officially accepted - was not outright rejected which is a good sign.

This series incorporates it and builds a proposed power sequencing subsystem together with the first dedicated driver around it. Then it adds first two users: the Bluetooth and WLAN modules of the QCA6391.

The Bluetooth part is pretty straightforward. The WLAN however is a PCIe device and as such needs to be powered-up *before* it's detected on the PCI bus. To that end, we modify the PCI core to instantiate platform devices for existing DT child nodes of the PCIe ports. For those nodes for which a power-sequencing driver exists, we bind it and let it probe. The driver then triggers a rescan of the PCI bus with the aim of detecting the now powered-on device. The device will consume the same DT node as the platform, power-sequencing device. We use device links to make the latter become the parent of the former.

Quoted 5 lines

The main advantage of the above approach (both for PCI as well as generic power sequencers) is that we don't introduce significant changes in DT bindings and don't introduce new properties. We merely define new resources.

How can we tell? There are still no Documentation/dt-bindings changes in your series.

Regards,
Bjorn

Quoted 51 lines

[1] https://lore.kernel.org/all/CAMRc=MckG32DQv7b1AQL-mbnYdx4fsdYWtLwCyXc5Ma7EeSAKw@mail.gmail.com/T/#md5dc62007d12f6833d4e51658b14e0493954ba68

Bartosz Golaszewski (9):
of: provide a cleanup helper for OF nodes
arm64: dts: qcom: qrb5165-rb5: model the PMU of the QCA6391
power: sequencing: new subsystem
power: pwrseq: add a driver for the QCA6390 PMU module
Bluetooth: qca: use the power sequencer for QCA6390
PCI: create platform devices for child OF nodes of the port node
PCI: hold the rescan mutex when scanning for the first time PCI/pwrctl: add PCI power control core code
PCI/pwrctl: add a PCI power control driver for power sequenced devices

 arch/arm64/boot/dts/qcom/qrb5165-rb5.dts  | 128 +++++-
 arch/arm64/boot/dts/qcom/sm8250.dtsi      |  10 +
 drivers/bluetooth/hci_qca.c               |  30 ++
 drivers/pci/Kconfig                       |   1 +
 drivers/pci/Makefile                      |   1 +
 drivers/pci/bus.c                         |   9 +-
 drivers/pci/probe.c                       |   2 +
 drivers/pci/pwrctl/Kconfig                |  17 +
 drivers/pci/pwrctl/Makefile               |   4 +
 drivers/pci/pwrctl/core.c                 |  82 ++++
 drivers/pci/pwrctl/pci-pwrctl-pwrseq.c    |  83 ++++
 drivers/pci/remove.c                      |   2 +
 drivers/power/Kconfig                     |   1 +
 drivers/power/Makefile                    |   1 +
 drivers/power/sequencing/Kconfig          |  28 ++
 drivers/power/sequencing/Makefile         |   6 +
 drivers/power/sequencing/core.c           | 482 ++++++++++++++++++++++
 drivers/power/sequencing/pwrseq-qca6390.c | 232 +++++++++++
 include/linux/of.h                        |   4 +
 include/linux/pci-pwrctl.h                |  24 ++
 include/linux/pwrseq/consumer.h           |  53 +++
 include/linux/pwrseq/provider.h           |  41 ++
 22 files changed, 1229 insertions(+), 12 deletions(-)
 create mode 100644 drivers/pci/pwrctl/Kconfig
 create mode 100644 drivers/pci/pwrctl/Makefile
 create mode 100644 drivers/pci/pwrctl/core.c
 create mode 100644 drivers/pci/pwrctl/pci-pwrctl-pwrseq.c
 create mode 100644 drivers/power/sequencing/Kconfig
 create mode 100644 drivers/power/sequencing/Makefile
 create mode 100644 drivers/power/sequencing/core.c
 create mode 100644 drivers/power/sequencing/pwrseq-qca6390.c
 create mode 100644 include/linux/pci-pwrctl.h
 create mode 100644 include/linux/pwrseq/consumer.h
 create mode 100644 include/linux/pwrseq/provider.h
Signature · 1 line
2.40.1
#44 lore raw
Quoted 8 lines · Bjorn Andersson
Quoted 2 lines · Bartosz Golaszewski

From: Bartosz Golaszewski <[email protected]>

We now have 3 RFC and 1 PATCH versions of these patches on the list in under a month. Please at least add a version to your subject...

So there was an RFC for the PCI power sequencing (now renamed to PCI power control - pci_pwrctl), then a proper series for it (with changes listed). Then an RFC with just proposed DT changes (sent mostly to DT maintainers to clear it with them) and now an RFC with power sequencing + PCI power control. Hard to figure out how to version it if these are pretty much separate developments.

I'll provide links to everything next time.

Quoted 24 lines
Quoted 24 lines

I'd like to preface the cover letter by saying right away that this series is not complete. It's an RFC that presents my approach and is sent to the list for discussion. There are no DT bindings nor docs in Documentation/ yet. Please review it as an RFC and not an upstreambound series. If the approach is accepted as correct, I'll add missing bits.

The RFC[1] presenting my proposed device-tree representation of the QCA6391 package present on the RB5 board - while not really officially accepted - was not outright rejected which is a good sign.

This series incorporates it and builds a proposed power sequencing subsystem together with the first dedicated driver around it. Then it adds first two users: the Bluetooth and WLAN modules of the QCA6391.

The Bluetooth part is pretty straightforward. The WLAN however is a PCIe device and as such needs to be powered-up *before* it's detected on the PCI bus. To that end, we modify the PCI core to instantiate platform devices for existing DT child nodes of the PCIe ports. For those nodes for which a power-sequencing driver exists, we bind it and let it probe. The driver then triggers a rescan of the PCI bus with the aim of detecting the now powered-on device. The device will consume the same DT node as the platform, power-sequencing device. We use device links to make the latter become the parent of the former.

Quoted 8 lines
Quoted 5 lines

The main advantage of the above approach (both for PCI as well as generic power sequencers) is that we don't introduce significant changes in DT bindings and don't introduce new properties. We merely define new resources.

How can we tell? There are still no Documentation/dt-bindings changes in your series.

Noted.

Bartosz

Quoted 55 lines

Regards,
Bjorn

Quoted 51 lines

[1] https://lore.kernel.org/all/CAMRc=MckG32DQv7b1AQL-mbnYdx4fsdYWtLwCyXc5Ma7EeSAKw@mail.gmail.com/T/#md5dc62007d12f6833d4e51658b14e0493954ba68

Bartosz Golaszewski (9):
of: provide a cleanup helper for OF nodes
arm64: dts: qcom: qrb5165-rb5: model the PMU of the QCA6391
power: sequencing: new subsystem
power: pwrseq: add a driver for the QCA6390 PMU module
Bluetooth: qca: use the power sequencer for QCA6390
PCI: create platform devices for child OF nodes of the port node
PCI: hold the rescan mutex when scanning for the first time PCI/pwrctl: add PCI power control core code
PCI/pwrctl: add a PCI power control driver for power sequenced devices

 arch/arm64/boot/dts/qcom/qrb5165-rb5.dts  | 128 +++++-
 arch/arm64/boot/dts/qcom/sm8250.dtsi      |  10 +
 drivers/bluetooth/hci_qca.c               |  30 ++
 drivers/pci/Kconfig                       |   1 +
 drivers/pci/Makefile                      |   1 +
 drivers/pci/bus.c                         |   9 +-
 drivers/pci/probe.c                       |   2 +
 drivers/pci/pwrctl/Kconfig                |  17 +
 drivers/pci/pwrctl/Makefile               |   4 +
 drivers/pci/pwrctl/core.c                 |  82 ++++
 drivers/pci/pwrctl/pci-pwrctl-pwrseq.c    |  83 ++++
 drivers/pci/remove.c                      |   2 +
 drivers/power/Kconfig                     |   1 +
 drivers/power/Makefile                    |   1 +
 drivers/power/sequencing/Kconfig          |  28 ++
 drivers/power/sequencing/Makefile         |   6 +
 drivers/power/sequencing/core.c           | 482 ++++++++++++++++++++++
 drivers/power/sequencing/pwrseq-qca6390.c | 232 +++++++++++
 include/linux/of.h                        |   4 +
 include/linux/pci-pwrctl.h                |  24 ++
 include/linux/pwrseq/consumer.h           |  53 +++
 include/linux/pwrseq/provider.h           |  41 ++
 22 files changed, 1229 insertions(+), 12 deletions(-)
 create mode 100644 drivers/pci/pwrctl/Kconfig
 create mode 100644 drivers/pci/pwrctl/Makefile
 create mode 100644 drivers/pci/pwrctl/core.c
 create mode 100644 drivers/pci/pwrctl/pci-pwrctl-pwrseq.c
 create mode 100644 drivers/power/sequencing/Kconfig
 create mode 100644 drivers/power/sequencing/Makefile
 create mode 100644 drivers/power/sequencing/core.c
 create mode 100644 drivers/power/sequencing/pwrseq-qca6390.c
 create mode 100644 include/linux/pci-pwrctl.h
 create mode 100644 include/linux/pwrseq/consumer.h
 create mode 100644 include/linux/pwrseq/provider.h

--
2.40.1

maintainer
#45 lore raw
In reply to Bartosz Golaszewski
Quoted 26 lines · Bartosz Golaszewski

From: Bartosz Golaszewski <[email protected]>

I'd like to preface the cover letter by saying right away that this series is not complete. It's an RFC that presents my approach and is sent to the list for discussion. There are no DT bindings nor docs in Documentation/ yet. Please review it as an RFC and not an upstreambound series. If the approach is accepted as correct, I'll add missing bits.

The RFC[1] presenting my proposed device-tree representation of the QCA6391 package present on the RB5 board - while not really officially accepted - was not outright rejected which is a good sign.

This series incorporates it and builds a proposed power sequencing subsystem together with the first dedicated driver around it. Then it adds first two users: the Bluetooth and WLAN modules of the QCA6391.

The Bluetooth part is pretty straightforward. The WLAN however is a PCIe device and as such needs to be powered-up *before* it's detected on the PCI bus. To that end, we modify the PCI core to instantiate platform devices for existing DT child nodes of the PCIe ports. For those nodes for which a power-sequencing driver exists, we bind it and let it probe. The driver then triggers a rescan of the PCI bus with the aim of detecting the now powered-on device. The device will consume the same DT node as the platform, power-sequencing device. We use device links to make the latter become the parent of the former.

Quoted 6 lines

The main advantage of the above approach (both for PCI as well as generic power sequencers) is that we don't introduce significant changes in DT bindings and don't introduce new properties. We merely define new resources.

[1] https://lore.kernel.org/all/CAMRc=MckG32DQv7b1AQL-mbnYdx4fsdYWtLwCyXc5Ma7EeSAKw@mail.gmail.com/T/#md5dc62007d12f6833d4e51658b14e0493954ba68

FWIW, booting RB5 with this patch series does give me working working WiFI. But I do see the following splat during boot:

[    5.880411] sysfs: cannot create duplicate filename '/devices/platform/soc@0/1c00000.pcie/pci0000:00/0000:00:00.0/resource0'
[    5.891938] CPU: 5 PID: 68 Comm: kworker/u16:4 Not tainted 6.8.0-rc2-next-20240131-00009-g079fdad54c8f #199
[    5.901927] Hardware name: Qualcomm Technologies, Inc. Robotics RB5 (DT)
[    5.908808] Workqueue: events_unbound async_run_entry_fn
[    5.914274] Call trace:
[    5.916794]  dump_backtrace+0xec/0x108
[    5.920649]  show_stack+0x18/0x24
[    5.924062]  dump_stack_lvl+0x50/0x68
[    5.927826]  dump_stack+0x18/0x24
[    5.931238]  sysfs_warn_dup+0x64/0x80
[    5.935004]  sysfs_create_bin_file+0xf4/0x130
[    5.939480]  pci_create_attr+0x100/0x168
[    5.943509]  pci_create_sysfs_dev_files+0x6c/0xc0
[    5.948337]  pci_bus_add_device+0x60/0x114
[    5.952551]  pci_bus_add_devices+0x4c/0x7c
[    5.956762]  pci_host_probe+0x138/0x188
[    5.960700]  dw_pcie_host_init+0x290/0x334
[    5.964914]  qcom_pcie_probe+0x1f8/0x23c
[    5.968942]  platform_probe+0xa8/0xd0
[    5.972707]  really_probe+0x130/0x2e4
[    5.976469]  __driver_probe_device+0xa0/0x128
[    5.980944]  driver_probe_device+0x3c/0x1f8
[    5.985245]  __device_attach_driver+0x118/0x140
[    5.989897]  bus_for_each_drv+0xf4/0x14c
[    5.993923]  __device_attach_async_helper+0x78/0xd0
[    5.998937]  async_run_entry_fn+0x24/0xdc
[    6.003051]  process_scheduled_works+0x210/0x328
[    6.007793]  worker_thread+0x28c/0x450
[    6.011642]  kthread+0xfc/0x184
[    6.014865]  ret_from_fork+0x10/0x20
[    6.018572] ------------[ cut here ]------------
[    6.023339] proc_dir_entry '0000:00/00.0' already registered

Regards,
Bjorn