* Re: [PATCH 2/3] arm64: dts: socfpga: agilex5: Add SoCDK TSN Config2 board
From: Andrew Lunn @ 2026-07-01 12:47 UTC (permalink / raw)
To: Nazle Asmade, Muhammad Nazim Amirul
Cc: dinguyen@kernel.org, maxime.chevallier@bootlin.com,
rmk+kernel@armlinux.org.uk, krzk+dt@kernel.org,
conor+dt@kernel.org, robh@kernel.org, davem@davemloft.net,
edumazet@google.com, kuba@kernel.org, pabeni@redhat.com,
andrew+netdev@lunn.ch, devicetree@vger.kernel.org,
linux-arm-kernel@lists.infradead.org, netdev@vger.kernel.org,
linux-kernel@vger.kernel.org
In-Reply-To: <5a0c962e-1af0-4d6a-b871-d8a0b0197ff5@altera.com>
> > # There are a small number of cases where the MAC has hard coded
> > # delays which cannot be disabled. The 'phy-mode' only describes the
> > # PCB. The inability to disable the delays in the MAC does not change
> > # the meaning of 'phy-mode'. It does however mean that a 'phy-mode' of
> > # 'rgmii' is now invalid, it cannot be supported, since both the PCB
> > # and the MAC and PHY adding delays cannot result in a functional
> > # link. Thus the MAC should report a fatal error for any modes which
> > # cannot be supported. When the MAC implements the delay, it must
> > # ensure that the PHY does not also implement the same delay. So it
> > # must modify the phy-mode it passes to the PHY, removing the delay it
> > # has added. Failure to remove the delay will result in a
> > # non-functioning link.
> >
> > Andrew
> >
> > ---
> > pw-bot: cr
> Hi Andrew,
>
> The delays are provided by the FPGA GMII-to-RGMII converter soft IP,
> which is hardcoded in the FPGA bitstream and cannot be disabled or
> modified from the driver side.
>
> Using phy-mode = "rgmii" is intentional here — it prevents the PHY from
> adding its own internal delays on top, since the FPGA converter already
> provides the full required delay. This is consistent with how all other
> Agilex5 SoCDK board variants are described, as seen in commit
> c5637e5ceb4b ("arm64: dts: socfpga: agilex5: Fix phy-mode to rgmii as HW
> provides clock delay") already in Dinh Nguyen's tree, which applies the
> same rationale across all Agilex5 boards.
I've become more insistent that designs get this correct. So i don't
care too much about past systems. Many vendors are having to fix up
their drivers and DT in order to make new boards consistent.
You can look at your system as the FPGA being the MAC, and the PHY is
the PHY. The PCB is not providing the delay, the MAC is. This exactly
fits the description above.
Andrew
^ permalink raw reply
* [PATCH v7 09/11] arm64: dts: ti: k3-am62a-ti-ipc-firmware: Split r5f memory region
From: Markus Schneider-Pargmann (TI) @ 2026-07-01 12:39 UTC (permalink / raw)
To: Nishanth Menon, Vignesh Raghavendra, Tero Kristo, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Nathan Chancellor,
Nick Desaulniers, Bill Wendling, Justin Stitt, Judith Mendez,
Daniel Schultz, Andrew Davis, Siddharth Vadapalli, Paresh Bhagat,
Bryan Brattlof, Jai Luthra, Devarsh Thakkar, Beleswar Padhi,
Francesco Dolcini, Stefano Radaelli
Cc: Vishal Mahaveer, Kevin Hilman, Sebin Francis, Kendall Willis,
Akashdeep Kaur, linux-arm-kernel, devicetree, linux-kernel, llvm,
Hari Nagalla, Markus Schneider-Pargmann (TI)
In-Reply-To: <20260701-topic-am62a-ioddr-dt-v6-19-v7-0-e9db8b16821a@baylibre.com>
Split the firmware memory region in more specific parts so it is better
described where to find which information. Specifically the LPM metadata
region is important as bootloader software like U-Boot has to know where
that data is to be able to read that data.
Signed-off-by: Markus Schneider-Pargmann (TI) <msp@baylibre.com>
---
.../boot/dts/ti/k3-am62a-ti-ipc-firmware.dtsi | 38 +++++++++++++++++++---
1 file changed, 34 insertions(+), 4 deletions(-)
diff --git a/arch/arm64/boot/dts/ti/k3-am62a-ti-ipc-firmware.dtsi b/arch/arm64/boot/dts/ti/k3-am62a-ti-ipc-firmware.dtsi
index 682b1c9f3071ddf23044c1fde1e88f2b901ec64c..fe10d3e75ceee35f84d34b892f9925efceb7743a 100644
--- a/arch/arm64/boot/dts/ti/k3-am62a-ti-ipc-firmware.dtsi
+++ b/arch/arm64/boot/dts/ti/k3-am62a-ti-ipc-firmware.dtsi
@@ -36,12 +36,36 @@ wkup_r5fss0_core0_dma_memory_region: memory@9c800000 {
no-map;
};
- wkup_r5fss0_core0_memory_region: memory@9c900000 {
+ wkup_r5fss0_core0_ipc_region: memory@9c900000 {
compatible = "shared-dma-pool";
- reg = <0x00 0x9c900000 0x00 0x01d00000>;
+ reg = <0x00 0x9c900000 0x00 0x100000>;
+ no-map;
+ };
+
+ wkup_r5fss0_core0_lpm_fs_stub_region: memory@9ca00000 {
+ compatible = "shared-dma-pool";
+ reg = <0x00 0x9ca00000 0x00 0x8000>;
+ no-map;
+ };
+
+ wkup_r5fss0_core0_lpm_metadata_region: memory@9ca08000 {
+ compatible = "shared-dma-pool";
+ reg = <0x00 0x9ca08000 0x00 0x1000>;
no-map;
bootph-pre-ram;
};
+
+ wkup_r5fss0_core0_lpm_rest_region: memory@9ca09000 {
+ compatible = "shared-dma-pool";
+ reg = <0x00 0x9ca09000 0x00 0x97000>;
+ no-map;
+ };
+
+ wkup_r5fss0_core0_dm_region: memory@9caa0000 {
+ compatible = "shared-dma-pool";
+ reg = <0x00 0x9caa0000 0x00 0x1b60000>;
+ no-map;
+ };
};
&mailbox0_cluster0 {
@@ -78,8 +102,14 @@ &wkup_r5fss0 {
&wkup_r5fss0_core0 {
mboxes = <&mailbox0_cluster0>, <&mbox_r5_0>;
memory-region = <&wkup_r5fss0_core0_dma_memory_region>,
- <&wkup_r5fss0_core0_memory_region>;
- memory-region-names = "dma", "firmware";
+ <&wkup_r5fss0_core0_ipc_region>,
+ <&wkup_r5fss0_core0_lpm_fs_stub_region>,
+ <&wkup_r5fss0_core0_lpm_metadata_region>,
+ <&wkup_r5fss0_core0_lpm_rest_region>,
+ <&wkup_r5fss0_core0_dm_region>;
+ memory-region-names = "dma", "ipc", "lpm-stub",
+ "lpm-metadata", "lpm-context",
+ "dm-firmware";
bootph-pre-ram;
status = "okay";
};
--
2.53.0
^ permalink raw reply related
* [PATCH v7 10/11] arm64: dts: ti: k3-am62p-ti-ipc-firmware: Split r5f memory region
From: Markus Schneider-Pargmann (TI) @ 2026-07-01 12:39 UTC (permalink / raw)
To: Nishanth Menon, Vignesh Raghavendra, Tero Kristo, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Nathan Chancellor,
Nick Desaulniers, Bill Wendling, Justin Stitt, Judith Mendez,
Daniel Schultz, Andrew Davis, Siddharth Vadapalli, Paresh Bhagat,
Bryan Brattlof, Jai Luthra, Devarsh Thakkar, Beleswar Padhi,
Francesco Dolcini, Stefano Radaelli
Cc: Vishal Mahaveer, Kevin Hilman, Sebin Francis, Kendall Willis,
Akashdeep Kaur, linux-arm-kernel, devicetree, linux-kernel, llvm,
Hari Nagalla, Markus Schneider-Pargmann (TI)
In-Reply-To: <20260701-topic-am62a-ioddr-dt-v6-19-v7-0-e9db8b16821a@baylibre.com>
Split the firmware memory region in more specific parts so it is better
described where to find which information. Specifically the LPM metadata
region is important as bootloader software like U-Boot has to know where
that data is to be able to read that data.
Signed-off-by: Markus Schneider-Pargmann (TI) <msp@baylibre.com>
---
.../boot/dts/ti/k3-am62p-ti-ipc-firmware.dtsi | 38 +++++++++++++++++++---
1 file changed, 34 insertions(+), 4 deletions(-)
diff --git a/arch/arm64/boot/dts/ti/k3-am62p-ti-ipc-firmware.dtsi b/arch/arm64/boot/dts/ti/k3-am62p-ti-ipc-firmware.dtsi
index f77651109564224408723b72baba93e39a82be07..8f7409da83392d2d1f160a9645ef4d68f7aaa1bf 100644
--- a/arch/arm64/boot/dts/ti/k3-am62p-ti-ipc-firmware.dtsi
+++ b/arch/arm64/boot/dts/ti/k3-am62p-ti-ipc-firmware.dtsi
@@ -24,9 +24,33 @@ wkup_r5fss0_core0_dma_memory_region: memory@9c800000 {
no-map;
};
- wkup_r5fss0_core0_memory_region: memory@9c900000 {
+ wkup_r5fss0_core0_ipc_region: memory@9c900000 {
compatible = "shared-dma-pool";
- reg = <0x00 0x9c900000 0x00 0x01d08000>;
+ reg = <0x00 0x9c900000 0x00 0x100000>;
+ no-map;
+ };
+
+ wkup_r5fss0_core0_lpm_fs_stub_region: memory@9ca00000 {
+ compatible = "shared-dma-pool";
+ reg = <0x00 0x9ca00000 0x00 0x8000>;
+ no-map;
+ };
+
+ wkup_r5fss0_core0_lpm_metadata_region: memory@9ca08000 {
+ compatible = "shared-dma-pool";
+ reg = <0x00 0x9ca08000 0x00 0x1000>;
+ no-map;
+ };
+
+ wkup_r5fss0_core0_lpm_rest_region: memory@9ca09000 {
+ compatible = "shared-dma-pool";
+ reg = <0x00 0x9ca09000 0x00 0x97000>;
+ no-map;
+ };
+
+ wkup_r5fss0_core0_dm_region: memory@9caa0000 {
+ compatible = "shared-dma-pool";
+ reg = <0x00 0x9caa0000 0x00 0x1b68000>;
no-map;
};
};
@@ -56,8 +80,14 @@ &wkup_r5fss0 {
&wkup_r5fss0_core0 {
mboxes = <&mailbox0_cluster0 &mbox_r5_0>;
memory-region = <&wkup_r5fss0_core0_dma_memory_region>,
- <&wkup_r5fss0_core0_memory_region>;
- memory-region-names = "dma", "firmware";
+ <&wkup_r5fss0_core0_ipc_region>,
+ <&wkup_r5fss0_core0_lpm_fs_stub_region>,
+ <&wkup_r5fss0_core0_lpm_metadata_region>,
+ <&wkup_r5fss0_core0_lpm_rest_region>,
+ <&wkup_r5fss0_core0_dm_region>;
+ memory-region-names = "dma", "ipc", "lpm-stub",
+ "lpm-metadata", "lpm-context",
+ "dm-firmware";
status = "okay";
};
--
2.53.0
^ permalink raw reply related
* [PATCH v7 11/11] arm64: dts: ti: k3-am62p-ti-ipc-firmware: Add r5f nodes to pre-ram bootphase
From: Markus Schneider-Pargmann (TI) @ 2026-07-01 12:39 UTC (permalink / raw)
To: Nishanth Menon, Vignesh Raghavendra, Tero Kristo, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Nathan Chancellor,
Nick Desaulniers, Bill Wendling, Justin Stitt, Judith Mendez,
Daniel Schultz, Andrew Davis, Siddharth Vadapalli, Paresh Bhagat,
Bryan Brattlof, Jai Luthra, Devarsh Thakkar, Beleswar Padhi,
Francesco Dolcini, Stefano Radaelli
Cc: Vishal Mahaveer, Kevin Hilman, Sebin Francis, Kendall Willis,
Akashdeep Kaur, linux-arm-kernel, devicetree, linux-kernel, llvm,
Hari Nagalla, Markus Schneider-Pargmann (TI)
In-Reply-To: <20260701-topic-am62a-ioddr-dt-v6-19-v7-0-e9db8b16821a@baylibre.com>
For IO+DDR the wkup_r5fss0_core0 and the
wkup_r5fss0_core0_lpm_metadata_region need to be accessed before RAM
setup is done. These are used to read the lpm metadata region in which
data is stored to resume. This needs to be done before RAM is in use to
avoid overwriting data.
Signed-off-by: Markus Schneider-Pargmann (TI) <msp@baylibre.com>
---
arch/arm64/boot/dts/ti/k3-am62p-ti-ipc-firmware.dtsi | 2 ++
1 file changed, 2 insertions(+)
diff --git a/arch/arm64/boot/dts/ti/k3-am62p-ti-ipc-firmware.dtsi b/arch/arm64/boot/dts/ti/k3-am62p-ti-ipc-firmware.dtsi
index 8f7409da83392d2d1f160a9645ef4d68f7aaa1bf..04fcd5115b9d95e6e23c4e43782c06501a0fa601 100644
--- a/arch/arm64/boot/dts/ti/k3-am62p-ti-ipc-firmware.dtsi
+++ b/arch/arm64/boot/dts/ti/k3-am62p-ti-ipc-firmware.dtsi
@@ -40,6 +40,7 @@ wkup_r5fss0_core0_lpm_metadata_region: memory@9ca08000 {
compatible = "shared-dma-pool";
reg = <0x00 0x9ca08000 0x00 0x1000>;
no-map;
+ bootph-pre-ram;
};
wkup_r5fss0_core0_lpm_rest_region: memory@9ca09000 {
@@ -89,6 +90,7 @@ &wkup_r5fss0_core0 {
"lpm-metadata", "lpm-context",
"dm-firmware";
status = "okay";
+ bootph-pre-ram;
};
&mcu_r5fss0 {
--
2.53.0
^ permalink raw reply related
* [PATCH v7 06/11] arm64: dts: ti: var-som-am62p: Fix wkup R5F memory region size
From: Markus Schneider-Pargmann (TI) @ 2026-07-01 12:39 UTC (permalink / raw)
To: Nishanth Menon, Vignesh Raghavendra, Tero Kristo, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Nathan Chancellor,
Nick Desaulniers, Bill Wendling, Justin Stitt, Judith Mendez,
Daniel Schultz, Andrew Davis, Siddharth Vadapalli, Paresh Bhagat,
Bryan Brattlof, Jai Luthra, Devarsh Thakkar, Beleswar Padhi,
Francesco Dolcini, Stefano Radaelli
Cc: Vishal Mahaveer, Kevin Hilman, Sebin Francis, Kendall Willis,
Akashdeep Kaur, linux-arm-kernel, devicetree, linux-kernel, llvm,
Hari Nagalla, Markus Schneider-Pargmann (TI)
In-Reply-To: <20260701-topic-am62a-ioddr-dt-v6-19-v7-0-e9db8b16821a@baylibre.com>
The wkup_r5fss0_core0_memory_region was reserved with
0x01e00000 but the MCU SDK linker for the wkup R5F firmware on
AM62P defines the DM code/data DDR footprint differently:
/* DDR for DM R5F code/data [ size 27 MiB + 396 KB ] */
DDR : ORIGIN = 0x9CAA5000 LENGTH = 0x1B63000
which results in an end at 0x9e608000. For this memory region which
starts at 0x9c900000 this means a length of:
0x9e608000 - 0x9c900000 = 0x1d08000
Link: https://github.com/TexasInstruments/mcupsdk-core-k3/blob/k3_main/examples/drivers/ipc/ipc_rpmsg_echo_linux/am62px-sk/wkup-r5fss0-0_freertos/ti-arm-clang/linker.cmd
Fixes: 571562e76458 ("arm64: dts: ti: Add support for Variscite VAR-SOM-AM62P")
Signed-off-by: Markus Schneider-Pargmann (TI) <msp@baylibre.com>
---
arch/arm64/boot/dts/ti/k3-am62p5-var-som.dtsi | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/arch/arm64/boot/dts/ti/k3-am62p5-var-som.dtsi b/arch/arm64/boot/dts/ti/k3-am62p5-var-som.dtsi
index fc5a3942cde001ce33fa295f68a3850b622cac7d..1408c970f1942e8a720c9cf071b2f49eafa9db5e 100644
--- a/arch/arm64/boot/dts/ti/k3-am62p5-var-som.dtsi
+++ b/arch/arm64/boot/dts/ti/k3-am62p5-var-som.dtsi
@@ -71,7 +71,7 @@ wkup_r5fss0_core0_dma_memory_region: r5f-dma-memory@9c800000 {
wkup_r5fss0_core0_memory_region: r5f-memory@9c900000 {
compatible = "shared-dma-pool";
- reg = <0x00 0x9c900000 0x00 0x01e00000>;
+ reg = <0x00 0x9c900000 0x00 0x01d08000>;
no-map;
};
--
2.53.0
^ permalink raw reply related
* [PATCH v7 05/11] arm64: dts: ti: k3-am62p5-sk: Fix wkup R5F memory region size
From: Markus Schneider-Pargmann (TI) @ 2026-07-01 12:39 UTC (permalink / raw)
To: Nishanth Menon, Vignesh Raghavendra, Tero Kristo, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Nathan Chancellor,
Nick Desaulniers, Bill Wendling, Justin Stitt, Judith Mendez,
Daniel Schultz, Andrew Davis, Siddharth Vadapalli, Paresh Bhagat,
Bryan Brattlof, Jai Luthra, Devarsh Thakkar, Beleswar Padhi,
Francesco Dolcini, Stefano Radaelli
Cc: Vishal Mahaveer, Kevin Hilman, Sebin Francis, Kendall Willis,
Akashdeep Kaur, linux-arm-kernel, devicetree, linux-kernel, llvm,
Hari Nagalla, Markus Schneider-Pargmann (TI)
In-Reply-To: <20260701-topic-am62a-ioddr-dt-v6-19-v7-0-e9db8b16821a@baylibre.com>
The wkup_r5fss0_core0_memory_region was reserved with only
0x0f00000 but the MCU SDK linker for the wkup R5F firmware on
AM62P defines the DM code/data DDR footprint differently:
/* DDR for DM R5F code/data [ size 27 MiB + 396 KB ] */
DDR : ORIGIN = 0x9CAA5000 LENGTH = 0x1B63000
which results in an end at 0x9e608000. For this memory region which
starts at 0x9c900000 this means a length of:
0x9e608000 - 0x9c900000 = 0x1d08000
Link: https://github.com/TexasInstruments/mcupsdk-core-k3/blob/k3_main/examples/drivers/ipc/ipc_rpmsg_echo_linux/am62px-sk/wkup-r5fss0-0_freertos/ti-arm-clang/linker.cmd
Fixes: b05a6c145001 ("arm64: dts: ti: k3-am62p5-sk: Enable IPC with remote processors")
Signed-off-by: Markus Schneider-Pargmann (TI) <msp@baylibre.com>
---
arch/arm64/boot/dts/ti/k3-am62p5-sk.dts | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/arch/arm64/boot/dts/ti/k3-am62p5-sk.dts b/arch/arm64/boot/dts/ti/k3-am62p5-sk.dts
index b770ed82be9d8f5827c49ed871351a6423db8026..16549fd7340a556798cf5a242746c219d3168d83 100644
--- a/arch/arm64/boot/dts/ti/k3-am62p5-sk.dts
+++ b/arch/arm64/boot/dts/ti/k3-am62p5-sk.dts
@@ -57,7 +57,7 @@ wkup_r5fss0_core0_dma_memory_region: memory@9c800000 {
wkup_r5fss0_core0_memory_region: memory@9c900000 {
compatible = "shared-dma-pool";
- reg = <0x00 0x9c900000 0x00 0xf00000>;
+ reg = <0x00 0x9c900000 0x00 0x01d08000>;
no-map;
};
--
2.53.0
^ permalink raw reply related
* [PATCH v7 03/11] arm64: dts: ti: k3-am62a7-sk: Fix wkup R5F memory region size
From: Markus Schneider-Pargmann (TI) @ 2026-07-01 12:39 UTC (permalink / raw)
To: Nishanth Menon, Vignesh Raghavendra, Tero Kristo, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Nathan Chancellor,
Nick Desaulniers, Bill Wendling, Justin Stitt, Judith Mendez,
Daniel Schultz, Andrew Davis, Siddharth Vadapalli, Paresh Bhagat,
Bryan Brattlof, Jai Luthra, Devarsh Thakkar, Beleswar Padhi,
Francesco Dolcini, Stefano Radaelli
Cc: Vishal Mahaveer, Kevin Hilman, Sebin Francis, Kendall Willis,
Akashdeep Kaur, linux-arm-kernel, devicetree, linux-kernel, llvm,
Hari Nagalla, Markus Schneider-Pargmann (TI)
In-Reply-To: <20260701-topic-am62a-ioddr-dt-v6-19-v7-0-e9db8b16821a@baylibre.com>
The wkup_r5fss0_core0_memory_region was reserved with only
0x0f00000 but the MCU SDK linker for the wkup R5F firmware on
AM62A defines the DM code/data DDR footprint differently:
/* DDR for DM R5F code/data [ size 27 MiB + 364 KB ] */
DDR : ORIGIN = 0x9CAA5000 LENGTH = 0x1B5B000
which results in an end at 0x9e600000. For this memory region which
starts at 0x9c900000 this means a length of:
0x9e600000 - 0x9c900000 = 0x1d00000
Link: https://github.com/TexasInstruments/mcupsdk-core-k3/blob/k3_main/examples/drivers/ipc/ipc_rpmsg_echo_linux/am62ax-sk/r5fss0-0_freertos/ti-arm-clang/linker.cmd
Fixes: 77c29ebe76d8 ("arm64: dts: ti: k3-am62a7-sk: Enable IPC with remote processors")
Signed-off-by: Markus Schneider-Pargmann (TI) <msp@baylibre.com>
---
arch/arm64/boot/dts/ti/k3-am62a7-sk.dts | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/arch/arm64/boot/dts/ti/k3-am62a7-sk.dts b/arch/arm64/boot/dts/ti/k3-am62a7-sk.dts
index 821a9705bb7d42091d4ad0e68d8769b49c115bcd..08c73cae26c73993a613372110bfd5611c403846 100644
--- a/arch/arm64/boot/dts/ti/k3-am62a7-sk.dts
+++ b/arch/arm64/boot/dts/ti/k3-am62a7-sk.dts
@@ -61,7 +61,7 @@ wkup_r5fss0_core0_dma_memory_region: memory@9c800000 {
wkup_r5fss0_core0_memory_region: memory@9c900000 {
compatible = "shared-dma-pool";
- reg = <0x00 0x9c900000 0x00 0xf00000>;
+ reg = <0x00 0x9c900000 0x00 0x01d00000>;
no-map;
};
--
2.53.0
^ permalink raw reply related
* [PATCH v7 01/11] arm64: dts: ti: k3-am62a-phycore-som: Fix wkup R5F memory region size
From: Markus Schneider-Pargmann (TI) @ 2026-07-01 12:39 UTC (permalink / raw)
To: Nishanth Menon, Vignesh Raghavendra, Tero Kristo, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Nathan Chancellor,
Nick Desaulniers, Bill Wendling, Justin Stitt, Judith Mendez,
Daniel Schultz, Andrew Davis, Siddharth Vadapalli, Paresh Bhagat,
Bryan Brattlof, Jai Luthra, Devarsh Thakkar, Beleswar Padhi,
Francesco Dolcini, Stefano Radaelli
Cc: Vishal Mahaveer, Kevin Hilman, Sebin Francis, Kendall Willis,
Akashdeep Kaur, linux-arm-kernel, devicetree, linux-kernel, llvm,
Hari Nagalla, Markus Schneider-Pargmann (TI)
In-Reply-To: <20260701-topic-am62a-ioddr-dt-v6-19-v7-0-e9db8b16821a@baylibre.com>
The wkup_r5fss0_core0_memory_region was reserved with only
0x0f00000 but the MCU SDK linker for the wkup R5F firmware on
AM62A defines the DM code/data DDR footprint differently:
/* DDR for DM R5F code/data [ size 27 MiB + 364 KB ] */
DDR : ORIGIN = 0x9CAA5000 LENGTH = 0x1B5B000
which results in an end at 0x9e600000. For this memory region which
starts at 0x9c900000 this means a length of:
0x9e600000 - 0x9c900000 = 0x1d00000
Link: https://github.com/TexasInstruments/mcupsdk-core-k3/blob/k3_main/examples/drivers/ipc/ipc_rpmsg_echo_linux/am62ax-sk/r5fss0-0_freertos/ti-arm-clang/linker.cmd
Fixes: 8dd0ac27fcd1 ("arm64: dts: ti: k3-am62a-phycore-som: Enable Co-processors")
Signed-off-by: Markus Schneider-Pargmann (TI) <msp@baylibre.com>
---
arch/arm64/boot/dts/ti/k3-am62a-phycore-som.dtsi | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/arch/arm64/boot/dts/ti/k3-am62a-phycore-som.dtsi b/arch/arm64/boot/dts/ti/k3-am62a-phycore-som.dtsi
index de4048a3564bcac9558f88c94381f07db30d4f99..e13da7c95a30459e7649f284689039b89a95f651 100644
--- a/arch/arm64/boot/dts/ti/k3-am62a-phycore-som.dtsi
+++ b/arch/arm64/boot/dts/ti/k3-am62a-phycore-som.dtsi
@@ -67,7 +67,7 @@ wkup_r5fss0_core0_dma_memory_region: memory@9c800000 {
wkup_r5fss0_core0_memory_region: memory@9c900000 {
compatible = "shared-dma-pool";
- reg = <0x00 0x9c900000 0x00 0xf00000>;
+ reg = <0x00 0x9c900000 0x00 0x01d00000>;
no-map;
};
--
2.53.0
^ permalink raw reply related
* [PATCH 1/6] selftests/arm64: fix spelling errors in comments
From: Wang Yan @ 2026-07-01 12:35 UTC (permalink / raw)
To: Shuah Khan, Catalin Marinas, Will Deacon, linux-arm-kernel,
linux-kselftest, linux-kernel
Cc: Wang Yan
In-Reply-To: <20260701123520.271580-1-wangyan01@kylinos.cn>
Fix two spelling mistakes in arm64 selftest comments:
- "whcih" -> "which" (arm64/gcs/libc-gcs.c)
- "resutls" -> "results" (arm64/pauth/pac.c)
Signed-off-by: Wang Yan <wangyan01@kylinos.cn>
---
tools/testing/selftests/arm64/gcs/libc-gcs.c | 2 +-
tools/testing/selftests/arm64/pauth/pac.c | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/tools/testing/selftests/arm64/gcs/libc-gcs.c b/tools/testing/selftests/arm64/gcs/libc-gcs.c
index 72e82bfbecc9..ddb0b2b20155 100644
--- a/tools/testing/selftests/arm64/gcs/libc-gcs.c
+++ b/tools/testing/selftests/arm64/gcs/libc-gcs.c
@@ -130,7 +130,7 @@ TEST(gcs_find_terminator)
* We can access a GCS via ptrace
*
* This could usefully have a fixture but note that each test is
- * fork()ed into a new child whcih causes issues. Might be better to
+ * fork()ed into a new child which causes issues. Might be better to
* lift at least some of this out into a separate, non-harness, test
* program.
*/
diff --git a/tools/testing/selftests/arm64/pauth/pac.c b/tools/testing/selftests/arm64/pauth/pac.c
index 67d138057707..f4b859c75a5a 100644
--- a/tools/testing/selftests/arm64/pauth/pac.c
+++ b/tools/testing/selftests/arm64/pauth/pac.c
@@ -292,7 +292,7 @@ TEST(single_thread_different_keys)
/*
* fork() does not change keys. Only exec() does so call a worker program.
- * Its only job is to sign a value and report back the resutls
+ * Its only job is to sign a value and report back the results
*/
TEST(exec_changed_keys)
{
--
2.25.1
^ permalink raw reply related
* Re: [RFC 0/2] arm64: kprobes: Fix single-step fault and reentry handling
From: Pu Hu @ 2026-07-01 12:30 UTC (permalink / raw)
To: catalin.marinas@arm.com, will@kernel.org, naveen@kernel.org,
davem@davemloft.net, mhiramat@kernel.org,
yang@os.amperecomputing.com, Hongyan Xia, Jiazi Li,
ada.coupriediaz@arm.com, linux-arm-kernel@lists.infradead.org,
linux-kernel@vger.kernel.org, linux-trace-kernel@vger.kernel.org
In-Reply-To: <20260701121448.3926-1-hupu@transsion.com>
Dear Maintainers,
I would like to provide some additional background for this patchset.
We observed a high-probability crash on an Android device running a
6.1.145-based kernel when recording preemptirq tracepoints for a user
space process with dwarf callchains enabled.
The command used to reproduce the issue is:
simpleperf record -p <PID> -f 10000 \
-e preemptirq:preempt_disable \
-e preemptirq:preempt_enable \
--duration 9 --call-graph dwarf \
-o /data/local/tmp/perf.data
Here <PID> is the PID of a user space process, for example a foreground
application UI thread or RenderThread.
One important observation is that the crash does not reproduce if
"--call-graph dwarf" is removed.
The crash log shows a data abort on a user virtual address while the PC
is at a probed kernel instruction:
[ 297.177775] Unable to handle kernel paging request at virtual
address 0000007ff042e000
[ 297.177792] Mem abort info:
[ 297.177795] ESR = 0x0000000096000007
[ 297.177799] EC = 0x25: DABT (current EL), IL = 32 bits
[ 297.177803] SET = 0, FnV = 0
[ 297.177806] EA = 0, S1PTW = 0
[ 297.177808] FSC = 0x07: level 3 translation fault
[ 297.177811] Data abort info:
[ 297.177814] ISV = 0, ISS = 0x00000007
[ 297.177817] CM = 0, WnR = 0
[ 297.177820] user pgtable: 4k pages, 39-bit VAs, pgdp=000000098c9f2000
[ 297.177825] [0000007ff042e000] pgd=08000009aaaea003,
p4d=08000009aaaea003, pud=08000009aaaea003, pmd=08000000abca0003,
pte=0000000000000000
[ 297.177835] Internal error: Oops: 0000000096000007 [#1] PREEMPT SMP
[ 297.178070] Skip md ftrace buffer dump for: 0x2800d70
...
[ 297.178485] CPU: 6 PID: 10214 Comm: id.article.news Tainted: P S
W O 6.1.145-android14-11-maybe-dirty-qki-consolidate #1
[ 297.178489] Hardware name: Qualcomm Technologies, Inc. Volcano
QRD,x6878 (DT)
[ 297.178491] pstate: 22400005 (nzCv daif +PAN -UAO +TCO -DIT -SSBS
BTYPE=--)
[ 297.178493] pc : folio_wait_bit_common+0x0/0x408
[ 297.178499] lr : perf_output_sample+0x57c/0xacc
[ 297.178502] sp : ffffffc0366c2f90
[ 297.178503] x29: ffffffc0366c2fb0 x28: 0000000000001000 x27:
0000007ff042d5f8
[ 297.178507] x26: 00000000000035e7 x25: 0000000000000000 x24:
ffffff892cec3000
[ 297.178510] x23: 0000000000001000 x22: 0000000000009370 x21:
ffffffc0366c3140
[ 297.178512] x20: ffffff888aa1a180 x19: ffffffc0366c3020 x18:
ffffffe01103b340
[ 297.178515] x17: 00000000ad6b63b6 x16: 00000000ad6b63b6 x15:
0000007ff042d5f8
[ 297.178518] x14: 0000000000000000 x13: 003436737365636f x12:
72705f7070612f6e
[ 297.178520] x11: 69622f6d65747379 x10: 732f0030333d7972 x9 :
616d6972705f6c6f
[ 297.178523] x8 : 6f705f706173755f x7 : 54454b434f535f44 x6 :
ffffff892cec39d8
[ 297.178526] x5 : ffffff892cec4000 x4 : 0000000000000008 x3 :
6e6f6973736e6172
[ 297.178528] x2 : 00000000000005b8 x1 : 0000007ff042e000 x0 :
ffffff892cec3000
[ 297.178531] Call trace:
[ 297.178532] folio_wait_bit_common+0x0/0x408
[ 297.178535] perf_event_output_forward+0x90/0xdc
[ 297.178537] __perf_event_overflow+0x128/0x1e8
[ 297.178540] perf_swevent_event+0x94/0x1a0
[ 297.178543] perf_tp_event+0x140/0x270
[ 297.178545] perf_trace_run_bpf_submit+0x84/0xe0
[ 297.178547] perf_trace_preemptirq_template+0xe8/0x124
[ 297.178553] trace_preempt_on+0xec/0x150
[ 297.178555] preempt_count_sub+0xa8/0x12c
[ 297.178562] do_debug_exception+0xd0/0x148
[ 297.178568] el1_dbg+0x64/0x80
[ 297.178575] el1h_64_sync_handler+0x3c/0x90
[ 297.178577] el1h_64_sync+0x68/0x6c
[ 297.178579] folio_wait_bit_common+0x0/0x408
[ 297.178582] __get_node_page+0xdc/0x49c
[ 297.178587] f2fs_get_dnode_of_data+0x404/0x950
[ 297.178589] f2fs_map_blocks+0x1e0/0xdf8
[ 297.178591] f2fs_mpage_readpages+0x1f0/0x8d0
[ 297.178594] f2fs_readahead+0x84/0x10c
[ 297.178596] read_pages+0xb8/0x434
[ 297.178603] page_cache_ra_unbounded+0x9c/0x2f0
[ 297.178605] page_cache_ra_order+0x2b0/0x348
[ 297.178608] do_sync_mmap_readahead+0xd0/0x228
[ 297.178612] filemap_fault+0x158/0x46c
[ 297.178615] f2fs_filemap_fault+0x28/0x114
[ 297.178617] handle_mm_fault+0x4f8/0x1468
[ 297.178620] do_page_fault+0x208/0x4b8
[ 297.178622] do_translation_fault+0x38/0x54
[ 297.178624] do_mem_abort+0x58/0x118
[ 297.178626] el0_da+0x48/0xb8
[ 297.178629] el0t_64_sync_handler+0x98/0xb4
[ 297.178632] el0t_64_sync+0x1a4/0x1a8
[ 297.178634] Code: 94000004 a8c17bfd d50323bf d65f03c0 (d4200080)
[ 297.178639] ---[ end trace 0000000000000000 ]---
The instruction d4200080 is the kprobe BRK instruction. The stack also
shows that the fault happens while handling a kprobe debug exception,
and the perf/trace path is entered from that window.
From the fulldump analysis, the issue appears to be related to the arm64
kprobe single-step/reentry handling. While a kprobe is preparing or
executing its XOL single-step instruction, perf/trace code may run in
the same window. With dwarf callchains enabled, this path may also
access user memory and take a data abort. In addition, another kprobe
may be hit while the first kprobe is still in KPROBE_HIT_SS state.
This matches the type of issue that was fixed on x86 by the following
commits:
6381c24cd6d5 ("kprobes/x86: Fix page-fault handling logic")
6a5022a56ac3 ("kprobes/x86: Allow to handle reentered kprobe on
single-stepping")
This patchset applies the same idea to arm64:
- Patch 1 makes the arm64 kprobe fault handler handle a fault in
KPROBE_HIT_SS/KPROBE_REENTER only when the faulting PC is the current
kprobe's XOL instruction. Otherwise, the fault is left to the normal
fault handling path.
- Patch 2 allows a kprobe hit in KPROBE_HIT_SS to be handled as a
recoverable one-level reentry. The unrecoverable case remains a hit
while already in KPROBE_REENTER.
With both patches applied, we have kept the same stress test running for
three days and the crash is no longer reproduced.
I still have the full dmesg and fulldump from the crash device. Please
let me know if any additional information would be useful.
Thanks,
hupu
^ permalink raw reply
* [PATCH 12/12] phy: phy-mtk-dp: Add support for MT8196 eDP PHY
From: AngeloGioacchino Del Regno @ 2026-07-01 12:20 UTC (permalink / raw)
To: chunfeng.yun
Cc: vkoul, neil.armstrong, robh, krzk+dt, conor+dt, matthias.bgg,
angelogioacchino.delregno, chunkuang.hu, p.zabel, justin.yeh,
linux-arm-kernel, linux-mediatek, linux-phy, devicetree,
linux-kernel, dri-devel, kernel
In-Reply-To: <20260701122008.19509-1-angelogioacchino.delregno@collabora.com>
The MT8196 SoC features an updated PHY IP compared to the older
ones, and there is one that is specific to Embedded DisplayPort.
Add support for the eDP PHY found in the MediaTek MT8196 SoC and
all of its variants.
Signed-off-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
---
drivers/phy/mediatek/phy-mtk-dp.c | 66 ++++++++++++++++++++++++++++++-
1 file changed, 65 insertions(+), 1 deletion(-)
diff --git a/drivers/phy/mediatek/phy-mtk-dp.c b/drivers/phy/mediatek/phy-mtk-dp.c
index 2c402b416683..c8abc4a2af0a 100644
--- a/drivers/phy/mediatek/phy-mtk-dp.c
+++ b/drivers/phy/mediatek/phy-mtk-dp.c
@@ -5,7 +5,7 @@
* Copyright (c) 2022, BayLibre Inc.
* Copyright (c) 2022, MediaTek Inc.
*
- * Major refactoring
+ * Major refactoring and new SoCs support
* Copyright (c) 2026, Collabora Ltd.
* AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
*/
@@ -41,6 +41,7 @@
#define TPLL_SSC_EN BIT(3)
/* DP_PHYD_BIT_RATE */
+#define PHYD_DIG_RG_BIT_RATE_V2 GENMASK(3, 0)
#define PHYD_DIG_RG_BIT_RATE GENMASK(1, 0)
/* DP_PHYD_SW_RST */
@@ -57,6 +58,7 @@
/* DP_PHYD_TX_CTL_0 */
#define PHYD_TX_LN_EN GENMASK(7, 4)
+#define PHYD_TX_LN_EN_V2 GENMASK(3, 0)
/* DP_PHYD_DRIVING_FORCE */
#define PHYD_DP_TX_FORCE_VOLT_SWING_EN BIT(0)
@@ -123,6 +125,16 @@
#define MT8195_DRIVING_PARAM_7_DEFAULT BUILD_DRIVING_PARAM_12(0, 6, 12, 0)
#define MT8195_DRIVING_PARAM_8_DEFAULT BUILD_DRIVING_PARAM_23(8, 0)
+/* MT8196/MT6991: Logic State Change Point (LC TX C) */
+#define MT8196_DRIVING_PARAM_3_DEFAULT BUILD_DRIVING_PARAM_0( 10, 12, 14, 17)
+#define MT8196_DRIVING_PARAM_4_DEFAULT BUILD_DRIVING_PARAM_12(14, 17, 18, 18)
+#define MT8196_DRIVING_PARAM_5_DEFAULT BUILD_DRIVING_PARAM_23(21, 24)
+
+/* MT8196/MT6991: Positive Edge (LC TX CP) */
+#define MT8196_DRIVING_PARAM_6_DEFAULT BUILD_DRIVING_PARAM_0( 0, 2, 4, 7)
+#define MT8196_DRIVING_PARAM_7_DEFAULT BUILD_DRIVING_PARAM_12(0, 3, 6, 0)
+#define MT8196_DRIVING_PARAM_8_DEFAULT BUILD_DRIVING_PARAM_23(3, 0)
+
enum mtk_dp_phya_ana_glb_regidx {
DP_PHYA_GLB_BIAS_GEN_0,
DP_PHYA_GLB_BIAS_GEN_1,
@@ -178,6 +190,11 @@ static const u8 mt8195_phy_dig_lane_regs[DP_PHYD_LAN_MAX] = {
[DP_PHYD_LAN_DRIVING_PARAM_0] = 0x2c,
};
+static const u8 mt8196_phy_dig_lane_regs[DP_PHYD_LAN_MAX] = {
+ [DP_PHYD_LAN_DRIVING_FORCE] = 0x30,
+ [DP_PHYD_LAN_DRIVING_PARAM_0] = 0x2c,
+};
+
static const u8 mt8195_phy_dig_glb_regs[DP_PHYD_GLOBAL_MAX] = {
[DP_PHYD_PLL_CTL_0] = 0x10,
[DP_PHYD_PLL_CTL_1] = 0x14,
@@ -187,6 +204,15 @@ static const u8 mt8195_phy_dig_glb_regs[DP_PHYD_GLOBAL_MAX] = {
[DP_PHYD_TX_CTL_0] = 0x44,
};
+static const u8 mt8196_phy_dig_glb_regs[DP_PHYD_GLOBAL_MAX] = {
+ [DP_PHYD_PLL_CTL_0] = 0x10,
+ [DP_PHYD_PLL_CTL_1] = 0x14,
+ [DP_PHYD_SW_RST] = 0x38,
+ [DP_PHYD_BIT_RATE] = 0x3c,
+ [DP_PHYD_AUX_RX_CTL] = 0x40,
+ [DP_PHYD_TX_CTL_0] = 0x74,
+};
+
static const u8 mt8195_phy_dig_bitrate_val[DP_PHYD_BIT_RATE_MAX] = {
[DP_PHYD_BIT_RATE_RBR] = 0,
[DP_PHYD_BIT_RATE_HBR] = 1,
@@ -194,6 +220,13 @@ static const u8 mt8195_phy_dig_bitrate_val[DP_PHYD_BIT_RATE_MAX] = {
[DP_PHYD_BIT_RATE_HBR3] = 3
};
+static const u8 mt8196_edp_phy_dig_bitrate_val[DP_PHYD_BIT_RATE_MAX] = {
+ [DP_PHYD_BIT_RATE_RBR] = 1,
+ [DP_PHYD_BIT_RATE_HBR] = 4,
+ [DP_PHYD_BIT_RATE_HBR2] = 7,
+ [DP_PHYD_BIT_RATE_HBR3] = 9
+};
+
/**
* struct mtk_dp_phya_imp_sel - Per-Lane Impedance Selection
* @pmos: Impedance selection for P-Channel MOSFET
@@ -751,8 +784,39 @@ static const struct mtk_dp_phy_pdata mt8195_dp_phy_data = {
},
};
+static const struct mtk_dp_phy_pdata mt8196_edp_phy_data = {
+ .off_ana_glb = 0x400,
+ .off_ana_lane = (const u16[]) { 0x0, 0x100, 0x200, 0x300 },
+ .off_dig_glb = 0x1400,
+ .off_dig_lane = (const u16[]) { 0x1000, 0x1100, 0x1200, 0x1300 },
+ .regs_ana_glb = mt8195_phy_ana_glb_regs,
+ .regs_ana_lane = mt8195_phy_ana_lane_regs,
+ .regs_dig_glb = mt8196_phy_dig_glb_regs,
+ .regs_dig_lane = mt8196_phy_dig_lane_regs,
+ .mask_dig_tx_ln = PHYD_TX_LN_EN_V2,
+ .val_dig_bitrate = mt8196_edp_phy_dig_bitrate_val,
+ .ana_bias_r = 15,
+ .ana_cktx_imp = 8,
+ .ana_lanes_imp = {
+ .pmos = 8,
+ .nmos = 8,
+ },
+ .driving_params = (const u32[]) {
+ [0] = 0,
+ [1] = 0,
+ [2] = 0,
+ [3] = MT8196_DRIVING_PARAM_3_DEFAULT,
+ [4] = MT8196_DRIVING_PARAM_4_DEFAULT,
+ [5] = MT8196_DRIVING_PARAM_5_DEFAULT,
+ [6] = MT8196_DRIVING_PARAM_6_DEFAULT,
+ [7] = MT8196_DRIVING_PARAM_7_DEFAULT,
+ [8] = MT8196_DRIVING_PARAM_8_DEFAULT
+ },
+};
+
static const struct of_device_id mtk_dp_phy_of_match[] = {
{ .compatible = "mediatek,mt8195-dp-phy", .data = &mt8195_dp_phy_data },
+ { .compatible = "mediatek,mt8196-edp-phy", .data = &mt8196_edp_phy_data },
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, mtk_dp_phy_of_match);
--
2.54.0
^ permalink raw reply related
* [PATCH 11/12] phy: phy-mtk-dp: Add PHYD Lane EN register mask to SoC data
From: AngeloGioacchino Del Regno @ 2026-07-01 12:20 UTC (permalink / raw)
To: chunfeng.yun
Cc: vkoul, neil.armstrong, robh, krzk+dt, conor+dt, matthias.bgg,
angelogioacchino.delregno, chunkuang.hu, p.zabel, justin.yeh,
linux-arm-kernel, linux-mediatek, linux-phy, devicetree,
linux-kernel, dri-devel, kernel
In-Reply-To: <20260701122008.19509-1-angelogioacchino.delregno@collabora.com>
In preparation for adding support for the eDP PHY found in newer
SoCs, transfer the register mask for PHYD_TX_LN_EN to SoC specific
data.
Signed-off-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
---
drivers/phy/mediatek/phy-mtk-dp.c | 13 +++++++++----
1 file changed, 9 insertions(+), 4 deletions(-)
diff --git a/drivers/phy/mediatek/phy-mtk-dp.c b/drivers/phy/mediatek/phy-mtk-dp.c
index 73fc724e0ecc..2c402b416683 100644
--- a/drivers/phy/mediatek/phy-mtk-dp.c
+++ b/drivers/phy/mediatek/phy-mtk-dp.c
@@ -214,6 +214,7 @@ struct mtk_dp_phya_imp_sel {
* @regs_ana_lane: Register (layout) offsets for ana_lan
* @regs_dig_glb: Register (layout) offsets for dig_glb
* @regs_dig_lane: Register (layout) offsets for dig_lan
+ * @mask_dig_tx_ln: Register mask for PHYD_TX_LN_EN field
* @val_dig_bitrate:IP Version specific register values for Bit Rate setting
* @ana_bias_r: Internal resistance "R" Selection Settings (global)
* @ana_cktx_imp: TX Clock Impedance Selection Settings (global)
@@ -233,6 +234,9 @@ struct mtk_dp_phy_pdata {
const u8 *regs_dig_glb;
const u8 *regs_dig_lane;
+ /* Register masks */
+ u32 mask_dig_tx_ln;
+
/* IP-Version specific register value arrays */
const u8 *val_dig_bitrate;
@@ -370,10 +374,10 @@ static int mtk_dp_phy_configure(struct phy *phy, union phy_configure_opts *opts)
val = 0;
for (i = 0; i < opts->dp.lanes; i++)
- val |= FIELD_PREP(PHYD_TX_LN_EN, BIT(i));
+ val |= field_prep(pdata->mask_dig_tx_ln, BIT(i));
regmap_update_bits(dp_phy->regmap, pdata->off_dig_glb + reg_dig_tx_ctl,
- PHYD_TX_LN_EN, val);
+ pdata->mask_dig_tx_ln, val);
}
if (opts->dp.set_voltages) {
@@ -442,7 +446,7 @@ static int mtk_dp_phy_disable_all_lanes(struct mtk_dp_phy *dp_phy)
return ret;
/* Get mask of currently enabled lane */
- val = FIELD_GET(PHYD_TX_LN_EN, val);
+ val = field_get(pdata->mask_dig_tx_ln, val);
/* Disable all lanes (needs to be done one by one, from last to first) */
do {
@@ -451,7 +455,7 @@ static int mtk_dp_phy_disable_all_lanes(struct mtk_dp_phy *dp_phy)
ret = regmap_clear_bits(dp_phy->regmap,
pdata->off_dig_glb + regs[DP_PHYD_TX_CTL_0],
- FIELD_PREP(PHYD_TX_LN_EN, lane_num));
+ field_prep(pdata->mask_dig_tx_ln, lane_num));
if (ret)
return ret;
} while (val);
@@ -726,6 +730,7 @@ static const struct mtk_dp_phy_pdata mt8195_dp_phy_data = {
.regs_ana_lane = mt8195_phy_ana_lane_regs,
.regs_dig_glb = mt8195_phy_dig_glb_regs,
.regs_dig_lane = mt8195_phy_dig_lane_regs,
+ .mask_dig_tx_ln = PHYD_TX_LN_EN,
.val_dig_bitrate = mt8195_phy_dig_bitrate_val,
.ana_bias_r = 15,
.ana_cktx_imp = 8,
--
2.54.0
^ permalink raw reply related
* [PATCH 10/12] phy: phy-mtk-dp: Add bitrate register val definitions to SoC data
From: AngeloGioacchino Del Regno @ 2026-07-01 12:20 UTC (permalink / raw)
To: chunfeng.yun
Cc: vkoul, neil.armstrong, robh, krzk+dt, conor+dt, matthias.bgg,
angelogioacchino.delregno, chunkuang.hu, p.zabel, justin.yeh,
linux-arm-kernel, linux-mediatek, linux-phy, devicetree,
linux-kernel, dri-devel, kernel
In-Reply-To: <20260701122008.19509-1-angelogioacchino.delregno@collabora.com>
In preparation for adding support for the eDP PHY found in newer
SoCs, transfer the bitrate register value definitions to SoC
specific data.
Signed-off-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
---
drivers/phy/mediatek/phy-mtk-dp.c | 36 +++++++++++++++++++++++--------
1 file changed, 27 insertions(+), 9 deletions(-)
diff --git a/drivers/phy/mediatek/phy-mtk-dp.c b/drivers/phy/mediatek/phy-mtk-dp.c
index bda262d437ed..73fc724e0ecc 100644
--- a/drivers/phy/mediatek/phy-mtk-dp.c
+++ b/drivers/phy/mediatek/phy-mtk-dp.c
@@ -42,10 +42,6 @@
/* DP_PHYD_BIT_RATE */
#define PHYD_DIG_RG_BIT_RATE GENMASK(1, 0)
-# define BIT_RATE_RBR 0
-# define BIT_RATE_HBR 1
-# define BIT_RATE_HBR2 2
-# define BIT_RATE_HBR3 3
/* DP_PHYD_SW_RST */
#define PHYD_DIG_GLB_SW_RST_B GENMASK(7, 0)
@@ -157,6 +153,14 @@ enum mtk_dp_phyd_dig_glb_regidx {
DP_PHYD_GLOBAL_MAX
};
+enum mtk_dp_phyd_bit_rate_regval {
+ DP_PHYD_BIT_RATE_RBR,
+ DP_PHYD_BIT_RATE_HBR,
+ DP_PHYD_BIT_RATE_HBR2,
+ DP_PHYD_BIT_RATE_HBR3,
+ DP_PHYD_BIT_RATE_MAX,
+};
+
static const u8 mt8195_phy_ana_glb_regs[DP_PHYA_GLOBAL_MAX] = {
[DP_PHYA_GLB_BIAS_GEN_0] = 0x0,
[DP_PHYA_GLB_BIAS_GEN_1] = 0x4,
@@ -183,6 +187,13 @@ static const u8 mt8195_phy_dig_glb_regs[DP_PHYD_GLOBAL_MAX] = {
[DP_PHYD_TX_CTL_0] = 0x44,
};
+static const u8 mt8195_phy_dig_bitrate_val[DP_PHYD_BIT_RATE_MAX] = {
+ [DP_PHYD_BIT_RATE_RBR] = 0,
+ [DP_PHYD_BIT_RATE_HBR] = 1,
+ [DP_PHYD_BIT_RATE_HBR2] = 2,
+ [DP_PHYD_BIT_RATE_HBR3] = 3
+};
+
/**
* struct mtk_dp_phya_imp_sel - Per-Lane Impedance Selection
* @pmos: Impedance selection for P-Channel MOSFET
@@ -203,6 +214,7 @@ struct mtk_dp_phya_imp_sel {
* @regs_ana_lane: Register (layout) offsets for ana_lan
* @regs_dig_glb: Register (layout) offsets for dig_glb
* @regs_dig_lane: Register (layout) offsets for dig_lan
+ * @val_dig_bitrate:IP Version specific register values for Bit Rate setting
* @ana_bias_r: Internal resistance "R" Selection Settings (global)
* @ana_cktx_imp: TX Clock Impedance Selection Settings (global)
* @ana_lanes_imp: TX Impedance Selection Settings (for all lanes)
@@ -221,6 +233,9 @@ struct mtk_dp_phy_pdata {
const u8 *regs_dig_glb;
const u8 *regs_dig_lane;
+ /* IP-Version specific register value arrays */
+ const u8 *val_dig_bitrate;
+
/* Calibration defaults */
u8 ana_bias_r;
u8 ana_cktx_imp;
@@ -325,6 +340,7 @@ static int mtk_dp_phy_configure(struct phy *phy, union phy_configure_opts *opts)
if (opts->dp.set_rate) {
const u32 reg_bit_rate = pdata->regs_dig_glb[DP_PHYD_BIT_RATE];
+ enum mtk_dp_phyd_bit_rate_regval regval_idx;
switch (opts->dp.link_rate) {
default:
@@ -333,19 +349,20 @@ static int mtk_dp_phy_configure(struct phy *phy, union phy_configure_opts *opts)
opts->dp.link_rate);
return -EINVAL;
case 1620:
- val = BIT_RATE_RBR;
+ regval_idx = DP_PHYD_BIT_RATE_RBR;
break;
case 2700:
- val = BIT_RATE_HBR;
+ regval_idx = DP_PHYD_BIT_RATE_HBR;
break;
case 5400:
- val = BIT_RATE_HBR2;
+ regval_idx = DP_PHYD_BIT_RATE_HBR2;
break;
case 8100:
- val = BIT_RATE_HBR3;
+ regval_idx = DP_PHYD_BIT_RATE_HBR3;
break;
}
- regmap_write(dp_phy->regmap, pdata->off_dig_glb + reg_bit_rate, val);
+ regmap_write(dp_phy->regmap, pdata->off_dig_glb + reg_bit_rate,
+ pdata->val_dig_bitrate[regval_idx]);
}
if (opts->dp.set_lanes) {
@@ -709,6 +726,7 @@ static const struct mtk_dp_phy_pdata mt8195_dp_phy_data = {
.regs_ana_lane = mt8195_phy_ana_lane_regs,
.regs_dig_glb = mt8195_phy_dig_glb_regs,
.regs_dig_lane = mt8195_phy_dig_lane_regs,
+ .val_dig_bitrate = mt8195_phy_dig_bitrate_val,
.ana_bias_r = 15,
.ana_cktx_imp = 8,
.ana_lanes_imp = {
--
2.54.0
^ permalink raw reply related
* Re: [PATCH 2/3] can: rockchip: add RK3588 CAN-FD support
From: 💫.220 @ 2026-07-01 12:29 UTC (permalink / raw)
To: Marc Kleine-Budde, heiko
Cc: linux-can, mailhol, kernel, robh, krzk+dt, conor+dt, devicetree,
linux-arm-kernel, linux-rockchip, linux-kernel
In-Reply-To: <20260701-flashy-crocodile-of-flowers-a6a23e-mkl@pengutronix.de>
Hi Heiko, Marc,
thanks for the review.
> please use a real name, not an alias.
I will use my real name in future revisions.
> Funnily enough, we seem to have worked on the same topic
> at the same time :-)
>
> https://lore.kernel.org/lkml/20260630164336.3444550-1-heiko@sntech.de/
I missed Heiko's series before sending mine, sorry for the noise.
(But it really is a very interesting coincidence.)
Since the series overlap, I am happy to base further work on Heiko's
series, or to let Heiko fold the RK3588 RX_FIFO_CNT bitfield change into
his v2 if that is preferred.
> Here I could reproduce erratum 6 though:
> https://lore.kernel.org/lkml/20260630164336.3444550-4-heiko@sntech.de/
Thanks for pointing this out. My local test setup did not reproduce it,
but given Heiko's result I agree that RK3588v2 should keep the erratum 6
workaround enabled. If I respin this series, I will remove the "not
reproduced" statement and enable RKCANFD_QUIRK_RK3568_ERRATUM_6 for
RK3588v2.
> The "Rockchip RK3588 TRM V1.0-Part1-20220309.pdf" datasheet says bits
> "7:5" are RX_FIFO_FRAME_CNT, while bit "6" is marked as reserved.
For RX_FIFO_CNT, I found the bitfield difference by reading Rockchip's
vendor kernel 6.1 driver and comparing the CAN support for RK3568 and
RK3588. The vendor driver uses different RX FIFO count bitfields for the
two SoCs, and my testing on RK3588v2 also indicates that bits 7:5 are
needed. I can add a short note about this in the commit message or
code comment.
One more question about RKCANFD_QUIRK_CANFD_BROKEN: in my RK3588v2 test
setup the two known CAN-FD trigger frames did not cause an Error
Interrupt or Error-Warning. I also ran a 12 hour CAN-FD stress test with
can0/can1 directly connected, 200 MHz CAN clock, 500 kbit/s nominal
bitrate and 1 Mbit/s data bitrate. That test included periodic
transmission of the two CANFD_BROKEN frames, variable DLC CAN-FD frames,
CAN-FD+BRS+EFF load, and a canfdtest run with 19,417,129 frames without
data mismatch.
Would it make sense to leave RKCANFD_QUIRK_CANFD_BROKEN disabled for
RK3588v2, or have you seen this issue on RK3588 as well?
Thanks,
Cunhao Lu
^ permalink raw reply
* [PATCH 2/6] dt-bindings: soc: mediatek: mutex: Allow #trigger-source-cells
From: AngeloGioacchino Del Regno @ 2026-07-01 12:20 UTC (permalink / raw)
To: chunkuang.hu
Cc: p.zabel, maarten.lankhorst, mripard, tzimmermann, airlied, simona,
robh, krzk+dt, conor+dt, mcoquelin.stm32, alexandre.torgue,
matthias.bgg, angelogioacchino.delregno, andi.shyti, djakov,
broonie, jitao.shi, ck.hu, dri-devel, linux-mediatek, devicetree,
linux-kernel, linux-stm32, linux-arm-kernel, justin.yeh,
jason-jh.lin, kernel
In-Reply-To: <20260701122043.19612-1-angelogioacchino.delregno@collabora.com>
This hardware controls trigger sources, and there's even a generic
binding just for that: allow #trigger-source-cells in MuteX, so
that this is allowed to provide triggers to external HW.
Signed-off-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
---
.../devicetree/bindings/soc/mediatek/mediatek,mutex.yaml | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/Documentation/devicetree/bindings/soc/mediatek/mediatek,mutex.yaml b/Documentation/devicetree/bindings/soc/mediatek/mediatek,mutex.yaml
index 1ba086ad749d..429ea149068e 100644
--- a/Documentation/devicetree/bindings/soc/mediatek/mediatek,mutex.yaml
+++ b/Documentation/devicetree/bindings/soc/mediatek/mediatek,mutex.yaml
@@ -57,6 +57,9 @@ properties:
items:
- description: MUTEX Clock
+ '#trigger-source-cells':
+ const: 1
+
mediatek,gce-events:
description:
The event id which is mapping to the specific hardware event signal
@@ -119,6 +122,7 @@ examples:
interrupts = <GIC_SPI 169 IRQ_TYPE_LEVEL_LOW>;
power-domains = <&spm MT8173_POWER_DOMAIN_MM>;
clocks = <&mmsys CLK_MM_MUTEX_32K>;
+ #trigger-source-cells = <1>;
mediatek,gce-events = <CMDQ_EVENT_MUTEX0_STREAM_EOF>,
<CMDQ_EVENT_MUTEX1_STREAM_EOF>;
};
--
2.54.0
^ permalink raw reply related
* [PATCH 4/6] soc: mediatek: mtk-mutex: Add new functions to add/remove triggers
From: AngeloGioacchino Del Regno @ 2026-07-01 12:20 UTC (permalink / raw)
To: chunkuang.hu
Cc: p.zabel, maarten.lankhorst, mripard, tzimmermann, airlied, simona,
robh, krzk+dt, conor+dt, mcoquelin.stm32, alexandre.torgue,
matthias.bgg, angelogioacchino.delregno, andi.shyti, djakov,
broonie, jitao.shi, ck.hu, dri-devel, linux-mediatek, devicetree,
linux-kernel, linux-stm32, linux-arm-kernel, justin.yeh,
jason-jh.lin, kernel
In-Reply-To: <20260701122043.19612-1-angelogioacchino.delregno@collabora.com>
Add new mtk_mutex_add_trigger() and mtk_mutex_remove_trigger() to
replace, in the near future, their older style equivalents such as
mtk_mutex_add_comp() and mtk_mutex_remove_comp() for the Display
Controller related MuteX triggers.
The same functions will be used to also replace the Media Data
Path 3 (MDP3) specific mtk_mutex_write_mod(), unifying the MuteX
handling across all of the currently supported multimedia-related
drivers for MediaTek SoCs.
While at it, this also takes into account the upcoming refactoring
of mtk_mmsys and mediatek-drm, which are about to migrate to a new
Component "Type -> Hardware ID" mapping, by adding a new function
parameter "hw_inst_id" to support that.
Signed-off-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
---
drivers/soc/mediatek/mtk-mutex.c | 60 ++++++++++++++++++++++++++
include/linux/soc/mediatek/mtk-mutex.h | 6 +++
2 files changed, 66 insertions(+)
diff --git a/drivers/soc/mediatek/mtk-mutex.c b/drivers/soc/mediatek/mtk-mutex.c
index 6ffdcb673ae9..28715b07e668 100644
--- a/drivers/soc/mediatek/mtk-mutex.c
+++ b/drivers/soc/mediatek/mtk-mutex.c
@@ -960,6 +960,65 @@ void mtk_mutex_unprepare(struct mtk_mutex *mutex)
}
EXPORT_SYMBOL_GPL(mtk_mutex_unprepare);
+static enum mtk_mutex_sof_id mtk_mutex_get_sof_trig(enum mtk_ddp_comp_type type,
+ unsigned int hw_inst_id)
+{
+ switch (type) {
+ case MTK_DISP_DSI:
+ return MUTEX_SOF_DSI0 + hw_inst_id;
+ case MTK_DISP_DPI:
+ return MUTEX_SOF_DPI0 + hw_inst_id;
+ case MTK_DISP_DP_INTF:
+ return MUTEX_SOF_DP_INTF0 + hw_inst_id;
+ default:
+ break;
+ }
+
+ return DDP_MUTEX_SOF_MAX;
+}
+
+void mtk_mutex_add_trigger(struct mtk_mutex *mutex, enum mtk_ddp_comp_type type,
+ unsigned int hw_inst_id, unsigned int mtx_trig_id)
+{
+ struct mtk_mutex_ctx *ctx = container_of(mutex, struct mtk_mutex_ctx, mutex[mutex->id]);
+ enum mtk_mutex_sof_id sof_id = mtk_mutex_get_sof_trig(type, hw_inst_id);
+ const u32 offset = DISP_REG_MUTEX_MOD(ctx, mtx_trig_id, mutex->id);
+ u32 val;
+
+ if (sof_id < DDP_MUTEX_SOF_MAX) {
+ const u32 sof_offset = DISP_REG_MUTEX_SOF(ctx->data->mutex_sof_reg, mutex->id);
+
+ writel(ctx->data->mutex_sof[sof_id], ctx->regs + sof_offset);
+ return;
+ }
+
+ val = readl(ctx->regs + offset);
+ writel(val | BIT(mtx_trig_id % 32), ctx->regs + offset);
+}
+EXPORT_SYMBOL_NS_GPL(mtk_mutex_add_trigger, "MTK_MUTEX");
+
+void mtk_mutex_remove_trigger(struct mtk_mutex *mutex, enum mtk_ddp_comp_type type,
+ unsigned int hw_inst_id, unsigned int mtx_trig_id)
+{
+ struct mtk_mutex_ctx *ctx = container_of(mutex, struct mtk_mutex_ctx, mutex[mutex->id]);
+ enum mtk_mutex_sof_id sof_id = mtk_mutex_get_sof_trig(type, hw_inst_id);
+ const u32 offset = DISP_REG_MUTEX_MOD(ctx, mtx_trig_id, mutex->id);
+ u32 val;
+
+ if (sof_id < DDP_MUTEX_SOF_MAX) {
+ const u32 sof_offset = DISP_REG_MUTEX_SOF(ctx->data->mutex_sof_reg, mutex->id);
+
+ val = readl(ctx->regs + sof_offset);
+ writel(val & ~ctx->data->mutex_sof[sof_id], ctx->regs + sof_offset);
+ return;
+ }
+
+ val = readl(ctx->regs + offset);
+ writel(val & ~BIT(mtx_trig_id % 32), ctx->regs + offset);
+}
+EXPORT_SYMBOL_NS_GPL(mtk_mutex_remove_trigger, "MTK_MUTEX");
+
+/* TODO: Legacy - Scheduled for removal */
void mtk_mutex_add_comp(struct mtk_mutex *mutex,
enum mtk_ddp_comp_id id)
{
@@ -1011,6 +1070,7 @@ void mtk_mutex_add_comp(struct mtk_mutex *mutex,
}
EXPORT_SYMBOL_GPL(mtk_mutex_add_comp);
+/* TODO: Legacy - Scheduled for removal */
void mtk_mutex_remove_comp(struct mtk_mutex *mutex,
enum mtk_ddp_comp_id id)
{
diff --git a/include/linux/soc/mediatek/mtk-mutex.h b/include/linux/soc/mediatek/mtk-mutex.h
index 635218e3ac68..5368206dd62c 100644
--- a/include/linux/soc/mediatek/mtk-mutex.h
+++ b/include/linux/soc/mediatek/mtk-mutex.h
@@ -67,16 +67,22 @@ enum mtk_mutex_sof_index {
MUTEX_SOF_IDX_MAX /* ALWAYS keep at the end */
};
+enum mtk_ddp_comp_type;
+
struct mtk_mutex *mtk_mutex_get(struct device *dev);
int mtk_mutex_prepare(struct mtk_mutex *mutex);
void mtk_mutex_add_comp(struct mtk_mutex *mutex,
enum mtk_ddp_comp_id id);
+void mtk_mutex_add_trigger(struct mtk_mutex *mutex, enum mtk_ddp_comp_type type,
+ unsigned int hw_inst_id, unsigned int mtx_trig_id);
void mtk_mutex_enable(struct mtk_mutex *mutex);
int mtk_mutex_enable_by_cmdq(struct mtk_mutex *mutex,
void *pkt);
void mtk_mutex_disable(struct mtk_mutex *mutex);
void mtk_mutex_remove_comp(struct mtk_mutex *mutex,
enum mtk_ddp_comp_id id);
+void mtk_mutex_remove_trigger(struct mtk_mutex *mutex, enum mtk_ddp_comp_type type,
+ unsigned int hw_inst_id, unsigned int mtx_trig_id);
void mtk_mutex_unprepare(struct mtk_mutex *mutex);
void mtk_mutex_put(struct mtk_mutex *mutex);
void mtk_mutex_acquire(struct mtk_mutex *mutex);
--
2.54.0
^ permalink raw reply related
* Re: [PATCH 2/2] arm64: topology: read CPPC FFH feedback counters in one operation
From: Pengjie Zhang @ 2026-07-01 12:21 UTC (permalink / raw)
To: Beata Michalska
Cc: catalin.marinas, will, rafael, lenb, robert.moore, zhenglifeng1,
zhanjie9, sumitg, cuiyunhui, linux-arm-kernel, linux-kernel,
linux-acpi, acpica-devel, linuxarm, jonathan.cameron, prime.zeng,
wanghuiqiang, xuwei5, lihuisong, yubowen8, wangzhi12
In-Reply-To: <akNxo5HzHARnrCT1@arm.com>
On 6/30/2026 3:34 PM, Beata Michalska wrote:
> On Fri, Apr 10, 2026 at 05:41:45PM +0800, Pengjie Zhang wrote:
>> arm64 implements CPPC FFH feedback-counter reads using AMU counters.
>> Because those counters must be sampled on the target CPU, reading the
>> delivered and reference counters separately widens the observation window
>> between them.
>>
>> Implement the paired FFH feedback-counter read hook on arm64 and sample
>> both AMU counters together before decoding the requested CPC register
>> values.
>>
>> Also factor the FFH bitfield extraction logic into a helper and reuse
>> it from the existing single-counter FFH read path.
>>
>> Signed-off-by: Pengjie Zhang <zhangpengjie2@huawei.com>
>> ---
>> arch/arm64/kernel/topology.c | 75 ++++++++++++++++++++++++++++++++----
>> 1 file changed, 67 insertions(+), 8 deletions(-)
>>
>> diff --git a/arch/arm64/kernel/topology.c b/arch/arm64/kernel/topology.c
>> index b32f13358fbb..b90a767b2a1f 100644
>> --- a/arch/arm64/kernel/topology.c
>> +++ b/arch/arm64/kernel/topology.c
>> @@ -50,6 +50,16 @@ struct amu_cntr_sample {
>> unsigned long last_scale_update;
>> };
>>
>> +struct amu_ffh_ctrs {
>> + u64 corecnt;
>> + u64 constcnt;
>> +};
>> +
>> +enum cpc_ffh_ctr_id {
>> + CPC_FFH_CTR_CORE = 0x0,
>> + CPC_FFH_CTR_CONST = 0x1,
>> +};
>> +
> Those should probably go under the #ifdef CONFIG_ACPI_CPPC_LIB section.
yes
>> static DEFINE_PER_CPU_SHARED_ALIGNED(struct amu_cntr_sample, cpu_amu_samples);
>>
>> void update_freq_counters_refs(void)
>> @@ -397,7 +407,7 @@ static void cpu_read_constcnt(void *val)
>> }
>>
>> static inline
>> -int counters_read_on_cpu(int cpu, smp_call_func_t func, u64 *val)
>> +int counters_read_on_cpu(int cpu, smp_call_func_t func, void *val)
>> {
>> /*
>> * Abort call on counterless CPU.
>> @@ -447,24 +457,73 @@ bool cpc_ffh_supported(void)
>> return true;
>> }
>>
>> +static void amu_read_core_const_ctrs(void *val)
>> +{
>> + struct amu_ffh_ctrs *ctrs = val;
>> +
>> + cpu_read_constcnt(&ctrs->constcnt);
>> + cpu_read_corecnt(&ctrs->corecnt);
>> +}
>> +
>> +static u64 cpc_ffh_extract_bits(const struct cpc_reg *reg, u64 val)
>> +{
>> + val &= GENMASK_ULL(reg->bit_offset + reg->bit_width - 1,
>> + reg->bit_offset);
>> + val >>= reg->bit_offset;
>> +
>> + return val;
>> +}
>> +
>> +static bool cpc_ffh_ctr_value(const struct cpc_reg *reg,
>> + const struct amu_ffh_ctrs *ctrs, u64 *val)
>> +{
>> + switch ((u64)reg->address) {
>> + case CPC_FFH_CTR_CORE:
>> + *val = ctrs->corecnt;
>> + break;
>> + case CPC_FFH_CTR_CONST:
>> + *val = ctrs->constcnt;
>> + break;
>> + default:
>> + return false;
>> + }
>> +
>> + *val = cpc_ffh_extract_bits(reg, *val);
>> + return true;
>> +}
>> +
>> +int cpc_read_ffh_fb_ctrs(int cpu, struct cpc_reg *reg1, u64 *val1,
>> + struct cpc_reg *reg2, u64 *val2)
>> +{
>> + struct amu_ffh_ctrs ctrs;
>> + int ret;
>> +
>> + ret = counters_read_on_cpu(cpu, amu_read_core_const_ctrs, &ctrs);
>> + if (ret)
>> + return ret;
>> +
>> + if (!cpc_ffh_ctr_value(reg1, &ctrs, val1) ||
>> + !cpc_ffh_ctr_value(reg2, &ctrs, val2))
>> + return -EOPNOTSUPP;
> Right, so there might be an issues with that:
> If you return EOPNOTSUPP here, that would trigger reading the registers again,
> this time one by one. Is that intentional ?
> Also counters_read_on_cpu might also return EOPNOTSUPP, in which case trying
> again to read the counters is pointless.
>
> I'm not entirely sure I understand the condition itself though.
> This will fail if either of the requested registers in not really expected.
> And that should probably be verified upfront ?
>
>
> ---
> BR
> Beata
Right. The following code may be more appropriate.
static bool is_valid_cpc_ffh_reg(const struct cpc_reg *reg)
{
return reg->address == CPC_FFH_CTR_CORE ||
reg->address == CPC_FFH_CTR_CONST;
}
int cpc_read_ffh_fb_ctrs(int cpu, struct cpc_reg *reg1, u64 *val1,
struct cpc_reg *reg2, u64 *val2)
{
struct amu_ffh_ctrs ctrs;
int ret;
if (!is_valid_cpc_ffh_reg(reg1) || !is_valid_cpc_ffh_reg(reg2))
return -EINVAL;
ret = counters_read_on_cpu(cpu, amu_read_core_const_ctrs, &ctrs);
if (ret)
return ret == -EOPNOTSUPP ? -ENODEV : ret;
cpc_ffh_ctr_value(reg1, &ctrs, val1);
cpc_ffh_ctr_value(reg2, &ctrs, val2);
return 0;
}
thanks,
Pengjie
>> +
>> + return 0;
>> +}
>> +
>> int cpc_read_ffh(int cpu, struct cpc_reg *reg, u64 *val)
>> {
>> int ret = -EOPNOTSUPP;
>>
>> switch ((u64)reg->address) {
>> - case 0x0:
>> + case CPC_FFH_CTR_CORE:
>> ret = counters_read_on_cpu(cpu, cpu_read_corecnt, val);
>> break;
>> - case 0x1:
>> + case CPC_FFH_CTR_CONST:
>> ret = counters_read_on_cpu(cpu, cpu_read_constcnt, val);
>> break;
>> }
>>
>> - if (!ret) {
>> - *val &= GENMASK_ULL(reg->bit_offset + reg->bit_width - 1,
>> - reg->bit_offset);
>> - *val >>= reg->bit_offset;
>> - }
>> + if (!ret)
>> + *val = cpc_ffh_extract_bits(reg, *val);
>>
>> return ret;
>> }
>> --
>> 2.33.0
>>
^ permalink raw reply
* [PATCH 37/42] soc: mediatek: mtk-mmsys: Populate multimedia subsystem subdevices
From: AngeloGioacchino Del Regno @ 2026-07-01 12:20 UTC (permalink / raw)
To: chunkuang.hu
Cc: p.zabel, airlied, simona, maarten.lankhorst, mripard, tzimmermann,
robh, krzk+dt, conor+dt, matthias.bgg, angelogioacchino.delregno,
dri-devel, linux-mediatek, devicetree, linux-kernel,
linux-arm-kernel, justin.yeh, jason-jh.lin, kernel
In-Reply-To: <20260701122057.19648-1-angelogioacchino.delregno@collabora.com>
The multimedia hardware subsystem contains all of the multimedia
related sub-devices, and that really is by hardware design, not
anything software related.
In order to allow specifying a correct description of the hardware
in devicetrees, add support for probing subdevices of multimedia
controllers, specified as subnodes.
Acked-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
Signed-off-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
---
drivers/soc/mediatek/mtk-mmsys.c | 12 ++++++++++++
1 file changed, 12 insertions(+)
diff --git a/drivers/soc/mediatek/mtk-mmsys.c b/drivers/soc/mediatek/mtk-mmsys.c
index 24296ebcbae3..37f7c888e7e2 100644
--- a/drivers/soc/mediatek/mtk-mmsys.c
+++ b/drivers/soc/mediatek/mtk-mmsys.c
@@ -498,6 +498,13 @@ static int mtk_mmsys_probe(struct platform_device *pdev)
return PTR_ERR(clks);
mmsys->clks_pdev = clks;
+ ret = devm_of_platform_populate(dev);
+ if (ret) {
+ dev_err(dev, "Failed to populate child devices: %d\n", ret);
+ platform_device_unregister(clks);
+ return ret;
+ }
+
if (mmsys->data->is_vppsys)
goto out_probe_done;
@@ -543,6 +550,11 @@ static const struct of_device_id of_match_mtk_mmsys[] = {
{ .compatible = "mediatek,mt8195-vdosys1", .data = &mt8195_vdosys1_driver_data },
{ .compatible = "mediatek,mt8195-vppsys0", .data = &mt8195_vppsys0_driver_data },
{ .compatible = "mediatek,mt8195-vppsys1", .data = &mt8195_vppsys1_driver_data },
+ { .compatible = "mediatek,mt8196-dispsys0", .data = &mt8196_dispsys0_driver_data },
+ { .compatible = "mediatek,mt8196-dispsys1", .data = &mt8196_dispsys1_driver_data },
+ { .compatible = "mediatek,mt8196-ovlsys0", .data = &mt8196_ovlsys0_driver_data },
+ { .compatible = "mediatek,mt8196-ovlsys1", .data = &mt8196_ovlsys1_driver_data },
+ { .compatible = "mediatek,mt8196-vdisp-ao", .data = &mt8196_vdisp_ao_driver_data },
{ .compatible = "mediatek,mt8365-mmsys", .data = &mt8365_mmsys_driver_data },
{ /* sentinel */ }
};
--
2.54.0
^ permalink raw reply related
* [PATCH 35/42] drm/mediatek: Introduce MediaTek Asynchronous DirectLink Controller
From: AngeloGioacchino Del Regno @ 2026-07-01 12:20 UTC (permalink / raw)
To: chunkuang.hu
Cc: p.zabel, airlied, simona, maarten.lankhorst, mripard, tzimmermann,
robh, krzk+dt, conor+dt, matthias.bgg, angelogioacchino.delregno,
dri-devel, linux-mediatek, devicetree, linux-kernel,
linux-arm-kernel, justin.yeh, jason-jh.lin, kernel
In-Reply-To: <20260701122057.19648-1-angelogioacchino.delregno@collabora.com>
Add support for the MediaTek Display Controller's Asynchronous
Direct Link Controller.
This is responsible for managing internal I/O connections between
multiple display controllers in a leader to follower(s) topology,
adding the ability to enable data exchange between multimedia
related controllers and the display controller(s), and between
multiple display controllers, effectively changing the hardware
capabilities of multiple display output paths.
For example, this could be used to support multiple outputs with
lower resolution and/or color depth, or to support less outputs
but with high resolution and/or color depth, up to 8k60 in some
MediaTek SoCs like MT8196.
Moreover please note that, on new generation SoCs, (MT8196, MT8894,
MT6991, MT6993, etc), the Asynchronous DirectLink (DL_ASYNC) sub
component is required to be set up in order to achieve any display
output at all as, differently from slightly older ones (MT8195)
where a display controller reset resulted in default valid outputs
being set, the new ones have a "muted" configuration by default.
Signed-off-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
---
drivers/gpu/drm/mediatek/Makefile | 1 +
drivers/gpu/drm/mediatek/mtk_ddp_comp.c | 42 +-
drivers/gpu/drm/mediatek/mtk_ddp_comp.h | 33 +-
.../gpu/drm/mediatek/mtk_disp_directlink.c | 434 ++++++++++++++++++
drivers/gpu/drm/mediatek/mtk_disp_drv.h | 12 +
drivers/gpu/drm/mediatek/mtk_drm_drv.c | 160 ++++++-
drivers/gpu/drm/mediatek/mtk_drm_drv.h | 1 +
include/linux/soc/mediatek/mtk-mmsys.h | 4 +
8 files changed, 661 insertions(+), 26 deletions(-)
create mode 100644 drivers/gpu/drm/mediatek/mtk_disp_directlink.c
diff --git a/drivers/gpu/drm/mediatek/Makefile b/drivers/gpu/drm/mediatek/Makefile
index bec46e981ae1..e9478fa1a2ba 100644
--- a/drivers/gpu/drm/mediatek/Makefile
+++ b/drivers/gpu/drm/mediatek/Makefile
@@ -7,6 +7,7 @@ mediatek-drm-y := mtk_crtc.o \
mtk_disp_ccorr.o \
mtk_disp_color.o \
mtk_disp_dsc.o \
+ mtk_disp_directlink.o \
mtk_disp_exdma.o \
mtk_disp_gamma.o \
mtk_disp_merge.o \
diff --git a/drivers/gpu/drm/mediatek/mtk_ddp_comp.c b/drivers/gpu/drm/mediatek/mtk_ddp_comp.c
index a305b5f6a42d..7e12ddffbe77 100644
--- a/drivers/gpu/drm/mediatek/mtk_ddp_comp.c
+++ b/drivers/gpu/drm/mediatek/mtk_ddp_comp.c
@@ -13,6 +13,7 @@
#include <linux/clk.h>
#include <linux/of.h>
#include <linux/of_address.h>
+#include <linux/of_graph.h>
#include <linux/of_platform.h>
#include <linux/platform_device.h>
#include <linux/soc/mediatek/mtk-cmdq.h>
@@ -274,6 +275,16 @@ static const struct mtk_ddp_comp_funcs ddp_color = {
.start = mtk_color_start,
};
+static const struct mtk_ddp_comp_funcs ddp_direct_link = {
+ .add = mtk_direct_link_add,
+ .remove = mtk_direct_link_mtx_remove,
+ .connect = mtk_direct_link_connect,
+ .disconnect = mtk_direct_link_disconnect,
+ .clk_enable = mtk_direct_link_clk_enable,
+ .clk_disable = mtk_direct_link_clk_disable,
+ .config = mtk_direct_link_config,
+};
+
static const struct mtk_ddp_comp_funcs ddp_dither = {
.clk_enable = mtk_ddp_clk_enable,
.clk_disable = mtk_ddp_clk_disable,
@@ -503,6 +514,8 @@ static const struct mtk_ddp_comp_funcs *mtk_ddp_funcs[MTK_DDP_COMP_TYPE_MAX] = {
[MTK_DISP_DP_INTF] = &ddp_dpi,
[MTK_DISP_DSI] = &ddp_dsi,
[MTK_DISP_DVO] = &ddp_dvo,
+ [MTK_DISP_DIRECT_LINK_OUT] = &ddp_direct_link,
+ [MTK_DISP_DIRECT_LINK_IN] = &ddp_direct_link,
};
bool mtk_ddp_find_comp_dev_in_table(const struct mtk_drm_comp_list *hlist,
@@ -549,7 +562,7 @@ static int mtk_ddp_comp_find_in_route(struct device *dev,
return -ENODEV;
}
-int mtk_ddp_comp_get_id(struct device_node *node,
+int mtk_ddp_comp_get_id(struct device_node *node, struct device_node *ep_node,
enum mtk_ddp_comp_type comp_type)
{
/* If there's an alias, return the ID from that */
@@ -559,6 +572,24 @@ int mtk_ddp_comp_get_id(struct device_node *node,
return alias_id;
}
+ /*
+ * Alias ID -1 means that hardcoded IDs are not supported and
+ * must be taken from the endpoint.
+ */
+ if ((comp_type == MTK_DISP_DIRECT_LINK_IN ||
+ comp_type == MTK_DISP_DIRECT_LINK_OUT) && ep_node) {
+ struct of_endpoint endpoint;
+ int ret;
+
+ ret = of_graph_parse_endpoint(ep_node, &endpoint);
+ if (ret) {
+ pr_err("Cannot parse endpoint for node %pOF\n", ep_node);
+ return ret;
+ }
+
+ return endpoint.id;
+ }
+
return 0;
}
@@ -698,6 +729,15 @@ int mtk_ddp_comp_init(struct device *dev, struct device_node *node,
comp->inst_id = comp_inst_id;
comp->controller_id = comp_controller_id;
comp->funcs = mtk_ddp_funcs[comp_type];
+
+ /*
+ * For DirectLink components, call the DirectLink-specific connection
+ * and disconnection callbacks regardless of whether it is a source or
+ * a destination component during the pipeline setup.
+ */
+ if (comp->type == MTK_DISP_DIRECT_LINK_OUT || comp->type == MTK_DISP_DIRECT_LINK_IN)
+ comp->special_connect = true;
+
/* Not all drm components have a DTS device node, such as ovl_adaptor,
* which is the drm bring up sub driver
*/
diff --git a/drivers/gpu/drm/mediatek/mtk_ddp_comp.h b/drivers/gpu/drm/mediatek/mtk_ddp_comp.h
index 165bf83ccd10..9f483d9cb873 100644
--- a/drivers/gpu/drm/mediatek/mtk_ddp_comp.h
+++ b/drivers/gpu/drm/mediatek/mtk_ddp_comp.h
@@ -91,6 +91,7 @@ struct mtk_ddp_comp {
u8 controller_id;
int encoder_index;
const struct mtk_ddp_comp_funcs *funcs;
+ bool special_connect;
struct hlist_node lnode;
};
@@ -334,9 +335,18 @@ static inline bool mtk_ddp_comp_remove(struct mtk_ddp_comp *comp, struct mtk_mut
static inline bool mtk_ddp_comp_connect(struct mtk_ddp_comp *comp, struct device *mmsys_dev,
struct mtk_ddp_comp *next)
{
- if (comp->funcs && comp->funcs->connect) {
- comp->funcs->connect(comp, mmsys_dev, next);
- return true;
+ if (comp->funcs) {
+ const struct mtk_ddp_comp_funcs *funcs;
+
+ if (next->special_connect)
+ funcs = next->funcs;
+ else
+ funcs = comp->funcs;
+
+ if (funcs->connect) {
+ funcs->connect(comp, mmsys_dev, next);
+ return true;
+ }
}
return false;
}
@@ -344,9 +354,18 @@ static inline bool mtk_ddp_comp_connect(struct mtk_ddp_comp *comp, struct device
static inline bool mtk_ddp_comp_disconnect(struct mtk_ddp_comp *comp, struct device *mmsys_dev,
struct mtk_ddp_comp *next)
{
- if (comp->funcs && comp->funcs->disconnect) {
- comp->funcs->disconnect(comp, mmsys_dev, next);
- return true;
+ if (comp->funcs) {
+ const struct mtk_ddp_comp_funcs *funcs;
+
+ if (next->special_connect)
+ funcs = next->funcs;
+ else
+ funcs = comp->funcs;
+
+ if (funcs->disconnect) {
+ funcs->disconnect(comp, mmsys_dev, next);
+ return true;
+ }
}
return false;
}
@@ -375,7 +394,7 @@ bool mtk_ddp_find_comp_dev_in_table(const struct mtk_drm_comp_list *hlist,
const unsigned int comp_type,
struct device *dev);
bool mtk_ddp_comp_is_internal_comp(enum mtk_ddp_comp_type type);
-int mtk_ddp_comp_get_id(struct device_node *node,
+int mtk_ddp_comp_get_id(struct device_node *node, struct device_node *ep_node,
enum mtk_ddp_comp_type comp_type);
int mtk_find_possible_crtcs(struct drm_device *drm, struct device *dev);
int mtk_ddp_comp_init(struct device *dev, struct device_node *node,
diff --git a/drivers/gpu/drm/mediatek/mtk_disp_directlink.c b/drivers/gpu/drm/mediatek/mtk_disp_directlink.c
new file mode 100644
index 000000000000..a473939dab5c
--- /dev/null
+++ b/drivers/gpu/drm/mediatek/mtk_disp_directlink.c
@@ -0,0 +1,434 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * MediaTek Asynchronous Direct Link (DL_ASYNC) driver
+ *
+ * Copyright (c) 2026 Collabora Ltd.
+ * AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
+ */
+
+#include <linux/bitfield.h>
+#include <linux/clk.h>
+#include <linux/component.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_graph.h>
+#include <linux/platform_device.h>
+#include <linux/soc/mediatek/mtk-cmdq.h>
+#include <linux/soc/mediatek/mtk-mmsys.h>
+
+#include "mtk_crtc.h"
+#include "mtk_ddp_comp.h"
+#include "mtk_disp_drv.h"
+#include "mtk_drm_drv.h"
+
+#define MTK_DISP_REG_DL_IN_ASYNC0_SIZE_MT8196 0
+#define MTK_DISP_REG_DL_OUT_ASYNC0_SIZE_MT8196 0x64
+#define MTK_OVL_REG_DL_IN_RELAY0_SIZE_MT8196 0
+#define MTK_OVL_REG_DL_OUT_RELAY0_SIZE_MT8196 0x28
+
+#define MTK_DL_INOUT_REG_WIDTH 0x4
+
+#define MTK_DISP_DL_RELAY_WIDTH GENMASK(15, 0)
+#define MTK_DISP_DL_RELAY_HEIGHT GENMASK(29, 16)
+#define MTK_DISP_DL_IN_RELAY_PIXITER GENMASK(31, 30)
+# define MTK_DISP_DL_IN_RELAY_1T1P 0
+# define MTK_DISP_DL_IN_RELAY_1T2P 1
+# define MTK_DISP_DL_IN_RELAY_1T4P 2
+
+/**
+ * struct mtk_direct_link_data - SoC-specific data for DL_ASYNC
+ * @dli0_size_reg: Register offset of DL_IN_ASYNC0_SIZE
+ * @dlo0_size_reg: Register offset of DL_OUT_ASYNC0_SIZE
+ * @pixels_per_iter: Number of pixels per iteration
+ */
+struct mtk_direct_link_data {
+ u16 dli0_size_reg;
+ u16 dlo0_size_reg;
+ u8 pixels_per_iter;
+};
+
+/**
+ * struct mtk_disp_dl_port - DirectLink Input/Output/Relay Port structure
+ * @clks: Clocks for all of the DirectLink endpoints in port
+ * @link_ids: Active DirectLink hardware endpoint identifier
+ * @num_links: Number of active DirectLink hardware endpoints
+ * @p0_mtx_trig_id: Mute-X trigger idenrifier for first DirectLink HW Endpoint
+ */
+struct mtk_disp_dl_port {
+ struct clk **clks;
+ u8 *link_ids;
+ u8 num_links;
+ u8 p0_mtx_trig_id;
+};
+
+/**
+ * enum mtk_direct_link_port_type - DirectLink Hardware Port Type
+ * @MTK_DISP_DL_IN: DirectLink input port
+ * @MTK_DISP_DL_OUT: DirectLink output port
+ * @MTK_DISP_DL_PORT_MAX: Number of supported DirectLink port types
+ */
+enum mtk_direct_link_port_type {
+ MTK_DISP_DL_IN,
+ MTK_DISP_DL_OUT,
+ MTK_DISP_DL_PORT_MAX
+};
+
+/**
+ * struct mtk_direct_link - Main Asynchronous DirectLink driver structure
+ * @data: SoC-specific data for DirectLink
+ * @regs: DirectLink registers handle
+ * @clk: Main configuration clock for DirectLink HW
+ * @cmdq_reg: CMDQ Client register
+ * @dl_port: Array of DirectLink Port structure
+ */
+struct mtk_direct_link {
+ const struct mtk_direct_link_data *data;
+ void __iomem *regs;
+ struct clk *clk;
+ struct cmdq_client_reg cmdq_reg;
+ struct mtk_disp_dl_port dl_port[MTK_DISP_DL_PORT_MAX];
+};
+
+static struct mtk_disp_dl_port *mtk_direct_link_get_port(struct mtk_ddp_comp *comp)
+{
+ struct mtk_direct_link *dl_async;
+
+ if (comp->type != MTK_DISP_DIRECT_LINK_IN && comp->type != MTK_DISP_DIRECT_LINK_OUT)
+ return NULL;
+
+ dl_async = dev_get_drvdata(comp->dev);
+
+ if (comp->type == MTK_DISP_DIRECT_LINK_OUT)
+ return &dl_async->dl_port[MTK_DISP_DL_OUT];
+
+ return &dl_async->dl_port[MTK_DISP_DL_IN];
+}
+
+void mtk_direct_link_add(struct mtk_ddp_comp *comp, struct mtk_mutex *mutex)
+{
+ struct mtk_disp_dl_port *dl_port = mtk_direct_link_get_port(comp);
+ u8 port_id = dl_port->link_ids[comp->inst_id];
+
+ mtk_mutex_add_trigger(mutex, comp->type, comp->inst_id,
+ dl_port->p0_mtx_trig_id + port_id);
+
+ return;
+}
+
+void mtk_direct_link_mtx_remove(struct mtk_ddp_comp *comp, struct mtk_mutex *mutex)
+{
+ struct mtk_disp_dl_port *dl_port = mtk_direct_link_get_port(comp);
+ u8 port_id = dl_port->link_ids[comp->inst_id];
+
+ mtk_mutex_remove_trigger(mutex, comp->type, comp->inst_id,
+ dl_port->p0_mtx_trig_id + port_id);
+
+ return;
+}
+
+void mtk_direct_link_connect(struct mtk_ddp_comp *comp, struct device *mmsys_dev,
+ struct mtk_ddp_comp *next)
+{
+ struct mtk_disp_dl_port *dl_comp_port = mtk_direct_link_get_port(comp);
+ struct mtk_disp_dl_port *dl_next_port = mtk_direct_link_get_port(next);
+ u8 comp_inst_id, next_inst_id;
+
+ comp_inst_id = dl_comp_port ? dl_comp_port->link_ids[comp->inst_id] : comp->inst_id;
+ next_inst_id = dl_next_port ? dl_next_port->link_ids[next->inst_id] : next->inst_id;
+
+ mtk_mmsys_hw_connect(mmsys_dev, comp->type, comp_inst_id, next->type, next_inst_id);
+}
+
+void mtk_direct_link_disconnect(struct mtk_ddp_comp *comp, struct device *mmsys_dev,
+ struct mtk_ddp_comp *next)
+{
+ struct mtk_disp_dl_port *dl_comp_port = mtk_direct_link_get_port(comp);
+ struct mtk_disp_dl_port *dl_next_port = mtk_direct_link_get_port(next);
+ u8 comp_inst_id, next_inst_id;
+
+ comp_inst_id = dl_comp_port ? dl_comp_port->link_ids[comp->inst_id] : comp->inst_id;
+ next_inst_id = dl_next_port ? dl_next_port->link_ids[next->inst_id] : next->inst_id;
+
+ mtk_mmsys_hw_disconnect(mmsys_dev, comp->type, comp_inst_id, next->type, next_inst_id);
+}
+
+int mtk_direct_link_clk_enable(struct mtk_ddp_comp *comp)
+{
+ struct mtk_disp_dl_port *dl_port = mtk_direct_link_get_port(comp);
+
+ return clk_prepare_enable(dl_port->clks[comp->inst_id]);
+}
+
+void mtk_direct_link_clk_disable(struct mtk_ddp_comp *comp)
+{
+ struct mtk_disp_dl_port *dl_port = mtk_direct_link_get_port(comp);
+
+ clk_disable_unprepare(dl_port->clks[comp->inst_id]);
+}
+
+void mtk_direct_link_config(struct mtk_ddp_comp *comp,
+ unsigned int w, unsigned int h, unsigned int vrefresh,
+ unsigned int bpc, struct cmdq_pkt *cmdq_pkt)
+{
+ struct mtk_direct_link *dl_async = dev_get_drvdata(comp->dev);
+ struct mtk_disp_dl_port *dl_port;
+ u32 reg_offset;
+ u8 port_id;
+ u32 mask;
+ u32 val;
+
+ dl_port = mtk_direct_link_get_port(comp);
+ if (!dl_port) {
+ dev_err(comp->dev, "Could not get DirectLink port.\n");
+ return;
+ }
+
+ /* DL_IN or DL_OUT */
+ if (comp->type == MTK_DISP_DIRECT_LINK_OUT)
+ reg_offset = dl_async->data->dlo0_size_reg;
+ else
+ reg_offset = dl_async->data->dli0_size_reg;
+
+ port_id = dl_port->link_ids[comp->inst_id];
+ reg_offset += port_id * MTK_DL_INOUT_REG_WIDTH;
+
+ mask = MTK_DISP_DL_RELAY_WIDTH | MTK_DISP_DL_RELAY_HEIGHT;
+ val = FIELD_PREP(MTK_DISP_DL_RELAY_WIDTH, w);
+ val |= FIELD_PREP(MTK_DISP_DL_RELAY_HEIGHT, h);
+
+ if (dl_async->data->pixels_per_iter) {
+ val |= FIELD_PREP(MTK_DISP_DL_IN_RELAY_PIXITER, dl_async->data->pixels_per_iter);
+ mask |= MTK_DISP_DL_IN_RELAY_PIXITER;
+ }
+
+ mtk_ddp_write_mask(NULL, val, &dl_async->cmdq_reg, dl_async->regs,
+ reg_offset, mask);
+
+ return;
+}
+
+static int mtk_direct_link_bind(struct device *dev, struct device *master, void *data)
+{
+ struct mtk_direct_link *dl_async = dev_get_drvdata(dev);
+
+ return clk_prepare_enable(dl_async->clk);
+}
+
+static void mtk_direct_link_unbind(struct device *dev, struct device *master, void *data)
+{
+ struct mtk_direct_link *dl_async = dev_get_drvdata(dev);
+
+ clk_disable_unprepare(dl_async->clk);
+}
+
+static const struct component_ops mtk_direct_link_component_ops = {
+ .bind = mtk_direct_link_bind,
+ .unbind = mtk_direct_link_unbind,
+};
+
+static int mtk_direct_link_port_probe(struct device *dev, struct mtk_disp_dl_port *dl_port, u32 of_port_id)
+{
+ struct device_node *node = dev->of_node;
+ struct device_node *of_port;
+ struct clk **clks;
+ u8 *link_ids;
+ u8 num_links = 0;
+ u8 i;
+
+ /*
+ * HW Port IDs: 0=DL_IN, 1=DL_OUT, 2=DL_IN_RELAY, 3=DL_OUT_RELAY
+ *
+ * Relay ports are currently not handled here because at the time of
+ * writing those share configurations with the DL_IN/DL_OUT ports and
+ * they don't need any special and/or extra configuration.
+ *
+ * Since port 2/3 do actually exist, those are handled gracefully, but
+ * anything greater doesn't exist, so has to return an error.
+ */
+ if (of_port_id > 3)
+ return dev_err_probe(dev, -EINVAL, "Port %d out of range", of_port_id);
+ else if (of_port_id > 1)
+ return 0;
+
+ of_port = of_graph_get_port_by_id(node, of_port_id);
+ if (!of_port)
+ return -ENOENT;
+
+ for_each_of_graph_port_endpoint(of_port, ep)
+ num_links++;
+
+ clks = devm_kcalloc(dev, num_links, sizeof(*clks), GFP_KERNEL);
+ if (!clks)
+ return -ENOMEM;
+
+ link_ids = devm_kcalloc(dev, num_links, sizeof(*link_ids), GFP_KERNEL);
+ if (!link_ids)
+ return -ENOMEM;
+
+ i = 0;
+ for_each_of_graph_port_endpoint(of_port, ep) {
+ struct of_endpoint endpoint;
+ u32 hw_port_id;
+ int ret;
+
+ ret = of_graph_parse_endpoint(ep, &endpoint);
+ if (ret)
+ continue;
+
+ ret = of_property_read_u32(ep, "mediatek,port-id", &hw_port_id);
+ link_ids[i] = ret ? endpoint.id : hw_port_id;
+ clks[i] = devm_get_clk_from_child(dev, ep, NULL);
+ if (IS_ERR(clks[i])) {
+ return dev_err_probe(dev, PTR_ERR(clks[i]),
+ "Could not get clock\n");
+ }
+ i++;
+ }
+ dl_port->clks = clks;
+ dl_port->link_ids = link_ids;
+ dl_port->num_links = num_links;
+
+ return 0;
+}
+
+static int mtk_direct_link_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct device_node *main_node = dev->of_node;
+ struct mtk_direct_link *dl_async;
+ int in_mtx_id, out_mtx_id;
+ unsigned int num_ports;
+ int i, ret;
+
+ dl_async = devm_kzalloc(dev, sizeof(*dl_async), GFP_KERNEL);
+ if (!dl_async)
+ return -ENOMEM;
+
+ dl_async->data = device_get_match_data(dev);
+
+ dl_async->regs = of_iomap(dev->of_node, 0);
+ if (IS_ERR(dl_async->regs))
+ return dev_err_probe(&pdev->dev, PTR_ERR(dl_async->regs),
+ "Could not get regs\n");
+
+ num_ports = of_graph_get_port_count(main_node);
+ if (num_ports == 0)
+ return dev_err_probe(dev, -ENOENT, "No Input/Output ports found.\n");
+
+ /*
+ * Get the Trigger ID for DL_IN_0 and for DL_OUT_0, as all of the other
+ * HW ports have linearly increasing IDs.
+ */
+ in_mtx_id = mtk_ddp_comp_get_mutex_trigger(main_node, MTK_DISP_DL_IN);
+ out_mtx_id = mtk_ddp_comp_get_mutex_trigger(main_node, MTK_DISP_DL_OUT);
+ switch (num_ports) {
+ default:
+ /* fallthrough */
+ case 2:
+ if (in_mtx_id && out_mtx_id) {
+ ret = 0;
+ break;
+ }
+
+ ret = in_mtx_id < 0 ? in_mtx_id : out_mtx_id;
+ break;
+ case 1:
+ if (in_mtx_id || out_mtx_id) {
+ if (in_mtx_id < 0)
+ in_mtx_id = 0;
+ if (out_mtx_id < 0)
+ out_mtx_id = 0;
+
+ ret = 0;
+ break;
+ }
+
+ ret = in_mtx_id < 0 ? in_mtx_id : out_mtx_id;
+ break;
+ }
+
+ if (ret)
+ return dev_err_probe(dev, ret, "Could not get %s port 0 trigger ID\n",
+ in_mtx_id < 0 ? "input" : "output");
+
+ if (in_mtx_id > U8_MAX || out_mtx_id > U8_MAX)
+ return dev_err_probe(dev, -EINVAL, "Implausible trigger ID found\n");
+
+ /* IDs are now validated and safe to assign */
+ dl_async->dl_port[MTK_DISP_DL_IN].p0_mtx_trig_id = in_mtx_id;
+ dl_async->dl_port[MTK_DISP_DL_OUT].p0_mtx_trig_id = out_mtx_id;
+
+ i = 0;
+ for_each_of_graph_port(main_node, port_node) {
+ u32 port_id;
+
+ of_property_read_u32(port_node, "reg", &port_id);
+ if (port_id > 1)
+ continue;
+
+ ret = mtk_direct_link_port_probe(dev, &dl_async->dl_port[i], port_id);
+ if (ret)
+ return ret;
+
+ i++;
+ }
+
+ dl_async->clk = devm_clk_get(dev, 0);
+ if (IS_ERR(dl_async->clk))
+ return dev_err_probe(dev, PTR_ERR(dl_async->clk),
+ "Could not get config clock\n");
+
+#if IS_REACHABLE(CONFIG_MTK_CMDQ)
+ ret = cmdq_dev_get_client_reg(dev, &dl_async->cmdq_reg, 0);
+ if (ret)
+ dev_dbg(dev, "get mediatek,gce-client-reg fail!\n");
+#endif
+
+ platform_set_drvdata(pdev, dl_async);
+
+ ret = component_add(dev, &mtk_direct_link_component_ops);
+ if (ret)
+ return dev_err_probe(dev, ret, "Failed to add component\n");
+
+ dev_info(&pdev->dev, "Found %u HW Inputs and %u HW Outputs\n",
+ dl_async->dl_port[0].num_links, dl_async->dl_port[1].num_links);
+
+ return 0;
+}
+
+static void mtk_direct_link_remove(struct platform_device *pdev)
+{
+ component_del(&pdev->dev, &mtk_direct_link_component_ops);
+}
+
+static const struct mtk_direct_link_data mt8196_disp_dl_async_data = {
+ .dli0_size_reg = MTK_DISP_REG_DL_IN_ASYNC0_SIZE_MT8196,
+ .dlo0_size_reg = MTK_DISP_REG_DL_OUT_ASYNC0_SIZE_MT8196,
+ .pixels_per_iter = MTK_DISP_DL_IN_RELAY_1T2P,
+};
+
+static const struct mtk_direct_link_data mt8196_ovl_dl_async_data = {
+ .dli0_size_reg = MTK_OVL_REG_DL_IN_RELAY0_SIZE_MT8196,
+ .dlo0_size_reg = MTK_OVL_REG_DL_OUT_RELAY0_SIZE_MT8196,
+};
+
+static const struct of_device_id mtk_direct_link_driver_dt_match[] = {
+ { .compatible = "mediatek,mt8196-disp-direct-link", .data = &mt8196_disp_dl_async_data },
+ { .compatible = "mediatek,mt8196-ovl-direct-link", .data = &mt8196_ovl_dl_async_data },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, mtk_direct_link_driver_dt_match);
+
+struct platform_driver mtk_direct_link_driver = {
+ .probe = mtk_direct_link_probe,
+ .remove = mtk_direct_link_remove,
+ .driver = {
+ .name = "mediatek-disp-direct-link",
+ .of_match_table = mtk_direct_link_driver_dt_match,
+ },
+};
+
+MODULE_AUTHOR("AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>");
+MODULE_DESCRIPTION("MediaTek Display Controller Direct Link Driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/gpu/drm/mediatek/mtk_disp_drv.h b/drivers/gpu/drm/mediatek/mtk_disp_drv.h
index 7b16f46ce9e2..f78f12da08a8 100644
--- a/drivers/gpu/drm/mediatek/mtk_disp_drv.h
+++ b/drivers/gpu/drm/mediatek/mtk_disp_drv.h
@@ -59,6 +59,18 @@ void mtk_color_config(struct mtk_ddp_comp *comp, unsigned int w,
unsigned int bpc, struct cmdq_pkt *cmdq_pkt);
void mtk_color_start(struct device *dev);
+void mtk_direct_link_connect(struct mtk_ddp_comp *comp, struct device *mmsys_dev,
+ struct mtk_ddp_comp *next);
+void mtk_direct_link_disconnect(struct mtk_ddp_comp *comp, struct device *mmsys_dev,
+ struct mtk_ddp_comp *next);
+int mtk_direct_link_clk_enable(struct mtk_ddp_comp *comp);
+void mtk_direct_link_clk_disable(struct mtk_ddp_comp *comp);
+void mtk_direct_link_config(struct mtk_ddp_comp *comp,
+ unsigned int w, unsigned int h, unsigned int vrefresh,
+ unsigned int bpc, struct cmdq_pkt *cmdq_pkt);
+void mtk_direct_link_mtx_remove(struct mtk_ddp_comp *comp, struct mtk_mutex *mutex);
+void mtk_direct_link_add(struct mtk_ddp_comp *comp, struct mtk_mutex *mutex);
+
void mtk_dither_set_common(void __iomem *regs, struct cmdq_client_reg *cmdq_reg,
unsigned int bpc, unsigned int cfg,
unsigned int dither_en, struct cmdq_pkt *cmdq_pkt);
diff --git a/drivers/gpu/drm/mediatek/mtk_drm_drv.c b/drivers/gpu/drm/mediatek/mtk_drm_drv.c
index 3bee730cd34f..482d05071125 100644
--- a/drivers/gpu/drm/mediatek/mtk_drm_drv.c
+++ b/drivers/gpu/drm/mediatek/mtk_drm_drv.c
@@ -251,7 +251,8 @@ static bool mtk_drm_find_mmsys_comp(struct mtk_drm_private *private,
for (j = 0; j < output_path->len; j++) {
if (output_path->comp[j].type != type ||
- output_path->comp[j].inst_id != inst_id)
+ (inst_id != MTK_DISP_CONTROLLER_MAX_HW_COMP_INSTANCE &&
+ output_path->comp[j].inst_id != inst_id))
continue;
return true;
@@ -267,6 +268,19 @@ static bool mtk_drm_find_mmsys_comp(struct mtk_drm_private *private,
return false;
}
+static bool mtk_drm_find_directlink_comp(struct mtk_drm_private *private)
+{
+ if (mtk_drm_find_mmsys_comp(private, MTK_DISP_DIRECT_LINK_IN,
+ MTK_DISP_CONTROLLER_MAX_HW_COMP_INSTANCE))
+ return true;
+
+ if (mtk_drm_find_mmsys_comp(private, MTK_DISP_DIRECT_LINK_OUT,
+ MTK_DISP_CONTROLLER_MAX_HW_COMP_INSTANCE))
+ return true;
+
+ return false;
+}
+
static struct mtk_drm_private *
mtk_drm_find_matching_controller(struct mtk_drm_private **all_drm_private,
struct device_node *target_node)
@@ -607,6 +621,8 @@ static const struct of_device_id mtk_ddp_comp_dt_ids[] = {
.data = (void *)MTK_DISP_COLOR },
{ .compatible = "mediatek,mt8173-disp-color",
.data = (void *)MTK_DISP_COLOR },
+ { .compatible = "mediatek,mt8196-disp-direct-link",
+ .data = (void *)MTK_DISP_DIRECT_LINK },
{ .compatible = "mediatek,mt8167-disp-dither",
.data = (void *)MTK_DISP_DITHER },
{ .compatible = "mediatek,mt8183-disp-dither",
@@ -689,6 +705,8 @@ static const struct of_device_id mtk_ddp_comp_dt_ids[] = {
.data = (void *)MTK_DISP_WDMA },
{ .compatible = "mediatek,mt8173-disp-wdma",
.data = (void *)MTK_DISP_WDMA },
+ { .compatible = "mediatek,mt8196-ovl-direct-link",
+ .data = (void *)MTK_DISP_DIRECT_LINK },
{ .compatible = "mediatek,mt2701-dpi",
.data = (void *)MTK_DISP_DPI },
{ .compatible = "mediatek,mt8167-dsi",
@@ -794,10 +812,27 @@ static int mtk_drm_of_get_first_input(struct device *dev, struct device_node *no
if (ret)
return -ENOENT;
- inst_id = mtk_ddp_comp_get_id(ep_dev_node, comp_type);
+ inst_id = mtk_ddp_comp_get_id(ep_dev_node, ep_in, comp_type);
if (inst_id < 0)
return inst_id;
+ if (comp_type == MTK_DISP_DIRECT_LINK) {
+ struct device_node *remote_port = of_graph_get_remote_port(ep_in);
+
+ /* If there's a remote port this input is active, otherwise it's unused */
+ if (!remote_port)
+ return -ENOENT;
+ of_node_put(remote_port);
+
+ /* All even ports describe inputs, all odd ports describe outputs */
+ comp_type = (crtc_endpoint + 1) % 2 ?
+ MTK_DISP_DIRECT_LINK_IN : MTK_DISP_DIRECT_LINK_OUT;
+
+ dev_dbg(dev, "Found First DirectLink %s with port %pOF and ID %u\n",
+ comp_type == MTK_DISP_DIRECT_LINK_OUT ? "OUT" : "IN",
+ ep_in, crtc_endpoint);
+ }
+
/* All ok! Pass the Component ID to the caller. */
comp_def->type = comp_type;
comp_def->inst_id = inst_id;
@@ -838,7 +873,7 @@ static int mtk_drm_of_get_ddp_ep_cid(struct device *dev, struct device_node *nod
struct mtk_drm_comp_definition *comp_def,
bool controller_arch_v2)
{
- struct device_node *ep_dev_node, *ep_out;
+ struct device_node *ep_dev_node, *ep_out, *remote_ep;
enum mtk_ddp_comp_type comp_type;
int ret;
@@ -846,10 +881,16 @@ static int mtk_drm_of_get_ddp_ep_cid(struct device *dev, struct device_node *nod
if (!ep_out)
return -EINVAL;
- ep_dev_node = of_graph_get_remote_port_parent(ep_out);
+ remote_ep = of_graph_get_remote_endpoint(ep_out);
of_node_put(ep_out);
- if (!ep_dev_node)
+ if (!remote_ep)
+ return -ENOENT;
+
+ ep_dev_node = of_graph_get_port_parent(remote_ep);
+ if (!ep_dev_node) {
+ of_node_put(remote_ep);
return -EINVAL;
+ };
/*
* Pass the next node pointer regardless of failures in the later code
@@ -867,17 +908,20 @@ static int mtk_drm_of_get_ddp_ep_cid(struct device *dev, struct device_node *nod
dev_dbg(dev, "Found connection to external mmsys %pOF\n",
rmt_ctrlr_node);
- of_node_put(ep_dev_node);
of_node_put(rmt_ctrlr_node);
+ of_node_put(remote_ep);
return -EREMOTE;
}
}
- if (!of_device_is_available(ep_dev_node))
+ if (!of_device_is_available(ep_dev_node)) {
+ of_node_put(remote_ep);
return -ENODEV;
+ }
ret = mtk_drm_of_get_ddp_comp_type(ep_dev_node, &comp_type);
if (ret) {
+ of_node_put(remote_ep);
if (mtk_ovl_adaptor_is_comp_present(ep_dev_node)) {
comp_def->type = MTK_DISP_OVL_ADAPTOR;
comp_def->inst_id = 0;
@@ -887,10 +931,26 @@ static int mtk_drm_of_get_ddp_ep_cid(struct device *dev, struct device_node *nod
return ret;
}
- ret = mtk_ddp_comp_get_id(ep_dev_node, comp_type);
+ ret = mtk_ddp_comp_get_id(ep_dev_node, remote_ep, comp_type);
+ of_node_put(remote_ep);
if (ret < 0)
return ret;
+ if (comp_type == MTK_DISP_DIRECT_LINK) {
+ struct device_node *remote_port = of_graph_get_remote_port(ep_out);
+ u32 port_id;
+
+ of_property_read_u32(remote_port, "reg", &port_id);
+ of_node_put(remote_port);
+
+ /* All even ports describe inputs, all odd ports describe outputs */
+ comp_type = (port_id + 1) % 2 ? MTK_DISP_DIRECT_LINK_IN : MTK_DISP_DIRECT_LINK_OUT;
+
+ dev_dbg(dev, "Found DirectLink %s with port %pOF and ID %u\n",
+ comp_type == MTK_DISP_DIRECT_LINK_OUT ? "OUT" : "IN",
+ remote_port, port_id);
+ }
+
/* All ok! Pass the Component ID to the caller. */
comp_def->type = comp_type;
comp_def->inst_id = ret;
@@ -1007,6 +1067,22 @@ static int mtk_drm_of_ddp_path_build_one(struct device *dev, struct device_node
ret = mtk_drm_of_get_ddp_ep_cid(dev, prev, 3, cpath, &next,
&temp_path[idx], controller_arch_v2);
of_node_put(prev);
+
+ /*
+ * Avoid recursion for special DL_IN/DL_OUT connections:
+ * 1. IN may be directly connected to OUT, expressing a RELAY
+ * internal connection, or
+ * 2. A component's OUT may be directly connected to an
+ * output of DirectLink, expressing a (rare) fixed connection.
+ */
+ for (int i = 1; i <= min(idx, 2); i++) {
+ if (temp_path[idx].type == temp_path[idx - i].type &&
+ temp_path[idx].inst_id == temp_path[idx - i].inst_id) {
+ ret = -ELOOP;
+ break;
+ }
+ }
+
if (ret) {
dev_vdbg(dev, "Invalid comp reached with result %d\n", ret);
of_node_put(next);
@@ -1037,6 +1113,8 @@ static int mtk_drm_of_ddp_path_build_one(struct device *dev, struct device_node
/* If the last entry is not a final display output, the configuration is wrong */
switch (temp_path[idx - 1].type) {
+ case MTK_DISP_DIRECT_LINK_IN:
+ case MTK_DISP_DIRECT_LINK_OUT:
case MTK_DISP_DP_INTF:
case MTK_DISP_DPI:
case MTK_DISP_DSI:
@@ -1190,8 +1268,13 @@ static int mtk_drm_probe(struct platform_device *pdev)
hash_init(private->hlist.ddp_list);
+ if (of_graph_is_present(phandle))
+ node = phandle;
+ else
+ node = of_find_node_by_name(phandle, "direct-link");
+
/* Try to build the display pipeline from devicetree graphs */
- if (of_graph_is_present(phandle)) {
+ if (node) {
dev_dbg(dev, "Building display pipeline for MMSYS %u\n",
mtk_drm_data->mmsys_id);
private->data = devm_kmemdup(dev, mtk_drm_data,
@@ -1199,7 +1282,7 @@ static int mtk_drm_probe(struct platform_device *pdev)
if (!private->data)
return -ENOMEM;
- ret = mtk_drm_of_ddp_path_build(dev, phandle, private->data);
+ ret = mtk_drm_of_ddp_path_build(dev, node, private->data);
if (ret)
return ret;
} else {
@@ -1218,6 +1301,7 @@ static int mtk_drm_probe(struct platform_device *pdev)
for_each_child_of_node(phandle->parent, node) {
enum mtk_ddp_comp_type comp_type;
u8 comp_inst_id;
+ bool comp_found;
ret = mtk_drm_of_get_ddp_comp_type(node, &comp_type);
if (ret)
@@ -1240,14 +1324,20 @@ static int mtk_drm_probe(struct platform_device *pdev)
continue;
}
- comp_inst_id = mtk_ddp_comp_get_id(node, comp_type);
+ comp_inst_id = mtk_ddp_comp_get_id(node, NULL, comp_type);
if (comp_inst_id < 0) {
dev_warn(dev, "Skipping unknown component %pOF\n",
node);
continue;
}
- if (!mtk_drm_find_mmsys_comp(private, comp_type, comp_inst_id))
+ if (comp_type == MTK_DISP_DIRECT_LINK)
+ comp_found = mtk_drm_find_directlink_comp(private);
+ else
+ comp_found = mtk_drm_find_mmsys_comp(private,
+ comp_type, comp_inst_id);
+
+ if (!comp_found)
continue;
/*
@@ -1263,12 +1353,45 @@ static int mtk_drm_probe(struct platform_device *pdev)
node);
}
- ret = mtk_ddp_comp_init(dev, node, &private->hlist,
- private->data->mmsys_id,
- comp_type, comp_inst_id);
- if (ret) {
- of_node_put(node);
- goto err_node;
+ if (comp_type == MTK_DISP_DIRECT_LINK) {
+ for_each_of_graph_port(node, port) {
+ u32 port_id;
+
+ of_property_read_u32(port, "reg", &port_id);
+ if (port_id > 1)
+ continue;
+
+ /* Even ports are inputs, odd ports are outputs */
+ if (port_id % 2)
+ comp_type = MTK_DISP_DIRECT_LINK_OUT;
+
+ for_each_of_graph_port_endpoint(port, ep) {
+ struct of_endpoint of_ep;
+
+ ret = of_graph_parse_endpoint(ep, &of_ep);
+ if (ret)
+ break;
+
+ ret = mtk_ddp_comp_init(dev, node, &private->hlist,
+ private->data->mmsys_id,
+ comp_type, of_ep.id);
+ if (ret)
+ break;
+ }
+
+ if (ret) {
+ of_node_put(node);
+ goto err_node;
+ }
+ }
+ } else {
+ ret = mtk_ddp_comp_init(dev, node, &private->hlist,
+ private->data->mmsys_id,
+ comp_type, comp_inst_id);
+ if (ret) {
+ of_node_put(node);
+ goto err_node;
+ }
}
}
@@ -1361,6 +1484,7 @@ static struct platform_driver mtk_drm_platform_driver = {
};
static struct platform_driver * const mtk_drm_drivers[] = {
+ &mtk_direct_link_driver,
&mtk_disp_aal_driver,
&mtk_disp_blender_driver,
&mtk_disp_ccorr_driver,
diff --git a/drivers/gpu/drm/mediatek/mtk_drm_drv.h b/drivers/gpu/drm/mediatek/mtk_drm_drv.h
index 3c403bc8f4fe..76325d1be5f4 100644
--- a/drivers/gpu/drm/mediatek/mtk_drm_drv.h
+++ b/drivers/gpu/drm/mediatek/mtk_drm_drv.h
@@ -74,6 +74,7 @@ struct mtk_drm_private {
struct mtk_drm_private **all_drm_private;
};
+extern struct platform_driver mtk_direct_link_driver;
extern struct platform_driver mtk_disp_aal_driver;
extern struct platform_driver mtk_disp_blender_driver;
extern struct platform_driver mtk_disp_ccorr_driver;
diff --git a/include/linux/soc/mediatek/mtk-mmsys.h b/include/linux/soc/mediatek/mtk-mmsys.h
index a1c8a436b3dc..d6742ca39d86 100644
--- a/include/linux/soc/mediatek/mtk-mmsys.h
+++ b/include/linux/soc/mediatek/mtk-mmsys.h
@@ -91,6 +91,8 @@ enum mtk_ddp_comp_type {
MTK_DISP_BLENDER,
MTK_DISP_CCORR,
MTK_DISP_COLOR,
+ MTK_DISP_DIRECT_LINK_OUT,
+ MTK_DISP_DIRECT_LINK_IN,
MTK_DISP_DITHER,
MTK_DISP_DSC,
MTK_DISP_ETHDR_MIXER,
@@ -122,6 +124,8 @@ enum mtk_ddp_comp_type {
MTK_DDP_COMP_TYPE_MAX
};
+#define MTK_DISP_DIRECT_LINK MTK_DISP_DIRECT_LINK_IN
+
void mtk_mmsys_ddp_dpi_fmt_config(struct device *dev, u32 val);
void mtk_mmsys_merge_async_config(struct device *dev, int idx, int width,
--
2.54.0
^ permalink raw reply related
* [PATCH 42/42] drm/mediatek: mtk_drm_drv: Fail init only if all paths are invalid
From: AngeloGioacchino Del Regno @ 2026-07-01 12:20 UTC (permalink / raw)
To: chunkuang.hu
Cc: p.zabel, airlied, simona, maarten.lankhorst, mripard, tzimmermann,
robh, krzk+dt, conor+dt, matthias.bgg, angelogioacchino.delregno,
dri-devel, linux-mediatek, devicetree, linux-kernel,
linux-arm-kernel, justin.yeh, jason-jh.lin, kernel
In-Reply-To: <20260701122057.19648-1-angelogioacchino.delregno@collabora.com>
Up until now, if not all display controller paths were valid, the
driver would fail probing and refuse to bind components: while
that was a good idea before, now that mediatek-drm gained much
more flexibility, it is finally possible to gracefully handle
this situation and register only the valid paths while leaving
the invalid ones unregistered, without any crash.
Count how many output paths are found, and then count how many
have failed probing: if there is at least one valid path, avoid
erroring out, so that at least some outputs will just work.
Of course, any path failing is not a clean situation and must be
resolved: in this case, function mtk_crtc_create() still prints
error messages so, even though some output works, that will not
go unnoticed, as a quick check in kmsg will show the errors that
made a certain path not to register.
Signed-off-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
---
drivers/gpu/drm/mediatek/mtk_drm_drv.c | 20 ++++++++++++++++++--
1 file changed, 18 insertions(+), 2 deletions(-)
diff --git a/drivers/gpu/drm/mediatek/mtk_drm_drv.c b/drivers/gpu/drm/mediatek/mtk_drm_drv.c
index f5c9fe1588d0..65a891815408 100644
--- a/drivers/gpu/drm/mediatek/mtk_drm_drv.c
+++ b/drivers/gpu/drm/mediatek/mtk_drm_drv.c
@@ -379,6 +379,8 @@ static int mtk_drm_kms_init(struct drm_device *drm)
struct mtk_drm_private *priv_n;
struct device *dma_dev = NULL;
struct drm_crtc *crtc;
+ int num_failed = 0;
+ int num_paths = 0;
int ret, i, j;
if (drm_firmware_drivers_only())
@@ -445,15 +447,29 @@ static int mtk_drm_kms_init(struct drm_device *drm)
if (!priv_n->data->output_paths[i].len)
continue;
+ num_paths++;
+
+ dev_vdbg(drm->dev,
+ "[CTRL%d-CRTC%d] Path Len:%d, Controller Order:%u\n",
+ j, i, priv_n->data->output_paths[i].len,
+ priv_n->data->output_paths[i].order);
+
ret = mtk_crtc_create(drm, i, j,
priv_n->data->conn_routes,
priv_n->data->num_conn_routes);
+ if (ret == 0)
+ break;
- if (ret)
- goto err_component_unbind;
+ num_failed++;
}
}
+ if (num_failed == num_paths) {
+ dev_err(drm->dev, "No valid Display Controller path! Going out.\n");
+ ret = -ENODEV;
+ goto err_component_unbind;
+ }
+
/* IGT will check if the cursor size is configured */
drm->mode_config.cursor_width = 512;
drm->mode_config.cursor_height = 512;
--
2.54.0
^ permalink raw reply related
* [PATCH 40/42] dt-bindings: display: mediatek: Introduce MT8196 Image Resizer
From: AngeloGioacchino Del Regno @ 2026-07-01 12:20 UTC (permalink / raw)
To: chunkuang.hu
Cc: p.zabel, airlied, simona, maarten.lankhorst, mripard, tzimmermann,
robh, krzk+dt, conor+dt, matthias.bgg, angelogioacchino.delregno,
dri-devel, linux-mediatek, devicetree, linux-kernel,
linux-arm-kernel, justin.yeh, jason-jh.lin, kernel
In-Reply-To: <20260701122057.19648-1-angelogioacchino.delregno@collabora.com>
Add documentation for the Image Resizer "RSZ" Scaler block found
in the MT8196 SoC and its variants.
Signed-off-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
---
.../display/mediatek/mediatek,mt8196-rsz.yaml | 97 +++++++++++++++++++
1 file changed, 97 insertions(+)
create mode 100644 Documentation/devicetree/bindings/display/mediatek/mediatek,mt8196-rsz.yaml
diff --git a/Documentation/devicetree/bindings/display/mediatek/mediatek,mt8196-rsz.yaml b/Documentation/devicetree/bindings/display/mediatek/mediatek,mt8196-rsz.yaml
new file mode 100644
index 000000000000..cf6b0ed08bfb
--- /dev/null
+++ b/Documentation/devicetree/bindings/display/mediatek/mediatek,mt8196-rsz.yaml
@@ -0,0 +1,97 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/display/mediatek/mediatek,mt8196-rsz.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: MediaTek Display Image Resizer (RSZ)
+
+maintainers:
+ - AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
+
+description:
+ The MediaTek Display Image Resizer (RSZ) is a high fidelity scaler block,
+ with filters and signal enhancers, responsible for performing downscaling
+ or upscaling of a frame.
+
+properties:
+ compatible:
+ - const: mediatek,mt8196-disp-rsz
+
+ reg:
+ maxItems: 1
+
+ clocks:
+ maxItems: 1
+
+ power-domains:
+ maxItems: 1
+
+ ports:
+ $ref: /schemas/graph.yaml#/properties/ports
+
+ properties:
+ port@0:
+ $ref: /schemas/graph.yaml#/properties/port
+
+ port@1:
+ $ref: /schemas/graph.yaml#/properties/port
+
+ required:
+ - port@0
+ - port@1
+
+ trigger-sources:
+ maxItems: 1
+
+required:
+ - compatible
+ - reg
+ - clocks
+ - clock-names
+ - ports
+
+additionalProperties: false
+
+examples:
+ - |
+ #include <dt-bindings/interrupt-controller/arm-gic.h>
+ #include <dt-bindings/clock/mediatek,mt8196-clock.h>
+ #include <dt-bindings/power/mediatek,mt8196-power.h>
+
+ scaler@329d0000 {
+ compatible = "mediatek,mt8196-disp-rsz";
+ reg = <0x329d0000 0x1000>;
+ clocks = <&ovlsys0 CLK_OVL_MDP_RSZ0>;
+ power-domains = <&hpm_hwv MT8196_POWER_DOMAIN_OVL0_DORMANT>;
+ trigger-sources = <&ovl0_mutex 26>;
+
+ ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ port@0 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <0>;
+
+ endpoint@0 {
+ reg = <0>;
+ remote-endpoint = <&ep_main_out>;
+ };
+ };
+
+ port@1 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <1>;
+
+ endpoint@0 {
+ reg = <0>;
+ remote-endpoint = <&exdma0_2_in>;
+ };
+ };
+ };
+ };
+
+...
--
2.54.0
^ permalink raw reply related
* [PATCH 41/42] drm/mediatek: Add support for Display Image Resizer (Scaler)
From: AngeloGioacchino Del Regno @ 2026-07-01 12:20 UTC (permalink / raw)
To: chunkuang.hu
Cc: p.zabel, airlied, simona, maarten.lankhorst, mripard, tzimmermann,
robh, krzk+dt, conor+dt, matthias.bgg, angelogioacchino.delregno,
dri-devel, linux-mediatek, devicetree, linux-kernel,
linux-arm-kernel, justin.yeh, jason-jh.lin, kernel
In-Reply-To: <20260701122057.19648-1-angelogioacchino.delregno@collabora.com>
Add basic support for the Image Resizer hardware found in some
MediaTek Display Controller IPs, like the one found in MT8196.
This is currently set in bypass mode and used to pass the frame
buffer from a RSZ input component to supported RSZ outputs.
Full implementation of hardware-accelerated DRM scaling will be
done later.
Signed-off-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
---
drivers/gpu/drm/mediatek/mtk_ddp_comp.c | 22 ++++++++++++++++++++++
drivers/gpu/drm/mediatek/mtk_drm_drv.c | 2 ++
2 files changed, 24 insertions(+)
diff --git a/drivers/gpu/drm/mediatek/mtk_ddp_comp.c b/drivers/gpu/drm/mediatek/mtk_ddp_comp.c
index ea09af8d4705..453a4a9ad565 100644
--- a/drivers/gpu/drm/mediatek/mtk_ddp_comp.c
+++ b/drivers/gpu/drm/mediatek/mtk_ddp_comp.c
@@ -56,6 +56,10 @@
#define POSTMASK_RELAY_MODE BIT(0)
#define DISP_REG_POSTMASK_SIZE 0x0030
+#define DISP_REG_RSZ_EN 0x0000
+#define DISP_REG_RSZ_INPUT_SIZE 0x0010
+#define DISP_REG_RSZ_OUTPUT_SIZE 0x0014
+
#define DISP_REG_UFO_START 0x0000
#define UFO_BYPASS BIT(2)
@@ -230,6 +234,16 @@ static void mtk_postmask_stop(struct device *dev)
writel_relaxed(0x0, priv->regs + DISP_REG_POSTMASK_EN);
}
+static void mtk_rsz_config(struct mtk_ddp_comp *comp, unsigned int w,
+ unsigned int h, unsigned int vrefresh,
+ unsigned int bpc, struct cmdq_pkt *cmdq_pkt)
+{
+ struct mtk_ddp_comp_dev *priv = dev_get_drvdata(comp->dev);
+
+ mtk_ddp_write(cmdq_pkt, 0, &priv->cmdq_reg, priv->regs, DISP_REG_RSZ_INPUT_SIZE);
+ mtk_ddp_write(cmdq_pkt, 0, &priv->cmdq_reg, priv->regs, DISP_REG_RSZ_OUTPUT_SIZE);
+}
+
static void mtk_ufoe_start(struct device *dev)
{
struct mtk_ddp_comp_dev *priv = dev_get_drvdata(dev);
@@ -414,6 +428,12 @@ static const struct mtk_ddp_comp_funcs ddp_rdma = {
.get_num_formats = mtk_rdma_get_num_formats,
};
+static const struct mtk_ddp_comp_funcs ddp_rsz = {
+ .clk_enable = mtk_ddp_clk_enable,
+ .clk_disable = mtk_ddp_clk_disable,
+ .config = mtk_rsz_config,
+};
+
static const struct mtk_ddp_comp_funcs ddp_tdshp = {
.clk_enable = mtk_tdshp_clk_enable,
.clk_disable = mtk_tdshp_clk_disable,
@@ -489,6 +509,7 @@ static const char * const mtk_ddp_comp_stem[MTK_DDP_COMP_TYPE_MAX] = {
[MTK_DISP_POSTMASK] = "postmask",
[MTK_DISP_PWM] = "pwm",
[MTK_DISP_RDMA] = "rdma",
+ [MTK_DISP_RSZ] = "resizer",
[MTK_DISP_TDSHP] = "tdshp",
[MTK_DISP_UFOE] = "ufoe",
[MTK_DISP_WDMA] = "wdma",
@@ -517,6 +538,7 @@ static const struct mtk_ddp_comp_funcs *mtk_ddp_funcs[MTK_DDP_COMP_TYPE_MAX] = {
[MTK_DISP_POSTMASK] = &ddp_postmask,
[MTK_DISP_PWM] = NULL,
[MTK_DISP_RDMA] = &ddp_rdma,
+ [MTK_DISP_RSZ] = &ddp_rsz,
[MTK_DISP_TDSHP] = &ddp_tdshp,
[MTK_DISP_UFOE] = &ddp_ufoe,
[MTK_DISP_WDMA] = &ddp_wdma,
diff --git a/drivers/gpu/drm/mediatek/mtk_drm_drv.c b/drivers/gpu/drm/mediatek/mtk_drm_drv.c
index b96cf2f435e5..f5c9fe1588d0 100644
--- a/drivers/gpu/drm/mediatek/mtk_drm_drv.c
+++ b/drivers/gpu/drm/mediatek/mtk_drm_drv.c
@@ -699,6 +699,8 @@ static const struct of_device_id mtk_ddp_comp_dt_ids[] = {
.data = (void *)MTK_DISP_RDMA },
{ .compatible = "mediatek,mt8195-disp-rdma",
.data = (void *)MTK_DISP_RDMA },
+ { .compatible = "mediatek,mt8196-disp-rsz",
+ .data = (void *)MTK_DISP_RSZ },
{ .compatible = "mediatek,mt8196-disp-tdshp",
.data = (void *)MTK_DISP_TDSHP },
{ .compatible = "mediatek,mt8173-disp-ufoe",
--
2.54.0
^ permalink raw reply related
* [PATCH 39/42] drm/mediatek: Add Two-Dimension Sharpness Processor (TDSHP) driver
From: AngeloGioacchino Del Regno @ 2026-07-01 12:20 UTC (permalink / raw)
To: chunkuang.hu
Cc: p.zabel, airlied, simona, maarten.lankhorst, mripard, tzimmermann,
robh, krzk+dt, conor+dt, matthias.bgg, angelogioacchino.delregno,
dri-devel, linux-mediatek, devicetree, linux-kernel,
linux-arm-kernel, justin.yeh, jason-jh.lin, kernel
In-Reply-To: <20260701122057.19648-1-angelogioacchino.delregno@collabora.com>
The MediaTek 2D Sharpness Processor (TDSHP) is responsible for
performing image sharpness adjustments/enhancements in a display
pipeline.
Even though this hardware block supports adjusting the luma and
contour 2D histograms, frequency weighting, luma-chroma gain and
others, this only introduces a basic configuration which allows
to bypass TDSHP processing in an effort to forward the data from
this block to others.
That is necessary because some components cannot be connected
directly in specific pipelines; for example, in MT8196/MT6991
pipelines, when Display Resizer (RSZ) and Color Correction (CCORR)
components are required, it is necessary to pass through TDSHP as
direct connection between RSZ and CCORR is not possible due to HW
limitations.
Signed-off-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
---
drivers/gpu/drm/mediatek/Makefile | 1 +
drivers/gpu/drm/mediatek/mtk_ddp_comp.c | 10 ++
drivers/gpu/drm/mediatek/mtk_disp_drv.h | 8 ++
drivers/gpu/drm/mediatek/mtk_disp_tdshp.c | 167 ++++++++++++++++++++++
drivers/gpu/drm/mediatek/mtk_drm_drv.c | 3 +
drivers/gpu/drm/mediatek/mtk_drm_drv.h | 1 +
include/linux/soc/mediatek/mtk-mmsys.h | 2 +
7 files changed, 192 insertions(+)
create mode 100644 drivers/gpu/drm/mediatek/mtk_disp_tdshp.c
diff --git a/drivers/gpu/drm/mediatek/Makefile b/drivers/gpu/drm/mediatek/Makefile
index e9478fa1a2ba..47ba6bc17d9e 100644
--- a/drivers/gpu/drm/mediatek/Makefile
+++ b/drivers/gpu/drm/mediatek/Makefile
@@ -15,6 +15,7 @@ mediatek-drm-y := mtk_crtc.o \
mtk_disp_ovl.o \
mtk_disp_ovl_adaptor.o \
mtk_disp_rdma.o \
+ mtk_disp_tdshp.o \
mtk_disp_wdma.o \
mtk_drm_drv.o \
mtk_drm_legacy.o \
diff --git a/drivers/gpu/drm/mediatek/mtk_ddp_comp.c b/drivers/gpu/drm/mediatek/mtk_ddp_comp.c
index 7e12ddffbe77..ea09af8d4705 100644
--- a/drivers/gpu/drm/mediatek/mtk_ddp_comp.c
+++ b/drivers/gpu/drm/mediatek/mtk_ddp_comp.c
@@ -414,6 +414,14 @@ static const struct mtk_ddp_comp_funcs ddp_rdma = {
.get_num_formats = mtk_rdma_get_num_formats,
};
+static const struct mtk_ddp_comp_funcs ddp_tdshp = {
+ .clk_enable = mtk_tdshp_clk_enable,
+ .clk_disable = mtk_tdshp_clk_disable,
+ .config = mtk_tdshp_config,
+ .start = mtk_tdshp_start,
+ .stop = mtk_tdshp_stop,
+};
+
static const struct mtk_ddp_comp_funcs ddp_wdma = {
.clk_enable = mtk_wdma_clk_enable,
.clk_disable = mtk_wdma_clk_disable,
@@ -481,6 +489,7 @@ static const char * const mtk_ddp_comp_stem[MTK_DDP_COMP_TYPE_MAX] = {
[MTK_DISP_POSTMASK] = "postmask",
[MTK_DISP_PWM] = "pwm",
[MTK_DISP_RDMA] = "rdma",
+ [MTK_DISP_TDSHP] = "tdshp",
[MTK_DISP_UFOE] = "ufoe",
[MTK_DISP_WDMA] = "wdma",
[MTK_DISP_DP_INTF] = "dp-intf",
@@ -508,6 +517,7 @@ static const struct mtk_ddp_comp_funcs *mtk_ddp_funcs[MTK_DDP_COMP_TYPE_MAX] = {
[MTK_DISP_POSTMASK] = &ddp_postmask,
[MTK_DISP_PWM] = NULL,
[MTK_DISP_RDMA] = &ddp_rdma,
+ [MTK_DISP_TDSHP] = &ddp_tdshp,
[MTK_DISP_UFOE] = &ddp_ufoe,
[MTK_DISP_WDMA] = &ddp_wdma,
[MTK_DISP_DPI] = &ddp_dpi,
diff --git a/drivers/gpu/drm/mediatek/mtk_disp_drv.h b/drivers/gpu/drm/mediatek/mtk_disp_drv.h
index f78f12da08a8..0308094b29cd 100644
--- a/drivers/gpu/drm/mediatek/mtk_disp_drv.h
+++ b/drivers/gpu/drm/mediatek/mtk_disp_drv.h
@@ -243,6 +243,14 @@ void mtk_mdp_rdma_config(struct device *dev, struct mtk_mdp_rdma_cfg *cfg,
const u32 *mtk_mdp_rdma_get_formats(struct device *dev);
size_t mtk_mdp_rdma_get_num_formats(struct device *dev);
+int mtk_tdshp_clk_enable(struct mtk_ddp_comp *comp);
+void mtk_tdshp_clk_disable(struct mtk_ddp_comp *comp);
+void mtk_tdshp_config(struct mtk_ddp_comp *comp, unsigned int w,
+ unsigned int h, unsigned int vrefresh,
+ unsigned int bpc, struct cmdq_pkt *cmdq_pkt);
+void mtk_tdshp_start(struct device *dev);
+void mtk_tdshp_stop(struct device *dev);
+
int mtk_wdma_clk_enable(struct mtk_ddp_comp *comp);
void mtk_wdma_clk_disable(struct mtk_ddp_comp *comp);
void mtk_wdma_config(struct mtk_ddp_comp *comp, unsigned int width,
diff --git a/drivers/gpu/drm/mediatek/mtk_disp_tdshp.c b/drivers/gpu/drm/mediatek/mtk_disp_tdshp.c
new file mode 100644
index 000000000000..31f57c567137
--- /dev/null
+++ b/drivers/gpu/drm/mediatek/mtk_disp_tdshp.c
@@ -0,0 +1,167 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * MediaTek Two-Dimension Sharpness Processor (TDSHP)
+ *
+ * Copyright (c) 2025 MediaTek Inc.
+ * Copyright (c) 2026 Collabora Ltd.
+ * AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
+ */
+
+#include <linux/clk.h>
+#include <linux/component.h>
+#include <linux/module.h>
+#include <linux/of_device.h>
+#include <linux/of_platform.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/soc/mediatek/mtk-cmdq.h>
+
+#include "mtk_disp_drv.h"
+#include "mtk_disp_ovl.h"
+#include "mtk_drm_drv.h"
+
+#define DISP_REG_TDSHP_EN 0x0000
+# define DISP_TDSHP_TDS_EN BIT(31)
+#define DISP_REG_TDSHP_CTRL 0x0100
+# define DISP_TDSHP_CTRL_EN BIT(0)
+# define DISP_TDSHP_PWR_SCL_EN BIT(2)
+#define DISP_REG_TDSHP_CFG 0x0110
+# define DISP_TDSHP_RELAY_MODE BIT(0)
+#define DISP_REG_TDSHP_INPUT_SIZE 0x0120
+#define DISP_REG_TDSHP_OUTPUT_OFFSET 0x0124
+#define DISP_REG_TDSHP_OUTPUT_SIZE 0x0128
+
+struct mtk_disp_tdshp {
+ void __iomem *regs;
+ struct clk *clk;
+ struct cmdq_client_reg cmdq_reg;
+};
+
+void mtk_tdshp_config(struct mtk_ddp_comp *comp, unsigned int w,
+ unsigned int h, unsigned int vrefresh,
+ unsigned int bpc, struct cmdq_pkt *cmdq_pkt)
+{
+ struct mtk_disp_tdshp *tdshp = dev_get_drvdata(comp->dev);
+ u32 val = bpc == 8 ? DISP_TDSHP_PWR_SCL_EN : 0;
+
+ /* Set basic parameters to at least pass the data on */
+ mtk_ddp_write(cmdq_pkt, val | DISP_TDSHP_CTRL_EN, &tdshp->cmdq_reg,
+ tdshp->regs, DISP_REG_TDSHP_CTRL);
+
+ mtk_ddp_write(cmdq_pkt, w << 16 | h, &tdshp->cmdq_reg,
+ tdshp->regs, DISP_REG_TDSHP_INPUT_SIZE);
+ mtk_ddp_write(cmdq_pkt, w << 16 | h, &tdshp->cmdq_reg,
+ tdshp->regs, DISP_REG_TDSHP_OUTPUT_SIZE);
+ mtk_ddp_write(cmdq_pkt, 0x0, &tdshp->cmdq_reg,
+ tdshp->regs, DISP_REG_TDSHP_OUTPUT_OFFSET);
+
+ /* Set RELAY mode to bypass 2D Sharpness processing */
+ mtk_ddp_write(cmdq_pkt, DISP_TDSHP_RELAY_MODE, &tdshp->cmdq_reg,
+ tdshp->regs, DISP_REG_TDSHP_CFG);
+
+ mtk_ddp_write_mask(cmdq_pkt, DISP_TDSHP_TDS_EN, &tdshp->cmdq_reg,
+ tdshp->regs, DISP_REG_TDSHP_EN, DISP_TDSHP_TDS_EN);
+}
+
+void mtk_tdshp_start(struct device *dev)
+{
+ struct mtk_disp_tdshp *tdshp = dev_get_drvdata(dev);
+
+ writel(DISP_TDSHP_CTRL_EN, tdshp->regs + DISP_REG_TDSHP_CTRL);
+}
+
+void mtk_tdshp_stop(struct device *dev)
+{
+ struct mtk_disp_tdshp *tdshp = dev_get_drvdata(dev);
+
+ writel(0, tdshp->regs + DISP_REG_TDSHP_CTRL);
+}
+
+int mtk_tdshp_clk_enable(struct mtk_ddp_comp *comp)
+{
+ struct mtk_disp_tdshp *tdshp = dev_get_drvdata(comp->dev);
+
+ return clk_prepare_enable(tdshp->clk);
+}
+
+void mtk_tdshp_clk_disable(struct mtk_ddp_comp *comp)
+{
+ struct mtk_disp_tdshp *tdshp = dev_get_drvdata(comp->dev);
+
+ clk_disable_unprepare(tdshp->clk);
+}
+
+static int mtk_tdshp_bind(struct device *dev, struct device *master, void *data)
+{
+ return 0;
+}
+
+static void mtk_tdshp_unbind(struct device *dev, struct device *master, void *data)
+{
+}
+
+static const struct component_ops mtk_disp_tdshp_component_ops = {
+ .bind = mtk_tdshp_bind,
+ .unbind = mtk_tdshp_unbind,
+};
+
+static int mtk_disp_tdshp_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct mtk_disp_tdshp *tdshp;
+ int ret = 0;
+
+ tdshp = devm_kzalloc(dev, sizeof(*tdshp), GFP_KERNEL);
+ if (!tdshp)
+ return -ENOMEM;
+
+ tdshp->regs = devm_platform_ioremap_resource(pdev, 0);
+ if (IS_ERR(tdshp->regs))
+ return dev_err_probe(dev, PTR_ERR(tdshp->regs), "Cannot get reg resource\n");
+
+ tdshp->clk = devm_clk_get(dev, NULL);
+ if (IS_ERR(tdshp->clk))
+ return dev_err_probe(dev, PTR_ERR(tdshp->clk), "Cannot get clocks\n");
+
+#if IS_REACHABLE(CONFIG_MTK_CMDQ)
+ ret = cmdq_dev_get_client_reg(dev, &tdshp->cmdq_reg, 0);
+ if (ret)
+ dev_dbg(dev, "No mediatek,gce-client-reg\n");
+#endif
+ platform_set_drvdata(pdev, tdshp);
+
+ ret = devm_pm_runtime_enable(dev);
+ if (ret)
+ return ret;
+
+ ret = component_add(dev, &mtk_disp_tdshp_component_ops);
+ if (ret)
+ return dev_err_probe(dev, ret, "Failed to add component\n");
+
+ return 0;
+}
+
+static void mtk_disp_tdshp_remove(struct platform_device *pdev)
+{
+ component_del(&pdev->dev, &mtk_disp_tdshp_component_ops);
+}
+
+static const struct of_device_id mtk_disp_tdshp_driver_dt_match[] = {
+ { .compatible = "mediatek,mt8196-disp-tdshp", },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, mtk_disp_tdshp_driver_dt_match);
+
+struct platform_driver mtk_disp_tdshp_driver = {
+ .probe = mtk_disp_tdshp_probe,
+ .remove = mtk_disp_tdshp_remove,
+ .driver = {
+ .name = "mediatek-disp-tdshp",
+ .owner = THIS_MODULE,
+ .of_match_table = mtk_disp_tdshp_driver_dt_match,
+ },
+};
+
+MODULE_AUTHOR("AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>");
+MODULE_DESCRIPTION("MediaTek Display Controller 2D Sharpness Processor Driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/gpu/drm/mediatek/mtk_drm_drv.c b/drivers/gpu/drm/mediatek/mtk_drm_drv.c
index 50b4f79295b3..b96cf2f435e5 100644
--- a/drivers/gpu/drm/mediatek/mtk_drm_drv.c
+++ b/drivers/gpu/drm/mediatek/mtk_drm_drv.c
@@ -699,6 +699,8 @@ static const struct of_device_id mtk_ddp_comp_dt_ids[] = {
.data = (void *)MTK_DISP_RDMA },
{ .compatible = "mediatek,mt8195-disp-rdma",
.data = (void *)MTK_DISP_RDMA },
+ { .compatible = "mediatek,mt8196-disp-tdshp",
+ .data = (void *)MTK_DISP_TDSHP },
{ .compatible = "mediatek,mt8173-disp-ufoe",
.data = (void *)MTK_DISP_UFOE },
{ .compatible = "mediatek,mt6893-disp-wdma",
@@ -1521,6 +1523,7 @@ static struct platform_driver * const mtk_drm_drivers[] = {
&mtk_disp_ovl_adaptor_driver,
&mtk_disp_ovl_driver,
&mtk_disp_rdma_driver,
+ &mtk_disp_tdshp_driver,
&mtk_disp_wdma_driver,
&mtk_dpi_driver,
&mtk_dvo_driver,
diff --git a/drivers/gpu/drm/mediatek/mtk_drm_drv.h b/drivers/gpu/drm/mediatek/mtk_drm_drv.h
index 76325d1be5f4..8bdd7f1017b9 100644
--- a/drivers/gpu/drm/mediatek/mtk_drm_drv.h
+++ b/drivers/gpu/drm/mediatek/mtk_drm_drv.h
@@ -87,6 +87,7 @@ extern struct platform_driver mtk_disp_outproc_driver;
extern struct platform_driver mtk_disp_ovl_adaptor_driver;
extern struct platform_driver mtk_disp_ovl_driver;
extern struct platform_driver mtk_disp_rdma_driver;
+extern struct platform_driver mtk_disp_tdshp_driver;
extern struct platform_driver mtk_disp_wdma_driver;
extern struct platform_driver mtk_dpi_driver;
extern struct platform_driver mtk_dsi_driver;
diff --git a/include/linux/soc/mediatek/mtk-mmsys.h b/include/linux/soc/mediatek/mtk-mmsys.h
index d6742ca39d86..e33cb5b2638c 100644
--- a/include/linux/soc/mediatek/mtk-mmsys.h
+++ b/include/linux/soc/mediatek/mtk-mmsys.h
@@ -109,6 +109,8 @@ enum mtk_ddp_comp_type {
MTK_DISP_POSTMASK,
MTK_DISP_PWM,
MTK_DISP_RDMA,
+ MTK_DISP_RSZ,
+ MTK_DISP_TDSHP,
MTK_DISP_UFOE,
MTK_DISP_WDMA,
--
2.54.0
^ permalink raw reply related
* [PATCH 38/42] dt-bindings: display: mediatek: Introduce MT8196 2D Sharpness Processor
From: AngeloGioacchino Del Regno @ 2026-07-01 12:20 UTC (permalink / raw)
To: chunkuang.hu
Cc: p.zabel, airlied, simona, maarten.lankhorst, mripard, tzimmermann,
robh, krzk+dt, conor+dt, matthias.bgg, angelogioacchino.delregno,
dri-devel, linux-mediatek, devicetree, linux-kernel,
linux-arm-kernel, justin.yeh, jason-jh.lin, kernel
In-Reply-To: <20260701122057.19648-1-angelogioacchino.delregno@collabora.com>
Add documentation for the Two-Dimension Sharpness Processor, or
"TDSHP", found in many MediaTek SoCs including MT8196 and its
variants.
Signed-off-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
---
.../mediatek/mediatek,mt8196-tdshp.yaml | 98 +++++++++++++++++++
1 file changed, 98 insertions(+)
create mode 100644 Documentation/devicetree/bindings/display/mediatek/mediatek,mt8196-tdshp.yaml
diff --git a/Documentation/devicetree/bindings/display/mediatek/mediatek,mt8196-tdshp.yaml b/Documentation/devicetree/bindings/display/mediatek/mediatek,mt8196-tdshp.yaml
new file mode 100644
index 000000000000..7aa176c788fc
--- /dev/null
+++ b/Documentation/devicetree/bindings/display/mediatek/mediatek,mt8196-tdshp.yaml
@@ -0,0 +1,98 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/display/mediatek/mediatek,mt8196-tdshp.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: MediaTek Display Two-Dimension Sharpness Processor (TDSHP)
+
+maintainers:
+ - AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
+
+description:
+ The MediaTek 2D Sharpness Processor (TDSHP) is responsible for performing
+ image sharpness adjustments/enhancements in a display pipeline.
+ This hardware block supports adjusting the luma and contour 2d histograms,
+ frequency weighting, luma-chroma gain and others, with adaptive weights.
+
+properties:
+ compatible:
+ - const: mediatek,mt8196-disp-tdshp
+
+ reg:
+ maxItems: 1
+
+ clocks:
+ maxItems: 1
+
+ power-domains:
+ maxItems: 1
+
+ ports:
+ $ref: /schemas/graph.yaml#/properties/ports
+
+ properties:
+ port@0:
+ $ref: /schemas/graph.yaml#/properties/port
+
+ port@1:
+ $ref: /schemas/graph.yaml#/properties/port
+
+ required:
+ - port@0
+ - port@1
+
+ trigger-sources:
+ maxItems: 1
+
+required:
+ - compatible
+ - reg
+ - clocks
+ - clock-names
+ - ports
+
+additionalProperties: false
+
+examples:
+ - |
+ #include <dt-bindings/interrupt-controller/arm-gic.h>
+ #include <dt-bindings/clock/mediatek,mt8196-clock.h>
+ #include <dt-bindings/power/mediatek,mt8196-power.h>
+
+ tdshp@321e0000 {
+ compatible = "mediatek,mt8196-disp-tdshp";
+ reg = <0x321e0000 0x1000>;
+ clocks = <&dispsys0 CLK_MM_DISP_TDSHP0>;
+ power-domains = <&hpm_hwv MT8196_POWER_DOMAIN_DIS0_DORMANT>;
+ trigger-sources = <&disp0_mutex 53>;
+
+ ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ port@0 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <0>;
+
+ endpoint@0 {
+ reg = <0>;
+ remote-endpoint = <&resizer0_out>;
+ };
+ };
+
+ port@1 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <1>;
+
+ endpoint@0 {
+ reg = <0>;
+ remote-endpoint = <&ccorr0_in>;
+ };
+ };
+ };
+ };
+
+...
--
2.54.0
^ permalink raw reply related
* [PATCH 36/42] drm/mediatek: Support registering disp controller device subnodes
From: AngeloGioacchino Del Regno @ 2026-07-01 12:20 UTC (permalink / raw)
To: chunkuang.hu
Cc: p.zabel, airlied, simona, maarten.lankhorst, mripard, tzimmermann,
robh, krzk+dt, conor+dt, matthias.bgg, angelogioacchino.delregno,
dri-devel, linux-mediatek, devicetree, linux-kernel,
linux-arm-kernel, justin.yeh, jason-jh.lin, kernel
In-Reply-To: <20260701122057.19648-1-angelogioacchino.delregno@collabora.com>
In order to have a correct description of the hardware in the SoC
devicetree, look for Display Controller Subsystem sub-components
declared as subnodes of the display controller itself; to retain
compatibility with the older devicetrees, also keep looking for
sub-components in the main /soc node like before.
Signed-off-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
---
drivers/gpu/drm/mediatek/mtk_drm_drv.c | 218 ++++++++++++++-----------
1 file changed, 121 insertions(+), 97 deletions(-)
diff --git a/drivers/gpu/drm/mediatek/mtk_drm_drv.c b/drivers/gpu/drm/mediatek/mtk_drm_drv.c
index 482d05071125..50b4f79295b3 100644
--- a/drivers/gpu/drm/mediatek/mtk_drm_drv.c
+++ b/drivers/gpu/drm/mediatek/mtk_drm_drv.c
@@ -1237,6 +1237,107 @@ static int mtk_drm_of_ddp_path_build(struct device *dev, struct device_node *nod
return 0;
}
+static int mtk_drm_register_sibling(struct device *dev, struct mtk_drm_private *private,
+ struct device_node *node, struct component_match **match)
+{
+ enum mtk_ddp_comp_type comp_type;
+ int comp_inst_id;
+ bool comp_found;
+ int ret;
+
+ ret = mtk_drm_of_get_ddp_comp_type(node, &comp_type);
+ if (ret)
+ return -EAGAIN;
+
+ ret = of_device_is_available(node);
+ if (!ret) {
+ dev_dbg(dev, "Skipping disabled component %pOF\n", node);
+ return -EAGAIN;
+ }
+
+ if (comp_type == MTK_DISP_MUTEX) {
+ int id;
+
+ id = of_alias_get_id(node, "mutex");
+ if (id < 0 || id == private->data->mmsys_id) {
+ private->mutex_node = of_node_get(node);
+ dev_dbg(dev, "get mutex for mmsys %d", private->data->mmsys_id);
+ }
+ return 0;
+ }
+
+ comp_inst_id = mtk_ddp_comp_get_id(node, NULL, comp_type);
+ if (comp_inst_id < 0) {
+ dev_info(dev, "Skipping unknown component %pOF\n", node);
+ return 0;
+ }
+
+ if (comp_type == MTK_DISP_DIRECT_LINK)
+ comp_found = mtk_drm_find_directlink_comp(private);
+ else
+ comp_found = mtk_drm_find_mmsys_comp(private,
+ comp_type, comp_inst_id);
+
+ if (!comp_found)
+ return -EAGAIN;
+
+ /*
+ * Currently only the AAL, CCORR, COLOR, GAMMA, MERGE, OVL, RDMA, DSI, and DPI
+ * blocks have separate component platform drivers and initialize their own
+ * DDP component structure. The others are initialized here.
+ */
+ if (!mtk_ddp_comp_is_internal_comp(comp_type) &&
+ !mtk_ovl_adaptor_is_comp_present(node)) {
+ dev_info(dev, "Adding component match for %pOF\n",
+ node);
+ drm_of_component_match_add(dev, match, component_compare_of,
+ node);
+ }
+
+ if (comp_type == MTK_DISP_DIRECT_LINK) {
+ for_each_of_graph_port(node, port) {
+ u32 port_id;
+
+ of_property_read_u32(port, "reg", &port_id);
+ if (port_id > 1)
+ continue;
+
+ /* Even ports are inputs, odd ports are outputs */
+ if (port_id % 2)
+ comp_type = MTK_DISP_DIRECT_LINK_OUT;
+
+ for_each_of_graph_port_endpoint(port, ep) {
+ struct of_endpoint of_ep;
+
+ ret = of_graph_parse_endpoint(ep, &of_ep);
+ if (ret)
+ break;
+
+ ret = mtk_ddp_comp_init(dev, node, &private->hlist,
+ private->data->mmsys_id,
+ comp_type, of_ep.id);
+ if (ret)
+ break;
+ }
+
+ if (ret) {
+ of_node_put(node);
+ return ret;
+ }
+ }
+ } else {
+ ret = mtk_ddp_comp_init(dev, node, &private->hlist,
+ private->data->mmsys_id,
+ comp_type, comp_inst_id);
+ if (ret) {
+ of_node_put(node);
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
static int mtk_drm_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
@@ -1298,107 +1399,29 @@ static int mtk_drm_probe(struct platform_device *pdev)
return -ENOMEM;
/* Iterate over sibling DISP function blocks */
- for_each_child_of_node(phandle->parent, node) {
- enum mtk_ddp_comp_type comp_type;
- u8 comp_inst_id;
- bool comp_found;
-
- ret = mtk_drm_of_get_ddp_comp_type(node, &comp_type);
- if (ret)
- continue;
-
- if (!of_device_is_available(node)) {
- dev_dbg(dev, "Skipping disabled component %pOF\n",
- node);
- continue;
- }
-
- if (comp_type == MTK_DISP_MUTEX) {
- int id;
-
- id = of_alias_get_id(node, "mutex");
- if (id < 0 || id == private->data->mmsys_id) {
- private->mutex_node = of_node_get(node);
- dev_dbg(dev, "get mutex for mmsys %d", private->data->mmsys_id);
- }
- continue;
- }
-
- comp_inst_id = mtk_ddp_comp_get_id(node, NULL, comp_type);
- if (comp_inst_id < 0) {
- dev_warn(dev, "Skipping unknown component %pOF\n",
- node);
- continue;
- }
-
- if (comp_type == MTK_DISP_DIRECT_LINK)
- comp_found = mtk_drm_find_directlink_comp(private);
- else
- comp_found = mtk_drm_find_mmsys_comp(private,
- comp_type, comp_inst_id);
-
- if (!comp_found)
- continue;
-
- /*
- * Currently only the AAL, CCORR, COLOR, GAMMA, MERGE, OVL, RDMA, DSI, and DPI
- * blocks have separate component platform drivers and initialize their own
- * DDP component structure. The others are initialized here.
- */
- if (!mtk_ddp_comp_is_internal_comp(comp_type) &&
- !mtk_ovl_adaptor_is_comp_present(node)) {
- dev_info(dev, "Adding component match for %pOF\n",
- node);
- drm_of_component_match_add(dev, &match, component_compare_of,
- node);
- }
-
- if (comp_type == MTK_DISP_DIRECT_LINK) {
- for_each_of_graph_port(node, port) {
- u32 port_id;
-
- of_property_read_u32(port, "reg", &port_id);
- if (port_id > 1)
- continue;
-
- /* Even ports are inputs, odd ports are outputs */
- if (port_id % 2)
- comp_type = MTK_DISP_DIRECT_LINK_OUT;
-
- for_each_of_graph_port_endpoint(port, ep) {
- struct of_endpoint of_ep;
-
- ret = of_graph_parse_endpoint(ep, &of_ep);
- if (ret)
- break;
-
- ret = mtk_ddp_comp_init(dev, node, &private->hlist,
- private->data->mmsys_id,
- comp_type, of_ep.id);
- if (ret)
- break;
- }
+ for_each_child_of_node(phandle, node) {
+ ret = mtk_drm_register_sibling(dev, private, node, &match);
+ if (ret && ret != -EAGAIN)
+ goto err_node;
+ }
- if (ret) {
- of_node_put(node);
- goto err_node;
- }
- }
- } else {
- ret = mtk_ddp_comp_init(dev, node, &private->hlist,
- private->data->mmsys_id,
- comp_type, comp_inst_id);
- if (ret) {
- of_node_put(node);
- goto err_node;
- }
- }
+ /*
+ * After the previous loop, it is expected to have all of the display
+ * controller sibling function blocks registered and added to the list.
+ *
+ * If nothing got registered this is a legacy devicetree with DISP
+ * siblings located under the /soc node instead of being children of
+ * the main Display Controller node.
+ */
+ for_each_child_of_node(phandle->parent, node) {
+ ret = mtk_drm_register_sibling(dev, private, node, &match);
+ if (ret && ret != -EAGAIN)
+ goto err_node;
}
if (!private->mutex_node) {
dev_err(dev, "Failed to find disp-mutex node\n");
- ret = -ENODEV;
- goto err_node;
+ return -ENODEV;
}
/* If mtk-mutex is not a trigger source, this is an old devicetree */
@@ -1425,7 +1448,8 @@ static int mtk_drm_probe(struct platform_device *pdev)
err_pm:
pm_runtime_disable(dev);
err_node:
- of_node_put(private->mutex_node);
+ if (private->mutex_node)
+ of_node_put(private->mutex_node);
return ret;
}
--
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