Skip to contentSkip to conversation

Add RP1 PWM controller support

PATCH Superseded Andrea della Porta 5 participants 15 messages Jul 20 – Sep 4

Subsystems (4)

v7 of 12 Superseded Latest is v12 →

lore
Share & tools
lore

Andrea della Porta

author maintainer
#0 lore raw

v7 cover Add RP1 PWM controller support

This patchset adds support for the PWM controller found on the Raspberry Pi RP1 southbridge. This is necessary to operate the cooling fan connected to one of the PWM channels.

The tachometer pin for the fan speed is managed by the firmware running on the RP1's M-core. It uses the PHASE2 register to report the RPM, which is then exported by this driver via syscon registers. A subsequent patch will add a new device and driver to read the RPM and export this value via hwmon.

Subsequent patches will also add the CPU thermal zone, which acts as a consumer of the PWM device.

Best regards,
Andrea

CHANGES in V7:

- _tohw(): use *wfhw = (typeof(*wfhw)){...} to initialize the structure in the disable case
- _tohw(): fixed the offset_ticks calculation
- _fromhw(): fixed a rounding error in the duty_offset_ns calculation
- _write_waveform(): dropped the goto in favor of return in diasble channel exit path
- _read_waveform(): use *wfhw = (typeof(*wfhw)){...} to initialize the structure in the disable case
- dropped rp1_pwm_remove() since this driver depends on syscon and cannot be removed/unbound (added a comment to explain that)

Naushir Patuck (2):
dt-bindings: pwm: Add Raspberry Pi RP1 PWM controller
pwm: rp1: Add RP1 PWM controller driver

Stanimir Varbanov (1):
arm64: dts: broadcom: rpi-5: Add RP1 PWM node

 .../bindings/pwm/raspberrypi,rp1-pwm.yaml     |  66 +++
 .../boot/dts/broadcom/bcm2712-rpi-5-b.dts     |  12 +
 arch/arm64/boot/dts/broadcom/rp1-common.dtsi  |   9 +
 drivers/pwm/Kconfig                           |   9 +
 drivers/pwm/Makefile                          |   1 +
 drivers/pwm/pwm-rp1.c                         | 428 ++++++++++++++++++
 6 files changed, 525 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/pwm/raspberrypi,rp1-pwm.yaml
 create mode 100644 drivers/pwm/pwm-rp1.c
Signature · 1 line
2.35.3
author maintainer
#1 lore raw

PATCH v7 1/3 dt-bindings: pwm: Add Raspberry Pi RP1 PWM controller

From: Naushir Patuck <[email protected]>

Add the devicetree binding documentation for the PWM controller found in the Raspberry Pi RP1 chipset.

---
 .../bindings/pwm/raspberrypi,rp1-pwm.yaml     | 66 +++++++++++++++++++
 1 file changed, 66 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/pwm/raspberrypi,rp1-pwm.yaml
Documentation/devicetree/bindings/pwm/raspberrypi,rp1-pwm.yaml new file +66 -0
new file mode 100644
index 0000000000000..970d0f3b33bbb
@@ -0,0 +1,66 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/pwm/raspberrypi,rp1-pwm.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Raspberry Pi RP1 PWM controller
+
+maintainers:
+  - Naushir Patuck <[email protected]>
+  - Andrea della Porta <[email protected]>
+  - Stanimir Varbanov <[email protected]>
+
+allOf:
+  - $ref: pwm.yaml#
+
+description: |
+  The PWM peripheral is a flexible waveform generator with a
+  variety of operational modes. It has the following features:
+   - four independent output channels
+   - 32-bit counter widths
+   - Seven output generation modes
+   - Optional per-channel output inversion
+   - Optional duty-cycle data FIFO with DMA support
+   - Optional sigma-delta noise shaping engine
+  Serves as a fan speed provider to other nodes for a PWM-connected
+  fan using shared registers (syscon).
+
+properties:
+  compatible:
+    const: raspberrypi,rp1-pwm
+
+  reg:
+    maxItems: 1
+
+  clocks:
+    maxItems: 1
+
+  "#pwm-cells":
+    const: 3
+
+  dmas:
+    maxItems: 1
+    description: |
+      Phandle to the DMA controller and the channel specifier for
+      the duty-cycle FIFO.
+
+  dma-names:
+    items:
+      - const: tx
+
+required:
+  - compatible
+  - reg
+  - clocks
+
+unevaluatedProperties: false
+
+examples:
+  - |
+    pwm@98000 {
+      compatible = "raspberrypi,rp1-pwm";
+      reg = <0x98000 0x100>;
+      clocks = <&rp1_clocks 17>;
+      #pwm-cells = <3>;
+    };
Signature · 1 line
2.35.3
#2 lore raw

Re: [PATCH v7 1/3] dt-bindings: pwm: Add Raspberry Pi RP1 PWM controller

Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider: - [Medium] The binding description states the device acts as a syscon provider for shared registers, but…

Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [Medium] The binding description states the device acts as a syscon provider for shared registers, but the schema prohibits the use of the "syscon" compatible string. --

--- Patch [1]: [PATCH v7 1/3] dt-bindings: pwm: Add Raspberry Pi RP1 PWM controller --- commit 06ebdbe78362ab02ea5e88d503ad7c179855b48a
Author: Naushir Patuck <[email protected]>

dt-bindings: pwm: Add Raspberry Pi RP1 PWM controller

This commit adds the devicetree binding documentation for the PWM controller found in the Raspberry Pi RP1 chipset.

Quoted 5 lines
Documentation/devicetree/bindings/pwm/raspberrypi,rp1-pwm.yaml new file +0 -0
new file mode 100644
@@ -0,0 +1,66 @@

[ ... ]

Quoted 5 lines
Documentation/devicetree/bindings/pwm/raspberrypi,rp1-pwm.yaml new file +5 -0
+description: |
+  The PWM peripheral is a flexible waveform generator with a
+  variety of operational modes. It has the following features:
+   - four independent output channels
+   - 32-bit counter widths

Documentation/devicetree/bindings/pwm/raspberrypi,rp1-pwm.yaml line 31

Quoted 10 lines
Documentation/devicetree/bindings/pwm/raspberrypi,rp1-pwm.yaml new file +10 -0
+   - Seven output generation modes
+   - Optional per-channel output inversion
+   - Optional duty-cycle data FIFO with DMA support
+   - Optional sigma-delta noise shaping engine
+  Serves as a fan speed provider to other nodes for a PWM-connected
+  fan using shared registers (syscon).
+
+properties:
+  compatible:
+    const: raspberrypi,rp1-pwm

[Severity: Medium]
The description states this device acts as a syscon provider for shared registers, but the compatible property is restricted to a single string.

