* Re: [PATCH 1/3] dt-bindings: soc: apple: Add bindings for apple PMGR misc controls
From: Conor Dooley @ 2026-07-02 19:18 UTC (permalink / raw)
To: Sasha Finkelstein
Cc: Sven Peter, Janne Grunau, Neal Gompa, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, asahi, linux-arm-kernel,
devicetree, linux-kernel
In-Reply-To: <20260702-pmgr-misc-v1-1-4f075a3a95c1@chaosmail.tech>
[-- Attachment #1: Type: text/plain, Size: 3293 bytes --]
On Thu, Jul 02, 2026 at 02:06:26PM +0200, Sasha Finkelstein wrote:
> Certain Apple SoCs include additional PMGR power states that are
> controlled via a different "misc" control block. On existing SoCs, this
> includes the fabric and memory controller state.
>
> Signed-off-by: Sasha Finkelstein <k@chaosmail.tech>
> ---
> Documentation/devicetree/bindings/soc/apple/apple,t6000-pmgr-misc.yaml | 45 +++++++++++++++++++++++++++++++++++++++++++++
> MAINTAINERS | 1 +
> 2 files changed, 46 insertions(+)
>
> diff --git a/Documentation/devicetree/bindings/soc/apple/apple,t6000-pmgr-misc.yaml b/Documentation/devicetree/bindings/soc/apple/apple,t6000-pmgr-misc.yaml
> new file mode 100644
> index 000000000000..30abedc67fa4
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/soc/apple/apple,t6000-pmgr-misc.yaml
> @@ -0,0 +1,45 @@
> +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
> +%YAML 1.2
> +---
> +$id: http://devicetree.org/schemas/soc/apple/apple,t6000-pmgr-misc.yaml#
> +$schema: http://devicetree.org/meta-schemas/core.yaml#
> +
> +title: Apple SoC PMGR Misc Power States
> +
> +maintainers:
> + - Sasha Finkelstein <k@chaosmail.tech>
> +
> +description: |
> + Certain Apple SoCs include additional PMGR power states that are controlled
> + via a different "misc" control block. On existing SoCs, this includes the
> + fabric and memory controller state.
Are t6000 and t6020 the "certain Apple SoCs"? I assume so. The bit about
"existing SoCs" is confusing in a binding (although it would be ok in the
commit message), because you run into language semantics that imply that
this sentence is about devices to the ones you're addressing here. I
think you can just do s/. On existing SoCs//. And add an s to the final
"state" to make it "states".
> +
> +properties:
> + compatible:
> + enum:
> + - apple,t6000-pmgr-misc
> + - apple,t6020-pmgr-misc
> +
> + reg:
> + maxItems: 2
> +
> + reg-names:
> + items:
> + - const: fabric-ps
> + - const: dcs-ps
"dcs" means memory controller then?
> +
> +required:
> + - compatible
> + - reg
> + - reg-names
> +
> +additionalProperties: false
> +
> +examples:
> + - |
> + pmgr_misc: power-management@8e20c000 {
If there's a new version, drop the unused label here please.
> + compatible = "apple,t6000-pmgr-misc";
> + reg = <0x8e20c000 0x400>,
> + <0x8e20c800 0x400>;
> + reg-names = "fabric-ps", "dcs-ps";
> + };
> diff --git a/MAINTAINERS b/MAINTAINERS
> index 15011f5752a9..5a29bb86499f 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -2607,6 +2607,7 @@ F: Documentation/devicetree/bindings/power/apple*
> F: Documentation/devicetree/bindings/power/reset/apple,smc-reboot.yaml
> F: Documentation/devicetree/bindings/pwm/apple,s5l-fpwm.yaml
> F: Documentation/devicetree/bindings/rtc/apple,smc-rtc.yaml
> +F: Documentation/devicetree/bindings/soc/apple/apple,t6000-pmgr-misc.yaml
> F: Documentation/devicetree/bindings/spi/apple,spi.yaml
> F: Documentation/devicetree/bindings/spmi/apple,spmi.yaml
> F: Documentation/devicetree/bindings/usb/apple,dwc3.yaml
>
> --
> 2.55.0
>
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 228 bytes --]
^ permalink raw reply
* Re: [PATCH rc v7 0/7] iommu/arm-smmu-v3: Fix device crash on kdump kernel
From: Nicolin Chen @ 2026-07-02 19:25 UTC (permalink / raw)
To: Jason Gunthorpe
Cc: Pranjal Shrivastava, Mostafa Saleh, will, robin.murphy, joro,
kees, baolu.lu, kevin.tian, miko.lenczewski, linux-arm-kernel,
iommu, linux-kernel, stable, jamien
In-Reply-To: <20260702144157.GM7481@nvidia.com>
On Thu, Jul 02, 2026 at 11:41:57AM -0300, Jason Gunthorpe wrote:
> On Wed, Jul 01, 2026 at 01:36:29PM +0000, Pranjal Shrivastava wrote:
>
> > However, I agree with the overall problem, i.e. IF an active device
> > unmaps the DMA addr after the transaction in the previous kernel,
> > (with the SMMU powered ON) but the TLBI was missed due to a crash/panic,
> > Any new DMA in the new kernel may alias onto a memory in the previous
> > (crashed) kernel, not the kdump kernel.
>
> It looks like there is an issue in this series, it isn't doing
> anything with the VMIDs.
>
> The VMIDs that are in-used by the adopted stream table have to be
> removed from the idr as well (and similarly for ASID if we don't have
> VMID HW support).
>
> Then the VMIDs that may be dirtied by the prior kernel remain isolated
> and are never re-used by the new kernel. When the new kernel wants to
> do DMA it will replace the STE with a new, clean VMID, and there is no
> problem.
I see. I assume the reserved VMID for the kdump kernel will be a
clean VMID (!=0). That should guarantee different cache tags.
But, do we have to scan CDs for ASID? I wonder if we could limit
to ARM_SMMU_FEAT_TRANS_S2 only, as this series does not memremap
CDs at all..
Nicolin
^ permalink raw reply
* Re: [PATCH RFC v5 00/12] ZTE zx297520v3 clock bindings and driver
From: Stefan Dösinger @ 2026-07-02 19:26 UTC (permalink / raw)
To: Conor Dooley
Cc: Michael Turquette, Stephen Boyd, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Philipp Zabel, Brian Masney, linux-clk, devicetree,
linux-kernel, linux-arm-kernel
In-Reply-To: <20260702-frequent-refreeze-9850982156cb@spud>
[-- Attachment #1: Type: text/plain, Size: 736 bytes --]
Am Donnerstag, 2. Juli 2026, 22:05:14 Ostafrikanische Zeit schrieben Sie:
> > I am not aware of any IO region to configure the PHY, although one may
> > exist. topcrm + 0x84 has two status bits reporting if USB and HSIC are
> > powered and out of reset. Nevertheless, the PHY feels distinct enough
> > from topcrm that it should have its own binding. The phy driver would
> > merely deassert the reset
> This is the sort of thing that should be a child node of the syscon,
> rather than integrated into the parent, given it consumes resources from
> another feature of the syscon.
Ok, I'll go that route then
I think I can add the phy child to the binding later without breaking the ABI
if I make it an optional member of the binding.
[-- Attachment #2: This is a digitally signed message part. --]
[-- Type: application/pgp-signature, Size: 870 bytes --]
^ permalink raw reply
* Re: [PATCH 08/10] HID: apple: Add DockChannel HID transport driver
From: Julian Braha @ 2026-07-02 19:32 UTC (permalink / raw)
To: michael.reeves077, Sven Peter, Janne Grunau, Neal Gompa,
Jassi Brar, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Hector Martin, Joerg Roedel (AMD), Will Deacon, Robin Murphy,
Dmitry Torokhov, Jiri Kosina, Benjamin Tissoires
Cc: asahi, linux-arm-kernel, linux-kernel, devicetree, iommu,
linux-input
In-Reply-To: <20260630-apple-mtp-keyboard-final-v1-8-506d936a1707@gmail.com>
Hi Michael,
On 6/30/26 13:54, Michael Reeves via B4 Relay wrote:
> +source "drivers/hid/dockchannel/Kconfig"
> +
> endif # HID
>
> +++ b/drivers/hid/dockchannel/Kconfig
> @@ -0,0 +1,15 @@
> +# SPDX-License-Identifier: GPL-2.0-only OR MIT
> +
> +config APPLE_DOCKCHANNEL_HID
> + tristate "HID over Apple DockChannel"
> + depends on APPLE_DOCKCHANNEL
> + depends on APPLE_RTKIT
> + depends on HID
APPLE_DOCKCHANNEL_HID has a duplicate dependency on HID,
since you put the import for this file inside of 'if HID..endif',
and then also gave it a 'depends on HID'.
- Julian Braha
^ permalink raw reply
* Re: [PATCH 1/3] dt-bindings: soc: apple: Add bindings for apple PMGR misc controls
From: Sasha Finkelstein @ 2026-07-02 19:35 UTC (permalink / raw)
To: Conor Dooley
Cc: Sven Peter, Janne Grunau, Neal Gompa, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, asahi, linux-arm-kernel,
devicetree, linux-kernel
In-Reply-To: <20260702-kitchen-census-d79e1abb9f36@spud>
On Jul 2, 2026, at 21:18, Conor Dooley <conor@kernel.org> wrote:
> Are t6000 and t6020 the "certain Apple SoCs"? I assume so. The bit about
> "existing SoCs" is confusing in a binding (although it would be ok in the
> commit message), because you run into language semantics that imply that
> this sentence is about devices to the ones you're addressing here. I
> think you can just do s/. On existing SoCs//. And add an s to the final
> "state" to make it "states".
t600{0,1,2}, t602{0,1,2}, t603{1,2,4} (no upstream DT for those yet)
It is kind of a long list, with most t6xxx ones on it.
> "dcs" means memory controller then?
It is memory controller related, unclear if this covers the entire
controller or a subset of it. The name comes from Apple device trees
and macos kernel logs
^ permalink raw reply
* [PATCH v4 0/3] Add devicetree for the Graperain G3568 v2
From: Coia Prant @ 2026-07-02 19:35 UTC (permalink / raw)
To: Rob Herring, Krzysztof Kozlowski, Conor Dooley, Heiko Stuebner,
Dragan Simic, Jonas Karlman
Cc: devicetree, linux-arm-kernel, linux-rockchip, linux-kernel,
Coia Prant
Changes in v2:
- Fix trailing whitespaces and other formatting issues.
Changes in v3:
- Picked up Acked-by tag for patch 1.
- Fixed text wrapping in the commit message of patch 2.
- Replace the legacy 'gpio' label with 'gpios'.
- Add the basic WiFi child node.
- Add the Bluetooth UART child node.
Changes in v4:
- Fix incorrect pinctrl bluetooth node name.
- Disable bluetooth sound since rk3568-codec-digital unavailable.
- Add WiFi fallback compatible string.
- Add WiFi host wake interrupt.
Notes/Unchanged from v1:
- ADC keys have been verified with evtest and works fine; kept unchanged.
- The 'regulator-off-in-suspend' property for vqmmc-supply is retained.
This is a known issue shared by most similar boards and should be
addressed globally later.
---
Coia Prant (3):
dt-bindings: vendor-prefixes: Add graperain
dt-bindings: arm: rockchip: Add Graperain G3568 series
arm64: dts: rockchip: Add devicetree for the Graperain G3568 v2
.../devicetree/bindings/arm/rockchip.yaml | 6 +
.../devicetree/bindings/vendor-prefixes.yaml | 2 +
arch/arm64/boot/dts/rockchip/Makefile | 1 +
.../rockchip/rk3568-graperain-g3568-v2.dts | 943 ++++++++++++++++++
4 files changed, 952 insertions(+)
create mode 100644 arch/arm64/boot/dts/rockchip/rk3568-graperain-g3568-v2.dts
--
2.47.3
^ permalink raw reply
* [PATCH v4 1/3] dt-bindings: vendor-prefixes: Add graperain
From: Coia Prant @ 2026-07-02 19:35 UTC (permalink / raw)
To: Rob Herring, Krzysztof Kozlowski, Conor Dooley, Heiko Stuebner,
Dragan Simic, Jonas Karlman
Cc: devicetree, linux-arm-kernel, linux-rockchip, linux-kernel,
Coia Prant, Krzysztof Kozlowski
In-Reply-To: <20260702193538.2195973-1-coiaprant@gmail.com>
Add graperain to the vendor prefixes.
Link: https://www.graperain.cn/ (China)
Link: https://www.graperain.com/ (Global)
Signed-off-by: Coia Prant <coiaprant@gmail.com>
Acked-by: Krzysztof Kozlowski <krzysztof.kozlowski@oss.qualcomm.com>
---
Documentation/devicetree/bindings/vendor-prefixes.yaml | 2 ++
1 file changed, 2 insertions(+)
diff --git a/Documentation/devicetree/bindings/vendor-prefixes.yaml b/Documentation/devicetree/bindings/vendor-prefixes.yaml
index 396044f368e7c..641a37c0debc9 100644
--- a/Documentation/devicetree/bindings/vendor-prefixes.yaml
+++ b/Documentation/devicetree/bindings/vendor-prefixes.yaml
@@ -682,6 +682,8 @@ patternProperties:
description: Goramo Gorecki
"^gplus,.*":
description: GPLUS
+ "^graperain,.*":
+ description: Shenzhen Graperain Technology Co., Ltd.
"^grinn,.*":
description: Grinn
"^grmn,.*":
--
2.47.3
^ permalink raw reply related
* [PATCH v4 2/3] dt-bindings: arm: rockchip: Add Graperain G3568 series
From: Coia Prant @ 2026-07-02 19:35 UTC (permalink / raw)
To: Rob Herring, Krzysztof Kozlowski, Conor Dooley, Heiko Stuebner,
Dragan Simic, Jonas Karlman
Cc: devicetree, linux-arm-kernel, linux-rockchip, linux-kernel,
Coia Prant, Krzysztof Kozlowski
In-Reply-To: <20260702193538.2195973-1-coiaprant@gmail.com>
Document the Graperain G3568 v2, which is a development board based on
the Rockchip RK3568 SoC.
Graperain G3568 series also have an SBC series with the suffix "box".
Graperain G3568 v2 belongs to development board series, not SBC series.
Link: https://www.graperain.cn/RK3568/RK3568-Development/ (China)
Link: https://www.graperain.com/ARM-Embedded-RK3568-Development-Board/ (Global)
Link: https://image.chukouplus.com/upload/C_153/product_file/20211022/6daddec9e400458816dd4c57ba807fc3.pdf
Signed-off-by: Coia Prant <coiaprant@gmail.com>
Acked-by: Krzysztof Kozlowski <krzysztof.kozlowski@oss.qualcomm.com>
---
Documentation/devicetree/bindings/arm/rockchip.yaml | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/Documentation/devicetree/bindings/arm/rockchip.yaml b/Documentation/devicetree/bindings/arm/rockchip.yaml
index 1a9dde18626d0..9eb2f66ba3856 100644
--- a/Documentation/devicetree/bindings/arm/rockchip.yaml
+++ b/Documentation/devicetree/bindings/arm/rockchip.yaml
@@ -684,6 +684,12 @@ properties:
- const: google,veyron
- const: rockchip,rk3288
+ - description: Graperain G3568 series board
+ items:
+ - enum:
+ - graperain,g3568-v2
+ - const: rockchip,rk3568
+
- description: H96 Max V58 TV Box
items:
- const: haochuangyi,h96-max-v58
--
2.47.3
^ permalink raw reply related
* [PATCH v4 3/3] arm64: dts: rockchip: Add devicetree for the Graperain G3568 v2
From: Coia Prant @ 2026-07-02 19:35 UTC (permalink / raw)
To: Rob Herring, Krzysztof Kozlowski, Conor Dooley, Heiko Stuebner,
Dragan Simic, Jonas Karlman
Cc: devicetree, linux-arm-kernel, linux-rockchip, linux-kernel,
Coia Prant
In-Reply-To: <20260702193538.2195973-1-coiaprant@gmail.com>
The Graperain G3568 v2 is an RK3568-based development board, just like
the RK3568-EVB.
It always uses soldered connections between the GR3568CV2 core board and
the RK3568BV2/GR3568BV2 I/O board.
The G3568 board has multiple hardware revisions, and we currently
support v2 (I/O board).
Specification:
- SoC: RockChip RK3568 ARM64 (4 cores)
- eMMC: 16-128 GB
- RAM: 2-16 GB
- Power: DC 12V 2A
- Ethernet: 2x RTL8211F RGMII (10/100/1000 Mbps)
- Wireless radio: 802.11b/g/n/ac dual-band
- LED:
Power: AlwaysOn
User: GPIO
- Button:
ESC: SARADC/0 <1100k µV>
MENU: SARADC/0 <1400k µV>
VOL-: SARADC/0 <430k µV>
VOL+: SARADC/0 <50k µV>
Power/Reset: PMIC RK809
- CAN
CAN/1: 4-pin (PH 2.0)
- PWM
PWM/4: Backlight
PWM/5: Backlight
PWM/7: IR Receiver
- UART:
UART/2: Debug TTL - 1500000 8N1 (1.25mm)
UART/3: TTL (PH 2.0)
UART/4: TTL (PH 2.0)
UART/8: AP6356S Bluetooth
UART/9: TTL (PH 2.0)
- I2C:
I2C/0: PMIC RK809
I2C/1: Touchscreen
I2C/4: Camera
I2C/5: RTC@51 PCF8563
- I2S:
I2S/0: HDMI Sound
I2S/1: RK809 Audio Codec
I2S/3: AP6356S Bluetooth Sound
- SDMMC:
SDMMC/0: microSD (TF) slot
SDMMC/2: AP6356S SDIO WiFi card
- Camera: 1x CSI
- Video: HDMI / DSI0 (MIPI/LVDS) / DSI1 (MIPI/EDP)
- Audio: HDMI / MIC / Speaker / SPDIF / 3.5mm Headphones / AP6356S Bluetooth
- USB:
USB 2.0 HOST x2
USB 2.0 OTG x1 (shared with USB 3.0 OTG/HOST)
USB 3.0 HOST x1
USB 3.0 OTG/HOST x1
- SATA: 1x SATA 3.0 with Power/4-pin
- PCIe: 1x PCIe 3.0 x2 (x4 connector)
Link:
- https://image.chukouplus.com/upload/C_153/product_file/20211022/6daddec9e400458816dd4c57ba807fc3.pdf
- https://blog.gov.cooking/archives/research-graperain-g3568-v2-and-flash.html
Signed-off-by: Coia Prant <coiaprant@gmail.com>
---
arch/arm64/boot/dts/rockchip/Makefile | 1 +
.../rockchip/rk3568-graperain-g3568-v2.dts | 943 ++++++++++++++++++
2 files changed, 944 insertions(+)
create mode 100644 arch/arm64/boot/dts/rockchip/rk3568-graperain-g3568-v2.dts
diff --git a/arch/arm64/boot/dts/rockchip/Makefile b/arch/arm64/boot/dts/rockchip/Makefile
index 761d82b4f4f2a..6e9d049e8ddaf 100644
--- a/arch/arm64/boot/dts/rockchip/Makefile
+++ b/arch/arm64/boot/dts/rockchip/Makefile
@@ -144,6 +144,7 @@ dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3568-easepi-r1.dtb
dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3568-evb1-v10.dtb
dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3568-fastrhino-r66s.dtb
dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3568-fastrhino-r68s.dtb
+dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3568-graperain-g3568-v2.dtb
dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3568-hinlink-h66k.dtb
dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3568-hinlink-h68k.dtb
dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3568-lubancat-2.dtb
diff --git a/arch/arm64/boot/dts/rockchip/rk3568-graperain-g3568-v2.dts b/arch/arm64/boot/dts/rockchip/rk3568-graperain-g3568-v2.dts
new file mode 100644
index 0000000000000..5fc043b352042
--- /dev/null
+++ b/arch/arm64/boot/dts/rockchip/rk3568-graperain-g3568-v2.dts
@@ -0,0 +1,943 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+
+/dts-v1/;
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/input/input.h>
+#include <dt-bindings/leds/common.h>
+#include <dt-bindings/pinctrl/rockchip.h>
+#include <dt-bindings/soc/rockchip,vop2.h>
+#include "rk3568.dtsi"
+
+/ {
+ model = "Graperain G3568 v2";
+ compatible = "graperain,g3568-v2", "rockchip,rk3568";
+
+ aliases {
+ ethernet0 = &gmac0;
+ ethernet1 = &gmac1;
+ mmc0 = &sdhci;
+ mmc1 = &sdmmc0;
+ mmc2 = &sdmmc2;
+ rtc0 = &rtc0;
+ };
+
+ chosen {
+ stdout-path = "serial2:1500000n8";
+ };
+
+ adc-keys {
+ compatible = "adc-keys";
+ io-channels = <&saradc 0>;
+ io-channel-names = "buttons";
+ keyup-threshold-microvolt = <1800000>;
+ poll-interval = <100>;
+
+ button-esc {
+ label = "esc";
+ linux,code = <KEY_ESC>;
+ press-threshold-microvolt = <1250000>;
+ };
+
+ button-menu {
+ label = "menu";
+ linux,code = <KEY_MENU>;
+ press-threshold-microvolt = <1600000>;
+ };
+
+ button-vol-down {
+ label = "volume down";
+ linux,code = <KEY_VOLUMEDOWN>;
+ press-threshold-microvolt = <600000>;
+ };
+
+ button-vol-up {
+ label = "volume up";
+ linux,code = <KEY_VOLUMEUP>;
+ press-threshold-microvolt = <100000>;
+ };
+ };
+
+ hdmi-con {
+ compatible = "hdmi-connector";
+ type = "a";
+
+ port {
+ hdmi_con_in: endpoint {
+ remote-endpoint = <&hdmi_out_con>;
+ };
+ };
+ };
+
+ leds {
+ compatible = "gpio-leds";
+
+ led_work: led-0 {
+ gpios = <&gpio0 RK_PC0 GPIO_ACTIVE_HIGH>;
+ function = LED_FUNCTION_HEARTBEAT;
+ color = <LED_COLOR_ID_BLUE>;
+ linux,default-trigger = "heartbeat";
+ pinctrl-names = "default";
+ pinctrl-0 = <&led_work_en>;
+ };
+ };
+
+ rk809-sound {
+ compatible = "simple-audio-card";
+ simple-audio-card,format = "i2s";
+ simple-audio-card,name = "Analog RK809";
+ simple-audio-card,mclk-fs = <256>;
+
+ simple-audio-card,cpu {
+ sound-dai = <&i2s1_8ch>;
+ };
+ simple-audio-card,codec {
+ sound-dai = <&rk809>;
+ };
+ };
+
+ pdm_codec: pdm-codec {
+ compatible = "dmic-codec";
+ num-channels = <2>;
+ #sound-dai-cells = <0>;
+ };
+
+ pdm_sound: pdm-sound {
+ compatible = "simple-audio-card";
+ simple-audio-card,name = "microphone";
+
+ simple-audio-card,cpu {
+ sound-dai = <&pdm>;
+ };
+
+ simple-audio-card,codec {
+ sound-dai = <&pdm_codec>;
+ };
+ };
+
+ spdif_dit: spdif-dit {
+ compatible = "linux,spdif-dit";
+ #sound-dai-cells = <0>;
+ };
+
+ spdif_sound: spdif-sound {
+ compatible = "simple-audio-card";
+ simple-audio-card,name = "SPDIF";
+
+ simple-audio-card,cpu {
+ sound-dai = <&spdif>;
+ };
+ simple-audio-card,codec {
+ sound-dai = <&spdif_dit>;
+ };
+ };
+
+ sdio_pwrseq: sdio-pwrseq {
+ compatible = "mmc-pwrseq-simple";
+ clocks = <&rk809 1>;
+ clock-names = "ext_clock";
+ pinctrl-names = "default";
+ pinctrl-0 = <&wifi_enable>;
+ post-power-on-delay-ms = <100>;
+ power-off-delay-us = <300>;
+ reset-gpios = <&gpio3 RK_PD5 GPIO_ACTIVE_LOW>;
+ };
+
+ dc_12v: regulator-dc-12v {
+ compatible = "regulator-fixed";
+ regulator-name = "dc_12v";
+ regulator-always-on;
+ regulator-boot-on;
+ regulator-min-microvolt = <12000000>;
+ regulator-max-microvolt = <12000000>;
+ };
+
+ pcie30_avdd0v9: regulator-pcie30-avdd0v9 {
+ compatible = "regulator-fixed";
+ regulator-name = "pcie30_avdd0v9";
+ regulator-always-on;
+ regulator-boot-on;
+ regulator-min-microvolt = <900000>;
+ regulator-max-microvolt = <900000>;
+ vin-supply = <&vcc3v3_sys>;
+ };
+
+ pcie30_avdd1v8: regulator-pcie30-avdd1v8 {
+ compatible = "regulator-fixed";
+ regulator-name = "pcie30_avdd1v8";
+ regulator-always-on;
+ regulator-boot-on;
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ vin-supply = <&vcc3v3_sys>;
+ };
+
+ vcc3v3_sys: regulator-vcc3v3-sys {
+ compatible = "regulator-fixed";
+ regulator-name = "vcc3v3_sys";
+ regulator-always-on;
+ regulator-boot-on;
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ vin-supply = <&dc_12v>;
+ };
+
+ vcc3v3_pcie: regulator-vcc3v3-pcie {
+ compatible = "regulator-fixed";
+ enable-active-high;
+ gpios = <&gpio3 RK_PC3 GPIO_ACTIVE_HIGH>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&vcc3v3_pcie_en_pin>;
+ regulator-name = "vcc3v3_pcie";
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ startup-delay-us = <5000>;
+ vin-supply = <&dc_12v>;
+ };
+
+ vcc5v0_sys: regulator-vcc5v0-sys {
+ compatible = "regulator-fixed";
+ regulator-name = "vcc5v0_sys";
+ regulator-always-on;
+ regulator-boot-on;
+ regulator-min-microvolt = <5000000>;
+ regulator-max-microvolt = <5000000>;
+ vin-supply = <&dc_12v>;
+ };
+
+ vcc5v0_usb: regulator-vcc5v0-usb {
+ compatible = "regulator-fixed";
+ regulator-name = "vcc5v0_usb";
+ regulator-always-on;
+ regulator-boot-on;
+ regulator-min-microvolt = <5000000>;
+ regulator-max-microvolt = <5000000>;
+ vin-supply = <&dc_12v>;
+ };
+
+ vcc5v0_usb_host: regulator-vcc5v0-usb-host {
+ compatible = "regulator-fixed";
+ enable-active-high;
+ gpios = <&gpio0 RK_PA6 GPIO_ACTIVE_HIGH>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&vcc5v0_usb_host_en>;
+ regulator-name = "vcc5v0_usb_host";
+ regulator-min-microvolt = <5000000>;
+ regulator-max-microvolt = <5000000>;
+ vin-supply = <&vcc5v0_usb>;
+ };
+
+ vcc5v0_usb_otg: regulator-vcc5v0-usb-otg {
+ compatible = "regulator-fixed";
+ enable-active-high;
+ gpios = <&gpio0 RK_PA5 GPIO_ACTIVE_HIGH>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&vcc5v0_usb_otg_en>;
+ regulator-name = "vcc5v0_usb_otg";
+ regulator-min-microvolt = <5000000>;
+ regulator-max-microvolt = <5000000>;
+ vin-supply = <&vcc5v0_usb>;
+ };
+};
+
+&can1 {
+ assigned-clocks = <&cru CLK_CAN1>;
+ assigned-clock-rates = <150000000>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&can1m1_pins>;
+ status = "okay";
+};
+
+/* used for usb_host0_xhci */
+&combphy0 {
+ status = "okay";
+};
+
+/* used for usb_host1_xhci */
+&combphy1 {
+ status = "okay";
+};
+
+/* connected to sata2 */
+&combphy2 {
+ status = "okay";
+};
+
+&cpu0 {
+ cpu-supply = <&vdd_cpu>;
+};
+
+&cpu1 {
+ cpu-supply = <&vdd_cpu>;
+};
+
+&cpu2 {
+ cpu-supply = <&vdd_cpu>;
+};
+
+&cpu3 {
+ cpu-supply = <&vdd_cpu>;
+};
+
+&gmac0 {
+ assigned-clocks = <&cru SCLK_GMAC0_RX_TX>, <&cru SCLK_GMAC0>;
+ assigned-clock-parents = <&cru SCLK_GMAC0_RGMII_SPEED>;
+ assigned-clock-rates = <0>, <125000000>;
+ clock_in_out = "output";
+ pinctrl-names = "default";
+ pinctrl-0 = <&gmac0_miim
+ &gmac0_tx_bus2
+ &gmac0_rx_bus2
+ &gmac0_rgmii_clk
+ &gmac0_rgmii_bus>;
+ phy-handle = <&rgmii_phy0>;
+ phy-mode = "rgmii-id";
+ status = "okay";
+};
+
+&gmac1 {
+ assigned-clocks = <&cru SCLK_GMAC1_RX_TX>, <&cru SCLK_GMAC1>;
+ assigned-clock-parents = <&cru SCLK_GMAC1_RGMII_SPEED>;
+ assigned-clock-rates = <0>, <125000000>;
+ clock_in_out = "output";
+ pinctrl-names = "default";
+ pinctrl-0 = <&gmac1m1_miim
+ &gmac1m1_tx_bus2
+ &gmac1m1_rx_bus2
+ &gmac1m1_rgmii_clk
+ &gmac1m1_rgmii_bus>;
+ phy-handle = <&rgmii_phy1>;
+ phy-mode = "rgmii-id";
+ status = "okay";
+};
+
+&gpu {
+ mali-supply = <&vdd_gpu>;
+ status = "okay";
+};
+
+&hdmi {
+ avdd-0v9-supply = <&vdda0v9_image>;
+ avdd-1v8-supply = <&vcca1v8_image>;
+ status = "okay";
+};
+
+&hdmi_in {
+ hdmi_in_vp0: endpoint {
+ remote-endpoint = <&vp0_out_hdmi>;
+ };
+};
+
+&hdmi_out {
+ hdmi_out_con: endpoint {
+ remote-endpoint = <&hdmi_con_in>;
+ };
+};
+
+&hdmi_sound {
+ status = "okay";
+};
+
+&i2c0 {
+ status = "okay";
+
+ vdd_cpu: regulator@1c {
+ compatible = "tcs,tcs4525";
+ reg = <0x1c>;
+ fcs,suspend-voltage-selector = <1>;
+ regulator-name = "vdd_cpu";
+ regulator-always-on;
+ regulator-boot-on;
+ regulator-min-microvolt = <800000>;
+ regulator-max-microvolt = <1150000>;
+ regulator-ramp-delay = <2300>;
+ vin-supply = <&vcc5v0_sys>;
+
+ regulator-state-mem {
+ regulator-off-in-suspend;
+ };
+ };
+
+ rk809: pmic@20 {
+ compatible = "rockchip,rk809";
+ reg = <0x20>;
+ interrupt-parent = <&gpio0>;
+ interrupts = <RK_PA3 IRQ_TYPE_LEVEL_LOW>;
+ assigned-clocks = <&cru I2S1_MCLKOUT_TX>;
+ assigned-clock-parents = <&cru CLK_I2S1_8CH_TX>;
+ #clock-cells = <1>;
+ clock-names = "mclk";
+ clocks = <&cru I2S1_MCLKOUT_TX>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pmic_int>, <&i2s1m0_mclk>;
+ system-power-controller;
+ #sound-dai-cells = <0>;
+ vcc1-supply = <&vcc3v3_sys>;
+ vcc2-supply = <&vcc3v3_sys>;
+ vcc3-supply = <&vcc3v3_sys>;
+ vcc4-supply = <&vcc3v3_sys>;
+ vcc5-supply = <&vcc3v3_sys>;
+ vcc6-supply = <&vcc3v3_sys>;
+ vcc7-supply = <&vcc3v3_sys>;
+ vcc8-supply = <&vcc3v3_sys>;
+ vcc9-supply = <&vcc3v3_sys>;
+ wakeup-source;
+
+ regulators {
+ vdd_logic: DCDC_REG1 {
+ regulator-name = "vdd_logic";
+ regulator-always-on;
+ regulator-boot-on;
+ regulator-initial-mode = <0x2>;
+ regulator-min-microvolt = <500000>;
+ regulator-max-microvolt = <1350000>;
+ regulator-ramp-delay = <6001>;
+
+ regulator-state-mem {
+ regulator-off-in-suspend;
+ };
+ };
+
+ vdd_gpu: DCDC_REG2 {
+ regulator-name = "vdd_gpu";
+ regulator-always-on;
+ regulator-initial-mode = <0x2>;
+ regulator-min-microvolt = <500000>;
+ regulator-max-microvolt = <1350000>;
+ regulator-ramp-delay = <6001>;
+
+ regulator-state-mem {
+ regulator-off-in-suspend;
+ };
+ };
+
+ vcc_ddr: DCDC_REG3 {
+ regulator-name = "vcc_ddr";
+ regulator-always-on;
+ regulator-boot-on;
+ regulator-initial-mode = <0x2>;
+
+ regulator-state-mem {
+ regulator-on-in-suspend;
+ };
+ };
+
+ vdd_npu: DCDC_REG4 {
+ regulator-name = "vdd_npu";
+ regulator-initial-mode = <0x2>;
+ regulator-min-microvolt = <500000>;
+ regulator-max-microvolt = <1350000>;
+ regulator-ramp-delay = <6001>;
+
+ regulator-state-mem {
+ regulator-off-in-suspend;
+ };
+ };
+
+ vcc_1v8: DCDC_REG5 {
+ regulator-name = "vcc_1v8";
+ regulator-always-on;
+ regulator-boot-on;
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+
+ regulator-state-mem {
+ regulator-off-in-suspend;
+ };
+ };
+
+ vdda0v9_image: LDO_REG1 {
+ regulator-name = "vdda0v9_image";
+ regulator-min-microvolt = <900000>;
+ regulator-max-microvolt = <900000>;
+
+ regulator-state-mem {
+ regulator-off-in-suspend;
+ };
+ };
+
+ vdda_0v9: LDO_REG2 {
+ regulator-name = "vdda_0v9";
+ regulator-always-on;
+ regulator-boot-on;
+ regulator-min-microvolt = <900000>;
+ regulator-max-microvolt = <900000>;
+
+ regulator-state-mem {
+ regulator-off-in-suspend;
+ };
+ };
+
+ vdda0v9_pmu: LDO_REG3 {
+ regulator-name = "vdda0v9_pmu";
+ regulator-always-on;
+ regulator-boot-on;
+ regulator-min-microvolt = <900000>;
+ regulator-max-microvolt = <900000>;
+
+ regulator-state-mem {
+ regulator-on-in-suspend;
+ regulator-suspend-microvolt = <900000>;
+ };
+ };
+
+ vccio_acodec: LDO_REG4 {
+ regulator-name = "vccio_acodec";
+ regulator-always-on;
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+
+ regulator-state-mem {
+ regulator-off-in-suspend;
+ };
+ };
+
+ vccio_sd: LDO_REG5 {
+ regulator-name = "vccio_sd";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <3300000>;
+
+ regulator-state-mem {
+ regulator-off-in-suspend;
+ };
+ };
+
+ vcc3v3_pmu: LDO_REG6 {
+ regulator-name = "vcc3v3_pmu";
+ regulator-always-on;
+ regulator-boot-on;
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+
+ regulator-state-mem {
+ regulator-on-in-suspend;
+ regulator-suspend-microvolt = <3300000>;
+ };
+ };
+
+ vcca_1v8: LDO_REG7 {
+ regulator-name = "vcca_1v8";
+ regulator-always-on;
+ regulator-boot-on;
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+
+ regulator-state-mem {
+ regulator-off-in-suspend;
+ };
+ };
+
+ vcca1v8_pmu: LDO_REG8 {
+ regulator-name = "vcca1v8_pmu";
+ regulator-always-on;
+ regulator-boot-on;
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+
+ regulator-state-mem {
+ regulator-on-in-suspend;
+ regulator-suspend-microvolt = <1800000>;
+ };
+ };
+
+ vcca1v8_image: LDO_REG9 {
+ regulator-name = "vcca1v8_image";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+
+ regulator-state-mem {
+ regulator-off-in-suspend;
+ };
+ };
+
+ vcc_3v3: SWITCH_REG1 {
+ regulator-name = "vcc_3v3";
+ regulator-always-on;
+ regulator-boot-on;
+
+ regulator-state-mem {
+ regulator-off-in-suspend;
+ };
+ };
+
+ vcc3v3_sd: SWITCH_REG2 {
+ regulator-name = "vcc3v3_sd";
+
+ regulator-state-mem {
+ regulator-off-in-suspend;
+ };
+ };
+ };
+
+ codec {
+ rockchip,mic-in-differential;
+ };
+ };
+};
+
+&i2c5 {
+ status = "okay";
+
+ rtc0: rtc@51 {
+ compatible = "nxp,pcf8563";
+ reg = <0x51>;
+ #clock-cells = <0>;
+ };
+};
+
+&i2s0_8ch {
+ status = "okay";
+};
+
+&i2s1_8ch {
+ pinctrl-0 = <&i2s1m0_sclktx &i2s1m0_lrcktx &i2s1m0_sdi0 &i2s1m0_sdo0>;
+ rockchip,trcm-sync-tx-only;
+ status = "okay";
+};
+
+/* required rk3568-codec-digital for AP6356S Bluetooth Sound */
+&i2s3_2ch {
+ status = "disabled";
+};
+
+&mdio0 {
+ rgmii_phy0: ethernet-phy@1 {
+ compatible = "ethernet-phy-ieee802.3-c22";
+ reg = <1>;
+ reset-assert-us = <20000>;
+ reset-deassert-us = <100000>;
+ reset-gpios = <&gpio2 RK_PD3 GPIO_ACTIVE_LOW>;
+
+ leds {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ led@1 {
+ reg = <1>;
+ color = <LED_COLOR_ID_GREEN>;
+ function = LED_FUNCTION_LAN;
+ default-state = "keep";
+ };
+
+ led@2 {
+ reg = <2>;
+ color = <LED_COLOR_ID_AMBER>;
+ function = LED_FUNCTION_LAN;
+ default-state = "keep";
+ };
+ };
+ };
+};
+
+&mdio1 {
+ rgmii_phy1: ethernet-phy@1 {
+ compatible = "ethernet-phy-ieee802.3-c22";
+ reg = <1>;
+ reset-assert-us = <20000>;
+ reset-deassert-us = <100000>;
+ reset-gpios = <&gpio2 RK_PD1 GPIO_ACTIVE_LOW>;
+
+ leds {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ led@1 {
+ reg = <1>;
+ color = <LED_COLOR_ID_GREEN>;
+ function = LED_FUNCTION_LAN;
+ default-state = "keep";
+ };
+
+ led@2 {
+ reg = <2>;
+ color = <LED_COLOR_ID_AMBER>;
+ function = LED_FUNCTION_LAN;
+ default-state = "keep";
+ };
+ };
+ };
+};
+
+&pcie30phy {
+ status = "okay";
+};
+
+&pcie3x2 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pcie_reset_pin>;
+ reset-gpios = <&gpio2 RK_PD6 GPIO_ACTIVE_HIGH>;
+ vpcie3v3-supply = <&vcc3v3_pcie>;
+ status = "okay";
+};
+
+&pdm {
+ status = "okay";
+};
+
+&pinctrl {
+ bluetooth {
+ bt_reg_on_h: bt-reg-on-h {
+ rockchip,pins = <3 RK_PA0 RK_FUNC_GPIO &pcfg_pull_none>;
+ };
+
+ bt_wake_host_h: bt-wake-host-h {
+ rockchip,pins = <3 RK_PA1 RK_FUNC_GPIO &pcfg_pull_down>;
+ };
+
+ host_wake_bt_h: host-wake-bt-h {
+ rockchip,pins = <3 RK_PA2 RK_FUNC_GPIO &pcfg_pull_none>;
+ };
+ };
+
+ leds {
+ led_work_en: led_work_en {
+ rockchip,pins = <0 RK_PC0 RK_FUNC_GPIO &pcfg_pull_none>;
+ };
+ };
+
+ pmic {
+ pmic_int: pmic_int {
+ rockchip,pins = <0 RK_PA3 RK_FUNC_GPIO &pcfg_pull_up>;
+ };
+ };
+
+ sdio-pwrseq {
+ wifi_enable: wifi-enable {
+ rockchip,pins = <3 RK_PD5 RK_FUNC_GPIO &pcfg_pull_none>;
+ };
+ };
+
+ usb {
+ vcc5v0_usb_host_en: vcc5v0_usb_host_en {
+ rockchip,pins = <0 RK_PA6 RK_FUNC_GPIO &pcfg_pull_none>;
+ };
+ vcc5v0_usb_otg_en: vcc5v0_usb_otg_en {
+ rockchip,pins = <0 RK_PA5 RK_FUNC_GPIO &pcfg_pull_none>;
+ };
+ };
+
+ pcie {
+ pcie_reset_pin: pcie-reset-pin {
+ rockchip,pins = <2 RK_PD6 RK_FUNC_GPIO &pcfg_pull_none>;
+ };
+ vcc3v3_pcie_en_pin: vcc3v3-pcie-en-pin {
+ rockchip,pins = <3 RK_PC3 RK_FUNC_GPIO &pcfg_pull_none>;
+ };
+ };
+
+ wifi-irq {
+ wifi_host_wake_irq: wifi-host-wake-irq {
+ rockchip,pins = <3 RK_PD4 RK_FUNC_GPIO &pcfg_pull_down>;
+ };
+ };
+};
+
+&pmu_io_domains {
+ pmuio1-supply = <&vcc3v3_pmu>;
+ pmuio2-supply = <&vcc3v3_pmu>;
+ vccio1-supply = <&vccio_acodec>;
+ vccio2-supply = <&vcc_1v8>;
+ vccio3-supply = <&vccio_sd>;
+ vccio4-supply = <&vcc_1v8>;
+ vccio5-supply = <&vcc_3v3>;
+ vccio6-supply = <&vcc_1v8>;
+ vccio7-supply = <&vcc_3v3>;
+ status = "okay";
+};
+
+&pwm4 {
+ status = "okay";
+};
+
+&pwm5 {
+ status = "okay";
+};
+
+/* Required remotectl for IR receiver */
+&pwm7 {
+ status = "disabled";
+};
+
+&saradc {
+ vref-supply = <&vcca_1v8>;
+ status = "okay";
+};
+
+&sata2 {
+ status = "okay";
+};
+
+/* used for eMMC */
+&sdhci {
+ bus-width = <8>;
+ max-frequency = <200000000>;
+ mmc-hs200-1_8v;
+ non-removable;
+ pinctrl-names = "default";
+ pinctrl-0 = <&emmc_bus8 &emmc_clk &emmc_cmd &emmc_datastrobe>;
+ status = "okay";
+};
+
+/* used for microSD (TF) Slot */
+&sdmmc0 {
+ bus-width = <4>;
+ cap-sd-highspeed;
+ cd-gpios = <&gpio0 RK_PA4 GPIO_ACTIVE_LOW>;
+ disable-wp;
+ pinctrl-names = "default";
+ pinctrl-0 = <&sdmmc0_bus4 &sdmmc0_clk &sdmmc0_cmd &sdmmc0_det>;
+ sd-uhs-sdr104;
+ vmmc-supply = <&vcc3v3_sd>;
+ vqmmc-supply = <&vccio_sd>;
+ status = "okay";
+};
+
+/* used for AP6356S WiFi */
+&sdmmc2 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ bus-width = <4>;
+ cap-sd-highspeed;
+ cap-sdio-irq;
+ keep-power-in-suspend;
+ mmc-pwrseq = <&sdio_pwrseq>;
+ non-removable;
+ pinctrl-names = "default";
+ pinctrl-0 = <&sdmmc2m0_bus4 &sdmmc2m0_cmd &sdmmc2m0_clk>;
+ sd-uhs-sdr104;
+ vmmc-supply = <&vcc3v3_sys>;
+ vqmmc-supply = <&vcc_1v8>;
+ status = "okay";
+
+ wifi@1 {
+ compatible = "brcm,bcm4356-fmac", "brcm,bcm4329-fmac";
+ reg = <1>;
+ interrupt-parent = <&gpio3>;
+ interrupts = <RK_PD4 IRQ_TYPE_LEVEL_LOW>;
+ interrupt-names = "host-wake";
+ pinctrl-names = "default";
+ pinctrl-0 = <&wifi_host_wake_irq>;
+ };
+};
+
+&spdif {
+ status = "okay";
+};
+
+&tsadc {
+ rockchip,hw-tshut-mode = <1>;
+ rockchip,hw-tshut-polarity = <0>;
+ status = "okay";
+};
+
+/* used for Debug */
+&uart2 {
+ status = "okay";
+};
+
+&uart3 {
+ pinctrl-0 = <&uart3m1_xfer>;
+ status = "okay";
+};
+
+&uart4 {
+ pinctrl-0 = <&uart4m1_xfer>;
+ status = "okay";
+};
+
+/* used for AP6356S Bluetooth */
+&uart8 {
+ dma-names = "tx", "rx";
+ pinctrl-names = "default";
+ pinctrl-0 = <&uart8m0_xfer &uart8m0_ctsn &uart8m0_rtsn>;
+ uart-has-rtscts;
+ status = "okay";
+
+ bluetooth {
+ compatible = "brcm,bcm4345c5";
+ clocks = <&rk809 1>;
+ clock-names = "lpo";
+ device-wakeup-gpios = <&gpio3 RK_PA2 GPIO_ACTIVE_HIGH>;
+ host-wakeup-gpios = <&gpio3 RK_PA1 GPIO_ACTIVE_HIGH>;
+ max-speed = <1500000>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&bt_reg_on_h &bt_wake_host_h &host_wake_bt_h>;
+ shutdown-gpios = <&gpio3 RK_PA0 GPIO_ACTIVE_HIGH>;
+ vddio-supply = <&vcc_1v8>;
+ };
+};
+
+&uart9 {
+ pinctrl-0 = <&uart9m1_xfer>;
+ status = "okay";
+};
+
+&usb_host0_ehci {
+ status = "okay";
+};
+
+&usb_host0_ohci {
+ status = "okay";
+};
+
+&usb_host0_xhci {
+ extcon = <&usb2phy0>;
+ status = "okay";
+};
+
+&usb_host1_ehci {
+ status = "okay";
+};
+
+&usb_host1_ohci {
+ status = "okay";
+};
+
+&usb_host1_xhci {
+ status = "okay";
+};
+
+&usb2phy0 {
+ status = "okay";
+};
+
+&usb2phy0_host {
+ phy-supply = <&vcc5v0_usb_host>;
+ status = "okay";
+};
+
+&usb2phy0_otg {
+ phy-supply = <&vcc5v0_usb_otg>;
+ status = "okay";
+};
+
+&usb2phy1 {
+ status = "okay";
+};
+
+&usb2phy1_host {
+ phy-supply = <&vcc5v0_usb_host>;
+ status = "okay";
+};
+
+&usb2phy1_otg {
+ phy-supply = <&vcc5v0_usb_host>;
+ status = "okay";
+};
+
+&vop {
+ assigned-clocks = <&cru DCLK_VOP0>, <&cru DCLK_VOP1>;
+ assigned-clock-parents = <&pmucru PLL_HPLL>, <&cru PLL_VPLL>;
+ status = "okay";
+};
+
+&vop_mmu {
+ status = "okay";
+};
+
+&vp0 {
+ vp0_out_hdmi: endpoint@ROCKCHIP_VOP2_EP_HDMI0 {
+ reg = <ROCKCHIP_VOP2_EP_HDMI0>;
+ remote-endpoint = <&hdmi_in_vp0>;
+ };
+};
--
2.47.3
^ permalink raw reply related
* [PATCH v11 1/9] perf cs-etm: Fix thread leaks on trace queue init failure
From: Leo Yan @ 2026-07-02 19:51 UTC (permalink / raw)
To: Arnaldo Carvalho de Melo, John Garry, Will Deacon, James Clark,
Mike Leach, Suzuki K Poulose, Namhyung Kim, Mark Rutland,
Alexander Shishkin, Jiri Olsa, Ian Rogers, Adrian Hunter,
Al Grant, Paschalis Mpeis, Amir Ayupov
Cc: linux-arm-kernel, coresight, linux-perf-users, Leo Yan
In-Reply-To: <20260702-b4-arm_cs_callchain_support_v1-v11-0-846abbf600d7@arm.com>
cs_etm__init_traceid_queue() allocates the frontend and decode threads,
if a later allocation fails, the error path does not drop thread
reference that was already acquired.
Release both thread pointers with thread__zput() on the error path, so
does not leak thread references or leave stale pointers behind.
Fixes: 951ccccdc715 ("perf cs-etm: Only track threads instead of PID and TIDs")
Reviewed-by: James Clark <james.clark@linaro.org>
Signed-off-by: Leo Yan <leo.yan@arm.com>
---
tools/perf/util/cs-etm.c | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/tools/perf/util/cs-etm.c b/tools/perf/util/cs-etm.c
index 2284cda78abe1341d3823d2cfed027e711ff7e62..deca07d57282e431ff4d86350e222092930d330f 100644
--- a/tools/perf/util/cs-etm.c
+++ b/tools/perf/util/cs-etm.c
@@ -645,6 +645,8 @@ static int cs_etm__init_traceid_queue(struct cs_etm_queue *etmq,
queue->tid);
tidq->decode_thread = machine__findnew_thread(&etm->session->machines.host, -1,
queue->tid);
+ if (!tidq->frontend_thread || !tidq->decode_thread)
+ goto out;
tidq->packet = zalloc(sizeof(struct cs_etm_packet));
if (!tidq->packet)
@@ -679,6 +681,8 @@ static int cs_etm__init_traceid_queue(struct cs_etm_queue *etmq,
zfree(&tidq->prev_packet);
zfree(&tidq->packet);
out:
+ thread__zput(tidq->frontend_thread);
+ thread__zput(tidq->decode_thread);
return rc;
}
--
2.34.1
^ permalink raw reply related
* [PATCH v11 2/9] perf cs-etm: Filter synthesized branch samples
From: Leo Yan @ 2026-07-02 19:51 UTC (permalink / raw)
To: Arnaldo Carvalho de Melo, John Garry, Will Deacon, James Clark,
Mike Leach, Suzuki K Poulose, Namhyung Kim, Mark Rutland,
Alexander Shishkin, Jiri Olsa, Ian Rogers, Adrian Hunter,
Al Grant, Paschalis Mpeis, Amir Ayupov
Cc: linux-arm-kernel, coresight, linux-perf-users, Leo Yan, Leo Yan
In-Reply-To: <20260702-b4-arm_cs_callchain_support_v1-v11-0-846abbf600d7@arm.com>
From: Leo Yan <leo.yan@linaro.org>
The itrace 'c' and 'r' options request synthesized branch events for
calls and returns only. For perf script the default itrace options are
"--itrace=ce", so CS ETM should emit call branches and error events by
default.
CS ETM currently synthesizes a branch sample for every decoded taken
branch whenever branch synthesis is enabled. This produces redundant
jump and conditional branch samples.
Add a branch filter derived from the itrace calls and returns options.
When neither option is set, keep the existing behavior and synthesize all
branch samples. When calls or returns are requested, emit only branch
samples whose flags match the selected branch type, while preserving trace
begin/end markers.
Also update test_arm_coresight_disasm.sh and arm-cs-trace-disasm.py
to use the --itrace=b option for generating branch samples.
Before:
perf script -F,+flags
callchain_test 6114 [005] 331519.825214: 1 branches: tr strt jmp 0 [unknown] ([unknown]) => ffff8000803a3a68 perf_report_aux_output_id+0x50 ([kernel.kallsyms])
callchain_test 6114 [005] 331519.825214: 1 branches: call ffff8000803a3a74 perf_report_aux_output_id+0x5c ([kernel.kallsyms]) => ffff8000817f4d88 memset+0x0 ([kernel.kallsyms])
callchain_test 6114 [005] 331519.825214: 1 branches: jmp ffff8000817f4d8c memset+0x4 ([kernel.kallsyms]) => ffff8000817f4c00 __pi_memset_generic+0x0 ([kernel.kallsyms])
callchain_test 6114 [005] 331519.825214: 1 branches: jcc ffff8000817f4c1c __pi_memset_generic+0x1c ([kernel.kallsyms]) => ffff8000817f4c44 __pi_memset_generic+0x44 ([kernel.kallsyms])
callchain_test 6114 [005] 331519.825214: 1 branches: jcc ffff8000817f4c4c __pi_memset_generic+0x4c ([kernel.kallsyms]) => ffff8000817f4c5c __pi_memset_generic+0x5c ([kernel.kallsyms])
callchain_test 6114 [005] 331519.825214: 1 branches: jcc ffff8000817f4c5c __pi_memset_generic+0x5c ([kernel.kallsyms]) => ffff8000817f4cf0 __pi_memset_generic+0xf0 ([kernel.kallsyms])
callchain_test 6114 [005] 331519.825214: 1 branches: jcc ffff8000817f4d30 __pi_memset_generic+0x130 ([kernel.kallsyms]) => ffff8000817f4d68 __pi_memset_generic+0x168 ([kernel.kallsyms])
callchain_test 6114 [005] 331519.825214: 1 branches: jcc ffff8000817f4d78 __pi_memset_generic+0x178 ([kernel.kallsyms]) => ffff8000817f4d6c __pi_memset_generic+0x16c ([kernel.kallsyms])
callchain_test 6114 [005] 331519.825214: 1 branches: jcc ffff8000817f4d78 __pi_memset_generic+0x178 ([kernel.kallsyms]) => ffff8000817f4d6c __pi_memset_generic+0x16c ([kernel.kallsyms])
callchain_test 6114 [005] 331519.825214: 1 branches: jcc ffff8000817f4d78 __pi_memset_generic+0x178 ([kernel.kallsyms]) => ffff8000817f4d6c __pi_memset_generic+0x16c ([kernel.kallsyms])
callchain_test 6114 [005] 331519.825214: 1 branches: return ffff8000817f4d84 __pi_memset_generic+0x184 ([kernel.kallsyms]) => ffff8000803a3a78 perf_report_aux_output_id+0x60 ([kernel.kallsyms])
callchain_test 6114 [005] 331519.825214: 1 branches: jcc ffff8000803a3a98 perf_report_aux_output_id+0x80 ([kernel.kallsyms]) => ffff8000803a3b04 perf_report_aux_output_id+0xec ([kernel.kallsyms])
callchain_test 6114 [005] 331519.825214: 1 branches: call ffff8000803a3b1c perf_report_aux_output_id+0x104 ([kernel.kallsyms]) => ffff8000803a38f8 __perf_event_header__init_id+0x0 ([kernel.kallsyms])
After:
callchain_test 6114 [005] 331519.825214: 1 branches: tr strt jmp 0 [unknown] ([unknown]) => ffff8000803a3a68 perf_report_aux_output_id+0x50 ([kernel.kallsyms])
callchain_test 6114 [005] 331519.825214: 1 branches: call ffff8000803a3a74 perf_report_aux_output_id+0x5c ([kernel.kallsyms]) => ffff8000817f4d88 memset+0x0 ([kernel.kallsyms])
callchain_test 6114 [005] 331519.825214: 1 branches: call ffff8000803a3b1c perf_report_aux_output_id+0x104 ([kernel.kallsyms]) => ffff8000803a38f8 __perf_event_header__init_id+0x0 ([kernel.kallsyms])
callchain_test 6114 [005] 331519.825214: 1 branches: call ffff8000803a39c0 __perf_event_header__init_id+0xc8 ([kernel.kallsyms]) => ffff800080105258 __task_pid_nr_ns+0x0 ([kernel.kallsyms])
callchain_test 6114 [005] 331519.825214: 1 branches: call ffff80008010528c __task_pid_nr_ns+0x34 ([kernel.kallsyms]) => ffff8000801d5610 __rcu_read_lock+0x0 ([kernel.kallsyms])
callchain_test 6114 [005] 331519.825214: 1 branches: call ffff8000801052b0 __task_pid_nr_ns+0x58 ([kernel.kallsyms]) => ffff800080192078 lock_acquire+0x0 ([kernel.kallsyms])
callchain_test 6114 [005] 331519.825214: 1 branches: call ffff8000801923f4 lock_acquire+0x37c ([kernel.kallsyms]) => ffff8000801d6da0 rcu_is_watching+0x0 ([kernel.kallsyms])
Fixes: b12235b113cf ("perf tools: Add mechanic to synthesise CoreSight trace packets")
Signed-off-by: Leo Yan <leo.yan@linaro.org>
Reviewed-by: James Clark <james.clark@linaro.org>
Signed-off-by: Leo Yan <leo.yan@arm.com>
---
tools/perf/scripts/python/arm-cs-trace-disasm.py | 9 +++++----
.../tests/shell/coresight/test_arm_coresight_disasm.sh | 4 ++--
tools/perf/util/cs-etm.c | 15 +++++++++++++++
3 files changed, 22 insertions(+), 6 deletions(-)
diff --git a/tools/perf/scripts/python/arm-cs-trace-disasm.py b/tools/perf/scripts/python/arm-cs-trace-disasm.py
index 8f6fa4a007b42fcc98e71b74b36ba3a61d7acb2f..42579f8586842704d3800ad731d4609d2bb968da 100755
--- a/tools/perf/scripts/python/arm-cs-trace-disasm.py
+++ b/tools/perf/scripts/python/arm-cs-trace-disasm.py
@@ -31,18 +31,19 @@ from perf_trace_context import perf_sample_srccode, perf_config_get
#
# Output disassembly with objdump and auto detect vmlinux
# (when running on same machine.):
-# perf script -s scripts/python/arm-cs-trace-disasm.py -d
+# perf script --itrace=b -s scripts/python/arm-cs-trace-disasm.py \
+# -- -d
#
# Output disassembly with llvm-objdump:
-# perf script -s scripts/python/arm-cs-trace-disasm.py \
+# perf script --itrace=b -s scripts/python/arm-cs-trace-disasm.py \
# -- -d llvm-objdump-11 -k path/to/vmlinux
#
# Output accurate disassembly by passing kcore to script:
-# perf script -s scripts/python/arm-cs-trace-disasm.py \
+# perf script --itrace=b -s scripts/python/arm-cs-trace-disasm.py \
# -- -d -k perf.data/kcore_dir/kcore
#
# Output only source line and symbols:
-# perf script -s scripts/python/arm-cs-trace-disasm.py
+# perf script --itrace=b -s scripts/python/arm-cs-trace-disasm.py
def default_objdump():
config = perf_config_get("annotate.objdump")
diff --git a/tools/perf/tests/shell/coresight/test_arm_coresight_disasm.sh b/tools/perf/tests/shell/coresight/test_arm_coresight_disasm.sh
index ccb90dda24758522be12cba27140abc9b60d8261..f3ebad5963783e9ae74be5b046d20c3f2e01a5a1 100755
--- a/tools/perf/tests/shell/coresight/test_arm_coresight_disasm.sh
+++ b/tools/perf/tests/shell/coresight/test_arm_coresight_disasm.sh
@@ -44,7 +44,7 @@ branch_search='[[:space:]](bl|b(\.(eq|ne|cs|cc|mi|pl|vs|vc|hi|ls|ge|lt|gt|le|al)
if [ "$(id -u)" == 0 ] && [ -e /proc/kcore ]; then
echo "Testing kernel disassembly"
perf record -o ${perfdata} -e cs_etm//k --kcore -Se -m,64K -- touch $file > /dev/null 2>&1
- perf script -i ${perfdata} -s python:${script_path} -- \
+ perf script -i ${perfdata} --itrace=b -s python:${script_path} -- \
-d --stop-sample=2 -k ${perfdata}/kcore_dir/kcore 2> /dev/null > ${file}
grep -q -E ${branch_search} ${file}
echo "Found kernel branches"
@@ -56,7 +56,7 @@ fi
## Test user ##
echo "Testing userspace disassembly"
perf record -o ${perfdata} -e cs_etm//u -Se -m,64K -- touch $file > /dev/null 2>&1
-perf script -i ${perfdata} -s python:${script_path} -- \
+perf script -i ${perfdata} --itrace=b -s python:${script_path} -- \
-d --stop-sample=2 2> /dev/null > ${file}
grep -q -E ${branch_search} ${file}
echo "Found userspace branches"
diff --git a/tools/perf/util/cs-etm.c b/tools/perf/util/cs-etm.c
index deca07d57282e431ff4d86350e222092930d330f..95530e10e010c3c31f9a9c4b6c89b782c66c03b5 100644
--- a/tools/perf/util/cs-etm.c
+++ b/tools/perf/util/cs-etm.c
@@ -71,6 +71,7 @@ struct cs_etm_auxtrace {
int num_cpu;
u64 latest_kernel_timestamp;
u32 auxtrace_type;
+ u32 branches_filter;
u64 branches_sample_type;
u64 branches_id;
u64 instructions_sample_type;
@@ -1705,6 +1706,10 @@ static int cs_etm__synth_branch_sample(struct cs_etm_queue *etmq,
} dummy_bs;
u64 ip;
+ if (etm->branches_filter &&
+ !(etm->branches_filter & tidq->prev_packet->flags))
+ return 0;
+
perf_sample__init(&sample, /*all=*/true);
ip = cs_etm__last_executed_instr(tidq->prev_packet);
@@ -3564,6 +3569,16 @@ int cs_etm__process_auxtrace_info_full(union perf_event *event,
etm->synth_opts.callchain = false;
}
+ if (etm->synth_opts.calls)
+ etm->branches_filter |= PERF_IP_FLAG_CALL |
+ PERF_IP_FLAG_TRACE_BEGIN |
+ PERF_IP_FLAG_TRACE_END;
+
+ if (etm->synth_opts.returns)
+ etm->branches_filter |= PERF_IP_FLAG_RETURN |
+ PERF_IP_FLAG_TRACE_BEGIN |
+ PERF_IP_FLAG_TRACE_END;
+
etm->session = session;
etm->num_cpu = num_cpu;
--
2.34.1
^ permalink raw reply related
* [PATCH v11 5/9] perf cs-etm: Use thread-stack for last branch entries
From: Leo Yan @ 2026-07-02 19:51 UTC (permalink / raw)
To: Arnaldo Carvalho de Melo, John Garry, Will Deacon, James Clark,
Mike Leach, Suzuki K Poulose, Namhyung Kim, Mark Rutland,
Alexander Shishkin, Jiri Olsa, Ian Rogers, Adrian Hunter,
Al Grant, Paschalis Mpeis, Amir Ayupov
Cc: linux-arm-kernel, coresight, linux-perf-users, Leo Yan
In-Reply-To: <20260702-b4-arm_cs_callchain_support_v1-v11-0-846abbf600d7@arm.com>
CS ETM maintains its own circular array for last branch entries, with
local helpers to update, copy and reset the branch stack. This
duplicates logic already provided by the common code.
Record taken branches with thread_stack__event() and synthesize
PERF_SAMPLE_BRANCH_STACK data with thread_stack__br_sample(). This
removes the private last_branch_rb buffer and its position tracking.
This also makes the branch history state belong to the thread rather
than the trace queue. That is a better fit for CoreSight traces where
a trace queue can effectively be CPU scoped, while call/return history
is per thread.
Keep the buffer number updated via thread_stack__set_trace_nr(), which
is used when exporting samples to Python scripts. Pass callstack=false
for now; synthesized callchains are added by a later patch.
The output should remain same, except that be->flags.predicted is no
longer set. Since CoreSight trace does not provide branch prediction
information, clearing the flag avoids confusion.
Reviewed-by: James Clark <james.clark@linaro.org>
Signed-off-by: Leo Yan <leo.yan@arm.com>
---
tools/perf/util/cs-etm.c | 173 ++++++++++++++++-------------------------------
1 file changed, 58 insertions(+), 115 deletions(-)
diff --git a/tools/perf/util/cs-etm.c b/tools/perf/util/cs-etm.c
index 838c2d00471333b86d33aa86972a3e852ba6502e..ba9ffb7bdb4bd95c9dc6c323c0d56f516aae56b8 100644
--- a/tools/perf/util/cs-etm.c
+++ b/tools/perf/util/cs-etm.c
@@ -85,10 +85,9 @@ struct cs_etm_auxtrace {
struct cs_etm_traceid_queue {
u8 trace_chan_id;
u64 period_instructions;
- size_t last_branch_pos;
union perf_event *event_buf;
+ unsigned int br_stack_sz;
struct branch_stack *last_branch;
- struct branch_stack *last_branch_rb;
struct cs_etm_packet *prev_packet;
struct cs_etm_packet *packet;
struct cs_etm_packet_queue packet_queue;
@@ -665,9 +664,8 @@ static int cs_etm__init_traceid_queue(struct cs_etm_queue *etmq,
tidq->last_branch = zalloc(sz);
if (!tidq->last_branch)
goto out_free;
- tidq->last_branch_rb = zalloc(sz);
- if (!tidq->last_branch_rb)
- goto out_free;
+
+ tidq->br_stack_sz = etm->synth_opts.last_branch_sz;
}
tidq->event_buf = malloc(PERF_SAMPLE_MAX_SIZE);
@@ -677,7 +675,6 @@ static int cs_etm__init_traceid_queue(struct cs_etm_queue *etmq,
return 0;
out_free:
- zfree(&tidq->last_branch_rb);
zfree(&tidq->last_branch);
zfree(&tidq->prev_packet);
zfree(&tidq->packet);
@@ -962,7 +959,6 @@ static void cs_etm__free_traceid_queues(struct cs_etm_queue *etmq)
thread__zput(tidq->decode_thread);
zfree(&tidq->event_buf);
zfree(&tidq->last_branch);
- zfree(&tidq->last_branch_rb);
zfree(&tidq->prev_packet);
zfree(&tidq->packet);
zfree(&tidq);
@@ -1322,57 +1318,6 @@ static int cs_etm__queue_first_cs_timestamp(struct cs_etm_auxtrace *etm,
return ret;
}
-static inline
-void cs_etm__copy_last_branch_rb(struct cs_etm_queue *etmq,
- struct cs_etm_traceid_queue *tidq)
-{
- struct branch_stack *bs_src = tidq->last_branch_rb;
- struct branch_stack *bs_dst = tidq->last_branch;
- size_t nr = 0;
-
- /*
- * Set the number of records before early exit: ->nr is used to
- * determine how many branches to copy from ->entries.
- */
- bs_dst->nr = bs_src->nr;
-
- /*
- * Early exit when there is nothing to copy.
- */
- if (!bs_src->nr)
- return;
-
- /*
- * As bs_src->entries is a circular buffer, we need to copy from it in
- * two steps. First, copy the branches from the most recently inserted
- * branch ->last_branch_pos until the end of bs_src->entries buffer.
- */
- nr = etmq->etm->synth_opts.last_branch_sz - tidq->last_branch_pos;
- memcpy(&bs_dst->entries[0],
- &bs_src->entries[tidq->last_branch_pos],
- sizeof(struct branch_entry) * nr);
-
- /*
- * If we wrapped around at least once, the branches from the beginning
- * of the bs_src->entries buffer and until the ->last_branch_pos element
- * are older valid branches: copy them over. The total number of
- * branches copied over will be equal to the number of branches asked by
- * the user in last_branch_sz.
- */
- if (bs_src->nr >= etmq->etm->synth_opts.last_branch_sz) {
- memcpy(&bs_dst->entries[nr],
- &bs_src->entries[0],
- sizeof(struct branch_entry) * tidq->last_branch_pos);
- }
-}
-
-static inline
-void cs_etm__reset_last_branch_rb(struct cs_etm_traceid_queue *tidq)
-{
- tidq->last_branch_pos = 0;
- tidq->last_branch_rb->nr = 0;
-}
-
static inline int cs_etm__t32_instr_size(struct cs_etm_queue *etmq,
struct cs_etm_traceid_queue *tidq,
struct cs_etm_packet *packet, u64 addr)
@@ -1442,38 +1387,6 @@ static inline u64 cs_etm__instr_addr(struct cs_etm_queue *etmq,
return addr;
}
-static void cs_etm__update_last_branch_rb(struct cs_etm_queue *etmq,
- struct cs_etm_traceid_queue *tidq)
-{
- struct branch_stack *bs = tidq->last_branch_rb;
- struct branch_entry *be;
-
- /*
- * The branches are recorded in a circular buffer in reverse
- * chronological order: we start recording from the last element of the
- * buffer down. After writing the first element of the stack, move the
- * insert position back to the end of the buffer.
- */
- if (!tidq->last_branch_pos)
- tidq->last_branch_pos = etmq->etm->synth_opts.last_branch_sz;
-
- tidq->last_branch_pos -= 1;
-
- be = &bs->entries[tidq->last_branch_pos];
- be->from = cs_etm__last_executed_instr(tidq->prev_packet);
- be->to = cs_etm__first_executed_instr(tidq->packet);
- /* No support for mispredict */
- be->flags.mispred = 0;
- be->flags.predicted = 1;
-
- /*
- * Increment bs->nr until reaching the number of last branches asked by
- * the user on the command line.
- */
- if (bs->nr < etmq->etm->synth_opts.last_branch_sz)
- bs->nr += 1;
-}
-
static int cs_etm__inject_event(struct cs_etm_auxtrace *etm, union perf_event *event,
struct perf_sample *sample, u64 type)
{
@@ -1637,6 +1550,57 @@ static inline u64 cs_etm__resolve_sample_time(struct cs_etm_queue *etmq,
return etm->latest_kernel_timestamp;
}
+static bool cs_etm__packet_has_taken_branch(struct cs_etm_packet *packet)
+{
+ if (packet->sample_type == CS_ETM_RANGE &&
+ packet->last_instr_taken_branch)
+ return true;
+
+ return false;
+}
+
+static void cs_etm__add_stack_event(struct cs_etm_queue *etmq,
+ struct cs_etm_traceid_queue *tidq)
+{
+ struct cs_etm_auxtrace *etm = etmq->etm;
+ u64 from, to;
+ int size;
+
+ if (!etm->synth_opts.branches && !etm->synth_opts.instructions)
+ return;
+
+ if (!cs_etm__packet_has_taken_branch(tidq->prev_packet))
+ return;
+
+ if (etmq->etm->synth_opts.last_branch) {
+ from = cs_etm__last_executed_instr(tidq->prev_packet);
+ to = cs_etm__first_executed_instr(tidq->packet);
+
+ size = cs_etm__instr_size(etmq, tidq, tidq->prev_packet, from);
+
+ /* Enable callchain so thread stack entry can be allocated */
+ thread_stack__event(tidq->frontend_thread, tidq->prev_packet->cpu,
+ tidq->prev_packet->flags, from, to, size,
+ etmq->buffer->buffer_nr + 1, false,
+ tidq->br_stack_sz, 0);
+ } else {
+ thread_stack__set_trace_nr(tidq->frontend_thread,
+ tidq->prev_packet->cpu,
+ etmq->buffer->buffer_nr + 1);
+ }
+}
+
+static void cs_etm__sample_branch_stack(struct cs_etm_auxtrace *etm,
+ struct cs_etm_traceid_queue *tidq,
+ struct perf_sample *sample)
+{
+ if (etm->synth_opts.last_branch) {
+ thread_stack__br_sample(tidq->frontend_thread, tidq->packet->cpu,
+ tidq->last_branch, tidq->br_stack_sz);
+ sample->branch_stack = tidq->last_branch;
+ }
+}
+
static int cs_etm__synth_instruction_sample(struct cs_etm_queue *etmq,
struct cs_etm_traceid_queue *tidq,
struct cs_etm_packet *packet,
@@ -1666,9 +1630,7 @@ static int cs_etm__synth_instruction_sample(struct cs_etm_queue *etmq,
sample.cpumode = event->sample.header.misc;
cs_etm__copy_insn(etmq, tidq, packet, &sample);
-
- if (etm->synth_opts.last_branch)
- sample.branch_stack = tidq->last_branch;
+ cs_etm__sample_branch_stack(etm, tidq, &sample);
if (etm->synth_opts.inject) {
ret = cs_etm__inject_event(etm, event, &sample,
@@ -1862,14 +1824,7 @@ static int cs_etm__sample(struct cs_etm_queue *etmq,
tidq->period_instructions += tidq->packet->instr_count;
- /*
- * Record a branch when the last instruction in
- * PREV_PACKET is a branch.
- */
- if (etm->synth_opts.last_branch &&
- tidq->prev_packet->sample_type == CS_ETM_RANGE &&
- tidq->prev_packet->last_instr_taken_branch)
- cs_etm__update_last_branch_rb(etmq, tidq);
+ cs_etm__add_stack_event(etmq, tidq);
if (etm->synth_opts.instructions &&
tidq->period_instructions >= etm->instructions_sample_period) {
@@ -1928,10 +1883,6 @@ static int cs_etm__sample(struct cs_etm_queue *etmq,
u64 offset = etm->instructions_sample_period - instrs_prev;
u64 addr;
- /* Prepare last branches for instruction sample */
- if (etm->synth_opts.last_branch)
- cs_etm__copy_last_branch_rb(etmq, tidq);
-
while (tidq->period_instructions >=
etm->instructions_sample_period) {
/*
@@ -1962,8 +1913,7 @@ static int cs_etm__sample(struct cs_etm_queue *etmq,
generate_sample = true;
/* Generate sample for branch taken packet */
- if (tidq->prev_packet->sample_type == CS_ETM_RANGE &&
- tidq->prev_packet->last_instr_taken_branch)
+ if (cs_etm__packet_has_taken_branch(tidq->prev_packet))
generate_sample = true;
if (generate_sample) {
@@ -2011,10 +1961,6 @@ static int cs_etm__flush(struct cs_etm_queue *etmq,
etmq->etm->synth_opts.instructions &&
tidq->prev_packet->sample_type == CS_ETM_RANGE) {
u64 addr;
-
- /* Prepare last branches for instruction sample */
- cs_etm__copy_last_branch_rb(etmq, tidq);
-
/*
* Generate a last branch event for the branches left in the
* circular buffer at the end of the trace.
@@ -2046,7 +1992,7 @@ static int cs_etm__flush(struct cs_etm_queue *etmq,
/* Reset last branches after flush the trace */
if (etm->synth_opts.last_branch)
- cs_etm__reset_last_branch_rb(tidq);
+ thread_stack__flush(tidq->frontend_thread);
return err;
}
@@ -2070,9 +2016,6 @@ static int cs_etm__end_block(struct cs_etm_queue *etmq,
tidq->prev_packet->sample_type == CS_ETM_RANGE) {
u64 addr;
- /* Prepare last branches for instruction sample */
- cs_etm__copy_last_branch_rb(etmq, tidq);
-
/*
* Use the address of the end of the last reported execution
* range.
--
2.34.1
^ permalink raw reply related
* [PATCH v11 3/9] perf cs-etm: Decode ETE exception packets
From: Leo Yan @ 2026-07-02 19:51 UTC (permalink / raw)
To: Arnaldo Carvalho de Melo, John Garry, Will Deacon, James Clark,
Mike Leach, Suzuki K Poulose, Namhyung Kim, Mark Rutland,
Alexander Shishkin, Jiri Olsa, Ian Rogers, Adrian Hunter,
Al Grant, Paschalis Mpeis, Amir Ayupov
Cc: linux-arm-kernel, coresight, linux-perf-users, Leo Yan
In-Reply-To: <20260702-b4-arm_cs_callchain_support_v1-v11-0-846abbf600d7@arm.com>
ETE shares the same packet format as ETMv4, but exception decoding
handled ETMv4 packets only. As a result, ETE exception packets were
not classified.
Recognize the ETE magic for exception number decoding.
Reviewed-by: James Clark <james.clark@linaro.org>
Signed-off-by: Leo Yan <leo.yan@arm.com>
---
tools/perf/util/cs-etm.c | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/tools/perf/util/cs-etm.c b/tools/perf/util/cs-etm.c
index 95530e10e010c3c31f9a9c4b6c89b782c66c03b5..0ad6cccc292d6bec1596d4826390762a83c04931 100644
--- a/tools/perf/util/cs-etm.c
+++ b/tools/perf/util/cs-etm.c
@@ -2202,7 +2202,7 @@ static bool cs_etm__is_syscall(struct cs_etm_queue *etmq,
* HVC cases; need to check if it's SVC instruction based on
* packet address.
*/
- if (magic == __perf_cs_etmv4_magic) {
+ if (magic == __perf_cs_etmv4_magic || magic == __perf_cs_ete_magic) {
if (packet->exception_number == CS_ETMV4_EXC_CALL &&
cs_etm__is_svc_instr(etmq, tidq, prev_packet,
prev_packet->end_addr))
@@ -2225,7 +2225,7 @@ static bool cs_etm__is_async_exception(struct cs_etm_traceid_queue *tidq,
packet->exception_number == CS_ETMV3_EXC_FIQ)
return true;
- if (magic == __perf_cs_etmv4_magic)
+ if (magic == __perf_cs_etmv4_magic || magic == __perf_cs_ete_magic)
if (packet->exception_number == CS_ETMV4_EXC_RESET ||
packet->exception_number == CS_ETMV4_EXC_DEBUG_HALT ||
packet->exception_number == CS_ETMV4_EXC_SYSTEM_ERROR ||
@@ -2255,7 +2255,7 @@ static bool cs_etm__is_sync_exception(struct cs_etm_queue *etmq,
packet->exception_number == CS_ETMV3_EXC_GENERIC)
return true;
- if (magic == __perf_cs_etmv4_magic) {
+ if (magic == __perf_cs_etmv4_magic || magic == __perf_cs_ete_magic) {
if (packet->exception_number == CS_ETMV4_EXC_TRAP ||
packet->exception_number == CS_ETMV4_EXC_ALIGNMENT ||
packet->exception_number == CS_ETMV4_EXC_INST_FAULT ||
--
2.34.1
^ permalink raw reply related
* [PATCH v11 4/9] perf cs-etm: Refactor instruction size handling
From: Leo Yan @ 2026-07-02 19:51 UTC (permalink / raw)
To: Arnaldo Carvalho de Melo, John Garry, Will Deacon, James Clark,
Mike Leach, Suzuki K Poulose, Namhyung Kim, Mark Rutland,
Alexander Shishkin, Jiri Olsa, Ian Rogers, Adrian Hunter,
Al Grant, Paschalis Mpeis, Amir Ayupov
Cc: linux-arm-kernel, coresight, linux-perf-users, Leo Yan, Leo Yan
In-Reply-To: <20260702-b4-arm_cs_callchain_support_v1-v11-0-846abbf600d7@arm.com>
From: Leo Yan <leo.yan@linaro.org>
This patch introduces a new function cs_etm__instr_size() to calculate
the instruction size based on ISA type and instruction address.
Given the trace data can be MB and most likely that will be A64/A32 on
a lot of platforms, cs_etm__instr_addr() keeps a single ISA type check
for A64/A32 and executes an optimized calculation (addr + offset * 4).
Signed-off-by: Leo Yan <leo.yan@linaro.org>
Reviewed-by: James Clark <james.clark@linaro.org>
Signed-off-by: Leo Yan <leo.yan@arm.com>
---
tools/perf/util/cs-etm.c | 43 ++++++++++++++++++++++---------------------
1 file changed, 22 insertions(+), 21 deletions(-)
diff --git a/tools/perf/util/cs-etm.c b/tools/perf/util/cs-etm.c
index 0ad6cccc292d6bec1596d4826390762a83c04931..838c2d00471333b86d33aa86972a3e852ba6502e 100644
--- a/tools/perf/util/cs-etm.c
+++ b/tools/perf/util/cs-etm.c
@@ -1389,6 +1389,18 @@ static inline int cs_etm__t32_instr_size(struct cs_etm_queue *etmq,
return ((instrBytes[1] & 0xF8) >= 0xE8) ? 4 : 2;
}
+static inline int cs_etm__instr_size(struct cs_etm_queue *etmq,
+ struct cs_etm_traceid_queue *tidq,
+ struct cs_etm_packet *packet,
+ u64 addr)
+{
+ if (packet->isa == CS_ETM_ISA_T32)
+ return cs_etm__t32_instr_size(etmq, tidq, packet, addr);
+
+ /* Otherwise, 4-byte instruction size for A32/A64 */
+ return 4;
+}
+
static inline u64 cs_etm__first_executed_instr(struct cs_etm_packet *packet)
{
/*
@@ -1417,19 +1429,17 @@ static inline u64 cs_etm__instr_addr(struct cs_etm_queue *etmq,
struct cs_etm_packet *packet,
u64 offset)
{
- if (packet->isa == CS_ETM_ISA_T32) {
- u64 addr = packet->start_addr;
+ u64 addr = packet->start_addr;
- while (offset) {
- addr += cs_etm__t32_instr_size(etmq, tidq, packet,
- addr);
- offset--;
- }
- return addr;
- }
+ /* 4-byte instruction size for A32/A64 */
+ if (packet->isa == CS_ETM_ISA_A64 || packet->isa == CS_ETM_ISA_A32)
+ return addr + offset * 4;
- /* Assume a 4 byte instruction size (A32/A64) */
- return packet->start_addr + offset * 4;
+ while (offset) {
+ addr += cs_etm__instr_size(etmq, tidq, packet, addr);
+ offset--;
+ }
+ return addr;
}
static void cs_etm__update_last_branch_rb(struct cs_etm_queue *etmq,
@@ -1599,16 +1609,7 @@ static void cs_etm__copy_insn(struct cs_etm_queue *etmq,
return;
}
- /*
- * T32 instruction size might be 32-bit or 16-bit, decide by calling
- * cs_etm__t32_instr_size().
- */
- if (packet->isa == CS_ETM_ISA_T32)
- sample->insn_len = cs_etm__t32_instr_size(etmq, tidq, packet,
- sample->ip);
- /* Otherwise, A64 and A32 instruction size are always 32-bit. */
- else
- sample->insn_len = 4;
+ sample->insn_len = cs_etm__instr_size(etmq, tidq, packet, sample->ip);
cs_etm__frontend_mem_access(etmq, tidq, packet, sample->ip,
sample->insn_len, (void *)sample->insn);
--
2.34.1
^ permalink raw reply related
* [PATCH v11 8/9] perf cs-etm: Synthesize callchains for instruction samples
From: Leo Yan @ 2026-07-02 19:51 UTC (permalink / raw)
To: Arnaldo Carvalho de Melo, John Garry, Will Deacon, James Clark,
Mike Leach, Suzuki K Poulose, Namhyung Kim, Mark Rutland,
Alexander Shishkin, Jiri Olsa, Ian Rogers, Adrian Hunter,
Al Grant, Paschalis Mpeis, Amir Ayupov
Cc: linux-arm-kernel, coresight, linux-perf-users, Leo Yan, Leo Yan
In-Reply-To: <20260702-b4-arm_cs_callchain_support_v1-v11-0-846abbf600d7@arm.com>
From: Leo Yan <leo.yan@linaro.org>
CS ETM already records branches into the thread stack, but instruction
samples do not carry synthesized callchains. It misses to support the
callchain and no output with the itrace option 'g'.
Allocate a callchain buffer per queue and use thread_stack__sample()
when synthesizing instruction samples.
Advertise PERF_SAMPLE_CALLCHAIN on the synthetic instruction event.
Allocate one extra callchain entry than requested, as the first entry
is reserved for storing context information.
cs_etm__context() is introduced for handling context packet and update
the thread info and start kernel address for frontend decoding.
After:
perf script --itrace=g16l64i1i
callchain_test 6543 [002] 1 instructions:
ffff800080010c14 vectors+0x414 ([kernel.kallsyms])
aaaad6b60784 do_svc+0x1c (/home/kernel/leoy/test_cs_callchain/callchain_test)
aaaad6b60798 print+0xc (/home/kernel/leoy/test_cs_callchain/callchain_test)
aaaad6b607b0 foo+0xc (/home/kernel/leoy/test_cs_callchain/callchain_test)
aaaad6b607c8 main+0xc (/home/kernel/leoy/test_cs_callchain/callchain_test)
ffff9325225c __libc_start_call_main+0x7c (/usr/lib/aarch64-linux-gnu/libc.so.6)
ffff9325233c call_init+0x9c (inlined)
ffff9325233c __libc_start_main_impl+0x9c (inlined)
aaaad6b60670 _start+0x30 (/home/kernel/leoy/test_cs_callchain/callchain_test)
ffff800080012290 ret_to_user+0x120 ([kernel.kallsyms])
Signed-off-by: Leo Yan <leo.yan@linaro.org>
Reviewed-by: James Clark <james.clark@linaro.org>
Signed-off-by: Leo Yan <leo.yan@arm.com>
---
tools/perf/util/cs-etm.c | 83 +++++++++++++++++++++++++++++++++++++++++++++---
1 file changed, 78 insertions(+), 5 deletions(-)
diff --git a/tools/perf/util/cs-etm.c b/tools/perf/util/cs-etm.c
index f76648fa67681c464faf5e9cf4e019653bce5b4c..95e3ec1171acc8442d8539a72a26a1a5a53a2f37 100644
--- a/tools/perf/util/cs-etm.c
+++ b/tools/perf/util/cs-etm.c
@@ -18,6 +18,7 @@
#include <stdlib.h>
#include "auxtrace.h"
+#include "callchain.h"
#include "color.h"
#include "cs-etm.h"
#include "cs-etm-decoder/cs-etm-decoder.h"
@@ -87,9 +88,11 @@ struct cs_etm_auxtrace {
struct cs_etm_traceid_queue {
u8 trace_chan_id;
u64 period_instructions;
+ u64 kernel_start;
union perf_event *event_buf;
unsigned int br_stack_sz;
struct branch_stack *last_branch;
+ struct ip_callchain *callchain;
struct cs_etm_packet *prev_packet;
struct cs_etm_packet *packet;
struct cs_etm_packet_queue packet_queue;
@@ -670,6 +673,15 @@ static int cs_etm__init_traceid_queue(struct cs_etm_queue *etmq,
tidq->br_stack_sz = etm->synth_opts.last_branch_sz;
}
+ if (etm->synth_opts.callchain) {
+ /* Add 1 to callchain_sz for callchain context */
+ tidq->callchain =
+ zalloc(struct_size(tidq->callchain, ips,
+ etm->synth_opts.callchain_sz + 1));
+ if (!tidq->callchain)
+ goto out_free;
+ }
+
tidq->event_buf = malloc(PERF_SAMPLE_MAX_SIZE);
if (!tidq->event_buf)
goto out_free;
@@ -677,6 +689,7 @@ static int cs_etm__init_traceid_queue(struct cs_etm_queue *etmq,
return 0;
out_free:
+ zfree(&tidq->callchain);
zfree(&tidq->last_branch);
zfree(&tidq->prev_packet);
zfree(&tidq->packet);
@@ -960,6 +973,7 @@ static void cs_etm__free_traceid_queues(struct cs_etm_queue *etmq)
thread__zput(tidq->frontend_thread);
thread__zput(tidq->decode_thread);
zfree(&tidq->event_buf);
+ zfree(&tidq->callchain);
zfree(&tidq->last_branch);
zfree(&tidq->prev_packet);
zfree(&tidq->packet);
@@ -1602,6 +1616,26 @@ static void cs_etm__sample_branch_stack(struct cs_etm_auxtrace *etm,
tidq->last_branch, tidq->br_stack_sz);
sample->branch_stack = tidq->last_branch;
}
+
+ if (etm->synth_opts.callchain) {
+ if (tidq->kernel_start)
+ thread_stack__sample(tidq->frontend_thread,
+ tidq->packet->cpu,
+ tidq->callchain,
+ etm->synth_opts.callchain_sz + 1,
+ sample->ip, tidq->kernel_start);
+ else
+ /*
+ * Clear the callchain when the kernel start address is
+ * not available yet. The empty callchain can then be
+ * consumed by cs_etm__inject_event().
+ */
+ memset(tidq->callchain, 0,
+ struct_size(tidq->callchain, ips,
+ etm->synth_opts.callchain_sz + 1));
+
+ sample->callchain = tidq->callchain;
+ }
}
static int cs_etm__synth_instruction_sample(struct cs_etm_queue *etmq,
@@ -1800,6 +1834,9 @@ static int cs_etm__synth_events(struct cs_etm_auxtrace *etm,
attr.branch_sample_type |= PERF_SAMPLE_BRANCH_HW_INDEX;
}
+ if (etm->synth_opts.callchain)
+ attr.sample_type |= PERF_SAMPLE_CALLCHAIN;
+
if (etm->synth_opts.instructions) {
attr.config = PERF_COUNT_HW_INSTRUCTIONS;
attr.sample_period = etm->synth_opts.period;
@@ -1931,6 +1968,34 @@ static int cs_etm__sample(struct cs_etm_queue *etmq,
return 0;
}
+static int cs_etm__context(struct cs_etm_queue *etmq,
+ struct cs_etm_traceid_queue *tidq)
+{
+ ocsd_ex_level el = tidq->packet->el;
+ struct machine *machine;
+ int ret;
+
+ machine = cs_etm__get_machine(etmq, el);
+ if (!machine) {
+ ret = -EINVAL;
+ goto err;
+ }
+
+ tidq->kernel_start = machine__kernel_start(machine);
+
+ ret = cs_etm__etmq_update_thread(etmq, el, tidq->packet->tid,
+ &tidq->frontend_thread);
+ if (ret)
+ goto err;
+
+ return 0;
+
+err:
+ thread__zput(tidq->frontend_thread);
+ tidq->kernel_start = 0;
+ return ret;
+}
+
static int cs_etm__exception(struct cs_etm_traceid_queue *tidq)
{
/*
@@ -2531,9 +2596,7 @@ static int cs_etm__process_traceid_queue(struct cs_etm_queue *etmq,
* tracing the kernel the context packet will be emitted
* between two ranges.
*/
- ret = cs_etm__etmq_update_thread(etmq, tidq->packet->el,
- tidq->packet->tid,
- &tidq->frontend_thread);
+ ret = cs_etm__context(etmq, tidq);
if (ret)
goto out;
break;
@@ -3572,6 +3635,14 @@ int cs_etm__process_auxtrace_info_full(union perf_event *event,
PERF_IP_FLAG_TRACE_BEGIN |
PERF_IP_FLAG_TRACE_END;
+ if (etm->synth_opts.callchain && !symbol_conf.use_callchain) {
+ symbol_conf.use_callchain = true;
+ if (callchain_register_param(&callchain_param) < 0) {
+ symbol_conf.use_callchain = false;
+ etm->synth_opts.callchain = false;
+ }
+ }
+
etm->session = session;
etm->num_cpu = num_cpu;
@@ -3623,9 +3694,11 @@ int cs_etm__process_auxtrace_info_full(union perf_event *event,
}
etm->use_thread_stack = etm->synth_opts.thread_stack ||
- etm->synth_opts.last_branch;
+ etm->synth_opts.last_branch ||
+ etm->synth_opts.callchain;
- etm->use_callchain = etm->synth_opts.thread_stack;
+ etm->use_callchain = etm->synth_opts.thread_stack ||
+ etm->synth_opts.callchain;
err = cs_etm__synth_events(etm, session);
if (err)
--
2.34.1
^ permalink raw reply related
* [PATCH v11 7/9] perf cs-etm: Support call indentation
From: Leo Yan @ 2026-07-02 19:51 UTC (permalink / raw)
To: Arnaldo Carvalho de Melo, John Garry, Will Deacon, James Clark,
Mike Leach, Suzuki K Poulose, Namhyung Kim, Mark Rutland,
Alexander Shishkin, Jiri Olsa, Ian Rogers, Adrian Hunter,
Al Grant, Paschalis Mpeis, Amir Ayupov
Cc: linux-arm-kernel, coresight, linux-perf-users, Leo Yan, Leo Yan
In-Reply-To: <20260702-b4-arm_cs_callchain_support_v1-v11-0-846abbf600d7@arm.com>
From: Leo Yan <leo.yan@linaro.org>
The perf script callindent is derived from call stack in thread context,
CS ETM ignores the requirement for callindent without pushing and poping
call stack.
Enable thread-stack when either itrace thread-stack support or last branch
entries are requested, allocate the branch stack storage accordingly, and
feed taken branches to thread_stack__event() whenever thread-stack state
is needed.
When callindent is requested, pass callstack=true to thread_stack__event()
so the common thread-stack code maintains call depth for branch samples.
Before:
perf script -F +callindent
callchain_test 6543 [002] 1 branches: main ffff93252258 __libc_start_call_main+0x78 (/usr/lib/aarch64-linux-gnu/libc.so.6)
callchain_test 6543 [002] 1 branches: foo aaaad6b607c4 main+0x8 (/home/kernel/leoy/test_cs_callchain/callchain_test)
callchain_test 6543 [002] 1 branches: print aaaad6b607ac foo+0x8 (/home/kernel/leoy/test_cs_callchain/callchain_test)
callchain_test 6543 [002] 1 branches: do_svc aaaad6b60794 print+0x8 (/home/kernel/leoy/test_cs_callchain/callchain_test)
callchain_test 6543 [002] 1 branches: vectors aaaad6b60780 do_svc+0x18 (/home/kernel/leoy/test_cs_callchain/callchain_test)
callchain_test 6543 [002] 1 branches: el0t_64_sync_handler ffff80008001159c el0t_64_sync+0x194 ([kernel.kallsyms])
callchain_test 6543 [002] 1 branches: el0_svc ffff800081829194 el0t_64_sync_handler+0x9c ([kernel.kallsyms])
callchain_test 6543 [002] 1 branches: lockdep_hardirqs_off ffff800081828794 el0_svc+0x24 ([kernel.kallsyms])
callchain_test 6543 [002] 1 branches: __this_cpu_preempt_check ffff80008182b348 lockdep_hardirqs_off+0xf0 ([kernel.kallsyms])
After:
callchain_test 6543 [002] 1 branches: main ffff93252258 __libc_start_call_main+0x78 (/usr/lib/aarch64-linux-gnu/libc.so.6)
callchain_test 6543 [002] 1 branches: foo aaaad6b607c4 main+0x8 (/home/kernel/leoy/test_cs_callchain/callchain_test)
callchain_test 6543 [002] 1 branches: print aaaad6b607ac foo+0x8 (/home/kernel/leoy/test_cs_callchain/callchain_test)
callchain_test 6543 [002] 1 branches: do_svc aaaad6b60794 print+0x8 (/home/kernel/leoy/test_cs_callchain/callchain_test)
callchain_test 6543 [002] 1 branches: vectors aaaad6b60780 do_svc+0x18 (/home/kernel/leoy/test_cs_callchain/callchain_test)
callchain_test 6543 [002] 1 branches: el0t_64_sync_handler ffff80008001159c el0t_64_sync+0x194 ([kernel.kallsyms])
callchain_test 6543 [002] 1 branches: el0_svc ffff800081829194 el0t_64_sync_handler+0x9c ([kernel.kallsyms])
callchain_test 6543 [002] 1 branches: lockdep_hardirqs_off ffff800081828794 el0_svc+0x24 ([kernel.kallsyms])
callchain_test 6543 [002] 1 branches: __this_cpu_preempt_check ffff80008182b348 lockdep_hardirqs_off+0xf0 ([kernel.kallsyms])
Signed-off-by: Leo Yan <leo.yan@linaro.org>
Reviewed-by: James Clark <james.clark@linaro.org>
Signed-off-by: Leo Yan <leo.yan@arm.com>
---
tools/perf/util/cs-etm.c | 20 +++++++++++++++-----
1 file changed, 15 insertions(+), 5 deletions(-)
diff --git a/tools/perf/util/cs-etm.c b/tools/perf/util/cs-etm.c
index 996317687ce7b241afed83444b554155edb09564..f76648fa67681c464faf5e9cf4e019653bce5b4c 100644
--- a/tools/perf/util/cs-etm.c
+++ b/tools/perf/util/cs-etm.c
@@ -67,6 +67,8 @@ struct cs_etm_auxtrace {
bool snapshot_mode;
bool data_queued;
bool has_virtual_ts; /* Virtual/Kernel timestamps in the trace. */
+ bool use_thread_stack;
+ bool use_callchain;
int num_cpu;
u64 latest_kernel_timestamp;
@@ -656,7 +658,7 @@ static int cs_etm__init_traceid_queue(struct cs_etm_queue *etmq,
if (!tidq->prev_packet)
goto out_free;
- if (etm->synth_opts.last_branch) {
+ if (etm->use_thread_stack) {
size_t sz = sizeof(struct branch_stack);
sz += etm->synth_opts.last_branch_sz *
@@ -1572,7 +1574,7 @@ static void cs_etm__add_stack_event(struct cs_etm_queue *etmq,
if (!cs_etm__packet_has_taken_branch(tidq->prev_packet))
return;
- if (etmq->etm->synth_opts.last_branch) {
+ if (etmq->etm->use_thread_stack) {
from = cs_etm__last_executed_instr(tidq->prev_packet);
to = cs_etm__first_executed_instr(tidq->packet);
@@ -1581,7 +1583,8 @@ static void cs_etm__add_stack_event(struct cs_etm_queue *etmq,
/* Enable callchain so thread stack entry can be allocated */
thread_stack__event(tidq->frontend_thread, tidq->prev_packet->cpu,
tidq->prev_packet->flags, from, to, size,
- etmq->buffer->buffer_nr + 1, false,
+ etmq->buffer->buffer_nr + 1,
+ etmq->etm->use_callchain,
tidq->br_stack_sz, 0);
} else {
thread_stack__set_trace_nr(tidq->frontend_thread,
@@ -1991,7 +1994,7 @@ static int cs_etm__flush(struct cs_etm_queue *etmq,
cs_etm__packet_swap(etm, tidq);
/* Reset last branches after flush the trace */
- if (etm->synth_opts.last_branch)
+ if (etm->use_thread_stack)
thread_stack__flush(tidq->frontend_thread);
return err;
@@ -2054,7 +2057,7 @@ static void cs_etm__flush_all_stack(struct cs_etm_queue *etmq)
{
enum cs_etm_pid_fmt pid_fmt = cs_etm__get_pid_fmt(etmq);
- if (!etmq->etm->synth_opts.last_branch)
+ if (!etmq->etm->use_thread_stack)
return;
switch (pid_fmt) {
@@ -3556,6 +3559,7 @@ int cs_etm__process_auxtrace_info_full(union perf_event *event,
itrace_synth_opts__set_default(&etm->synth_opts,
session->itrace_synth_opts->default_no_sample);
etm->synth_opts.callchain = false;
+ etm->synth_opts.thread_stack = session->itrace_synth_opts->thread_stack;
}
if (etm->synth_opts.calls)
@@ -3617,6 +3621,12 @@ int cs_etm__process_auxtrace_info_full(union perf_event *event,
etm->tc.cap_user_time_zero = tc->cap_user_time_zero;
etm->tc.cap_user_time_short = tc->cap_user_time_short;
}
+
+ etm->use_thread_stack = etm->synth_opts.thread_stack ||
+ etm->synth_opts.last_branch;
+
+ etm->use_callchain = etm->synth_opts.thread_stack;
+
err = cs_etm__synth_events(etm, session);
if (err)
goto err_free_queues;
--
2.34.1
^ permalink raw reply related
* [PATCH v11 9/9] perf test: Add Arm CoreSight callchain test
From: Leo Yan @ 2026-07-02 19:51 UTC (permalink / raw)
To: Arnaldo Carvalho de Melo, John Garry, Will Deacon, James Clark,
Mike Leach, Suzuki K Poulose, Namhyung Kim, Mark Rutland,
Alexander Shishkin, Jiri Olsa, Ian Rogers, Adrian Hunter,
Al Grant, Paschalis Mpeis, Amir Ayupov
Cc: linux-arm-kernel, coresight, linux-perf-users, Leo Yan
In-Reply-To: <20260702-b4-arm_cs_callchain_support_v1-v11-0-846abbf600d7@arm.com>
Add a CoreSight shell test for synthesized callchains.
The test uses the new callchain workload to generate trace and decodes
it with synthesis callchain. It then verifies that the instruction
samples show the expected callchain push and pop.
Use control FIFOs so tracing starts only around the workload, which
keeps the trace data small. The test is limited to with the cs_etm
event available and root permission.
After:
perf test 138 -vvv
138: CoreSight synthesized callchain:
---- start ----
test child forked, pid 35581
Callchain flow matched:
l1=4642868 l2=4642880 l3=4642895 l4=4642919 l5=4670494 l6=4670500 l7=4670520
---- end(0) ----
138: CoreSight synthesized callchain : Ok
Assisted-by: Codex:GPT-5.5
Reviewed-by: James Clark <james.clark@linaro.org>
Signed-off-by: Leo Yan <leo.yan@arm.com>
---
tools/perf/Documentation/perf-test.txt | 6 +-
tools/perf/tests/builtin-test.c | 1 +
tools/perf/tests/shell/coresight/callchain.sh | 172 ++++++++++++++++++++++++++
tools/perf/tests/tests.h | 1 +
tools/perf/tests/workloads/Build | 2 +
tools/perf/tests/workloads/callchain.c | 33 +++++
6 files changed, 213 insertions(+), 2 deletions(-)
diff --git a/tools/perf/Documentation/perf-test.txt b/tools/perf/Documentation/perf-test.txt
index 81c8525f594680d814f80e6f88bcce8d867bb350..859df74e62efc4b1e80da13ae8e053356f68ae54 100644
--- a/tools/perf/Documentation/perf-test.txt
+++ b/tools/perf/Documentation/perf-test.txt
@@ -57,7 +57,8 @@ OPTIONS
--workload=::
Run a built-in workload, to list them use '--list-workloads', current
ones include: noploop, thloop, leafloop, sqrtloop, brstack, datasym,
- context_switch_loop, deterministic, named_threads and landlock.
+ context_switch_loop, deterministic, named_threads, landlock and
+ callchain.
Used with the shell script regression tests.
@@ -69,7 +70,8 @@ OPTIONS
'named_threads' accepts the number of threads and the number of loops to
do in each thread.
- The datasym, landlock and deterministic workloads don't accept any.
+ The datasym, landlock, deterministic and callchain workloads don't accept
+ any.
--list-workloads::
List the available workloads to use with -w/--workload.
diff --git a/tools/perf/tests/builtin-test.c b/tools/perf/tests/builtin-test.c
index d115a19e5f0f59ade91f1a743c08cae05d043ba8..7d18cb6021d37ec0a1ed47a0072ddb4e2ad99421 100644
--- a/tools/perf/tests/builtin-test.c
+++ b/tools/perf/tests/builtin-test.c
@@ -171,6 +171,7 @@ static struct test_workload *workloads[] = {
&workload__jitdump,
&workload__context_switch_loop,
&workload__deterministic,
+ &workload__callchain,
#ifdef HAVE_RUST_SUPPORT
&workload__code_with_type,
diff --git a/tools/perf/tests/shell/coresight/callchain.sh b/tools/perf/tests/shell/coresight/callchain.sh
new file mode 100755
index 0000000000000000000000000000000000000000..13cca7dc11184002e3ddc058c0d0ffa1c458c483
--- /dev/null
+++ b/tools/perf/tests/shell/coresight/callchain.sh
@@ -0,0 +1,172 @@
+#!/bin/bash
+# CoreSight synthesized callchain (exclusive)
+# SPDX-License-Identifier: GPL-2.0
+
+glb_err=1
+
+if ! tmpdir=$(mktemp -d /tmp/perf-cs-callchain-test.XXXXXX); then
+ echo "mktemp failed"
+ exit 1
+fi
+
+cleanup_files()
+{
+ rm -rf "$tmpdir"
+}
+
+trap cleanup_files EXIT
+trap 'cleanup_files; exit $glb_err' TERM INT
+
+skip_if_system_is_not_ready()
+{
+ perf list | grep -Pzq 'cs_etm//' || {
+ echo "[Skip] cs_etm event is not available" >&2
+ return 2
+ }
+
+ # Requires root for trace in kernel
+ [ "$(id -u)" = 0 ] || {
+ echo "[Skip] No root permission" >&2
+ return 2
+ }
+
+ return 0
+}
+
+record_trace()
+{
+ local data=$1
+ local script=$2
+
+ local cf="$tmpdir/ctl"
+ local af="$tmpdir/ack"
+
+ mkfifo "$cf" "$af"
+
+ perf record -o "$data" -e cs_etm// --per-thread -D -1 --control fifo:"$cf","$af" -- \
+ perf test --record-ctl fifo:"$cf","$af" -w callchain >/dev/null 2>&1 &&
+
+ # It is safe to use 'i3i' with a three-instruction interval, since the
+ # workload is compiled with -O0.
+ perf script --itrace=g16i3il64 -i "$data" > "$script"
+}
+
+callchain_regex_1()
+{
+ printf '%s' \
+'perf[[:space:]]+[0-9]+[[:space:]]+\[[0-9]+\][[:space:]]+([0-9.]+:[[:space:]]+)?[0-9]+ instructions:[[:space:]]*\n'\
+'[[:space:]]+[[:xdigit:]]+ callchain_foo\+0x[[:xdigit:]]+ \(.*/perf\)\n'\
+'[[:space:]]+[[:xdigit:]]+ callchain\+0x[[:xdigit:]]+ \(.*/perf\)\n'\
+'([[:space:]]+[[:xdigit:]]+ .*\n)*'
+}
+
+callchain_regex_2()
+{
+ printf '%s' \
+'perf[[:space:]]+[0-9]+[[:space:]]+\[[0-9]+\][[:space:]]+([0-9.]+:[[:space:]]+)?[0-9]+ instructions:[[:space:]]*\n'\
+'[[:space:]]+[[:xdigit:]]+ callchain_do_syscall\+0x[[:xdigit:]]+ \(.*/perf\)\n'\
+'[[:space:]]+[[:xdigit:]]+ callchain_foo\+0x[[:xdigit:]]+ \(.*/perf\)\n'\
+'[[:space:]]+[[:xdigit:]]+ callchain\+0x[[:xdigit:]]+ \(.*/perf\)\n'\
+'([[:space:]]+[[:xdigit:]]+ .*\n)*'
+}
+
+callchain_regex_3()
+{
+ printf '%s' \
+'perf[[:space:]]+[0-9]+[[:space:]]+\[[0-9]+\][[:space:]]+([0-9.]+:[[:space:]]+)?[0-9]+ instructions:[[:space:]]*\n'\
+'[[:space:]]+[[:xdigit:]]+ syscall(@plt)?\+0x[[:xdigit:]]+ \(.*\)\n'\
+'[[:space:]]+[[:xdigit:]]+ callchain_do_syscall\+0x[[:xdigit:]]+ \(.*/perf\)\n'\
+'[[:space:]]+[[:xdigit:]]+ callchain_foo\+0x[[:xdigit:]]+ \(.*/perf\)\n'\
+'[[:space:]]+[[:xdigit:]]+ callchain\+0x[[:xdigit:]]+ \(.*/perf\)\n'\
+'([[:space:]]+[[:xdigit:]]+ .*\n)*'
+}
+
+callchain_regex_4()
+{
+ printf '%s' \
+'perf[[:space:]]+[0-9]+[[:space:]]+\[[0-9]+\][[:space:]]+([0-9.]+:[[:space:]]+)?[0-9]+ instructions:[[:space:]]*\n'\
+'[[:space:]]+[[:xdigit:]]+ .*\+0x[[:xdigit:]]+ \(\[kernel\.kallsyms\]\)\n'\
+'[[:space:]]+[[:xdigit:]]+ syscall(@plt)?\+0x[[:xdigit:]]+ \(.*\)\n'\
+'[[:space:]]+[[:xdigit:]]+ callchain_do_syscall\+0x[[:xdigit:]]+ \(.*/perf\)\n'\
+'[[:space:]]+[[:xdigit:]]+ callchain_foo\+0x[[:xdigit:]]+ \(.*/perf\)\n'\
+'[[:space:]]+[[:xdigit:]]+ callchain\+0x[[:xdigit:]]+ \(.*/perf\)\n'\
+'([[:space:]]+[[:xdigit:]]+ .*\n)*'
+}
+
+find_after_line()
+{
+ local regex="$1"
+ local file="$2"
+ local start="$3"
+ local offset
+ local line
+
+ # Search in byte offset
+ offset=$(
+ tail -n +"$start" "$file" |
+ grep -Pzob -m1 "$regex" |
+ tr '\0' '\n' |
+ sed -n 's/^\([0-9][0-9]*\):.*/\1/p;q'
+ )
+
+ if [ -z "$offset" ]; then
+ echo "Failed to match regex after line $start" >&2
+ echo "Regex:" >&2
+ printf '%s\n' "$regex" >&2
+ echo "Context from line $start:" >&2
+ sed -n "${start},$((start + 100))p" "$file" >&2
+ return 1
+ fi
+
+ # Convert from offset to line
+ line=$(
+ tail -n +"$start" "$file" |
+ head -c "$offset" |
+ wc -l
+ )
+
+ echo "$((start + line))"
+}
+
+check_callchain_flow()
+{
+ local file="$1"
+ local l1 l2 l3 l4 l5 l6 l7
+
+ # Callchain push
+ l1=$(find_after_line "$(callchain_regex_1)" "$file" 1) || return 1
+ l2=$(find_after_line "$(callchain_regex_2)" "$file" "$((l1 + 1))") || return 1
+ l3=$(find_after_line "$(callchain_regex_3)" "$file" "$((l2 + 1))") || return 1
+ l4=$(find_after_line "$(callchain_regex_4)" "$file" "$((l3 + 1))") || return 1
+
+ # Callchain pop
+ l5=$(find_after_line "$(callchain_regex_3)" "$file" "$((l4 + 1))") || return 1
+ l6=$(find_after_line "$(callchain_regex_2)" "$file" "$((l5 + 1))") || return 1
+ l7=$(find_after_line "$(callchain_regex_1)" "$file" "$((l6 + 1))") || return 1
+
+ echo "Callchain flow matched:"
+ echo " l1=$l1 l2=$l2 l3=$l3 l4=$l4 l5=$l5 l6=$l6 l7=$l7"
+
+ return 0
+}
+
+run_test()
+{
+ local data=$tmpdir/perf.data
+ local script=$tmpdir/perf.script
+
+ if ! record_trace "$data" "$script"; then
+ echo "perf record/script failed"
+ return
+ fi
+
+ check_callchain_flow "$script" || return
+
+ glb_err=0
+}
+
+skip_if_system_is_not_ready || exit 2
+
+run_test
+
+exit $glb_err
diff --git a/tools/perf/tests/tests.h b/tools/perf/tests/tests.h
index 7cedf05be544ad79a99e86d30dfa4f7b01ca0837..cee9e6b62dcc838c864bbe76efe3b638ed75b134 100644
--- a/tools/perf/tests/tests.h
+++ b/tools/perf/tests/tests.h
@@ -248,6 +248,7 @@ DECLARE_WORKLOAD(inlineloop);
DECLARE_WORKLOAD(jitdump);
DECLARE_WORKLOAD(context_switch_loop);
DECLARE_WORKLOAD(deterministic);
+DECLARE_WORKLOAD(callchain);
#ifdef HAVE_RUST_SUPPORT
DECLARE_WORKLOAD(code_with_type);
diff --git a/tools/perf/tests/workloads/Build b/tools/perf/tests/workloads/Build
index 7bb4b9829ba245740c8967e6bf3235614cdd55a3..048e371eb63e316453b6b46ebd0a02794c3d25d7 100644
--- a/tools/perf/tests/workloads/Build
+++ b/tools/perf/tests/workloads/Build
@@ -13,6 +13,7 @@ perf-test-y += inlineloop.o
perf-test-y += jitdump.o
perf-test-y += context_switch_loop.o
perf-test-y += deterministic.o
+perf-test-y += callchain.o
ifeq ($(CONFIG_RUST_SUPPORT),y)
perf-test-y += code_with_type.o
@@ -27,3 +28,4 @@ CFLAGS_traploop.o = -g -O0 -fno-inline -U_FORTIFY_SOURCE
CFLAGS_inlineloop.o = -g -O2
CFLAGS_deterministic.o = -g -O0 -fno-inline -U_FORTIFY_SOURCE
CFLAGS_named_threads.o = -g -O0 -fno-inline -U_FORTIFY_SOURCE
+CFLAGS_callchain.o = -g -O0 -fno-inline -U_FORTIFY_SOURCE
diff --git a/tools/perf/tests/workloads/callchain.c b/tools/perf/tests/workloads/callchain.c
new file mode 100644
index 0000000000000000000000000000000000000000..abbb406ba90b30a012620f46c6e84a5661066b76
--- /dev/null
+++ b/tools/perf/tests/workloads/callchain.c
@@ -0,0 +1,33 @@
+// SPDX-License-Identifier: GPL-2.0
+#include <linux/compiler.h>
+#include <sys/syscall.h>
+#include <unistd.h>
+#include "../tests.h"
+
+/*
+ * Mark as noinline to establish the call chain, and avoid the static
+ * annotation to prevent LTO from renaming the functions.
+ */
+noinline void callchain_do_syscall(void);
+noinline void callchain_foo(void);
+noinline int callchain(int argc, const char **argv);
+
+noinline void callchain_do_syscall(void)
+{
+ syscall(SYS_gettid);
+}
+
+noinline void callchain_foo(void)
+{
+ callchain_do_syscall();
+}
+
+noinline int callchain(int argc __maybe_unused,
+ const char **argv __maybe_unused)
+{
+ callchain_foo();
+
+ return 0;
+}
+
+DEFINE_WORKLOAD(callchain);
--
2.34.1
^ permalink raw reply related
* Re: [PATCH v3 2/2] iio: adc: add Axiado SARADC driver
From: Jonathan Cameron @ 2026-07-02 19:54 UTC (permalink / raw)
To: Petar Stepanovic
Cc: Joshua Crofts, Akhila Kavi, Prasad Bolisetty, David Lechner,
Nuno Sá, Andy Shevchenko, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Harshit Shah, linux-iio, devicetree,
linux-arm-kernel, linux-kernel
In-Reply-To: <5e84024c-041b-4e2b-9a91-6c0bb9fb3bb2@axiado.com>
On Tue, 23 Jun 2026 10:30:37 +0200
Petar Stepanovic <pstepanovic@axiado.com> wrote:
> On 6/22/2026 11:55 AM, Joshua Crofts wrote:
> > CAUTION: This email originated from outside of the organization. Do not click links or open attachments unless you recognize the sender and know the content is safe.
> >
> >
> > On Mon, 22 Jun 2026 00:47:28 -0700
> > Petar Stepanovic <pstepanovic@axiado.com> wrote:
> >
> >> Add support for the SARADC controller found on Axiado AX3000 and
> >> AX3005 SoCs.
> >>
> >> The driver supports single-shot voltage reads through the IIO
> >> subsystem. The number of available input channels is selected from
> >> the SoC match data, allowing AX3000 and AX3005 variants to use the
> >> same driver.
> >>
> >> Signed-off-by: Petar Stepanovic <pstepanovic@axiado.com>
> >> ---
> >> + info->clk_rate = clk_get_rate(info->clk);
> >> + if (!info->clk_rate)
> >> + return dev_err_probe(dev, -EINVAL, "invalid clock rate\n");
> >> +
> >> + ret = devm_regulator_get_enable_read_voltage(dev, "vref");
> >> + if (ret < 0)
> >> + return dev_err_probe(dev, info->vref_uV,
> >> + "failed to get vref voltage\n");
> > Sashiko raised an issue that I've missed on previous reads - why
> > are you using info->vref_uV in dev_err_probe()? The info struct
> > is not zeroed out on initialization, which means that dev_err_probe
> > will return a different value each time when read_voltage() fails.
> > It was designed to accept the retval from whatever function we're
> > checking.
>
> Thank you for catching this.
> You are right, |dev_err_probe()| should use the return value from |devm_regulator_get_enable_read_voltage()|, not |info->vref_uV|.
> I will fix this in the next version by passing |ret| to |dev_err_probe()| and assigning |info->vref_uV| only after the call succeeds.
>
Hi Petar, Quick process thing. If you fully agree with some
feedback, don't send an email to say that. The place for thanks
etc is the change log of the next version.
We are all swamped in email and it takes a non trivial amount
of time to check every reply for discussion that needs to continue.
This is probably the most common thing people who are new to the kernel
do that I'd rather they didn't :) I send this email once or twice
a week at the moment.
Thanks,
Jonathan
> Regards,
> Petar
>
>
^ permalink raw reply
* [PATCH v11 6/9] perf cs-etm: Flush thread stacks after decoder reset
From: Leo Yan @ 2026-07-02 19:51 UTC (permalink / raw)
To: Arnaldo Carvalho de Melo, John Garry, Will Deacon, James Clark,
Mike Leach, Suzuki K Poulose, Namhyung Kim, Mark Rutland,
Alexander Shishkin, Jiri Olsa, Ian Rogers, Adrian Hunter,
Al Grant, Paschalis Mpeis, Amir Ayupov
Cc: linux-arm-kernel, coresight, linux-perf-users, Leo Yan
In-Reply-To: <20260702-b4-arm_cs_callchain_support_v1-v11-0-846abbf600d7@arm.com>
Perf resets the CoreSight decoder when moving to a new AUX trace buffer,
this causes trace discontinunity globally.
For callchain synthesis, keeping thread-stack state after decoder reset
can leave stale call/return history attached to threads that are decoded
later, producing incorrect synthesized callchains.
Flush all host thread stacks after a decoder reset. When virtualization
is present, flush the guest thread stacks as well.
Reviewed-by: James Clark <james.clark@linaro.org>
Signed-off-by: Leo Yan <leo.yan@arm.com>
---
tools/perf/util/cs-etm.c | 45 +++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 45 insertions(+)
diff --git a/tools/perf/util/cs-etm.c b/tools/perf/util/cs-etm.c
index ba9ffb7bdb4bd95c9dc6c323c0d56f516aae56b8..996317687ce7b241afed83444b554155edb09564 100644
--- a/tools/perf/util/cs-etm.c
+++ b/tools/perf/util/cs-etm.c
@@ -2033,6 +2033,45 @@ static int cs_etm__end_block(struct cs_etm_queue *etmq,
return 0;
}
+
+static int cs_etm__flush_stack_cb(struct thread *thread,
+ void *data __maybe_unused)
+{
+ thread_stack__flush(thread);
+ return 0;
+}
+
+static void cs_etm__flush_machine_stack(struct cs_etm_queue *etmq, pid_t pid)
+{
+ struct machine *machine;
+
+ machine = machines__find(&etmq->etm->session->machines, pid);
+ if (machine)
+ machine__for_each_thread(machine, cs_etm__flush_stack_cb, NULL);
+}
+
+static void cs_etm__flush_all_stack(struct cs_etm_queue *etmq)
+{
+ enum cs_etm_pid_fmt pid_fmt = cs_etm__get_pid_fmt(etmq);
+
+ if (!etmq->etm->synth_opts.last_branch)
+ return;
+
+ switch (pid_fmt) {
+ case CS_ETM_PIDFMT_CTXTID2:
+ /* Clear the guest stack if virtualization is supported */
+ cs_etm__flush_machine_stack(etmq, DEFAULT_GUEST_KERNEL_ID);
+ fallthrough;
+ case CS_ETM_PIDFMT_CTXTID:
+ cs_etm__flush_machine_stack(etmq, HOST_KERNEL_ID);
+ break;
+ case CS_ETM_PIDFMT_NONE:
+ default:
+ break;
+
+ }
+}
+
/*
* cs_etm__get_data_block: Fetch a block from the auxtrace_buffer queue
* if need be.
@@ -2055,6 +2094,12 @@ static int cs_etm__get_data_block(struct cs_etm_queue *etmq)
ret = cs_etm_decoder__reset(etmq->decoder);
if (ret)
return ret;
+
+ /*
+ * Since the decoder is reset, this causes a global trace
+ * discontinuity. Flush all thread stacks.
+ */
+ cs_etm__flush_all_stack(etmq);
}
return etmq->buf_len;
--
2.34.1
^ permalink raw reply related
* [PATCH v4] drm/rockchip: Remove dependency on DRM simple helpers
From: Diogo Silva @ 2026-07-02 20:18 UTC (permalink / raw)
To: Sandy Huang, Heiko Stübner, Andy Yan
Cc: Maarten Lankhorst, David Airlie, Maxime Ripard, Simona Vetter,
linux-arm-kernel, Thomas Zimmermann, dri-devel, linux-rockchip,
linux-kernel, javierm@redhat.com
In-Reply-To: <CAJpoHp6DnspnA0rirGb6E=A9wCS3eaDn=eFaqmae98Q+39b1PA@mail.gmail.com>
Simple KMS helper are deprecated since they only add an intermediate
layer between drivers and the atomic modesetting.
This patch removes the drm_simple_encoder_init() helper usage in the
rockchip drivers by open coding it and using the encoder atomic helpers
directly. This is a step to eventually get rid of this simple KMS helper,
once all drivers that use it have been converted.
Reviewed-by: Javier Martinez Canillas <javierm@redhat.com>
Signed-off-by: Diogo Silva <diogompaissilva@gmail.com>
---
v4:
- improved commit message based on Javier Canillas feedback
v3:
- rebase on drm-tip tree
drivers/gpu/drm/rockchip/analogix_dp-rockchip.c | 9 ++++++---
drivers/gpu/drm/rockchip/cdn-dp-core.c | 9 ++++++---
drivers/gpu/drm/rockchip/dw-mipi-dsi-rockchip.c | 9 +++++++--
drivers/gpu/drm/rockchip/dw-mipi-dsi2-rockchip.c | 8 ++++++--
drivers/gpu/drm/rockchip/dw_dp-rockchip.c | 1 -
drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c | 1 -
drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c | 1 -
drivers/gpu/drm/rockchip/rk3066_hdmi.c | 8 ++++++--
drivers/gpu/drm/rockchip/rockchip_lvds.c | 9 +++++++--
drivers/gpu/drm/rockchip/rockchip_rgb.c | 8 ++++++--
10 files changed, 44 insertions(+), 19 deletions(-)
diff --git a/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c
b/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c
index 776954c7d052..46c245e35d21 100644
--- a/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c
+++ b/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c
@@ -30,7 +30,6 @@
#include <drm/drm_of.h>
#include <drm/drm_print.h>
#include <drm/drm_probe_helper.h>
-#include <drm/drm_simple_kms_helper.h>
#include "rockchip_drm_drv.h"
@@ -303,6 +302,10 @@ rockchip_dp_drm_encoder_atomic_check(struct
drm_encoder *encoder,
return 0;
}
+static const struct drm_encoder_funcs rockchip_dp_encoder_funcs = {
+ .destroy = drm_encoder_cleanup,
+};
+
static const struct drm_encoder_helper_funcs
rockchip_dp_encoder_helper_funcs = {
.mode_fixup = rockchip_dp_drm_encoder_mode_fixup,
.mode_set = rockchip_dp_drm_encoder_mode_set,
@@ -361,8 +364,8 @@ static int rockchip_dp_drm_create_encoder(struct
rockchip_dp_device *dp)
dev->of_node);
DRM_DEBUG_KMS("possible_crtcs = 0x%x\n", encoder->possible_crtcs);
- ret = drm_simple_encoder_init(drm_dev, encoder,
- DRM_MODE_ENCODER_TMDS);
+ ret = drm_encoder_init(drm_dev, encoder, &rockchip_dp_encoder_funcs,
+ DRM_MODE_ENCODER_TMDS, NULL);
if (ret) {
DRM_ERROR("failed to initialize encoder with drm\n");
return ret;
diff --git a/drivers/gpu/drm/rockchip/cdn-dp-core.c
b/drivers/gpu/drm/rockchip/cdn-dp-core.c
index 190cce9530c8..c3f41a4449f5 100644
--- a/drivers/gpu/drm/rockchip/cdn-dp-core.c
+++ b/drivers/gpu/drm/rockchip/cdn-dp-core.c
@@ -23,7 +23,6 @@
#include <drm/drm_of.h>
#include <drm/drm_print.h>
#include <drm/drm_probe_helper.h>
-#include <drm/drm_simple_kms_helper.h>
#include "cdn-dp-core.h"
#include "cdn-dp-reg.h"
@@ -671,6 +670,10 @@ static int cdn_dp_encoder_atomic_check(struct
drm_encoder *encoder,
return 0;
}
+static const struct drm_encoder_funcs cdn_dp_encoder_funcs = {
+ .destroy = drm_encoder_cleanup,
+};
+
static const struct drm_encoder_helper_funcs cdn_dp_encoder_helper_funcs = {
.atomic_check = cdn_dp_encoder_atomic_check,
};
@@ -988,8 +991,8 @@ static int cdn_dp_bind(struct device *dev, struct
device *master, void *data)
dev->of_node);
DRM_DEBUG_KMS("possible_crtcs = 0x%x\n", encoder->possible_crtcs);
- ret = drm_simple_encoder_init(drm_dev, encoder,
- DRM_MODE_ENCODER_TMDS);
+ ret = drm_encoder_init(drm_dev, encoder, &cdn_dp_encoder_funcs,
+ DRM_MODE_ENCODER_TMDS, NULL);
if (ret) {
DRM_ERROR("failed to initialize encoder with drm\n");
return ret;
diff --git a/drivers/gpu/drm/rockchip/dw-mipi-dsi-rockchip.c
b/drivers/gpu/drm/rockchip/dw-mipi-dsi-rockchip.c
index 3547d91b25d3..a09b382d208e 100644
--- a/drivers/gpu/drm/rockchip/dw-mipi-dsi-rockchip.c
+++ b/drivers/gpu/drm/rockchip/dw-mipi-dsi-rockchip.c
@@ -25,7 +25,6 @@
#include <drm/drm_mipi_dsi.h>
#include <drm/drm_of.h>
#include <drm/drm_print.h>
-#include <drm/drm_simple_kms_helper.h>
#include "rockchip_drm_drv.h"
@@ -825,6 +824,10 @@ static void dw_mipi_dsi_encoder_enable(struct
drm_encoder *encoder)
clk_disable_unprepare(dsi->grf_clk);
}
+static const struct drm_encoder_funcs dw_mipi_dsi_encoder_funcs = {
+ .destroy = drm_encoder_cleanup,
+};
+
static const struct drm_encoder_helper_funcs
dw_mipi_dsi_encoder_helper_funcs = {
.atomic_check = dw_mipi_dsi_encoder_atomic_check,
@@ -840,7 +843,9 @@ static int rockchip_dsi_drm_create_encoder(struct
dw_mipi_dsi_rockchip *dsi,
encoder->possible_crtcs = drm_of_find_possible_crtcs(drm_dev,
dsi->dev->of_node);
- ret = drm_simple_encoder_init(drm_dev, encoder, DRM_MODE_ENCODER_DSI);
+ ret = drm_encoder_init(drm_dev, encoder,
+ &dw_mipi_dsi_encoder_funcs,
+ DRM_MODE_ENCODER_DSI, NULL);
if (ret) {
DRM_ERROR("Failed to initialize encoder with drm\n");
return ret;
diff --git a/drivers/gpu/drm/rockchip/dw-mipi-dsi2-rockchip.c
b/drivers/gpu/drm/rockchip/dw-mipi-dsi2-rockchip.c
index d2e76d36d724..9dc207c2d20d 100644
--- a/drivers/gpu/drm/rockchip/dw-mipi-dsi2-rockchip.c
+++ b/drivers/gpu/drm/rockchip/dw-mipi-dsi2-rockchip.c
@@ -23,7 +23,6 @@
#include <drm/bridge/dw_mipi_dsi2.h>
#include <drm/drm_mipi_dsi.h>
#include <drm/drm_of.h>
-#include <drm/drm_simple_kms_helper.h>
#include <uapi/linux/videodev2.h>
@@ -275,6 +274,10 @@ dw_mipi_dsi2_encoder_atomic_check(struct
drm_encoder *encoder,
return 0;
}
+static const struct drm_encoder_funcs dw_mipi_dsi2_encoder_funcs = {
+ .destroy = drm_encoder_cleanup,
+};
+
static const struct drm_encoder_helper_funcs
dw_mipi_dsi2_encoder_helper_funcs = {
.atomic_enable = dw_mipi_dsi2_encoder_atomic_enable,
@@ -290,7 +293,8 @@ static int rockchip_dsi2_drm_create_encoder(struct
dw_mipi_dsi2_rockchip *dsi2,
encoder->possible_crtcs = drm_of_find_possible_crtcs(drm_dev,
dsi2->dev->of_node);
- ret = drm_simple_encoder_init(drm_dev, encoder, DRM_MODE_ENCODER_DSI);
+ ret = drm_encoder_init(drm_dev, encoder, &dw_mipi_dsi2_encoder_funcs,
+ DRM_MODE_ENCODER_DSI, NULL);
if (ret) {
dev_err(dsi2->dev, "Failed to initialize encoder with drm\n");
return ret;
diff --git a/drivers/gpu/drm/rockchip/dw_dp-rockchip.c
b/drivers/gpu/drm/rockchip/dw_dp-rockchip.c
index 0de822360c8d..b23efb153c9e 100644
--- a/drivers/gpu/drm/rockchip/dw_dp-rockchip.c
+++ b/drivers/gpu/drm/rockchip/dw_dp-rockchip.c
@@ -20,7 +20,6 @@
#include <drm/drm_of.h>
#include <drm/drm_print.h>
#include <drm/drm_probe_helper.h>
-#include <drm/drm_simple_kms_helper.h>
#include "rockchip_drm_drv.h"
diff --git a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c
b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c
index cffc0af5190f..b6e154c35e7c 100644
--- a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c
+++ b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c
@@ -18,7 +18,6 @@
#include <drm/drm_managed.h>
#include <drm/drm_of.h>
#include <drm/drm_probe_helper.h>
-#include <drm/drm_simple_kms_helper.h>
#include "rockchip_drm_drv.h"
diff --git a/drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c
b/drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c
index f35484715c2d..af34062685cd 100644
--- a/drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c
+++ b/drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c
@@ -24,7 +24,6 @@
#include <drm/drm_managed.h>
#include <drm/drm_of.h>
#include <drm/drm_probe_helper.h>
-#include <drm/drm_simple_kms_helper.h>
#include "rockchip_drm_drv.h"
diff --git a/drivers/gpu/drm/rockchip/rk3066_hdmi.c
b/drivers/gpu/drm/rockchip/rk3066_hdmi.c
index 1996f8656612..b4ba9f894360 100644
--- a/drivers/gpu/drm/rockchip/rk3066_hdmi.c
+++ b/drivers/gpu/drm/rockchip/rk3066_hdmi.c
@@ -12,7 +12,6 @@
#include <drm/drm_of.h>
#include <drm/drm_print.h>
#include <drm/drm_probe_helper.h>
-#include <drm/drm_simple_kms_helper.h>
#include <linux/clk.h>
#include <linux/mfd/syscon.h>
@@ -454,6 +453,10 @@ rk3066_hdmi_encoder_atomic_check(struct
drm_encoder *encoder,
return 0;
}
+static const struct drm_encoder_funcs rk3066_hdmi_encoder_funcs = {
+ .destroy = drm_encoder_cleanup,
+};
+
static const
struct drm_encoder_helper_funcs rk3066_hdmi_encoder_helper_funcs = {
.atomic_check = rk3066_hdmi_encoder_atomic_check,
@@ -696,7 +699,8 @@ rk3066_hdmi_register(struct drm_device *drm,
struct rk3066_hdmi *hdmi)
return -EPROBE_DEFER;
drm_encoder_helper_add(encoder, &rk3066_hdmi_encoder_helper_funcs);
- drm_simple_encoder_init(drm, encoder, DRM_MODE_ENCODER_TMDS);
+ drm_encoder_init(drm, encoder, &rk3066_hdmi_encoder_funcs,
+ DRM_MODE_ENCODER_TMDS, NULL);
hdmi->bridge.driver_private = hdmi;
hdmi->bridge.funcs = &rk3066_hdmi_bridge_funcs;
diff --git a/drivers/gpu/drm/rockchip/rockchip_lvds.c
b/drivers/gpu/drm/rockchip/rockchip_lvds.c
index 7a0c4fa29f2f..f3be2c91d147 100644
--- a/drivers/gpu/drm/rockchip/rockchip_lvds.c
+++ b/drivers/gpu/drm/rockchip/rockchip_lvds.c
@@ -24,7 +24,6 @@
#include <drm/drm_panel.h>
#include <drm/drm_print.h>
#include <drm/drm_probe_helper.h>
-#include <drm/drm_simple_kms_helper.h>
#include "rockchip_drm_drv.h"
#include "rockchip_lvds.h"
@@ -427,6 +426,10 @@ static void px30_lvds_encoder_disable(struct
drm_encoder *encoder)
drm_panel_unprepare(lvds->panel);
}
+static const struct drm_encoder_funcs rockchip_lvds_encoder_funcs = {
+ .destroy = drm_encoder_cleanup,
+};
+
static const
struct drm_encoder_helper_funcs rk3288_lvds_encoder_helper_funcs = {
.enable = rk3288_lvds_encoder_enable,
@@ -594,7 +597,9 @@ static int rockchip_lvds_bind(struct device *dev,
struct device *master,
encoder->possible_crtcs = drm_of_find_possible_crtcs(drm_dev,
dev->of_node);
- ret = drm_simple_encoder_init(drm_dev, encoder, DRM_MODE_ENCODER_LVDS);
+ ret = drm_encoder_init(drm_dev, encoder,
+ &rockchip_lvds_encoder_funcs,
+ DRM_MODE_ENCODER_LVDS, NULL);
if (ret < 0) {
drm_err(drm_dev,
"failed to initialize encoder: %d\n", ret);
diff --git a/drivers/gpu/drm/rockchip/rockchip_rgb.c
b/drivers/gpu/drm/rockchip/rockchip_rgb.c
index add3123e5ce7..2ad24b914989 100644
--- a/drivers/gpu/drm/rockchip/rockchip_rgb.c
+++ b/drivers/gpu/drm/rockchip/rockchip_rgb.c
@@ -17,7 +17,6 @@
#include <drm/drm_panel.h>
#include <drm/drm_print.h>
#include <drm/drm_probe_helper.h>
-#include <drm/drm_simple_kms_helper.h>
#include "rockchip_drm_drv.h"
#include "rockchip_rgb.h"
@@ -65,6 +64,10 @@ rockchip_rgb_encoder_atomic_check(struct
drm_encoder *encoder,
return 0;
}
+static const struct drm_encoder_funcs rockchip_rgb_encoder_funcs = {
+ .destroy = drm_encoder_cleanup,
+};
+
static const
struct drm_encoder_helper_funcs rockchip_rgb_encoder_helper_funcs = {
.atomic_check = rockchip_rgb_encoder_atomic_check,
@@ -127,7 +130,8 @@ struct rockchip_rgb *rockchip_rgb_init(struct device *dev,
encoder = &rgb->encoder.encoder;
encoder->possible_crtcs = drm_crtc_mask(crtc);
- ret = drm_simple_encoder_init(drm_dev, encoder, DRM_MODE_ENCODER_NONE);
+ ret = drm_encoder_init(drm_dev, encoder, &rockchip_rgb_encoder_funcs,
+ DRM_MODE_ENCODER_NONE, NULL);
if (ret < 0) {
DRM_DEV_ERROR(drm_dev->dev,
"failed to initialize encoder: %d\n", ret);
--
2.51.2
^ permalink raw reply related
* Re: [PATCH v2] iommu/arm-smmu-v3: Shrink command/event/PRI queues in kdump kernel
From: Pranjal Shrivastava @ 2026-07-02 20:25 UTC (permalink / raw)
To: Kiryl Shutsemau
Cc: Will Deacon, Robin Murphy, Joerg Roedel, Jason Gunthorpe,
Nicolin Chen, Kyle McMartin, Breno Leitao, Usama Arif,
linux-arm-kernel, iommu, linux-kernel
In-Reply-To: <akaFcwcSHVGeT8PZ@thinkstation>
On Thu, Jul 02, 2026 at 04:38:55PM +0100, Kiryl Shutsemau wrote:
> On Thu, Jul 02, 2026 at 03:05:12PM +0000, Pranjal Shrivastava wrote:
> > On Thu, Jul 02, 2026 at 12:28:25PM +0100, Kiryl Shutsemau (Meta) wrote:
> > > The command, event and PRI queues are sized from the maxima the hardware
> >
> > A minor note here is PRI & EVT queues are disabled for the kdump kernel
> > (see arm_smmu_device_reset). We could just mention all SMMU queues are
> > sized [...] in the commit message.
>
> Fair enough.
>
> Here's updated commit message (I will send v3 in few days, if no new
> feedback):
>
> Subject: [PATCH v3] iommu/arm-smmu-v3: Shrink command/event/PRI queues in
> kdump kernel
>
> All SMMU queues are sized from the maxima the hardware advertises in IDR1,
> which can be several megabytes each, and are allocated at probe. The kdump
> kernel already disables the event and PRI queues (arm_smmu_device_reset()
> drops CR0_EVTQEN/CR0_PRIQEN) but still allocates them at full size. On
> systems with many SMMUv3 instances that cost is paid per instance and adds
> up to tens of megabytes of coherent DMA in the capture kernel.
>
> A kdump capture kernel runs from a small crashkernel reservation and only
> has to drive the few devices used to save the dump, so deep queues serve
> no purpose. The queues are not on the DMA data path, so dump throughput is
> unaffected; a shallower command queue only bounds how many commands may be
> in flight before a sync, which does not matter for the capture kernel's
> small device count and modest I/O.
>
> Clamp every queue to a single page when is_kdump_kernel() is true. Doing
> it in arm_smmu_init_one_queue() covers the command, event and PRI queues
> in one place. The command queue still holds at least one batch plus a sync
> (256 entries on a 4K-page kernel, well above CMDQ_BATCH_ENTRIES), so
> command batching keeps working.
>
Looks good. Thanks!
Praan
^ permalink raw reply
* [PATCH v6 00/12] ZTE zx297520v3 clock bindings and driver
From: Stefan Dösinger @ 2026-07-02 20:27 UTC (permalink / raw)
To: Michael Turquette, Stephen Boyd, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Philipp Zabel, Brian Masney
Cc: linux-clk, devicetree, linux-kernel, linux-arm-kernel,
Stefan Dösinger
Hi,
I am sending version 5 of my zx297520v3 clock patch. The major change is
using regmaps rather than raw mmio to access the clocks and moving reset
handling into its own mfd/aux bus driver.
I think the list of clocks in my driver is fairly complete; It is
certainly a lot better than what the downstream ZTE drivers have. I
deduced a lot of it by trial and error. I am sure there are some clocks
missing that will need to be added to the binding later. Afaiu adding
clocks is not an issue, but removing or reordering them is an ABI break.
Signed-off-by: Stefan Dösinger <stefandoesinger@gmail.com>
---
Changes in v6:
*) Use MFD for all 3 controllers - I hope both Conor and Philipp will
agree. I kept top and matrix bindings in soc/zte and lsp in clock/
though.
*) Clean up issues found by Sashiko. I pointed them out in the individual
patches. They are localized fixes and don't affect the overall design
*)small code consistency: Changed "zx297520v3_lsp" to use "-" , "rst" in
driver names to "reset"
Changes in v5:
*) Use MFD instead of aux bus for top and matrix clocks
*) Move top and matrix bindings to soc/zte
*) Give USB PHY its own resets
*) Other localized changes are noted in the individual patches
- Link to v4: https://lore.kernel.org/r/20260616-zx29clk-v4-0-ca994bd22e9d@gmail.com
Changes in v4:
*) Use syscon and regmap instead of raw IO
*) Move reset to its own driver on the aux bus, but keep reset and clk
in the same binding as it matches the way the hardware works
*) Go back to having matrixclk in its own device because syscon deals
poorly with multi io reg devices. List all PLL outputs from topclk as
inputs to matrixclk
*) Some more hardware research: Figure out the parents of the 4 possible
GPIO clock outputs and declare them in the driver. They are unused on
the hardware I have, but they show that all PLLs can be used.
- Link to v3: https://lore.kernel.org/r/20260529-zx29clk-v3-0-c7fe54ea388f@gmail.com
Changes in v3:
Model top and matrix clocks as one device
Add PLL driver
Fixed a few issues found by Sashiko: register lock, some missing devm_,
error handling
v2: Fix build issues introduced by checkpatch.pl fixes that I didn't
spot earlier.
---
Stefan Dösinger (12):
dt-bindings: soc: zte: Add zx297520v3 top clock and reset bindings
dt-bindings: soc: zte: Add zx297520v3 matrix clock and reset bindings
dt-bindings: clk: zte: Add zx297520v3 LSP clock and reset bindings
mfd: zx297520v3: Add a clock and reset MFD driver.
clk: zte: Add Clock registration infrastructure.
clk: zte: Add regmap based clocks
clk: zte: Add zx PLL support infrastructure
clk: zte: Introduce a driver for zx297520v3 top clocks
clk: zte: Introduce a driver for zx297520v3 matrix clocks
clk: zte: Introduce a driver for zx297520v3 LSP clocks
reset: zte: Add a zx297520v3 reset driver
ARM: dts: zte: Declare zx297520v3 CRM device nodes
.../bindings/clock/zte,zx297520v3-lspcrm.yaml | 96 +++
.../bindings/soc/zte/zte,zx297520v3-matrixcrm.yaml | 178 +++++
.../bindings/soc/zte/zte,zx297520v3-topcrm.yaml | 86 +++
MAINTAINERS | 7 +
arch/arm/boot/dts/zte/zx297520v3.dtsi | 98 ++-
drivers/clk/Kconfig | 1 +
drivers/clk/Makefile | 1 +
drivers/clk/zte/Kconfig | 27 +
drivers/clk/zte/Makefile | 6 +
drivers/clk/zte/clk-regmap.c | 250 +++++++
drivers/clk/zte/clk-zx.c | 142 ++++
drivers/clk/zte/clk-zx.h | 80 ++
drivers/clk/zte/clk-zx297520v3.c | 819 +++++++++++++++++++++
drivers/clk/zte/pll-zx.c | 495 +++++++++++++
drivers/reset/Kconfig | 10 +
drivers/reset/Makefile | 1 +
drivers/reset/reset-zte-zx297520v3.c | 234 ++++++
drivers/soc/Kconfig | 1 +
drivers/soc/Makefile | 1 +
drivers/soc/zte/Kconfig | 20 +
drivers/soc/zte/Makefile | 3 +
drivers/soc/zte/zx297520v3-crm.c | 95 +++
include/dt-bindings/clock/zte,zx297520v3-clk.h | 171 +++++
include/dt-bindings/reset/zte,zx297520v3-reset.h | 61 ++
24 files changed, 2875 insertions(+), 8 deletions(-)
---
base-commit: 6eb8711ece2ce27e52e327a5b7a628ed39b97f45
change-id: 20260510-zx29clk-2e4d39e3128c
Best regards,
--
Stefan Dösinger <stefandoesinger@gmail.com>
^ permalink raw reply
* [PATCH v6 01/12] dt-bindings: soc: zte: Add zx297520v3 top clock and reset bindings
From: Stefan Dösinger @ 2026-07-02 20:27 UTC (permalink / raw)
To: Michael Turquette, Stephen Boyd, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Philipp Zabel, Brian Masney
Cc: linux-clk, devicetree, linux-kernel, linux-arm-kernel,
Stefan Dösinger
In-Reply-To: <20260702-zx29clk-v6-0-377b704f80c4@gmail.com>
These SoCs have 3 clock and reset controllers: Top, Matrix and LSP. The
separation of concerns between Top and Matrix and the interface between
them is poorly defined in the hardware, so the bindings list all
potential PLL clocks that might be passed between them.
Generally every device has two clocks (one work clock, and one that
connects it to the bus, I call it PCLK), two reset bits (I don't know
what the difference is - sometimes asserting one is enough to reset the
device, sometimes both need to be asserted). PCLK and WCLK are
controlled by individual gates. Some devices have a mux and/or a
divider for their work clock. Some devices, like the GPIO controller,
only have reset bits and no clocks.
The top clock controller is fed by a 26mhz external oscillator and has 4
PLLs to generate other clock rates. ZTE's kernel mostly relies on the
boot ROM to set up PLLs, but one LTE-Related PLL is not configured
on some boards. Therefore my driver contains code to program PLLs. It
produces identical settings as the boot ROM for the pre-programmed
frequencies.
Not all clocks will have an explicit user in the end. I am defining a
lot of them simply to shut them off. The boot loader sets up a few of
the proprietary timers, which will send regular IRQs (although the
kernel of course doesn't need to listen to them). I don't plan to add a
driver for the proprietary timer as I see no use for them - the ARM arch
timer works just fine. I will add a driver for the very similar
proprietary watchdog though.
The clock list in this patch is pretty complete but not exhaustive.
There are other bits that are enabled, but I couldn't deduce what they
are controlling by trial and error. Some of them seem to do nothing.
Others cause an instant hang of the board when disabled. It is quite
likely that a handful more clocks will be added in the future, but not a
large number.
Signed-off-by: Stefan Dösinger <stefandoesinger@gmail.com>
---
Changes v5->v6:
Set value for syscon-reboot example (Sashiko). It was my intention to
set only the lowest bit, and I think Sashiko is right that without
'value' being set, all other bits are actively set to 0. It shouldn't
matter given my understanding of the hardware (afaics all other bits are
ignored), but actively clearing bits was not my intention.
I haven't changed the name match for "syscon-reboot". I see plenty of
examples of hardcoding this string as opposed to having a regex for
syscon-reboot@12345678 in other bindings.
Changes v4->v5:
Rename from zte,zx297520v3-topclk to zte,zx297520v3-topcrm and move to
soc/zte
Fix path in MAINTAINERS
Add syscon-reboot node to the binding
Give the USB and HSIC PHY resets their own reset control
---
.../bindings/soc/zte/zte,zx297520v3-topcrm.yaml | 86 +++++++++++++++++++
MAINTAINERS | 3 +
include/dt-bindings/clock/zte,zx297520v3-clk.h | 97 ++++++++++++++++++++++
include/dt-bindings/reset/zte,zx297520v3-reset.h | 32 +++++++
4 files changed, 218 insertions(+)
diff --git a/Documentation/devicetree/bindings/soc/zte/zte,zx297520v3-topcrm.yaml b/Documentation/devicetree/bindings/soc/zte/zte,zx297520v3-topcrm.yaml
new file mode 100644
index 000000000000..5a5d97120056
--- /dev/null
+++ b/Documentation/devicetree/bindings/soc/zte/zte,zx297520v3-topcrm.yaml
@@ -0,0 +1,86 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/soc/zte/zte,zx297520v3-topcrm.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: ZTE zx297520v3 SoC top clock and reset controller
+
+maintainers:
+ - Stefan Dösinger <stefandoesinger@gmail.com>
+
+description: |
+ The zx297520v3's top clock and reset controller generates clocks for core
+ devices on the board like the main bus, USB and timers. In addition to clocks
+ it has reset controls for peripherals, a global board reset, watchdog reset
+ controls and a USB status register.
+
+ The controller has two clock inputs: a 26 MHz and a 32 KHz external
+ oscillator. They need to be provided as input clocks. The controller provides
+ clocks to the downstream Matrix clock controller.
+
+ All available clocks are defined as preprocessor macros in the
+ 'dt-bindings/clock/zte,zx297520v3-clk.h' header. The resets are defined in the
+ 'dt-bindings/reset/zte,zx297520v3-reset.h' header.
+
+properties:
+ compatible:
+ items:
+ - const: zte,zx297520v3-topcrm
+ - const: syscon
+
+ reg:
+ maxItems: 1
+
+ clocks:
+ items:
+ - description: 26 MHz external oscillator
+ - description: 32 KHz external oscillator
+
+ clock-names:
+ items:
+ - const: osc26m
+ - const: osc32k
+
+ "#clock-cells":
+ const: 1
+
+ "#reset-cells":
+ const: 1
+
+ syscon-reboot:
+ type: object
+ $ref: /schemas/power/reset/syscon-reboot.yaml#
+ description:
+ Reboot method for the SoC.
+
+required:
+ - compatible
+ - reg
+ - clocks
+ - clock-names
+ - '#clock-cells'
+ - '#reset-cells'
+
+additionalProperties: false
+
+examples:
+ - |
+ #include <dt-bindings/clock/zte,zx297520v3-clk.h>
+ #include <dt-bindings/reset/zte,zx297520v3-reset.h>
+
+ clock-controller@13b000 {
+ compatible = "zte,zx297520v3-topcrm", "syscon";
+ reg = <0x0013b000 0x400>;
+ clocks = <&osc26m>, <&osc32k>;
+ clock-names = "osc26m", "osc32k";
+ #clock-cells = <1>;
+ #reset-cells = <1>;
+
+ syscon-reboot {
+ compatible = "syscon-reboot";
+ offset = <0x0>;
+ mask = <0x1>;
+ value = <0x1>;
+ };
+ };
diff --git a/MAINTAINERS b/MAINTAINERS
index 2f0a4192b0e9..2b1cf28dff5d 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -3878,8 +3878,11 @@ L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
S: Odd fixes
F: Documentation/arch/arm/zte/
F: Documentation/devicetree/bindings/arm/zte.yaml
+F: Documentation/devicetree/bindings/soc/zte/
F: arch/arm/boot/dts/zte/
F: arch/arm/mach-zte/
+F: include/dt-bindings/clock/zte,zx297520v3-clk.h
+F: include/dt-bindings/reset/zte,zx297520v3-reset.h
ARM/ZYNQ ARCHITECTURE
M: Michal Simek <michal.simek@amd.com>
diff --git a/include/dt-bindings/clock/zte,zx297520v3-clk.h b/include/dt-bindings/clock/zte,zx297520v3-clk.h
new file mode 100644
index 000000000000..de1c08b6a5a9
--- /dev/null
+++ b/include/dt-bindings/clock/zte,zx297520v3-clk.h
@@ -0,0 +1,97 @@
+/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) */
+/*
+ * Copyright (C) Stefan Dösinger.
+ */
+
+#ifndef __DT_BINDINGS_CLOCK_ZX297520V3_H
+#define __DT_BINDINGS_CLOCK_ZX297520V3_H
+
+#define ZX297520V3_M0_WCLK 1
+#define ZX297520V3_SRAM1_PCLK 2
+#define ZX297520V3_SRAM2_PCLK 3
+#define ZX297520V3_UART0_WCLK 4
+#define ZX297520V3_UART0_PCLK 5
+#define ZX297520V3_I2C0_WCLK 6
+#define ZX297520V3_I2C0_PCLK 7
+#define ZX297520V3_RTC_WCLK 8
+#define ZX297520V3_RTC_PCLK 9
+#define ZX297520V3_LPM_GSM_WCLK 10
+#define ZX297520V3_LPM_GSM_PCLK 11
+#define ZX297520V3_LPM_LTE_WCLK 12
+#define ZX297520V3_LPM_LTE_PCLK 13
+#define ZX297520V3_LPM_TD_WCLK 14
+#define ZX297520V3_LPM_TD_PCLK 15
+#define ZX297520V3_LPM_W_WCLK 16
+#define ZX297520V3_LPM_W_PCLK 17
+#define ZX297520V3_TIMER_T08_WCLK 18
+#define ZX297520V3_TIMER_T08_PCLK 19
+#define ZX297520V3_TIMER_T09_WCLK 20
+#define ZX297520V3_TIMER_T09_PCLK 21
+#define ZX297520V3_MPLL 22
+#define ZX297520V3_MPLL_D2 23
+#define ZX297520V3_MPLL_D3 24
+#define ZX297520V3_MPLL_D4 25
+#define ZX297520V3_MPLL_D5 26
+#define ZX297520V3_MPLL_D6 27
+#define ZX297520V3_MPLL_D8 28
+#define ZX297520V3_MPLL_D12 29
+#define ZX297520V3_MPLL_D16 30
+#define ZX297520V3_MPLL_D26 31
+#define ZX297520V3_UPLL 32
+#define ZX297520V3_UPLL_D2 33
+#define ZX297520V3_UPLL_D3 34
+#define ZX297520V3_UPLL_D4 35
+#define ZX297520V3_UPLL_D5 36
+#define ZX297520V3_UPLL_D6 37
+#define ZX297520V3_UPLL_D8 38
+#define ZX297520V3_UPLL_D12 39
+#define ZX297520V3_UPLL_D16 40
+#define ZX297520V3_DPLL 41
+#define ZX297520V3_DPLL_D2 42
+#define ZX297520V3_DPLL_D3 43
+#define ZX297520V3_DPLL_D4 44
+#define ZX297520V3_DPLL_D5 45
+#define ZX297520V3_DPLL_D6 46
+#define ZX297520V3_DPLL_D8 47
+#define ZX297520V3_DPLL_D12 48
+#define ZX297520V3_DPLL_D16 49
+#define ZX297520V3_GPLL 50
+#define ZX297520V3_GPLL_D2 51
+#define ZX297520V3_GPLL_D3 52
+#define ZX297520V3_GPLL_D4 53
+#define ZX297520V3_GPLL_D5 54
+#define ZX297520V3_GPLL_D6 55
+#define ZX297520V3_GPLL_D8 56
+#define ZX297520V3_GPLL_D12 57
+#define ZX297520V3_GPLL_D16 58
+#define ZX297520V3_PMM_WCLK 59
+#define ZX297520V3_PMM_PCLK 60
+#define ZX297520V3_OUT0_WCLK 61
+#define ZX297520V3_OUT1_WCLK 62
+#define ZX297520V3_OUT2_WCLK 63
+#define ZX297520V3_OUT32K_WCLK 64
+#define ZX297520V3_RMIIPHY_WCLK 65
+#define ZX297520V3_TIMER_T12_WCLK 66
+#define ZX297520V3_TIMER_T12_PCLK 67
+#define ZX297520V3_TIMER_T13_WCLK 68
+#define ZX297520V3_TIMER_T13_PCLK 69
+#define ZX297520V3_TIMER_T14_WCLK 70
+#define ZX297520V3_TIMER_T14_PCLK 71
+#define ZX297520V3_TIMER_T15_WCLK 72
+#define ZX297520V3_TIMER_T15_PCLK 73
+#define ZX297520V3_TIMER_T16_WCLK 74
+#define ZX297520V3_TIMER_T16_PCLK 75
+#define ZX297520V3_TIMER_T17_WCLK 76
+#define ZX297520V3_TIMER_T17_PCLK 77
+#define ZX297520V3_WDT_T18_WCLK 78
+#define ZX297520V3_WDT_T18_PCLK 79
+#define ZX297520V3_USIM1_WCLK 80
+#define ZX297520V3_USIM1_PCLK 81
+#define ZX297520V3_AHB_WCLK 82
+#define ZX297520V3_AHB_PCLK 83
+#define ZX297520V3_USB_WCLK 84
+#define ZX297520V3_USB_PCLK 85
+#define ZX297520V3_HSIC_WCLK 86
+#define ZX297520V3_HSIC_PCLK 87
+
+#endif /* __DT_BINDINGS_CLOCK_ZX297520V3_H */
diff --git a/include/dt-bindings/reset/zte,zx297520v3-reset.h b/include/dt-bindings/reset/zte,zx297520v3-reset.h
new file mode 100644
index 000000000000..43db72bb59de
--- /dev/null
+++ b/include/dt-bindings/reset/zte,zx297520v3-reset.h
@@ -0,0 +1,32 @@
+/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) */
+/*
+ * Copyright (C) Stefan Dösinger.
+ */
+
+#ifndef __DT_BINDINGS_RESET_ZX297520V3_H
+#define __DT_BINDINGS_RESET_ZX297520V3_H
+
+#define ZX297520V3_ZSP_RESET 0
+#define ZX297520V3_UART0_RESET 1
+#define ZX297520V3_I2C0_RESET 2
+#define ZX297520V3_RTC_RESET 3
+#define ZX297520V3_TIMER_T08_RESET 4
+#define ZX297520V3_TIMER_T09_RESET 5
+#define ZX297520V3_PMM_RESET 6
+#define ZX297520V3_GPIO_RESET 7
+#define ZX297520V3_GPIO8_RESET 8
+#define ZX297520V3_TIMER_T12_RESET 9
+#define ZX297520V3_TIMER_T13_RESET 10
+#define ZX297520V3_TIMER_T14_RESET 11
+#define ZX297520V3_TIMER_T15_RESET 12
+#define ZX297520V3_TIMER_T16_RESET 13
+#define ZX297520V3_TIMER_T17_RESET 14
+#define ZX297520V3_WDT_T18_RESET 15
+#define ZX297520V3_USIM1_RESET 16
+#define ZX297520V3_AHB_RESET 17
+#define ZX297520V3_USB_PHY_RESET 18
+#define ZX297520V3_USB_RESET 19
+#define ZX297520V3_HSIC_PHY_RESET 20
+#define ZX297520V3_HSIC_RESET 21
+
+#endif /* __DT_BINDINGS_RESET_ZX297520V3_H */
--
2.54.0
^ permalink raw reply related
* [PATCH v6 02/12] dt-bindings: soc: zte: Add zx297520v3 matrix clock and reset bindings
From: Stefan Dösinger @ 2026-07-02 20:27 UTC (permalink / raw)
To: Michael Turquette, Stephen Boyd, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Philipp Zabel, Brian Masney
Cc: linux-clk, devicetree, linux-kernel, linux-arm-kernel,
Stefan Dösinger
In-Reply-To: <20260702-zx29clk-v6-0-377b704f80c4@gmail.com>
This controller contains clocks and resets for high speed devices on the
zx297520v3 board and hardware spinlocks that I expect will be necessary
to communicate correctly with the LTE DSP firmware blob.
A simple MFD driver will instantiate independent clock, reset and hwlock
drivers.
Signed-off-by: Stefan Dösinger <stefandoesinger@gmail.com>
---
Changes
v5->v6:
Add syscon compatible - Conor suggested this after v4 and I forgot it in v5.
v4->v5:
Move binding to soc/zte
Remove topclk from the example
Add #hwlock-cells for hw spinlock registers
Add more clocks I stumbled into: sram0 and another LTE related device
v3->v4:
Split matrixclk into its own controller again because syscon/regmap
deals poorly with device nodes that have more than one memory region. As
a consequence I am passing all PLL outputs generated on Topclk down to
Matrixclk.
---
.../bindings/soc/zte/zte,zx297520v3-matrixcrm.yaml | 178 +++++++++++++++++++++
include/dt-bindings/clock/zte,zx297520v3-clk.h | 37 +++++
include/dt-bindings/reset/zte,zx297520v3-reset.h | 10 ++
3 files changed, 225 insertions(+)
diff --git a/Documentation/devicetree/bindings/soc/zte/zte,zx297520v3-matrixcrm.yaml b/Documentation/devicetree/bindings/soc/zte/zte,zx297520v3-matrixcrm.yaml
new file mode 100644
index 000000000000..90224ee35703
--- /dev/null
+++ b/Documentation/devicetree/bindings/soc/zte/zte,zx297520v3-matrixcrm.yaml
@@ -0,0 +1,178 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/soc/zte/zte,zx297520v3-matrixcrm.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: ZTE zx297520v3 SoC matrix clock and reset controller
+
+maintainers:
+ - Stefan Dösinger <stefandoesinger@gmail.com>
+
+description: |
+ This controller contains clock and reset controls for high speed devices on
+ the zx297520v3 board: The CPU, RAM, SDIO and Ethernet clocks and resets are
+ found here. This controller requires PLL-generated clocks from Topcrm as well
+ as the fixed 26 MHz and 32 KHz oscillators found on this board.
+
+ This controller also contains hardware mutex registers for synchronization
+ with different processors on this board.
+
+ All available clocks are defined as preprocessor macros in the
+ 'dt-bindings/clock/zte,zx297520v3-clk.h' header. Resets are defined in the
+ 'dt-bindings/reset/zte,zx297520v3-reset.h' header.
+
+properties:
+ compatible:
+ items:
+ - const: zte,zx297520v3-matrixcrm
+ - const: syscon
+
+ reg:
+ maxItems: 1
+
+ clocks:
+ items:
+ - description: 26 MHz external oscillator
+ - description: 32 KHz external oscillator
+ - description: Main PLL output from topcrm (usually 624 MHz)
+ - description: Main PLL subdivision factor 2
+ - description: Main PLL subdivision factor 3
+ - description: Main PLL subdivision factor 4
+ - description: Main PLL subdivision factor 5
+ - description: Main PLL subdivision factor 6
+ - description: Main PLL subdivision factor 8
+ - description: Main PLL subdivision factor 12
+ - description: Main PLL subdivision factor 16
+ - description: Main PLL subdivision factor 26
+ - description: Upll output from topcrm (Usually 480 MHz)
+ - description: Upll subdivision factor 2
+ - description: Upll subdivision factor 3
+ - description: Upll subdivision factor 4
+ - description: Upll subdivision factor 5
+ - description: Upll subdivision factor 6
+ - description: Upll subdivision factor 8
+ - description: Upll subdivision factor 12
+ - description: Upll subdivision factor 16
+ - description: Dpll output from topcrm (usually 492.88 MHz)
+ - description: Dpll subdivision factor 2
+ - description: Dpll subdivision factor 3
+ - description: Dpll subdivision factor 4
+ - description: Dpll subdivision factor 5
+ - description: Dpll subdivision factor 6
+ - description: Dpll subdivision factor 8
+ - description: Dpll subdivision factor 12
+ - description: Dpll subdivision factor 16
+ - description: Gpll output from topcrm (usually 200 MHz)
+ - description: Gpll subdivision factor 2
+ - description: Gpll subdivision factor 3
+ - description: Gpll subdivision factor 4
+ - description: Gpll subdivision factor 5
+ - description: Gpll subdivision factor 6
+ - description: Gpll subdivision factor 8
+ - description: Gpll subdivision factor 12
+ - description: Gpll subdivision factor 16
+
+ clock-names:
+ items:
+ - const: osc26m
+ - const: osc32k
+ - const: mpll
+ - const: mpll_d2
+ - const: mpll_d3
+ - const: mpll_d4
+ - const: mpll_d5
+ - const: mpll_d6
+ - const: mpll_d8
+ - const: mpll_d12
+ - const: mpll_d16
+ - const: mpll_d26
+ - const: upll
+ - const: upll_d2
+ - const: upll_d3
+ - const: upll_d4
+ - const: upll_d5
+ - const: upll_d6
+ - const: upll_d8
+ - const: upll_d12
+ - const: upll_d16
+ - const: dpll
+ - const: dpll_d2
+ - const: dpll_d3
+ - const: dpll_d4
+ - const: dpll_d5
+ - const: dpll_d6
+ - const: dpll_d8
+ - const: dpll_d12
+ - const: dpll_d16
+ - const: gpll
+ - const: gpll_d2
+ - const: gpll_d3
+ - const: gpll_d4
+ - const: gpll_d5
+ - const: gpll_d6
+ - const: gpll_d8
+ - const: gpll_d12
+ - const: gpll_d16
+
+ "#clock-cells":
+ const: 1
+
+ "#hwlock-cells":
+ const: 1
+
+ "#reset-cells":
+ const: 1
+
+required:
+ - compatible
+ - reg
+ - clocks
+ - clock-names
+ - '#clock-cells'
+ - "#hwlock-cells"
+ - '#reset-cells'
+
+additionalProperties: false
+
+examples:
+ - |
+ #include <dt-bindings/clock/zte,zx297520v3-clk.h>
+ #include <dt-bindings/reset/zte,zx297520v3-reset.h>
+
+ clock-controller@1306000 {
+ compatible = "zte,zx297520v3-matrixcrm", "syscon";
+ reg = <0x01306000 0x400>;
+ clocks = <&osc26m>, <&osc32k>,
+ <&topcrm ZX297520V3_MPLL>, <&topcrm ZX297520V3_MPLL_D2>,
+ <&topcrm ZX297520V3_MPLL_D3>, <&topcrm ZX297520V3_MPLL_D4>,
+ <&topcrm ZX297520V3_MPLL_D5>, <&topcrm ZX297520V3_MPLL_D6>,
+ <&topcrm ZX297520V3_MPLL_D8>, <&topcrm ZX297520V3_MPLL_D12>,
+ <&topcrm ZX297520V3_MPLL_D16>, <&topcrm ZX297520V3_MPLL_D26>,
+ <&topcrm ZX297520V3_UPLL>, <&topcrm ZX297520V3_UPLL_D2>,
+ <&topcrm ZX297520V3_UPLL_D3>, <&topcrm ZX297520V3_UPLL_D4>,
+ <&topcrm ZX297520V3_UPLL_D5>, <&topcrm ZX297520V3_UPLL_D6>,
+ <&topcrm ZX297520V3_UPLL_D8>, <&topcrm ZX297520V3_UPLL_D12>,
+ <&topcrm ZX297520V3_UPLL_D16>,
+ <&topcrm ZX297520V3_DPLL>, <&topcrm ZX297520V3_DPLL_D2>,
+ <&topcrm ZX297520V3_DPLL_D3>, <&topcrm ZX297520V3_DPLL_D4>,
+ <&topcrm ZX297520V3_DPLL_D5>, <&topcrm ZX297520V3_DPLL_D6>,
+ <&topcrm ZX297520V3_DPLL_D8>, <&topcrm ZX297520V3_DPLL_D12>,
+ <&topcrm ZX297520V3_DPLL_D16>,
+ <&topcrm ZX297520V3_GPLL>, <&topcrm ZX297520V3_GPLL_D2>,
+ <&topcrm ZX297520V3_GPLL_D3>, <&topcrm ZX297520V3_GPLL_D4>,
+ <&topcrm ZX297520V3_GPLL_D5>, <&topcrm ZX297520V3_GPLL_D6>,
+ <&topcrm ZX297520V3_GPLL_D8>, <&topcrm ZX297520V3_GPLL_D12>,
+ <&topcrm ZX297520V3_GPLL_D16>;
+ clock-names = "osc26m", "osc32k", "mpll", "mpll_d2", "mpll_d3",
+ "mpll_d4", "mpll_d5", "mpll_d6", "mpll_d8", "mpll_d12",
+ "mpll_d16", "mpll_d26", "upll", "upll_d2", "upll_d3",
+ "upll_d4", "upll_d5", "upll_d6", "upll_d8", "upll_d12",
+ "upll_d16", "dpll", "dpll_d2", "dpll_d3", "dpll_d4",
+ "dpll_d5", "dpll_d6", "dpll_d8", "dpll_d12", "dpll_d16",
+ "gpll", "gpll_d2", "gpll_d3", "gpll_d4", "gpll_d5",
+ "gpll_d6", "gpll_d8", "gpll_d12", "gpll_d16";
+ #clock-cells = <1>;
+ #hwlock-cells = <1>;
+ #reset-cells = <1>;
+ };
diff --git a/include/dt-bindings/clock/zte,zx297520v3-clk.h b/include/dt-bindings/clock/zte,zx297520v3-clk.h
index de1c08b6a5a9..8a6aa456a708 100644
--- a/include/dt-bindings/clock/zte,zx297520v3-clk.h
+++ b/include/dt-bindings/clock/zte,zx297520v3-clk.h
@@ -94,4 +94,41 @@
#define ZX297520V3_HSIC_WCLK 86
#define ZX297520V3_HSIC_PCLK 87
+#define ZX297520V3_CPU_WCLK 1
+#define ZX297520V3_CPU_PCLK 2
+#define ZX297520V3_ZSP_WCLK 3
+#define ZX297520V3_EDCP_WCLK 4
+#define ZX297520V3_EDCP_PCLK 5
+#define ZX297520V3_SD0_WCLK 6
+#define ZX297520V3_SD0_PCLK 7
+#define ZX297520V3_SD0_CDET 8
+#define ZX297520V3_SD1_WCLK 9
+#define ZX297520V3_SD1_PCLK 10
+#define ZX297520V3_SD1_CDET 11
+#define ZX297520V3_NAND_WCLK 12
+#define ZX297520V3_NAND_PCLK 13
+#define ZX297520V3_DMA_PCLK 14
+#define ZX297520V3_MBOX_PCLK 15
+#define ZX297520V3_PDCFG_WCLK 16
+#define ZX297520V3_PDCFG_PCLK 17
+#define ZX297520V3_SSC_WCLK 18
+#define ZX297520V3_SSC_PCLK 19
+#define ZX297520V3_GMAC_WCLK 20
+#define ZX297520V3_GMAC_PCLK 21
+#define ZX297520V3_GMAC_AHB 22
+#define ZX297520V3_VOU_WCLK 23
+#define ZX297520V3_VOU_PCLK 24
+#define ZX297520V3_LSP_MPLL_D5_WCLK 25
+#define ZX297520V3_LSP_MPLL_D4_WCLK 26
+#define ZX297520V3_LSP_MPLL_D6_WCLK 27
+#define ZX297520V3_LSP_MPLL_D8_WCLK 28
+#define ZX297520V3_LSP_MPLL_D12_WCLK 29
+#define ZX297520V3_LSP_OSC26M_WCLK 30
+#define ZX297520V3_LSP_OSC32K_WCLK 31
+#define ZX297520V3_LSP_PCLK 32
+#define ZX297520V3_LSP_TDM_WCLK 33
+#define ZX297520V3_LSP_DPLL_D4_WCLK 34
+#define ZX297520V3_SRAM0_PCLK 35
+#define ZX297520V3_GSM_CFG_PCLK 36
+
#endif /* __DT_BINDINGS_CLOCK_ZX297520V3_H */
diff --git a/include/dt-bindings/reset/zte,zx297520v3-reset.h b/include/dt-bindings/reset/zte,zx297520v3-reset.h
index 43db72bb59de..81ffc8bc34c5 100644
--- a/include/dt-bindings/reset/zte,zx297520v3-reset.h
+++ b/include/dt-bindings/reset/zte,zx297520v3-reset.h
@@ -29,4 +29,14 @@
#define ZX297520V3_HSIC_PHY_RESET 20
#define ZX297520V3_HSIC_RESET 21
+#define ZX297520V3_CPU_RESET 0
+#define ZX297520V3_EDCP_RESET 1
+#define ZX297520V3_SD0_RESET 2
+#define ZX297520V3_SD1_RESET 3
+#define ZX297520V3_NAND_RESET 4
+#define ZX297520V3_PDCFG_RESET 5
+#define ZX297520V3_SSC_RESET 6
+#define ZX297520V3_GMAC_RESET 7
+#define ZX297520V3_VOU_RESET 8
+
#endif /* __DT_BINDINGS_RESET_ZX297520V3_H */
--
2.54.0
^ permalink raw reply related
* [PATCH v6 03/12] dt-bindings: clk: zte: Add zx297520v3 LSP clock and reset bindings
From: Stefan Dösinger @ 2026-07-02 20:27 UTC (permalink / raw)
To: Michael Turquette, Stephen Boyd, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Philipp Zabel, Brian Masney
Cc: linux-clk, devicetree, linux-kernel, linux-arm-kernel,
Stefan Dösinger
In-Reply-To: <20260702-zx29clk-v6-0-377b704f80c4@gmail.com>
The clock controller of the zx297520v3 Low Speed Peripherals is
relatively clean. One register per device with gates, muxes and resets
and for some devices a divider. There are even bits in the matrix
controller to control propagation of clock lines down to LSP.
The clocks are sorted by register address and I am convinced that the
device list is complete. There are however a few more registers that are
likely extra dividers for TDM and I2S devices
Signed-off-by: Stefan Dösinger <stefandoesinger@gmail.com>
---
Patch changelog:
v5:
Rename from lspclk to lspcrm
Remove matrixcrm from example
v4: Order properties compatible->reg->clocks->clock->names->#cells
---
.../bindings/clock/zte,zx297520v3-lspcrm.yaml | 96 ++++++++++++++++++++++
MAINTAINERS | 1 +
include/dt-bindings/clock/zte,zx297520v3-clk.h | 37 +++++++++
include/dt-bindings/reset/zte,zx297520v3-reset.h | 19 +++++
4 files changed, 153 insertions(+)
diff --git a/Documentation/devicetree/bindings/clock/zte,zx297520v3-lspcrm.yaml b/Documentation/devicetree/bindings/clock/zte,zx297520v3-lspcrm.yaml
new file mode 100644
index 000000000000..c510129068de
--- /dev/null
+++ b/Documentation/devicetree/bindings/clock/zte,zx297520v3-lspcrm.yaml
@@ -0,0 +1,96 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/clock/zte,zx297520v3-lspcrm.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: ZTE zx297520v3 SoC LSP clock and reset controller
+
+maintainers:
+ - Stefan Dösinger <stefandoesinger@gmail.com>
+
+description: |
+ This clock and reset controller controls low speed peripherals on the board.
+ This is a relatively isolated subsystem containing UART, I2C, I2S and SPI
+ devices. The controller is responsible for bringing the devices out of reset
+ and enabling their clocks as needed.
+
+ The controller receives its clock signal from the matrix controller and need
+ to be declared as clock inputs.
+
+ All available clocks are defined as preprocessor macros in the
+ 'dt-bindings/clock/zte,zx297520v3-clk.h' header. Resets are defined in the
+ 'dt-bindings/reset/zte,zx297520v3-reset.h' header.
+
+properties:
+ compatible:
+ const: zte,zx297520v3-lspcrm
+
+ reg:
+ maxItems: 1
+
+ clocks:
+ items:
+ - description: Main PLL divided by 5 output from matrixcrm (124.8 MHz)
+ - description: Main PLL divided by 4 output from matrixcrm (156 MHz)
+ - description: Main PLL divided by 6 output from matrixcrm (104 MHz)
+ - description: Main PLL divided by 8 output from matrixcrm (78 MHz)
+ - description: Main PLL divided by 12 output from matrixcrm (52 MHz)
+ - description: Main oscillator output from matrixcrm (26 MHz)
+ - description: Timer oscillator output from matrixcrm (32 KHz)
+ - description: LSP pclk output from matrixcrm (26 MHz)
+ - description: TDM wclk mux output from matrixcrm
+ - description: DPLL divided by 4 output from matrixcrm (122.88 MHz)
+
+ clock-names:
+ items:
+ - const: mpll_d5
+ - const: mpll_d4
+ - const: mpll_d6
+ - const: mpll_d8
+ - const: mpll_d12
+ - const: osc26m
+ - const: osc32k
+ - const: pclk
+ - const: tdm_wclk
+ - const: dpll_d4
+
+ "#clock-cells":
+ const: 1
+
+ "#reset-cells":
+ const: 1
+
+required:
+ - compatible
+ - reg
+ - clocks
+ - clock-names
+ - '#clock-cells'
+ - '#reset-cells'
+
+additionalProperties: false
+
+examples:
+ - |
+ #include <dt-bindings/clock/zte,zx297520v3-clk.h>
+ #include <dt-bindings/reset/zte,zx297520v3-reset.h>
+
+ clock-controller@1400000 {
+ compatible = "zte,zx297520v3-lspcrm";
+ reg = <0x01400000 0x100>;
+ clocks = <&matrixcrm ZX297520V3_LSP_MPLL_D5_WCLK>,
+ <&matrixcrm ZX297520V3_LSP_MPLL_D4_WCLK>,
+ <&matrixcrm ZX297520V3_LSP_MPLL_D6_WCLK>,
+ <&matrixcrm ZX297520V3_LSP_MPLL_D8_WCLK>,
+ <&matrixcrm ZX297520V3_LSP_MPLL_D12_WCLK>,
+ <&matrixcrm ZX297520V3_LSP_OSC26M_WCLK>,
+ <&matrixcrm ZX297520V3_LSP_OSC32K_WCLK>,
+ <&matrixcrm ZX297520V3_LSP_PCLK>,
+ <&matrixcrm ZX297520V3_LSP_TDM_WCLK>,
+ <&matrixcrm ZX297520V3_LSP_DPLL_D4_WCLK>;
+ clock-names = "mpll_d5", "mpll_d4", "mpll_d6", "mpll_d8", "mpll_d12",
+ "osc26m", "osc32k", "pclk", "tdm_wclk", "dpll_d4";
+ #clock-cells = <1>;
+ #reset-cells = <1>;
+ };
diff --git a/MAINTAINERS b/MAINTAINERS
index 2b1cf28dff5d..ceedfa359d47 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -3878,6 +3878,7 @@ L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
S: Odd fixes
F: Documentation/arch/arm/zte/
F: Documentation/devicetree/bindings/arm/zte.yaml
+F: Documentation/devicetree/bindings/clock/zte,zx297520v3-lspcrm.yaml
F: Documentation/devicetree/bindings/soc/zte/
F: arch/arm/boot/dts/zte/
F: arch/arm/mach-zte/
diff --git a/include/dt-bindings/clock/zte,zx297520v3-clk.h b/include/dt-bindings/clock/zte,zx297520v3-clk.h
index 8a6aa456a708..3c390211f897 100644
--- a/include/dt-bindings/clock/zte,zx297520v3-clk.h
+++ b/include/dt-bindings/clock/zte,zx297520v3-clk.h
@@ -131,4 +131,41 @@
#define ZX297520V3_SRAM0_PCLK 35
#define ZX297520V3_GSM_CFG_PCLK 36
+#define ZX297520V3_TIMER_L1_WCLK 1
+#define ZX297520V3_TIMER_L1_PCLK 2
+#define ZX297520V3_WDT_L2_WCLK 3
+#define ZX297520V3_WDT_L2_PCLK 4
+#define ZX297520V3_WDT_L3_WCLK 5
+#define ZX297520V3_WDT_L3_PCLK 6
+#define ZX297520V3_PWM_WCLK 7
+#define ZX297520V3_PWM_PCLK 8
+#define ZX297520V3_I2S0_WCLK 9
+#define ZX297520V3_I2S0_PCLK 10
+#define ZX297520V3_I2S1_WCLK 11
+#define ZX297520V3_I2S1_PCLK 12
+#define ZX297520V3_QSPI_WCLK 13
+#define ZX297520V3_QSPI_PCLK 14
+#define ZX297520V3_UART1_WCLK 15
+#define ZX297520V3_UART1_PCLK 16
+#define ZX297520V3_I2C1_WCLK 17
+#define ZX297520V3_I2C1_PCLK 18
+#define ZX297520V3_SPI0_WCLK 19
+#define ZX297520V3_SPI0_PCLK 20
+#define ZX297520V3_TIMER_LB_WCLK 21
+#define ZX297520V3_TIMER_LB_PCLK 22
+#define ZX297520V3_TIMER_LC_WCLK 23
+#define ZX297520V3_TIMER_LC_PCLK 24
+#define ZX297520V3_UART2_WCLK 25
+#define ZX297520V3_UART2_PCLK 26
+#define ZX297520V3_WDT_LE_WCLK 27
+#define ZX297520V3_WDT_LE_PCLK 28
+#define ZX297520V3_TIMER_LF_WCLK 29
+#define ZX297520V3_TIMER_LF_PCLK 30
+#define ZX297520V3_SPI1_WCLK 31
+#define ZX297520V3_SPI1_PCLK 32
+#define ZX297520V3_TIMER_L11_WCLK 33
+#define ZX297520V3_TIMER_L11_PCLK 34
+#define ZX297520V3_TDM_WCLK 35
+#define ZX297520V3_TDM_PCLK 36
+
#endif /* __DT_BINDINGS_CLOCK_ZX297520V3_H */
diff --git a/include/dt-bindings/reset/zte,zx297520v3-reset.h b/include/dt-bindings/reset/zte,zx297520v3-reset.h
index 81ffc8bc34c5..85a2f0707cdc 100644
--- a/include/dt-bindings/reset/zte,zx297520v3-reset.h
+++ b/include/dt-bindings/reset/zte,zx297520v3-reset.h
@@ -39,4 +39,23 @@
#define ZX297520V3_GMAC_RESET 7
#define ZX297520V3_VOU_RESET 8
+#define ZX297520V3_TIMER_L1_RESET 0
+#define ZX297520V3_WDT_L2_RESET 1
+#define ZX297520V3_WDT_L3_RESET 2
+#define ZX297520V3_PWM_RESET 3
+#define ZX297520V3_I2S0_RESET 4
+#define ZX297520V3_I2S1_RESET 5
+#define ZX297520V3_QSPI_RESET 6
+#define ZX297520V3_UART1_RESET 7
+#define ZX297520V3_I2C1_RESET 8
+#define ZX297520V3_SPI0_RESET 9
+#define ZX297520V3_TIMER_LB_RESET 10
+#define ZX297520V3_TIMER_LC_RESET 11
+#define ZX297520V3_UART2_RESET 12
+#define ZX297520V3_WDT_LE_RESET 13
+#define ZX297520V3_TIMER_LF_RESET 14
+#define ZX297520V3_SPI1_RESET 15
+#define ZX297520V3_TIMER_L11_RESET 16
+#define ZX297520V3_TDM_RESET 17
+
#endif /* __DT_BINDINGS_RESET_ZX297520V3_H */
--
2.54.0
^ permalink raw reply related
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox