Skip to contentSkip to conversation

pinctrl: msm: fix gpio-hog related boot issues

PATCH New Christian Lamparter 3 participants 6 messages Mar 28, 2018 – Apr 12, 2018

Subsystems (7)
lore
Share & tools
lore
#0 lore raw

PATCH 1/1 pinctrl: msm: fix gpio-hog related boot issues

Sven Eckelmann reported an issue with the current IPQ4019 pinctrl. Setting up any gpio-hog in the device-tree for his device would "kill the bootup completely":

| [    0.477838] msm_serial 78af000.serial: could not find pctldev for node /soc/pinctrl at 1000000/serial_pinmux, deferring probe
| [    0.499828] spi_qup 78b5000.spi: could not find pctldev for node /soc/pinctrl at 1000000/spi_0_pinmux, deferring probe
| [    1.298883] requesting hog GPIO enable USB2 power (chip 1000000.pinctrl, offset 58) failed, -517
| [    1.299609] gpiochip_add_data: GPIOs 0..99 (1000000.pinctrl) failed to register
| [    1.308589] ipq4019-pinctrl 1000000.pinctrl: Failed register gpiochip
| [    1.316586] msm_serial 78af000.serial: could not find pctldev for node /soc/pinctrl at 1000000/serial_pinmux, deferring probe
| [    1.322415] spi_qup 78b5000.spi: could not find pctldev for node /soc/pinctrl at 1000000/spi_0_pinmux, deferri

This was also verified on a RT-AC58U (IPQ4018) which would no longer boot, if a gpio-hog was specified. (Tried forcing the USB LED PIN (GPIO0) to high.).

The problem is that Pinctrl+GPIO registration is currently peformed in the following order in pinctrl-msm.c:
1. pinctrl_register()
2. gpiochip_add()
3. gpiochip_add_pin_range()

The actual error code -517 == -EPROBE_DEFER is coming from pinctrl_get_device_gpio_range(), which is called through:

        gpiochip_add
            of_gpiochip_add
                of_gpiochip_scan_gpios
                    gpiod_hog
                        gpiochip_request_own_desc
                            __gpiod_request
                                chip->request
                                    gpiochip_generic_request
                                       pinctrl_gpio_request
                                          pinctrl_get_device_gpio_range

pinctrl_get_device_gpio_range() is unable to find any valid pin ranges, since nothing has been added to the pinctrldev_list yet. so the range can't be found, and the operation fails with -EPROBE_DEFER.

This patch fixes the issue by adding the "gpio-ranges" property to the pinctrl device node of all upstream Qcom SoC, so the ranges are added by of_gpiochip_add_pin_range(), which is called by of_gpiochip_add() before the call to of_gpiochip_scan_gpios() happens.gpiochip_add_pin_range() is longer needed and removed (to prevent adding the same entry to the pinctrldev_list twice).

Cc stable at vger.kernel.org

---
The msm8998 would need something like

	gpio-ranges = <&tlmm 0 0 150>;
---
 arch/arm/boot/dts/qcom-apq8064.dtsi   | 1 +
 arch/arm/boot/dts/qcom-apq8084.dtsi   | 1 +
 arch/arm/boot/dts/qcom-ipq4019.dtsi   | 1 +
 arch/arm/boot/dts/qcom-ipq8064.dtsi   | 1 +
 arch/arm/boot/dts/qcom-mdm9615.dtsi   | 1 +
 arch/arm/boot/dts/qcom-msm8660.dtsi   | 1 +
 arch/arm/boot/dts/qcom-msm8960.dtsi   | 1 +
 arch/arm/boot/dts/qcom-msm8974.dtsi   | 1 +
 arch/arm64/boot/dts/qcom/ipq8074.dtsi | 3 ++-
 arch/arm64/boot/dts/qcom/msm8916.dtsi | 1 +
 arch/arm64/boot/dts/qcom/msm8992.dtsi | 1 +
 arch/arm64/boot/dts/qcom/msm8994.dtsi | 1 +
 arch/arm64/boot/dts/qcom/msm8996.dtsi | 1 +
 drivers/pinctrl/qcom/pinctrl-msm.c    | 7 -------
 14 files changed, 14 insertions(+), 8 deletions(-)