Will device tree validation fail if a user includes the "syscon" string normally required for standard kernel syscon lookup APIs alongside the "raspberrypi,rp1-pwm" compatible string?

Signature · 1 line
Sashiko AI review · https://sashiko.dev/#/patchset/[email protected]?part=1
author maintainer
#3 lore raw

Re: [PATCH v7 1/3] dt-bindings: pwm: Add Raspberry Pi RP1 PWM controller

Hi,

Quoted 41 lines · On 09:50 Mon 20 Jul , [email protected] wrote:

Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [Medium] The binding description states the device acts as a syscon provider for shared registers, but the schema prohibits the use of the "syscon" compatible string. --

--- Patch [1]: [PATCH v7 1/3] dt-bindings: pwm: Add Raspberry Pi RP1 PWM controller --- commit 06ebdbe78362ab02ea5e88d503ad7c179855b48a
Author: Naushir Patuck <[email protected]>

dt-bindings: pwm: Add Raspberry Pi RP1 PWM controller

This commit adds the devicetree binding documentation for the PWM controller found in the Raspberry Pi RP1 chipset.

Quoted 5 lines
Documentation/devicetree/bindings/pwm/raspberrypi,rp1-pwm.yaml new file +0 -0
new file mode 100644
@@ -0,0 +1,66 @@

[ ... ]

Quoted 5 lines
Documentation/devicetree/bindings/pwm/raspberrypi,rp1-pwm.yaml new file +5 -0
+description: |
+  The PWM peripheral is a flexible waveform generator with a
+  variety of operational modes. It has the following features:
+   - four independent output channels
+   - 32-bit counter widths

Documentation/devicetree/bindings/pwm/raspberrypi,rp1-pwm.yaml line 31

Quoted 10 lines
Documentation/devicetree/bindings/pwm/raspberrypi,rp1-pwm.yaml new file +10 -0
+   - Seven output generation modes
+   - Optional per-channel output inversion
+   - Optional duty-cycle data FIFO with DMA support
+   - Optional sigma-delta noise shaping engine
+  Serves as a fan speed provider to other nodes for a PWM-connected
+  fan using shared registers (syscon).
+
+properties:
+  compatible:
+    const: raspberrypi,rp1-pwm

[Severity: Medium]
The description states this device acts as a syscon provider for shared registers, but the compatible property is restricted to a single string.

Quoted 3 lines

Will device tree validation fail if a user includes the "syscon" string normally required for standard kernel syscon lookup APIs alongside the "raspberrypi,rp1-pwm" compatible string?

I deliberately chose not to include 'syscon' in the 'compatible' property to retain the flexibility to constrain the regmap exported through syscon in the future.
Including 'syscon' in the producer's compatible string causes the syscon framework to register the entire 'reg' property range, whereas the driver uses of_syscon_register_regmap(), which could restrict the regmap later on.

Additionally, the fact that a specific register is used as a tachometer depends solely on the firmware; if this changes in the future, the syscon requirement might go away. Therefore, we might not want 'syscon' in the compatible string at all.

Thanks,
Andrea

Quoted 3 lines
Signature · 2 lines
-- 
Sashiko AI review · https://sashiko.dev/#/patchset/[email protected]?part=1
author maintainer
#4 lore raw

PATCH v7 2/3 pwm: rp1: Add RP1 PWM controller driver

In reply to Andrea della Porta

From: Naushir Patuck <[email protected]>

The Raspberry Pi RP1 southbridge features an embedded PWM controller with 4 output channels, alongside an RPM interface to read the fan speed on the Raspberry Pi 5.

Add the supporting driver.

---
 drivers/pwm/Kconfig   |   9 +
 drivers/pwm/Makefile  |   1 +
 drivers/pwm/pwm-rp1.c | 428 ++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 438 insertions(+)
 create mode 100644 drivers/pwm/pwm-rp1.c
drivers/pwm/Kconfig +9 -0
index e8886a9b64d96..0373dcf8d400d 100644
@@ -637,6 +637,15 @@ config PWM_ROCKCHIP
 	  Generic PWM framework driver for the PWM controller found on
 	  Rockchip SoCs.
 
+config PWM_RASPBERRYPI_RP1
+	tristate "RP1 PWM support"
+	depends on MISC_RP1 || COMPILE_TEST
+	depends on HAS_IOMEM
+	select REGMAP_MMIO
+	select MFD_SYSCON
+	help
+	  PWM framework driver for Raspberry Pi RP1 controller.
+
 config PWM_SAMSUNG
 	tristate "Samsung PWM support"
 	depends on PLAT_SAMSUNG || ARCH_S5PV210 || ARCH_EXYNOS || COMPILE_TEST
drivers/pwm/Makefile +1 -0
index 5630a521a7cff..c07fd24f69f39 100644
@@ -57,6 +57,7 @@ obj-$(CONFIG_PWM_RENESAS_RZG2L_GPT)	+= pwm-rzg2l-gpt.o
 obj-$(CONFIG_PWM_RENESAS_RZ_MTU3)	+= pwm-rz-mtu3.o
 obj-$(CONFIG_PWM_RENESAS_TPU)	+= pwm-renesas-tpu.o
 obj-$(CONFIG_PWM_ROCKCHIP)	+= pwm-rockchip.o
+obj-$(CONFIG_PWM_RASPBERRYPI_RP1)	+= pwm-rp1.o
 obj-$(CONFIG_PWM_SAMSUNG)	+= pwm-samsung.o
 obj-$(CONFIG_PWM_SIFIVE)	+= pwm-sifive.o
 obj-$(CONFIG_PWM_SL28CPLD)	+= pwm-sl28cpld.o
drivers/pwm/pwm-rp1.c new file +428 -0

428 lines not on this page · raw message

Signature · 1 line
2.35.3
#5 lore raw

Re: [PATCH v7 2/3] pwm: rp1: Add RP1 PWM controller driver

Thank you for your contribution! Sashiko AI review found 3 potential issue(s) to consider: - [High] Missing `.remove` callback leads to Use-After-Free in the PWM and Syscon cores and leaks clock…

Thank you for your contribution! Sashiko AI review found 3 potential issue(s) to consider:
- [High] Missing .remove callback leads to Use-After-Free in the PWM and Syscon cores and leaks clock resources on driver unbind.
- [High] Register context loss on suspend/resume silently breaks PWM output.
- [High] Unclamped hardware duty ticks lead to integer underflow in the PWM core for normal polarity.
--

--- Patch [2]: [PATCH v7 2/3] pwm: rp1: Add RP1 PWM controller driver --- commit 0c98703d857577902e57d25b42a3d46dfbde5795
Author: Naushir Patuck <[email protected]>

pwm: rp1: Add RP1 PWM controller driver

The Raspberry Pi RP1 southbridge features an embedded PWM controller with 4 output channels, alongside an RPM interface to read the fan speed on the Raspberry Pi 5. Add the supporting driver.

Quoted 4 lines
drivers/pwm/pwm-rp1.c new file +0 -0
new file mode 100644

[ ... ]

Quoted 12 lines
drivers/pwm/pwm-rp1.c new file +12 -0
+static int rp1_pwm_round_waveform_fromhw(struct pwm_chip *chip,
+					 struct pwm_device *pwm,
+					 const void *_wfhw,
+					 struct pwm_waveform *wf)
+{
+	struct rp1_pwm *rp1 = pwmchip_get_drvdata(chip);
+	const struct rp1_pwm_waveform *wfhw = _wfhw;
+	u64 clk_rate = rp1->clk_rate;
+	u64 ticks;
+
+	*wf = (struct pwm_waveform){ };
+

drivers/pwm/pwm-rp1.c line 198

Quoted 10 lines
drivers/pwm/pwm-rp1.c new file +10 -0
+	if (!wfhw->enabled)
+		return 0;
+
+	wf->period_length_ns = DIV_ROUND_UP_ULL(((u64)wfhw->period_ticks + 1) * NSEC_PER_SEC,
+						clk_rate);
+
+	if (!wfhw->inverted_polarity) {
+		wf->duty_length_ns = DIV_ROUND_UP_ULL((u64)wfhw->duty_ticks * NSEC_PER_SEC,
+						      (u32)clk_rate);
+	} else {

[Severity: High]
Does the normal polarity case need to clamp the duty ticks similar to the inverted polarity case?

If the bootloader configures a continuous-high state where the raw hardware duty ticks exceed the period ticks + 1, this path calculates a duty_length_ns that is strictly greater than the period_length_ns.

When the PWM core subsequently reads this initial state, pwm_wf2state() handles duty > period by treating it as an inverted polarity and calculating duty_cycle = period - duty_length_ns. This subtraction can silently underflow, causing the core to interpret the hardware state as having a badly corrupted duty cycle.

Quoted 4 lines
drivers/pwm/pwm-rp1.c new file +4 -0
+		if (wfhw->duty_ticks > (u64)wfhw->period_ticks + 1) {
+			/* 100% duty cycle case */
+			ticks = 0;
+		} else {

[ ... ]

Quoted 5 lines
drivers/pwm/pwm-rp1.c new file +5 -0
+static int rp1_pwm_write_waveform(struct pwm_chip *chip,
+				  struct pwm_device *pwm,
+				  const void *_wfhw)
+{
+	struct rp1_pwm *rp1 = pwmchip_get_drvdata(chip);

drivers/pwm/pwm-rp1.c line 227

Quoted 10 lines
drivers/pwm/pwm-rp1.c new file +10 -0
+	const struct rp1_pwm_waveform *wfhw = _wfhw;
+	u32 value, ctrl;
+
+	/* set polarity */
+	regmap_read(rp1->regmap, RP1_PWM_CHAN_CTRL(pwm->hwpwm), &value);
+	if (!wfhw->inverted_polarity)
+		value &= ~RP1_PWM_CHAN_CTRL_POLARITY;
+	else
+		value |= RP1_PWM_CHAN_CTRL_POLARITY;
+	regmap_write(rp1->regmap, RP1_PWM_CHAN_CTRL(pwm->hwpwm), value);

[Severity: High]
Could the PWM controller lose its hardware configuration after a system suspend and resume?

During rp1_pwm_request(), the channel control register is initialized with essential bits like RP1_PWM_CHAN_CTRL_DEFAULT, which includes the MODE_TE_MS and FIFO_POP_MASK configurations.

If the hardware loses power during suspend, the registers reset. On resume, when a consumer re-applies its state, this regmap_read() will read the wiped hardware register. The driver will then update only the polarity bit and write it back, failing to restore the required operational mode bits that were initialized during the request phase.

Quoted 2 lines
drivers/pwm/pwm-rp1.c new file +2 -0
+
+	/* early exit if disabled */

[ ... ]

drivers/pwm/pwm-rp1.c line 417

Quoted 8 lines
drivers/pwm/pwm-rp1.c new file +8 -0
+static struct platform_driver rp1_pwm_driver = {
+	.probe = rp1_pwm_probe,
+	/*
+	 * .remove is not needed because this driver cannot be removed/unbound
+	 * cause it relies on syscon which cannot be removed
+	 */
+	.driver = {
+		.name = "rp1-pwm",

[Severity: High]
Is it safe to omit the remove callback here?

Even with suppress_bind_attrs set on the driver, if the parent RP1 PCIe device is removed, reset, or unbound via sysfs, it will forcibly unbind all child devices.

Without a remove callback to run cleanup, pwmchip_remove() is never called and the clock is left enabled. Because the backing memory is devm-managed, the devres subsystem will eventually free the pwm_chip and regmap memory. This can leave dangling pointers in the core pwm_chips IDR and the global syscon_list, which could result in a use-after-free.

Quoted 5 lines
drivers/pwm/pwm-rp1.c new file +5 -0
+		.of_match_table = rp1_pwm_of_match,
+		.pm = pm_ptr(&rp1_pwm_pm_ops),
+		.suppress_bind_attrs = true,
+	},
+};
Signature · 1 line
Sashiko AI review · https://sashiko.dev/#/patchset/[email protected]?part=2
author maintainer
#6 lore raw

Re: [PATCH v7 2/3] pwm: rp1: Add RP1 PWM controller driver

Hi,

Quoted 54 lines · On 10:02 Mon 20 Jul , [email protected] wrote:

Thank you for your contribution! Sashiko AI review found 3 potential issue(s) to consider:
- [High] Missing .remove callback leads to Use-After-Free in the PWM and Syscon cores and leaks clock resources on driver unbind.
- [High] Register context loss on suspend/resume silently breaks PWM output.
- [High] Unclamped hardware duty ticks lead to integer underflow in the PWM core for normal polarity.
--

--- Patch [2]: [PATCH v7 2/3] pwm: rp1: Add RP1 PWM controller driver --- commit 0c98703d857577902e57d25b42a3d46dfbde5795
Author: Naushir Patuck <[email protected]>

pwm: rp1: Add RP1 PWM controller driver

The Raspberry Pi RP1 southbridge features an embedded PWM controller with 4 output channels, alongside an RPM interface to read the fan speed on the Raspberry Pi 5. Add the supporting driver.

Quoted 4 lines
drivers/pwm/pwm-rp1.c new file +0 -0
new file mode 100644

[ ... ]

Quoted 12 lines
drivers/pwm/pwm-rp1.c new file +12 -0
+static int rp1_pwm_round_waveform_fromhw(struct pwm_chip *chip,
+					 struct pwm_device *pwm,
+					 const void *_wfhw,
+					 struct pwm_waveform *wf)
+{
+	struct rp1_pwm *rp1 = pwmchip_get_drvdata(chip);
+	const struct rp1_pwm_waveform *wfhw = _wfhw;
+	u64 clk_rate = rp1->clk_rate;
+	u64 ticks;
+
+	*wf = (struct pwm_waveform){ };
+

drivers/pwm/pwm-rp1.c line 198

Quoted 10 lines
drivers/pwm/pwm-rp1.c new file +10 -0
+	if (!wfhw->enabled)
+		return 0;
+
+	wf->period_length_ns = DIV_ROUND_UP_ULL(((u64)wfhw->period_ticks + 1) * NSEC_PER_SEC,
+						clk_rate);
+
+	if (!wfhw->inverted_polarity) {
+		wf->duty_length_ns = DIV_ROUND_UP_ULL((u64)wfhw->duty_ticks * NSEC_PER_SEC,
+						      (u32)clk_rate);
+	} else {

[Severity: High]
Does the normal polarity case need to clamp the duty ticks similar to the inverted polarity case?

If the bootloader configures a continuous-high state where the raw hardware duty ticks exceed the period ticks + 1, this path calculates a duty_length_ns that is strictly greater than the period_length_ns.

Quoted 5 lines

When the PWM core subsequently reads this initial state, pwm_wf2state() handles duty > period by treating it as an inverted polarity and calculating duty_cycle = period - duty_length_ns. This subtraction can silently underflow, causing the core to interpret the hardware state as having a badly corrupted duty cycle.

The conditional right after the opening bracket of this else branch (see below for the code) is there just for that: clamping the duty to sane values. So it already takes care of that.

Quoted 32 lines
Quoted 5 lines
drivers/pwm/pwm-rp1.c new file +4 -0
+		if (wfhw->duty_ticks > (u64)wfhw->period_ticks + 1) {
+			/* 100% duty cycle case */
+			ticks = 0;
+		} else {

[ ... ]

Quoted 5 lines
drivers/pwm/pwm-rp1.c new file +5 -0
+static int rp1_pwm_write_waveform(struct pwm_chip *chip,
+				  struct pwm_device *pwm,
+				  const void *_wfhw)
+{
+	struct rp1_pwm *rp1 = pwmchip_get_drvdata(chip);

drivers/pwm/pwm-rp1.c line 227

Quoted 10 lines
drivers/pwm/pwm-rp1.c new file +10 -0
+	const struct rp1_pwm_waveform *wfhw = _wfhw;
+	u32 value, ctrl;
+
+	/* set polarity */
+	regmap_read(rp1->regmap, RP1_PWM_CHAN_CTRL(pwm->hwpwm), &value);
+	if (!wfhw->inverted_polarity)
+		value &= ~RP1_PWM_CHAN_CTRL_POLARITY;
+	else
+		value |= RP1_PWM_CHAN_CTRL_POLARITY;
+	regmap_write(rp1->regmap, RP1_PWM_CHAN_CTRL(pwm->hwpwm), value);

[Severity: High]
Could the PWM controller lose its hardware configuration after a system suspend and resume?

During rp1_pwm_request(), the channel control register is initialized with essential bits like RP1_PWM_CHAN_CTRL_DEFAULT, which includes the MODE_TE_MS and FIFO_POP_MASK configurations.

Quoted 5 lines

If the hardware loses power during suspend, the registers reset. On resume, when a consumer re-applies its state, this regmap_read() will read the wiped hardware register. The driver will then update only the polarity bit and write it back, failing to restore the required operational mode bits that were initialized during the request phase.

I think I've already answered this here:
https://lore.kernel.org/all/aiGAINsTG8VZLn28@apocalypse/
so I guess Sashiko is not sotring the entire history as context, so I'll reply it here:

AFAIK the RP1 is never powered-off, so just shutting down the clock should be ok and no register are reset to default.

Quoted 22 lines
Quoted 3 lines
drivers/pwm/pwm-rp1.c new file +2 -0
+
+	/* early exit if disabled */

[ ... ]

drivers/pwm/pwm-rp1.c line 417

Quoted 8 lines
drivers/pwm/pwm-rp1.c new file +8 -0
+static struct platform_driver rp1_pwm_driver = {
+	.probe = rp1_pwm_probe,
+	/*
+	 * .remove is not needed because this driver cannot be removed/unbound
+	 * cause it relies on syscon which cannot be removed
+	 */
+	.driver = {
+		.name = "rp1-pwm",

[Severity: High]
Is it safe to omit the remove callback here?

Even with suppress_bind_attrs set on the driver, if the parent RP1 PCIe device is removed, reset, or unbound via sysfs, it will forcibly unbind all child devices.

Quoted 5 lines

Without a remove callback to run cleanup, pwmchip_remove() is never called and the clock is left enabled. Because the backing memory is devm-managed, the devres subsystem will eventually free the pwm_chip and regmap memory. This can leave dangling pointers in the core pwm_chips IDR and the global syscon_list, which could result in a use-after-free.

This is true. Uwe, I guess I should reintroduce the .remove callback, what do you think?

Thanks,
Andrea

Quoted 9 lines
Quoted 6 lines
drivers/pwm/pwm-rp1.c new file +5 -0
+		.of_match_table = rp1_pwm_of_match,
+		.pm = pm_ptr(&rp1_pwm_pm_ops),
+		.suppress_bind_attrs = true,
+	},
+};
Signature · 1 line
Sashiko AI review · https://sashiko.dev/#/patchset/[email protected]?part=2
#7 lore raw

Re: [PATCH v7 2/3] pwm: rp1: Add RP1 PWM controller driver

Quoted 35 lines · Andrea della Porta

Hi,

Quoted 32 lines · On 10:02 Mon 20 Jul , [email protected] wrote:

Thank you for your contribution! Sashiko AI review found 3 potential issue(s) to consider:
- [High] Missing .remove callback leads to Use-After-Free in the PWM and Syscon cores and leaks clock resources on driver unbind.
- [High] Register context loss on suspend/resume silently breaks PWM output.
- [High] Unclamped hardware duty ticks lead to integer underflow in the PWM core for normal polarity.
--

--- Patch [2]: [PATCH v7 2/3] pwm: rp1: Add RP1 PWM controller driver --- commit 0c98703d857577902e57d25b42a3d46dfbde5795
Author: Naushir Patuck <[email protected]>

pwm: rp1: Add RP1 PWM controller driver

The Raspberry Pi RP1 southbridge features an embedded PWM controller with 4 output channels, alongside an RPM interface to read the fan speed on the Raspberry Pi 5. Add the supporting driver.

drivers/pwm/pwm-rp1.c line 417

Quoted 8 lines
drivers/pwm/pwm-rp1.c new file +8 -0
+static struct platform_driver rp1_pwm_driver = {
+	.probe = rp1_pwm_probe,
+	/*
+	 * .remove is not needed because this driver cannot be removed/unbound
+	 * cause it relies on syscon which cannot be removed
+	 */
+	.driver = {
+		.name = "rp1-pwm",

[Severity: High]
Is it safe to omit the remove callback here?

Even with suppress_bind_attrs set on the driver, if the parent RP1 PCIe device is removed, reset, or unbound via sysfs, it will forcibly unbind all child devices.

Quoted 9 lines
Quoted 5 lines

Without a remove callback to run cleanup, pwmchip_remove() is never called and the clock is left enabled. Because the backing memory is devm-managed, the devres subsystem will eventually free the pwm_chip and regmap memory. This can leave dangling pointers in the core pwm_chips IDR and the global syscon_list, which could result in a use-after-free.

This is true. Uwe, I guess I should reintroduce the .remove callback, what do you think?

How is remove going to work with syscon? The previous version seems to just ignore it completely.

Also, do you actually need syscon here? Given that the pwm fan device is going to depend on the PWM fan device anyway, you could just EXPORT_SYMBOL_NS an API from the rp1 driver that returns the tachometer reading when supplied with a rp1 pwm device pointer?

Best,
Gary

author maintainer
#8 lore raw

Re: [PATCH v7 2/3] pwm: rp1: Add RP1 PWM controller driver

Hi Gary,

Quoted 42 lines · Gary Guo
Quoted 41 lines · Andrea della Porta

Hi,

Quoted 37 lines · On 10:02 Mon 20 Jul , [email protected] wrote:

Thank you for your contribution! Sashiko AI review found 3 potential issue(s) to consider:
- [High] Missing .remove callback leads to Use-After-Free in the PWM and Syscon cores and leaks clock resources on driver unbind.
- [High] Register context loss on suspend/resume silently breaks PWM output.
- [High] Unclamped hardware duty ticks lead to integer underflow in the PWM core for normal polarity.
--

--- Patch [2]: [PATCH v7 2/3] pwm: rp1: Add RP1 PWM controller driver --- commit 0c98703d857577902e57d25b42a3d46dfbde5795
Author: Naushir Patuck <[email protected]>

pwm: rp1: Add RP1 PWM controller driver

The Raspberry Pi RP1 southbridge features an embedded PWM controller with 4 output channels, alongside an RPM interface to read the fan speed on the Raspberry Pi 5. Add the supporting driver.

drivers/pwm/pwm-rp1.c line 417

Quoted 8 lines
drivers/pwm/pwm-rp1.c new file +8 -0
+static struct platform_driver rp1_pwm_driver = {
+	.probe = rp1_pwm_probe,
+	/*
+	 * .remove is not needed because this driver cannot be removed/unbound
+	 * cause it relies on syscon which cannot be removed
+	 */
+	.driver = {
+		.name = "rp1-pwm",

[Severity: High]
Is it safe to omit the remove callback here?

Even with suppress_bind_attrs set on the driver, if the parent RP1 PCIe device is removed, reset, or unbound via sysfs, it will forcibly unbind all child devices.

Without a remove callback to run cleanup, pwmchip_remove() is never called and the clock is left enabled. Because the backing memory is devm-managed, the devres subsystem will eventually free the pwm_chip and regmap memory. This can leave dangling pointers in the core pwm_chips IDR and the global syscon_list, which could result in a use-after-free.

Quoted 6 lines
Quoted 3 lines

This is true. Uwe, I guess I should reintroduce the .remove callback, what do you think?

How is remove going to work with syscon? The previous version seems to just ignore it completely.

True, unfortunately we have not much choice with syscon because it does not contemplate a corresponding remove function. The best well-behaved code could just deal with clocks and resources that can be released, while syscon is unfortunately not among them.

On the other hand, I'd like to emphasize the following:

- the driver could not be unbinded nor unloaded (directly) by the user, and...
- ...PWM driver removal as a consequence of the pci bus device being forcibly removed will almost surely leave the system unusable.

As a matter of fact, even though it's not impossible for the remove callback to be called, it seems highly unlikely. So maybe it's not that big deal.

Quoted 5 lines

Also, do you actually need syscon here? Given that the pwm fan device is going to depend on the PWM fan device anyway, you could just EXPORT_SYMBOL_NS an API from the rp1 driver that returns the tachometer reading when supplied with a rp1 pwm device pointer?

I'm not devoted to syscon so if everyone agrees on the EXPORT_SYMBOL_NS solution I'm perfectly fine. It seems to be used throughout several drivers and as long as it's not considered to couple the consumer and the PWM producer too much, I think it's an easy alternative. Uwe, are you fine with that?

Many thanks,
Andrea

Quoted 4 lines

Best,
Gary

#9 lore raw

Re: [PATCH v7 2/3] pwm: rp1: Add RP1 PWM controller driver

Quoted 57 lines · Andrea della Porta

Hi Gary,

Quoted 42 lines · Gary Guo
Quoted 41 lines · Andrea della Porta

Hi,

Quoted 37 lines · On 10:02 Mon 20 Jul , [email protected] wrote:

Thank you for your contribution! Sashiko AI review found 3 potential issue(s) to consider:
- [High] Missing .remove callback leads to Use-After-Free in the PWM and Syscon cores and leaks clock resources on driver unbind.
- [High] Register context loss on suspend/resume silently breaks PWM output.
- [High] Unclamped hardware duty ticks lead to integer underflow in the PWM core for normal polarity.
--

--- Patch [2]: [PATCH v7 2/3] pwm: rp1: Add RP1 PWM controller driver --- commit 0c98703d857577902e57d25b42a3d46dfbde5795
Author: Naushir Patuck <[email protected]>

pwm: rp1: Add RP1 PWM controller driver

The Raspberry Pi RP1 southbridge features an embedded PWM controller with 4 output channels, alongside an RPM interface to read the fan speed on the Raspberry Pi 5. Add the supporting driver.

drivers/pwm/pwm-rp1.c line 417

Quoted 8 lines
drivers/pwm/pwm-rp1.c new file +8 -0
+static struct platform_driver rp1_pwm_driver = {
+	.probe = rp1_pwm_probe,
+	/*
+	 * .remove is not needed because this driver cannot be removed/unbound
+	 * cause it relies on syscon which cannot be removed
+	 */
+	.driver = {
+		.name = "rp1-pwm",

[Severity: High]
Is it safe to omit the remove callback here?

Even with suppress_bind_attrs set on the driver, if the parent RP1 PCIe device is removed, reset, or unbound via sysfs, it will forcibly unbind all child devices.

Without a remove callback to run cleanup, pwmchip_remove() is never called and the clock is left enabled. Because the backing memory is devm-managed, the devres subsystem will eventually free the pwm_chip and regmap memory. This can leave dangling pointers in the core pwm_chips IDR and the global syscon_list, which could result in a use-after-free.

Quoted 6 lines
Quoted 3 lines

This is true. Uwe, I guess I should reintroduce the .remove callback, what do you think?

How is remove going to work with syscon? The previous version seems to just ignore it completely.

True, unfortunately we have not much choice with syscon because it does not contemplate a corresponding remove function. The best well-behaved code could just deal with clocks and resources that can be released, while syscon is unfortunately not among them.

Quoted 12 lines

On the other hand, I'd like to emphasize the following:

- the driver could not be unbinded nor unloaded (directly) by the user, and...
- ...PWM driver removal as a consequence of the pci bus device being forcibly removed will almost surely leave the system unusable.

As a matter of fact, even though it's not impossible for the remove callback to be called, it seems highly unlikely. So maybe it's not that big deal.

Quoted 3 lines

Also, do you actually need syscon here? Given that the pwm fan device is going to depend on the PWM fan device anyway,

Oops, it should have been "PWM fan device depend on PWM device". But you got it.

Quoted 8 lines
Quoted 3 lines

you could just EXPORT_SYMBOL_NS an API
from the rp1 driver that returns the tachometer reading when supplied with a rp1 pwm device pointer?

I'm not devoted to syscon so if everyone agrees on the EXPORT_SYMBOL_NS solution I'm perfectly fine. It seems to be used throughout several drivers and as long as it's not considered to couple the consumer and the PWM producer too much, I think it's an easy alternative. Uwe, are you fine with that?

I think that's pretty typical for platform devices, provided that the consumer and the producer are closely related.

I checked the RPi vendor kernel code and it looks like they're modifying the PWM fan driver code directly -- in which case the coupling would definitely be problematic. But I think that modification is problematic itself and not upstreamable. I suppose you'll add a separate, dedicated RP1 fan driver?

In which case I don't see the coupling being an issue.

Best,
Gary

Quoted 8 lines

Many thanks,
Andrea

Quoted 4 lines

Best,
Gary

author maintainer
#10 lore raw

Re: [PATCH v7 2/3] pwm: rp1: Add RP1 PWM controller driver

Hi Gary,

Quoted 82 lines · Gary Guo
Quoted 57 lines · Andrea della Porta

Hi Gary,

Quoted 42 lines · Gary Guo
Quoted 41 lines · Andrea della Porta

Hi,

Quoted 37 lines · On 10:02 Mon 20 Jul , [email protected] wrote:

Thank you for your contribution! Sashiko AI review found 3 potential issue(s) to consider:
- [High] Missing .remove callback leads to Use-After-Free in the PWM and Syscon cores and leaks clock resources on driver unbind.
- [High] Register context loss on suspend/resume silently breaks PWM output.
- [High] Unclamped hardware duty ticks lead to integer underflow in the PWM core for normal polarity.
--

--- Patch [2]: [PATCH v7 2/3] pwm: rp1: Add RP1 PWM controller driver --- commit 0c98703d857577902e57d25b42a3d46dfbde5795
Author: Naushir Patuck <[email protected]>

pwm: rp1: Add RP1 PWM controller driver

The Raspberry Pi RP1 southbridge features an embedded PWM controller with 4 output channels, alongside an RPM interface to read the fan speed on the Raspberry Pi 5. Add the supporting driver.

drivers/pwm/pwm-rp1.c line 417

Quoted 8 lines
drivers/pwm/pwm-rp1.c new file +8 -0
+static struct platform_driver rp1_pwm_driver = {
+	.probe = rp1_pwm_probe,
+	/*
+	 * .remove is not needed because this driver cannot be removed/unbound
+	 * cause it relies on syscon which cannot be removed
+	 */
+	.driver = {
+		.name = "rp1-pwm",

[Severity: High]
Is it safe to omit the remove callback here?

Even with suppress_bind_attrs set on the driver, if the parent RP1 PCIe device is removed, reset, or unbound via sysfs, it will forcibly unbind all child devices.

Without a remove callback to run cleanup, pwmchip_remove() is never called and the clock is left enabled. Because the backing memory is devm-managed, the devres subsystem will eventually free the pwm_chip and regmap memory. This can leave dangling pointers in the core pwm_chips IDR and the global syscon_list, which could result in a use-after-free.

Quoted 6 lines
Quoted 3 lines

This is true. Uwe, I guess I should reintroduce the .remove callback, what do you think?

How is remove going to work with syscon? The previous version seems to just ignore it completely.

True, unfortunately we have not much choice with syscon because it does not contemplate a corresponding remove function. The best well-behaved code could just deal with clocks and resources that can be released, while syscon is unfortunately not among them.

Quoted 12 lines

On the other hand, I'd like to emphasize the following:

- the driver could not be unbinded nor unloaded (directly) by the user, and...
- ...PWM driver removal as a consequence of the pci bus device being forcibly removed will almost surely leave the system unusable.

As a matter of fact, even though it's not impossible for the remove callback to be called, it seems highly unlikely. So maybe it's not that big deal.

Quoted 3 lines

Also, do you actually need syscon here? Given that the pwm fan device is going to depend on the PWM fan device anyway,

Oops, it should have been "PWM fan device depend on PWM device". But you got it.

Quoted 8 lines
Quoted 3 lines

you could just EXPORT_SYMBOL_NS an API
from the rp1 driver that returns the tachometer reading when supplied with a rp1 pwm device pointer?

I'm not devoted to syscon so if everyone agrees on the EXPORT_SYMBOL_NS solution I'm perfectly fine. It seems to be used throughout several drivers and as long as it's not considered to couple the consumer and the PWM producer too much, I think it's an easy alternative. Uwe, are you fine with that?

Quoted 7 lines

I think that's pretty typical for platform devices, provided that the consumer and the producer are closely related.

I checked the RPi vendor kernel code and it looks like they're modifying the PWM fan driver code directly -- in which case the coupling would definitely be problematic. But I think that modification is problematic itself and not upstreamable. I suppose you'll add a separate, dedicated RP1 fan driver?

You nailed it. I've changed downstream driver approach because it was too invasive to the pwm-fan driver and, as you mentioned, not upstreamable.
A separate RP1-custom fan driver was in plan from teh beginning.

Quoted 2 lines

In which case I don't see the coupling being an issue.

Perfect!

Many thanks,
Andrea

Quoted 14 lines

Best,
Gary

Quoted 8 lines

Many thanks,
Andrea

Quoted 4 lines

Best,
Gary

#11 lore raw

Re: [PATCH v7 2/3] pwm: rp1: Add RP1 PWM controller driver

In reply to Andrea della Porta

Le 20/07/2026 à 11:44, Andrea della Porta a écrit :

Quoted 6 lines

From: Naushir Patuck <[email protected]>

The Raspberry Pi RP1 southbridge features an embedded PWM controller with 4 output channels, alongside an RPM interface to read the fan speed on the Raspberry Pi 5.

Quoted 6 lines

Add the supporting driver.

Hi,

...

Quoted 15 lines
drivers/pwm/pwm-rp1.c new file +15 -0
+static int rp1_pwm_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct device_node *np = dev->of_node;
+	unsigned long clk_rate;
+	struct pwm_chip *chip;
+	void __iomem	*base;
+	struct rp1_pwm *rp1;
+	int ret;
+
+	chip = devm_pwmchip_alloc(dev, RP1_PWM_NUM_PWMS, sizeof(*rp1));
+	if (IS_ERR(chip))
+		return PTR_ERR(chip);
+
+	rp1 = pwmchip_get_drvdata(chip);

drivers/pwm/pwm-rp1.c line 314

Quoted 10 lines
drivers/pwm/pwm-rp1.c new file +10 -0
+
+	base = devm_platform_ioremap_resource(pdev, 0);
+	if (IS_ERR(base))
+		return PTR_ERR(base);
+
+	rp1->regmap = devm_regmap_init_mmio(dev, base, &rp1_pwm_regmap_config);
+	if (IS_ERR(rp1->regmap))
+		return dev_err_probe(dev, PTR_ERR(rp1->regmap), "Cannot initialize regmap\n");
+
+	rp1->clk = devm_clk_get(dev, NULL);

Could it be devm_clk_get_enabled() to simplify the error handling path as done above with other devm function?
...

drivers/pwm/pwm-rp1.c line 320

Quoted 6 lines
drivers/pwm/pwm-rp1.c new file +6 -0
+	if (IS_ERR(rp1->clk))
+		return dev_err_probe(dev, PTR_ERR(rp1->clk), "Clock not found\n");
+
+	ret = clk_prepare_enable(rp1->clk);
+	if (ret)
+		return dev_err_probe(dev, ret, "Failed to enable clock\n");

... this also saves these 3 lines.

Quoted 20 lines
drivers/pwm/pwm-rp1.c new file +20 -0
+	rp1->clk_enabled = true;
+
+	ret = devm_clk_rate_exclusive_get(dev, rp1->clk);
+	if (ret) {
+		dev_err_probe(dev, ret, "Failed to get exclusive rate\n");
+		goto err_disable_clk;
+	}
+
+	clk_rate = clk_get_rate(rp1->clk);
+	if (!clk_rate) {
+		ret = dev_err_probe(dev, -EINVAL, "Failed to get clock rate\n");
+		goto err_disable_clk;
+	}
+	/*
+	 * To prevent u64 overflow in period calculations:
+	 * mul_u64_u64_div_u64(period_ns, clk_rate, NSEC_PER_SEC)
+	 * If clk_rate > 1 GHz, the result can overflow.
+	 */
+	if (clk_rate > HZ_PER_GHZ) {
+		ret = dev_err_probe(dev, -EINVAL, "Clock rate > 1 GHz is not supported\n");

drivers/pwm/pwm-rp1.c line 350

Quoted 10 lines
drivers/pwm/pwm-rp1.c new file +10 -0
+		goto err_disable_clk;
+	}
+	rp1->clk_rate = clk_rate;
+
+	chip->ops = &rp1_pwm_ops;
+	chip->atomic = true;
+
+	platform_set_drvdata(pdev, chip);
+
+	ret = pwmchip_add(chip);

Could it be devm_pwmchip_add() to simplify the error handling path as done above with other devm function?

Quoted 10 lines
drivers/pwm/pwm-rp1.c new file +10 -0
+	if (ret) {
+		dev_err_probe(dev, ret, "Failed to register PWM chip\n");
+		goto err_disable_clk;
+	}
+
+	ret = of_syscon_register_regmap(np, rp1->regmap);
+	if (ret) {
+		dev_err_probe(dev, ret, "Failed to register syscon\n");
+		goto err_remove_chip;
+	}

drivers/pwm/pwm-rp1.c line 370

Quoted 10 lines
drivers/pwm/pwm-rp1.c new file +10 -0
+
+	return 0;
+
+err_remove_chip:
+	pwmchip_remove(chip);
+err_disable_clk:
+	clk_disable_unprepare(rp1->clk);
+
+	return ret;
+}

...

CJ

author maintainer
#12 lore raw

Re: [PATCH v7 2/3] pwm: rp1: Add RP1 PWM controller driver

Hi Christophe,

Quoted 38 lines · Christophe JAILLET

Le 20/07/2026 à 11:44, Andrea della Porta a écrit :

Quoted 6 lines

From: Naushir Patuck <[email protected]>

The Raspberry Pi RP1 southbridge features an embedded PWM controller with 4 output channels, alongside an RPM interface to read the fan speed on the Raspberry Pi 5.

Quoted 6 lines

Add the supporting driver.

Hi,

...

Quoted 20 lines
drivers/pwm/pwm-rp1.c new file +20 -0
+static int rp1_pwm_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct device_node *np = dev->of_node;
+	unsigned long clk_rate;
+	struct pwm_chip *chip;
+	void __iomem	*base;
+	struct rp1_pwm *rp1;
+	int ret;
+
+	chip = devm_pwmchip_alloc(dev, RP1_PWM_NUM_PWMS, sizeof(*rp1));
+	if (IS_ERR(chip))
+		return PTR_ERR(chip);
+
+	rp1 = pwmchip_get_drvdata(chip);
+
+	base = devm_platform_ioremap_resource(pdev, 0);
+	if (IS_ERR(base))
+		return PTR_ERR(base);
+
Quoted 8 lines

drivers/pwm/pwm-rp1.c line 314

Quoted 5 lines
drivers/pwm/pwm-rp1.c new file +5 -0
+	rp1->regmap = devm_regmap_init_mmio(dev, base, &rp1_pwm_regmap_config);
+	if (IS_ERR(rp1->regmap))
+		return dev_err_probe(dev, PTR_ERR(rp1->regmap), "Cannot initialize regmap\n");
+
+	rp1->clk = devm_clk_get(dev, NULL);

Could it be devm_clk_get_enabled() to simplify the error handling path as done above with other devm function?

The very first version of this patches had devres everywhere, but Uwe has correctly spotted that this could lead to clock ops imbalance, please see:
https://lore.kernel.org/all/adLTwOTbkJ0VQXy6@monoceros/
As a result, I turned devm_clk_get_enabled() into the corresponding non devres/single component functions since now disengaging the clock depends on a conditional. Of course this does not make much sense in case we don't need a .remove callback, but it seems that I can reintroduce it again if we agree to use EXPORT_SYMBOL_NS.

Quoted 10 lines

...

drivers/pwm/pwm-rp1.c line 320

Quoted 6 lines
drivers/pwm/pwm-rp1.c new file +6 -0
+	if (IS_ERR(rp1->clk))
+		return dev_err_probe(dev, PTR_ERR(rp1->clk), "Clock not found\n");
+
+	ret = clk_prepare_enable(rp1->clk);
+	if (ret)
+		return dev_err_probe(dev, ret, "Failed to enable clock\n");

... this also saves these 3 lines.

See above.

Quoted 26 lines
Quoted 26 lines
drivers/pwm/pwm-rp1.c new file +25 -0
+	rp1->clk_enabled = true;
+
+	ret = devm_clk_rate_exclusive_get(dev, rp1->clk);
+	if (ret) {
+		dev_err_probe(dev, ret, "Failed to get exclusive rate\n");
+		goto err_disable_clk;
+	}
+
+	clk_rate = clk_get_rate(rp1->clk);
+	if (!clk_rate) {
+		ret = dev_err_probe(dev, -EINVAL, "Failed to get clock rate\n");
+		goto err_disable_clk;
+	}
+	/*
+	 * To prevent u64 overflow in period calculations:
+	 * mul_u64_u64_div_u64(period_ns, clk_rate, NSEC_PER_SEC)
+	 * If clk_rate > 1 GHz, the result can overflow.
+	 */
+	if (clk_rate > HZ_PER_GHZ) {
+		ret = dev_err_probe(dev, -EINVAL, "Clock rate > 1 GHz is not supported\n");
+		goto err_disable_clk;
+	}
+	rp1->clk_rate = clk_rate;
+
+	chip->ops = &rp1_pwm_ops;
Quoted 8 lines

drivers/pwm/pwm-rp1.c line 350

Quoted 5 lines
drivers/pwm/pwm-rp1.c new file +5 -0
+	chip->atomic = true;
+
+	platform_set_drvdata(pdev, chip);
+
+	ret = pwmchip_add(chip);

Could it be devm_pwmchip_add() to simplify the error handling path as done above with other devm function?

Due to the above-mentioned scenario and since .remove is called before devres release funtions, that would make the clock to be released before the pwm chip, causing inconsistencies if the pwm is used in the meanwhile.

Many thanks,
Andrea.

Quoted 24 lines
Quoted 11 lines
drivers/pwm/pwm-rp1.c new file +10 -0
+	if (ret) {
+		dev_err_probe(dev, ret, "Failed to register PWM chip\n");
+		goto err_disable_clk;
+	}
+
+	ret = of_syscon_register_regmap(np, rp1->regmap);
+	if (ret) {
+		dev_err_probe(dev, ret, "Failed to register syscon\n");
+		goto err_remove_chip;
+	}

drivers/pwm/pwm-rp1.c line 370

Quoted 10 lines
drivers/pwm/pwm-rp1.c new file +10 -0
+
+	return 0;
+
+err_remove_chip:
+	pwmchip_remove(chip);
+err_disable_clk:
+	clk_disable_unprepare(rp1->clk);
+
+	return ret;
+}

...

CJ

author maintainer
#13 lore raw

PATCH v7 3/3 arm64: dts: broadcom: rpi-5: Add RP1 PWM node

In reply to Andrea della Porta

From: Stanimir Varbanov <[email protected]>

The RP1 chipset used on the Raspberry Pi 5 features an integrated PWM controller to drive the cooling fan.

Add the corresponding DT node for this PWM controller.

---
 arch/arm64/boot/dts/broadcom/bcm2712-rpi-5-b.dts | 12 ++++++++++++
 arch/arm64/boot/dts/broadcom/rp1-common.dtsi     |  9 +++++++++
 2 files changed, 21 insertions(+)
arch/arm64/boot/dts/broadcom/bcm2712-rpi-5-b.dts +12 -0
index 0fc57e72632ed..748be8f1ee9e2 100644
@@ -64,6 +64,12 @@ phy1: ethernet-phy@1 {
 };
 
 &rp1_gpio {
+	fan_pwm_default_state: fan-pwm-default-state {
+		function = "pwm1";
+		pins = "gpio45";
+		bias-pull-down;
+	};
+
 	usb_vbus_default_state: usb-vbus-default-state {
 		function = "vbus1";
 		groups = "vbus1";
@@ -94,6 +100,12 @@ &rp1_i2c6 {
 	pinctrl-names = "default";
 };
 
+&rp1_pwm1 {
+	pinctrl-0 = <&fan_pwm_default_state>;
+	pinctrl-names = "default";
+	status = "okay";
+};
+
 &rp1_usb0 {
 	pinctrl-0 = <&usb_vbus_default_state>;
 	pinctrl-names = "default";
arch/arm64/boot/dts/broadcom/rp1-common.dtsi +9 -0
index 16f5359395835..df4c2d09c8d34 100644
@@ -99,7 +99,16 @@ rp1_i2c6: i2c@40088000 {
 		clocks = <&rp1_clocks RP1_CLK_SYS>;
 		i2c-scl-rising-time-ns = <65>;
 		i2c-scl-falling-time-ns = <100>;
+		status = "disabled";
+	};
 
+	rp1_pwm1: pwm@4009c000 {
+		compatible = "raspberrypi,rp1-pwm";
+		reg = <0x00 0x4009c000  0x0 0x100>;
+		clocks = <&rp1_clocks RP1_CLK_PWM1>;
+		assigned-clocks = <&rp1_clocks RP1_CLK_PWM1>;
+		assigned-clock-rates = <50000000>;
+		#pwm-cells = <3>;
 		status = "disabled";
 	};
 
Signature · 1 line
2.35.3
maintainer
#14 lore raw
In reply to Andrea della Porta
Quoted 10 lines · Andrea della Porta

This patchset adds support for the PWM controller found on the Raspberry Pi RP1 southbridge. This is necessary to operate the cooling fan connected to one of the PWM channels.

The tachometer pin for the fan speed is managed by the firmware running on the RP1's M-core. It uses the PHASE2 register to report the RPM, which is then exported by this driver via syscon registers. A subsequent patch will add a new device and driver to read the RPM and export this value via hwmon.

Quoted 5 lines

Subsequent patches will also add the CPU thermal zone, which acts as a consumer of the PWM device.

Best regards,
Andrea

Uwe, how do we go about applying these patches? Do you want to take patch #2 and I take patches #1 and #3 through the Broadcom ARM SoC tree(s)?

Signature · 1 line
Florian