arch/arm/boot/dts/qcom-apq8064.dtsi +1 -0
index 3ca96e361878..17ad9cbd9f8c 100644
@@ -327,6 +327,7 @@
 			reg = <0x800000 0x4000>;
 
 			gpio-controller;
+			gpio-ranges = <&tlmm_pinmux 0 0 90>;
 			#gpio-cells = <2>;
 			interrupt-controller;
 			#interrupt-cells = <2>;
arch/arm/boot/dts/qcom-apq8084.dtsi +1 -0
index 0e1e98707e3f..d9481d083802 100644
@@ -396,6 +396,7 @@
 			compatible = "qcom,apq8084-pinctrl";
 			reg = <0xfd510000 0x4000>;
 			gpio-controller;
+			gpio-ranges = <&tlmm 0 0 147>;
 			#gpio-cells = <2>;
 			interrupt-controller;
 			#interrupt-cells = <2>;
arch/arm/boot/dts/qcom-ipq4019.dtsi +1 -0
index c1e65aaf3cad..d85b15774c64 100644
@@ -147,6 +147,7 @@
 			compatible = "qcom,ipq4019-pinctrl";
 			reg = <0x01000000 0x300000>;
 			gpio-controller;
+			gpio-ranges = <&tlmm 0 0 100>;
 			#gpio-cells = <2>;
 			interrupt-controller;
 			#interrupt-cells = <2>;
arch/arm/boot/dts/qcom-ipq8064.dtsi +1 -0
index 1e0a3b446f7a..26eab9a68d90 100644
@@ -108,6 +108,7 @@
 			reg = <0x800000 0x4000>;
 
 			gpio-controller;
+			gpio-ranges = <&qcom_pinmux 0 0 69>;
 			#gpio-cells = <2>;
 			interrupt-controller;
 			#interrupt-cells = <2>;
arch/arm/boot/dts/qcom-mdm9615.dtsi +1 -0
index c852b69229c9..cfdaca5f259a 100644
@@ -128,6 +128,7 @@
 		msmgpio: pinctrl at 800000 {
 			compatible = "qcom,mdm9615-pinctrl";
 			gpio-controller;
+			gpio-ranges = <&msmgpio 0 0 88>;
 			#gpio-cells = <2>;
 			interrupts = <GIC_SPI 16 IRQ_TYPE_LEVEL_HIGH>;
 			interrupt-controller;
arch/arm/boot/dts/qcom-msm8660.dtsi +1 -0
index 33030f9419fe..47cf9c4ca062 100644
@@ -110,6 +110,7 @@
 			reg = <0x800000 0x4000>;
 
 			gpio-controller;
+			gpio-ranges = <&tlmm 0 0 173>;
 			#gpio-cells = <2>;
 			interrupts = <0 16 0x4>;
 			interrupt-controller;
arch/arm/boot/dts/qcom-msm8960.dtsi +1 -0
index 1733d8f40ab1..f6d8b1af5a8a 100644
@@ -102,6 +102,7 @@
 		msmgpio: pinctrl at 800000 {
 			compatible = "qcom,msm8960-pinctrl";
 			gpio-controller;
+			gpio-ranges = <&msmgpio 0 0 152>;
 			#gpio-cells = <2>;
 			interrupts = <0 16 0x4>;
 			interrupt-controller;
arch/arm/boot/dts/qcom-msm8974.dtsi +1 -0
index d9019a49b292..1250e071a6e2 100644
@@ -696,6 +696,7 @@
 			compatible = "qcom,msm8974-pinctrl";
 			reg = <0xfd510000 0x4000>;
 			gpio-controller;
+			gpio-ranges = <&msmgpio 0 0 146>;
 			#gpio-cells = <2>;
 			interrupt-controller;
 			#interrupt-cells = <2>;
arch/arm64/boot/dts/qcom/ipq8074.dtsi +2 -1
index 2bc5dec5614d..d2c36b467466 100644
@@ -24,11 +24,12 @@
 		ranges = <0 0 0 0xffffffff>;
 		compatible = "simple-bus";
 
-		pinctrl at 1000000 {
+		tlmm: pinctrl at 1000000 {
 			compatible = "qcom,ipq8074-pinctrl";
 			reg = <0x1000000 0x300000>;
 			interrupts = <GIC_SPI 208 IRQ_TYPE_LEVEL_HIGH>;
 			gpio-controller;
+			gpio-ranges = <&tlmm 0 0 70>;
 			#gpio-cells = <0x2>;
 			interrupt-controller;
 			#interrupt-cells = <0x2>;
arch/arm64/boot/dts/qcom/msm8916.dtsi +1 -0
index e51b04900726..e06cb90c8ec3 100644
@@ -281,6 +281,7 @@
 			reg = <0x1000000 0x300000>;
 			interrupts = <GIC_SPI 208 IRQ_TYPE_LEVEL_HIGH>;
 			gpio-controller;
+			gpio-ranges = <&msmgpio 0 0 122>;
 			#gpio-cells = <2>;
 			interrupt-controller;
 			#interrupt-cells = <2>;
arch/arm64/boot/dts/qcom/msm8992.dtsi +1 -0
index 171578747ed0..173b6bc60816 100644
@@ -179,6 +179,7 @@
 			reg = <0xfd510000 0x4000>;
 			interrupts = <GIC_SPI 208 IRQ_TYPE_LEVEL_HIGH>;
 			gpio-controller;
+			gpio-ranges = <&msmgpio 0 0 146>;
 			#gpio-cells = <2>;
 			interrupt-controller;
 			#interrupt-cells = <2>;
arch/arm64/boot/dts/qcom/msm8994.dtsi +1 -0
index f33c41d01c86..68705db4696b 100644
@@ -141,6 +141,7 @@
 			reg = <0xfd510000 0x4000>;
 			interrupts = <GIC_SPI 208 IRQ_TYPE_LEVEL_HIGH>;
 			gpio-controller;
+			gpio-ranges = <&msmgpio 0 0 146>;
 			#gpio-cells = <2>;
 			interrupt-controller;
 			#interrupt-cells = <2>;
arch/arm64/boot/dts/qcom/msm8996.dtsi +1 -0
index 0a6f7952bbb1..18511e782cbd 100644
@@ -530,6 +530,7 @@
 			reg = <0x01010000 0x300000>;
 			interrupts = <GIC_SPI 208 IRQ_TYPE_LEVEL_HIGH>;
 			gpio-controller;
+			gpio-ranges = <&msmgpio 0 0 150>;
 			#gpio-cells = <2>;
 			interrupt-controller;
 			#interrupt-cells = <2>;
drivers/pinctrl/qcom/pinctrl-msm.c +0 -7
index 495432f3341b..f2580bbba741 100644
@@ -831,13 +831,6 @@ static int msm_gpio_init(struct msm_pinctrl *pctrl)
 		return ret;
 	}
 
-	ret = gpiochip_add_pin_range(&pctrl->chip, dev_name(pctrl->dev), 0, 0, chip->ngpio);
-	if (ret) {
-		dev_err(pctrl->dev, "Failed to add pin range\n");
-		gpiochip_remove(&pctrl->chip);
-		return ret;
-	}
-
 	ret = gpiochip_irqchip_add(chip,
 				   &msm_gpio_irq_chip,
 				   0,
Signature · 1 line
2.16.3
#1 lore raw

PATCH 1/1 pinctrl: msm: fix gpio-hog related boot issues

Quoted 12 lines · Christian Lamparter

Sven Eckelmann reported an issue with the current IPQ4019 pinctrl. Setting up any gpio-hog in the device-tree for his device would "kill the bootup completely":

| [    0.477838] msm_serial 78af000.serial: could not find pctldev for node /soc/pinctrl at 1000000/serial_pinmux, deferring probe
| [    0.499828] spi_qup 78b5000.spi: could not find pctldev for node /soc/pinctrl at 1000000/spi_0_pinmux, deferring probe
| [    1.298883] requesting hog GPIO enable USB2 power (chip 1000000.pinctrl, offset 58) failed, -517
| [    1.299609] gpiochip_add_data: GPIOs 0..99 (1000000.pinctrl) failed to register
| [    1.308589] ipq4019-pinctrl 1000000.pinctrl: Failed register gpiochip
| [    1.316586] msm_serial 78af000.serial: could not find pctldev for node /soc/pinctrl at 1000000/serial_pinmux, deferring probe
| [    1.322415] spi_qup 78b5000.spi: could not find pctldev for node /soc/pinctrl at 1000000/spi_0_pinmux, deferri
Quoted 4 lines

This was also verified on a RT-AC58U (IPQ4018) which would no longer boot, if a gpio-hog was specified. (Tried forcing the USB LED PIN (GPIO0) to high.).

It's quite clear that this is a generic issue with the msm pinctrl driver.

For the cases where I've been in need of static configuration of certain pins I've simply made the pinctrl node itself have a pinctrl-0 that refer to a state that I want to hold. This has worked well and I didn't even know about the gpio-hog property.

[..]

arch/arm/boot/dts/qcom-apq8064.dtsi line 330

Quoted 9 lines
arch/arm/boot/dts/qcom-apq8064.dtsi +1 -0
index 3ca96e361878..17ad9cbd9f8c 100644
@@ -327,6 +327,7 @@
 			reg = <0x800000 0x4000>;
 
 			gpio-controller;
+			gpio-ranges = <&tlmm_pinmux 0 0 90>;

This seems reasonable.

Quoted 3 lines
arch/arm/boot/dts/qcom-apq8064.dtsi +0 -0
 			#gpio-cells = <2>;
 			interrupt-controller;
 			#interrupt-cells = <2>;

[..]

Quoted 5 lines
drivers/pinctrl/qcom/pinctrl-msm.c +0 -0
index 495432f3341b..f2580bbba741 100644

drivers/pinctrl/qcom/pinctrl-msm.c static int msm_gpio_init(struct msm_pinctrl *pctrl) · line 840

Quoted 10 lines
drivers/pinctrl/qcom/pinctrl-msm.c +0 -7
@@ -831,13 +831,6 @@ static int msm_gpio_init(struct msm_pinctrl *pctrl)
 		return ret;
 	}
 
-	ret = gpiochip_add_pin_range(&pctrl->chip, dev_name(pctrl->dev), 0, 0, chip->ngpio);
-	if (ret) {
-		dev_err(pctrl->dev, "Failed to add pin range\n");
-		gpiochip_remove(&pctrl->chip);
-		return ret;
-	}
-

But, this will break backwards compatibility with existing DTBs and I don't see how this would work with the ACPI based platforms using this driver.

Iirc this driver follows the same pattern as several other pinctrl drivers providing gpios, how are they handling this?

Regards,
Bjorn

#2 lore raw

PATCH 1/1 pinctrl: msm: fix gpio-hog related boot issues

Quoted 14 lines · On Thu 29 Mar 2018 02:27:23 CEST Bjorn Andersson wrote:
Quoted 12 lines · Christian Lamparter

Sven Eckelmann reported an issue with the current IPQ4019 pinctrl. Setting up any gpio-hog in the device-tree for his device would "kill the bootup completely":

| [    0.477838] msm_serial 78af000.serial: could not find pctldev for node /soc/pinctrl at 1000000/serial_pinmux, deferring probe
| [    0.499828] spi_qup 78b5000.spi: could not find pctldev for node /soc/pinctrl at 1000000/spi_0_pinmux, deferring probe
| [    1.298883] requesting hog GPIO enable USB2 power (chip 1000000.pinctrl, offset 58) failed, -517
| [    1.299609] gpiochip_add_data: GPIOs 0..99 (1000000.pinctrl) failed to register
| [    1.308589] ipq4019-pinctrl 1000000.pinctrl: Failed register gpiochip
| [    1.316586] msm_serial 78af000.serial: could not find pctldev for node /soc/pinctrl at 1000000/serial_pinmux, deferring probe
| [    1.322415] spi_qup 78b5000.spi: could not find pctldev for node /soc/pinctrl at 1000000/spi_0_pinmux, deferri
Quoted 8 lines
Quoted 4 lines

This was also verified on a RT-AC58U (IPQ4018) which would no longer boot, if a gpio-hog was specified. (Tried forcing the USB LED PIN (GPIO0) to high.).

It's quite clear that this is a generic issue with the msm pinctrl driver.
From what I understand it's not only the msm-pinctrl. All pinctrl and gpio

drivers that support a DT binding but use gpiochip_add_pin_range as the sole way to add the ranges. I made a (probably incomplete) list in the thread by Sven: <https://lkml.kernel.org/r/46130418.GjRpGRXmAF@debian64>

Quoted 4 lines

For the cases where I've been in need of static configuration of certain pins I've simply made the pinctrl node itself have a pinctrl-0 that refer to a state that I want to hold. This has worked well and I didn't even know about the gpio-hog property.

yes, that will work too.

One advantage of the gpio-hog is that it will also request the gpio properly. So it cannot be exported (and changed) without getting rid of the gpio-hog first. It also allows to specify a user-friendly line-name that shows up in various places.

i.e.:

|root at mbl:/# cat /sys/kernel/debug/gpio 
|gpiochip1: GPIOs 472-479, parent: platform/4e0000000.gpio1, 4e0000000.gpio1:
| gpio-472 (                    |enable EMAC PHY     ) out hi    
| gpio-475 (                    |Power Drive Port 1  ) out hi  
|
Quoted 25 lines

[..]

arch/arm/boot/dts/qcom-apq8064.dtsi line 330

Quoted 9 lines
arch/arm/boot/dts/qcom-apq8064.dtsi +1 -0
index 3ca96e361878..17ad9cbd9f8c 100644
@@ -327,6 +327,7 @@
 			reg = <0x800000 0x4000>;
 
 			gpio-controller;
+			gpio-ranges = <&tlmm_pinmux 0 0 90>;

This seems reasonable.

Quoted 3 lines
arch/arm/boot/dts/qcom-apq8064.dtsi +0 -0
 			#gpio-cells = <2>;
 			interrupt-controller;
 			#interrupt-cells = <2>;

[..]

Quoted 8 lines
drivers/pinctrl/qcom/pinctrl-msm.c +0 -0
index 495432f3341b..f2580bbba741 100644
@@ -831,13 +831,6 @@ static int msm_gpio_init(struct msm_pinctrl *pctrl)
 		return ret;
 	}
 
Quoted 11 lines

drivers/pinctrl/qcom/pinctrl-msm.c static int msm_gpio_init(struct msm_pinctrl *pctrl) · line 840

Quoted 7 lines
drivers/pinctrl/qcom/pinctrl-msm.c +0 -7
-	ret = gpiochip_add_pin_range(&pctrl->chip, dev_name(pctrl->dev), 0, 0, chip->ngpio);
-	if (ret) {
-		dev_err(pctrl->dev, "Failed to add pin range\n");
-		gpiochip_remove(&pctrl->chip);
-		return ret;
-	}
-

But, this will break backwards compatibility with existing DTBs and I don't see how this would work with the ACPI based platforms using this driver.

Ok I see, I was aware of ACPI but not that a pinctrl-msm based driver is using it. Well, I thinks is possible to use is_acpi_device_node() or !is_of_node() to detect whenever we are dealing with a OF or not:

would it be ok to do something like this?

|       if (!is_of_node(chip->of_node)) {
|					/*
|					 * (lengthy note about gpiochip_add_pin_range and OF with
|					 * reference to Documentation/devicetree/bindings/gpio/gpio.txt
|					 * - TBD)
|					 */
|					ret = gpiochip_add_pin_range(&pctrl->chip,
|					[...]
|		}
Quoted 2 lines

Iirc this driver follows the same pattern as several other pinctrl drivers providing gpios, how are they handling this?

Well, my commit message was based on a similar patch done by Geert Uytterhoeven <[email protected]> for the sh73a0:
<https://marc.info/?l=git-commits-head&m=144114029919118&w=2>

Another one was this patch from Linus:
<https://patches.linaro.org/patch/51382/>

and there are many more (basically git blame on every .dts* in arch/ that already has a gpio-ranges property.)

Regards,
Christian

#3 lore raw

PATCH 1/1 pinctrl: msm: fix gpio-hog related boot issues

Quoted 7 lines · On Thu 29 Mar 2018 14:23:35 CEST Christian Lamparter wrote:

Ok I see, I was aware of ACPI but not that a pinctrl-msm based driver is using it. Well, I thinks is possible to use is_acpi_device_node() or !is_of_node() to detect whenever we are dealing with a OF or not:

would it be ok to do something like this?

| if (!is_of_node(chip->of_node)) {

oops, this should be:

			if (!is_of_node(pctrl->dev->fwnode)) {
Quoted 8 lines
|					/*
|					 * (lengthy note about gpiochip_add_pin_range and OF with
|					 * reference to Documentation/devicetree/bindings/gpio/gpio.txt
|					 * - TBD)
|					 */
|					ret = gpiochip_add_pin_range(&pctrl->chip,
|					[...]
|		}
#4 lore raw

PATCH 1/1 pinctrl: msm: fix gpio-hog related boot issues

In reply to Christian Lamparter
Quoted 7 lines · Christian Lamparter

This patch fixes the issue by adding the "gpio-ranges" property to the pinctrl device node of all upstream Qcom SoC, so the ranges are added by of_gpiochip_add_pin_range(), which is called by of_gpiochip_add() before the call to of_gpiochip_scan_gpios() happens.gpiochip_add_pin_range() is longer needed and removed (to prevent adding the same entry to the pinctrldev_list twice).

That's pretty neat!

Quoted 2 lines
                        gpio-controller;

+ gpio-ranges = <&tlmm_pinmux 0 0 90>;

nice!

drivers/pinctrl/qcom/pinctrl-msm.c static int msm_gpio_init(struct msm_pinctrl *pctrl) · line 839

Quoted 6 lines
drivers/pinctrl/qcom/pinctrl-msm.c +0 -6
-       ret = gpiochip_add_pin_range(&pctrl->chip, dev_name(pctrl->dev), 0, 0, chip->ngpio);
-       if (ret) {
-               dev_err(pctrl->dev, "Failed to add pin range\n");
-               gpiochip_remove(&pctrl->chip);
-               return ret;
-       }

If you instead of deleteing this, just wrap it inside something like:

if (!of_property_read_bool(np, "gpio-ranges") {
(...)
}

You will stay compatible with elder device trees, solving Bj?rns issue. You will only be adding hogs to newer device trees with the ranges defined anyway.

Be genereous with comments in the code if you choose this approach so everyone realize what is going on.

Yours,
Linus Walleij

#5 lore raw

PATCH 1/1 pinctrl: msm: fix gpio-hog related boot issues

Quoted 16 lines · On Donnerstag, 12. April 2018 14:48:56 CEST Linus Walleij wrote:

drivers/pinctrl/qcom/pinctrl-msm.c static int msm_gpio_init(struct msm_pinctrl *pctrl) · line 839

Quoted 6 lines · Christian Lamparter
drivers/pinctrl/qcom/pinctrl-msm.c +0 -6
-       ret = gpiochip_add_pin_range(&pctrl->chip, dev_name(pctrl->dev), 0, 0, chip->ngpio);
-       if (ret) {
-               dev_err(pctrl->dev, "Failed to add pin range\n");
-               gpiochip_remove(&pctrl->chip);
-               return ret;
-       }

If you instead of deleteing this, just wrap it inside something like:

if (!of_property_read_bool(np, "gpio-ranges") {
(...)
}

Quoted 6 lines

You will stay compatible with elder device trees, solving Bj?rns issue. You will only be adding hogs to newer device trees with the ranges defined anyway.

Be genereous with comments in the code if you choose this approach so everyone realize what is going on.

Thank you for your insightful advice. I just sent out v4 which goes the of_property_read_bool route. Let's wait and see what kbuilt-bot has to say.

Best Regards,
Christian