Copy patches from patches-6.1 to patches-6.6. No changes.
Signed-off-by: Daniel Golle <daniel@makrotopia.org>
--- /dev/null
+From 363547d2191cbc32ca954ba75d72908712398ff2 Mon Sep 17 00:00:00 2001
+From: Andrew Davis <afd@ti.com>
+Date: Mon, 24 Oct 2022 12:34:28 -0500
+Subject: [PATCH] kbuild: Allow DTB overlays to built from .dtso named source
+ files
+
+Currently DTB Overlays (.dtbo) are build from source files with the same
+extension (.dts) as the base DTs (.dtb). This may become confusing and
+even lead to wrong results. For example, a composite DTB (created from a
+base DTB and a set of overlays) might have the same name as one of the
+overlays that create it.
+
+Different files should be generated from differently named sources.
+ .dtb <-> .dts
+ .dtbo <-> .dtso
+
+We do not remove the ability to compile DTBO files from .dts files here,
+only add a new rule allowing the .dtso file name. The current .dts named
+overlays can be renamed with time. After all have been renamed we can
+remove the other rule.
+
+Signed-off-by: Andrew Davis <afd@ti.com>
+Reviewed-by: Geert Uytterhoeven <geert+renesas@glider.be>
+Tested-by: Geert Uytterhoeven <geert+renesas@glider.be>
+Reviewed-by: Frank Rowand <frowand.list@gmail.com>
+Tested-by: Frank Rowand <frowand.list@gmail.com>
+Link: https://lore.kernel.org/r/20221024173434.32518-2-afd@ti.com
+Signed-off-by: Rob Herring <robh@kernel.org>
+---
+ scripts/Makefile.lib | 3 +++
+ 1 file changed, 3 insertions(+)
+
+--- a/scripts/Makefile.lib
++++ b/scripts/Makefile.lib
+@@ -408,6 +408,9 @@ $(obj)/%.dtb: $(src)/%.dts $(DTC) $(DT_T
+ $(obj)/%.dtbo: $(src)/%.dts $(DTC) FORCE
+ $(call if_changed_dep,dtc)
+
++$(obj)/%.dtbo: $(src)/%.dtso $(DTC) FORCE
++ $(call if_changed_dep,dtc)
++
+ dtc-tmp = $(subst $(comma),_,$(dot-target).dts.tmp)
+
+ # Bzip2
--- /dev/null
+From 2c4daed9580164522859fa100128be408cc69be2 Mon Sep 17 00:00:00 2001
+From: Lorenzo Bianconi <lorenzo@kernel.org>
+Date: Sat, 5 Nov 2022 23:36:16 +0100
+Subject: [PATCH 01/19] arm64: dts: mediatek: mt7986: add support for RX
+ Wireless Ethernet Dispatch
+
+Similar to TX Wireless Ethernet Dispatch, introduce RX Wireless Ethernet
+Dispatch to offload traffic received by the wlan interface to lan/wan
+one.
+
+Co-developed-by: Sujuan Chen <sujuan.chen@mediatek.com>
+Signed-off-by: Sujuan Chen <sujuan.chen@mediatek.com>
+Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+---
+ arch/arm64/boot/dts/mediatek/mt7986a.dtsi | 65 +++++++++++++++++++++++
+ 1 file changed, 65 insertions(+)
+
+--- a/arch/arm64/boot/dts/mediatek/mt7986a.dtsi
++++ b/arch/arm64/boot/dts/mediatek/mt7986a.dtsi
+@@ -76,6 +76,47 @@
+ no-map;
+ reg = <0 0x4fc00000 0 0x00100000>;
+ };
++
++ wo_emi0: wo-emi@4fd00000 {
++ reg = <0 0x4fd00000 0 0x40000>;
++ no-map;
++ };
++
++ wo_emi1: wo-emi@4fd40000 {
++ reg = <0 0x4fd40000 0 0x40000>;
++ no-map;
++ };
++
++ wo_ilm0: wo-ilm@151e0000 {
++ reg = <0 0x151e0000 0 0x8000>;
++ no-map;
++ };
++
++ wo_ilm1: wo-ilm@151f0000 {
++ reg = <0 0x151f0000 0 0x8000>;
++ no-map;
++ };
++
++ wo_data: wo-data@4fd80000 {
++ reg = <0 0x4fd80000 0 0x240000>;
++ no-map;
++ };
++
++ wo_dlm0: wo-dlm@151e8000 {
++ reg = <0 0x151e8000 0 0x2000>;
++ no-map;
++ };
++
++ wo_dlm1: wo-dlm@151f8000 {
++ reg = <0 0x151f8000 0 0x2000>;
++ no-map;
++ };
++
++ wo_boot: wo-boot@15194000 {
++ reg = <0 0x15194000 0 0x1000>;
++ no-map;
++ };
++
+ };
+
+ timer {
+@@ -239,6 +280,11 @@
+ reg = <0 0x15010000 0 0x1000>;
+ interrupt-parent = <&gic>;
+ interrupts = <GIC_SPI 205 IRQ_TYPE_LEVEL_HIGH>;
++ memory-region = <&wo_emi0>, <&wo_ilm0>, <&wo_dlm0>,
++ <&wo_data>, <&wo_boot>;
++ memory-region-names = "wo-emi", "wo-ilm", "wo-dlm",
++ "wo-data", "wo-boot";
++ mediatek,wo-ccif = <&wo_ccif0>;
+ };
+
+ wed1: wed@15011000 {
+@@ -247,6 +293,25 @@
+ reg = <0 0x15011000 0 0x1000>;
+ interrupt-parent = <&gic>;
+ interrupts = <GIC_SPI 206 IRQ_TYPE_LEVEL_HIGH>;
++ memory-region = <&wo_emi1>, <&wo_ilm1>, <&wo_dlm1>,
++ <&wo_data>, <&wo_boot>;
++ memory-region-names = "wo-emi", "wo-ilm", "wo-dlm",
++ "wo-data", "wo-boot";
++ mediatek,wo-ccif = <&wo_ccif1>;
++ };
++
++ wo_ccif0: syscon@151a5000 {
++ compatible = "mediatek,mt7986-wo-ccif", "syscon";
++ reg = <0 0x151a5000 0 0x1000>;
++ interrupt-parent = <&gic>;
++ interrupts = <GIC_SPI 211 IRQ_TYPE_LEVEL_HIGH>;
++ };
++
++ wo_ccif1: syscon@151ad000 {
++ compatible = "mediatek,mt7986-wo-ccif", "syscon";
++ reg = <0 0x151ad000 0 0x1000>;
++ interrupt-parent = <&gic>;
++ interrupts = <GIC_SPI 212 IRQ_TYPE_LEVEL_HIGH>;
+ };
+
+ eth: ethernet@15100000 {
--- /dev/null
+From 438e53828c08cf0e8a65b61cf6ce1e4b6620551a Mon Sep 17 00:00:00 2001
+From: Sam Shih <sam.shih@mediatek.com>
+Date: Sun, 6 Nov 2022 09:50:24 +0100
+Subject: [PATCH 02/19] arm64: dts: mt7986: harmonize device node order
+
+This arrange device tree nodes in alphabetical order.
+
+Signed-off-by: Sam Shih <sam.shih@mediatek.com>
+Signed-off-by: Frank Wunderlich <frank-w@public-files.de>
+Reviewed-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
+Link: https://lore.kernel.org/r/20221106085034.12582-2-linux@fw-web.de
+Signed-off-by: Matthias Brugger <matthias.bgg@gmail.com>
+---
+ arch/arm64/boot/dts/mediatek/mt7986a-rfb.dts | 94 ++++++++++----------
+ arch/arm64/boot/dts/mediatek/mt7986b-rfb.dts | 22 ++---
+ 2 files changed, 58 insertions(+), 58 deletions(-)
+
+--- a/arch/arm64/boot/dts/mediatek/mt7986a-rfb.dts
++++ b/arch/arm64/boot/dts/mediatek/mt7986a-rfb.dts
+@@ -54,6 +54,53 @@
+ };
+ };
+
++&pio {
++ uart1_pins: uart1-pins {
++ mux {
++ function = "uart";
++ groups = "uart1";
++ };
++ };
++
++ uart2_pins: uart2-pins {
++ mux {
++ function = "uart";
++ groups = "uart2";
++ };
++ };
++
++ wf_2g_5g_pins: wf-2g-5g-pins {
++ mux {
++ function = "wifi";
++ groups = "wf_2g", "wf_5g";
++ };
++ conf {
++ pins = "WF0_HB1", "WF0_HB2", "WF0_HB3", "WF0_HB4",
++ "WF0_HB0", "WF0_HB0_B", "WF0_HB5", "WF0_HB6",
++ "WF0_HB7", "WF0_HB8", "WF0_HB9", "WF0_HB10",
++ "WF0_TOP_CLK", "WF0_TOP_DATA", "WF1_HB1",
++ "WF1_HB2", "WF1_HB3", "WF1_HB4", "WF1_HB0",
++ "WF1_HB5", "WF1_HB6", "WF1_HB7", "WF1_HB8",
++ "WF1_TOP_CLK", "WF1_TOP_DATA";
++ drive-strength = <4>;
++ };
++ };
++
++ wf_dbdc_pins: wf-dbdc-pins {
++ mux {
++ function = "wifi";
++ groups = "wf_dbdc";
++ };
++ conf {
++ pins = "WF0_HB1", "WF0_HB2", "WF0_HB3", "WF0_HB4",
++ "WF0_HB0", "WF0_HB0_B", "WF0_HB5", "WF0_HB6",
++ "WF0_HB7", "WF0_HB8", "WF0_HB9", "WF0_HB10",
++ "WF0_TOP_CLK", "WF0_TOP_DATA";
++ drive-strength = <4>;
++ };
++ };
++};
++
+ &switch {
+ ports {
+ #address-cells = <1>;
+@@ -121,50 +168,3 @@
+ pinctrl-0 = <&wf_2g_5g_pins>;
+ pinctrl-1 = <&wf_dbdc_pins>;
+ };
+-
+-&pio {
+- uart1_pins: uart1-pins {
+- mux {
+- function = "uart";
+- groups = "uart1";
+- };
+- };
+-
+- uart2_pins: uart2-pins {
+- mux {
+- function = "uart";
+- groups = "uart2";
+- };
+- };
+-
+- wf_2g_5g_pins: wf-2g-5g-pins {
+- mux {
+- function = "wifi";
+- groups = "wf_2g", "wf_5g";
+- };
+- conf {
+- pins = "WF0_HB1", "WF0_HB2", "WF0_HB3", "WF0_HB4",
+- "WF0_HB0", "WF0_HB0_B", "WF0_HB5", "WF0_HB6",
+- "WF0_HB7", "WF0_HB8", "WF0_HB9", "WF0_HB10",
+- "WF0_TOP_CLK", "WF0_TOP_DATA", "WF1_HB1",
+- "WF1_HB2", "WF1_HB3", "WF1_HB4", "WF1_HB0",
+- "WF1_HB5", "WF1_HB6", "WF1_HB7", "WF1_HB8",
+- "WF1_TOP_CLK", "WF1_TOP_DATA";
+- drive-strength = <4>;
+- };
+- };
+-
+- wf_dbdc_pins: wf-dbdc-pins {
+- mux {
+- function = "wifi";
+- groups = "wf_dbdc";
+- };
+- conf {
+- pins = "WF0_HB1", "WF0_HB2", "WF0_HB3", "WF0_HB4",
+- "WF0_HB0", "WF0_HB0_B", "WF0_HB5", "WF0_HB6",
+- "WF0_HB7", "WF0_HB8", "WF0_HB9", "WF0_HB10",
+- "WF0_TOP_CLK", "WF0_TOP_DATA";
+- drive-strength = <4>;
+- };
+- };
+-};
+--- a/arch/arm64/boot/dts/mediatek/mt7986b-rfb.dts
++++ b/arch/arm64/boot/dts/mediatek/mt7986b-rfb.dts
+@@ -25,10 +25,6 @@
+ };
+ };
+
+-&uart0 {
+- status = "okay";
+-};
+-
+ ð {
+ status = "okay";
+
+@@ -99,13 +95,6 @@
+ };
+ };
+
+-&wifi {
+- status = "okay";
+- pinctrl-names = "default", "dbdc";
+- pinctrl-0 = <&wf_2g_5g_pins>;
+- pinctrl-1 = <&wf_dbdc_pins>;
+-};
+-
+ &pio {
+ wf_2g_5g_pins: wf-2g-5g-pins {
+ mux {
+@@ -138,3 +127,14 @@
+ };
+ };
+ };
++
++&uart0 {
++ status = "okay";
++};
++
++&wifi {
++ status = "okay";
++ pinctrl-names = "default", "dbdc";
++ pinctrl-0 = <&wf_2g_5g_pins>;
++ pinctrl-1 = <&wf_dbdc_pins>;
++};
--- /dev/null
+From ffb05357b47f06b2b4d1e14ba89169e28feb727b Mon Sep 17 00:00:00 2001
+From: Sam Shih <sam.shih@mediatek.com>
+Date: Sun, 6 Nov 2022 09:50:27 +0100
+Subject: [PATCH 03/19] arm64: dts: mt7986: add crypto related device nodes
+
+This patch adds crypto engine support for MT7986.
+
+Signed-off-by: Vic Wu <vic.wu@mediatek.com>
+Signed-off-by: Sam Shih <sam.shih@mediatek.com>
+Signed-off-by: Frank Wunderlich <frank-w@public-files.de>
+Link: https://lore.kernel.org/r/20221106085034.12582-5-linux@fw-web.de
+Signed-off-by: Matthias Brugger <matthias.bgg@gmail.com>
+---
+ arch/arm64/boot/dts/mediatek/mt7986a-rfb.dts | 4 ++++
+ arch/arm64/boot/dts/mediatek/mt7986a.dtsi | 15 +++++++++++++++
+ arch/arm64/boot/dts/mediatek/mt7986b-rfb.dts | 4 ++++
+ 3 files changed, 23 insertions(+)
+
+--- a/arch/arm64/boot/dts/mediatek/mt7986a-rfb.dts
++++ b/arch/arm64/boot/dts/mediatek/mt7986a-rfb.dts
+@@ -25,6 +25,10 @@
+ };
+ };
+
++&crypto {
++ status = "okay";
++};
++
+ ð {
+ status = "okay";
+
+--- a/arch/arm64/boot/dts/mediatek/mt7986a.dtsi
++++ b/arch/arm64/boot/dts/mediatek/mt7986a.dtsi
+@@ -223,6 +223,21 @@
+ status = "disabled";
+ };
+
++ crypto: crypto@10320000 {
++ compatible = "inside-secure,safexcel-eip97";
++ reg = <0 0x10320000 0 0x40000>;
++ interrupts = <GIC_SPI 116 IRQ_TYPE_LEVEL_HIGH>,
++ <GIC_SPI 117 IRQ_TYPE_LEVEL_HIGH>,
++ <GIC_SPI 118 IRQ_TYPE_LEVEL_HIGH>,
++ <GIC_SPI 119 IRQ_TYPE_LEVEL_HIGH>;
++ interrupt-names = "ring0", "ring1", "ring2", "ring3";
++ clocks = <&infracfg CLK_INFRA_EIP97_CK>;
++ clock-names = "infra_eip97_ck";
++ assigned-clocks = <&topckgen CLK_TOP_EIP_B_SEL>;
++ assigned-clock-parents = <&apmixedsys CLK_APMIXED_NET2PLL>;
++ status = "disabled";
++ };
++
+ uart0: serial@11002000 {
+ compatible = "mediatek,mt7986-uart",
+ "mediatek,mt6577-uart";
+--- a/arch/arm64/boot/dts/mediatek/mt7986b-rfb.dts
++++ b/arch/arm64/boot/dts/mediatek/mt7986b-rfb.dts
+@@ -25,6 +25,10 @@
+ };
+ };
+
++&crypto {
++ status = "okay";
++};
++
+ ð {
+ status = "okay";
+
--- /dev/null
+From b49b7dc404ded1d89cbc568d875009a5c1ed4ef6 Mon Sep 17 00:00:00 2001
+From: Frank Wunderlich <frank-w@public-files.de>
+Date: Sun, 6 Nov 2022 09:50:29 +0100
+Subject: [PATCH 04/19] arm64: dts: mt7986: add i2c node
+
+Add i2c Node to mt7986 devicetree.
+
+Signed-off-by: Frank Wunderlich <frank-w@public-files.de>
+Link: https://lore.kernel.org/r/20221106085034.12582-7-linux@fw-web.de
+Signed-off-by: Matthias Brugger <matthias.bgg@gmail.com>
+---
+ arch/arm64/boot/dts/mediatek/mt7986a.dtsi | 14 ++++++++++++++
+ 1 file changed, 14 insertions(+)
+
+--- a/arch/arm64/boot/dts/mediatek/mt7986a.dtsi
++++ b/arch/arm64/boot/dts/mediatek/mt7986a.dtsi
+@@ -279,6 +279,20 @@
+ status = "disabled";
+ };
+
++ i2c0: i2c@11008000 {
++ compatible = "mediatek,mt7986-i2c";
++ reg = <0 0x11008000 0 0x90>,
++ <0 0x10217080 0 0x80>;
++ interrupts = <GIC_SPI 136 IRQ_TYPE_LEVEL_HIGH>;
++ clock-div = <5>;
++ clocks = <&infracfg CLK_INFRA_I2C0_CK>,
++ <&infracfg CLK_INFRA_AP_DMA_CK>;
++ clock-names = "main", "dma";
++ #address-cells = <1>;
++ #size-cells = <0>;
++ status = "disabled";
++ };
++
+ ethsys: syscon@15000000 {
+ #address-cells = <1>;
+ #size-cells = <1>;
--- /dev/null
+From 2cd6022800d6da7822e169f3e6f7f790c1431445 Mon Sep 17 00:00:00 2001
+From: Matthias Brugger <mbrugger@suse.com>
+Date: Mon, 14 Nov 2022 13:16:53 +0100
+Subject: [PATCH 05/19] arm64: dts: mediatek: mt7986: Add SoC compatible
+
+Missing SoC compatible in the board file causes dt bindings check.
+
+Signed-off-by: Matthias Brugger <mbrugger@suse.com>
+Link: https://lore.kernel.org/r/20221114121653.14739-1-matthias.bgg@kernel.org
+Signed-off-by: Matthias Brugger <matthias.bgg@gmail.com>
+---
+ arch/arm64/boot/dts/mediatek/mt7986a-rfb.dts | 2 +-
+ arch/arm64/boot/dts/mediatek/mt7986a.dtsi | 1 +
+ arch/arm64/boot/dts/mediatek/mt7986b-rfb.dts | 2 +-
+ arch/arm64/boot/dts/mediatek/mt7986b.dtsi | 3 +++
+ 4 files changed, 6 insertions(+), 2 deletions(-)
+
+--- a/arch/arm64/boot/dts/mediatek/mt7986a-rfb.dts
++++ b/arch/arm64/boot/dts/mediatek/mt7986a-rfb.dts
+@@ -9,7 +9,7 @@
+
+ / {
+ model = "MediaTek MT7986a RFB";
+- compatible = "mediatek,mt7986a-rfb";
++ compatible = "mediatek,mt7986a-rfb", "mediatek,mt7986a";
+
+ aliases {
+ serial0 = &uart0;
+--- a/arch/arm64/boot/dts/mediatek/mt7986a.dtsi
++++ b/arch/arm64/boot/dts/mediatek/mt7986a.dtsi
+@@ -10,6 +10,7 @@
+ #include <dt-bindings/reset/mt7986-resets.h>
+
+ / {
++ compatible = "mediatek,mt7986a";
+ interrupt-parent = <&gic>;
+ #address-cells = <2>;
+ #size-cells = <2>;
+--- a/arch/arm64/boot/dts/mediatek/mt7986b-rfb.dts
++++ b/arch/arm64/boot/dts/mediatek/mt7986b-rfb.dts
+@@ -9,7 +9,7 @@
+
+ / {
+ model = "MediaTek MT7986b RFB";
+- compatible = "mediatek,mt7986b-rfb";
++ compatible = "mediatek,mt7986b-rfb", "mediatek,mt7986b";
+
+ aliases {
+ serial0 = &uart0;
+--- a/arch/arm64/boot/dts/mediatek/mt7986b.dtsi
++++ b/arch/arm64/boot/dts/mediatek/mt7986b.dtsi
+@@ -5,6 +5,9 @@
+ */
+
+ #include "mt7986a.dtsi"
++/ {
++ compatible = "mediatek,mt7986b";
++};
+
+ &pio {
+ compatible = "mediatek,mt7986b-pinctrl";
--- /dev/null
+From f4029538f063a845dc9aae46cce4cf386e6253a5 Mon Sep 17 00:00:00 2001
+From: Sam Shih <sam.shih@mediatek.com>
+Date: Fri, 18 Nov 2022 20:01:21 +0100
+Subject: [PATCH 06/19] arm64: dts: mt7986: add spi related device nodes
+
+This patch adds spi support for MT7986.
+
+Signed-off-by: Sam Shih <sam.shih@mediatek.com>
+Signed-off-by: Frank Wunderlich <frank-w@public-files.de>
+Reviewed-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
+Link: https://lore.kernel.org/r/20221118190126.100895-7-linux@fw-web.de
+Signed-off-by: Matthias Brugger <matthias.bgg@gmail.com>
+---
+ arch/arm64/boot/dts/mediatek/mt7986a-rfb.dts | 35 ++++++++++++++++++++
+ arch/arm64/boot/dts/mediatek/mt7986a.dtsi | 28 ++++++++++++++++
+ arch/arm64/boot/dts/mediatek/mt7986b-rfb.dts | 35 ++++++++++++++++++++
+ 3 files changed, 98 insertions(+)
+
+--- a/arch/arm64/boot/dts/mediatek/mt7986a-rfb.dts
++++ b/arch/arm64/boot/dts/mediatek/mt7986a-rfb.dts
+@@ -59,6 +59,20 @@
+ };
+
+ &pio {
++ spi_flash_pins: spi-flash-pins {
++ mux {
++ function = "spi";
++ groups = "spi0", "spi0_wp_hold";
++ };
++ };
++
++ spic_pins: spic-pins {
++ mux {
++ function = "spi";
++ groups = "spi1_2";
++ };
++ };
++
+ uart1_pins: uart1-pins {
+ mux {
+ function = "uart";
+@@ -105,6 +119,27 @@
+ };
+ };
+
++&spi0 {
++ pinctrl-names = "default";
++ pinctrl-0 = <&spi_flash_pins>;
++ cs-gpios = <0>, <0>;
++ status = "okay";
++ spi_nand: spi_nand@0 {
++ compatible = "spi-nand";
++ reg = <0>;
++ spi-max-frequency = <10000000>;
++ spi-tx-bus-width = <4>;
++ spi-rx-bus-width = <4>;
++ };
++};
++
++&spi1 {
++ pinctrl-names = "default";
++ pinctrl-0 = <&spic_pins>;
++ cs-gpios = <0>, <0>;
++ status = "okay";
++};
++
+ &switch {
+ ports {
+ #address-cells = <1>;
+--- a/arch/arm64/boot/dts/mediatek/mt7986a.dtsi
++++ b/arch/arm64/boot/dts/mediatek/mt7986a.dtsi
+@@ -294,6 +294,34 @@
+ status = "disabled";
+ };
+
++ spi0: spi@1100a000 {
++ compatible = "mediatek,mt7986-spi-ipm", "mediatek,spi-ipm";
++ #address-cells = <1>;
++ #size-cells = <0>;
++ reg = <0 0x1100a000 0 0x100>;
++ interrupts = <GIC_SPI 140 IRQ_TYPE_LEVEL_HIGH>;
++ clocks = <&topckgen CLK_TOP_MPLL_D2>,
++ <&topckgen CLK_TOP_SPI_SEL>,
++ <&infracfg CLK_INFRA_SPI0_CK>,
++ <&infracfg CLK_INFRA_SPI0_HCK_CK>;
++ clock-names = "parent-clk", "sel-clk", "spi-clk", "hclk";
++ status = "disabled";
++ };
++
++ spi1: spi@1100b000 {
++ compatible = "mediatek,mt7986-spi-ipm", "mediatek,spi-ipm";
++ #address-cells = <1>;
++ #size-cells = <0>;
++ reg = <0 0x1100b000 0 0x100>;
++ interrupts = <GIC_SPI 141 IRQ_TYPE_LEVEL_HIGH>;
++ clocks = <&topckgen CLK_TOP_MPLL_D2>,
++ <&topckgen CLK_TOP_SPIM_MST_SEL>,
++ <&infracfg CLK_INFRA_SPI1_CK>,
++ <&infracfg CLK_INFRA_SPI1_HCK_CK>;
++ clock-names = "parent-clk", "sel-clk", "spi-clk", "hclk";
++ status = "disabled";
++ };
++
+ ethsys: syscon@15000000 {
+ #address-cells = <1>;
+ #size-cells = <1>;
+--- a/arch/arm64/boot/dts/mediatek/mt7986b-rfb.dts
++++ b/arch/arm64/boot/dts/mediatek/mt7986b-rfb.dts
+@@ -100,6 +100,20 @@
+ };
+
+ &pio {
++ spi_flash_pins: spi-flash-pins {
++ mux {
++ function = "spi";
++ groups = "spi0", "spi0_wp_hold";
++ };
++ };
++
++ spic_pins: spic-pins {
++ mux {
++ function = "spi";
++ groups = "spi1_2";
++ };
++ };
++
+ wf_2g_5g_pins: wf-2g-5g-pins {
+ mux {
+ function = "wifi";
+@@ -132,6 +146,27 @@
+ };
+ };
+
++&spi0 {
++ pinctrl-names = "default";
++ pinctrl-0 = <&spi_flash_pins>;
++ cs-gpios = <0>, <0>;
++ status = "okay";
++ spi_nand: spi_nand@0 {
++ compatible = "spi-nand";
++ reg = <0>;
++ spi-max-frequency = <10000000>;
++ spi-tx-bus-width = <4>;
++ spi-rx-bus-width = <4>;
++ };
++};
++
++&spi1 {
++ pinctrl-names = "default";
++ pinctrl-0 = <&spic_pins>;
++ cs-gpios = <0>, <0>;
++ status = "okay";
++};
++
+ &uart0 {
+ status = "okay";
+ };
--- /dev/null
+From 9e8e24ab716098e617195ce29b88e84608bf2108 Mon Sep 17 00:00:00 2001
+From: Sam Shih <sam.shih@mediatek.com>
+Date: Fri, 6 Jan 2023 16:28:42 +0100
+Subject: [PATCH 07/19] arm64: dts: mt7986: add usb related device nodes
+
+This patch adds USB support for MT7986.
+
+Signed-off-by: Sam Shih <sam.shih@mediatek.com>
+Signed-off-by: Frank Wunderlich <frank-w@public-files.de>
+Reviewed-by: Chunfeng Yun <chunfeng.yun@mediatek.com>
+Link: https://lore.kernel.org/r/20230106152845.88717-3-linux@fw-web.de
+Signed-off-by: Matthias Brugger <matthias.bgg@gmail.com>
+---
+ arch/arm64/boot/dts/mediatek/mt7986a-rfb.dts | 8 +++
+ arch/arm64/boot/dts/mediatek/mt7986a.dtsi | 55 ++++++++++++++++++++
+ arch/arm64/boot/dts/mediatek/mt7986b-rfb.dts | 8 +++
+ 3 files changed, 71 insertions(+)
+
+--- a/arch/arm64/boot/dts/mediatek/mt7986a-rfb.dts
++++ b/arch/arm64/boot/dts/mediatek/mt7986a-rfb.dts
+@@ -140,6 +140,10 @@
+ status = "okay";
+ };
+
++&ssusb {
++ status = "okay";
++};
++
+ &switch {
+ ports {
+ #address-cells = <1>;
+@@ -201,6 +205,10 @@
+ status = "okay";
+ };
+
++&usb_phy {
++ status = "okay";
++};
++
+ &wifi {
+ status = "okay";
+ pinctrl-names = "default", "dbdc";
+--- a/arch/arm64/boot/dts/mediatek/mt7986a.dtsi
++++ b/arch/arm64/boot/dts/mediatek/mt7986a.dtsi
+@@ -322,6 +322,61 @@
+ status = "disabled";
+ };
+
++ ssusb: usb@11200000 {
++ compatible = "mediatek,mt7986-xhci",
++ "mediatek,mtk-xhci";
++ reg = <0 0x11200000 0 0x2e00>,
++ <0 0x11203e00 0 0x0100>;
++ reg-names = "mac", "ippc";
++ interrupts = <GIC_SPI 173 IRQ_TYPE_LEVEL_HIGH>;
++ clocks = <&infracfg CLK_INFRA_IUSB_SYS_CK>,
++ <&infracfg CLK_INFRA_IUSB_CK>,
++ <&infracfg CLK_INFRA_IUSB_133_CK>,
++ <&infracfg CLK_INFRA_IUSB_66M_CK>,
++ <&topckgen CLK_TOP_U2U3_XHCI_SEL>;
++ clock-names = "sys_ck",
++ "ref_ck",
++ "mcu_ck",
++ "dma_ck",
++ "xhci_ck";
++ phys = <&u2port0 PHY_TYPE_USB2>,
++ <&u3port0 PHY_TYPE_USB3>,
++ <&u2port1 PHY_TYPE_USB2>;
++ status = "disabled";
++ };
++
++ usb_phy: t-phy@11e10000 {
++ compatible = "mediatek,mt7986-tphy",
++ "mediatek,generic-tphy-v2";
++ #address-cells = <1>;
++ #size-cells = <1>;
++ ranges = <0 0 0x11e10000 0x1700>;
++ status = "disabled";
++
++ u2port0: usb-phy@0 {
++ reg = <0x0 0x700>;
++ clocks = <&topckgen CLK_TOP_DA_U2_REFSEL>,
++ <&topckgen CLK_TOP_DA_U2_CK_1P_SEL>;
++ clock-names = "ref", "da_ref";
++ #phy-cells = <1>;
++ };
++
++ u3port0: usb-phy@700 {
++ reg = <0x700 0x900>;
++ clocks = <&topckgen CLK_TOP_USB3_PHY_SEL>;
++ clock-names = "ref";
++ #phy-cells = <1>;
++ };
++
++ u2port1: usb-phy@1000 {
++ reg = <0x1000 0x700>;
++ clocks = <&topckgen CLK_TOP_DA_U2_REFSEL>,
++ <&topckgen CLK_TOP_DA_U2_CK_1P_SEL>;
++ clock-names = "ref", "da_ref";
++ #phy-cells = <1>;
++ };
++ };
++
+ ethsys: syscon@15000000 {
+ #address-cells = <1>;
+ #size-cells = <1>;
+--- a/arch/arm64/boot/dts/mediatek/mt7986b-rfb.dts
++++ b/arch/arm64/boot/dts/mediatek/mt7986b-rfb.dts
+@@ -167,10 +167,18 @@
+ status = "okay";
+ };
+
++&ssusb {
++ status = "okay";
++};
++
+ &uart0 {
+ status = "okay";
+ };
+
++&usb_phy {
++ status = "okay";
++};
++
+ &wifi {
+ status = "okay";
+ pinctrl-names = "default", "dbdc";
--- /dev/null
+From c1744e9e75a6a8abc7c893f349bcbf725b9c0d74 Mon Sep 17 00:00:00 2001
+From: Sam Shih <sam.shih@mediatek.com>
+Date: Fri, 6 Jan 2023 16:28:43 +0100
+Subject: [PATCH 08/19] arm64: dts: mt7986: add mmc related device nodes
+
+This patch adds mmc support for MT7986.
+
+Signed-off-by: Sam Shih <sam.shih@mediatek.com>
+Signed-off-by: Frank Wunderlich <frank-w@public-files.de>
+Link: https://lore.kernel.org/r/20230106152845.88717-4-linux@fw-web.de
+Signed-off-by: Matthias Brugger <matthias.bgg@gmail.com>
+---
+ arch/arm64/boot/dts/mediatek/mt7986a-rfb.dts | 96 ++++++++++++++++++++
+ arch/arm64/boot/dts/mediatek/mt7986a.dtsi | 15 +++
+ 2 files changed, 111 insertions(+)
+
+--- a/arch/arm64/boot/dts/mediatek/mt7986a-rfb.dts
++++ b/arch/arm64/boot/dts/mediatek/mt7986a-rfb.dts
+@@ -5,6 +5,8 @@
+ */
+
+ /dts-v1/;
++#include <dt-bindings/pinctrl/mt65xx.h>
++
+ #include "mt7986a.dtsi"
+
+ / {
+@@ -23,6 +25,24 @@
+ device_type = "memory";
+ reg = <0 0x40000000 0 0x40000000>;
+ };
++
++ reg_1p8v: regulator-1p8v {
++ compatible = "regulator-fixed";
++ regulator-name = "fixed-1.8V";
++ regulator-min-microvolt = <1800000>;
++ regulator-max-microvolt = <1800000>;
++ regulator-boot-on;
++ regulator-always-on;
++ };
++
++ reg_3p3v: regulator-3p3v {
++ compatible = "regulator-fixed";
++ regulator-name = "fixed-3.3V";
++ regulator-min-microvolt = <3300000>;
++ regulator-max-microvolt = <3300000>;
++ regulator-boot-on;
++ regulator-always-on;
++ };
+ };
+
+ &crypto {
+@@ -58,7 +78,83 @@
+ };
+ };
+
++&mmc0 {
++ pinctrl-names = "default", "state_uhs";
++ pinctrl-0 = <&mmc0_pins_default>;
++ pinctrl-1 = <&mmc0_pins_uhs>;
++ bus-width = <8>;
++ max-frequency = <200000000>;
++ cap-mmc-highspeed;
++ mmc-hs200-1_8v;
++ mmc-hs400-1_8v;
++ hs400-ds-delay = <0x14014>;
++ vmmc-supply = <®_3p3v>;
++ vqmmc-supply = <®_1p8v>;
++ non-removable;
++ no-sd;
++ no-sdio;
++ status = "okay";
++};
++
+ &pio {
++ mmc0_pins_default: mmc0-pins {
++ mux {
++ function = "emmc";
++ groups = "emmc_51";
++ };
++ conf-cmd-dat {
++ pins = "EMMC_DATA_0", "EMMC_DATA_1", "EMMC_DATA_2",
++ "EMMC_DATA_3", "EMMC_DATA_4", "EMMC_DATA_5",
++ "EMMC_DATA_6", "EMMC_DATA_7", "EMMC_CMD";
++ input-enable;
++ drive-strength = <4>;
++ bias-pull-up = <MTK_PUPD_SET_R1R0_01>; /* pull-up 10K */
++ };
++ conf-clk {
++ pins = "EMMC_CK";
++ drive-strength = <6>;
++ bias-pull-down = <MTK_PUPD_SET_R1R0_10>; /* pull-down 50K */
++ };
++ conf-ds {
++ pins = "EMMC_DSL";
++ bias-pull-down = <MTK_PUPD_SET_R1R0_10>; /* pull-down 50K */
++ };
++ conf-rst {
++ pins = "EMMC_RSTB";
++ drive-strength = <4>;
++ bias-pull-up = <MTK_PUPD_SET_R1R0_01>; /* pull-up 10K */
++ };
++ };
++
++ mmc0_pins_uhs: mmc0-uhs-pins {
++ mux {
++ function = "emmc";
++ groups = "emmc_51";
++ };
++ conf-cmd-dat {
++ pins = "EMMC_DATA_0", "EMMC_DATA_1", "EMMC_DATA_2",
++ "EMMC_DATA_3", "EMMC_DATA_4", "EMMC_DATA_5",
++ "EMMC_DATA_6", "EMMC_DATA_7", "EMMC_CMD";
++ input-enable;
++ drive-strength = <4>;
++ bias-pull-up = <MTK_PUPD_SET_R1R0_01>; /* pull-up 10K */
++ };
++ conf-clk {
++ pins = "EMMC_CK";
++ drive-strength = <6>;
++ bias-pull-down = <MTK_PUPD_SET_R1R0_10>; /* pull-down 50K */
++ };
++ conf-ds {
++ pins = "EMMC_DSL";
++ bias-pull-down = <MTK_PUPD_SET_R1R0_10>; /* pull-down 50K */
++ };
++ conf-rst {
++ pins = "EMMC_RSTB";
++ drive-strength = <4>;
++ bias-pull-up = <MTK_PUPD_SET_R1R0_01>; /* pull-up 10K */
++ };
++ };
++
+ spi_flash_pins: spi-flash-pins {
+ mux {
+ function = "spi";
+--- a/arch/arm64/boot/dts/mediatek/mt7986a.dtsi
++++ b/arch/arm64/boot/dts/mediatek/mt7986a.dtsi
+@@ -345,6 +345,21 @@
+ status = "disabled";
+ };
+
++ mmc0: mmc@11230000 {
++ compatible = "mediatek,mt7986-mmc";
++ reg = <0 0x11230000 0 0x1000>,
++ <0 0x11c20000 0 0x1000>;
++ interrupts = <GIC_SPI 143 IRQ_TYPE_LEVEL_HIGH>;
++ clocks = <&topckgen CLK_TOP_EMMC_416M_SEL>,
++ <&infracfg CLK_INFRA_MSDC_HCK_CK>,
++ <&infracfg CLK_INFRA_MSDC_CK>,
++ <&infracfg CLK_INFRA_MSDC_133M_CK>,
++ <&infracfg CLK_INFRA_MSDC_66M_CK>;
++ clock-names = "source", "hclk", "source_cg", "bus_clk",
++ "sys_cg";
++ status = "disabled";
++ };
++
+ usb_phy: t-phy@11e10000 {
+ compatible = "mediatek,mt7986-tphy",
+ "mediatek,generic-tphy-v2";
--- /dev/null
+From 87a42ef1d6cf602e4aa40555b4404cad6149a90f Mon Sep 17 00:00:00 2001
+From: Sam Shih <sam.shih@mediatek.com>
+Date: Fri, 6 Jan 2023 16:28:44 +0100
+Subject: [PATCH 09/19] arm64: dts: mt7986: add pcie related device nodes
+
+This patch adds PCIe support for MT7986.
+
+Signed-off-by: Jieyy Yang <jieyy.yang@mediatek.com>
+Signed-off-by: Sam Shih <sam.shih@mediatek.com>
+Signed-off-by: Frank Wunderlich <frank-w@public-files.de>
+Reviewed-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
+Link: https://lore.kernel.org/r/20230106152845.88717-5-linux@fw-web.de
+Signed-off-by: Matthias Brugger <matthias.bgg@gmail.com>
+---
+ arch/arm64/boot/dts/mediatek/mt7986a-rfb.dts | 16 ++++++
+ arch/arm64/boot/dts/mediatek/mt7986a.dtsi | 52 ++++++++++++++++++++
+ 2 files changed, 68 insertions(+)
+
+--- a/arch/arm64/boot/dts/mediatek/mt7986a-rfb.dts
++++ b/arch/arm64/boot/dts/mediatek/mt7986a-rfb.dts
+@@ -93,6 +93,15 @@
+ non-removable;
+ no-sd;
+ no-sdio;
++};
++
++&pcie {
++ pinctrl-names = "default";
++ pinctrl-0 = <&pcie_pins>;
++ status = "okay";
++};
++
++&pcie_phy {
+ status = "okay";
+ };
+
+@@ -155,6 +164,13 @@
+ };
+ };
+
++ pcie_pins: pcie-pins {
++ mux {
++ function = "pcie";
++ groups = "pcie_clk", "pcie_wake", "pcie_pereset";
++ };
++ };
++
+ spi_flash_pins: spi-flash-pins {
+ mux {
+ function = "spi";
+--- a/arch/arm64/boot/dts/mediatek/mt7986a.dtsi
++++ b/arch/arm64/boot/dts/mediatek/mt7986a.dtsi
+@@ -8,6 +8,7 @@
+ #include <dt-bindings/interrupt-controller/arm-gic.h>
+ #include <dt-bindings/clock/mt7986-clk.h>
+ #include <dt-bindings/reset/mt7986-resets.h>
++#include <dt-bindings/phy/phy.h>
+
+ / {
+ compatible = "mediatek,mt7986a";
+@@ -360,6 +361,57 @@
+ status = "disabled";
+ };
+
++ pcie: pcie@11280000 {
++ compatible = "mediatek,mt7986-pcie",
++ "mediatek,mt8192-pcie";
++ device_type = "pci";
++ #address-cells = <3>;
++ #size-cells = <2>;
++ reg = <0x00 0x11280000 0x00 0x4000>;
++ reg-names = "pcie-mac";
++ interrupts = <GIC_SPI 168 IRQ_TYPE_LEVEL_HIGH>;
++ bus-range = <0x00 0xff>;
++ ranges = <0x82000000 0x00 0x20000000 0x00
++ 0x20000000 0x00 0x10000000>;
++ clocks = <&infracfg CLK_INFRA_IPCIE_PIPE_CK>,
++ <&infracfg CLK_INFRA_IPCIE_CK>,
++ <&infracfg CLK_INFRA_IPCIER_CK>,
++ <&infracfg CLK_INFRA_IPCIEB_CK>;
++ clock-names = "pl_250m", "tl_26m", "peri_26m", "top_133m";
++ status = "disabled";
++
++ phys = <&pcie_port PHY_TYPE_PCIE>;
++ phy-names = "pcie-phy";
++
++ #interrupt-cells = <1>;
++ interrupt-map-mask = <0 0 0 0x7>;
++ interrupt-map = <0 0 0 1 &pcie_intc 0>,
++ <0 0 0 2 &pcie_intc 1>,
++ <0 0 0 3 &pcie_intc 2>,
++ <0 0 0 4 &pcie_intc 3>;
++ pcie_intc: interrupt-controller {
++ #address-cells = <0>;
++ #interrupt-cells = <1>;
++ interrupt-controller;
++ };
++ };
++
++ pcie_phy: t-phy@11c00000 {
++ compatible = "mediatek,mt7986-tphy",
++ "mediatek,generic-tphy-v2";
++ #address-cells = <2>;
++ #size-cells = <2>;
++ ranges;
++ status = "disabled";
++
++ pcie_port: pcie-phy@11c00000 {
++ reg = <0 0x11c00000 0 0x20000>;
++ clocks = <&clk40m>;
++ clock-names = "ref";
++ #phy-cells = <1>;
++ };
++ };
++
+ usb_phy: t-phy@11e10000 {
+ compatible = "mediatek,mt7986-tphy",
+ "mediatek,generic-tphy-v2";
--- /dev/null
+From a751f7412e0098801673b80bc7a4738ae7d710ce Mon Sep 17 00:00:00 2001
+From: Frank Wunderlich <frank-w@public-files.de>
+Date: Fri, 6 Jan 2023 16:28:45 +0100
+Subject: [PATCH 10/19] arm64: dts: mt7986: add Bananapi R3
+
+Add support for Bananapi R3 SBC.
+
+- SD/eMMC support (switching first 4 bits of data-bus with sw6/D)
+- SPI-NAND/NOR support (switched CS by sw5/C)
+- all rj45 ports and both SFP working (eth1/lan4)
+- all USB-Ports + SIM-Slot tested
+- i2c and all uarts tested
+- wifi tested (with eeprom calibration data)
+
+The device can boot from all 4 storage options. Both, SPI and MMC, can
+be switched using hardware switches on the board, see
+https://wiki.banana-pi.org/Banana_Pi_BPI-R3#Jumper_setting
+
+Signed-off-by: Frank Wunderlich <frank-w@public-files.de>
+Link: https://lore.kernel.org/r/20230106152845.88717-6-linux@fw-web.de
+Signed-off-by: Matthias Brugger <matthias.bgg@gmail.com>
+---
+ arch/arm64/boot/dts/mediatek/Makefile | 5 +
+ .../mt7986a-bananapi-bpi-r3-emmc.dtso | 29 ++
+ .../mt7986a-bananapi-bpi-r3-nand.dtso | 55 +++
+ .../mediatek/mt7986a-bananapi-bpi-r3-nor.dtso | 68 +++
+ .../mediatek/mt7986a-bananapi-bpi-r3-sd.dtso | 23 +
+ .../dts/mediatek/mt7986a-bananapi-bpi-r3.dts | 450 ++++++++++++++++++
+ 6 files changed, 630 insertions(+)
+ create mode 100644 arch/arm64/boot/dts/mediatek/mt7986a-bananapi-bpi-r3-emmc.dtso
+ create mode 100644 arch/arm64/boot/dts/mediatek/mt7986a-bananapi-bpi-r3-nand.dtso
+ create mode 100644 arch/arm64/boot/dts/mediatek/mt7986a-bananapi-bpi-r3-nor.dtso
+ create mode 100644 arch/arm64/boot/dts/mediatek/mt7986a-bananapi-bpi-r3-sd.dtso
+ create mode 100644 arch/arm64/boot/dts/mediatek/mt7986a-bananapi-bpi-r3.dts
+
+--- a/arch/arm64/boot/dts/mediatek/Makefile
++++ b/arch/arm64/boot/dts/mediatek/Makefile
+@@ -7,6 +7,11 @@ dtb-$(CONFIG_ARCH_MEDIATEK) += mt6797-ev
+ dtb-$(CONFIG_ARCH_MEDIATEK) += mt6797-x20-dev.dtb
+ dtb-$(CONFIG_ARCH_MEDIATEK) += mt7622-rfb1.dtb
+ dtb-$(CONFIG_ARCH_MEDIATEK) += mt7622-bananapi-bpi-r64.dtb
++dtb-$(CONFIG_ARCH_MEDIATEK) += mt7986a-bananapi-bpi-r3.dtb
++dtb-$(CONFIG_ARCH_MEDIATEK) += mt7986a-bananapi-bpi-r3-emmc.dtbo
++dtb-$(CONFIG_ARCH_MEDIATEK) += mt7986a-bananapi-bpi-r3-nand.dtbo
++dtb-$(CONFIG_ARCH_MEDIATEK) += mt7986a-bananapi-bpi-r3-nor.dtbo
++dtb-$(CONFIG_ARCH_MEDIATEK) += mt7986a-bananapi-bpi-r3-sd.dtbo
+ dtb-$(CONFIG_ARCH_MEDIATEK) += mt7986a-rfb.dtb
+ dtb-$(CONFIG_ARCH_MEDIATEK) += mt7986b-rfb.dtb
+ dtb-$(CONFIG_ARCH_MEDIATEK) += mt8167-pumpkin.dtb
+--- /dev/null
++++ b/arch/arm64/boot/dts/mediatek/mt7986a-bananapi-bpi-r3-emmc.dtso
+@@ -0,0 +1,29 @@
++// SPDX-License-Identifier: (GPL-2.0 OR MIT)
++/*
++ * Copyright (C) 2021 MediaTek Inc.
++ * Author: Sam.Shih <sam.shih@mediatek.com>
++ */
++
++/dts-v1/;
++/plugin/;
++
++/ {
++ compatible = "bananapi,bpi-r3", "mediatek,mt7986a";
++
++ fragment@0 {
++ target-path = "/soc/mmc@11230000";
++ __overlay__ {
++ bus-width = <8>;
++ max-frequency = <200000000>;
++ cap-mmc-highspeed;
++ mmc-hs200-1_8v;
++ mmc-hs400-1_8v;
++ hs400-ds-delay = <0x14014>;
++ non-removable;
++ no-sd;
++ no-sdio;
++ status = "okay";
++ };
++ };
++};
++
+--- /dev/null
++++ b/arch/arm64/boot/dts/mediatek/mt7986a-bananapi-bpi-r3-nand.dtso
+@@ -0,0 +1,55 @@
++/* SPDX-License-Identifier: (GPL-2.0-only OR MIT) */
++/*
++ * Authors: Daniel Golle <daniel@makrotopia.org>
++ * Frank Wunderlich <frank-w@public-files.de>
++ */
++
++/dts-v1/;
++/plugin/;
++
++/ {
++ compatible = "bananapi,bpi-r3", "mediatek,mt7986a";
++
++ fragment@0 {
++ target-path = "/soc/spi@1100a000";
++ __overlay__ {
++ #address-cells = <1>;
++ #size-cells = <0>;
++ spi_nand: spi_nand@0 {
++ compatible = "spi-nand";
++ reg = <0>;
++ spi-max-frequency = <10000000>;
++ spi-tx-bus-width = <4>;
++ spi-rx-bus-width = <4>;
++
++ partitions {
++ compatible = "fixed-partitions";
++ #address-cells = <1>;
++ #size-cells = <1>;
++
++ partition@0 {
++ label = "bl2";
++ reg = <0x0 0x80000>;
++ read-only;
++ };
++
++ partition@80000 {
++ label = "reserved";
++ reg = <0x80000 0x300000>;
++ };
++
++ partition@380000 {
++ label = "fip";
++ reg = <0x380000 0x200000>;
++ read-only;
++ };
++
++ partition@580000 {
++ label = "ubi";
++ reg = <0x580000 0x7a80000>;
++ };
++ };
++ };
++ };
++ };
++};
+--- /dev/null
++++ b/arch/arm64/boot/dts/mediatek/mt7986a-bananapi-bpi-r3-nor.dtso
+@@ -0,0 +1,68 @@
++/* SPDX-License-Identifier: (GPL-2.0-only OR MIT) */
++/*
++ * Authors: Daniel Golle <daniel@makrotopia.org>
++ * Frank Wunderlich <frank-w@public-files.de>
++ */
++
++/dts-v1/;
++/plugin/;
++
++/ {
++ compatible = "bananapi,bpi-r3", "mediatek,mt7986a";
++
++ fragment@0 {
++ target-path = "/soc/spi@1100a000";
++ __overlay__ {
++ #address-cells = <1>;
++ #size-cells = <0>;
++ flash@0 {
++ compatible = "jedec,spi-nor";
++ reg = <0>;
++ spi-max-frequency = <10000000>;
++
++ partitions {
++ compatible = "fixed-partitions";
++ #address-cells = <1>;
++ #size-cells = <1>;
++
++ partition@0 {
++ label = "bl2";
++ reg = <0x0 0x20000>;
++ read-only;
++ };
++
++ partition@20000 {
++ label = "reserved";
++ reg = <0x20000 0x20000>;
++ };
++
++ partition@40000 {
++ label = "u-boot-env";
++ reg = <0x40000 0x40000>;
++ };
++
++ partition@80000 {
++ label = "reserved2";
++ reg = <0x80000 0x80000>;
++ };
++
++ partition@100000 {
++ label = "fip";
++ reg = <0x100000 0x80000>;
++ read-only;
++ };
++
++ partition@180000 {
++ label = "recovery";
++ reg = <0x180000 0xa80000>;
++ };
++
++ partition@c00000 {
++ label = "fit";
++ reg = <0xc00000 0x1400000>;
++ };
++ };
++ };
++ };
++ };
++};
+--- /dev/null
++++ b/arch/arm64/boot/dts/mediatek/mt7986a-bananapi-bpi-r3-sd.dtso
+@@ -0,0 +1,23 @@
++// SPDX-License-Identifier: (GPL-2.0 OR MIT)
++/*
++ * Copyright (C) 2021 MediaTek Inc.
++ * Author: Sam.Shih <sam.shih@mediatek.com>
++ */
++
++/dts-v1/;
++/plugin/;
++
++/ {
++ compatible = "bananapi,bpi-r3", "mediatek,mt7986a";
++
++ fragment@0 {
++ target-path = "/soc/mmc@11230000";
++ __overlay__ {
++ bus-width = <4>;
++ max-frequency = <52000000>;
++ cap-sd-highspeed;
++ status = "okay";
++ };
++ };
++};
++
+--- /dev/null
++++ b/arch/arm64/boot/dts/mediatek/mt7986a-bananapi-bpi-r3.dts
+@@ -0,0 +1,450 @@
++// SPDX-License-Identifier: (GPL-2.0 OR MIT)
++/*
++ * Copyright (C) 2021 MediaTek Inc.
++ * Authors: Sam.Shih <sam.shih@mediatek.com>
++ * Frank Wunderlich <frank-w@public-files.de>
++ * Daniel Golle <daniel@makrotopia.org>
++ */
++
++/dts-v1/;
++#include <dt-bindings/gpio/gpio.h>
++#include <dt-bindings/input/input.h>
++#include <dt-bindings/leds/common.h>
++#include <dt-bindings/pinctrl/mt65xx.h>
++
++#include "mt7986a.dtsi"
++
++/ {
++ model = "Bananapi BPI-R3";
++ compatible = "bananapi,bpi-r3", "mediatek,mt7986a";
++
++ aliases {
++ serial0 = &uart0;
++ ethernet0 = &gmac0;
++ ethernet1 = &gmac1;
++ };
++
++ chosen {
++ stdout-path = "serial0:115200n8";
++ };
++
++ dcin: regulator-12vd {
++ compatible = "regulator-fixed";
++ regulator-name = "12vd";
++ regulator-min-microvolt = <12000000>;
++ regulator-max-microvolt = <12000000>;
++ regulator-boot-on;
++ regulator-always-on;
++ };
++
++ gpio-keys {
++ compatible = "gpio-keys";
++
++ reset-key {
++ label = "reset";
++ linux,code = <KEY_RESTART>;
++ gpios = <&pio 9 GPIO_ACTIVE_LOW>;
++ };
++
++ wps-key {
++ label = "wps";
++ linux,code = <KEY_WPS_BUTTON>;
++ gpios = <&pio 10 GPIO_ACTIVE_LOW>;
++ };
++ };
++
++ /* i2c of the left SFP cage (wan) */
++ i2c_sfp1: i2c-gpio-0 {
++ compatible = "i2c-gpio";
++ sda-gpios = <&pio 16 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>;
++ scl-gpios = <&pio 17 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>;
++ i2c-gpio,delay-us = <2>;
++ #address-cells = <1>;
++ #size-cells = <0>;
++ };
++
++ /* i2c of the right SFP cage (lan) */
++ i2c_sfp2: i2c-gpio-1 {
++ compatible = "i2c-gpio";
++ sda-gpios = <&pio 18 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>;
++ scl-gpios = <&pio 19 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>;
++ i2c-gpio,delay-us = <2>;
++ #address-cells = <1>;
++ #size-cells = <0>;
++ };
++
++ leds {
++ compatible = "gpio-leds";
++
++ green_led: led-0 {
++ color = <LED_COLOR_ID_GREEN>;
++ function = LED_FUNCTION_POWER;
++ gpios = <&pio 69 GPIO_ACTIVE_HIGH>;
++ default-state = "on";
++ };
++
++ blue_led: led-1 {
++ color = <LED_COLOR_ID_BLUE>;
++ function = LED_FUNCTION_STATUS;
++ gpios = <&pio 86 GPIO_ACTIVE_HIGH>;
++ default-state = "off";
++ };
++ };
++
++ reg_1p8v: regulator-1p8v {
++ compatible = "regulator-fixed";
++ regulator-name = "1.8vd";
++ regulator-min-microvolt = <1800000>;
++ regulator-max-microvolt = <1800000>;
++ regulator-boot-on;
++ regulator-always-on;
++ vin-supply = <&dcin>;
++ };
++
++ reg_3p3v: regulator-3p3v {
++ compatible = "regulator-fixed";
++ regulator-name = "3.3vd";
++ regulator-min-microvolt = <3300000>;
++ regulator-max-microvolt = <3300000>;
++ regulator-boot-on;
++ regulator-always-on;
++ vin-supply = <&dcin>;
++ };
++
++ /* left SFP cage (wan) */
++ sfp1: sfp-1 {
++ compatible = "sff,sfp";
++ i2c-bus = <&i2c_sfp1>;
++ los-gpios = <&pio 46 GPIO_ACTIVE_HIGH>;
++ mod-def0-gpios = <&pio 49 GPIO_ACTIVE_LOW>;
++ tx-disable-gpios = <&pio 20 GPIO_ACTIVE_HIGH>;
++ tx-fault-gpios = <&pio 7 GPIO_ACTIVE_HIGH>;
++ };
++
++ /* right SFP cage (lan) */
++ sfp2: sfp-2 {
++ compatible = "sff,sfp";
++ i2c-bus = <&i2c_sfp2>;
++ los-gpios = <&pio 31 GPIO_ACTIVE_HIGH>;
++ mod-def0-gpios = <&pio 47 GPIO_ACTIVE_LOW>;
++ tx-disable-gpios = <&pio 15 GPIO_ACTIVE_HIGH>;
++ tx-fault-gpios = <&pio 48 GPIO_ACTIVE_HIGH>;
++ };
++};
++
++&crypto {
++ status = "okay";
++};
++
++ð {
++ status = "okay";
++
++ gmac0: mac@0 {
++ compatible = "mediatek,eth-mac";
++ reg = <0>;
++ phy-mode = "2500base-x";
++
++ fixed-link {
++ speed = <2500>;
++ full-duplex;
++ pause;
++ };
++ };
++
++ gmac1: mac@1 {
++ compatible = "mediatek,eth-mac";
++ reg = <1>;
++ phy-mode = "2500base-x";
++ sfp = <&sfp1>;
++ managed = "in-band-status";
++ };
++
++ mdio: mdio-bus {
++ #address-cells = <1>;
++ #size-cells = <0>;
++ };
++};
++
++&mdio {
++ switch: switch@1f {
++ compatible = "mediatek,mt7531";
++ reg = <31>;
++ interrupt-controller;
++ #interrupt-cells = <1>;
++ interrupt-parent = <&pio>;
++ interrupts = <66 IRQ_TYPE_LEVEL_HIGH>;
++ reset-gpios = <&pio 5 GPIO_ACTIVE_HIGH>;
++ };
++};
++
++&mmc0 {
++ pinctrl-names = "default", "state_uhs";
++ pinctrl-0 = <&mmc0_pins_default>;
++ pinctrl-1 = <&mmc0_pins_uhs>;
++ vmmc-supply = <®_3p3v>;
++ vqmmc-supply = <®_1p8v>;
++};
++
++&i2c0 {
++ pinctrl-names = "default";
++ pinctrl-0 = <&i2c_pins>;
++ status = "okay";
++};
++
++&pcie {
++ pinctrl-names = "default";
++ pinctrl-0 = <&pcie_pins>;
++ status = "okay";
++};
++
++&pcie_phy {
++ status = "okay";
++};
++
++&pio {
++ i2c_pins: i2c-pins {
++ mux {
++ function = "i2c";
++ groups = "i2c";
++ };
++ };
++
++ mmc0_pins_default: mmc0-pins {
++ mux {
++ function = "emmc";
++ groups = "emmc_51";
++ };
++ conf-cmd-dat {
++ pins = "EMMC_DATA_0", "EMMC_DATA_1", "EMMC_DATA_2",
++ "EMMC_DATA_3", "EMMC_DATA_4", "EMMC_DATA_5",
++ "EMMC_DATA_6", "EMMC_DATA_7", "EMMC_CMD";
++ input-enable;
++ drive-strength = <4>;
++ bias-pull-up = <MTK_PUPD_SET_R1R0_01>; /* pull-up 10K */
++ };
++ conf-clk {
++ pins = "EMMC_CK";
++ drive-strength = <6>;
++ bias-pull-down = <MTK_PUPD_SET_R1R0_10>; /* pull-down 50K */
++ };
++ conf-ds {
++ pins = "EMMC_DSL";
++ bias-pull-down = <MTK_PUPD_SET_R1R0_10>; /* pull-down 50K */
++ };
++ conf-rst {
++ pins = "EMMC_RSTB";
++ drive-strength = <4>;
++ bias-pull-up = <MTK_PUPD_SET_R1R0_01>; /* pull-up 10K */
++ };
++ };
++
++ mmc0_pins_uhs: mmc0-uhs-pins {
++ mux {
++ function = "emmc";
++ groups = "emmc_51";
++ };
++ conf-cmd-dat {
++ pins = "EMMC_DATA_0", "EMMC_DATA_1", "EMMC_DATA_2",
++ "EMMC_DATA_3", "EMMC_DATA_4", "EMMC_DATA_5",
++ "EMMC_DATA_6", "EMMC_DATA_7", "EMMC_CMD";
++ input-enable;
++ drive-strength = <4>;
++ bias-pull-up = <MTK_PUPD_SET_R1R0_01>; /* pull-up 10K */
++ };
++ conf-clk {
++ pins = "EMMC_CK";
++ drive-strength = <6>;
++ bias-pull-down = <MTK_PUPD_SET_R1R0_10>; /* pull-down 50K */
++ };
++ conf-ds {
++ pins = "EMMC_DSL";
++ bias-pull-down = <MTK_PUPD_SET_R1R0_10>; /* pull-down 50K */
++ };
++ conf-rst {
++ pins = "EMMC_RSTB";
++ drive-strength = <4>;
++ bias-pull-up = <MTK_PUPD_SET_R1R0_01>; /* pull-up 10K */
++ };
++ };
++
++ pcie_pins: pcie-pins {
++ mux {
++ function = "pcie";
++ groups = "pcie_clk", "pcie_pereset";
++ };
++ };
++
++ spi_flash_pins: spi-flash-pins {
++ mux {
++ function = "spi";
++ groups = "spi0", "spi0_wp_hold";
++ };
++ };
++
++ spic_pins: spic-pins {
++ mux {
++ function = "spi";
++ groups = "spi1_0";
++ };
++ };
++
++ uart1_pins: uart1-pins {
++ mux {
++ function = "uart";
++ groups = "uart1_rx_tx";
++ };
++ };
++
++ uart2_pins: uart2-pins {
++ mux {
++ function = "uart";
++ groups = "uart2_0_rx_tx";
++ };
++ };
++
++ wf_2g_5g_pins: wf-2g-5g-pins {
++ mux {
++ function = "wifi";
++ groups = "wf_2g", "wf_5g";
++ };
++ conf {
++ pins = "WF0_HB1", "WF0_HB2", "WF0_HB3", "WF0_HB4",
++ "WF0_HB0", "WF0_HB0_B", "WF0_HB5", "WF0_HB6",
++ "WF0_HB7", "WF0_HB8", "WF0_HB9", "WF0_HB10",
++ "WF0_TOP_CLK", "WF0_TOP_DATA", "WF1_HB1",
++ "WF1_HB2", "WF1_HB3", "WF1_HB4", "WF1_HB0",
++ "WF1_HB5", "WF1_HB6", "WF1_HB7", "WF1_HB8",
++ "WF1_TOP_CLK", "WF1_TOP_DATA";
++ drive-strength = <4>;
++ };
++ };
++
++ wf_dbdc_pins: wf-dbdc-pins {
++ mux {
++ function = "wifi";
++ groups = "wf_dbdc";
++ };
++ conf {
++ pins = "WF0_HB1", "WF0_HB2", "WF0_HB3", "WF0_HB4",
++ "WF0_HB0", "WF0_HB0_B", "WF0_HB5", "WF0_HB6",
++ "WF0_HB7", "WF0_HB8", "WF0_HB9", "WF0_HB10",
++ "WF0_TOP_CLK", "WF0_TOP_DATA", "WF1_HB1",
++ "WF1_HB2", "WF1_HB3", "WF1_HB4", "WF1_HB0",
++ "WF1_HB5", "WF1_HB6", "WF1_HB7", "WF1_HB8",
++ "WF1_TOP_CLK", "WF1_TOP_DATA";
++ drive-strength = <4>;
++ };
++ };
++
++ wf_led_pins: wf-led-pins {
++ mux {
++ function = "led";
++ groups = "wifi_led";
++ };
++ };
++};
++
++&spi0 {
++ pinctrl-names = "default";
++ pinctrl-0 = <&spi_flash_pins>;
++ status = "okay";
++};
++
++&spi1 {
++ pinctrl-names = "default";
++ pinctrl-0 = <&spic_pins>;
++ status = "okay";
++};
++
++&ssusb {
++ status = "okay";
++};
++
++&switch {
++ ports {
++ #address-cells = <1>;
++ #size-cells = <0>;
++
++ port@0 {
++ reg = <0>;
++ label = "wan";
++ };
++
++ port@1 {
++ reg = <1>;
++ label = "lan0";
++ };
++
++ port@2 {
++ reg = <2>;
++ label = "lan1";
++ };
++
++ port@3 {
++ reg = <3>;
++ label = "lan2";
++ };
++
++ port@4 {
++ reg = <4>;
++ label = "lan3";
++ };
++
++ port5: port@5 {
++ reg = <5>;
++ label = "lan4";
++ phy-mode = "2500base-x";
++ sfp = <&sfp2>;
++ managed = "in-band-status";
++ };
++
++ port@6 {
++ reg = <6>;
++ label = "cpu";
++ ethernet = <&gmac0>;
++ phy-mode = "2500base-x";
++
++ fixed-link {
++ speed = <2500>;
++ full-duplex;
++ pause;
++ };
++ };
++ };
++};
++
++&trng {
++ status = "okay";
++};
++
++&uart0 {
++ status = "okay";
++};
++
++&uart1 {
++ pinctrl-names = "default";
++ pinctrl-0 = <&uart1_pins>;
++ status = "okay";
++};
++
++&uart2 {
++ pinctrl-names = "default";
++ pinctrl-0 = <&uart2_pins>;
++ status = "okay";
++};
++
++&usb_phy {
++ status = "okay";
++};
++
++&watchdog {
++ status = "okay";
++};
++
++&wifi {
++ status = "okay";
++ pinctrl-names = "default", "dbdc";
++ pinctrl-0 = <&wf_2g_5g_pins>, <&wf_led_pins>;
++ pinctrl-1 = <&wf_dbdc_pins>, <&wf_led_pins>;
++};
++
--- /dev/null
+From 4c2d5411f4b101f7aa0fd74f80109e3afd6dc967 Mon Sep 17 00:00:00 2001
+From: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
+Date: Wed, 17 May 2023 12:11:08 +0200
+Subject: [PATCH 11/19] arm64: mediatek: Propagate chassis-type where possible
+
+The chassis-type string identifies the form-factor of the system:
+add this property to all device trees of devices for which the form
+factor is known.
+
+Signed-off-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
+Link: https://lore.kernel.org/r/20230517101108.205654-1-angelogioacchino.delregno@collabora.com
+Signed-off-by: Matthias Brugger <matthias.bgg@gmail.com>
+---
+ arch/arm64/boot/dts/mediatek/mt2712-evb.dts | 1 +
+ arch/arm64/boot/dts/mediatek/mt6755-evb.dts | 1 +
+ arch/arm64/boot/dts/mediatek/mt6779-evb.dts | 1 +
+ arch/arm64/boot/dts/mediatek/mt6795-evb.dts | 1 +
+ arch/arm64/boot/dts/mediatek/mt6797-evb.dts | 1 +
+ arch/arm64/boot/dts/mediatek/mt6797-x20-dev.dts | 1 +
+ arch/arm64/boot/dts/mediatek/mt7622-bananapi-bpi-r64.dts | 1 +
+ arch/arm64/boot/dts/mediatek/mt7622-rfb1.dts | 1 +
+ arch/arm64/boot/dts/mediatek/mt7986a-bananapi-bpi-r3.dts | 1 +
+ arch/arm64/boot/dts/mediatek/mt7986a-rfb.dts | 1 +
+ arch/arm64/boot/dts/mediatek/mt7986b-rfb.dts | 1 +
+ arch/arm64/boot/dts/mediatek/mt8167-pumpkin.dts | 1 +
+ arch/arm64/boot/dts/mediatek/mt8173-elm-hana-rev7.dts | 1 +
+ arch/arm64/boot/dts/mediatek/mt8173-elm-hana.dts | 1 +
+ arch/arm64/boot/dts/mediatek/mt8173-elm.dts | 1 +
+ arch/arm64/boot/dts/mediatek/mt8173-evb.dts | 1 +
+ arch/arm64/boot/dts/mediatek/mt8183-evb.dts | 1 +
+ arch/arm64/boot/dts/mediatek/mt8183-kukui-jacuzzi-burnet.dts | 1 +
+ arch/arm64/boot/dts/mediatek/mt8183-kukui-jacuzzi-damu.dts | 1 +
+ .../boot/dts/mediatek/mt8183-kukui-jacuzzi-juniper-sku16.dts | 1 +
+ arch/arm64/boot/dts/mediatek/mt8183-kukui-kakadu-sku22.dts | 1 +
+ arch/arm64/boot/dts/mediatek/mt8183-kukui-kakadu.dts | 1 +
+ arch/arm64/boot/dts/mediatek/mt8183-kukui-kodama-sku16.dts | 1 +
+ arch/arm64/boot/dts/mediatek/mt8183-kukui-kodama-sku272.dts | 1 +
+ arch/arm64/boot/dts/mediatek/mt8183-kukui-kodama-sku288.dts | 1 +
+ arch/arm64/boot/dts/mediatek/mt8183-kukui-krane-sku0.dts | 1 +
+ arch/arm64/boot/dts/mediatek/mt8183-kukui-krane-sku176.dts | 1 +
+ arch/arm64/boot/dts/mediatek/mt8186-evb.dts | 1 +
+ 28 files changed, 28 insertions(+)
+
+--- a/arch/arm64/boot/dts/mediatek/mt2712-evb.dts
++++ b/arch/arm64/boot/dts/mediatek/mt2712-evb.dts
+@@ -11,6 +11,7 @@
+
+ / {
+ model = "MediaTek MT2712 evaluation board";
++ chassis-type = "embedded";
+ compatible = "mediatek,mt2712-evb", "mediatek,mt2712";
+
+ aliases {
+--- a/arch/arm64/boot/dts/mediatek/mt6755-evb.dts
++++ b/arch/arm64/boot/dts/mediatek/mt6755-evb.dts
+@@ -9,6 +9,7 @@
+
+ / {
+ model = "MediaTek MT6755 EVB";
++ chassis-type = "embedded";
+ compatible = "mediatek,mt6755-evb", "mediatek,mt6755";
+
+ aliases {
+--- a/arch/arm64/boot/dts/mediatek/mt6779-evb.dts
++++ b/arch/arm64/boot/dts/mediatek/mt6779-evb.dts
+@@ -10,6 +10,7 @@
+
+ / {
+ model = "MediaTek MT6779 EVB";
++ chassis-type = "embedded";
+ compatible = "mediatek,mt6779-evb", "mediatek,mt6779";
+
+ aliases {
+--- a/arch/arm64/boot/dts/mediatek/mt6795-evb.dts
++++ b/arch/arm64/boot/dts/mediatek/mt6795-evb.dts
+@@ -9,6 +9,7 @@
+
+ / {
+ model = "MediaTek MT6795 Evaluation Board";
++ chassis-type = "embedded";
+ compatible = "mediatek,mt6795-evb", "mediatek,mt6795";
+
+ aliases {
+--- a/arch/arm64/boot/dts/mediatek/mt6797-evb.dts
++++ b/arch/arm64/boot/dts/mediatek/mt6797-evb.dts
+@@ -9,6 +9,7 @@
+
+ / {
+ model = "MediaTek MT6797 Evaluation Board";
++ chassis-type = "embedded";
+ compatible = "mediatek,mt6797-evb", "mediatek,mt6797";
+
+ aliases {
+--- a/arch/arm64/boot/dts/mediatek/mt6797-x20-dev.dts
++++ b/arch/arm64/boot/dts/mediatek/mt6797-x20-dev.dts
+@@ -12,6 +12,7 @@
+
+ / {
+ model = "Mediatek X20 Development Board";
++ chassis-type = "embedded";
+ compatible = "archermind,mt6797-x20-dev", "mediatek,mt6797";
+
+ aliases {
+--- a/arch/arm64/boot/dts/mediatek/mt7622-bananapi-bpi-r64.dts
++++ b/arch/arm64/boot/dts/mediatek/mt7622-bananapi-bpi-r64.dts
+@@ -15,6 +15,7 @@
+
+ / {
+ model = "Bananapi BPI-R64";
++ chassis-type = "embedded";
+ compatible = "bananapi,bpi-r64", "mediatek,mt7622";
+
+ aliases {
+--- a/arch/arm64/boot/dts/mediatek/mt7622-rfb1.dts
++++ b/arch/arm64/boot/dts/mediatek/mt7622-rfb1.dts
+@@ -15,6 +15,7 @@
+
+ / {
+ model = "MediaTek MT7622 RFB1 board";
++ chassis-type = "embedded";
+ compatible = "mediatek,mt7622-rfb1", "mediatek,mt7622";
+
+ aliases {
+--- a/arch/arm64/boot/dts/mediatek/mt7986a-bananapi-bpi-r3.dts
++++ b/arch/arm64/boot/dts/mediatek/mt7986a-bananapi-bpi-r3.dts
+@@ -16,6 +16,7 @@
+
+ / {
+ model = "Bananapi BPI-R3";
++ chassis-type = "embedded";
+ compatible = "bananapi,bpi-r3", "mediatek,mt7986a";
+
+ aliases {
+--- a/arch/arm64/boot/dts/mediatek/mt7986a-rfb.dts
++++ b/arch/arm64/boot/dts/mediatek/mt7986a-rfb.dts
+@@ -11,6 +11,7 @@
+
+ / {
+ model = "MediaTek MT7986a RFB";
++ chassis-type = "embedded";
+ compatible = "mediatek,mt7986a-rfb", "mediatek,mt7986a";
+
+ aliases {
+--- a/arch/arm64/boot/dts/mediatek/mt7986b-rfb.dts
++++ b/arch/arm64/boot/dts/mediatek/mt7986b-rfb.dts
+@@ -9,6 +9,7 @@
+
+ / {
+ model = "MediaTek MT7986b RFB";
++ chassis-type = "embedded";
+ compatible = "mediatek,mt7986b-rfb", "mediatek,mt7986b";
+
+ aliases {
+--- a/arch/arm64/boot/dts/mediatek/mt8167-pumpkin.dts
++++ b/arch/arm64/boot/dts/mediatek/mt8167-pumpkin.dts
+@@ -11,6 +11,7 @@
+
+ / {
+ model = "Pumpkin MT8167";
++ chassis-type = "embedded";
+ compatible = "mediatek,mt8167-pumpkin", "mediatek,mt8167";
+
+ memory@40000000 {
+--- a/arch/arm64/boot/dts/mediatek/mt8173-elm-hana-rev7.dts
++++ b/arch/arm64/boot/dts/mediatek/mt8173-elm-hana-rev7.dts
+@@ -8,6 +8,7 @@
+
+ / {
+ model = "Google Hanawl";
++ chassis-type = "laptop";
+ compatible = "google,hana-rev7", "mediatek,mt8173";
+ };
+
+--- a/arch/arm64/boot/dts/mediatek/mt8173-elm-hana.dts
++++ b/arch/arm64/boot/dts/mediatek/mt8173-elm-hana.dts
+@@ -8,6 +8,7 @@
+
+ / {
+ model = "Google Hana";
++ chassis-type = "laptop";
+ compatible = "google,hana-rev6", "google,hana-rev5",
+ "google,hana-rev4", "google,hana-rev3",
+ "google,hana", "mediatek,mt8173";
+--- a/arch/arm64/boot/dts/mediatek/mt8173-elm.dts
++++ b/arch/arm64/boot/dts/mediatek/mt8173-elm.dts
+@@ -8,6 +8,7 @@
+
+ / {
+ model = "Google Elm";
++ chassis-type = "laptop";
+ compatible = "google,elm-rev8", "google,elm-rev7", "google,elm-rev6",
+ "google,elm-rev5", "google,elm-rev4", "google,elm-rev3",
+ "google,elm", "mediatek,mt8173";
+--- a/arch/arm64/boot/dts/mediatek/mt8173-evb.dts
++++ b/arch/arm64/boot/dts/mediatek/mt8173-evb.dts
+@@ -10,6 +10,7 @@
+
+ / {
+ model = "MediaTek MT8173 evaluation board";
++ chassis-type = "embedded";
+ compatible = "mediatek,mt8173-evb", "mediatek,mt8173";
+
+ aliases {
+--- a/arch/arm64/boot/dts/mediatek/mt8183-evb.dts
++++ b/arch/arm64/boot/dts/mediatek/mt8183-evb.dts
+@@ -11,6 +11,7 @@
+
+ / {
+ model = "MediaTek MT8183 evaluation board";
++ chassis-type = "embedded";
+ compatible = "mediatek,mt8183-evb", "mediatek,mt8183";
+
+ aliases {
+--- a/arch/arm64/boot/dts/mediatek/mt8183-kukui-jacuzzi-burnet.dts
++++ b/arch/arm64/boot/dts/mediatek/mt8183-kukui-jacuzzi-burnet.dts
+@@ -9,6 +9,7 @@
+
+ / {
+ model = "Google burnet board";
++ chassis-type = "convertible";
+ compatible = "google,burnet", "mediatek,mt8183";
+ };
+
+--- a/arch/arm64/boot/dts/mediatek/mt8183-kukui-jacuzzi-damu.dts
++++ b/arch/arm64/boot/dts/mediatek/mt8183-kukui-jacuzzi-damu.dts
+@@ -9,6 +9,7 @@
+
+ / {
+ model = "Google damu board";
++ chassis-type = "convertible";
+ compatible = "google,damu", "mediatek,mt8183";
+ };
+
+--- a/arch/arm64/boot/dts/mediatek/mt8183-kukui-jacuzzi-juniper-sku16.dts
++++ b/arch/arm64/boot/dts/mediatek/mt8183-kukui-jacuzzi-juniper-sku16.dts
+@@ -9,6 +9,7 @@
+
+ / {
+ model = "Google juniper sku16 board";
++ chassis-type = "convertible";
+ compatible = "google,juniper-sku16", "google,juniper", "mediatek,mt8183";
+ };
+
+--- a/arch/arm64/boot/dts/mediatek/mt8183-kukui-kakadu-sku22.dts
++++ b/arch/arm64/boot/dts/mediatek/mt8183-kukui-kakadu-sku22.dts
+@@ -9,6 +9,7 @@
+
+ / {
+ model = "MediaTek kakadu board sku22";
++ chassis-type = "tablet";
+ compatible = "google,kakadu-rev3-sku22", "google,kakadu-rev2-sku22",
+ "google,kakadu", "mediatek,mt8183";
+ };
+--- a/arch/arm64/boot/dts/mediatek/mt8183-kukui-kakadu.dts
++++ b/arch/arm64/boot/dts/mediatek/mt8183-kukui-kakadu.dts
+@@ -9,6 +9,7 @@
+
+ / {
+ model = "MediaTek kakadu board";
++ chassis-type = "tablet";
+ compatible = "google,kakadu-rev3", "google,kakadu-rev2",
+ "google,kakadu", "mediatek,mt8183";
+ };
+--- a/arch/arm64/boot/dts/mediatek/mt8183-kukui-kodama-sku16.dts
++++ b/arch/arm64/boot/dts/mediatek/mt8183-kukui-kodama-sku16.dts
+@@ -12,6 +12,7 @@
+
+ / {
+ model = "MediaTek kodama sku16 board";
++ chassis-type = "tablet";
+ compatible = "google,kodama-sku16", "google,kodama", "mediatek,mt8183";
+ };
+
+--- a/arch/arm64/boot/dts/mediatek/mt8183-kukui-kodama-sku272.dts
++++ b/arch/arm64/boot/dts/mediatek/mt8183-kukui-kodama-sku272.dts
+@@ -12,6 +12,7 @@
+
+ / {
+ model = "MediaTek kodama sku272 board";
++ chassis-type = "tablet";
+ compatible = "google,kodama-sku272", "google,kodama", "mediatek,mt8183";
+ };
+
+--- a/arch/arm64/boot/dts/mediatek/mt8183-kukui-kodama-sku288.dts
++++ b/arch/arm64/boot/dts/mediatek/mt8183-kukui-kodama-sku288.dts
+@@ -12,6 +12,7 @@
+
+ / {
+ model = "MediaTek kodama sku288 board";
++ chassis-type = "tablet";
+ compatible = "google,kodama-sku288", "google,kodama", "mediatek,mt8183";
+ };
+
+--- a/arch/arm64/boot/dts/mediatek/mt8183-kukui-krane-sku0.dts
++++ b/arch/arm64/boot/dts/mediatek/mt8183-kukui-krane-sku0.dts
+@@ -14,6 +14,7 @@
+
+ / {
+ model = "MediaTek krane sku0 board";
++ chassis-type = "tablet";
+ compatible = "google,krane-sku0", "google,krane", "mediatek,mt8183";
+ };
+
+--- a/arch/arm64/boot/dts/mediatek/mt8183-kukui-krane-sku176.dts
++++ b/arch/arm64/boot/dts/mediatek/mt8183-kukui-krane-sku176.dts
+@@ -14,6 +14,7 @@
+
+ / {
+ model = "MediaTek krane sku176 board";
++ chassis-type = "tablet";
+ compatible = "google,krane-sku176", "google,krane", "mediatek,mt8183";
+ };
+
+--- a/arch/arm64/boot/dts/mediatek/mt8186-evb.dts
++++ b/arch/arm64/boot/dts/mediatek/mt8186-evb.dts
+@@ -7,6 +7,7 @@
+
+ / {
+ model = "MediaTek MT8186 evaluation board";
++ chassis-type = "embedded";
+ compatible = "mediatek,mt8186-evb", "mediatek,mt8186";
+
+ aliases {
--- /dev/null
+From 3b92c547e3d4a35c6214b3e7fa1103d0749d83b1 Mon Sep 17 00:00:00 2001
+From: Daniel Golle <daniel@makrotopia.org>
+Date: Fri, 21 Apr 2023 15:20:44 +0200
+Subject: [PATCH 12/19] arm64: dts: mt7986: add PWM
+
+This adds pwm node to mt7986.
+
+Signed-off-by: Daniel Golle <daniel@makrotopia.org>
+Signed-off-by: Frank Wunderlich <frank-w@public-files.de>
+Link: https://lore.kernel.org/r/20230421132047.42166-5-linux@fw-web.de
+Signed-off-by: Matthias Brugger <matthias.bgg@gmail.com>
+---
+ arch/arm64/boot/dts/mediatek/mt7986a.dtsi | 14 ++++++++++++++
+ 1 file changed, 14 insertions(+)
+
+--- a/arch/arm64/boot/dts/mediatek/mt7986a.dtsi
++++ b/arch/arm64/boot/dts/mediatek/mt7986a.dtsi
+@@ -240,6 +240,20 @@
+ status = "disabled";
+ };
+
++ pwm: pwm@10048000 {
++ compatible = "mediatek,mt7986-pwm";
++ reg = <0 0x10048000 0 0x1000>;
++ #clock-cells = <1>;
++ #pwm-cells = <2>;
++ interrupts = <GIC_SPI 137 IRQ_TYPE_LEVEL_HIGH>;
++ clocks = <&topckgen CLK_TOP_PWM_SEL>,
++ <&infracfg CLK_INFRA_PWM_STA>,
++ <&infracfg CLK_INFRA_PWM1_CK>,
++ <&infracfg CLK_INFRA_PWM2_CK>;
++ clock-names = "top", "main", "pwm1", "pwm2";
++ status = "disabled";
++ };
++
+ uart0: serial@11002000 {
+ compatible = "mediatek,mt7986-uart",
+ "mediatek,mt6577-uart";
--- /dev/null
+From 35e482bb599df010b4869017ff576dbb7a4d4c2e Mon Sep 17 00:00:00 2001
+From: Frank Wunderlich <frank-w@public-files.de>
+Date: Fri, 21 Apr 2023 15:20:45 +0200
+Subject: [PATCH 13/19] arm64: dts: mt7986: add PWM to BPI-R3
+
+Add pwm node and pinctrl to BananaPi R3 devicetree.
+
+Signed-off-by: Frank Wunderlich <frank-w@public-files.de>
+Link: https://lore.kernel.org/r/20230421132047.42166-6-linux@fw-web.de
+Signed-off-by: Matthias Brugger <matthias.bgg@gmail.com>
+---
+ .../boot/dts/mediatek/mt7986a-bananapi-bpi-r3.dts | 13 +++++++++++++
+ 1 file changed, 13 insertions(+)
+
+--- a/arch/arm64/boot/dts/mediatek/mt7986a-bananapi-bpi-r3.dts
++++ b/arch/arm64/boot/dts/mediatek/mt7986a-bananapi-bpi-r3.dts
+@@ -275,6 +275,13 @@
+ };
+ };
+
++ pwm_pins: pwm-pins {
++ mux {
++ function = "pwm";
++ groups = "pwm0", "pwm1_0";
++ };
++ };
++
+ spi_flash_pins: spi-flash-pins {
+ mux {
+ function = "spi";
+@@ -345,6 +352,12 @@
+ };
+ };
+
++&pwm {
++ pinctrl-names = "default";
++ pinctrl-0 = <&pwm_pins>;
++ status = "okay";
++};
++
+ &spi0 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&spi_flash_pins>;
--- /dev/null
+From ccdda5714446db8690505371442f7807f5d7c6fc Mon Sep 17 00:00:00 2001
+From: Frank Wunderlich <frank-w@public-files.de>
+Date: Sun, 5 Feb 2023 18:48:33 +0100
+Subject: [PATCH 14/19] arm64: dts: mt7986: set Wifi Leds low-active for BPI-R3
+
+Leds for Wifi are low-active, so add property to devicetree.
+
+Signed-off-by: Frank Wunderlich <frank-w@public-files.de>
+Reviewed-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
+Link: https://lore.kernel.org/r/20230205174833.107050-1-linux@fw-web.de
+Signed-off-by: Matthias Brugger <matthias.bgg@gmail.com>
+---
+ arch/arm64/boot/dts/mediatek/mt7986a-bananapi-bpi-r3.dts | 4 ++++
+ 1 file changed, 4 insertions(+)
+
+--- a/arch/arm64/boot/dts/mediatek/mt7986a-bananapi-bpi-r3.dts
++++ b/arch/arm64/boot/dts/mediatek/mt7986a-bananapi-bpi-r3.dts
+@@ -460,5 +460,9 @@
+ pinctrl-names = "default", "dbdc";
+ pinctrl-0 = <&wf_2g_5g_pins>, <&wf_led_pins>;
+ pinctrl-1 = <&wf_dbdc_pins>, <&wf_led_pins>;
++
++ led {
++ led-active-low;
++ };
+ };
+
--- /dev/null
+From 1423b4b780adcf3994e63a5988a62d5d1d509bb1 Mon Sep 17 00:00:00 2001
+From: Frank Wunderlich <frank-w@public-files.de>
+Date: Sun, 28 May 2023 13:33:42 +0200
+Subject: [PATCH 15/19] arm64: dts: mt7986: use size of reserved partition for
+ bl2
+
+To store uncompressed bl2 more space is required than partition is
+actually defined.
+
+There is currently no known usage of this reserved partition.
+Openwrt uses same partition layout.
+
+We added same change to u-boot with commit d7bb1099 [1].
+
+[1] https://source.denx.de/u-boot/u-boot/-/commit/d7bb109900c1ca754a0198b9afb50e3161ffc21e
+
+Cc: stable@vger.kernel.org
+Fixes: 8e01fb15b815 ("arm64: dts: mt7986: add Bananapi R3")
+Signed-off-by: Frank Wunderlich <frank-w@public-files.de>
+Reviewed-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
+Reviewed-by: Daniel Golle <daniel@makrotopia.org>
+Link: https://lore.kernel.org/r/20230528113343.7649-1-linux@fw-web.de
+Signed-off-by: Matthias Brugger <matthias.bgg@gmail.com>
+---
+ .../boot/dts/mediatek/mt7986a-bananapi-bpi-r3-nor.dtso | 7 +------
+ 1 file changed, 1 insertion(+), 6 deletions(-)
+
+--- a/arch/arm64/boot/dts/mediatek/mt7986a-bananapi-bpi-r3-nor.dtso
++++ b/arch/arm64/boot/dts/mediatek/mt7986a-bananapi-bpi-r3-nor.dtso
+@@ -27,15 +27,10 @@
+
+ partition@0 {
+ label = "bl2";
+- reg = <0x0 0x20000>;
++ reg = <0x0 0x40000>;
+ read-only;
+ };
+
+- partition@20000 {
+- label = "reserved";
+- reg = <0x20000 0x20000>;
+- };
+-
+ partition@40000 {
+ label = "u-boot-env";
+ reg = <0x40000 0x40000>;
--- /dev/null
+From 40a5a767d698ef7a71f8be851ea18b0a7a8b47bd Mon Sep 17 00:00:00 2001
+From: Daniel Golle <daniel@makrotopia.org>
+Date: Tue, 30 May 2023 22:12:33 +0200
+Subject: [PATCH 16/19] arm64: dts: mt7986: add thermal and efuse
+
+Add thermal related nodes to mt7986 devicetree.
+
+Signed-off-by: Daniel Golle <daniel@makrotopia.org>
+Signed-off-by: Frank Wunderlich <frank-w@public-files.de>
+Reviewed-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
+Link: https://lore.kernel.org/r/20230530201235.22330-3-linux@fw-web.de
+Signed-off-by: Matthias Brugger <matthias.bgg@gmail.com>
+---
+ arch/arm64/boot/dts/mediatek/mt7986a.dtsi | 36 ++++++++++++++++++++++-
+ 1 file changed, 35 insertions(+), 1 deletion(-)
+
+--- a/arch/arm64/boot/dts/mediatek/mt7986a.dtsi
++++ b/arch/arm64/boot/dts/mediatek/mt7986a.dtsi
+@@ -337,6 +337,15 @@
+ status = "disabled";
+ };
+
++ auxadc: adc@1100d000 {
++ compatible = "mediatek,mt7986-auxadc";
++ reg = <0 0x1100d000 0 0x1000>;
++ clocks = <&infracfg CLK_INFRA_ADC_26M_CK>;
++ clock-names = "main";
++ #io-channel-cells = <1>;
++ status = "disabled";
++ };
++
+ ssusb: usb@11200000 {
+ compatible = "mediatek,mt7986-xhci",
+ "mediatek,mtk-xhci";
+@@ -375,6 +384,21 @@
+ status = "disabled";
+ };
+
++ thermal: thermal@1100c800 {
++ #thermal-sensor-cells = <1>;
++ compatible = "mediatek,mt7986-thermal";
++ reg = <0 0x1100c800 0 0x800>;
++ interrupts = <GIC_SPI 138 IRQ_TYPE_LEVEL_HIGH>;
++ clocks = <&infracfg CLK_INFRA_THERM_CK>,
++ <&infracfg CLK_INFRA_ADC_26M_CK>,
++ <&infracfg CLK_INFRA_ADC_FRC_CK>;
++ clock-names = "therm", "auxadc", "adc_32k";
++ mediatek,auxadc = <&auxadc>;
++ mediatek,apmixedsys = <&apmixedsys>;
++ nvmem-cells = <&thermal_calibration>;
++ nvmem-cell-names = "calibration-data";
++ };
++
+ pcie: pcie@11280000 {
+ compatible = "mediatek,mt7986-pcie",
+ "mediatek,mt8192-pcie";
+@@ -426,6 +450,17 @@
+ };
+ };
+
++ efuse: efuse@11d00000 {
++ compatible = "mediatek,mt7986-efuse", "mediatek,efuse";
++ reg = <0 0x11d00000 0 0x1000>;
++ #address-cells = <1>;
++ #size-cells = <1>;
++
++ thermal_calibration: calib@274 {
++ reg = <0x274 0xc>;
++ };
++ };
++
+ usb_phy: t-phy@11e10000 {
+ compatible = "mediatek,mt7986-tphy",
+ "mediatek,generic-tphy-v2";
+@@ -567,5 +602,4 @@
+ memory-region = <&wmcpu_emi>;
+ };
+ };
+-
+ };
--- /dev/null
+From bb78d0cf5117517f1ed296ae71048945d9107675 Mon Sep 17 00:00:00 2001
+From: Daniel Golle <daniel@makrotopia.org>
+Date: Tue, 30 May 2023 22:12:34 +0200
+Subject: [PATCH 17/19] arm64: dts: mt7986: add thermal-zones
+
+Add thermal-zones to mt7986 devicetree.
+
+Signed-off-by: Daniel Golle <daniel@makrotopia.org>
+Signed-off-by: Frank Wunderlich <frank-w@public-files.de>
+Reviewed-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
+Link: https://lore.kernel.org/r/20230530201235.22330-4-linux@fw-web.de
+Signed-off-by: Matthias Brugger <matthias.bgg@gmail.com>
+---
+ arch/arm64/boot/dts/mediatek/mt7986a.dtsi | 28 +++++++++++++++++++++++
+ 1 file changed, 28 insertions(+)
+
+--- a/arch/arm64/boot/dts/mediatek/mt7986a.dtsi
++++ b/arch/arm64/boot/dts/mediatek/mt7986a.dtsi
+@@ -602,4 +602,32 @@
+ memory-region = <&wmcpu_emi>;
+ };
+ };
++
++ thermal-zones {
++ cpu_thermal: cpu-thermal {
++ polling-delay-passive = <1000>;
++ polling-delay = <1000>;
++ thermal-sensors = <&thermal 0>;
++
++ trips {
++ cpu_trip_active_high: active-high {
++ temperature = <115000>;
++ hysteresis = <2000>;
++ type = "active";
++ };
++
++ cpu_trip_active_low: active-low {
++ temperature = <85000>;
++ hysteresis = <2000>;
++ type = "active";
++ };
++
++ cpu_trip_passive: passive {
++ temperature = <40000>;
++ hysteresis = <2000>;
++ type = "passive";
++ };
++ };
++ };
++ };
+ };
--- /dev/null
+From 5d90603b09e5814ffc38c47e79ccf9bc564f9296 Mon Sep 17 00:00:00 2001
+From: Daniel Golle <daniel@makrotopia.org>
+Date: Tue, 30 May 2023 22:12:35 +0200
+Subject: [PATCH 18/19] arm64: dts: mt7986: add pwm-fan and cooling-maps to
+ BPI-R3 dts
+
+Add pwm-fan and cooling-maps to BananaPi-R3 devicetree.
+
+Signed-off-by: Daniel Golle <daniel@makrotopia.org>
+Signed-off-by: Frank Wunderlich <frank-w@public-files.de>
+Reviewed-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
+Link: https://lore.kernel.org/r/20230530201235.22330-5-linux@fw-web.de
+Signed-off-by: Matthias Brugger <matthias.bgg@gmail.com>
+---
+ .../dts/mediatek/mt7986a-bananapi-bpi-r3.dts | 31 +++++++++++++++++++
+ 1 file changed, 31 insertions(+)
+
+--- a/arch/arm64/boot/dts/mediatek/mt7986a-bananapi-bpi-r3.dts
++++ b/arch/arm64/boot/dts/mediatek/mt7986a-bananapi-bpi-r3.dts
+@@ -38,6 +38,15 @@
+ regulator-always-on;
+ };
+
++ fan: pwm-fan {
++ compatible = "pwm-fan";
++ #cooling-cells = <2>;
++ /* cooling level (0, 1, 2) - pwm inverted */
++ cooling-levels = <255 96 0>;
++ pwms = <&pwm 0 10000 0>;
++ status = "okay";
++ };
++
+ gpio-keys {
+ compatible = "gpio-keys";
+
+@@ -133,6 +142,28 @@
+ };
+ };
+
++&cpu_thermal {
++ cooling-maps {
++ cpu-active-high {
++ /* active: set fan to cooling level 2 */
++ cooling-device = <&fan 2 2>;
++ trip = <&cpu_trip_active_high>;
++ };
++
++ cpu-active-low {
++ /* active: set fan to cooling level 1 */
++ cooling-device = <&fan 1 1>;
++ trip = <&cpu_trip_active_low>;
++ };
++
++ cpu-passive {
++ /* passive: set fan to cooling level 0 */
++ cooling-device = <&fan 0 0>;
++ trip = <&cpu_trip_passive>;
++ };
++ };
++};
++
+ &crypto {
+ status = "okay";
+ };
--- /dev/null
+From 6dd3b939370094eb79529683be84500f3c757404 Mon Sep 17 00:00:00 2001
+From: Daniel Golle <daniel@makrotopia.org>
+Date: Tue, 6 Jun 2023 16:43:20 +0100
+Subject: [PATCH 19/19] arm64: dts: mt7986: increase bl2 partition on NAND of
+ Bananapi R3
+
+The bootrom burned into the MT7986 SoC will try multiple locations on
+the SPI-NAND flash to load bl2 in case the bl2 image located at the the
+previously attempted offset is corrupt.
+
+Use 0x100000 instead of 0x80000 as partition size for bl2 on SPI-NAND,
+allowing for up to four redundant copies of bl2 (typically sized a
+bit less than 0x40000).
+
+Fixes: 8e01fb15b8157 ("arm64: dts: mt7986: add Bananapi R3")
+Signed-off-by: Daniel Golle <daniel@makrotopia.org>
+Link: https://lore.kernel.org/r/ZH9UGF99RgzrHZ88@makrotopia.org
+Signed-off-by: Matthias Brugger <matthias.bgg@gmail.com>
+---
+ .../boot/dts/mediatek/mt7986a-bananapi-bpi-r3-nand.dtso | 6 +++---
+ 1 file changed, 3 insertions(+), 3 deletions(-)
+
+--- a/arch/arm64/boot/dts/mediatek/mt7986a-bananapi-bpi-r3-nand.dtso
++++ b/arch/arm64/boot/dts/mediatek/mt7986a-bananapi-bpi-r3-nand.dtso
+@@ -29,13 +29,13 @@
+
+ partition@0 {
+ label = "bl2";
+- reg = <0x0 0x80000>;
++ reg = <0x0 0x100000>;
+ read-only;
+ };
+
+- partition@80000 {
++ partition@100000 {
+ label = "reserved";
+- reg = <0x80000 0x300000>;
++ reg = <0x100000 0x280000>;
+ };
+
+ partition@380000 {
--- /dev/null
+From f8ed4088ed9c61ae92193da6130d04c37e7b19f2 Mon Sep 17 00:00:00 2001
+From: Frank Wunderlich <frank-w@public-files.de>
+Date: Sun, 20 Aug 2023 17:31:33 +0200
+Subject: [PATCH 20/22] arm64: dts: mt7986: define 3W max power to both SFP on
+ BPI-R3
+
+All SFP power supplies are connected to the system VDD33 which is 3v3/8A.
+Set 3A per SFP slot to allow SFPs work which need more power than the
+default 1W.
+
+Fixes: 8e01fb15b815 ("arm64: dts: mt7986: add Bananapi R3")
+Signed-off-by: Frank Wunderlich <frank-w@public-files.de>
+---
+ arch/arm64/boot/dts/mediatek/mt7986a-bananapi-bpi-r3.dts | 2 ++
+ 1 file changed, 2 insertions(+)
+
+--- a/arch/arm64/boot/dts/mediatek/mt7986a-bananapi-bpi-r3.dts
++++ b/arch/arm64/boot/dts/mediatek/mt7986a-bananapi-bpi-r3.dts
+@@ -126,6 +126,7 @@
+ compatible = "sff,sfp";
+ i2c-bus = <&i2c_sfp1>;
+ los-gpios = <&pio 46 GPIO_ACTIVE_HIGH>;
++ maximum-power-milliwatt = <3000>;
+ mod-def0-gpios = <&pio 49 GPIO_ACTIVE_LOW>;
+ tx-disable-gpios = <&pio 20 GPIO_ACTIVE_HIGH>;
+ tx-fault-gpios = <&pio 7 GPIO_ACTIVE_HIGH>;
+@@ -137,6 +138,7 @@
+ i2c-bus = <&i2c_sfp2>;
+ los-gpios = <&pio 31 GPIO_ACTIVE_HIGH>;
+ mod-def0-gpios = <&pio 47 GPIO_ACTIVE_LOW>;
++ maximum-power-milliwatt = <3000>;
+ tx-disable-gpios = <&pio 15 GPIO_ACTIVE_HIGH>;
+ tx-fault-gpios = <&pio 48 GPIO_ACTIVE_HIGH>;
+ };
--- /dev/null
+From aa3d6df9803c267725dc72286bb91602b7579882 Mon Sep 17 00:00:00 2001
+From: Frank Wunderlich <frank-w@public-files.de>
+Date: Sun, 20 Aug 2023 17:31:34 +0200
+Subject: [PATCH 21/22] arm64: dts: mt7986: change cooling trips
+
+Add Critical and hot trips for emergency system shutdown and limiting
+system load.
+
+Change passive trip to active to make sure fan is activated on the
+lowest trip.
+
+Fixes: 1f5be05132f3 ("arm64: dts: mt7986: add thermal-zones")
+Suggested-by: Daniel Golle <daniel@makrotopia.org>
+Signed-off-by: Frank Wunderlich <frank-w@public-files.de>
+---
+ arch/arm64/boot/dts/mediatek/mt7986a.dtsi | 20 ++++++++++++++++----
+ 1 file changed, 16 insertions(+), 4 deletions(-)
+
+--- a/arch/arm64/boot/dts/mediatek/mt7986a.dtsi
++++ b/arch/arm64/boot/dts/mediatek/mt7986a.dtsi
+@@ -610,22 +610,34 @@
+ thermal-sensors = <&thermal 0>;
+
+ trips {
++ cpu_trip_crit: crit {
++ temperature = <125000>;
++ hysteresis = <2000>;
++ type = "critical";
++ };
++
++ cpu_trip_hot: hot {
++ temperature = <120000>;
++ hysteresis = <2000>;
++ type = "hot";
++ };
++
+ cpu_trip_active_high: active-high {
+ temperature = <115000>;
+ hysteresis = <2000>;
+ type = "active";
+ };
+
+- cpu_trip_active_low: active-low {
++ cpu_trip_active_med: active-med {
+ temperature = <85000>;
+ hysteresis = <2000>;
+ type = "active";
+ };
+
+- cpu_trip_passive: passive {
+- temperature = <40000>;
++ cpu_trip_active_low: active-low {
++ temperature = <60000>;
+ hysteresis = <2000>;
+- type = "passive";
++ type = "active";
+ };
+ };
+ };
--- /dev/null
+From 6ddf23526955b8dbedfeaa57e691261fd73f9d4e Mon Sep 17 00:00:00 2001
+From: Frank Wunderlich <frank-w@public-files.de>
+Date: Sun, 20 Aug 2023 17:31:35 +0200
+Subject: [PATCH 22/22] arm64: dts: mt7986: change thermal trips on BPI-R3
+
+Apply new naming after mt7986 thermal trips were changed.
+
+Fixes: c26f779a2295 ("arm64: dts: mt7986: add pwm-fan and cooling-maps to BPI-R3 dts")
+Suggested-by: Daniel Golle <daniel@makrotopia.org>
+Signed-off-by: Frank Wunderlich <frank-w@public-files.de>
+---
+ .../boot/dts/mediatek/mt7986a-bananapi-bpi-r3.dts | 10 +++++-----
+ 1 file changed, 5 insertions(+), 5 deletions(-)
+
+--- a/arch/arm64/boot/dts/mediatek/mt7986a-bananapi-bpi-r3.dts
++++ b/arch/arm64/boot/dts/mediatek/mt7986a-bananapi-bpi-r3.dts
+@@ -152,16 +152,16 @@
+ trip = <&cpu_trip_active_high>;
+ };
+
+- cpu-active-low {
++ cpu-active-med {
+ /* active: set fan to cooling level 1 */
+ cooling-device = <&fan 1 1>;
+- trip = <&cpu_trip_active_low>;
++ trip = <&cpu_trip_active_med>;
+ };
+
+- cpu-passive {
+- /* passive: set fan to cooling level 0 */
++ cpu-active-low {
++ /* active: set fan to cooling level 0 */
+ cooling-device = <&fan 0 0>;
+- trip = <&cpu_trip_passive>;
++ trip = <&cpu_trip_active_low>;
+ };
+ };
+ };
--- /dev/null
+From 69357074558daf6ff24c9f58714935e9e095a865 Mon Sep 17 00:00:00 2001
+From: OpenWrt community <openwrt-devel@lists.openwrt.org>
+Date: Wed, 13 Jul 2022 13:37:33 +0200
+Subject: [PATCH] kernel: add block fit partition parser
+
+---
+ block/blk.h | 2 ++
+ block/partitions/Kconfig | 7 +++++++
+ block/partitions/Makefile | 1 +
+ block/partitions/check.h | 3 +++
+ block/partitions/core.c | 17 +++++++++++++++++
+ block/partitions/efi.c | 8 ++++++++
+ block/partitions/efi.h | 3 +++
+ block/partitions/msdos.c | 10 ++++++++++
+ drivers/mtd/mtd_blkdevs.c | 2 ++
+ drivers/mtd/ubi/block.c | 3 +++
+ include/linux/msdos_partition.h | 1 +
+ 11 files changed, 57 insertions(+)
+
+--- a/block/blk.h
++++ b/block/blk.h
+@@ -414,6 +414,8 @@ void blk_free_ext_minor(unsigned int min
+ #define ADDPART_FLAG_NONE 0
+ #define ADDPART_FLAG_RAID 1
+ #define ADDPART_FLAG_WHOLEDISK 2
++#define ADDPART_FLAG_READONLY 4
++#define ADDPART_FLAG_ROOTDEV 8
+ int bdev_add_partition(struct gendisk *disk, int partno, sector_t start,
+ sector_t length);
+ int bdev_del_partition(struct gendisk *disk, int partno);
+--- a/block/partitions/Kconfig
++++ b/block/partitions/Kconfig
+@@ -103,6 +103,13 @@ config ATARI_PARTITION
+ Say Y here if you would like to use hard disks under Linux which
+ were partitioned under the Atari OS.
+
++config FIT_PARTITION
++ bool "Flattened-Image-Tree (FIT) partition support" if PARTITION_ADVANCED
++ default n
++ help
++ Say Y here if your system needs to mount the filesystem part of
++ a Flattened-Image-Tree (FIT) image commonly used with Das U-Boot.
++
+ config IBM_PARTITION
+ bool "IBM disk label and partition support"
+ depends on PARTITION_ADVANCED && S390
+--- a/block/partitions/Makefile
++++ b/block/partitions/Makefile
+@@ -8,6 +8,7 @@ obj-$(CONFIG_ACORN_PARTITION) += acorn.o
+ obj-$(CONFIG_AMIGA_PARTITION) += amiga.o
+ obj-$(CONFIG_ATARI_PARTITION) += atari.o
+ obj-$(CONFIG_AIX_PARTITION) += aix.o
++obj-$(CONFIG_FIT_PARTITION) += fit.o
+ obj-$(CONFIG_CMDLINE_PARTITION) += cmdline.o
+ obj-$(CONFIG_MAC_PARTITION) += mac.o
+ obj-$(CONFIG_LDM_PARTITION) += ldm.o
+--- a/block/partitions/check.h
++++ b/block/partitions/check.h
+@@ -57,6 +57,7 @@ int amiga_partition(struct parsed_partit
+ int atari_partition(struct parsed_partitions *state);
+ int cmdline_partition(struct parsed_partitions *state);
+ int efi_partition(struct parsed_partitions *state);
++int fit_partition(struct parsed_partitions *state);
+ int ibm_partition(struct parsed_partitions *);
+ int karma_partition(struct parsed_partitions *state);
+ int ldm_partition(struct parsed_partitions *state);
+@@ -67,3 +68,5 @@ int sgi_partition(struct parsed_partitio
+ int sun_partition(struct parsed_partitions *state);
+ int sysv68_partition(struct parsed_partitions *state);
+ int ultrix_partition(struct parsed_partitions *state);
++
++int parse_fit_partitions(struct parsed_partitions *state, u64 start_sector, u64 nr_sectors, int *slot, int add_remain);
+--- a/block/partitions/core.c
++++ b/block/partitions/core.c
+@@ -11,6 +11,9 @@
+ #include <linux/vmalloc.h>
+ #include <linux/raid/detect.h>
+ #include <linux/property.h>
++#ifdef CONFIG_FIT_PARTITION
++#include <linux/root_dev.h>
++#endif
+
+ #include "check.h"
+
+@@ -48,6 +51,9 @@ static int (*check_part[])(struct parsed
+ #ifdef CONFIG_EFI_PARTITION
+ efi_partition, /* this must come before msdos */
+ #endif
++#ifdef CONFIG_FIT_PARTITION
++ fit_partition,
++#endif
+ #ifdef CONFIG_SGI_PARTITION
+ sgi_partition,
+ #endif
+@@ -439,6 +445,11 @@ static struct block_device *add_partitio
+ goto out_del;
+ }
+
++#ifdef CONFIG_FIT_PARTITION
++ if (flags & ADDPART_FLAG_READONLY)
++ bdev->bd_read_only = true;
++#endif
++
+ /* everything is up and running, commence */
+ err = xa_insert(&disk->part_tbl, partno, bdev, GFP_KERNEL);
+ if (err)
+@@ -631,6 +642,11 @@ static bool blk_add_partition(struct gen
+ (state->parts[p].flags & ADDPART_FLAG_RAID))
+ md_autodetect_dev(part->bd_dev);
+
++#ifdef CONFIG_FIT_PARTITION
++ if ((state->parts[p].flags & ADDPART_FLAG_ROOTDEV) && ROOT_DEV == 0)
++ ROOT_DEV = part->bd_dev;
++#endif
++
+ return true;
+ }
+
+--- a/block/partitions/efi.c
++++ b/block/partitions/efi.c
+@@ -716,6 +716,9 @@ int efi_partition(struct parsed_partitio
+ gpt_entry *ptes = NULL;
+ u32 i;
+ unsigned ssz = queue_logical_block_size(state->disk->queue) / 512;
++#ifdef CONFIG_FIT_PARTITION
++ u32 extra_slot = 64;
++#endif
+
+ if (!find_valid_gpt(state, &gpt, &ptes) || !gpt || !ptes) {
+ kfree(gpt);
+@@ -749,6 +752,11 @@ int efi_partition(struct parsed_partitio
+ ARRAY_SIZE(ptes[i].partition_name));
+ utf16_le_to_7bit(ptes[i].partition_name, label_max, info->volname);
+ state->parts[i + 1].has_info = true;
++#ifdef CONFIG_FIT_PARTITION
++ /* If this is a U-Boot FIT volume it may have subpartitions */
++ if (!efi_guidcmp(ptes[i].partition_type_guid, PARTITION_LINUX_FIT_GUID))
++ (void) parse_fit_partitions(state, start * ssz, size * ssz, &extra_slot, 1);
++#endif
+ }
+ kfree(ptes);
+ kfree(gpt);
+--- a/block/partitions/efi.h
++++ b/block/partitions/efi.h
+@@ -51,6 +51,9 @@
+ #define PARTITION_LINUX_LVM_GUID \
+ EFI_GUID( 0xe6d6d379, 0xf507, 0x44c2, \
+ 0xa2, 0x3c, 0x23, 0x8f, 0x2a, 0x3d, 0xf9, 0x28)
++#define PARTITION_LINUX_FIT_GUID \
++ EFI_GUID( 0xcae9be83, 0xb15f, 0x49cc, \
++ 0x86, 0x3f, 0x08, 0x1b, 0x74, 0x4a, 0x2d, 0x93)
+
+ typedef struct _gpt_header {
+ __le64 signature;
+--- a/block/partitions/msdos.c
++++ b/block/partitions/msdos.c
+@@ -564,6 +564,15 @@ static void parse_minix(struct parsed_pa
+ #endif /* CONFIG_MINIX_SUBPARTITION */
+ }
+
++static void parse_fit_mbr(struct parsed_partitions *state,
++ sector_t offset, sector_t size, int origin)
++{
++#ifdef CONFIG_FIT_PARTITION
++ u32 extra_slot = 64;
++ (void) parse_fit_partitions(state, offset, size, &extra_slot, 1);
++#endif /* CONFIG_FIT_PARTITION */
++}
++
+ static struct {
+ unsigned char id;
+ void (*parse)(struct parsed_partitions *, sector_t, sector_t, int);
+@@ -575,6 +584,7 @@ static struct {
+ {UNIXWARE_PARTITION, parse_unixware},
+ {SOLARIS_X86_PARTITION, parse_solaris_x86},
+ {NEW_SOLARIS_X86_PARTITION, parse_solaris_x86},
++ {FIT_PARTITION, parse_fit_mbr},
+ {0, NULL},
+ };
+
+--- a/drivers/mtd/mtd_blkdevs.c
++++ b/drivers/mtd/mtd_blkdevs.c
+@@ -359,7 +359,9 @@ int add_mtd_blktrans_dev(struct mtd_blkt
+ } else {
+ snprintf(gd->disk_name, sizeof(gd->disk_name),
+ "%s%d", tr->name, new->devnum);
+- gd->flags |= GENHD_FL_NO_PART;
++
++ if (!IS_ENABLED(CONFIG_FIT_PARTITION) || mtd_type_is_nand(new->mtd))
++ gd->flags |= GENHD_FL_NO_PART;
+ }
+
+ set_capacity(gd, ((u64)new->size * tr->blksize) >> 9);
+--- a/drivers/mtd/ubi/block.c
++++ b/drivers/mtd/ubi/block.c
+@@ -432,7 +432,9 @@ int ubiblock_create(struct ubi_volume_in
+ ret = -ENODEV;
+ goto out_cleanup_disk;
+ }
+- gd->flags |= GENHD_FL_NO_PART;
++ if (!IS_ENABLED(CONFIG_FIT_PARTITION))
++ gd->flags |= GENHD_FL_NO_PART;
++
+ gd->private_data = dev;
+ sprintf(gd->disk_name, "ubiblock%d_%d", dev->ubi_num, dev->vol_id);
+ set_capacity(gd, disk_capacity);
+--- a/include/linux/msdos_partition.h
++++ b/include/linux/msdos_partition.h
+@@ -31,6 +31,7 @@ enum msdos_sys_ind {
+ LINUX_LVM_PARTITION = 0x8e,
+ LINUX_RAID_PARTITION = 0xfd, /* autodetect RAID partition */
+
++ FIT_PARTITION = 0x2e, /* U-Boot uImage.FIT */
+ SOLARIS_X86_PARTITION = 0x82, /* also Linux swap partitions */
+ NEW_SOLARIS_X86_PARTITION = 0xbf,
+
--- /dev/null
+--- a/arch/arm64/boot/dts/mediatek/mt7622-rfb1.dts
++++ b/arch/arm64/boot/dts/mediatek/mt7622-rfb1.dts
+@@ -1,7 +1,6 @@
+ /*
+- * Copyright (c) 2017 MediaTek Inc.
+- * Author: Ming Huang <ming.huang@mediatek.com>
+- * Sean Wang <sean.wang@mediatek.com>
++ * Copyright (c) 2018 MediaTek Inc.
++ * Author: Ryder Lee <ryder.lee@mediatek.com>
+ *
+ * SPDX-License-Identifier: (GPL-2.0 OR MIT)
+ */
+@@ -24,7 +23,7 @@
+
+ chosen {
+ stdout-path = "serial0:115200n8";
+- bootargs = "earlycon=uart8250,mmio32,0x11002000 swiotlb=512";
++ bootargs = "earlycon=uart8250,mmio32,0x11002000 console=ttyS0,115200n1 swiotlb=512";
+ };
+
+ cpus {
+@@ -45,18 +44,18 @@
+ key-factory {
+ label = "factory";
+ linux,code = <BTN_0>;
+- gpios = <&pio 0 0>;
++ gpios = <&pio 0 GPIO_ACTIVE_LOW>;
+ };
+
+ key-wps {
+ label = "wps";
+ linux,code = <KEY_WPS_BUTTON>;
+- gpios = <&pio 102 0>;
++ gpios = <&pio 102 GPIO_ACTIVE_LOW>;
+ };
+ };
+
+ memory@40000000 {
+- reg = <0 0x40000000 0 0x20000000>;
++ reg = <0 0x40000000 0 0x40000000>;
+ };
+
+ reg_1p8v: regulator-1p8v {
+@@ -132,22 +131,22 @@
+
+ port@0 {
+ reg = <0>;
+- label = "lan0";
++ label = "lan1";
+ };
+
+ port@1 {
+ reg = <1>;
+- label = "lan1";
++ label = "lan2";
+ };
+
+ port@2 {
+ reg = <2>;
+- label = "lan2";
++ label = "lan3";
+ };
+
+ port@3 {
+ reg = <3>;
+- label = "lan3";
++ label = "lan4";
+ };
+
+ port@4 {
+@@ -240,7 +239,22 @@
+ status = "okay";
+ };
+
++&pcie1 {
++ pinctrl-names = "default";
++ pinctrl-0 = <&pcie1_pins>;
++ status = "okay";
++};
++
+ &pio {
++ /* Attention: GPIO 90 is used to switch between PCIe@1,0 and
++ * SATA functions. i.e. output-high: PCIe, output-low: SATA
++ */
++ asm_sel {
++ gpio-hog;
++ gpios = <90 GPIO_ACTIVE_HIGH>;
++ output-high;
++ };
++
+ /* eMMC is shared pin with parallel NAND */
+ emmc_pins_default: emmc-pins-default {
+ mux {
+@@ -517,11 +531,11 @@
+ };
+
+ &sata {
+- status = "okay";
++ status = "disabled";
+ };
+
+ &sata_phy {
+- status = "okay";
++ status = "disabled";
+ };
+
+ &spi0 {
--- /dev/null
+--- a/arch/arm/boot/dts/mt7629-rfb.dts
++++ b/arch/arm/boot/dts/mt7629-rfb.dts
+@@ -18,6 +18,7 @@
+
+ chosen {
+ stdout-path = "serial0:115200n8";
++ bootargs = "earlycon=uart8250,mmio32,0x11002000 console=ttyS0,115200n8";
+ };
+
+ gpio-keys {
+@@ -70,6 +71,10 @@
+ compatible = "mediatek,eth-mac";
+ reg = <0>;
+ phy-mode = "2500base-x";
++
++ nvmem-cells = <&macaddr_factory_2a>;
++ nvmem-cell-names = "mac-address";
++
+ fixed-link {
+ speed = <2500>;
+ full-duplex;
+@@ -82,6 +87,9 @@
+ reg = <1>;
+ phy-mode = "gmii";
+ phy-handle = <&phy0>;
++
++ nvmem-cells = <&macaddr_factory_24>;
++ nvmem-cell-names = "mac-address";
+ };
+
+ mdio: mdio-bus {
+@@ -133,8 +141,9 @@
+ };
+
+ partition@b0000 {
+- label = "kernel";
++ label = "firmware";
+ reg = <0xb0000 0xb50000>;
++ compatible = "denx,fit";
+ };
+ };
+ };
+@@ -273,3 +282,17 @@
+ pinctrl-0 = <&watchdog_pins>;
+ status = "okay";
+ };
++
++&factory {
++ compatible = "nvmem-cells";
++ #address-cells = <1>;
++ #size-cells = <1>;
++
++ macaddr_factory_24: macaddr@24 {
++ reg = <0x24 0x6>;
++ };
++
++ macaddr_factory_2a: macaddr@2a {
++ reg = <0x2a 0x6>;
++ };
++};
--- /dev/null
+From d6a596012150960f0f3a214d31bbac4b607dbd1e Mon Sep 17 00:00:00 2001
+From: Chuanhong Guo <gch981213@gmail.com>
+Date: Fri, 29 Apr 2022 10:40:56 +0800
+Subject: [PATCH] arm: mediatek: select arch timer for mt7623
+
+Signed-off-by: Chuanhong Guo <gch981213@gmail.com>
+---
+ arch/arm/mach-mediatek/Kconfig | 1 +
+ 1 file changed, 1 insertion(+)
+
+--- a/arch/arm/mach-mediatek/Kconfig
++++ b/arch/arm/mach-mediatek/Kconfig
+@@ -26,6 +26,7 @@ config MACH_MT6592
+ config MACH_MT7623
+ bool "MediaTek MT7623 SoCs support"
+ default ARCH_MEDIATEK
++ select HAVE_ARM_ARCH_TIMER
+
+ config MACH_MT7629
+ bool "MediaTek MT7629 SoCs support"
--- /dev/null
+--- a/arch/arm64/boot/dts/mediatek/mt7622.dtsi
++++ b/arch/arm64/boot/dts/mediatek/mt7622.dtsi
+@@ -578,6 +578,7 @@
+ compatible = "mediatek,mt7622-nor",
+ "mediatek,mt8173-nor";
+ reg = <0 0x11014000 0 0xe0>;
++ interrupts = <GIC_SPI 88 IRQ_TYPE_LEVEL_LOW>;
+ clocks = <&pericfg CLK_PERI_FLASH_PD>,
+ <&topckgen CLK_TOP_FLASH_SEL>;
+ clock-names = "spi", "sf";
--- /dev/null
+--- a/arch/arm64/boot/dts/mediatek/mt7622.dtsi
++++ b/arch/arm64/boot/dts/mediatek/mt7622.dtsi
+@@ -134,6 +134,13 @@
+ #size-cells = <2>;
+ ranges;
+
++ /* 64 KiB reserved for ramoops/pstore */
++ ramoops@42ff0000 {
++ compatible = "ramoops";
++ reg = <0 0x42ff0000 0 0x10000>;
++ record-size = <0x1000>;
++ };
++
+ /* 192 KiB reserved for ARM Trusted Firmware (BL31) */
+ secmon_reserved: secmon@43000000 {
+ reg = <0 0x43000000 0 0x30000>;
--- /dev/null
+--- a/arch/arm64/boot/dts/mediatek/mt7622-bananapi-bpi-r64.dts
++++ b/arch/arm64/boot/dts/mediatek/mt7622-bananapi-bpi-r64.dts
+@@ -108,10 +108,6 @@
+ status = "disabled";
+ };
+
+-&btif {
+- status = "okay";
+-};
+-
+ &cir {
+ pinctrl-names = "default";
+ pinctrl-0 = <&irrx_pins>;
+--- a/arch/arm64/boot/dts/mediatek/mt7622-rfb1.dts
++++ b/arch/arm64/boot/dts/mediatek/mt7622-rfb1.dts
+@@ -89,10 +89,6 @@
+ status = "disabled";
+ };
+
+-&btif {
+- status = "okay";
+-};
+-
+ &cir {
+ pinctrl-names = "default";
+ pinctrl-0 = <&irrx_pins>;
--- /dev/null
+--- a/arch/arm/boot/dts/mt7623n-bananapi-bpi-r2.dts
++++ b/arch/arm/boot/dts/mt7623n-bananapi-bpi-r2.dts
+@@ -19,6 +19,7 @@
+
+ chosen {
+ stdout-path = "serial2:115200n8";
++ bootargs = "console=ttyS2,115200n8 console=tty1";
+ };
+
+ connector {
--- /dev/null
+--- a/arch/arm64/boot/dts/mediatek/mt7622-bananapi-bpi-r64.dts
++++ b/arch/arm64/boot/dts/mediatek/mt7622-bananapi-bpi-r64.dts
+@@ -24,7 +24,7 @@
+
+ chosen {
+ stdout-path = "serial0:115200n8";
+- bootargs = "earlycon=uart8250,mmio32,0x11002000 swiotlb=512";
++ bootargs = "earlycon=uart8250,mmio32,0x11002000 console=ttyS0,115200n1 swiotlb=512";
+ };
+
+ cpus {
--- /dev/null
+--- a/arch/arm64/boot/dts/mediatek/mt7622-bananapi-bpi-r64.dts
++++ b/arch/arm64/boot/dts/mediatek/mt7622-bananapi-bpi-r64.dts
+@@ -20,6 +20,7 @@
+
+ aliases {
+ serial0 = &uart0;
++ ethernet0 = &gmac0;
+ };
+
+ chosen {
+@@ -160,22 +161,22 @@
+
+ port@1 {
+ reg = <1>;
+- label = "lan0";
++ label = "lan1";
+ };
+
+ port@2 {
+ reg = <2>;
+- label = "lan1";
++ label = "lan2";
+ };
+
+ port@3 {
+ reg = <3>;
+- label = "lan2";
++ label = "lan3";
+ };
+
+ port@4 {
+ reg = <4>;
+- label = "lan3";
++ label = "lan4";
+ };
+
+ port@6 {
--- /dev/null
+--- a/arch/arm64/boot/dts/mediatek/mt7622-bananapi-bpi-r64.dts
++++ b/arch/arm64/boot/dts/mediatek/mt7622-bananapi-bpi-r64.dts
+@@ -21,6 +21,12 @@
+ aliases {
+ serial0 = &uart0;
+ ethernet0 = &gmac0;
++ led-boot = &led_system_green;
++ led-failsafe = &led_system_blue;
++ led-running = &led_system_green;
++ led-upgrade = &led_system_blue;
++ mmc0 = &mmc0;
++ mmc1 = &mmc1;
+ };
+
+ chosen {
+@@ -44,8 +50,8 @@
+ compatible = "gpio-keys";
+
+ factory-key {
+- label = "factory";
+- linux,code = <BTN_0>;
++ label = "reset";
++ linux,code = <KEY_RESTART>;
+ gpios = <&pio 0 GPIO_ACTIVE_HIGH>;
+ };
+
+@@ -59,17 +65,17 @@
+ leds {
+ compatible = "gpio-leds";
+
+- led-0 {
++ led_system_green: led-0 {
+ label = "bpi-r64:pio:green";
+ color = <LED_COLOR_ID_GREEN>;
+ gpios = <&pio 89 GPIO_ACTIVE_HIGH>;
+ default-state = "off";
+ };
+
+- led-1 {
+- label = "bpi-r64:pio:red";
+- color = <LED_COLOR_ID_RED>;
+- gpios = <&pio 88 GPIO_ACTIVE_HIGH>;
++ led_system_blue: led-1 {
++ label = "bpi-r64:pio:blue";
++ color = <LED_COLOR_ID_BLUE>;
++ gpios = <&pio 85 GPIO_ACTIVE_HIGH>;
+ default-state = "off";
+ };
+ };
--- /dev/null
+--- a/arch/arm64/boot/dts/mediatek/mt7622-bananapi-bpi-r64.dts
++++ b/arch/arm64/boot/dts/mediatek/mt7622-bananapi-bpi-r64.dts
+@@ -556,12 +556,16 @@
+ status = "okay";
+ };
+
++&rtc {
++ status = "disabled";
++};
++
+ &sata {
+- status = "disable";
++ status = "disabled";
+ };
+
+ &sata_phy {
+- status = "disable";
++ status = "disabled";
+ };
+
+ &spi0 {
--- /dev/null
+From d278f43f25beedfd0cb784d1dd0a9e7e8c8f123f Mon Sep 17 00:00:00 2001
+From: Daniel Golle <daniel@makrotopia.org>
+Date: Wed, 19 Apr 2023 20:15:53 +0100
+Subject: [PATCH] arm64: dts: mt7622: declare SPI-NAND present on BPI-R64
+
+The SPI-NOR node in the device tree of the BananaPi R64 has most likely
+been copied from the reference board's device tree even though the R64
+comes with an SPI-NAND chip rather than SPI-NOR.
+
+Setup the Serial NAND Flash Interface (SNFI) controller, enable
+hardware BCH error detection and correction engine and add the SPI-NAND
+chip including basic partitions,
+
+Signed-off-by: Daniel Golle <daniel@makrotopia.org>
+Link: https://lore.kernel.org/r/ZEA96dmaXqTpk8u8@makrotopia.org
+Signed-off-by: Matthias Brugger <matthias.bgg@gmail.com>
+---
+ .../dts/mediatek/mt7622-bananapi-bpi-r64.dts | 38 ++++++++++++++++---
+ 1 file changed, 33 insertions(+), 5 deletions(-)
+
+--- a/arch/arm64/boot/dts/mediatek/mt7622-bananapi-bpi-r64.dts
++++ b/arch/arm64/boot/dts/mediatek/mt7622-bananapi-bpi-r64.dts
+@@ -253,14 +253,42 @@
+ status = "disabled";
+ };
+
+-&nor_flash {
+- pinctrl-names = "default";
+- pinctrl-0 = <&spi_nor_pins>;
+- status = "disabled";
++&bch {
++ status = "okay";
++};
+
++&snfi {
++ pinctrl-names = "default";
++ pinctrl-0 = <&serial_nand_pins>;
++ status = "okay";
+ flash@0 {
+- compatible = "jedec,spi-nor";
++ compatible = "spi-nand";
+ reg = <0>;
++ spi-tx-bus-width = <4>;
++ spi-rx-bus-width = <4>;
++ nand-ecc-engine = <&snfi>;
++ partitions {
++ compatible = "fixed-partitions";
++ #address-cells = <1>;
++ #size-cells = <1>;
++
++ partition@0 {
++ label = "bl2";
++ reg = <0x0 0x80000>;
++ read-only;
++ };
++
++ partition@80000 {
++ label = "fip";
++ reg = <0x80000 0x200000>;
++ read-only;
++ };
++
++ ubi: partition@280000 {
++ label = "ubi";
++ reg = <0x280000 0x7d80000>;
++ };
++ };
+ };
+ };
+
--- /dev/null
+--- a/drivers/mtd/nand/spi/core.c
++++ b/drivers/mtd/nand/spi/core.c
+@@ -724,7 +724,7 @@ static int spinand_mtd_write(struct mtd_
+ static bool spinand_isbad(struct nand_device *nand, const struct nand_pos *pos)
+ {
+ struct spinand_device *spinand = nand_to_spinand(nand);
+- u8 marker[2] = { };
++ u8 marker[1] = { };
+ struct nand_page_io_req req = {
+ .pos = *pos,
+ .ooblen = sizeof(marker),
+@@ -735,7 +735,7 @@ static bool spinand_isbad(struct nand_de
+
+ spinand_select_target(spinand, pos->target);
+ spinand_read_page(spinand, &req);
+- if (marker[0] != 0xff || marker[1] != 0xff)
++ if (marker[0] != 0xff)
+ return true;
+
+ return false;
--- /dev/null
+From c813fbe806257c574240770ef716fbee19f7dbfa Mon Sep 17 00:00:00 2001
+From: Xiangsheng Hou <xiangsheng.hou@mediatek.com>
+Date: Thu, 6 Jun 2019 16:29:04 +0800
+Subject: [PATCH] spi: spi-mem: Mediatek: Add SPI Nand support for MT7629
+
+Signed-off-by: Xiangsheng Hou <xiangsheng.hou@mediatek.com>
+---
+ arch/arm/boot/dts/mt7629-rfb.dts | 45 ++++++++++++++++++++++++++++++++
+ arch/arm/boot/dts/mt7629.dtsi | 22 ++++++++++++++++
+ 3 files changed, 79 insertions(+)
+
+--- a/arch/arm/boot/dts/mt7629.dtsi
++++ b/arch/arm/boot/dts/mt7629.dtsi
+@@ -272,6 +272,27 @@
+ status = "disabled";
+ };
+
++ snfi: spi@1100d000 {
++ compatible = "mediatek,mt7629-snand";
++ reg = <0x1100d000 0x1000>;
++ interrupts = <GIC_SPI 96 IRQ_TYPE_LEVEL_LOW>;
++ clocks = <&pericfg CLK_PERI_NFI_PD>, <&pericfg CLK_PERI_SNFI_PD>;
++ clock-names = "nfi_clk", "pad_clk";
++ nand-ecc-engine = <&bch>;
++ #address-cells = <1>;
++ #size-cells = <0>;
++ status = "disabled";
++ };
++
++ bch: ecc@1100e000 {
++ compatible = "mediatek,mt7622-ecc";
++ reg = <0x1100e000 0x1000>;
++ interrupts = <GIC_SPI 95 IRQ_TYPE_LEVEL_LOW>;
++ clocks = <&pericfg CLK_PERI_NFIECC_PD>;
++ clock-names = "nfiecc_clk";
++ status = "disabled";
++ };
++
+ spi: spi@1100a000 {
+ compatible = "mediatek,mt7629-spi",
+ "mediatek,mt7622-spi";
+--- a/arch/arm/boot/dts/mt7629-rfb.dts
++++ b/arch/arm/boot/dts/mt7629-rfb.dts
+@@ -255,6 +255,50 @@
+ };
+ };
+
++&bch {
++ status = "okay";
++};
++
++&snfi {
++ pinctrl-names = "default";
++ pinctrl-0 = <&serial_nand_pins>;
++ status = "okay";
++ flash@0 {
++ compatible = "spi-nand";
++ reg = <0>;
++ spi-tx-bus-width = <4>;
++ spi-rx-bus-width = <4>;
++ nand-ecc-engine = <&snfi>;
++
++ partitions {
++ compatible = "fixed-partitions";
++ #address-cells = <1>;
++ #size-cells = <1>;
++
++ partition@0 {
++ label = "Bootloader";
++ reg = <0x00000 0x0100000>;
++ read-only;
++ };
++
++ partition@100000 {
++ label = "Config";
++ reg = <0x100000 0x0040000>;
++ };
++
++ partition@140000 {
++ label = "factory";
++ reg = <0x140000 0x0080000>;
++ };
++
++ partition@1c0000 {
++ label = "firmware";
++ reg = <0x1c0000 0x1000000>;
++ };
++ };
++ };
++};
++
+ &spi {
+ pinctrl-names = "default";
+ pinctrl-0 = <&spi_pins>;
--- /dev/null
+--- a/arch/arm64/boot/dts/mediatek/mt7622-rfb1.dts
++++ b/arch/arm64/boot/dts/mediatek/mt7622-rfb1.dts
+@@ -534,6 +534,65 @@
+ status = "disabled";
+ };
+
++&bch {
++ status = "okay";
++};
++
++&snfi {
++ pinctrl-names = "default";
++ pinctrl-0 = <&serial_nand_pins>;
++ status = "okay";
++ flash@0 {
++ compatible = "spi-nand";
++ reg = <0>;
++ spi-tx-bus-width = <4>;
++ spi-rx-bus-width = <4>;
++ nand-ecc-engine = <&snfi>;
++
++ partitions {
++ compatible = "fixed-partitions";
++ #address-cells = <1>;
++ #size-cells = <1>;
++
++ partition@0 {
++ label = "Preloader";
++ reg = <0x00000 0x0080000>;
++ read-only;
++ };
++
++ partition@80000 {
++ label = "ATF";
++ reg = <0x80000 0x0040000>;
++ };
++
++ partition@c0000 {
++ label = "Bootloader";
++ reg = <0xc0000 0x0080000>;
++ };
++
++ partition@140000 {
++ label = "Config";
++ reg = <0x140000 0x0080000>;
++ };
++
++ partition@1c0000 {
++ label = "Factory";
++ reg = <0x1c0000 0x0100000>;
++ };
++
++ partition@200000 {
++ label = "firmware";
++ reg = <0x2c0000 0x2000000>;
++ };
++
++ partition@2200000 {
++ label = "User_data";
++ reg = <0x22c0000 0x4000000>;
++ };
++ };
++ };
++};
++
+ &spi0 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&spic0_pins>;
--- /dev/null
+--- a/arch/arm64/boot/dts/mediatek/mt7622-rfb1.dts
++++ b/arch/arm64/boot/dts/mediatek/mt7622-rfb1.dts
+@@ -575,7 +575,7 @@
+ reg = <0x140000 0x0080000>;
+ };
+
+- partition@1c0000 {
++ factory: partition@1c0000 {
+ label = "Factory";
+ reg = <0x1c0000 0x0100000>;
+ };
+@@ -636,5 +636,6 @@
+ &wmac {
+ pinctrl-names = "default";
+ pinctrl-0 = <&wmac_pins>;
++ mediatek,mtd-eeprom = <&factory 0x0000>;
+ status = "okay";
+ };
--- /dev/null
+--- a/arch/arm/boot/dts/mt7623.dtsi
++++ b/arch/arm/boot/dts/mt7623.dtsi
+@@ -984,17 +984,15 @@
+ };
+
+ crypto: crypto@1b240000 {
+- compatible = "mediatek,eip97-crypto";
++ compatible = "inside-secure,safexcel-eip97";
+ reg = <0 0x1b240000 0 0x20000>;
+ interrupts = <GIC_SPI 82 IRQ_TYPE_LEVEL_LOW>,
+ <GIC_SPI 83 IRQ_TYPE_LEVEL_LOW>,
+ <GIC_SPI 84 IRQ_TYPE_LEVEL_LOW>,
+- <GIC_SPI 91 IRQ_TYPE_LEVEL_LOW>,
+- <GIC_SPI 97 IRQ_TYPE_LEVEL_LOW>;
++ <GIC_SPI 91 IRQ_TYPE_LEVEL_LOW>;
++ interrupt-names = "ring0", "ring1", "ring2", "ring3";
+ clocks = <ðsys CLK_ETHSYS_CRYPTO>;
+- clock-names = "cryp";
+- power-domains = <&scpsys MT2701_POWER_DOMAIN_ETH>;
+- status = "disabled";
++ status = "okay";
+ };
+
+ bdpsys: syscon@1c000000 {
--- /dev/null
+--- a/arch/arm/boot/dts/mt7623n-bananapi-bpi-r2.dts
++++ b/arch/arm/boot/dts/mt7623n-bananapi-bpi-r2.dts
+@@ -19,7 +19,7 @@
+
+ chosen {
+ stdout-path = "serial2:115200n8";
+- bootargs = "console=ttyS2,115200n8 console=tty1";
++ bootargs = "earlycon=uart8250,mmio32,0x11004000 console=ttyS2,115200n8 console=tty1";
+ };
+
+ connector {
--- /dev/null
+--- a/arch/arm/boot/dts/mt7623n-bananapi-bpi-r2.dts
++++ b/arch/arm/boot/dts/mt7623n-bananapi-bpi-r2.dts
+@@ -15,6 +15,8 @@
+
+ aliases {
+ serial2 = &uart2;
++ mmc0 = &mmc0;
++ mmc1 = &mmc1;
+ };
+
+ chosen {
--- /dev/null
+--- a/arch/arm/boot/dts/mt7623n-bananapi-bpi-r2.dts
++++ b/arch/arm/boot/dts/mt7623n-bananapi-bpi-r2.dts
+@@ -17,6 +17,10 @@
+ serial2 = &uart2;
+ mmc0 = &mmc0;
+ mmc1 = &mmc1;
++ led-boot = &led_system_green;
++ led-failsafe = &led_system_blue;
++ led-running = &led_system_green;
++ led-upgrade = &led_system_blue;
+ };
+
+ chosen {
+@@ -112,13 +116,13 @@
+ pinctrl-names = "default";
+ pinctrl-0 = <&led_pins_a>;
+
+- blue {
++ led_system_blue: blue {
+ label = "bpi-r2:pio:blue";
+ gpios = <&pio 240 GPIO_ACTIVE_LOW>;
+ default-state = "off";
+ };
+
+- green {
++ led_system_green: green {
+ label = "bpi-r2:pio:green";
+ gpios = <&pio 241 GPIO_ACTIVE_LOW>;
+ default-state = "off";
--- /dev/null
+--- a/arch/arm/boot/dts/mt7623n-bananapi-bpi-r2.dts
++++ b/arch/arm/boot/dts/mt7623n-bananapi-bpi-r2.dts
+@@ -15,6 +15,7 @@
+
+ aliases {
+ serial2 = &uart2;
++ ethernet0 = &gmac0;
+ mmc0 = &mmc0;
+ mmc1 = &mmc1;
+ led-boot = &led_system_green;
--- /dev/null
+--- a/arch/arm/boot/dts/mt7623n-bananapi-bpi-r2.dts
++++ b/arch/arm/boot/dts/mt7623n-bananapi-bpi-r2.dts
+@@ -26,7 +26,9 @@
+
+ chosen {
+ stdout-path = "serial2:115200n8";
+- bootargs = "earlycon=uart8250,mmio32,0x11004000 console=ttyS2,115200n8 console=tty1";
++ bootargs = "root=/dev/fit0 earlycon=uart8250,mmio32,0x11004000 console=ttyS2,115200n8 console=tty1";
++ rootdisk-emmc = <&emmc_rootdisk>;
++ rootdisk-sd = <&sd_rootdisk>;
+ };
+
+ connector {
+@@ -315,6 +317,20 @@
+ vmmc-supply = <®_3p3v>;
+ vqmmc-supply = <®_1p8v>;
+ non-removable;
++
++ card@0 {
++ compatible = "mmc-card";
++ reg = <0>;
++
++ block {
++ compatible = "block-device";
++ partitions {
++ emmc_rootdisk: block-partition-fit {
++ partno = <3>;
++ };
++ };
++ };
++ };
+ };
+
+ &mmc1 {
+@@ -328,6 +344,20 @@
+ cd-gpios = <&pio 261 GPIO_ACTIVE_LOW>;
+ vmmc-supply = <®_3p3v>;
+ vqmmc-supply = <®_3p3v>;
++
++ card@0 {
++ compatible = "mmc-card";
++ reg = <0>;
++
++ block {
++ compatible = "block-device";
++ partitions {
++ sd_rootdisk: block-partition-fit {
++ partno = <3>;
++ };
++ };
++ };
++ };
+ };
+
+ &mt6323_leds {
--- /dev/null
+From 983f37ee08acb60435744f1b1e2afea2d2a09c48 Mon Sep 17 00:00:00 2001
+From: Daniel Golle <daniel@makrotopia.org>
+Date: Wed, 19 Apr 2023 20:16:29 +0100
+Subject: [PATCH] arm64: dts: mt7622: handle interrupts from MT7531 switch on
+ BPI-R64
+
+Since commit ba751e28d442 ("net: dsa: mt7530: add interrupt support")
+the mt7530 driver can act as an interrupt controller. Wire up irq line
+of the MT7531 switch on the BananaPi BPi-R64 board, so the status of
+the PHYs of the five 1000Base-T ports doesn't need to be polled any
+more.
+
+Signed-off-by: Daniel Golle <daniel@makrotopia.org>
+Link: https://lore.kernel.org/r/ZEA-DV_OsmFg5egL@makrotopia.org
+Signed-off-by: Matthias Brugger <matthias.bgg@gmail.com>
+---
+ arch/arm64/boot/dts/mediatek/mt7622-bananapi-bpi-r64.dts | 4 ++++
+ 1 file changed, 4 insertions(+)
+
+--- a/arch/arm64/boot/dts/mediatek/mt7622-bananapi-bpi-r64.dts
++++ b/arch/arm64/boot/dts/mediatek/mt7622-bananapi-bpi-r64.dts
+@@ -154,6 +154,10 @@
+ switch@0 {
+ compatible = "mediatek,mt7531";
+ reg = <0>;
++ interrupt-controller;
++ #interrupt-cells = <1>;
++ interrupt-parent = <&pio>;
++ interrupts = <53 IRQ_TYPE_LEVEL_HIGH>;
+ reset-gpios = <&pio 54 0>;
+
+ ports {
--- /dev/null
+From patchwork Tue Apr 26 19:51:36 2022
+Content-Type: text/plain; charset="utf-8"
+MIME-Version: 1.0
+Content-Transfer-Encoding: 7bit
+X-Patchwork-Submitter: Daniel Golle <daniel@makrotopia.org>
+X-Patchwork-Id: 12827872
+Return-Path:
+ <linux-arm-kernel-bounces+linux-arm-kernel=archiver.kernel.org@lists.infradead.org>
+X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on
+ aws-us-west-2-korg-lkml-1.web.codeaurora.org
+Received: from bombadil.infradead.org (bombadil.infradead.org
+ [198.137.202.133])
+ (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits))
+ (No client certificate requested)
+ by smtp.lore.kernel.org (Postfix) with ESMTPS id BACF3C433EF
+ for <linux-arm-kernel@archiver.kernel.org>;
+ Tue, 26 Apr 2022 19:53:05 +0000 (UTC)
+DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed;
+ d=lists.infradead.org; s=bombadil.20210309; h=Sender:
+ Content-Transfer-Encoding:Content-Type:List-Subscribe:List-Help:List-Post:
+ List-Archive:List-Unsubscribe:List-Id:MIME-Version:Message-ID:Subject:Cc:To:
+ From:Date:Reply-To:Content-ID:Content-Description:Resent-Date:Resent-From:
+ Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID:In-Reply-To:References:
+ List-Owner; bh=OWGSxvlKoyPWz6b629RNINucULo6oOdFssAIiJETWRg=; b=T0HEjee0FX3hlb
+ x5jl7xLK5sKM0pkE2oRgwzthbFlNg8ST1j/2GkgcgT0S2Bi0vRfFxHeu/RKzS9RmiVnKJnPGL8ctg
+ WoBLyO5i+NcmosGoy6MmoOjGTNhj/+3q3Z1jRLBSJ4ySSP22X77YeuJTmVzySPUllQhWvDhjMVCR9
+ QBRmQdc6gCAg3IYGEbWwS2TG+UHveDCeZRWxMzrwI8UPadNCRFROwugmiQ3mdU41lHCTDpnlfuRJh
+ o1igLKfMBLz+D8rFYvDh7FfkcKkY6lNoswA2HKUun1MEzgoyQKmITPnG2maX/BvJJuj/B3ZJShh4k
+ AZHmXoQxq1mrsm2FxfnQ==;
+Received: from localhost ([::1] helo=bombadil.infradead.org)
+ by bombadil.infradead.org with esmtp (Exim 4.94.2 #2 (Red Hat Linux))
+ id 1njRE5-00G05D-9z; Tue, 26 Apr 2022 19:51:57 +0000
+Received: from fudo.makrotopia.org ([2a07:2ec0:3002::71])
+ by bombadil.infradead.org with esmtps (Exim 4.94.2 #2 (Red Hat Linux))
+ id 1njRE1-00G03h-9H; Tue, 26 Apr 2022 19:51:55 +0000
+Received: from local
+ by fudo.makrotopia.org with esmtpsa (TLS1.3:TLS_AES_256_GCM_SHA384:256)
+ (Exim 4.94.2) (envelope-from <daniel@makrotopia.org>)
+ id 1njRDu-0006aF-4F; Tue, 26 Apr 2022 21:51:46 +0200
+Date: Tue, 26 Apr 2022 20:51:36 +0100
+From: Daniel Golle <daniel@makrotopia.org>
+To: devicetree@vger.kernel.org, linux-mediatek@lists.infradead.org,
+ linux-arm-kernel@lists.infradead.org, linux-kernel@vger.kernel.org
+Cc: Rob Herring <robh+dt@kernel.org>,
+ Krzysztof Kozlowski <krzysztof.kozlowski+dt@linaro.org>,
+ Matthias Brugger <matthias.bgg@gmail.com>
+Subject: [PATCH] arm64: dts: mediatek: mt7622: fix GICv2 range
+Message-ID: <YmhNSLgp/yg8Vr1F@makrotopia.org>
+MIME-Version: 1.0
+Content-Disposition: inline
+X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3
+X-CRM114-CacheID: sfid-20220426_125153_359242_EA3D452C
+X-CRM114-Status: GOOD ( 12.45 )
+X-BeenThere: linux-arm-kernel@lists.infradead.org
+X-Mailman-Version: 2.1.34
+Precedence: list
+List-Id: <linux-arm-kernel.lists.infradead.org>
+List-Unsubscribe:
+ <http://lists.infradead.org/mailman/options/linux-arm-kernel>,
+ <mailto:linux-arm-kernel-request@lists.infradead.org?subject=unsubscribe>
+List-Archive: <http://lists.infradead.org/pipermail/linux-arm-kernel/>
+List-Post: <mailto:linux-arm-kernel@lists.infradead.org>
+List-Help: <mailto:linux-arm-kernel-request@lists.infradead.org?subject=help>
+List-Subscribe:
+ <http://lists.infradead.org/mailman/listinfo/linux-arm-kernel>,
+ <mailto:linux-arm-kernel-request@lists.infradead.org?subject=subscribe>
+Sender: "linux-arm-kernel" <linux-arm-kernel-bounces@lists.infradead.org>
+Errors-To:
+ linux-arm-kernel-bounces+linux-arm-kernel=archiver.kernel.org@lists.infradead.org
+
+With the current range specified for the CPU interface there is an
+error message at boot:
+
+GIC: GICv2 detected, but range too small and irqchip.gicv2_force_probe not set
+
+Setting irqchip.gicv2_force_probe=1 in bootargs results in:
+
+GIC: Aliased GICv2 at 0x0000000010320000, trying to find the canonical range over 128kB
+GIC: Adjusting CPU interface base to 0x000000001032f000
+GIC: Using split EOI/Deactivate mode
+
+Using the adjusted CPU interface base and 8K size results in only the
+final line remaining and fully working system as well as /proc/interrupts
+showing additional IPI3,4,5,6:
+
+IPI3: 0 0 CPU stop (for crash dump) interrupts
+IPI4: 0 0 Timer broadcast interrupts
+IPI5: 0 0 IRQ work interrupts
+IPI6: 0 0 CPU wake-up interrupts
+
+Signed-off-by: Daniel Golle <daniel@makrotopia.org>
+---
+ arch/arm64/boot/dts/mediatek/mt7622.dtsi | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/arch/arm64/boot/dts/mediatek/mt7622.dtsi
++++ b/arch/arm64/boot/dts/mediatek/mt7622.dtsi
+@@ -346,7 +346,7 @@
+ #interrupt-cells = <3>;
+ interrupt-parent = <&gic>;
+ reg = <0 0x10310000 0 0x1000>,
+- <0 0x10320000 0 0x1000>,
++ <0 0x1032f000 0 0x2000>,
+ <0 0x10340000 0 0x2000>,
+ <0 0x10360000 0 0x2000>;
+ };
--- /dev/null
+From 824d56e753a588fcfd650db1822e34a02a48bb77 Mon Sep 17 00:00:00 2001
+From: Bruno Umuarama <anonimou_eu@hotmail.com>
+Date: Thu, 13 Oct 2022 21:18:21 +0000
+Subject: [PATCH] mediatek: mt7623: fix thermal zone
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Raising the temperatures for passive and active trips. @VA1DER
+proposed at issue 9396 to remove passive trip. This commit relates to
+his suggestion.
+
+Without this patch. the CPU will be throttled all the way down to 98MHz
+if the temperature rises even a degree above the trip point, and it was
+further discovered that if the internal temperature of the device is
+above the first trip point temperature when it boots then it will start
+in a throttled state and even
+$ echo disabled > /sys/class/thermal/thermal_zone0/mode
+will have no effect.
+
+The patch increases the passive trip point and active cooling map. The
+throttling temperature will then be at 77°C and 82°C, which is still a
+low enough temperature for ARM devices to not be in the real danger
+zone, and gives some operational headroom.
+
+Signed-off-by: Bruno Umuarama <anonimou_eu@hotmail.com>
+---
+ arch/arm/boot/dts/mt7623.dtsi | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+--- a/arch/arm/boot/dts/mt7623.dtsi
++++ b/arch/arm/boot/dts/mt7623.dtsi
+@@ -160,13 +160,13 @@
+
+ trips {
+ cpu_passive: cpu-passive {
+- temperature = <57000>;
++ temperature = <77000>;
+ hysteresis = <2000>;
+ type = "passive";
+ };
+
+ cpu_active: cpu-active {
+- temperature = <67000>;
++ temperature = <82000>;
+ hysteresis = <2000>;
+ type = "active";
+ };
--- /dev/null
+--- a/arch/arm64/boot/dts/mediatek/mt7986a.dtsi
++++ b/arch/arm64/boot/dts/mediatek/mt7986a.dtsi
+@@ -68,6 +68,14 @@
+ #address-cells = <2>;
+ #size-cells = <2>;
+ ranges;
++
++ /* 64 KiB reserved for ramoops/pstore */
++ ramoops@42ff0000 {
++ compatible = "ramoops";
++ reg = <0 0x42ff0000 0 0x10000>;
++ record-size = <0x1000>;
++ };
++
+ /* 192 KiB reserved for ARM Trusted Firmware (BL31) */
+ secmon_reserved: secmon@43000000 {
+ reg = <0 0x43000000 0 0x30000>;
--- /dev/null
+--- a/arch/arm64/boot/dts/mediatek/mt7986a-bananapi-bpi-r3.dts
++++ b/arch/arm64/boot/dts/mediatek/mt7986a-bananapi-bpi-r3.dts
+@@ -23,6 +23,10 @@
+ serial0 = &uart0;
+ ethernet0 = &gmac0;
+ ethernet1 = &gmac1;
++ led-boot = &green_led;
++ led-failsafe = &green_led;
++ led-running = &green_led;
++ led-upgrade = &blue_led;
+ };
+
+ chosen {
+@@ -419,27 +423,27 @@
+
+ port@1 {
+ reg = <1>;
+- label = "lan0";
++ label = "lan1";
+ };
+
+ port@2 {
+ reg = <2>;
+- label = "lan1";
++ label = "lan2";
+ };
+
+ port@3 {
+ reg = <3>;
+- label = "lan2";
++ label = "lan3";
+ };
+
+ port@4 {
+ reg = <4>;
+- label = "lan3";
++ label = "lan4";
+ };
+
+ port5: port@5 {
+ reg = <5>;
+- label = "lan4";
++ label = "sfp2";
+ phy-mode = "2500base-x";
+ sfp = <&sfp2>;
+ managed = "in-band-status";
+@@ -490,9 +494,137 @@
+
+ &wifi {
+ status = "okay";
+- pinctrl-names = "default", "dbdc";
++ pinctrl-names = "default";
+ pinctrl-0 = <&wf_2g_5g_pins>, <&wf_led_pins>;
+- pinctrl-1 = <&wf_dbdc_pins>, <&wf_led_pins>;
++
++ mediatek,eeprom-data = <0x86790900 0x000c4326 0x60000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000
++ 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000
++ 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x01000000
++ 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000
++ 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000
++ 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000
++ 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000
++ 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000
++ 0x00000000 0x00000800 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000
++ 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000
++ 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000
++ 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000
++ 0x00000000 0x00000000 0x00000000 0x00000000 0x24649090 0x00280000 0x05100000 0x00000000
++ 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000
++ 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000
++ 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000
++ 0x00021e00 0x021e0002 0x1e00021e 0x00022800 0x02280002 0x28000228 0x00000000 0x00000000
++ 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00008080 0x8080fdf7
++ 0x0903150d 0x80808080 0x80808080 0x05050d0d 0x1313c6c6 0xc3c3c200 0x00c200c2 0x00008182
++ 0x8585c2c2 0x82828282 0x858500c2 0xc2000081 0x82858587 0x87c2c200 0x81818285 0x858787c2
++ 0xc2000081 0x82858587 0x87c2c200 0x00818285 0x858787c2 0xc2000081 0x82858587 0x87c4c4c2
++ 0xc100c300 0xc3c3c100 0x818383c3 0xc3c3c100 0x81838300 0xc2c2c2c0 0x81828484 0x000000c3
++ 0xc3c3c100 0x81838386 0x86c3c3c3 0xc1008183 0x838686c2 0xc2c2c081 0x82848486 0x86c3c3c3
++ 0xc1008183 0x838686c3 0xc3c3c100 0x81838386 0x86c3c3c3 0xc1008183 0x83868622 0x28002228
++ 0x00222800 0x22280000 0xdddddddd 0xdddddddd 0xddbbbbbb 0xccccccdd 0xdddddddd 0xdddddddd
++ 0xeeeeeecc 0xccccdddd 0xdddddddd 0x004a5662 0x0000004a 0x56620000 0x004a5662 0x0000004a
++ 0x56620000 0x88888888 0x33333326 0x26262626 0x26262600 0x33333326 0x26262626 0x26262600
++ 0x33333326 0x26262626 0x26262600 0x33333326 0x26262626 0x26262600 0x00000000 0xf0f0cc00
++ 0x00000000 0x0000aaaa 0xaabbbbbb 0xcccccccc 0xccccbbbb 0xbbbbbbbb 0xbbbbbbaa 0xaaaabbbb
++ 0xbbaaaaaa 0x999999aa 0xaaaabbbb 0xbbcccccc 0x00000000 0x0000aaaa 0xaa000000 0xbbbbbbbb
++ 0xbbbbaaaa 0xaa999999 0xaaaaaaaa 0xaaaaaaaa 0xaaaaaaaa 0xaaaaaaaa 0xaaaabbbb 0xbbbbbbbb
++ 0x00000000 0x00000000 0x00000000 0x99999999 0x9999aaaa 0xaaaaaaaa 0x999999aa 0xaaaaaaaa
++ 0xaaaaaaaa 0xaaaaaaaa 0xaaaabbbb 0xbbbbbbbb 0x00000000 0x0000eeee 0xeeffffff 0xcccccccc
++ 0xccccdddd 0xddbbbbbb 0xccccccbb 0xbbbbbbbb 0xbbbbbbbb 0xbbbbbbbb 0xbbbbcccc 0xccdddddd
++ 0x00516200 0x686e0051 0x6200686e 0x00516200 0x686e0051 0x6200686e 0x00516200 0x686e0051
++ 0x6200686e 0x00516200 0x686e0051 0x6200686e 0x00516200 0x686e0051 0x6200686e 0x00516200
++ 0x686e0051 0x6200686e 0x00516200 0x686e0051 0x6200686e 0x00516200 0x686e0051 0x6200686e
++ 0x00516200 0x686e0051 0x6200686e 0x00516200 0x686e0051 0x6200686e 0x00516200 0x686e0051
++ 0x6200686e 0x00516200 0x686e0051 0x6200686e 0x00516200 0x686e0051 0x6200686e 0x00516200
++ 0x686e0051 0x6200686e 0x00516200 0x686e0051 0x6200686e 0x00516200 0x686e0051 0x6200686e
++ 0x88888888 0x88888888 0x88888888 0x88888888 0x88888888 0x88888888 0x88888888 0x88888888
++ 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000
++ 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000
++ 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000
++ 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000
++ 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000
++ 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000
++ 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000
++ 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000
++ 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000
++ 0x00000000 0x00000000 0x00000000 0x00000000 0x00000001 0x06000100 0x01050002 0x00ff0300
++ 0xf900fe03 0x00000000 0x00000000 0x0000009b 0x6e370000 0x00000000 0x00fc0009 0x0a00fe00
++ 0x060700fe 0x00070800 0x05000b0a 0x00000000 0x00000000 0x000000e2 0x96460000 0x00000000
++ 0x000400f7 0xf8000300 0xfcfe0003 0x00fbfc00 0xee00e3f2 0x00000000 0x00000000 0x00000011
++ 0xbb550000 0x00000000 0x000600f6 0xfc000300 0xfbfe0004 0x00fafe00 0xf600ecf2 0x00000000
++ 0x00000000 0x0000001f 0xbf580000 0x00000000 0x000600f5 0xf6000400 0xf8f90004 0x00f7f800
++ 0xf700f0f4 0x00000000 0x00000000 0x00000024 0xbe570000 0x00000000 0x000800f8 0xfe000600
++ 0xf8fd0007 0x00f9fe00 0xf500f0f4 0x00000000 0x00000000 0x0000002d 0xd6610000 0x00000000
++ 0x000400f7 0xfc000500 0xf7fc0005 0x00f7fc00 0xf900f5f8 0x00000000 0x00000000 0x00000026
++ 0xd96e0000 0x00000000 0x000400f7 0xf9000600 0xf5f70005 0x00f5f800 0xf900f4f7 0x00000000
++ 0x00000000 0x0000001b 0xce690000 0x00000000 0x000300f8 0xf8000600 0xf6f60004 0x00f6f700
++ 0xf900f4f7 0x00000000 0x00000000 0x00000018 0xd8720000 0x00000000 0x00000000 0x02404002
++ 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000
++ 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000
++ 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000
++ 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000
++ 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000
++ 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000
++ 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000
++ 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000
++ 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000
++ 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000
++ 0xc1c2c1c2 0x41c341c3 0x3fc13fc1 0x40c13fc2 0x3fc240c1 0x41c040c0 0x3fc23fc2 0x40c13fc2
++ 0x3fc140c0 0x41c040c0 0x3fc33fc3 0x40c23fc2 0x3fc240c1 0x41c040c0 0x3fc23fc2 0x40c23fc2
++ 0x3fc140c1 0x41c040c0 0x00000000 0x00000000 0x41c741c7 0xc1c7c1c7 0x00000000 0x00000000
++ 0x3fc03fc0 0x3fc03fc0 0x3fc03fc0 0x3fc03fc0 0x3fc03fc0 0x3fc03fc0 0x3fc03fc0 0x3fc03fc0
++ 0x3fc03fc0 0x3fc03fc0 0x3fc03fc0 0x3fc03fc0 0x3fc03fc0 0x3fc03fc0 0x3fc03fc0 0x3fc03fc0
++ 0x00a0ce00 0x00000000 0xb6840000 0x00000000 0x00000000 0x00000000 0x18181818 0x18181818
++ 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000
++ 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000
++ 0x004b5763 0x0000004b 0x57630000 0x004b5763 0x0000004b 0x57630000 0x88888888 0x08474759
++ 0x69780849 0x49596d7a 0x0849495a 0x6d790848 0x48596c78 0x08484858 0x6a780848 0x48586a78
++ 0x08484858 0x6c78084a 0x4a5b6d79 0x08474759 0x697a0848 0x48596b79 0x08484859 0x6c7a0848
++ 0x48586c79 0x08484857 0x68770848 0x48576877 0x08484857 0x6a77084a 0x4a5a6a77 0x08464659
++ 0x69790848 0x48586b79 0x08484858 0x6c7a0848 0x48596c79 0x08484857 0x68770848 0x48576877
++ 0x08494958 0x6d7a084b 0x4b5c6c77 0x0847475a 0x6a7b0849 0x495a6e7c 0x0849495a 0x6e7c0849
++ 0x495b6e7c 0x08494959 0x6a7a0849 0x49596a7a 0x084a4a5a 0x6f7d084b 0x4b5c6e7b 0x00000000
++ 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x85848484
++ 0xc3c4c4c5 0xc4c3c33f 0xc3c3c2c2 0xc2c2c03f 0xc3c3c3c4 0xc4c4c33f 0xc2c2c2c2 0xc1c3c1c1
++ 0xc0c08282 0x83848686 0x88880000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000
++ 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000
++ 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000
++ 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000
++ 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000
++ 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000
++ 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000
++ 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000
++ 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000
++ 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000
++ 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000
++ 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000
++ 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000
++ 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000
++ 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000
++ 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000
++ 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000
++ 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000
++ 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00001111 0x00000000
++ 0x8080f703 0x10808080 0x80050d13 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000
++ 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000
++ 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000
++ 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000
++ 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000
++ 0x00000000 0x00000000 0x00000000 0x000000a4 0xce000000 0x0000b684 0x00000000 0x00000000
++ 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000
++ 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000
++ 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000
++ 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000
++ 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000
++ 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000
++ 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000
++ 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000
++ 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000
++ 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000
++ 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000
++ 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000
++ 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000
++ 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000>;
+
+ led {
+ led-active-low;
+--- a/arch/arm64/boot/dts/mediatek/mt7986a-bananapi-bpi-r3-nor.dtso
++++ b/arch/arm64/boot/dts/mediatek/mt7986a-bananapi-bpi-r3-nor.dtso
+@@ -55,6 +55,7 @@
+ partition@c00000 {
+ label = "fit";
+ reg = <0xc00000 0x1400000>;
++ compatible = "denx,fit";
+ };
+ };
+ };
--- /dev/null
+--- a/arch/arm64/boot/dts/mediatek/mt7986a-bananapi-bpi-r3-emmc.dtso
++++ b/arch/arm64/boot/dts/mediatek/mt7986a-bananapi-bpi-r3-emmc.dtso
+@@ -23,7 +23,27 @@
+ no-sd;
+ no-sdio;
+ status = "okay";
++
++ card@0 {
++ compatible = "mmc-card";
++ reg = <0>;
++
++ block {
++ compatible = "block-device";
++ partitions {
++ emmc_rootdisk: block-partition-production {
++ partname = "production";
++ };
++ };
++ };
++ };
+ };
+ };
+-};
+
++ fragment@1 {
++ target-path = "/chosen";
++ __overlay__ {
++ rootdisk-emmc = <&emmc_rootdisk>;
++ };
++ };
++};
+--- a/arch/arm64/boot/dts/mediatek/mt7986a-bananapi-bpi-r3-nand.dtso
++++ b/arch/arm64/boot/dts/mediatek/mt7986a-bananapi-bpi-r3-nand.dtso
+@@ -29,27 +29,30 @@
+
+ partition@0 {
+ label = "bl2";
+- reg = <0x0 0x100000>;
++ reg = <0x0 0x200000>;
+ read-only;
+ };
+
+- partition@100000 {
+- label = "reserved";
+- reg = <0x100000 0x280000>;
+- };
+-
+- partition@380000 {
+- label = "fip";
+- reg = <0x380000 0x200000>;
+- read-only;
+- };
+-
+- partition@580000 {
++ partition@200000 {
+ label = "ubi";
+- reg = <0x580000 0x7a80000>;
++ reg = <0x200000 0x7e00000>;
++ compatible = "linux,ubi";
++
++ volumes {
++ nand_rootdisk: ubi-volume-fit {
++ volname = "fit";
++ };
++ };
+ };
+ };
+ };
+ };
+ };
++
++ fragment@1 {
++ target-path = "/chosen";
++ __overlay__ {
++ rootdisk-spim-nand = <&nand_rootdisk>;
++ };
++ };
+ };
+--- a/arch/arm64/boot/dts/mediatek/mt7986a-bananapi-bpi-r3-nor.dtso
++++ b/arch/arm64/boot/dts/mediatek/mt7986a-bananapi-bpi-r3-nor.dtso
+@@ -52,7 +52,7 @@
+ reg = <0x180000 0xa80000>;
+ };
+
+- partition@c00000 {
++ nor_rootdisk: partition@c00000 {
+ label = "fit";
+ reg = <0xc00000 0x1400000>;
+ compatible = "denx,fit";
+@@ -61,4 +61,11 @@
+ };
+ };
+ };
++
++ fragment@1 {
++ target-path = "/chosen";
++ __overlay__ {
++ rootdisk-nor = <&nor_rootdisk>;
++ };
++ };
+ };
+--- a/arch/arm64/boot/dts/mediatek/mt7986a-bananapi-bpi-r3-sd.dtso
++++ b/arch/arm64/boot/dts/mediatek/mt7986a-bananapi-bpi-r3-sd.dtso
+@@ -17,6 +17,27 @@
+ max-frequency = <52000000>;
+ cap-sd-highspeed;
+ status = "okay";
++
++ card@0 {
++ compatible = "mmc-card";
++ reg = <0>;
++
++ block {
++ compatible = "block-device";
++ partitions {
++ sd_rootdisk: block-partition-production {
++ partname = "production";
++ };
++ };
++ };
++ };
++ };
++ };
++
++ fragment@1 {
++ target-path = "/chosen";
++ __overlay__ {
++ rootdisk-sd = <&sd_rootdisk>;
+ };
+ };
+ };
--- /dev/null
+From 28f9a5e2a3f5441ab5594669ed82da11e32277a9 Mon Sep 17 00:00:00 2001
+From: Kristian Evensen <kristian.evensen@gmail.com>
+Date: Mon, 30 Apr 2018 14:38:01 +0200
+Subject: [PATCH] phy: phy-mtk-tphy: Add hifsys-support
+
+---
+ drivers/phy/mediatek/phy-mtk-tphy.c | 20 ++++++++++++++++++++
+ 1 file changed, 20 insertions(+)
+
+--- a/drivers/phy/mediatek/phy-mtk-tphy.c
++++ b/drivers/phy/mediatek/phy-mtk-tphy.c
+@@ -17,6 +17,8 @@
+ #include <linux/phy/phy.h>
+ #include <linux/platform_device.h>
+ #include <linux/regmap.h>
++#include <linux/mfd/syscon.h>
++#include <linux/regmap.h>
+
+ #include "phy-mtk-io.h"
+
+@@ -264,6 +266,9 @@
+
+ #define TPHY_CLKS_CNT 2
+
++#define HIF_SYSCFG1 0x14
++#define HIF_SYSCFG1_PHY2_MASK (0x3 << 20)
++
+ enum mtk_phy_version {
+ MTK_PHY_V1 = 1,
+ MTK_PHY_V2,
+@@ -331,6 +336,7 @@ struct mtk_tphy {
+ void __iomem *sif_base; /* only shared sif */
+ const struct mtk_phy_pdata *pdata;
+ struct mtk_phy_instance **phys;
++ struct regmap *hif;
+ int nphys;
+ int src_ref_clk; /* MHZ, reference clock for slew rate calibrate */
+ int src_coef; /* coefficient for slew rate calibrate */
+@@ -596,6 +602,10 @@ static void pcie_phy_instance_init(struc
+ if (tphy->pdata->version != MTK_PHY_V1)
+ return;
+
++ if (tphy->hif)
++ regmap_update_bits(tphy->hif, HIF_SYSCFG1,
++ HIF_SYSCFG1_PHY2_MASK, 0);
++
+ mtk_phy_update_bits(phya + U3P_U3_PHYA_DA_REG0,
+ P3A_RG_XTAL_EXT_PE1H | P3A_RG_XTAL_EXT_PE2H,
+ FIELD_PREP(P3A_RG_XTAL_EXT_PE1H, 0x2) |
+@@ -1241,6 +1251,16 @@ static int mtk_tphy_probe(struct platfor
+ &tphy->src_coef);
+ }
+
++ if (of_find_property(np, "mediatek,phy-switch", NULL)) {
++ tphy->hif = syscon_regmap_lookup_by_phandle(np,
++ "mediatek,phy-switch");
++ if (IS_ERR(tphy->hif)) {
++ dev_err(&pdev->dev,
++ "missing \"mediatek,phy-switch\" phandle\n");
++ return PTR_ERR(tphy->hif);
++ }
++ }
++
+ port = 0;
+ for_each_child_of_node(np, child_np) {
+ struct mtk_phy_instance *instance;
--- /dev/null
+From f76e8bc416bebb0f7b9f57b1247eae945421c0b9 Mon Sep 17 00:00:00 2001
+From: Sam Shih <sam.shih@mediatek.com>
+Date: Sat, 8 Oct 2022 18:48:06 +0200
+Subject: [PATCH 1/2] pinctrl: mt7986: allow configuring uart rx/tx and rts/cts
+ separately
+
+Some mt7986 boards use uart rts/cts pins as gpio,
+This patch allows to change rts/cts to gpio mode, but keep
+rx/tx as UART function.
+
+Signed-off-by: Frank Wunderlich <frank-w@public-files.de>
+Signed-off-by: Sam Shih <sam.shih@mediatek.com>
+Link: https://lore.kernel.org/r/20221008164807.113590-1-linux@fw-web.de
+Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
+---
+ drivers/pinctrl/mediatek/pinctrl-mt7986.c | 32 ++++++++++++++++++-----
+ 1 file changed, 25 insertions(+), 7 deletions(-)
+
+--- a/drivers/pinctrl/mediatek/pinctrl-mt7986.c
++++ b/drivers/pinctrl/mediatek/pinctrl-mt7986.c
+@@ -675,11 +675,17 @@ static int mt7986_uart1_1_funcs[] = { 4,
+ static int mt7986_spi1_2_pins[] = { 29, 30, 31, 32, };
+ static int mt7986_spi1_2_funcs[] = { 1, 1, 1, 1, };
+
+-static int mt7986_uart1_2_pins[] = { 29, 30, 31, 32, };
+-static int mt7986_uart1_2_funcs[] = { 3, 3, 3, 3, };
++static int mt7986_uart1_2_rx_tx_pins[] = { 29, 30, };
++static int mt7986_uart1_2_rx_tx_funcs[] = { 3, 3, };
+
+-static int mt7986_uart2_0_pins[] = { 29, 30, 31, 32, };
+-static int mt7986_uart2_0_funcs[] = { 4, 4, 4, 4, };
++static int mt7986_uart1_2_cts_rts_pins[] = { 31, 32, };
++static int mt7986_uart1_2_cts_rts_funcs[] = { 3, 3, };
++
++static int mt7986_uart2_0_rx_tx_pins[] = { 29, 30, };
++static int mt7986_uart2_0_rx_tx_funcs[] = { 4, 4, };
++
++static int mt7986_uart2_0_cts_rts_pins[] = { 31, 32, };
++static int mt7986_uart2_0_cts_rts_funcs[] = { 4, 4, };
+
+ static int mt7986_spi0_pins[] = { 33, 34, 35, 36, };
+ static int mt7986_spi0_funcs[] = { 1, 1, 1, 1, };
+@@ -708,6 +714,12 @@ static int mt7986_pcie_reset_funcs[] = {
+ static int mt7986_uart1_pins[] = { 42, 43, 44, 45, };
+ static int mt7986_uart1_funcs[] = { 1, 1, 1, 1, };
+
++static int mt7986_uart1_rx_tx_pins[] = { 42, 43, };
++static int mt7986_uart1_rx_tx_funcs[] = { 1, 1, };
++
++static int mt7986_uart1_cts_rts_pins[] = { 44, 45, };
++static int mt7986_uart1_cts_rts_funcs[] = { 1, 1, };
++
+ static int mt7986_uart2_pins[] = { 46, 47, 48, 49, };
+ static int mt7986_uart2_funcs[] = { 1, 1, 1, 1, };
+
+@@ -749,6 +761,8 @@ static const struct group_desc mt7986_gr
+ PINCTRL_PIN_GROUP("wifi_led", mt7986_wifi_led),
+ PINCTRL_PIN_GROUP("i2c", mt7986_i2c),
+ PINCTRL_PIN_GROUP("uart1_0", mt7986_uart1_0),
++ PINCTRL_PIN_GROUP("uart1_rx_tx", mt7986_uart1_rx_tx),
++ PINCTRL_PIN_GROUP("uart1_cts_rts", mt7986_uart1_cts_rts),
+ PINCTRL_PIN_GROUP("pcie_clk", mt7986_pcie_clk),
+ PINCTRL_PIN_GROUP("pcie_wake", mt7986_pcie_wake),
+ PINCTRL_PIN_GROUP("spi1_0", mt7986_spi1_0),
+@@ -760,8 +774,10 @@ static const struct group_desc mt7986_gr
+ PINCTRL_PIN_GROUP("spi1_1", mt7986_spi1_1),
+ PINCTRL_PIN_GROUP("uart1_1", mt7986_uart1_1),
+ PINCTRL_PIN_GROUP("spi1_2", mt7986_spi1_2),
+- PINCTRL_PIN_GROUP("uart1_2", mt7986_uart1_2),
+- PINCTRL_PIN_GROUP("uart2_0", mt7986_uart2_0),
++ PINCTRL_PIN_GROUP("uart1_2_rx_tx", mt7986_uart1_2_rx_tx),
++ PINCTRL_PIN_GROUP("uart1_2_cts_rts", mt7986_uart1_2_cts_rts),
++ PINCTRL_PIN_GROUP("uart2_0_rx_tx", mt7986_uart2_0_rx_tx),
++ PINCTRL_PIN_GROUP("uart2_0_cts_rts", mt7986_uart2_0_cts_rts),
+ PINCTRL_PIN_GROUP("spi0", mt7986_spi0),
+ PINCTRL_PIN_GROUP("spi0_wp_hold", mt7986_spi0_wp_hold),
+ PINCTRL_PIN_GROUP("uart2_1", mt7986_uart2_1),
+@@ -800,7 +816,9 @@ static const char *mt7986_pwm_groups[] =
+ static const char *mt7986_spi_groups[] = {
+ "spi0", "spi0_wp_hold", "spi1_0", "spi1_1", "spi1_2", "spi1_3", };
+ static const char *mt7986_uart_groups[] = {
+- "uart1_0", "uart1_1", "uart1_2", "uart1_3_rx_tx", "uart1_3_cts_rts",
++ "uart1_0", "uart1_1", "uart1_rx_tx", "uart1_cts_rts",
++ "uart1_2_rx_tx", "uart1_2_cts_rts",
++ "uart1_3_rx_tx", "uart1_3_cts_rts", "uart2_0_rx_tx", "uart2_0_cts_rts",
+ "uart2_0", "uart2_1", "uart0", "uart1", "uart2",
+ };
+ static const char *mt7986_wdt_groups[] = { "watchdog", };
--- /dev/null
+From 822d774abbcc66b811e28c68b59b40b964ba5b46 Mon Sep 17 00:00:00 2001
+From: Sam Shih <sam.shih@mediatek.com>
+Date: Sun, 6 Nov 2022 09:01:13 +0100
+Subject: [PATCH 2/2] pinctrl: mediatek: add pull_type attribute for mediatek
+ MT7986 SoC
+
+Commit fb34a9ae383a ("pinctrl: mediatek: support rsel feature")
+add SoC specify 'pull_type' attribute for bias configuration.
+
+This patch add pull_type attribute to pinctrl-mt7986.c, and make
+bias_set_combo and bias_get_combo available to mediatek MT7986 SoC.
+
+Signed-off-by: Sam Shih <sam.shih@mediatek.com>
+Signed-off-by: Frank Wunderlich <frank-w@public-files.de>
+Reviewed-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
+Link: https://lore.kernel.org/r/20221106080114.7426-7-linux@fw-web.de
+Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
+---
+ drivers/pinctrl/mediatek/pinctrl-mt7986.c | 56 +++++++++++++++++++++++
+ 1 file changed, 56 insertions(+)
+
+--- a/drivers/pinctrl/mediatek/pinctrl-mt7986.c
++++ b/drivers/pinctrl/mediatek/pinctrl-mt7986.c
+@@ -407,6 +407,60 @@ static const struct mtk_pin_field_calc m
+ PIN_FIELD_BASE(66, 68, IOCFG_LB_BASE, 0x60, 0x10, 2, 1),
+ };
+
++static const unsigned int mt7986_pull_type[] = {
++ MTK_PULL_PUPD_R1R0_TYPE,/*0*/ MTK_PULL_PUPD_R1R0_TYPE,/*1*/
++ MTK_PULL_PUPD_R1R0_TYPE,/*2*/ MTK_PULL_PUPD_R1R0_TYPE,/*3*/
++ MTK_PULL_PUPD_R1R0_TYPE,/*4*/ MTK_PULL_PUPD_R1R0_TYPE,/*5*/
++ MTK_PULL_PUPD_R1R0_TYPE,/*6*/ MTK_PULL_PUPD_R1R0_TYPE,/*7*/
++ MTK_PULL_PUPD_R1R0_TYPE,/*8*/ MTK_PULL_PUPD_R1R0_TYPE,/*9*/
++ MTK_PULL_PUPD_R1R0_TYPE,/*10*/ MTK_PULL_PUPD_R1R0_TYPE,/*11*/
++ MTK_PULL_PUPD_R1R0_TYPE,/*12*/ MTK_PULL_PUPD_R1R0_TYPE,/*13*/
++ MTK_PULL_PUPD_R1R0_TYPE,/*14*/ MTK_PULL_PUPD_R1R0_TYPE,/*15*/
++ MTK_PULL_PUPD_R1R0_TYPE,/*16*/ MTK_PULL_PUPD_R1R0_TYPE,/*17*/
++ MTK_PULL_PUPD_R1R0_TYPE,/*18*/ MTK_PULL_PUPD_R1R0_TYPE,/*19*/
++ MTK_PULL_PUPD_R1R0_TYPE,/*20*/ MTK_PULL_PUPD_R1R0_TYPE,/*21*/
++ MTK_PULL_PUPD_R1R0_TYPE,/*22*/ MTK_PULL_PUPD_R1R0_TYPE,/*23*/
++ MTK_PULL_PUPD_R1R0_TYPE,/*24*/ MTK_PULL_PUPD_R1R0_TYPE,/*25*/
++ MTK_PULL_PUPD_R1R0_TYPE,/*26*/ MTK_PULL_PUPD_R1R0_TYPE,/*27*/
++ MTK_PULL_PUPD_R1R0_TYPE,/*28*/ MTK_PULL_PUPD_R1R0_TYPE,/*29*/
++ MTK_PULL_PUPD_R1R0_TYPE,/*30*/ MTK_PULL_PUPD_R1R0_TYPE,/*31*/
++ MTK_PULL_PUPD_R1R0_TYPE,/*32*/ MTK_PULL_PUPD_R1R0_TYPE,/*33*/
++ MTK_PULL_PUPD_R1R0_TYPE,/*34*/ MTK_PULL_PUPD_R1R0_TYPE,/*35*/
++ MTK_PULL_PUPD_R1R0_TYPE,/*36*/ MTK_PULL_PUPD_R1R0_TYPE,/*37*/
++ MTK_PULL_PUPD_R1R0_TYPE,/*38*/ MTK_PULL_PUPD_R1R0_TYPE,/*39*/
++ MTK_PULL_PUPD_R1R0_TYPE,/*40*/ MTK_PULL_PUPD_R1R0_TYPE,/*41*/
++ MTK_PULL_PUPD_R1R0_TYPE,/*42*/ MTK_PULL_PUPD_R1R0_TYPE,/*43*/
++ MTK_PULL_PUPD_R1R0_TYPE,/*44*/ MTK_PULL_PUPD_R1R0_TYPE,/*45*/
++ MTK_PULL_PUPD_R1R0_TYPE,/*46*/ MTK_PULL_PUPD_R1R0_TYPE,/*47*/
++ MTK_PULL_PUPD_R1R0_TYPE,/*48*/ MTK_PULL_PUPD_R1R0_TYPE,/*49*/
++ MTK_PULL_PUPD_R1R0_TYPE,/*50*/ MTK_PULL_PUPD_R1R0_TYPE,/*51*/
++ MTK_PULL_PUPD_R1R0_TYPE,/*52*/ MTK_PULL_PUPD_R1R0_TYPE,/*53*/
++ MTK_PULL_PUPD_R1R0_TYPE,/*54*/ MTK_PULL_PUPD_R1R0_TYPE,/*55*/
++ MTK_PULL_PUPD_R1R0_TYPE,/*56*/ MTK_PULL_PUPD_R1R0_TYPE,/*57*/
++ MTK_PULL_PUPD_R1R0_TYPE,/*58*/ MTK_PULL_PUPD_R1R0_TYPE,/*59*/
++ MTK_PULL_PUPD_R1R0_TYPE,/*60*/ MTK_PULL_PUPD_R1R0_TYPE,/*61*/
++ MTK_PULL_PUPD_R1R0_TYPE,/*62*/ MTK_PULL_PUPD_R1R0_TYPE,/*63*/
++ MTK_PULL_PUPD_R1R0_TYPE,/*64*/ MTK_PULL_PUPD_R1R0_TYPE,/*65*/
++ MTK_PULL_PUPD_R1R0_TYPE,/*66*/ MTK_PULL_PUPD_R1R0_TYPE,/*67*/
++ MTK_PULL_PUPD_R1R0_TYPE,/*68*/ MTK_PULL_PU_PD_TYPE,/*69*/
++ MTK_PULL_PU_PD_TYPE,/*70*/ MTK_PULL_PU_PD_TYPE,/*71*/
++ MTK_PULL_PU_PD_TYPE,/*72*/ MTK_PULL_PU_PD_TYPE,/*73*/
++ MTK_PULL_PU_PD_TYPE,/*74*/ MTK_PULL_PU_PD_TYPE,/*75*/
++ MTK_PULL_PU_PD_TYPE,/*76*/ MTK_PULL_PU_PD_TYPE,/*77*/
++ MTK_PULL_PU_PD_TYPE,/*78*/ MTK_PULL_PU_PD_TYPE,/*79*/
++ MTK_PULL_PU_PD_TYPE,/*80*/ MTK_PULL_PU_PD_TYPE,/*81*/
++ MTK_PULL_PU_PD_TYPE,/*82*/ MTK_PULL_PU_PD_TYPE,/*83*/
++ MTK_PULL_PU_PD_TYPE,/*84*/ MTK_PULL_PU_PD_TYPE,/*85*/
++ MTK_PULL_PU_PD_TYPE,/*86*/ MTK_PULL_PU_PD_TYPE,/*87*/
++ MTK_PULL_PU_PD_TYPE,/*88*/ MTK_PULL_PU_PD_TYPE,/*89*/
++ MTK_PULL_PU_PD_TYPE,/*90*/ MTK_PULL_PU_PD_TYPE,/*91*/
++ MTK_PULL_PU_PD_TYPE,/*92*/ MTK_PULL_PU_PD_TYPE,/*93*/
++ MTK_PULL_PU_PD_TYPE,/*94*/ MTK_PULL_PU_PD_TYPE,/*95*/
++ MTK_PULL_PU_PD_TYPE,/*96*/ MTK_PULL_PU_PD_TYPE,/*97*/
++ MTK_PULL_PU_PD_TYPE,/*98*/ MTK_PULL_PU_PD_TYPE,/*99*/
++ MTK_PULL_PU_PD_TYPE,/*100*/
++};
++
+ static const struct mtk_pin_reg_calc mt7986_reg_cals[] = {
+ [PINCTRL_PIN_REG_MODE] = MTK_RANGE(mt7986_pin_mode_range),
+ [PINCTRL_PIN_REG_DIR] = MTK_RANGE(mt7986_pin_dir_range),
+@@ -868,6 +922,7 @@ static struct mtk_pin_soc mt7986a_data =
+ .ies_present = false,
+ .base_names = mt7986_pinctrl_register_base_names,
+ .nbase_names = ARRAY_SIZE(mt7986_pinctrl_register_base_names),
++ .pull_type = mt7986_pull_type,
+ .bias_set_combo = mtk_pinconf_bias_set_combo,
+ .bias_get_combo = mtk_pinconf_bias_get_combo,
+ .drive_set = mtk_pinconf_drive_set_rev1,
+@@ -889,6 +944,7 @@ static struct mtk_pin_soc mt7986b_data =
+ .ies_present = false,
+ .base_names = mt7986_pinctrl_register_base_names,
+ .nbase_names = ARRAY_SIZE(mt7986_pinctrl_register_base_names),
++ .pull_type = mt7986_pull_type,
+ .bias_set_combo = mtk_pinconf_bias_set_combo,
+ .bias_get_combo = mtk_pinconf_bias_get_combo,
+ .drive_set = mtk_pinconf_drive_set_rev1,
--- /dev/null
+From 6c83b2d94fcca735cf7d8aa7a55a4957eb404a9d Mon Sep 17 00:00:00 2001
+From: Daniel Golle <daniel@makrotopia.org>
+Date: Thu, 26 Jan 2023 00:34:56 +0000
+Subject: [PATCH] pinctrl: add mt7981 pinctrl driver
+
+Add pinctrl driver for the MediaTek MT7981 SoC, based on the driver
+which can also be found the SDK.
+
+Signed-off-by: Daniel Golle <daniel@makrotopia.org>
+Reviewed-by: Rob Herring <robh@kernel.org>
+Link: https://lore.kernel.org/r/ef5112946d16cacc67e65e439ba7b52a9950c1bb.1674693008.git.daniel@makrotopia.org
+Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
+---
+ drivers/pinctrl/mediatek/Kconfig | 5 +
+ drivers/pinctrl/mediatek/Makefile | 1 +
+ drivers/pinctrl/mediatek/pinctrl-mt7981.c | 1048 +++++++++++++++++++++
+ 3 files changed, 1054 insertions(+)
+ create mode 100644 drivers/pinctrl/mediatek/pinctrl-mt7981.c
+
+--- a/drivers/pinctrl/mediatek/Kconfig
++++ b/drivers/pinctrl/mediatek/Kconfig
+@@ -127,6 +127,11 @@ config PINCTRL_MT7622
+ default ARM64 && ARCH_MEDIATEK
+ select PINCTRL_MTK_MOORE
+
++config PINCTRL_MT7981
++ bool "Mediatek MT7981 pin control"
++ depends on OF
++ select PINCTRL_MTK_MOORE
++
+ config PINCTRL_MT7986
+ bool "Mediatek MT7986 pin control"
+ depends on OF
+--- a/drivers/pinctrl/mediatek/Makefile
++++ b/drivers/pinctrl/mediatek/Makefile
+@@ -18,6 +18,7 @@ obj-$(CONFIG_PINCTRL_MT6797) += pinctrl-
+ obj-$(CONFIG_PINCTRL_MT7622) += pinctrl-mt7622.o
+ obj-$(CONFIG_PINCTRL_MT7623) += pinctrl-mt7623.o
+ obj-$(CONFIG_PINCTRL_MT7629) += pinctrl-mt7629.o
++obj-$(CONFIG_PINCTRL_MT7981) += pinctrl-mt7981.o
+ obj-$(CONFIG_PINCTRL_MT7986) += pinctrl-mt7986.o
+ obj-$(CONFIG_PINCTRL_MT8167) += pinctrl-mt8167.o
+ obj-$(CONFIG_PINCTRL_MT8173) += pinctrl-mt8173.o
+--- /dev/null
++++ b/drivers/pinctrl/mediatek/pinctrl-mt7981.c
+@@ -0,0 +1,1048 @@
++// SPDX-License-Identifier: GPL-2.0
++/*
++ * The MT7981 driver based on Linux generic pinctrl binding.
++ *
++ * Copyright (C) 2020 MediaTek Inc.
++ * Author: Sam Shih <sam.shih@mediatek.com>
++ */
++
++#include "pinctrl-moore.h"
++
++#define MT7981_PIN(_number, _name) \
++ MTK_PIN(_number, _name, 0, _number, DRV_GRP4)
++
++#define PIN_FIELD_BASE(_s_pin, _e_pin, _i_base, _s_addr, _x_addrs, _s_bit, _x_bits) \
++ PIN_FIELD_CALC(_s_pin, _e_pin, _i_base, _s_addr, _x_addrs, _s_bit, \
++ _x_bits, 32, 0)
++
++#define PINS_FIELD_BASE(_s_pin, _e_pin, _i_base, _s_addr, _x_addrs, _s_bit, _x_bits) \
++ PIN_FIELD_CALC(_s_pin, _e_pin, _i_base, _s_addr, _x_addrs, _s_bit, \
++ _x_bits, 32, 1)
++
++static const struct mtk_pin_field_calc mt7981_pin_mode_range[] = {
++ PIN_FIELD(0, 56, 0x300, 0x10, 0, 4),
++};
++
++static const struct mtk_pin_field_calc mt7981_pin_dir_range[] = {
++ PIN_FIELD(0, 56, 0x0, 0x10, 0, 1),
++};
++
++static const struct mtk_pin_field_calc mt7981_pin_di_range[] = {
++ PIN_FIELD(0, 56, 0x200, 0x10, 0, 1),
++};
++
++static const struct mtk_pin_field_calc mt7981_pin_do_range[] = {
++ PIN_FIELD(0, 56, 0x100, 0x10, 0, 1),
++};
++
++static const struct mtk_pin_field_calc mt7981_pin_ies_range[] = {
++ PIN_FIELD_BASE(0, 0, 1, 0x10, 0x10, 1, 1),
++ PIN_FIELD_BASE(1, 1, 1, 0x10, 0x10, 0, 1),
++ PIN_FIELD_BASE(2, 2, 5, 0x20, 0x10, 6, 1),
++ PIN_FIELD_BASE(3, 3, 4, 0x20, 0x10, 6, 1),
++ PIN_FIELD_BASE(4, 4, 4, 0x20, 0x10, 2, 1),
++ PIN_FIELD_BASE(5, 5, 4, 0x20, 0x10, 1, 1),
++ PIN_FIELD_BASE(6, 6, 4, 0x20, 0x10, 3, 1),
++ PIN_FIELD_BASE(7, 7, 4, 0x20, 0x10, 0, 1),
++ PIN_FIELD_BASE(8, 8, 4, 0x20, 0x10, 4, 1),
++
++ PIN_FIELD_BASE(9, 9, 5, 0x20, 0x10, 9, 1),
++ PIN_FIELD_BASE(10, 10, 5, 0x20, 0x10, 8, 1),
++ PIN_FIELD_BASE(11, 11, 5, 0x40, 0x10, 10, 1),
++ PIN_FIELD_BASE(12, 12, 5, 0x20, 0x10, 7, 1),
++ PIN_FIELD_BASE(13, 13, 5, 0x20, 0x10, 11, 1),
++
++ PIN_FIELD_BASE(14, 14, 4, 0x20, 0x10, 8, 1),
++
++ PIN_FIELD_BASE(15, 15, 2, 0x20, 0x10, 0, 1),
++ PIN_FIELD_BASE(16, 16, 2, 0x20, 0x10, 1, 1),
++ PIN_FIELD_BASE(17, 17, 2, 0x20, 0x10, 5, 1),
++ PIN_FIELD_BASE(18, 18, 2, 0x20, 0x10, 4, 1),
++ PIN_FIELD_BASE(19, 19, 2, 0x20, 0x10, 2, 1),
++ PIN_FIELD_BASE(20, 20, 2, 0x20, 0x10, 3, 1),
++ PIN_FIELD_BASE(21, 21, 2, 0x20, 0x10, 6, 1),
++ PIN_FIELD_BASE(22, 22, 2, 0x20, 0x10, 7, 1),
++ PIN_FIELD_BASE(23, 23, 2, 0x20, 0x10, 10, 1),
++ PIN_FIELD_BASE(24, 24, 2, 0x20, 0x10, 9, 1),
++ PIN_FIELD_BASE(25, 25, 2, 0x20, 0x10, 8, 1),
++
++ PIN_FIELD_BASE(26, 26, 5, 0x20, 0x10, 0, 1),
++ PIN_FIELD_BASE(27, 27, 5, 0x20, 0x10, 4, 1),
++ PIN_FIELD_BASE(28, 28, 5, 0x20, 0x10, 3, 1),
++ PIN_FIELD_BASE(29, 29, 5, 0x20, 0x10, 1, 1),
++ PIN_FIELD_BASE(30, 30, 5, 0x20, 0x10, 2, 1),
++ PIN_FIELD_BASE(31, 31, 5, 0x20, 0x10, 5, 1),
++
++ PIN_FIELD_BASE(32, 32, 1, 0x10, 0x10, 2, 1),
++ PIN_FIELD_BASE(33, 33, 1, 0x10, 0x10, 3, 1),
++
++ PIN_FIELD_BASE(34, 34, 4, 0x20, 0x10, 5, 1),
++ PIN_FIELD_BASE(35, 35, 4, 0x20, 0x10, 7, 1),
++
++ PIN_FIELD_BASE(36, 36, 3, 0x10, 0x10, 2, 1),
++ PIN_FIELD_BASE(37, 37, 3, 0x10, 0x10, 3, 1),
++ PIN_FIELD_BASE(38, 38, 3, 0x10, 0x10, 0, 1),
++ PIN_FIELD_BASE(39, 39, 3, 0x10, 0x10, 1, 1),
++
++ PIN_FIELD_BASE(40, 40, 7, 0x30, 0x10, 1, 1),
++ PIN_FIELD_BASE(41, 41, 7, 0x30, 0x10, 0, 1),
++ PIN_FIELD_BASE(42, 42, 7, 0x30, 0x10, 9, 1),
++ PIN_FIELD_BASE(43, 43, 7, 0x30, 0x10, 7, 1),
++ PIN_FIELD_BASE(44, 44, 7, 0x30, 0x10, 8, 1),
++ PIN_FIELD_BASE(45, 45, 7, 0x30, 0x10, 3, 1),
++ PIN_FIELD_BASE(46, 46, 7, 0x30, 0x10, 4, 1),
++ PIN_FIELD_BASE(47, 47, 7, 0x30, 0x10, 5, 1),
++ PIN_FIELD_BASE(48, 48, 7, 0x30, 0x10, 6, 1),
++ PIN_FIELD_BASE(49, 49, 7, 0x30, 0x10, 2, 1),
++
++ PIN_FIELD_BASE(50, 50, 6, 0x10, 0x10, 0, 1),
++ PIN_FIELD_BASE(51, 51, 6, 0x10, 0x10, 2, 1),
++ PIN_FIELD_BASE(52, 52, 6, 0x10, 0x10, 3, 1),
++ PIN_FIELD_BASE(53, 53, 6, 0x10, 0x10, 4, 1),
++ PIN_FIELD_BASE(54, 54, 6, 0x10, 0x10, 5, 1),
++ PIN_FIELD_BASE(55, 55, 6, 0x10, 0x10, 6, 1),
++ PIN_FIELD_BASE(56, 56, 6, 0x10, 0x10, 1, 1),
++};
++
++static const struct mtk_pin_field_calc mt7981_pin_smt_range[] = {
++ PIN_FIELD_BASE(0, 0, 1, 0x60, 0x10, 1, 1),
++ PIN_FIELD_BASE(1, 1, 1, 0x60, 0x10, 0, 1),
++ PIN_FIELD_BASE(2, 2, 5, 0x90, 0x10, 6, 1),
++ PIN_FIELD_BASE(3, 3, 4, 0x80, 0x10, 6, 1),
++ PIN_FIELD_BASE(4, 4, 4, 0x80, 0x10, 2, 1),
++ PIN_FIELD_BASE(5, 5, 4, 0x80, 0x10, 1, 1),
++ PIN_FIELD_BASE(6, 6, 4, 0x80, 0x10, 3, 1),
++ PIN_FIELD_BASE(7, 7, 4, 0x80, 0x10, 0, 1),
++ PIN_FIELD_BASE(8, 8, 4, 0x80, 0x10, 4, 1),
++
++ PIN_FIELD_BASE(9, 9, 5, 0x90, 0x10, 9, 1),
++ PIN_FIELD_BASE(10, 10, 5, 0x90, 0x10, 8, 1),
++ PIN_FIELD_BASE(11, 11, 5, 0x90, 0x10, 10, 1),
++ PIN_FIELD_BASE(12, 12, 5, 0x90, 0x10, 7, 1),
++ PIN_FIELD_BASE(13, 13, 5, 0x90, 0x10, 11, 1),
++
++ PIN_FIELD_BASE(14, 14, 4, 0x80, 0x10, 8, 1),
++
++ PIN_FIELD_BASE(15, 15, 2, 0x90, 0x10, 0, 1),
++ PIN_FIELD_BASE(16, 16, 2, 0x90, 0x10, 1, 1),
++ PIN_FIELD_BASE(17, 17, 2, 0x90, 0x10, 5, 1),
++ PIN_FIELD_BASE(18, 18, 2, 0x90, 0x10, 4, 1),
++ PIN_FIELD_BASE(19, 19, 2, 0x90, 0x10, 2, 1),
++ PIN_FIELD_BASE(20, 20, 2, 0x90, 0x10, 3, 1),
++ PIN_FIELD_BASE(21, 21, 2, 0x90, 0x10, 6, 1),
++ PIN_FIELD_BASE(22, 22, 2, 0x90, 0x10, 7, 1),
++ PIN_FIELD_BASE(23, 23, 2, 0x90, 0x10, 10, 1),
++ PIN_FIELD_BASE(24, 24, 2, 0x90, 0x10, 9, 1),
++ PIN_FIELD_BASE(25, 25, 2, 0x90, 0x10, 8, 1),
++
++ PIN_FIELD_BASE(26, 26, 5, 0x90, 0x10, 0, 1),
++ PIN_FIELD_BASE(27, 27, 5, 0x90, 0x10, 4, 1),
++ PIN_FIELD_BASE(28, 28, 5, 0x90, 0x10, 3, 1),
++ PIN_FIELD_BASE(29, 29, 5, 0x90, 0x10, 1, 1),
++ PIN_FIELD_BASE(30, 30, 5, 0x90, 0x10, 2, 1),
++ PIN_FIELD_BASE(31, 31, 5, 0x90, 0x10, 5, 1),
++
++ PIN_FIELD_BASE(32, 32, 1, 0x60, 0x10, 2, 1),
++ PIN_FIELD_BASE(33, 33, 1, 0x60, 0x10, 3, 1),
++
++ PIN_FIELD_BASE(34, 34, 4, 0x80, 0x10, 5, 1),
++ PIN_FIELD_BASE(35, 35, 4, 0x80, 0x10, 7, 1),
++
++ PIN_FIELD_BASE(36, 36, 3, 0x60, 0x10, 2, 1),
++ PIN_FIELD_BASE(37, 37, 3, 0x60, 0x10, 3, 1),
++ PIN_FIELD_BASE(38, 38, 3, 0x60, 0x10, 0, 1),
++ PIN_FIELD_BASE(39, 39, 3, 0x60, 0x10, 1, 1),
++
++ PIN_FIELD_BASE(40, 40, 7, 0x70, 0x10, 1, 1),
++ PIN_FIELD_BASE(41, 41, 7, 0x70, 0x10, 0, 1),
++ PIN_FIELD_BASE(42, 42, 7, 0x70, 0x10, 9, 1),
++ PIN_FIELD_BASE(43, 43, 7, 0x70, 0x10, 7, 1),
++ PIN_FIELD_BASE(44, 44, 7, 0x30, 0x10, 8, 1),
++ PIN_FIELD_BASE(45, 45, 7, 0x70, 0x10, 3, 1),
++ PIN_FIELD_BASE(46, 46, 7, 0x70, 0x10, 4, 1),
++ PIN_FIELD_BASE(47, 47, 7, 0x70, 0x10, 5, 1),
++ PIN_FIELD_BASE(48, 48, 7, 0x70, 0x10, 6, 1),
++ PIN_FIELD_BASE(49, 49, 7, 0x70, 0x10, 2, 1),
++
++ PIN_FIELD_BASE(50, 50, 6, 0x50, 0x10, 0, 1),
++ PIN_FIELD_BASE(51, 51, 6, 0x50, 0x10, 2, 1),
++ PIN_FIELD_BASE(52, 52, 6, 0x50, 0x10, 3, 1),
++ PIN_FIELD_BASE(53, 53, 6, 0x50, 0x10, 4, 1),
++ PIN_FIELD_BASE(54, 54, 6, 0x50, 0x10, 5, 1),
++ PIN_FIELD_BASE(55, 55, 6, 0x50, 0x10, 6, 1),
++ PIN_FIELD_BASE(56, 56, 6, 0x50, 0x10, 1, 1),
++};
++
++static const struct mtk_pin_field_calc mt7981_pin_pu_range[] = {
++ PIN_FIELD_BASE(40, 40, 7, 0x50, 0x10, 1, 1),
++ PIN_FIELD_BASE(41, 41, 7, 0x50, 0x10, 0, 1),
++ PIN_FIELD_BASE(42, 42, 7, 0x50, 0x10, 9, 1),
++ PIN_FIELD_BASE(43, 43, 7, 0x50, 0x10, 7, 1),
++ PIN_FIELD_BASE(44, 44, 7, 0x50, 0x10, 8, 1),
++ PIN_FIELD_BASE(45, 45, 7, 0x50, 0x10, 3, 1),
++ PIN_FIELD_BASE(46, 46, 7, 0x50, 0x10, 4, 1),
++ PIN_FIELD_BASE(47, 47, 7, 0x50, 0x10, 5, 1),
++ PIN_FIELD_BASE(48, 48, 7, 0x50, 0x10, 6, 1),
++ PIN_FIELD_BASE(49, 49, 7, 0x50, 0x10, 2, 1),
++
++ PIN_FIELD_BASE(50, 50, 6, 0x30, 0x10, 0, 1),
++ PIN_FIELD_BASE(51, 51, 6, 0x30, 0x10, 2, 1),
++ PIN_FIELD_BASE(52, 52, 6, 0x30, 0x10, 3, 1),
++ PIN_FIELD_BASE(53, 53, 6, 0x30, 0x10, 4, 1),
++ PIN_FIELD_BASE(54, 54, 6, 0x30, 0x10, 5, 1),
++ PIN_FIELD_BASE(55, 55, 6, 0x30, 0x10, 6, 1),
++ PIN_FIELD_BASE(56, 56, 6, 0x30, 0x10, 1, 1),
++};
++
++static const struct mtk_pin_field_calc mt7981_pin_pd_range[] = {
++ PIN_FIELD_BASE(40, 40, 7, 0x40, 0x10, 1, 1),
++ PIN_FIELD_BASE(41, 41, 7, 0x40, 0x10, 0, 1),
++ PIN_FIELD_BASE(42, 42, 7, 0x40, 0x10, 9, 1),
++ PIN_FIELD_BASE(43, 43, 7, 0x40, 0x10, 7, 1),
++ PIN_FIELD_BASE(44, 44, 7, 0x40, 0x10, 8, 1),
++ PIN_FIELD_BASE(45, 45, 7, 0x40, 0x10, 3, 1),
++ PIN_FIELD_BASE(46, 46, 7, 0x40, 0x10, 4, 1),
++ PIN_FIELD_BASE(47, 47, 7, 0x40, 0x10, 5, 1),
++ PIN_FIELD_BASE(48, 48, 7, 0x40, 0x10, 6, 1),
++ PIN_FIELD_BASE(49, 49, 7, 0x40, 0x10, 2, 1),
++
++ PIN_FIELD_BASE(50, 50, 6, 0x20, 0x10, 0, 1),
++ PIN_FIELD_BASE(51, 51, 6, 0x20, 0x10, 2, 1),
++ PIN_FIELD_BASE(52, 52, 6, 0x20, 0x10, 3, 1),
++ PIN_FIELD_BASE(53, 53, 6, 0x20, 0x10, 4, 1),
++ PIN_FIELD_BASE(54, 54, 6, 0x20, 0x10, 5, 1),
++ PIN_FIELD_BASE(55, 55, 6, 0x20, 0x10, 6, 1),
++ PIN_FIELD_BASE(56, 56, 6, 0x20, 0x10, 1, 1),
++};
++
++static const struct mtk_pin_field_calc mt7981_pin_drv_range[] = {
++ PIN_FIELD_BASE(0, 0, 1, 0x00, 0x10, 3, 3),
++ PIN_FIELD_BASE(1, 1, 1, 0x00, 0x10, 0, 3),
++
++ PIN_FIELD_BASE(2, 2, 5, 0x00, 0x10, 18, 3),
++
++ PIN_FIELD_BASE(3, 3, 4, 0x00, 0x10, 18, 1),
++ PIN_FIELD_BASE(4, 4, 4, 0x00, 0x10, 6, 1),
++ PIN_FIELD_BASE(5, 5, 4, 0x00, 0x10, 3, 3),
++ PIN_FIELD_BASE(6, 6, 4, 0x00, 0x10, 9, 3),
++ PIN_FIELD_BASE(7, 7, 4, 0x00, 0x10, 0, 3),
++ PIN_FIELD_BASE(8, 8, 4, 0x00, 0x10, 12, 3),
++
++ PIN_FIELD_BASE(9, 9, 5, 0x00, 0x10, 27, 3),
++ PIN_FIELD_BASE(10, 10, 5, 0x00, 0x10, 24, 3),
++ PIN_FIELD_BASE(11, 11, 5, 0x00, 0x10, 0, 3),
++ PIN_FIELD_BASE(12, 12, 5, 0x00, 0x10, 21, 3),
++ PIN_FIELD_BASE(13, 13, 5, 0x00, 0x10, 3, 3),
++
++ PIN_FIELD_BASE(14, 14, 4, 0x00, 0x10, 27, 3),
++
++ PIN_FIELD_BASE(15, 15, 2, 0x00, 0x10, 0, 3),
++ PIN_FIELD_BASE(16, 16, 2, 0x00, 0x10, 3, 3),
++ PIN_FIELD_BASE(17, 17, 2, 0x00, 0x10, 15, 3),
++ PIN_FIELD_BASE(18, 18, 2, 0x00, 0x10, 12, 3),
++ PIN_FIELD_BASE(19, 19, 2, 0x00, 0x10, 6, 3),
++ PIN_FIELD_BASE(20, 20, 2, 0x00, 0x10, 9, 3),
++ PIN_FIELD_BASE(21, 21, 2, 0x00, 0x10, 18, 3),
++ PIN_FIELD_BASE(22, 22, 2, 0x00, 0x10, 21, 3),
++ PIN_FIELD_BASE(23, 23, 2, 0x00, 0x10, 0, 3),
++ PIN_FIELD_BASE(24, 24, 2, 0x00, 0x10, 27, 3),
++ PIN_FIELD_BASE(25, 25, 2, 0x00, 0x10, 24, 3),
++
++ PIN_FIELD_BASE(26, 26, 5, 0x00, 0x10, 0, 3),
++ PIN_FIELD_BASE(27, 27, 5, 0x00, 0x10, 12, 3),
++ PIN_FIELD_BASE(28, 28, 5, 0x00, 0x10, 9, 3),
++ PIN_FIELD_BASE(29, 29, 5, 0x00, 0x10, 3, 3),
++ PIN_FIELD_BASE(30, 30, 5, 0x00, 0x10, 6, 3),
++ PIN_FIELD_BASE(31, 31, 5, 0x00, 0x10, 15, 3),
++
++ PIN_FIELD_BASE(32, 32, 1, 0x00, 0x10, 9, 3),
++ PIN_FIELD_BASE(33, 33, 1, 0x00, 0x10, 12, 3),
++
++ PIN_FIELD_BASE(34, 34, 4, 0x00, 0x10, 15, 3),
++ PIN_FIELD_BASE(35, 35, 4, 0x00, 0x10, 21, 3),
++
++ PIN_FIELD_BASE(36, 36, 3, 0x00, 0x10, 6, 3),
++ PIN_FIELD_BASE(37, 37, 3, 0x00, 0x10, 9, 3),
++ PIN_FIELD_BASE(38, 38, 3, 0x00, 0x10, 0, 3),
++ PIN_FIELD_BASE(39, 39, 3, 0x00, 0x10, 3, 3),
++
++ PIN_FIELD_BASE(40, 40, 7, 0x00, 0x10, 3, 3),
++ PIN_FIELD_BASE(41, 41, 7, 0x00, 0x10, 0, 3),
++ PIN_FIELD_BASE(42, 42, 7, 0x00, 0x10, 27, 3),
++ PIN_FIELD_BASE(43, 43, 7, 0x00, 0x10, 21, 3),
++ PIN_FIELD_BASE(44, 44, 7, 0x00, 0x10, 24, 3),
++ PIN_FIELD_BASE(45, 45, 7, 0x00, 0x10, 9, 3),
++ PIN_FIELD_BASE(46, 46, 7, 0x00, 0x10, 12, 3),
++ PIN_FIELD_BASE(47, 47, 7, 0x00, 0x10, 15, 3),
++ PIN_FIELD_BASE(48, 48, 7, 0x00, 0x10, 18, 3),
++ PIN_FIELD_BASE(49, 49, 7, 0x00, 0x10, 6, 3),
++
++ PIN_FIELD_BASE(50, 50, 6, 0x00, 0x10, 0, 3),
++ PIN_FIELD_BASE(51, 51, 6, 0x00, 0x10, 6, 3),
++ PIN_FIELD_BASE(52, 52, 6, 0x00, 0x10, 9, 3),
++ PIN_FIELD_BASE(53, 53, 6, 0x00, 0x10, 12, 3),
++ PIN_FIELD_BASE(54, 54, 6, 0x00, 0x10, 15, 3),
++ PIN_FIELD_BASE(55, 55, 6, 0x00, 0x10, 18, 3),
++ PIN_FIELD_BASE(56, 56, 6, 0x00, 0x10, 3, 3),
++};
++
++static const struct mtk_pin_field_calc mt7981_pin_pupd_range[] = {
++ PIN_FIELD_BASE(0, 0, 1, 0x20, 0x10, 1, 1),
++ PIN_FIELD_BASE(1, 1, 1, 0x20, 0x10, 0, 1),
++ PIN_FIELD_BASE(2, 2, 5, 0x30, 0x10, 6, 1),
++ PIN_FIELD_BASE(3, 3, 4, 0x30, 0x10, 6, 1),
++ PIN_FIELD_BASE(4, 4, 4, 0x30, 0x10, 2, 1),
++ PIN_FIELD_BASE(5, 5, 4, 0x30, 0x10, 1, 1),
++ PIN_FIELD_BASE(6, 6, 4, 0x30, 0x10, 3, 1),
++ PIN_FIELD_BASE(7, 7, 4, 0x30, 0x10, 0, 1),
++ PIN_FIELD_BASE(8, 8, 4, 0x30, 0x10, 4, 1),
++
++ PIN_FIELD_BASE(9, 9, 5, 0x30, 0x10, 9, 1),
++ PIN_FIELD_BASE(10, 10, 5, 0x30, 0x10, 8, 1),
++ PIN_FIELD_BASE(11, 11, 5, 0x30, 0x10, 10, 1),
++ PIN_FIELD_BASE(12, 12, 5, 0x30, 0x10, 7, 1),
++ PIN_FIELD_BASE(13, 13, 5, 0x30, 0x10, 11, 1),
++
++ PIN_FIELD_BASE(14, 14, 4, 0x30, 0x10, 8, 1),
++
++ PIN_FIELD_BASE(15, 15, 2, 0x30, 0x10, 0, 1),
++ PIN_FIELD_BASE(16, 16, 2, 0x30, 0x10, 1, 1),
++ PIN_FIELD_BASE(17, 17, 2, 0x30, 0x10, 5, 1),
++ PIN_FIELD_BASE(18, 18, 2, 0x30, 0x10, 4, 1),
++ PIN_FIELD_BASE(19, 19, 2, 0x30, 0x10, 2, 1),
++ PIN_FIELD_BASE(20, 20, 2, 0x90, 0x10, 3, 1),
++ PIN_FIELD_BASE(21, 21, 2, 0x30, 0x10, 6, 1),
++ PIN_FIELD_BASE(22, 22, 2, 0x30, 0x10, 7, 1),
++ PIN_FIELD_BASE(23, 23, 2, 0x30, 0x10, 10, 1),
++ PIN_FIELD_BASE(24, 24, 2, 0x30, 0x10, 9, 1),
++ PIN_FIELD_BASE(25, 25, 2, 0x30, 0x10, 8, 1),
++
++ PIN_FIELD_BASE(26, 26, 5, 0x30, 0x10, 0, 1),
++ PIN_FIELD_BASE(27, 27, 5, 0x30, 0x10, 4, 1),
++ PIN_FIELD_BASE(28, 28, 5, 0x30, 0x10, 3, 1),
++ PIN_FIELD_BASE(29, 29, 5, 0x30, 0x10, 1, 1),
++ PIN_FIELD_BASE(30, 30, 5, 0x30, 0x10, 2, 1),
++ PIN_FIELD_BASE(31, 31, 5, 0x30, 0x10, 5, 1),
++
++ PIN_FIELD_BASE(32, 32, 1, 0x20, 0x10, 2, 1),
++ PIN_FIELD_BASE(33, 33, 1, 0x20, 0x10, 3, 1),
++
++ PIN_FIELD_BASE(34, 34, 4, 0x30, 0x10, 5, 1),
++ PIN_FIELD_BASE(35, 35, 4, 0x30, 0x10, 7, 1),
++
++ PIN_FIELD_BASE(36, 36, 3, 0x20, 0x10, 2, 1),
++ PIN_FIELD_BASE(37, 37, 3, 0x20, 0x10, 3, 1),
++ PIN_FIELD_BASE(38, 38, 3, 0x20, 0x10, 0, 1),
++ PIN_FIELD_BASE(39, 39, 3, 0x20, 0x10, 1, 1),
++};
++
++static const struct mtk_pin_field_calc mt7981_pin_r0_range[] = {
++ PIN_FIELD_BASE(0, 0, 1, 0x30, 0x10, 1, 1),
++ PIN_FIELD_BASE(1, 1, 1, 0x30, 0x10, 0, 1),
++ PIN_FIELD_BASE(2, 2, 5, 0x40, 0x10, 6, 1),
++ PIN_FIELD_BASE(3, 3, 4, 0x40, 0x10, 6, 1),
++ PIN_FIELD_BASE(4, 4, 4, 0x40, 0x10, 2, 1),
++ PIN_FIELD_BASE(5, 5, 4, 0x40, 0x10, 1, 1),
++ PIN_FIELD_BASE(6, 6, 4, 0x40, 0x10, 3, 1),
++ PIN_FIELD_BASE(7, 7, 4, 0x40, 0x10, 0, 1),
++ PIN_FIELD_BASE(8, 8, 4, 0x40, 0x10, 4, 1),
++
++ PIN_FIELD_BASE(9, 9, 5, 0x40, 0x10, 9, 1),
++ PIN_FIELD_BASE(10, 10, 5, 0x40, 0x10, 8, 1),
++ PIN_FIELD_BASE(11, 11, 5, 0x40, 0x10, 10, 1),
++ PIN_FIELD_BASE(12, 12, 5, 0x40, 0x10, 7, 1),
++ PIN_FIELD_BASE(13, 13, 5, 0x40, 0x10, 11, 1),
++
++ PIN_FIELD_BASE(14, 14, 4, 0x40, 0x10, 8, 1),
++
++ PIN_FIELD_BASE(15, 15, 2, 0x40, 0x10, 0, 1),
++ PIN_FIELD_BASE(16, 16, 2, 0x40, 0x10, 1, 1),
++ PIN_FIELD_BASE(17, 17, 2, 0x40, 0x10, 5, 1),
++ PIN_FIELD_BASE(18, 18, 2, 0x40, 0x10, 4, 1),
++ PIN_FIELD_BASE(19, 19, 2, 0x40, 0x10, 2, 1),
++ PIN_FIELD_BASE(20, 20, 2, 0x40, 0x10, 3, 1),
++ PIN_FIELD_BASE(21, 21, 2, 0x40, 0x10, 6, 1),
++ PIN_FIELD_BASE(22, 22, 2, 0x40, 0x10, 7, 1),
++ PIN_FIELD_BASE(23, 23, 2, 0x40, 0x10, 10, 1),
++ PIN_FIELD_BASE(24, 24, 2, 0x40, 0x10, 9, 1),
++ PIN_FIELD_BASE(25, 25, 2, 0x40, 0x10, 8, 1),
++
++ PIN_FIELD_BASE(26, 26, 5, 0x40, 0x10, 0, 1),
++ PIN_FIELD_BASE(27, 27, 5, 0x40, 0x10, 4, 1),
++ PIN_FIELD_BASE(28, 28, 5, 0x40, 0x10, 3, 1),
++ PIN_FIELD_BASE(29, 29, 5, 0x40, 0x10, 1, 1),
++ PIN_FIELD_BASE(30, 30, 5, 0x40, 0x10, 2, 1),
++ PIN_FIELD_BASE(31, 31, 5, 0x40, 0x10, 5, 1),
++
++ PIN_FIELD_BASE(32, 32, 1, 0x30, 0x10, 2, 1),
++ PIN_FIELD_BASE(33, 33, 1, 0x30, 0x10, 3, 1),
++
++ PIN_FIELD_BASE(34, 34, 4, 0x40, 0x10, 5, 1),
++ PIN_FIELD_BASE(35, 35, 4, 0x40, 0x10, 7, 1),
++
++ PIN_FIELD_BASE(36, 36, 3, 0x30, 0x10, 2, 1),
++ PIN_FIELD_BASE(37, 37, 3, 0x30, 0x10, 3, 1),
++ PIN_FIELD_BASE(38, 38, 3, 0x30, 0x10, 0, 1),
++ PIN_FIELD_BASE(39, 39, 3, 0x30, 0x10, 1, 1),
++};
++
++static const struct mtk_pin_field_calc mt7981_pin_r1_range[] = {
++ PIN_FIELD_BASE(0, 0, 1, 0x40, 0x10, 1, 1),
++ PIN_FIELD_BASE(1, 1, 1, 0x40, 0x10, 0, 1),
++ PIN_FIELD_BASE(2, 2, 5, 0x50, 0x10, 6, 1),
++ PIN_FIELD_BASE(3, 3, 4, 0x50, 0x10, 6, 1),
++ PIN_FIELD_BASE(4, 4, 4, 0x50, 0x10, 2, 1),
++ PIN_FIELD_BASE(5, 5, 4, 0x50, 0x10, 1, 1),
++ PIN_FIELD_BASE(6, 6, 4, 0x50, 0x10, 3, 1),
++ PIN_FIELD_BASE(7, 7, 4, 0x50, 0x10, 0, 1),
++ PIN_FIELD_BASE(8, 8, 4, 0x50, 0x10, 4, 1),
++
++ PIN_FIELD_BASE(9, 9, 5, 0x50, 0x10, 9, 1),
++ PIN_FIELD_BASE(10, 10, 5, 0x50, 0x10, 8, 1),
++ PIN_FIELD_BASE(11, 11, 5, 0x50, 0x10, 10, 1),
++ PIN_FIELD_BASE(12, 12, 5, 0x50, 0x10, 7, 1),
++ PIN_FIELD_BASE(13, 13, 5, 0x50, 0x10, 11, 1),
++
++ PIN_FIELD_BASE(14, 14, 4, 0x50, 0x10, 8, 1),
++
++ PIN_FIELD_BASE(15, 15, 2, 0x50, 0x10, 0, 1),
++ PIN_FIELD_BASE(16, 16, 2, 0x50, 0x10, 1, 1),
++ PIN_FIELD_BASE(17, 17, 2, 0x50, 0x10, 5, 1),
++ PIN_FIELD_BASE(18, 18, 2, 0x50, 0x10, 4, 1),
++ PIN_FIELD_BASE(19, 19, 2, 0x50, 0x10, 2, 1),
++ PIN_FIELD_BASE(20, 20, 2, 0x50, 0x10, 3, 1),
++ PIN_FIELD_BASE(21, 21, 2, 0x50, 0x10, 6, 1),
++ PIN_FIELD_BASE(22, 22, 2, 0x50, 0x10, 7, 1),
++ PIN_FIELD_BASE(23, 23, 2, 0x50, 0x10, 10, 1),
++ PIN_FIELD_BASE(24, 24, 2, 0x50, 0x10, 9, 1),
++ PIN_FIELD_BASE(25, 25, 2, 0x50, 0x10, 8, 1),
++
++ PIN_FIELD_BASE(26, 26, 5, 0x50, 0x10, 0, 1),
++ PIN_FIELD_BASE(27, 27, 5, 0x50, 0x10, 4, 1),
++ PIN_FIELD_BASE(28, 28, 5, 0x50, 0x10, 3, 1),
++ PIN_FIELD_BASE(29, 29, 5, 0x50, 0x10, 1, 1),
++ PIN_FIELD_BASE(30, 30, 5, 0x50, 0x10, 2, 1),
++ PIN_FIELD_BASE(31, 31, 5, 0x50, 0x10, 5, 1),
++
++ PIN_FIELD_BASE(32, 32, 1, 0x40, 0x10, 2, 1),
++ PIN_FIELD_BASE(33, 33, 1, 0x40, 0x10, 3, 1),
++
++ PIN_FIELD_BASE(34, 34, 4, 0x50, 0x10, 5, 1),
++ PIN_FIELD_BASE(35, 35, 4, 0x50, 0x10, 7, 1),
++
++ PIN_FIELD_BASE(36, 36, 3, 0x40, 0x10, 2, 1),
++ PIN_FIELD_BASE(37, 37, 3, 0x40, 0x10, 3, 1),
++ PIN_FIELD_BASE(38, 38, 3, 0x40, 0x10, 0, 1),
++ PIN_FIELD_BASE(39, 39, 3, 0x40, 0x10, 1, 1),
++};
++
++static const unsigned int mt7981_pull_type[] = {
++ MTK_PULL_PUPD_R1R0_TYPE,/*0*/ MTK_PULL_PUPD_R1R0_TYPE,/*1*/
++ MTK_PULL_PUPD_R1R0_TYPE,/*2*/ MTK_PULL_PUPD_R1R0_TYPE,/*3*/
++ MTK_PULL_PUPD_R1R0_TYPE,/*4*/ MTK_PULL_PUPD_R1R0_TYPE,/*5*/
++ MTK_PULL_PUPD_R1R0_TYPE,/*6*/ MTK_PULL_PUPD_R1R0_TYPE,/*7*/
++ MTK_PULL_PUPD_R1R0_TYPE,/*8*/ MTK_PULL_PUPD_R1R0_TYPE,/*9*/
++ MTK_PULL_PUPD_R1R0_TYPE,/*10*/ MTK_PULL_PUPD_R1R0_TYPE,/*11*/
++ MTK_PULL_PUPD_R1R0_TYPE,/*12*/ MTK_PULL_PUPD_R1R0_TYPE,/*13*/
++ MTK_PULL_PUPD_R1R0_TYPE,/*14*/ MTK_PULL_PUPD_R1R0_TYPE,/*15*/
++ MTK_PULL_PUPD_R1R0_TYPE,/*16*/ MTK_PULL_PUPD_R1R0_TYPE,/*17*/
++ MTK_PULL_PUPD_R1R0_TYPE,/*18*/ MTK_PULL_PUPD_R1R0_TYPE,/*19*/
++ MTK_PULL_PUPD_R1R0_TYPE,/*20*/ MTK_PULL_PUPD_R1R0_TYPE,/*21*/
++ MTK_PULL_PUPD_R1R0_TYPE,/*22*/ MTK_PULL_PUPD_R1R0_TYPE,/*23*/
++ MTK_PULL_PUPD_R1R0_TYPE,/*24*/ MTK_PULL_PUPD_R1R0_TYPE,/*25*/
++ MTK_PULL_PUPD_R1R0_TYPE,/*26*/ MTK_PULL_PUPD_R1R0_TYPE,/*27*/
++ MTK_PULL_PUPD_R1R0_TYPE,/*28*/ MTK_PULL_PUPD_R1R0_TYPE,/*29*/
++ MTK_PULL_PUPD_R1R0_TYPE,/*30*/ MTK_PULL_PUPD_R1R0_TYPE,/*31*/
++ MTK_PULL_PUPD_R1R0_TYPE,/*32*/ MTK_PULL_PUPD_R1R0_TYPE,/*33*/
++ MTK_PULL_PUPD_R1R0_TYPE,/*34*/ MTK_PULL_PUPD_R1R0_TYPE,/*35*/
++ MTK_PULL_PUPD_R1R0_TYPE,/*36*/ MTK_PULL_PUPD_R1R0_TYPE,/*37*/
++ MTK_PULL_PUPD_R1R0_TYPE,/*38*/ MTK_PULL_PUPD_R1R0_TYPE,/*39*/
++ MTK_PULL_PUPD_R1R0_TYPE,/*40*/ MTK_PULL_PUPD_R1R0_TYPE,/*41*/
++ MTK_PULL_PUPD_R1R0_TYPE,/*42*/ MTK_PULL_PUPD_R1R0_TYPE,/*43*/
++ MTK_PULL_PUPD_R1R0_TYPE,/*44*/ MTK_PULL_PUPD_R1R0_TYPE,/*45*/
++ MTK_PULL_PUPD_R1R0_TYPE,/*46*/ MTK_PULL_PUPD_R1R0_TYPE,/*47*/
++ MTK_PULL_PUPD_R1R0_TYPE,/*48*/ MTK_PULL_PUPD_R1R0_TYPE,/*49*/
++ MTK_PULL_PUPD_R1R0_TYPE,/*50*/ MTK_PULL_PUPD_R1R0_TYPE,/*51*/
++ MTK_PULL_PUPD_R1R0_TYPE,/*52*/ MTK_PULL_PUPD_R1R0_TYPE,/*53*/
++ MTK_PULL_PUPD_R1R0_TYPE,/*54*/ MTK_PULL_PUPD_R1R0_TYPE,/*55*/
++ MTK_PULL_PUPD_R1R0_TYPE,/*56*/ MTK_PULL_PUPD_R1R0_TYPE,/*57*/
++ MTK_PULL_PUPD_R1R0_TYPE,/*58*/ MTK_PULL_PUPD_R1R0_TYPE,/*59*/
++ MTK_PULL_PUPD_R1R0_TYPE,/*60*/ MTK_PULL_PUPD_R1R0_TYPE,/*61*/
++ MTK_PULL_PUPD_R1R0_TYPE,/*62*/ MTK_PULL_PUPD_R1R0_TYPE,/*63*/
++ MTK_PULL_PUPD_R1R0_TYPE,/*64*/ MTK_PULL_PUPD_R1R0_TYPE,/*65*/
++ MTK_PULL_PUPD_R1R0_TYPE,/*66*/ MTK_PULL_PUPD_R1R0_TYPE,/*67*/
++ MTK_PULL_PUPD_R1R0_TYPE,/*68*/ MTK_PULL_PU_PD_TYPE,/*69*/
++ MTK_PULL_PU_PD_TYPE,/*70*/ MTK_PULL_PU_PD_TYPE,/*71*/
++ MTK_PULL_PU_PD_TYPE,/*72*/ MTK_PULL_PU_PD_TYPE,/*73*/
++ MTK_PULL_PU_PD_TYPE,/*74*/ MTK_PULL_PU_PD_TYPE,/*75*/
++ MTK_PULL_PU_PD_TYPE,/*76*/ MTK_PULL_PU_PD_TYPE,/*77*/
++ MTK_PULL_PU_PD_TYPE,/*78*/ MTK_PULL_PU_PD_TYPE,/*79*/
++ MTK_PULL_PU_PD_TYPE,/*80*/ MTK_PULL_PU_PD_TYPE,/*81*/
++ MTK_PULL_PU_PD_TYPE,/*82*/ MTK_PULL_PU_PD_TYPE,/*83*/
++ MTK_PULL_PU_PD_TYPE,/*84*/ MTK_PULL_PU_PD_TYPE,/*85*/
++ MTK_PULL_PU_PD_TYPE,/*86*/ MTK_PULL_PU_PD_TYPE,/*87*/
++ MTK_PULL_PU_PD_TYPE,/*88*/ MTK_PULL_PU_PD_TYPE,/*89*/
++ MTK_PULL_PU_PD_TYPE,/*90*/ MTK_PULL_PU_PD_TYPE,/*91*/
++ MTK_PULL_PU_PD_TYPE,/*92*/ MTK_PULL_PU_PD_TYPE,/*93*/
++ MTK_PULL_PU_PD_TYPE,/*94*/ MTK_PULL_PU_PD_TYPE,/*95*/
++ MTK_PULL_PU_PD_TYPE,/*96*/ MTK_PULL_PU_PD_TYPE,/*97*/
++ MTK_PULL_PU_PD_TYPE,/*98*/ MTK_PULL_PU_PD_TYPE,/*99*/
++ MTK_PULL_PU_PD_TYPE,/*100*/
++};
++
++static const struct mtk_pin_reg_calc mt7981_reg_cals[] = {
++ [PINCTRL_PIN_REG_MODE] = MTK_RANGE(mt7981_pin_mode_range),
++ [PINCTRL_PIN_REG_DIR] = MTK_RANGE(mt7981_pin_dir_range),
++ [PINCTRL_PIN_REG_DI] = MTK_RANGE(mt7981_pin_di_range),
++ [PINCTRL_PIN_REG_DO] = MTK_RANGE(mt7981_pin_do_range),
++ [PINCTRL_PIN_REG_SMT] = MTK_RANGE(mt7981_pin_smt_range),
++ [PINCTRL_PIN_REG_IES] = MTK_RANGE(mt7981_pin_ies_range),
++ [PINCTRL_PIN_REG_PU] = MTK_RANGE(mt7981_pin_pu_range),
++ [PINCTRL_PIN_REG_PD] = MTK_RANGE(mt7981_pin_pd_range),
++ [PINCTRL_PIN_REG_DRV] = MTK_RANGE(mt7981_pin_drv_range),
++ [PINCTRL_PIN_REG_PUPD] = MTK_RANGE(mt7981_pin_pupd_range),
++ [PINCTRL_PIN_REG_R0] = MTK_RANGE(mt7981_pin_r0_range),
++ [PINCTRL_PIN_REG_R1] = MTK_RANGE(mt7981_pin_r1_range),
++};
++
++static const struct mtk_pin_desc mt7981_pins[] = {
++ MT7981_PIN(0, "GPIO_WPS"),
++ MT7981_PIN(1, "GPIO_RESET"),
++ MT7981_PIN(2, "SYS_WATCHDOG"),
++ MT7981_PIN(3, "PCIE_PERESET_N"),
++ MT7981_PIN(4, "JTAG_JTDO"),
++ MT7981_PIN(5, "JTAG_JTDI"),
++ MT7981_PIN(6, "JTAG_JTMS"),
++ MT7981_PIN(7, "JTAG_JTCLK"),
++ MT7981_PIN(8, "JTAG_JTRST_N"),
++ MT7981_PIN(9, "WO_JTAG_JTDO"),
++ MT7981_PIN(10, "WO_JTAG_JTDI"),
++ MT7981_PIN(11, "WO_JTAG_JTMS"),
++ MT7981_PIN(12, "WO_JTAG_JTCLK"),
++ MT7981_PIN(13, "WO_JTAG_JTRST_N"),
++ MT7981_PIN(14, "USB_VBUS"),
++ MT7981_PIN(15, "PWM0"),
++ MT7981_PIN(16, "SPI0_CLK"),
++ MT7981_PIN(17, "SPI0_MOSI"),
++ MT7981_PIN(18, "SPI0_MISO"),
++ MT7981_PIN(19, "SPI0_CS"),
++ MT7981_PIN(20, "SPI0_HOLD"),
++ MT7981_PIN(21, "SPI0_WP"),
++ MT7981_PIN(22, "SPI1_CLK"),
++ MT7981_PIN(23, "SPI1_MOSI"),
++ MT7981_PIN(24, "SPI1_MISO"),
++ MT7981_PIN(25, "SPI1_CS"),
++ MT7981_PIN(26, "SPI2_CLK"),
++ MT7981_PIN(27, "SPI2_MOSI"),
++ MT7981_PIN(28, "SPI2_MISO"),
++ MT7981_PIN(29, "SPI2_CS"),
++ MT7981_PIN(30, "SPI2_HOLD"),
++ MT7981_PIN(31, "SPI2_WP"),
++ MT7981_PIN(32, "UART0_RXD"),
++ MT7981_PIN(33, "UART0_TXD"),
++ MT7981_PIN(34, "PCIE_CLK_REQ"),
++ MT7981_PIN(35, "PCIE_WAKE_N"),
++ MT7981_PIN(36, "SMI_MDC"),
++ MT7981_PIN(37, "SMI_MDIO"),
++ MT7981_PIN(38, "GBE_INT"),
++ MT7981_PIN(39, "GBE_RESET"),
++ MT7981_PIN(40, "WF_DIG_RESETB"),
++ MT7981_PIN(41, "WF_CBA_RESETB"),
++ MT7981_PIN(42, "WF_XO_REQ"),
++ MT7981_PIN(43, "WF_TOP_CLK"),
++ MT7981_PIN(44, "WF_TOP_DATA"),
++ MT7981_PIN(45, "WF_HB1"),
++ MT7981_PIN(46, "WF_HB2"),
++ MT7981_PIN(47, "WF_HB3"),
++ MT7981_PIN(48, "WF_HB4"),
++ MT7981_PIN(49, "WF_HB0"),
++ MT7981_PIN(50, "WF_HB0_B"),
++ MT7981_PIN(51, "WF_HB5"),
++ MT7981_PIN(52, "WF_HB6"),
++ MT7981_PIN(53, "WF_HB7"),
++ MT7981_PIN(54, "WF_HB8"),
++ MT7981_PIN(55, "WF_HB9"),
++ MT7981_PIN(56, "WF_HB10"),
++};
++
++/* List all groups consisting of these pins dedicated to the enablement of
++ * certain hardware block and the corresponding mode for all of the pins.
++ * The hardware probably has multiple combinations of these pinouts.
++ */
++
++/* WA_AICE */
++static int mt7981_wa_aice1_pins[] = { 0, 1, };
++static int mt7981_wa_aice1_funcs[] = { 2, 2, };
++
++static int mt7981_wa_aice2_pins[] = { 0, 1, };
++static int mt7981_wa_aice2_funcs[] = { 3, 3, };
++
++static int mt7981_wa_aice3_pins[] = { 28, 29, };
++static int mt7981_wa_aice3_funcs[] = { 3, 3, };
++
++static int mt7981_wm_aice1_pins[] = { 9, 10, };
++static int mt7981_wm_aice1_funcs[] = { 2, 2, };
++
++static int mt7981_wm_aice2_pins[] = { 30, 31, };
++static int mt7981_wm_aice2_funcs[] = { 5, 5, };
++
++/* WM_UART */
++static int mt7981_wm_uart_0_pins[] = { 0, 1, };
++static int mt7981_wm_uart_0_funcs[] = { 5, 5, };
++
++static int mt7981_wm_uart_1_pins[] = { 20, 21, };
++static int mt7981_wm_uart_1_funcs[] = { 4, 4, };
++
++static int mt7981_wm_uart_2_pins[] = { 30, 31, };
++static int mt7981_wm_uart_2_funcs[] = { 3, 3, };
++
++/* DFD */
++static int mt7981_dfd_pins[] = { 0, 1, 4, 5, };
++static int mt7981_dfd_funcs[] = { 5, 5, 6, 6, };
++
++/* SYS_WATCHDOG */
++static int mt7981_watchdog_pins[] = { 2, };
++static int mt7981_watchdog_funcs[] = { 1, };
++
++static int mt7981_watchdog1_pins[] = { 13, };
++static int mt7981_watchdog1_funcs[] = { 5, };
++
++/* PCIE_PERESET_N */
++static int mt7981_pcie_pereset_pins[] = { 3, };
++static int mt7981_pcie_pereset_funcs[] = { 1, };
++
++/* JTAG */
++static int mt7981_jtag_pins[] = { 4, 5, 6, 7, 8, };
++static int mt7981_jtag_funcs[] = { 1, 1, 1, 1, 1, };
++
++/* WM_JTAG */
++static int mt7981_wm_jtag_0_pins[] = { 4, 5, 6, 7, 8, };
++static int mt7981_wm_jtag_0_funcs[] = { 2, 2, 2, 2, 2, };
++
++static int mt7981_wm_jtag_1_pins[] = { 20, 21, 22, 23, 24, };
++static int mt7981_wm_jtag_1_funcs[] = { 5, 5, 5, 5, 5, };
++
++/* WO0_JTAG */
++static int mt7981_wo0_jtag_0_pins[] = { 9, 10, 11, 12, 13, };
++static int mt7981_wo0_jtag_0_funcs[] = { 1, 1, 1, 1, 1, };
++
++static int mt7981_wo0_jtag_1_pins[] = { 25, 26, 27, 28, 29, };
++static int mt7981_wo0_jtag_1_funcs[] = { 5, 5, 5, 5, 5, };
++
++/* UART2 */
++static int mt7981_uart2_0_pins[] = { 4, 5, 6, 7, };
++static int mt7981_uart2_0_funcs[] = { 3, 3, 3, 3, };
++
++/* GBE_LED0 */
++static int mt7981_gbe_led0_pins[] = { 8, };
++static int mt7981_gbe_led0_funcs[] = { 3, };
++
++/* PTA_EXT */
++static int mt7981_pta_ext_0_pins[] = { 4, 5, 6, };
++static int mt7981_pta_ext_0_funcs[] = { 4, 4, 4, };
++
++static int mt7981_pta_ext_1_pins[] = { 22, 23, 24, };
++static int mt7981_pta_ext_1_funcs[] = { 4, 4, 4, };
++
++/* PWM2 */
++static int mt7981_pwm2_pins[] = { 7, };
++static int mt7981_pwm2_funcs[] = { 4, };
++
++/* NET_WO0_UART_TXD */
++static int mt7981_net_wo0_uart_txd_0_pins[] = { 8, };
++static int mt7981_net_wo0_uart_txd_0_funcs[] = { 4, };
++
++static int mt7981_net_wo0_uart_txd_1_pins[] = { 14, };
++static int mt7981_net_wo0_uart_txd_1_funcs[] = { 3, };
++
++static int mt7981_net_wo0_uart_txd_2_pins[] = { 15, };
++static int mt7981_net_wo0_uart_txd_2_funcs[] = { 4, };
++
++/* SPI1 */
++static int mt7981_spi1_0_pins[] = { 4, 5, 6, 7, };
++static int mt7981_spi1_0_funcs[] = { 5, 5, 5, 5, };
++
++/* I2C */
++static int mt7981_i2c0_0_pins[] = { 6, 7, };
++static int mt7981_i2c0_0_funcs[] = { 6, 6, };
++
++static int mt7981_i2c0_1_pins[] = { 30, 31, };
++static int mt7981_i2c0_1_funcs[] = { 4, 4, };
++
++static int mt7981_i2c0_2_pins[] = { 36, 37, };
++static int mt7981_i2c0_2_funcs[] = { 2, 2, };
++
++static int mt7981_u2_phy_i2c_pins[] = { 30, 31, };
++static int mt7981_u2_phy_i2c_funcs[] = { 6, 6, };
++
++static int mt7981_u3_phy_i2c_pins[] = { 32, 33, };
++static int mt7981_u3_phy_i2c_funcs[] = { 3, 3, };
++
++static int mt7981_sgmii1_phy_i2c_pins[] = { 32, 33, };
++static int mt7981_sgmii1_phy_i2c_funcs[] = { 2, 2, };
++
++static int mt7981_sgmii0_phy_i2c_pins[] = { 32, 33, };
++static int mt7981_sgmii0_phy_i2c_funcs[] = { 5, 5, };
++
++/* DFD_NTRST */
++static int mt7981_dfd_ntrst_pins[] = { 8, };
++static int mt7981_dfd_ntrst_funcs[] = { 6, };
++
++/* PWM0 */
++static int mt7981_pwm0_0_pins[] = { 13, };
++static int mt7981_pwm0_0_funcs[] = { 2, };
++
++static int mt7981_pwm0_1_pins[] = { 15, };
++static int mt7981_pwm0_1_funcs[] = { 1, };
++
++/* PWM1 */
++static int mt7981_pwm1_0_pins[] = { 14, };
++static int mt7981_pwm1_0_funcs[] = { 2, };
++
++static int mt7981_pwm1_1_pins[] = { 15, };
++static int mt7981_pwm1_1_funcs[] = { 3, };
++
++/* GBE_LED1 */
++static int mt7981_gbe_led1_pins[] = { 13, };
++static int mt7981_gbe_led1_funcs[] = { 3, };
++
++/* PCM */
++static int mt7981_pcm_pins[] = { 9, 10, 11, 12, 13, 25 };
++static int mt7981_pcm_funcs[] = { 4, 4, 4, 4, 4, 4, };
++
++/* UDI */
++static int mt7981_udi_pins[] = { 9, 10, 11, 12, 13, };
++static int mt7981_udi_funcs[] = { 6, 6, 6, 6, 6, };
++
++/* DRV_VBUS */
++static int mt7981_drv_vbus_pins[] = { 14, };
++static int mt7981_drv_vbus_funcs[] = { 1, };
++
++/* EMMC */
++static int mt7981_emmc_45_pins[] = { 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, };
++static int mt7981_emmc_45_funcs[] = { 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, };
++
++/* SNFI */
++static int mt7981_snfi_pins[] = { 16, 17, 18, 19, 20, 21, };
++static int mt7981_snfi_funcs[] = { 3, 3, 3, 3, 3, 3, };
++
++/* SPI0 */
++static int mt7981_spi0_pins[] = { 16, 17, 18, 19, };
++static int mt7981_spi0_funcs[] = { 1, 1, 1, 1, };
++
++/* SPI0 */
++static int mt7981_spi0_wp_hold_pins[] = { 20, 21, };
++static int mt7981_spi0_wp_hold_funcs[] = { 1, 1, };
++
++/* SPI1 */
++static int mt7981_spi1_1_pins[] = { 22, 23, 24, 25, };
++static int mt7981_spi1_1_funcs[] = { 1, 1, 1, 1, };
++
++/* SPI2 */
++static int mt7981_spi2_pins[] = { 26, 27, 28, 29, };
++static int mt7981_spi2_funcs[] = { 1, 1, 1, 1, };
++
++/* SPI2 */
++static int mt7981_spi2_wp_hold_pins[] = { 30, 31, };
++static int mt7981_spi2_wp_hold_funcs[] = { 1, 1, };
++
++/* UART1 */
++static int mt7981_uart1_0_pins[] = { 16, 17, 18, 19, };
++static int mt7981_uart1_0_funcs[] = { 4, 4, 4, 4, };
++
++static int mt7981_uart1_1_pins[] = { 26, 27, 28, 29, };
++static int mt7981_uart1_1_funcs[] = { 2, 2, 2, 2, };
++
++/* UART2 */
++static int mt7981_uart2_1_pins[] = { 22, 23, 24, 25, };
++static int mt7981_uart2_1_funcs[] = { 3, 3, 3, 3, };
++
++/* UART0 */
++static int mt7981_uart0_pins[] = { 32, 33, };
++static int mt7981_uart0_funcs[] = { 1, 1, };
++
++/* PCIE_CLK_REQ */
++static int mt7981_pcie_clk_pins[] = { 34, };
++static int mt7981_pcie_clk_funcs[] = { 2, };
++
++/* PCIE_WAKE_N */
++static int mt7981_pcie_wake_pins[] = { 35, };
++static int mt7981_pcie_wake_funcs[] = { 2, };
++
++/* MDC_MDIO */
++static int mt7981_smi_mdc_mdio_pins[] = { 36, 37, };
++static int mt7981_smi_mdc_mdio_funcs[] = { 1, 1, };
++
++static int mt7981_gbe_ext_mdc_mdio_pins[] = { 36, 37, };
++static int mt7981_gbe_ext_mdc_mdio_funcs[] = { 3, 3, };
++
++/* WF0_MODE1 */
++static int mt7981_wf0_mode1_pins[] = { 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56 };
++static int mt7981_wf0_mode1_funcs[] = { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 };
++
++/* WF0_MODE3 */
++static int mt7981_wf0_mode3_pins[] = { 45, 46, 47, 48, 49, 51 };
++static int mt7981_wf0_mode3_funcs[] = { 2, 2, 2, 2, 2, 2 };
++
++/* WF2G_LED */
++static int mt7981_wf2g_led0_pins[] = { 30, };
++static int mt7981_wf2g_led0_funcs[] = { 2, };
++
++static int mt7981_wf2g_led1_pins[] = { 34, };
++static int mt7981_wf2g_led1_funcs[] = { 1, };
++
++/* WF5G_LED */
++static int mt7981_wf5g_led0_pins[] = { 31, };
++static int mt7981_wf5g_led0_funcs[] = { 2, };
++
++static int mt7981_wf5g_led1_pins[] = { 35, };
++static int mt7981_wf5g_led1_funcs[] = { 1, };
++
++/* MT7531_INT */
++static int mt7981_mt7531_int_pins[] = { 38, };
++static int mt7981_mt7531_int_funcs[] = { 1, };
++
++/* ANT_SEL */
++static int mt7981_ant_sel_pins[] = { 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 34, 35 };
++static int mt7981_ant_sel_funcs[] = { 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6 };
++
++static const struct group_desc mt7981_groups[] = {
++ /* @GPIO(0,1): WA_AICE(2) */
++ PINCTRL_PIN_GROUP("wa_aice1", mt7981_wa_aice1),
++ /* @GPIO(0,1): WA_AICE(3) */
++ PINCTRL_PIN_GROUP("wa_aice2", mt7981_wa_aice2),
++ /* @GPIO(0,1): WM_UART(5) */
++ PINCTRL_PIN_GROUP("wm_uart_0", mt7981_wm_uart_0),
++ /* @GPIO(0,1,4,5): DFD(6) */
++ PINCTRL_PIN_GROUP("dfd", mt7981_dfd),
++ /* @GPIO(2): SYS_WATCHDOG(1) */
++ PINCTRL_PIN_GROUP("watchdog", mt7981_watchdog),
++ /* @GPIO(3): PCIE_PERESET_N(1) */
++ PINCTRL_PIN_GROUP("pcie_pereset", mt7981_pcie_pereset),
++ /* @GPIO(4,8) JTAG(1) */
++ PINCTRL_PIN_GROUP("jtag", mt7981_jtag),
++ /* @GPIO(4,8) WM_JTAG(2) */
++ PINCTRL_PIN_GROUP("wm_jtag_0", mt7981_wm_jtag_0),
++ /* @GPIO(9,13) WO0_JTAG(1) */
++ PINCTRL_PIN_GROUP("wo0_jtag_0", mt7981_wo0_jtag_0),
++ /* @GPIO(4,7) WM_JTAG(3) */
++ PINCTRL_PIN_GROUP("uart2_0", mt7981_uart2_0),
++ /* @GPIO(8) GBE_LED0(3) */
++ PINCTRL_PIN_GROUP("gbe_led0", mt7981_gbe_led0),
++ /* @GPIO(4,6) PTA_EXT(4) */
++ PINCTRL_PIN_GROUP("pta_ext_0", mt7981_pta_ext_0),
++ /* @GPIO(7) PWM2(4) */
++ PINCTRL_PIN_GROUP("pwm2", mt7981_pwm2),
++ /* @GPIO(8) NET_WO0_UART_TXD(4) */
++ PINCTRL_PIN_GROUP("net_wo0_uart_txd_0", mt7981_net_wo0_uart_txd_0),
++ /* @GPIO(4,7) SPI1(5) */
++ PINCTRL_PIN_GROUP("spi1_0", mt7981_spi1_0),
++ /* @GPIO(6,7) I2C(5) */
++ PINCTRL_PIN_GROUP("i2c0_0", mt7981_i2c0_0),
++ /* @GPIO(0,1,4,5): DFD_NTRST(6) */
++ PINCTRL_PIN_GROUP("dfd_ntrst", mt7981_dfd_ntrst),
++ /* @GPIO(9,10): WM_AICE(2) */
++ PINCTRL_PIN_GROUP("wm_aice1", mt7981_wm_aice1),
++ /* @GPIO(13): PWM0(2) */
++ PINCTRL_PIN_GROUP("pwm0_0", mt7981_pwm0_0),
++ /* @GPIO(15): PWM0(1) */
++ PINCTRL_PIN_GROUP("pwm0_1", mt7981_pwm0_1),
++ /* @GPIO(14): PWM1(2) */
++ PINCTRL_PIN_GROUP("pwm1_0", mt7981_pwm1_0),
++ /* @GPIO(15): PWM1(3) */
++ PINCTRL_PIN_GROUP("pwm1_1", mt7981_pwm1_1),
++ /* @GPIO(14) NET_WO0_UART_TXD(3) */
++ PINCTRL_PIN_GROUP("net_wo0_uart_txd_1", mt7981_net_wo0_uart_txd_1),
++ /* @GPIO(15) NET_WO0_UART_TXD(4) */
++ PINCTRL_PIN_GROUP("net_wo0_uart_txd_2", mt7981_net_wo0_uart_txd_2),
++ /* @GPIO(13) GBE_LED0(3) */
++ PINCTRL_PIN_GROUP("gbe_led1", mt7981_gbe_led1),
++ /* @GPIO(9,13) PCM(4) */
++ PINCTRL_PIN_GROUP("pcm", mt7981_pcm),
++ /* @GPIO(13): SYS_WATCHDOG1(5) */
++ PINCTRL_PIN_GROUP("watchdog1", mt7981_watchdog1),
++ /* @GPIO(9,13) UDI(4) */
++ PINCTRL_PIN_GROUP("udi", mt7981_udi),
++ /* @GPIO(14) DRV_VBUS(1) */
++ PINCTRL_PIN_GROUP("drv_vbus", mt7981_drv_vbus),
++ /* @GPIO(15,25): EMMC(2) */
++ PINCTRL_PIN_GROUP("emmc_45", mt7981_emmc_45),
++ /* @GPIO(16,21): SNFI(3) */
++ PINCTRL_PIN_GROUP("snfi", mt7981_snfi),
++ /* @GPIO(16,19): SPI0(1) */
++ PINCTRL_PIN_GROUP("spi0", mt7981_spi0),
++ /* @GPIO(20,21): SPI0(1) */
++ PINCTRL_PIN_GROUP("spi0_wp_hold", mt7981_spi0_wp_hold),
++ /* @GPIO(22,25) SPI1(1) */
++ PINCTRL_PIN_GROUP("spi1_1", mt7981_spi1_1),
++ /* @GPIO(26,29): SPI2(1) */
++ PINCTRL_PIN_GROUP("spi2", mt7981_spi2),
++ /* @GPIO(30,31): SPI0(1) */
++ PINCTRL_PIN_GROUP("spi2_wp_hold", mt7981_spi2_wp_hold),
++ /* @GPIO(16,19): UART1(4) */
++ PINCTRL_PIN_GROUP("uart1_0", mt7981_uart1_0),
++ /* @GPIO(26,29): UART1(2) */
++ PINCTRL_PIN_GROUP("uart1_1", mt7981_uart1_1),
++ /* @GPIO(22,25): UART1(3) */
++ PINCTRL_PIN_GROUP("uart2_1", mt7981_uart2_1),
++ /* @GPIO(22,24) PTA_EXT(4) */
++ PINCTRL_PIN_GROUP("pta_ext_1", mt7981_pta_ext_1),
++ /* @GPIO(20,21): WM_UART(4) */
++ PINCTRL_PIN_GROUP("wm_aurt_1", mt7981_wm_uart_1),
++ /* @GPIO(30,31): WM_UART(3) */
++ PINCTRL_PIN_GROUP("wm_aurt_2", mt7981_wm_uart_2),
++ /* @GPIO(20,24) WM_JTAG(5) */
++ PINCTRL_PIN_GROUP("wm_jtag_1", mt7981_wm_jtag_1),
++ /* @GPIO(25,29) WO0_JTAG(5) */
++ PINCTRL_PIN_GROUP("wo0_jtag_1", mt7981_wo0_jtag_1),
++ /* @GPIO(28,29): WA_AICE(3) */
++ PINCTRL_PIN_GROUP("wa_aice3", mt7981_wa_aice3),
++ /* @GPIO(30,31): WM_AICE(5) */
++ PINCTRL_PIN_GROUP("wm_aice2", mt7981_wm_aice2),
++ /* @GPIO(30,31): I2C(4) */
++ PINCTRL_PIN_GROUP("i2c0_1", mt7981_i2c0_1),
++ /* @GPIO(30,31): I2C(6) */
++ PINCTRL_PIN_GROUP("u2_phy_i2c", mt7981_u2_phy_i2c),
++ /* @GPIO(32,33): I2C(1) */
++ PINCTRL_PIN_GROUP("uart0", mt7981_uart0),
++ /* @GPIO(32,33): I2C(2) */
++ PINCTRL_PIN_GROUP("sgmii1_phy_i2c", mt7981_sgmii1_phy_i2c),
++ /* @GPIO(32,33): I2C(3) */
++ PINCTRL_PIN_GROUP("u3_phy_i2c", mt7981_u3_phy_i2c),
++ /* @GPIO(32,33): I2C(5) */
++ PINCTRL_PIN_GROUP("sgmii0_phy_i2c", mt7981_sgmii0_phy_i2c),
++ /* @GPIO(34): PCIE_CLK_REQ(2) */
++ PINCTRL_PIN_GROUP("pcie_clk", mt7981_pcie_clk),
++ /* @GPIO(35): PCIE_WAKE_N(2) */
++ PINCTRL_PIN_GROUP("pcie_wake", mt7981_pcie_wake),
++ /* @GPIO(36,37): I2C(2) */
++ PINCTRL_PIN_GROUP("i2c0_2", mt7981_i2c0_2),
++ /* @GPIO(36,37): MDC_MDIO(1) */
++ PINCTRL_PIN_GROUP("smi_mdc_mdio", mt7981_smi_mdc_mdio),
++ /* @GPIO(36,37): MDC_MDIO(3) */
++ PINCTRL_PIN_GROUP("gbe_ext_mdc_mdio", mt7981_gbe_ext_mdc_mdio),
++ /* @GPIO(69,85): WF0_MODE1(1) */
++ PINCTRL_PIN_GROUP("wf0_mode1", mt7981_wf0_mode1),
++ /* @GPIO(74,80): WF0_MODE3(3) */
++ PINCTRL_PIN_GROUP("wf0_mode3", mt7981_wf0_mode3),
++ /* @GPIO(30): WF2G_LED(2) */
++ PINCTRL_PIN_GROUP("wf2g_led0", mt7981_wf2g_led0),
++ /* @GPIO(34): WF2G_LED(1) */
++ PINCTRL_PIN_GROUP("wf2g_led1", mt7981_wf2g_led1),
++ /* @GPIO(31): WF5G_LED(2) */
++ PINCTRL_PIN_GROUP("wf5g_led0", mt7981_wf5g_led0),
++ /* @GPIO(35): WF5G_LED(1) */
++ PINCTRL_PIN_GROUP("wf5g_led1", mt7981_wf5g_led1),
++ /* @GPIO(38): MT7531_INT(1) */
++ PINCTRL_PIN_GROUP("mt7531_int", mt7981_mt7531_int),
++ /* @GPIO(14,15,26,17,18,19,20,21,22,23,24,25,34,35): ANT_SEL(1) */
++ PINCTRL_PIN_GROUP("ant_sel", mt7981_ant_sel),
++};
++
++/* Joint those groups owning the same capability in user point of view which
++ * allows that people tend to use through the device tree.
++ */
++static const char *mt7981_wa_aice_groups[] = { "wa_aice1", "wa_aice2", "wm_aice1_1",
++ "wa_aice3", "wm_aice1_2", };
++static const char *mt7981_uart_groups[] = { "wm_uart_0", "uart2_0",
++ "net_wo0_uart_txd_0", "net_wo0_uart_txd_1", "net_wo0_uart_txd_2",
++ "uart1_0", "uart1_1", "uart2_1", "wm_aurt_1", "wm_aurt_2", "uart0", };
++static const char *mt7981_dfd_groups[] = { "dfd", "dfd_ntrst", };
++static const char *mt7981_wdt_groups[] = { "watchdog", "watchdog1", };
++static const char *mt7981_pcie_groups[] = { "pcie_pereset", "pcie_clk", "pcie_wake", };
++static const char *mt7981_jtag_groups[] = { "jtag", "wm_jtag_0", "wo0_jtag_0",
++ "wo0_jtag_1", "wm_jtag_1", };
++static const char *mt7981_led_groups[] = { "gbe_led0", "gbe_led1", "wf2g_led0",
++ "wf2g_led1", "wf5g_led0", "wf5g_led1", };
++static const char *mt7981_pta_groups[] = { "pta_ext_0", "pta_ext_1", };
++static const char *mt7981_pwm_groups[] = { "pwm2", "pwm0_0", "pwm0_1",
++ "pwm1_0", "pwm1_1", };
++static const char *mt7981_spi_groups[] = { "spi1_0", "spi0", "spi0_wp_hold", "spi1_1", "spi2",
++ "spi2_wp_hold", };
++static const char *mt7981_i2c_groups[] = { "i2c0_0", "i2c0_1", "u2_phy_i2c",
++ "sgmii1_phy_i2c", "u3_phy_i2c", "sgmii0_phy_i2c", "i2c0_2", };
++static const char *mt7981_pcm_groups[] = { "pcm", };
++static const char *mt7981_udi_groups[] = { "udi", };
++static const char *mt7981_usb_groups[] = { "drv_vbus", };
++static const char *mt7981_flash_groups[] = { "emmc_45", "snfi", };
++static const char *mt7981_ethernet_groups[] = { "smi_mdc_mdio", "gbe_ext_mdc_mdio",
++ "wf0_mode1", "wf0_mode3", "mt7531_int", };
++static const char *mt7981_ant_groups[] = { "ant_sel", };
++
++static const struct function_desc mt7981_functions[] = {
++ {"wa_aice", mt7981_wa_aice_groups, ARRAY_SIZE(mt7981_wa_aice_groups)},
++ {"dfd", mt7981_dfd_groups, ARRAY_SIZE(mt7981_dfd_groups)},
++ {"jtag", mt7981_jtag_groups, ARRAY_SIZE(mt7981_jtag_groups)},
++ {"pta", mt7981_pta_groups, ARRAY_SIZE(mt7981_pta_groups)},
++ {"pcm", mt7981_pcm_groups, ARRAY_SIZE(mt7981_pcm_groups)},
++ {"udi", mt7981_udi_groups, ARRAY_SIZE(mt7981_udi_groups)},
++ {"usb", mt7981_usb_groups, ARRAY_SIZE(mt7981_usb_groups)},
++ {"ant", mt7981_ant_groups, ARRAY_SIZE(mt7981_ant_groups)},
++ {"eth", mt7981_ethernet_groups, ARRAY_SIZE(mt7981_ethernet_groups)},
++ {"i2c", mt7981_i2c_groups, ARRAY_SIZE(mt7981_i2c_groups)},
++ {"led", mt7981_led_groups, ARRAY_SIZE(mt7981_led_groups)},
++ {"pwm", mt7981_pwm_groups, ARRAY_SIZE(mt7981_pwm_groups)},
++ {"spi", mt7981_spi_groups, ARRAY_SIZE(mt7981_spi_groups)},
++ {"uart", mt7981_uart_groups, ARRAY_SIZE(mt7981_uart_groups)},
++ {"watchdog", mt7981_wdt_groups, ARRAY_SIZE(mt7981_wdt_groups)},
++ {"flash", mt7981_flash_groups, ARRAY_SIZE(mt7981_flash_groups)},
++ {"pcie", mt7981_pcie_groups, ARRAY_SIZE(mt7981_pcie_groups)},
++};
++
++static const struct mtk_eint_hw mt7981_eint_hw = {
++ .port_mask = 7,
++ .ports = 7,
++ .ap_num = ARRAY_SIZE(mt7981_pins),
++ .db_cnt = 16,
++};
++
++static const char * const mt7981_pinctrl_register_base_names[] = {
++ "gpio", "iocfg_rt", "iocfg_rm", "iocfg_rb",
++ "iocfg_lb", "iocfg_bl", "iocfg_tm", "iocfg_tl",
++};
++
++static struct mtk_pin_soc mt7981_data = {
++ .reg_cal = mt7981_reg_cals,
++ .pins = mt7981_pins,
++ .npins = ARRAY_SIZE(mt7981_pins),
++ .grps = mt7981_groups,
++ .ngrps = ARRAY_SIZE(mt7981_groups),
++ .funcs = mt7981_functions,
++ .nfuncs = ARRAY_SIZE(mt7981_functions),
++ .eint_hw = &mt7981_eint_hw,
++ .gpio_m = 0,
++ .ies_present = false,
++ .base_names = mt7981_pinctrl_register_base_names,
++ .nbase_names = ARRAY_SIZE(mt7981_pinctrl_register_base_names),
++ .pull_type = mt7981_pull_type,
++ .bias_set_combo = mtk_pinconf_bias_set_combo,
++ .bias_get_combo = mtk_pinconf_bias_get_combo,
++ .drive_set = mtk_pinconf_drive_set_rev1,
++ .drive_get = mtk_pinconf_drive_get_rev1,
++ .adv_pull_get = mtk_pinconf_adv_pull_get,
++ .adv_pull_set = mtk_pinconf_adv_pull_set,
++};
++
++static const struct of_device_id mt7981_pinctrl_of_match[] = {
++ { .compatible = "mediatek,mt7981-pinctrl", },
++ {}
++};
++
++static int mt7981_pinctrl_probe(struct platform_device *pdev)
++{
++ return mtk_moore_pinctrl_probe(pdev, &mt7981_data);
++}
++
++static struct platform_driver mt7981_pinctrl_driver = {
++ .driver = {
++ .name = "mt7981-pinctrl",
++ .of_match_table = mt7981_pinctrl_of_match,
++ },
++ .probe = mt7981_pinctrl_probe,
++};
++
++static int __init mt7981_pinctrl_init(void)
++{
++ return platform_driver_register(&mt7981_pinctrl_driver);
++}
++arch_initcall(mt7981_pinctrl_init);
--- /dev/null
+From c0ad453e94e5c404efbcf668648d07eaa1a71ed7 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Ar=C4=B1n=C3=A7=20=C3=9CNAL?= <arinc.unal@arinc9.com>
+Date: Sat, 18 Feb 2023 09:51:06 +0300
+Subject: [PATCH] pinctrl: mediatek: add missing options to PINCTRL_MT7981
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+There are options missing from PINCTRL_MT7981 whilst being on every other
+pin controller. Add them.
+
+Signed-off-by: Arınç ÜNAL <arinc.unal@arinc9.com>
+Acked-by: Daniel Golle <daniel@makrotopia.org>
+Link: https://lore.kernel.org/r/20230218065108.8958-1-arinc.unal@arinc9.com
+Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
+---
+ drivers/pinctrl/mediatek/Kconfig | 2 ++
+ 1 file changed, 2 insertions(+)
+
+--- a/drivers/pinctrl/mediatek/Kconfig
++++ b/drivers/pinctrl/mediatek/Kconfig
+@@ -130,6 +130,8 @@ config PINCTRL_MT7622
+ config PINCTRL_MT7981
+ bool "Mediatek MT7981 pin control"
+ depends on OF
++ depends on ARM64 || COMPILE_TEST
++ default ARM64 && ARCH_MEDIATEK
+ select PINCTRL_MTK_MOORE
+
+ config PINCTRL_MT7986
--- /dev/null
+From 8f6f16fe1553ce63edfb98a39ef9d4754a0c39bf Mon Sep 17 00:00:00 2001
+From: Daniel Golle <daniel@makrotopia.org>
+Date: Fri, 18 Aug 2023 04:02:35 +0100
+Subject: [PATCH] pinctrl: mediatek: fix pull_type data for MT7981
+
+MediaTek has released pull_type data for MT7981 in their SDK.
+Use it and set functions to configure pin bias.
+
+Fixes: 6c83b2d94fcc ("pinctrl: add mt7981 pinctrl driver")
+Signed-off-by: Daniel Golle <daniel@makrotopia.org>
+Link: https://lore.kernel.org/r/7bcc8ead25dbfabc7f5a85d066224a926fbb4941.1692327317.git.daniel@makrotopia.org
+Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
+---
+ drivers/pinctrl/mediatek/pinctrl-mt7981.c | 44 +++++++----------------
+ 1 file changed, 13 insertions(+), 31 deletions(-)
+
+--- a/drivers/pinctrl/mediatek/pinctrl-mt7981.c
++++ b/drivers/pinctrl/mediatek/pinctrl-mt7981.c
+@@ -457,37 +457,15 @@ static const unsigned int mt7981_pull_ty
+ MTK_PULL_PUPD_R1R0_TYPE,/*34*/ MTK_PULL_PUPD_R1R0_TYPE,/*35*/
+ MTK_PULL_PUPD_R1R0_TYPE,/*36*/ MTK_PULL_PUPD_R1R0_TYPE,/*37*/
+ MTK_PULL_PUPD_R1R0_TYPE,/*38*/ MTK_PULL_PUPD_R1R0_TYPE,/*39*/
+- MTK_PULL_PUPD_R1R0_TYPE,/*40*/ MTK_PULL_PUPD_R1R0_TYPE,/*41*/
+- MTK_PULL_PUPD_R1R0_TYPE,/*42*/ MTK_PULL_PUPD_R1R0_TYPE,/*43*/
+- MTK_PULL_PUPD_R1R0_TYPE,/*44*/ MTK_PULL_PUPD_R1R0_TYPE,/*45*/
+- MTK_PULL_PUPD_R1R0_TYPE,/*46*/ MTK_PULL_PUPD_R1R0_TYPE,/*47*/
+- MTK_PULL_PUPD_R1R0_TYPE,/*48*/ MTK_PULL_PUPD_R1R0_TYPE,/*49*/
+- MTK_PULL_PUPD_R1R0_TYPE,/*50*/ MTK_PULL_PUPD_R1R0_TYPE,/*51*/
+- MTK_PULL_PUPD_R1R0_TYPE,/*52*/ MTK_PULL_PUPD_R1R0_TYPE,/*53*/
+- MTK_PULL_PUPD_R1R0_TYPE,/*54*/ MTK_PULL_PUPD_R1R0_TYPE,/*55*/
+- MTK_PULL_PUPD_R1R0_TYPE,/*56*/ MTK_PULL_PUPD_R1R0_TYPE,/*57*/
+- MTK_PULL_PUPD_R1R0_TYPE,/*58*/ MTK_PULL_PUPD_R1R0_TYPE,/*59*/
+- MTK_PULL_PUPD_R1R0_TYPE,/*60*/ MTK_PULL_PUPD_R1R0_TYPE,/*61*/
+- MTK_PULL_PUPD_R1R0_TYPE,/*62*/ MTK_PULL_PUPD_R1R0_TYPE,/*63*/
+- MTK_PULL_PUPD_R1R0_TYPE,/*64*/ MTK_PULL_PUPD_R1R0_TYPE,/*65*/
+- MTK_PULL_PUPD_R1R0_TYPE,/*66*/ MTK_PULL_PUPD_R1R0_TYPE,/*67*/
+- MTK_PULL_PUPD_R1R0_TYPE,/*68*/ MTK_PULL_PU_PD_TYPE,/*69*/
+- MTK_PULL_PU_PD_TYPE,/*70*/ MTK_PULL_PU_PD_TYPE,/*71*/
+- MTK_PULL_PU_PD_TYPE,/*72*/ MTK_PULL_PU_PD_TYPE,/*73*/
+- MTK_PULL_PU_PD_TYPE,/*74*/ MTK_PULL_PU_PD_TYPE,/*75*/
+- MTK_PULL_PU_PD_TYPE,/*76*/ MTK_PULL_PU_PD_TYPE,/*77*/
+- MTK_PULL_PU_PD_TYPE,/*78*/ MTK_PULL_PU_PD_TYPE,/*79*/
+- MTK_PULL_PU_PD_TYPE,/*80*/ MTK_PULL_PU_PD_TYPE,/*81*/
+- MTK_PULL_PU_PD_TYPE,/*82*/ MTK_PULL_PU_PD_TYPE,/*83*/
+- MTK_PULL_PU_PD_TYPE,/*84*/ MTK_PULL_PU_PD_TYPE,/*85*/
+- MTK_PULL_PU_PD_TYPE,/*86*/ MTK_PULL_PU_PD_TYPE,/*87*/
+- MTK_PULL_PU_PD_TYPE,/*88*/ MTK_PULL_PU_PD_TYPE,/*89*/
+- MTK_PULL_PU_PD_TYPE,/*90*/ MTK_PULL_PU_PD_TYPE,/*91*/
+- MTK_PULL_PU_PD_TYPE,/*92*/ MTK_PULL_PU_PD_TYPE,/*93*/
+- MTK_PULL_PU_PD_TYPE,/*94*/ MTK_PULL_PU_PD_TYPE,/*95*/
+- MTK_PULL_PU_PD_TYPE,/*96*/ MTK_PULL_PU_PD_TYPE,/*97*/
+- MTK_PULL_PU_PD_TYPE,/*98*/ MTK_PULL_PU_PD_TYPE,/*99*/
+- MTK_PULL_PU_PD_TYPE,/*100*/
++ MTK_PULL_PU_PD_TYPE,/*40*/ MTK_PULL_PU_PD_TYPE,/*41*/
++ MTK_PULL_PU_PD_TYPE,/*42*/ MTK_PULL_PU_PD_TYPE,/*43*/
++ MTK_PULL_PU_PD_TYPE,/*44*/ MTK_PULL_PU_PD_TYPE,/*45*/
++ MTK_PULL_PU_PD_TYPE,/*46*/ MTK_PULL_PU_PD_TYPE,/*47*/
++ MTK_PULL_PU_PD_TYPE,/*48*/ MTK_PULL_PU_PD_TYPE,/*49*/
++ MTK_PULL_PU_PD_TYPE,/*50*/ MTK_PULL_PU_PD_TYPE,/*51*/
++ MTK_PULL_PU_PD_TYPE,/*52*/ MTK_PULL_PU_PD_TYPE,/*53*/
++ MTK_PULL_PU_PD_TYPE,/*54*/ MTK_PULL_PU_PD_TYPE,/*55*/
++ MTK_PULL_PU_PD_TYPE,/*56*/
+ };
+
+ static const struct mtk_pin_reg_calc mt7981_reg_cals[] = {
+@@ -1014,6 +992,10 @@ static struct mtk_pin_soc mt7981_data =
+ .ies_present = false,
+ .base_names = mt7981_pinctrl_register_base_names,
+ .nbase_names = ARRAY_SIZE(mt7981_pinctrl_register_base_names),
++ .bias_disable_set = mtk_pinconf_bias_disable_set,
++ .bias_disable_get = mtk_pinconf_bias_disable_get,
++ .bias_set = mtk_pinconf_bias_set,
++ .bias_get = mtk_pinconf_bias_get,
+ .pull_type = mt7981_pull_type,
+ .bias_set_combo = mtk_pinconf_bias_set_combo,
+ .bias_get_combo = mtk_pinconf_bias_get_combo,
--- /dev/null
+From 11db447f257231e08065989100311df57b7f1f1c Mon Sep 17 00:00:00 2001
+From: Daniel Golle <daniel@makrotopia.org>
+Date: Sat, 26 Aug 2023 21:06:14 +0100
+Subject: [PATCH] pinctrl: mediatek: mt7981: add additional uart groups
+
+Add uart2_0_tx_rx (pin 4, 5) and uart1_2 (pins 9, 10) groups.
+
+Signed-off-by: Daniel Golle <daniel@makrotopia.org>
+---
+ drivers/pinctrl/mediatek/pinctrl-mt7981.c | 16 +++++++++++++---
+ 1 file changed, 13 insertions(+), 3 deletions(-)
+
+--- a/drivers/pinctrl/mediatek/pinctrl-mt7981.c
++++ b/drivers/pinctrl/mediatek/pinctrl-mt7981.c
+@@ -611,6 +611,9 @@ static int mt7981_wo0_jtag_1_funcs[] = {
+ static int mt7981_uart2_0_pins[] = { 4, 5, 6, 7, };
+ static int mt7981_uart2_0_funcs[] = { 3, 3, 3, 3, };
+
++static int mt7981_uart2_0_tx_rx_pins[] = { 4, 5, };
++static int mt7981_uart2_0_tx_rx_funcs[] = { 3, 3, };
++
+ /* GBE_LED0 */
+ static int mt7981_gbe_led0_pins[] = { 8, };
+ static int mt7981_gbe_led0_funcs[] = { 3, };
+@@ -731,6 +734,9 @@ static int mt7981_uart1_0_funcs[] = { 4,
+ static int mt7981_uart1_1_pins[] = { 26, 27, 28, 29, };
+ static int mt7981_uart1_1_funcs[] = { 2, 2, 2, 2, };
+
++static int mt7981_uart1_2_pins[] = { 9, 10, };
++static int mt7981_uart1_2_funcs[] = { 2, 2, };
++
+ /* UART2 */
+ static int mt7981_uart2_1_pins[] = { 22, 23, 24, 25, };
+ static int mt7981_uart2_1_funcs[] = { 3, 3, 3, 3, };
+@@ -805,6 +811,8 @@ static const struct group_desc mt7981_gr
+ PINCTRL_PIN_GROUP("wo0_jtag_0", mt7981_wo0_jtag_0),
+ /* @GPIO(4,7) WM_JTAG(3) */
+ PINCTRL_PIN_GROUP("uart2_0", mt7981_uart2_0),
++ /* @GPIO(4,5) WM_JTAG(4) */
++ PINCTRL_PIN_GROUP("uart2_0_tx_rx", mt7981_uart2_0_tx_rx),
+ /* @GPIO(8) GBE_LED0(3) */
+ PINCTRL_PIN_GROUP("gbe_led0", mt7981_gbe_led0),
+ /* @GPIO(4,6) PTA_EXT(4) */
+@@ -861,6 +869,8 @@ static const struct group_desc mt7981_gr
+ PINCTRL_PIN_GROUP("uart1_0", mt7981_uart1_0),
+ /* @GPIO(26,29): UART1(2) */
+ PINCTRL_PIN_GROUP("uart1_1", mt7981_uart1_1),
++ /* @GPIO(9,10): UART1(2) */
++ PINCTRL_PIN_GROUP("uart1_2", mt7981_uart1_2),
+ /* @GPIO(22,25): UART1(3) */
+ PINCTRL_PIN_GROUP("uart2_1", mt7981_uart2_1),
+ /* @GPIO(22,24) PTA_EXT(4) */
+@@ -922,9 +932,9 @@ static const struct group_desc mt7981_gr
+ */
+ static const char *mt7981_wa_aice_groups[] = { "wa_aice1", "wa_aice2", "wm_aice1_1",
+ "wa_aice3", "wm_aice1_2", };
+-static const char *mt7981_uart_groups[] = { "wm_uart_0", "uart2_0",
+- "net_wo0_uart_txd_0", "net_wo0_uart_txd_1", "net_wo0_uart_txd_2",
+- "uart1_0", "uart1_1", "uart2_1", "wm_aurt_1", "wm_aurt_2", "uart0", };
++static const char *mt7981_uart_groups[] = { "net_wo0_uart_txd_0", "net_wo0_uart_txd_1",
++ "net_wo0_uart_txd_2", "uart0", "uart1_0", "uart1_1", "uart1_2", "uart2_0",
++ "uart2_0_tx_rx", "uart2_1", "wm_uart_0", "wm_aurt_1", "wm_aurt_2", };
+ static const char *mt7981_dfd_groups[] = { "dfd", "dfd_ntrst", };
+ static const char *mt7981_wdt_groups[] = { "watchdog", "watchdog1", };
+ static const char *mt7981_pcie_groups[] = { "pcie_pereset", "pcie_clk", "pcie_wake", };
--- /dev/null
+From 0d8387fba9f151220e48dc3dcdc2335539708f13 Mon Sep 17 00:00:00 2001
+From: Daniel Golle <daniel@makrotopia.org>
+Date: Fri, 18 Aug 2023 04:03:26 +0100
+Subject: [PATCH] pinctrl: mediatek: assign functions to configure pin bias on
+ MT7986
+
+Assign bias_disable_get/set and bias_get/set functions to allow
+configuring pin bias on MT7986.
+
+Fixes: 2c58d8dc9cd0 ("pinctrl: mediatek: add pull_type attribute for mediatek MT7986 SoC")
+Signed-off-by: Daniel Golle <daniel@makrotopia.org>
+Link: https://lore.kernel.org/r/47f72372354312a839b9337e09476aadcc206e8b.1692327317.git.daniel@makrotopia.org
+Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
+---
+ drivers/pinctrl/mediatek/pinctrl-mt7986.c | 8 ++++++++
+ 1 file changed, 8 insertions(+)
+
+--- a/drivers/pinctrl/mediatek/pinctrl-mt7986.c
++++ b/drivers/pinctrl/mediatek/pinctrl-mt7986.c
+@@ -922,6 +922,10 @@ static struct mtk_pin_soc mt7986a_data =
+ .ies_present = false,
+ .base_names = mt7986_pinctrl_register_base_names,
+ .nbase_names = ARRAY_SIZE(mt7986_pinctrl_register_base_names),
++ .bias_disable_set = mtk_pinconf_bias_disable_set,
++ .bias_disable_get = mtk_pinconf_bias_disable_get,
++ .bias_set = mtk_pinconf_bias_set,
++ .bias_get = mtk_pinconf_bias_get,
+ .pull_type = mt7986_pull_type,
+ .bias_set_combo = mtk_pinconf_bias_set_combo,
+ .bias_get_combo = mtk_pinconf_bias_get_combo,
+@@ -944,6 +948,10 @@ static struct mtk_pin_soc mt7986b_data =
+ .ies_present = false,
+ .base_names = mt7986_pinctrl_register_base_names,
+ .nbase_names = ARRAY_SIZE(mt7986_pinctrl_register_base_names),
++ .bias_disable_set = mtk_pinconf_bias_disable_set,
++ .bias_disable_get = mtk_pinconf_bias_disable_get,
++ .bias_set = mtk_pinconf_bias_set,
++ .bias_get = mtk_pinconf_bias_get,
+ .pull_type = mt7986_pull_type,
+ .bias_set_combo = mtk_pinconf_bias_set_combo,
+ .bias_get_combo = mtk_pinconf_bias_get_combo,
--- /dev/null
+From fe5c8d03f3de89ae058e365b783f8c1314f47490 Mon Sep 17 00:00:00 2001
+From: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
+Date: Fri, 20 Jan 2023 10:20:33 +0100
+Subject: [PATCH 01/15] clk: mediatek: clk-gate: Propagate struct device with
+ mtk_clk_register_gates()
+
+Commit e4c23e19aa2a ("clk: mediatek: Register clock gate with device")
+introduces a helper function for the sole purpose of propagating a
+struct device pointer to the clk API when registering the mtk-gate
+clocks to take advantage of Runtime PM when/where needed and where
+a power domain is defined in devicetree.
+
+Function mtk_clk_register_gates() then becomes a wrapper around the
+new mtk_clk_register_gates_with_dev() function that will simply pass
+NULL as struct device: this is essential when registering drivers
+with CLK_OF_DECLARE instead of as a platform device, as there will
+be no struct device to pass... but we can as well simply have only
+one function that always takes such pointer as a param and pass NULL
+when unavoidable.
+
+This commit removes the mtk_clk_register_gates() wrapper and renames
+mtk_clk_register_gates_with_dev() to the former and all of the calls
+to either of the two functions were fixed in all drivers in order to
+reflect this change; also, to improve consistency with other kernel
+functions, the pointer to struct device was moved as the first param.
+
+Since a lot of MediaTek clock drivers are actually registering as a
+platform device, but were still registering the mtk-gate clocks
+without passing any struct device to the clock framework, they've
+been changed to pass a valid one now, as to make all those platforms
+able to use runtime power management where available.
+
+While at it, some much needed indentation changes were also done.
+
+Signed-off-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
+Reviewed-by: Chen-Yu Tsai <wenst@chromium.org>
+Reviewed-by: Markus Schneider-Pargmann <msp@baylibre.com>
+Tested-by: Miles Chen <miles.chen@mediatek.com>
+Link: https://lore.kernel.org/r/20230120092053.182923-4-angelogioacchino.delregno@collabora.com
+Tested-by: Mingming Su <mingming.su@mediatek.com>
+Signed-off-by: Stephen Boyd <sboyd@kernel.org>
+
+[daniel@makrotopia.org: dropped parts not relevant for OpenWrt]
+---
+ drivers/clk/mediatek/clk-gate.c | 23 +++++++---------------
+ drivers/clk/mediatek/clk-gate.h | 7 +------
+ drivers/clk/mediatek/clk-mt2701-aud.c | 4 ++--
+ drivers/clk/mediatek/clk-mt2701-eth.c | 4 ++--
+ drivers/clk/mediatek/clk-mt2701-g3d.c | 2 +-
+ drivers/clk/mediatek/clk-mt2701-hif.c | 4 ++--
+ drivers/clk/mediatek/clk-mt2701-mm.c | 4 ++--
+ drivers/clk/mediatek/clk-mt2701.c | 12 +++++------
+ drivers/clk/mediatek/clk-mt2712-mm.c | 4 ++--
+ drivers/clk/mediatek/clk-mt2712.c | 12 +++++------
+ drivers/clk/mediatek/clk-mt7622-aud.c | 4 ++--
+ drivers/clk/mediatek/clk-mt7622-eth.c | 8 ++++----
+ drivers/clk/mediatek/clk-mt7622-hif.c | 8 ++++----
+ drivers/clk/mediatek/clk-mt7622.c | 14 ++++++-------
+ drivers/clk/mediatek/clk-mt7629-eth.c | 7 ++++---
+ drivers/clk/mediatek/clk-mt7629-hif.c | 8 ++++----
+ drivers/clk/mediatek/clk-mt7629.c | 10 +++++-----
+ drivers/clk/mediatek/clk-mt7986-eth.c | 10 +++++-----
+ drivers/clk/mediatek/clk-mt7986-infracfg.c | 4 ++--
+ 19 files changed, 68 insertions(+), 81 deletions(-)
+
+--- a/drivers/clk/mediatek/clk-gate.c
++++ b/drivers/clk/mediatek/clk-gate.c
+@@ -152,12 +152,12 @@ const struct clk_ops mtk_clk_gate_ops_no
+ };
+ EXPORT_SYMBOL_GPL(mtk_clk_gate_ops_no_setclr_inv);
+
+-static struct clk_hw *mtk_clk_register_gate(const char *name,
++static struct clk_hw *mtk_clk_register_gate(struct device *dev, const char *name,
+ const char *parent_name,
+ struct regmap *regmap, int set_ofs,
+ int clr_ofs, int sta_ofs, u8 bit,
+ const struct clk_ops *ops,
+- unsigned long flags, struct device *dev)
++ unsigned long flags)
+ {
+ struct mtk_clk_gate *cg;
+ int ret;
+@@ -202,10 +202,9 @@ static void mtk_clk_unregister_gate(stru
+ kfree(cg);
+ }
+
+-int mtk_clk_register_gates_with_dev(struct device_node *node,
+- const struct mtk_gate *clks, int num,
+- struct clk_hw_onecell_data *clk_data,
+- struct device *dev)
++int mtk_clk_register_gates(struct device *dev, struct device_node *node,
++ const struct mtk_gate *clks, int num,
++ struct clk_hw_onecell_data *clk_data)
+ {
+ int i;
+ struct clk_hw *hw;
+@@ -229,13 +228,13 @@ int mtk_clk_register_gates_with_dev(stru
+ continue;
+ }
+
+- hw = mtk_clk_register_gate(gate->name, gate->parent_name,
++ hw = mtk_clk_register_gate(dev, gate->name, gate->parent_name,
+ regmap,
+ gate->regs->set_ofs,
+ gate->regs->clr_ofs,
+ gate->regs->sta_ofs,
+ gate->shift, gate->ops,
+- gate->flags, dev);
++ gate->flags);
+
+ if (IS_ERR(hw)) {
+ pr_err("Failed to register clk %s: %pe\n", gate->name,
+@@ -261,14 +260,6 @@ err:
+
+ return PTR_ERR(hw);
+ }
+-EXPORT_SYMBOL_GPL(mtk_clk_register_gates_with_dev);
+-
+-int mtk_clk_register_gates(struct device_node *node,
+- const struct mtk_gate *clks, int num,
+- struct clk_hw_onecell_data *clk_data)
+-{
+- return mtk_clk_register_gates_with_dev(node, clks, num, clk_data, NULL);
+-}
+ EXPORT_SYMBOL_GPL(mtk_clk_register_gates);
+
+ void mtk_clk_unregister_gates(const struct mtk_gate *clks, int num,
+--- a/drivers/clk/mediatek/clk-gate.h
++++ b/drivers/clk/mediatek/clk-gate.h
+@@ -50,15 +50,10 @@ struct mtk_gate {
+ #define GATE_MTK(_id, _name, _parent, _regs, _shift, _ops) \
+ GATE_MTK_FLAGS(_id, _name, _parent, _regs, _shift, _ops, 0)
+
+-int mtk_clk_register_gates(struct device_node *node,
++int mtk_clk_register_gates(struct device *dev, struct device_node *node,
+ const struct mtk_gate *clks, int num,
+ struct clk_hw_onecell_data *clk_data);
+
+-int mtk_clk_register_gates_with_dev(struct device_node *node,
+- const struct mtk_gate *clks, int num,
+- struct clk_hw_onecell_data *clk_data,
+- struct device *dev);
+-
+ void mtk_clk_unregister_gates(const struct mtk_gate *clks, int num,
+ struct clk_hw_onecell_data *clk_data);
+
+--- a/drivers/clk/mediatek/clk-mt2701-aud.c
++++ b/drivers/clk/mediatek/clk-mt2701-aud.c
+@@ -127,8 +127,8 @@ static int clk_mt2701_aud_probe(struct p
+
+ clk_data = mtk_alloc_clk_data(CLK_AUD_NR);
+
+- mtk_clk_register_gates(node, audio_clks, ARRAY_SIZE(audio_clks),
+- clk_data);
++ mtk_clk_register_gates(&pdev->dev, node, audio_clks,
++ ARRAY_SIZE(audio_clks), clk_data);
+
+ r = of_clk_add_hw_provider(node, of_clk_hw_onecell_get, clk_data);
+ if (r) {
+--- a/drivers/clk/mediatek/clk-mt2701-eth.c
++++ b/drivers/clk/mediatek/clk-mt2701-eth.c
+@@ -51,8 +51,8 @@ static int clk_mt2701_eth_probe(struct p
+
+ clk_data = mtk_alloc_clk_data(CLK_ETHSYS_NR);
+
+- mtk_clk_register_gates(node, eth_clks, ARRAY_SIZE(eth_clks),
+- clk_data);
++ mtk_clk_register_gates(&pdev->dev, node, eth_clks,
++ ARRAY_SIZE(eth_clks), clk_data);
+
+ r = of_clk_add_hw_provider(node, of_clk_hw_onecell_get, clk_data);
+ if (r)
+--- a/drivers/clk/mediatek/clk-mt2701-g3d.c
++++ b/drivers/clk/mediatek/clk-mt2701-g3d.c
+@@ -45,7 +45,7 @@ static int clk_mt2701_g3dsys_init(struct
+
+ clk_data = mtk_alloc_clk_data(CLK_G3DSYS_NR);
+
+- mtk_clk_register_gates(node, g3d_clks, ARRAY_SIZE(g3d_clks),
++ mtk_clk_register_gates(&pdev->dev, node, g3d_clks, ARRAY_SIZE(g3d_clks),
+ clk_data);
+
+ r = of_clk_add_hw_provider(node, of_clk_hw_onecell_get, clk_data);
+--- a/drivers/clk/mediatek/clk-mt2701-hif.c
++++ b/drivers/clk/mediatek/clk-mt2701-hif.c
+@@ -48,8 +48,8 @@ static int clk_mt2701_hif_probe(struct p
+
+ clk_data = mtk_alloc_clk_data(CLK_HIFSYS_NR);
+
+- mtk_clk_register_gates(node, hif_clks, ARRAY_SIZE(hif_clks),
+- clk_data);
++ mtk_clk_register_gates(&pdev->dev, node, hif_clks,
++ ARRAY_SIZE(hif_clks), clk_data);
+
+ r = of_clk_add_hw_provider(node, of_clk_hw_onecell_get, clk_data);
+ if (r) {
+--- a/drivers/clk/mediatek/clk-mt2701-mm.c
++++ b/drivers/clk/mediatek/clk-mt2701-mm.c
+@@ -76,8 +76,8 @@ static int clk_mt2701_mm_probe(struct pl
+
+ clk_data = mtk_alloc_clk_data(CLK_MM_NR);
+
+- mtk_clk_register_gates(node, mm_clks, ARRAY_SIZE(mm_clks),
+- clk_data);
++ mtk_clk_register_gates(&pdev->dev, node, mm_clks,
++ ARRAY_SIZE(mm_clks), clk_data);
+
+ r = of_clk_add_hw_provider(node, of_clk_hw_onecell_get, clk_data);
+ if (r)
+--- a/drivers/clk/mediatek/clk-mt2701.c
++++ b/drivers/clk/mediatek/clk-mt2701.c
+@@ -685,8 +685,8 @@ static int mtk_topckgen_init(struct plat
+ mtk_clk_register_dividers(top_adj_divs, ARRAY_SIZE(top_adj_divs),
+ base, &mt2701_clk_lock, clk_data);
+
+- mtk_clk_register_gates(node, top_clks, ARRAY_SIZE(top_clks),
+- clk_data);
++ mtk_clk_register_gates(&pdev->dev, node, top_clks,
++ ARRAY_SIZE(top_clks), clk_data);
+
+ return of_clk_add_hw_provider(node, of_clk_hw_onecell_get, clk_data);
+ }
+@@ -789,8 +789,8 @@ static int mtk_infrasys_init(struct plat
+ }
+ }
+
+- mtk_clk_register_gates(node, infra_clks, ARRAY_SIZE(infra_clks),
+- infra_clk_data);
++ mtk_clk_register_gates(&pdev->dev, node, infra_clks,
++ ARRAY_SIZE(infra_clks), infra_clk_data);
+ mtk_clk_register_factors(infra_fixed_divs, ARRAY_SIZE(infra_fixed_divs),
+ infra_clk_data);
+
+@@ -902,8 +902,8 @@ static int mtk_pericfg_init(struct platf
+ if (!clk_data)
+ return -ENOMEM;
+
+- mtk_clk_register_gates(node, peri_clks, ARRAY_SIZE(peri_clks),
+- clk_data);
++ mtk_clk_register_gates(&pdev->dev, node, peri_clks,
++ ARRAY_SIZE(peri_clks), clk_data);
+
+ mtk_clk_register_composites(peri_muxs, ARRAY_SIZE(peri_muxs), base,
+ &mt2701_clk_lock, clk_data);
+--- a/drivers/clk/mediatek/clk-mt2712-mm.c
++++ b/drivers/clk/mediatek/clk-mt2712-mm.c
+@@ -117,8 +117,8 @@ static int clk_mt2712_mm_probe(struct pl
+
+ clk_data = mtk_alloc_clk_data(CLK_MM_NR_CLK);
+
+- mtk_clk_register_gates(node, mm_clks, ARRAY_SIZE(mm_clks),
+- clk_data);
++ mtk_clk_register_gates(&pdev->dev, node, mm_clks,
++ ARRAY_SIZE(mm_clks), clk_data);
+
+ r = of_clk_add_hw_provider(node, of_clk_hw_onecell_get, clk_data);
+
+--- a/drivers/clk/mediatek/clk-mt2712.c
++++ b/drivers/clk/mediatek/clk-mt2712.c
+@@ -1324,8 +1324,8 @@ static int clk_mt2712_top_probe(struct p
+ &mt2712_clk_lock, top_clk_data);
+ mtk_clk_register_dividers(top_adj_divs, ARRAY_SIZE(top_adj_divs), base,
+ &mt2712_clk_lock, top_clk_data);
+- mtk_clk_register_gates(node, top_clks, ARRAY_SIZE(top_clks),
+- top_clk_data);
++ mtk_clk_register_gates(&pdev->dev, node, top_clks,
++ ARRAY_SIZE(top_clks), top_clk_data);
+
+ r = of_clk_add_hw_provider(node, of_clk_hw_onecell_get, top_clk_data);
+
+@@ -1344,8 +1344,8 @@ static int clk_mt2712_infra_probe(struct
+
+ clk_data = mtk_alloc_clk_data(CLK_INFRA_NR_CLK);
+
+- mtk_clk_register_gates(node, infra_clks, ARRAY_SIZE(infra_clks),
+- clk_data);
++ mtk_clk_register_gates(&pdev->dev, node, infra_clks,
++ ARRAY_SIZE(infra_clks), clk_data);
+
+ r = of_clk_add_hw_provider(node, of_clk_hw_onecell_get, clk_data);
+
+@@ -1366,8 +1366,8 @@ static int clk_mt2712_peri_probe(struct
+
+ clk_data = mtk_alloc_clk_data(CLK_PERI_NR_CLK);
+
+- mtk_clk_register_gates(node, peri_clks, ARRAY_SIZE(peri_clks),
+- clk_data);
++ mtk_clk_register_gates(&pdev->dev, node, peri_clks,
++ ARRAY_SIZE(peri_clks), clk_data);
+
+ r = of_clk_add_hw_provider(node, of_clk_hw_onecell_get, clk_data);
+
+--- a/drivers/clk/mediatek/clk-mt7622-aud.c
++++ b/drivers/clk/mediatek/clk-mt7622-aud.c
+@@ -114,8 +114,8 @@ static int clk_mt7622_audiosys_init(stru
+
+ clk_data = mtk_alloc_clk_data(CLK_AUDIO_NR_CLK);
+
+- mtk_clk_register_gates(node, audio_clks, ARRAY_SIZE(audio_clks),
+- clk_data);
++ mtk_clk_register_gates(&pdev->dev, node, audio_clks,
++ ARRAY_SIZE(audio_clks), clk_data);
+
+ r = of_clk_add_hw_provider(node, of_clk_hw_onecell_get, clk_data);
+ if (r) {
+--- a/drivers/clk/mediatek/clk-mt7622-eth.c
++++ b/drivers/clk/mediatek/clk-mt7622-eth.c
+@@ -69,8 +69,8 @@ static int clk_mt7622_ethsys_init(struct
+
+ clk_data = mtk_alloc_clk_data(CLK_ETH_NR_CLK);
+
+- mtk_clk_register_gates(node, eth_clks, ARRAY_SIZE(eth_clks),
+- clk_data);
++ mtk_clk_register_gates(&pdev->dev, node, eth_clks,
++ ARRAY_SIZE(eth_clks), clk_data);
+
+ r = of_clk_add_hw_provider(node, of_clk_hw_onecell_get, clk_data);
+ if (r)
+@@ -91,8 +91,8 @@ static int clk_mt7622_sgmiisys_init(stru
+
+ clk_data = mtk_alloc_clk_data(CLK_SGMII_NR_CLK);
+
+- mtk_clk_register_gates(node, sgmii_clks, ARRAY_SIZE(sgmii_clks),
+- clk_data);
++ mtk_clk_register_gates(&pdev->dev, node, sgmii_clks,
++ ARRAY_SIZE(sgmii_clks), clk_data);
+
+ r = of_clk_add_hw_provider(node, of_clk_hw_onecell_get, clk_data);
+ if (r)
+--- a/drivers/clk/mediatek/clk-mt7622-hif.c
++++ b/drivers/clk/mediatek/clk-mt7622-hif.c
+@@ -80,8 +80,8 @@ static int clk_mt7622_ssusbsys_init(stru
+
+ clk_data = mtk_alloc_clk_data(CLK_SSUSB_NR_CLK);
+
+- mtk_clk_register_gates(node, ssusb_clks, ARRAY_SIZE(ssusb_clks),
+- clk_data);
++ mtk_clk_register_gates(&pdev->dev, node, ssusb_clks,
++ ARRAY_SIZE(ssusb_clks), clk_data);
+
+ r = of_clk_add_hw_provider(node, of_clk_hw_onecell_get, clk_data);
+ if (r)
+@@ -102,8 +102,8 @@ static int clk_mt7622_pciesys_init(struc
+
+ clk_data = mtk_alloc_clk_data(CLK_PCIE_NR_CLK);
+
+- mtk_clk_register_gates(node, pcie_clks, ARRAY_SIZE(pcie_clks),
+- clk_data);
++ mtk_clk_register_gates(&pdev->dev, node, pcie_clks,
++ ARRAY_SIZE(pcie_clks), clk_data);
+
+ r = of_clk_add_hw_provider(node, of_clk_hw_onecell_get, clk_data);
+ if (r)
+--- a/drivers/clk/mediatek/clk-mt7622.c
++++ b/drivers/clk/mediatek/clk-mt7622.c
+@@ -621,8 +621,8 @@ static int mtk_topckgen_init(struct plat
+ mtk_clk_register_dividers(top_adj_divs, ARRAY_SIZE(top_adj_divs),
+ base, &mt7622_clk_lock, clk_data);
+
+- mtk_clk_register_gates(node, top_clks, ARRAY_SIZE(top_clks),
+- clk_data);
++ mtk_clk_register_gates(&pdev->dev, node, top_clks,
++ ARRAY_SIZE(top_clks), clk_data);
+
+ return of_clk_add_hw_provider(node, of_clk_hw_onecell_get, clk_data);
+ }
+@@ -635,8 +635,8 @@ static int mtk_infrasys_init(struct plat
+
+ clk_data = mtk_alloc_clk_data(CLK_INFRA_NR_CLK);
+
+- mtk_clk_register_gates(node, infra_clks, ARRAY_SIZE(infra_clks),
+- clk_data);
++ mtk_clk_register_gates(&pdev->dev, node, infra_clks,
++ ARRAY_SIZE(infra_clks), clk_data);
+
+ mtk_clk_register_cpumuxes(node, infra_muxes, ARRAY_SIZE(infra_muxes),
+ clk_data);
+@@ -663,7 +663,7 @@ static int mtk_apmixedsys_init(struct pl
+ mtk_clk_register_plls(node, plls, ARRAY_SIZE(plls),
+ clk_data);
+
+- mtk_clk_register_gates(node, apmixed_clks,
++ mtk_clk_register_gates(&pdev->dev, node, apmixed_clks,
+ ARRAY_SIZE(apmixed_clks), clk_data);
+
+ return of_clk_add_hw_provider(node, of_clk_hw_onecell_get, clk_data);
+@@ -682,8 +682,8 @@ static int mtk_pericfg_init(struct platf
+
+ clk_data = mtk_alloc_clk_data(CLK_PERI_NR_CLK);
+
+- mtk_clk_register_gates(node, peri_clks, ARRAY_SIZE(peri_clks),
+- clk_data);
++ mtk_clk_register_gates(&pdev->dev, node, peri_clks,
++ ARRAY_SIZE(peri_clks), clk_data);
+
+ mtk_clk_register_composites(peri_muxes, ARRAY_SIZE(peri_muxes), base,
+ &mt7622_clk_lock, clk_data);
+--- a/drivers/clk/mediatek/clk-mt7629-eth.c
++++ b/drivers/clk/mediatek/clk-mt7629-eth.c
+@@ -82,7 +82,8 @@ static int clk_mt7629_ethsys_init(struct
+ if (!clk_data)
+ return -ENOMEM;
+
+- mtk_clk_register_gates(node, eth_clks, CLK_ETH_NR_CLK, clk_data);
++ mtk_clk_register_gates(&pdev->dev, node, eth_clks,
++ CLK_ETH_NR_CLK, clk_data);
+
+ r = of_clk_add_hw_provider(node, of_clk_hw_onecell_get, clk_data);
+ if (r)
+@@ -106,8 +107,8 @@ static int clk_mt7629_sgmiisys_init(stru
+ if (!clk_data)
+ return -ENOMEM;
+
+- mtk_clk_register_gates(node, sgmii_clks[id++], CLK_SGMII_NR_CLK,
+- clk_data);
++ mtk_clk_register_gates(&pdev->dev, node, sgmii_clks[id++],
++ CLK_SGMII_NR_CLK, clk_data);
+
+ r = of_clk_add_hw_provider(node, of_clk_hw_onecell_get, clk_data);
+ if (r)
+--- a/drivers/clk/mediatek/clk-mt7629-hif.c
++++ b/drivers/clk/mediatek/clk-mt7629-hif.c
+@@ -75,8 +75,8 @@ static int clk_mt7629_ssusbsys_init(stru
+
+ clk_data = mtk_alloc_clk_data(CLK_SSUSB_NR_CLK);
+
+- mtk_clk_register_gates(node, ssusb_clks, ARRAY_SIZE(ssusb_clks),
+- clk_data);
++ mtk_clk_register_gates(&pdev->dev, node, ssusb_clks,
++ ARRAY_SIZE(ssusb_clks), clk_data);
+
+ r = of_clk_add_hw_provider(node, of_clk_hw_onecell_get, clk_data);
+ if (r)
+@@ -97,8 +97,8 @@ static int clk_mt7629_pciesys_init(struc
+
+ clk_data = mtk_alloc_clk_data(CLK_PCIE_NR_CLK);
+
+- mtk_clk_register_gates(node, pcie_clks, ARRAY_SIZE(pcie_clks),
+- clk_data);
++ mtk_clk_register_gates(&pdev->dev, node, pcie_clks,
++ ARRAY_SIZE(pcie_clks), clk_data);
+
+ r = of_clk_add_hw_provider(node, of_clk_hw_onecell_get, clk_data);
+ if (r)
+--- a/drivers/clk/mediatek/clk-mt7629.c
++++ b/drivers/clk/mediatek/clk-mt7629.c
+@@ -585,8 +585,8 @@ static int mtk_infrasys_init(struct plat
+ if (!clk_data)
+ return -ENOMEM;
+
+- mtk_clk_register_gates(node, infra_clks, ARRAY_SIZE(infra_clks),
+- clk_data);
++ mtk_clk_register_gates(&pdev->dev, node, infra_clks,
++ ARRAY_SIZE(infra_clks), clk_data);
+
+ mtk_clk_register_cpumuxes(node, infra_muxes, ARRAY_SIZE(infra_muxes),
+ clk_data);
+@@ -610,8 +610,8 @@ static int mtk_pericfg_init(struct platf
+ if (!clk_data)
+ return -ENOMEM;
+
+- mtk_clk_register_gates(node, peri_clks, ARRAY_SIZE(peri_clks),
+- clk_data);
++ mtk_clk_register_gates(&pdev->dev, node, peri_clks,
++ ARRAY_SIZE(peri_clks), clk_data);
+
+ mtk_clk_register_composites(peri_muxes, ARRAY_SIZE(peri_muxes), base,
+ &mt7629_clk_lock, clk_data);
+@@ -637,7 +637,7 @@ static int mtk_apmixedsys_init(struct pl
+ mtk_clk_register_plls(node, plls, ARRAY_SIZE(plls),
+ clk_data);
+
+- mtk_clk_register_gates(node, apmixed_clks,
++ mtk_clk_register_gates(&pdev->dev, node, apmixed_clks,
+ ARRAY_SIZE(apmixed_clks), clk_data);
+
+ clk_prepare_enable(clk_data->hws[CLK_APMIXED_ARMPLL]->clk);
+--- a/drivers/clk/mediatek/clk-mt7986-eth.c
++++ b/drivers/clk/mediatek/clk-mt7986-eth.c
+@@ -72,8 +72,8 @@ static void __init mtk_sgmiisys_0_init(s
+
+ clk_data = mtk_alloc_clk_data(ARRAY_SIZE(sgmii0_clks));
+
+- mtk_clk_register_gates(node, sgmii0_clks, ARRAY_SIZE(sgmii0_clks),
+- clk_data);
++ mtk_clk_register_gates(NULL, node, sgmii0_clks,
++ ARRAY_SIZE(sgmii0_clks), clk_data);
+
+ r = of_clk_add_hw_provider(node, of_clk_hw_onecell_get, clk_data);
+ if (r)
+@@ -90,8 +90,8 @@ static void __init mtk_sgmiisys_1_init(s
+
+ clk_data = mtk_alloc_clk_data(ARRAY_SIZE(sgmii1_clks));
+
+- mtk_clk_register_gates(node, sgmii1_clks, ARRAY_SIZE(sgmii1_clks),
+- clk_data);
++ mtk_clk_register_gates(NULL, node, sgmii1_clks,
++ ARRAY_SIZE(sgmii1_clks), clk_data);
+
+ r = of_clk_add_hw_provider(node, of_clk_hw_onecell_get, clk_data);
+
+@@ -109,7 +109,7 @@ static void __init mtk_ethsys_init(struc
+
+ clk_data = mtk_alloc_clk_data(ARRAY_SIZE(eth_clks));
+
+- mtk_clk_register_gates(node, eth_clks, ARRAY_SIZE(eth_clks), clk_data);
++ mtk_clk_register_gates(NULL, node, eth_clks, ARRAY_SIZE(eth_clks), clk_data);
+
+ r = of_clk_add_hw_provider(node, of_clk_hw_onecell_get, clk_data);
+
+--- a/drivers/clk/mediatek/clk-mt7986-infracfg.c
++++ b/drivers/clk/mediatek/clk-mt7986-infracfg.c
+@@ -180,8 +180,8 @@ static int clk_mt7986_infracfg_probe(str
+ mtk_clk_register_factors(infra_divs, ARRAY_SIZE(infra_divs), clk_data);
+ mtk_clk_register_muxes(infra_muxes, ARRAY_SIZE(infra_muxes), node,
+ &mt7986_clk_lock, clk_data);
+- mtk_clk_register_gates(node, infra_clks, ARRAY_SIZE(infra_clks),
+- clk_data);
++ mtk_clk_register_gates(&pdev->dev, node, infra_clks,
++ ARRAY_SIZE(infra_clks), clk_data);
+
+ r = of_clk_add_hw_provider(node, of_clk_hw_onecell_get, clk_data);
+ if (r) {
+--- a/drivers/clk/mediatek/clk-mtk.c
++++ b/drivers/clk/mediatek/clk-mtk.c
+@@ -459,8 +459,8 @@ int mtk_clk_simple_probe(struct platform
+ if (!clk_data)
+ return -ENOMEM;
+
+- r = mtk_clk_register_gates_with_dev(node, mcd->clks, mcd->num_clks,
+- clk_data, &pdev->dev);
++ r = mtk_clk_register_gates(&pdev->dev, node, mcd->clks, mcd->num_clks,
++ clk_data);
+ if (r)
+ goto free_data;
+
--- /dev/null
+From b888303c7d23d7bd0c8667cfc657669e5d153fea Mon Sep 17 00:00:00 2001
+From: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
+Date: Fri, 20 Jan 2023 10:20:34 +0100
+Subject: [PATCH 02/15] clk: mediatek: cpumux: Propagate struct device where
+ possible
+
+Take a pointer to a struct device in mtk_clk_register_cpumuxes() and
+propagate the same to mtk_clk_register_cpumux() => clk_hw_register().
+Even though runtime pm is unlikely to be used with CPU muxes, this
+helps with code consistency and possibly opens to commonization of
+some mtk_clk_register_(x) functions.
+
+Signed-off-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
+Reviewed-by: Chen-Yu Tsai <wenst@chromium.org>
+Reviewed-by: Markus Schneider-Pargmann <msp@baylibre.com>
+Tested-by: Miles Chen <miles.chen@mediatek.com>
+Link: https://lore.kernel.org/r/20230120092053.182923-5-angelogioacchino.delregno@collabora.com
+Tested-by: Mingming Su <mingming.su@mediatek.com>
+Signed-off-by: Stephen Boyd <sboyd@kernel.org>
+---
+ drivers/clk/mediatek/clk-cpumux.c | 8 ++++----
+ drivers/clk/mediatek/clk-cpumux.h | 2 +-
+ drivers/clk/mediatek/clk-mt2701.c | 2 +-
+ drivers/clk/mediatek/clk-mt6795-infracfg.c | 3 ++-
+ drivers/clk/mediatek/clk-mt7622.c | 4 ++--
+ drivers/clk/mediatek/clk-mt7629.c | 4 ++--
+ drivers/clk/mediatek/clk-mt8173.c | 4 ++--
+ 7 files changed, 14 insertions(+), 13 deletions(-)
+
+--- a/drivers/clk/mediatek/clk-cpumux.c
++++ b/drivers/clk/mediatek/clk-cpumux.c
+@@ -58,7 +58,7 @@ static const struct clk_ops clk_cpumux_o
+ };
+
+ static struct clk_hw *
+-mtk_clk_register_cpumux(const struct mtk_composite *mux,
++mtk_clk_register_cpumux(struct device *dev, const struct mtk_composite *mux,
+ struct regmap *regmap)
+ {
+ struct mtk_clk_cpumux *cpumux;
+@@ -81,7 +81,7 @@ mtk_clk_register_cpumux(const struct mtk
+ cpumux->regmap = regmap;
+ cpumux->hw.init = &init;
+
+- ret = clk_hw_register(NULL, &cpumux->hw);
++ ret = clk_hw_register(dev, &cpumux->hw);
+ if (ret) {
+ kfree(cpumux);
+ return ERR_PTR(ret);
+@@ -102,7 +102,7 @@ static void mtk_clk_unregister_cpumux(st
+ kfree(cpumux);
+ }
+
+-int mtk_clk_register_cpumuxes(struct device_node *node,
++int mtk_clk_register_cpumuxes(struct device *dev, struct device_node *node,
+ const struct mtk_composite *clks, int num,
+ struct clk_hw_onecell_data *clk_data)
+ {
+@@ -125,7 +125,7 @@ int mtk_clk_register_cpumuxes(struct dev
+ continue;
+ }
+
+- hw = mtk_clk_register_cpumux(mux, regmap);
++ hw = mtk_clk_register_cpumux(dev, mux, regmap);
+ if (IS_ERR(hw)) {
+ pr_err("Failed to register clk %s: %pe\n", mux->name,
+ hw);
+--- a/drivers/clk/mediatek/clk-cpumux.h
++++ b/drivers/clk/mediatek/clk-cpumux.h
+@@ -11,7 +11,7 @@ struct clk_hw_onecell_data;
+ struct device_node;
+ struct mtk_composite;
+
+-int mtk_clk_register_cpumuxes(struct device_node *node,
++int mtk_clk_register_cpumuxes(struct device *dev, struct device_node *node,
+ const struct mtk_composite *clks, int num,
+ struct clk_hw_onecell_data *clk_data);
+
+--- a/drivers/clk/mediatek/clk-mt2701.c
++++ b/drivers/clk/mediatek/clk-mt2701.c
+@@ -761,7 +761,7 @@ static void __init mtk_infrasys_init_ear
+ mtk_clk_register_factors(infra_fixed_divs, ARRAY_SIZE(infra_fixed_divs),
+ infra_clk_data);
+
+- mtk_clk_register_cpumuxes(node, cpu_muxes, ARRAY_SIZE(cpu_muxes),
++ mtk_clk_register_cpumuxes(NULL, node, cpu_muxes, ARRAY_SIZE(cpu_muxes),
+ infra_clk_data);
+
+ r = of_clk_add_hw_provider(node, of_clk_hw_onecell_get,
+--- a/drivers/clk/mediatek/clk-mt6795-infracfg.c
++++ b/drivers/clk/mediatek/clk-mt6795-infracfg.c
+@@ -105,7 +105,8 @@ static int clk_mt6795_infracfg_probe(str
+ if (ret)
+ goto free_clk_data;
+
+- ret = mtk_clk_register_cpumuxes(node, cpu_muxes, ARRAY_SIZE(cpu_muxes), clk_data);
++ ret = mtk_clk_register_cpumuxes(&pdev->dev, node, cpu_muxes,
++ ARRAY_SIZE(cpu_muxes), clk_data);
+ if (ret)
+ goto unregister_gates;
+
+--- a/drivers/clk/mediatek/clk-mt7622.c
++++ b/drivers/clk/mediatek/clk-mt7622.c
+@@ -638,8 +638,8 @@ static int mtk_infrasys_init(struct plat
+ mtk_clk_register_gates(&pdev->dev, node, infra_clks,
+ ARRAY_SIZE(infra_clks), clk_data);
+
+- mtk_clk_register_cpumuxes(node, infra_muxes, ARRAY_SIZE(infra_muxes),
+- clk_data);
++ mtk_clk_register_cpumuxes(&pdev->dev, node, infra_muxes,
++ ARRAY_SIZE(infra_muxes), clk_data);
+
+ r = of_clk_add_hw_provider(node, of_clk_hw_onecell_get,
+ clk_data);
+--- a/drivers/clk/mediatek/clk-mt7629.c
++++ b/drivers/clk/mediatek/clk-mt7629.c
+@@ -588,8 +588,8 @@ static int mtk_infrasys_init(struct plat
+ mtk_clk_register_gates(&pdev->dev, node, infra_clks,
+ ARRAY_SIZE(infra_clks), clk_data);
+
+- mtk_clk_register_cpumuxes(node, infra_muxes, ARRAY_SIZE(infra_muxes),
+- clk_data);
++ mtk_clk_register_cpumuxes(&pdev->dev, node, infra_muxes,
++ ARRAY_SIZE(infra_muxes), clk_data);
+
+ return of_clk_add_hw_provider(node, of_clk_hw_onecell_get,
+ clk_data);
+--- a/drivers/clk/mediatek/clk-mt8173.c
++++ b/drivers/clk/mediatek/clk-mt8173.c
+@@ -892,8 +892,8 @@ static void __init mtk_infrasys_init(str
+ clk_data);
+ mtk_clk_register_factors(infra_divs, ARRAY_SIZE(infra_divs), clk_data);
+
+- mtk_clk_register_cpumuxes(node, cpu_muxes, ARRAY_SIZE(cpu_muxes),
+- clk_data);
++ mtk_clk_register_cpumuxes(NULL, node, cpu_muxes,
++ ARRAY_SIZE(cpu_muxes), clk_data);
+
+ r = of_clk_add_hw_provider(node, of_clk_hw_onecell_get, clk_data);
+ if (r)
--- /dev/null
+From f23375db001ec0fe9f565be75eff43adde15407e Mon Sep 17 00:00:00 2001
+From: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
+Date: Fri, 20 Jan 2023 10:20:35 +0100
+Subject: [PATCH 03/15] clk: mediatek: clk-mtk: Propagate struct device for
+ composites
+
+Like done for cpumux clocks, propagate struct device for composite
+clocks registered through clk-mtk helpers to be able to get runtime
+pm support for MTK clocks.
+
+Signed-off-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
+Tested-by: Miles Chen <miles.chen@mediatek.com>
+Link: https://lore.kernel.org/r/20230120092053.182923-6-angelogioacchino.delregno@collabora.com
+Tested-by: Mingming Su <mingming.su@mediatek.com>
+Signed-off-by: Stephen Boyd <sboyd@kernel.org>
+
+[daniel@makrotopia.org: remove parts not relevant for OpenWrt]
+---
+ drivers/clk/mediatek/clk-mt2701.c | 10 ++++++----
+ drivers/clk/mediatek/clk-mt2712.c | 12 ++++++++----
+ drivers/clk/mediatek/clk-mt7622.c | 8 +++++---
+ drivers/clk/mediatek/clk-mt7629.c | 8 +++++---
+ drivers/clk/mediatek/clk-mtk.c | 11 ++++++-----
+ drivers/clk/mediatek/clk-mtk.h | 3 ++-
+ 6 files changed, 32 insertions(+), 20 deletions(-)
+
+--- a/drivers/clk/mediatek/clk-mt2701.c
++++ b/drivers/clk/mediatek/clk-mt2701.c
+@@ -679,8 +679,9 @@ static int mtk_topckgen_init(struct plat
+ mtk_clk_register_factors(top_fixed_divs, ARRAY_SIZE(top_fixed_divs),
+ clk_data);
+
+- mtk_clk_register_composites(top_muxes, ARRAY_SIZE(top_muxes),
+- base, &mt2701_clk_lock, clk_data);
++ mtk_clk_register_composites(&pdev->dev, top_muxes,
++ ARRAY_SIZE(top_muxes), base,
++ &mt2701_clk_lock, clk_data);
+
+ mtk_clk_register_dividers(top_adj_divs, ARRAY_SIZE(top_adj_divs),
+ base, &mt2701_clk_lock, clk_data);
+@@ -905,8 +906,9 @@ static int mtk_pericfg_init(struct platf
+ mtk_clk_register_gates(&pdev->dev, node, peri_clks,
+ ARRAY_SIZE(peri_clks), clk_data);
+
+- mtk_clk_register_composites(peri_muxs, ARRAY_SIZE(peri_muxs), base,
+- &mt2701_clk_lock, clk_data);
++ mtk_clk_register_composites(&pdev->dev, peri_muxs,
++ ARRAY_SIZE(peri_muxs), base,
++ &mt2701_clk_lock, clk_data);
+
+ r = of_clk_add_hw_provider(node, of_clk_hw_onecell_get, clk_data);
+ if (r)
+--- a/drivers/clk/mediatek/clk-mt2712.c
++++ b/drivers/clk/mediatek/clk-mt2712.c
+@@ -1320,8 +1320,9 @@ static int clk_mt2712_top_probe(struct p
+ mtk_clk_register_factors(top_early_divs, ARRAY_SIZE(top_early_divs),
+ top_clk_data);
+ mtk_clk_register_factors(top_divs, ARRAY_SIZE(top_divs), top_clk_data);
+- mtk_clk_register_composites(top_muxes, ARRAY_SIZE(top_muxes), base,
+- &mt2712_clk_lock, top_clk_data);
++ mtk_clk_register_composites(&pdev->dev, top_muxes,
++ ARRAY_SIZE(top_muxes), base,
++ &mt2712_clk_lock, top_clk_data);
+ mtk_clk_register_dividers(top_adj_divs, ARRAY_SIZE(top_adj_divs), base,
+ &mt2712_clk_lock, top_clk_data);
+ mtk_clk_register_gates(&pdev->dev, node, top_clks,
+@@ -1395,8 +1396,11 @@ static int clk_mt2712_mcu_probe(struct p
+
+ clk_data = mtk_alloc_clk_data(CLK_MCU_NR_CLK);
+
+- mtk_clk_register_composites(mcu_muxes, ARRAY_SIZE(mcu_muxes), base,
+- &mt2712_clk_lock, clk_data);
++ r = mtk_clk_register_composites(&pdev->dev, mcu_muxes,
++ ARRAY_SIZE(mcu_muxes), base,
++ &mt2712_clk_lock, clk_data);
++ if (r)
++ dev_err(&pdev->dev, "Could not register composites: %d\n", r);
+
+ r = of_clk_add_hw_provider(node, of_clk_hw_onecell_get, clk_data);
+
+--- a/drivers/clk/mediatek/clk-mt7622.c
++++ b/drivers/clk/mediatek/clk-mt7622.c
+@@ -615,8 +615,9 @@ static int mtk_topckgen_init(struct plat
+ mtk_clk_register_factors(top_divs, ARRAY_SIZE(top_divs),
+ clk_data);
+
+- mtk_clk_register_composites(top_muxes, ARRAY_SIZE(top_muxes),
+- base, &mt7622_clk_lock, clk_data);
++ mtk_clk_register_composites(&pdev->dev, top_muxes,
++ ARRAY_SIZE(top_muxes), base,
++ &mt7622_clk_lock, clk_data);
+
+ mtk_clk_register_dividers(top_adj_divs, ARRAY_SIZE(top_adj_divs),
+ base, &mt7622_clk_lock, clk_data);
+@@ -685,7 +686,8 @@ static int mtk_pericfg_init(struct platf
+ mtk_clk_register_gates(&pdev->dev, node, peri_clks,
+ ARRAY_SIZE(peri_clks), clk_data);
+
+- mtk_clk_register_composites(peri_muxes, ARRAY_SIZE(peri_muxes), base,
++ mtk_clk_register_composites(&pdev->dev, peri_muxes,
++ ARRAY_SIZE(peri_muxes), base,
+ &mt7622_clk_lock, clk_data);
+
+ r = of_clk_add_hw_provider(node, of_clk_hw_onecell_get, clk_data);
+--- a/drivers/clk/mediatek/clk-mt7629.c
++++ b/drivers/clk/mediatek/clk-mt7629.c
+@@ -566,8 +566,9 @@ static int mtk_topckgen_init(struct plat
+ mtk_clk_register_factors(top_divs, ARRAY_SIZE(top_divs),
+ clk_data);
+
+- mtk_clk_register_composites(top_muxes, ARRAY_SIZE(top_muxes),
+- base, &mt7629_clk_lock, clk_data);
++ mtk_clk_register_composites(&pdev->dev, top_muxes,
++ ARRAY_SIZE(top_muxes), base,
++ &mt7629_clk_lock, clk_data);
+
+ clk_prepare_enable(clk_data->hws[CLK_TOP_AXI_SEL]->clk);
+ clk_prepare_enable(clk_data->hws[CLK_TOP_MEM_SEL]->clk);
+@@ -613,7 +614,8 @@ static int mtk_pericfg_init(struct platf
+ mtk_clk_register_gates(&pdev->dev, node, peri_clks,
+ ARRAY_SIZE(peri_clks), clk_data);
+
+- mtk_clk_register_composites(peri_muxes, ARRAY_SIZE(peri_muxes), base,
++ mtk_clk_register_composites(&pdev->dev, peri_muxes,
++ ARRAY_SIZE(peri_muxes), base,
+ &mt7629_clk_lock, clk_data);
+
+ r = of_clk_add_hw_provider(node, of_clk_hw_onecell_get, clk_data);
+--- a/drivers/clk/mediatek/clk-mtk.c
++++ b/drivers/clk/mediatek/clk-mtk.c
+@@ -197,8 +197,8 @@ void mtk_clk_unregister_factors(const st
+ }
+ EXPORT_SYMBOL_GPL(mtk_clk_unregister_factors);
+
+-static struct clk_hw *mtk_clk_register_composite(const struct mtk_composite *mc,
+- void __iomem *base, spinlock_t *lock)
++static struct clk_hw *mtk_clk_register_composite(struct device *dev,
++ const struct mtk_composite *mc, void __iomem *base, spinlock_t *lock)
+ {
+ struct clk_hw *hw;
+ struct clk_mux *mux = NULL;
+@@ -264,7 +264,7 @@ static struct clk_hw *mtk_clk_register_c
+ div_ops = &clk_divider_ops;
+ }
+
+- hw = clk_hw_register_composite(NULL, mc->name, parent_names, num_parents,
++ hw = clk_hw_register_composite(dev, mc->name, parent_names, num_parents,
+ mux_hw, mux_ops,
+ div_hw, div_ops,
+ gate_hw, gate_ops,
+@@ -308,7 +308,8 @@ static void mtk_clk_unregister_composite
+ kfree(mux);
+ }
+
+-int mtk_clk_register_composites(const struct mtk_composite *mcs, int num,
++int mtk_clk_register_composites(struct device *dev,
++ const struct mtk_composite *mcs, int num,
+ void __iomem *base, spinlock_t *lock,
+ struct clk_hw_onecell_data *clk_data)
+ {
+@@ -327,7 +328,7 @@ int mtk_clk_register_composites(const st
+ continue;
+ }
+
+- hw = mtk_clk_register_composite(mc, base, lock);
++ hw = mtk_clk_register_composite(dev, mc, base, lock);
+
+ if (IS_ERR(hw)) {
+ pr_err("Failed to register clk %s: %pe\n", mc->name,
+--- a/drivers/clk/mediatek/clk-mtk.h
++++ b/drivers/clk/mediatek/clk-mtk.h
+@@ -149,7 +149,8 @@ struct mtk_composite {
+ .flags = 0, \
+ }
+
+-int mtk_clk_register_composites(const struct mtk_composite *mcs, int num,
++int mtk_clk_register_composites(struct device *dev,
++ const struct mtk_composite *mcs, int num,
+ void __iomem *base, spinlock_t *lock,
+ struct clk_hw_onecell_data *clk_data);
+ void mtk_clk_unregister_composites(const struct mtk_composite *mcs, int num,
--- /dev/null
+From 5d911479e4c732729bfa798e4a9e3e5aec3e30a7 Mon Sep 17 00:00:00 2001
+From: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
+Date: Fri, 20 Jan 2023 10:20:36 +0100
+Subject: [PATCH 04/15] clk: mediatek: clk-mux: Propagate struct device for
+ mtk-mux
+
+Like done for other clocks, propagate struct device for mtk mux clocks
+registered through clk-mux helpers to enable runtime pm support.
+
+Signed-off-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
+Tested-by: Miles Chen <miles.chen@mediatek.com>
+Link: https://lore.kernel.org/r/20230120092053.182923-7-angelogioacchino.delregno@collabora.com
+Tested-by: Mingming Su <mingming.su@mediatek.com>
+Signed-off-by: Stephen Boyd <sboyd@kernel.org>
+
+[daniel@makrotopia.org: removed parts not relevant for OpenWrt]
+---
+ drivers/clk/mediatek/clk-mt7986-infracfg.c | 3 ++-
+ drivers/clk/mediatek/clk-mt7986-topckgen.c | 3 ++-
+ drivers/clk/mediatek/clk-mux.c | 14 ++++++++------
+ drivers/clk/mediatek/clk-mux.h | 3 ++-
+ 4 files changed, 14 insertions(+), 9 deletions(-)
+
+--- a/drivers/clk/mediatek/clk-mt7986-infracfg.c
++++ b/drivers/clk/mediatek/clk-mt7986-infracfg.c
+@@ -178,7 +178,8 @@ static int clk_mt7986_infracfg_probe(str
+ return -ENOMEM;
+
+ mtk_clk_register_factors(infra_divs, ARRAY_SIZE(infra_divs), clk_data);
+- mtk_clk_register_muxes(infra_muxes, ARRAY_SIZE(infra_muxes), node,
++ mtk_clk_register_muxes(&pdev->dev, infra_muxes,
++ ARRAY_SIZE(infra_muxes), node,
+ &mt7986_clk_lock, clk_data);
+ mtk_clk_register_gates(&pdev->dev, node, infra_clks,
+ ARRAY_SIZE(infra_clks), clk_data);
+--- a/drivers/clk/mediatek/clk-mt7986-topckgen.c
++++ b/drivers/clk/mediatek/clk-mt7986-topckgen.c
+@@ -303,7 +303,8 @@ static int clk_mt7986_topckgen_probe(str
+ mtk_clk_register_fixed_clks(top_fixed_clks, ARRAY_SIZE(top_fixed_clks),
+ clk_data);
+ mtk_clk_register_factors(top_divs, ARRAY_SIZE(top_divs), clk_data);
+- mtk_clk_register_muxes(top_muxes, ARRAY_SIZE(top_muxes), node,
++ mtk_clk_register_muxes(&pdev->dev, top_muxes,
++ ARRAY_SIZE(top_muxes), node,
+ &mt7986_clk_lock, clk_data);
+
+ clk_prepare_enable(clk_data->hws[CLK_TOP_SYSAXI_SEL]->clk);
+--- a/drivers/clk/mediatek/clk-mux.c
++++ b/drivers/clk/mediatek/clk-mux.c
+@@ -154,9 +154,10 @@ const struct clk_ops mtk_mux_gate_clr_se
+ };
+ EXPORT_SYMBOL_GPL(mtk_mux_gate_clr_set_upd_ops);
+
+-static struct clk_hw *mtk_clk_register_mux(const struct mtk_mux *mux,
+- struct regmap *regmap,
+- spinlock_t *lock)
++static struct clk_hw *mtk_clk_register_mux(struct device *dev,
++ const struct mtk_mux *mux,
++ struct regmap *regmap,
++ spinlock_t *lock)
+ {
+ struct mtk_clk_mux *clk_mux;
+ struct clk_init_data init = {};
+@@ -177,7 +178,7 @@ static struct clk_hw *mtk_clk_register_m
+ clk_mux->lock = lock;
+ clk_mux->hw.init = &init;
+
+- ret = clk_hw_register(NULL, &clk_mux->hw);
++ ret = clk_hw_register(dev, &clk_mux->hw);
+ if (ret) {
+ kfree(clk_mux);
+ return ERR_PTR(ret);
+@@ -198,7 +199,8 @@ static void mtk_clk_unregister_mux(struc
+ kfree(mux);
+ }
+
+-int mtk_clk_register_muxes(const struct mtk_mux *muxes,
++int mtk_clk_register_muxes(struct device *dev,
++ const struct mtk_mux *muxes,
+ int num, struct device_node *node,
+ spinlock_t *lock,
+ struct clk_hw_onecell_data *clk_data)
+@@ -222,7 +224,7 @@ int mtk_clk_register_muxes(const struct
+ continue;
+ }
+
+- hw = mtk_clk_register_mux(mux, regmap, lock);
++ hw = mtk_clk_register_mux(dev, mux, regmap, lock);
+
+ if (IS_ERR(hw)) {
+ pr_err("Failed to register clk %s: %pe\n", mux->name,
+--- a/drivers/clk/mediatek/clk-mux.h
++++ b/drivers/clk/mediatek/clk-mux.h
+@@ -83,7 +83,8 @@ extern const struct clk_ops mtk_mux_gate
+ 0, _upd_ofs, _upd, CLK_SET_RATE_PARENT, \
+ mtk_mux_clr_set_upd_ops)
+
+-int mtk_clk_register_muxes(const struct mtk_mux *muxes,
++int mtk_clk_register_muxes(struct device *dev,
++ const struct mtk_mux *muxes,
+ int num, struct device_node *node,
+ spinlock_t *lock,
+ struct clk_hw_onecell_data *clk_data);
--- /dev/null
+From b8eb1081d267708ba976525a1fe2162901b34f3a Mon Sep 17 00:00:00 2001
+From: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
+Date: Fri, 20 Jan 2023 10:20:37 +0100
+Subject: [PATCH] clk: mediatek: clk-mtk: Add dummy clock ops
+
+In order to migrate some (few) old clock drivers to the common
+mtk_clk_simple_probe() function, add dummy clock ops to be able
+to insert a dummy clock with ID 0 at the beginning of the list.
+
+Signed-off-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
+Reviewed-by: Miles Chen <miles.chen@mediatek.com>
+Reviewed-by: Chen-Yu Tsai <wenst@chromium.org>
+Tested-by: Miles Chen <miles.chen@mediatek.com>
+Link: https://lore.kernel.org/r/20230120092053.182923-8-angelogioacchino.delregno@collabora.com
+Tested-by: Mingming Su <mingming.su@mediatek.com>
+Signed-off-by: Stephen Boyd <sboyd@kernel.org>
+---
+ drivers/clk/mediatek/clk-mtk.c | 16 ++++++++++++++++
+ drivers/clk/mediatek/clk-mtk.h | 19 +++++++++++++++++++
+ 2 files changed, 35 insertions(+)
+
+--- a/drivers/clk/mediatek/clk-mtk.c
++++ b/drivers/clk/mediatek/clk-mtk.c
+@@ -18,6 +18,22 @@
+ #include "clk-mtk.h"
+ #include "clk-gate.h"
+
++const struct mtk_gate_regs cg_regs_dummy = { 0, 0, 0 };
++EXPORT_SYMBOL_GPL(cg_regs_dummy);
++
++static int mtk_clk_dummy_enable(struct clk_hw *hw)
++{
++ return 0;
++}
++
++static void mtk_clk_dummy_disable(struct clk_hw *hw) { }
++
++const struct clk_ops mtk_clk_dummy_ops = {
++ .enable = mtk_clk_dummy_enable,
++ .disable = mtk_clk_dummy_disable,
++};
++EXPORT_SYMBOL_GPL(mtk_clk_dummy_ops);
++
+ static void mtk_init_clk_data(struct clk_hw_onecell_data *clk_data,
+ unsigned int clk_num)
+ {
+--- a/drivers/clk/mediatek/clk-mtk.h
++++ b/drivers/clk/mediatek/clk-mtk.h
+@@ -22,6 +22,25 @@
+
+ struct platform_device;
+
++/*
++ * We need the clock IDs to start from zero but to maintain devicetree
++ * backwards compatibility we can't change bindings to start from zero.
++ * Only a few platforms are affected, so we solve issues given by the
++ * commonized MTK clocks probe function(s) by adding a dummy clock at
++ * the beginning where needed.
++ */
++#define CLK_DUMMY 0
++
++extern const struct clk_ops mtk_clk_dummy_ops;
++extern const struct mtk_gate_regs cg_regs_dummy;
++
++#define GATE_DUMMY(_id, _name) { \
++ .id = _id, \
++ .name = _name, \
++ .regs = &cg_regs_dummy, \
++ .ops = &mtk_clk_dummy_ops, \
++ }
++
+ struct mtk_fixed_clk {
+ int id;
+ const char *name;
--- /dev/null
+From c26e28015b74af73e0b299f6ad3ff22931e600b4 Mon Sep 17 00:00:00 2001
+From: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
+Date: Fri, 20 Jan 2023 10:20:41 +0100
+Subject: [PATCH 05/15] clk: mediatek: Switch to mtk_clk_simple_probe() where
+ possible
+
+mtk_clk_simple_probe() is a function that registers mtk gate clocks
+and, if reset data is present, a reset controller and across all of
+the MTK clock drivers, such a function is duplicated many times:
+switch to the common mtk_clk_simple_probe() function for all of the
+clock drivers that are registering as platform drivers.
+
+Signed-off-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
+Reviewed-by: Miles Chen <miles.chen@mediatek.com>
+Tested-by: Miles Chen <miles.chen@mediatek.com>
+Link: https://lore.kernel.org/r/20230120092053.182923-12-angelogioacchino.delregno@collabora.com
+Tested-by: Mingming Su <mingming.su@mediatek.com>
+Signed-off-by: Stephen Boyd <sboyd@kernel.org>
+
+[daniel@makrotopia.org: removed parts not relevant for OpenWrt]
+---
+ drivers/clk/mediatek/clk-mt2701-aud.c | 31 ++++++----
+ drivers/clk/mediatek/clk-mt2701-eth.c | 36 ++++--------
+ drivers/clk/mediatek/clk-mt2701-g3d.c | 56 ++++--------------
+ drivers/clk/mediatek/clk-mt2701-hif.c | 38 ++++--------
+ drivers/clk/mediatek/clk-mt2712.c | 83 ++++++++++----------------
+ drivers/clk/mediatek/clk-mt7622-aud.c | 54 ++++++-----------
+ drivers/clk/mediatek/clk-mt7622-eth.c | 82 +++++---------------------
+ drivers/clk/mediatek/clk-mt7622-hif.c | 85 +++++----------------------
+ drivers/clk/mediatek/clk-mt7629-hif.c | 85 +++++----------------------
+ 9 files changed, 144 insertions(+), 406 deletions(-)
+
+--- a/drivers/clk/mediatek/clk-mt2701-aud.c
++++ b/drivers/clk/mediatek/clk-mt2701-aud.c
+@@ -52,6 +52,7 @@ static const struct mtk_gate_regs audio3
+ };
+
+ static const struct mtk_gate audio_clks[] = {
++ GATE_DUMMY(CLK_DUMMY, "aud_dummy"),
+ /* AUDIO0 */
+ GATE_AUDIO0(CLK_AUD_AFE, "audio_afe", "aud_intbus_sel", 2),
+ GATE_AUDIO0(CLK_AUD_HDMI, "audio_hdmi", "audpll_sel", 20),
+@@ -114,29 +115,27 @@ static const struct mtk_gate audio_clks[
+ GATE_AUDIO3(CLK_AUD_MEM_ASRC5, "audio_mem_asrc5", "asm_h_sel", 14),
+ };
+
++static const struct mtk_clk_desc audio_desc = {
++ .clks = audio_clks,
++ .num_clks = ARRAY_SIZE(audio_clks),
++};
++
+ static const struct of_device_id of_match_clk_mt2701_aud[] = {
+- { .compatible = "mediatek,mt2701-audsys", },
+- {}
++ { .compatible = "mediatek,mt2701-audsys", .data = &audio_desc },
++ { /* sentinel */ }
+ };
+
+ static int clk_mt2701_aud_probe(struct platform_device *pdev)
+ {
+- struct clk_hw_onecell_data *clk_data;
+- struct device_node *node = pdev->dev.of_node;
+ int r;
+
+- clk_data = mtk_alloc_clk_data(CLK_AUD_NR);
+-
+- mtk_clk_register_gates(&pdev->dev, node, audio_clks,
+- ARRAY_SIZE(audio_clks), clk_data);
+-
+- r = of_clk_add_hw_provider(node, of_clk_hw_onecell_get, clk_data);
++ r = mtk_clk_simple_probe(pdev);
+ if (r) {
+ dev_err(&pdev->dev,
+ "could not register clock provider: %s: %d\n",
+ pdev->name, r);
+
+- goto err_clk_provider;
++ return r;
+ }
+
+ r = devm_of_platform_populate(&pdev->dev);
+@@ -146,13 +145,19 @@ static int clk_mt2701_aud_probe(struct p
+ return 0;
+
+ err_plat_populate:
+- of_clk_del_provider(node);
+-err_clk_provider:
++ mtk_clk_simple_remove(pdev);
+ return r;
+ }
+
++static int clk_mt2701_aud_remove(struct platform_device *pdev)
++{
++ of_platform_depopulate(&pdev->dev);
++ return mtk_clk_simple_remove(pdev);
++}
++
+ static struct platform_driver clk_mt2701_aud_drv = {
+ .probe = clk_mt2701_aud_probe,
++ .remove = clk_mt2701_aud_remove,
+ .driver = {
+ .name = "clk-mt2701-aud",
+ .of_match_table = of_match_clk_mt2701_aud,
+--- a/drivers/clk/mediatek/clk-mt2701-eth.c
++++ b/drivers/clk/mediatek/clk-mt2701-eth.c
+@@ -20,6 +20,7 @@ static const struct mtk_gate_regs eth_cg
+ GATE_MTK(_id, _name, _parent, ð_cg_regs, _shift, &mtk_clk_gate_ops_no_setclr_inv)
+
+ static const struct mtk_gate eth_clks[] = {
++ GATE_DUMMY(CLK_DUMMY, "eth_dummy"),
+ GATE_ETH(CLK_ETHSYS_HSDMA, "hsdma_clk", "ethif_sel", 5),
+ GATE_ETH(CLK_ETHSYS_ESW, "esw_clk", "ethpll_500m_ck", 6),
+ GATE_ETH(CLK_ETHSYS_GP2, "gp2_clk", "trgpll", 7),
+@@ -38,35 +39,20 @@ static const struct mtk_clk_rst_desc clk
+ .rst_bank_nr = ARRAY_SIZE(rst_ofs),
+ };
+
+-static const struct of_device_id of_match_clk_mt2701_eth[] = {
+- { .compatible = "mediatek,mt2701-ethsys", },
+- {}
++static const struct mtk_clk_desc eth_desc = {
++ .clks = eth_clks,
++ .num_clks = ARRAY_SIZE(eth_clks),
++ .rst_desc = &clk_rst_desc,
+ };
+
+-static int clk_mt2701_eth_probe(struct platform_device *pdev)
+-{
+- struct clk_hw_onecell_data *clk_data;
+- int r;
+- struct device_node *node = pdev->dev.of_node;
+-
+- clk_data = mtk_alloc_clk_data(CLK_ETHSYS_NR);
+-
+- mtk_clk_register_gates(&pdev->dev, node, eth_clks,
+- ARRAY_SIZE(eth_clks), clk_data);
+-
+- r = of_clk_add_hw_provider(node, of_clk_hw_onecell_get, clk_data);
+- if (r)
+- dev_err(&pdev->dev,
+- "could not register clock provider: %s: %d\n",
+- pdev->name, r);
+-
+- mtk_register_reset_controller_with_dev(&pdev->dev, &clk_rst_desc);
+-
+- return r;
+-}
++static const struct of_device_id of_match_clk_mt2701_eth[] = {
++ { .compatible = "mediatek,mt2701-ethsys", .data = ð_desc },
++ { /* sentinel */ }
++};
+
+ static struct platform_driver clk_mt2701_eth_drv = {
+- .probe = clk_mt2701_eth_probe,
++ .probe = mtk_clk_simple_probe,
++ .remove = mtk_clk_simple_remove,
+ .driver = {
+ .name = "clk-mt2701-eth",
+ .of_match_table = of_match_clk_mt2701_eth,
+--- a/drivers/clk/mediatek/clk-mt2701-g3d.c
++++ b/drivers/clk/mediatek/clk-mt2701-g3d.c
+@@ -26,6 +26,7 @@ static const struct mtk_gate_regs g3d_cg
+ };
+
+ static const struct mtk_gate g3d_clks[] = {
++ GATE_DUMMY(CLK_DUMMY, "g3d_dummy"),
+ GATE_G3D(CLK_G3DSYS_CORE, "g3d_core", "mfg_sel", 0),
+ };
+
+@@ -37,57 +38,20 @@ static const struct mtk_clk_rst_desc clk
+ .rst_bank_nr = ARRAY_SIZE(rst_ofs),
+ };
+
+-static int clk_mt2701_g3dsys_init(struct platform_device *pdev)
+-{
+- struct clk_hw_onecell_data *clk_data;
+- struct device_node *node = pdev->dev.of_node;
+- int r;
+-
+- clk_data = mtk_alloc_clk_data(CLK_G3DSYS_NR);
+-
+- mtk_clk_register_gates(&pdev->dev, node, g3d_clks, ARRAY_SIZE(g3d_clks),
+- clk_data);
+-
+- r = of_clk_add_hw_provider(node, of_clk_hw_onecell_get, clk_data);
+- if (r)
+- dev_err(&pdev->dev,
+- "could not register clock provider: %s: %d\n",
+- pdev->name, r);
+-
+- mtk_register_reset_controller_with_dev(&pdev->dev, &clk_rst_desc);
+-
+- return r;
+-}
++static const struct mtk_clk_desc g3d_desc = {
++ .clks = g3d_clks,
++ .num_clks = ARRAY_SIZE(g3d_clks),
++ .rst_desc = &clk_rst_desc,
++};
+
+ static const struct of_device_id of_match_clk_mt2701_g3d[] = {
+- {
+- .compatible = "mediatek,mt2701-g3dsys",
+- .data = clk_mt2701_g3dsys_init,
+- }, {
+- /* sentinel */
+- }
++ { .compatible = "mediatek,mt2701-g3dsys", .data = &g3d_desc },
++ { /* sentinel */ }
+ };
+
+-static int clk_mt2701_g3d_probe(struct platform_device *pdev)
+-{
+- int (*clk_init)(struct platform_device *);
+- int r;
+-
+- clk_init = of_device_get_match_data(&pdev->dev);
+- if (!clk_init)
+- return -EINVAL;
+-
+- r = clk_init(pdev);
+- if (r)
+- dev_err(&pdev->dev,
+- "could not register clock provider: %s: %d\n",
+- pdev->name, r);
+-
+- return r;
+-}
+-
+ static struct platform_driver clk_mt2701_g3d_drv = {
+- .probe = clk_mt2701_g3d_probe,
++ .probe = mtk_clk_simple_probe,
++ .remove = mtk_clk_simple_remove,
+ .driver = {
+ .name = "clk-mt2701-g3d",
+ .of_match_table = of_match_clk_mt2701_g3d,
+--- a/drivers/clk/mediatek/clk-mt2701-hif.c
++++ b/drivers/clk/mediatek/clk-mt2701-hif.c
+@@ -20,6 +20,7 @@ static const struct mtk_gate_regs hif_cg
+ GATE_MTK(_id, _name, _parent, &hif_cg_regs, _shift, &mtk_clk_gate_ops_no_setclr_inv)
+
+ static const struct mtk_gate hif_clks[] = {
++ GATE_DUMMY(CLK_DUMMY, "hif_dummy"),
+ GATE_HIF(CLK_HIFSYS_USB0PHY, "usb0_phy_clk", "ethpll_500m_ck", 21),
+ GATE_HIF(CLK_HIFSYS_USB1PHY, "usb1_phy_clk", "ethpll_500m_ck", 22),
+ GATE_HIF(CLK_HIFSYS_PCIE0, "pcie0_clk", "ethpll_500m_ck", 24),
+@@ -35,37 +36,20 @@ static const struct mtk_clk_rst_desc clk
+ .rst_bank_nr = ARRAY_SIZE(rst_ofs),
+ };
+
+-static const struct of_device_id of_match_clk_mt2701_hif[] = {
+- { .compatible = "mediatek,mt2701-hifsys", },
+- {}
++static const struct mtk_clk_desc hif_desc = {
++ .clks = hif_clks,
++ .num_clks = ARRAY_SIZE(hif_clks),
++ .rst_desc = &clk_rst_desc,
+ };
+
+-static int clk_mt2701_hif_probe(struct platform_device *pdev)
+-{
+- struct clk_hw_onecell_data *clk_data;
+- int r;
+- struct device_node *node = pdev->dev.of_node;
+-
+- clk_data = mtk_alloc_clk_data(CLK_HIFSYS_NR);
+-
+- mtk_clk_register_gates(&pdev->dev, node, hif_clks,
+- ARRAY_SIZE(hif_clks), clk_data);
+-
+- r = of_clk_add_hw_provider(node, of_clk_hw_onecell_get, clk_data);
+- if (r) {
+- dev_err(&pdev->dev,
+- "could not register clock provider: %s: %d\n",
+- pdev->name, r);
+- return r;
+- }
+-
+- mtk_register_reset_controller_with_dev(&pdev->dev, &clk_rst_desc);
+-
+- return 0;
+-}
++static const struct of_device_id of_match_clk_mt2701_hif[] = {
++ { .compatible = "mediatek,mt2701-hifsys", .data = &hif_desc },
++ { /* sentinel */ }
++};
+
+ static struct platform_driver clk_mt2701_hif_drv = {
+- .probe = clk_mt2701_hif_probe,
++ .probe = mtk_clk_simple_probe,
++ .remove = mtk_clk_simple_remove,
+ .driver = {
+ .name = "clk-mt2701-hif",
+ .of_match_table = of_match_clk_mt2701_hif,
+--- a/drivers/clk/mediatek/clk-mt2712.c
++++ b/drivers/clk/mediatek/clk-mt2712.c
+@@ -1337,50 +1337,6 @@ static int clk_mt2712_top_probe(struct p
+ return r;
+ }
+
+-static int clk_mt2712_infra_probe(struct platform_device *pdev)
+-{
+- struct clk_hw_onecell_data *clk_data;
+- int r;
+- struct device_node *node = pdev->dev.of_node;
+-
+- clk_data = mtk_alloc_clk_data(CLK_INFRA_NR_CLK);
+-
+- mtk_clk_register_gates(&pdev->dev, node, infra_clks,
+- ARRAY_SIZE(infra_clks), clk_data);
+-
+- r = of_clk_add_hw_provider(node, of_clk_hw_onecell_get, clk_data);
+-
+- if (r != 0)
+- pr_err("%s(): could not register clock provider: %d\n",
+- __func__, r);
+-
+- mtk_register_reset_controller_with_dev(&pdev->dev, &clk_rst_desc[0]);
+-
+- return r;
+-}
+-
+-static int clk_mt2712_peri_probe(struct platform_device *pdev)
+-{
+- struct clk_hw_onecell_data *clk_data;
+- int r;
+- struct device_node *node = pdev->dev.of_node;
+-
+- clk_data = mtk_alloc_clk_data(CLK_PERI_NR_CLK);
+-
+- mtk_clk_register_gates(&pdev->dev, node, peri_clks,
+- ARRAY_SIZE(peri_clks), clk_data);
+-
+- r = of_clk_add_hw_provider(node, of_clk_hw_onecell_get, clk_data);
+-
+- if (r != 0)
+- pr_err("%s(): could not register clock provider: %d\n",
+- __func__, r);
+-
+- mtk_register_reset_controller_with_dev(&pdev->dev, &clk_rst_desc[1]);
+-
+- return r;
+-}
+-
+ static int clk_mt2712_mcu_probe(struct platform_device *pdev)
+ {
+ struct clk_hw_onecell_data *clk_data;
+@@ -1419,12 +1375,6 @@ static const struct of_device_id of_matc
+ .compatible = "mediatek,mt2712-topckgen",
+ .data = clk_mt2712_top_probe,
+ }, {
+- .compatible = "mediatek,mt2712-infracfg",
+- .data = clk_mt2712_infra_probe,
+- }, {
+- .compatible = "mediatek,mt2712-pericfg",
+- .data = clk_mt2712_peri_probe,
+- }, {
+ .compatible = "mediatek,mt2712-mcucfg",
+ .data = clk_mt2712_mcu_probe,
+ }, {
+@@ -1450,6 +1400,33 @@ static int clk_mt2712_probe(struct platf
+ return r;
+ }
+
++static const struct mtk_clk_desc infra_desc = {
++ .clks = infra_clks,
++ .num_clks = ARRAY_SIZE(infra_clks),
++ .rst_desc = &clk_rst_desc[0],
++};
++
++static const struct mtk_clk_desc peri_desc = {
++ .clks = peri_clks,
++ .num_clks = ARRAY_SIZE(peri_clks),
++ .rst_desc = &clk_rst_desc[1],
++};
++
++static const struct of_device_id of_match_clk_mt2712_simple[] = {
++ { .compatible = "mediatek,mt2712-infracfg", .data = &infra_desc },
++ { .compatible = "mediatek,mt2712-pericfg", .data = &peri_desc, },
++ { /* sentinel */ }
++};
++
++static struct platform_driver clk_mt2712_simple_drv = {
++ .probe = mtk_clk_simple_probe,
++ .remove = mtk_clk_simple_remove,
++ .driver = {
++ .name = "clk-mt2712-simple",
++ .of_match_table = of_match_clk_mt2712_simple,
++ },
++};
++
+ static struct platform_driver clk_mt2712_drv = {
+ .probe = clk_mt2712_probe,
+ .driver = {
+@@ -1460,7 +1437,11 @@ static struct platform_driver clk_mt2712
+
+ static int __init clk_mt2712_init(void)
+ {
+- return platform_driver_register(&clk_mt2712_drv);
++ int ret = platform_driver_register(&clk_mt2712_drv);
++
++ if (ret)
++ return ret;
++ return platform_driver_register(&clk_mt2712_simple_drv);
+ }
+
+ arch_initcall(clk_mt2712_init);
+--- a/drivers/clk/mediatek/clk-mt7622-aud.c
++++ b/drivers/clk/mediatek/clk-mt7622-aud.c
+@@ -106,24 +106,22 @@ static const struct mtk_gate audio_clks[
+ GATE_AUDIO3(CLK_AUDIO_MEM_ASRC5, "audio_mem_asrc5", "asm_h_sel", 14),
+ };
+
+-static int clk_mt7622_audiosys_init(struct platform_device *pdev)
++static const struct mtk_clk_desc audio_desc = {
++ .clks = audio_clks,
++ .num_clks = ARRAY_SIZE(audio_clks),
++};
++
++static int clk_mt7622_aud_probe(struct platform_device *pdev)
+ {
+- struct clk_hw_onecell_data *clk_data;
+- struct device_node *node = pdev->dev.of_node;
+ int r;
+
+- clk_data = mtk_alloc_clk_data(CLK_AUDIO_NR_CLK);
+-
+- mtk_clk_register_gates(&pdev->dev, node, audio_clks,
+- ARRAY_SIZE(audio_clks), clk_data);
+-
+- r = of_clk_add_hw_provider(node, of_clk_hw_onecell_get, clk_data);
++ r = mtk_clk_simple_probe(pdev);
+ if (r) {
+ dev_err(&pdev->dev,
+ "could not register clock provider: %s: %d\n",
+ pdev->name, r);
+
+- goto err_clk_provider;
++ return r;
+ }
+
+ r = devm_of_platform_populate(&pdev->dev);
+@@ -133,40 +131,24 @@ static int clk_mt7622_audiosys_init(stru
+ return 0;
+
+ err_plat_populate:
+- of_clk_del_provider(node);
+-err_clk_provider:
++ mtk_clk_simple_remove(pdev);
+ return r;
+ }
+
+-static const struct of_device_id of_match_clk_mt7622_aud[] = {
+- {
+- .compatible = "mediatek,mt7622-audsys",
+- .data = clk_mt7622_audiosys_init,
+- }, {
+- /* sentinel */
+- }
+-};
+-
+-static int clk_mt7622_aud_probe(struct platform_device *pdev)
++static int clk_mt7622_aud_remove(struct platform_device *pdev)
+ {
+- int (*clk_init)(struct platform_device *);
+- int r;
+-
+- clk_init = of_device_get_match_data(&pdev->dev);
+- if (!clk_init)
+- return -EINVAL;
+-
+- r = clk_init(pdev);
+- if (r)
+- dev_err(&pdev->dev,
+- "could not register clock provider: %s: %d\n",
+- pdev->name, r);
+-
+- return r;
++ of_platform_depopulate(&pdev->dev);
++ return mtk_clk_simple_remove(pdev);
+ }
+
++static const struct of_device_id of_match_clk_mt7622_aud[] = {
++ { .compatible = "mediatek,mt7622-audsys", .data = &audio_desc },
++ { /* sentinel */ }
++};
++
+ static struct platform_driver clk_mt7622_aud_drv = {
+ .probe = clk_mt7622_aud_probe,
++ .remove = clk_mt7622_aud_remove,
+ .driver = {
+ .name = "clk-mt7622-aud",
+ .of_match_table = of_match_clk_mt7622_aud,
+--- a/drivers/clk/mediatek/clk-mt7622-eth.c
++++ b/drivers/clk/mediatek/clk-mt7622-eth.c
+@@ -61,80 +61,26 @@ static const struct mtk_clk_rst_desc clk
+ .rst_bank_nr = ARRAY_SIZE(rst_ofs),
+ };
+
+-static int clk_mt7622_ethsys_init(struct platform_device *pdev)
+-{
+- struct clk_hw_onecell_data *clk_data;
+- struct device_node *node = pdev->dev.of_node;
+- int r;
+-
+- clk_data = mtk_alloc_clk_data(CLK_ETH_NR_CLK);
+-
+- mtk_clk_register_gates(&pdev->dev, node, eth_clks,
+- ARRAY_SIZE(eth_clks), clk_data);
+-
+- r = of_clk_add_hw_provider(node, of_clk_hw_onecell_get, clk_data);
+- if (r)
+- dev_err(&pdev->dev,
+- "could not register clock provider: %s: %d\n",
+- pdev->name, r);
+-
+- mtk_register_reset_controller_with_dev(&pdev->dev, &clk_rst_desc);
+-
+- return r;
+-}
+-
+-static int clk_mt7622_sgmiisys_init(struct platform_device *pdev)
+-{
+- struct clk_hw_onecell_data *clk_data;
+- struct device_node *node = pdev->dev.of_node;
+- int r;
+-
+- clk_data = mtk_alloc_clk_data(CLK_SGMII_NR_CLK);
+-
+- mtk_clk_register_gates(&pdev->dev, node, sgmii_clks,
+- ARRAY_SIZE(sgmii_clks), clk_data);
+-
+- r = of_clk_add_hw_provider(node, of_clk_hw_onecell_get, clk_data);
+- if (r)
+- dev_err(&pdev->dev,
+- "could not register clock provider: %s: %d\n",
+- pdev->name, r);
++static const struct mtk_clk_desc eth_desc = {
++ .clks = eth_clks,
++ .num_clks = ARRAY_SIZE(eth_clks),
++ .rst_desc = &clk_rst_desc,
++};
+
+- return r;
+-}
++static const struct mtk_clk_desc sgmii_desc = {
++ .clks = sgmii_clks,
++ .num_clks = ARRAY_SIZE(sgmii_clks),
++};
+
+ static const struct of_device_id of_match_clk_mt7622_eth[] = {
+- {
+- .compatible = "mediatek,mt7622-ethsys",
+- .data = clk_mt7622_ethsys_init,
+- }, {
+- .compatible = "mediatek,mt7622-sgmiisys",
+- .data = clk_mt7622_sgmiisys_init,
+- }, {
+- /* sentinel */
+- }
++ { .compatible = "mediatek,mt7622-ethsys", .data = ð_desc },
++ { .compatible = "mediatek,mt7622-sgmiisys", .data = &sgmii_desc },
++ { /* sentinel */ }
+ };
+
+-static int clk_mt7622_eth_probe(struct platform_device *pdev)
+-{
+- int (*clk_init)(struct platform_device *);
+- int r;
+-
+- clk_init = of_device_get_match_data(&pdev->dev);
+- if (!clk_init)
+- return -EINVAL;
+-
+- r = clk_init(pdev);
+- if (r)
+- dev_err(&pdev->dev,
+- "could not register clock provider: %s: %d\n",
+- pdev->name, r);
+-
+- return r;
+-}
+-
+ static struct platform_driver clk_mt7622_eth_drv = {
+- .probe = clk_mt7622_eth_probe,
++ .probe = mtk_clk_simple_probe,
++ .remove = mtk_clk_simple_remove,
+ .driver = {
+ .name = "clk-mt7622-eth",
+ .of_match_table = of_match_clk_mt7622_eth,
+--- a/drivers/clk/mediatek/clk-mt7622-hif.c
++++ b/drivers/clk/mediatek/clk-mt7622-hif.c
+@@ -72,82 +72,27 @@ static const struct mtk_clk_rst_desc clk
+ .rst_bank_nr = ARRAY_SIZE(rst_ofs),
+ };
+
+-static int clk_mt7622_ssusbsys_init(struct platform_device *pdev)
+-{
+- struct clk_hw_onecell_data *clk_data;
+- struct device_node *node = pdev->dev.of_node;
+- int r;
+-
+- clk_data = mtk_alloc_clk_data(CLK_SSUSB_NR_CLK);
+-
+- mtk_clk_register_gates(&pdev->dev, node, ssusb_clks,
+- ARRAY_SIZE(ssusb_clks), clk_data);
+-
+- r = of_clk_add_hw_provider(node, of_clk_hw_onecell_get, clk_data);
+- if (r)
+- dev_err(&pdev->dev,
+- "could not register clock provider: %s: %d\n",
+- pdev->name, r);
+-
+- mtk_register_reset_controller_with_dev(&pdev->dev, &clk_rst_desc);
+-
+- return r;
+-}
+-
+-static int clk_mt7622_pciesys_init(struct platform_device *pdev)
+-{
+- struct clk_hw_onecell_data *clk_data;
+- struct device_node *node = pdev->dev.of_node;
+- int r;
+-
+- clk_data = mtk_alloc_clk_data(CLK_PCIE_NR_CLK);
+-
+- mtk_clk_register_gates(&pdev->dev, node, pcie_clks,
+- ARRAY_SIZE(pcie_clks), clk_data);
+-
+- r = of_clk_add_hw_provider(node, of_clk_hw_onecell_get, clk_data);
+- if (r)
+- dev_err(&pdev->dev,
+- "could not register clock provider: %s: %d\n",
+- pdev->name, r);
+-
+- mtk_register_reset_controller_with_dev(&pdev->dev, &clk_rst_desc);
++static const struct mtk_clk_desc ssusb_desc = {
++ .clks = ssusb_clks,
++ .num_clks = ARRAY_SIZE(ssusb_clks),
++ .rst_desc = &clk_rst_desc,
++};
+
+- return r;
+-}
++static const struct mtk_clk_desc pcie_desc = {
++ .clks = pcie_clks,
++ .num_clks = ARRAY_SIZE(pcie_clks),
++ .rst_desc = &clk_rst_desc,
++};
+
+ static const struct of_device_id of_match_clk_mt7622_hif[] = {
+- {
+- .compatible = "mediatek,mt7622-pciesys",
+- .data = clk_mt7622_pciesys_init,
+- }, {
+- .compatible = "mediatek,mt7622-ssusbsys",
+- .data = clk_mt7622_ssusbsys_init,
+- }, {
+- /* sentinel */
+- }
++ { .compatible = "mediatek,mt7622-pciesys", .data = &pcie_desc },
++ { .compatible = "mediatek,mt7622-ssusbsys", .data = &ssusb_desc },
++ { /* sentinel */ }
+ };
+
+-static int clk_mt7622_hif_probe(struct platform_device *pdev)
+-{
+- int (*clk_init)(struct platform_device *);
+- int r;
+-
+- clk_init = of_device_get_match_data(&pdev->dev);
+- if (!clk_init)
+- return -EINVAL;
+-
+- r = clk_init(pdev);
+- if (r)
+- dev_err(&pdev->dev,
+- "could not register clock provider: %s: %d\n",
+- pdev->name, r);
+-
+- return r;
+-}
+-
+ static struct platform_driver clk_mt7622_hif_drv = {
+- .probe = clk_mt7622_hif_probe,
++ .probe = mtk_clk_simple_probe,
++ .remove = mtk_clk_simple_remove,
+ .driver = {
+ .name = "clk-mt7622-hif",
+ .of_match_table = of_match_clk_mt7622_hif,
+--- a/drivers/clk/mediatek/clk-mt7629-hif.c
++++ b/drivers/clk/mediatek/clk-mt7629-hif.c
+@@ -67,82 +67,27 @@ static const struct mtk_clk_rst_desc clk
+ .rst_bank_nr = ARRAY_SIZE(rst_ofs),
+ };
+
+-static int clk_mt7629_ssusbsys_init(struct platform_device *pdev)
+-{
+- struct clk_hw_onecell_data *clk_data;
+- struct device_node *node = pdev->dev.of_node;
+- int r;
+-
+- clk_data = mtk_alloc_clk_data(CLK_SSUSB_NR_CLK);
+-
+- mtk_clk_register_gates(&pdev->dev, node, ssusb_clks,
+- ARRAY_SIZE(ssusb_clks), clk_data);
+-
+- r = of_clk_add_hw_provider(node, of_clk_hw_onecell_get, clk_data);
+- if (r)
+- dev_err(&pdev->dev,
+- "could not register clock provider: %s: %d\n",
+- pdev->name, r);
+-
+- mtk_register_reset_controller_with_dev(&pdev->dev, &clk_rst_desc);
+-
+- return r;
+-}
+-
+-static int clk_mt7629_pciesys_init(struct platform_device *pdev)
+-{
+- struct clk_hw_onecell_data *clk_data;
+- struct device_node *node = pdev->dev.of_node;
+- int r;
+-
+- clk_data = mtk_alloc_clk_data(CLK_PCIE_NR_CLK);
+-
+- mtk_clk_register_gates(&pdev->dev, node, pcie_clks,
+- ARRAY_SIZE(pcie_clks), clk_data);
+-
+- r = of_clk_add_hw_provider(node, of_clk_hw_onecell_get, clk_data);
+- if (r)
+- dev_err(&pdev->dev,
+- "could not register clock provider: %s: %d\n",
+- pdev->name, r);
+-
+- mtk_register_reset_controller_with_dev(&pdev->dev, &clk_rst_desc);
++static const struct mtk_clk_desc ssusb_desc = {
++ .clks = ssusb_clks,
++ .num_clks = ARRAY_SIZE(ssusb_clks),
++ .rst_desc = &clk_rst_desc,
++};
+
+- return r;
+-}
++static const struct mtk_clk_desc pcie_desc = {
++ .clks = pcie_clks,
++ .num_clks = ARRAY_SIZE(pcie_clks),
++ .rst_desc = &clk_rst_desc,
++};
+
+ static const struct of_device_id of_match_clk_mt7629_hif[] = {
+- {
+- .compatible = "mediatek,mt7629-pciesys",
+- .data = clk_mt7629_pciesys_init,
+- }, {
+- .compatible = "mediatek,mt7629-ssusbsys",
+- .data = clk_mt7629_ssusbsys_init,
+- }, {
+- /* sentinel */
+- }
++ { .compatible = "mediatek,mt7629-pciesys", .data = &pcie_desc },
++ { .compatible = "mediatek,mt7629-ssusbsys", .data = &ssusb_desc },
++ { /* sentinel */ }
+ };
+
+-static int clk_mt7629_hif_probe(struct platform_device *pdev)
+-{
+- int (*clk_init)(struct platform_device *);
+- int r;
+-
+- clk_init = of_device_get_match_data(&pdev->dev);
+- if (!clk_init)
+- return -EINVAL;
+-
+- r = clk_init(pdev);
+- if (r)
+- dev_err(&pdev->dev,
+- "could not register clock provider: %s: %d\n",
+- pdev->name, r);
+-
+- return r;
+-}
+-
+ static struct platform_driver clk_mt7629_hif_drv = {
+- .probe = clk_mt7629_hif_probe,
++ .probe = mtk_clk_simple_probe,
++ .remove = mtk_clk_simple_remove,
+ .driver = {
+ .name = "clk-mt7629-hif",
+ .of_match_table = of_match_clk_mt7629_hif,
--- /dev/null
+From 7b6183108c8ccf0dc295f39cdf78bd8078455636 Mon Sep 17 00:00:00 2001
+From: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
+Date: Fri, 20 Jan 2023 10:20:42 +0100
+Subject: [PATCH] clk: mediatek: clk-mtk: Extend mtk_clk_simple_probe()
+
+As a preparation to increase probe functions commonization across
+various MediaTek SoC clock controller drivers, extend function
+mtk_clk_simple_probe() to be able to register not only gates, but
+also fixed clocks, factors, muxes and composites.
+
+Signed-off-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
+Reviewed-by: Miles Chen <miles.chen@mediatek.com>
+Reviewed-by: Chen-Yu Tsai <wenst@chromium.org>
+Tested-by: Miles Chen <miles.chen@mediatek.com>
+Link: https://lore.kernel.org/r/20230120092053.182923-13-angelogioacchino.delregno@collabora.com
+Tested-by: Mingming Su <mingming.su@mediatek.com>
+Signed-off-by: Stephen Boyd <sboyd@kernel.org>
+---
+ drivers/clk/mediatek/clk-mtk.c | 101 ++++++++++++++++++++++++++++++---
+ drivers/clk/mediatek/clk-mtk.h | 10 ++++
+ 2 files changed, 103 insertions(+), 8 deletions(-)
+
+--- a/drivers/clk/mediatek/clk-mtk.c
++++ b/drivers/clk/mediatek/clk-mtk.c
+@@ -11,12 +11,14 @@
+ #include <linux/mfd/syscon.h>
+ #include <linux/module.h>
+ #include <linux/of.h>
++#include <linux/of_address.h>
+ #include <linux/of_device.h>
+ #include <linux/platform_device.h>
+ #include <linux/slab.h>
+
+ #include "clk-mtk.h"
+ #include "clk-gate.h"
++#include "clk-mux.h"
+
+ const struct mtk_gate_regs cg_regs_dummy = { 0, 0, 0 };
+ EXPORT_SYMBOL_GPL(cg_regs_dummy);
+@@ -466,20 +468,71 @@ int mtk_clk_simple_probe(struct platform
+ const struct mtk_clk_desc *mcd;
+ struct clk_hw_onecell_data *clk_data;
+ struct device_node *node = pdev->dev.of_node;
+- int r;
++ void __iomem *base;
++ int num_clks, r;
+
+ mcd = of_device_get_match_data(&pdev->dev);
+ if (!mcd)
+ return -EINVAL;
+
+- clk_data = mtk_alloc_clk_data(mcd->num_clks);
++ /* Composite clocks needs us to pass iomem pointer */
++ if (mcd->composite_clks) {
++ if (!mcd->shared_io)
++ base = devm_platform_ioremap_resource(pdev, 0);
++ else
++ base = of_iomap(node, 0);
++
++ if (IS_ERR_OR_NULL(base))
++ return IS_ERR(base) ? PTR_ERR(base) : -ENOMEM;
++ }
++
++ /* Calculate how many clk_hw_onecell_data entries to allocate */
++ num_clks = mcd->num_clks + mcd->num_composite_clks;
++ num_clks += mcd->num_fixed_clks + mcd->num_factor_clks;
++ num_clks += mcd->num_mux_clks;
++
++ clk_data = mtk_alloc_clk_data(num_clks);
+ if (!clk_data)
+ return -ENOMEM;
+
+- r = mtk_clk_register_gates(&pdev->dev, node, mcd->clks, mcd->num_clks,
+- clk_data);
+- if (r)
+- goto free_data;
++ if (mcd->fixed_clks) {
++ r = mtk_clk_register_fixed_clks(mcd->fixed_clks,
++ mcd->num_fixed_clks, clk_data);
++ if (r)
++ goto free_data;
++ }
++
++ if (mcd->factor_clks) {
++ r = mtk_clk_register_factors(mcd->factor_clks,
++ mcd->num_factor_clks, clk_data);
++ if (r)
++ goto unregister_fixed_clks;
++ }
++
++ if (mcd->mux_clks) {
++ r = mtk_clk_register_muxes(&pdev->dev, mcd->mux_clks,
++ mcd->num_mux_clks, node,
++ mcd->clk_lock, clk_data);
++ if (r)
++ goto unregister_factors;
++ };
++
++ if (mcd->composite_clks) {
++ /* We don't check composite_lock because it's optional */
++ r = mtk_clk_register_composites(&pdev->dev,
++ mcd->composite_clks,
++ mcd->num_composite_clks,
++ base, mcd->clk_lock, clk_data);
++ if (r)
++ goto unregister_muxes;
++ }
++
++ if (mcd->clks) {
++ r = mtk_clk_register_gates(&pdev->dev, node, mcd->clks,
++ mcd->num_clks, clk_data);
++ if (r)
++ goto unregister_composites;
++ }
+
+ r = of_clk_add_hw_provider(node, of_clk_hw_onecell_get, clk_data);
+ if (r)
+@@ -497,9 +550,28 @@ int mtk_clk_simple_probe(struct platform
+ return r;
+
+ unregister_clks:
+- mtk_clk_unregister_gates(mcd->clks, mcd->num_clks, clk_data);
++ if (mcd->clks)
++ mtk_clk_unregister_gates(mcd->clks, mcd->num_clks, clk_data);
++unregister_composites:
++ if (mcd->composite_clks)
++ mtk_clk_unregister_composites(mcd->composite_clks,
++ mcd->num_composite_clks, clk_data);
++unregister_muxes:
++ if (mcd->mux_clks)
++ mtk_clk_unregister_muxes(mcd->mux_clks,
++ mcd->num_mux_clks, clk_data);
++unregister_factors:
++ if (mcd->factor_clks)
++ mtk_clk_unregister_factors(mcd->factor_clks,
++ mcd->num_factor_clks, clk_data);
++unregister_fixed_clks:
++ if (mcd->fixed_clks)
++ mtk_clk_unregister_fixed_clks(mcd->fixed_clks,
++ mcd->num_fixed_clks, clk_data);
+ free_data:
+ mtk_free_clk_data(clk_data);
++ if (mcd->shared_io && base)
++ iounmap(base);
+ return r;
+ }
+ EXPORT_SYMBOL_GPL(mtk_clk_simple_probe);
+@@ -511,7 +583,20 @@ int mtk_clk_simple_remove(struct platfor
+ struct device_node *node = pdev->dev.of_node;
+
+ of_clk_del_provider(node);
+- mtk_clk_unregister_gates(mcd->clks, mcd->num_clks, clk_data);
++ if (mcd->clks)
++ mtk_clk_unregister_gates(mcd->clks, mcd->num_clks, clk_data);
++ if (mcd->composite_clks)
++ mtk_clk_unregister_composites(mcd->composite_clks,
++ mcd->num_composite_clks, clk_data);
++ if (mcd->mux_clks)
++ mtk_clk_unregister_muxes(mcd->mux_clks,
++ mcd->num_mux_clks, clk_data);
++ if (mcd->factor_clks)
++ mtk_clk_unregister_factors(mcd->factor_clks,
++ mcd->num_factor_clks, clk_data);
++ if (mcd->fixed_clks)
++ mtk_clk_unregister_fixed_clks(mcd->fixed_clks,
++ mcd->num_fixed_clks, clk_data);
+ mtk_free_clk_data(clk_data);
+
+ return 0;
+--- a/drivers/clk/mediatek/clk-mtk.h
++++ b/drivers/clk/mediatek/clk-mtk.h
+@@ -215,7 +215,17 @@ void mtk_clk_unregister_ref2usb_tx(struc
+ struct mtk_clk_desc {
+ const struct mtk_gate *clks;
+ size_t num_clks;
++ const struct mtk_composite *composite_clks;
++ size_t num_composite_clks;
++ const struct mtk_fixed_clk *fixed_clks;
++ size_t num_fixed_clks;
++ const struct mtk_fixed_factor *factor_clks;
++ size_t num_factor_clks;
++ const struct mtk_mux *mux_clks;
++ size_t num_mux_clks;
+ const struct mtk_clk_rst_desc *rst_desc;
++ spinlock_t *clk_lock;
++ bool shared_io;
+ };
+
+ int mtk_clk_simple_probe(struct platform_device *pdev);
--- /dev/null
+From 3511004225ce917a4aa6e6ac61481ac60f08f401 Mon Sep 17 00:00:00 2001
+From: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
+Date: Fri, 20 Jan 2023 10:20:52 +0100
+Subject: [PATCH 06/15] clk: mediatek: clk-mt7986-topckgen: Properly keep some
+ clocks enabled
+
+Instead of calling clk_prepare_enable() on a bunch of clocks at probe
+time, set the CLK_IS_CRITICAL flag to the same as these are required
+to be always on, and this is the right way of achieving that.
+
+Signed-off-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
+Reviewed-by: Chen-Yu Tsai <wenst@chromium.org>
+Reviewed-by: Miles Chen <miles.chen@mediatek.com>
+Link: https://lore.kernel.org/r/20230120092053.182923-23-angelogioacchino.delregno@collabora.com
+Tested-by: Mingming Su <mingming.su@mediatek.com>
+Signed-off-by: Stephen Boyd <sboyd@kernel.org>
+---
+ drivers/clk/mediatek/clk-mt7986-topckgen.c | 46 +++++++++++-----------
+ 1 file changed, 24 insertions(+), 22 deletions(-)
+
+--- a/drivers/clk/mediatek/clk-mt7986-topckgen.c
++++ b/drivers/clk/mediatek/clk-mt7986-topckgen.c
+@@ -202,16 +202,23 @@ static const struct mtk_mux top_muxes[]
+ MUX_GATE_CLR_SET_UPD(CLK_TOP_F_26M_ADC_SEL, "f_26m_adc_sel",
+ f_26m_adc_parents, 0x020, 0x024, 0x028, 16, 1, 23,
+ 0x1C0, 10),
+- MUX_GATE_CLR_SET_UPD(CLK_TOP_DRAMC_SEL, "dramc_sel", f_26m_adc_parents,
+- 0x020, 0x024, 0x028, 24, 1, 31, 0x1C0, 11),
++ MUX_GATE_CLR_SET_UPD_FLAGS(CLK_TOP_DRAMC_SEL, "dramc_sel",
++ f_26m_adc_parents, 0x020, 0x024, 0x028,
++ 24, 1, 31, 0x1C0, 11,
++ CLK_IS_CRITICAL | CLK_SET_RATE_PARENT),
+ /* CLK_CFG_3 */
+- MUX_GATE_CLR_SET_UPD(CLK_TOP_DRAMC_MD32_SEL, "dramc_md32_sel",
+- dramc_md32_parents, 0x030, 0x034, 0x038, 0, 1, 7,
+- 0x1C0, 12),
+- MUX_GATE_CLR_SET_UPD(CLK_TOP_SYSAXI_SEL, "sysaxi_sel", sysaxi_parents,
+- 0x030, 0x034, 0x038, 8, 2, 15, 0x1C0, 13),
+- MUX_GATE_CLR_SET_UPD(CLK_TOP_SYSAPB_SEL, "sysapb_sel", sysapb_parents,
+- 0x030, 0x034, 0x038, 16, 2, 23, 0x1C0, 14),
++ MUX_GATE_CLR_SET_UPD_FLAGS(CLK_TOP_DRAMC_MD32_SEL, "dramc_md32_sel",
++ dramc_md32_parents, 0x030, 0x034, 0x038,
++ 0, 1, 7, 0x1C0, 12,
++ CLK_IS_CRITICAL | CLK_SET_RATE_PARENT),
++ MUX_GATE_CLR_SET_UPD_FLAGS(CLK_TOP_SYSAXI_SEL, "sysaxi_sel",
++ sysaxi_parents, 0x030, 0x034, 0x038,
++ 8, 2, 15, 0x1C0, 13,
++ CLK_IS_CRITICAL | CLK_SET_RATE_PARENT),
++ MUX_GATE_CLR_SET_UPD_FLAGS(CLK_TOP_SYSAPB_SEL, "sysapb_sel",
++ sysapb_parents, 0x030, 0x034, 0x038,
++ 16, 2, 23, 0x1C0, 14,
++ CLK_IS_CRITICAL | CLK_SET_RATE_PARENT),
+ MUX_GATE_CLR_SET_UPD(CLK_TOP_ARM_DB_MAIN_SEL, "arm_db_main_sel",
+ arm_db_main_parents, 0x030, 0x034, 0x038, 24, 1,
+ 31, 0x1C0, 15),
+@@ -234,9 +241,10 @@ static const struct mtk_mux top_muxes[]
+ MUX_GATE_CLR_SET_UPD(CLK_TOP_SGM_325M_SEL, "sgm_325m_sel",
+ sgm_325m_parents, 0x050, 0x054, 0x058, 8, 1, 15,
+ 0x1C0, 21),
+- MUX_GATE_CLR_SET_UPD(CLK_TOP_SGM_REG_SEL, "sgm_reg_sel",
+- sgm_reg_parents, 0x050, 0x054, 0x058, 16, 1, 23,
+- 0x1C0, 22),
++ MUX_GATE_CLR_SET_UPD_FLAGS(CLK_TOP_SGM_REG_SEL, "sgm_reg_sel",
++ sgm_reg_parents, 0x050, 0x054, 0x058,
++ 16, 1, 23, 0x1C0, 22,
++ CLK_IS_CRITICAL | CLK_SET_RATE_PARENT),
+ MUX_GATE_CLR_SET_UPD(CLK_TOP_A1SYS_SEL, "a1sys_sel", a1sys_parents,
+ 0x050, 0x054, 0x058, 24, 1, 31, 0x1C0, 23),
+ /* CLK_CFG_6 */
+@@ -252,9 +260,10 @@ static const struct mtk_mux top_muxes[]
+ f_26m_adc_parents, 0x060, 0x064, 0x068, 24, 1, 31,
+ 0x1C0, 27),
+ /* CLK_CFG_7 */
+- MUX_GATE_CLR_SET_UPD(CLK_TOP_F26M_SEL, "csw_f26m_sel",
+- f_26m_adc_parents, 0x070, 0x074, 0x078, 0, 1, 7,
+- 0x1C0, 28),
++ MUX_GATE_CLR_SET_UPD_FLAGS(CLK_TOP_F26M_SEL, "csw_f26m_sel",
++ f_26m_adc_parents, 0x070, 0x074, 0x078,
++ 0, 1, 7, 0x1C0, 28,
++ CLK_IS_CRITICAL | CLK_SET_RATE_PARENT),
+ MUX_GATE_CLR_SET_UPD(CLK_TOP_AUD_L_SEL, "aud_l_sel", aud_l_parents,
+ 0x070, 0x074, 0x078, 8, 2, 15, 0x1C0, 29),
+ MUX_GATE_CLR_SET_UPD(CLK_TOP_A_TUNER_SEL, "a_tuner_sel",
+@@ -307,13 +316,6 @@ static int clk_mt7986_topckgen_probe(str
+ ARRAY_SIZE(top_muxes), node,
+ &mt7986_clk_lock, clk_data);
+
+- clk_prepare_enable(clk_data->hws[CLK_TOP_SYSAXI_SEL]->clk);
+- clk_prepare_enable(clk_data->hws[CLK_TOP_SYSAPB_SEL]->clk);
+- clk_prepare_enable(clk_data->hws[CLK_TOP_DRAMC_SEL]->clk);
+- clk_prepare_enable(clk_data->hws[CLK_TOP_DRAMC_MD32_SEL]->clk);
+- clk_prepare_enable(clk_data->hws[CLK_TOP_F26M_SEL]->clk);
+- clk_prepare_enable(clk_data->hws[CLK_TOP_SGM_REG_SEL]->clk);
+-
+ r = of_clk_add_hw_provider(node, of_clk_hw_onecell_get, clk_data);
+
+ if (r) {
--- /dev/null
+From 9ce3b4e4719d4eec38b2c8da939c073835573d1d Mon Sep 17 00:00:00 2001
+From: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
+Date: Fri, 20 Jan 2023 10:20:53 +0100
+Subject: [PATCH 07/15] clk: mediatek: clk-mt7986-topckgen: Migrate to
+ mtk_clk_simple_probe()
+
+There are no more non-common calls in clk_mt7986_topckgen_probe():
+migrate this driver to mtk_clk_simple_probe().
+
+Signed-off-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
+Reviewed-by: Miles Chen <miles.chen@mediatek.com>
+Reviewed-by: Chen-Yu Tsai <wenst@chromium.org>
+Link: https://lore.kernel.org/r/20230120092053.182923-24-angelogioacchino.delregno@collabora.com
+Tested-by: Mingming Su <mingming.su@mediatek.com>
+Signed-off-by: Stephen Boyd <sboyd@kernel.org>
+---
+ drivers/clk/mediatek/clk-mt7986-topckgen.c | 55 +++++-----------------
+ 1 file changed, 13 insertions(+), 42 deletions(-)
+
+--- a/drivers/clk/mediatek/clk-mt7986-topckgen.c
++++ b/drivers/clk/mediatek/clk-mt7986-topckgen.c
+@@ -290,53 +290,24 @@ static const struct mtk_mux top_muxes[]
+ 0x1C4, 5),
+ };
+
+-static int clk_mt7986_topckgen_probe(struct platform_device *pdev)
+-{
+- struct clk_hw_onecell_data *clk_data;
+- struct device_node *node = pdev->dev.of_node;
+- int r;
+- void __iomem *base;
+- int nr = ARRAY_SIZE(top_fixed_clks) + ARRAY_SIZE(top_divs) +
+- ARRAY_SIZE(top_muxes);
+-
+- base = of_iomap(node, 0);
+- if (!base) {
+- pr_err("%s(): ioremap failed\n", __func__);
+- return -ENOMEM;
+- }
+-
+- clk_data = mtk_alloc_clk_data(nr);
+- if (!clk_data)
+- return -ENOMEM;
+-
+- mtk_clk_register_fixed_clks(top_fixed_clks, ARRAY_SIZE(top_fixed_clks),
+- clk_data);
+- mtk_clk_register_factors(top_divs, ARRAY_SIZE(top_divs), clk_data);
+- mtk_clk_register_muxes(&pdev->dev, top_muxes,
+- ARRAY_SIZE(top_muxes), node,
+- &mt7986_clk_lock, clk_data);
+-
+- r = of_clk_add_hw_provider(node, of_clk_hw_onecell_get, clk_data);
+-
+- if (r) {
+- pr_err("%s(): could not register clock provider: %d\n",
+- __func__, r);
+- goto free_topckgen_data;
+- }
+- return r;
+-
+-free_topckgen_data:
+- mtk_free_clk_data(clk_data);
+- return r;
+-}
++static const struct mtk_clk_desc topck_desc = {
++ .fixed_clks = top_fixed_clks,
++ .num_fixed_clks = ARRAY_SIZE(top_fixed_clks),
++ .factor_clks = top_divs,
++ .num_factor_clks = ARRAY_SIZE(top_divs),
++ .mux_clks = top_muxes,
++ .num_mux_clks = ARRAY_SIZE(top_muxes),
++ .clk_lock = &mt7986_clk_lock,
++};
+
+ static const struct of_device_id of_match_clk_mt7986_topckgen[] = {
+- { .compatible = "mediatek,mt7986-topckgen", },
+- {}
++ { .compatible = "mediatek,mt7986-topckgen", .data = &topck_desc },
++ { /* sentinel */ }
+ };
+
+ static struct platform_driver clk_mt7986_topckgen_drv = {
+- .probe = clk_mt7986_topckgen_probe,
++ .probe = mtk_clk_simple_probe,
++ .remove = mtk_clk_simple_remove,
+ .driver = {
+ .name = "clk-mt7986-topckgen",
+ .of_match_table = of_match_clk_mt7986_topckgen,
--- /dev/null
+From 06abdc84080729dc2c54946e1712c5ee1589ca1c Mon Sep 17 00:00:00 2001
+From: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
+Date: Mon, 6 Mar 2023 15:05:21 +0100
+Subject: [PATCH 13/15] clk: mediatek: mt7986-apmixed: Use PLL_AO flag to set
+ critical clock
+
+Instead of calling clk_prepare_enable() at probe time, add the PLL_AO
+flag to CLK_APMIXED_ARMPLL clock: this will set CLK_IS_CRITICAL.
+
+Signed-off-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
+Reviewed-by: Chen-Yu Tsai <wenst@chromium.org>
+Tested-by: Daniel Golle <daniel@makrotopia.org>
+Link: https://lore.kernel.org/r/20230306140543.1813621-33-angelogioacchino.delregno@collabora.com
+Signed-off-by: Stephen Boyd <sboyd@kernel.org>
+---
+ drivers/clk/mediatek/clk-mt7986-apmixed.c | 4 +---
+ 1 file changed, 1 insertion(+), 3 deletions(-)
+
+--- a/drivers/clk/mediatek/clk-mt7986-apmixed.c
++++ b/drivers/clk/mediatek/clk-mt7986-apmixed.c
+@@ -42,7 +42,7 @@
+ "clkxtal")
+
+ static const struct mtk_pll_data plls[] = {
+- PLL(CLK_APMIXED_ARMPLL, "armpll", 0x0200, 0x020C, 0x0, 0, 32,
++ PLL(CLK_APMIXED_ARMPLL, "armpll", 0x0200, 0x020C, 0x0, PLL_AO, 32,
+ 0x0200, 4, 0, 0x0204, 0),
+ PLL(CLK_APMIXED_NET2PLL, "net2pll", 0x0210, 0x021C, 0x0, 0, 32,
+ 0x0210, 4, 0, 0x0214, 0),
+@@ -77,8 +77,6 @@ static int clk_mt7986_apmixed_probe(stru
+
+ mtk_clk_register_plls(node, plls, ARRAY_SIZE(plls), clk_data);
+
+- clk_prepare_enable(clk_data->hws[CLK_APMIXED_ARMPLL]->clk);
+-
+ r = of_clk_add_hw_provider(node, of_clk_hw_onecell_get, clk_data);
+ if (r) {
+ pr_err("%s(): could not register clock provider: %d\n",
--- /dev/null
+From a6473d0f9f07b1196f3a67099826f50a2a4e84e8 Mon Sep 17 00:00:00 2001
+From: Daniel Golle <daniel@makrotopia.org>
+Date: Thu, 26 Jan 2023 03:34:05 +0000
+Subject: [PATCH] dt-bindings: clock: mediatek: add mt7981 clock IDs
+
+Add MT7981 clock dt-bindings, include topckgen, apmixedsys,
+infracfg, and ethernet subsystem clocks.
+
+Acked-by: Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>
+Signed-off-by: Jianhui Zhao <zhaojh329@gmail.com>
+Signed-off-by: Daniel Golle <daniel@makrotopia.org>
+Link: https://lore.kernel.org/r/e353d32b5a4481766519a037afe1ed44e31ece1a.1674703830.git.daniel@makrotopia.org
+Reviewed-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
+Signed-off-by: Stephen Boyd <sboyd@kernel.org>
+---
+ .../dt-bindings/clock/mediatek,mt7981-clk.h | 215 ++++++++++++++++++
+ 1 file changed, 215 insertions(+)
+ create mode 100644 include/dt-bindings/clock/mediatek,mt7981-clk.h
+
+--- /dev/null
++++ b/include/dt-bindings/clock/mediatek,mt7981-clk.h
+@@ -0,0 +1,215 @@
++/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) */
++/*
++ * Copyright (c) 2021 MediaTek Inc.
++ * Author: Wenzhen.Yu <wenzhen.yu@mediatek.com>
++ * Author: Jianhui Zhao <zhaojh329@gmail.com>
++ * Author: Daniel Golle <daniel@makrotopia.org>
++ */
++
++#ifndef _DT_BINDINGS_CLK_MT7981_H
++#define _DT_BINDINGS_CLK_MT7981_H
++
++/* TOPCKGEN */
++#define CLK_TOP_CB_CKSQ_40M 0
++#define CLK_TOP_CB_M_416M 1
++#define CLK_TOP_CB_M_D2 2
++#define CLK_TOP_CB_M_D3 3
++#define CLK_TOP_M_D3_D2 4
++#define CLK_TOP_CB_M_D4 5
++#define CLK_TOP_CB_M_D8 6
++#define CLK_TOP_M_D8_D2 7
++#define CLK_TOP_CB_MM_720M 8
++#define CLK_TOP_CB_MM_D2 9
++#define CLK_TOP_CB_MM_D3 10
++#define CLK_TOP_CB_MM_D3_D5 11
++#define CLK_TOP_CB_MM_D4 12
++#define CLK_TOP_CB_MM_D6 13
++#define CLK_TOP_MM_D6_D2 14
++#define CLK_TOP_CB_MM_D8 15
++#define CLK_TOP_CB_APLL2_196M 16
++#define CLK_TOP_APLL2_D2 17
++#define CLK_TOP_APLL2_D4 18
++#define CLK_TOP_NET1_2500M 19
++#define CLK_TOP_CB_NET1_D4 20
++#define CLK_TOP_CB_NET1_D5 21
++#define CLK_TOP_NET1_D5_D2 22
++#define CLK_TOP_NET1_D5_D4 23
++#define CLK_TOP_CB_NET1_D8 24
++#define CLK_TOP_NET1_D8_D2 25
++#define CLK_TOP_NET1_D8_D4 26
++#define CLK_TOP_CB_NET2_800M 27
++#define CLK_TOP_CB_NET2_D2 28
++#define CLK_TOP_CB_NET2_D4 29
++#define CLK_TOP_NET2_D4_D2 30
++#define CLK_TOP_NET2_D4_D4 31
++#define CLK_TOP_CB_NET2_D6 32
++#define CLK_TOP_CB_WEDMCU_208M 33
++#define CLK_TOP_CB_SGM_325M 34
++#define CLK_TOP_CKSQ_40M_D2 35
++#define CLK_TOP_CB_RTC_32K 36
++#define CLK_TOP_CB_RTC_32P7K 37
++#define CLK_TOP_USB_TX250M 38
++#define CLK_TOP_FAUD 39
++#define CLK_TOP_NFI1X 40
++#define CLK_TOP_USB_EQ_RX250M 41
++#define CLK_TOP_USB_CDR_CK 42
++#define CLK_TOP_USB_LN0_CK 43
++#define CLK_TOP_SPINFI_BCK 44
++#define CLK_TOP_SPI 45
++#define CLK_TOP_SPIM_MST 46
++#define CLK_TOP_UART_BCK 47
++#define CLK_TOP_PWM_BCK 48
++#define CLK_TOP_I2C_BCK 49
++#define CLK_TOP_PEXTP_TL 50
++#define CLK_TOP_EMMC_208M 51
++#define CLK_TOP_EMMC_400M 52
++#define CLK_TOP_DRAMC_REF 53
++#define CLK_TOP_DRAMC_MD32 54
++#define CLK_TOP_SYSAXI 55
++#define CLK_TOP_SYSAPB 56
++#define CLK_TOP_ARM_DB_MAIN 57
++#define CLK_TOP_AP2CNN_HOST 58
++#define CLK_TOP_NETSYS 59
++#define CLK_TOP_NETSYS_500M 60
++#define CLK_TOP_NETSYS_WED_MCU 61
++#define CLK_TOP_NETSYS_2X 62
++#define CLK_TOP_SGM_325M 63
++#define CLK_TOP_SGM_REG 64
++#define CLK_TOP_F26M 65
++#define CLK_TOP_EIP97B 66
++#define CLK_TOP_USB3_PHY 67
++#define CLK_TOP_AUD 68
++#define CLK_TOP_A1SYS 69
++#define CLK_TOP_AUD_L 70
++#define CLK_TOP_A_TUNER 71
++#define CLK_TOP_U2U3_REF 72
++#define CLK_TOP_U2U3_SYS 73
++#define CLK_TOP_U2U3_XHCI 74
++#define CLK_TOP_USB_FRMCNT 75
++#define CLK_TOP_NFI1X_SEL 76
++#define CLK_TOP_SPINFI_SEL 77
++#define CLK_TOP_SPI_SEL 78
++#define CLK_TOP_SPIM_MST_SEL 79
++#define CLK_TOP_UART_SEL 80
++#define CLK_TOP_PWM_SEL 81
++#define CLK_TOP_I2C_SEL 82
++#define CLK_TOP_PEXTP_TL_SEL 83
++#define CLK_TOP_EMMC_208M_SEL 84
++#define CLK_TOP_EMMC_400M_SEL 85
++#define CLK_TOP_F26M_SEL 86
++#define CLK_TOP_DRAMC_SEL 87
++#define CLK_TOP_DRAMC_MD32_SEL 88
++#define CLK_TOP_SYSAXI_SEL 89
++#define CLK_TOP_SYSAPB_SEL 90
++#define CLK_TOP_ARM_DB_MAIN_SEL 91
++#define CLK_TOP_AP2CNN_HOST_SEL 92
++#define CLK_TOP_NETSYS_SEL 93
++#define CLK_TOP_NETSYS_500M_SEL 94
++#define CLK_TOP_NETSYS_MCU_SEL 95
++#define CLK_TOP_NETSYS_2X_SEL 96
++#define CLK_TOP_SGM_325M_SEL 97
++#define CLK_TOP_SGM_REG_SEL 98
++#define CLK_TOP_EIP97B_SEL 99
++#define CLK_TOP_USB3_PHY_SEL 100
++#define CLK_TOP_AUD_SEL 101
++#define CLK_TOP_A1SYS_SEL 102
++#define CLK_TOP_AUD_L_SEL 103
++#define CLK_TOP_A_TUNER_SEL 104
++#define CLK_TOP_U2U3_SEL 105
++#define CLK_TOP_U2U3_SYS_SEL 106
++#define CLK_TOP_U2U3_XHCI_SEL 107
++#define CLK_TOP_USB_FRMCNT_SEL 108
++#define CLK_TOP_AUD_I2S_M 109
++
++/* INFRACFG */
++#define CLK_INFRA_66M_MCK 0
++#define CLK_INFRA_UART0_SEL 1
++#define CLK_INFRA_UART1_SEL 2
++#define CLK_INFRA_UART2_SEL 3
++#define CLK_INFRA_SPI0_SEL 4
++#define CLK_INFRA_SPI1_SEL 5
++#define CLK_INFRA_SPI2_SEL 6
++#define CLK_INFRA_PWM1_SEL 7
++#define CLK_INFRA_PWM2_SEL 8
++#define CLK_INFRA_PWM3_SEL 9
++#define CLK_INFRA_PWM_BSEL 10
++#define CLK_INFRA_PCIE_SEL 11
++#define CLK_INFRA_GPT_STA 12
++#define CLK_INFRA_PWM_HCK 13
++#define CLK_INFRA_PWM_STA 14
++#define CLK_INFRA_PWM1_CK 15
++#define CLK_INFRA_PWM2_CK 16
++#define CLK_INFRA_PWM3_CK 17
++#define CLK_INFRA_CQ_DMA_CK 18
++#define CLK_INFRA_AUD_BUS_CK 19
++#define CLK_INFRA_AUD_26M_CK 20
++#define CLK_INFRA_AUD_L_CK 21
++#define CLK_INFRA_AUD_AUD_CK 22
++#define CLK_INFRA_AUD_EG2_CK 23
++#define CLK_INFRA_DRAMC_26M_CK 24
++#define CLK_INFRA_DBG_CK 25
++#define CLK_INFRA_AP_DMA_CK 26
++#define CLK_INFRA_SEJ_CK 27
++#define CLK_INFRA_SEJ_13M_CK 28
++#define CLK_INFRA_THERM_CK 29
++#define CLK_INFRA_I2C0_CK 30
++#define CLK_INFRA_UART0_CK 31
++#define CLK_INFRA_UART1_CK 32
++#define CLK_INFRA_UART2_CK 33
++#define CLK_INFRA_SPI2_CK 34
++#define CLK_INFRA_SPI2_HCK_CK 35
++#define CLK_INFRA_NFI1_CK 36
++#define CLK_INFRA_SPINFI1_CK 37
++#define CLK_INFRA_NFI_HCK_CK 38
++#define CLK_INFRA_SPI0_CK 39
++#define CLK_INFRA_SPI1_CK 40
++#define CLK_INFRA_SPI0_HCK_CK 41
++#define CLK_INFRA_SPI1_HCK_CK 42
++#define CLK_INFRA_FRTC_CK 43
++#define CLK_INFRA_MSDC_CK 44
++#define CLK_INFRA_MSDC_HCK_CK 45
++#define CLK_INFRA_MSDC_133M_CK 46
++#define CLK_INFRA_MSDC_66M_CK 47
++#define CLK_INFRA_ADC_26M_CK 48
++#define CLK_INFRA_ADC_FRC_CK 49
++#define CLK_INFRA_FBIST2FPC_CK 50
++#define CLK_INFRA_I2C_MCK_CK 51
++#define CLK_INFRA_I2C_PCK_CK 52
++#define CLK_INFRA_IUSB_133_CK 53
++#define CLK_INFRA_IUSB_66M_CK 54
++#define CLK_INFRA_IUSB_SYS_CK 55
++#define CLK_INFRA_IUSB_CK 56
++#define CLK_INFRA_IPCIE_CK 57
++#define CLK_INFRA_IPCIE_PIPE_CK 58
++#define CLK_INFRA_IPCIER_CK 59
++#define CLK_INFRA_IPCIEB_CK 60
++
++/* APMIXEDSYS */
++#define CLK_APMIXED_ARMPLL 0
++#define CLK_APMIXED_NET2PLL 1
++#define CLK_APMIXED_MMPLL 2
++#define CLK_APMIXED_SGMPLL 3
++#define CLK_APMIXED_WEDMCUPLL 4
++#define CLK_APMIXED_NET1PLL 5
++#define CLK_APMIXED_MPLL 6
++#define CLK_APMIXED_APLL2 7
++
++/* SGMIISYS_0 */
++#define CLK_SGM0_TX_EN 0
++#define CLK_SGM0_RX_EN 1
++#define CLK_SGM0_CK0_EN 2
++#define CLK_SGM0_CDR_CK0_EN 3
++
++/* SGMIISYS_1 */
++#define CLK_SGM1_TX_EN 0
++#define CLK_SGM1_RX_EN 1
++#define CLK_SGM1_CK1_EN 2
++#define CLK_SGM1_CDR_CK1_EN 3
++
++/* ETHSYS */
++#define CLK_ETH_FE_EN 0
++#define CLK_ETH_GP2_EN 1
++#define CLK_ETH_GP1_EN 2
++#define CLK_ETH_WOCPU0_EN 3
++
++#endif /* _DT_BINDINGS_CLK_MT7981_H */
--- /dev/null
+From 8efeeb9c8b4ecf4fb4a74be9403aba951403bbaa Mon Sep 17 00:00:00 2001
+From: Daniel Golle <daniel@makrotopia.org>
+Date: Thu, 26 Jan 2023 03:34:24 +0000
+Subject: [PATCH] clk: mediatek: add MT7981 clock support
+
+Add MT7981 clock support, include topckgen, apmixedsys, infracfg and
+ethernet subsystem clocks.
+
+The drivers are based on clk-mt7981.c which can be found in MediaTek's
+SDK sources. To be fit for upstream inclusion the driver has been split
+into clock domains and the infracfg part has been significantly
+de-bloated by removing all the 1:1 factors (aliases).
+
+Signed-off-by: Jianhui Zhao <zhaojh329@gmail.com>
+Signed-off-by: Daniel Golle <daniel@makrotopia.org>
+Link: https://lore.kernel.org/r/8136eb5b2049177bc2f6d3e0f2aefecc342d626f.1674703830.git.daniel@makrotopia.org
+Reviewed-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
+[sboyd@kernel.org: Add module license]
+Signed-off-by: Stephen Boyd <sboyd@kernel.org>
+---
+ drivers/clk/mediatek/Kconfig | 17 +
+ drivers/clk/mediatek/Makefile | 4 +
+ drivers/clk/mediatek/clk-mt7981-apmixed.c | 102 +++++
+ drivers/clk/mediatek/clk-mt7981-eth.c | 118 ++++++
+ drivers/clk/mediatek/clk-mt7981-infracfg.c | 207 ++++++++++
+ drivers/clk/mediatek/clk-mt7981-topckgen.c | 422 +++++++++++++++++++++
+ 6 files changed, 870 insertions(+)
+ create mode 100644 drivers/clk/mediatek/clk-mt7981-apmixed.c
+ create mode 100644 drivers/clk/mediatek/clk-mt7981-eth.c
+ create mode 100644 drivers/clk/mediatek/clk-mt7981-infracfg.c
+ create mode 100644 drivers/clk/mediatek/clk-mt7981-topckgen.c
+
+--- a/drivers/clk/mediatek/Kconfig
++++ b/drivers/clk/mediatek/Kconfig
+@@ -381,6 +381,23 @@ config COMMON_CLK_MT7629_HIFSYS
+ This driver supports MediaTek MT7629 HIFSYS clocks providing
+ to PCI-E and USB.
+
++config COMMON_CLK_MT7981
++ bool "Clock driver for MediaTek MT7981"
++ depends on ARCH_MEDIATEK || COMPILE_TEST
++ select COMMON_CLK_MEDIATEK
++ default ARCH_MEDIATEK
++ help
++ This driver supports MediaTek MT7981 basic clocks and clocks
++ required for various peripherals found on this SoC.
++
++config COMMON_CLK_MT7981_ETHSYS
++ tristate "Clock driver for MediaTek MT7981 ETHSYS"
++ depends on COMMON_CLK_MT7981
++ default COMMON_CLK_MT7981
++ help
++ This driver adds support for clocks for Ethernet and SGMII
++ required on MediaTek MT7981 SoC.
++
+ config COMMON_CLK_MT7986
+ bool "Clock driver for MediaTek MT7986"
+ depends on ARCH_MEDIATEK || COMPILE_TEST
+--- a/drivers/clk/mediatek/Makefile
++++ b/drivers/clk/mediatek/Makefile
+@@ -52,6 +52,10 @@ obj-$(CONFIG_COMMON_CLK_MT7622_AUDSYS) +
+ obj-$(CONFIG_COMMON_CLK_MT7629) += clk-mt7629.o
+ obj-$(CONFIG_COMMON_CLK_MT7629_ETHSYS) += clk-mt7629-eth.o
+ obj-$(CONFIG_COMMON_CLK_MT7629_HIFSYS) += clk-mt7629-hif.o
++obj-$(CONFIG_COMMON_CLK_MT7981) += clk-mt7981-apmixed.o
++obj-$(CONFIG_COMMON_CLK_MT7981) += clk-mt7981-topckgen.o
++obj-$(CONFIG_COMMON_CLK_MT7981) += clk-mt7981-infracfg.o
++obj-$(CONFIG_COMMON_CLK_MT7981_ETHSYS) += clk-mt7981-eth.o
+ obj-$(CONFIG_COMMON_CLK_MT7986) += clk-mt7986-apmixed.o
+ obj-$(CONFIG_COMMON_CLK_MT7986) += clk-mt7986-topckgen.o
+ obj-$(CONFIG_COMMON_CLK_MT7986) += clk-mt7986-infracfg.o
+--- /dev/null
++++ b/drivers/clk/mediatek/clk-mt7981-apmixed.c
+@@ -0,0 +1,102 @@
++// SPDX-License-Identifier: GPL-2.0
++/*
++ * Copyright (c) 2021 MediaTek Inc.
++ * Author: Sam Shih <sam.shih@mediatek.com>
++ * Author: Wenzhen Yu <wenzhen.yu@mediatek.com>
++ * Author: Jianhui Zhao <zhaojh329@gmail.com>
++ * Author: Daniel Golle <daniel@makrotopia.org>
++ */
++
++#include <linux/clk-provider.h>
++#include <linux/of.h>
++#include <linux/of_address.h>
++#include <linux/of_device.h>
++#include <linux/platform_device.h>
++
++#include "clk-gate.h"
++#include "clk-mtk.h"
++#include "clk-mux.h"
++#include "clk-pll.h"
++
++#include <dt-bindings/clock/mediatek,mt7981-clk.h>
++#include <linux/clk.h>
++
++#define MT7981_PLL_FMAX (2500UL * MHZ)
++#define CON0_MT7981_RST_BAR BIT(27)
++
++#define PLL_xtal(_id, _name, _reg, _pwr_reg, _en_mask, _flags, _pcwbits, \
++ _pd_reg, _pd_shift, _tuner_reg, _pcw_reg, _pcw_shift, \
++ _div_table, _parent_name) \
++ { \
++ .id = _id, .name = _name, .reg = _reg, .pwr_reg = _pwr_reg, \
++ .en_mask = _en_mask, .flags = _flags, \
++ .rst_bar_mask = CON0_MT7981_RST_BAR, .fmax = MT7981_PLL_FMAX, \
++ .pcwbits = _pcwbits, .pd_reg = _pd_reg, .pd_shift = _pd_shift, \
++ .tuner_reg = _tuner_reg, .pcw_reg = _pcw_reg, \
++ .pcw_shift = _pcw_shift, .div_table = _div_table, \
++ .parent_name = _parent_name, \
++ }
++
++#define PLL(_id, _name, _reg, _pwr_reg, _en_mask, _flags, _pcwbits, _pd_reg, \
++ _pd_shift, _tuner_reg, _pcw_reg, _pcw_shift) \
++ PLL_xtal(_id, _name, _reg, _pwr_reg, _en_mask, _flags, _pcwbits, \
++ _pd_reg, _pd_shift, _tuner_reg, _pcw_reg, _pcw_shift, NULL, \
++ "clkxtal")
++
++static const struct mtk_pll_data plls[] = {
++ PLL(CLK_APMIXED_ARMPLL, "armpll", 0x0200, 0x020C, 0x00000001, PLL_AO,
++ 32, 0x0200, 4, 0, 0x0204, 0),
++ PLL(CLK_APMIXED_NET2PLL, "net2pll", 0x0210, 0x021C, 0x00000001, 0, 32,
++ 0x0210, 4, 0, 0x0214, 0),
++ PLL(CLK_APMIXED_MMPLL, "mmpll", 0x0220, 0x022C, 0x00000001, 0, 32,
++ 0x0220, 4, 0, 0x0224, 0),
++ PLL(CLK_APMIXED_SGMPLL, "sgmpll", 0x0230, 0x023C, 0x00000001, 0, 32,
++ 0x0230, 4, 0, 0x0234, 0),
++ PLL(CLK_APMIXED_WEDMCUPLL, "wedmcupll", 0x0240, 0x024C, 0x00000001, 0, 32,
++ 0x0240, 4, 0, 0x0244, 0),
++ PLL(CLK_APMIXED_NET1PLL, "net1pll", 0x0250, 0x025C, 0x00000001, 0, 32,
++ 0x0250, 4, 0, 0x0254, 0),
++ PLL(CLK_APMIXED_MPLL, "mpll", 0x0260, 0x0270, 0x00000001, 0, 32,
++ 0x0260, 4, 0, 0x0264, 0),
++ PLL(CLK_APMIXED_APLL2, "apll2", 0x0278, 0x0288, 0x00000001, 0, 32,
++ 0x0278, 4, 0, 0x027C, 0),
++};
++
++static const struct of_device_id of_match_clk_mt7981_apmixed[] = {
++ { .compatible = "mediatek,mt7981-apmixedsys", },
++ { /* sentinel */ }
++};
++
++static int clk_mt7981_apmixed_probe(struct platform_device *pdev)
++{
++ struct clk_hw_onecell_data *clk_data;
++ struct device_node *node = pdev->dev.of_node;
++ int r;
++
++ clk_data = mtk_alloc_clk_data(ARRAY_SIZE(plls));
++ if (!clk_data)
++ return -ENOMEM;
++
++ mtk_clk_register_plls(node, plls, ARRAY_SIZE(plls), clk_data);
++
++ r = of_clk_add_hw_provider(node, of_clk_hw_onecell_get, clk_data);
++ if (r) {
++ pr_err("%s(): could not register clock provider: %d\n",
++ __func__, r);
++ goto free_apmixed_data;
++ }
++ return r;
++
++free_apmixed_data:
++ mtk_free_clk_data(clk_data);
++ return r;
++}
++
++static struct platform_driver clk_mt7981_apmixed_drv = {
++ .probe = clk_mt7981_apmixed_probe,
++ .driver = {
++ .name = "clk-mt7981-apmixed",
++ .of_match_table = of_match_clk_mt7981_apmixed,
++ },
++};
++builtin_platform_driver(clk_mt7981_apmixed_drv);
+--- /dev/null
++++ b/drivers/clk/mediatek/clk-mt7981-eth.c
+@@ -0,0 +1,118 @@
++// SPDX-License-Identifier: GPL-2.0
++/*
++ * Copyright (c) 2021 MediaTek Inc.
++ * Author: Sam Shih <sam.shih@mediatek.com>
++ * Author: Wenzhen Yu <wenzhen.yu@mediatek.com>
++ * Author: Jianhui Zhao <zhaojh329@gmail.com>
++ * Author: Daniel Golle <daniel@makrotopia.org>
++ */
++
++#include <linux/clk-provider.h>
++#include <linux/of.h>
++#include <linux/of_address.h>
++#include <linux/of_device.h>
++#include <linux/platform_device.h>
++
++#include "clk-mtk.h"
++#include "clk-gate.h"
++
++#include <dt-bindings/clock/mediatek,mt7981-clk.h>
++
++static const struct mtk_gate_regs sgmii0_cg_regs = {
++ .set_ofs = 0xE4,
++ .clr_ofs = 0xE4,
++ .sta_ofs = 0xE4,
++};
++
++#define GATE_SGMII0(_id, _name, _parent, _shift) { \
++ .id = _id, \
++ .name = _name, \
++ .parent_name = _parent, \
++ .regs = &sgmii0_cg_regs, \
++ .shift = _shift, \
++ .ops = &mtk_clk_gate_ops_no_setclr_inv, \
++ }
++
++static const struct mtk_gate sgmii0_clks[] __initconst = {
++ GATE_SGMII0(CLK_SGM0_TX_EN, "sgm0_tx_en", "usb_tx250m", 2),
++ GATE_SGMII0(CLK_SGM0_RX_EN, "sgm0_rx_en", "usb_eq_rx250m", 3),
++ GATE_SGMII0(CLK_SGM0_CK0_EN, "sgm0_ck0_en", "usb_ln0", 4),
++ GATE_SGMII0(CLK_SGM0_CDR_CK0_EN, "sgm0_cdr_ck0_en", "usb_cdr", 5),
++};
++
++static const struct mtk_gate_regs sgmii1_cg_regs = {
++ .set_ofs = 0xE4,
++ .clr_ofs = 0xE4,
++ .sta_ofs = 0xE4,
++};
++
++#define GATE_SGMII1(_id, _name, _parent, _shift) { \
++ .id = _id, \
++ .name = _name, \
++ .parent_name = _parent, \
++ .regs = &sgmii1_cg_regs, \
++ .shift = _shift, \
++ .ops = &mtk_clk_gate_ops_no_setclr_inv, \
++ }
++
++static const struct mtk_gate sgmii1_clks[] __initconst = {
++ GATE_SGMII1(CLK_SGM1_TX_EN, "sgm1_tx_en", "usb_tx250m", 2),
++ GATE_SGMII1(CLK_SGM1_RX_EN, "sgm1_rx_en", "usb_eq_rx250m", 3),
++ GATE_SGMII1(CLK_SGM1_CK1_EN, "sgm1_ck1_en", "usb_ln0", 4),
++ GATE_SGMII1(CLK_SGM1_CDR_CK1_EN, "sgm1_cdr_ck1_en", "usb_cdr", 5),
++};
++
++static const struct mtk_gate_regs eth_cg_regs = {
++ .set_ofs = 0x30,
++ .clr_ofs = 0x30,
++ .sta_ofs = 0x30,
++};
++
++#define GATE_ETH(_id, _name, _parent, _shift) { \
++ .id = _id, \
++ .name = _name, \
++ .parent_name = _parent, \
++ .regs = ð_cg_regs, \
++ .shift = _shift, \
++ .ops = &mtk_clk_gate_ops_no_setclr_inv, \
++ }
++
++static const struct mtk_gate eth_clks[] __initconst = {
++ GATE_ETH(CLK_ETH_FE_EN, "eth_fe_en", "netsys_2x", 6),
++ GATE_ETH(CLK_ETH_GP2_EN, "eth_gp2_en", "sgm_325m", 7),
++ GATE_ETH(CLK_ETH_GP1_EN, "eth_gp1_en", "sgm_325m", 8),
++ GATE_ETH(CLK_ETH_WOCPU0_EN, "eth_wocpu0_en", "netsys_wed_mcu", 15),
++};
++
++static const struct mtk_clk_desc eth_desc = {
++ .clks = eth_clks,
++ .num_clks = ARRAY_SIZE(eth_clks),
++};
++
++static const struct mtk_clk_desc sgmii0_desc = {
++ .clks = sgmii0_clks,
++ .num_clks = ARRAY_SIZE(sgmii0_clks),
++};
++
++static const struct mtk_clk_desc sgmii1_desc = {
++ .clks = sgmii1_clks,
++ .num_clks = ARRAY_SIZE(sgmii1_clks),
++};
++
++static const struct of_device_id of_match_clk_mt7981_eth[] = {
++ { .compatible = "mediatek,mt7981-ethsys", .data = ð_desc },
++ { .compatible = "mediatek,mt7981-sgmiisys_0", .data = &sgmii0_desc },
++ { .compatible = "mediatek,mt7981-sgmiisys_1", .data = &sgmii1_desc },
++ { /* sentinel */ }
++};
++
++static struct platform_driver clk_mt7981_eth_drv = {
++ .probe = mtk_clk_simple_probe,
++ .remove = mtk_clk_simple_remove,
++ .driver = {
++ .name = "clk-mt7981-eth",
++ .of_match_table = of_match_clk_mt7981_eth,
++ },
++};
++module_platform_driver(clk_mt7981_eth_drv);
++MODULE_LICENSE("GPL v2");
+--- /dev/null
++++ b/drivers/clk/mediatek/clk-mt7981-infracfg.c
+@@ -0,0 +1,207 @@
++// SPDX-License-Identifier: GPL-2.0
++/*
++ * Copyright (c) 2021 MediaTek Inc.
++ * Author: Sam Shih <sam.shih@mediatek.com>
++ * Author: Wenzhen Yu <wenzhen.yu@mediatek.com>
++ * Author: Jianhui Zhao <zhaojh329@gmail.com>
++ * Author: Daniel Golle <daniel@makrotopia.org>
++ */
++
++#include <linux/clk-provider.h>
++#include <linux/of.h>
++#include <linux/of_address.h>
++#include <linux/of_device.h>
++#include <linux/platform_device.h>
++#include "clk-mtk.h"
++#include "clk-gate.h"
++#include "clk-mux.h"
++
++#include <dt-bindings/clock/mediatek,mt7981-clk.h>
++#include <linux/clk.h>
++
++static DEFINE_SPINLOCK(mt7981_clk_lock);
++
++static const struct mtk_fixed_factor infra_divs[] = {
++ FACTOR(CLK_INFRA_66M_MCK, "infra_66m_mck", "sysaxi_sel", 1, 2),
++};
++
++static const char *const infra_uart_parent[] __initconst = { "csw_f26m_sel",
++ "uart_sel" };
++
++static const char *const infra_spi0_parents[] __initconst = { "i2c_sel",
++ "spi_sel" };
++
++static const char *const infra_spi1_parents[] __initconst = { "i2c_sel",
++ "spim_mst_sel" };
++
++static const char *const infra_pwm1_parents[] __initconst = { "pwm_sel" };
++
++static const char *const infra_pwm_bsel_parents[] __initconst = {
++ "cb_rtc_32p7k", "csw_f26m_sel", "infra_66m_mck", "pwm_sel"
++};
++
++static const char *const infra_pcie_parents[] __initconst = {
++ "cb_rtc_32p7k", "csw_f26m_sel", "cb_cksq_40m", "pextp_tl_ck_sel"
++};
++
++static const struct mtk_mux infra_muxes[] = {
++ /* MODULE_CLK_SEL_0 */
++ MUX_GATE_CLR_SET_UPD(CLK_INFRA_UART0_SEL, "infra_uart0_sel",
++ infra_uart_parent, 0x0018, 0x0010, 0x0014, 0, 1,
++ -1, -1, -1),
++ MUX_GATE_CLR_SET_UPD(CLK_INFRA_UART1_SEL, "infra_uart1_sel",
++ infra_uart_parent, 0x0018, 0x0010, 0x0014, 1, 1,
++ -1, -1, -1),
++ MUX_GATE_CLR_SET_UPD(CLK_INFRA_UART2_SEL, "infra_uart2_sel",
++ infra_uart_parent, 0x0018, 0x0010, 0x0014, 2, 1,
++ -1, -1, -1),
++ MUX_GATE_CLR_SET_UPD(CLK_INFRA_SPI0_SEL, "infra_spi0_sel",
++ infra_spi0_parents, 0x0018, 0x0010, 0x0014, 4, 1,
++ -1, -1, -1),
++ MUX_GATE_CLR_SET_UPD(CLK_INFRA_SPI1_SEL, "infra_spi1_sel",
++ infra_spi1_parents, 0x0018, 0x0010, 0x0014, 5, 1,
++ -1, -1, -1),
++ MUX_GATE_CLR_SET_UPD(CLK_INFRA_SPI2_SEL, "infra_spi2_sel",
++ infra_spi0_parents, 0x0018, 0x0010, 0x0014, 6, 1,
++ -1, -1, -1),
++ MUX_GATE_CLR_SET_UPD(CLK_INFRA_PWM1_SEL, "infra_pwm1_sel",
++ infra_pwm1_parents, 0x0018, 0x0010, 0x0014, 9, 1,
++ -1, -1, -1),
++ MUX_GATE_CLR_SET_UPD(CLK_INFRA_PWM2_SEL, "infra_pwm2_sel",
++ infra_pwm1_parents, 0x0018, 0x0010, 0x0014, 11, 1,
++ -1, -1, -1),
++ MUX_GATE_CLR_SET_UPD(CLK_INFRA_PWM3_SEL, "infra_pwm3_sel",
++ infra_pwm1_parents, 0x0018, 0x0010, 0x0014, 15, 1,
++ -1, -1, -1),
++ MUX_GATE_CLR_SET_UPD(CLK_INFRA_PWM_BSEL, "infra_pwm_bsel",
++ infra_pwm_bsel_parents, 0x0018, 0x0010, 0x0014, 13,
++ 2, -1, -1, -1),
++ /* MODULE_CLK_SEL_1 */
++ MUX_GATE_CLR_SET_UPD(CLK_INFRA_PCIE_SEL, "infra_pcie_sel",
++ infra_pcie_parents, 0x0028, 0x0020, 0x0024, 0, 2,
++ -1, -1, -1),
++};
++
++static const struct mtk_gate_regs infra0_cg_regs = {
++ .set_ofs = 0x40,
++ .clr_ofs = 0x44,
++ .sta_ofs = 0x48,
++};
++
++static const struct mtk_gate_regs infra1_cg_regs = {
++ .set_ofs = 0x50,
++ .clr_ofs = 0x54,
++ .sta_ofs = 0x58,
++};
++
++static const struct mtk_gate_regs infra2_cg_regs = {
++ .set_ofs = 0x60,
++ .clr_ofs = 0x64,
++ .sta_ofs = 0x68,
++};
++
++#define GATE_INFRA0(_id, _name, _parent, _shift) \
++ { \
++ .id = _id, .name = _name, .parent_name = _parent, \
++ .regs = &infra0_cg_regs, .shift = _shift, \
++ .ops = &mtk_clk_gate_ops_setclr, \
++ }
++
++#define GATE_INFRA1(_id, _name, _parent, _shift) \
++ { \
++ .id = _id, .name = _name, .parent_name = _parent, \
++ .regs = &infra1_cg_regs, .shift = _shift, \
++ .ops = &mtk_clk_gate_ops_setclr, \
++ }
++
++#define GATE_INFRA2(_id, _name, _parent, _shift) \
++ { \
++ .id = _id, .name = _name, .parent_name = _parent, \
++ .regs = &infra2_cg_regs, .shift = _shift, \
++ .ops = &mtk_clk_gate_ops_setclr, \
++ }
++
++static const struct mtk_gate infra_clks[] = {
++ /* INFRA0 */
++ GATE_INFRA0(CLK_INFRA_GPT_STA, "infra_gpt_sta", "infra_66m_mck", 0),
++ GATE_INFRA0(CLK_INFRA_PWM_HCK, "infra_pwm_hck", "infra_66m_mck", 1),
++ GATE_INFRA0(CLK_INFRA_PWM_STA, "infra_pwm_sta", "infra_pwm_bsel", 2),
++ GATE_INFRA0(CLK_INFRA_PWM1_CK, "infra_pwm1", "infra_pwm1_sel", 3),
++ GATE_INFRA0(CLK_INFRA_PWM2_CK, "infra_pwm2", "infra_pwm2_sel", 4),
++ GATE_INFRA0(CLK_INFRA_CQ_DMA_CK, "infra_cq_dma", "sysaxi", 6),
++
++ GATE_INFRA0(CLK_INFRA_AUD_BUS_CK, "infra_aud_bus", "sysaxi", 8),
++ GATE_INFRA0(CLK_INFRA_AUD_26M_CK, "infra_aud_26m", "csw_f26m_sel", 9),
++ GATE_INFRA0(CLK_INFRA_AUD_L_CK, "infra_aud_l", "aud_l", 10),
++ GATE_INFRA0(CLK_INFRA_AUD_AUD_CK, "infra_aud_aud", "a1sys", 11),
++ GATE_INFRA0(CLK_INFRA_AUD_EG2_CK, "infra_aud_eg2", "a_tuner", 13),
++ GATE_INFRA0(CLK_INFRA_DRAMC_26M_CK, "infra_dramc_26m", "csw_f26m_sel",
++ 14),
++ GATE_INFRA0(CLK_INFRA_DBG_CK, "infra_dbg", "infra_66m_mck", 15),
++ GATE_INFRA0(CLK_INFRA_AP_DMA_CK, "infra_ap_dma", "infra_66m_mck", 16),
++ GATE_INFRA0(CLK_INFRA_SEJ_CK, "infra_sej", "infra_66m_mck", 24),
++ GATE_INFRA0(CLK_INFRA_SEJ_13M_CK, "infra_sej_13m", "csw_f26m_sel", 25),
++ GATE_INFRA0(CLK_INFRA_PWM3_CK, "infra_pwm3", "infra_pwm3_sel", 27),
++ /* INFRA1 */
++ GATE_INFRA1(CLK_INFRA_THERM_CK, "infra_therm", "csw_f26m_sel", 0),
++ GATE_INFRA1(CLK_INFRA_I2C0_CK, "infra_i2c0", "i2c_bck", 1),
++ GATE_INFRA1(CLK_INFRA_UART0_CK, "infra_uart0", "infra_uart0_sel", 2),
++ GATE_INFRA1(CLK_INFRA_UART1_CK, "infra_uart1", "infra_uart1_sel", 3),
++ GATE_INFRA1(CLK_INFRA_UART2_CK, "infra_uart2", "infra_uart2_sel", 4),
++ GATE_INFRA1(CLK_INFRA_SPI2_CK, "infra_spi2", "infra_spi2_sel", 6),
++ GATE_INFRA1(CLK_INFRA_SPI2_HCK_CK, "infra_spi2_hck", "infra_66m_mck", 7),
++ GATE_INFRA1(CLK_INFRA_NFI1_CK, "infra_nfi1", "nfi1x", 8),
++ GATE_INFRA1(CLK_INFRA_SPINFI1_CK, "infra_spinfi1", "spinfi_bck", 9),
++ GATE_INFRA1(CLK_INFRA_NFI_HCK_CK, "infra_nfi_hck", "infra_66m_mck", 10),
++ GATE_INFRA1(CLK_INFRA_SPI0_CK, "infra_spi0", "infra_spi0_sel", 11),
++ GATE_INFRA1(CLK_INFRA_SPI1_CK, "infra_spi1", "infra_spi1_sel", 12),
++ GATE_INFRA1(CLK_INFRA_SPI0_HCK_CK, "infra_spi0_hck", "infra_66m_mck",
++ 13),
++ GATE_INFRA1(CLK_INFRA_SPI1_HCK_CK, "infra_spi1_hck", "infra_66m_mck",
++ 14),
++ GATE_INFRA1(CLK_INFRA_FRTC_CK, "infra_frtc", "cb_rtc_32k", 15),
++ GATE_INFRA1(CLK_INFRA_MSDC_CK, "infra_msdc", "emmc_400m", 16),
++ GATE_INFRA1(CLK_INFRA_MSDC_HCK_CK, "infra_msdc_hck", "emmc_208m", 17),
++ GATE_INFRA1(CLK_INFRA_MSDC_133M_CK, "infra_msdc_133m", "sysaxi", 18),
++ GATE_INFRA1(CLK_INFRA_MSDC_66M_CK, "infra_msdc_66m", "sysaxi", 19),
++ GATE_INFRA1(CLK_INFRA_ADC_26M_CK, "infra_adc_26m", "infra_adc_frc", 20),
++ GATE_INFRA1(CLK_INFRA_ADC_FRC_CK, "infra_adc_frc", "csw_f26m", 21),
++ GATE_INFRA1(CLK_INFRA_FBIST2FPC_CK, "infra_fbist2fpc", "nfi1x", 23),
++ GATE_INFRA1(CLK_INFRA_I2C_MCK_CK, "infra_i2c_mck", "sysaxi", 25),
++ GATE_INFRA1(CLK_INFRA_I2C_PCK_CK, "infra_i2c_pck", "infra_66m_mck", 26),
++ /* INFRA2 */
++ GATE_INFRA2(CLK_INFRA_IUSB_133_CK, "infra_iusb_133", "sysaxi", 0),
++ GATE_INFRA2(CLK_INFRA_IUSB_66M_CK, "infra_iusb_66m", "sysaxi", 1),
++ GATE_INFRA2(CLK_INFRA_IUSB_SYS_CK, "infra_iusb_sys", "u2u3_sys", 2),
++ GATE_INFRA2(CLK_INFRA_IUSB_CK, "infra_iusb", "u2u3_ref", 3),
++ GATE_INFRA2(CLK_INFRA_IPCIE_CK, "infra_ipcie", "pextp_tl", 12),
++ GATE_INFRA2(CLK_INFRA_IPCIE_PIPE_CK, "infra_ipcie_pipe", "cb_cksq_40m",
++ 13),
++ GATE_INFRA2(CLK_INFRA_IPCIER_CK, "infra_ipcier", "csw_f26m", 14),
++ GATE_INFRA2(CLK_INFRA_IPCIEB_CK, "infra_ipcieb", "sysaxi", 15),
++};
++
++static const struct mtk_clk_desc infracfg_desc = {
++ .factor_clks = infra_divs,
++ .num_factor_clks = ARRAY_SIZE(infra_divs),
++ .mux_clks = infra_muxes,
++ .num_mux_clks = ARRAY_SIZE(infra_muxes),
++ .clks = infra_clks,
++ .num_clks = ARRAY_SIZE(infra_clks),
++ .clk_lock = &mt7981_clk_lock,
++};
++
++static const struct of_device_id of_match_clk_mt7981_infracfg[] = {
++ { .compatible = "mediatek,mt7981-infracfg", .data = &infracfg_desc },
++ { /* sentinel */ }
++};
++
++static struct platform_driver clk_mt7981_infracfg_drv = {
++ .probe = mtk_clk_simple_probe,
++ .remove = mtk_clk_simple_remove,
++ .driver = {
++ .name = "clk-mt7981-infracfg",
++ .of_match_table = of_match_clk_mt7981_infracfg,
++ },
++};
++builtin_platform_driver(clk_mt7981_infracfg_drv);
+--- /dev/null
++++ b/drivers/clk/mediatek/clk-mt7981-topckgen.c
+@@ -0,0 +1,422 @@
++// SPDX-License-Identifier: GPL-2.0
++/*
++ * Copyright (c) 2021 MediaTek Inc.
++ * Author: Sam Shih <sam.shih@mediatek.com>
++ * Author: Wenzhen Yu <wenzhen.yu@mediatek.com>
++ * Author: Jianhui Zhao <zhaojh329@gmail.com>
++ */
++
++
++#include <linux/clk-provider.h>
++#include <linux/of.h>
++#include <linux/of_address.h>
++#include <linux/of_device.h>
++#include <linux/platform_device.h>
++#include "clk-mtk.h"
++#include "clk-gate.h"
++#include "clk-mux.h"
++
++#include <dt-bindings/clock/mediatek,mt7981-clk.h>
++#include <linux/clk.h>
++
++static DEFINE_SPINLOCK(mt7981_clk_lock);
++
++static const struct mtk_fixed_factor top_divs[] = {
++ FACTOR(CLK_TOP_CB_CKSQ_40M, "cb_cksq_40m", "clkxtal", 1, 1),
++ FACTOR(CLK_TOP_CB_M_416M, "cb_m_416m", "mpll", 1, 1),
++ FACTOR(CLK_TOP_CB_M_D2, "cb_m_d2", "mpll", 1, 2),
++ FACTOR(CLK_TOP_CB_M_D3, "cb_m_d3", "mpll", 1, 3),
++ FACTOR(CLK_TOP_M_D3_D2, "m_d3_d2", "mpll", 1, 2),
++ FACTOR(CLK_TOP_CB_M_D4, "cb_m_d4", "mpll", 1, 4),
++ FACTOR(CLK_TOP_CB_M_D8, "cb_m_d8", "mpll", 1, 8),
++ FACTOR(CLK_TOP_M_D8_D2, "m_d8_d2", "mpll", 1, 16),
++ FACTOR(CLK_TOP_CB_MM_720M, "cb_mm_720m", "mmpll", 1, 1),
++ FACTOR(CLK_TOP_CB_MM_D2, "cb_mm_d2", "mmpll", 1, 2),
++ FACTOR(CLK_TOP_CB_MM_D3, "cb_mm_d3", "mmpll", 1, 3),
++ FACTOR(CLK_TOP_CB_MM_D3_D5, "cb_mm_d3_d5", "mmpll", 1, 15),
++ FACTOR(CLK_TOP_CB_MM_D4, "cb_mm_d4", "mmpll", 1, 4),
++ FACTOR(CLK_TOP_CB_MM_D6, "cb_mm_d6", "mmpll", 1, 6),
++ FACTOR(CLK_TOP_MM_D6_D2, "mm_d6_d2", "mmpll", 1, 12),
++ FACTOR(CLK_TOP_CB_MM_D8, "cb_mm_d8", "mmpll", 1, 8),
++ FACTOR(CLK_TOP_CB_APLL2_196M, "cb_apll2_196m", "apll2", 1, 1),
++ FACTOR(CLK_TOP_APLL2_D2, "apll2_d2", "apll2", 1, 2),
++ FACTOR(CLK_TOP_APLL2_D4, "apll2_d4", "apll2", 1, 4),
++ FACTOR(CLK_TOP_NET1_2500M, "net1_2500m", "net1pll", 1, 1),
++ FACTOR(CLK_TOP_CB_NET1_D4, "cb_net1_d4", "net1pll", 1, 4),
++ FACTOR(CLK_TOP_CB_NET1_D5, "cb_net1_d5", "net1pll", 1, 5),
++ FACTOR(CLK_TOP_NET1_D5_D2, "net1_d5_d2", "net1pll", 1, 10),
++ FACTOR(CLK_TOP_NET1_D5_D4, "net1_d5_d4", "net1pll", 1, 20),
++ FACTOR(CLK_TOP_CB_NET1_D8, "cb_net1_d8", "net1pll", 1, 8),
++ FACTOR(CLK_TOP_NET1_D8_D2, "net1_d8_d2", "net1pll", 1, 16),
++ FACTOR(CLK_TOP_NET1_D8_D4, "net1_d8_d4", "net1pll", 1, 32),
++ FACTOR(CLK_TOP_CB_NET2_800M, "cb_net2_800m", "net2pll", 1, 1),
++ FACTOR(CLK_TOP_CB_NET2_D2, "cb_net2_d2", "net2pll", 1, 2),
++ FACTOR(CLK_TOP_CB_NET2_D4, "cb_net2_d4", "net2pll", 1, 4),
++ FACTOR(CLK_TOP_NET2_D4_D2, "net2_d4_d2", "net2pll", 1, 8),
++ FACTOR(CLK_TOP_NET2_D4_D4, "net2_d4_d4", "net2pll", 1, 16),
++ FACTOR(CLK_TOP_CB_NET2_D6, "cb_net2_d6", "net2pll", 1, 6),
++ FACTOR(CLK_TOP_CB_WEDMCU_208M, "cb_wedmcu_208m", "wedmcupll", 1, 1),
++ FACTOR(CLK_TOP_CB_SGM_325M, "cb_sgm_325m", "sgmpll", 1, 1),
++ FACTOR(CLK_TOP_CKSQ_40M_D2, "cksq_40m_d2", "cb_cksq_40m", 1, 2),
++ FACTOR(CLK_TOP_CB_RTC_32K, "cb_rtc_32k", "cb_cksq_40m", 1, 1250),
++ FACTOR(CLK_TOP_CB_RTC_32P7K, "cb_rtc_32p7k", "cb_cksq_40m", 1, 1220),
++ FACTOR(CLK_TOP_USB_TX250M, "usb_tx250m", "cb_cksq_40m", 1, 1),
++ FACTOR(CLK_TOP_FAUD, "faud", "aud_sel", 1, 1),
++ FACTOR(CLK_TOP_NFI1X, "nfi1x", "nfi1x_sel", 1, 1),
++ FACTOR(CLK_TOP_USB_EQ_RX250M, "usb_eq_rx250m", "cb_cksq_40m", 1, 1),
++ FACTOR(CLK_TOP_USB_CDR_CK, "usb_cdr", "cb_cksq_40m", 1, 1),
++ FACTOR(CLK_TOP_USB_LN0_CK, "usb_ln0", "cb_cksq_40m", 1, 1),
++ FACTOR(CLK_TOP_SPINFI_BCK, "spinfi_bck", "spinfi_sel", 1, 1),
++ FACTOR(CLK_TOP_SPI, "spi", "spi_sel", 1, 1),
++ FACTOR(CLK_TOP_SPIM_MST, "spim_mst", "spim_mst_sel", 1, 1),
++ FACTOR(CLK_TOP_UART_BCK, "uart_bck", "uart_sel", 1, 1),
++ FACTOR(CLK_TOP_PWM_BCK, "pwm_bck", "pwm_sel", 1, 1),
++ FACTOR(CLK_TOP_I2C_BCK, "i2c_bck", "i2c_sel", 1, 1),
++ FACTOR(CLK_TOP_PEXTP_TL, "pextp_tl", "pextp_tl_ck_sel", 1, 1),
++ FACTOR(CLK_TOP_EMMC_208M, "emmc_208m", "emmc_208m_sel", 1, 1),
++ FACTOR(CLK_TOP_EMMC_400M, "emmc_400m", "emmc_400m_sel", 1, 1),
++ FACTOR(CLK_TOP_DRAMC_REF, "dramc_ref", "dramc_sel", 1, 1),
++ FACTOR(CLK_TOP_DRAMC_MD32, "dramc_md32", "dramc_md32_sel", 1, 1),
++ FACTOR(CLK_TOP_SYSAXI, "sysaxi", "sysaxi_sel", 1, 1),
++ FACTOR(CLK_TOP_SYSAPB, "sysapb", "sysapb_sel", 1, 1),
++ FACTOR(CLK_TOP_ARM_DB_MAIN, "arm_db_main", "arm_db_main_sel", 1, 1),
++ FACTOR(CLK_TOP_AP2CNN_HOST, "ap2cnn_host", "ap2cnn_host_sel", 1, 1),
++ FACTOR(CLK_TOP_NETSYS, "netsys", "netsys_sel", 1, 1),
++ FACTOR(CLK_TOP_NETSYS_500M, "netsys_500m", "netsys_500m_sel", 1, 1),
++ FACTOR(CLK_TOP_NETSYS_WED_MCU, "netsys_wed_mcu", "netsys_mcu_sel", 1, 1),
++ FACTOR(CLK_TOP_NETSYS_2X, "netsys_2x", "netsys_2x_sel", 1, 1),
++ FACTOR(CLK_TOP_SGM_325M, "sgm_325m", "sgm_325m_sel", 1, 1),
++ FACTOR(CLK_TOP_SGM_REG, "sgm_reg", "sgm_reg_sel", 1, 1),
++ FACTOR(CLK_TOP_F26M, "csw_f26m", "csw_f26m_sel", 1, 1),
++ FACTOR(CLK_TOP_EIP97B, "eip97b", "eip97b_sel", 1, 1),
++ FACTOR(CLK_TOP_USB3_PHY, "usb3_phy", "usb3_phy_sel", 1, 1),
++ FACTOR(CLK_TOP_AUD, "aud", "faud", 1, 1),
++ FACTOR(CLK_TOP_A1SYS, "a1sys", "a1sys_sel", 1, 1),
++ FACTOR(CLK_TOP_AUD_L, "aud_l", "aud_l_sel", 1, 1),
++ FACTOR(CLK_TOP_A_TUNER, "a_tuner", "a_tuner_sel", 1, 1),
++ FACTOR(CLK_TOP_U2U3_REF, "u2u3_ref", "u2u3_sel", 1, 1),
++ FACTOR(CLK_TOP_U2U3_SYS, "u2u3_sys", "u2u3_sys_sel", 1, 1),
++ FACTOR(CLK_TOP_U2U3_XHCI, "u2u3_xhci", "u2u3_xhci_sel", 1, 1),
++ FACTOR(CLK_TOP_USB_FRMCNT, "usb_frmcnt", "usb_frmcnt_sel", 1, 1),
++};
++
++static const char * const nfi1x_parents[] __initconst = {
++ "cb_cksq_40m",
++ "cb_mm_d4",
++ "net1_d8_d2",
++ "cb_net2_d6",
++ "cb_m_d4",
++ "cb_mm_d8",
++ "net1_d8_d4",
++ "cb_m_d8"
++};
++
++static const char * const spinfi_parents[] __initconst = {
++ "cksq_40m_d2",
++ "cb_cksq_40m",
++ "net1_d5_d4",
++ "cb_m_d4",
++ "cb_mm_d8",
++ "net1_d8_d4",
++ "mm_d6_d2",
++ "cb_m_d8"
++};
++
++static const char * const spi_parents[] __initconst = {
++ "cb_cksq_40m",
++ "cb_m_d2",
++ "cb_mm_d4",
++ "net1_d8_d2",
++ "cb_net2_d6",
++ "net1_d5_d4",
++ "cb_m_d4",
++ "net1_d8_d4"
++};
++
++static const char * const uart_parents[] __initconst = {
++ "cb_cksq_40m",
++ "cb_m_d8",
++ "m_d8_d2"
++};
++
++static const char * const pwm_parents[] __initconst = {
++ "cb_cksq_40m",
++ "net1_d8_d2",
++ "net1_d5_d4",
++ "cb_m_d4",
++ "m_d8_d2",
++ "cb_rtc_32k"
++};
++
++static const char * const i2c_parents[] __initconst = {
++ "cb_cksq_40m",
++ "net1_d5_d4",
++ "cb_m_d4",
++ "net1_d8_d4"
++};
++
++static const char * const pextp_tl_ck_parents[] __initconst = {
++ "cb_cksq_40m",
++ "net1_d5_d4",
++ "cb_m_d4",
++ "cb_rtc_32k"
++};
++
++static const char * const emmc_208m_parents[] __initconst = {
++ "cb_cksq_40m",
++ "cb_m_d2",
++ "cb_net2_d4",
++ "cb_apll2_196m",
++ "cb_mm_d4",
++ "net1_d8_d2",
++ "cb_mm_d6"
++};
++
++static const char * const emmc_400m_parents[] __initconst = {
++ "cb_cksq_40m",
++ "cb_net2_d2",
++ "cb_mm_d2",
++ "cb_net2_d2"
++};
++
++static const char * const csw_f26m_parents[] __initconst = {
++ "cksq_40m_d2",
++ "m_d8_d2"
++};
++
++static const char * const dramc_md32_parents[] __initconst = {
++ "cb_cksq_40m",
++ "cb_m_d2",
++ "cb_wedmcu_208m"
++};
++
++static const char * const sysaxi_parents[] __initconst = {
++ "cb_cksq_40m",
++ "net1_d8_d2"
++};
++
++static const char * const sysapb_parents[] __initconst = {
++ "cb_cksq_40m",
++ "m_d3_d2"
++};
++
++static const char * const arm_db_main_parents[] __initconst = {
++ "cb_cksq_40m",
++ "cb_net2_d6"
++};
++
++static const char * const ap2cnn_host_parents[] __initconst = {
++ "cb_cksq_40m",
++ "net1_d8_d4"
++};
++
++static const char * const netsys_parents[] __initconst = {
++ "cb_cksq_40m",
++ "cb_mm_d2"
++};
++
++static const char * const netsys_500m_parents[] __initconst = {
++ "cb_cksq_40m",
++ "cb_net1_d5"
++};
++
++static const char * const netsys_mcu_parents[] __initconst = {
++ "cb_cksq_40m",
++ "cb_mm_720m",
++ "cb_net1_d4",
++ "cb_net1_d5",
++ "cb_m_416m"
++};
++
++static const char * const netsys_2x_parents[] __initconst = {
++ "cb_cksq_40m",
++ "cb_net2_800m",
++ "cb_mm_720m"
++};
++
++static const char * const sgm_325m_parents[] __initconst = {
++ "cb_cksq_40m",
++ "cb_sgm_325m"
++};
++
++static const char * const sgm_reg_parents[] __initconst = {
++ "cb_cksq_40m",
++ "cb_net2_d4"
++};
++
++static const char * const eip97b_parents[] __initconst = {
++ "cb_cksq_40m",
++ "cb_net1_d5",
++ "cb_m_416m",
++ "cb_mm_d2",
++ "net1_d5_d2"
++};
++
++static const char * const aud_parents[] __initconst = {
++ "cb_cksq_40m",
++ "cb_apll2_196m"
++};
++
++static const char * const a1sys_parents[] __initconst = {
++ "cb_cksq_40m",
++ "apll2_d4"
++};
++
++static const char * const aud_l_parents[] __initconst = {
++ "cb_cksq_40m",
++ "cb_apll2_196m",
++ "m_d8_d2"
++};
++
++static const char * const a_tuner_parents[] __initconst = {
++ "cb_cksq_40m",
++ "apll2_d4",
++ "m_d8_d2"
++};
++
++static const char * const u2u3_parents[] __initconst = {
++ "cb_cksq_40m",
++ "m_d8_d2"
++};
++
++static const char * const u2u3_sys_parents[] __initconst = {
++ "cb_cksq_40m",
++ "net1_d5_d4"
++};
++
++static const char * const usb_frmcnt_parents[] __initconst = {
++ "cb_cksq_40m",
++ "cb_mm_d3_d5"
++};
++
++static const struct mtk_mux top_muxes[] = {
++ /* CLK_CFG_0 */
++ MUX_GATE_CLR_SET_UPD(CLK_TOP_NFI1X_SEL, "nfi1x_sel", nfi1x_parents,
++ 0x000, 0x004, 0x008, 0, 3, 7, 0x1C0, 0),
++ MUX_GATE_CLR_SET_UPD(CLK_TOP_SPINFI_SEL, "spinfi_sel", spinfi_parents,
++ 0x000, 0x004, 0x008, 8, 3, 15, 0x1C0, 1),
++ MUX_GATE_CLR_SET_UPD(CLK_TOP_SPI_SEL, "spi_sel", spi_parents,
++ 0x000, 0x004, 0x008, 16, 3, 23, 0x1C0, 2),
++ MUX_GATE_CLR_SET_UPD(CLK_TOP_SPIM_MST_SEL, "spim_mst_sel", spi_parents,
++ 0x000, 0x004, 0x008, 24, 3, 31, 0x1C0, 3),
++ /* CLK_CFG_1 */
++ MUX_GATE_CLR_SET_UPD(CLK_TOP_UART_SEL, "uart_sel", uart_parents,
++ 0x010, 0x014, 0x018, 0, 2, 7, 0x1C0, 4),
++ MUX_GATE_CLR_SET_UPD(CLK_TOP_PWM_SEL, "pwm_sel", pwm_parents,
++ 0x010, 0x014, 0x018, 8, 3, 15, 0x1C0, 5),
++ MUX_GATE_CLR_SET_UPD(CLK_TOP_I2C_SEL, "i2c_sel", i2c_parents,
++ 0x010, 0x014, 0x018, 16, 2, 23, 0x1C0, 6),
++ MUX_GATE_CLR_SET_UPD(CLK_TOP_PEXTP_TL_SEL, "pextp_tl_ck_sel",
++ pextp_tl_ck_parents, 0x010, 0x014, 0x018, 24, 2, 31,
++ 0x1C0, 7),
++ /* CLK_CFG_2 */
++ MUX_GATE_CLR_SET_UPD(CLK_TOP_EMMC_208M_SEL, "emmc_208m_sel",
++ emmc_208m_parents, 0x020, 0x024, 0x028, 0, 3, 7,
++ 0x1C0, 8),
++ MUX_GATE_CLR_SET_UPD(CLK_TOP_EMMC_400M_SEL, "emmc_400m_sel",
++ emmc_400m_parents, 0x020, 0x024, 0x028, 8, 2, 15,
++ 0x1C0, 9),
++ MUX_GATE_CLR_SET_UPD_FLAGS(CLK_TOP_F26M_SEL, "csw_f26m_sel",
++ csw_f26m_parents, 0x020, 0x024, 0x028, 16, 1, 23,
++ 0x1C0, 10,
++ CLK_IS_CRITICAL | CLK_SET_RATE_PARENT),
++ MUX_GATE_CLR_SET_UPD_FLAGS(CLK_TOP_DRAMC_SEL, "dramc_sel",
++ csw_f26m_parents, 0x020, 0x024, 0x028, 24, 1,
++ 31, 0x1C0, 11,
++ CLK_IS_CRITICAL | CLK_SET_RATE_PARENT),
++ /* CLK_CFG_3 */
++ MUX_GATE_CLR_SET_UPD_FLAGS(CLK_TOP_DRAMC_MD32_SEL, "dramc_md32_sel",
++ dramc_md32_parents, 0x030, 0x034, 0x038, 0, 2,
++ 7, 0x1C0, 12,
++ CLK_IS_CRITICAL | CLK_SET_RATE_PARENT),
++ MUX_GATE_CLR_SET_UPD_FLAGS(CLK_TOP_SYSAXI_SEL, "sysaxi_sel",
++ sysaxi_parents, 0x030, 0x034, 0x038, 8, 1, 15,
++ 0x1C0, 13,
++ CLK_IS_CRITICAL | CLK_SET_RATE_PARENT),
++ MUX_GATE_CLR_SET_UPD_FLAGS(CLK_TOP_SYSAPB_SEL, "sysapb_sel",
++ sysapb_parents, 0x030, 0x034, 0x038, 16, 1,
++ 23, 0x1C0, 14,
++ CLK_IS_CRITICAL | CLK_SET_RATE_PARENT),
++ MUX_GATE_CLR_SET_UPD(CLK_TOP_ARM_DB_MAIN_SEL, "arm_db_main_sel",
++ arm_db_main_parents, 0x030, 0x034, 0x038, 24, 1, 31,
++ 0x1C0, 15),
++ /* CLK_CFG_4 */
++ MUX_GATE_CLR_SET_UPD(CLK_TOP_AP2CNN_HOST_SEL, "ap2cnn_host_sel",
++ ap2cnn_host_parents, 0x040, 0x044, 0x048, 0, 1, 7,
++ 0x1C0, 16),
++ MUX_GATE_CLR_SET_UPD(CLK_TOP_NETSYS_SEL, "netsys_sel", netsys_parents,
++ 0x040, 0x044, 0x048, 8, 1, 15, 0x1C0, 17),
++ MUX_GATE_CLR_SET_UPD(CLK_TOP_NETSYS_500M_SEL, "netsys_500m_sel",
++ netsys_500m_parents, 0x040, 0x044, 0x048, 16, 1, 23,
++ 0x1C0, 18),
++ MUX_GATE_CLR_SET_UPD(CLK_TOP_NETSYS_MCU_SEL, "netsys_mcu_sel",
++ netsys_mcu_parents, 0x040, 0x044, 0x048, 24, 3, 31,
++ 0x1C0, 19),
++ /* CLK_CFG_5 */
++ MUX_GATE_CLR_SET_UPD(CLK_TOP_NETSYS_2X_SEL, "netsys_2x_sel",
++ netsys_2x_parents, 0x050, 0x054, 0x058, 0, 2, 7,
++ 0x1C0, 20),
++ MUX_GATE_CLR_SET_UPD(CLK_TOP_SGM_325M_SEL, "sgm_325m_sel",
++ sgm_325m_parents, 0x050, 0x054, 0x058, 8, 1, 15,
++ 0x1C0, 21),
++ MUX_GATE_CLR_SET_UPD(CLK_TOP_SGM_REG_SEL, "sgm_reg_sel", sgm_reg_parents,
++ 0x050, 0x054, 0x058, 16, 1, 23, 0x1C0, 22),
++ MUX_GATE_CLR_SET_UPD(CLK_TOP_EIP97B_SEL, "eip97b_sel", eip97b_parents,
++ 0x050, 0x054, 0x058, 24, 3, 31, 0x1C0, 23),
++ /* CLK_CFG_6 */
++ MUX_GATE_CLR_SET_UPD(CLK_TOP_USB3_PHY_SEL, "usb3_phy_sel",
++ csw_f26m_parents, 0x060, 0x064, 0x068, 0, 1,
++ 7, 0x1C0, 24),
++ MUX_GATE_CLR_SET_UPD(CLK_TOP_AUD_SEL, "aud_sel", aud_parents, 0x060,
++ 0x064, 0x068, 8, 1, 15, 0x1C0, 25),
++ MUX_GATE_CLR_SET_UPD(CLK_TOP_A1SYS_SEL, "a1sys_sel", a1sys_parents,
++ 0x060, 0x064, 0x068, 16, 1, 23, 0x1C0, 26),
++ MUX_GATE_CLR_SET_UPD(CLK_TOP_AUD_L_SEL, "aud_l_sel", aud_l_parents,
++ 0x060, 0x064, 0x068, 24, 2, 31, 0x1C0, 27),
++ /* CLK_CFG_7 */
++ MUX_GATE_CLR_SET_UPD(CLK_TOP_A_TUNER_SEL, "a_tuner_sel",
++ a_tuner_parents, 0x070, 0x074, 0x078, 0, 2, 7,
++ 0x1C0, 28),
++ MUX_GATE_CLR_SET_UPD(CLK_TOP_U2U3_SEL, "u2u3_sel", u2u3_parents, 0x070,
++ 0x074, 0x078, 8, 1, 15, 0x1C0, 29),
++ MUX_GATE_CLR_SET_UPD(CLK_TOP_U2U3_SYS_SEL, "u2u3_sys_sel",
++ u2u3_sys_parents, 0x070, 0x074, 0x078, 16, 1, 23,
++ 0x1C0, 30),
++ MUX_GATE_CLR_SET_UPD(CLK_TOP_U2U3_XHCI_SEL, "u2u3_xhci_sel",
++ u2u3_sys_parents, 0x070, 0x074, 0x078, 24, 1, 31,
++ 0x1C4, 0),
++ /* CLK_CFG_8 */
++ MUX_GATE_CLR_SET_UPD(CLK_TOP_USB_FRMCNT_SEL, "usb_frmcnt_sel",
++ usb_frmcnt_parents, 0x080, 0x084, 0x088, 0, 1, 7,
++ 0x1C4, 1),
++};
++
++static struct mtk_composite top_aud_divs[] = {
++ DIV_GATE(CLK_TOP_AUD_I2S_M, "aud_i2s_m", "aud",
++ 0x0420, 0, 0x0420, 8, 8),
++};
++
++static const struct mtk_clk_desc topck_desc = {
++ .factor_clks = top_divs,
++ .num_factor_clks = ARRAY_SIZE(top_divs),
++ .mux_clks = top_muxes,
++ .num_mux_clks = ARRAY_SIZE(top_muxes),
++ .composite_clks = top_aud_divs,
++ .num_composite_clks = ARRAY_SIZE(top_aud_divs),
++ .clk_lock = &mt7981_clk_lock,
++};
++
++static const struct of_device_id of_match_clk_mt7981_topckgen[] = {
++ { .compatible = "mediatek,mt7981-topckgen", .data = &topck_desc },
++ { /* sentinel */ }
++};
++
++static struct platform_driver clk_mt7981_topckgen_drv = {
++ .probe = mtk_clk_simple_probe,
++ .remove = mtk_clk_simple_remove,
++ .driver = {
++ .name = "clk-mt7981-topckgen",
++ .of_match_table = of_match_clk_mt7981_topckgen,
++ },
++};
++builtin_platform_driver(clk_mt7981_topckgen_drv);
--- /dev/null
+From fc157139e6b7f8dfb6430ac7191ba754027705e8 Mon Sep 17 00:00:00 2001
+From: Daniel Golle <daniel@makrotopia.org>
+Date: Sun, 18 Feb 2024 01:59:59 +0000
+Subject: [PATCH] clk: mediatek: mt7981-topckgen: flag SGM_REG_SEL as critical
+
+Without the SGM_REG_SEL clock enabled the system freezes if trying to
+access registers used by MT7981 clock drivers itself.
+Mark SGM_REG_SEL as critical to make sure it is always enabled to
+prevent freezes on boot depending on probe order.
+
+Fixes: 813c3b53b55ba ("clk: mediatek: add MT7981 clock support")
+Signed-off-by: Daniel Golle <daniel@makrotopia.org>
+---
+ drivers/clk/mediatek/clk-mt7981-topckgen.c | 5 +++--
+ 1 file changed, 3 insertions(+), 2 deletions(-)
+
+--- a/drivers/clk/mediatek/clk-mt7981-topckgen.c
++++ b/drivers/clk/mediatek/clk-mt7981-topckgen.c
+@@ -359,8 +359,9 @@ static const struct mtk_mux top_muxes[]
+ MUX_GATE_CLR_SET_UPD(CLK_TOP_SGM_325M_SEL, "sgm_325m_sel",
+ sgm_325m_parents, 0x050, 0x054, 0x058, 8, 1, 15,
+ 0x1C0, 21),
+- MUX_GATE_CLR_SET_UPD(CLK_TOP_SGM_REG_SEL, "sgm_reg_sel", sgm_reg_parents,
+- 0x050, 0x054, 0x058, 16, 1, 23, 0x1C0, 22),
++ MUX_GATE_CLR_SET_UPD_FLAGS(CLK_TOP_SGM_REG_SEL, "sgm_reg_sel", sgm_reg_parents,
++ 0x050, 0x054, 0x058, 16, 1, 23, 0x1C0, 22,
++ CLK_IS_CRITICAL | CLK_SET_RATE_PARENT),
+ MUX_GATE_CLR_SET_UPD(CLK_TOP_EIP97B_SEL, "eip97b_sel", eip97b_parents,
+ 0x050, 0x054, 0x058, 24, 3, 31, 0x1C0, 23),
+ /* CLK_CFG_6 */
--- /dev/null
+--- a/drivers/pinctrl/mediatek/Kconfig
++++ b/drivers/pinctrl/mediatek/Kconfig
+@@ -141,6 +141,13 @@ config PINCTRL_MT7986
+ default ARM64 && ARCH_MEDIATEK
+ select PINCTRL_MTK_MOORE
+
++config PINCTRL_MT7988
++ bool "Mediatek MT7988 pin control"
++ depends on OF
++ depends on ARM64 || COMPILE_TEST
++ default ARCH_MEDIATEK
++ select PINCTRL_MTK_MOORE
++
+ config PINCTRL_MT8167
+ bool "Mediatek MT8167 pin control"
+ depends on OF
+--- a/drivers/pinctrl/mediatek/Makefile
++++ b/drivers/pinctrl/mediatek/Makefile
+@@ -20,6 +20,7 @@ obj-$(CONFIG_PINCTRL_MT7623) += pinctrl-
+ obj-$(CONFIG_PINCTRL_MT7629) += pinctrl-mt7629.o
+ obj-$(CONFIG_PINCTRL_MT7981) += pinctrl-mt7981.o
+ obj-$(CONFIG_PINCTRL_MT7986) += pinctrl-mt7986.o
++obj-$(CONFIG_PINCTRL_MT7988) += pinctrl-mt7988.o
+ obj-$(CONFIG_PINCTRL_MT8167) += pinctrl-mt8167.o
+ obj-$(CONFIG_PINCTRL_MT8173) += pinctrl-mt8173.o
+ obj-$(CONFIG_PINCTRL_MT8183) += pinctrl-mt8183.o
--- /dev/null
+From cc4d9e0c77494fcf6bccbc57e23db0007cf681b7 Mon Sep 17 00:00:00 2001
+From: Daniel Golle <daniel@makrotopia.org>
+Date: Thu, 26 Jan 2023 03:33:46 +0000
+Subject: [PATCH] dt-bindings: clock: Add compatibles for MT7981
+
+Add compatible string for MT7981 to existing bindings at
+ - mediatek,apmixedsys.yaml
+ - mediatek,topckgen.yaml
+ - mediatek,ethsys.txt
+ - mediatek,infracfg.yaml
+ - mediatek,sgmiisys.txt
+
+Signed-off-by: Jianhui Zhao <zhaojh329@gmail.com>
+Signed-off-by: Daniel Golle <daniel@makrotopia.org>
+Link: https://lore.kernel.org/r/cc85ee470c781ff4013f6c21c92c0a21574b12b2.1674703830.git.daniel@makrotopia.org
+Signed-off-by: Stephen Boyd <sboyd@kernel.org>
+---
+ .../devicetree/bindings/arm/mediatek/mediatek,ethsys.txt | 1 +
+ .../devicetree/bindings/arm/mediatek/mediatek,infracfg.yaml | 1 +
+ .../devicetree/bindings/arm/mediatek/mediatek,sgmiisys.txt | 2 ++
+ .../devicetree/bindings/clock/mediatek,apmixedsys.yaml | 1 +
+ Documentation/devicetree/bindings/clock/mediatek,topckgen.yaml | 1 +
+ 5 files changed, 6 insertions(+)
+
+--- a/Documentation/devicetree/bindings/arm/mediatek/mediatek,ethsys.txt
++++ b/Documentation/devicetree/bindings/arm/mediatek/mediatek,ethsys.txt
+@@ -10,6 +10,7 @@ Required Properties:
+ - "mediatek,mt7622-ethsys", "syscon"
+ - "mediatek,mt7623-ethsys", "mediatek,mt2701-ethsys", "syscon"
+ - "mediatek,mt7629-ethsys", "syscon"
++ - "mediatek,mt7981-ethsys", "syscon"
+ - "mediatek,mt7986-ethsys", "syscon"
+ - #clock-cells: Must be 1
+ - #reset-cells: Must be 1
+--- a/Documentation/devicetree/bindings/arm/mediatek/mediatek,infracfg.yaml
++++ b/Documentation/devicetree/bindings/arm/mediatek/mediatek,infracfg.yaml
+@@ -28,6 +28,7 @@ properties:
+ - mediatek,mt6797-infracfg
+ - mediatek,mt7622-infracfg
+ - mediatek,mt7629-infracfg
++ - mediatek,mt7981-infracfg
+ - mediatek,mt7986-infracfg
+ - mediatek,mt8135-infracfg
+ - mediatek,mt8167-infracfg
+--- a/Documentation/devicetree/bindings/arm/mediatek/mediatek,sgmiisys.txt
++++ b/Documentation/devicetree/bindings/arm/mediatek/mediatek,sgmiisys.txt
+@@ -8,6 +8,8 @@ Required Properties:
+ - compatible: Should be:
+ - "mediatek,mt7622-sgmiisys", "syscon"
+ - "mediatek,mt7629-sgmiisys", "syscon"
++ - "mediatek,mt7981-sgmiisys_0", "syscon"
++ - "mediatek,mt7981-sgmiisys_1", "syscon"
+ - "mediatek,mt7986-sgmiisys_0", "syscon"
+ - "mediatek,mt7986-sgmiisys_1", "syscon"
+ - #clock-cells: Must be 1
+--- a/Documentation/devicetree/bindings/clock/mediatek,apmixedsys.yaml
++++ b/Documentation/devicetree/bindings/clock/mediatek,apmixedsys.yaml
+@@ -20,6 +20,7 @@ properties:
+ - enum:
+ - mediatek,mt6797-apmixedsys
+ - mediatek,mt7622-apmixedsys
++ - mediatek,mt7981-apmixedsys
+ - mediatek,mt7986-apmixedsys
+ - mediatek,mt8135-apmixedsys
+ - mediatek,mt8173-apmixedsys
+--- a/Documentation/devicetree/bindings/clock/mediatek,topckgen.yaml
++++ b/Documentation/devicetree/bindings/clock/mediatek,topckgen.yaml
+@@ -35,6 +35,7 @@ properties:
+ - mediatek,mt6779-topckgen
+ - mediatek,mt6795-topckgen
+ - mediatek,mt7629-topckgen
++ - mediatek,mt7981-topckgen
+ - mediatek,mt7986-topckgen
+ - mediatek,mt8167-topckgen
+ - mediatek,mt8183-topckgen
--- /dev/null
+From d4f08a703565abf47baa5a77d05365cf4598d55c Mon Sep 17 00:00:00 2001
+From: Daniel Golle <daniel@makrotopia.org>
+Date: Sun, 19 Mar 2023 12:56:52 +0000
+Subject: [PATCH 1/2] dt-bindings: arm: mediatek: sgmiisys: Convert to DT
+ schema
+
+Convert mediatek,sgmiiisys bindings to DT schema format.
+Add maintainer Matthias Brugger, no maintainers were listed in the
+original documentation.
+As this node is also referenced by the Ethernet controller and used
+as SGMII PCS add this fact to the description.
+Move the file to Documentation/devicetree/bindings/net/pcs/ which seems
+more appropriate given that the great majority of registers are related
+to SGMII PCS functionality and only one register represents clock bits.
+
+Reviewed-by: Rob Herring <robh@kernel.org>
+Signed-off-by: Daniel Golle <daniel@makrotopia.org>
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+---
+ .../arm/mediatek/mediatek,sgmiisys.txt | 27 ----------
+ .../bindings/net/pcs/mediatek,sgmiisys.yaml | 49 +++++++++++++++++++
+ 2 files changed, 49 insertions(+), 27 deletions(-)
+ delete mode 100644 Documentation/devicetree/bindings/arm/mediatek/mediatek,sgmiisys.txt
+ create mode 100644 Documentation/devicetree/bindings/net/pcs/mediatek,sgmiisys.yaml
+
+--- a/Documentation/devicetree/bindings/arm/mediatek/mediatek,sgmiisys.txt
++++ /dev/null
+@@ -1,27 +0,0 @@
+-MediaTek SGMIISYS controller
+-============================
+-
+-The MediaTek SGMIISYS controller provides various clocks to the system.
+-
+-Required Properties:
+-
+-- compatible: Should be:
+- - "mediatek,mt7622-sgmiisys", "syscon"
+- - "mediatek,mt7629-sgmiisys", "syscon"
+- - "mediatek,mt7981-sgmiisys_0", "syscon"
+- - "mediatek,mt7981-sgmiisys_1", "syscon"
+- - "mediatek,mt7986-sgmiisys_0", "syscon"
+- - "mediatek,mt7986-sgmiisys_1", "syscon"
+-- #clock-cells: Must be 1
+-
+-The SGMIISYS controller uses the common clk binding from
+-Documentation/devicetree/bindings/clock/clock-bindings.txt
+-The available clocks are defined in dt-bindings/clock/mt*-clk.h.
+-
+-Example:
+-
+-sgmiisys: sgmiisys@1b128000 {
+- compatible = "mediatek,mt7622-sgmiisys", "syscon";
+- reg = <0 0x1b128000 0 0x1000>;
+- #clock-cells = <1>;
+-};
+--- /dev/null
++++ b/Documentation/devicetree/bindings/net/pcs/mediatek,sgmiisys.yaml
+@@ -0,0 +1,49 @@
++# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
++%YAML 1.2
++---
++$id: http://devicetree.org/schemas/net/pcs/mediatek,sgmiisys.yaml#
++$schema: http://devicetree.org/meta-schemas/core.yaml#
++
++title: MediaTek SGMIISYS Controller
++
++maintainers:
++ - Matthias Brugger <matthias.bgg@gmail.com>
++
++description:
++ The MediaTek SGMIISYS controller provides a SGMII PCS and some clocks
++ to the ethernet subsystem to which it is attached.
++
++properties:
++ compatible:
++ items:
++ - enum:
++ - mediatek,mt7622-sgmiisys
++ - mediatek,mt7629-sgmiisys
++ - mediatek,mt7986-sgmiisys_0
++ - mediatek,mt7986-sgmiisys_1
++ - const: syscon
++
++ reg:
++ maxItems: 1
++
++ '#clock-cells':
++ const: 1
++
++required:
++ - compatible
++ - reg
++ - '#clock-cells'
++
++additionalProperties: false
++
++examples:
++ - |
++ soc {
++ #address-cells = <2>;
++ #size-cells = <2>;
++ sgmiisys: syscon@1b128000 {
++ compatible = "mediatek,mt7622-sgmiisys", "syscon";
++ reg = <0 0x1b128000 0 0x1000>;
++ #clock-cells = <1>;
++ };
++ };
--- /dev/null
+From 4f7eb19c4f44078100659f6ba073b0cc7191bc91 Mon Sep 17 00:00:00 2001
+From: Daniel Golle <daniel@makrotopia.org>
+Date: Sun, 19 Mar 2023 12:57:04 +0000
+Subject: [PATCH 2/2] dt-bindings: net: pcs: mediatek,sgmiisys: add MT7981 SoC
+
+Add mediatek,pnswap boolean property needed on many boards using the
+MediaTek MT7981 SoC.
+
+Reviewed-by: Rob Herring <robh@kernel.org>
+Signed-off-by: Daniel Golle <daniel@makrotopia.org>
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+---
+ .../devicetree/bindings/net/pcs/mediatek,sgmiisys.yaml | 6 ++++++
+ 1 file changed, 6 insertions(+)
+
+--- a/Documentation/devicetree/bindings/net/pcs/mediatek,sgmiisys.yaml
++++ b/Documentation/devicetree/bindings/net/pcs/mediatek,sgmiisys.yaml
+@@ -19,6 +19,8 @@ properties:
+ - enum:
+ - mediatek,mt7622-sgmiisys
+ - mediatek,mt7629-sgmiisys
++ - mediatek,mt7981-sgmiisys_0
++ - mediatek,mt7981-sgmiisys_1
+ - mediatek,mt7986-sgmiisys_0
+ - mediatek,mt7986-sgmiisys_1
+ - const: syscon
+@@ -29,6 +31,10 @@ properties:
+ '#clock-cells':
+ const: 1
+
++ mediatek,pnswap:
++ description: Invert polarity of the SGMII data lanes
++ type: boolean
++
+ required:
+ - compatible
+ - reg
--- /dev/null
+From 94b0f301f6ee92f79a2fe2c655dfdbdfe2aec536 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= <rafal@milecki.pl>
+Date: Sun, 19 Nov 2023 22:24:16 +0100
+Subject: [PATCH] dt-bindings: arm: mediatek: move ethsys controller & convert
+ to DT schema
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+DT schema helps validating DTS files. Binding was moved to clock/ as
+this hardware is a clock provider. Example required a small fix for
+"reg" value (1 address cell + 1 size cell).
+
+Signed-off-by: Rafał Miłecki <rafal@milecki.pl>
+Reviewed-by: Rob Herring <robh@kernel.org>
+Link: https://lore.kernel.org/r/20231119212416.2682-1-zajec5@gmail.com
+Signed-off-by: Stephen Boyd <sboyd@kernel.org>
+---
+ .../bindings/arm/mediatek/mediatek,ethsys.txt | 29 ----------
+ .../bindings/clock/mediatek,ethsys.yaml | 54 +++++++++++++++++++
+ 2 files changed, 54 insertions(+), 29 deletions(-)
+ delete mode 100644 Documentation/devicetree/bindings/arm/mediatek/mediatek,ethsys.txt
+ create mode 100644 Documentation/devicetree/bindings/clock/mediatek,ethsys.yaml
+
+--- a/Documentation/devicetree/bindings/arm/mediatek/mediatek,ethsys.txt
++++ /dev/null
+@@ -1,29 +0,0 @@
+-Mediatek ethsys controller
+-============================
+-
+-The Mediatek ethsys controller provides various clocks to the system.
+-
+-Required Properties:
+-
+-- compatible: Should be:
+- - "mediatek,mt2701-ethsys", "syscon"
+- - "mediatek,mt7622-ethsys", "syscon"
+- - "mediatek,mt7623-ethsys", "mediatek,mt2701-ethsys", "syscon"
+- - "mediatek,mt7629-ethsys", "syscon"
+- - "mediatek,mt7981-ethsys", "syscon"
+- - "mediatek,mt7986-ethsys", "syscon"
+-- #clock-cells: Must be 1
+-- #reset-cells: Must be 1
+-
+-The ethsys controller uses the common clk binding from
+-Documentation/devicetree/bindings/clock/clock-bindings.txt
+-The available clocks are defined in dt-bindings/clock/mt*-clk.h.
+-
+-Example:
+-
+-ethsys: clock-controller@1b000000 {
+- compatible = "mediatek,mt2701-ethsys", "syscon";
+- reg = <0 0x1b000000 0 0x1000>;
+- #clock-cells = <1>;
+- #reset-cells = <1>;
+-};
+--- /dev/null
++++ b/Documentation/devicetree/bindings/clock/mediatek,ethsys.yaml
+@@ -0,0 +1,54 @@
++# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
++%YAML 1.2
++---
++$id: http://devicetree.org/schemas/clock/mediatek,ethsys.yaml#
++$schema: http://devicetree.org/meta-schemas/core.yaml#
++
++title: Mediatek ethsys controller
++
++description:
++ The available clocks are defined in dt-bindings/clock/mt*-clk.h.
++
++maintainers:
++ - James Liao <jamesjj.liao@mediatek.com>
++
++properties:
++ compatible:
++ oneOf:
++ - items:
++ - enum:
++ - mediatek,mt2701-ethsys
++ - mediatek,mt7622-ethsys
++ - mediatek,mt7629-ethsys
++ - mediatek,mt7981-ethsys
++ - mediatek,mt7986-ethsys
++ - const: syscon
++ - items:
++ - const: mediatek,mt7623-ethsys
++ - const: mediatek,mt2701-ethsys
++ - const: syscon
++
++ reg:
++ maxItems: 1
++
++ "#clock-cells":
++ const: 1
++
++ "#reset-cells":
++ const: 1
++
++required:
++ - reg
++ - "#clock-cells"
++ - "#reset-cells"
++
++additionalProperties: false
++
++examples:
++ - |
++ clock-controller@1b000000 {
++ compatible = "mediatek,mt2701-ethsys", "syscon";
++ reg = <0x1b000000 0x1000>;
++ #clock-cells = <1>;
++ #reset-cells = <1>;
++ };
--- /dev/null
+From 5cfa3beb7761cb84be77225902e018d9d3f9b973 Mon Sep 17 00:00:00 2001
+From: Daniel Golle <daniel@makrotopia.org>
+Date: Sun, 17 Dec 2023 21:49:45 +0000
+Subject: [PATCH 1/4] dt-bindings: reset: mediatek: add MT7988 ethwarp reset
+ IDs
+
+Add reset ID for ethwarp subsystem allowing to reset the built-in
+Ethernet switch of the MediaTek MT7988 SoC.
+
+Signed-off-by: Daniel Golle <daniel@makrotopia.org>
+Reviewed-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
+Acked-by: Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>
+Link: https://lore.kernel.org/r/0c14bbacf471683af67ffa7572bfa1d5c45a0b5d.1702849494.git.daniel@makrotopia.org
+Signed-off-by: Stephen Boyd <sboyd@kernel.org>
+---
+ include/dt-bindings/reset/mediatek,mt7988-resets.h | 13 +++++++++++++
+ 1 file changed, 13 insertions(+)
+ create mode 100644 include/dt-bindings/reset/mediatek,mt7988-resets.h
+
+--- /dev/null
++++ b/include/dt-bindings/reset/mediatek,mt7988-resets.h
+@@ -0,0 +1,13 @@
++/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) */
++/*
++ * Copyright (c) 2023 Daniel Golle <daniel@makrotopia.org>
++ * Author: Daniel Golle <daniel@makrotopia.org>
++ */
++
++#ifndef _DT_BINDINGS_RESET_CONTROLLER_MT7988
++#define _DT_BINDINGS_RESET_CONTROLLER_MT7988
++
++/* ETHWARP resets */
++#define MT7988_ETHWARP_RST_SWITCH 0
++
++#endif /* _DT_BINDINGS_RESET_CONTROLLER_MT7988 */
--- /dev/null
+From 8187e001de156e99ef95366ffd10d627ed090826 Mon Sep 17 00:00:00 2001
+From: Sam Shih <sam.shih@mediatek.com>
+Date: Sun, 17 Dec 2023 21:49:33 +0000
+Subject: [PATCH] dt-bindings: clock: mediatek: add MT7988 clock IDs
+
+Add MT7988 clock dt-bindings for topckgen, apmixedsys, infracfg,
+ethernet and xfipll subsystem clocks.
+
+Signed-off-by: Sam Shih <sam.shih@mediatek.com>
+Signed-off-by: Daniel Golle <daniel@makrotopia.org>
+Acked-by: Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>
+Reviewed-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
+Link: https://lore.kernel.org/r/27f99db432e9ccc804cc5b6501d7d17d72cae879.1702849494.git.daniel@makrotopia.org
+Signed-off-by: Stephen Boyd <sboyd@kernel.org>
+---
+ .../dt-bindings/clock/mediatek,mt7988-clk.h | 280 ++++++++++++++++++
+ 1 file changed, 280 insertions(+)
+ create mode 100644 include/dt-bindings/clock/mediatek,mt7988-clk.h
+
+--- /dev/null
++++ b/include/dt-bindings/clock/mediatek,mt7988-clk.h
+@@ -0,0 +1,280 @@
++/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) */
++/*
++ * Copyright (c) 2023 MediaTek Inc.
++ * Author: Sam Shih <sam.shih@mediatek.com>
++ * Author: Xiufeng Li <Xiufeng.Li@mediatek.com>
++ */
++
++#ifndef _DT_BINDINGS_CLK_MT7988_H
++#define _DT_BINDINGS_CLK_MT7988_H
++
++/* APMIXEDSYS */
++
++#define CLK_APMIXED_NETSYSPLL 0
++#define CLK_APMIXED_MPLL 1
++#define CLK_APMIXED_MMPLL 2
++#define CLK_APMIXED_APLL2 3
++#define CLK_APMIXED_NET1PLL 4
++#define CLK_APMIXED_NET2PLL 5
++#define CLK_APMIXED_WEDMCUPLL 6
++#define CLK_APMIXED_SGMPLL 7
++#define CLK_APMIXED_ARM_B 8
++#define CLK_APMIXED_CCIPLL2_B 9
++#define CLK_APMIXED_USXGMIIPLL 10
++#define CLK_APMIXED_MSDCPLL 11
++
++/* TOPCKGEN */
++
++#define CLK_TOP_XTAL 0
++#define CLK_TOP_XTAL_D2 1
++#define CLK_TOP_RTC_32K 2
++#define CLK_TOP_RTC_32P7K 3
++#define CLK_TOP_MPLL_D2 4
++#define CLK_TOP_MPLL_D3_D2 5
++#define CLK_TOP_MPLL_D4 6
++#define CLK_TOP_MPLL_D8 7
++#define CLK_TOP_MPLL_D8_D2 8
++#define CLK_TOP_MMPLL_D2 9
++#define CLK_TOP_MMPLL_D3_D5 10
++#define CLK_TOP_MMPLL_D4 11
++#define CLK_TOP_MMPLL_D6_D2 12
++#define CLK_TOP_MMPLL_D8 13
++#define CLK_TOP_APLL2_D4 14
++#define CLK_TOP_NET1PLL_D4 15
++#define CLK_TOP_NET1PLL_D5 16
++#define CLK_TOP_NET1PLL_D5_D2 17
++#define CLK_TOP_NET1PLL_D5_D4 18
++#define CLK_TOP_NET1PLL_D8 19
++#define CLK_TOP_NET1PLL_D8_D2 20
++#define CLK_TOP_NET1PLL_D8_D4 21
++#define CLK_TOP_NET1PLL_D8_D8 22
++#define CLK_TOP_NET1PLL_D8_D16 23
++#define CLK_TOP_NET2PLL_D2 24
++#define CLK_TOP_NET2PLL_D4 25
++#define CLK_TOP_NET2PLL_D4_D4 26
++#define CLK_TOP_NET2PLL_D4_D8 27
++#define CLK_TOP_NET2PLL_D6 28
++#define CLK_TOP_NET2PLL_D8 29
++#define CLK_TOP_NETSYS_SEL 30
++#define CLK_TOP_NETSYS_500M_SEL 31
++#define CLK_TOP_NETSYS_2X_SEL 32
++#define CLK_TOP_NETSYS_GSW_SEL 33
++#define CLK_TOP_ETH_GMII_SEL 34
++#define CLK_TOP_NETSYS_MCU_SEL 35
++#define CLK_TOP_NETSYS_PAO_2X_SEL 36
++#define CLK_TOP_EIP197_SEL 37
++#define CLK_TOP_AXI_INFRA_SEL 38
++#define CLK_TOP_UART_SEL 39
++#define CLK_TOP_EMMC_250M_SEL 40
++#define CLK_TOP_EMMC_400M_SEL 41
++#define CLK_TOP_SPI_SEL 42
++#define CLK_TOP_SPIM_MST_SEL 43
++#define CLK_TOP_NFI1X_SEL 44
++#define CLK_TOP_SPINFI_SEL 45
++#define CLK_TOP_PWM_SEL 46
++#define CLK_TOP_I2C_SEL 47
++#define CLK_TOP_PCIE_MBIST_250M_SEL 48
++#define CLK_TOP_PEXTP_TL_SEL 49
++#define CLK_TOP_PEXTP_TL_P1_SEL 50
++#define CLK_TOP_PEXTP_TL_P2_SEL 51
++#define CLK_TOP_PEXTP_TL_P3_SEL 52
++#define CLK_TOP_USB_SYS_SEL 53
++#define CLK_TOP_USB_SYS_P1_SEL 54
++#define CLK_TOP_USB_XHCI_SEL 55
++#define CLK_TOP_USB_XHCI_P1_SEL 56
++#define CLK_TOP_USB_FRMCNT_SEL 57
++#define CLK_TOP_USB_FRMCNT_P1_SEL 58
++#define CLK_TOP_AUD_SEL 59
++#define CLK_TOP_A1SYS_SEL 60
++#define CLK_TOP_AUD_L_SEL 61
++#define CLK_TOP_A_TUNER_SEL 62
++#define CLK_TOP_SSPXTP_SEL 63
++#define CLK_TOP_USB_PHY_SEL 64
++#define CLK_TOP_USXGMII_SBUS_0_SEL 65
++#define CLK_TOP_USXGMII_SBUS_1_SEL 66
++#define CLK_TOP_SGM_0_SEL 67
++#define CLK_TOP_SGM_SBUS_0_SEL 68
++#define CLK_TOP_SGM_1_SEL 69
++#define CLK_TOP_SGM_SBUS_1_SEL 70
++#define CLK_TOP_XFI_PHY_0_XTAL_SEL 71
++#define CLK_TOP_XFI_PHY_1_XTAL_SEL 72
++#define CLK_TOP_SYSAXI_SEL 73
++#define CLK_TOP_SYSAPB_SEL 74
++#define CLK_TOP_ETH_REFCK_50M_SEL 75
++#define CLK_TOP_ETH_SYS_200M_SEL 76
++#define CLK_TOP_ETH_SYS_SEL 77
++#define CLK_TOP_ETH_XGMII_SEL 78
++#define CLK_TOP_BUS_TOPS_SEL 79
++#define CLK_TOP_NPU_TOPS_SEL 80
++#define CLK_TOP_DRAMC_SEL 81
++#define CLK_TOP_DRAMC_MD32_SEL 82
++#define CLK_TOP_INFRA_F26M_SEL 83
++#define CLK_TOP_PEXTP_P0_SEL 84
++#define CLK_TOP_PEXTP_P1_SEL 85
++#define CLK_TOP_PEXTP_P2_SEL 86
++#define CLK_TOP_PEXTP_P3_SEL 87
++#define CLK_TOP_DA_XTP_GLB_P0_SEL 88
++#define CLK_TOP_DA_XTP_GLB_P1_SEL 89
++#define CLK_TOP_DA_XTP_GLB_P2_SEL 90
++#define CLK_TOP_DA_XTP_GLB_P3_SEL 91
++#define CLK_TOP_CKM_SEL 92
++#define CLK_TOP_DA_SEL 93
++#define CLK_TOP_PEXTP_SEL 94
++#define CLK_TOP_TOPS_P2_26M_SEL 95
++#define CLK_TOP_MCUSYS_BACKUP_625M_SEL 96
++#define CLK_TOP_NETSYS_SYNC_250M_SEL 97
++#define CLK_TOP_MACSEC_SEL 98
++#define CLK_TOP_NETSYS_TOPS_400M_SEL 99
++#define CLK_TOP_NETSYS_PPEFB_250M_SEL 100
++#define CLK_TOP_NETSYS_WARP_SEL 101
++#define CLK_TOP_ETH_MII_SEL 102
++#define CLK_TOP_NPU_SEL 103
++#define CLK_TOP_AUD_I2S_M 104
++
++/* MCUSYS */
++
++#define CLK_MCU_BUS_DIV_SEL 0
++#define CLK_MCU_ARM_DIV_SEL 1
++
++/* INFRACFG_AO */
++
++#define CLK_INFRA_MUX_UART0_SEL 0
++#define CLK_INFRA_MUX_UART1_SEL 1
++#define CLK_INFRA_MUX_UART2_SEL 2
++#define CLK_INFRA_MUX_SPI0_SEL 3
++#define CLK_INFRA_MUX_SPI1_SEL 4
++#define CLK_INFRA_MUX_SPI2_SEL 5
++#define CLK_INFRA_PWM_SEL 6
++#define CLK_INFRA_PWM_CK1_SEL 7
++#define CLK_INFRA_PWM_CK2_SEL 8
++#define CLK_INFRA_PWM_CK3_SEL 9
++#define CLK_INFRA_PWM_CK4_SEL 10
++#define CLK_INFRA_PWM_CK5_SEL 11
++#define CLK_INFRA_PWM_CK6_SEL 12
++#define CLK_INFRA_PWM_CK7_SEL 13
++#define CLK_INFRA_PWM_CK8_SEL 14
++#define CLK_INFRA_PCIE_GFMUX_TL_O_P0_SEL 15
++#define CLK_INFRA_PCIE_GFMUX_TL_O_P1_SEL 16
++#define CLK_INFRA_PCIE_GFMUX_TL_O_P2_SEL 17
++#define CLK_INFRA_PCIE_GFMUX_TL_O_P3_SEL 18
++
++/* INFRACFG */
++
++#define CLK_INFRA_PCIE_PERI_26M_CK_P0 19
++#define CLK_INFRA_PCIE_PERI_26M_CK_P1 20
++#define CLK_INFRA_PCIE_PERI_26M_CK_P2 21
++#define CLK_INFRA_PCIE_PERI_26M_CK_P3 22
++#define CLK_INFRA_66M_GPT_BCK 23
++#define CLK_INFRA_66M_PWM_HCK 24
++#define CLK_INFRA_66M_PWM_BCK 25
++#define CLK_INFRA_66M_PWM_CK1 26
++#define CLK_INFRA_66M_PWM_CK2 27
++#define CLK_INFRA_66M_PWM_CK3 28
++#define CLK_INFRA_66M_PWM_CK4 29
++#define CLK_INFRA_66M_PWM_CK5 30
++#define CLK_INFRA_66M_PWM_CK6 31
++#define CLK_INFRA_66M_PWM_CK7 32
++#define CLK_INFRA_66M_PWM_CK8 33
++#define CLK_INFRA_133M_CQDMA_BCK 34
++#define CLK_INFRA_66M_AUD_SLV_BCK 35
++#define CLK_INFRA_AUD_26M 36
++#define CLK_INFRA_AUD_L 37
++#define CLK_INFRA_AUD_AUD 38
++#define CLK_INFRA_AUD_EG2 39
++#define CLK_INFRA_DRAMC_F26M 40
++#define CLK_INFRA_133M_DBG_ACKM 41
++#define CLK_INFRA_66M_AP_DMA_BCK 42
++#define CLK_INFRA_66M_SEJ_BCK 43
++#define CLK_INFRA_PRE_CK_SEJ_F13M 44
++#define CLK_INFRA_26M_THERM_SYSTEM 45
++#define CLK_INFRA_I2C_BCK 46
++#define CLK_INFRA_52M_UART0_CK 47
++#define CLK_INFRA_52M_UART1_CK 48
++#define CLK_INFRA_52M_UART2_CK 49
++#define CLK_INFRA_NFI 50
++#define CLK_INFRA_SPINFI 51
++#define CLK_INFRA_66M_NFI_HCK 52
++#define CLK_INFRA_104M_SPI0 53
++#define CLK_INFRA_104M_SPI1 54
++#define CLK_INFRA_104M_SPI2_BCK 55
++#define CLK_INFRA_66M_SPI0_HCK 56
++#define CLK_INFRA_66M_SPI1_HCK 57
++#define CLK_INFRA_66M_SPI2_HCK 58
++#define CLK_INFRA_66M_FLASHIF_AXI 59
++#define CLK_INFRA_RTC 60
++#define CLK_INFRA_26M_ADC_BCK 61
++#define CLK_INFRA_RC_ADC 62
++#define CLK_INFRA_MSDC400 63
++#define CLK_INFRA_MSDC2_HCK 64
++#define CLK_INFRA_133M_MSDC_0_HCK 65
++#define CLK_INFRA_66M_MSDC_0_HCK 66
++#define CLK_INFRA_133M_CPUM_BCK 67
++#define CLK_INFRA_BIST2FPC 68
++#define CLK_INFRA_I2C_X16W_MCK_CK_P1 69
++#define CLK_INFRA_I2C_X16W_PCK_CK_P1 70
++#define CLK_INFRA_133M_USB_HCK 71
++#define CLK_INFRA_133M_USB_HCK_CK_P1 72
++#define CLK_INFRA_66M_USB_HCK 73
++#define CLK_INFRA_66M_USB_HCK_CK_P1 74
++#define CLK_INFRA_USB_SYS 75
++#define CLK_INFRA_USB_SYS_CK_P1 76
++#define CLK_INFRA_USB_REF 77
++#define CLK_INFRA_USB_CK_P1 78
++#define CLK_INFRA_USB_FRMCNT 79
++#define CLK_INFRA_USB_FRMCNT_CK_P1 80
++#define CLK_INFRA_USB_PIPE 81
++#define CLK_INFRA_USB_PIPE_CK_P1 82
++#define CLK_INFRA_USB_UTMI 83
++#define CLK_INFRA_USB_UTMI_CK_P1 84
++#define CLK_INFRA_USB_XHCI 85
++#define CLK_INFRA_USB_XHCI_CK_P1 86
++#define CLK_INFRA_PCIE_GFMUX_TL_P0 87
++#define CLK_INFRA_PCIE_GFMUX_TL_P1 88
++#define CLK_INFRA_PCIE_GFMUX_TL_P2 89
++#define CLK_INFRA_PCIE_GFMUX_TL_P3 90
++#define CLK_INFRA_PCIE_PIPE_P0 91
++#define CLK_INFRA_PCIE_PIPE_P1 92
++#define CLK_INFRA_PCIE_PIPE_P2 93
++#define CLK_INFRA_PCIE_PIPE_P3 94
++#define CLK_INFRA_133M_PCIE_CK_P0 95
++#define CLK_INFRA_133M_PCIE_CK_P1 96
++#define CLK_INFRA_133M_PCIE_CK_P2 97
++#define CLK_INFRA_133M_PCIE_CK_P3 98
++
++/* ETHDMA */
++
++#define CLK_ETHDMA_XGP1_EN 0
++#define CLK_ETHDMA_XGP2_EN 1
++#define CLK_ETHDMA_XGP3_EN 2
++#define CLK_ETHDMA_FE_EN 3
++#define CLK_ETHDMA_GP2_EN 4
++#define CLK_ETHDMA_GP1_EN 5
++#define CLK_ETHDMA_GP3_EN 6
++#define CLK_ETHDMA_ESW_EN 7
++#define CLK_ETHDMA_CRYPT0_EN 8
++#define CLK_ETHDMA_NR_CLK 9
++
++/* SGMIISYS_0 */
++
++#define CLK_SGM0_TX_EN 0
++#define CLK_SGM0_RX_EN 1
++#define CLK_SGMII0_NR_CLK 2
++
++/* SGMIISYS_1 */
++
++#define CLK_SGM1_TX_EN 0
++#define CLK_SGM1_RX_EN 1
++#define CLK_SGMII1_NR_CLK 2
++
++/* ETHWARP */
++
++#define CLK_ETHWARP_WOCPU2_EN 0
++#define CLK_ETHWARP_WOCPU1_EN 1
++#define CLK_ETHWARP_WOCPU0_EN 2
++#define CLK_ETHWARP_NR_CLK 3
++
++/* XFIPLL */
++#define CLK_XFIPLL_PLL 0
++#define CLK_XFIPLL_PLL_EN 1
++
++#endif /* _DT_BINDINGS_CLK_MT7988_H */
--- /dev/null
+From afd36e9d91b0a840983b829a9e95407d8151f7e7 Mon Sep 17 00:00:00 2001
+From: Daniel Golle <daniel@makrotopia.org>
+Date: Sun, 17 Dec 2023 21:49:55 +0000
+Subject: [PATCH 2/4] dt-bindings: clock: mediatek: add clock controllers of
+ MT7988
+
+Add various clock controllers found in the MT7988 SoC to existing
+bindings (if applicable) and add files for the new ethwarp, mcusys
+and xfi-pll clock controllers not previously present in any SoC.
+
+Signed-off-by: Daniel Golle <daniel@makrotopia.org>
+Reviewed-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
+Link: https://lore.kernel.org/r/07e76a544ce4392bcb88e34d5480e99bb7994618.1702849494.git.daniel@makrotopia.org
+Reviewed-by: Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>
+Signed-off-by: Stephen Boyd <sboyd@kernel.org>
+---
+ .../arm/mediatek/mediatek,infracfg.yaml | 1 +
+ .../bindings/clock/mediatek,apmixedsys.yaml | 1 +
+ .../bindings/clock/mediatek,ethsys.yaml | 1 +
+ .../clock/mediatek,mt7988-ethwarp.yaml | 52 +++++++++++++++
+ .../clock/mediatek,mt7988-xfi-pll.yaml | 48 ++++++++++++++
+ .../bindings/clock/mediatek,topckgen.yaml | 2 +
+ .../bindings/net/pcs/mediatek,sgmiisys.yaml | 65 ++++++++++++++++---
+ 7 files changed, 161 insertions(+), 9 deletions(-)
+ create mode 100644 Documentation/devicetree/bindings/clock/mediatek,mt7988-ethwarp.yaml
+ create mode 100644 Documentation/devicetree/bindings/clock/mediatek,mt7988-xfi-pll.yaml
+
+--- a/Documentation/devicetree/bindings/arm/mediatek/mediatek,infracfg.yaml
++++ b/Documentation/devicetree/bindings/arm/mediatek/mediatek,infracfg.yaml
+@@ -30,6 +30,7 @@ properties:
+ - mediatek,mt7629-infracfg
+ - mediatek,mt7981-infracfg
+ - mediatek,mt7986-infracfg
++ - mediatek,mt7988-infracfg
+ - mediatek,mt8135-infracfg
+ - mediatek,mt8167-infracfg
+ - mediatek,mt8173-infracfg
+--- a/Documentation/devicetree/bindings/clock/mediatek,apmixedsys.yaml
++++ b/Documentation/devicetree/bindings/clock/mediatek,apmixedsys.yaml
+@@ -22,6 +22,7 @@ properties:
+ - mediatek,mt7622-apmixedsys
+ - mediatek,mt7981-apmixedsys
+ - mediatek,mt7986-apmixedsys
++ - mediatek,mt7988-apmixedsys
+ - mediatek,mt8135-apmixedsys
+ - mediatek,mt8173-apmixedsys
+ - mediatek,mt8516-apmixedsys
+--- a/Documentation/devicetree/bindings/clock/mediatek,ethsys.yaml
++++ b/Documentation/devicetree/bindings/clock/mediatek,ethsys.yaml
+@@ -22,6 +22,7 @@ properties:
+ - mediatek,mt7629-ethsys
+ - mediatek,mt7981-ethsys
+ - mediatek,mt7986-ethsys
++ - mediatek,mt7988-ethsys
+ - const: syscon
+ - items:
+ - const: mediatek,mt7623-ethsys
+--- /dev/null
++++ b/Documentation/devicetree/bindings/clock/mediatek,mt7988-ethwarp.yaml
+@@ -0,0 +1,52 @@
++# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
++%YAML 1.2
++---
++$id: http://devicetree.org/schemas/clock/mediatek,mt7988-ethwarp.yaml#
++$schema: http://devicetree.org/meta-schemas/core.yaml#
++
++title: MediaTek MT7988 ethwarp Controller
++
++maintainers:
++ - Daniel Golle <daniel@makrotopia.org>
++
++description:
++ The Mediatek MT7988 ethwarp controller provides clocks and resets for the
++ Ethernet related subsystems found the MT7988 SoC.
++ The clock values can be found in <dt-bindings/clock/mt*-clk.h>.
++
++properties:
++ compatible:
++ items:
++ - const: mediatek,mt7988-ethwarp
++
++ reg:
++ maxItems: 1
++
++ '#clock-cells':
++ const: 1
++
++ '#reset-cells':
++ const: 1
++
++required:
++ - compatible
++ - reg
++ - '#clock-cells'
++ - '#reset-cells'
++
++additionalProperties: false
++
++examples:
++ - |
++ #include <dt-bindings/reset/ti-syscon.h>
++ soc {
++ #address-cells = <2>;
++ #size-cells = <2>;
++
++ clock-controller@15031000 {
++ compatible = "mediatek,mt7988-ethwarp";
++ reg = <0 0x15031000 0 0x1000>;
++ #clock-cells = <1>;
++ #reset-cells = <1>;
++ };
++ };
+--- /dev/null
++++ b/Documentation/devicetree/bindings/clock/mediatek,mt7988-xfi-pll.yaml
+@@ -0,0 +1,48 @@
++# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
++%YAML 1.2
++---
++$id: http://devicetree.org/schemas/clock/mediatek,mt7988-xfi-pll.yaml#
++$schema: http://devicetree.org/meta-schemas/core.yaml#
++
++title: MediaTek MT7988 XFI PLL Clock Controller
++
++maintainers:
++ - Daniel Golle <daniel@makrotopia.org>
++
++description:
++ The MediaTek XFI PLL controller provides the 156.25MHz clock for the
++ Ethernet SerDes PHY from the 40MHz top_xtal clock.
++
++properties:
++ compatible:
++ const: mediatek,mt7988-xfi-pll
++
++ reg:
++ maxItems: 1
++
++ resets:
++ maxItems: 1
++
++ '#clock-cells':
++ const: 1
++
++required:
++ - compatible
++ - reg
++ - resets
++ - '#clock-cells'
++
++additionalProperties: false
++
++examples:
++ - |
++ soc {
++ #address-cells = <2>;
++ #size-cells = <2>;
++ clock-controller@11f40000 {
++ compatible = "mediatek,mt7988-xfi-pll";
++ reg = <0 0x11f40000 0 0x1000>;
++ resets = <&watchdog 16>;
++ #clock-cells = <1>;
++ };
++ };
+--- a/Documentation/devicetree/bindings/clock/mediatek,topckgen.yaml
++++ b/Documentation/devicetree/bindings/clock/mediatek,topckgen.yaml
+@@ -37,6 +37,8 @@ properties:
+ - mediatek,mt7629-topckgen
+ - mediatek,mt7981-topckgen
+ - mediatek,mt7986-topckgen
++ - mediatek,mt7988-mcusys
++ - mediatek,mt7988-topckgen
+ - mediatek,mt8167-topckgen
+ - mediatek,mt8183-topckgen
+ - const: syscon
+--- a/Documentation/devicetree/bindings/net/pcs/mediatek,sgmiisys.yaml
++++ b/Documentation/devicetree/bindings/net/pcs/mediatek,sgmiisys.yaml
+@@ -15,15 +15,22 @@ description:
+
+ properties:
+ compatible:
+- items:
+- - enum:
+- - mediatek,mt7622-sgmiisys
+- - mediatek,mt7629-sgmiisys
+- - mediatek,mt7981-sgmiisys_0
+- - mediatek,mt7981-sgmiisys_1
+- - mediatek,mt7986-sgmiisys_0
+- - mediatek,mt7986-sgmiisys_1
+- - const: syscon
++ oneOf:
++ - items:
++ - enum:
++ - mediatek,mt7622-sgmiisys
++ - mediatek,mt7629-sgmiisys
++ - mediatek,mt7981-sgmiisys_0
++ - mediatek,mt7981-sgmiisys_1
++ - mediatek,mt7986-sgmiisys_0
++ - mediatek,mt7986-sgmiisys_1
++ - const: syscon
++ - items:
++ - enum:
++ - mediatek,mt7988-sgmiisys0
++ - mediatek,mt7988-sgmiisys1
++ - const: simple-mfd
++ - const: syscon
+
+ reg:
+ maxItems: 1
+@@ -35,11 +42,51 @@ properties:
+ description: Invert polarity of the SGMII data lanes
+ type: boolean
+
++ pcs:
++ type: object
++ description: MediaTek LynxI HSGMII PCS
++ properties:
++ compatible:
++ const: mediatek,mt7988-sgmii
++
++ clocks:
++ maxItems: 3
++
++ clock-names:
++ items:
++ - const: sgmii_sel
++ - const: sgmii_tx
++ - const: sgmii_rx
++
++ required:
++ - compatible
++ - clocks
++ - clock-names
++
++ additionalProperties: false
++
+ required:
+ - compatible
+ - reg
+ - '#clock-cells'
+
++allOf:
++ - if:
++ properties:
++ compatible:
++ contains:
++ enum:
++ - mediatek,mt7988-sgmiisys0
++ - mediatek,mt7988-sgmiisys1
++
++ then:
++ required:
++ - pcs
++
++ else:
++ properties:
++ pcs: false
++
+ additionalProperties: false
+
+ examples:
--- /dev/null
+From d9bf944beaaad1890ad3fcb755c61e1c7e4c5630 Mon Sep 17 00:00:00 2001
+From: Sam Shih <sam.shih@mediatek.com>
+Date: Sun, 17 Dec 2023 21:50:07 +0000
+Subject: [PATCH 3/4] clk: mediatek: add pcw_chg_bit control for PLLs of MT7988
+
+Introduce pcw_chg_bit member to struct mtk_pll_data and use it instead
+of the previously hardcoded PCW_CHG_MASK macro if set.
+This will needed for clocks on the MT7988 SoC.
+
+Signed-off-by: Sam Shih <sam.shih@mediatek.com>
+Signed-off-by: Daniel Golle <daniel@makrotopia.org>
+Reviewed-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
+Link: https://lore.kernel.org/r/3b9c65ddb08c8bedf790aacf29871af026b6f0b7.1702849494.git.daniel@makrotopia.org
+Signed-off-by: Stephen Boyd <sboyd@kernel.org>
+---
+ drivers/clk/mediatek/clk-pll.c | 5 +++--
+ drivers/clk/mediatek/clk-pll.h | 1 +
+ 2 files changed, 4 insertions(+), 2 deletions(-)
+
+--- a/drivers/clk/mediatek/clk-pll.c
++++ b/drivers/clk/mediatek/clk-pll.c
+@@ -23,7 +23,7 @@
+ #define CON0_BASE_EN BIT(0)
+ #define CON0_PWR_ON BIT(0)
+ #define CON0_ISO_EN BIT(1)
+-#define PCW_CHG_MASK BIT(31)
++#define PCW_CHG_BIT 31
+
+ #define AUDPLL_TUNER_EN BIT(31)
+
+@@ -141,7 +141,8 @@ static void mtk_pll_set_rate_regs(struct
+ pll->data->pcw_shift);
+ val |= pcw << pll->data->pcw_shift;
+ writel(val, pll->pcw_addr);
+- chg = readl(pll->pcw_chg_addr) | PCW_CHG_MASK;
++ chg = readl(pll->pcw_chg_addr) |
++ BIT(pll->data->pcw_chg_bit ? : PCW_CHG_BIT);
+ writel(chg, pll->pcw_chg_addr);
+ if (pll->tuner_addr)
+ writel(val + 1, pll->tuner_addr);
+--- a/drivers/clk/mediatek/clk-pll.h
++++ b/drivers/clk/mediatek/clk-pll.h
+@@ -46,6 +46,7 @@ struct mtk_pll_data {
+ const char *parent_name;
+ u32 en_reg;
+ u8 pll_en_bit; /* Assume 0, indicates BIT(0) by default */
++ u8 pcw_chg_bit;
+ };
+
+ int mtk_clk_register_plls(struct device_node *node,
--- /dev/null
+From 4b4719437d85f0173d344f2c76fa1a5b7f7d184b Mon Sep 17 00:00:00 2001
+From: Sam Shih <sam.shih@mediatek.com>
+Date: Sun, 17 Dec 2023 21:50:15 +0000
+Subject: [PATCH 4/4] clk: mediatek: add drivers for MT7988 SoC
+
+Add APMIXED, ETH, INFRACFG and TOPCKGEN clock drivers which are
+typical MediaTek designs.
+
+Also add driver for XFIPLL clock generating the 156.25MHz clock for
+the XFI SerDes. It needs an undocumented software workaround and has
+an unknown internal design.
+
+Signed-off-by: Sam Shih <sam.shih@mediatek.com>
+Signed-off-by: Daniel Golle <daniel@makrotopia.org>
+Reviewed-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
+Link: https://lore.kernel.org/r/c7574d808e2da1a530182f0fd790c1337c336e1b.1702849494.git.daniel@makrotopia.org
+[sboyd@kernel.org: Add module license to infracfg file]
+Signed-off-by: Stephen Boyd <sboyd@kernel.org>
+---
+ drivers/clk/mediatek/Kconfig | 9 +
+ drivers/clk/mediatek/Makefile | 5 +
+ drivers/clk/mediatek/clk-mt7988-apmixed.c | 114 ++++++++
+ drivers/clk/mediatek/clk-mt7988-eth.c | 150 ++++++++++
+ drivers/clk/mediatek/clk-mt7988-infracfg.c | 275 +++++++++++++++++
+ drivers/clk/mediatek/clk-mt7988-topckgen.c | 325 +++++++++++++++++++++
+ drivers/clk/mediatek/clk-mt7988-xfipll.c | 82 ++++++
+ 7 files changed, 960 insertions(+)
+ create mode 100644 drivers/clk/mediatek/clk-mt7988-apmixed.c
+ create mode 100644 drivers/clk/mediatek/clk-mt7988-eth.c
+ create mode 100644 drivers/clk/mediatek/clk-mt7988-infracfg.c
+ create mode 100644 drivers/clk/mediatek/clk-mt7988-topckgen.c
+ create mode 100644 drivers/clk/mediatek/clk-mt7988-xfipll.c
+
+--- a/drivers/clk/mediatek/Kconfig
++++ b/drivers/clk/mediatek/Kconfig
+@@ -415,6 +415,15 @@ config COMMON_CLK_MT7986_ETHSYS
+ This driver adds support for clocks for Ethernet and SGMII
+ required on MediaTek MT7986 SoC.
+
++config COMMON_CLK_MT7988
++ tristate "Clock driver for MediaTek MT7988"
++ depends on ARCH_MEDIATEK || COMPILE_TEST
++ select COMMON_CLK_MEDIATEK
++ default ARCH_MEDIATEK
++ help
++ This driver supports MediaTek MT7988 basic clocks and clocks
++ required for various periperals found on this SoC.
++
+ config COMMON_CLK_MT8135
+ bool "Clock driver for MediaTek MT8135"
+ depends on (ARCH_MEDIATEK && ARM) || COMPILE_TEST
+--- a/drivers/clk/mediatek/Makefile
++++ b/drivers/clk/mediatek/Makefile
+@@ -60,6 +60,11 @@ obj-$(CONFIG_COMMON_CLK_MT7986) += clk-m
+ obj-$(CONFIG_COMMON_CLK_MT7986) += clk-mt7986-topckgen.o
+ obj-$(CONFIG_COMMON_CLK_MT7986) += clk-mt7986-infracfg.o
+ obj-$(CONFIG_COMMON_CLK_MT7986_ETHSYS) += clk-mt7986-eth.o
++obj-$(CONFIG_COMMON_CLK_MT7988) += clk-mt7988-apmixed.o
++obj-$(CONFIG_COMMON_CLK_MT7988) += clk-mt7988-topckgen.o
++obj-$(CONFIG_COMMON_CLK_MT7988) += clk-mt7988-infracfg.o
++obj-$(CONFIG_COMMON_CLK_MT7988) += clk-mt7988-eth.o
++obj-$(CONFIG_COMMON_CLK_MT7988) += clk-mt7988-xfipll.o
+ obj-$(CONFIG_COMMON_CLK_MT8135) += clk-mt8135.o
+ obj-$(CONFIG_COMMON_CLK_MT8167) += clk-mt8167.o
+ obj-$(CONFIG_COMMON_CLK_MT8167_AUDSYS) += clk-mt8167-aud.o
+--- /dev/null
++++ b/drivers/clk/mediatek/clk-mt7988-apmixed.c
+@@ -0,0 +1,114 @@
++// SPDX-License-Identifier: GPL-2.0
++/*
++ * Copyright (c) 2023 MediaTek Inc.
++ * Author: Sam Shih <sam.shih@mediatek.com>
++ * Author: Xiufeng Li <Xiufeng.Li@mediatek.com>
++ */
++
++#include <linux/clk-provider.h>
++#include <linux/of.h>
++#include <linux/of_address.h>
++#include <linux/of_device.h>
++#include <linux/platform_device.h>
++#include "clk-mtk.h"
++#include "clk-gate.h"
++#include "clk-mux.h"
++#include "clk-pll.h"
++#include <dt-bindings/clock/mediatek,mt7988-clk.h>
++
++#define MT7988_PLL_FMAX (2500UL * MHZ)
++#define MT7988_PCW_CHG_BIT 2
++
++#define PLL(_id, _name, _reg, _pwr_reg, _en_mask, _flags, _rst_bar_mask, _pcwbits, _pd_reg, \
++ _pd_shift, _tuner_reg, _tuner_en_reg, _tuner_en_bit, _pcw_reg, _pcw_shift, \
++ _pcw_chg_reg) \
++ { \
++ .id = _id, \
++ .name = _name, \
++ .reg = _reg, \
++ .pwr_reg = _pwr_reg, \
++ .en_mask = _en_mask, \
++ .flags = _flags, \
++ .rst_bar_mask = BIT(_rst_bar_mask), \
++ .fmax = MT7988_PLL_FMAX, \
++ .pcwbits = _pcwbits, \
++ .pd_reg = _pd_reg, \
++ .pd_shift = _pd_shift, \
++ .tuner_reg = _tuner_reg, \
++ .tuner_en_reg = _tuner_en_reg, \
++ .tuner_en_bit = _tuner_en_bit, \
++ .pcw_reg = _pcw_reg, \
++ .pcw_shift = _pcw_shift, \
++ .pcw_chg_reg = _pcw_chg_reg, \
++ .pcw_chg_bit = MT7988_PCW_CHG_BIT, \
++ .parent_name = "clkxtal", \
++ }
++
++static const struct mtk_pll_data plls[] = {
++ PLL(CLK_APMIXED_NETSYSPLL, "netsyspll", 0x0104, 0x0110, 0x00000001, 0, 0, 32, 0x0104, 4, 0,
++ 0, 0, 0x0108, 0, 0x0104),
++ PLL(CLK_APMIXED_MPLL, "mpll", 0x0114, 0x0120, 0xff000001, HAVE_RST_BAR, 23, 32, 0x0114, 4,
++ 0, 0, 0, 0x0118, 0, 0x0114),
++ PLL(CLK_APMIXED_MMPLL, "mmpll", 0x0124, 0x0130, 0xff000001, HAVE_RST_BAR, 23, 32, 0x0124, 4,
++ 0, 0, 0, 0x0128, 0, 0x0124),
++ PLL(CLK_APMIXED_APLL2, "apll2", 0x0134, 0x0140, 0x00000001, 0, 0, 32, 0x0134, 4, 0x0704,
++ 0x0700, 1, 0x0138, 0, 0x0134),
++ PLL(CLK_APMIXED_NET1PLL, "net1pll", 0x0144, 0x0150, 0xff000001, HAVE_RST_BAR, 23, 32,
++ 0x0144, 4, 0, 0, 0, 0x0148, 0, 0x0144),
++ PLL(CLK_APMIXED_NET2PLL, "net2pll", 0x0154, 0x0160, 0xff000001, (HAVE_RST_BAR | PLL_AO), 23,
++ 32, 0x0154, 4, 0, 0, 0, 0x0158, 0, 0x0154),
++ PLL(CLK_APMIXED_WEDMCUPLL, "wedmcupll", 0x0164, 0x0170, 0x00000001, 0, 0, 32, 0x0164, 4, 0,
++ 0, 0, 0x0168, 0, 0x0164),
++ PLL(CLK_APMIXED_SGMPLL, "sgmpll", 0x0174, 0x0180, 0x00000001, 0, 0, 32, 0x0174, 4, 0, 0, 0,
++ 0x0178, 0, 0x0174),
++ PLL(CLK_APMIXED_ARM_B, "arm_b", 0x0204, 0x0210, 0xff000001, (HAVE_RST_BAR | PLL_AO), 23, 32,
++ 0x0204, 4, 0, 0, 0, 0x0208, 0, 0x0204),
++ PLL(CLK_APMIXED_CCIPLL2_B, "ccipll2_b", 0x0214, 0x0220, 0xff000001, HAVE_RST_BAR, 23, 32,
++ 0x0214, 4, 0, 0, 0, 0x0218, 0, 0x0214),
++ PLL(CLK_APMIXED_USXGMIIPLL, "usxgmiipll", 0x0304, 0x0310, 0xff000001, HAVE_RST_BAR, 23, 32,
++ 0x0304, 4, 0, 0, 0, 0x0308, 0, 0x0304),
++ PLL(CLK_APMIXED_MSDCPLL, "msdcpll", 0x0314, 0x0320, 0x00000001, 0, 0, 32, 0x0314, 4, 0, 0,
++ 0, 0x0318, 0, 0x0314),
++};
++
++static const struct of_device_id of_match_clk_mt7988_apmixed[] = {
++ { .compatible = "mediatek,mt7988-apmixedsys" },
++ { /* sentinel */ }
++};
++
++static int clk_mt7988_apmixed_probe(struct platform_device *pdev)
++{
++ struct clk_hw_onecell_data *clk_data;
++ struct device_node *node = pdev->dev.of_node;
++ int r;
++
++ clk_data = mtk_alloc_clk_data(ARRAY_SIZE(plls));
++ if (!clk_data)
++ return -ENOMEM;
++
++ r = mtk_clk_register_plls(node, plls, ARRAY_SIZE(plls), clk_data);
++ if (r)
++ goto free_apmixed_data;
++
++ r = of_clk_add_hw_provider(node, of_clk_hw_onecell_get, clk_data);
++ if (r)
++ goto unregister_plls;
++
++ return r;
++
++unregister_plls:
++ mtk_clk_unregister_plls(plls, ARRAY_SIZE(plls), clk_data);
++free_apmixed_data:
++ mtk_free_clk_data(clk_data);
++ return r;
++}
++
++static struct platform_driver clk_mt7988_apmixed_drv = {
++ .probe = clk_mt7988_apmixed_probe,
++ .driver = {
++ .name = "clk-mt7988-apmixed",
++ .of_match_table = of_match_clk_mt7988_apmixed,
++ },
++};
++builtin_platform_driver(clk_mt7988_apmixed_drv);
++MODULE_LICENSE("GPL");
+--- /dev/null
++++ b/drivers/clk/mediatek/clk-mt7988-eth.c
+@@ -0,0 +1,150 @@
++// SPDX-License-Identifier: GPL-2.0
++/*
++ * Copyright (c) 2023 MediaTek Inc.
++ * Author: Sam Shih <sam.shih@mediatek.com>
++ * Author: Xiufeng Li <Xiufeng.Li@mediatek.com>
++ */
++
++#include <linux/clk-provider.h>
++#include <linux/of.h>
++#include <linux/of_address.h>
++#include <linux/of_device.h>
++#include <linux/platform_device.h>
++#include "clk-mtk.h"
++#include "clk-gate.h"
++#include "reset.h"
++#include <dt-bindings/clock/mediatek,mt7988-clk.h>
++#include <dt-bindings/reset/mediatek,mt7988-resets.h>
++
++static const struct mtk_gate_regs ethdma_cg_regs = {
++ .set_ofs = 0x30,
++ .clr_ofs = 0x30,
++ .sta_ofs = 0x30,
++};
++
++#define GATE_ETHDMA(_id, _name, _parent, _shift) \
++ { \
++ .id = _id, \
++ .name = _name, \
++ .parent_name = _parent, \
++ .regs = ðdma_cg_regs, \
++ .shift = _shift, \
++ .ops = &mtk_clk_gate_ops_no_setclr_inv, \
++ }
++
++static const struct mtk_gate ethdma_clks[] = {
++ GATE_ETHDMA(CLK_ETHDMA_XGP1_EN, "ethdma_xgp1_en", "top_xtal", 0),
++ GATE_ETHDMA(CLK_ETHDMA_XGP2_EN, "ethdma_xgp2_en", "top_xtal", 1),
++ GATE_ETHDMA(CLK_ETHDMA_XGP3_EN, "ethdma_xgp3_en", "top_xtal", 2),
++ GATE_ETHDMA(CLK_ETHDMA_FE_EN, "ethdma_fe_en", "netsys_2x_sel", 6),
++ GATE_ETHDMA(CLK_ETHDMA_GP2_EN, "ethdma_gp2_en", "top_xtal", 7),
++ GATE_ETHDMA(CLK_ETHDMA_GP1_EN, "ethdma_gp1_en", "top_xtal", 8),
++ GATE_ETHDMA(CLK_ETHDMA_GP3_EN, "ethdma_gp3_en", "top_xtal", 10),
++ GATE_ETHDMA(CLK_ETHDMA_ESW_EN, "ethdma_esw_en", "netsys_gsw_sel", 16),
++ GATE_ETHDMA(CLK_ETHDMA_CRYPT0_EN, "ethdma_crypt0_en", "eip197_sel", 29),
++};
++
++static const struct mtk_clk_desc ethdma_desc = {
++ .clks = ethdma_clks,
++ .num_clks = ARRAY_SIZE(ethdma_clks),
++};
++
++static const struct mtk_gate_regs sgmii_cg_regs = {
++ .set_ofs = 0xe4,
++ .clr_ofs = 0xe4,
++ .sta_ofs = 0xe4,
++};
++
++#define GATE_SGMII(_id, _name, _parent, _shift) \
++ { \
++ .id = _id, \
++ .name = _name, \
++ .parent_name = _parent, \
++ .regs = &sgmii_cg_regs, \
++ .shift = _shift, \
++ .ops = &mtk_clk_gate_ops_no_setclr_inv, \
++ }
++
++static const struct mtk_gate sgmii0_clks[] = {
++ GATE_SGMII(CLK_SGM0_TX_EN, "sgm0_tx_en", "top_xtal", 2),
++ GATE_SGMII(CLK_SGM0_RX_EN, "sgm0_rx_en", "top_xtal", 3),
++};
++
++static const struct mtk_clk_desc sgmii0_desc = {
++ .clks = sgmii0_clks,
++ .num_clks = ARRAY_SIZE(sgmii0_clks),
++};
++
++static const struct mtk_gate sgmii1_clks[] = {
++ GATE_SGMII(CLK_SGM1_TX_EN, "sgm1_tx_en", "top_xtal", 2),
++ GATE_SGMII(CLK_SGM1_RX_EN, "sgm1_rx_en", "top_xtal", 3),
++};
++
++static const struct mtk_clk_desc sgmii1_desc = {
++ .clks = sgmii1_clks,
++ .num_clks = ARRAY_SIZE(sgmii1_clks),
++};
++
++static const struct mtk_gate_regs ethwarp_cg_regs = {
++ .set_ofs = 0x14,
++ .clr_ofs = 0x14,
++ .sta_ofs = 0x14,
++};
++
++#define GATE_ETHWARP(_id, _name, _parent, _shift) \
++ { \
++ .id = _id, \
++ .name = _name, \
++ .parent_name = _parent, \
++ .regs = ðwarp_cg_regs, \
++ .shift = _shift, \
++ .ops = &mtk_clk_gate_ops_no_setclr_inv, \
++ }
++
++static const struct mtk_gate ethwarp_clks[] = {
++ GATE_ETHWARP(CLK_ETHWARP_WOCPU2_EN, "ethwarp_wocpu2_en", "netsys_mcu_sel", 13),
++ GATE_ETHWARP(CLK_ETHWARP_WOCPU1_EN, "ethwarp_wocpu1_en", "netsys_mcu_sel", 14),
++ GATE_ETHWARP(CLK_ETHWARP_WOCPU0_EN, "ethwarp_wocpu0_en", "netsys_mcu_sel", 15),
++};
++
++static u16 ethwarp_rst_ofs[] = { 0x8 };
++
++static u16 ethwarp_idx_map[] = {
++ [MT7988_ETHWARP_RST_SWITCH] = 9,
++};
++
++static const struct mtk_clk_rst_desc ethwarp_rst_desc = {
++ .version = MTK_RST_SIMPLE,
++ .rst_bank_ofs = ethwarp_rst_ofs,
++ .rst_bank_nr = ARRAY_SIZE(ethwarp_rst_ofs),
++ .rst_idx_map = ethwarp_idx_map,
++ .rst_idx_map_nr = ARRAY_SIZE(ethwarp_idx_map),
++};
++
++static const struct mtk_clk_desc ethwarp_desc = {
++ .clks = ethwarp_clks,
++ .num_clks = ARRAY_SIZE(ethwarp_clks),
++ .rst_desc = ðwarp_rst_desc,
++};
++
++static const struct of_device_id of_match_clk_mt7988_eth[] = {
++ { .compatible = "mediatek,mt7988-ethsys", .data = ðdma_desc },
++ { .compatible = "mediatek,mt7988-sgmiisys0", .data = &sgmii0_desc },
++ { .compatible = "mediatek,mt7988-sgmiisys1", .data = &sgmii1_desc },
++ { .compatible = "mediatek,mt7988-ethwarp", .data = ðwarp_desc },
++ { /* sentinel */ }
++};
++MODULE_DEVICE_TABLE(of, of_match_clk_mt7988_eth);
++
++static struct platform_driver clk_mt7988_eth_drv = {
++ .driver = {
++ .name = "clk-mt7988-eth",
++ .of_match_table = of_match_clk_mt7988_eth,
++ },
++ .probe = mtk_clk_simple_probe,
++ .remove = mtk_clk_simple_remove,
++};
++module_platform_driver(clk_mt7988_eth_drv);
++
++MODULE_DESCRIPTION("MediaTek MT7988 Ethernet clocks driver");
++MODULE_LICENSE("GPL");
+--- /dev/null
++++ b/drivers/clk/mediatek/clk-mt7988-infracfg.c
+@@ -0,0 +1,275 @@
++// SPDX-License-Identifier: GPL-2.0
++/*
++ * Copyright (c) 2023 MediaTek Inc.
++ * Author: Sam Shih <sam.shih@mediatek.com>
++ * Author: Xiufeng Li <Xiufeng.Li@mediatek.com>
++ */
++
++#include <linux/clk-provider.h>
++#include <linux/of.h>
++#include <linux/of_address.h>
++#include <linux/of_device.h>
++#include <linux/platform_device.h>
++#include "clk-mtk.h"
++#include "clk-gate.h"
++#include "clk-mux.h"
++#include <dt-bindings/clock/mediatek,mt7988-clk.h>
++
++static DEFINE_SPINLOCK(mt7988_clk_lock);
++
++static const char *const infra_mux_uart0_parents[] __initconst = { "csw_infra_f26m_sel",
++ "uart_sel" };
++
++static const char *const infra_mux_uart1_parents[] __initconst = { "csw_infra_f26m_sel",
++ "uart_sel" };
++
++static const char *const infra_mux_uart2_parents[] __initconst = { "csw_infra_f26m_sel",
++ "uart_sel" };
++
++static const char *const infra_mux_spi0_parents[] __initconst = { "i2c_sel", "spi_sel" };
++
++static const char *const infra_mux_spi1_parents[] __initconst = { "i2c_sel", "spim_mst_sel" };
++
++static const char *const infra_pwm_bck_parents[] __initconst = { "top_rtc_32p7k",
++ "csw_infra_f26m_sel", "sysaxi_sel",
++ "pwm_sel" };
++
++static const char *const infra_pcie_gfmux_tl_ck_o_p0_parents[] __initconst = {
++ "top_rtc_32p7k", "csw_infra_f26m_sel", "csw_infra_f26m_sel", "pextp_tl_sel"
++};
++
++static const char *const infra_pcie_gfmux_tl_ck_o_p1_parents[] __initconst = {
++ "top_rtc_32p7k", "csw_infra_f26m_sel", "csw_infra_f26m_sel", "pextp_tl_p1_sel"
++};
++
++static const char *const infra_pcie_gfmux_tl_ck_o_p2_parents[] __initconst = {
++ "top_rtc_32p7k", "csw_infra_f26m_sel", "csw_infra_f26m_sel", "pextp_tl_p2_sel"
++};
++
++static const char *const infra_pcie_gfmux_tl_ck_o_p3_parents[] __initconst = {
++ "top_rtc_32p7k", "csw_infra_f26m_sel", "csw_infra_f26m_sel", "pextp_tl_p3_sel"
++};
++
++static const struct mtk_mux infra_muxes[] = {
++ /* MODULE_CLK_SEL_0 */
++ MUX_GATE_CLR_SET_UPD(CLK_INFRA_MUX_UART0_SEL, "infra_mux_uart0_sel",
++ infra_mux_uart0_parents, 0x0018, 0x0010, 0x0014, 0, 1, -1, -1, -1),
++ MUX_GATE_CLR_SET_UPD(CLK_INFRA_MUX_UART1_SEL, "infra_mux_uart1_sel",
++ infra_mux_uart1_parents, 0x0018, 0x0010, 0x0014, 1, 1, -1, -1, -1),
++ MUX_GATE_CLR_SET_UPD(CLK_INFRA_MUX_UART2_SEL, "infra_mux_uart2_sel",
++ infra_mux_uart2_parents, 0x0018, 0x0010, 0x0014, 2, 1, -1, -1, -1),
++ MUX_GATE_CLR_SET_UPD(CLK_INFRA_MUX_SPI0_SEL, "infra_mux_spi0_sel", infra_mux_spi0_parents,
++ 0x0018, 0x0010, 0x0014, 4, 1, -1, -1, -1),
++ MUX_GATE_CLR_SET_UPD(CLK_INFRA_MUX_SPI1_SEL, "infra_mux_spi1_sel", infra_mux_spi1_parents,
++ 0x0018, 0x0010, 0x0014, 5, 1, -1, -1, -1),
++ MUX_GATE_CLR_SET_UPD(CLK_INFRA_MUX_SPI2_SEL, "infra_mux_spi2_sel", infra_mux_spi0_parents,
++ 0x0018, 0x0010, 0x0014, 6, 1, -1, -1, -1),
++ MUX_GATE_CLR_SET_UPD(CLK_INFRA_PWM_SEL, "infra_pwm_sel", infra_pwm_bck_parents, 0x0018,
++ 0x0010, 0x0014, 14, 2, -1, -1, -1),
++ MUX_GATE_CLR_SET_UPD(CLK_INFRA_PWM_CK1_SEL, "infra_pwm_ck1_sel", infra_pwm_bck_parents,
++ 0x0018, 0x0010, 0x0014, 16, 2, -1, -1, -1),
++ MUX_GATE_CLR_SET_UPD(CLK_INFRA_PWM_CK2_SEL, "infra_pwm_ck2_sel", infra_pwm_bck_parents,
++ 0x0018, 0x0010, 0x0014, 18, 2, -1, -1, -1),
++ MUX_GATE_CLR_SET_UPD(CLK_INFRA_PWM_CK3_SEL, "infra_pwm_ck3_sel", infra_pwm_bck_parents,
++ 0x0018, 0x0010, 0x0014, 20, 2, -1, -1, -1),
++ MUX_GATE_CLR_SET_UPD(CLK_INFRA_PWM_CK4_SEL, "infra_pwm_ck4_sel", infra_pwm_bck_parents,
++ 0x0018, 0x0010, 0x0014, 22, 2, -1, -1, -1),
++ MUX_GATE_CLR_SET_UPD(CLK_INFRA_PWM_CK5_SEL, "infra_pwm_ck5_sel", infra_pwm_bck_parents,
++ 0x0018, 0x0010, 0x0014, 24, 2, -1, -1, -1),
++ MUX_GATE_CLR_SET_UPD(CLK_INFRA_PWM_CK6_SEL, "infra_pwm_ck6_sel", infra_pwm_bck_parents,
++ 0x0018, 0x0010, 0x0014, 26, 2, -1, -1, -1),
++ MUX_GATE_CLR_SET_UPD(CLK_INFRA_PWM_CK7_SEL, "infra_pwm_ck7_sel", infra_pwm_bck_parents,
++ 0x0018, 0x0010, 0x0014, 28, 2, -1, -1, -1),
++ MUX_GATE_CLR_SET_UPD(CLK_INFRA_PWM_CK8_SEL, "infra_pwm_ck8_sel", infra_pwm_bck_parents,
++ 0x0018, 0x0010, 0x0014, 30, 2, -1, -1, -1),
++ /* MODULE_CLK_SEL_1 */
++ MUX_GATE_CLR_SET_UPD(CLK_INFRA_PCIE_GFMUX_TL_O_P0_SEL, "infra_pcie_gfmux_tl_o_p0_sel",
++ infra_pcie_gfmux_tl_ck_o_p0_parents, 0x0028, 0x0020, 0x0024, 0, 2, -1,
++ -1, -1),
++ MUX_GATE_CLR_SET_UPD(CLK_INFRA_PCIE_GFMUX_TL_O_P1_SEL, "infra_pcie_gfmux_tl_o_p1_sel",
++ infra_pcie_gfmux_tl_ck_o_p1_parents, 0x0028, 0x0020, 0x0024, 2, 2, -1,
++ -1, -1),
++ MUX_GATE_CLR_SET_UPD(CLK_INFRA_PCIE_GFMUX_TL_O_P2_SEL, "infra_pcie_gfmux_tl_o_p2_sel",
++ infra_pcie_gfmux_tl_ck_o_p2_parents, 0x0028, 0x0020, 0x0024, 4, 2, -1,
++ -1, -1),
++ MUX_GATE_CLR_SET_UPD(CLK_INFRA_PCIE_GFMUX_TL_O_P3_SEL, "infra_pcie_gfmux_tl_o_p3_sel",
++ infra_pcie_gfmux_tl_ck_o_p3_parents, 0x0028, 0x0020, 0x0024, 6, 2, -1,
++ -1, -1),
++};
++
++static const struct mtk_gate_regs infra0_cg_regs = {
++ .set_ofs = 0x10,
++ .clr_ofs = 0x14,
++ .sta_ofs = 0x18,
++};
++
++static const struct mtk_gate_regs infra1_cg_regs = {
++ .set_ofs = 0x40,
++ .clr_ofs = 0x44,
++ .sta_ofs = 0x48,
++};
++
++static const struct mtk_gate_regs infra2_cg_regs = {
++ .set_ofs = 0x50,
++ .clr_ofs = 0x54,
++ .sta_ofs = 0x58,
++};
++
++static const struct mtk_gate_regs infra3_cg_regs = {
++ .set_ofs = 0x60,
++ .clr_ofs = 0x64,
++ .sta_ofs = 0x68,
++};
++
++#define GATE_INFRA0_FLAGS(_id, _name, _parent, _shift, _flags) \
++ GATE_MTK_FLAGS(_id, _name, _parent, &infra0_cg_regs, _shift, &mtk_clk_gate_ops_setclr, \
++ _flags)
++
++#define GATE_INFRA1_FLAGS(_id, _name, _parent, _shift, _flags) \
++ GATE_MTK_FLAGS(_id, _name, _parent, &infra1_cg_regs, _shift, &mtk_clk_gate_ops_setclr, \
++ _flags)
++
++#define GATE_INFRA2_FLAGS(_id, _name, _parent, _shift, _flags) \
++ GATE_MTK_FLAGS(_id, _name, _parent, &infra2_cg_regs, _shift, &mtk_clk_gate_ops_setclr, \
++ _flags)
++
++#define GATE_INFRA3_FLAGS(_id, _name, _parent, _shift, _flags) \
++ GATE_MTK_FLAGS(_id, _name, _parent, &infra3_cg_regs, _shift, &mtk_clk_gate_ops_setclr, \
++ _flags)
++
++#define GATE_INFRA0(_id, _name, _parent, _shift) GATE_INFRA0_FLAGS(_id, _name, _parent, _shift, 0)
++
++#define GATE_INFRA1(_id, _name, _parent, _shift) GATE_INFRA1_FLAGS(_id, _name, _parent, _shift, 0)
++
++#define GATE_INFRA2(_id, _name, _parent, _shift) GATE_INFRA2_FLAGS(_id, _name, _parent, _shift, 0)
++
++#define GATE_INFRA3(_id, _name, _parent, _shift) GATE_INFRA3_FLAGS(_id, _name, _parent, _shift, 0)
++
++static const struct mtk_gate infra_clks[] = {
++ /* INFRA0 */
++ GATE_INFRA0(CLK_INFRA_PCIE_PERI_26M_CK_P0, "infra_pcie_peri_ck_26m_ck_p0",
++ "csw_infra_f26m_sel", 7),
++ GATE_INFRA0(CLK_INFRA_PCIE_PERI_26M_CK_P1, "infra_pcie_peri_ck_26m_ck_p1",
++ "csw_infra_f26m_sel", 8),
++ GATE_INFRA0(CLK_INFRA_PCIE_PERI_26M_CK_P2, "infra_pcie_peri_ck_26m_ck_p2",
++ "csw_infra_f26m_sel", 9),
++ GATE_INFRA0(CLK_INFRA_PCIE_PERI_26M_CK_P3, "infra_pcie_peri_ck_26m_ck_p3",
++ "csw_infra_f26m_sel", 10),
++ /* INFRA1 */
++ GATE_INFRA1(CLK_INFRA_66M_GPT_BCK, "infra_hf_66m_gpt_bck", "sysaxi_sel", 0),
++ GATE_INFRA1(CLK_INFRA_66M_PWM_HCK, "infra_hf_66m_pwm_hck", "sysaxi_sel", 1),
++ GATE_INFRA1(CLK_INFRA_66M_PWM_BCK, "infra_hf_66m_pwm_bck", "infra_pwm_sel", 2),
++ GATE_INFRA1(CLK_INFRA_66M_PWM_CK1, "infra_hf_66m_pwm_ck1", "infra_pwm_ck1_sel", 3),
++ GATE_INFRA1(CLK_INFRA_66M_PWM_CK2, "infra_hf_66m_pwm_ck2", "infra_pwm_ck2_sel", 4),
++ GATE_INFRA1(CLK_INFRA_66M_PWM_CK3, "infra_hf_66m_pwm_ck3", "infra_pwm_ck3_sel", 5),
++ GATE_INFRA1(CLK_INFRA_66M_PWM_CK4, "infra_hf_66m_pwm_ck4", "infra_pwm_ck4_sel", 6),
++ GATE_INFRA1(CLK_INFRA_66M_PWM_CK5, "infra_hf_66m_pwm_ck5", "infra_pwm_ck5_sel", 7),
++ GATE_INFRA1(CLK_INFRA_66M_PWM_CK6, "infra_hf_66m_pwm_ck6", "infra_pwm_ck6_sel", 8),
++ GATE_INFRA1(CLK_INFRA_66M_PWM_CK7, "infra_hf_66m_pwm_ck7", "infra_pwm_ck7_sel", 9),
++ GATE_INFRA1(CLK_INFRA_66M_PWM_CK8, "infra_hf_66m_pwm_ck8", "infra_pwm_ck8_sel", 10),
++ GATE_INFRA1(CLK_INFRA_133M_CQDMA_BCK, "infra_hf_133m_cqdma_bck", "sysaxi_sel", 12),
++ GATE_INFRA1(CLK_INFRA_66M_AUD_SLV_BCK, "infra_66m_aud_slv_bck", "sysaxi_sel", 13),
++ GATE_INFRA1(CLK_INFRA_AUD_26M, "infra_f_faud_26m", "csw_infra_f26m_sel", 14),
++ GATE_INFRA1(CLK_INFRA_AUD_L, "infra_f_faud_l", "aud_l_sel", 15),
++ GATE_INFRA1(CLK_INFRA_AUD_AUD, "infra_f_aud_aud", "a1sys_sel", 16),
++ GATE_INFRA1(CLK_INFRA_AUD_EG2, "infra_f_faud_eg2", "a_tuner_sel", 18),
++ GATE_INFRA1_FLAGS(CLK_INFRA_DRAMC_F26M, "infra_dramc_f26m", "csw_infra_f26m_sel", 19,
++ CLK_IS_CRITICAL),
++ /* JTAG */
++ GATE_INFRA1_FLAGS(CLK_INFRA_133M_DBG_ACKM, "infra_hf_133m_dbg_ackm", "sysaxi_sel", 20,
++ CLK_IS_CRITICAL),
++ GATE_INFRA1(CLK_INFRA_66M_AP_DMA_BCK, "infra_66m_ap_dma_bck", "sysaxi_sel", 21),
++ GATE_INFRA1(CLK_INFRA_66M_SEJ_BCK, "infra_hf_66m_sej_bck", "sysaxi_sel", 29),
++ GATE_INFRA1(CLK_INFRA_PRE_CK_SEJ_F13M, "infra_pre_ck_sej_f13m", "csw_infra_f26m_sel", 30),
++ /* INFRA2 */
++ GATE_INFRA2(CLK_INFRA_26M_THERM_SYSTEM, "infra_hf_26m_therm_system", "csw_infra_f26m_sel",
++ 0),
++ GATE_INFRA2(CLK_INFRA_I2C_BCK, "infra_i2c_bck", "i2c_sel", 1),
++ GATE_INFRA2(CLK_INFRA_52M_UART0_CK, "infra_f_52m_uart0", "infra_mux_uart0_sel", 3),
++ GATE_INFRA2(CLK_INFRA_52M_UART1_CK, "infra_f_52m_uart1", "infra_mux_uart1_sel", 4),
++ GATE_INFRA2(CLK_INFRA_52M_UART2_CK, "infra_f_52m_uart2", "infra_mux_uart2_sel", 5),
++ GATE_INFRA2(CLK_INFRA_NFI, "infra_f_fnfi", "nfi1x_sel", 9),
++ GATE_INFRA2(CLK_INFRA_SPINFI, "infra_f_fspinfi", "spinfi_sel", 10),
++ GATE_INFRA2_FLAGS(CLK_INFRA_66M_NFI_HCK, "infra_hf_66m_nfi_hck", "sysaxi_sel", 11,
++ CLK_IS_CRITICAL),
++ GATE_INFRA2_FLAGS(CLK_INFRA_104M_SPI0, "infra_hf_104m_spi0", "infra_mux_spi0_sel", 12,
++ CLK_IS_CRITICAL),
++ GATE_INFRA2(CLK_INFRA_104M_SPI1, "infra_hf_104m_spi1", "infra_mux_spi1_sel", 13),
++ GATE_INFRA2(CLK_INFRA_104M_SPI2_BCK, "infra_hf_104m_spi2_bck", "infra_mux_spi2_sel", 14),
++ GATE_INFRA2_FLAGS(CLK_INFRA_66M_SPI0_HCK, "infra_hf_66m_spi0_hck", "sysaxi_sel", 15,
++ CLK_IS_CRITICAL),
++ GATE_INFRA2(CLK_INFRA_66M_SPI1_HCK, "infra_hf_66m_spi1_hck", "sysaxi_sel", 16),
++ GATE_INFRA2(CLK_INFRA_66M_SPI2_HCK, "infra_hf_66m_spi2_hck", "sysaxi_sel", 17),
++ GATE_INFRA2(CLK_INFRA_66M_FLASHIF_AXI, "infra_hf_66m_flashif_axi", "sysaxi_sel", 18),
++ GATE_INFRA2_FLAGS(CLK_INFRA_RTC, "infra_f_frtc", "top_rtc_32k", 19, CLK_IS_CRITICAL),
++ GATE_INFRA2(CLK_INFRA_26M_ADC_BCK, "infra_f_26m_adc_bck", "csw_infra_f26m_sel", 20),
++ GATE_INFRA2(CLK_INFRA_RC_ADC, "infra_f_frc_adc", "infra_f_26m_adc_bck", 21),
++ GATE_INFRA2(CLK_INFRA_MSDC400, "infra_f_fmsdc400", "emmc_400m_sel", 22),
++ GATE_INFRA2(CLK_INFRA_MSDC2_HCK, "infra_f_fmsdc2_hck", "emmc_250m_sel", 23),
++ GATE_INFRA2(CLK_INFRA_133M_MSDC_0_HCK, "infra_hf_133m_msdc_0_hck", "sysaxi_sel", 24),
++ GATE_INFRA2(CLK_INFRA_66M_MSDC_0_HCK, "infra_66m_msdc_0_hck", "sysaxi_sel", 25),
++ GATE_INFRA2(CLK_INFRA_133M_CPUM_BCK, "infra_hf_133m_cpum_bck", "sysaxi_sel", 26),
++ GATE_INFRA2(CLK_INFRA_BIST2FPC, "infra_hf_fbist2fpc", "nfi1x_sel", 27),
++ GATE_INFRA2(CLK_INFRA_I2C_X16W_MCK_CK_P1, "infra_hf_i2c_x16w_mck_ck_p1", "sysaxi_sel", 29),
++ GATE_INFRA2(CLK_INFRA_I2C_X16W_PCK_CK_P1, "infra_hf_i2c_x16w_pck_ck_p1", "sysaxi_sel", 31),
++ /* INFRA3 */
++ GATE_INFRA3(CLK_INFRA_133M_USB_HCK, "infra_133m_usb_hck", "sysaxi_sel", 0),
++ GATE_INFRA3(CLK_INFRA_133M_USB_HCK_CK_P1, "infra_133m_usb_hck_ck_p1", "sysaxi_sel", 1),
++ GATE_INFRA3(CLK_INFRA_66M_USB_HCK, "infra_66m_usb_hck", "sysaxi_sel", 2),
++ GATE_INFRA3(CLK_INFRA_66M_USB_HCK_CK_P1, "infra_66m_usb_hck_ck_p1", "sysaxi_sel", 3),
++ GATE_INFRA3(CLK_INFRA_USB_SYS, "infra_usb_sys", "usb_sys_sel", 4),
++ GATE_INFRA3(CLK_INFRA_USB_SYS_CK_P1, "infra_usb_sys_ck_p1", "usb_sys_p1_sel", 5),
++ GATE_INFRA3(CLK_INFRA_USB_REF, "infra_usb_ref", "top_xtal", 6),
++ GATE_INFRA3(CLK_INFRA_USB_CK_P1, "infra_usb_ck_p1", "top_xtal", 7),
++ GATE_INFRA3_FLAGS(CLK_INFRA_USB_FRMCNT, "infra_usb_frmcnt", "usb_frmcnt_sel", 8,
++ CLK_IS_CRITICAL),
++ GATE_INFRA3_FLAGS(CLK_INFRA_USB_FRMCNT_CK_P1, "infra_usb_frmcnt_ck_p1", "usb_frmcnt_p1_sel",
++ 9, CLK_IS_CRITICAL),
++ GATE_INFRA3(CLK_INFRA_USB_PIPE, "infra_usb_pipe", "sspxtp_sel", 10),
++ GATE_INFRA3(CLK_INFRA_USB_PIPE_CK_P1, "infra_usb_pipe_ck_p1", "usb_phy_sel", 11),
++ GATE_INFRA3(CLK_INFRA_USB_UTMI, "infra_usb_utmi", "top_xtal", 12),
++ GATE_INFRA3(CLK_INFRA_USB_UTMI_CK_P1, "infra_usb_utmi_ck_p1", "top_xtal", 13),
++ GATE_INFRA3(CLK_INFRA_USB_XHCI, "infra_usb_xhci", "usb_xhci_sel", 14),
++ GATE_INFRA3(CLK_INFRA_USB_XHCI_CK_P1, "infra_usb_xhci_ck_p1", "usb_xhci_p1_sel", 15),
++ GATE_INFRA3(CLK_INFRA_PCIE_GFMUX_TL_P0, "infra_pcie_gfmux_tl_ck_p0",
++ "infra_pcie_gfmux_tl_o_p0_sel", 20),
++ GATE_INFRA3(CLK_INFRA_PCIE_GFMUX_TL_P1, "infra_pcie_gfmux_tl_ck_p1",
++ "infra_pcie_gfmux_tl_o_p1_sel", 21),
++ GATE_INFRA3(CLK_INFRA_PCIE_GFMUX_TL_P2, "infra_pcie_gfmux_tl_ck_p2",
++ "infra_pcie_gfmux_tl_o_p2_sel", 22),
++ GATE_INFRA3(CLK_INFRA_PCIE_GFMUX_TL_P3, "infra_pcie_gfmux_tl_ck_p3",
++ "infra_pcie_gfmux_tl_o_p3_sel", 23),
++ GATE_INFRA3(CLK_INFRA_PCIE_PIPE_P0, "infra_pcie_pipe_ck_p0", "top_xtal", 24),
++ GATE_INFRA3(CLK_INFRA_PCIE_PIPE_P1, "infra_pcie_pipe_ck_p1", "top_xtal", 25),
++ GATE_INFRA3(CLK_INFRA_PCIE_PIPE_P2, "infra_pcie_pipe_ck_p2", "top_xtal", 26),
++ GATE_INFRA3(CLK_INFRA_PCIE_PIPE_P3, "infra_pcie_pipe_ck_p3", "top_xtal", 27),
++ GATE_INFRA3(CLK_INFRA_133M_PCIE_CK_P0, "infra_133m_pcie_ck_p0", "sysaxi_sel", 28),
++ GATE_INFRA3(CLK_INFRA_133M_PCIE_CK_P1, "infra_133m_pcie_ck_p1", "sysaxi_sel", 29),
++ GATE_INFRA3(CLK_INFRA_133M_PCIE_CK_P2, "infra_133m_pcie_ck_p2", "sysaxi_sel", 30),
++ GATE_INFRA3(CLK_INFRA_133M_PCIE_CK_P3, "infra_133m_pcie_ck_p3", "sysaxi_sel", 31),
++};
++
++static const struct mtk_clk_desc infra_desc = {
++ .clks = infra_clks,
++ .num_clks = ARRAY_SIZE(infra_clks),
++ .mux_clks = infra_muxes,
++ .num_mux_clks = ARRAY_SIZE(infra_muxes),
++ .clk_lock = &mt7988_clk_lock,
++};
++
++static const struct of_device_id of_match_clk_mt7988_infracfg[] = {
++ { .compatible = "mediatek,mt7988-infracfg", .data = &infra_desc },
++ { /* sentinel */ }
++};
++MODULE_DEVICE_TABLE(of, of_match_clk_mt7988_infracfg);
++
++static struct platform_driver clk_mt7988_infracfg_drv = {
++ .driver = {
++ .name = "clk-mt7988-infracfg",
++ .of_match_table = of_match_clk_mt7988_infracfg,
++ },
++ .probe = mtk_clk_simple_probe,
++ .remove = mtk_clk_simple_remove,
++};
++module_platform_driver(clk_mt7988_infracfg_drv);
++MODULE_LICENSE("GPL");
+--- /dev/null
++++ b/drivers/clk/mediatek/clk-mt7988-topckgen.c
+@@ -0,0 +1,325 @@
++// SPDX-License-Identifier: GPL-2.0
++/*
++ * Copyright (c) 2023 MediaTek Inc.
++ * Author: Sam Shih <sam.shih@mediatek.com>
++ * Author: Xiufeng Li <Xiufeng.Li@mediatek.com>
++ */
++
++#include <linux/clk-provider.h>
++#include <linux/of.h>
++#include <linux/of_address.h>
++#include <linux/of_device.h>
++#include <linux/platform_device.h>
++#include "clk-mtk.h"
++#include "clk-gate.h"
++#include "clk-mux.h"
++#include <dt-bindings/clock/mediatek,mt7988-clk.h>
++
++static DEFINE_SPINLOCK(mt7988_clk_lock);
++
++static const struct mtk_fixed_clk top_fixed_clks[] = {
++ FIXED_CLK(CLK_TOP_XTAL, "top_xtal", "clkxtal", 40000000),
++};
++
++static const struct mtk_fixed_factor top_divs[] = {
++ FACTOR(CLK_TOP_XTAL_D2, "top_xtal_d2", "top_xtal", 1, 2),
++ FACTOR(CLK_TOP_RTC_32K, "top_rtc_32k", "top_xtal", 1, 1250),
++ FACTOR(CLK_TOP_RTC_32P7K, "top_rtc_32p7k", "top_xtal", 1, 1220),
++ FACTOR(CLK_TOP_MPLL_D2, "mpll_d2", "mpll", 1, 2),
++ FACTOR(CLK_TOP_MPLL_D3_D2, "mpll_d3_d2", "mpll", 1, 2),
++ FACTOR(CLK_TOP_MPLL_D4, "mpll_d4", "mpll", 1, 4),
++ FACTOR(CLK_TOP_MPLL_D8, "mpll_d8", "mpll", 1, 8),
++ FACTOR(CLK_TOP_MPLL_D8_D2, "mpll_d8_d2", "mpll", 1, 16),
++ FACTOR(CLK_TOP_MMPLL_D2, "mmpll_d2", "mmpll", 1, 2),
++ FACTOR(CLK_TOP_MMPLL_D3_D5, "mmpll_d3_d5", "mmpll", 1, 15),
++ FACTOR(CLK_TOP_MMPLL_D4, "mmpll_d4", "mmpll", 1, 4),
++ FACTOR(CLK_TOP_MMPLL_D6_D2, "mmpll_d6_d2", "mmpll", 1, 12),
++ FACTOR(CLK_TOP_MMPLL_D8, "mmpll_d8", "mmpll", 1, 8),
++ FACTOR(CLK_TOP_APLL2_D4, "apll2_d4", "apll2", 1, 4),
++ FACTOR(CLK_TOP_NET1PLL_D4, "net1pll_d4", "net1pll", 1, 4),
++ FACTOR(CLK_TOP_NET1PLL_D5, "net1pll_d5", "net1pll", 1, 5),
++ FACTOR(CLK_TOP_NET1PLL_D5_D2, "net1pll_d5_d2", "net1pll", 1, 10),
++ FACTOR(CLK_TOP_NET1PLL_D5_D4, "net1pll_d5_d4", "net1pll", 1, 20),
++ FACTOR(CLK_TOP_NET1PLL_D8, "net1pll_d8", "net1pll", 1, 8),
++ FACTOR(CLK_TOP_NET1PLL_D8_D2, "net1pll_d8_d2", "net1pll", 1, 16),
++ FACTOR(CLK_TOP_NET1PLL_D8_D4, "net1pll_d8_d4", "net1pll", 1, 32),
++ FACTOR(CLK_TOP_NET1PLL_D8_D8, "net1pll_d8_d8", "net1pll", 1, 64),
++ FACTOR(CLK_TOP_NET1PLL_D8_D16, "net1pll_d8_d16", "net1pll", 1, 128),
++ FACTOR(CLK_TOP_NET2PLL_D2, "net2pll_d2", "net2pll", 1, 2),
++ FACTOR(CLK_TOP_NET2PLL_D4, "net2pll_d4", "net2pll", 1, 4),
++ FACTOR(CLK_TOP_NET2PLL_D4_D4, "net2pll_d4_d4", "net2pll", 1, 16),
++ FACTOR(CLK_TOP_NET2PLL_D4_D8, "net2pll_d4_d8", "net2pll", 1, 32),
++ FACTOR(CLK_TOP_NET2PLL_D6, "net2pll_d6", "net2pll", 1, 6),
++ FACTOR(CLK_TOP_NET2PLL_D8, "net2pll_d8", "net2pll", 1, 8),
++};
++
++static const char *const netsys_parents[] = { "top_xtal", "net2pll_d2", "mmpll_d2" };
++static const char *const netsys_500m_parents[] = { "top_xtal", "net1pll_d5", "net1pll_d5_d2" };
++static const char *const netsys_2x_parents[] = { "top_xtal", "net2pll", "mmpll" };
++static const char *const netsys_gsw_parents[] = { "top_xtal", "net1pll_d4", "net1pll_d5" };
++static const char *const eth_gmii_parents[] = { "top_xtal", "net1pll_d5_d4" };
++static const char *const netsys_mcu_parents[] = { "top_xtal", "net2pll", "mmpll",
++ "net1pll_d4", "net1pll_d5", "mpll" };
++static const char *const eip197_parents[] = { "top_xtal", "netsyspll", "net2pll",
++ "mmpll", "net1pll_d4", "net1pll_d5" };
++static const char *const axi_infra_parents[] = { "top_xtal", "net1pll_d8_d2" };
++static const char *const uart_parents[] = { "top_xtal", "mpll_d8", "mpll_d8_d2" };
++static const char *const emmc_250m_parents[] = { "top_xtal", "net1pll_d5_d2", "mmpll_d4" };
++static const char *const emmc_400m_parents[] = { "top_xtal", "msdcpll", "mmpll_d2",
++ "mpll_d2", "mmpll_d4", "net1pll_d8_d2" };
++static const char *const spi_parents[] = { "top_xtal", "mpll_d2", "mmpll_d4",
++ "net1pll_d8_d2", "net2pll_d6", "net1pll_d5_d4",
++ "mpll_d4", "net1pll_d8_d4" };
++static const char *const nfi1x_parents[] = { "top_xtal", "mmpll_d4", "net1pll_d8_d2", "net2pll_d6",
++ "mpll_d4", "mmpll_d8", "net1pll_d8_d4", "mpll_d8" };
++static const char *const spinfi_parents[] = { "top_xtal_d2", "top_xtal", "net1pll_d5_d4",
++ "mpll_d4", "mmpll_d8", "net1pll_d8_d4",
++ "mmpll_d6_d2", "mpll_d8" };
++static const char *const pwm_parents[] = { "top_xtal", "net1pll_d8_d2", "net1pll_d5_d4",
++ "mpll_d4", "mpll_d8_d2", "top_rtc_32k" };
++static const char *const i2c_parents[] = { "top_xtal", "net1pll_d5_d4", "mpll_d4",
++ "net1pll_d8_d4" };
++static const char *const pcie_mbist_250m_parents[] = { "top_xtal", "net1pll_d5_d2" };
++static const char *const pextp_tl_ck_parents[] = { "top_xtal", "net2pll_d6", "mmpll_d8",
++ "mpll_d8_d2", "top_rtc_32k" };
++static const char *const usb_frmcnt_parents[] = { "top_xtal", "mmpll_d3_d5" };
++static const char *const aud_parents[] = { "top_xtal", "apll2" };
++static const char *const a1sys_parents[] = { "top_xtal", "apll2_d4" };
++static const char *const aud_l_parents[] = { "top_xtal", "apll2", "mpll_d8_d2" };
++static const char *const sspxtp_parents[] = { "top_xtal_d2", "mpll_d8_d2" };
++static const char *const usxgmii_sbus_0_parents[] = { "top_xtal", "net1pll_d8_d4" };
++static const char *const sgm_0_parents[] = { "top_xtal", "sgmpll" };
++static const char *const sysapb_parents[] = { "top_xtal", "mpll_d3_d2" };
++static const char *const eth_refck_50m_parents[] = { "top_xtal", "net2pll_d4_d4" };
++static const char *const eth_sys_200m_parents[] = { "top_xtal", "net2pll_d4" };
++static const char *const eth_xgmii_parents[] = { "top_xtal_d2", "net1pll_d8_d8", "net1pll_d8_d16" };
++static const char *const bus_tops_parents[] = { "top_xtal", "net1pll_d5", "net2pll_d2" };
++static const char *const npu_tops_parents[] = { "top_xtal", "net2pll" };
++static const char *const dramc_md32_parents[] = { "top_xtal", "mpll_d2", "wedmcupll" };
++static const char *const da_xtp_glb_p0_parents[] = { "top_xtal", "net2pll_d8" };
++static const char *const mcusys_backup_625m_parents[] = { "top_xtal", "net1pll_d4" };
++static const char *const macsec_parents[] = { "top_xtal", "sgmpll", "net1pll_d8" };
++static const char *const netsys_tops_400m_parents[] = { "top_xtal", "net2pll_d2" };
++static const char *const eth_mii_parents[] = { "top_xtal_d2", "net2pll_d4_d8" };
++
++static const struct mtk_mux top_muxes[] = {
++ /* CLK_CFG_0 */
++ MUX_GATE_CLR_SET_UPD(CLK_TOP_NETSYS_SEL, "netsys_sel", netsys_parents, 0x000, 0x004, 0x008,
++ 0, 2, 7, 0x1c0, 0),
++ MUX_GATE_CLR_SET_UPD(CLK_TOP_NETSYS_500M_SEL, "netsys_500m_sel", netsys_500m_parents, 0x000,
++ 0x004, 0x008, 8, 2, 15, 0x1C0, 1),
++ MUX_GATE_CLR_SET_UPD(CLK_TOP_NETSYS_2X_SEL, "netsys_2x_sel", netsys_2x_parents, 0x000,
++ 0x004, 0x008, 16, 2, 23, 0x1C0, 2),
++ MUX_GATE_CLR_SET_UPD(CLK_TOP_NETSYS_GSW_SEL, "netsys_gsw_sel", netsys_gsw_parents, 0x000,
++ 0x004, 0x008, 24, 2, 31, 0x1C0, 3),
++ /* CLK_CFG_1 */
++ MUX_GATE_CLR_SET_UPD(CLK_TOP_ETH_GMII_SEL, "eth_gmii_sel", eth_gmii_parents, 0x010, 0x014,
++ 0x018, 0, 1, 7, 0x1C0, 4),
++ MUX_GATE_CLR_SET_UPD(CLK_TOP_NETSYS_MCU_SEL, "netsys_mcu_sel", netsys_mcu_parents, 0x010,
++ 0x014, 0x018, 8, 3, 15, 0x1C0, 5),
++ MUX_GATE_CLR_SET_UPD(CLK_TOP_NETSYS_PAO_2X_SEL, "netsys_pao_2x_sel", netsys_mcu_parents,
++ 0x010, 0x014, 0x018, 16, 3, 23, 0x1C0, 6),
++ MUX_GATE_CLR_SET_UPD(CLK_TOP_EIP197_SEL, "eip197_sel", eip197_parents, 0x010, 0x014, 0x018,
++ 24, 3, 31, 0x1c0, 7),
++ /* CLK_CFG_2 */
++ MUX_GATE_CLR_SET_UPD_FLAGS(CLK_TOP_AXI_INFRA_SEL, "axi_infra_sel", axi_infra_parents, 0x020,
++ 0x024, 0x028, 0, 1, 7, 0x1C0, 8, CLK_IS_CRITICAL),
++ MUX_GATE_CLR_SET_UPD(CLK_TOP_UART_SEL, "uart_sel", uart_parents, 0x020, 0x024, 0x028, 8, 2,
++ 15, 0x1c0, 9),
++ MUX_GATE_CLR_SET_UPD(CLK_TOP_EMMC_250M_SEL, "emmc_250m_sel", emmc_250m_parents, 0x020,
++ 0x024, 0x028, 16, 2, 23, 0x1C0, 10),
++ MUX_GATE_CLR_SET_UPD(CLK_TOP_EMMC_400M_SEL, "emmc_400m_sel", emmc_400m_parents, 0x020,
++ 0x024, 0x028, 24, 3, 31, 0x1C0, 11),
++ /* CLK_CFG_3 */
++ MUX_GATE_CLR_SET_UPD(CLK_TOP_SPI_SEL, "spi_sel", spi_parents, 0x030, 0x034, 0x038, 0, 3, 7,
++ 0x1c0, 12),
++ MUX_GATE_CLR_SET_UPD(CLK_TOP_SPIM_MST_SEL, "spim_mst_sel", spi_parents, 0x030, 0x034, 0x038,
++ 8, 3, 15, 0x1c0, 13),
++ MUX_GATE_CLR_SET_UPD(CLK_TOP_NFI1X_SEL, "nfi1x_sel", nfi1x_parents, 0x030, 0x034, 0x038, 16,
++ 3, 23, 0x1c0, 14),
++ MUX_GATE_CLR_SET_UPD(CLK_TOP_SPINFI_SEL, "spinfi_sel", spinfi_parents, 0x030, 0x034, 0x038,
++ 24, 3, 31, 0x1c0, 15),
++ /* CLK_CFG_4 */
++ MUX_GATE_CLR_SET_UPD(CLK_TOP_PWM_SEL, "pwm_sel", pwm_parents, 0x040, 0x044, 0x048, 0, 3, 7,
++ 0x1c0, 16),
++ MUX_GATE_CLR_SET_UPD(CLK_TOP_I2C_SEL, "i2c_sel", i2c_parents, 0x040, 0x044, 0x048, 8, 2, 15,
++ 0x1c0, 17),
++ MUX_GATE_CLR_SET_UPD(CLK_TOP_PCIE_MBIST_250M_SEL, "pcie_mbist_250m_sel",
++ pcie_mbist_250m_parents, 0x040, 0x044, 0x048, 16, 1, 23, 0x1C0, 18),
++ MUX_GATE_CLR_SET_UPD(CLK_TOP_PEXTP_TL_SEL, "pextp_tl_sel", pextp_tl_ck_parents, 0x040,
++ 0x044, 0x048, 24, 3, 31, 0x1C0, 19),
++ /* CLK_CFG_5 */
++ MUX_GATE_CLR_SET_UPD(CLK_TOP_PEXTP_TL_P1_SEL, "pextp_tl_p1_sel", pextp_tl_ck_parents, 0x050,
++ 0x054, 0x058, 0, 3, 7, 0x1C0, 20),
++ MUX_GATE_CLR_SET_UPD(CLK_TOP_PEXTP_TL_P2_SEL, "pextp_tl_p2_sel", pextp_tl_ck_parents, 0x050,
++ 0x054, 0x058, 8, 3, 15, 0x1C0, 21),
++ MUX_GATE_CLR_SET_UPD(CLK_TOP_PEXTP_TL_P3_SEL, "pextp_tl_p3_sel", pextp_tl_ck_parents, 0x050,
++ 0x054, 0x058, 16, 3, 23, 0x1C0, 22),
++ MUX_GATE_CLR_SET_UPD(CLK_TOP_USB_SYS_SEL, "usb_sys_sel", eth_gmii_parents, 0x050, 0x054,
++ 0x058, 24, 1, 31, 0x1C0, 23),
++ /* CLK_CFG_6 */
++ MUX_GATE_CLR_SET_UPD(CLK_TOP_USB_SYS_P1_SEL, "usb_sys_p1_sel", eth_gmii_parents, 0x060,
++ 0x064, 0x068, 0, 1, 7, 0x1C0, 24),
++ MUX_GATE_CLR_SET_UPD(CLK_TOP_USB_XHCI_SEL, "usb_xhci_sel", eth_gmii_parents, 0x060, 0x064,
++ 0x068, 8, 1, 15, 0x1C0, 25),
++ MUX_GATE_CLR_SET_UPD(CLK_TOP_USB_XHCI_P1_SEL, "usb_xhci_p1_sel", eth_gmii_parents, 0x060,
++ 0x064, 0x068, 16, 1, 23, 0x1C0, 26),
++ MUX_GATE_CLR_SET_UPD(CLK_TOP_USB_FRMCNT_SEL, "usb_frmcnt_sel", usb_frmcnt_parents, 0x060,
++ 0x064, 0x068, 24, 1, 31, 0x1C0, 27),
++ /* CLK_CFG_7 */
++ MUX_GATE_CLR_SET_UPD(CLK_TOP_USB_FRMCNT_P1_SEL, "usb_frmcnt_p1_sel", usb_frmcnt_parents,
++ 0x070, 0x074, 0x078, 0, 1, 7, 0x1C0, 28),
++ MUX_GATE_CLR_SET_UPD(CLK_TOP_AUD_SEL, "aud_sel", aud_parents, 0x070, 0x074, 0x078, 8, 1, 15,
++ 0x1c0, 29),
++ MUX_GATE_CLR_SET_UPD(CLK_TOP_A1SYS_SEL, "a1sys_sel", a1sys_parents, 0x070, 0x074, 0x078, 16,
++ 1, 23, 0x1c0, 30),
++ MUX_GATE_CLR_SET_UPD(CLK_TOP_AUD_L_SEL, "aud_l_sel", aud_l_parents, 0x070, 0x074, 0x078, 24,
++ 2, 31, 0x1c4, 0),
++ /* CLK_CFG_8 */
++ MUX_GATE_CLR_SET_UPD(CLK_TOP_A_TUNER_SEL, "a_tuner_sel", a1sys_parents, 0x080, 0x084, 0x088,
++ 0, 1, 7, 0x1c4, 1),
++ MUX_GATE_CLR_SET_UPD(CLK_TOP_SSPXTP_SEL, "sspxtp_sel", sspxtp_parents, 0x080, 0x084, 0x088,
++ 8, 1, 15, 0x1c4, 2),
++ MUX_GATE_CLR_SET_UPD(CLK_TOP_USB_PHY_SEL, "usb_phy_sel", sspxtp_parents, 0x080, 0x084,
++ 0x088, 16, 1, 23, 0x1c4, 3),
++ MUX_GATE_CLR_SET_UPD(CLK_TOP_USXGMII_SBUS_0_SEL, "usxgmii_sbus_0_sel",
++ usxgmii_sbus_0_parents, 0x080, 0x084, 0x088, 24, 1, 31, 0x1C4, 4),
++ /* CLK_CFG_9 */
++ MUX_GATE_CLR_SET_UPD(CLK_TOP_USXGMII_SBUS_1_SEL, "usxgmii_sbus_1_sel",
++ usxgmii_sbus_0_parents, 0x090, 0x094, 0x098, 0, 1, 7, 0x1C4, 5),
++ MUX_GATE_CLR_SET_UPD(CLK_TOP_SGM_0_SEL, "sgm_0_sel", sgm_0_parents, 0x090, 0x094, 0x098, 8,
++ 1, 15, 0x1c4, 6),
++ MUX_GATE_CLR_SET_UPD_FLAGS(CLK_TOP_SGM_SBUS_0_SEL, "sgm_sbus_0_sel", usxgmii_sbus_0_parents,
++ 0x090, 0x094, 0x098, 16, 1, 23, 0x1C4, 7, CLK_IS_CRITICAL),
++ MUX_GATE_CLR_SET_UPD(CLK_TOP_SGM_1_SEL, "sgm_1_sel", sgm_0_parents, 0x090, 0x094, 0x098, 24,
++ 1, 31, 0x1c4, 8),
++ /* CLK_CFG_10 */
++ MUX_GATE_CLR_SET_UPD_FLAGS(CLK_TOP_SGM_SBUS_1_SEL, "sgm_sbus_1_sel", usxgmii_sbus_0_parents,
++ 0x0a0, 0x0a4, 0x0a8, 0, 1, 7, 0x1C4, 9, CLK_IS_CRITICAL),
++ MUX_GATE_CLR_SET_UPD(CLK_TOP_XFI_PHY_0_XTAL_SEL, "xfi_phy_0_xtal_sel", sspxtp_parents,
++ 0x0a0, 0x0a4, 0x0a8, 8, 1, 15, 0x1C4, 10),
++ MUX_GATE_CLR_SET_UPD(CLK_TOP_XFI_PHY_1_XTAL_SEL, "xfi_phy_1_xtal_sel", sspxtp_parents,
++ 0x0a0, 0x0a4, 0x0a8, 16, 1, 23, 0x1C4, 11),
++ /* CLK_CFG_11 */
++ MUX_GATE_CLR_SET_UPD_FLAGS(CLK_TOP_SYSAXI_SEL, "sysaxi_sel", axi_infra_parents, 0x0a0,
++ 0x0a4, 0x0a8, 24, 1, 31, 0x1C4, 12, CLK_IS_CRITICAL),
++ MUX_GATE_CLR_SET_UPD_FLAGS(CLK_TOP_SYSAPB_SEL, "sysapb_sel", sysapb_parents, 0x0b0, 0x0b4,
++ 0x0b8, 0, 1, 7, 0x1c4, 13, CLK_IS_CRITICAL),
++ MUX_GATE_CLR_SET_UPD(CLK_TOP_ETH_REFCK_50M_SEL, "eth_refck_50m_sel", eth_refck_50m_parents,
++ 0x0b0, 0x0b4, 0x0b8, 8, 1, 15, 0x1C4, 14),
++ MUX_GATE_CLR_SET_UPD(CLK_TOP_ETH_SYS_200M_SEL, "eth_sys_200m_sel", eth_sys_200m_parents,
++ 0x0b0, 0x0b4, 0x0b8, 16, 1, 23, 0x1C4, 15),
++ MUX_GATE_CLR_SET_UPD(CLK_TOP_ETH_SYS_SEL, "eth_sys_sel", pcie_mbist_250m_parents, 0x0b0,
++ 0x0b4, 0x0b8, 24, 1, 31, 0x1C4, 16),
++ /* CLK_CFG_12 */
++ MUX_GATE_CLR_SET_UPD(CLK_TOP_ETH_XGMII_SEL, "eth_xgmii_sel", eth_xgmii_parents, 0x0c0,
++ 0x0c4, 0x0c8, 0, 2, 7, 0x1C4, 17),
++ MUX_GATE_CLR_SET_UPD(CLK_TOP_BUS_TOPS_SEL, "bus_tops_sel", bus_tops_parents, 0x0c0, 0x0c4,
++ 0x0c8, 8, 2, 15, 0x1C4, 18),
++ MUX_GATE_CLR_SET_UPD(CLK_TOP_NPU_TOPS_SEL, "npu_tops_sel", npu_tops_parents, 0x0c0, 0x0c4,
++ 0x0c8, 16, 1, 23, 0x1C4, 19),
++ MUX_GATE_CLR_SET_UPD_FLAGS(CLK_TOP_DRAMC_SEL, "dramc_sel", sspxtp_parents, 0x0c0, 0x0c4,
++ 0x0c8, 24, 1, 31, 0x1C4, 20, CLK_IS_CRITICAL),
++ /* CLK_CFG_13 */
++ MUX_GATE_CLR_SET_UPD_FLAGS(CLK_TOP_DRAMC_MD32_SEL, "dramc_md32_sel", dramc_md32_parents,
++ 0x0d0, 0x0d4, 0x0d8, 0, 2, 7, 0x1C4, 21, CLK_IS_CRITICAL),
++ MUX_GATE_CLR_SET_UPD_FLAGS(CLK_TOP_INFRA_F26M_SEL, "csw_infra_f26m_sel", sspxtp_parents,
++ 0x0d0, 0x0d4, 0x0d8, 8, 1, 15, 0x1C4, 22, CLK_IS_CRITICAL),
++ MUX_GATE_CLR_SET_UPD(CLK_TOP_PEXTP_P0_SEL, "pextp_p0_sel", sspxtp_parents, 0x0d0, 0x0d4,
++ 0x0d8, 16, 1, 23, 0x1C4, 23),
++ MUX_GATE_CLR_SET_UPD(CLK_TOP_PEXTP_P1_SEL, "pextp_p1_sel", sspxtp_parents, 0x0d0, 0x0d4,
++ 0x0d8, 24, 1, 31, 0x1C4, 24),
++ /* CLK_CFG_14 */
++ MUX_GATE_CLR_SET_UPD(CLK_TOP_PEXTP_P2_SEL, "pextp_p2_sel", sspxtp_parents, 0x0e0, 0x0e4,
++ 0x0e8, 0, 1, 7, 0x1C4, 25),
++ MUX_GATE_CLR_SET_UPD(CLK_TOP_PEXTP_P3_SEL, "pextp_p3_sel", sspxtp_parents, 0x0e0, 0x0e4,
++ 0x0e8, 8, 1, 15, 0x1C4, 26),
++ MUX_GATE_CLR_SET_UPD(CLK_TOP_DA_XTP_GLB_P0_SEL, "da_xtp_glb_p0_sel", da_xtp_glb_p0_parents,
++ 0x0e0, 0x0e4, 0x0e8, 16, 1, 23, 0x1C4, 27),
++ MUX_GATE_CLR_SET_UPD(CLK_TOP_DA_XTP_GLB_P1_SEL, "da_xtp_glb_p1_sel", da_xtp_glb_p0_parents,
++ 0x0e0, 0x0e4, 0x0e8, 24, 1, 31, 0x1C4, 28),
++ /* CLK_CFG_15 */
++ MUX_GATE_CLR_SET_UPD(CLK_TOP_DA_XTP_GLB_P2_SEL, "da_xtp_glb_p2_sel", da_xtp_glb_p0_parents,
++ 0x0f0, 0x0f4, 0x0f8, 0, 1, 7, 0x1C4, 29),
++ MUX_GATE_CLR_SET_UPD(CLK_TOP_DA_XTP_GLB_P3_SEL, "da_xtp_glb_p3_sel", da_xtp_glb_p0_parents,
++ 0x0f0, 0x0f4, 0x0f8, 8, 1, 15, 0x1C4, 30),
++ MUX_GATE_CLR_SET_UPD(CLK_TOP_CKM_SEL, "ckm_sel", sspxtp_parents, 0x0F0, 0x0f4, 0x0f8, 16, 1,
++ 23, 0x1c8, 0),
++ MUX_GATE_CLR_SET_UPD(CLK_TOP_DA_SEL, "da_sel", sspxtp_parents, 0x0f0, 0x0f4, 0x0f8, 24, 1,
++ 31, 0x1C8, 1),
++ /* CLK_CFG_16 */
++ MUX_GATE_CLR_SET_UPD(CLK_TOP_PEXTP_SEL, "pextp_sel", sspxtp_parents, 0x0100, 0x104, 0x108,
++ 0, 1, 7, 0x1c8, 2),
++ MUX_GATE_CLR_SET_UPD(CLK_TOP_TOPS_P2_26M_SEL, "tops_p2_26m_sel", sspxtp_parents, 0x0100,
++ 0x104, 0x108, 8, 1, 15, 0x1C8, 3),
++ MUX_GATE_CLR_SET_UPD(CLK_TOP_MCUSYS_BACKUP_625M_SEL, "mcusys_backup_625m_sel",
++ mcusys_backup_625m_parents, 0x0100, 0x104, 0x108, 16, 1, 23, 0x1C8, 4),
++ MUX_GATE_CLR_SET_UPD(CLK_TOP_NETSYS_SYNC_250M_SEL, "netsys_sync_250m_sel",
++ pcie_mbist_250m_parents, 0x0100, 0x104, 0x108, 24, 1, 31, 0x1c8, 5),
++ /* CLK_CFG_17 */
++ MUX_GATE_CLR_SET_UPD(CLK_TOP_MACSEC_SEL, "macsec_sel", macsec_parents, 0x0110, 0x114, 0x118,
++ 0, 2, 7, 0x1c8, 6),
++ MUX_GATE_CLR_SET_UPD(CLK_TOP_NETSYS_TOPS_400M_SEL, "netsys_tops_400m_sel",
++ netsys_tops_400m_parents, 0x0110, 0x114, 0x118, 8, 1, 15, 0x1c8, 7),
++ MUX_GATE_CLR_SET_UPD(CLK_TOP_NETSYS_PPEFB_250M_SEL, "netsys_ppefb_250m_sel",
++ pcie_mbist_250m_parents, 0x0110, 0x114, 0x118, 16, 1, 23, 0x1c8, 8),
++ MUX_GATE_CLR_SET_UPD(CLK_TOP_NETSYS_WARP_SEL, "netsys_warp_sel", netsys_parents, 0x0110,
++ 0x114, 0x118, 24, 2, 31, 0x1C8, 9),
++ /* CLK_CFG_18 */
++ MUX_GATE_CLR_SET_UPD(CLK_TOP_ETH_MII_SEL, "eth_mii_sel", eth_mii_parents, 0x0120, 0x124,
++ 0x128, 0, 1, 7, 0x1c8, 10),
++ MUX_GATE_CLR_SET_UPD(CLK_TOP_NPU_SEL, "ck_npu_sel", netsys_2x_parents, 0x0120, 0x124, 0x128,
++ 8, 2, 15, 0x1c8, 11),
++};
++
++static const struct mtk_composite top_aud_divs[] = {
++ DIV_GATE(CLK_TOP_AUD_I2S_M, "aud_i2s_m", "aud_sel", 0x0420, 0, 0x0420, 8, 8),
++};
++
++static const struct mtk_clk_desc topck_desc = {
++ .fixed_clks = top_fixed_clks,
++ .num_fixed_clks = ARRAY_SIZE(top_fixed_clks),
++ .factor_clks = top_divs,
++ .num_factor_clks = ARRAY_SIZE(top_divs),
++ .mux_clks = top_muxes,
++ .num_mux_clks = ARRAY_SIZE(top_muxes),
++ .composite_clks = top_aud_divs,
++ .num_composite_clks = ARRAY_SIZE(top_aud_divs),
++ .clk_lock = &mt7988_clk_lock,
++};
++
++static const char *const mcu_bus_div_parents[] = { "top_xtal", "ccipll2_b", "net1pll_d4" };
++
++static const char *const mcu_arm_div_parents[] = { "top_xtal", "arm_b", "net1pll_d4" };
++
++static struct mtk_composite mcu_muxes[] = {
++ /* bus_pll_divider_cfg */
++ MUX_GATE_FLAGS(CLK_MCU_BUS_DIV_SEL, "mcu_bus_div_sel", mcu_bus_div_parents, 0x7C0, 9, 2, -1,
++ CLK_IS_CRITICAL),
++ /* mp2_pll_divider_cfg */
++ MUX_GATE_FLAGS(CLK_MCU_ARM_DIV_SEL, "mcu_arm_div_sel", mcu_arm_div_parents, 0x7A8, 9, 2, -1,
++ CLK_IS_CRITICAL),
++};
++
++static const struct mtk_clk_desc mcusys_desc = {
++ .composite_clks = mcu_muxes,
++ .num_composite_clks = ARRAY_SIZE(mcu_muxes),
++};
++
++static const struct of_device_id of_match_clk_mt7988_topckgen[] = {
++ { .compatible = "mediatek,mt7988-topckgen", .data = &topck_desc },
++ { .compatible = "mediatek,mt7988-mcusys", .data = &mcusys_desc },
++ { /* sentinel */ }
++};
++MODULE_DEVICE_TABLE(of, of_match_clk_mt7988_topckgen);
++
++static struct platform_driver clk_mt7988_topckgen_drv = {
++ .probe = mtk_clk_simple_probe,
++ .remove = mtk_clk_simple_remove,
++ .driver = {
++ .name = "clk-mt7988-topckgen",
++ .of_match_table = of_match_clk_mt7988_topckgen,
++ },
++};
++module_platform_driver(clk_mt7988_topckgen_drv);
++MODULE_LICENSE("GPL");
+--- /dev/null
++++ b/drivers/clk/mediatek/clk-mt7988-xfipll.c
+@@ -0,0 +1,82 @@
++// SPDX-License-Identifier: GPL-2.0
++/*
++ * Copyright (c) 2023 Daniel Golle <daniel@makrotopia.org>
++ */
++
++#include <linux/clk-provider.h>
++#include <linux/of.h>
++#include <linux/of_address.h>
++#include <linux/of_device.h>
++#include <linux/platform_device.h>
++#include "clk-mtk.h"
++#include "clk-gate.h"
++#include <dt-bindings/clock/mediatek,mt7988-clk.h>
++
++/* Register to control USXGMII XFI PLL analog */
++#define XFI_PLL_ANA_GLB8 0x108
++#define RG_XFI_PLL_ANA_SWWA 0x02283248
++
++static const struct mtk_gate_regs xfipll_cg_regs = {
++ .set_ofs = 0x8,
++ .clr_ofs = 0x8,
++ .sta_ofs = 0x8,
++};
++
++#define GATE_XFIPLL(_id, _name, _parent, _shift) \
++ { \
++ .id = _id, \
++ .name = _name, \
++ .parent_name = _parent, \
++ .regs = &xfipll_cg_regs, \
++ .shift = _shift, \
++ .ops = &mtk_clk_gate_ops_no_setclr_inv, \
++ }
++
++static const struct mtk_fixed_factor xfipll_divs[] = {
++ FACTOR(CLK_XFIPLL_PLL, "xfipll_pll", "top_xtal", 125, 32),
++};
++
++static const struct mtk_gate xfipll_clks[] = {
++ GATE_XFIPLL(CLK_XFIPLL_PLL_EN, "xfipll_pll_en", "xfipll_pll", 31),
++};
++
++static const struct mtk_clk_desc xfipll_desc = {
++ .clks = xfipll_clks,
++ .num_clks = ARRAY_SIZE(xfipll_clks),
++ .factor_clks = xfipll_divs,
++ .num_factor_clks = ARRAY_SIZE(xfipll_divs),
++};
++
++static int clk_mt7988_xfipll_probe(struct platform_device *pdev)
++{
++ struct device_node *node = pdev->dev.of_node;
++ void __iomem *base = of_iomap(node, 0);
++
++ if (!base)
++ return -ENOMEM;
++
++ /* Apply software workaround for USXGMII PLL TCL issue */
++ writel(RG_XFI_PLL_ANA_SWWA, base + XFI_PLL_ANA_GLB8);
++ iounmap(base);
++
++ return mtk_clk_simple_probe(pdev);
++};
++
++static const struct of_device_id of_match_clk_mt7988_xfipll[] = {
++ { .compatible = "mediatek,mt7988-xfi-pll", .data = &xfipll_desc },
++ { /* sentinel */ }
++};
++MODULE_DEVICE_TABLE(of, of_match_clk_mt7988_xfipll);
++
++static struct platform_driver clk_mt7988_xfipll_drv = {
++ .driver = {
++ .name = "clk-mt7988-xfipll",
++ .of_match_table = of_match_clk_mt7988_xfipll,
++ },
++ .probe = clk_mt7988_xfipll_probe,
++ .remove = mtk_clk_simple_remove,
++};
++module_platform_driver(clk_mt7988_xfipll_drv);
++
++MODULE_DESCRIPTION("MediaTek MT7988 XFI PLL clock driver");
++MODULE_LICENSE("GPL");
--- /dev/null
+From 26ced94177b150710d94cf365002a09cc48950e9 Mon Sep 17 00:00:00 2001
+From: Frank Wunderlich <frank-w@public-files.de>
+Date: Wed, 17 Jan 2024 19:41:11 +0100
+Subject: [PATCH] clk: mediatek: add infracfg reset controller for mt7988
+
+Infracfg can also operate as reset controller, add support for it.
+
+Signed-off-by: Frank Wunderlich <frank-w@public-files.de>
+---
+ drivers/clk/mediatek/clk-mt7988-infracfg.c | 23 ++++++++++++++++++++++
+ 1 file changed, 23 insertions(+)
+
+--- a/drivers/clk/mediatek/clk-mt7988-infracfg.c
++++ b/drivers/clk/mediatek/clk-mt7988-infracfg.c
+@@ -14,6 +14,10 @@
+ #include "clk-gate.h"
+ #include "clk-mux.h"
+ #include <dt-bindings/clock/mediatek,mt7988-clk.h>
++#include <dt-bindings/reset/mediatek,mt7988-resets.h>
++
++#define MT7988_INFRA_RST0_SET_OFFSET 0x70
++#define MT7988_INFRA_RST1_SET_OFFSET 0x80
+
+ static DEFINE_SPINLOCK(mt7988_clk_lock);
+
+@@ -249,12 +253,31 @@ static const struct mtk_gate infra_clks[
+ GATE_INFRA3(CLK_INFRA_133M_PCIE_CK_P3, "infra_133m_pcie_ck_p3", "sysaxi_sel", 31),
+ };
+
++static u16 infra_rst_ofs[] = {
++ MT7988_INFRA_RST0_SET_OFFSET,
++ MT7988_INFRA_RST1_SET_OFFSET,
++};
++
++static u16 infra_idx_map[] = {
++ [MT7988_INFRA_RST0_PEXTP_MAC_SWRST] = 0 * RST_NR_PER_BANK + 6,
++ [MT7988_INFRA_RST1_THERM_CTRL_SWRST] = 1 * RST_NR_PER_BANK + 9,
++};
++
++static struct mtk_clk_rst_desc infra_rst_desc = {
++ .version = MTK_RST_SET_CLR,
++ .rst_bank_ofs = infra_rst_ofs,
++ .rst_bank_nr = ARRAY_SIZE(infra_rst_ofs),
++ .rst_idx_map = infra_idx_map,
++ .rst_idx_map_nr = ARRAY_SIZE(infra_idx_map),
++};
++
+ static const struct mtk_clk_desc infra_desc = {
+ .clks = infra_clks,
+ .num_clks = ARRAY_SIZE(infra_clks),
+ .mux_clks = infra_muxes,
+ .num_mux_clks = ARRAY_SIZE(infra_muxes),
+ .clk_lock = &mt7988_clk_lock,
++ .rst_desc = &infra_rst_desc,
+ };
+
+ static const struct of_device_id of_match_clk_mt7988_infracfg[] = {
--- /dev/null
+From 3c810da3206f2e52c92f9f15a87f05db4bbba734 Mon Sep 17 00:00:00 2001
+From: Frank Wunderlich <frank-w@public-files.de>
+Date: Wed, 17 Jan 2024 19:41:10 +0100
+Subject: [PATCH] dt-bindings: reset: mediatek: add MT7988 reset IDs
+
+Add reset constants for using as index in driver and dts.
+
+Signed-off-by: Frank Wunderlich <frank-w@public-files.de>
+---
+ include/dt-bindings/reset/mediatek,mt7988-resets.h | 6 ++++++
+ 1 file changed, 6 insertions(+)
+
+--- a/include/dt-bindings/reset/mediatek,mt7988-resets.h
++++ b/include/dt-bindings/reset/mediatek,mt7988-resets.h
+@@ -10,4 +10,10 @@
+ /* ETHWARP resets */
+ #define MT7988_ETHWARP_RST_SWITCH 0
+
++/* INFRA resets */
++#define MT7988_INFRA_RST0_PEXTP_MAC_SWRST 0
++#define MT7988_INFRA_RST1_THERM_CTRL_SWRST 1
++
++
+ #endif /* _DT_BINDINGS_RESET_CONTROLLER_MT7988 */
++
--- /dev/null
+From 137c9e08e5e542d58aa606b0bb4f0990117309a0 Mon Sep 17 00:00:00 2001
+From: Daniel Golle <daniel@makrotopia.org>
+Date: Mon, 20 Nov 2023 18:22:31 +0000
+Subject: [PATCH] watchdog: mediatek: mt7988: add wdt support
+
+Add support for watchdog and reset generator unit of the MediaTek
+MT7988 SoC.
+
+Signed-off-by: Daniel Golle <daniel@makrotopia.org>
+Reviewed-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
+Reviewed-by: Guenter Roeck <linux@roeck-us.net>
+Link: https://lore.kernel.org/r/c0cf5f701801cce60470853fa15f1d9dced78c4f.1700504385.git.daniel@makrotopia.org
+Signed-off-by: Guenter Roeck <linux@roeck-us.net>
+Signed-off-by: Wim Van Sebroeck <wim@linux-watchdog.org>
+---
+ drivers/watchdog/mtk_wdt.c | 42 ++++++++++++++++++++++++++++++++++++++
+ 1 file changed, 42 insertions(+)
+
+--- a/drivers/watchdog/mtk_wdt.c
++++ b/drivers/watchdog/mtk_wdt.c
+@@ -56,9 +56,13 @@
+ #define WDT_SWSYSRST 0x18U
+ #define WDT_SWSYS_RST_KEY 0x88000000
+
++#define WDT_SWSYSRST_EN 0xfc
++
+ #define DRV_NAME "mtk-wdt"
+ #define DRV_VERSION "1.0"
+
++#define MT7988_TOPRGU_SW_RST_NUM 24
++
+ static bool nowayout = WATCHDOG_NOWAYOUT;
+ static unsigned int timeout;
+
+@@ -68,10 +72,12 @@ struct mtk_wdt_dev {
+ spinlock_t lock; /* protects WDT_SWSYSRST reg */
+ struct reset_controller_dev rcdev;
+ bool disable_wdt_extrst;
++ bool has_swsysrst_en;
+ };
+
+ struct mtk_wdt_data {
+ int toprgu_sw_rst_num;
++ bool has_swsysrst_en;
+ };
+
+ static const struct mtk_wdt_data mt2712_data = {
+@@ -82,6 +88,11 @@ static const struct mtk_wdt_data mt7986_
+ .toprgu_sw_rst_num = MT7986_TOPRGU_SW_RST_NUM,
+ };
+
++static const struct mtk_wdt_data mt7988_data = {
++ .toprgu_sw_rst_num = MT7988_TOPRGU_SW_RST_NUM,
++ .has_swsysrst_en = true,
++};
++
+ static const struct mtk_wdt_data mt8183_data = {
+ .toprgu_sw_rst_num = MT8183_TOPRGU_SW_RST_NUM,
+ };
+@@ -98,6 +109,28 @@ static const struct mtk_wdt_data mt8195_
+ .toprgu_sw_rst_num = MT8195_TOPRGU_SW_RST_NUM,
+ };
+
++/**
++ * toprgu_reset_sw_en_unlocked() - enable/disable software control for reset bit
++ * @data: Pointer to instance of driver data.
++ * @id: Bit number identifying the reset to be enabled or disabled.
++ * @enable: If true, enable software control for that bit, disable otherwise.
++ *
++ * Context: The caller must hold lock of struct mtk_wdt_dev.
++ */
++static void toprgu_reset_sw_en_unlocked(struct mtk_wdt_dev *data,
++ unsigned long id, bool enable)
++{
++ u32 tmp;
++
++ tmp = readl(data->wdt_base + WDT_SWSYSRST_EN);
++ if (enable)
++ tmp |= BIT(id);
++ else
++ tmp &= ~BIT(id);
++
++ writel(tmp, data->wdt_base + WDT_SWSYSRST_EN);
++}
++
+ static int toprgu_reset_update(struct reset_controller_dev *rcdev,
+ unsigned long id, bool assert)
+ {
+@@ -108,6 +141,9 @@ static int toprgu_reset_update(struct re
+
+ spin_lock_irqsave(&data->lock, flags);
+
++ if (assert && data->has_swsysrst_en)
++ toprgu_reset_sw_en_unlocked(data, id, true);
++
+ tmp = readl(data->wdt_base + WDT_SWSYSRST);
+ if (assert)
+ tmp |= BIT(id);
+@@ -116,6 +152,9 @@ static int toprgu_reset_update(struct re
+ tmp |= WDT_SWSYS_RST_KEY;
+ writel(tmp, data->wdt_base + WDT_SWSYSRST);
+
++ if (!assert && data->has_swsysrst_en)
++ toprgu_reset_sw_en_unlocked(data, id, false);
++
+ spin_unlock_irqrestore(&data->lock, flags);
+
+ return 0;
+@@ -393,6 +432,8 @@ static int mtk_wdt_probe(struct platform
+ wdt_data->toprgu_sw_rst_num);
+ if (err)
+ return err;
++
++ mtk_wdt->has_swsysrst_en = wdt_data->has_swsysrst_en;
+ }
+
+ mtk_wdt->disable_wdt_extrst =
+@@ -427,6 +468,7 @@ static const struct of_device_id mtk_wdt
+ { .compatible = "mediatek,mt2712-wdt", .data = &mt2712_data },
+ { .compatible = "mediatek,mt6589-wdt" },
+ { .compatible = "mediatek,mt7986-wdt", .data = &mt7986_data },
++ { .compatible = "mediatek,mt7988-wdt", .data = &mt7988_data },
+ { .compatible = "mediatek,mt8183-wdt", .data = &mt8183_data },
+ { .compatible = "mediatek,mt8186-wdt", .data = &mt8186_data },
+ { .compatible = "mediatek,mt8192-wdt", .data = &mt8192_data },
--- /dev/null
+From c202f510bbaa34ab5d65a69a61e0e72761374b17 Mon Sep 17 00:00:00 2001
+From: Daniel Golle <daniel@makrotopia.org>
+Date: Mon, 11 Mar 2024 17:14:19 +0000
+Subject: [PATCH] clk: mediatek: mt7988-infracfg: fix clocks for 2nd PCIe port
+
+Due to what seems to be an undocumented oddity in MediaTek's MT7988
+SoC design the CLK_INFRA_PCIE_PERI_26M_CK_P2 clock requires
+CLK_INFRA_PCIE_PERI_26M_CK_P3 to be enabled.
+
+This currently leads to PCIe port 2 not working in Linux.
+
+Reflect the apparent relationship in the clk driver to make sure PCIe
+port 2 of the MT7988 SoC works.
+
+Suggested-by: Sam Shih <sam.shih@mediatek.com>
+Signed-off-by: Daniel Golle <daniel@makrotopia.org>
+---
+ drivers/clk/mediatek/clk-mt7988-infracfg.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/drivers/clk/mediatek/clk-mt7988-infracfg.c
++++ b/drivers/clk/mediatek/clk-mt7988-infracfg.c
+@@ -156,7 +156,7 @@ static const struct mtk_gate infra_clks[
+ GATE_INFRA0(CLK_INFRA_PCIE_PERI_26M_CK_P1, "infra_pcie_peri_ck_26m_ck_p1",
+ "csw_infra_f26m_sel", 8),
+ GATE_INFRA0(CLK_INFRA_PCIE_PERI_26M_CK_P2, "infra_pcie_peri_ck_26m_ck_p2",
+- "csw_infra_f26m_sel", 9),
++ "infra_pcie_peri_ck_26m_ck_p3", 9),
+ GATE_INFRA0(CLK_INFRA_PCIE_PERI_26M_CK_P3, "infra_pcie_peri_ck_26m_ck_p3",
+ "csw_infra_f26m_sel", 10),
+ /* INFRA1 */
--- /dev/null
+From 24e961b93d292d0dd6380213d22a071a99ea787d Mon Sep 17 00:00:00 2001
+From: Sam Shih <sam.shih@mediatek.com>
+Date: Tue, 25 Oct 2022 15:29:53 +0200
+Subject: [PATCH 1/6] mmc: mediatek: add support for MT7986 SoC
+
+Adding mt7986 own characteristics and of_device_id to have support
+of MT7986 SoC.
+
+Signed-off-by: Sam Shih <sam.shih@mediatek.com>
+Signed-off-by: Frank Wunderlich <frank-w@public-files.de>
+Reviewed-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
+Link: https://lore.kernel.org/r/20221025132953.81286-7-linux@fw-web.de
+Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>
+---
+ drivers/mmc/host/mtk-sd.c | 14 ++++++++++++++
+ 1 file changed, 14 insertions(+)
+
+--- a/drivers/mmc/host/mtk-sd.c
++++ b/drivers/mmc/host/mtk-sd.c
+@@ -552,6 +552,19 @@ static const struct mtk_mmc_compatible m
+ .support_64g = false,
+ };
+
++static const struct mtk_mmc_compatible mt7986_compat = {
++ .clk_div_bits = 12,
++ .recheck_sdio_irq = true,
++ .hs400_tune = false,
++ .pad_tune_reg = MSDC_PAD_TUNE0,
++ .async_fifo = true,
++ .data_tune = true,
++ .busy_check = true,
++ .stop_clk_fix = true,
++ .enhance_rx = true,
++ .support_64g = true,
++};
++
+ static const struct mtk_mmc_compatible mt8135_compat = {
+ .clk_div_bits = 8,
+ .recheck_sdio_irq = true,
+@@ -609,6 +622,7 @@ static const struct of_device_id msdc_of
+ { .compatible = "mediatek,mt6795-mmc", .data = &mt6795_compat},
+ { .compatible = "mediatek,mt7620-mmc", .data = &mt7620_compat},
+ { .compatible = "mediatek,mt7622-mmc", .data = &mt7622_compat},
++ { .compatible = "mediatek,mt7986-mmc", .data = &mt7986_compat},
+ { .compatible = "mediatek,mt8135-mmc", .data = &mt8135_compat},
+ { .compatible = "mediatek,mt8173-mmc", .data = &mt8173_compat},
+ { .compatible = "mediatek,mt8183-mmc", .data = &mt8183_compat},
--- /dev/null
+From 7b438d0377fbd520b475a68bdd9de1692393f22d Mon Sep 17 00:00:00 2001
+From: Mengqi Zhang <mengqi.zhang@mediatek.com>
+Date: Sun, 6 Nov 2022 11:39:24 +0800
+Subject: [PATCH 2/6] mmc: mtk-sd: add Inline Crypto Engine clock control
+
+Add crypto clock control and ungate it before CQHCI init.
+
+Signed-off-by: Mengqi Zhang <mengqi.zhang@mediatek.com>
+Reviewed-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
+Link: https://lore.kernel.org/r/20221106033924.9854-2-mengqi.zhang@mediatek.com
+Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>
+---
+ drivers/mmc/host/mtk-sd.c | 12 ++++++++++++
+ 1 file changed, 12 insertions(+)
+
+--- a/drivers/mmc/host/mtk-sd.c
++++ b/drivers/mmc/host/mtk-sd.c
+@@ -452,6 +452,7 @@ struct msdc_host {
+ struct clk *bus_clk; /* bus clock which used to access register */
+ struct clk *src_clk_cg; /* msdc source clock control gate */
+ struct clk *sys_clk_cg; /* msdc subsys clock control gate */
++ struct clk *crypto_clk; /* msdc crypto clock control gate */
+ struct clk_bulk_data bulk_clks[MSDC_NR_CLOCKS];
+ u32 mclk; /* mmc subsystem clock frequency */
+ u32 src_clk_freq; /* source clock frequency */
+@@ -840,6 +841,7 @@ static void msdc_set_busy_timeout(struct
+ static void msdc_gate_clock(struct msdc_host *host)
+ {
+ clk_bulk_disable_unprepare(MSDC_NR_CLOCKS, host->bulk_clks);
++ clk_disable_unprepare(host->crypto_clk);
+ clk_disable_unprepare(host->src_clk_cg);
+ clk_disable_unprepare(host->src_clk);
+ clk_disable_unprepare(host->bus_clk);
+@@ -855,6 +857,7 @@ static int msdc_ungate_clock(struct msdc
+ clk_prepare_enable(host->bus_clk);
+ clk_prepare_enable(host->src_clk);
+ clk_prepare_enable(host->src_clk_cg);
++ clk_prepare_enable(host->crypto_clk);
+ ret = clk_bulk_prepare_enable(MSDC_NR_CLOCKS, host->bulk_clks);
+ if (ret) {
+ dev_err(host->dev, "Cannot enable pclk/axi/ahb clock gates\n");
+@@ -2670,6 +2673,15 @@ static int msdc_drv_probe(struct platfor
+ goto host_free;
+ }
+
++ /* only eMMC has crypto property */
++ if (!(mmc->caps2 & MMC_CAP2_NO_MMC)) {
++ host->crypto_clk = devm_clk_get_optional(&pdev->dev, "crypto");
++ if (IS_ERR(host->crypto_clk))
++ host->crypto_clk = NULL;
++ else
++ mmc->caps2 |= MMC_CAP2_CRYPTO;
++ }
++
+ host->irq = platform_get_irq(pdev, 0);
+ if (host->irq < 0) {
+ ret = host->irq;
--- /dev/null
+From 4b323f02b6e8df1b04292635ef829e7f723bf50e Mon Sep 17 00:00:00 2001
+From: Yu Zhe <yuzhe@nfschina.com>
+Date: Thu, 10 Nov 2022 15:28:19 +0800
+Subject: [PATCH 3/6] mmc: mtk-sd: fix two spelling mistakes in comment
+
+spelling mistake fix : "alreay" -> "already"
+ "checksume" -> "checksum"
+
+Signed-off-by: Yu Zhe <yuzhe@nfschina.com>
+Reviewed-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
+Link: https://lore.kernel.org/r/20221110072819.11530-1-yuzhe@nfschina.com
+Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>
+---
+ drivers/mmc/host/mtk-sd.c | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+--- a/drivers/mmc/host/mtk-sd.c
++++ b/drivers/mmc/host/mtk-sd.c
+@@ -750,7 +750,7 @@ static inline void msdc_dma_setup(struct
+ else
+ bd[j].bd_info &= ~BDMA_DESC_EOL;
+
+- /* checksume need to clear first */
++ /* checksum need to clear first */
+ bd[j].bd_info &= ~BDMA_DESC_CHECKSUM;
+ bd[j].bd_info |= msdc_dma_calcs((u8 *)(&bd[j]), 16) << 8;
+ }
+@@ -1229,7 +1229,7 @@ static bool msdc_cmd_done(struct msdc_ho
+ !host->hs400_tuning))
+ /*
+ * should not clear fifo/interrupt as the tune data
+- * may have alreay come when cmd19/cmd21 gets response
++ * may have already come when cmd19/cmd21 gets response
+ * CRC error.
+ */
+ msdc_reset_hw(host);
--- /dev/null
+From b98e7e8daf0ebab9dcc36812378a71e1be0b5089 Mon Sep 17 00:00:00 2001
+From: ChanWoo Lee <cw9316.lee@samsung.com>
+Date: Thu, 24 Nov 2022 17:00:31 +0900
+Subject: [PATCH 4/6] mmc: Avoid open coding by using mmc_op_tuning()
+
+Replace code with the already defined function. No functional changes.
+
+Signed-off-by: ChanWoo Lee <cw9316.lee@samsung.com>
+Reviewed-by: Adrian Hunter <adrian.hunter@intel.com>
+Link: https://lore.kernel.org/r/20221124080031.14690-1-cw9316.lee@samsung.com
+Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>
+---
+ drivers/mmc/host/mtk-sd.c | 8 ++------
+ 1 file changed, 2 insertions(+), 6 deletions(-)
+
+--- a/drivers/mmc/host/mtk-sd.c
++++ b/drivers/mmc/host/mtk-sd.c
+@@ -1224,9 +1224,7 @@ static bool msdc_cmd_done(struct msdc_ho
+
+ if (!sbc_error && !(events & MSDC_INT_CMDRDY)) {
+ if (events & MSDC_INT_CMDTMO ||
+- (cmd->opcode != MMC_SEND_TUNING_BLOCK &&
+- cmd->opcode != MMC_SEND_TUNING_BLOCK_HS200 &&
+- !host->hs400_tuning))
++ (!mmc_op_tuning(cmd->opcode) && !host->hs400_tuning))
+ /*
+ * should not clear fifo/interrupt as the tune data
+ * may have already come when cmd19/cmd21 gets response
+@@ -1320,9 +1318,7 @@ static void msdc_cmd_next(struct msdc_ho
+ {
+ if ((cmd->error &&
+ !(cmd->error == -EILSEQ &&
+- (cmd->opcode == MMC_SEND_TUNING_BLOCK ||
+- cmd->opcode == MMC_SEND_TUNING_BLOCK_HS200 ||
+- host->hs400_tuning))) ||
++ (mmc_op_tuning(cmd->opcode) || host->hs400_tuning))) ||
+ (mrq->sbc && mrq->sbc->error))
+ msdc_request_done(host, mrq);
+ else if (cmd == mrq->sbc)
--- /dev/null
+--- a/drivers/mtd/nand/spi/core.c
++++ b/drivers/mtd/nand/spi/core.c
+@@ -19,6 +19,7 @@
+ #include <linux/string.h>
+ #include <linux/spi/spi.h>
+ #include <linux/spi/spi-mem.h>
++#include <linux/mtd/mtk_bmt.h>
+
+ static int spinand_read_reg_op(struct spinand_device *spinand, u8 reg, u8 *val)
+ {
+@@ -1344,6 +1345,7 @@ static int spinand_probe(struct spi_mem
+ if (ret)
+ return ret;
+
++ mtk_bmt_attach(mtd);
+ ret = mtd_device_register(mtd, NULL, 0);
+ if (ret)
+ goto err_spinand_cleanup;
+@@ -1351,6 +1353,7 @@ static int spinand_probe(struct spi_mem
+ return 0;
+
+ err_spinand_cleanup:
++ mtk_bmt_detach(mtd);
+ spinand_cleanup(spinand);
+
+ return ret;
+@@ -1369,6 +1372,7 @@ static int spinand_remove(struct spi_mem
+ if (ret)
+ return ret;
+
++ mtk_bmt_detach(mtd);
+ spinand_cleanup(spinand);
+
+ return 0;
--- /dev/null
+--- a/arch/arm64/boot/dts/mediatek/mt7622-rfb1.dts
++++ b/arch/arm64/boot/dts/mediatek/mt7622-rfb1.dts
+@@ -548,6 +548,7 @@
+ spi-tx-bus-width = <4>;
+ spi-rx-bus-width = <4>;
+ nand-ecc-engine = <&snfi>;
++ mediatek,bmt-v2;
+
+ partitions {
+ compatible = "fixed-partitions";
--- /dev/null
+From 5f49a5c9b16330e0df8f639310e4715dcad71947 Mon Sep 17 00:00:00 2001
+From: Davide Fioravanti <pantanastyle@gmail.com>
+Date: Fri, 8 Jan 2021 15:35:24 +0100
+Subject: [PATCH] mtd: spinand: Add support for the Fidelix FM35X1GA
+
+Datasheet: http://www.hobos.com.cn/upload/datasheet/DS35X1GAXXX_100_rev00.pdf
+
+Signed-off-by: Davide Fioravanti <pantanastyle@gmail.com>
+---
+ drivers/mtd/nand/spi/Makefile | 2 +-
+ drivers/mtd/nand/spi/core.c | 1 +
+ drivers/mtd/nand/spi/fidelix.c | 76 ++++++++++++++++++++++++++++++++++
+ include/linux/mtd/spinand.h | 1 +
+ 4 files changed, 79 insertions(+), 1 deletion(-)
+ create mode 100644 drivers/mtd/nand/spi/fidelix.c
+
+--- a/drivers/mtd/nand/spi/Makefile
++++ b/drivers/mtd/nand/spi/Makefile
+@@ -1,3 +1,3 @@
+ # SPDX-License-Identifier: GPL-2.0
+-spinand-objs := core.o ato.o esmt.o etron.o gigadevice.o macronix.o micron.o paragon.o toshiba.o winbond.o xtx.o
++spinand-objs := core.o ato.o esmt.o etron.o fidelix.o gigadevice.o macronix.o micron.o paragon.o toshiba.o winbond.o xtx.o
+ obj-$(CONFIG_MTD_SPI_NAND) += spinand.o
+--- a/drivers/mtd/nand/spi/core.c
++++ b/drivers/mtd/nand/spi/core.c
+@@ -940,6 +940,7 @@ static const struct nand_ops spinand_ops
+ static const struct spinand_manufacturer *spinand_manufacturers[] = {
+ &ato_spinand_manufacturer,
+ &esmt_c8_spinand_manufacturer,
++ &fidelix_spinand_manufacturer,
+ &etron_spinand_manufacturer,
+ &gigadevice_spinand_manufacturer,
+ ¯onix_spinand_manufacturer,
+--- /dev/null
++++ b/drivers/mtd/nand/spi/fidelix.c
+@@ -0,0 +1,76 @@
++// SPDX-License-Identifier: GPL-2.0
++/*
++ * Copyright (c) 2020 Davide Fioravanti <pantanastyle@gmail.com>
++ */
++
++#include <linux/device.h>
++#include <linux/kernel.h>
++#include <linux/mtd/spinand.h>
++
++#define SPINAND_MFR_FIDELIX 0xE5
++#define FIDELIX_ECCSR_MASK 0x0F
++
++static SPINAND_OP_VARIANTS(read_cache_variants,
++ SPINAND_PAGE_READ_FROM_CACHE_X4_OP(0, 1, NULL, 0),
++ SPINAND_PAGE_READ_FROM_CACHE_OP(true, 0, 1, NULL, 0),
++ SPINAND_PAGE_READ_FROM_CACHE_OP(false, 0, 1, NULL, 0));
++
++static SPINAND_OP_VARIANTS(write_cache_variants,
++ SPINAND_PROG_LOAD_X4(true, 0, NULL, 0),
++ SPINAND_PROG_LOAD(true, 0, NULL, 0));
++
++static SPINAND_OP_VARIANTS(update_cache_variants,
++ SPINAND_PROG_LOAD_X4(false, 0, NULL, 0),
++ SPINAND_PROG_LOAD(false, 0, NULL, 0));
++
++static int fm35x1ga_ooblayout_ecc(struct mtd_info *mtd, int section,
++ struct mtd_oob_region *region)
++{
++ if (section > 3)
++ return -ERANGE;
++
++ region->offset = (16 * section) + 8;
++ region->length = 8;
++
++ return 0;
++}
++
++static int fm35x1ga_ooblayout_free(struct mtd_info *mtd, int section,
++ struct mtd_oob_region *region)
++{
++ if (section > 3)
++ return -ERANGE;
++
++ region->offset = (16 * section) + 2;
++ region->length = 6;
++
++ return 0;
++}
++
++static const struct mtd_ooblayout_ops fm35x1ga_ooblayout = {
++ .ecc = fm35x1ga_ooblayout_ecc,
++ .free = fm35x1ga_ooblayout_free,
++};
++
++static const struct spinand_info fidelix_spinand_table[] = {
++ SPINAND_INFO("FM35X1GA",
++ SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x71),
++ NAND_MEMORG(1, 2048, 64, 64, 1024, 20, 1, 1, 1),
++ NAND_ECCREQ(4, 512),
++ SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
++ &write_cache_variants,
++ &update_cache_variants),
++ SPINAND_HAS_QE_BIT,
++ SPINAND_ECCINFO(&fm35x1ga_ooblayout, NULL)),
++};
++
++static const struct spinand_manufacturer_ops fidelix_spinand_manuf_ops = {
++};
++
++const struct spinand_manufacturer fidelix_spinand_manufacturer = {
++ .id = SPINAND_MFR_FIDELIX,
++ .name = "Fidelix",
++ .chips = fidelix_spinand_table,
++ .nchips = ARRAY_SIZE(fidelix_spinand_table),
++ .ops = &fidelix_spinand_manuf_ops,
++};
+--- a/include/linux/mtd/spinand.h
++++ b/include/linux/mtd/spinand.h
+@@ -263,6 +263,7 @@ struct spinand_manufacturer {
+ extern const struct spinand_manufacturer ato_spinand_manufacturer;
+ extern const struct spinand_manufacturer esmt_c8_spinand_manufacturer;
+ extern const struct spinand_manufacturer etron_spinand_manufacturer;
++extern const struct spinand_manufacturer fidelix_spinand_manufacturer;
+ extern const struct spinand_manufacturer gigadevice_spinand_manufacturer;
+ extern const struct spinand_manufacturer macronix_spinand_manufacturer;
+ extern const struct spinand_manufacturer micron_spinand_manufacturer;
--- /dev/null
+From 4983a1517e7ddbc6f53fc07607e4ebeb51412843 Mon Sep 17 00:00:00 2001
+From: Sam Shih <sam.shih@mediatek.com>
+Date: Tue, 28 Feb 2023 19:59:22 +0800
+Subject: [PATCH 21/21] cpufreq: mediatek: Add support for MT7988
+
+This add cpufreq support for mediatek MT7988 SoC.
+
+The platform data of MT7988 is different from previous MediaTek SoCs,
+so we add a new compatible and platform data for it.
+
+Signed-off-by: Sam Shih <sam.shih@mediatek.com>
+---
+ drivers/cpufreq/mediatek-cpufreq.c | 10 ++++++++++
+ 1 file changed, 10 insertions(+)
+
+--- a/drivers/cpufreq/mediatek-cpufreq.c
++++ b/drivers/cpufreq/mediatek-cpufreq.c
+@@ -709,6 +709,15 @@ static const struct mtk_cpufreq_platform
+ .ccifreq_supported = false,
+ };
+
++static const struct mtk_cpufreq_platform_data mt7988_platform_data = {
++ .min_volt_shift = 100000,
++ .max_volt_shift = 200000,
++ .proc_max_volt = 900000,
++ .sram_min_volt = 0,
++ .sram_max_volt = 1150000,
++ .ccifreq_supported = true,
++};
++
+ static const struct mtk_cpufreq_platform_data mt8183_platform_data = {
+ .min_volt_shift = 100000,
+ .max_volt_shift = 200000,
+@@ -742,6 +751,7 @@ static const struct of_device_id mtk_cpu
+ { .compatible = "mediatek,mt2712", .data = &mt2701_platform_data },
+ { .compatible = "mediatek,mt7622", .data = &mt7622_platform_data },
+ { .compatible = "mediatek,mt7623", .data = &mt7623_platform_data },
++ { .compatible = "mediatek,mt7988", .data = &mt7988_platform_data },
+ { .compatible = "mediatek,mt8167", .data = &mt8516_platform_data },
+ { .compatible = "mediatek,mt817x", .data = &mt2701_platform_data },
+ { .compatible = "mediatek,mt8173", .data = &mt2701_platform_data },
--- /dev/null
+--- a/drivers/pinctrl/mediatek/pinctrl-mtk-common-v2.c
++++ b/drivers/pinctrl/mediatek/pinctrl-mtk-common-v2.c
+@@ -601,6 +601,30 @@ out:
+ return err;
+ }
+
++static int mtk_pinconf_bias_set_pd(struct mtk_pinctrl *hw,
++ const struct mtk_pin_desc *desc,
++ u32 pullup, u32 arg)
++{
++ int err, pd;
++
++ if (arg == MTK_DISABLE)
++ pd = 0;
++ else if ((arg == MTK_ENABLE) && pullup)
++ pd = 0;
++ else if ((arg == MTK_ENABLE) && !pullup)
++ pd = 1;
++ else {
++ err = -EINVAL;
++ goto out;
++ }
++
++ err = mtk_hw_set_value(hw, desc, PINCTRL_PIN_REG_PD, pd);
++
++out:
++ return err;
++
++}
++
+ static int mtk_pinconf_bias_set_pullsel_pullen(struct mtk_pinctrl *hw,
+ const struct mtk_pin_desc *desc,
+ u32 pullup, u32 arg)
+@@ -755,6 +779,12 @@ int mtk_pinconf_bias_set_combo(struct mt
+ return err;
+ }
+
++ if (try_all_type & MTK_PULL_PD_TYPE) {
++ err = mtk_pinconf_bias_set_pd(hw, desc, pullup, arg);
++ if (!err)
++ return err;
++ }
++
+ if (try_all_type & MTK_PULL_PU_PD_TYPE) {
+ err = mtk_pinconf_bias_set_pu_pd(hw, desc, pullup, arg);
+ if (!err)
+@@ -875,6 +905,29 @@ out:
+ return err;
+ }
+
++static int mtk_pinconf_bias_get_pd(struct mtk_pinctrl *hw,
++ const struct mtk_pin_desc *desc,
++ u32 *pullup, u32 *enable)
++{
++ int err, pd;
++
++ err = mtk_hw_get_value(hw, desc, PINCTRL_PIN_REG_PD, &pd);
++ if (err)
++ goto out;
++
++ if (pd == 0) {
++ *pullup = 0;
++ *enable = MTK_DISABLE;
++ } else if (pd == 1) {
++ *pullup = 0;
++ *enable = MTK_ENABLE;
++ } else
++ err = -EINVAL;
++
++out:
++ return err;
++}
++
+ static int mtk_pinconf_bias_get_pullsel_pullen(struct mtk_pinctrl *hw,
+ const struct mtk_pin_desc *desc,
+ u32 *pullup, u32 *enable)
+@@ -943,6 +996,12 @@ int mtk_pinconf_bias_get_combo(struct mt
+ if (!err)
+ return err;
+ }
++
++ if (try_all_type & MTK_PULL_PD_TYPE) {
++ err = mtk_pinconf_bias_get_pd(hw, desc, pullup, enable);
++ if (!err)
++ return err;
++ }
+
+ if (try_all_type & MTK_PULL_PU_PD_TYPE) {
+ err = mtk_pinconf_bias_get_pu_pd(hw, desc, pullup, enable);
+--- a/drivers/pinctrl/mediatek/pinctrl-mtk-common-v2.h
++++ b/drivers/pinctrl/mediatek/pinctrl-mtk-common-v2.h
+@@ -24,6 +24,7 @@
+ * turned on/off itself. But it can't be selected pull up/down
+ */
+ #define MTK_PULL_RSEL_TYPE BIT(3)
++#define MTK_PULL_PD_TYPE BIT(4)
+ /* MTK_PULL_PU_PD_RSEL_TYPE is a type which is controlled by
+ * MTK_PULL_PU_PD_TYPE and MTK_PULL_RSEL_TYPE.
+ */
--- /dev/null
+--- a/drivers/crypto/inside-secure/safexcel.c
++++ b/drivers/crypto/inside-secure/safexcel.c
+@@ -600,6 +600,14 @@ static int safexcel_hw_init(struct safex
+ val |= EIP197_MST_CTRL_TX_MAX_CMD(5);
+ writel(val, EIP197_HIA_AIC(priv) + EIP197_HIA_MST_CTRL);
+ }
++ /*
++ * Set maximum number of TX commands to 2^4 = 16 for EIP97 HW2.1/HW2.3
++ */
++ else {
++ val = 0;
++ val |= EIP97_MST_CTRL_TX_MAX_CMD(4);
++ writel(val, EIP197_HIA_AIC(priv) + EIP197_HIA_MST_CTRL);
++ }
+
+ /* Configure wr/rd cache values */
+ writel(EIP197_MST_CTRL_RD_CACHE(RD_CACHE_4BITS) |
+--- a/drivers/crypto/inside-secure/safexcel.h
++++ b/drivers/crypto/inside-secure/safexcel.h
+@@ -315,6 +315,7 @@
+ #define EIP197_MST_CTRL_RD_CACHE(n) (((n) & 0xf) << 0)
+ #define EIP197_MST_CTRL_WD_CACHE(n) (((n) & 0xf) << 4)
+ #define EIP197_MST_CTRL_TX_MAX_CMD(n) (((n) & 0xf) << 20)
++#define EIP97_MST_CTRL_TX_MAX_CMD(n) (((n) & 0xf) << 4)
+ #define EIP197_MST_CTRL_BYTE_SWAP BIT(24)
+ #define EIP197_MST_CTRL_NO_BYTE_SWAP BIT(25)
+ #define EIP197_MST_CTRL_BYTE_SWAP_BITS GENMASK(25, 24)
--- /dev/null
+--- a/drivers/crypto/inside-secure/safexcel.h
++++ b/drivers/crypto/inside-secure/safexcel.h
+@@ -737,6 +737,9 @@ enum safexcel_eip_version {
+ /* Priority we use for advertising our algorithms */
+ #define SAFEXCEL_CRA_PRIORITY 300
+
++/* System cache line size */
++#define SYSTEM_CACHELINE_SIZE 64
++
+ /* SM3 digest result for zero length message */
+ #define EIP197_SM3_ZEROM_HASH "\x1A\xB2\x1D\x83\x55\xCF\xA1\x7F" \
+ "\x8E\x61\x19\x48\x31\xE8\x1A\x8F" \
+--- a/drivers/crypto/inside-secure/safexcel_hash.c
++++ b/drivers/crypto/inside-secure/safexcel_hash.c
+@@ -55,9 +55,9 @@ struct safexcel_ahash_req {
+ u8 block_sz; /* block size, only set once */
+ u8 digest_sz; /* output digest size, only set once */
+ __le32 state[SHA3_512_BLOCK_SIZE /
+- sizeof(__le32)] __aligned(sizeof(__le32));
++ sizeof(__le32)] __aligned(SYSTEM_CACHELINE_SIZE);
+
+- u64 len;
++ u64 len __aligned(SYSTEM_CACHELINE_SIZE);
+ u64 processed;
+
+ u8 cache[HASH_CACHE_SIZE] __aligned(sizeof(u32));
--- /dev/null
+From f1da27b7c4191f78ed81d3dabf64c769f896296c Mon Sep 17 00:00:00 2001
+From: "Mingming.Su" <Mingming.Su@mediatek.com>
+Date: Sat, 8 Oct 2022 18:45:53 +0200
+Subject: [PATCH] hwrng: mtk - add mt7986 support
+
+1. Add trng compatible name for MT7986
+2. Fix mtk_rng_wait_ready() function
+
+Signed-off-by: Mingming.Su <Mingming.Su@mediatek.com>
+Signed-off-by: Frank Wunderlich <frank-w@public-files.de>
+Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
+---
+ drivers/char/hw_random/mtk-rng.c | 5 +++--
+ 1 file changed, 3 insertions(+), 2 deletions(-)
+
+--- a/drivers/char/hw_random/mtk-rng.c
++++ b/drivers/char/hw_random/mtk-rng.c
+@@ -22,7 +22,7 @@
+ #define RNG_AUTOSUSPEND_TIMEOUT 100
+
+ #define USEC_POLL 2
+-#define TIMEOUT_POLL 20
++#define TIMEOUT_POLL 60
+
+ #define RNG_CTRL 0x00
+ #define RNG_EN BIT(0)
+@@ -77,7 +77,7 @@ static bool mtk_rng_wait_ready(struct hw
+ readl_poll_timeout_atomic(priv->base + RNG_CTRL, ready,
+ ready & RNG_READY, USEC_POLL,
+ TIMEOUT_POLL);
+- return !!ready;
++ return !!(ready & RNG_READY);
+ }
+
+ static int mtk_rng_read(struct hwrng *rng, void *buf, size_t max, bool wait)
+@@ -179,6 +179,7 @@ static const struct dev_pm_ops mtk_rng_p
+ #endif /* CONFIG_PM */
+
+ static const struct of_device_id mtk_rng_match[] = {
++ { .compatible = "mediatek,mt7986-rng" },
+ { .compatible = "mediatek,mt7623-rng" },
+ {},
+ };
--- /dev/null
+--- a/drivers/tty/serial/8250/8250.h
++++ b/drivers/tty/serial/8250/8250.h
+@@ -86,6 +86,7 @@ struct serial8250_config {
+ * STOP PARITY EPAR SPAR WLEN5 WLEN6
+ */
+ #define UART_CAP_NOTEMT BIT(18) /* UART without interrupt on TEMT available */
++#define UART_CAP_NMOD BIT(19) /* UART doesn't do termios */
+
+ #define UART_BUG_QUOT BIT(0) /* UART has buggy quot LSB */
+ #define UART_BUG_TXEN BIT(1) /* UART has buggy TX IIR status */
+--- a/drivers/tty/serial/8250/8250_port.c
++++ b/drivers/tty/serial/8250/8250_port.c
+@@ -287,7 +287,7 @@ static const struct serial8250_config ua
+ .tx_loadsz = 16,
+ .fcr = UART_FCR_ENABLE_FIFO |
+ UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT,
+- .flags = UART_CAP_FIFO,
++ .flags = UART_CAP_FIFO | UART_CAP_NMOD,
+ },
+ [PORT_NPCM] = {
+ .name = "Nuvoton 16550",
+@@ -2773,6 +2773,11 @@ serial8250_do_set_termios(struct uart_po
+ unsigned long flags;
+ unsigned int baud, quot, frac = 0;
+
++ if (up->capabilities & UART_CAP_NMOD) {
++ termios->c_cflag = 0;
++ return;
++ }
++
+ if (up->capabilities & UART_CAP_MINI) {
+ termios->c_cflag &= ~(CSTOPB | PARENB | PARODD | CMSPAR);
+ if ((termios->c_cflag & CSIZE) == CS5 ||
--- /dev/null
+From bfd3acc428085742d754a6d328d1a93ebf9451df Mon Sep 17 00:00:00 2001
+From: "SkyLake.Huang" <skylake.huang@mediatek.com>
+Date: Thu, 23 Jun 2022 18:29:51 +0800
+Subject: [PATCH 1/6] drivers: spi-mt65xx: Move chip_config to driver's private
+ data
+
+Signed-off-by: SkyLake.Huang <skylake.huang@mediatek.com>
+---
+ drivers/spi/spi-mt65xx.c | 29 +++++++++---------------
+ include/linux/platform_data/spi-mt65xx.h | 17 --------------
+ 2 files changed, 11 insertions(+), 35 deletions(-)
+ delete mode 100644 include/linux/platform_data/spi-mt65xx.h
+
+--- a/drivers/spi/spi-mt65xx.c
++++ b/drivers/spi/spi-mt65xx.c
+@@ -14,7 +14,6 @@
+ #include <linux/of.h>
+ #include <linux/gpio/consumer.h>
+ #include <linux/platform_device.h>
+-#include <linux/platform_data/spi-mt65xx.h>
+ #include <linux/pm_runtime.h>
+ #include <linux/spi/spi.h>
+ #include <linux/spi/spi-mem.h>
+@@ -171,6 +170,8 @@ struct mtk_spi {
+ struct device *dev;
+ dma_addr_t tx_dma;
+ dma_addr_t rx_dma;
++ u32 sample_sel;
++ u32 get_tick_dly;
+ };
+
+ static const struct mtk_spi_compatible mtk_common_compat;
+@@ -216,15 +217,6 @@ static const struct mtk_spi_compatible m
+ .no_need_unprepare = true,
+ };
+
+-/*
+- * A piece of default chip info unless the platform
+- * supplies it.
+- */
+-static const struct mtk_chip_config mtk_default_chip_info = {
+- .sample_sel = 0,
+- .tick_delay = 0,
+-};
+-
+ static const struct of_device_id mtk_spi_of_match[] = {
+ { .compatible = "mediatek,spi-ipm",
+ .data = (void *)&mtk_ipm_compat,
+@@ -352,7 +344,6 @@ static int mtk_spi_hw_init(struct spi_ma
+ {
+ u16 cpha, cpol;
+ u32 reg_val;
+- struct mtk_chip_config *chip_config = spi->controller_data;
+ struct mtk_spi *mdata = spi_master_get_devdata(master);
+
+ cpha = spi->mode & SPI_CPHA ? 1 : 0;
+@@ -402,7 +393,7 @@ static int mtk_spi_hw_init(struct spi_ma
+ else
+ reg_val &= ~SPI_CMD_CS_POL;
+
+- if (chip_config->sample_sel)
++ if (mdata->sample_sel)
+ reg_val |= SPI_CMD_SAMPLE_SEL;
+ else
+ reg_val &= ~SPI_CMD_SAMPLE_SEL;
+@@ -429,20 +420,20 @@ static int mtk_spi_hw_init(struct spi_ma
+ if (mdata->dev_comp->ipm_design) {
+ reg_val = readl(mdata->base + SPI_CMD_REG);
+ reg_val &= ~SPI_CMD_IPM_GET_TICKDLY_MASK;
+- reg_val |= ((chip_config->tick_delay & 0x7)
++ reg_val |= ((mdata->get_tick_dly & 0x7)
+ << SPI_CMD_IPM_GET_TICKDLY_OFFSET);
+ writel(reg_val, mdata->base + SPI_CMD_REG);
+ } else {
+ reg_val = readl(mdata->base + SPI_CFG1_REG);
+ reg_val &= ~SPI_CFG1_GET_TICK_DLY_MASK;
+- reg_val |= ((chip_config->tick_delay & 0x7)
++ reg_val |= ((mdata->get_tick_dly & 0x7)
+ << SPI_CFG1_GET_TICK_DLY_OFFSET);
+ writel(reg_val, mdata->base + SPI_CFG1_REG);
+ }
+ } else {
+ reg_val = readl(mdata->base + SPI_CFG1_REG);
+ reg_val &= ~SPI_CFG1_GET_TICK_DLY_MASK_V1;
+- reg_val |= ((chip_config->tick_delay & 0x3)
++ reg_val |= ((mdata->get_tick_dly & 0x3)
+ << SPI_CFG1_GET_TICK_DLY_OFFSET_V1);
+ writel(reg_val, mdata->base + SPI_CFG1_REG);
+ }
+@@ -732,9 +723,6 @@ static int mtk_spi_setup(struct spi_devi
+ {
+ struct mtk_spi *mdata = spi_master_get_devdata(spi->master);
+
+- if (!spi->controller_data)
+- spi->controller_data = (void *)&mtk_default_chip_info;
+-
+ if (mdata->dev_comp->need_pad_sel && spi->cs_gpiod)
+ /* CS de-asserted, gpiolib will handle inversion */
+ gpiod_direction_output(spi->cs_gpiod, 0);
+@@ -1138,6 +1126,10 @@ static int mtk_spi_probe(struct platform
+ mdata = spi_master_get_devdata(master);
+ mdata->dev_comp = device_get_match_data(dev);
+
++ /* Set device configs to default first. Calibrate it later. */
++ mdata->sample_sel = 0;
++ mdata->get_tick_dly = 2;
++
+ if (mdata->dev_comp->enhance_timing)
+ master->mode_bits |= SPI_CS_HIGH;
+
+--- a/include/linux/platform_data/spi-mt65xx.h
++++ /dev/null
+@@ -1,17 +0,0 @@
+-/* SPDX-License-Identifier: GPL-2.0-only */
+-/*
+- * MTK SPI bus driver definitions
+- *
+- * Copyright (c) 2015 MediaTek Inc.
+- * Author: Leilk Liu <leilk.liu@mediatek.com>
+- */
+-
+-#ifndef ____LINUX_PLATFORM_DATA_SPI_MTK_H
+-#define ____LINUX_PLATFORM_DATA_SPI_MTK_H
+-
+-/* Board specific platform_data */
+-struct mtk_chip_config {
+- u32 sample_sel;
+- u32 tick_delay;
+-};
+-#endif
--- /dev/null
+From 2ade0172154e50c8a2bfd8634c6eff943cffea29 Mon Sep 17 00:00:00 2001
+From: "SkyLake.Huang" <skylake.huang@mediatek.com>
+Date: Thu, 23 Jun 2022 18:35:52 +0800
+Subject: [PATCH 2/6] drivers: spi: Add support for dynamic calibration
+
+Signed-off-by: SkyLake.Huang <skylake.huang@mediatek.com>
+---
+ drivers/spi/spi.c | 137 ++++++++++++++++++++++++++++++++++++++++
+ include/linux/spi/spi.h | 42 ++++++++++++
+ 2 files changed, 179 insertions(+)
+
+--- a/drivers/spi/spi.c
++++ b/drivers/spi/spi.c
+@@ -1385,6 +1385,70 @@ static int spi_transfer_wait(struct spi_
+ return 0;
+ }
+
++int spi_do_calibration(struct spi_controller *ctlr, struct spi_device *spi,
++ int (*cal_read)(void *priv, u32 *addr, int addrlen, u8 *buf, int readlen), void *drv_priv)
++{
++ int datalen = ctlr->cal_rule->datalen;
++ int addrlen = ctlr->cal_rule->addrlen;
++ u8 *buf;
++ int ret;
++ int i;
++ struct list_head *cal_head, *listptr;
++ struct spi_cal_target *target;
++
++ /* Calculate calibration result */
++ int hit_val, total_hit, origin;
++ bool hit;
++
++ /* Make sure we can start calibration */
++ if(!ctlr->cal_target || !ctlr->cal_rule || !ctlr->append_caldata)
++ return 0;
++
++ buf = kzalloc(datalen * sizeof(u8), GFP_KERNEL);
++ if(!buf)
++ return -ENOMEM;
++
++ ret = ctlr->append_caldata(ctlr);
++ if (ret)
++ goto cal_end;
++
++ cal_head = ctlr->cal_target;
++ list_for_each(listptr, cal_head) {
++ target = list_entry(listptr, struct spi_cal_target, list);
++
++ hit = false;
++ hit_val = 0;
++ total_hit = 0;
++ origin = *target->cal_item;
++
++ for(i=target->cal_min; i<=target->cal_max; i+=target->step) {
++ *target->cal_item = i;
++ ret = (*cal_read)(drv_priv, ctlr->cal_rule->addr, addrlen, buf, datalen);
++ if(ret)
++ break;
++ dev_dbg(&spi->dev, "controller cal item value: 0x%x\n", i);
++ if(memcmp(ctlr->cal_rule->match_data, buf, datalen * sizeof(u8)) == 0) {
++ hit = true;
++ hit_val += i;
++ total_hit++;
++ dev_dbg(&spi->dev, "golden data matches data read!\n");
++ }
++ }
++ if(hit) {
++ *target->cal_item = DIV_ROUND_CLOSEST(hit_val, total_hit);
++ dev_info(&spi->dev, "calibration result: 0x%x", *target->cal_item);
++ } else {
++ *target->cal_item = origin;
++ dev_warn(&spi->dev, "calibration failed, fallback to default: 0x%x", origin);
++ }
++ }
++
++cal_end:
++ kfree(buf);
++ return ret? ret: 0;
++}
++EXPORT_SYMBOL_GPL(spi_do_calibration);
++
+ static void _spi_transfer_delay_ns(u32 ns)
+ {
+ if (!ns)
+@@ -2223,6 +2287,75 @@ void spi_flush_queue(struct spi_controll
+ /*-------------------------------------------------------------------------*/
+
+ #if defined(CONFIG_OF)
++static inline void alloc_cal_data(struct list_head **cal_target,
++ struct spi_cal_rule **cal_rule, bool enable)
++{
++ if(enable) {
++ *cal_target = kmalloc(sizeof(struct list_head), GFP_KERNEL);
++ INIT_LIST_HEAD(*cal_target);
++ *cal_rule = kmalloc(sizeof(struct spi_cal_rule), GFP_KERNEL);
++ } else {
++ kfree(*cal_target);
++ kfree(*cal_rule);
++ }
++}
++
++static int of_spi_parse_cal_dt(struct spi_controller *ctlr, struct spi_device *spi,
++ struct device_node *nc)
++{
++ u32 value;
++ int rc;
++ const char *cal_mode;
++
++ rc = of_property_read_bool(nc, "spi-cal-enable");
++ if (rc)
++ alloc_cal_data(&ctlr->cal_target, &ctlr->cal_rule, true);
++ else
++ return 0;
++
++ rc = of_property_read_string(nc, "spi-cal-mode", &cal_mode);
++ if(!rc) {
++ if(strcmp("read-data", cal_mode) == 0){
++ ctlr->cal_rule->mode = SPI_CAL_READ_DATA;
++ } else if(strcmp("read-pp", cal_mode) == 0) {
++ ctlr->cal_rule->mode = SPI_CAL_READ_PP;
++ return 0;
++ } else if(strcmp("read-sfdp", cal_mode) == 0){
++ ctlr->cal_rule->mode = SPI_CAL_READ_SFDP;
++ return 0;
++ }
++ } else
++ goto err;
++
++ ctlr->cal_rule->datalen = 0;
++ rc = of_property_read_u32(nc, "spi-cal-datalen", &value);
++ if(!rc && value > 0) {
++ ctlr->cal_rule->datalen = value;
++
++ ctlr->cal_rule->match_data = kzalloc(value * sizeof(u8), GFP_KERNEL);
++ rc = of_property_read_u8_array(nc, "spi-cal-data",
++ ctlr->cal_rule->match_data, value);
++ if(rc)
++ kfree(ctlr->cal_rule->match_data);
++ }
++
++ rc = of_property_read_u32(nc, "spi-cal-addrlen", &value);
++ if(!rc && value > 0) {
++ ctlr->cal_rule->addrlen = value;
++
++ ctlr->cal_rule->addr = kzalloc(value * sizeof(u32), GFP_KERNEL);
++ rc = of_property_read_u32_array(nc, "spi-cal-addr",
++ ctlr->cal_rule->addr, value);
++ if(rc)
++ kfree(ctlr->cal_rule->addr);
++ }
++ return 0;
++
++err:
++ alloc_cal_data(&ctlr->cal_target, &ctlr->cal_rule, false);
++ return 0;
++}
++
+ static int of_spi_parse_dt(struct spi_controller *ctlr, struct spi_device *spi,
+ struct device_node *nc)
+ {
+@@ -2341,6 +2474,10 @@ of_register_spi_device(struct spi_contro
+ if (rc)
+ goto err_out;
+
++ rc = of_spi_parse_cal_dt(ctlr, spi, nc);
++ if (rc)
++ goto err_out;
++
+ /* Store a pointer to the node in the device structure */
+ of_node_get(nc);
+ spi->dev.of_node = nc;
+--- a/include/linux/spi/spi.h
++++ b/include/linux/spi/spi.h
+@@ -318,6 +318,40 @@ struct spi_driver {
+ struct device_driver driver;
+ };
+
++enum {
++ SPI_CAL_READ_DATA = 0,
++ SPI_CAL_READ_PP = 1, /* only for SPI-NAND */
++ SPI_CAL_READ_SFDP = 2, /* only for SPI-NOR */
++};
++
++struct nand_addr {
++ unsigned int lun;
++ unsigned int plane;
++ unsigned int eraseblock;
++ unsigned int page;
++ unsigned int dataoffs;
++};
++
++/**
++ * Read calibration rule from device dts node.
++ * Once calibration result matches the rule, we regard is as success.
++ */
++struct spi_cal_rule {
++ int datalen;
++ u8 *match_data;
++ int addrlen;
++ u32 *addr;
++ int mode;
++};
++
++struct spi_cal_target {
++ u32 *cal_item;
++ int cal_min; /* min of cal_item */
++ int cal_max; /* max of cal_item */
++ int step; /* Increase/decrease cal_item */
++ struct list_head list;
++};
++
+ static inline struct spi_driver *to_spi_driver(struct device_driver *drv)
+ {
+ return drv ? container_of(drv, struct spi_driver, driver) : NULL;
+@@ -703,6 +737,11 @@ struct spi_controller {
+ void *dummy_rx;
+ void *dummy_tx;
+
++ /* For calibration */
++ int (*append_caldata)(struct spi_controller *ctlr);
++ struct list_head *cal_target;
++ struct spi_cal_rule *cal_rule;
++
+ int (*fw_translate_cs)(struct spi_controller *ctlr, unsigned cs);
+
+ /*
+@@ -1510,6 +1549,9 @@ spi_register_board_info(struct spi_board
+ { return 0; }
+ #endif
+
++extern int spi_do_calibration(struct spi_controller *ctlr,
++ struct spi_device *spi, int (*cal_read)(void *, u32 *, int, u8 *, int), void *drv_priv);
++
+ /* If you're hotplugging an adapter with devices (parport, usb, etc)
+ * use spi_new_device() to describe each device. You can also call
+ * spi_unregister_device() to start making that device vanish, but
--- /dev/null
+From 06640a5da2973318c06e516da16a5b579622e7c5 Mon Sep 17 00:00:00 2001
+From: "SkyLake.Huang" <skylake.huang@mediatek.com>
+Date: Thu, 23 Jun 2022 18:37:55 +0800
+Subject: [PATCH 3/6] drivers: spi-mem: Add spi calibration hook
+
+Signed-off-by: SkyLake.Huang <skylake.huang@mediatek.com>
+---
+ drivers/spi/spi-mem.c | 8 ++++++++
+ include/linux/spi/spi-mem.h | 4 ++++
+ 2 files changed, 12 insertions(+)
+
+--- a/drivers/spi/spi-mem.c
++++ b/drivers/spi/spi-mem.c
+@@ -419,6 +419,14 @@ int spi_mem_exec_op(struct spi_mem *mem,
+ }
+ EXPORT_SYMBOL_GPL(spi_mem_exec_op);
+
++int spi_mem_do_calibration(struct spi_mem *mem,
++ int (*cal_read)(void *priv, u32 *addr, int addrlen, u8 *buf, int readlen),
++ void *priv)
++{
++ return spi_do_calibration(mem->spi->controller, mem->spi, cal_read, priv);
++}
++EXPORT_SYMBOL_GPL(spi_mem_do_calibration);
++
+ /**
+ * spi_mem_get_name() - Return the SPI mem device name to be used by the
+ * upper layer if necessary
+--- a/include/linux/spi/spi-mem.h
++++ b/include/linux/spi/spi-mem.h
+@@ -366,6 +366,10 @@ bool spi_mem_supports_op(struct spi_mem
+ int spi_mem_exec_op(struct spi_mem *mem,
+ const struct spi_mem_op *op);
+
++int spi_mem_do_calibration(struct spi_mem *mem,
++ int (*cal_read)(void *, u32 *, int, u8 *, int),
++ void *priv);
++
+ const char *spi_mem_get_name(struct spi_mem *mem);
+
+ struct spi_mem_dirmap_desc *
--- /dev/null
+From d278c7a0bf730318a7ccf8d0a8b434c813e23fd0 Mon Sep 17 00:00:00 2001
+From: "SkyLake.Huang" <skylake.huang@mediatek.com>
+Date: Thu, 23 Jun 2022 18:39:03 +0800
+Subject: [PATCH 4/6] drivers: spi-mt65xx: Add controller's calibration
+ paramter
+
+Signed-off-by: SkyLake.Huang <skylake.huang@mediatek.com>
+---
+ drivers/spi/spi-mt65xx.c | 16 ++++++++++++++++
+ 1 file changed, 16 insertions(+)
+
+--- a/drivers/spi/spi-mt65xx.c
++++ b/drivers/spi/spi-mt65xx.c
+@@ -832,6 +832,21 @@ static irqreturn_t mtk_spi_interrupt(int
+ return IRQ_HANDLED;
+ }
+
++static int mtk_spi_append_caldata(struct spi_controller *ctlr)
++{
++ struct spi_cal_target *cal_target = kmalloc(sizeof(*cal_target), GFP_KERNEL);
++ struct mtk_spi *mdata = spi_master_get_devdata(ctlr);
++
++ cal_target->cal_item = &mdata->get_tick_dly;
++ cal_target->cal_min = 0;
++ cal_target->cal_max = 7;
++ cal_target->step = 1;
++
++ list_add(&cal_target->list, ctlr->cal_target);
++
++ return 0;
++}
++
+ static int mtk_spi_mem_adjust_op_size(struct spi_mem *mem,
+ struct spi_mem_op *op)
+ {
+@@ -1122,6 +1137,7 @@ static int mtk_spi_probe(struct platform
+ master->setup = mtk_spi_setup;
+ master->set_cs_timing = mtk_spi_set_hw_cs_timing;
+ master->use_gpio_descriptors = true;
++ master->append_caldata = mtk_spi_append_caldata;
+
+ mdata = spi_master_get_devdata(master);
+ mdata->dev_comp = device_get_match_data(dev);
--- /dev/null
+From 7670ec4a14891a1a182b98a9c403ffbf6b49e4b1 Mon Sep 17 00:00:00 2001
+From: "SkyLake.Huang" <skylake.huang@mediatek.com>
+Date: Thu, 23 Jun 2022 18:39:56 +0800
+Subject: [PATCH 5/6] drivers: mtd: spinand: Add calibration support for
+ spinand
+
+Signed-off-by: SkyLake.Huang <skylake.huang@mediatek.com>
+---
+ drivers/mtd/nand/spi/core.c | 54 +++++++++++++++++++++++++++++++++++++
+ 1 file changed, 54 insertions(+)
+
+--- a/drivers/mtd/nand/spi/core.c
++++ b/drivers/mtd/nand/spi/core.c
+@@ -978,6 +978,56 @@ static int spinand_manufacturer_match(st
+ return -ENOTSUPP;
+ }
+
++int spinand_cal_read(void *priv, u32 *addr, int addrlen, u8 *buf, int readlen) {
++ struct spinand_device *spinand = (struct spinand_device *)priv;
++ struct device *dev = &spinand->spimem->spi->dev;
++ struct spi_mem_op op = SPINAND_PAGE_READ_FROM_CACHE_OP(false, 0, 1, buf, readlen);
++ struct nand_pos pos;
++ struct nand_page_io_req req;
++ u8 status;
++ int ret;
++
++ if(addrlen != sizeof(struct nand_addr)/sizeof(unsigned int)) {
++ dev_err(dev, "Must provide correct addr(length) for spinand calibration\n");
++ return -EINVAL;
++ }
++
++ ret = spinand_reset_op(spinand);
++ if (ret)
++ return ret;
++
++ /* We should store our golden data in first target because
++ * we can't switch target at this moment.
++ */
++ pos = (struct nand_pos){
++ .target = 0,
++ .lun = *addr,
++ .plane = *(addr+1),
++ .eraseblock = *(addr+2),
++ .page = *(addr+3),
++ };
++
++ req = (struct nand_page_io_req){
++ .pos = pos,
++ .dataoffs = *(addr+4),
++ .datalen = readlen,
++ .databuf.in = buf,
++ .mode = MTD_OPS_AUTO_OOB,
++ };
++
++ ret = spinand_load_page_op(spinand, &req);
++ if (ret)
++ return ret;
++
++ ret = spinand_wait(spinand, &status);
++ if (ret < 0)
++ return ret;
++
++ ret = spi_mem_exec_op(spinand->spimem, &op);
++
++ return 0;
++}
++
+ static int spinand_id_detect(struct spinand_device *spinand)
+ {
+ u8 *id = spinand->id.data;
+@@ -1228,6 +1278,10 @@ static int spinand_init(struct spinand_d
+ if (!spinand->scratchbuf)
+ return -ENOMEM;
+
++ ret = spi_mem_do_calibration(spinand->spimem, spinand_cal_read, spinand);
++ if (ret)
++ dev_err(dev, "Failed to calibrate SPI-NAND (err = %d)\n", ret);
++
+ ret = spinand_detect(spinand);
+ if (ret)
+ goto err_free_bufs;
--- /dev/null
+From f3fe3b15eca7908eaac57f9b8387a5dbc45ec5b2 Mon Sep 17 00:00:00 2001
+From: "SkyLake.Huang" <skylake.huang@mediatek.com>
+Date: Thu, 23 Jun 2022 18:40:59 +0800
+Subject: [PATCH 6/6] drivers: mtd: spi-nor: Add calibration support for
+ spi-nor
+
+Signed-off-by: SkyLake.Huang <skylake.huang@mediatek.com>
+---
+ drivers/mtd/nand/spi/core.c | 5 ++++-
+ drivers/mtd/spi-nor/core.c | 15 +++++++++++++++
+ 2 files changed, 19 insertions(+), 1 deletion(-)
+
+--- a/drivers/mtd/nand/spi/core.c
++++ b/drivers/mtd/nand/spi/core.c
+@@ -1019,7 +1019,10 @@ int spinand_cal_read(void *priv, u32 *ad
+ if (ret)
+ return ret;
+
+- ret = spinand_wait(spinand, &status);
++ ret = spinand_wait(spinand,
++ SPINAND_READ_INITIAL_DELAY_US,
++ SPINAND_READ_POLL_DELAY_US,
++ &status);
+ if (ret < 0)
+ return ret;
+
+--- a/drivers/mtd/spi-nor/core.c
++++ b/drivers/mtd/spi-nor/core.c
+@@ -2900,6 +2900,18 @@ static const struct flash_info *spi_nor_
+ return NULL;
+ }
+
++static int spi_nor_cal_read(void *priv, u32 *addr, int addrlen, u8 *buf, int readlen)
++{
++ struct spi_nor *nor = (struct spi_nor *)priv;
++
++ nor->reg_proto = SNOR_PROTO_1_1_1;
++ nor->read_proto = SNOR_PROTO_1_1_1;
++ nor->read_opcode = SPINOR_OP_READ;
++ nor->read_dummy = 0;
++
++ return nor->controller_ops->read(nor, *addr, readlen, buf);
++}
++
+ static const struct flash_info *spi_nor_get_flash_info(struct spi_nor *nor,
+ const char *name)
+ {
+@@ -3003,6 +3015,9 @@ int spi_nor_scan(struct spi_nor *nor, co
+ if (!nor->bouncebuf)
+ return -ENOMEM;
+
++ if(nor->spimem)
++ spi_mem_do_calibration(nor->spimem, spi_nor_cal_read, nor);
++
+ info = spi_nor_get_flash_info(nor, name);
+ if (IS_ERR(info))
+ return PTR_ERR(info);
--- /dev/null
+--- a/drivers/net/phy/Kconfig
++++ b/drivers/net/phy/Kconfig
+@@ -384,6 +384,12 @@ config ROCKCHIP_PHY
+ help
+ Currently supports the integrated Ethernet PHY.
+
++config RTL8367S_GSW
++ tristate "rtl8367 Gigabit Switch support for mt7622"
++ depends on NET_VENDOR_MEDIATEK
++ help
++ This driver supports rtl8367s in mt7622
++
+ config SMSC_PHY
+ tristate "SMSC PHYs"
+ help
+--- a/drivers/net/phy/Makefile
++++ b/drivers/net/phy/Makefile
+@@ -95,6 +95,7 @@ obj-$(CONFIG_QSEMI_PHY) += qsemi.o
+ obj-$(CONFIG_REALTEK_PHY) += realtek.o
+ obj-$(CONFIG_RENESAS_PHY) += uPD60620.o
+ obj-$(CONFIG_ROCKCHIP_PHY) += rockchip.o
++obj-$(CONFIG_RTL8367S_GSW) += rtk/
+ obj-$(CONFIG_SMSC_PHY) += smsc.o
+ obj-$(CONFIG_STE10XP) += ste10Xp.o
+ obj-$(CONFIG_TERANETICS_PHY) += teranetics.o
--- /dev/null
+From: qizhong cheng <qizhong.cheng@mediatek.com>
+Date: Mon, 27 Dec 2021 21:31:10 +0800
+Subject: [PATCH] PCI: mediatek: Assert PERST# for 100ms for power and clock to
+ stabilize
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Described in PCIe CEM specification sections 2.2 (PERST# Signal) and
+2.2.1 (Initial Power-Up (G3 to S0)). The deassertion of PERST# should
+be delayed 100ms (TPVPERL) for the power and clock to become stable.
+
+Link: https://lore.kernel.org/r/20211227133110.14500-1-qizhong.cheng@mediatek.com
+Signed-off-by: qizhong cheng <qizhong.cheng@mediatek.com>
+Signed-off-by: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com>
+Acked-by: Pali Rohár <pali@kernel.org>
+---
+
+--- a/drivers/pci/controller/pcie-mediatek.c
++++ b/drivers/pci/controller/pcie-mediatek.c
+@@ -708,6 +708,13 @@ static int mtk_pcie_startup_port_v2(stru
+ */
+ msleep(100);
+
++ /*
++ * Described in PCIe CEM specification sections 2.2 (PERST# Signal) and
++ * 2.2.1 (Initial Power-Up (G3 to S0)). The deassertion of PERST# should
++ * be delayed 100ms (TPVPERL) for the power and clock to become stable.
++ */
++ msleep(100);
++
+ /* De-assert PHY, PE, PIPE, MAC and configuration reset */
+ val = readl(port->base + PCIE_RST_CTRL);
+ val |= PCIE_PHY_RSTB | PCIE_PERSTB | PCIE_PIPE_SRSTB |
--- /dev/null
+--- a/arch/arm64/boot/dts/mediatek/mt7622.dtsi
++++ b/arch/arm64/boot/dts/mediatek/mt7622.dtsi
+@@ -849,6 +849,12 @@
+ #address-cells = <0>;
+ #interrupt-cells = <1>;
+ };
++
++ slot0: pcie@0,0 {
++ reg = <0x0000 0 0 0 0>;
++ #address-cells = <3>;
++ #size-cells = <2>;
++ };
+ };
+
+ pcie1: pcie@1a145000 {
+@@ -887,6 +893,12 @@
+ #address-cells = <0>;
+ #interrupt-cells = <1>;
+ };
++
++ slot1: pcie@1,0 {
++ reg = <0x0800 0 0 0 0>;
++ #address-cells = <3>;
++ #size-cells = <2>;
++ };
+ };
+
+ sata: sata@1a200000 {
--- /dev/null
+From: Felix Fietkau <nbd@nbd.name>
+Date: Fri, 4 Sep 2020 18:33:27 +0200
+Subject: [PATCH] pcie-mediatek: fix clearing interrupt status
+
+Clearing the status needs to happen after running the handler, otherwise
+we will get an extra spurious interrupt after the cause has been cleared
+
+Signed-off-by: Felix Fietkau <nbd@nbd.name>
+---
+
+--- a/drivers/pci/controller/pcie-mediatek.c
++++ b/drivers/pci/controller/pcie-mediatek.c
+@@ -607,9 +607,9 @@ static void mtk_pcie_intr_handler(struct
+ if (status & INTX_MASK) {
+ for_each_set_bit_from(bit, &status, PCI_NUM_INTX + INTX_SHIFT) {
+ /* Clear the INTx */
+- writel(1 << bit, port->base + PCIE_INT_STATUS);
+ generic_handle_domain_irq(port->irq_domain,
+ bit - INTX_SHIFT);
++ writel(1 << bit, port->base + PCIE_INT_STATUS);
+ }
+ }
+
--- /dev/null
+--- a/drivers/pci/controller/pcie-mediatek-gen3.c
++++ b/drivers/pci/controller/pcie-mediatek-gen3.c
+@@ -375,7 +375,13 @@ static int mtk_pcie_startup_port(struct
+ msleep(100);
+
+ /* De-assert reset signals */
+- val &= ~(PCIE_MAC_RSTB | PCIE_PHY_RSTB | PCIE_BRG_RSTB | PCIE_PE_RSTB);
++ val &= ~(PCIE_MAC_RSTB | PCIE_PHY_RSTB | PCIE_BRG_RSTB);
++ writel_relaxed(val, pcie->base + PCIE_RST_CTRL_REG);
++
++ msleep(100);
++
++ /* De-assert PERST# signals */
++ val &= ~(PCIE_PE_RSTB);
+ writel_relaxed(val, pcie->base + PCIE_RST_CTRL_REG);
+
+ /* Check if the link is up or not */
--- /dev/null
+From 50cefacc6c001eea1d9b1c78ba27304566f304f1 Mon Sep 17 00:00:00 2001
+From: Daniel Golle <daniel@makrotopia.org>
+Date: Fri, 2 Jun 2023 13:06:26 +0800
+Subject: [PATCH] phy: mediatek: xsphy: support type switch by pericfg
+
+Patch from Sam Shih <sam.shih@mediatek.com> found in MediaTek SDK
+released under GPL.
+
+Get syscon and use it to set the PHY type.
+Extend support to PCIe and SGMII mode in addition to USB2 and USB3.
+
+Signed-off-by: Daniel Golle <daniel@makrotopia.org>
+---
+ drivers/phy/mediatek/phy-mtk-xsphy.c | 81 +++++++++++++++++++++++++++-
+ 1 file changed, 80 insertions(+), 1 deletion(-)
+
+--- a/drivers/phy/mediatek/phy-mtk-xsphy.c
++++ b/drivers/phy/mediatek/phy-mtk-xsphy.c
+@@ -11,10 +11,12 @@
+ #include <linux/clk.h>
+ #include <linux/delay.h>
+ #include <linux/iopoll.h>
++#include <linux/mfd/syscon.h>
+ #include <linux/module.h>
+ #include <linux/of_address.h>
+ #include <linux/phy/phy.h>
+ #include <linux/platform_device.h>
++#include <linux/regmap.h>
+
+ #include "phy-mtk-io.h"
+
+@@ -81,12 +83,22 @@
+ #define XSP_SR_COEF_DIVISOR 1000
+ #define XSP_FM_DET_CYCLE_CNT 1024
+
++/* PHY switch between pcie/usb3/sgmii */
++#define USB_PHY_SWITCH_CTRL 0x0
++#define RG_PHY_SW_TYPE GENMASK(3, 0)
++#define RG_PHY_SW_PCIE 0x0
++#define RG_PHY_SW_USB3 0x1
++#define RG_PHY_SW_SGMII 0x2
++
+ struct xsphy_instance {
+ struct phy *phy;
+ void __iomem *port_base;
+ struct clk *ref_clk; /* reference clock of anolog phy */
+ u32 index;
+ u32 type;
++ struct regmap *type_sw;
++ u32 type_sw_reg;
++ u32 type_sw_index;
+ /* only for HQA test */
+ int efuse_intr;
+ int efuse_tx_imp;
+@@ -259,6 +271,10 @@ static void phy_parse_property(struct mt
+ inst->efuse_intr, inst->efuse_tx_imp,
+ inst->efuse_rx_imp);
+ break;
++ case PHY_TYPE_PCIE:
++ case PHY_TYPE_SGMII:
++ /* nothing to do */
++ break;
+ default:
+ dev_err(xsphy->dev, "incompatible phy type\n");
+ return;
+@@ -305,6 +321,62 @@ static void u3_phy_props_set(struct mtk_
+ RG_XTP_LN0_RX_IMPSEL, inst->efuse_rx_imp);
+ }
+
++/* type switch for usb3/pcie/sgmii */
++static int phy_type_syscon_get(struct xsphy_instance *instance,
++ struct device_node *dn)
++{
++ struct of_phandle_args args;
++ int ret;
++
++ /* type switch function is optional */
++ if (!of_property_read_bool(dn, "mediatek,syscon-type"))
++ return 0;
++
++ ret = of_parse_phandle_with_fixed_args(dn, "mediatek,syscon-type",
++ 2, 0, &args);
++ if (ret)
++ return ret;
++
++ instance->type_sw_reg = args.args[0];
++ instance->type_sw_index = args.args[1] & 0x3; /* <=3 */
++ instance->type_sw = syscon_node_to_regmap(args.np);
++ of_node_put(args.np);
++ dev_info(&instance->phy->dev, "type_sw - reg %#x, index %d\n",
++ instance->type_sw_reg, instance->type_sw_index);
++
++ return PTR_ERR_OR_ZERO(instance->type_sw);
++}
++
++static int phy_type_set(struct xsphy_instance *instance)
++{
++ int type;
++ u32 offset;
++
++ if (!instance->type_sw)
++ return 0;
++
++ switch (instance->type) {
++ case PHY_TYPE_USB3:
++ type = RG_PHY_SW_USB3;
++ break;
++ case PHY_TYPE_PCIE:
++ type = RG_PHY_SW_PCIE;
++ break;
++ case PHY_TYPE_SGMII:
++ type = RG_PHY_SW_SGMII;
++ break;
++ case PHY_TYPE_USB2:
++ default:
++ return 0;
++ }
++
++ offset = instance->type_sw_index * BITS_PER_BYTE;
++ regmap_update_bits(instance->type_sw, instance->type_sw_reg,
++ RG_PHY_SW_TYPE << offset, type << offset);
++
++ return 0;
++}
++
+ static int mtk_phy_init(struct phy *phy)
+ {
+ struct xsphy_instance *inst = phy_get_drvdata(phy);
+@@ -325,6 +397,10 @@ static int mtk_phy_init(struct phy *phy)
+ case PHY_TYPE_USB3:
+ u3_phy_props_set(xsphy, inst);
+ break;
++ case PHY_TYPE_PCIE:
++ case PHY_TYPE_SGMII:
++ /* nothing to do, only used to set type */
++ break;
+ default:
+ dev_err(xsphy->dev, "incompatible phy type\n");
+ clk_disable_unprepare(inst->ref_clk);
+@@ -403,12 +479,15 @@ static struct phy *mtk_phy_xlate(struct
+
+ inst->type = args->args[0];
+ if (!(inst->type == PHY_TYPE_USB2 ||
+- inst->type == PHY_TYPE_USB3)) {
++ inst->type == PHY_TYPE_USB3 ||
++ inst->type == PHY_TYPE_PCIE ||
++ inst->type == PHY_TYPE_SGMII)) {
+ dev_err(dev, "unsupported phy type: %d\n", inst->type);
+ return ERR_PTR(-EINVAL);
+ }
+
+ phy_parse_property(xsphy, inst);
++ phy_type_set(inst);
+
+ return inst->phy;
+ }
+@@ -515,6 +594,10 @@ static int mtk_xsphy_probe(struct platfo
+ retval = PTR_ERR(inst->ref_clk);
+ goto put_child;
+ }
++
++ retval = phy_type_syscon_get(inst, child_np);
++ if (retval)
++ goto put_child;
+ }
+
+ provider = devm_of_phy_provider_register(dev, mtk_phy_xlate);
--- /dev/null
+From: Felix Fietkau <nbd@nbd.name>
+Date: Fri, 4 Sep 2020 18:42:42 +0200
+Subject: [PATCH] pci: pcie-mediatek: add support for coherent DMA
+
+It improves performance by eliminating the need for a cache flush for DMA on
+attached devices
+
+Signed-off-by: Felix Fietkau <nbd@nbd.name>
+---
+
+--- a/arch/arm64/boot/dts/mediatek/mt7622.dtsi
++++ b/arch/arm64/boot/dts/mediatek/mt7622.dtsi
+@@ -837,6 +837,9 @@
+ bus-range = <0x00 0xff>;
+ ranges = <0x82000000 0 0x20000000 0x0 0x20000000 0 0x8000000>;
+ status = "disabled";
++ dma-coherent;
++ mediatek,hifsys = <&hifsys>;
++ mediatek,cci-control = <&cci_control2>;
+
+ #interrupt-cells = <1>;
+ interrupt-map-mask = <0 0 0 7>;
+@@ -881,6 +884,9 @@
+ bus-range = <0x00 0xff>;
+ ranges = <0x82000000 0 0x28000000 0x0 0x28000000 0 0x8000000>;
+ status = "disabled";
++ dma-coherent;
++ mediatek,hifsys = <&hifsys>;
++ mediatek,cci-control = <&cci_control2>;
+
+ #interrupt-cells = <1>;
+ interrupt-map-mask = <0 0 0 7>;
+--- a/drivers/pci/controller/pcie-mediatek.c
++++ b/drivers/pci/controller/pcie-mediatek.c
+@@ -20,6 +20,7 @@
+ #include <linux/of_address.h>
+ #include <linux/of_pci.h>
+ #include <linux/of_platform.h>
++#include <linux/of_address.h>
+ #include <linux/pci.h>
+ #include <linux/phy/phy.h>
+ #include <linux/platform_device.h>
+@@ -139,6 +140,11 @@
+ #define PCIE_LINK_STATUS_V2 0x804
+ #define PCIE_PORT_LINKUP_V2 BIT(10)
+
++/* DMA channel mapping */
++#define HIFSYS_DMA_AG_MAP 0x008
++#define HIFSYS_DMA_AG_MAP_PCIE0 BIT(0)
++#define HIFSYS_DMA_AG_MAP_PCIE1 BIT(1)
++
+ struct mtk_pcie_port;
+
+ /**
+@@ -1060,6 +1066,27 @@ static int mtk_pcie_setup(struct mtk_pci
+ struct mtk_pcie_port *port, *tmp;
+ int err, slot;
+
++ if (of_dma_is_coherent(node)) {
++ struct regmap *con;
++ u32 mask;
++
++ con = syscon_regmap_lookup_by_phandle(node,
++ "mediatek,cci-control");
++ /* enable CPU/bus coherency */
++ if (!IS_ERR(con))
++ regmap_write(con, 0, 3);
++
++ con = syscon_regmap_lookup_by_phandle(node,
++ "mediatek,hifsys");
++ if (IS_ERR(con)) {
++ dev_err(dev, "missing hifsys node\n");
++ return PTR_ERR(con);
++ }
++
++ mask = HIFSYS_DMA_AG_MAP_PCIE0 | HIFSYS_DMA_AG_MAP_PCIE1;
++ regmap_update_bits(con, HIFSYS_DMA_AG_MAP, mask, mask);
++ }
++
+ slot = of_get_pci_domain_nr(dev->of_node);
+ if (slot < 0) {
+ for_each_available_child_of_node(node, child) {
--- /dev/null
+From: Jip de Beer <gpk6x3591g0l@opayq.com>
+Date: Sun, 9 Jan 2022 13:14:04 +0100
+Subject: [PATCH] mediatek mt7622: fix 300mhz typo in dts
+
+The lowest frequency should be 300MHz, since that is the label
+assigned to the OPP in the mt7622.dtsi device tree, while there is one
+missing zero in the actual value.
+
+To be clear, the lowest frequency should be 300MHz instead of 30MHz.
+
+As mentioned @dangowrt on the OpenWrt forum there is no benefit in
+leaving 30MHz as the lowest frequency.
+
+Signed-off-by: Jip de Beer <gpk6x3591g0l@opayq.com>
+Signed-off-by: Fritz D. Ansel <fdansel@yandex.ru>
+---
+--- a/arch/arm64/boot/dts/mediatek/mt7622.dtsi
++++ b/arch/arm64/boot/dts/mediatek/mt7622.dtsi
+@@ -24,7 +24,7 @@
+ compatible = "operating-points-v2";
+ opp-shared;
+ opp-300000000 {
+- opp-hz = /bits/ 64 <30000000>;
++ opp-hz = /bits/ 64 <300000000>;
+ opp-microvolt = <950000>;
+ };
+
--- /dev/null
+--- a/arch/arm64/boot/dts/mediatek/mt7622.dtsi
++++ b/arch/arm64/boot/dts/mediatek/mt7622.dtsi
+@@ -23,11 +23,17 @@
+ cpu_opp_table: opp-table {
+ compatible = "operating-points-v2";
+ opp-shared;
+- opp-300000000 {
+- opp-hz = /bits/ 64 <300000000>;
+- opp-microvolt = <950000>;
+- };
+-
++ /* Due to the bug described at the link below, remove the 300 MHz clock to avoid a low
++ * voltage condition that can cause a hang when rebooting the RT3200/E8450.
++ *
++ * https://forum.openwrt.org/t/belkin-rt3200-linksys-e8450-wifi-ax-discussion/94302/1490
++ *
++ * opp-300000000 {
++ * opp-hz = /bits/ 64 <300000000>;
++ * opp-microvolt = <950000>;
++ * };
++ *
++ */
+ opp-437500000 {
+ opp-hz = /bits/ 64 <437500000>;
+ opp-microvolt = <1000000>;
--- /dev/null
+From 98c485eaf509bc0e2a85f9b58d17cd501f274c4e Mon Sep 17 00:00:00 2001
+From: Daniel Golle <daniel@makrotopia.org>
+Date: Sun, 11 Jun 2023 00:48:10 +0100
+Subject: [PATCH] net: phy: add driver for MediaTek SoC built-in GE PHYs
+
+Some of MediaTek's Filogic SoCs come with built-in gigabit Ethernet
+PHYs which require calibration data from the SoC's efuse.
+Despite the similar design the driver doesn't share any code with the
+existing mediatek-ge.c.
+Add support for such PHYs by introducing a new driver with basic
+support for MediaTek SoCs MT7981 and MT7988 built-in 1GE PHYs.
+
+Signed-off-by: Daniel Golle <daniel@makrotopia.org>
+Reviewed-by: Andrew Lunn <andrew@lunn.ch>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+---
+ MAINTAINERS | 9 +
+ drivers/net/phy/Kconfig | 12 +
+ drivers/net/phy/Makefile | 1 +
+ drivers/net/phy/mediatek-ge-soc.c | 1116 +++++++++++++++++++++++++++++
+ drivers/net/phy/mediatek-ge.c | 3 +-
+ 5 files changed, 1140 insertions(+), 1 deletion(-)
+ create mode 100644 drivers/net/phy/mediatek-ge-soc.c
+
+--- a/MAINTAINERS
++++ b/MAINTAINERS
+@@ -12938,6 +12938,15 @@ F: drivers/net/pcs/pcs-mtk-usxgmii.c
+ F: include/linux/pcs/pcs-mtk-lynxi.h
+ F: include/linux/pcs/pcs-mtk-usxgmii.h
+
++MEDIATEK ETHERNET PHY DRIVERS
++M: Daniel Golle <daniel@makrotopia.org>
++M: Qingfang Deng <dqfext@gmail.com>
++M: SkyLake Huang <SkyLake.Huang@mediatek.com>
++L: netdev@vger.kernel.org
++S: Maintained
++F: drivers/net/phy/mediatek-ge-soc.c
++F: drivers/net/phy/mediatek-ge.c
++
+ MEDIATEK I2C CONTROLLER DRIVER
+ M: Qii Wang <qii.wang@mediatek.com>
+ L: linux-i2c@vger.kernel.org
+--- a/drivers/net/phy/Kconfig
++++ b/drivers/net/phy/Kconfig
+@@ -314,6 +314,18 @@ config MEDIATEK_GE_PHY
+ help
+ Supports the MediaTek Gigabit Ethernet PHYs.
+
++config MEDIATEK_GE_SOC_PHY
++ tristate "MediaTek SoC Ethernet PHYs"
++ depends on (ARM64 && ARCH_MEDIATEK) || COMPILE_TEST
++ select NVMEM_MTK_EFUSE
++ help
++ Supports MediaTek SoC built-in Gigabit Ethernet PHYs.
++
++ Include support for built-in Ethernet PHYs which are present in
++ the MT7981 and MT7988 SoCs. These PHYs need calibration data
++ present in the SoCs efuse and will dynamically calibrate VCM
++ (common-mode voltage) during startup.
++
+ config MICREL_PHY
+ tristate "Micrel PHYs"
+ depends on PTP_1588_CLOCK_OPTIONAL
+--- a/drivers/net/phy/Makefile
++++ b/drivers/net/phy/Makefile
+@@ -80,6 +80,7 @@ obj-$(CONFIG_MARVELL_PHY) += marvell.o
+ obj-$(CONFIG_MARVELL_88X2222_PHY) += marvell-88x2222.o
+ obj-$(CONFIG_MAXLINEAR_GPHY) += mxl-gpy.o
+ obj-$(CONFIG_MEDIATEK_GE_PHY) += mediatek-ge.o
++obj-$(CONFIG_MEDIATEK_GE_SOC_PHY) += mediatek-ge-soc.o
+ obj-$(CONFIG_MESON_GXL_PHY) += meson-gxl.o
+ obj-$(CONFIG_MICREL_KS8995MA) += spi_ks8995.o
+ obj-$(CONFIG_MICREL_PHY) += micrel.o
+--- /dev/null
++++ b/drivers/net/phy/mediatek-ge-soc.c
+@@ -0,0 +1,1116 @@
++// SPDX-License-Identifier: GPL-2.0+
++#include <linux/bitfield.h>
++#include <linux/module.h>
++#include <linux/nvmem-consumer.h>
++#include <linux/of_address.h>
++#include <linux/of_platform.h>
++#include <linux/pinctrl/consumer.h>
++#include <linux/phy.h>
++
++#define MTK_GPHY_ID_MT7981 0x03a29461
++#define MTK_GPHY_ID_MT7988 0x03a29481
++
++#define MTK_EXT_PAGE_ACCESS 0x1f
++#define MTK_PHY_PAGE_STANDARD 0x0000
++#define MTK_PHY_PAGE_EXTENDED_3 0x0003
++
++#define MTK_PHY_LPI_REG_14 0x14
++#define MTK_PHY_LPI_WAKE_TIMER_1000_MASK GENMASK(8, 0)
++
++#define MTK_PHY_LPI_REG_1c 0x1c
++#define MTK_PHY_SMI_DET_ON_THRESH_MASK GENMASK(13, 8)
++
++#define MTK_PHY_PAGE_EXTENDED_2A30 0x2a30
++#define MTK_PHY_PAGE_EXTENDED_52B5 0x52b5
++
++#define ANALOG_INTERNAL_OPERATION_MAX_US 20
++#define TXRESERVE_MIN 0
++#define TXRESERVE_MAX 7
++
++#define MTK_PHY_ANARG_RG 0x10
++#define MTK_PHY_TCLKOFFSET_MASK GENMASK(12, 8)
++
++/* Registers on MDIO_MMD_VEND1 */
++#define MTK_PHY_TXVLD_DA_RG 0x12
++#define MTK_PHY_DA_TX_I2MPB_A_GBE_MASK GENMASK(15, 10)
++#define MTK_PHY_DA_TX_I2MPB_A_TBT_MASK GENMASK(5, 0)
++
++#define MTK_PHY_TX_I2MPB_TEST_MODE_A2 0x16
++#define MTK_PHY_DA_TX_I2MPB_A_HBT_MASK GENMASK(15, 10)
++#define MTK_PHY_DA_TX_I2MPB_A_TST_MASK GENMASK(5, 0)
++
++#define MTK_PHY_TX_I2MPB_TEST_MODE_B1 0x17
++#define MTK_PHY_DA_TX_I2MPB_B_GBE_MASK GENMASK(13, 8)
++#define MTK_PHY_DA_TX_I2MPB_B_TBT_MASK GENMASK(5, 0)
++
++#define MTK_PHY_TX_I2MPB_TEST_MODE_B2 0x18
++#define MTK_PHY_DA_TX_I2MPB_B_HBT_MASK GENMASK(13, 8)
++#define MTK_PHY_DA_TX_I2MPB_B_TST_MASK GENMASK(5, 0)
++
++#define MTK_PHY_TX_I2MPB_TEST_MODE_C1 0x19
++#define MTK_PHY_DA_TX_I2MPB_C_GBE_MASK GENMASK(13, 8)
++#define MTK_PHY_DA_TX_I2MPB_C_TBT_MASK GENMASK(5, 0)
++
++#define MTK_PHY_TX_I2MPB_TEST_MODE_C2 0x20
++#define MTK_PHY_DA_TX_I2MPB_C_HBT_MASK GENMASK(13, 8)
++#define MTK_PHY_DA_TX_I2MPB_C_TST_MASK GENMASK(5, 0)
++
++#define MTK_PHY_TX_I2MPB_TEST_MODE_D1 0x21
++#define MTK_PHY_DA_TX_I2MPB_D_GBE_MASK GENMASK(13, 8)
++#define MTK_PHY_DA_TX_I2MPB_D_TBT_MASK GENMASK(5, 0)
++
++#define MTK_PHY_TX_I2MPB_TEST_MODE_D2 0x22
++#define MTK_PHY_DA_TX_I2MPB_D_HBT_MASK GENMASK(13, 8)
++#define MTK_PHY_DA_TX_I2MPB_D_TST_MASK GENMASK(5, 0)
++
++#define MTK_PHY_RXADC_CTRL_RG7 0xc6
++#define MTK_PHY_DA_AD_BUF_BIAS_LP_MASK GENMASK(9, 8)
++
++#define MTK_PHY_RXADC_CTRL_RG9 0xc8
++#define MTK_PHY_DA_RX_PSBN_TBT_MASK GENMASK(14, 12)
++#define MTK_PHY_DA_RX_PSBN_HBT_MASK GENMASK(10, 8)
++#define MTK_PHY_DA_RX_PSBN_GBE_MASK GENMASK(6, 4)
++#define MTK_PHY_DA_RX_PSBN_LP_MASK GENMASK(2, 0)
++
++#define MTK_PHY_LDO_OUTPUT_V 0xd7
++
++#define MTK_PHY_RG_ANA_CAL_RG0 0xdb
++#define MTK_PHY_RG_CAL_CKINV BIT(12)
++#define MTK_PHY_RG_ANA_CALEN BIT(8)
++#define MTK_PHY_RG_ZCALEN_A BIT(0)
++
++#define MTK_PHY_RG_ANA_CAL_RG1 0xdc
++#define MTK_PHY_RG_ZCALEN_B BIT(12)
++#define MTK_PHY_RG_ZCALEN_C BIT(8)
++#define MTK_PHY_RG_ZCALEN_D BIT(4)
++#define MTK_PHY_RG_TXVOS_CALEN BIT(0)
++
++#define MTK_PHY_RG_ANA_CAL_RG5 0xe0
++#define MTK_PHY_RG_REXT_TRIM_MASK GENMASK(13, 8)
++
++#define MTK_PHY_RG_TX_FILTER 0xfe
++
++#define MTK_PHY_RG_LPI_PCS_DSP_CTRL_REG120 0x120
++#define MTK_PHY_LPI_SIG_EN_LO_THRESH1000_MASK GENMASK(12, 8)
++#define MTK_PHY_LPI_SIG_EN_HI_THRESH1000_MASK GENMASK(4, 0)
++
++#define MTK_PHY_RG_LPI_PCS_DSP_CTRL_REG122 0x122
++#define MTK_PHY_LPI_NORM_MSE_HI_THRESH1000_MASK GENMASK(7, 0)
++
++#define MTK_PHY_RG_TESTMUX_ADC_CTRL 0x144
++#define MTK_PHY_RG_TXEN_DIG_MASK GENMASK(5, 5)
++
++#define MTK_PHY_RG_CR_TX_AMP_OFFSET_A_B 0x172
++#define MTK_PHY_CR_TX_AMP_OFFSET_A_MASK GENMASK(13, 8)
++#define MTK_PHY_CR_TX_AMP_OFFSET_B_MASK GENMASK(6, 0)
++
++#define MTK_PHY_RG_CR_TX_AMP_OFFSET_C_D 0x173
++#define MTK_PHY_CR_TX_AMP_OFFSET_C_MASK GENMASK(13, 8)
++#define MTK_PHY_CR_TX_AMP_OFFSET_D_MASK GENMASK(6, 0)
++
++#define MTK_PHY_RG_AD_CAL_COMP 0x17a
++#define MTK_PHY_AD_CAL_COMP_OUT_SHIFT (8)
++
++#define MTK_PHY_RG_AD_CAL_CLK 0x17b
++#define MTK_PHY_DA_CAL_CLK BIT(0)
++
++#define MTK_PHY_RG_AD_CALIN 0x17c
++#define MTK_PHY_DA_CALIN_FLAG BIT(0)
++
++#define MTK_PHY_RG_DASN_DAC_IN0_A 0x17d
++#define MTK_PHY_DASN_DAC_IN0_A_MASK GENMASK(9, 0)
++
++#define MTK_PHY_RG_DASN_DAC_IN0_B 0x17e
++#define MTK_PHY_DASN_DAC_IN0_B_MASK GENMASK(9, 0)
++
++#define MTK_PHY_RG_DASN_DAC_IN0_C 0x17f
++#define MTK_PHY_DASN_DAC_IN0_C_MASK GENMASK(9, 0)
++
++#define MTK_PHY_RG_DASN_DAC_IN0_D 0x180
++#define MTK_PHY_DASN_DAC_IN0_D_MASK GENMASK(9, 0)
++
++#define MTK_PHY_RG_DASN_DAC_IN1_A 0x181
++#define MTK_PHY_DASN_DAC_IN1_A_MASK GENMASK(9, 0)
++
++#define MTK_PHY_RG_DASN_DAC_IN1_B 0x182
++#define MTK_PHY_DASN_DAC_IN1_B_MASK GENMASK(9, 0)
++
++#define MTK_PHY_RG_DASN_DAC_IN1_C 0x183
++#define MTK_PHY_DASN_DAC_IN1_C_MASK GENMASK(9, 0)
++
++#define MTK_PHY_RG_DASN_DAC_IN1_D 0x184
++#define MTK_PHY_DASN_DAC_IN1_D_MASK GENMASK(9, 0)
++
++#define MTK_PHY_RG_DEV1E_REG19b 0x19b
++#define MTK_PHY_BYPASS_DSP_LPI_READY BIT(8)
++
++#define MTK_PHY_RG_LP_IIR2_K1_L 0x22a
++#define MTK_PHY_RG_LP_IIR2_K1_U 0x22b
++#define MTK_PHY_RG_LP_IIR2_K2_L 0x22c
++#define MTK_PHY_RG_LP_IIR2_K2_U 0x22d
++#define MTK_PHY_RG_LP_IIR2_K3_L 0x22e
++#define MTK_PHY_RG_LP_IIR2_K3_U 0x22f
++#define MTK_PHY_RG_LP_IIR2_K4_L 0x230
++#define MTK_PHY_RG_LP_IIR2_K4_U 0x231
++#define MTK_PHY_RG_LP_IIR2_K5_L 0x232
++#define MTK_PHY_RG_LP_IIR2_K5_U 0x233
++
++#define MTK_PHY_RG_DEV1E_REG234 0x234
++#define MTK_PHY_TR_OPEN_LOOP_EN_MASK GENMASK(0, 0)
++#define MTK_PHY_LPF_X_AVERAGE_MASK GENMASK(7, 4)
++#define MTK_PHY_TR_LP_IIR_EEE_EN BIT(12)
++
++#define MTK_PHY_RG_LPF_CNT_VAL 0x235
++
++#define MTK_PHY_RG_DEV1E_REG238 0x238
++#define MTK_PHY_LPI_SLV_SEND_TX_TIMER_MASK GENMASK(8, 0)
++#define MTK_PHY_LPI_SLV_SEND_TX_EN BIT(12)
++
++#define MTK_PHY_RG_DEV1E_REG239 0x239
++#define MTK_PHY_LPI_SEND_LOC_TIMER_MASK GENMASK(8, 0)
++#define MTK_PHY_LPI_TXPCS_LOC_RCV BIT(12)
++
++#define MTK_PHY_RG_DEV1E_REG27C 0x27c
++#define MTK_PHY_VGASTATE_FFE_THR_ST1_MASK GENMASK(12, 8)
++#define MTK_PHY_RG_DEV1E_REG27D 0x27d
++#define MTK_PHY_VGASTATE_FFE_THR_ST2_MASK GENMASK(4, 0)
++
++#define MTK_PHY_RG_DEV1E_REG2C7 0x2c7
++#define MTK_PHY_MAX_GAIN_MASK GENMASK(4, 0)
++#define MTK_PHY_MIN_GAIN_MASK GENMASK(12, 8)
++
++#define MTK_PHY_RG_DEV1E_REG2D1 0x2d1
++#define MTK_PHY_VCO_SLICER_THRESH_BITS_HIGH_EEE_MASK GENMASK(7, 0)
++#define MTK_PHY_LPI_SKIP_SD_SLV_TR BIT(8)
++#define MTK_PHY_LPI_TR_READY BIT(9)
++#define MTK_PHY_LPI_VCO_EEE_STG0_EN BIT(10)
++
++#define MTK_PHY_RG_DEV1E_REG323 0x323
++#define MTK_PHY_EEE_WAKE_MAS_INT_DC BIT(0)
++#define MTK_PHY_EEE_WAKE_SLV_INT_DC BIT(4)
++
++#define MTK_PHY_RG_DEV1E_REG324 0x324
++#define MTK_PHY_SMI_DETCNT_MAX_MASK GENMASK(5, 0)
++#define MTK_PHY_SMI_DET_MAX_EN BIT(8)
++
++#define MTK_PHY_RG_DEV1E_REG326 0x326
++#define MTK_PHY_LPI_MODE_SD_ON BIT(0)
++#define MTK_PHY_RESET_RANDUPD_CNT BIT(1)
++#define MTK_PHY_TREC_UPDATE_ENAB_CLR BIT(2)
++#define MTK_PHY_LPI_QUIT_WAIT_DFE_SIG_DET_OFF BIT(4)
++#define MTK_PHY_TR_READY_SKIP_AFE_WAKEUP BIT(5)
++
++#define MTK_PHY_LDO_PUMP_EN_PAIRAB 0x502
++#define MTK_PHY_LDO_PUMP_EN_PAIRCD 0x503
++
++#define MTK_PHY_DA_TX_R50_PAIR_A 0x53d
++#define MTK_PHY_DA_TX_R50_PAIR_B 0x53e
++#define MTK_PHY_DA_TX_R50_PAIR_C 0x53f
++#define MTK_PHY_DA_TX_R50_PAIR_D 0x540
++
++#define MTK_PHY_RG_BG_RASEL 0x115
++#define MTK_PHY_RG_BG_RASEL_MASK GENMASK(2, 0)
++
++/* These macro privides efuse parsing for internal phy. */
++#define EFS_DA_TX_I2MPB_A(x) (((x) >> 0) & GENMASK(5, 0))
++#define EFS_DA_TX_I2MPB_B(x) (((x) >> 6) & GENMASK(5, 0))
++#define EFS_DA_TX_I2MPB_C(x) (((x) >> 12) & GENMASK(5, 0))
++#define EFS_DA_TX_I2MPB_D(x) (((x) >> 18) & GENMASK(5, 0))
++#define EFS_DA_TX_AMP_OFFSET_A(x) (((x) >> 24) & GENMASK(5, 0))
++
++#define EFS_DA_TX_AMP_OFFSET_B(x) (((x) >> 0) & GENMASK(5, 0))
++#define EFS_DA_TX_AMP_OFFSET_C(x) (((x) >> 6) & GENMASK(5, 0))
++#define EFS_DA_TX_AMP_OFFSET_D(x) (((x) >> 12) & GENMASK(5, 0))
++#define EFS_DA_TX_R50_A(x) (((x) >> 18) & GENMASK(5, 0))
++#define EFS_DA_TX_R50_B(x) (((x) >> 24) & GENMASK(5, 0))
++
++#define EFS_DA_TX_R50_C(x) (((x) >> 0) & GENMASK(5, 0))
++#define EFS_DA_TX_R50_D(x) (((x) >> 6) & GENMASK(5, 0))
++
++#define EFS_RG_BG_RASEL(x) (((x) >> 4) & GENMASK(2, 0))
++#define EFS_RG_REXT_TRIM(x) (((x) >> 7) & GENMASK(5, 0))
++
++enum {
++ NO_PAIR,
++ PAIR_A,
++ PAIR_B,
++ PAIR_C,
++ PAIR_D,
++};
++
++enum {
++ GPHY_PORT0,
++ GPHY_PORT1,
++ GPHY_PORT2,
++ GPHY_PORT3,
++};
++
++enum calibration_mode {
++ EFUSE_K,
++ SW_K
++};
++
++enum CAL_ITEM {
++ REXT,
++ TX_OFFSET,
++ TX_AMP,
++ TX_R50,
++ TX_VCM
++};
++
++enum CAL_MODE {
++ EFUSE_M,
++ SW_M
++};
++
++static int mtk_socphy_read_page(struct phy_device *phydev)
++{
++ return __phy_read(phydev, MTK_EXT_PAGE_ACCESS);
++}
++
++static int mtk_socphy_write_page(struct phy_device *phydev, int page)
++{
++ return __phy_write(phydev, MTK_EXT_PAGE_ACCESS, page);
++}
++
++/* One calibration cycle consists of:
++ * 1.Set DA_CALIN_FLAG high to start calibration. Keep it high
++ * until AD_CAL_COMP is ready to output calibration result.
++ * 2.Wait until DA_CAL_CLK is available.
++ * 3.Fetch AD_CAL_COMP_OUT.
++ */
++static int cal_cycle(struct phy_device *phydev, int devad,
++ u32 regnum, u16 mask, u16 cal_val)
++{
++ int reg_val;
++ int ret;
++
++ phy_modify_mmd(phydev, devad, regnum,
++ mask, cal_val);
++ phy_set_bits_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_AD_CALIN,
++ MTK_PHY_DA_CALIN_FLAG);
++
++ ret = phy_read_mmd_poll_timeout(phydev, MDIO_MMD_VEND1,
++ MTK_PHY_RG_AD_CAL_CLK, reg_val,
++ reg_val & MTK_PHY_DA_CAL_CLK, 500,
++ ANALOG_INTERNAL_OPERATION_MAX_US, false);
++ if (ret) {
++ phydev_err(phydev, "Calibration cycle timeout\n");
++ return ret;
++ }
++
++ phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_AD_CALIN,
++ MTK_PHY_DA_CALIN_FLAG);
++ ret = phy_read_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_AD_CAL_COMP) >>
++ MTK_PHY_AD_CAL_COMP_OUT_SHIFT;
++ phydev_dbg(phydev, "cal_val: 0x%x, ret: %d\n", cal_val, ret);
++
++ return ret;
++}
++
++static int rext_fill_result(struct phy_device *phydev, u16 *buf)
++{
++ phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_ANA_CAL_RG5,
++ MTK_PHY_RG_REXT_TRIM_MASK, buf[0] << 8);
++ phy_modify_mmd(phydev, MDIO_MMD_VEND2, MTK_PHY_RG_BG_RASEL,
++ MTK_PHY_RG_BG_RASEL_MASK, buf[1]);
++
++ return 0;
++}
++
++static int rext_cal_efuse(struct phy_device *phydev, u32 *buf)
++{
++ u16 rext_cal_val[2];
++
++ rext_cal_val[0] = EFS_RG_REXT_TRIM(buf[3]);
++ rext_cal_val[1] = EFS_RG_BG_RASEL(buf[3]);
++ rext_fill_result(phydev, rext_cal_val);
++
++ return 0;
++}
++
++static int tx_offset_fill_result(struct phy_device *phydev, u16 *buf)
++{
++ phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_CR_TX_AMP_OFFSET_A_B,
++ MTK_PHY_CR_TX_AMP_OFFSET_A_MASK, buf[0] << 8);
++ phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_CR_TX_AMP_OFFSET_A_B,
++ MTK_PHY_CR_TX_AMP_OFFSET_B_MASK, buf[1]);
++ phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_CR_TX_AMP_OFFSET_C_D,
++ MTK_PHY_CR_TX_AMP_OFFSET_C_MASK, buf[2] << 8);
++ phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_CR_TX_AMP_OFFSET_C_D,
++ MTK_PHY_CR_TX_AMP_OFFSET_D_MASK, buf[3]);
++
++ return 0;
++}
++
++static int tx_offset_cal_efuse(struct phy_device *phydev, u32 *buf)
++{
++ u16 tx_offset_cal_val[4];
++
++ tx_offset_cal_val[0] = EFS_DA_TX_AMP_OFFSET_A(buf[0]);
++ tx_offset_cal_val[1] = EFS_DA_TX_AMP_OFFSET_B(buf[1]);
++ tx_offset_cal_val[2] = EFS_DA_TX_AMP_OFFSET_C(buf[1]);
++ tx_offset_cal_val[3] = EFS_DA_TX_AMP_OFFSET_D(buf[1]);
++
++ tx_offset_fill_result(phydev, tx_offset_cal_val);
++
++ return 0;
++}
++
++static int tx_amp_fill_result(struct phy_device *phydev, u16 *buf)
++{
++ int i;
++ int bias[16] = {};
++ const int vals_9461[16] = { 7, 1, 4, 7,
++ 7, 1, 4, 7,
++ 7, 1, 4, 7,
++ 7, 1, 4, 7 };
++ const int vals_9481[16] = { 10, 6, 6, 10,
++ 10, 6, 6, 10,
++ 10, 6, 6, 10,
++ 10, 6, 6, 10 };
++ switch (phydev->drv->phy_id) {
++ case MTK_GPHY_ID_MT7981:
++ /* We add some calibration to efuse values
++ * due to board level influence.
++ * GBE: +7, TBT: +1, HBT: +4, TST: +7
++ */
++ memcpy(bias, (const void *)vals_9461, sizeof(bias));
++ break;
++ case MTK_GPHY_ID_MT7988:
++ memcpy(bias, (const void *)vals_9481, sizeof(bias));
++ break;
++ }
++
++ /* Prevent overflow */
++ for (i = 0; i < 12; i++) {
++ if (buf[i >> 2] + bias[i] > 63) {
++ buf[i >> 2] = 63;
++ bias[i] = 0;
++ }
++ }
++
++ phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TXVLD_DA_RG,
++ MTK_PHY_DA_TX_I2MPB_A_GBE_MASK, (buf[0] + bias[0]) << 10);
++ phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TXVLD_DA_RG,
++ MTK_PHY_DA_TX_I2MPB_A_TBT_MASK, buf[0] + bias[1]);
++ phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_A2,
++ MTK_PHY_DA_TX_I2MPB_A_HBT_MASK, (buf[0] + bias[2]) << 10);
++ phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_A2,
++ MTK_PHY_DA_TX_I2MPB_A_TST_MASK, buf[0] + bias[3]);
++
++ phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_B1,
++ MTK_PHY_DA_TX_I2MPB_B_GBE_MASK, (buf[1] + bias[4]) << 8);
++ phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_B1,
++ MTK_PHY_DA_TX_I2MPB_B_TBT_MASK, buf[1] + bias[5]);
++ phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_B2,
++ MTK_PHY_DA_TX_I2MPB_B_HBT_MASK, (buf[1] + bias[6]) << 8);
++ phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_B2,
++ MTK_PHY_DA_TX_I2MPB_B_TST_MASK, buf[1] + bias[7]);
++
++ phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_C1,
++ MTK_PHY_DA_TX_I2MPB_C_GBE_MASK, (buf[2] + bias[8]) << 8);
++ phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_C1,
++ MTK_PHY_DA_TX_I2MPB_C_TBT_MASK, buf[2] + bias[9]);
++ phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_C2,
++ MTK_PHY_DA_TX_I2MPB_C_HBT_MASK, (buf[2] + bias[10]) << 8);
++ phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_C2,
++ MTK_PHY_DA_TX_I2MPB_C_TST_MASK, buf[2] + bias[11]);
++
++ phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_D1,
++ MTK_PHY_DA_TX_I2MPB_D_GBE_MASK, (buf[3] + bias[12]) << 8);
++ phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_D1,
++ MTK_PHY_DA_TX_I2MPB_D_TBT_MASK, buf[3] + bias[13]);
++ phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_D2,
++ MTK_PHY_DA_TX_I2MPB_D_HBT_MASK, (buf[3] + bias[14]) << 8);
++ phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_D2,
++ MTK_PHY_DA_TX_I2MPB_D_TST_MASK, buf[3] + bias[15]);
++
++ return 0;
++}
++
++static int tx_amp_cal_efuse(struct phy_device *phydev, u32 *buf)
++{
++ u16 tx_amp_cal_val[4];
++
++ tx_amp_cal_val[0] = EFS_DA_TX_I2MPB_A(buf[0]);
++ tx_amp_cal_val[1] = EFS_DA_TX_I2MPB_B(buf[0]);
++ tx_amp_cal_val[2] = EFS_DA_TX_I2MPB_C(buf[0]);
++ tx_amp_cal_val[3] = EFS_DA_TX_I2MPB_D(buf[0]);
++ tx_amp_fill_result(phydev, tx_amp_cal_val);
++
++ return 0;
++}
++
++static int tx_r50_fill_result(struct phy_device *phydev, u16 tx_r50_cal_val,
++ u8 txg_calen_x)
++{
++ int bias = 0;
++ u16 reg, val;
++
++ if (phydev->drv->phy_id == MTK_GPHY_ID_MT7988)
++ bias = -2;
++
++ val = clamp_val(bias + tx_r50_cal_val, 0, 63);
++
++ switch (txg_calen_x) {
++ case PAIR_A:
++ reg = MTK_PHY_DA_TX_R50_PAIR_A;
++ break;
++ case PAIR_B:
++ reg = MTK_PHY_DA_TX_R50_PAIR_B;
++ break;
++ case PAIR_C:
++ reg = MTK_PHY_DA_TX_R50_PAIR_C;
++ break;
++ case PAIR_D:
++ reg = MTK_PHY_DA_TX_R50_PAIR_D;
++ break;
++ default:
++ return -EINVAL;
++ }
++
++ phy_write_mmd(phydev, MDIO_MMD_VEND1, reg, val | val << 8);
++
++ return 0;
++}
++
++static int tx_r50_cal_efuse(struct phy_device *phydev, u32 *buf,
++ u8 txg_calen_x)
++{
++ u16 tx_r50_cal_val;
++
++ switch (txg_calen_x) {
++ case PAIR_A:
++ tx_r50_cal_val = EFS_DA_TX_R50_A(buf[1]);
++ break;
++ case PAIR_B:
++ tx_r50_cal_val = EFS_DA_TX_R50_B(buf[1]);
++ break;
++ case PAIR_C:
++ tx_r50_cal_val = EFS_DA_TX_R50_C(buf[2]);
++ break;
++ case PAIR_D:
++ tx_r50_cal_val = EFS_DA_TX_R50_D(buf[2]);
++ break;
++ default:
++ return -EINVAL;
++ }
++ tx_r50_fill_result(phydev, tx_r50_cal_val, txg_calen_x);
++
++ return 0;
++}
++
++static int tx_vcm_cal_sw(struct phy_device *phydev, u8 rg_txreserve_x)
++{
++ u8 lower_idx, upper_idx, txreserve_val;
++ u8 lower_ret, upper_ret;
++ int ret;
++
++ phy_set_bits_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_ANA_CAL_RG0,
++ MTK_PHY_RG_ANA_CALEN);
++ phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_ANA_CAL_RG0,
++ MTK_PHY_RG_CAL_CKINV);
++ phy_set_bits_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_ANA_CAL_RG1,
++ MTK_PHY_RG_TXVOS_CALEN);
++
++ switch (rg_txreserve_x) {
++ case PAIR_A:
++ phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1,
++ MTK_PHY_RG_DASN_DAC_IN0_A,
++ MTK_PHY_DASN_DAC_IN0_A_MASK);
++ phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1,
++ MTK_PHY_RG_DASN_DAC_IN1_A,
++ MTK_PHY_DASN_DAC_IN1_A_MASK);
++ phy_set_bits_mmd(phydev, MDIO_MMD_VEND1,
++ MTK_PHY_RG_ANA_CAL_RG0,
++ MTK_PHY_RG_ZCALEN_A);
++ break;
++ case PAIR_B:
++ phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1,
++ MTK_PHY_RG_DASN_DAC_IN0_B,
++ MTK_PHY_DASN_DAC_IN0_B_MASK);
++ phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1,
++ MTK_PHY_RG_DASN_DAC_IN1_B,
++ MTK_PHY_DASN_DAC_IN1_B_MASK);
++ phy_set_bits_mmd(phydev, MDIO_MMD_VEND1,
++ MTK_PHY_RG_ANA_CAL_RG1,
++ MTK_PHY_RG_ZCALEN_B);
++ break;
++ case PAIR_C:
++ phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1,
++ MTK_PHY_RG_DASN_DAC_IN0_C,
++ MTK_PHY_DASN_DAC_IN0_C_MASK);
++ phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1,
++ MTK_PHY_RG_DASN_DAC_IN1_C,
++ MTK_PHY_DASN_DAC_IN1_C_MASK);
++ phy_set_bits_mmd(phydev, MDIO_MMD_VEND1,
++ MTK_PHY_RG_ANA_CAL_RG1,
++ MTK_PHY_RG_ZCALEN_C);
++ break;
++ case PAIR_D:
++ phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1,
++ MTK_PHY_RG_DASN_DAC_IN0_D,
++ MTK_PHY_DASN_DAC_IN0_D_MASK);
++ phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1,
++ MTK_PHY_RG_DASN_DAC_IN1_D,
++ MTK_PHY_DASN_DAC_IN1_D_MASK);
++ phy_set_bits_mmd(phydev, MDIO_MMD_VEND1,
++ MTK_PHY_RG_ANA_CAL_RG1,
++ MTK_PHY_RG_ZCALEN_D);
++ break;
++ default:
++ ret = -EINVAL;
++ goto restore;
++ }
++
++ lower_idx = TXRESERVE_MIN;
++ upper_idx = TXRESERVE_MAX;
++
++ phydev_dbg(phydev, "Start TX-VCM SW cal.\n");
++ while ((upper_idx - lower_idx) > 1) {
++ txreserve_val = DIV_ROUND_CLOSEST(lower_idx + upper_idx, 2);
++ ret = cal_cycle(phydev, MDIO_MMD_VEND1, MTK_PHY_RXADC_CTRL_RG9,
++ MTK_PHY_DA_RX_PSBN_TBT_MASK |
++ MTK_PHY_DA_RX_PSBN_HBT_MASK |
++ MTK_PHY_DA_RX_PSBN_GBE_MASK |
++ MTK_PHY_DA_RX_PSBN_LP_MASK,
++ txreserve_val << 12 | txreserve_val << 8 |
++ txreserve_val << 4 | txreserve_val);
++ if (ret == 1) {
++ upper_idx = txreserve_val;
++ upper_ret = ret;
++ } else if (ret == 0) {
++ lower_idx = txreserve_val;
++ lower_ret = ret;
++ } else {
++ goto restore;
++ }
++ }
++
++ if (lower_idx == TXRESERVE_MIN) {
++ lower_ret = cal_cycle(phydev, MDIO_MMD_VEND1,
++ MTK_PHY_RXADC_CTRL_RG9,
++ MTK_PHY_DA_RX_PSBN_TBT_MASK |
++ MTK_PHY_DA_RX_PSBN_HBT_MASK |
++ MTK_PHY_DA_RX_PSBN_GBE_MASK |
++ MTK_PHY_DA_RX_PSBN_LP_MASK,
++ lower_idx << 12 | lower_idx << 8 |
++ lower_idx << 4 | lower_idx);
++ ret = lower_ret;
++ } else if (upper_idx == TXRESERVE_MAX) {
++ upper_ret = cal_cycle(phydev, MDIO_MMD_VEND1,
++ MTK_PHY_RXADC_CTRL_RG9,
++ MTK_PHY_DA_RX_PSBN_TBT_MASK |
++ MTK_PHY_DA_RX_PSBN_HBT_MASK |
++ MTK_PHY_DA_RX_PSBN_GBE_MASK |
++ MTK_PHY_DA_RX_PSBN_LP_MASK,
++ upper_idx << 12 | upper_idx << 8 |
++ upper_idx << 4 | upper_idx);
++ ret = upper_ret;
++ }
++ if (ret < 0)
++ goto restore;
++
++ /* We calibrate TX-VCM in different logic. Check upper index and then
++ * lower index. If this calibration is valid, apply lower index's result.
++ */
++ ret = upper_ret - lower_ret;
++ if (ret == 1) {
++ ret = 0;
++ /* Make sure we use upper_idx in our calibration system */
++ cal_cycle(phydev, MDIO_MMD_VEND1, MTK_PHY_RXADC_CTRL_RG9,
++ MTK_PHY_DA_RX_PSBN_TBT_MASK |
++ MTK_PHY_DA_RX_PSBN_HBT_MASK |
++ MTK_PHY_DA_RX_PSBN_GBE_MASK |
++ MTK_PHY_DA_RX_PSBN_LP_MASK,
++ upper_idx << 12 | upper_idx << 8 |
++ upper_idx << 4 | upper_idx);
++ phydev_dbg(phydev, "TX-VCM SW cal result: 0x%x\n", upper_idx);
++ } else if (lower_idx == TXRESERVE_MIN && upper_ret == 1 &&
++ lower_ret == 1) {
++ ret = 0;
++ cal_cycle(phydev, MDIO_MMD_VEND1, MTK_PHY_RXADC_CTRL_RG9,
++ MTK_PHY_DA_RX_PSBN_TBT_MASK |
++ MTK_PHY_DA_RX_PSBN_HBT_MASK |
++ MTK_PHY_DA_RX_PSBN_GBE_MASK |
++ MTK_PHY_DA_RX_PSBN_LP_MASK,
++ lower_idx << 12 | lower_idx << 8 |
++ lower_idx << 4 | lower_idx);
++ phydev_warn(phydev, "TX-VCM SW cal result at low margin 0x%x\n",
++ lower_idx);
++ } else if (upper_idx == TXRESERVE_MAX && upper_ret == 0 &&
++ lower_ret == 0) {
++ ret = 0;
++ phydev_warn(phydev, "TX-VCM SW cal result at high margin 0x%x\n",
++ upper_idx);
++ } else {
++ ret = -EINVAL;
++ }
++
++restore:
++ phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_ANA_CAL_RG0,
++ MTK_PHY_RG_ANA_CALEN);
++ phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_ANA_CAL_RG1,
++ MTK_PHY_RG_TXVOS_CALEN);
++ phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_ANA_CAL_RG0,
++ MTK_PHY_RG_ZCALEN_A);
++ phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_ANA_CAL_RG1,
++ MTK_PHY_RG_ZCALEN_B | MTK_PHY_RG_ZCALEN_C |
++ MTK_PHY_RG_ZCALEN_D);
++
++ return ret;
++}
++
++static void mt798x_phy_common_finetune(struct phy_device *phydev)
++{
++ phy_select_page(phydev, MTK_PHY_PAGE_EXTENDED_52B5);
++ /* EnabRandUpdTrig = 1 */
++ __phy_write(phydev, 0x11, 0x2f00);
++ __phy_write(phydev, 0x12, 0xe);
++ __phy_write(phydev, 0x10, 0x8fb0);
++
++ /* NormMseLoThresh = 85 */
++ __phy_write(phydev, 0x11, 0x55a0);
++ __phy_write(phydev, 0x12, 0x0);
++ __phy_write(phydev, 0x10, 0x83aa);
++
++ /* TrFreeze = 0 */
++ __phy_write(phydev, 0x11, 0x0);
++ __phy_write(phydev, 0x12, 0x0);
++ __phy_write(phydev, 0x10, 0x9686);
++
++ /* SSTrKp1000Slv = 5 */
++ __phy_write(phydev, 0x11, 0xbaef);
++ __phy_write(phydev, 0x12, 0x2e);
++ __phy_write(phydev, 0x10, 0x968c);
++
++ /* MrvlTrFix100Kp = 3, MrvlTrFix100Kf = 2,
++ * MrvlTrFix1000Kp = 3, MrvlTrFix1000Kf = 2
++ */
++ __phy_write(phydev, 0x11, 0xd10a);
++ __phy_write(phydev, 0x12, 0x34);
++ __phy_write(phydev, 0x10, 0x8f82);
++
++ /* VcoSlicerThreshBitsHigh */
++ __phy_write(phydev, 0x11, 0x5555);
++ __phy_write(phydev, 0x12, 0x55);
++ __phy_write(phydev, 0x10, 0x8ec0);
++ phy_restore_page(phydev, MTK_PHY_PAGE_STANDARD, 0);
++
++ /* TR_OPEN_LOOP_EN = 1, lpf_x_average = 9*/
++ phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_DEV1E_REG234,
++ MTK_PHY_TR_OPEN_LOOP_EN_MASK | MTK_PHY_LPF_X_AVERAGE_MASK,
++ BIT(0) | FIELD_PREP(MTK_PHY_LPF_X_AVERAGE_MASK, 0x9));
++
++ /* rg_tr_lpf_cnt_val = 512 */
++ phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_LPF_CNT_VAL, 0x200);
++
++ /* IIR2 related */
++ phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_LP_IIR2_K1_L, 0x82);
++ phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_LP_IIR2_K1_U, 0x0);
++ phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_LP_IIR2_K2_L, 0x103);
++ phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_LP_IIR2_K2_U, 0x0);
++ phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_LP_IIR2_K3_L, 0x82);
++ phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_LP_IIR2_K3_U, 0x0);
++ phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_LP_IIR2_K4_L, 0xd177);
++ phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_LP_IIR2_K4_U, 0x3);
++ phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_LP_IIR2_K5_L, 0x2c82);
++ phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_LP_IIR2_K5_U, 0xe);
++
++ /* FFE peaking */
++ phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_DEV1E_REG27C,
++ MTK_PHY_VGASTATE_FFE_THR_ST1_MASK, 0x1b << 8);
++ phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_DEV1E_REG27D,
++ MTK_PHY_VGASTATE_FFE_THR_ST2_MASK, 0x1e);
++
++ /* Disable LDO pump */
++ phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_LDO_PUMP_EN_PAIRAB, 0x0);
++ phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_LDO_PUMP_EN_PAIRCD, 0x0);
++ /* Adjust LDO output voltage */
++ phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_LDO_OUTPUT_V, 0x2222);
++}
++
++static void mt7981_phy_finetune(struct phy_device *phydev)
++{
++ u16 val[8] = { 0x01ce, 0x01c1,
++ 0x020f, 0x0202,
++ 0x03d0, 0x03c0,
++ 0x0013, 0x0005 };
++ int i, k;
++
++ /* 100M eye finetune:
++ * Keep middle level of TX MLT3 shapper as default.
++ * Only change TX MLT3 overshoot level here.
++ */
++ for (k = 0, i = 1; i < 12; i++) {
++ if (i % 3 == 0)
++ continue;
++ phy_write_mmd(phydev, MDIO_MMD_VEND1, i, val[k++]);
++ }
++
++ phy_select_page(phydev, MTK_PHY_PAGE_EXTENDED_52B5);
++ /* SlvDSPreadyTime = 24, MasDSPreadyTime = 24 */
++ __phy_write(phydev, 0x11, 0xc71);
++ __phy_write(phydev, 0x12, 0xc);
++ __phy_write(phydev, 0x10, 0x8fae);
++
++ /* ResetSyncOffset = 6 */
++ __phy_write(phydev, 0x11, 0x600);
++ __phy_write(phydev, 0x12, 0x0);
++ __phy_write(phydev, 0x10, 0x8fc0);
++
++ /* VgaDecRate = 1 */
++ __phy_write(phydev, 0x11, 0x4c2a);
++ __phy_write(phydev, 0x12, 0x3e);
++ __phy_write(phydev, 0x10, 0x8fa4);
++
++ /* FfeUpdGainForce = 4 */
++ __phy_write(phydev, 0x11, 0x240);
++ __phy_write(phydev, 0x12, 0x0);
++ __phy_write(phydev, 0x10, 0x9680);
++
++ phy_restore_page(phydev, MTK_PHY_PAGE_STANDARD, 0);
++}
++
++static void mt7988_phy_finetune(struct phy_device *phydev)
++{
++ u16 val[12] = { 0x0187, 0x01cd, 0x01c8, 0x0182,
++ 0x020d, 0x0206, 0x0384, 0x03d0,
++ 0x03c6, 0x030a, 0x0011, 0x0005 };
++ int i;
++
++ /* Set default MLT3 shaper first */
++ for (i = 0; i < 12; i++)
++ phy_write_mmd(phydev, MDIO_MMD_VEND1, i, val[i]);
++
++ /* TCT finetune */
++ phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_TX_FILTER, 0x5);
++
++ /* Disable TX power saving */
++ phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RXADC_CTRL_RG7,
++ MTK_PHY_DA_AD_BUF_BIAS_LP_MASK, 0x3 << 8);
++
++ phy_select_page(phydev, MTK_PHY_PAGE_EXTENDED_52B5);
++
++ /* SlvDSPreadyTime = 24, MasDSPreadyTime = 12 */
++ __phy_write(phydev, 0x11, 0x671);
++ __phy_write(phydev, 0x12, 0xc);
++ __phy_write(phydev, 0x10, 0x8fae);
++
++ /* ResetSyncOffset = 5 */
++ __phy_write(phydev, 0x11, 0x500);
++ __phy_write(phydev, 0x12, 0x0);
++ __phy_write(phydev, 0x10, 0x8fc0);
++
++ /* VgaDecRate is 1 at default on mt7988 */
++
++ phy_restore_page(phydev, MTK_PHY_PAGE_STANDARD, 0);
++
++ phy_select_page(phydev, MTK_PHY_PAGE_EXTENDED_2A30);
++ /* TxClkOffset = 2 */
++ __phy_modify(phydev, MTK_PHY_ANARG_RG, MTK_PHY_TCLKOFFSET_MASK,
++ FIELD_PREP(MTK_PHY_TCLKOFFSET_MASK, 0x2));
++ phy_restore_page(phydev, MTK_PHY_PAGE_STANDARD, 0);
++}
++
++static void mt798x_phy_eee(struct phy_device *phydev)
++{
++ phy_modify_mmd(phydev, MDIO_MMD_VEND1,
++ MTK_PHY_RG_LPI_PCS_DSP_CTRL_REG120,
++ MTK_PHY_LPI_SIG_EN_LO_THRESH1000_MASK |
++ MTK_PHY_LPI_SIG_EN_HI_THRESH1000_MASK,
++ FIELD_PREP(MTK_PHY_LPI_SIG_EN_LO_THRESH1000_MASK, 0x0) |
++ FIELD_PREP(MTK_PHY_LPI_SIG_EN_HI_THRESH1000_MASK, 0x14));
++
++ phy_modify_mmd(phydev, MDIO_MMD_VEND1,
++ MTK_PHY_RG_LPI_PCS_DSP_CTRL_REG122,
++ MTK_PHY_LPI_NORM_MSE_HI_THRESH1000_MASK,
++ FIELD_PREP(MTK_PHY_LPI_NORM_MSE_HI_THRESH1000_MASK,
++ 0xff));
++
++ phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1,
++ MTK_PHY_RG_TESTMUX_ADC_CTRL,
++ MTK_PHY_RG_TXEN_DIG_MASK);
++
++ phy_set_bits_mmd(phydev, MDIO_MMD_VEND1,
++ MTK_PHY_RG_DEV1E_REG19b, MTK_PHY_BYPASS_DSP_LPI_READY);
++
++ phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1,
++ MTK_PHY_RG_DEV1E_REG234, MTK_PHY_TR_LP_IIR_EEE_EN);
++
++ phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_DEV1E_REG238,
++ MTK_PHY_LPI_SLV_SEND_TX_TIMER_MASK |
++ MTK_PHY_LPI_SLV_SEND_TX_EN,
++ FIELD_PREP(MTK_PHY_LPI_SLV_SEND_TX_TIMER_MASK, 0x120));
++
++ phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_DEV1E_REG239,
++ MTK_PHY_LPI_SEND_LOC_TIMER_MASK |
++ MTK_PHY_LPI_TXPCS_LOC_RCV,
++ FIELD_PREP(MTK_PHY_LPI_SEND_LOC_TIMER_MASK, 0x117));
++
++ phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_DEV1E_REG2C7,
++ MTK_PHY_MAX_GAIN_MASK | MTK_PHY_MIN_GAIN_MASK,
++ FIELD_PREP(MTK_PHY_MAX_GAIN_MASK, 0x8) |
++ FIELD_PREP(MTK_PHY_MIN_GAIN_MASK, 0x13));
++
++ phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_DEV1E_REG2D1,
++ MTK_PHY_VCO_SLICER_THRESH_BITS_HIGH_EEE_MASK,
++ FIELD_PREP(MTK_PHY_VCO_SLICER_THRESH_BITS_HIGH_EEE_MASK,
++ 0x33) |
++ MTK_PHY_LPI_SKIP_SD_SLV_TR | MTK_PHY_LPI_TR_READY |
++ MTK_PHY_LPI_VCO_EEE_STG0_EN);
++
++ phy_set_bits_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_DEV1E_REG323,
++ MTK_PHY_EEE_WAKE_MAS_INT_DC |
++ MTK_PHY_EEE_WAKE_SLV_INT_DC);
++
++ phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_DEV1E_REG324,
++ MTK_PHY_SMI_DETCNT_MAX_MASK,
++ FIELD_PREP(MTK_PHY_SMI_DETCNT_MAX_MASK, 0x3f) |
++ MTK_PHY_SMI_DET_MAX_EN);
++
++ phy_set_bits_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_DEV1E_REG326,
++ MTK_PHY_LPI_MODE_SD_ON | MTK_PHY_RESET_RANDUPD_CNT |
++ MTK_PHY_TREC_UPDATE_ENAB_CLR |
++ MTK_PHY_LPI_QUIT_WAIT_DFE_SIG_DET_OFF |
++ MTK_PHY_TR_READY_SKIP_AFE_WAKEUP);
++
++ phy_select_page(phydev, MTK_PHY_PAGE_EXTENDED_52B5);
++ /* Regsigdet_sel_1000 = 0 */
++ __phy_write(phydev, 0x11, 0xb);
++ __phy_write(phydev, 0x12, 0x0);
++ __phy_write(phydev, 0x10, 0x9690);
++
++ /* REG_EEE_st2TrKf1000 = 3 */
++ __phy_write(phydev, 0x11, 0x114f);
++ __phy_write(phydev, 0x12, 0x2);
++ __phy_write(phydev, 0x10, 0x969a);
++
++ /* RegEEE_slv_wake_tr_timer_tar = 6, RegEEE_slv_remtx_timer_tar = 20 */
++ __phy_write(phydev, 0x11, 0x3028);
++ __phy_write(phydev, 0x12, 0x0);
++ __phy_write(phydev, 0x10, 0x969e);
++
++ /* RegEEE_slv_wake_int_timer_tar = 8 */
++ __phy_write(phydev, 0x11, 0x5010);
++ __phy_write(phydev, 0x12, 0x0);
++ __phy_write(phydev, 0x10, 0x96a0);
++
++ /* RegEEE_trfreeze_timer2 = 586 */
++ __phy_write(phydev, 0x11, 0x24a);
++ __phy_write(phydev, 0x12, 0x0);
++ __phy_write(phydev, 0x10, 0x96a8);
++
++ /* RegEEE100Stg1_tar = 16 */
++ __phy_write(phydev, 0x11, 0x3210);
++ __phy_write(phydev, 0x12, 0x0);
++ __phy_write(phydev, 0x10, 0x96b8);
++
++ /* REGEEE_wake_slv_tr_wait_dfesigdet_en = 1 */
++ __phy_write(phydev, 0x11, 0x1463);
++ __phy_write(phydev, 0x12, 0x0);
++ __phy_write(phydev, 0x10, 0x96ca);
++
++ /* DfeTailEnableVgaThresh1000 = 27 */
++ __phy_write(phydev, 0x11, 0x36);
++ __phy_write(phydev, 0x12, 0x0);
++ __phy_write(phydev, 0x10, 0x8f80);
++ phy_restore_page(phydev, MTK_PHY_PAGE_STANDARD, 0);
++
++ phy_select_page(phydev, MTK_PHY_PAGE_EXTENDED_3);
++ __phy_modify(phydev, MTK_PHY_LPI_REG_14, MTK_PHY_LPI_WAKE_TIMER_1000_MASK,
++ FIELD_PREP(MTK_PHY_LPI_WAKE_TIMER_1000_MASK, 0x19c));
++
++ __phy_modify(phydev, MTK_PHY_LPI_REG_1c, MTK_PHY_SMI_DET_ON_THRESH_MASK,
++ FIELD_PREP(MTK_PHY_SMI_DET_ON_THRESH_MASK, 0xc));
++ phy_restore_page(phydev, MTK_PHY_PAGE_STANDARD, 0);
++
++ phy_modify_mmd(phydev, MDIO_MMD_VEND1,
++ MTK_PHY_RG_LPI_PCS_DSP_CTRL_REG122,
++ MTK_PHY_LPI_NORM_MSE_HI_THRESH1000_MASK,
++ FIELD_PREP(MTK_PHY_LPI_NORM_MSE_HI_THRESH1000_MASK, 0xff));
++}
++
++static int cal_sw(struct phy_device *phydev, enum CAL_ITEM cal_item,
++ u8 start_pair, u8 end_pair)
++{
++ u8 pair_n;
++ int ret;
++
++ for (pair_n = start_pair; pair_n <= end_pair; pair_n++) {
++ /* TX_OFFSET & TX_AMP have no SW calibration. */
++ switch (cal_item) {
++ case TX_VCM:
++ ret = tx_vcm_cal_sw(phydev, pair_n);
++ break;
++ default:
++ return -EINVAL;
++ }
++ if (ret)
++ return ret;
++ }
++ return 0;
++}
++
++static int cal_efuse(struct phy_device *phydev, enum CAL_ITEM cal_item,
++ u8 start_pair, u8 end_pair, u32 *buf)
++{
++ u8 pair_n;
++ int ret;
++
++ for (pair_n = start_pair; pair_n <= end_pair; pair_n++) {
++ /* TX_VCM has no efuse calibration. */
++ switch (cal_item) {
++ case REXT:
++ ret = rext_cal_efuse(phydev, buf);
++ break;
++ case TX_OFFSET:
++ ret = tx_offset_cal_efuse(phydev, buf);
++ break;
++ case TX_AMP:
++ ret = tx_amp_cal_efuse(phydev, buf);
++ break;
++ case TX_R50:
++ ret = tx_r50_cal_efuse(phydev, buf, pair_n);
++ break;
++ default:
++ return -EINVAL;
++ }
++ if (ret)
++ return ret;
++ }
++
++ return 0;
++}
++
++static int start_cal(struct phy_device *phydev, enum CAL_ITEM cal_item,
++ enum CAL_MODE cal_mode, u8 start_pair,
++ u8 end_pair, u32 *buf)
++{
++ int ret;
++
++ switch (cal_mode) {
++ case EFUSE_M:
++ ret = cal_efuse(phydev, cal_item, start_pair,
++ end_pair, buf);
++ break;
++ case SW_M:
++ ret = cal_sw(phydev, cal_item, start_pair, end_pair);
++ break;
++ default:
++ return -EINVAL;
++ }
++
++ if (ret) {
++ phydev_err(phydev, "cal %d failed\n", cal_item);
++ return -EIO;
++ }
++
++ return 0;
++}
++
++static int mt798x_phy_calibration(struct phy_device *phydev)
++{
++ int ret = 0;
++ u32 *buf;
++ size_t len;
++ struct nvmem_cell *cell;
++
++ cell = nvmem_cell_get(&phydev->mdio.dev, "phy-cal-data");
++ if (IS_ERR(cell)) {
++ if (PTR_ERR(cell) == -EPROBE_DEFER)
++ return PTR_ERR(cell);
++ return 0;
++ }
++
++ buf = (u32 *)nvmem_cell_read(cell, &len);
++ if (IS_ERR(buf))
++ return PTR_ERR(buf);
++ nvmem_cell_put(cell);
++
++ if (!buf[0] || !buf[1] || !buf[2] || !buf[3] || len < 4 * sizeof(u32)) {
++ phydev_err(phydev, "invalid efuse data\n");
++ ret = -EINVAL;
++ goto out;
++ }
++
++ ret = start_cal(phydev, REXT, EFUSE_M, NO_PAIR, NO_PAIR, buf);
++ if (ret)
++ goto out;
++ ret = start_cal(phydev, TX_OFFSET, EFUSE_M, NO_PAIR, NO_PAIR, buf);
++ if (ret)
++ goto out;
++ ret = start_cal(phydev, TX_AMP, EFUSE_M, NO_PAIR, NO_PAIR, buf);
++ if (ret)
++ goto out;
++ ret = start_cal(phydev, TX_R50, EFUSE_M, PAIR_A, PAIR_D, buf);
++ if (ret)
++ goto out;
++ ret = start_cal(phydev, TX_VCM, SW_M, PAIR_A, PAIR_A, buf);
++ if (ret)
++ goto out;
++
++out:
++ kfree(buf);
++ return ret;
++}
++
++static int mt798x_phy_config_init(struct phy_device *phydev)
++{
++ switch (phydev->drv->phy_id) {
++ case MTK_GPHY_ID_MT7981:
++ mt7981_phy_finetune(phydev);
++ break;
++ case MTK_GPHY_ID_MT7988:
++ mt7988_phy_finetune(phydev);
++ break;
++ }
++
++ mt798x_phy_common_finetune(phydev);
++ mt798x_phy_eee(phydev);
++
++ return mt798x_phy_calibration(phydev);
++}
++
++static struct phy_driver mtk_socphy_driver[] = {
++ {
++ PHY_ID_MATCH_EXACT(MTK_GPHY_ID_MT7981),
++ .name = "MediaTek MT7981 PHY",
++ .config_init = mt798x_phy_config_init,
++ .config_intr = genphy_no_config_intr,
++ .handle_interrupt = genphy_handle_interrupt_no_ack,
++ .probe = mt798x_phy_calibration,
++ .suspend = genphy_suspend,
++ .resume = genphy_resume,
++ .read_page = mtk_socphy_read_page,
++ .write_page = mtk_socphy_write_page,
++ },
++ {
++ PHY_ID_MATCH_EXACT(MTK_GPHY_ID_MT7988),
++ .name = "MediaTek MT7988 PHY",
++ .config_init = mt798x_phy_config_init,
++ .config_intr = genphy_no_config_intr,
++ .handle_interrupt = genphy_handle_interrupt_no_ack,
++ .probe = mt798x_phy_calibration,
++ .suspend = genphy_suspend,
++ .resume = genphy_resume,
++ .read_page = mtk_socphy_read_page,
++ .write_page = mtk_socphy_write_page,
++ },
++};
++
++module_phy_driver(mtk_socphy_driver);
++
++static struct mdio_device_id __maybe_unused mtk_socphy_tbl[] = {
++ { PHY_ID_MATCH_EXACT(MTK_GPHY_ID_MT7981) },
++ { PHY_ID_MATCH_EXACT(MTK_GPHY_ID_MT7988) },
++ { }
++};
++
++MODULE_DESCRIPTION("MediaTek SoC Gigabit Ethernet PHY driver");
++MODULE_AUTHOR("Daniel Golle <daniel@makrotopia.org>");
++MODULE_AUTHOR("SkyLake Huang <SkyLake.Huang@mediatek.com>");
++MODULE_LICENSE("GPL");
++
++MODULE_DEVICE_TABLE(mdio, mtk_socphy_tbl);
+--- a/drivers/net/phy/mediatek-ge.c
++++ b/drivers/net/phy/mediatek-ge.c
+@@ -136,7 +136,8 @@ static struct phy_driver mtk_gephy_drive
+ module_phy_driver(mtk_gephy_driver);
+
+ static struct mdio_device_id __maybe_unused mtk_gephy_tbl[] = {
+- { PHY_ID_MATCH_VENDOR(0x03a29400) },
++ { PHY_ID_MATCH_EXACT(0x03a29441) },
++ { PHY_ID_MATCH_EXACT(0x03a29412) },
+ { }
+ };
+
--- /dev/null
+From c66937b0f8dbb4c6c043663c702b1053fb47fab2 Mon Sep 17 00:00:00 2001
+From: Daniel Golle <daniel@makrotopia.org>
+Date: Mon, 14 Aug 2023 02:58:14 +0100
+Subject: [PATCH] net: phy: mediatek-ge-soc: support PHY LEDs
+
+Implement netdev trigger and primitive bliking offloading as well as
+simple set_brigthness function for both PHY LEDs of the in-SoC PHYs
+found in MT7981 and MT7988.
+
+For MT7988, read boottrap register and apply LED polarities accordingly
+to get uniform behavior from all LEDs on MT7988.
+This requires syscon phandle 'mediatek,pio' present in parenting MDIO bus
+which should point to the syscon holding the boottrap register.
+
+Signed-off-by: Daniel Golle <daniel@makrotopia.org>
+Reviewed-by: Andrew Lunn <andrew@lunn.ch>
+Link: https://lore.kernel.org/r/dc324d48c00cd7350f3a506eaa785324cae97372.1691977904.git.daniel@makrotopia.org
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+---
+ drivers/net/phy/mediatek-ge-soc.c | 435 +++++++++++++++++++++++++++++-
+ 1 file changed, 426 insertions(+), 9 deletions(-)
+
+--- a/drivers/net/phy/mediatek-ge-soc.c
++++ b/drivers/net/phy/mediatek-ge-soc.c
+@@ -1,11 +1,14 @@
+ // SPDX-License-Identifier: GPL-2.0+
+ #include <linux/bitfield.h>
++#include <linux/bitmap.h>
++#include <linux/mfd/syscon.h>
+ #include <linux/module.h>
+ #include <linux/nvmem-consumer.h>
+ #include <linux/of_address.h>
+ #include <linux/of_platform.h>
+ #include <linux/pinctrl/consumer.h>
+ #include <linux/phy.h>
++#include <linux/regmap.h>
+
+ #define MTK_GPHY_ID_MT7981 0x03a29461
+ #define MTK_GPHY_ID_MT7988 0x03a29481
+@@ -208,9 +211,42 @@
+ #define MTK_PHY_DA_TX_R50_PAIR_C 0x53f
+ #define MTK_PHY_DA_TX_R50_PAIR_D 0x540
+
++/* Registers on MDIO_MMD_VEND2 */
++#define MTK_PHY_LED0_ON_CTRL 0x24
++#define MTK_PHY_LED1_ON_CTRL 0x26
++#define MTK_PHY_LED_ON_MASK GENMASK(6, 0)
++#define MTK_PHY_LED_ON_LINK1000 BIT(0)
++#define MTK_PHY_LED_ON_LINK100 BIT(1)
++#define MTK_PHY_LED_ON_LINK10 BIT(2)
++#define MTK_PHY_LED_ON_LINKDOWN BIT(3)
++#define MTK_PHY_LED_ON_FDX BIT(4) /* Full duplex */
++#define MTK_PHY_LED_ON_HDX BIT(5) /* Half duplex */
++#define MTK_PHY_LED_ON_FORCE_ON BIT(6)
++#define MTK_PHY_LED_ON_POLARITY BIT(14)
++#define MTK_PHY_LED_ON_ENABLE BIT(15)
++
++#define MTK_PHY_LED0_BLINK_CTRL 0x25
++#define MTK_PHY_LED1_BLINK_CTRL 0x27
++#define MTK_PHY_LED_BLINK_1000TX BIT(0)
++#define MTK_PHY_LED_BLINK_1000RX BIT(1)
++#define MTK_PHY_LED_BLINK_100TX BIT(2)
++#define MTK_PHY_LED_BLINK_100RX BIT(3)
++#define MTK_PHY_LED_BLINK_10TX BIT(4)
++#define MTK_PHY_LED_BLINK_10RX BIT(5)
++#define MTK_PHY_LED_BLINK_COLLISION BIT(6)
++#define MTK_PHY_LED_BLINK_RX_CRC_ERR BIT(7)
++#define MTK_PHY_LED_BLINK_RX_IDLE_ERR BIT(8)
++#define MTK_PHY_LED_BLINK_FORCE_BLINK BIT(9)
++
++#define MTK_PHY_LED1_DEFAULT_POLARITIES BIT(1)
++
+ #define MTK_PHY_RG_BG_RASEL 0x115
+ #define MTK_PHY_RG_BG_RASEL_MASK GENMASK(2, 0)
+
++/* 'boottrap' register reflecting the configuration of the 4 PHY LEDs */
++#define RG_GPIO_MISC_TPBANK0 0x6f0
++#define RG_GPIO_MISC_TPBANK0_BOOTMODE GENMASK(11, 8)
++
+ /* These macro privides efuse parsing for internal phy. */
+ #define EFS_DA_TX_I2MPB_A(x) (((x) >> 0) & GENMASK(5, 0))
+ #define EFS_DA_TX_I2MPB_B(x) (((x) >> 6) & GENMASK(5, 0))
+@@ -238,13 +274,6 @@ enum {
+ PAIR_D,
+ };
+
+-enum {
+- GPHY_PORT0,
+- GPHY_PORT1,
+- GPHY_PORT2,
+- GPHY_PORT3,
+-};
+-
+ enum calibration_mode {
+ EFUSE_K,
+ SW_K
+@@ -263,6 +292,19 @@ enum CAL_MODE {
+ SW_M
+ };
+
++#define MTK_PHY_LED_STATE_FORCE_ON 0
++#define MTK_PHY_LED_STATE_FORCE_BLINK 1
++#define MTK_PHY_LED_STATE_NETDEV 2
++
++struct mtk_socphy_priv {
++ unsigned long led_state;
++};
++
++struct mtk_socphy_shared {
++ u32 boottrap;
++ struct mtk_socphy_priv priv[4];
++};
++
+ static int mtk_socphy_read_page(struct phy_device *phydev)
+ {
+ return __phy_read(phydev, MTK_EXT_PAGE_ACCESS);
+@@ -1073,6 +1115,371 @@ static int mt798x_phy_config_init(struct
+ return mt798x_phy_calibration(phydev);
+ }
+
++static int mt798x_phy_hw_led_on_set(struct phy_device *phydev, u8 index,
++ bool on)
++{
++ unsigned int bit_on = MTK_PHY_LED_STATE_FORCE_ON + (index ? 16 : 0);
++ struct mtk_socphy_priv *priv = phydev->priv;
++ bool changed;
++
++ if (on)
++ changed = !test_and_set_bit(bit_on, &priv->led_state);
++ else
++ changed = !!test_and_clear_bit(bit_on, &priv->led_state);
++
++ changed |= !!test_and_clear_bit(MTK_PHY_LED_STATE_NETDEV +
++ (index ? 16 : 0), &priv->led_state);
++ if (changed)
++ return phy_modify_mmd(phydev, MDIO_MMD_VEND2, index ?
++ MTK_PHY_LED1_ON_CTRL : MTK_PHY_LED0_ON_CTRL,
++ MTK_PHY_LED_ON_MASK,
++ on ? MTK_PHY_LED_ON_FORCE_ON : 0);
++ else
++ return 0;
++}
++
++static int mt798x_phy_hw_led_blink_set(struct phy_device *phydev, u8 index,
++ bool blinking)
++{
++ unsigned int bit_blink = MTK_PHY_LED_STATE_FORCE_BLINK + (index ? 16 : 0);
++ struct mtk_socphy_priv *priv = phydev->priv;
++ bool changed;
++
++ if (blinking)
++ changed = !test_and_set_bit(bit_blink, &priv->led_state);
++ else
++ changed = !!test_and_clear_bit(bit_blink, &priv->led_state);
++
++ changed |= !!test_bit(MTK_PHY_LED_STATE_NETDEV +
++ (index ? 16 : 0), &priv->led_state);
++ if (changed)
++ return phy_write_mmd(phydev, MDIO_MMD_VEND2, index ?
++ MTK_PHY_LED1_BLINK_CTRL : MTK_PHY_LED0_BLINK_CTRL,
++ blinking ? MTK_PHY_LED_BLINK_FORCE_BLINK : 0);
++ else
++ return 0;
++}
++
++static int mt798x_phy_led_blink_set(struct phy_device *phydev, u8 index,
++ unsigned long *delay_on,
++ unsigned long *delay_off)
++{
++ bool blinking = false;
++ int err = 0;
++
++ if (index > 1)
++ return -EINVAL;
++
++ if (delay_on && delay_off && (*delay_on > 0) && (*delay_off > 0)) {
++ blinking = true;
++ *delay_on = 50;
++ *delay_off = 50;
++ }
++
++ err = mt798x_phy_hw_led_blink_set(phydev, index, blinking);
++ if (err)
++ return err;
++
++ return mt798x_phy_hw_led_on_set(phydev, index, false);
++}
++
++static int mt798x_phy_led_brightness_set(struct phy_device *phydev,
++ u8 index, enum led_brightness value)
++{
++ int err;
++
++ err = mt798x_phy_hw_led_blink_set(phydev, index, false);
++ if (err)
++ return err;
++
++ return mt798x_phy_hw_led_on_set(phydev, index, (value != LED_OFF));
++}
++
++static const unsigned long supported_triggers = (BIT(TRIGGER_NETDEV_FULL_DUPLEX) |
++ BIT(TRIGGER_NETDEV_HALF_DUPLEX) |
++ BIT(TRIGGER_NETDEV_LINK) |
++ BIT(TRIGGER_NETDEV_LINK_10) |
++ BIT(TRIGGER_NETDEV_LINK_100) |
++ BIT(TRIGGER_NETDEV_LINK_1000) |
++ BIT(TRIGGER_NETDEV_RX) |
++ BIT(TRIGGER_NETDEV_TX));
++
++static int mt798x_phy_led_hw_is_supported(struct phy_device *phydev, u8 index,
++ unsigned long rules)
++{
++ if (index > 1)
++ return -EINVAL;
++
++ /* All combinations of the supported triggers are allowed */
++ if (rules & ~supported_triggers)
++ return -EOPNOTSUPP;
++
++ return 0;
++};
++
++static int mt798x_phy_led_hw_control_get(struct phy_device *phydev, u8 index,
++ unsigned long *rules)
++{
++ unsigned int bit_blink = MTK_PHY_LED_STATE_FORCE_BLINK + (index ? 16 : 0);
++ unsigned int bit_netdev = MTK_PHY_LED_STATE_NETDEV + (index ? 16 : 0);
++ unsigned int bit_on = MTK_PHY_LED_STATE_FORCE_ON + (index ? 16 : 0);
++ struct mtk_socphy_priv *priv = phydev->priv;
++ int on, blink;
++
++ if (index > 1)
++ return -EINVAL;
++
++ on = phy_read_mmd(phydev, MDIO_MMD_VEND2,
++ index ? MTK_PHY_LED1_ON_CTRL : MTK_PHY_LED0_ON_CTRL);
++
++ if (on < 0)
++ return -EIO;
++
++ blink = phy_read_mmd(phydev, MDIO_MMD_VEND2,
++ index ? MTK_PHY_LED1_BLINK_CTRL :
++ MTK_PHY_LED0_BLINK_CTRL);
++ if (blink < 0)
++ return -EIO;
++
++ if ((on & (MTK_PHY_LED_ON_LINK1000 | MTK_PHY_LED_ON_LINK100 |
++ MTK_PHY_LED_ON_LINK10)) ||
++ (blink & (MTK_PHY_LED_BLINK_1000RX | MTK_PHY_LED_BLINK_100RX |
++ MTK_PHY_LED_BLINK_10RX | MTK_PHY_LED_BLINK_1000TX |
++ MTK_PHY_LED_BLINK_100TX | MTK_PHY_LED_BLINK_10TX)))
++ set_bit(bit_netdev, &priv->led_state);
++ else
++ clear_bit(bit_netdev, &priv->led_state);
++
++ if (on & MTK_PHY_LED_ON_FORCE_ON)
++ set_bit(bit_on, &priv->led_state);
++ else
++ clear_bit(bit_on, &priv->led_state);
++
++ if (blink & MTK_PHY_LED_BLINK_FORCE_BLINK)
++ set_bit(bit_blink, &priv->led_state);
++ else
++ clear_bit(bit_blink, &priv->led_state);
++
++ if (!rules)
++ return 0;
++
++ if (on & (MTK_PHY_LED_ON_LINK1000 | MTK_PHY_LED_ON_LINK100 | MTK_PHY_LED_ON_LINK10))
++ *rules |= BIT(TRIGGER_NETDEV_LINK);
++
++ if (on & MTK_PHY_LED_ON_LINK10)
++ *rules |= BIT(TRIGGER_NETDEV_LINK_10);
++
++ if (on & MTK_PHY_LED_ON_LINK100)
++ *rules |= BIT(TRIGGER_NETDEV_LINK_100);
++
++ if (on & MTK_PHY_LED_ON_LINK1000)
++ *rules |= BIT(TRIGGER_NETDEV_LINK_1000);
++
++ if (on & MTK_PHY_LED_ON_FDX)
++ *rules |= BIT(TRIGGER_NETDEV_FULL_DUPLEX);
++
++ if (on & MTK_PHY_LED_ON_HDX)
++ *rules |= BIT(TRIGGER_NETDEV_HALF_DUPLEX);
++
++ if (blink & (MTK_PHY_LED_BLINK_1000RX | MTK_PHY_LED_BLINK_100RX | MTK_PHY_LED_BLINK_10RX))
++ *rules |= BIT(TRIGGER_NETDEV_RX);
++
++ if (blink & (MTK_PHY_LED_BLINK_1000TX | MTK_PHY_LED_BLINK_100TX | MTK_PHY_LED_BLINK_10TX))
++ *rules |= BIT(TRIGGER_NETDEV_TX);
++
++ return 0;
++};
++
++static int mt798x_phy_led_hw_control_set(struct phy_device *phydev, u8 index,
++ unsigned long rules)
++{
++ unsigned int bit_netdev = MTK_PHY_LED_STATE_NETDEV + (index ? 16 : 0);
++ struct mtk_socphy_priv *priv = phydev->priv;
++ u16 on = 0, blink = 0;
++ int ret;
++
++ if (index > 1)
++ return -EINVAL;
++
++ if (rules & BIT(TRIGGER_NETDEV_FULL_DUPLEX))
++ on |= MTK_PHY_LED_ON_FDX;
++
++ if (rules & BIT(TRIGGER_NETDEV_HALF_DUPLEX))
++ on |= MTK_PHY_LED_ON_HDX;
++
++ if (rules & (BIT(TRIGGER_NETDEV_LINK_10) | BIT(TRIGGER_NETDEV_LINK)))
++ on |= MTK_PHY_LED_ON_LINK10;
++
++ if (rules & (BIT(TRIGGER_NETDEV_LINK_100) | BIT(TRIGGER_NETDEV_LINK)))
++ on |= MTK_PHY_LED_ON_LINK100;
++
++ if (rules & (BIT(TRIGGER_NETDEV_LINK_1000) | BIT(TRIGGER_NETDEV_LINK)))
++ on |= MTK_PHY_LED_ON_LINK1000;
++
++ if (rules & BIT(TRIGGER_NETDEV_RX)) {
++ blink |= MTK_PHY_LED_BLINK_10RX |
++ MTK_PHY_LED_BLINK_100RX |
++ MTK_PHY_LED_BLINK_1000RX;
++ }
++
++ if (rules & BIT(TRIGGER_NETDEV_TX)) {
++ blink |= MTK_PHY_LED_BLINK_10TX |
++ MTK_PHY_LED_BLINK_100TX |
++ MTK_PHY_LED_BLINK_1000TX;
++ }
++
++ if (blink || on)
++ set_bit(bit_netdev, &priv->led_state);
++ else
++ clear_bit(bit_netdev, &priv->led_state);
++
++ ret = phy_modify_mmd(phydev, MDIO_MMD_VEND2, index ?
++ MTK_PHY_LED1_ON_CTRL :
++ MTK_PHY_LED0_ON_CTRL,
++ MTK_PHY_LED_ON_FDX |
++ MTK_PHY_LED_ON_HDX |
++ MTK_PHY_LED_ON_LINK10 |
++ MTK_PHY_LED_ON_LINK100 |
++ MTK_PHY_LED_ON_LINK1000,
++ on);
++
++ if (ret)
++ return ret;
++
++ return phy_write_mmd(phydev, MDIO_MMD_VEND2, index ?
++ MTK_PHY_LED1_BLINK_CTRL :
++ MTK_PHY_LED0_BLINK_CTRL, blink);
++};
++
++static bool mt7988_phy_led_get_polarity(struct phy_device *phydev, int led_num)
++{
++ struct mtk_socphy_shared *priv = phydev->shared->priv;
++ u32 polarities;
++
++ if (led_num == 0)
++ polarities = ~(priv->boottrap);
++ else
++ polarities = MTK_PHY_LED1_DEFAULT_POLARITIES;
++
++ if (polarities & BIT(phydev->mdio.addr))
++ return true;
++
++ return false;
++}
++
++static int mt7988_phy_fix_leds_polarities(struct phy_device *phydev)
++{
++ struct pinctrl *pinctrl;
++ int index;
++
++ /* Setup LED polarity according to bootstrap use of LED pins */
++ for (index = 0; index < 2; ++index)
++ phy_modify_mmd(phydev, MDIO_MMD_VEND2, index ?
++ MTK_PHY_LED1_ON_CTRL : MTK_PHY_LED0_ON_CTRL,
++ MTK_PHY_LED_ON_POLARITY,
++ mt7988_phy_led_get_polarity(phydev, index) ?
++ MTK_PHY_LED_ON_POLARITY : 0);
++
++ /* Only now setup pinctrl to avoid bogus blinking */
++ pinctrl = devm_pinctrl_get_select(&phydev->mdio.dev, "gbe-led");
++ if (IS_ERR(pinctrl))
++ dev_err(&phydev->mdio.bus->dev, "Failed to setup PHY LED pinctrl\n");
++
++ return 0;
++}
++
++static int mt7988_phy_probe_shared(struct phy_device *phydev)
++{
++ struct device_node *np = dev_of_node(&phydev->mdio.bus->dev);
++ struct mtk_socphy_shared *shared = phydev->shared->priv;
++ struct regmap *regmap;
++ u32 reg;
++ int ret;
++
++ /* The LED0 of the 4 PHYs in MT7988 are wired to SoC pins LED_A, LED_B,
++ * LED_C and LED_D respectively. At the same time those pins are used to
++ * bootstrap configuration of the reference clock source (LED_A),
++ * DRAM DDRx16b x2/x1 (LED_B) and boot device (LED_C, LED_D).
++ * In practise this is done using a LED and a resistor pulling the pin
++ * either to GND or to VIO.
++ * The detected value at boot time is accessible at run-time using the
++ * TPBANK0 register located in the gpio base of the pinctrl, in order
++ * to read it here it needs to be referenced by a phandle called
++ * 'mediatek,pio' in the MDIO bus hosting the PHY.
++ * The 4 bits in TPBANK0 are kept as package shared data and are used to
++ * set LED polarity for each of the LED0.
++ */
++ regmap = syscon_regmap_lookup_by_phandle(np, "mediatek,pio");
++ if (IS_ERR(regmap))
++ return PTR_ERR(regmap);
++
++ ret = regmap_read(regmap, RG_GPIO_MISC_TPBANK0, ®);
++ if (ret)
++ return ret;
++
++ shared->boottrap = FIELD_GET(RG_GPIO_MISC_TPBANK0_BOOTMODE, reg);
++
++ return 0;
++}
++
++static void mt798x_phy_leds_state_init(struct phy_device *phydev)
++{
++ int i;
++
++ for (i = 0; i < 2; ++i)
++ mt798x_phy_led_hw_control_get(phydev, i, NULL);
++}
++
++static int mt7988_phy_probe(struct phy_device *phydev)
++{
++ struct mtk_socphy_shared *shared;
++ struct mtk_socphy_priv *priv;
++ int err;
++
++ if (phydev->mdio.addr > 3)
++ return -EINVAL;
++
++ err = devm_phy_package_join(&phydev->mdio.dev, phydev, 0,
++ sizeof(struct mtk_socphy_shared));
++ if (err)
++ return err;
++
++ if (phy_package_probe_once(phydev)) {
++ err = mt7988_phy_probe_shared(phydev);
++ if (err)
++ return err;
++ }
++
++ shared = phydev->shared->priv;
++ priv = &shared->priv[phydev->mdio.addr];
++
++ phydev->priv = priv;
++
++ mt798x_phy_leds_state_init(phydev);
++
++ err = mt7988_phy_fix_leds_polarities(phydev);
++ if (err)
++ return err;
++
++ return mt798x_phy_calibration(phydev);
++}
++
++static int mt7981_phy_probe(struct phy_device *phydev)
++{
++ struct mtk_socphy_priv *priv;
++
++ priv = devm_kzalloc(&phydev->mdio.dev, sizeof(struct mtk_socphy_priv),
++ GFP_KERNEL);
++ if (!priv)
++ return -ENOMEM;
++
++ phydev->priv = priv;
++
++ mt798x_phy_leds_state_init(phydev);
++
++ return mt798x_phy_calibration(phydev);
++}
++
+ static struct phy_driver mtk_socphy_driver[] = {
+ {
+ PHY_ID_MATCH_EXACT(MTK_GPHY_ID_MT7981),
+@@ -1080,11 +1487,16 @@ static struct phy_driver mtk_socphy_driv
+ .config_init = mt798x_phy_config_init,
+ .config_intr = genphy_no_config_intr,
+ .handle_interrupt = genphy_handle_interrupt_no_ack,
+- .probe = mt798x_phy_calibration,
++ .probe = mt7981_phy_probe,
+ .suspend = genphy_suspend,
+ .resume = genphy_resume,
+ .read_page = mtk_socphy_read_page,
+ .write_page = mtk_socphy_write_page,
++ .led_blink_set = mt798x_phy_led_blink_set,
++ .led_brightness_set = mt798x_phy_led_brightness_set,
++ .led_hw_is_supported = mt798x_phy_led_hw_is_supported,
++ .led_hw_control_set = mt798x_phy_led_hw_control_set,
++ .led_hw_control_get = mt798x_phy_led_hw_control_get,
+ },
+ {
+ PHY_ID_MATCH_EXACT(MTK_GPHY_ID_MT7988),
+@@ -1092,11 +1504,16 @@ static struct phy_driver mtk_socphy_driv
+ .config_init = mt798x_phy_config_init,
+ .config_intr = genphy_no_config_intr,
+ .handle_interrupt = genphy_handle_interrupt_no_ack,
+- .probe = mt798x_phy_calibration,
++ .probe = mt7988_phy_probe,
+ .suspend = genphy_suspend,
+ .resume = genphy_resume,
+ .read_page = mtk_socphy_read_page,
+ .write_page = mtk_socphy_write_page,
++ .led_blink_set = mt798x_phy_led_blink_set,
++ .led_brightness_set = mt798x_phy_led_brightness_set,
++ .led_hw_is_supported = mt798x_phy_led_hw_is_supported,
++ .led_hw_control_set = mt798x_phy_led_hw_control_set,
++ .led_hw_control_get = mt798x_phy_led_hw_control_get,
+ },
+ };
+
--- /dev/null
+From a969b663c866129ed9eb217785a6574fbe826f1d Mon Sep 17 00:00:00 2001
+From: Daniel Golle <daniel@makrotopia.org>
+Date: Thu, 6 Apr 2023 23:36:50 +0100
+Subject: [PATCH] net: phy: mxl-gpy: don't use SGMII AN if using phylink
+
+MAC drivers using phylink expect SGMII in-band-status to be switched off
+when attached to a PHY. Make sure this is the case also for mxl-gpy which
+keeps SGMII in-band-status in case of SGMII interface mode is used.
+
+Signed-off-by: Daniel Golle <daniel@makrotopia.org>
+---
+ drivers/net/phy/mxl-gpy.c | 19 ++++++++++++++++---
+ 1 file changed, 16 insertions(+), 3 deletions(-)
+
+--- a/drivers/net/phy/mxl-gpy.c
++++ b/drivers/net/phy/mxl-gpy.c
+@@ -371,8 +371,11 @@ static bool gpy_2500basex_chk(struct phy
+
+ phydev->speed = SPEED_2500;
+ phydev->interface = PHY_INTERFACE_MODE_2500BASEX;
+- phy_modify_mmd(phydev, MDIO_MMD_VEND1, VSPEC1_SGMII_CTRL,
+- VSPEC1_SGMII_CTRL_ANEN, 0);
++
++ if (!phydev->phylink)
++ phy_modify_mmd(phydev, MDIO_MMD_VEND1, VSPEC1_SGMII_CTRL,
++ VSPEC1_SGMII_CTRL_ANEN, 0);
++
+ return true;
+ }
+
+@@ -396,6 +399,14 @@ static int gpy_config_aneg(struct phy_de
+ u32 adv;
+ int ret;
+
++ /* Disable SGMII auto-negotiation if using phylink */
++ if (phydev->phylink) {
++ ret = phy_modify_mmd(phydev, MDIO_MMD_VEND1, VSPEC1_SGMII_CTRL,
++ VSPEC1_SGMII_CTRL_ANEN, 0);
++ if (ret < 0)
++ return ret;
++ }
++
+ if (phydev->autoneg == AUTONEG_DISABLE) {
+ /* Configure half duplex with genphy_setup_forced,
+ * because genphy_c45_pma_setup_forced does not support.
+@@ -486,6 +497,8 @@ static void gpy_update_interface(struct
+ switch (phydev->speed) {
+ case SPEED_2500:
+ phydev->interface = PHY_INTERFACE_MODE_2500BASEX;
++ if (phydev->phylink)
++ break;
+ ret = phy_modify_mmd(phydev, MDIO_MMD_VEND1, VSPEC1_SGMII_CTRL,
+ VSPEC1_SGMII_CTRL_ANEN, 0);
+ if (ret < 0)
+@@ -497,7 +510,7 @@ static void gpy_update_interface(struct
+ case SPEED_100:
+ case SPEED_10:
+ phydev->interface = PHY_INTERFACE_MODE_SGMII;
+- if (gpy_sgmii_aneg_en(phydev))
++ if (phydev->phylink || gpy_sgmii_aneg_en(phydev))
+ break;
+ /* Enable and restart SGMII ANEG for 10/100/1000Mbps link speed
+ * if ANEG is disabled (in 2500-BaseX mode).
--- /dev/null
+From 128dc09b0af36772062142ce9e85b19c84ac789a Mon Sep 17 00:00:00 2001
+From: Daniel Golle <daniel@makrotopia.org>
+Date: Tue, 28 Feb 2023 17:53:37 +0000
+Subject: [PATCH] net: phy: add driver for MediaTek 2.5G PHY
+
+Signed-off-by: Daniel Golle <daniel@makrotopia.org>
+---
+ drivers/net/phy/Kconfig | 7 ++
+ drivers/net/phy/Makefile | 1 +
+ drivers/net/phy/mediatek-2p5ge.c | 220 +++++++++++++++++++++++++++++++
+ 3 files changed, 226 insertions(+)
+ create mode 100644 drivers/net/phy/mediatek-2p5ge.c
+
+--- a/drivers/net/phy/Kconfig
++++ b/drivers/net/phy/Kconfig
+@@ -326,6 +326,13 @@ config MEDIATEK_GE_SOC_PHY
+ present in the SoCs efuse and will dynamically calibrate VCM
+ (common-mode voltage) during startup.
+
++config MEDIATEK_2P5G_PHY
++ tristate "MediaTek 2.5G Ethernet PHY"
++ depends on (ARCH_MEDIATEK && ARM64) || COMPILE_TEST
++ default NET_MEDIATEK_SOC
++ help
++ Supports the MediaTek 2.5G Ethernet PHY.
++
+ config MICREL_PHY
+ tristate "Micrel PHYs"
+ depends on PTP_1588_CLOCK_OPTIONAL
+--- a/drivers/net/phy/Makefile
++++ b/drivers/net/phy/Makefile
+@@ -79,6 +79,7 @@ obj-$(CONFIG_MARVELL_10G_PHY) += marvell
+ obj-$(CONFIG_MARVELL_PHY) += marvell.o
+ obj-$(CONFIG_MARVELL_88X2222_PHY) += marvell-88x2222.o
+ obj-$(CONFIG_MAXLINEAR_GPHY) += mxl-gpy.o
++obj-$(CONFIG_MEDIATEK_2P5G_PHY) += mediatek-2p5ge.o
+ obj-$(CONFIG_MEDIATEK_GE_PHY) += mediatek-ge.o
+ obj-$(CONFIG_MEDIATEK_GE_SOC_PHY) += mediatek-ge-soc.o
+ obj-$(CONFIG_MESON_GXL_PHY) += meson-gxl.o
--- /dev/null
+From f2195279c234c0f618946424b8236026126bc595 Mon Sep 17 00:00:00 2001
+Message-ID: <f2195279c234c0f618946424b8236026126bc595.1706071311.git.daniel@makrotopia.org>
+From: Daniel Golle <daniel@makrotopia.org>
+Date: Wed, 24 Jan 2024 02:27:04 +0000
+Subject: [PATCH net] net: phy: mediatek-ge-soc: sync driver with MediaTek SDK
+To: Daniel Golle <daniel@makrotopia.org>,
+ Qingfang Deng <dqfext@gmail.com>,
+ SkyLake Huang <SkyLake.Huang@mediatek.com>,
+ Andrew Lunn <andrew@lunn.ch>,
+ Heiner Kallweit <hkallweit1@gmail.com>,
+ Russell King <linux@armlinux.org.uk>,
+ David S. Miller <davem@davemloft.net>,
+ Eric Dumazet <edumazet@google.com>,
+ Jakub Kicinski <kuba@kernel.org>,
+ Paolo Abeni <pabeni@redhat.com>,
+ Matthias Brugger <matthias.bgg@gmail.com>,
+ AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>,
+ netdev@vger.kernel.org,
+ linux-kernel@vger.kernel.org,
+ linux-arm-kernel@lists.infradead.org,
+ linux-mediatek@lists.infradead.org
+
+Sync initialization and calibration routines with MediaTek's reference
+driver. Improves compliance and resolves link stability issues with
+CH340 IoT devices connected to MT798x built-in PHYs.
+
+Fixes: 98c485eaf509 ("net: phy: add driver for MediaTek SoC built-in GE PHYs")
+Signed-off-by: Daniel Golle <daniel@makrotopia.org>
+---
+ drivers/net/phy/mediatek-ge-soc.c | 147 ++++++++++++++++--------------
+ 1 file changed, 81 insertions(+), 66 deletions(-)
+
+--- a/drivers/net/phy/mediatek-ge-soc.c
++++ b/drivers/net/phy/mediatek-ge-soc.c
+@@ -491,7 +491,7 @@ static int tx_r50_fill_result(struct phy
+ u16 reg, val;
+
+ if (phydev->drv->phy_id == MTK_GPHY_ID_MT7988)
+- bias = -2;
++ bias = -1;
+
+ val = clamp_val(bias + tx_r50_cal_val, 0, 63);
+
+@@ -707,6 +707,11 @@ restore:
+ static void mt798x_phy_common_finetune(struct phy_device *phydev)
+ {
+ phy_select_page(phydev, MTK_PHY_PAGE_EXTENDED_52B5);
++ /* SlvDSPreadyTime = 24, MasDSPreadyTime = 24 */
++ __phy_write(phydev, 0x11, 0xc71);
++ __phy_write(phydev, 0x12, 0xc);
++ __phy_write(phydev, 0x10, 0x8fae);
++
+ /* EnabRandUpdTrig = 1 */
+ __phy_write(phydev, 0x11, 0x2f00);
+ __phy_write(phydev, 0x12, 0xe);
+@@ -717,15 +722,56 @@ static void mt798x_phy_common_finetune(s
+ __phy_write(phydev, 0x12, 0x0);
+ __phy_write(phydev, 0x10, 0x83aa);
+
+- /* TrFreeze = 0 */
++ /* FfeUpdGainForce = 1(Enable), FfeUpdGainForceVal = 4 */
++ __phy_write(phydev, 0x11, 0x240);
++ __phy_write(phydev, 0x12, 0x0);
++ __phy_write(phydev, 0x10, 0x9680);
++
++ /* TrFreeze = 0 (mt7988 default) */
+ __phy_write(phydev, 0x11, 0x0);
+ __phy_write(phydev, 0x12, 0x0);
+ __phy_write(phydev, 0x10, 0x9686);
+
++ /* SSTrKp100 = 5 */
++ /* SSTrKf100 = 6 */
++ /* SSTrKp1000Mas = 5 */
++ /* SSTrKf1000Mas = 6 */
+ /* SSTrKp1000Slv = 5 */
++ /* SSTrKf1000Slv = 6 */
+ __phy_write(phydev, 0x11, 0xbaef);
+ __phy_write(phydev, 0x12, 0x2e);
+ __phy_write(phydev, 0x10, 0x968c);
++ phy_restore_page(phydev, MTK_PHY_PAGE_STANDARD, 0);
++}
++
++static void mt7981_phy_finetune(struct phy_device *phydev)
++{
++ u16 val[8] = { 0x01ce, 0x01c1,
++ 0x020f, 0x0202,
++ 0x03d0, 0x03c0,
++ 0x0013, 0x0005 };
++ int i, k;
++
++ /* 100M eye finetune:
++ * Keep middle level of TX MLT3 shapper as default.
++ * Only change TX MLT3 overshoot level here.
++ */
++ for (k = 0, i = 1; i < 12; i++) {
++ if (i % 3 == 0)
++ continue;
++ phy_write_mmd(phydev, MDIO_MMD_VEND1, i, val[k++]);
++ }
++
++ phy_select_page(phydev, MTK_PHY_PAGE_EXTENDED_52B5);
++ /* ResetSyncOffset = 6 */
++ __phy_write(phydev, 0x11, 0x600);
++ __phy_write(phydev, 0x12, 0x0);
++ __phy_write(phydev, 0x10, 0x8fc0);
++
++ /* VgaDecRate = 1 */
++ __phy_write(phydev, 0x11, 0x4c2a);
++ __phy_write(phydev, 0x12, 0x3e);
++ __phy_write(phydev, 0x10, 0x8fa4);
+
+ /* MrvlTrFix100Kp = 3, MrvlTrFix100Kf = 2,
+ * MrvlTrFix1000Kp = 3, MrvlTrFix1000Kf = 2
+@@ -740,7 +786,7 @@ static void mt798x_phy_common_finetune(s
+ __phy_write(phydev, 0x10, 0x8ec0);
+ phy_restore_page(phydev, MTK_PHY_PAGE_STANDARD, 0);
+
+- /* TR_OPEN_LOOP_EN = 1, lpf_x_average = 9*/
++ /* TR_OPEN_LOOP_EN = 1, lpf_x_average = 9 */
+ phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_DEV1E_REG234,
+ MTK_PHY_TR_OPEN_LOOP_EN_MASK | MTK_PHY_LPF_X_AVERAGE_MASK,
+ BIT(0) | FIELD_PREP(MTK_PHY_LPF_X_AVERAGE_MASK, 0x9));
+@@ -773,48 +819,6 @@ static void mt798x_phy_common_finetune(s
+ phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_LDO_OUTPUT_V, 0x2222);
+ }
+
+-static void mt7981_phy_finetune(struct phy_device *phydev)
+-{
+- u16 val[8] = { 0x01ce, 0x01c1,
+- 0x020f, 0x0202,
+- 0x03d0, 0x03c0,
+- 0x0013, 0x0005 };
+- int i, k;
+-
+- /* 100M eye finetune:
+- * Keep middle level of TX MLT3 shapper as default.
+- * Only change TX MLT3 overshoot level here.
+- */
+- for (k = 0, i = 1; i < 12; i++) {
+- if (i % 3 == 0)
+- continue;
+- phy_write_mmd(phydev, MDIO_MMD_VEND1, i, val[k++]);
+- }
+-
+- phy_select_page(phydev, MTK_PHY_PAGE_EXTENDED_52B5);
+- /* SlvDSPreadyTime = 24, MasDSPreadyTime = 24 */
+- __phy_write(phydev, 0x11, 0xc71);
+- __phy_write(phydev, 0x12, 0xc);
+- __phy_write(phydev, 0x10, 0x8fae);
+-
+- /* ResetSyncOffset = 6 */
+- __phy_write(phydev, 0x11, 0x600);
+- __phy_write(phydev, 0x12, 0x0);
+- __phy_write(phydev, 0x10, 0x8fc0);
+-
+- /* VgaDecRate = 1 */
+- __phy_write(phydev, 0x11, 0x4c2a);
+- __phy_write(phydev, 0x12, 0x3e);
+- __phy_write(phydev, 0x10, 0x8fa4);
+-
+- /* FfeUpdGainForce = 4 */
+- __phy_write(phydev, 0x11, 0x240);
+- __phy_write(phydev, 0x12, 0x0);
+- __phy_write(phydev, 0x10, 0x9680);
+-
+- phy_restore_page(phydev, MTK_PHY_PAGE_STANDARD, 0);
+-}
+-
+ static void mt7988_phy_finetune(struct phy_device *phydev)
+ {
+ u16 val[12] = { 0x0187, 0x01cd, 0x01c8, 0x0182,
+@@ -829,17 +833,7 @@ static void mt7988_phy_finetune(struct p
+ /* TCT finetune */
+ phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_TX_FILTER, 0x5);
+
+- /* Disable TX power saving */
+- phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RXADC_CTRL_RG7,
+- MTK_PHY_DA_AD_BUF_BIAS_LP_MASK, 0x3 << 8);
+-
+ phy_select_page(phydev, MTK_PHY_PAGE_EXTENDED_52B5);
+-
+- /* SlvDSPreadyTime = 24, MasDSPreadyTime = 12 */
+- __phy_write(phydev, 0x11, 0x671);
+- __phy_write(phydev, 0x12, 0xc);
+- __phy_write(phydev, 0x10, 0x8fae);
+-
+ /* ResetSyncOffset = 5 */
+ __phy_write(phydev, 0x11, 0x500);
+ __phy_write(phydev, 0x12, 0x0);
+@@ -847,13 +841,27 @@ static void mt7988_phy_finetune(struct p
+
+ /* VgaDecRate is 1 at default on mt7988 */
+
+- phy_restore_page(phydev, MTK_PHY_PAGE_STANDARD, 0);
++ /* MrvlTrFix100Kp = 6, MrvlTrFix100Kf = 7,
++ * MrvlTrFix1000Kp = 6, MrvlTrFix1000Kf = 7
++ */
++ __phy_write(phydev, 0x11, 0xb90a);
++ __phy_write(phydev, 0x12, 0x6f);
++ __phy_write(phydev, 0x10, 0x8f82);
++
++ /* RemAckCntLimitCtrl = 1 */
++ __phy_write(phydev, 0x11, 0xfbba);
++ __phy_write(phydev, 0x12, 0xc3);
++ __phy_write(phydev, 0x10, 0x87f8);
+
+- phy_select_page(phydev, MTK_PHY_PAGE_EXTENDED_2A30);
+- /* TxClkOffset = 2 */
+- __phy_modify(phydev, MTK_PHY_ANARG_RG, MTK_PHY_TCLKOFFSET_MASK,
+- FIELD_PREP(MTK_PHY_TCLKOFFSET_MASK, 0x2));
+ phy_restore_page(phydev, MTK_PHY_PAGE_STANDARD, 0);
++
++ /* TR_OPEN_LOOP_EN = 1, lpf_x_average = 10 */
++ phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_DEV1E_REG234,
++ MTK_PHY_TR_OPEN_LOOP_EN_MASK | MTK_PHY_LPF_X_AVERAGE_MASK,
++ BIT(0) | FIELD_PREP(MTK_PHY_LPF_X_AVERAGE_MASK, 0xa));
++
++ /* rg_tr_lpf_cnt_val = 1023 */
++ phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_LPF_CNT_VAL, 0x3ff);
+ }
+
+ static void mt798x_phy_eee(struct phy_device *phydev)
+@@ -886,11 +894,11 @@ static void mt798x_phy_eee(struct phy_de
+ MTK_PHY_LPI_SLV_SEND_TX_EN,
+ FIELD_PREP(MTK_PHY_LPI_SLV_SEND_TX_TIMER_MASK, 0x120));
+
+- phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_DEV1E_REG239,
+- MTK_PHY_LPI_SEND_LOC_TIMER_MASK |
+- MTK_PHY_LPI_TXPCS_LOC_RCV,
+- FIELD_PREP(MTK_PHY_LPI_SEND_LOC_TIMER_MASK, 0x117));
++ /* Keep MTK_PHY_LPI_SEND_LOC_TIMER as 375 */
++ phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_DEV1E_REG239,
++ MTK_PHY_LPI_TXPCS_LOC_RCV);
+
++ /* This also fixes some IoT issues, such as CH340 */
+ phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_DEV1E_REG2C7,
+ MTK_PHY_MAX_GAIN_MASK | MTK_PHY_MIN_GAIN_MASK,
+ FIELD_PREP(MTK_PHY_MAX_GAIN_MASK, 0x8) |
+@@ -924,7 +932,7 @@ static void mt798x_phy_eee(struct phy_de
+ __phy_write(phydev, 0x12, 0x0);
+ __phy_write(phydev, 0x10, 0x9690);
+
+- /* REG_EEE_st2TrKf1000 = 3 */
++ /* REG_EEE_st2TrKf1000 = 2 */
+ __phy_write(phydev, 0x11, 0x114f);
+ __phy_write(phydev, 0x12, 0x2);
+ __phy_write(phydev, 0x10, 0x969a);
+@@ -949,7 +957,7 @@ static void mt798x_phy_eee(struct phy_de
+ __phy_write(phydev, 0x12, 0x0);
+ __phy_write(phydev, 0x10, 0x96b8);
+
+- /* REGEEE_wake_slv_tr_wait_dfesigdet_en = 1 */
++ /* REGEEE_wake_slv_tr_wait_dfesigdet_en = 0 */
+ __phy_write(phydev, 0x11, 0x1463);
+ __phy_write(phydev, 0x12, 0x0);
+ __phy_write(phydev, 0x10, 0x96ca);
+@@ -1461,6 +1469,13 @@ static int mt7988_phy_probe(struct phy_d
+ if (err)
+ return err;
+
++ /* Disable TX power saving at probing to:
++ * 1. Meet common mode compliance test criteria
++ * 2. Make sure that TX-VCM calibration works fine
++ */
++ phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RXADC_CTRL_RG7,
++ MTK_PHY_DA_AD_BUF_BIAS_LP_MASK, 0x3 << 8);
++
+ return mt798x_phy_calibration(phydev);
+ }
+
--- /dev/null
+--- a/drivers/pwm/pwm-mediatek.c
++++ b/drivers/pwm/pwm-mediatek.c
+@@ -329,6 +329,12 @@ static const struct pwm_mediatek_of_data
+ .has_ck_26m_sel = true,
+ };
+
++static const struct pwm_mediatek_of_data mt7986_pwm_data = {
++ .num_pwms = 2,
++ .pwm45_fixup = false,
++ .has_ck_26m_sel = true,
++};
++
+ static const struct pwm_mediatek_of_data mt8516_pwm_data = {
+ .num_pwms = 5,
+ .pwm45_fixup = false,
+@@ -342,6 +348,7 @@ static const struct of_device_id pwm_med
+ { .compatible = "mediatek,mt7623-pwm", .data = &mt7623_pwm_data },
+ { .compatible = "mediatek,mt7628-pwm", .data = &mt7628_pwm_data },
+ { .compatible = "mediatek,mt7629-pwm", .data = &mt7629_pwm_data },
++ { .compatible = "mediatek,mt7986-pwm", .data = &mt7986_pwm_data },
+ { .compatible = "mediatek,mt8183-pwm", .data = &mt8183_pwm_data },
+ { .compatible = "mediatek,mt8365-pwm", .data = &mt8365_pwm_data },
+ { .compatible = "mediatek,mt8516-pwm", .data = &mt8516_pwm_data },
--- /dev/null
+From fae82621ac33e2a4a96220c56e90d1ec6237d394 Mon Sep 17 00:00:00 2001
+From: Sam Shih <sam.shih@mediatek.com>
+Date: Sun, 6 Nov 2022 09:01:12 +0100
+Subject: [PATCH] pinctrl: mediatek: extend pinctrl-moore to support new bias
+ functions
+
+Commit fb34a9ae383a ("pinctrl: mediatek: support rsel feature")
+introduced SoC specify 'pull_type' attribute to mtk_pinconf_bias_set_combo
+and mtk_pinconf_bias_get_combo, and make the functions able to support
+almost all Mediatek SoCs that use pinctrl-mtk-common-v2.c.
+
+This patch enables pinctrl_moore to support these functions.
+
+Signed-off-by: Sam Shih <sam.shih@mediatek.com>
+Signed-off-by: Frank Wunderlich <frank-w@public-files.de>
+Reviewed-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
+Link: https://lore.kernel.org/r/20221106080114.7426-6-linux@fw-web.de
+Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
+---
+ drivers/pinctrl/mediatek/pinctrl-moore.c | 49 ++++++++++++++++++++----
+ 1 file changed, 42 insertions(+), 7 deletions(-)
+
+--- a/drivers/pinctrl/mediatek/pinctrl-moore.c
++++ b/drivers/pinctrl/mediatek/pinctrl-moore.c
+@@ -8,6 +8,7 @@
+ *
+ */
+
++#include <dt-bindings/pinctrl/mt65xx.h>
+ #include <linux/gpio/driver.h>
+ #include "pinctrl-moore.h"
+
+@@ -105,7 +106,7 @@ static int mtk_pinconf_get(struct pinctr
+ {
+ struct mtk_pinctrl *hw = pinctrl_dev_get_drvdata(pctldev);
+ u32 param = pinconf_to_config_param(*config);
+- int val, val2, err, reg, ret = 1;
++ int val, val2, err, pullup, reg, ret = 1;
+ const struct mtk_pin_desc *desc;
+
+ desc = (const struct mtk_pin_desc *)&hw->soc->pins[pin];
+@@ -114,7 +115,13 @@ static int mtk_pinconf_get(struct pinctr
+
+ switch (param) {
+ case PIN_CONFIG_BIAS_DISABLE:
+- if (hw->soc->bias_disable_get) {
++ if (hw->soc->bias_get_combo) {
++ err = hw->soc->bias_get_combo(hw, desc, &pullup, &ret);
++ if (err)
++ return err;
++ if (ret != MTK_PUPD_SET_R1R0_00 && ret != MTK_DISABLE)
++ return -EINVAL;
++ } else if (hw->soc->bias_disable_get) {
+ err = hw->soc->bias_disable_get(hw, desc, &ret);
+ if (err)
+ return err;
+@@ -123,7 +130,15 @@ static int mtk_pinconf_get(struct pinctr
+ }
+ break;
+ case PIN_CONFIG_BIAS_PULL_UP:
+- if (hw->soc->bias_get) {
++ if (hw->soc->bias_get_combo) {
++ err = hw->soc->bias_get_combo(hw, desc, &pullup, &ret);
++ if (err)
++ return err;
++ if (ret == MTK_PUPD_SET_R1R0_00 || ret == MTK_DISABLE)
++ return -EINVAL;
++ if (!pullup)
++ return -EINVAL;
++ } else if (hw->soc->bias_get) {
+ err = hw->soc->bias_get(hw, desc, 1, &ret);
+ if (err)
+ return err;
+@@ -132,7 +147,15 @@ static int mtk_pinconf_get(struct pinctr
+ }
+ break;
+ case PIN_CONFIG_BIAS_PULL_DOWN:
+- if (hw->soc->bias_get) {
++ if (hw->soc->bias_get_combo) {
++ err = hw->soc->bias_get_combo(hw, desc, &pullup, &ret);
++ if (err)
++ return err;
++ if (ret == MTK_PUPD_SET_R1R0_00 || ret == MTK_DISABLE)
++ return -EINVAL;
++ if (pullup)
++ return -EINVAL;
++ } else if (hw->soc->bias_get) {
+ err = hw->soc->bias_get(hw, desc, 0, &ret);
+ if (err)
+ return err;
+@@ -235,7 +258,11 @@ static int mtk_pinconf_set(struct pinctr
+
+ switch (param) {
+ case PIN_CONFIG_BIAS_DISABLE:
+- if (hw->soc->bias_disable_set) {
++ if (hw->soc->bias_set_combo) {
++ err = hw->soc->bias_set_combo(hw, desc, 0, MTK_DISABLE);
++ if (err)
++ return err;
++ } else if (hw->soc->bias_disable_set) {
+ err = hw->soc->bias_disable_set(hw, desc);
+ if (err)
+ return err;
+@@ -244,7 +271,11 @@ static int mtk_pinconf_set(struct pinctr
+ }
+ break;
+ case PIN_CONFIG_BIAS_PULL_UP:
+- if (hw->soc->bias_set) {
++ if (hw->soc->bias_set_combo) {
++ err = hw->soc->bias_set_combo(hw, desc, 1, arg);
++ if (err)
++ return err;
++ } else if (hw->soc->bias_set) {
+ err = hw->soc->bias_set(hw, desc, 1);
+ if (err)
+ return err;
+@@ -253,7 +284,11 @@ static int mtk_pinconf_set(struct pinctr
+ }
+ break;
+ case PIN_CONFIG_BIAS_PULL_DOWN:
+- if (hw->soc->bias_set) {
++ if (hw->soc->bias_set_combo) {
++ err = hw->soc->bias_set_combo(hw, desc, 0, arg);
++ if (err)
++ return err;
++ } else if (hw->soc->bias_set) {
+ err = hw->soc->bias_set(hw, desc, 0);
+ if (err)
+ return err;
--- /dev/null
+From f167da186acf90847e1a6d3716e253825a6218ec Mon Sep 17 00:00:00 2001
+From: Randy Dunlap <rdunlap@infradead.org>
+Date: Thu, 12 Jan 2023 22:44:49 -0800
+Subject: [PATCH 01/42] thermal/drivers/mtk_thermal: Fix kernel-doc function
+ name
+
+Use the correct function name in a kernel-doc comment to prevent
+a warning:
+
+drivers/thermal/mtk_thermal.c:562: warning: expecting prototype for raw_to_mcelsius(). Prototype was for raw_to_mcelsius_v1() instead
+
+Signed-off-by: Randy Dunlap <rdunlap@infradead.org>
+Cc: "Rafael J. Wysocki" <rafael@kernel.org>
+Cc: Daniel Lezcano <daniel.lezcano@linaro.org>
+Cc: Amit Kucheria <amitk@kernel.org>
+Cc: Zhang Rui <rui.zhang@intel.com>
+Cc: Matthias Brugger <matthias.bgg@gmail.com>
+Cc: linux-pm@vger.kernel.org
+Cc: linux-arm-kernel@lists.infradead.org
+Cc: linux-mediatek@lists.infradead.org
+Link: https://lore.kernel.org/r/20230113064449.15061-1-rdunlap@infradead.org
+Signed-off-by: Daniel Lezcano <daniel.lezcano@linaro.org>
+---
+ drivers/thermal/mtk_thermal.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/drivers/thermal/mtk_thermal.c
++++ b/drivers/thermal/mtk_thermal.c
+@@ -550,7 +550,7 @@ static const struct mtk_thermal_data mt8
+ };
+
+ /**
+- * raw_to_mcelsius - convert a raw ADC value to mcelsius
++ * raw_to_mcelsius_v1 - convert a raw ADC value to mcelsius
+ * @mt: The thermal controller
+ * @sensno: sensor number
+ * @raw: raw ADC value
--- /dev/null
+From 255509232417ee71fd606cb957d44cf6544f0c43 Mon Sep 17 00:00:00 2001
+From: ye xingchen <ye.xingchen@zte.com.cn>
+Date: Wed, 18 Jan 2023 16:37:47 +0800
+Subject: [PATCH 02/42] thermal/drivers/mtk_thermal: Use
+ devm_platform_get_and_ioremap_resource()
+
+Convert platform_get_resource(), devm_ioremap_resource() to a single
+call to devm_platform_get_and_ioremap_resource(), as this is exactly
+what this function does.
+
+Signed-off-by: ye xingchen <ye.xingchen@zte.com.cn>
+Link: https://lore.kernel.org/r/202301181637472073620@zte.com.cn
+Signed-off-by: Daniel Lezcano <daniel.lezcano@linaro.org>
+---
+ drivers/thermal/mtk_thermal.c | 4 +---
+ 1 file changed, 1 insertion(+), 3 deletions(-)
+
+--- a/drivers/thermal/mtk_thermal.c
++++ b/drivers/thermal/mtk_thermal.c
+@@ -990,7 +990,6 @@ static int mtk_thermal_probe(struct plat
+ int ret, i, ctrl_id;
+ struct device_node *auxadc, *apmixedsys, *np = pdev->dev.of_node;
+ struct mtk_thermal *mt;
+- struct resource *res;
+ u64 auxadc_phys_base, apmixed_phys_base;
+ struct thermal_zone_device *tzdev;
+ void __iomem *apmixed_base, *auxadc_base;
+@@ -1009,8 +1008,7 @@ static int mtk_thermal_probe(struct plat
+ if (IS_ERR(mt->clk_auxadc))
+ return PTR_ERR(mt->clk_auxadc);
+
+- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+- mt->thermal_base = devm_ioremap_resource(&pdev->dev, res);
++ mt->thermal_base = devm_platform_get_and_ioremap_resource(pdev, 0, NULL);
+ if (IS_ERR(mt->thermal_base))
+ return PTR_ERR(mt->thermal_base);
+
--- /dev/null
+From ca86dbd309ba03bef38ae91f037e2030bb671ab7 Mon Sep 17 00:00:00 2001
+From: Daniel Golle <daniel@makrotopia.org>
+Date: Wed, 18 Jan 2023 15:40:39 +0000
+Subject: [PATCH 03/42] thermal/drivers/mtk: Use function pointer for
+ raw_to_mcelsius
+
+Instead of having if-else logic selecting either raw_to_mcelsius_v1 or
+raw_to_mcelsius_v2 in mtk_thermal_bank_temperature introduce a function
+pointer raw_to_mcelsius to struct mtk_thermal which is initialized in the
+probe function.
+
+Reviewed-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
+Signed-off-by: Daniel Golle <daniel@makrotopia.org>
+Reviewed-by: Matthias Brugger <matthias.bgg@gmail.com>
+Link: https://lore.kernel.org/r/69c17529e8418da3eec703dde31e1b01e5b0f7e8.1674055882.git.daniel@makrotopia.org
+Signed-off-by: Daniel Lezcano <daniel.lezcano@linaro.org>
+---
+ drivers/thermal/mtk_thermal.c | 17 ++++++++++-------
+ 1 file changed, 10 insertions(+), 7 deletions(-)
+
+--- a/drivers/thermal/mtk_thermal.c
++++ b/drivers/thermal/mtk_thermal.c
+@@ -292,6 +292,8 @@ struct mtk_thermal {
+
+ const struct mtk_thermal_data *conf;
+ struct mtk_thermal_bank banks[MAX_NUM_ZONES];
++
++ int (*raw_to_mcelsius)(struct mtk_thermal *mt, int sensno, s32 raw);
+ };
+
+ /* MT8183 thermal sensor data */
+@@ -656,13 +658,9 @@ static int mtk_thermal_bank_temperature(
+ for (i = 0; i < conf->bank_data[bank->id].num_sensors; i++) {
+ raw = readl(mt->thermal_base + conf->msr[i]);
+
+- if (mt->conf->version == MTK_THERMAL_V1) {
+- temp = raw_to_mcelsius_v1(
+- mt, conf->bank_data[bank->id].sensors[i], raw);
+- } else {
+- temp = raw_to_mcelsius_v2(
+- mt, conf->bank_data[bank->id].sensors[i], raw);
+- }
++ temp = mt->raw_to_mcelsius(
++ mt, conf->bank_data[bank->id].sensors[i], raw);
++
+
+ /*
+ * The first read of a sensor often contains very high bogus
+@@ -1073,6 +1071,11 @@ static int mtk_thermal_probe(struct plat
+ mtk_thermal_release_periodic_ts(mt, auxadc_base);
+ }
+
++ if (mt->conf->version == MTK_THERMAL_V1)
++ mt->raw_to_mcelsius = raw_to_mcelsius_v1;
++ else
++ mt->raw_to_mcelsius = raw_to_mcelsius_v2;
++
+ for (ctrl_id = 0; ctrl_id < mt->conf->num_controller ; ctrl_id++)
+ for (i = 0; i < mt->conf->num_banks; i++)
+ mtk_thermal_init_bank(mt, i, apmixed_phys_base,
--- /dev/null
+From aec1d89dccc7cba04fdb3e52dfda328f3302ba17 Mon Sep 17 00:00:00 2001
+From: Daniel Golle <daniel@makrotopia.org>
+Date: Wed, 18 Jan 2023 15:40:58 +0000
+Subject: [PATCH 04/42] thermal/drivers/mtk: Add support for MT7986 and MT7981
+
+Add support for V3 generation thermal found in MT7986 and MT7981 SoCs.
+Brings code to assign values from efuse as well as new function to
+convert raw temperature to millidegree celsius, as found in MediaTek's
+SDK sources (but cleaned up and de-duplicated)
+
+[1]: https://git01.mediatek.com/plugins/gitiles/openwrt/feeds/mtk-openwrt-feeds/+/baf36c7eef477aae1f8f2653b6c29e2caf48475b
+
+Signed-off-by: Daniel Golle <daniel@makrotopia.org>
+Reviewed-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
+Link: https://lore.kernel.org/r/2d341fc45266217249586eb4bd3be3ac4ca83a12.1674055882.git.daniel@makrotopia.org
+Signed-off-by: Daniel Lezcano <daniel.lezcano@linaro.org>
+---
+ drivers/thermal/mtk_thermal.c | 128 ++++++++++++++++++++++++++++++++--
+ 1 file changed, 124 insertions(+), 4 deletions(-)
+
+--- a/drivers/thermal/mtk_thermal.c
++++ b/drivers/thermal/mtk_thermal.c
+@@ -150,6 +150,20 @@
+ #define CALIB_BUF1_VALID_V2(x) (((x) >> 4) & 0x1)
+ #define CALIB_BUF1_O_SLOPE_SIGN_V2(x) (((x) >> 3) & 0x1)
+
++/*
++ * Layout of the fuses providing the calibration data
++ * These macros can be used for MT7981 and MT7986.
++ */
++#define CALIB_BUF0_ADC_GE_V3(x) (((x) >> 0) & 0x3ff)
++#define CALIB_BUF0_DEGC_CALI_V3(x) (((x) >> 20) & 0x3f)
++#define CALIB_BUF0_O_SLOPE_V3(x) (((x) >> 26) & 0x3f)
++#define CALIB_BUF1_VTS_TS1_V3(x) (((x) >> 0) & 0x1ff)
++#define CALIB_BUF1_VTS_TS2_V3(x) (((x) >> 21) & 0x1ff)
++#define CALIB_BUF1_VTS_TSABB_V3(x) (((x) >> 9) & 0x1ff)
++#define CALIB_BUF1_VALID_V3(x) (((x) >> 18) & 0x1)
++#define CALIB_BUF1_O_SLOPE_SIGN_V3(x) (((x) >> 19) & 0x1)
++#define CALIB_BUF1_ID_V3(x) (((x) >> 20) & 0x1)
++
+ enum {
+ VTS1,
+ VTS2,
+@@ -163,6 +177,7 @@ enum {
+ enum mtk_thermal_version {
+ MTK_THERMAL_V1 = 1,
+ MTK_THERMAL_V2,
++ MTK_THERMAL_V3,
+ };
+
+ /* MT2701 thermal sensors */
+@@ -245,6 +260,27 @@ enum mtk_thermal_version {
+ /* The calibration coefficient of sensor */
+ #define MT8183_CALIBRATION 153
+
++/* AUXADC channel 11 is used for the temperature sensors */
++#define MT7986_TEMP_AUXADC_CHANNEL 11
++
++/* The total number of temperature sensors in the MT7986 */
++#define MT7986_NUM_SENSORS 1
++
++/* The number of banks in the MT7986 */
++#define MT7986_NUM_ZONES 1
++
++/* The number of sensing points per bank */
++#define MT7986_NUM_SENSORS_PER_ZONE 1
++
++/* MT7986 thermal sensors */
++#define MT7986_TS1 0
++
++/* The number of controller in the MT7986 */
++#define MT7986_NUM_CONTROLLER 1
++
++/* The calibration coefficient of sensor */
++#define MT7986_CALIBRATION 165
++
+ struct mtk_thermal;
+
+ struct thermal_bank_cfg {
+@@ -388,6 +424,14 @@ static const int mt7622_mux_values[MT762
+ static const int mt7622_vts_index[MT7622_NUM_SENSORS] = { VTS1 };
+ static const int mt7622_tc_offset[MT7622_NUM_CONTROLLER] = { 0x0, };
+
++/* MT7986 thermal sensor data */
++static const int mt7986_bank_data[MT7986_NUM_SENSORS] = { MT7986_TS1, };
++static const int mt7986_msr[MT7986_NUM_SENSORS_PER_ZONE] = { TEMP_MSR0, };
++static const int mt7986_adcpnp[MT7986_NUM_SENSORS_PER_ZONE] = { TEMP_ADCPNP0, };
++static const int mt7986_mux_values[MT7986_NUM_SENSORS] = { 0, };
++static const int mt7986_vts_index[MT7986_NUM_SENSORS] = { VTS1 };
++static const int mt7986_tc_offset[MT7986_NUM_CONTROLLER] = { 0x0, };
++
+ /*
+ * The MT8173 thermal controller has four banks. Each bank can read up to
+ * four temperature sensors simultaneously. The MT8173 has a total of 5
+@@ -551,6 +595,30 @@ static const struct mtk_thermal_data mt8
+ .version = MTK_THERMAL_V1,
+ };
+
++/*
++ * MT7986 uses AUXADC Channel 11 for raw data access.
++ */
++static const struct mtk_thermal_data mt7986_thermal_data = {
++ .auxadc_channel = MT7986_TEMP_AUXADC_CHANNEL,
++ .num_banks = MT7986_NUM_ZONES,
++ .num_sensors = MT7986_NUM_SENSORS,
++ .vts_index = mt7986_vts_index,
++ .cali_val = MT7986_CALIBRATION,
++ .num_controller = MT7986_NUM_CONTROLLER,
++ .controller_offset = mt7986_tc_offset,
++ .need_switch_bank = true,
++ .bank_data = {
++ {
++ .num_sensors = 1,
++ .sensors = mt7986_bank_data,
++ },
++ },
++ .msr = mt7986_msr,
++ .adcpnp = mt7986_adcpnp,
++ .sensor_mux_values = mt7986_mux_values,
++ .version = MTK_THERMAL_V3,
++};
++
+ /**
+ * raw_to_mcelsius_v1 - convert a raw ADC value to mcelsius
+ * @mt: The thermal controller
+@@ -605,6 +673,22 @@ static int raw_to_mcelsius_v2(struct mtk
+ return (format_2 - tmp) * 100;
+ }
+
++static int raw_to_mcelsius_v3(struct mtk_thermal *mt, int sensno, s32 raw)
++{
++ s32 tmp;
++
++ if (raw == 0)
++ return 0;
++
++ raw &= 0xfff;
++ tmp = 100000 * 15 / 16 * 10000;
++ tmp /= 4096 - 512 + mt->adc_ge;
++ tmp /= 1490;
++ tmp *= raw - mt->vts[sensno] - 2900;
++
++ return mt->degc_cali * 500 - tmp;
++}
++
+ /**
+ * mtk_thermal_get_bank - get bank
+ * @bank: The bank
+@@ -885,6 +969,25 @@ static int mtk_thermal_extract_efuse_v2(
+ return 0;
+ }
+
++static int mtk_thermal_extract_efuse_v3(struct mtk_thermal *mt, u32 *buf)
++{
++ if (!CALIB_BUF1_VALID_V3(buf[1]))
++ return -EINVAL;
++
++ mt->adc_ge = CALIB_BUF0_ADC_GE_V3(buf[0]);
++ mt->degc_cali = CALIB_BUF0_DEGC_CALI_V3(buf[0]);
++ mt->o_slope = CALIB_BUF0_O_SLOPE_V3(buf[0]);
++ mt->vts[VTS1] = CALIB_BUF1_VTS_TS1_V3(buf[1]);
++ mt->vts[VTS2] = CALIB_BUF1_VTS_TS2_V3(buf[1]);
++ mt->vts[VTSABB] = CALIB_BUF1_VTS_TSABB_V3(buf[1]);
++ mt->o_slope_sign = CALIB_BUF1_O_SLOPE_SIGN_V3(buf[1]);
++
++ if (CALIB_BUF1_ID_V3(buf[1]) == 0)
++ mt->o_slope = 0;
++
++ return 0;
++}
++
+ static int mtk_thermal_get_calibration_data(struct device *dev,
+ struct mtk_thermal *mt)
+ {
+@@ -895,6 +998,7 @@ static int mtk_thermal_get_calibration_d
+
+ /* Start with default values */
+ mt->adc_ge = 512;
++ mt->adc_oe = 512;
+ for (i = 0; i < mt->conf->num_sensors; i++)
+ mt->vts[i] = 260;
+ mt->degc_cali = 40;
+@@ -920,10 +1024,20 @@ static int mtk_thermal_get_calibration_d
+ goto out;
+ }
+
+- if (mt->conf->version == MTK_THERMAL_V1)
++ switch (mt->conf->version) {
++ case MTK_THERMAL_V1:
+ ret = mtk_thermal_extract_efuse_v1(mt, buf);
+- else
++ break;
++ case MTK_THERMAL_V2:
+ ret = mtk_thermal_extract_efuse_v2(mt, buf);
++ break;
++ case MTK_THERMAL_V3:
++ ret = mtk_thermal_extract_efuse_v3(mt, buf);
++ break;
++ default:
++ ret = -EINVAL;
++ break;
++ }
+
+ if (ret) {
+ dev_info(dev, "Device not calibrated, using default calibration values\n");
+@@ -954,6 +1068,10 @@ static const struct of_device_id mtk_the
+ .data = (void *)&mt7622_thermal_data,
+ },
+ {
++ .compatible = "mediatek,mt7986-thermal",
++ .data = (void *)&mt7986_thermal_data,
++ },
++ {
+ .compatible = "mediatek,mt8183-thermal",
+ .data = (void *)&mt8183_thermal_data,
+ }, {
+@@ -1066,15 +1184,17 @@ static int mtk_thermal_probe(struct plat
+ goto err_disable_clk_auxadc;
+ }
+
+- if (mt->conf->version == MTK_THERMAL_V2) {
++ if (mt->conf->version != MTK_THERMAL_V1) {
+ mtk_thermal_turn_on_buffer(apmixed_base);
+ mtk_thermal_release_periodic_ts(mt, auxadc_base);
+ }
+
+ if (mt->conf->version == MTK_THERMAL_V1)
+ mt->raw_to_mcelsius = raw_to_mcelsius_v1;
+- else
++ else if (mt->conf->version == MTK_THERMAL_V2)
+ mt->raw_to_mcelsius = raw_to_mcelsius_v2;
++ else
++ mt->raw_to_mcelsius = raw_to_mcelsius_v3;
+
+ for (ctrl_id = 0; ctrl_id < mt->conf->num_controller ; ctrl_id++)
+ for (i = 0; i < mt->conf->num_banks; i++)
--- /dev/null
+From 5e3aac197a74914ccec2732a89c29d960730d28f Mon Sep 17 00:00:00 2001
+From: Balsam CHIHI <bchihi@baylibre.com>
+Date: Thu, 9 Feb 2023 11:56:23 +0100
+Subject: [PATCH 05/42] thermal/drivers/mediatek: Relocate driver to mediatek
+ folder
+
+Add MediaTek proprietary folder to upstream more thermal zone and cooler
+drivers, relocate the original thermal controller driver to it, and rename it
+as "auxadc_thermal.c" to show its purpose more clearly.
+
+Signed-off-by: Balsam CHIHI <bchihi@baylibre.com>
+Reviewed-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
+Link: https://lore.kernel.org/r/20230209105628.50294-2-bchihi@baylibre.com
+Signed-off-by: Daniel Lezcano <daniel.lezcano@linaro.org>
+Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
+---
+ drivers/thermal/Kconfig | 14 ++++---------
+ drivers/thermal/Makefile | 2 +-
+ drivers/thermal/mediatek/Kconfig | 21 +++++++++++++++++++
+ drivers/thermal/mediatek/Makefile | 1 +
+ .../auxadc_thermal.c} | 2 +-
+ 5 files changed, 28 insertions(+), 12 deletions(-)
+ create mode 100644 drivers/thermal/mediatek/Kconfig
+ create mode 100644 drivers/thermal/mediatek/Makefile
+ rename drivers/thermal/{mtk_thermal.c => mediatek/auxadc_thermal.c} (99%)
+
+--- a/drivers/thermal/Kconfig
++++ b/drivers/thermal/Kconfig
+@@ -412,16 +412,10 @@ config DA9062_THERMAL
+ zone.
+ Compatible with the DA9062 and DA9061 PMICs.
+
+-config MTK_THERMAL
+- tristate "Temperature sensor driver for mediatek SoCs"
+- depends on ARCH_MEDIATEK || COMPILE_TEST
+- depends on HAS_IOMEM
+- depends on NVMEM || NVMEM=n
+- depends on RESET_CONTROLLER
+- default y
+- help
+- Enable this option if you want to have support for thermal management
+- controller present in Mediatek SoCs
++menu "Mediatek thermal drivers"
++depends on ARCH_MEDIATEK || COMPILE_TEST
++source "drivers/thermal/mediatek/Kconfig"
++endmenu
+
+ config AMLOGIC_THERMAL
+ tristate "Amlogic Thermal Support"
+--- a/drivers/thermal/Makefile
++++ b/drivers/thermal/Makefile
+@@ -55,7 +55,7 @@ obj-y += st/
+ obj-y += qcom/
+ obj-y += tegra/
+ obj-$(CONFIG_HISI_THERMAL) += hisi_thermal.o
+-obj-$(CONFIG_MTK_THERMAL) += mtk_thermal.o
++obj-y += mediatek/
+ obj-$(CONFIG_GENERIC_ADC_THERMAL) += thermal-generic-adc.o
+ obj-$(CONFIG_UNIPHIER_THERMAL) += uniphier_thermal.o
+ obj-$(CONFIG_AMLOGIC_THERMAL) += amlogic_thermal.o
+--- /dev/null
++++ b/drivers/thermal/mediatek/Kconfig
+@@ -0,0 +1,21 @@
++config MTK_THERMAL
++ tristate "MediaTek thermal drivers"
++ depends on THERMAL_OF
++ help
++ This is the option for MediaTek thermal software solutions.
++ Please enable corresponding options to get temperature
++ information from thermal sensors or turn on throttle
++ mechaisms for thermal mitigation.
++
++if MTK_THERMAL
++
++config MTK_SOC_THERMAL
++ tristate "AUXADC temperature sensor driver for MediaTek SoCs"
++ depends on HAS_IOMEM
++ help
++ Enable this option if you want to get SoC temperature
++ information for MediaTek platforms.
++ This driver configures thermal controllers to collect
++ temperature via AUXADC interface.
++
++endif
+--- /dev/null
++++ b/drivers/thermal/mediatek/Makefile
+@@ -0,0 +1 @@
++obj-$(CONFIG_MTK_SOC_THERMAL) += auxadc_thermal.o
+--- a/drivers/thermal/mtk_thermal.c
++++ /dev/null
+@@ -1,1254 +0,0 @@
+-// SPDX-License-Identifier: GPL-2.0-only
+-/*
+- * Copyright (c) 2015 MediaTek Inc.
+- * Author: Hanyi Wu <hanyi.wu@mediatek.com>
+- * Sascha Hauer <s.hauer@pengutronix.de>
+- * Dawei Chien <dawei.chien@mediatek.com>
+- * Louis Yu <louis.yu@mediatek.com>
+- */
+-
+-#include <linux/clk.h>
+-#include <linux/delay.h>
+-#include <linux/interrupt.h>
+-#include <linux/kernel.h>
+-#include <linux/module.h>
+-#include <linux/nvmem-consumer.h>
+-#include <linux/of.h>
+-#include <linux/of_address.h>
+-#include <linux/of_device.h>
+-#include <linux/platform_device.h>
+-#include <linux/slab.h>
+-#include <linux/io.h>
+-#include <linux/thermal.h>
+-#include <linux/reset.h>
+-#include <linux/types.h>
+-
+-#include "thermal_hwmon.h"
+-
+-/* AUXADC Registers */
+-#define AUXADC_CON1_SET_V 0x008
+-#define AUXADC_CON1_CLR_V 0x00c
+-#define AUXADC_CON2_V 0x010
+-#define AUXADC_DATA(channel) (0x14 + (channel) * 4)
+-
+-#define APMIXED_SYS_TS_CON1 0x604
+-
+-/* Thermal Controller Registers */
+-#define TEMP_MONCTL0 0x000
+-#define TEMP_MONCTL1 0x004
+-#define TEMP_MONCTL2 0x008
+-#define TEMP_MONIDET0 0x014
+-#define TEMP_MONIDET1 0x018
+-#define TEMP_MSRCTL0 0x038
+-#define TEMP_MSRCTL1 0x03c
+-#define TEMP_AHBPOLL 0x040
+-#define TEMP_AHBTO 0x044
+-#define TEMP_ADCPNP0 0x048
+-#define TEMP_ADCPNP1 0x04c
+-#define TEMP_ADCPNP2 0x050
+-#define TEMP_ADCPNP3 0x0b4
+-
+-#define TEMP_ADCMUX 0x054
+-#define TEMP_ADCEN 0x060
+-#define TEMP_PNPMUXADDR 0x064
+-#define TEMP_ADCMUXADDR 0x068
+-#define TEMP_ADCENADDR 0x074
+-#define TEMP_ADCVALIDADDR 0x078
+-#define TEMP_ADCVOLTADDR 0x07c
+-#define TEMP_RDCTRL 0x080
+-#define TEMP_ADCVALIDMASK 0x084
+-#define TEMP_ADCVOLTAGESHIFT 0x088
+-#define TEMP_ADCWRITECTRL 0x08c
+-#define TEMP_MSR0 0x090
+-#define TEMP_MSR1 0x094
+-#define TEMP_MSR2 0x098
+-#define TEMP_MSR3 0x0B8
+-
+-#define TEMP_SPARE0 0x0f0
+-
+-#define TEMP_ADCPNP0_1 0x148
+-#define TEMP_ADCPNP1_1 0x14c
+-#define TEMP_ADCPNP2_1 0x150
+-#define TEMP_MSR0_1 0x190
+-#define TEMP_MSR1_1 0x194
+-#define TEMP_MSR2_1 0x198
+-#define TEMP_ADCPNP3_1 0x1b4
+-#define TEMP_MSR3_1 0x1B8
+-
+-#define PTPCORESEL 0x400
+-
+-#define TEMP_MONCTL1_PERIOD_UNIT(x) ((x) & 0x3ff)
+-
+-#define TEMP_MONCTL2_FILTER_INTERVAL(x) (((x) & 0x3ff) << 16)
+-#define TEMP_MONCTL2_SENSOR_INTERVAL(x) ((x) & 0x3ff)
+-
+-#define TEMP_AHBPOLL_ADC_POLL_INTERVAL(x) (x)
+-
+-#define TEMP_ADCWRITECTRL_ADC_PNP_WRITE BIT(0)
+-#define TEMP_ADCWRITECTRL_ADC_MUX_WRITE BIT(1)
+-
+-#define TEMP_ADCVALIDMASK_VALID_HIGH BIT(5)
+-#define TEMP_ADCVALIDMASK_VALID_POS(bit) (bit)
+-
+-/* MT8173 thermal sensors */
+-#define MT8173_TS1 0
+-#define MT8173_TS2 1
+-#define MT8173_TS3 2
+-#define MT8173_TS4 3
+-#define MT8173_TSABB 4
+-
+-/* AUXADC channel 11 is used for the temperature sensors */
+-#define MT8173_TEMP_AUXADC_CHANNEL 11
+-
+-/* The total number of temperature sensors in the MT8173 */
+-#define MT8173_NUM_SENSORS 5
+-
+-/* The number of banks in the MT8173 */
+-#define MT8173_NUM_ZONES 4
+-
+-/* The number of sensing points per bank */
+-#define MT8173_NUM_SENSORS_PER_ZONE 4
+-
+-/* The number of controller in the MT8173 */
+-#define MT8173_NUM_CONTROLLER 1
+-
+-/* The calibration coefficient of sensor */
+-#define MT8173_CALIBRATION 165
+-
+-/*
+- * Layout of the fuses providing the calibration data
+- * These macros could be used for MT8183, MT8173, MT2701, and MT2712.
+- * MT8183 has 6 sensors and needs 6 VTS calibration data.
+- * MT8173 has 5 sensors and needs 5 VTS calibration data.
+- * MT2701 has 3 sensors and needs 3 VTS calibration data.
+- * MT2712 has 4 sensors and needs 4 VTS calibration data.
+- */
+-#define CALIB_BUF0_VALID_V1 BIT(0)
+-#define CALIB_BUF1_ADC_GE_V1(x) (((x) >> 22) & 0x3ff)
+-#define CALIB_BUF0_VTS_TS1_V1(x) (((x) >> 17) & 0x1ff)
+-#define CALIB_BUF0_VTS_TS2_V1(x) (((x) >> 8) & 0x1ff)
+-#define CALIB_BUF1_VTS_TS3_V1(x) (((x) >> 0) & 0x1ff)
+-#define CALIB_BUF2_VTS_TS4_V1(x) (((x) >> 23) & 0x1ff)
+-#define CALIB_BUF2_VTS_TS5_V1(x) (((x) >> 5) & 0x1ff)
+-#define CALIB_BUF2_VTS_TSABB_V1(x) (((x) >> 14) & 0x1ff)
+-#define CALIB_BUF0_DEGC_CALI_V1(x) (((x) >> 1) & 0x3f)
+-#define CALIB_BUF0_O_SLOPE_V1(x) (((x) >> 26) & 0x3f)
+-#define CALIB_BUF0_O_SLOPE_SIGN_V1(x) (((x) >> 7) & 0x1)
+-#define CALIB_BUF1_ID_V1(x) (((x) >> 9) & 0x1)
+-
+-/*
+- * Layout of the fuses providing the calibration data
+- * These macros could be used for MT7622.
+- */
+-#define CALIB_BUF0_ADC_OE_V2(x) (((x) >> 22) & 0x3ff)
+-#define CALIB_BUF0_ADC_GE_V2(x) (((x) >> 12) & 0x3ff)
+-#define CALIB_BUF0_DEGC_CALI_V2(x) (((x) >> 6) & 0x3f)
+-#define CALIB_BUF0_O_SLOPE_V2(x) (((x) >> 0) & 0x3f)
+-#define CALIB_BUF1_VTS_TS1_V2(x) (((x) >> 23) & 0x1ff)
+-#define CALIB_BUF1_VTS_TS2_V2(x) (((x) >> 14) & 0x1ff)
+-#define CALIB_BUF1_VTS_TSABB_V2(x) (((x) >> 5) & 0x1ff)
+-#define CALIB_BUF1_VALID_V2(x) (((x) >> 4) & 0x1)
+-#define CALIB_BUF1_O_SLOPE_SIGN_V2(x) (((x) >> 3) & 0x1)
+-
+-/*
+- * Layout of the fuses providing the calibration data
+- * These macros can be used for MT7981 and MT7986.
+- */
+-#define CALIB_BUF0_ADC_GE_V3(x) (((x) >> 0) & 0x3ff)
+-#define CALIB_BUF0_DEGC_CALI_V3(x) (((x) >> 20) & 0x3f)
+-#define CALIB_BUF0_O_SLOPE_V3(x) (((x) >> 26) & 0x3f)
+-#define CALIB_BUF1_VTS_TS1_V3(x) (((x) >> 0) & 0x1ff)
+-#define CALIB_BUF1_VTS_TS2_V3(x) (((x) >> 21) & 0x1ff)
+-#define CALIB_BUF1_VTS_TSABB_V3(x) (((x) >> 9) & 0x1ff)
+-#define CALIB_BUF1_VALID_V3(x) (((x) >> 18) & 0x1)
+-#define CALIB_BUF1_O_SLOPE_SIGN_V3(x) (((x) >> 19) & 0x1)
+-#define CALIB_BUF1_ID_V3(x) (((x) >> 20) & 0x1)
+-
+-enum {
+- VTS1,
+- VTS2,
+- VTS3,
+- VTS4,
+- VTS5,
+- VTSABB,
+- MAX_NUM_VTS,
+-};
+-
+-enum mtk_thermal_version {
+- MTK_THERMAL_V1 = 1,
+- MTK_THERMAL_V2,
+- MTK_THERMAL_V3,
+-};
+-
+-/* MT2701 thermal sensors */
+-#define MT2701_TS1 0
+-#define MT2701_TS2 1
+-#define MT2701_TSABB 2
+-
+-/* AUXADC channel 11 is used for the temperature sensors */
+-#define MT2701_TEMP_AUXADC_CHANNEL 11
+-
+-/* The total number of temperature sensors in the MT2701 */
+-#define MT2701_NUM_SENSORS 3
+-
+-/* The number of sensing points per bank */
+-#define MT2701_NUM_SENSORS_PER_ZONE 3
+-
+-/* The number of controller in the MT2701 */
+-#define MT2701_NUM_CONTROLLER 1
+-
+-/* The calibration coefficient of sensor */
+-#define MT2701_CALIBRATION 165
+-
+-/* MT2712 thermal sensors */
+-#define MT2712_TS1 0
+-#define MT2712_TS2 1
+-#define MT2712_TS3 2
+-#define MT2712_TS4 3
+-
+-/* AUXADC channel 11 is used for the temperature sensors */
+-#define MT2712_TEMP_AUXADC_CHANNEL 11
+-
+-/* The total number of temperature sensors in the MT2712 */
+-#define MT2712_NUM_SENSORS 4
+-
+-/* The number of sensing points per bank */
+-#define MT2712_NUM_SENSORS_PER_ZONE 4
+-
+-/* The number of controller in the MT2712 */
+-#define MT2712_NUM_CONTROLLER 1
+-
+-/* The calibration coefficient of sensor */
+-#define MT2712_CALIBRATION 165
+-
+-#define MT7622_TEMP_AUXADC_CHANNEL 11
+-#define MT7622_NUM_SENSORS 1
+-#define MT7622_NUM_ZONES 1
+-#define MT7622_NUM_SENSORS_PER_ZONE 1
+-#define MT7622_TS1 0
+-#define MT7622_NUM_CONTROLLER 1
+-
+-/* The maximum number of banks */
+-#define MAX_NUM_ZONES 8
+-
+-/* The calibration coefficient of sensor */
+-#define MT7622_CALIBRATION 165
+-
+-/* MT8183 thermal sensors */
+-#define MT8183_TS1 0
+-#define MT8183_TS2 1
+-#define MT8183_TS3 2
+-#define MT8183_TS4 3
+-#define MT8183_TS5 4
+-#define MT8183_TSABB 5
+-
+-/* AUXADC channel is used for the temperature sensors */
+-#define MT8183_TEMP_AUXADC_CHANNEL 11
+-
+-/* The total number of temperature sensors in the MT8183 */
+-#define MT8183_NUM_SENSORS 6
+-
+-/* The number of banks in the MT8183 */
+-#define MT8183_NUM_ZONES 1
+-
+-/* The number of sensing points per bank */
+-#define MT8183_NUM_SENSORS_PER_ZONE 6
+-
+-/* The number of controller in the MT8183 */
+-#define MT8183_NUM_CONTROLLER 2
+-
+-/* The calibration coefficient of sensor */
+-#define MT8183_CALIBRATION 153
+-
+-/* AUXADC channel 11 is used for the temperature sensors */
+-#define MT7986_TEMP_AUXADC_CHANNEL 11
+-
+-/* The total number of temperature sensors in the MT7986 */
+-#define MT7986_NUM_SENSORS 1
+-
+-/* The number of banks in the MT7986 */
+-#define MT7986_NUM_ZONES 1
+-
+-/* The number of sensing points per bank */
+-#define MT7986_NUM_SENSORS_PER_ZONE 1
+-
+-/* MT7986 thermal sensors */
+-#define MT7986_TS1 0
+-
+-/* The number of controller in the MT7986 */
+-#define MT7986_NUM_CONTROLLER 1
+-
+-/* The calibration coefficient of sensor */
+-#define MT7986_CALIBRATION 165
+-
+-struct mtk_thermal;
+-
+-struct thermal_bank_cfg {
+- unsigned int num_sensors;
+- const int *sensors;
+-};
+-
+-struct mtk_thermal_bank {
+- struct mtk_thermal *mt;
+- int id;
+-};
+-
+-struct mtk_thermal_data {
+- s32 num_banks;
+- s32 num_sensors;
+- s32 auxadc_channel;
+- const int *vts_index;
+- const int *sensor_mux_values;
+- const int *msr;
+- const int *adcpnp;
+- const int cali_val;
+- const int num_controller;
+- const int *controller_offset;
+- bool need_switch_bank;
+- struct thermal_bank_cfg bank_data[MAX_NUM_ZONES];
+- enum mtk_thermal_version version;
+-};
+-
+-struct mtk_thermal {
+- struct device *dev;
+- void __iomem *thermal_base;
+-
+- struct clk *clk_peri_therm;
+- struct clk *clk_auxadc;
+- /* lock: for getting and putting banks */
+- struct mutex lock;
+-
+- /* Calibration values */
+- s32 adc_ge;
+- s32 adc_oe;
+- s32 degc_cali;
+- s32 o_slope;
+- s32 o_slope_sign;
+- s32 vts[MAX_NUM_VTS];
+-
+- const struct mtk_thermal_data *conf;
+- struct mtk_thermal_bank banks[MAX_NUM_ZONES];
+-
+- int (*raw_to_mcelsius)(struct mtk_thermal *mt, int sensno, s32 raw);
+-};
+-
+-/* MT8183 thermal sensor data */
+-static const int mt8183_bank_data[MT8183_NUM_SENSORS] = {
+- MT8183_TS1, MT8183_TS2, MT8183_TS3, MT8183_TS4, MT8183_TS5, MT8183_TSABB
+-};
+-
+-static const int mt8183_msr[MT8183_NUM_SENSORS_PER_ZONE] = {
+- TEMP_MSR0_1, TEMP_MSR1_1, TEMP_MSR2_1, TEMP_MSR1, TEMP_MSR0, TEMP_MSR3_1
+-};
+-
+-static const int mt8183_adcpnp[MT8183_NUM_SENSORS_PER_ZONE] = {
+- TEMP_ADCPNP0_1, TEMP_ADCPNP1_1, TEMP_ADCPNP2_1,
+- TEMP_ADCPNP1, TEMP_ADCPNP0, TEMP_ADCPNP3_1
+-};
+-
+-static const int mt8183_mux_values[MT8183_NUM_SENSORS] = { 0, 1, 2, 3, 4, 0 };
+-static const int mt8183_tc_offset[MT8183_NUM_CONTROLLER] = {0x0, 0x100};
+-
+-static const int mt8183_vts_index[MT8183_NUM_SENSORS] = {
+- VTS1, VTS2, VTS3, VTS4, VTS5, VTSABB
+-};
+-
+-/* MT8173 thermal sensor data */
+-static const int mt8173_bank_data[MT8173_NUM_ZONES][3] = {
+- { MT8173_TS2, MT8173_TS3 },
+- { MT8173_TS2, MT8173_TS4 },
+- { MT8173_TS1, MT8173_TS2, MT8173_TSABB },
+- { MT8173_TS2 },
+-};
+-
+-static const int mt8173_msr[MT8173_NUM_SENSORS_PER_ZONE] = {
+- TEMP_MSR0, TEMP_MSR1, TEMP_MSR2, TEMP_MSR3
+-};
+-
+-static const int mt8173_adcpnp[MT8173_NUM_SENSORS_PER_ZONE] = {
+- TEMP_ADCPNP0, TEMP_ADCPNP1, TEMP_ADCPNP2, TEMP_ADCPNP3
+-};
+-
+-static const int mt8173_mux_values[MT8173_NUM_SENSORS] = { 0, 1, 2, 3, 16 };
+-static const int mt8173_tc_offset[MT8173_NUM_CONTROLLER] = { 0x0, };
+-
+-static const int mt8173_vts_index[MT8173_NUM_SENSORS] = {
+- VTS1, VTS2, VTS3, VTS4, VTSABB
+-};
+-
+-/* MT2701 thermal sensor data */
+-static const int mt2701_bank_data[MT2701_NUM_SENSORS] = {
+- MT2701_TS1, MT2701_TS2, MT2701_TSABB
+-};
+-
+-static const int mt2701_msr[MT2701_NUM_SENSORS_PER_ZONE] = {
+- TEMP_MSR0, TEMP_MSR1, TEMP_MSR2
+-};
+-
+-static const int mt2701_adcpnp[MT2701_NUM_SENSORS_PER_ZONE] = {
+- TEMP_ADCPNP0, TEMP_ADCPNP1, TEMP_ADCPNP2
+-};
+-
+-static const int mt2701_mux_values[MT2701_NUM_SENSORS] = { 0, 1, 16 };
+-static const int mt2701_tc_offset[MT2701_NUM_CONTROLLER] = { 0x0, };
+-
+-static const int mt2701_vts_index[MT2701_NUM_SENSORS] = {
+- VTS1, VTS2, VTS3
+-};
+-
+-/* MT2712 thermal sensor data */
+-static const int mt2712_bank_data[MT2712_NUM_SENSORS] = {
+- MT2712_TS1, MT2712_TS2, MT2712_TS3, MT2712_TS4
+-};
+-
+-static const int mt2712_msr[MT2712_NUM_SENSORS_PER_ZONE] = {
+- TEMP_MSR0, TEMP_MSR1, TEMP_MSR2, TEMP_MSR3
+-};
+-
+-static const int mt2712_adcpnp[MT2712_NUM_SENSORS_PER_ZONE] = {
+- TEMP_ADCPNP0, TEMP_ADCPNP1, TEMP_ADCPNP2, TEMP_ADCPNP3
+-};
+-
+-static const int mt2712_mux_values[MT2712_NUM_SENSORS] = { 0, 1, 2, 3 };
+-static const int mt2712_tc_offset[MT2712_NUM_CONTROLLER] = { 0x0, };
+-
+-static const int mt2712_vts_index[MT2712_NUM_SENSORS] = {
+- VTS1, VTS2, VTS3, VTS4
+-};
+-
+-/* MT7622 thermal sensor data */
+-static const int mt7622_bank_data[MT7622_NUM_SENSORS] = { MT7622_TS1, };
+-static const int mt7622_msr[MT7622_NUM_SENSORS_PER_ZONE] = { TEMP_MSR0, };
+-static const int mt7622_adcpnp[MT7622_NUM_SENSORS_PER_ZONE] = { TEMP_ADCPNP0, };
+-static const int mt7622_mux_values[MT7622_NUM_SENSORS] = { 0, };
+-static const int mt7622_vts_index[MT7622_NUM_SENSORS] = { VTS1 };
+-static const int mt7622_tc_offset[MT7622_NUM_CONTROLLER] = { 0x0, };
+-
+-/* MT7986 thermal sensor data */
+-static const int mt7986_bank_data[MT7986_NUM_SENSORS] = { MT7986_TS1, };
+-static const int mt7986_msr[MT7986_NUM_SENSORS_PER_ZONE] = { TEMP_MSR0, };
+-static const int mt7986_adcpnp[MT7986_NUM_SENSORS_PER_ZONE] = { TEMP_ADCPNP0, };
+-static const int mt7986_mux_values[MT7986_NUM_SENSORS] = { 0, };
+-static const int mt7986_vts_index[MT7986_NUM_SENSORS] = { VTS1 };
+-static const int mt7986_tc_offset[MT7986_NUM_CONTROLLER] = { 0x0, };
+-
+-/*
+- * The MT8173 thermal controller has four banks. Each bank can read up to
+- * four temperature sensors simultaneously. The MT8173 has a total of 5
+- * temperature sensors. We use each bank to measure a certain area of the
+- * SoC. Since TS2 is located centrally in the SoC it is influenced by multiple
+- * areas, hence is used in different banks.
+- *
+- * The thermal core only gets the maximum temperature of all banks, so
+- * the bank concept wouldn't be necessary here. However, the SVS (Smart
+- * Voltage Scaling) unit makes its decisions based on the same bank
+- * data, and this indeed needs the temperatures of the individual banks
+- * for making better decisions.
+- */
+-static const struct mtk_thermal_data mt8173_thermal_data = {
+- .auxadc_channel = MT8173_TEMP_AUXADC_CHANNEL,
+- .num_banks = MT8173_NUM_ZONES,
+- .num_sensors = MT8173_NUM_SENSORS,
+- .vts_index = mt8173_vts_index,
+- .cali_val = MT8173_CALIBRATION,
+- .num_controller = MT8173_NUM_CONTROLLER,
+- .controller_offset = mt8173_tc_offset,
+- .need_switch_bank = true,
+- .bank_data = {
+- {
+- .num_sensors = 2,
+- .sensors = mt8173_bank_data[0],
+- }, {
+- .num_sensors = 2,
+- .sensors = mt8173_bank_data[1],
+- }, {
+- .num_sensors = 3,
+- .sensors = mt8173_bank_data[2],
+- }, {
+- .num_sensors = 1,
+- .sensors = mt8173_bank_data[3],
+- },
+- },
+- .msr = mt8173_msr,
+- .adcpnp = mt8173_adcpnp,
+- .sensor_mux_values = mt8173_mux_values,
+- .version = MTK_THERMAL_V1,
+-};
+-
+-/*
+- * The MT2701 thermal controller has one bank, which can read up to
+- * three temperature sensors simultaneously. The MT2701 has a total of 3
+- * temperature sensors.
+- *
+- * The thermal core only gets the maximum temperature of this one bank,
+- * so the bank concept wouldn't be necessary here. However, the SVS (Smart
+- * Voltage Scaling) unit makes its decisions based on the same bank
+- * data.
+- */
+-static const struct mtk_thermal_data mt2701_thermal_data = {
+- .auxadc_channel = MT2701_TEMP_AUXADC_CHANNEL,
+- .num_banks = 1,
+- .num_sensors = MT2701_NUM_SENSORS,
+- .vts_index = mt2701_vts_index,
+- .cali_val = MT2701_CALIBRATION,
+- .num_controller = MT2701_NUM_CONTROLLER,
+- .controller_offset = mt2701_tc_offset,
+- .need_switch_bank = true,
+- .bank_data = {
+- {
+- .num_sensors = 3,
+- .sensors = mt2701_bank_data,
+- },
+- },
+- .msr = mt2701_msr,
+- .adcpnp = mt2701_adcpnp,
+- .sensor_mux_values = mt2701_mux_values,
+- .version = MTK_THERMAL_V1,
+-};
+-
+-/*
+- * The MT2712 thermal controller has one bank, which can read up to
+- * four temperature sensors simultaneously. The MT2712 has a total of 4
+- * temperature sensors.
+- *
+- * The thermal core only gets the maximum temperature of this one bank,
+- * so the bank concept wouldn't be necessary here. However, the SVS (Smart
+- * Voltage Scaling) unit makes its decisions based on the same bank
+- * data.
+- */
+-static const struct mtk_thermal_data mt2712_thermal_data = {
+- .auxadc_channel = MT2712_TEMP_AUXADC_CHANNEL,
+- .num_banks = 1,
+- .num_sensors = MT2712_NUM_SENSORS,
+- .vts_index = mt2712_vts_index,
+- .cali_val = MT2712_CALIBRATION,
+- .num_controller = MT2712_NUM_CONTROLLER,
+- .controller_offset = mt2712_tc_offset,
+- .need_switch_bank = true,
+- .bank_data = {
+- {
+- .num_sensors = 4,
+- .sensors = mt2712_bank_data,
+- },
+- },
+- .msr = mt2712_msr,
+- .adcpnp = mt2712_adcpnp,
+- .sensor_mux_values = mt2712_mux_values,
+- .version = MTK_THERMAL_V1,
+-};
+-
+-/*
+- * MT7622 have only one sensing point which uses AUXADC Channel 11 for raw data
+- * access.
+- */
+-static const struct mtk_thermal_data mt7622_thermal_data = {
+- .auxadc_channel = MT7622_TEMP_AUXADC_CHANNEL,
+- .num_banks = MT7622_NUM_ZONES,
+- .num_sensors = MT7622_NUM_SENSORS,
+- .vts_index = mt7622_vts_index,
+- .cali_val = MT7622_CALIBRATION,
+- .num_controller = MT7622_NUM_CONTROLLER,
+- .controller_offset = mt7622_tc_offset,
+- .need_switch_bank = true,
+- .bank_data = {
+- {
+- .num_sensors = 1,
+- .sensors = mt7622_bank_data,
+- },
+- },
+- .msr = mt7622_msr,
+- .adcpnp = mt7622_adcpnp,
+- .sensor_mux_values = mt7622_mux_values,
+- .version = MTK_THERMAL_V2,
+-};
+-
+-/*
+- * The MT8183 thermal controller has one bank for the current SW framework.
+- * The MT8183 has a total of 6 temperature sensors.
+- * There are two thermal controller to control the six sensor.
+- * The first one bind 2 sensor, and the other bind 4 sensors.
+- * The thermal core only gets the maximum temperature of all sensor, so
+- * the bank concept wouldn't be necessary here. However, the SVS (Smart
+- * Voltage Scaling) unit makes its decisions based on the same bank
+- * data, and this indeed needs the temperatures of the individual banks
+- * for making better decisions.
+- */
+-static const struct mtk_thermal_data mt8183_thermal_data = {
+- .auxadc_channel = MT8183_TEMP_AUXADC_CHANNEL,
+- .num_banks = MT8183_NUM_ZONES,
+- .num_sensors = MT8183_NUM_SENSORS,
+- .vts_index = mt8183_vts_index,
+- .cali_val = MT8183_CALIBRATION,
+- .num_controller = MT8183_NUM_CONTROLLER,
+- .controller_offset = mt8183_tc_offset,
+- .need_switch_bank = false,
+- .bank_data = {
+- {
+- .num_sensors = 6,
+- .sensors = mt8183_bank_data,
+- },
+- },
+-
+- .msr = mt8183_msr,
+- .adcpnp = mt8183_adcpnp,
+- .sensor_mux_values = mt8183_mux_values,
+- .version = MTK_THERMAL_V1,
+-};
+-
+-/*
+- * MT7986 uses AUXADC Channel 11 for raw data access.
+- */
+-static const struct mtk_thermal_data mt7986_thermal_data = {
+- .auxadc_channel = MT7986_TEMP_AUXADC_CHANNEL,
+- .num_banks = MT7986_NUM_ZONES,
+- .num_sensors = MT7986_NUM_SENSORS,
+- .vts_index = mt7986_vts_index,
+- .cali_val = MT7986_CALIBRATION,
+- .num_controller = MT7986_NUM_CONTROLLER,
+- .controller_offset = mt7986_tc_offset,
+- .need_switch_bank = true,
+- .bank_data = {
+- {
+- .num_sensors = 1,
+- .sensors = mt7986_bank_data,
+- },
+- },
+- .msr = mt7986_msr,
+- .adcpnp = mt7986_adcpnp,
+- .sensor_mux_values = mt7986_mux_values,
+- .version = MTK_THERMAL_V3,
+-};
+-
+-/**
+- * raw_to_mcelsius_v1 - convert a raw ADC value to mcelsius
+- * @mt: The thermal controller
+- * @sensno: sensor number
+- * @raw: raw ADC value
+- *
+- * This converts the raw ADC value to mcelsius using the SoC specific
+- * calibration constants
+- */
+-static int raw_to_mcelsius_v1(struct mtk_thermal *mt, int sensno, s32 raw)
+-{
+- s32 tmp;
+-
+- raw &= 0xfff;
+-
+- tmp = 203450520 << 3;
+- tmp /= mt->conf->cali_val + mt->o_slope;
+- tmp /= 10000 + mt->adc_ge;
+- tmp *= raw - mt->vts[sensno] - 3350;
+- tmp >>= 3;
+-
+- return mt->degc_cali * 500 - tmp;
+-}
+-
+-static int raw_to_mcelsius_v2(struct mtk_thermal *mt, int sensno, s32 raw)
+-{
+- s32 format_1;
+- s32 format_2;
+- s32 g_oe;
+- s32 g_gain;
+- s32 g_x_roomt;
+- s32 tmp;
+-
+- if (raw == 0)
+- return 0;
+-
+- raw &= 0xfff;
+- g_gain = 10000 + (((mt->adc_ge - 512) * 10000) >> 12);
+- g_oe = mt->adc_oe - 512;
+- format_1 = mt->vts[VTS2] + 3105 - g_oe;
+- format_2 = (mt->degc_cali * 10) >> 1;
+- g_x_roomt = (((format_1 * 10000) >> 12) * 10000) / g_gain;
+-
+- tmp = (((((raw - g_oe) * 10000) >> 12) * 10000) / g_gain) - g_x_roomt;
+- tmp = tmp * 10 * 100 / 11;
+-
+- if (mt->o_slope_sign == 0)
+- tmp = tmp / (165 - mt->o_slope);
+- else
+- tmp = tmp / (165 + mt->o_slope);
+-
+- return (format_2 - tmp) * 100;
+-}
+-
+-static int raw_to_mcelsius_v3(struct mtk_thermal *mt, int sensno, s32 raw)
+-{
+- s32 tmp;
+-
+- if (raw == 0)
+- return 0;
+-
+- raw &= 0xfff;
+- tmp = 100000 * 15 / 16 * 10000;
+- tmp /= 4096 - 512 + mt->adc_ge;
+- tmp /= 1490;
+- tmp *= raw - mt->vts[sensno] - 2900;
+-
+- return mt->degc_cali * 500 - tmp;
+-}
+-
+-/**
+- * mtk_thermal_get_bank - get bank
+- * @bank: The bank
+- *
+- * The bank registers are banked, we have to select a bank in the
+- * PTPCORESEL register to access it.
+- */
+-static void mtk_thermal_get_bank(struct mtk_thermal_bank *bank)
+-{
+- struct mtk_thermal *mt = bank->mt;
+- u32 val;
+-
+- if (mt->conf->need_switch_bank) {
+- mutex_lock(&mt->lock);
+-
+- val = readl(mt->thermal_base + PTPCORESEL);
+- val &= ~0xf;
+- val |= bank->id;
+- writel(val, mt->thermal_base + PTPCORESEL);
+- }
+-}
+-
+-/**
+- * mtk_thermal_put_bank - release bank
+- * @bank: The bank
+- *
+- * release a bank previously taken with mtk_thermal_get_bank,
+- */
+-static void mtk_thermal_put_bank(struct mtk_thermal_bank *bank)
+-{
+- struct mtk_thermal *mt = bank->mt;
+-
+- if (mt->conf->need_switch_bank)
+- mutex_unlock(&mt->lock);
+-}
+-
+-/**
+- * mtk_thermal_bank_temperature - get the temperature of a bank
+- * @bank: The bank
+- *
+- * The temperature of a bank is considered the maximum temperature of
+- * the sensors associated to the bank.
+- */
+-static int mtk_thermal_bank_temperature(struct mtk_thermal_bank *bank)
+-{
+- struct mtk_thermal *mt = bank->mt;
+- const struct mtk_thermal_data *conf = mt->conf;
+- int i, temp = INT_MIN, max = INT_MIN;
+- u32 raw;
+-
+- for (i = 0; i < conf->bank_data[bank->id].num_sensors; i++) {
+- raw = readl(mt->thermal_base + conf->msr[i]);
+-
+- temp = mt->raw_to_mcelsius(
+- mt, conf->bank_data[bank->id].sensors[i], raw);
+-
+-
+- /*
+- * The first read of a sensor often contains very high bogus
+- * temperature value. Filter these out so that the system does
+- * not immediately shut down.
+- */
+- if (temp > 200000)
+- temp = 0;
+-
+- if (temp > max)
+- max = temp;
+- }
+-
+- return max;
+-}
+-
+-static int mtk_read_temp(struct thermal_zone_device *tz, int *temperature)
+-{
+- struct mtk_thermal *mt = tz->devdata;
+- int i;
+- int tempmax = INT_MIN;
+-
+- for (i = 0; i < mt->conf->num_banks; i++) {
+- struct mtk_thermal_bank *bank = &mt->banks[i];
+-
+- mtk_thermal_get_bank(bank);
+-
+- tempmax = max(tempmax, mtk_thermal_bank_temperature(bank));
+-
+- mtk_thermal_put_bank(bank);
+- }
+-
+- *temperature = tempmax;
+-
+- return 0;
+-}
+-
+-static const struct thermal_zone_device_ops mtk_thermal_ops = {
+- .get_temp = mtk_read_temp,
+-};
+-
+-static void mtk_thermal_init_bank(struct mtk_thermal *mt, int num,
+- u32 apmixed_phys_base, u32 auxadc_phys_base,
+- int ctrl_id)
+-{
+- struct mtk_thermal_bank *bank = &mt->banks[num];
+- const struct mtk_thermal_data *conf = mt->conf;
+- int i;
+-
+- int offset = mt->conf->controller_offset[ctrl_id];
+- void __iomem *controller_base = mt->thermal_base + offset;
+-
+- bank->id = num;
+- bank->mt = mt;
+-
+- mtk_thermal_get_bank(bank);
+-
+- /* bus clock 66M counting unit is 12 * 15.15ns * 256 = 46.540us */
+- writel(TEMP_MONCTL1_PERIOD_UNIT(12), controller_base + TEMP_MONCTL1);
+-
+- /*
+- * filt interval is 1 * 46.540us = 46.54us,
+- * sen interval is 429 * 46.540us = 19.96ms
+- */
+- writel(TEMP_MONCTL2_FILTER_INTERVAL(1) |
+- TEMP_MONCTL2_SENSOR_INTERVAL(429),
+- controller_base + TEMP_MONCTL2);
+-
+- /* poll is set to 10u */
+- writel(TEMP_AHBPOLL_ADC_POLL_INTERVAL(768),
+- controller_base + TEMP_AHBPOLL);
+-
+- /* temperature sampling control, 1 sample */
+- writel(0x0, controller_base + TEMP_MSRCTL0);
+-
+- /* exceed this polling time, IRQ would be inserted */
+- writel(0xffffffff, controller_base + TEMP_AHBTO);
+-
+- /* number of interrupts per event, 1 is enough */
+- writel(0x0, controller_base + TEMP_MONIDET0);
+- writel(0x0, controller_base + TEMP_MONIDET1);
+-
+- /*
+- * The MT8173 thermal controller does not have its own ADC. Instead it
+- * uses AHB bus accesses to control the AUXADC. To do this the thermal
+- * controller has to be programmed with the physical addresses of the
+- * AUXADC registers and with the various bit positions in the AUXADC.
+- * Also the thermal controller controls a mux in the APMIXEDSYS register
+- * space.
+- */
+-
+- /*
+- * this value will be stored to TEMP_PNPMUXADDR (TEMP_SPARE0)
+- * automatically by hw
+- */
+- writel(BIT(conf->auxadc_channel), controller_base + TEMP_ADCMUX);
+-
+- /* AHB address for auxadc mux selection */
+- writel(auxadc_phys_base + AUXADC_CON1_CLR_V,
+- controller_base + TEMP_ADCMUXADDR);
+-
+- if (mt->conf->version == MTK_THERMAL_V1) {
+- /* AHB address for pnp sensor mux selection */
+- writel(apmixed_phys_base + APMIXED_SYS_TS_CON1,
+- controller_base + TEMP_PNPMUXADDR);
+- }
+-
+- /* AHB value for auxadc enable */
+- writel(BIT(conf->auxadc_channel), controller_base + TEMP_ADCEN);
+-
+- /* AHB address for auxadc enable (channel 0 immediate mode selected) */
+- writel(auxadc_phys_base + AUXADC_CON1_SET_V,
+- controller_base + TEMP_ADCENADDR);
+-
+- /* AHB address for auxadc valid bit */
+- writel(auxadc_phys_base + AUXADC_DATA(conf->auxadc_channel),
+- controller_base + TEMP_ADCVALIDADDR);
+-
+- /* AHB address for auxadc voltage output */
+- writel(auxadc_phys_base + AUXADC_DATA(conf->auxadc_channel),
+- controller_base + TEMP_ADCVOLTADDR);
+-
+- /* read valid & voltage are at the same register */
+- writel(0x0, controller_base + TEMP_RDCTRL);
+-
+- /* indicate where the valid bit is */
+- writel(TEMP_ADCVALIDMASK_VALID_HIGH | TEMP_ADCVALIDMASK_VALID_POS(12),
+- controller_base + TEMP_ADCVALIDMASK);
+-
+- /* no shift */
+- writel(0x0, controller_base + TEMP_ADCVOLTAGESHIFT);
+-
+- /* enable auxadc mux write transaction */
+- writel(TEMP_ADCWRITECTRL_ADC_MUX_WRITE,
+- controller_base + TEMP_ADCWRITECTRL);
+-
+- for (i = 0; i < conf->bank_data[num].num_sensors; i++)
+- writel(conf->sensor_mux_values[conf->bank_data[num].sensors[i]],
+- mt->thermal_base + conf->adcpnp[i]);
+-
+- writel((1 << conf->bank_data[num].num_sensors) - 1,
+- controller_base + TEMP_MONCTL0);
+-
+- writel(TEMP_ADCWRITECTRL_ADC_PNP_WRITE |
+- TEMP_ADCWRITECTRL_ADC_MUX_WRITE,
+- controller_base + TEMP_ADCWRITECTRL);
+-
+- mtk_thermal_put_bank(bank);
+-}
+-
+-static u64 of_get_phys_base(struct device_node *np)
+-{
+- u64 size64;
+- const __be32 *regaddr_p;
+-
+- regaddr_p = of_get_address(np, 0, &size64, NULL);
+- if (!regaddr_p)
+- return OF_BAD_ADDR;
+-
+- return of_translate_address(np, regaddr_p);
+-}
+-
+-static int mtk_thermal_extract_efuse_v1(struct mtk_thermal *mt, u32 *buf)
+-{
+- int i;
+-
+- if (!(buf[0] & CALIB_BUF0_VALID_V1))
+- return -EINVAL;
+-
+- mt->adc_ge = CALIB_BUF1_ADC_GE_V1(buf[1]);
+-
+- for (i = 0; i < mt->conf->num_sensors; i++) {
+- switch (mt->conf->vts_index[i]) {
+- case VTS1:
+- mt->vts[VTS1] = CALIB_BUF0_VTS_TS1_V1(buf[0]);
+- break;
+- case VTS2:
+- mt->vts[VTS2] = CALIB_BUF0_VTS_TS2_V1(buf[0]);
+- break;
+- case VTS3:
+- mt->vts[VTS3] = CALIB_BUF1_VTS_TS3_V1(buf[1]);
+- break;
+- case VTS4:
+- mt->vts[VTS4] = CALIB_BUF2_VTS_TS4_V1(buf[2]);
+- break;
+- case VTS5:
+- mt->vts[VTS5] = CALIB_BUF2_VTS_TS5_V1(buf[2]);
+- break;
+- case VTSABB:
+- mt->vts[VTSABB] =
+- CALIB_BUF2_VTS_TSABB_V1(buf[2]);
+- break;
+- default:
+- break;
+- }
+- }
+-
+- mt->degc_cali = CALIB_BUF0_DEGC_CALI_V1(buf[0]);
+- if (CALIB_BUF1_ID_V1(buf[1]) &
+- CALIB_BUF0_O_SLOPE_SIGN_V1(buf[0]))
+- mt->o_slope = -CALIB_BUF0_O_SLOPE_V1(buf[0]);
+- else
+- mt->o_slope = CALIB_BUF0_O_SLOPE_V1(buf[0]);
+-
+- return 0;
+-}
+-
+-static int mtk_thermal_extract_efuse_v2(struct mtk_thermal *mt, u32 *buf)
+-{
+- if (!CALIB_BUF1_VALID_V2(buf[1]))
+- return -EINVAL;
+-
+- mt->adc_oe = CALIB_BUF0_ADC_OE_V2(buf[0]);
+- mt->adc_ge = CALIB_BUF0_ADC_GE_V2(buf[0]);
+- mt->degc_cali = CALIB_BUF0_DEGC_CALI_V2(buf[0]);
+- mt->o_slope = CALIB_BUF0_O_SLOPE_V2(buf[0]);
+- mt->vts[VTS1] = CALIB_BUF1_VTS_TS1_V2(buf[1]);
+- mt->vts[VTS2] = CALIB_BUF1_VTS_TS2_V2(buf[1]);
+- mt->vts[VTSABB] = CALIB_BUF1_VTS_TSABB_V2(buf[1]);
+- mt->o_slope_sign = CALIB_BUF1_O_SLOPE_SIGN_V2(buf[1]);
+-
+- return 0;
+-}
+-
+-static int mtk_thermal_extract_efuse_v3(struct mtk_thermal *mt, u32 *buf)
+-{
+- if (!CALIB_BUF1_VALID_V3(buf[1]))
+- return -EINVAL;
+-
+- mt->adc_ge = CALIB_BUF0_ADC_GE_V3(buf[0]);
+- mt->degc_cali = CALIB_BUF0_DEGC_CALI_V3(buf[0]);
+- mt->o_slope = CALIB_BUF0_O_SLOPE_V3(buf[0]);
+- mt->vts[VTS1] = CALIB_BUF1_VTS_TS1_V3(buf[1]);
+- mt->vts[VTS2] = CALIB_BUF1_VTS_TS2_V3(buf[1]);
+- mt->vts[VTSABB] = CALIB_BUF1_VTS_TSABB_V3(buf[1]);
+- mt->o_slope_sign = CALIB_BUF1_O_SLOPE_SIGN_V3(buf[1]);
+-
+- if (CALIB_BUF1_ID_V3(buf[1]) == 0)
+- mt->o_slope = 0;
+-
+- return 0;
+-}
+-
+-static int mtk_thermal_get_calibration_data(struct device *dev,
+- struct mtk_thermal *mt)
+-{
+- struct nvmem_cell *cell;
+- u32 *buf;
+- size_t len;
+- int i, ret = 0;
+-
+- /* Start with default values */
+- mt->adc_ge = 512;
+- mt->adc_oe = 512;
+- for (i = 0; i < mt->conf->num_sensors; i++)
+- mt->vts[i] = 260;
+- mt->degc_cali = 40;
+- mt->o_slope = 0;
+-
+- cell = nvmem_cell_get(dev, "calibration-data");
+- if (IS_ERR(cell)) {
+- if (PTR_ERR(cell) == -EPROBE_DEFER)
+- return PTR_ERR(cell);
+- return 0;
+- }
+-
+- buf = (u32 *)nvmem_cell_read(cell, &len);
+-
+- nvmem_cell_put(cell);
+-
+- if (IS_ERR(buf))
+- return PTR_ERR(buf);
+-
+- if (len < 3 * sizeof(u32)) {
+- dev_warn(dev, "invalid calibration data\n");
+- ret = -EINVAL;
+- goto out;
+- }
+-
+- switch (mt->conf->version) {
+- case MTK_THERMAL_V1:
+- ret = mtk_thermal_extract_efuse_v1(mt, buf);
+- break;
+- case MTK_THERMAL_V2:
+- ret = mtk_thermal_extract_efuse_v2(mt, buf);
+- break;
+- case MTK_THERMAL_V3:
+- ret = mtk_thermal_extract_efuse_v3(mt, buf);
+- break;
+- default:
+- ret = -EINVAL;
+- break;
+- }
+-
+- if (ret) {
+- dev_info(dev, "Device not calibrated, using default calibration values\n");
+- ret = 0;
+- }
+-
+-out:
+- kfree(buf);
+-
+- return ret;
+-}
+-
+-static const struct of_device_id mtk_thermal_of_match[] = {
+- {
+- .compatible = "mediatek,mt8173-thermal",
+- .data = (void *)&mt8173_thermal_data,
+- },
+- {
+- .compatible = "mediatek,mt2701-thermal",
+- .data = (void *)&mt2701_thermal_data,
+- },
+- {
+- .compatible = "mediatek,mt2712-thermal",
+- .data = (void *)&mt2712_thermal_data,
+- },
+- {
+- .compatible = "mediatek,mt7622-thermal",
+- .data = (void *)&mt7622_thermal_data,
+- },
+- {
+- .compatible = "mediatek,mt7986-thermal",
+- .data = (void *)&mt7986_thermal_data,
+- },
+- {
+- .compatible = "mediatek,mt8183-thermal",
+- .data = (void *)&mt8183_thermal_data,
+- }, {
+- },
+-};
+-MODULE_DEVICE_TABLE(of, mtk_thermal_of_match);
+-
+-static void mtk_thermal_turn_on_buffer(void __iomem *apmixed_base)
+-{
+- int tmp;
+-
+- tmp = readl(apmixed_base + APMIXED_SYS_TS_CON1);
+- tmp &= ~(0x37);
+- tmp |= 0x1;
+- writel(tmp, apmixed_base + APMIXED_SYS_TS_CON1);
+- udelay(200);
+-}
+-
+-static void mtk_thermal_release_periodic_ts(struct mtk_thermal *mt,
+- void __iomem *auxadc_base)
+-{
+- int tmp;
+-
+- writel(0x800, auxadc_base + AUXADC_CON1_SET_V);
+- writel(0x1, mt->thermal_base + TEMP_MONCTL0);
+- tmp = readl(mt->thermal_base + TEMP_MSRCTL1);
+- writel((tmp & (~0x10e)), mt->thermal_base + TEMP_MSRCTL1);
+-}
+-
+-static int mtk_thermal_probe(struct platform_device *pdev)
+-{
+- int ret, i, ctrl_id;
+- struct device_node *auxadc, *apmixedsys, *np = pdev->dev.of_node;
+- struct mtk_thermal *mt;
+- u64 auxadc_phys_base, apmixed_phys_base;
+- struct thermal_zone_device *tzdev;
+- void __iomem *apmixed_base, *auxadc_base;
+-
+- mt = devm_kzalloc(&pdev->dev, sizeof(*mt), GFP_KERNEL);
+- if (!mt)
+- return -ENOMEM;
+-
+- mt->conf = of_device_get_match_data(&pdev->dev);
+-
+- mt->clk_peri_therm = devm_clk_get(&pdev->dev, "therm");
+- if (IS_ERR(mt->clk_peri_therm))
+- return PTR_ERR(mt->clk_peri_therm);
+-
+- mt->clk_auxadc = devm_clk_get(&pdev->dev, "auxadc");
+- if (IS_ERR(mt->clk_auxadc))
+- return PTR_ERR(mt->clk_auxadc);
+-
+- mt->thermal_base = devm_platform_get_and_ioremap_resource(pdev, 0, NULL);
+- if (IS_ERR(mt->thermal_base))
+- return PTR_ERR(mt->thermal_base);
+-
+- ret = mtk_thermal_get_calibration_data(&pdev->dev, mt);
+- if (ret)
+- return ret;
+-
+- mutex_init(&mt->lock);
+-
+- mt->dev = &pdev->dev;
+-
+- auxadc = of_parse_phandle(np, "mediatek,auxadc", 0);
+- if (!auxadc) {
+- dev_err(&pdev->dev, "missing auxadc node\n");
+- return -ENODEV;
+- }
+-
+- auxadc_base = of_iomap(auxadc, 0);
+- auxadc_phys_base = of_get_phys_base(auxadc);
+-
+- of_node_put(auxadc);
+-
+- if (auxadc_phys_base == OF_BAD_ADDR) {
+- dev_err(&pdev->dev, "Can't get auxadc phys address\n");
+- return -EINVAL;
+- }
+-
+- apmixedsys = of_parse_phandle(np, "mediatek,apmixedsys", 0);
+- if (!apmixedsys) {
+- dev_err(&pdev->dev, "missing apmixedsys node\n");
+- return -ENODEV;
+- }
+-
+- apmixed_base = of_iomap(apmixedsys, 0);
+- apmixed_phys_base = of_get_phys_base(apmixedsys);
+-
+- of_node_put(apmixedsys);
+-
+- if (apmixed_phys_base == OF_BAD_ADDR) {
+- dev_err(&pdev->dev, "Can't get auxadc phys address\n");
+- return -EINVAL;
+- }
+-
+- ret = device_reset_optional(&pdev->dev);
+- if (ret)
+- return ret;
+-
+- ret = clk_prepare_enable(mt->clk_auxadc);
+- if (ret) {
+- dev_err(&pdev->dev, "Can't enable auxadc clk: %d\n", ret);
+- return ret;
+- }
+-
+- ret = clk_prepare_enable(mt->clk_peri_therm);
+- if (ret) {
+- dev_err(&pdev->dev, "Can't enable peri clk: %d\n", ret);
+- goto err_disable_clk_auxadc;
+- }
+-
+- if (mt->conf->version != MTK_THERMAL_V1) {
+- mtk_thermal_turn_on_buffer(apmixed_base);
+- mtk_thermal_release_periodic_ts(mt, auxadc_base);
+- }
+-
+- if (mt->conf->version == MTK_THERMAL_V1)
+- mt->raw_to_mcelsius = raw_to_mcelsius_v1;
+- else if (mt->conf->version == MTK_THERMAL_V2)
+- mt->raw_to_mcelsius = raw_to_mcelsius_v2;
+- else
+- mt->raw_to_mcelsius = raw_to_mcelsius_v3;
+-
+- for (ctrl_id = 0; ctrl_id < mt->conf->num_controller ; ctrl_id++)
+- for (i = 0; i < mt->conf->num_banks; i++)
+- mtk_thermal_init_bank(mt, i, apmixed_phys_base,
+- auxadc_phys_base, ctrl_id);
+-
+- platform_set_drvdata(pdev, mt);
+-
+- tzdev = devm_thermal_of_zone_register(&pdev->dev, 0, mt,
+- &mtk_thermal_ops);
+- if (IS_ERR(tzdev)) {
+- ret = PTR_ERR(tzdev);
+- goto err_disable_clk_peri_therm;
+- }
+-
+- ret = devm_thermal_add_hwmon_sysfs(tzdev);
+- if (ret)
+- dev_warn(&pdev->dev, "error in thermal_add_hwmon_sysfs");
+-
+- return 0;
+-
+-err_disable_clk_peri_therm:
+- clk_disable_unprepare(mt->clk_peri_therm);
+-err_disable_clk_auxadc:
+- clk_disable_unprepare(mt->clk_auxadc);
+-
+- return ret;
+-}
+-
+-static int mtk_thermal_remove(struct platform_device *pdev)
+-{
+- struct mtk_thermal *mt = platform_get_drvdata(pdev);
+-
+- clk_disable_unprepare(mt->clk_peri_therm);
+- clk_disable_unprepare(mt->clk_auxadc);
+-
+- return 0;
+-}
+-
+-static struct platform_driver mtk_thermal_driver = {
+- .probe = mtk_thermal_probe,
+- .remove = mtk_thermal_remove,
+- .driver = {
+- .name = "mtk-thermal",
+- .of_match_table = mtk_thermal_of_match,
+- },
+-};
+-
+-module_platform_driver(mtk_thermal_driver);
+-
+-MODULE_AUTHOR("Michael Kao <michael.kao@mediatek.com>");
+-MODULE_AUTHOR("Louis Yu <louis.yu@mediatek.com>");
+-MODULE_AUTHOR("Dawei Chien <dawei.chien@mediatek.com>");
+-MODULE_AUTHOR("Sascha Hauer <s.hauer@pengutronix.de>");
+-MODULE_AUTHOR("Hanyi Wu <hanyi.wu@mediatek.com>");
+-MODULE_DESCRIPTION("Mediatek thermal driver");
+-MODULE_LICENSE("GPL v2");
+--- /dev/null
++++ b/drivers/thermal/mediatek/auxadc_thermal.c
+@@ -0,0 +1,1254 @@
++// SPDX-License-Identifier: GPL-2.0-only
++/*
++ * Copyright (c) 2015 MediaTek Inc.
++ * Author: Hanyi Wu <hanyi.wu@mediatek.com>
++ * Sascha Hauer <s.hauer@pengutronix.de>
++ * Dawei Chien <dawei.chien@mediatek.com>
++ * Louis Yu <louis.yu@mediatek.com>
++ */
++
++#include <linux/clk.h>
++#include <linux/delay.h>
++#include <linux/interrupt.h>
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/nvmem-consumer.h>
++#include <linux/of.h>
++#include <linux/of_address.h>
++#include <linux/of_device.h>
++#include <linux/platform_device.h>
++#include <linux/slab.h>
++#include <linux/io.h>
++#include <linux/thermal.h>
++#include <linux/reset.h>
++#include <linux/types.h>
++
++#include "../thermal_hwmon.h"
++
++/* AUXADC Registers */
++#define AUXADC_CON1_SET_V 0x008
++#define AUXADC_CON1_CLR_V 0x00c
++#define AUXADC_CON2_V 0x010
++#define AUXADC_DATA(channel) (0x14 + (channel) * 4)
++
++#define APMIXED_SYS_TS_CON1 0x604
++
++/* Thermal Controller Registers */
++#define TEMP_MONCTL0 0x000
++#define TEMP_MONCTL1 0x004
++#define TEMP_MONCTL2 0x008
++#define TEMP_MONIDET0 0x014
++#define TEMP_MONIDET1 0x018
++#define TEMP_MSRCTL0 0x038
++#define TEMP_MSRCTL1 0x03c
++#define TEMP_AHBPOLL 0x040
++#define TEMP_AHBTO 0x044
++#define TEMP_ADCPNP0 0x048
++#define TEMP_ADCPNP1 0x04c
++#define TEMP_ADCPNP2 0x050
++#define TEMP_ADCPNP3 0x0b4
++
++#define TEMP_ADCMUX 0x054
++#define TEMP_ADCEN 0x060
++#define TEMP_PNPMUXADDR 0x064
++#define TEMP_ADCMUXADDR 0x068
++#define TEMP_ADCENADDR 0x074
++#define TEMP_ADCVALIDADDR 0x078
++#define TEMP_ADCVOLTADDR 0x07c
++#define TEMP_RDCTRL 0x080
++#define TEMP_ADCVALIDMASK 0x084
++#define TEMP_ADCVOLTAGESHIFT 0x088
++#define TEMP_ADCWRITECTRL 0x08c
++#define TEMP_MSR0 0x090
++#define TEMP_MSR1 0x094
++#define TEMP_MSR2 0x098
++#define TEMP_MSR3 0x0B8
++
++#define TEMP_SPARE0 0x0f0
++
++#define TEMP_ADCPNP0_1 0x148
++#define TEMP_ADCPNP1_1 0x14c
++#define TEMP_ADCPNP2_1 0x150
++#define TEMP_MSR0_1 0x190
++#define TEMP_MSR1_1 0x194
++#define TEMP_MSR2_1 0x198
++#define TEMP_ADCPNP3_1 0x1b4
++#define TEMP_MSR3_1 0x1B8
++
++#define PTPCORESEL 0x400
++
++#define TEMP_MONCTL1_PERIOD_UNIT(x) ((x) & 0x3ff)
++
++#define TEMP_MONCTL2_FILTER_INTERVAL(x) (((x) & 0x3ff) << 16)
++#define TEMP_MONCTL2_SENSOR_INTERVAL(x) ((x) & 0x3ff)
++
++#define TEMP_AHBPOLL_ADC_POLL_INTERVAL(x) (x)
++
++#define TEMP_ADCWRITECTRL_ADC_PNP_WRITE BIT(0)
++#define TEMP_ADCWRITECTRL_ADC_MUX_WRITE BIT(1)
++
++#define TEMP_ADCVALIDMASK_VALID_HIGH BIT(5)
++#define TEMP_ADCVALIDMASK_VALID_POS(bit) (bit)
++
++/* MT8173 thermal sensors */
++#define MT8173_TS1 0
++#define MT8173_TS2 1
++#define MT8173_TS3 2
++#define MT8173_TS4 3
++#define MT8173_TSABB 4
++
++/* AUXADC channel 11 is used for the temperature sensors */
++#define MT8173_TEMP_AUXADC_CHANNEL 11
++
++/* The total number of temperature sensors in the MT8173 */
++#define MT8173_NUM_SENSORS 5
++
++/* The number of banks in the MT8173 */
++#define MT8173_NUM_ZONES 4
++
++/* The number of sensing points per bank */
++#define MT8173_NUM_SENSORS_PER_ZONE 4
++
++/* The number of controller in the MT8173 */
++#define MT8173_NUM_CONTROLLER 1
++
++/* The calibration coefficient of sensor */
++#define MT8173_CALIBRATION 165
++
++/*
++ * Layout of the fuses providing the calibration data
++ * These macros could be used for MT8183, MT8173, MT2701, and MT2712.
++ * MT8183 has 6 sensors and needs 6 VTS calibration data.
++ * MT8173 has 5 sensors and needs 5 VTS calibration data.
++ * MT2701 has 3 sensors and needs 3 VTS calibration data.
++ * MT2712 has 4 sensors and needs 4 VTS calibration data.
++ */
++#define CALIB_BUF0_VALID_V1 BIT(0)
++#define CALIB_BUF1_ADC_GE_V1(x) (((x) >> 22) & 0x3ff)
++#define CALIB_BUF0_VTS_TS1_V1(x) (((x) >> 17) & 0x1ff)
++#define CALIB_BUF0_VTS_TS2_V1(x) (((x) >> 8) & 0x1ff)
++#define CALIB_BUF1_VTS_TS3_V1(x) (((x) >> 0) & 0x1ff)
++#define CALIB_BUF2_VTS_TS4_V1(x) (((x) >> 23) & 0x1ff)
++#define CALIB_BUF2_VTS_TS5_V1(x) (((x) >> 5) & 0x1ff)
++#define CALIB_BUF2_VTS_TSABB_V1(x) (((x) >> 14) & 0x1ff)
++#define CALIB_BUF0_DEGC_CALI_V1(x) (((x) >> 1) & 0x3f)
++#define CALIB_BUF0_O_SLOPE_V1(x) (((x) >> 26) & 0x3f)
++#define CALIB_BUF0_O_SLOPE_SIGN_V1(x) (((x) >> 7) & 0x1)
++#define CALIB_BUF1_ID_V1(x) (((x) >> 9) & 0x1)
++
++/*
++ * Layout of the fuses providing the calibration data
++ * These macros could be used for MT7622.
++ */
++#define CALIB_BUF0_ADC_OE_V2(x) (((x) >> 22) & 0x3ff)
++#define CALIB_BUF0_ADC_GE_V2(x) (((x) >> 12) & 0x3ff)
++#define CALIB_BUF0_DEGC_CALI_V2(x) (((x) >> 6) & 0x3f)
++#define CALIB_BUF0_O_SLOPE_V2(x) (((x) >> 0) & 0x3f)
++#define CALIB_BUF1_VTS_TS1_V2(x) (((x) >> 23) & 0x1ff)
++#define CALIB_BUF1_VTS_TS2_V2(x) (((x) >> 14) & 0x1ff)
++#define CALIB_BUF1_VTS_TSABB_V2(x) (((x) >> 5) & 0x1ff)
++#define CALIB_BUF1_VALID_V2(x) (((x) >> 4) & 0x1)
++#define CALIB_BUF1_O_SLOPE_SIGN_V2(x) (((x) >> 3) & 0x1)
++
++/*
++ * Layout of the fuses providing the calibration data
++ * These macros can be used for MT7981 and MT7986.
++ */
++#define CALIB_BUF0_ADC_GE_V3(x) (((x) >> 0) & 0x3ff)
++#define CALIB_BUF0_DEGC_CALI_V3(x) (((x) >> 20) & 0x3f)
++#define CALIB_BUF0_O_SLOPE_V3(x) (((x) >> 26) & 0x3f)
++#define CALIB_BUF1_VTS_TS1_V3(x) (((x) >> 0) & 0x1ff)
++#define CALIB_BUF1_VTS_TS2_V3(x) (((x) >> 21) & 0x1ff)
++#define CALIB_BUF1_VTS_TSABB_V3(x) (((x) >> 9) & 0x1ff)
++#define CALIB_BUF1_VALID_V3(x) (((x) >> 18) & 0x1)
++#define CALIB_BUF1_O_SLOPE_SIGN_V3(x) (((x) >> 19) & 0x1)
++#define CALIB_BUF1_ID_V3(x) (((x) >> 20) & 0x1)
++
++enum {
++ VTS1,
++ VTS2,
++ VTS3,
++ VTS4,
++ VTS5,
++ VTSABB,
++ MAX_NUM_VTS,
++};
++
++enum mtk_thermal_version {
++ MTK_THERMAL_V1 = 1,
++ MTK_THERMAL_V2,
++ MTK_THERMAL_V3,
++};
++
++/* MT2701 thermal sensors */
++#define MT2701_TS1 0
++#define MT2701_TS2 1
++#define MT2701_TSABB 2
++
++/* AUXADC channel 11 is used for the temperature sensors */
++#define MT2701_TEMP_AUXADC_CHANNEL 11
++
++/* The total number of temperature sensors in the MT2701 */
++#define MT2701_NUM_SENSORS 3
++
++/* The number of sensing points per bank */
++#define MT2701_NUM_SENSORS_PER_ZONE 3
++
++/* The number of controller in the MT2701 */
++#define MT2701_NUM_CONTROLLER 1
++
++/* The calibration coefficient of sensor */
++#define MT2701_CALIBRATION 165
++
++/* MT2712 thermal sensors */
++#define MT2712_TS1 0
++#define MT2712_TS2 1
++#define MT2712_TS3 2
++#define MT2712_TS4 3
++
++/* AUXADC channel 11 is used for the temperature sensors */
++#define MT2712_TEMP_AUXADC_CHANNEL 11
++
++/* The total number of temperature sensors in the MT2712 */
++#define MT2712_NUM_SENSORS 4
++
++/* The number of sensing points per bank */
++#define MT2712_NUM_SENSORS_PER_ZONE 4
++
++/* The number of controller in the MT2712 */
++#define MT2712_NUM_CONTROLLER 1
++
++/* The calibration coefficient of sensor */
++#define MT2712_CALIBRATION 165
++
++#define MT7622_TEMP_AUXADC_CHANNEL 11
++#define MT7622_NUM_SENSORS 1
++#define MT7622_NUM_ZONES 1
++#define MT7622_NUM_SENSORS_PER_ZONE 1
++#define MT7622_TS1 0
++#define MT7622_NUM_CONTROLLER 1
++
++/* The maximum number of banks */
++#define MAX_NUM_ZONES 8
++
++/* The calibration coefficient of sensor */
++#define MT7622_CALIBRATION 165
++
++/* MT8183 thermal sensors */
++#define MT8183_TS1 0
++#define MT8183_TS2 1
++#define MT8183_TS3 2
++#define MT8183_TS4 3
++#define MT8183_TS5 4
++#define MT8183_TSABB 5
++
++/* AUXADC channel is used for the temperature sensors */
++#define MT8183_TEMP_AUXADC_CHANNEL 11
++
++/* The total number of temperature sensors in the MT8183 */
++#define MT8183_NUM_SENSORS 6
++
++/* The number of banks in the MT8183 */
++#define MT8183_NUM_ZONES 1
++
++/* The number of sensing points per bank */
++#define MT8183_NUM_SENSORS_PER_ZONE 6
++
++/* The number of controller in the MT8183 */
++#define MT8183_NUM_CONTROLLER 2
++
++/* The calibration coefficient of sensor */
++#define MT8183_CALIBRATION 153
++
++/* AUXADC channel 11 is used for the temperature sensors */
++#define MT7986_TEMP_AUXADC_CHANNEL 11
++
++/* The total number of temperature sensors in the MT7986 */
++#define MT7986_NUM_SENSORS 1
++
++/* The number of banks in the MT7986 */
++#define MT7986_NUM_ZONES 1
++
++/* The number of sensing points per bank */
++#define MT7986_NUM_SENSORS_PER_ZONE 1
++
++/* MT7986 thermal sensors */
++#define MT7986_TS1 0
++
++/* The number of controller in the MT7986 */
++#define MT7986_NUM_CONTROLLER 1
++
++/* The calibration coefficient of sensor */
++#define MT7986_CALIBRATION 165
++
++struct mtk_thermal;
++
++struct thermal_bank_cfg {
++ unsigned int num_sensors;
++ const int *sensors;
++};
++
++struct mtk_thermal_bank {
++ struct mtk_thermal *mt;
++ int id;
++};
++
++struct mtk_thermal_data {
++ s32 num_banks;
++ s32 num_sensors;
++ s32 auxadc_channel;
++ const int *vts_index;
++ const int *sensor_mux_values;
++ const int *msr;
++ const int *adcpnp;
++ const int cali_val;
++ const int num_controller;
++ const int *controller_offset;
++ bool need_switch_bank;
++ struct thermal_bank_cfg bank_data[MAX_NUM_ZONES];
++ enum mtk_thermal_version version;
++};
++
++struct mtk_thermal {
++ struct device *dev;
++ void __iomem *thermal_base;
++
++ struct clk *clk_peri_therm;
++ struct clk *clk_auxadc;
++ /* lock: for getting and putting banks */
++ struct mutex lock;
++
++ /* Calibration values */
++ s32 adc_ge;
++ s32 adc_oe;
++ s32 degc_cali;
++ s32 o_slope;
++ s32 o_slope_sign;
++ s32 vts[MAX_NUM_VTS];
++
++ const struct mtk_thermal_data *conf;
++ struct mtk_thermal_bank banks[MAX_NUM_ZONES];
++
++ int (*raw_to_mcelsius)(struct mtk_thermal *mt, int sensno, s32 raw);
++};
++
++/* MT8183 thermal sensor data */
++static const int mt8183_bank_data[MT8183_NUM_SENSORS] = {
++ MT8183_TS1, MT8183_TS2, MT8183_TS3, MT8183_TS4, MT8183_TS5, MT8183_TSABB
++};
++
++static const int mt8183_msr[MT8183_NUM_SENSORS_PER_ZONE] = {
++ TEMP_MSR0_1, TEMP_MSR1_1, TEMP_MSR2_1, TEMP_MSR1, TEMP_MSR0, TEMP_MSR3_1
++};
++
++static const int mt8183_adcpnp[MT8183_NUM_SENSORS_PER_ZONE] = {
++ TEMP_ADCPNP0_1, TEMP_ADCPNP1_1, TEMP_ADCPNP2_1,
++ TEMP_ADCPNP1, TEMP_ADCPNP0, TEMP_ADCPNP3_1
++};
++
++static const int mt8183_mux_values[MT8183_NUM_SENSORS] = { 0, 1, 2, 3, 4, 0 };
++static const int mt8183_tc_offset[MT8183_NUM_CONTROLLER] = {0x0, 0x100};
++
++static const int mt8183_vts_index[MT8183_NUM_SENSORS] = {
++ VTS1, VTS2, VTS3, VTS4, VTS5, VTSABB
++};
++
++/* MT8173 thermal sensor data */
++static const int mt8173_bank_data[MT8173_NUM_ZONES][3] = {
++ { MT8173_TS2, MT8173_TS3 },
++ { MT8173_TS2, MT8173_TS4 },
++ { MT8173_TS1, MT8173_TS2, MT8173_TSABB },
++ { MT8173_TS2 },
++};
++
++static const int mt8173_msr[MT8173_NUM_SENSORS_PER_ZONE] = {
++ TEMP_MSR0, TEMP_MSR1, TEMP_MSR2, TEMP_MSR3
++};
++
++static const int mt8173_adcpnp[MT8173_NUM_SENSORS_PER_ZONE] = {
++ TEMP_ADCPNP0, TEMP_ADCPNP1, TEMP_ADCPNP2, TEMP_ADCPNP3
++};
++
++static const int mt8173_mux_values[MT8173_NUM_SENSORS] = { 0, 1, 2, 3, 16 };
++static const int mt8173_tc_offset[MT8173_NUM_CONTROLLER] = { 0x0, };
++
++static const int mt8173_vts_index[MT8173_NUM_SENSORS] = {
++ VTS1, VTS2, VTS3, VTS4, VTSABB
++};
++
++/* MT2701 thermal sensor data */
++static const int mt2701_bank_data[MT2701_NUM_SENSORS] = {
++ MT2701_TS1, MT2701_TS2, MT2701_TSABB
++};
++
++static const int mt2701_msr[MT2701_NUM_SENSORS_PER_ZONE] = {
++ TEMP_MSR0, TEMP_MSR1, TEMP_MSR2
++};
++
++static const int mt2701_adcpnp[MT2701_NUM_SENSORS_PER_ZONE] = {
++ TEMP_ADCPNP0, TEMP_ADCPNP1, TEMP_ADCPNP2
++};
++
++static const int mt2701_mux_values[MT2701_NUM_SENSORS] = { 0, 1, 16 };
++static const int mt2701_tc_offset[MT2701_NUM_CONTROLLER] = { 0x0, };
++
++static const int mt2701_vts_index[MT2701_NUM_SENSORS] = {
++ VTS1, VTS2, VTS3
++};
++
++/* MT2712 thermal sensor data */
++static const int mt2712_bank_data[MT2712_NUM_SENSORS] = {
++ MT2712_TS1, MT2712_TS2, MT2712_TS3, MT2712_TS4
++};
++
++static const int mt2712_msr[MT2712_NUM_SENSORS_PER_ZONE] = {
++ TEMP_MSR0, TEMP_MSR1, TEMP_MSR2, TEMP_MSR3
++};
++
++static const int mt2712_adcpnp[MT2712_NUM_SENSORS_PER_ZONE] = {
++ TEMP_ADCPNP0, TEMP_ADCPNP1, TEMP_ADCPNP2, TEMP_ADCPNP3
++};
++
++static const int mt2712_mux_values[MT2712_NUM_SENSORS] = { 0, 1, 2, 3 };
++static const int mt2712_tc_offset[MT2712_NUM_CONTROLLER] = { 0x0, };
++
++static const int mt2712_vts_index[MT2712_NUM_SENSORS] = {
++ VTS1, VTS2, VTS3, VTS4
++};
++
++/* MT7622 thermal sensor data */
++static const int mt7622_bank_data[MT7622_NUM_SENSORS] = { MT7622_TS1, };
++static const int mt7622_msr[MT7622_NUM_SENSORS_PER_ZONE] = { TEMP_MSR0, };
++static const int mt7622_adcpnp[MT7622_NUM_SENSORS_PER_ZONE] = { TEMP_ADCPNP0, };
++static const int mt7622_mux_values[MT7622_NUM_SENSORS] = { 0, };
++static const int mt7622_vts_index[MT7622_NUM_SENSORS] = { VTS1 };
++static const int mt7622_tc_offset[MT7622_NUM_CONTROLLER] = { 0x0, };
++
++/* MT7986 thermal sensor data */
++static const int mt7986_bank_data[MT7986_NUM_SENSORS] = { MT7986_TS1, };
++static const int mt7986_msr[MT7986_NUM_SENSORS_PER_ZONE] = { TEMP_MSR0, };
++static const int mt7986_adcpnp[MT7986_NUM_SENSORS_PER_ZONE] = { TEMP_ADCPNP0, };
++static const int mt7986_mux_values[MT7986_NUM_SENSORS] = { 0, };
++static const int mt7986_vts_index[MT7986_NUM_SENSORS] = { VTS1 };
++static const int mt7986_tc_offset[MT7986_NUM_CONTROLLER] = { 0x0, };
++
++/*
++ * The MT8173 thermal controller has four banks. Each bank can read up to
++ * four temperature sensors simultaneously. The MT8173 has a total of 5
++ * temperature sensors. We use each bank to measure a certain area of the
++ * SoC. Since TS2 is located centrally in the SoC it is influenced by multiple
++ * areas, hence is used in different banks.
++ *
++ * The thermal core only gets the maximum temperature of all banks, so
++ * the bank concept wouldn't be necessary here. However, the SVS (Smart
++ * Voltage Scaling) unit makes its decisions based on the same bank
++ * data, and this indeed needs the temperatures of the individual banks
++ * for making better decisions.
++ */
++static const struct mtk_thermal_data mt8173_thermal_data = {
++ .auxadc_channel = MT8173_TEMP_AUXADC_CHANNEL,
++ .num_banks = MT8173_NUM_ZONES,
++ .num_sensors = MT8173_NUM_SENSORS,
++ .vts_index = mt8173_vts_index,
++ .cali_val = MT8173_CALIBRATION,
++ .num_controller = MT8173_NUM_CONTROLLER,
++ .controller_offset = mt8173_tc_offset,
++ .need_switch_bank = true,
++ .bank_data = {
++ {
++ .num_sensors = 2,
++ .sensors = mt8173_bank_data[0],
++ }, {
++ .num_sensors = 2,
++ .sensors = mt8173_bank_data[1],
++ }, {
++ .num_sensors = 3,
++ .sensors = mt8173_bank_data[2],
++ }, {
++ .num_sensors = 1,
++ .sensors = mt8173_bank_data[3],
++ },
++ },
++ .msr = mt8173_msr,
++ .adcpnp = mt8173_adcpnp,
++ .sensor_mux_values = mt8173_mux_values,
++ .version = MTK_THERMAL_V1,
++};
++
++/*
++ * The MT2701 thermal controller has one bank, which can read up to
++ * three temperature sensors simultaneously. The MT2701 has a total of 3
++ * temperature sensors.
++ *
++ * The thermal core only gets the maximum temperature of this one bank,
++ * so the bank concept wouldn't be necessary here. However, the SVS (Smart
++ * Voltage Scaling) unit makes its decisions based on the same bank
++ * data.
++ */
++static const struct mtk_thermal_data mt2701_thermal_data = {
++ .auxadc_channel = MT2701_TEMP_AUXADC_CHANNEL,
++ .num_banks = 1,
++ .num_sensors = MT2701_NUM_SENSORS,
++ .vts_index = mt2701_vts_index,
++ .cali_val = MT2701_CALIBRATION,
++ .num_controller = MT2701_NUM_CONTROLLER,
++ .controller_offset = mt2701_tc_offset,
++ .need_switch_bank = true,
++ .bank_data = {
++ {
++ .num_sensors = 3,
++ .sensors = mt2701_bank_data,
++ },
++ },
++ .msr = mt2701_msr,
++ .adcpnp = mt2701_adcpnp,
++ .sensor_mux_values = mt2701_mux_values,
++ .version = MTK_THERMAL_V1,
++};
++
++/*
++ * The MT2712 thermal controller has one bank, which can read up to
++ * four temperature sensors simultaneously. The MT2712 has a total of 4
++ * temperature sensors.
++ *
++ * The thermal core only gets the maximum temperature of this one bank,
++ * so the bank concept wouldn't be necessary here. However, the SVS (Smart
++ * Voltage Scaling) unit makes its decisions based on the same bank
++ * data.
++ */
++static const struct mtk_thermal_data mt2712_thermal_data = {
++ .auxadc_channel = MT2712_TEMP_AUXADC_CHANNEL,
++ .num_banks = 1,
++ .num_sensors = MT2712_NUM_SENSORS,
++ .vts_index = mt2712_vts_index,
++ .cali_val = MT2712_CALIBRATION,
++ .num_controller = MT2712_NUM_CONTROLLER,
++ .controller_offset = mt2712_tc_offset,
++ .need_switch_bank = true,
++ .bank_data = {
++ {
++ .num_sensors = 4,
++ .sensors = mt2712_bank_data,
++ },
++ },
++ .msr = mt2712_msr,
++ .adcpnp = mt2712_adcpnp,
++ .sensor_mux_values = mt2712_mux_values,
++ .version = MTK_THERMAL_V1,
++};
++
++/*
++ * MT7622 have only one sensing point which uses AUXADC Channel 11 for raw data
++ * access.
++ */
++static const struct mtk_thermal_data mt7622_thermal_data = {
++ .auxadc_channel = MT7622_TEMP_AUXADC_CHANNEL,
++ .num_banks = MT7622_NUM_ZONES,
++ .num_sensors = MT7622_NUM_SENSORS,
++ .vts_index = mt7622_vts_index,
++ .cali_val = MT7622_CALIBRATION,
++ .num_controller = MT7622_NUM_CONTROLLER,
++ .controller_offset = mt7622_tc_offset,
++ .need_switch_bank = true,
++ .bank_data = {
++ {
++ .num_sensors = 1,
++ .sensors = mt7622_bank_data,
++ },
++ },
++ .msr = mt7622_msr,
++ .adcpnp = mt7622_adcpnp,
++ .sensor_mux_values = mt7622_mux_values,
++ .version = MTK_THERMAL_V2,
++};
++
++/*
++ * The MT8183 thermal controller has one bank for the current SW framework.
++ * The MT8183 has a total of 6 temperature sensors.
++ * There are two thermal controller to control the six sensor.
++ * The first one bind 2 sensor, and the other bind 4 sensors.
++ * The thermal core only gets the maximum temperature of all sensor, so
++ * the bank concept wouldn't be necessary here. However, the SVS (Smart
++ * Voltage Scaling) unit makes its decisions based on the same bank
++ * data, and this indeed needs the temperatures of the individual banks
++ * for making better decisions.
++ */
++static const struct mtk_thermal_data mt8183_thermal_data = {
++ .auxadc_channel = MT8183_TEMP_AUXADC_CHANNEL,
++ .num_banks = MT8183_NUM_ZONES,
++ .num_sensors = MT8183_NUM_SENSORS,
++ .vts_index = mt8183_vts_index,
++ .cali_val = MT8183_CALIBRATION,
++ .num_controller = MT8183_NUM_CONTROLLER,
++ .controller_offset = mt8183_tc_offset,
++ .need_switch_bank = false,
++ .bank_data = {
++ {
++ .num_sensors = 6,
++ .sensors = mt8183_bank_data,
++ },
++ },
++
++ .msr = mt8183_msr,
++ .adcpnp = mt8183_adcpnp,
++ .sensor_mux_values = mt8183_mux_values,
++ .version = MTK_THERMAL_V1,
++};
++
++/*
++ * MT7986 uses AUXADC Channel 11 for raw data access.
++ */
++static const struct mtk_thermal_data mt7986_thermal_data = {
++ .auxadc_channel = MT7986_TEMP_AUXADC_CHANNEL,
++ .num_banks = MT7986_NUM_ZONES,
++ .num_sensors = MT7986_NUM_SENSORS,
++ .vts_index = mt7986_vts_index,
++ .cali_val = MT7986_CALIBRATION,
++ .num_controller = MT7986_NUM_CONTROLLER,
++ .controller_offset = mt7986_tc_offset,
++ .need_switch_bank = true,
++ .bank_data = {
++ {
++ .num_sensors = 1,
++ .sensors = mt7986_bank_data,
++ },
++ },
++ .msr = mt7986_msr,
++ .adcpnp = mt7986_adcpnp,
++ .sensor_mux_values = mt7986_mux_values,
++ .version = MTK_THERMAL_V3,
++};
++
++/**
++ * raw_to_mcelsius_v1 - convert a raw ADC value to mcelsius
++ * @mt: The thermal controller
++ * @sensno: sensor number
++ * @raw: raw ADC value
++ *
++ * This converts the raw ADC value to mcelsius using the SoC specific
++ * calibration constants
++ */
++static int raw_to_mcelsius_v1(struct mtk_thermal *mt, int sensno, s32 raw)
++{
++ s32 tmp;
++
++ raw &= 0xfff;
++
++ tmp = 203450520 << 3;
++ tmp /= mt->conf->cali_val + mt->o_slope;
++ tmp /= 10000 + mt->adc_ge;
++ tmp *= raw - mt->vts[sensno] - 3350;
++ tmp >>= 3;
++
++ return mt->degc_cali * 500 - tmp;
++}
++
++static int raw_to_mcelsius_v2(struct mtk_thermal *mt, int sensno, s32 raw)
++{
++ s32 format_1;
++ s32 format_2;
++ s32 g_oe;
++ s32 g_gain;
++ s32 g_x_roomt;
++ s32 tmp;
++
++ if (raw == 0)
++ return 0;
++
++ raw &= 0xfff;
++ g_gain = 10000 + (((mt->adc_ge - 512) * 10000) >> 12);
++ g_oe = mt->adc_oe - 512;
++ format_1 = mt->vts[VTS2] + 3105 - g_oe;
++ format_2 = (mt->degc_cali * 10) >> 1;
++ g_x_roomt = (((format_1 * 10000) >> 12) * 10000) / g_gain;
++
++ tmp = (((((raw - g_oe) * 10000) >> 12) * 10000) / g_gain) - g_x_roomt;
++ tmp = tmp * 10 * 100 / 11;
++
++ if (mt->o_slope_sign == 0)
++ tmp = tmp / (165 - mt->o_slope);
++ else
++ tmp = tmp / (165 + mt->o_slope);
++
++ return (format_2 - tmp) * 100;
++}
++
++static int raw_to_mcelsius_v3(struct mtk_thermal *mt, int sensno, s32 raw)
++{
++ s32 tmp;
++
++ if (raw == 0)
++ return 0;
++
++ raw &= 0xfff;
++ tmp = 100000 * 15 / 16 * 10000;
++ tmp /= 4096 - 512 + mt->adc_ge;
++ tmp /= 1490;
++ tmp *= raw - mt->vts[sensno] - 2900;
++
++ return mt->degc_cali * 500 - tmp;
++}
++
++/**
++ * mtk_thermal_get_bank - get bank
++ * @bank: The bank
++ *
++ * The bank registers are banked, we have to select a bank in the
++ * PTPCORESEL register to access it.
++ */
++static void mtk_thermal_get_bank(struct mtk_thermal_bank *bank)
++{
++ struct mtk_thermal *mt = bank->mt;
++ u32 val;
++
++ if (mt->conf->need_switch_bank) {
++ mutex_lock(&mt->lock);
++
++ val = readl(mt->thermal_base + PTPCORESEL);
++ val &= ~0xf;
++ val |= bank->id;
++ writel(val, mt->thermal_base + PTPCORESEL);
++ }
++}
++
++/**
++ * mtk_thermal_put_bank - release bank
++ * @bank: The bank
++ *
++ * release a bank previously taken with mtk_thermal_get_bank,
++ */
++static void mtk_thermal_put_bank(struct mtk_thermal_bank *bank)
++{
++ struct mtk_thermal *mt = bank->mt;
++
++ if (mt->conf->need_switch_bank)
++ mutex_unlock(&mt->lock);
++}
++
++/**
++ * mtk_thermal_bank_temperature - get the temperature of a bank
++ * @bank: The bank
++ *
++ * The temperature of a bank is considered the maximum temperature of
++ * the sensors associated to the bank.
++ */
++static int mtk_thermal_bank_temperature(struct mtk_thermal_bank *bank)
++{
++ struct mtk_thermal *mt = bank->mt;
++ const struct mtk_thermal_data *conf = mt->conf;
++ int i, temp = INT_MIN, max = INT_MIN;
++ u32 raw;
++
++ for (i = 0; i < conf->bank_data[bank->id].num_sensors; i++) {
++ raw = readl(mt->thermal_base + conf->msr[i]);
++
++ temp = mt->raw_to_mcelsius(
++ mt, conf->bank_data[bank->id].sensors[i], raw);
++
++
++ /*
++ * The first read of a sensor often contains very high bogus
++ * temperature value. Filter these out so that the system does
++ * not immediately shut down.
++ */
++ if (temp > 200000)
++ temp = 0;
++
++ if (temp > max)
++ max = temp;
++ }
++
++ return max;
++}
++
++static int mtk_read_temp(struct thermal_zone_device *tz, int *temperature)
++{
++ struct mtk_thermal *mt = tz->devdata;
++ int i;
++ int tempmax = INT_MIN;
++
++ for (i = 0; i < mt->conf->num_banks; i++) {
++ struct mtk_thermal_bank *bank = &mt->banks[i];
++
++ mtk_thermal_get_bank(bank);
++
++ tempmax = max(tempmax, mtk_thermal_bank_temperature(bank));
++
++ mtk_thermal_put_bank(bank);
++ }
++
++ *temperature = tempmax;
++
++ return 0;
++}
++
++static const struct thermal_zone_device_ops mtk_thermal_ops = {
++ .get_temp = mtk_read_temp,
++};
++
++static void mtk_thermal_init_bank(struct mtk_thermal *mt, int num,
++ u32 apmixed_phys_base, u32 auxadc_phys_base,
++ int ctrl_id)
++{
++ struct mtk_thermal_bank *bank = &mt->banks[num];
++ const struct mtk_thermal_data *conf = mt->conf;
++ int i;
++
++ int offset = mt->conf->controller_offset[ctrl_id];
++ void __iomem *controller_base = mt->thermal_base + offset;
++
++ bank->id = num;
++ bank->mt = mt;
++
++ mtk_thermal_get_bank(bank);
++
++ /* bus clock 66M counting unit is 12 * 15.15ns * 256 = 46.540us */
++ writel(TEMP_MONCTL1_PERIOD_UNIT(12), controller_base + TEMP_MONCTL1);
++
++ /*
++ * filt interval is 1 * 46.540us = 46.54us,
++ * sen interval is 429 * 46.540us = 19.96ms
++ */
++ writel(TEMP_MONCTL2_FILTER_INTERVAL(1) |
++ TEMP_MONCTL2_SENSOR_INTERVAL(429),
++ controller_base + TEMP_MONCTL2);
++
++ /* poll is set to 10u */
++ writel(TEMP_AHBPOLL_ADC_POLL_INTERVAL(768),
++ controller_base + TEMP_AHBPOLL);
++
++ /* temperature sampling control, 1 sample */
++ writel(0x0, controller_base + TEMP_MSRCTL0);
++
++ /* exceed this polling time, IRQ would be inserted */
++ writel(0xffffffff, controller_base + TEMP_AHBTO);
++
++ /* number of interrupts per event, 1 is enough */
++ writel(0x0, controller_base + TEMP_MONIDET0);
++ writel(0x0, controller_base + TEMP_MONIDET1);
++
++ /*
++ * The MT8173 thermal controller does not have its own ADC. Instead it
++ * uses AHB bus accesses to control the AUXADC. To do this the thermal
++ * controller has to be programmed with the physical addresses of the
++ * AUXADC registers and with the various bit positions in the AUXADC.
++ * Also the thermal controller controls a mux in the APMIXEDSYS register
++ * space.
++ */
++
++ /*
++ * this value will be stored to TEMP_PNPMUXADDR (TEMP_SPARE0)
++ * automatically by hw
++ */
++ writel(BIT(conf->auxadc_channel), controller_base + TEMP_ADCMUX);
++
++ /* AHB address for auxadc mux selection */
++ writel(auxadc_phys_base + AUXADC_CON1_CLR_V,
++ controller_base + TEMP_ADCMUXADDR);
++
++ if (mt->conf->version == MTK_THERMAL_V1) {
++ /* AHB address for pnp sensor mux selection */
++ writel(apmixed_phys_base + APMIXED_SYS_TS_CON1,
++ controller_base + TEMP_PNPMUXADDR);
++ }
++
++ /* AHB value for auxadc enable */
++ writel(BIT(conf->auxadc_channel), controller_base + TEMP_ADCEN);
++
++ /* AHB address for auxadc enable (channel 0 immediate mode selected) */
++ writel(auxadc_phys_base + AUXADC_CON1_SET_V,
++ controller_base + TEMP_ADCENADDR);
++
++ /* AHB address for auxadc valid bit */
++ writel(auxadc_phys_base + AUXADC_DATA(conf->auxadc_channel),
++ controller_base + TEMP_ADCVALIDADDR);
++
++ /* AHB address for auxadc voltage output */
++ writel(auxadc_phys_base + AUXADC_DATA(conf->auxadc_channel),
++ controller_base + TEMP_ADCVOLTADDR);
++
++ /* read valid & voltage are at the same register */
++ writel(0x0, controller_base + TEMP_RDCTRL);
++
++ /* indicate where the valid bit is */
++ writel(TEMP_ADCVALIDMASK_VALID_HIGH | TEMP_ADCVALIDMASK_VALID_POS(12),
++ controller_base + TEMP_ADCVALIDMASK);
++
++ /* no shift */
++ writel(0x0, controller_base + TEMP_ADCVOLTAGESHIFT);
++
++ /* enable auxadc mux write transaction */
++ writel(TEMP_ADCWRITECTRL_ADC_MUX_WRITE,
++ controller_base + TEMP_ADCWRITECTRL);
++
++ for (i = 0; i < conf->bank_data[num].num_sensors; i++)
++ writel(conf->sensor_mux_values[conf->bank_data[num].sensors[i]],
++ mt->thermal_base + conf->adcpnp[i]);
++
++ writel((1 << conf->bank_data[num].num_sensors) - 1,
++ controller_base + TEMP_MONCTL0);
++
++ writel(TEMP_ADCWRITECTRL_ADC_PNP_WRITE |
++ TEMP_ADCWRITECTRL_ADC_MUX_WRITE,
++ controller_base + TEMP_ADCWRITECTRL);
++
++ mtk_thermal_put_bank(bank);
++}
++
++static u64 of_get_phys_base(struct device_node *np)
++{
++ u64 size64;
++ const __be32 *regaddr_p;
++
++ regaddr_p = of_get_address(np, 0, &size64, NULL);
++ if (!regaddr_p)
++ return OF_BAD_ADDR;
++
++ return of_translate_address(np, regaddr_p);
++}
++
++static int mtk_thermal_extract_efuse_v1(struct mtk_thermal *mt, u32 *buf)
++{
++ int i;
++
++ if (!(buf[0] & CALIB_BUF0_VALID_V1))
++ return -EINVAL;
++
++ mt->adc_ge = CALIB_BUF1_ADC_GE_V1(buf[1]);
++
++ for (i = 0; i < mt->conf->num_sensors; i++) {
++ switch (mt->conf->vts_index[i]) {
++ case VTS1:
++ mt->vts[VTS1] = CALIB_BUF0_VTS_TS1_V1(buf[0]);
++ break;
++ case VTS2:
++ mt->vts[VTS2] = CALIB_BUF0_VTS_TS2_V1(buf[0]);
++ break;
++ case VTS3:
++ mt->vts[VTS3] = CALIB_BUF1_VTS_TS3_V1(buf[1]);
++ break;
++ case VTS4:
++ mt->vts[VTS4] = CALIB_BUF2_VTS_TS4_V1(buf[2]);
++ break;
++ case VTS5:
++ mt->vts[VTS5] = CALIB_BUF2_VTS_TS5_V1(buf[2]);
++ break;
++ case VTSABB:
++ mt->vts[VTSABB] =
++ CALIB_BUF2_VTS_TSABB_V1(buf[2]);
++ break;
++ default:
++ break;
++ }
++ }
++
++ mt->degc_cali = CALIB_BUF0_DEGC_CALI_V1(buf[0]);
++ if (CALIB_BUF1_ID_V1(buf[1]) &
++ CALIB_BUF0_O_SLOPE_SIGN_V1(buf[0]))
++ mt->o_slope = -CALIB_BUF0_O_SLOPE_V1(buf[0]);
++ else
++ mt->o_slope = CALIB_BUF0_O_SLOPE_V1(buf[0]);
++
++ return 0;
++}
++
++static int mtk_thermal_extract_efuse_v2(struct mtk_thermal *mt, u32 *buf)
++{
++ if (!CALIB_BUF1_VALID_V2(buf[1]))
++ return -EINVAL;
++
++ mt->adc_oe = CALIB_BUF0_ADC_OE_V2(buf[0]);
++ mt->adc_ge = CALIB_BUF0_ADC_GE_V2(buf[0]);
++ mt->degc_cali = CALIB_BUF0_DEGC_CALI_V2(buf[0]);
++ mt->o_slope = CALIB_BUF0_O_SLOPE_V2(buf[0]);
++ mt->vts[VTS1] = CALIB_BUF1_VTS_TS1_V2(buf[1]);
++ mt->vts[VTS2] = CALIB_BUF1_VTS_TS2_V2(buf[1]);
++ mt->vts[VTSABB] = CALIB_BUF1_VTS_TSABB_V2(buf[1]);
++ mt->o_slope_sign = CALIB_BUF1_O_SLOPE_SIGN_V2(buf[1]);
++
++ return 0;
++}
++
++static int mtk_thermal_extract_efuse_v3(struct mtk_thermal *mt, u32 *buf)
++{
++ if (!CALIB_BUF1_VALID_V3(buf[1]))
++ return -EINVAL;
++
++ mt->adc_ge = CALIB_BUF0_ADC_GE_V3(buf[0]);
++ mt->degc_cali = CALIB_BUF0_DEGC_CALI_V3(buf[0]);
++ mt->o_slope = CALIB_BUF0_O_SLOPE_V3(buf[0]);
++ mt->vts[VTS1] = CALIB_BUF1_VTS_TS1_V3(buf[1]);
++ mt->vts[VTS2] = CALIB_BUF1_VTS_TS2_V3(buf[1]);
++ mt->vts[VTSABB] = CALIB_BUF1_VTS_TSABB_V3(buf[1]);
++ mt->o_slope_sign = CALIB_BUF1_O_SLOPE_SIGN_V3(buf[1]);
++
++ if (CALIB_BUF1_ID_V3(buf[1]) == 0)
++ mt->o_slope = 0;
++
++ return 0;
++}
++
++static int mtk_thermal_get_calibration_data(struct device *dev,
++ struct mtk_thermal *mt)
++{
++ struct nvmem_cell *cell;
++ u32 *buf;
++ size_t len;
++ int i, ret = 0;
++
++ /* Start with default values */
++ mt->adc_ge = 512;
++ mt->adc_oe = 512;
++ for (i = 0; i < mt->conf->num_sensors; i++)
++ mt->vts[i] = 260;
++ mt->degc_cali = 40;
++ mt->o_slope = 0;
++
++ cell = nvmem_cell_get(dev, "calibration-data");
++ if (IS_ERR(cell)) {
++ if (PTR_ERR(cell) == -EPROBE_DEFER)
++ return PTR_ERR(cell);
++ return 0;
++ }
++
++ buf = (u32 *)nvmem_cell_read(cell, &len);
++
++ nvmem_cell_put(cell);
++
++ if (IS_ERR(buf))
++ return PTR_ERR(buf);
++
++ if (len < 3 * sizeof(u32)) {
++ dev_warn(dev, "invalid calibration data\n");
++ ret = -EINVAL;
++ goto out;
++ }
++
++ switch (mt->conf->version) {
++ case MTK_THERMAL_V1:
++ ret = mtk_thermal_extract_efuse_v1(mt, buf);
++ break;
++ case MTK_THERMAL_V2:
++ ret = mtk_thermal_extract_efuse_v2(mt, buf);
++ break;
++ case MTK_THERMAL_V3:
++ ret = mtk_thermal_extract_efuse_v3(mt, buf);
++ break;
++ default:
++ ret = -EINVAL;
++ break;
++ }
++
++ if (ret) {
++ dev_info(dev, "Device not calibrated, using default calibration values\n");
++ ret = 0;
++ }
++
++out:
++ kfree(buf);
++
++ return ret;
++}
++
++static const struct of_device_id mtk_thermal_of_match[] = {
++ {
++ .compatible = "mediatek,mt8173-thermal",
++ .data = (void *)&mt8173_thermal_data,
++ },
++ {
++ .compatible = "mediatek,mt2701-thermal",
++ .data = (void *)&mt2701_thermal_data,
++ },
++ {
++ .compatible = "mediatek,mt2712-thermal",
++ .data = (void *)&mt2712_thermal_data,
++ },
++ {
++ .compatible = "mediatek,mt7622-thermal",
++ .data = (void *)&mt7622_thermal_data,
++ },
++ {
++ .compatible = "mediatek,mt7986-thermal",
++ .data = (void *)&mt7986_thermal_data,
++ },
++ {
++ .compatible = "mediatek,mt8183-thermal",
++ .data = (void *)&mt8183_thermal_data,
++ }, {
++ },
++};
++MODULE_DEVICE_TABLE(of, mtk_thermal_of_match);
++
++static void mtk_thermal_turn_on_buffer(void __iomem *apmixed_base)
++{
++ int tmp;
++
++ tmp = readl(apmixed_base + APMIXED_SYS_TS_CON1);
++ tmp &= ~(0x37);
++ tmp |= 0x1;
++ writel(tmp, apmixed_base + APMIXED_SYS_TS_CON1);
++ udelay(200);
++}
++
++static void mtk_thermal_release_periodic_ts(struct mtk_thermal *mt,
++ void __iomem *auxadc_base)
++{
++ int tmp;
++
++ writel(0x800, auxadc_base + AUXADC_CON1_SET_V);
++ writel(0x1, mt->thermal_base + TEMP_MONCTL0);
++ tmp = readl(mt->thermal_base + TEMP_MSRCTL1);
++ writel((tmp & (~0x10e)), mt->thermal_base + TEMP_MSRCTL1);
++}
++
++static int mtk_thermal_probe(struct platform_device *pdev)
++{
++ int ret, i, ctrl_id;
++ struct device_node *auxadc, *apmixedsys, *np = pdev->dev.of_node;
++ struct mtk_thermal *mt;
++ u64 auxadc_phys_base, apmixed_phys_base;
++ struct thermal_zone_device *tzdev;
++ void __iomem *apmixed_base, *auxadc_base;
++
++ mt = devm_kzalloc(&pdev->dev, sizeof(*mt), GFP_KERNEL);
++ if (!mt)
++ return -ENOMEM;
++
++ mt->conf = of_device_get_match_data(&pdev->dev);
++
++ mt->clk_peri_therm = devm_clk_get(&pdev->dev, "therm");
++ if (IS_ERR(mt->clk_peri_therm))
++ return PTR_ERR(mt->clk_peri_therm);
++
++ mt->clk_auxadc = devm_clk_get(&pdev->dev, "auxadc");
++ if (IS_ERR(mt->clk_auxadc))
++ return PTR_ERR(mt->clk_auxadc);
++
++ mt->thermal_base = devm_platform_get_and_ioremap_resource(pdev, 0, NULL);
++ if (IS_ERR(mt->thermal_base))
++ return PTR_ERR(mt->thermal_base);
++
++ ret = mtk_thermal_get_calibration_data(&pdev->dev, mt);
++ if (ret)
++ return ret;
++
++ mutex_init(&mt->lock);
++
++ mt->dev = &pdev->dev;
++
++ auxadc = of_parse_phandle(np, "mediatek,auxadc", 0);
++ if (!auxadc) {
++ dev_err(&pdev->dev, "missing auxadc node\n");
++ return -ENODEV;
++ }
++
++ auxadc_base = of_iomap(auxadc, 0);
++ auxadc_phys_base = of_get_phys_base(auxadc);
++
++ of_node_put(auxadc);
++
++ if (auxadc_phys_base == OF_BAD_ADDR) {
++ dev_err(&pdev->dev, "Can't get auxadc phys address\n");
++ return -EINVAL;
++ }
++
++ apmixedsys = of_parse_phandle(np, "mediatek,apmixedsys", 0);
++ if (!apmixedsys) {
++ dev_err(&pdev->dev, "missing apmixedsys node\n");
++ return -ENODEV;
++ }
++
++ apmixed_base = of_iomap(apmixedsys, 0);
++ apmixed_phys_base = of_get_phys_base(apmixedsys);
++
++ of_node_put(apmixedsys);
++
++ if (apmixed_phys_base == OF_BAD_ADDR) {
++ dev_err(&pdev->dev, "Can't get auxadc phys address\n");
++ return -EINVAL;
++ }
++
++ ret = device_reset_optional(&pdev->dev);
++ if (ret)
++ return ret;
++
++ ret = clk_prepare_enable(mt->clk_auxadc);
++ if (ret) {
++ dev_err(&pdev->dev, "Can't enable auxadc clk: %d\n", ret);
++ return ret;
++ }
++
++ ret = clk_prepare_enable(mt->clk_peri_therm);
++ if (ret) {
++ dev_err(&pdev->dev, "Can't enable peri clk: %d\n", ret);
++ goto err_disable_clk_auxadc;
++ }
++
++ if (mt->conf->version != MTK_THERMAL_V1) {
++ mtk_thermal_turn_on_buffer(apmixed_base);
++ mtk_thermal_release_periodic_ts(mt, auxadc_base);
++ }
++
++ if (mt->conf->version == MTK_THERMAL_V1)
++ mt->raw_to_mcelsius = raw_to_mcelsius_v1;
++ else if (mt->conf->version == MTK_THERMAL_V2)
++ mt->raw_to_mcelsius = raw_to_mcelsius_v2;
++ else
++ mt->raw_to_mcelsius = raw_to_mcelsius_v3;
++
++ for (ctrl_id = 0; ctrl_id < mt->conf->num_controller ; ctrl_id++)
++ for (i = 0; i < mt->conf->num_banks; i++)
++ mtk_thermal_init_bank(mt, i, apmixed_phys_base,
++ auxadc_phys_base, ctrl_id);
++
++ platform_set_drvdata(pdev, mt);
++
++ tzdev = devm_thermal_of_zone_register(&pdev->dev, 0, mt,
++ &mtk_thermal_ops);
++ if (IS_ERR(tzdev)) {
++ ret = PTR_ERR(tzdev);
++ goto err_disable_clk_peri_therm;
++ }
++
++ ret = devm_thermal_add_hwmon_sysfs(tzdev);
++ if (ret)
++ dev_warn(&pdev->dev, "error in thermal_add_hwmon_sysfs");
++
++ return 0;
++
++err_disable_clk_peri_therm:
++ clk_disable_unprepare(mt->clk_peri_therm);
++err_disable_clk_auxadc:
++ clk_disable_unprepare(mt->clk_auxadc);
++
++ return ret;
++}
++
++static int mtk_thermal_remove(struct platform_device *pdev)
++{
++ struct mtk_thermal *mt = platform_get_drvdata(pdev);
++
++ clk_disable_unprepare(mt->clk_peri_therm);
++ clk_disable_unprepare(mt->clk_auxadc);
++
++ return 0;
++}
++
++static struct platform_driver mtk_thermal_driver = {
++ .probe = mtk_thermal_probe,
++ .remove = mtk_thermal_remove,
++ .driver = {
++ .name = "mtk-thermal",
++ .of_match_table = mtk_thermal_of_match,
++ },
++};
++
++module_platform_driver(mtk_thermal_driver);
++
++MODULE_AUTHOR("Michael Kao <michael.kao@mediatek.com>");
++MODULE_AUTHOR("Louis Yu <louis.yu@mediatek.com>");
++MODULE_AUTHOR("Dawei Chien <dawei.chien@mediatek.com>");
++MODULE_AUTHOR("Sascha Hauer <s.hauer@pengutronix.de>");
++MODULE_AUTHOR("Hanyi Wu <hanyi.wu@mediatek.com>");
++MODULE_DESCRIPTION("Mediatek thermal driver");
++MODULE_LICENSE("GPL v2");
--- /dev/null
+From 325fadf27b21f7d79843c3cc282b7f3e6620ad3d Mon Sep 17 00:00:00 2001
+From: Balsam CHIHI <bchihi@baylibre.com>
+Date: Thu, 9 Feb 2023 11:56:26 +0100
+Subject: [PATCH 06/42] thermal/drivers/mediatek: Add the Low Voltage Thermal
+ Sensor driver
+
+The Low Voltage Thermal Sensor (LVTS) is a multiple sensors, multi
+controllers contained in a thermal domain.
+
+A thermal domains can be the MCU or the AP.
+
+Each thermal domains contain up to seven controllers, each thermal
+controller handle up to four thermal sensors.
+
+The LVTS has two Finite State Machines (FSM), one to handle the
+functionin temperatures range like hot or cold temperature and another
+one to handle monitoring trip point. The FSM notifies via interrupts
+when a trip point is crossed.
+
+The interrupt is managed at the thermal controller level, so when an
+interrupt occurs, the driver has to find out which sensor triggered
+such an interrupt.
+
+The sampling of the thermal can be filtered or immediate. For the
+former, the LVTS measures several points and applies a low pass
+filter.
+
+Signed-off-by: Balsam CHIHI <bchihi@baylibre.com>
+Reviewed-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
+
+On MT8195 Tomato Chromebook:
+
+Tested-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
+Link: https://lore.kernel.org/r/20230209105628.50294-5-bchihi@baylibre.com
+Signed-off-by: Daniel Lezcano <daniel.lezcano@linaro.org>
+Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
+---
+ drivers/thermal/mediatek/Kconfig | 16 +
+ drivers/thermal/mediatek/Makefile | 1 +
+ drivers/thermal/mediatek/lvts_thermal.c | 1224 +++++++++++++++++++++++
+ 3 files changed, 1241 insertions(+)
+ create mode 100644 drivers/thermal/mediatek/lvts_thermal.c
+
+--- a/drivers/thermal/mediatek/Kconfig
++++ b/drivers/thermal/mediatek/Kconfig
+@@ -18,4 +18,20 @@ config MTK_SOC_THERMAL
+ This driver configures thermal controllers to collect
+ temperature via AUXADC interface.
+
++config MTK_LVTS_THERMAL
++ tristate "LVTS Thermal Driver for MediaTek SoCs"
++ depends on HAS_IOMEM
++ help
++ Enable this option if you want to get SoC temperature
++ information for supported MediaTek platforms.
++ This driver configures LVTS (Low Voltage Thermal Sensor)
++ thermal controllers to collect temperatures via ASIF
++ (Analog Serial Interface).
++
++config MTK_LVTS_THERMAL_DEBUGFS
++ bool "LVTS thermal debugfs"
++ depends on MTK_LVTS_THERMAL && DEBUG_FS
++ help
++ Enable this option to debug the internals of the device driver.
++
+ endif
+--- a/drivers/thermal/mediatek/Makefile
++++ b/drivers/thermal/mediatek/Makefile
+@@ -1 +1,2 @@
+ obj-$(CONFIG_MTK_SOC_THERMAL) += auxadc_thermal.o
++obj-$(CONFIG_MTK_LVTS_THERMAL) += lvts_thermal.o
+--- /dev/null
++++ b/drivers/thermal/mediatek/lvts_thermal.c
+@@ -0,0 +1,1224 @@
++// SPDX-License-Identifier: GPL-2.0-only
++/*
++ * Copyright (c) 2023 MediaTek Inc.
++ * Author: Balsam CHIHI <bchihi@baylibre.com>
++ */
++
++#include <linux/clk.h>
++#include <linux/clk-provider.h>
++#include <linux/delay.h>
++#include <linux/debugfs.h>
++#include <linux/init.h>
++#include <linux/interrupt.h>
++#include <linux/iopoll.h>
++#include <linux/kernel.h>
++#include <linux/nvmem-consumer.h>
++#include <linux/of_device.h>
++#include <linux/platform_device.h>
++#include <linux/reset.h>
++#include <linux/thermal.h>
++#include <dt-bindings/thermal/mediatek,lvts-thermal.h>
++
++#define LVTS_MONCTL0(__base) (__base + 0x0000)
++#define LVTS_MONCTL1(__base) (__base + 0x0004)
++#define LVTS_MONCTL2(__base) (__base + 0x0008)
++#define LVTS_MONINT(__base) (__base + 0x000C)
++#define LVTS_MONINTSTS(__base) (__base + 0x0010)
++#define LVTS_MONIDET0(__base) (__base + 0x0014)
++#define LVTS_MONIDET1(__base) (__base + 0x0018)
++#define LVTS_MONIDET2(__base) (__base + 0x001C)
++#define LVTS_MONIDET3(__base) (__base + 0x0020)
++#define LVTS_H2NTHRE(__base) (__base + 0x0024)
++#define LVTS_HTHRE(__base) (__base + 0x0028)
++#define LVTS_OFFSETH(__base) (__base + 0x0030)
++#define LVTS_OFFSETL(__base) (__base + 0x0034)
++#define LVTS_MSRCTL0(__base) (__base + 0x0038)
++#define LVTS_MSRCTL1(__base) (__base + 0x003C)
++#define LVTS_TSSEL(__base) (__base + 0x0040)
++#define LVTS_CALSCALE(__base) (__base + 0x0048)
++#define LVTS_ID(__base) (__base + 0x004C)
++#define LVTS_CONFIG(__base) (__base + 0x0050)
++#define LVTS_EDATA00(__base) (__base + 0x0054)
++#define LVTS_EDATA01(__base) (__base + 0x0058)
++#define LVTS_EDATA02(__base) (__base + 0x005C)
++#define LVTS_EDATA03(__base) (__base + 0x0060)
++#define LVTS_MSR0(__base) (__base + 0x0090)
++#define LVTS_MSR1(__base) (__base + 0x0094)
++#define LVTS_MSR2(__base) (__base + 0x0098)
++#define LVTS_MSR3(__base) (__base + 0x009C)
++#define LVTS_IMMD0(__base) (__base + 0x00A0)
++#define LVTS_IMMD1(__base) (__base + 0x00A4)
++#define LVTS_IMMD2(__base) (__base + 0x00A8)
++#define LVTS_IMMD3(__base) (__base + 0x00AC)
++#define LVTS_PROTCTL(__base) (__base + 0x00C0)
++#define LVTS_PROTTA(__base) (__base + 0x00C4)
++#define LVTS_PROTTB(__base) (__base + 0x00C8)
++#define LVTS_PROTTC(__base) (__base + 0x00CC)
++#define LVTS_CLKEN(__base) (__base + 0x00E4)
++
++#define LVTS_PERIOD_UNIT ((118 * 1000) / (256 * 38))
++#define LVTS_GROUP_INTERVAL 1
++#define LVTS_FILTER_INTERVAL 1
++#define LVTS_SENSOR_INTERVAL 1
++#define LVTS_HW_FILTER 0x2
++#define LVTS_TSSEL_CONF 0x13121110
++#define LVTS_CALSCALE_CONF 0x300
++#define LVTS_MONINT_CONF 0x9FBF7BDE
++
++#define LVTS_INT_SENSOR0 0x0009001F
++#define LVTS_INT_SENSOR1 0X000881F0
++#define LVTS_INT_SENSOR2 0x00247C00
++#define LVTS_INT_SENSOR3 0x1FC00000
++
++#define LVTS_SENSOR_MAX 4
++#define LVTS_GOLDEN_TEMP_MAX 62
++#define LVTS_GOLDEN_TEMP_DEFAULT 50
++#define LVTS_COEFF_A -250460
++#define LVTS_COEFF_B 250460
++
++#define LVTS_MSR_IMMEDIATE_MODE 0
++#define LVTS_MSR_FILTERED_MODE 1
++
++#define LVTS_HW_SHUTDOWN_MT8195 105000
++
++static int golden_temp = LVTS_GOLDEN_TEMP_DEFAULT;
++static int coeff_b = LVTS_COEFF_B;
++
++struct lvts_sensor_data {
++ int dt_id;
++};
++
++struct lvts_ctrl_data {
++ struct lvts_sensor_data lvts_sensor[LVTS_SENSOR_MAX];
++ int cal_offset[LVTS_SENSOR_MAX];
++ int hw_tshut_temp;
++ int num_lvts_sensor;
++ int offset;
++ int mode;
++};
++
++struct lvts_data {
++ const struct lvts_ctrl_data *lvts_ctrl;
++ int num_lvts_ctrl;
++};
++
++struct lvts_sensor {
++ struct thermal_zone_device *tz;
++ void __iomem *msr;
++ void __iomem *base;
++ int id;
++ int dt_id;
++};
++
++struct lvts_ctrl {
++ struct lvts_sensor sensors[LVTS_SENSOR_MAX];
++ u32 calibration[LVTS_SENSOR_MAX];
++ u32 hw_tshut_raw_temp;
++ int num_lvts_sensor;
++ int mode;
++ void __iomem *base;
++};
++
++struct lvts_domain {
++ struct lvts_ctrl *lvts_ctrl;
++ struct reset_control *reset;
++ struct clk *clk;
++ int num_lvts_ctrl;
++ void __iomem *base;
++ size_t calib_len;
++ u8 *calib;
++#ifdef CONFIG_DEBUG_FS
++ struct dentry *dom_dentry;
++#endif
++};
++
++#ifdef CONFIG_MTK_LVTS_THERMAL_DEBUGFS
++
++#define LVTS_DEBUG_FS_REGS(__reg) \
++{ \
++ .name = __stringify(__reg), \
++ .offset = __reg(0), \
++}
++
++static const struct debugfs_reg32 lvts_regs[] = {
++ LVTS_DEBUG_FS_REGS(LVTS_MONCTL0),
++ LVTS_DEBUG_FS_REGS(LVTS_MONCTL1),
++ LVTS_DEBUG_FS_REGS(LVTS_MONCTL2),
++ LVTS_DEBUG_FS_REGS(LVTS_MONINT),
++ LVTS_DEBUG_FS_REGS(LVTS_MONINTSTS),
++ LVTS_DEBUG_FS_REGS(LVTS_MONIDET0),
++ LVTS_DEBUG_FS_REGS(LVTS_MONIDET1),
++ LVTS_DEBUG_FS_REGS(LVTS_MONIDET2),
++ LVTS_DEBUG_FS_REGS(LVTS_MONIDET3),
++ LVTS_DEBUG_FS_REGS(LVTS_H2NTHRE),
++ LVTS_DEBUG_FS_REGS(LVTS_HTHRE),
++ LVTS_DEBUG_FS_REGS(LVTS_OFFSETH),
++ LVTS_DEBUG_FS_REGS(LVTS_OFFSETL),
++ LVTS_DEBUG_FS_REGS(LVTS_MSRCTL0),
++ LVTS_DEBUG_FS_REGS(LVTS_MSRCTL1),
++ LVTS_DEBUG_FS_REGS(LVTS_TSSEL),
++ LVTS_DEBUG_FS_REGS(LVTS_CALSCALE),
++ LVTS_DEBUG_FS_REGS(LVTS_ID),
++ LVTS_DEBUG_FS_REGS(LVTS_CONFIG),
++ LVTS_DEBUG_FS_REGS(LVTS_EDATA00),
++ LVTS_DEBUG_FS_REGS(LVTS_EDATA01),
++ LVTS_DEBUG_FS_REGS(LVTS_EDATA02),
++ LVTS_DEBUG_FS_REGS(LVTS_EDATA03),
++ LVTS_DEBUG_FS_REGS(LVTS_MSR0),
++ LVTS_DEBUG_FS_REGS(LVTS_MSR1),
++ LVTS_DEBUG_FS_REGS(LVTS_MSR2),
++ LVTS_DEBUG_FS_REGS(LVTS_MSR3),
++ LVTS_DEBUG_FS_REGS(LVTS_IMMD0),
++ LVTS_DEBUG_FS_REGS(LVTS_IMMD1),
++ LVTS_DEBUG_FS_REGS(LVTS_IMMD2),
++ LVTS_DEBUG_FS_REGS(LVTS_IMMD3),
++ LVTS_DEBUG_FS_REGS(LVTS_PROTCTL),
++ LVTS_DEBUG_FS_REGS(LVTS_PROTTA),
++ LVTS_DEBUG_FS_REGS(LVTS_PROTTB),
++ LVTS_DEBUG_FS_REGS(LVTS_PROTTC),
++ LVTS_DEBUG_FS_REGS(LVTS_CLKEN),
++};
++
++static int lvts_debugfs_init(struct device *dev, struct lvts_domain *lvts_td)
++{
++ struct debugfs_regset32 *regset;
++ struct lvts_ctrl *lvts_ctrl;
++ struct dentry *dentry;
++ char name[64];
++ int i;
++
++ lvts_td->dom_dentry = debugfs_create_dir(dev_name(dev), NULL);
++ if (!lvts_td->dom_dentry)
++ return 0;
++
++ for (i = 0; i < lvts_td->num_lvts_ctrl; i++) {
++
++ lvts_ctrl = &lvts_td->lvts_ctrl[i];
++
++ sprintf(name, "controller%d", i);
++ dentry = debugfs_create_dir(name, lvts_td->dom_dentry);
++ if (!dentry)
++ continue;
++
++ regset = devm_kzalloc(dev, sizeof(*regset), GFP_KERNEL);
++ if (!regset)
++ continue;
++
++ regset->base = lvts_ctrl->base;
++ regset->regs = lvts_regs;
++ regset->nregs = ARRAY_SIZE(lvts_regs);
++
++ debugfs_create_regset32("registers", 0400, dentry, regset);
++ }
++
++ return 0;
++}
++
++static void lvts_debugfs_exit(struct lvts_domain *lvts_td)
++{
++ debugfs_remove_recursive(lvts_td->dom_dentry);
++}
++
++#else
++
++static inline int lvts_debugfs_init(struct device *dev,
++ struct lvts_domain *lvts_td)
++{
++ return 0;
++}
++
++static void lvts_debugfs_exit(struct lvts_domain *lvts_td) { }
++
++#endif
++
++static int lvts_raw_to_temp(u32 raw_temp)
++{
++ int temperature;
++
++ temperature = ((s64)(raw_temp & 0xFFFF) * LVTS_COEFF_A) >> 14;
++ temperature += coeff_b;
++
++ return temperature;
++}
++
++static u32 lvts_temp_to_raw(int temperature)
++{
++ u32 raw_temp = ((s64)(coeff_b - temperature)) << 14;
++
++ raw_temp = div_s64(raw_temp, -LVTS_COEFF_A);
++
++ return raw_temp;
++}
++
++static int lvts_get_temp(struct thermal_zone_device *tz, int *temp)
++{
++ struct lvts_sensor *lvts_sensor = tz->devdata;
++ void __iomem *msr = lvts_sensor->msr;
++ u32 value;
++
++ /*
++ * Measurement registers:
++ *
++ * LVTS_MSR[0-3] / LVTS_IMMD[0-3]
++ *
++ * Bits:
++ *
++ * 32-17: Unused
++ * 16 : Valid temperature
++ * 15-0 : Raw temperature
++ */
++ value = readl(msr);
++
++ /*
++ * As the thermal zone temperature will read before the
++ * hardware sensor is fully initialized, we have to check the
++ * validity of the temperature returned when reading the
++ * measurement register. The thermal controller will set the
++ * valid bit temperature only when it is totally initialized.
++ *
++ * Otherwise, we may end up with garbage values out of the
++ * functionning temperature and directly jump to a system
++ * shutdown.
++ */
++ if (!(value & BIT(16)))
++ return -EAGAIN;
++
++ *temp = lvts_raw_to_temp(value & 0xFFFF);
++
++ return 0;
++}
++
++static int lvts_set_trips(struct thermal_zone_device *tz, int low, int high)
++{
++ struct lvts_sensor *lvts_sensor = tz->devdata;
++ void __iomem *base = lvts_sensor->base;
++ u32 raw_low = lvts_temp_to_raw(low);
++ u32 raw_high = lvts_temp_to_raw(high);
++
++ /*
++ * Hot to normal temperature threshold
++ *
++ * LVTS_H2NTHRE
++ *
++ * Bits:
++ *
++ * 14-0 : Raw temperature for threshold
++ */
++ if (low != -INT_MAX) {
++ dev_dbg(&tz->device, "Setting low limit temperature interrupt: %d\n", low);
++ writel(raw_low, LVTS_H2NTHRE(base));
++ }
++
++ /*
++ * Hot temperature threshold
++ *
++ * LVTS_HTHRE
++ *
++ * Bits:
++ *
++ * 14-0 : Raw temperature for threshold
++ */
++ dev_dbg(&tz->device, "Setting high limit temperature interrupt: %d\n", high);
++ writel(raw_high, LVTS_HTHRE(base));
++
++ return 0;
++}
++
++static irqreturn_t lvts_ctrl_irq_handler(struct lvts_ctrl *lvts_ctrl)
++{
++ irqreturn_t iret = IRQ_NONE;
++ u32 value;
++ u32 masks[] = {
++ LVTS_INT_SENSOR0,
++ LVTS_INT_SENSOR1,
++ LVTS_INT_SENSOR2,
++ LVTS_INT_SENSOR3
++ };
++ int i;
++
++ /*
++ * Interrupt monitoring status
++ *
++ * LVTS_MONINTST
++ *
++ * Bits:
++ *
++ * 31 : Interrupt for stage 3
++ * 30 : Interrupt for stage 2
++ * 29 : Interrupt for state 1
++ * 28 : Interrupt using filter on sensor 3
++ *
++ * 27 : Interrupt using immediate on sensor 3
++ * 26 : Interrupt normal to hot on sensor 3
++ * 25 : Interrupt high offset on sensor 3
++ * 24 : Interrupt low offset on sensor 3
++ *
++ * 23 : Interrupt hot threshold on sensor 3
++ * 22 : Interrupt cold threshold on sensor 3
++ * 21 : Interrupt using filter on sensor 2
++ * 20 : Interrupt using filter on sensor 1
++ *
++ * 19 : Interrupt using filter on sensor 0
++ * 18 : Interrupt using immediate on sensor 2
++ * 17 : Interrupt using immediate on sensor 1
++ * 16 : Interrupt using immediate on sensor 0
++ *
++ * 15 : Interrupt device access timeout interrupt
++ * 14 : Interrupt normal to hot on sensor 2
++ * 13 : Interrupt high offset interrupt on sensor 2
++ * 12 : Interrupt low offset interrupt on sensor 2
++ *
++ * 11 : Interrupt hot threshold on sensor 2
++ * 10 : Interrupt cold threshold on sensor 2
++ * 9 : Interrupt normal to hot on sensor 1
++ * 8 : Interrupt high offset interrupt on sensor 1
++ *
++ * 7 : Interrupt low offset interrupt on sensor 1
++ * 6 : Interrupt hot threshold on sensor 1
++ * 5 : Interrupt cold threshold on sensor 1
++ * 4 : Interrupt normal to hot on sensor 0
++ *
++ * 3 : Interrupt high offset interrupt on sensor 0
++ * 2 : Interrupt low offset interrupt on sensor 0
++ * 1 : Interrupt hot threshold on sensor 0
++ * 0 : Interrupt cold threshold on sensor 0
++ *
++ * We are interested in the sensor(s) responsible of the
++ * interrupt event. We update the thermal framework with the
++ * thermal zone associated with the sensor. The framework will
++ * take care of the rest whatever the kind of interrupt, we
++ * are only interested in which sensor raised the interrupt.
++ *
++ * sensor 3 interrupt: 0001 1111 1100 0000 0000 0000 0000 0000
++ * => 0x1FC00000
++ * sensor 2 interrupt: 0000 0000 0010 0100 0111 1100 0000 0000
++ * => 0x00247C00
++ * sensor 1 interrupt: 0000 0000 0001 0001 0000 0011 1110 0000
++ * => 0X000881F0
++ * sensor 0 interrupt: 0000 0000 0000 1001 0000 0000 0001 1111
++ * => 0x0009001F
++ */
++ value = readl(LVTS_MONINTSTS(lvts_ctrl->base));
++
++ /*
++ * Let's figure out which sensors raised the interrupt
++ *
++ * NOTE: the masks array must be ordered with the index
++ * corresponding to the sensor id eg. index=0, mask for
++ * sensor0.
++ */
++ for (i = 0; i < ARRAY_SIZE(masks); i++) {
++
++ if (!(value & masks[i]))
++ continue;
++
++ thermal_zone_device_update(lvts_ctrl->sensors[i].tz,
++ THERMAL_TRIP_VIOLATED);
++ iret = IRQ_HANDLED;
++ }
++
++ /*
++ * Write back to clear the interrupt status (W1C)
++ */
++ writel(value, LVTS_MONINTSTS(lvts_ctrl->base));
++
++ return iret;
++}
++
++/*
++ * Temperature interrupt handler. Even if the driver supports more
++ * interrupt modes, we use the interrupt when the temperature crosses
++ * the hot threshold the way up and the way down (modulo the
++ * hysteresis).
++ *
++ * Each thermal domain has a couple of interrupts, one for hardware
++ * reset and another one for all the thermal events happening on the
++ * different sensors.
++ *
++ * The interrupt is configured for thermal events when crossing the
++ * hot temperature limit. At each interrupt, we check in every
++ * controller if there is an interrupt pending.
++ */
++static irqreturn_t lvts_irq_handler(int irq, void *data)
++{
++ struct lvts_domain *lvts_td = data;
++ irqreturn_t aux, iret = IRQ_NONE;
++ int i;
++
++ for (i = 0; i < lvts_td->num_lvts_ctrl; i++) {
++
++ aux = lvts_ctrl_irq_handler(lvts_td->lvts_ctrl);
++ if (aux != IRQ_HANDLED)
++ continue;
++
++ iret = IRQ_HANDLED;
++ }
++
++ return iret;
++}
++
++static struct thermal_zone_device_ops lvts_ops = {
++ .get_temp = lvts_get_temp,
++ .set_trips = lvts_set_trips,
++};
++
++static int lvts_sensor_init(struct device *dev, struct lvts_ctrl *lvts_ctrl,
++ const struct lvts_ctrl_data *lvts_ctrl_data)
++{
++ struct lvts_sensor *lvts_sensor = lvts_ctrl->sensors;
++ void __iomem *msr_regs[] = {
++ LVTS_MSR0(lvts_ctrl->base),
++ LVTS_MSR1(lvts_ctrl->base),
++ LVTS_MSR2(lvts_ctrl->base),
++ LVTS_MSR3(lvts_ctrl->base)
++ };
++
++ void __iomem *imm_regs[] = {
++ LVTS_IMMD0(lvts_ctrl->base),
++ LVTS_IMMD1(lvts_ctrl->base),
++ LVTS_IMMD2(lvts_ctrl->base),
++ LVTS_IMMD3(lvts_ctrl->base)
++ };
++
++ int i;
++
++ for (i = 0; i < lvts_ctrl_data->num_lvts_sensor; i++) {
++
++ int dt_id = lvts_ctrl_data->lvts_sensor[i].dt_id;
++
++ /*
++ * At this point, we don't know which id matches which
++ * sensor. Let's set arbitrally the id from the index.
++ */
++ lvts_sensor[i].id = i;
++
++ /*
++ * The thermal zone registration will set the trip
++ * point interrupt in the thermal controller
++ * register. But this one will be reset in the
++ * initialization after. So we need to post pone the
++ * thermal zone creation after the controller is
++ * setup. For this reason, we store the device tree
++ * node id from the data in the sensor structure
++ */
++ lvts_sensor[i].dt_id = dt_id;
++
++ /*
++ * We assign the base address of the thermal
++ * controller as a back pointer. So it will be
++ * accessible from the different thermal framework ops
++ * as we pass the lvts_sensor pointer as thermal zone
++ * private data.
++ */
++ lvts_sensor[i].base = lvts_ctrl->base;
++
++ /*
++ * Each sensor has its own register address to read from.
++ */
++ lvts_sensor[i].msr = lvts_ctrl_data->mode == LVTS_MSR_IMMEDIATE_MODE ?
++ imm_regs[i] : msr_regs[i];
++ };
++
++ lvts_ctrl->num_lvts_sensor = lvts_ctrl_data->num_lvts_sensor;
++
++ return 0;
++}
++
++/*
++ * The efuse blob values follows the sensor enumeration per thermal
++ * controller. The decoding of the stream is as follow:
++ *
++ * <--?-> <----big0 ???---> <-sensor0-> <-0->
++ * ------------------------------------------
++ * index in the stream: : | 0x0 | 0x1 | 0x2 | 0x3 | 0x4 | 0x5 | 0x6 |
++ * ------------------------------------------
++ *
++ * <--sensor1--><-0-> <----big1 ???---> <-sen
++ * ------------------------------------------
++ * | 0x7 | 0x8 | 0x9 | 0xA | 0xB | OxC | OxD |
++ * ------------------------------------------
++ *
++ * sor0-> <-0-> <-sensor1-> <-0-> ..........
++ * ------------------------------------------
++ * | 0x7 | 0x8 | 0x9 | 0xA | 0xB | OxC | OxD |
++ * ------------------------------------------
++ *
++ * And so on ...
++ *
++ * The data description gives the offset of the calibration data in
++ * this bytes stream for each sensor.
++ *
++ * Each thermal controller can handle up to 4 sensors max, we don't
++ * care if there are less as the array of calibration is sized to 4
++ * anyway. The unused sensor slot will be zeroed.
++ */
++static int lvts_calibration_init(struct device *dev, struct lvts_ctrl *lvts_ctrl,
++ const struct lvts_ctrl_data *lvts_ctrl_data,
++ u8 *efuse_calibration)
++{
++ int i;
++
++ for (i = 0; i < lvts_ctrl_data->num_lvts_sensor; i++)
++ memcpy(&lvts_ctrl->calibration[i],
++ efuse_calibration + lvts_ctrl_data->cal_offset[i], 2);
++
++ return 0;
++}
++
++/*
++ * The efuse bytes stream can be split into different chunk of
++ * nvmems. This function reads and concatenate those into a single
++ * buffer so it can be read sequentially when initializing the
++ * calibration data.
++ */
++static int lvts_calibration_read(struct device *dev, struct lvts_domain *lvts_td,
++ const struct lvts_data *lvts_data)
++{
++ struct device_node *np = dev_of_node(dev);
++ struct nvmem_cell *cell;
++ struct property *prop;
++ const char *cell_name;
++
++ of_property_for_each_string(np, "nvmem-cell-names", prop, cell_name) {
++ size_t len;
++ u8 *efuse;
++
++ cell = of_nvmem_cell_get(np, cell_name);
++ if (IS_ERR(cell)) {
++ dev_err(dev, "Failed to get cell '%s'\n", cell_name);
++ return PTR_ERR(cell);
++ }
++
++ efuse = nvmem_cell_read(cell, &len);
++
++ nvmem_cell_put(cell);
++
++ if (IS_ERR(efuse)) {
++ dev_err(dev, "Failed to read cell '%s'\n", cell_name);
++ return PTR_ERR(efuse);
++ }
++
++ lvts_td->calib = devm_krealloc(dev, lvts_td->calib,
++ lvts_td->calib_len + len, GFP_KERNEL);
++ if (!lvts_td->calib)
++ return -ENOMEM;
++
++ memcpy(lvts_td->calib + lvts_td->calib_len, efuse, len);
++
++ lvts_td->calib_len += len;
++
++ kfree(efuse);
++ }
++
++ return 0;
++}
++
++static int lvts_golden_temp_init(struct device *dev, u32 *value)
++{
++ u32 gt;
++
++ gt = (*value) >> 24;
++
++ if (gt && gt < LVTS_GOLDEN_TEMP_MAX)
++ golden_temp = gt;
++
++ coeff_b = golden_temp * 500 + LVTS_COEFF_B;
++
++ return 0;
++}
++
++static int lvts_ctrl_init(struct device *dev, struct lvts_domain *lvts_td,
++ const struct lvts_data *lvts_data)
++{
++ size_t size = sizeof(*lvts_td->lvts_ctrl) * lvts_data->num_lvts_ctrl;
++ struct lvts_ctrl *lvts_ctrl;
++ int i, ret;
++
++ /*
++ * Create the calibration bytes stream from efuse data
++ */
++ ret = lvts_calibration_read(dev, lvts_td, lvts_data);
++ if (ret)
++ return ret;
++
++ /*
++ * The golden temp information is contained in the first chunk
++ * of efuse data.
++ */
++ ret = lvts_golden_temp_init(dev, (u32 *)lvts_td->calib);
++ if (ret)
++ return ret;
++
++ lvts_ctrl = devm_kzalloc(dev, size, GFP_KERNEL);
++ if (!lvts_ctrl)
++ return -ENOMEM;
++
++ for (i = 0; i < lvts_data->num_lvts_ctrl; i++) {
++
++ lvts_ctrl[i].base = lvts_td->base + lvts_data->lvts_ctrl[i].offset;
++
++ ret = lvts_sensor_init(dev, &lvts_ctrl[i],
++ &lvts_data->lvts_ctrl[i]);
++ if (ret)
++ return ret;
++
++ ret = lvts_calibration_init(dev, &lvts_ctrl[i],
++ &lvts_data->lvts_ctrl[i],
++ lvts_td->calib);
++ if (ret)
++ return ret;
++
++ /*
++ * The mode the ctrl will use to read the temperature
++ * (filtered or immediate)
++ */
++ lvts_ctrl[i].mode = lvts_data->lvts_ctrl[i].mode;
++
++ /*
++ * The temperature to raw temperature must be done
++ * after initializing the calibration.
++ */
++ lvts_ctrl[i].hw_tshut_raw_temp =
++ lvts_temp_to_raw(lvts_data->lvts_ctrl[i].hw_tshut_temp);
++ }
++
++ /*
++ * We no longer need the efuse bytes stream, let's free it
++ */
++ devm_kfree(dev, lvts_td->calib);
++
++ lvts_td->lvts_ctrl = lvts_ctrl;
++ lvts_td->num_lvts_ctrl = lvts_data->num_lvts_ctrl;
++
++ return 0;
++}
++
++/*
++ * At this point the configuration register is the only place in the
++ * driver where we write multiple values. Per hardware constraint,
++ * each write in the configuration register must be separated by a
++ * delay of 2 us.
++ */
++static void lvts_write_config(struct lvts_ctrl *lvts_ctrl, u32 *cmds, int nr_cmds)
++{
++ int i;
++
++ /*
++ * Configuration register
++ */
++ for (i = 0; i < nr_cmds; i++) {
++ writel(cmds[i], LVTS_CONFIG(lvts_ctrl->base));
++ usleep_range(2, 4);
++ }
++}
++
++static int lvts_irq_init(struct lvts_ctrl *lvts_ctrl)
++{
++ /*
++ * LVTS_PROTCTL : Thermal Protection Sensor Selection
++ *
++ * Bits:
++ *
++ * 19-18 : Sensor to base the protection on
++ * 17-16 : Strategy:
++ * 00 : Average of 4 sensors
++ * 01 : Max of 4 sensors
++ * 10 : Selected sensor with bits 19-18
++ * 11 : Reserved
++ */
++ writel(BIT(16), LVTS_PROTCTL(lvts_ctrl->base));
++
++ /*
++ * LVTS_PROTTA : Stage 1 temperature threshold
++ * LVTS_PROTTB : Stage 2 temperature threshold
++ * LVTS_PROTTC : Stage 3 temperature threshold
++ *
++ * Bits:
++ *
++ * 14-0: Raw temperature threshold
++ *
++ * writel(0x0, LVTS_PROTTA(lvts_ctrl->base));
++ * writel(0x0, LVTS_PROTTB(lvts_ctrl->base));
++ */
++ writel(lvts_ctrl->hw_tshut_raw_temp, LVTS_PROTTC(lvts_ctrl->base));
++
++ /*
++ * LVTS_MONINT : Interrupt configuration register
++ *
++ * The LVTS_MONINT register layout is the same as the LVTS_MONINTSTS
++ * register, except we set the bits to enable the interrupt.
++ */
++ writel(LVTS_MONINT_CONF, LVTS_MONINT(lvts_ctrl->base));
++
++ return 0;
++}
++
++static int lvts_domain_reset(struct device *dev, struct reset_control *reset)
++{
++ int ret;
++
++ ret = reset_control_assert(reset);
++ if (ret)
++ return ret;
++
++ return reset_control_deassert(reset);
++}
++
++/*
++ * Enable or disable the clocks of a specified thermal controller
++ */
++static int lvts_ctrl_set_enable(struct lvts_ctrl *lvts_ctrl, int enable)
++{
++ /*
++ * LVTS_CLKEN : Internal LVTS clock
++ *
++ * Bits:
++ *
++ * 0 : enable / disable clock
++ */
++ writel(enable, LVTS_CLKEN(lvts_ctrl->base));
++
++ return 0;
++}
++
++static int lvts_ctrl_connect(struct device *dev, struct lvts_ctrl *lvts_ctrl)
++{
++ u32 id, cmds[] = { 0xC103FFFF, 0xC502FF55 };
++
++ lvts_write_config(lvts_ctrl, cmds, ARRAY_SIZE(cmds));
++
++ /*
++ * LVTS_ID : Get ID and status of the thermal controller
++ *
++ * Bits:
++ *
++ * 0-5 : thermal controller id
++ * 7 : thermal controller connection is valid
++ */
++ id = readl(LVTS_ID(lvts_ctrl->base));
++ if (!(id & BIT(7)))
++ return -EIO;
++
++ return 0;
++}
++
++static int lvts_ctrl_initialize(struct device *dev, struct lvts_ctrl *lvts_ctrl)
++{
++ /*
++ * Write device mask: 0xC1030000
++ */
++ u32 cmds[] = {
++ 0xC1030E01, 0xC1030CFC, 0xC1030A8C, 0xC103098D, 0xC10308F1,
++ 0xC10307A6, 0xC10306B8, 0xC1030500, 0xC1030420, 0xC1030300,
++ 0xC1030030, 0xC10300F6, 0xC1030050, 0xC1030060, 0xC10300AC,
++ 0xC10300FC, 0xC103009D, 0xC10300F1, 0xC10300E1
++ };
++
++ lvts_write_config(lvts_ctrl, cmds, ARRAY_SIZE(cmds));
++
++ return 0;
++}
++
++static int lvts_ctrl_calibrate(struct device *dev, struct lvts_ctrl *lvts_ctrl)
++{
++ int i;
++ void __iomem *lvts_edata[] = {
++ LVTS_EDATA00(lvts_ctrl->base),
++ LVTS_EDATA01(lvts_ctrl->base),
++ LVTS_EDATA02(lvts_ctrl->base),
++ LVTS_EDATA03(lvts_ctrl->base)
++ };
++
++ /*
++ * LVTS_EDATA0X : Efuse calibration reference value for sensor X
++ *
++ * Bits:
++ *
++ * 20-0 : Efuse value for normalization data
++ */
++ for (i = 0; i < LVTS_SENSOR_MAX; i++)
++ writel(lvts_ctrl->calibration[i], lvts_edata[i]);
++
++ return 0;
++}
++
++static int lvts_ctrl_configure(struct device *dev, struct lvts_ctrl *lvts_ctrl)
++{
++ u32 value;
++
++ /*
++ * LVTS_TSSEL : Sensing point index numbering
++ *
++ * Bits:
++ *
++ * 31-24: ADC Sense 3
++ * 23-16: ADC Sense 2
++ * 15-8 : ADC Sense 1
++ * 7-0 : ADC Sense 0
++ */
++ value = LVTS_TSSEL_CONF;
++ writel(value, LVTS_TSSEL(lvts_ctrl->base));
++
++ /*
++ * LVTS_CALSCALE : ADC voltage round
++ */
++ value = 0x300;
++ value = LVTS_CALSCALE_CONF;
++
++ /*
++ * LVTS_MSRCTL0 : Sensor filtering strategy
++ *
++ * Filters:
++ *
++ * 000 : One sample
++ * 001 : Avg 2 samples
++ * 010 : 4 samples, drop min and max, avg 2 samples
++ * 011 : 6 samples, drop min and max, avg 4 samples
++ * 100 : 10 samples, drop min and max, avg 8 samples
++ * 101 : 18 samples, drop min and max, avg 16 samples
++ *
++ * Bits:
++ *
++ * 0-2 : Sensor0 filter
++ * 3-5 : Sensor1 filter
++ * 6-8 : Sensor2 filter
++ * 9-11 : Sensor3 filter
++ */
++ value = LVTS_HW_FILTER << 9 | LVTS_HW_FILTER << 6 |
++ LVTS_HW_FILTER << 3 | LVTS_HW_FILTER;
++ writel(value, LVTS_MSRCTL0(lvts_ctrl->base));
++
++ /*
++ * LVTS_MSRCTL1 : Measurement control
++ *
++ * Bits:
++ *
++ * 9: Ignore MSRCTL0 config and do immediate measurement on sensor3
++ * 6: Ignore MSRCTL0 config and do immediate measurement on sensor2
++ * 5: Ignore MSRCTL0 config and do immediate measurement on sensor1
++ * 4: Ignore MSRCTL0 config and do immediate measurement on sensor0
++ *
++ * That configuration will ignore the filtering and the delays
++ * introduced below in MONCTL1 and MONCTL2
++ */
++ if (lvts_ctrl->mode == LVTS_MSR_IMMEDIATE_MODE) {
++ value = BIT(9) | BIT(6) | BIT(5) | BIT(4);
++ writel(value, LVTS_MSRCTL1(lvts_ctrl->base));
++ }
++
++ /*
++ * LVTS_MONCTL1 : Period unit and group interval configuration
++ *
++ * The clock source of LVTS thermal controller is 26MHz.
++ *
++ * The period unit is a time base for all the interval delays
++ * specified in the registers. By default we use 12. The time
++ * conversion is done by multiplying by 256 and 1/26.10^6
++ *
++ * An interval delay multiplied by the period unit gives the
++ * duration in seconds.
++ *
++ * - Filter interval delay is a delay between two samples of
++ * the same sensor.
++ *
++ * - Sensor interval delay is a delay between two samples of
++ * different sensors.
++ *
++ * - Group interval delay is a delay between different rounds.
++ *
++ * For example:
++ * If Period unit = C, filter delay = 1, sensor delay = 2, group delay = 1,
++ * and two sensors, TS1 and TS2, are in a LVTS thermal controller
++ * and then
++ * Period unit time = C * 1/26M * 256 = 12 * 38.46ns * 256 = 118.149us
++ * Filter interval delay = 1 * Period unit = 118.149us
++ * Sensor interval delay = 2 * Period unit = 236.298us
++ * Group interval delay = 1 * Period unit = 118.149us
++ *
++ * TS1 TS1 ... TS1 TS2 TS2 ... TS2 TS1...
++ * <--> Filter interval delay
++ * <--> Sensor interval delay
++ * <--> Group interval delay
++ * Bits:
++ * 29 - 20 : Group interval
++ * 16 - 13 : Send a single interrupt when crossing the hot threshold (1)
++ * or an interrupt everytime the hot threshold is crossed (0)
++ * 9 - 0 : Period unit
++ *
++ */
++ value = LVTS_GROUP_INTERVAL << 20 | LVTS_PERIOD_UNIT;
++ writel(value, LVTS_MONCTL1(lvts_ctrl->base));
++
++ /*
++ * LVTS_MONCTL2 : Filtering and sensor interval
++ *
++ * Bits:
++ *
++ * 25-16 : Interval unit in PERIOD_UNIT between sample on
++ * the same sensor, filter interval
++ * 9-0 : Interval unit in PERIOD_UNIT between each sensor
++ *
++ */
++ value = LVTS_FILTER_INTERVAL << 16 | LVTS_SENSOR_INTERVAL;
++ writel(value, LVTS_MONCTL2(lvts_ctrl->base));
++
++ return lvts_irq_init(lvts_ctrl);
++}
++
++static int lvts_ctrl_start(struct device *dev, struct lvts_ctrl *lvts_ctrl)
++{
++ struct lvts_sensor *lvts_sensors = lvts_ctrl->sensors;
++ struct thermal_zone_device *tz;
++ u32 sensor_map = 0;
++ int i;
++
++ for (i = 0; i < lvts_ctrl->num_lvts_sensor; i++) {
++
++ int dt_id = lvts_sensors[i].dt_id;
++
++ tz = devm_thermal_of_zone_register(dev, dt_id, &lvts_sensors[i],
++ &lvts_ops);
++ if (IS_ERR(tz)) {
++ /*
++ * This thermal zone is not described in the
++ * device tree. It is not an error from the
++ * thermal OF code POV, we just continue.
++ */
++ if (PTR_ERR(tz) == -ENODEV)
++ continue;
++
++ return PTR_ERR(tz);
++ }
++
++ /*
++ * The thermal zone pointer will be needed in the
++ * interrupt handler, we store it in the sensor
++ * structure. The thermal domain structure will be
++ * passed to the interrupt handler private data as the
++ * interrupt is shared for all the controller
++ * belonging to the thermal domain.
++ */
++ lvts_sensors[i].tz = tz;
++
++ /*
++ * This sensor was correctly associated with a thermal
++ * zone, let's set the corresponding bit in the sensor
++ * map, so we can enable the temperature monitoring in
++ * the hardware thermal controller.
++ */
++ sensor_map |= BIT(i);
++ }
++
++ /*
++ * Bits:
++ * 9: Single point access flow
++ * 0-3: Enable sensing point 0-3
++ *
++ * The initialization of the thermal zones give us
++ * which sensor point to enable. If any thermal zone
++ * was not described in the device tree, it won't be
++ * enabled here in the sensor map.
++ */
++ writel(sensor_map | BIT(9), LVTS_MONCTL0(lvts_ctrl->base));
++
++ return 0;
++}
++
++static int lvts_domain_init(struct device *dev, struct lvts_domain *lvts_td,
++ const struct lvts_data *lvts_data)
++{
++ struct lvts_ctrl *lvts_ctrl;
++ int i, ret;
++
++ ret = lvts_ctrl_init(dev, lvts_td, lvts_data);
++ if (ret)
++ return ret;
++
++ ret = lvts_domain_reset(dev, lvts_td->reset);
++ if (ret) {
++ dev_dbg(dev, "Failed to reset domain");
++ return ret;
++ }
++
++ for (i = 0; i < lvts_td->num_lvts_ctrl; i++) {
++
++ lvts_ctrl = &lvts_td->lvts_ctrl[i];
++
++ /*
++ * Initialization steps:
++ *
++ * - Enable the clock
++ * - Connect to the LVTS
++ * - Initialize the LVTS
++ * - Prepare the calibration data
++ * - Select monitored sensors
++ * [ Configure sampling ]
++ * [ Configure the interrupt ]
++ * - Start measurement
++ */
++ ret = lvts_ctrl_set_enable(lvts_ctrl, true);
++ if (ret) {
++ dev_dbg(dev, "Failed to enable LVTS clock");
++ return ret;
++ }
++
++ ret = lvts_ctrl_connect(dev, lvts_ctrl);
++ if (ret) {
++ dev_dbg(dev, "Failed to connect to LVTS controller");
++ return ret;
++ }
++
++ ret = lvts_ctrl_initialize(dev, lvts_ctrl);
++ if (ret) {
++ dev_dbg(dev, "Failed to initialize controller");
++ return ret;
++ }
++
++ ret = lvts_ctrl_calibrate(dev, lvts_ctrl);
++ if (ret) {
++ dev_dbg(dev, "Failed to calibrate controller");
++ return ret;
++ }
++
++ ret = lvts_ctrl_configure(dev, lvts_ctrl);
++ if (ret) {
++ dev_dbg(dev, "Failed to configure controller");
++ return ret;
++ }
++
++ ret = lvts_ctrl_start(dev, lvts_ctrl);
++ if (ret) {
++ dev_dbg(dev, "Failed to start controller");
++ return ret;
++ }
++ }
++
++ return lvts_debugfs_init(dev, lvts_td);
++}
++
++static int lvts_probe(struct platform_device *pdev)
++{
++ const struct lvts_data *lvts_data;
++ struct lvts_domain *lvts_td;
++ struct device *dev = &pdev->dev;
++ struct resource *res;
++ int irq, ret;
++
++ lvts_td = devm_kzalloc(dev, sizeof(*lvts_td), GFP_KERNEL);
++ if (!lvts_td)
++ return -ENOMEM;
++
++ lvts_data = of_device_get_match_data(dev);
++
++ lvts_td->clk = devm_clk_get_enabled(dev, NULL);
++ if (IS_ERR(lvts_td->clk))
++ return dev_err_probe(dev, PTR_ERR(lvts_td->clk), "Failed to retrieve clock\n");
++
++ res = platform_get_mem_or_io(pdev, 0);
++ if (!res)
++ return dev_err_probe(dev, (-ENXIO), "No IO resource\n");
++
++ lvts_td->base = devm_platform_get_and_ioremap_resource(pdev, 0, &res);
++ if (IS_ERR(lvts_td->base))
++ return dev_err_probe(dev, PTR_ERR(lvts_td->base), "Failed to map io resource\n");
++
++ lvts_td->reset = devm_reset_control_get_by_index(dev, 0);
++ if (IS_ERR(lvts_td->reset))
++ return dev_err_probe(dev, PTR_ERR(lvts_td->reset), "Failed to get reset control\n");
++
++ irq = platform_get_irq(pdev, 0);
++ if (irq < 0)
++ return dev_err_probe(dev, irq, "No irq resource\n");
++
++ ret = lvts_domain_init(dev, lvts_td, lvts_data);
++ if (ret)
++ return dev_err_probe(dev, ret, "Failed to initialize the lvts domain\n");
++
++ /*
++ * At this point the LVTS is initialized and enabled. We can
++ * safely enable the interrupt.
++ */
++ ret = devm_request_threaded_irq(dev, irq, NULL, lvts_irq_handler,
++ IRQF_ONESHOT, dev_name(dev), lvts_td);
++ if (ret)
++ return dev_err_probe(dev, ret, "Failed to request interrupt\n");
++
++ platform_set_drvdata(pdev, lvts_td);
++
++ return 0;
++}
++
++static int lvts_remove(struct platform_device *pdev)
++{
++ struct lvts_domain *lvts_td;
++ int i;
++
++ lvts_td = platform_get_drvdata(pdev);
++
++ for (i = 0; i < lvts_td->num_lvts_ctrl; i++)
++ lvts_ctrl_set_enable(&lvts_td->lvts_ctrl[i], false);
++
++ lvts_debugfs_exit(lvts_td);
++
++ return 0;
++}
++
++static const struct lvts_ctrl_data mt8195_lvts_data_ctrl[] = {
++ {
++ .cal_offset = { 0x04, 0x07 },
++ .lvts_sensor = {
++ { .dt_id = MT8195_MCU_BIG_CPU0 },
++ { .dt_id = MT8195_MCU_BIG_CPU1 }
++ },
++ .num_lvts_sensor = 2,
++ .offset = 0x0,
++ .hw_tshut_temp = LVTS_HW_SHUTDOWN_MT8195,
++ },
++ {
++ .cal_offset = { 0x0d, 0x10 },
++ .lvts_sensor = {
++ { .dt_id = MT8195_MCU_BIG_CPU2 },
++ { .dt_id = MT8195_MCU_BIG_CPU3 }
++ },
++ .num_lvts_sensor = 2,
++ .offset = 0x100,
++ .hw_tshut_temp = LVTS_HW_SHUTDOWN_MT8195,
++ },
++ {
++ .cal_offset = { 0x16, 0x19, 0x1c, 0x1f },
++ .lvts_sensor = {
++ { .dt_id = MT8195_MCU_LITTLE_CPU0 },
++ { .dt_id = MT8195_MCU_LITTLE_CPU1 },
++ { .dt_id = MT8195_MCU_LITTLE_CPU2 },
++ { .dt_id = MT8195_MCU_LITTLE_CPU3 }
++ },
++ .num_lvts_sensor = 4,
++ .offset = 0x200,
++ .hw_tshut_temp = LVTS_HW_SHUTDOWN_MT8195,
++ }
++};
++
++static const struct lvts_data mt8195_lvts_mcu_data = {
++ .lvts_ctrl = mt8195_lvts_data_ctrl,
++ .num_lvts_ctrl = ARRAY_SIZE(mt8195_lvts_data_ctrl),
++};
++
++static const struct of_device_id lvts_of_match[] = {
++ { .compatible = "mediatek,mt8195-lvts-mcu", .data = &mt8195_lvts_mcu_data },
++ {},
++};
++MODULE_DEVICE_TABLE(of, lvts_of_match);
++
++static struct platform_driver lvts_driver = {
++ .probe = lvts_probe,
++ .remove = lvts_remove,
++ .driver = {
++ .name = "mtk-lvts-thermal",
++ .of_match_table = lvts_of_match,
++ },
++};
++module_platform_driver(lvts_driver);
++
++MODULE_AUTHOR("Balsam CHIHI <bchihi@baylibre.com>");
++MODULE_DESCRIPTION("MediaTek LVTS Thermal Driver");
++MODULE_LICENSE("GPL");
--- /dev/null
+From 498e2f7a6e69dcbca24715de2b4b97569fdfeff4 Mon Sep 17 00:00:00 2001
+From: Balsam CHIHI <bchihi@baylibre.com>
+Date: Thu, 9 Feb 2023 11:56:24 +0100
+Subject: [PATCH] dt-bindings: thermal: mediatek: Add LVTS thermal controllers
+
+Add LVTS thermal controllers dt-binding definition for mt8192 and mt8195.
+
+Signed-off-by: Balsam CHIHI <bchihi@baylibre.com>
+Reviewed-by: Rob Herring <robh@kernel.org>
+Link: https://lore.kernel.org/r/20230209105628.50294-3-bchihi@baylibre.com
+Signed-off-by: Daniel Lezcano <daniel.lezcano@linaro.org>
+Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
+---
+ .../thermal/mediatek,lvts-thermal.yaml | 142 ++++++++++++++++++
+ .../thermal/mediatek,lvts-thermal.h | 19 +++
+ 2 files changed, 161 insertions(+)
+ create mode 100644 Documentation/devicetree/bindings/thermal/mediatek,lvts-thermal.yaml
+ create mode 100644 include/dt-bindings/thermal/mediatek,lvts-thermal.h
+
+--- /dev/null
++++ b/Documentation/devicetree/bindings/thermal/mediatek,lvts-thermal.yaml
+@@ -0,0 +1,142 @@
++# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
++%YAML 1.2
++---
++$id: http://devicetree.org/schemas/thermal/mediatek,lvts-thermal.yaml#
++$schema: http://devicetree.org/meta-schemas/core.yaml#
++
++title: MediaTek SoC Low Voltage Thermal Sensor (LVTS)
++
++maintainers:
++ - Balsam CHIHI <bchihi@baylibre.com>
++
++description: |
++ LVTS is a thermal management architecture composed of three subsystems,
++ a Sensing device - Thermal Sensing Micro Circuit Unit (TSMCU),
++ a Converter - Low Voltage Thermal Sensor converter (LVTS), and
++ a Digital controller (LVTS_CTRL).
++
++properties:
++ compatible:
++ enum:
++ - mediatek,mt8192-lvts-ap
++ - mediatek,mt8192-lvts-mcu
++ - mediatek,mt8195-lvts-ap
++ - mediatek,mt8195-lvts-mcu
++
++ reg:
++ maxItems: 1
++
++ interrupts:
++ maxItems: 1
++
++ clocks:
++ maxItems: 1
++
++ resets:
++ maxItems: 1
++ description: LVTS reset for clearing temporary data on AP/MCU.
++
++ nvmem-cells:
++ minItems: 1
++ items:
++ - description: Calibration eFuse data 1 for LVTS
++ - description: Calibration eFuse data 2 for LVTS
++
++ nvmem-cell-names:
++ minItems: 1
++ items:
++ - const: lvts-calib-data-1
++ - const: lvts-calib-data-2
++
++ "#thermal-sensor-cells":
++ const: 1
++
++allOf:
++ - $ref: thermal-sensor.yaml#
++
++ - if:
++ properties:
++ compatible:
++ contains:
++ enum:
++ - mediatek,mt8192-lvts-ap
++ - mediatek,mt8192-lvts-mcu
++ then:
++ properties:
++ nvmem-cells:
++ maxItems: 1
++
++ nvmem-cell-names:
++ maxItems: 1
++
++ - if:
++ properties:
++ compatible:
++ contains:
++ enum:
++ - mediatek,mt8195-lvts-ap
++ - mediatek,mt8195-lvts-mcu
++ then:
++ properties:
++ nvmem-cells:
++ minItems: 2
++
++ nvmem-cell-names:
++ minItems: 2
++
++required:
++ - compatible
++ - reg
++ - interrupts
++ - clocks
++ - resets
++ - nvmem-cells
++ - nvmem-cell-names
++ - "#thermal-sensor-cells"
++
++additionalProperties: false
++
++examples:
++ - |
++ #include <dt-bindings/interrupt-controller/arm-gic.h>
++ #include <dt-bindings/clock/mt8195-clk.h>
++ #include <dt-bindings/reset/mt8195-resets.h>
++ #include <dt-bindings/thermal/mediatek,lvts-thermal.h>
++
++ soc {
++ #address-cells = <2>;
++ #size-cells = <2>;
++
++ lvts_mcu: thermal-sensor@11278000 {
++ compatible = "mediatek,mt8195-lvts-mcu";
++ reg = <0 0x11278000 0 0x1000>;
++ interrupts = <GIC_SPI 170 IRQ_TYPE_LEVEL_HIGH 0>;
++ clocks = <&infracfg_ao CLK_INFRA_AO_THERM>;
++ resets = <&infracfg_ao MT8195_INFRA_RST4_THERM_CTRL_MCU_SWRST>;
++ nvmem-cells = <&lvts_efuse_data1 &lvts_efuse_data2>;
++ nvmem-cell-names = "lvts-calib-data-1", "lvts-calib-data-2";
++ #thermal-sensor-cells = <1>;
++ };
++ };
++
++ thermal_zones: thermal-zones {
++ cpu0-thermal {
++ polling-delay = <1000>;
++ polling-delay-passive = <250>;
++ thermal-sensors = <&lvts_mcu MT8195_MCU_LITTLE_CPU0>;
++
++ trips {
++ cpu0_alert: trip-alert {
++ temperature = <85000>;
++ hysteresis = <2000>;
++ type = "passive";
++ };
++
++ cpu0_crit: trip-crit {
++ temperature = <100000>;
++ hysteresis = <2000>;
++ type = "critical";
++ };
++ };
++ };
++ };
+--- /dev/null
++++ b/include/dt-bindings/thermal/mediatek,lvts-thermal.h
+@@ -0,0 +1,19 @@
++/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) */
++/*
++ * Copyright (c) 2023 MediaTek Inc.
++ * Author: Balsam CHIHI <bchihi@baylibre.com>
++ */
++
++#ifndef __MEDIATEK_LVTS_DT_H
++#define __MEDIATEK_LVTS_DT_H
++
++#define MT8195_MCU_BIG_CPU0 0
++#define MT8195_MCU_BIG_CPU1 1
++#define MT8195_MCU_BIG_CPU2 2
++#define MT8195_MCU_BIG_CPU3 3
++#define MT8195_MCU_LITTLE_CPU0 4
++#define MT8195_MCU_LITTLE_CPU1 5
++#define MT8195_MCU_LITTLE_CPU2 6
++#define MT8195_MCU_LITTLE_CPU3 7
++
++#endif /* __MEDIATEK_LVTS_DT_H */
--- /dev/null
+From 05aaa7fdb0736262e224369b9b9f1410320fc71b Mon Sep 17 00:00:00 2001
+From: Balsam CHIHI <bchihi@baylibre.com>
+Date: Tue, 7 Mar 2023 16:45:21 +0100
+Subject: [PATCH] dt-bindings: thermal: mediatek: Add AP domain to LVTS thermal
+ controllers for mt8195
+
+Add AP Domain to LVTS thermal controllers dt-binding definition for mt8195.
+
+Signed-off-by: Balsam CHIHI <bchihi@baylibre.com>
+Acked-by: Rob Herring <robh@kernel.org>
+Reviewed-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
+Tested-by: Chen-Yu Tsai <wenst@chromium.org>
+Signed-off-by: Daniel Lezcano <daniel.lezcano@linaro.org>
+Link: https://lore.kernel.org/r/20230307154524.118541-2-bchihi@baylibre.com
+---
+ include/dt-bindings/thermal/mediatek,lvts-thermal.h | 10 ++++++++++
+ 1 file changed, 10 insertions(+)
+
+--- a/include/dt-bindings/thermal/mediatek,lvts-thermal.h
++++ b/include/dt-bindings/thermal/mediatek,lvts-thermal.h
+@@ -16,4 +16,14 @@
+ #define MT8195_MCU_LITTLE_CPU2 6
+ #define MT8195_MCU_LITTLE_CPU3 7
+
++#define MT8195_AP_VPU0 8
++#define MT8195_AP_VPU1 9
++#define MT8195_AP_GPU0 10
++#define MT8195_AP_GPU1 11
++#define MT8195_AP_VDEC 12
++#define MT8195_AP_IMG 13
++#define MT8195_AP_INFRA 14
++#define MT8195_AP_CAM0 15
++#define MT8195_AP_CAM1 16
++
+ #endif /* __MEDIATEK_LVTS_DT_H */
--- /dev/null
+From a6ff3c0021468721b96e84892a8cae24bde8d65f Mon Sep 17 00:00:00 2001
+From: Daniel Lezcano <daniel.lezcano@linaro.org>
+Date: Wed, 1 Mar 2023 21:14:29 +0100
+Subject: [PATCH] thermal/core: Add a thermal zone 'devdata' accessor
+
+The thermal zone device structure is exposed to the different drivers
+and obviously they access the internals while that should be
+restricted to the core thermal code.
+
+In order to self-encapsulate the thermal core code, we need to prevent
+the drivers accessing directly the thermal zone structure and provide
+accessor functions to deal with.
+
+Provide an accessor to the 'devdata' structure and make use of it in
+the different drivers.
+
+No functional changes intended.
+
+Signed-off-by: Daniel Lezcano <daniel.lezcano@linaro.org>
+Acked-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
+Acked-by: Mark Brown <broonie@kernel.org>
+Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
+---
+ drivers/thermal/thermal_core.c | 6 ++++++
+ include/linux/thermal.h | 7 +++++++
+ 2 files changed, 13 insertions(+)
+
+--- a/drivers/thermal/thermal_core.c
++++ b/drivers/thermal/thermal_core.c
+@@ -1346,6 +1346,12 @@ struct thermal_zone_device *thermal_zone
+ }
+ EXPORT_SYMBOL_GPL(thermal_zone_device_register);
+
++void *thermal_zone_device_priv(struct thermal_zone_device *tzd)
++{
++ return tzd->devdata;
++}
++EXPORT_SYMBOL_GPL(thermal_zone_device_priv);
++
+ /**
+ * thermal_zone_device_unregister - removes the registered thermal zone device
+ * @tz: the thermal zone device to remove
+--- a/include/linux/thermal.h
++++ b/include/linux/thermal.h
+@@ -346,6 +346,8 @@ thermal_zone_device_register_with_trips(
+ void *, struct thermal_zone_device_ops *,
+ struct thermal_zone_params *, int, int);
+
++void *thermal_zone_device_priv(struct thermal_zone_device *tzd);
++
+ int thermal_zone_bind_cooling_device(struct thermal_zone_device *, int,
+ struct thermal_cooling_device *,
+ unsigned long, unsigned long,
+@@ -417,6 +419,11 @@ static inline int thermal_zone_get_offse
+ struct thermal_zone_device *tz)
+ { return -ENODEV; }
+
++static inline void *thermal_zone_device_priv(struct thermal_zone_device *tz)
++{
++ return NULL;
++}
++
+ static inline int thermal_zone_device_enable(struct thermal_zone_device *tz)
+ { return -ENODEV; }
+
--- /dev/null
+From 072e35c98806100182c0a7263cf4cba09ce43463 Mon Sep 17 00:00:00 2001
+From: Daniel Lezcano <daniel.lezcano@linaro.org>
+Date: Wed, 1 Mar 2023 21:14:38 +0100
+Subject: [PATCH] thermal/core: Add thermal_zone_device structure 'type'
+ accessor
+
+The thermal zone device structure is exposed via the exported
+thermal.h header. This structure should stay private the thermal core
+code. In order to encapsulate the structure, let's add an accessor to
+get the 'type' of the thermal zone.
+
+Signed-off-by: Daniel Lezcano <daniel.lezcano@linaro.org>
+Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
+---
+ drivers/thermal/thermal_core.c | 6 ++++++
+ include/linux/thermal.h | 6 ++++++
+ 2 files changed, 12 insertions(+)
+
+--- a/drivers/thermal/thermal_core.c
++++ b/drivers/thermal/thermal_core.c
+@@ -1352,6 +1352,12 @@ void *thermal_zone_device_priv(struct th
+ }
+ EXPORT_SYMBOL_GPL(thermal_zone_device_priv);
+
++const char *thermal_zone_device_type(struct thermal_zone_device *tzd)
++{
++ return tzd->type;
++}
++EXPORT_SYMBOL_GPL(thermal_zone_device_type);
++
+ /**
+ * thermal_zone_device_unregister - removes the registered thermal zone device
+ * @tz: the thermal zone device to remove
+--- a/include/linux/thermal.h
++++ b/include/linux/thermal.h
+@@ -347,6 +347,7 @@ thermal_zone_device_register_with_trips(
+ struct thermal_zone_params *, int, int);
+
+ void *thermal_zone_device_priv(struct thermal_zone_device *tzd);
++const char *thermal_zone_device_type(struct thermal_zone_device *tzd);
+
+ int thermal_zone_bind_cooling_device(struct thermal_zone_device *, int,
+ struct thermal_cooling_device *,
+@@ -423,6 +424,11 @@ static inline void *thermal_zone_device_
+ {
+ return NULL;
+ }
++
++static inline const char *thermal_zone_device_type(struct thermal_zone_device *tzd)
++{
++ return NULL;
++}
+
+ static inline int thermal_zone_device_enable(struct thermal_zone_device *tz)
+ { return -ENODEV; }
--- /dev/null
+From 7d78bab533eb9aa0e5240e25a204e8f416723ed6 Mon Sep 17 00:00:00 2001
+From: Daniel Lezcano <daniel.lezcano@linaro.org>
+Date: Wed, 1 Mar 2023 21:14:30 +0100
+Subject: [PATCH 07/42] thermal/core: Use the thermal zone 'devdata' accessor
+ in thermal located drivers
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+The thermal zone device structure is exposed to the different drivers
+and obviously they access the internals while that should be
+restricted to the core thermal code.
+
+In order to self-encapsulate the thermal core code, we need to prevent
+the drivers accessing directly the thermal zone structure and provide
+accessor functions to deal with.
+
+Use the devdata accessor introduced in the previous patch.
+
+No functional changes intended.
+
+[skipped drivers not relevant for mediatek target]
+
+Signed-off-by: Daniel Lezcano <daniel.lezcano@linaro.org>
+Reviewed-by: Niklas Söderlund <niklas.soderlund+renesas@ragnatech.se> #R-Car
+Acked-by: Mark Brown <broonie@kernel.org>
+Reviewed-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com> #MediaTek auxadc and lvts
+Reviewed-by: Balsam CHIHI <bchihi@baylibre.com> #Mediatek lvts
+Reviewed-by: Adam Ward <DLG-Adam.Ward.opensource@dm.renesas.com> #da9062
+Reviewed-by: Baolin Wang <baolin.wang@linux.alibaba.com> #spread
+Acked-by: Jernej Skrabec <jernej.skrabec@gmail.com> #sun8i_thermal
+Acked-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
+Acked-by: Florian Fainelli <f.fainelli@gmail.com> #Broadcom
+Reviewed-by: Dhruva Gole <d-gole@ti.com> # K3 bandgap
+Acked-by: Linus Walleij <linus.walleij@linaro.org>
+Acked-by: Heiko Stuebner <heiko@sntech.de> #rockchip
+Reviewed-by: Kunihiko Hayashi <hayashi.kunihiko@socionext.com> #uniphier
+Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
+---
+ drivers/thermal/mediatek/auxadc_thermal.c | 2 +-
+ drivers/thermal/mediatek/lvts_thermal.c | 4 ++--
+ 43 files changed, 71 insertions(+), 73 deletions(-)
+
+--- a/drivers/thermal/mediatek/auxadc_thermal.c
++++ b/drivers/thermal/mediatek/auxadc_thermal.c
+@@ -763,7 +763,7 @@ static int mtk_thermal_bank_temperature(
+
+ static int mtk_read_temp(struct thermal_zone_device *tz, int *temperature)
+ {
+- struct mtk_thermal *mt = tz->devdata;
++ struct mtk_thermal *mt = thermal_zone_device_priv(tz);
+ int i;
+ int tempmax = INT_MIN;
+
+--- a/drivers/thermal/mediatek/lvts_thermal.c
++++ b/drivers/thermal/mediatek/lvts_thermal.c
+@@ -252,7 +252,7 @@ static u32 lvts_temp_to_raw(int temperat
+
+ static int lvts_get_temp(struct thermal_zone_device *tz, int *temp)
+ {
+- struct lvts_sensor *lvts_sensor = tz->devdata;
++ struct lvts_sensor *lvts_sensor = thermal_zone_device_priv(tz);
+ void __iomem *msr = lvts_sensor->msr;
+ u32 value;
+
+@@ -290,7 +290,7 @@ static int lvts_get_temp(struct thermal_
+
+ static int lvts_set_trips(struct thermal_zone_device *tz, int low, int high)
+ {
+- struct lvts_sensor *lvts_sensor = tz->devdata;
++ struct lvts_sensor *lvts_sensor = thermal_zone_device_priv(tz);
+ void __iomem *base = lvts_sensor->base;
+ u32 raw_low = lvts_temp_to_raw(low);
+ u32 raw_high = lvts_temp_to_raw(high);
--- /dev/null
+From cc9c60e9cfeeac45d63361fa8c085c43c4bdfe3a Mon Sep 17 00:00:00 2001
+From: Daniel Lezcano <daniel.lezcano@linaro.org>
+Date: Wed, 1 Mar 2023 21:14:36 +0100
+Subject: [PATCH 08/42] thermal/hwmon: Use the right device for
+ devm_thermal_add_hwmon_sysfs()
+
+The devres variant of thermal_add_hwmon_sysfs() only takes the thermal
+zone structure pointer as parameter.
+
+Actually, it uses the tz->device to add it in the devres list.
+
+It is preferable to use the device registering the thermal zone
+instead of the thermal zone device itself. That prevents the driver
+accessing the thermal zone structure internals and it is from my POV
+more correct regarding how devm_ is used.
+
+[skipped imx thermal which did not apply cleanly and irrelevant on
+mediatek target]
+
+Signed-off-by: Daniel Lezcano <daniel.lezcano@linaro.org>
+Acked-by: Martin Blumenstingl <martin.blumenstingl@googlemail.com> #amlogic_thermal
+Acked-by: Jernej Skrabec <jernej.skrabec@gmail.com> #sun8i_thermal
+Reviewed-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com> #MediaTek auxadc
+Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
+---
+ drivers/thermal/amlogic_thermal.c | 2 +-
+ drivers/thermal/imx_sc_thermal.c | 2 +-
+ drivers/thermal/k3_bandgap.c | 2 +-
+ drivers/thermal/mediatek/auxadc_thermal.c | 2 +-
+ drivers/thermal/qcom/qcom-spmi-adc-tm5.c | 2 +-
+ drivers/thermal/qcom/qcom-spmi-temp-alarm.c | 2 +-
+ drivers/thermal/qcom/tsens.c | 2 +-
+ drivers/thermal/qoriq_thermal.c | 2 +-
+ drivers/thermal/sun8i_thermal.c | 2 +-
+ drivers/thermal/tegra/tegra30-tsensor.c | 2 +-
+ drivers/thermal/thermal_hwmon.c | 4 ++--
+ drivers/thermal/thermal_hwmon.h | 4 ++--
+ drivers/thermal/ti-soc-thermal/ti-thermal-common.c | 2 +-
+ 13 files changed, 15 insertions(+), 15 deletions(-)
+
+--- a/drivers/thermal/amlogic_thermal.c
++++ b/drivers/thermal/amlogic_thermal.c
+@@ -286,7 +286,7 @@ static int amlogic_thermal_probe(struct
+ return ret;
+ }
+
+- if (devm_thermal_add_hwmon_sysfs(pdata->tzd))
++ if (devm_thermal_add_hwmon_sysfs(&pdev->dev, pdata->tzd))
+ dev_warn(&pdev->dev, "Failed to add hwmon sysfs attributes\n");
+
+ ret = amlogic_thermal_initialize(pdata);
+--- a/drivers/thermal/imx_sc_thermal.c
++++ b/drivers/thermal/imx_sc_thermal.c
+@@ -120,7 +120,7 @@ static int imx_sc_thermal_probe(struct p
+ return ret;
+ }
+
+- if (devm_thermal_add_hwmon_sysfs(sensor->tzd))
++ if (devm_thermal_add_hwmon_sysfs(&pdev->dev, sensor->tzd))
+ dev_warn(&pdev->dev, "failed to add hwmon sysfs attributes\n");
+ }
+
+--- a/drivers/thermal/k3_bandgap.c
++++ b/drivers/thermal/k3_bandgap.c
+@@ -222,7 +222,7 @@ static int k3_bandgap_probe(struct platf
+ goto err_alloc;
+ }
+
+- if (devm_thermal_add_hwmon_sysfs(data[id].tzd))
++ if (devm_thermal_add_hwmon_sysfs(dev, data[id].tzd))
+ dev_warn(dev, "Failed to add hwmon sysfs attributes\n");
+ }
+
+--- a/drivers/thermal/mediatek/auxadc_thermal.c
++++ b/drivers/thermal/mediatek/auxadc_thermal.c
+@@ -1210,7 +1210,7 @@ static int mtk_thermal_probe(struct plat
+ goto err_disable_clk_peri_therm;
+ }
+
+- ret = devm_thermal_add_hwmon_sysfs(tzdev);
++ ret = devm_thermal_add_hwmon_sysfs(&pdev->dev, tzdev);
+ if (ret)
+ dev_warn(&pdev->dev, "error in thermal_add_hwmon_sysfs");
+
+--- a/drivers/thermal/qcom/qcom-spmi-adc-tm5.c
++++ b/drivers/thermal/qcom/qcom-spmi-adc-tm5.c
+@@ -688,7 +688,7 @@ static int adc_tm5_register_tzd(struct a
+ return PTR_ERR(tzd);
+ }
+ adc_tm->channels[i].tzd = tzd;
+- if (devm_thermal_add_hwmon_sysfs(tzd))
++ if (devm_thermal_add_hwmon_sysfs(adc_tm->dev, tzd))
+ dev_warn(adc_tm->dev,
+ "Failed to add hwmon sysfs attributes\n");
+ }
+--- a/drivers/thermal/qcom/qcom-spmi-temp-alarm.c
++++ b/drivers/thermal/qcom/qcom-spmi-temp-alarm.c
+@@ -460,7 +460,7 @@ static int qpnp_tm_probe(struct platform
+ return ret;
+ }
+
+- if (devm_thermal_add_hwmon_sysfs(chip->tz_dev))
++ if (devm_thermal_add_hwmon_sysfs(&pdev->dev, chip->tz_dev))
+ dev_warn(&pdev->dev,
+ "Failed to add hwmon sysfs attributes\n");
+
+--- a/drivers/thermal/qcom/tsens.c
++++ b/drivers/thermal/qcom/tsens.c
+@@ -1056,7 +1056,7 @@ static int tsens_register(struct tsens_p
+ if (priv->ops->enable)
+ priv->ops->enable(priv, i);
+
+- if (devm_thermal_add_hwmon_sysfs(tzd))
++ if (devm_thermal_add_hwmon_sysfs(priv->dev, tzd))
+ dev_warn(priv->dev,
+ "Failed to add hwmon sysfs attributes\n");
+ }
+--- a/drivers/thermal/qoriq_thermal.c
++++ b/drivers/thermal/qoriq_thermal.c
+@@ -158,7 +158,7 @@ static int qoriq_tmu_register_tmu_zone(s
+ return ret;
+ }
+
+- if (devm_thermal_add_hwmon_sysfs(tzd))
++ if (devm_thermal_add_hwmon_sysfs(dev, tzd))
+ dev_warn(dev,
+ "Failed to add hwmon sysfs attributes\n");
+
+--- a/drivers/thermal/sun8i_thermal.c
++++ b/drivers/thermal/sun8i_thermal.c
+@@ -468,7 +468,7 @@ static int sun8i_ths_register(struct ths
+ if (IS_ERR(tmdev->sensor[i].tzd))
+ return PTR_ERR(tmdev->sensor[i].tzd);
+
+- if (devm_thermal_add_hwmon_sysfs(tmdev->sensor[i].tzd))
++ if (devm_thermal_add_hwmon_sysfs(tmdev->dev, tmdev->sensor[i].tzd))
+ dev_warn(tmdev->dev,
+ "Failed to add hwmon sysfs attributes\n");
+ }
+--- a/drivers/thermal/tegra/tegra30-tsensor.c
++++ b/drivers/thermal/tegra/tegra30-tsensor.c
+@@ -530,7 +530,7 @@ static int tegra_tsensor_register_channe
+ return 0;
+ }
+
+- if (devm_thermal_add_hwmon_sysfs(tsc->tzd))
++ if (devm_thermal_add_hwmon_sysfs(ts->dev, tsc->tzd))
+ dev_warn(ts->dev, "failed to add hwmon sysfs attributes\n");
+
+ return 0;
+--- a/drivers/thermal/thermal_hwmon.c
++++ b/drivers/thermal/thermal_hwmon.c
+@@ -255,7 +255,7 @@ static void devm_thermal_hwmon_release(s
+ thermal_remove_hwmon_sysfs(*(struct thermal_zone_device **)res);
+ }
+
+-int devm_thermal_add_hwmon_sysfs(struct thermal_zone_device *tz)
++int devm_thermal_add_hwmon_sysfs(struct device *dev, struct thermal_zone_device *tz)
+ {
+ struct thermal_zone_device **ptr;
+ int ret;
+@@ -272,7 +272,7 @@ int devm_thermal_add_hwmon_sysfs(struct
+ }
+
+ *ptr = tz;
+- devres_add(&tz->device, ptr);
++ devres_add(dev, ptr);
+
+ return ret;
+ }
+--- a/drivers/thermal/thermal_hwmon.h
++++ b/drivers/thermal/thermal_hwmon.h
+@@ -17,7 +17,7 @@
+
+ #ifdef CONFIG_THERMAL_HWMON
+ int thermal_add_hwmon_sysfs(struct thermal_zone_device *tz);
+-int devm_thermal_add_hwmon_sysfs(struct thermal_zone_device *tz);
++int devm_thermal_add_hwmon_sysfs(struct device *dev, struct thermal_zone_device *tz);
+ void thermal_remove_hwmon_sysfs(struct thermal_zone_device *tz);
+ #else
+ static inline int
+@@ -27,7 +27,7 @@ thermal_add_hwmon_sysfs(struct thermal_z
+ }
+
+ static inline int
+-devm_thermal_add_hwmon_sysfs(struct thermal_zone_device *tz)
++devm_thermal_add_hwmon_sysfs(struct device *dev, struct thermal_zone_device *tz)
+ {
+ return 0;
+ }
+--- a/drivers/thermal/ti-soc-thermal/ti-thermal-common.c
++++ b/drivers/thermal/ti-soc-thermal/ti-thermal-common.c
+@@ -182,7 +182,7 @@ int ti_thermal_expose_sensor(struct ti_b
+ ti_bandgap_set_sensor_data(bgp, id, data);
+ ti_bandgap_write_update_interval(bgp, data->sensor_id, interval);
+
+- if (devm_thermal_add_hwmon_sysfs(data->ti_thermal))
++ if (devm_thermal_add_hwmon_sysfs(bgp->dev, data->ti_thermal))
+ dev_warn(bgp->dev, "failed to add hwmon sysfs attributes\n");
+
+ return 0;
--- /dev/null
+From 5a72b8e4bac753e4dc74dc0a1335d120f63df97a Mon Sep 17 00:00:00 2001
+From: Daniel Lezcano <daniel.lezcano@linaro.org>
+Date: Wed, 1 Mar 2023 21:14:37 +0100
+Subject: [PATCH 09/42] thermal: Don't use 'device' internal thermal zone
+ structure field
+
+Some drivers are directly using the thermal zone's 'device' structure
+field.
+
+Use the driver device pointer instead of the thermal zone device when
+it is available.
+
+Remove the traces when they are duplicate with the traces in the core
+code.
+
+[again skipped imx_thermal.c]
+
+Cc: Jean Delvare <jdelvare@suse.com>
+Cc: Guenter Roeck <linux@roeck-us.net>
+Signed-off-by: Daniel Lezcano <daniel.lezcano@linaro.org>
+Reviewed-by: Balsam CHIHI <bchihi@baylibre.com> #Mediatek LVTS
+Reviewed-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com> #MediaTek LVTS
+Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
+---
+ drivers/thermal/mediatek/lvts_thermal.c | 4 ++--
+ drivers/thermal/thermal_hwmon.c | 4 ++--
+ drivers/thermal/ti-soc-thermal/ti-thermal-common.c | 2 +-
+ 3 files changed, 5 insertions(+), 5 deletions(-)
+
+--- a/drivers/thermal/mediatek/lvts_thermal.c
++++ b/drivers/thermal/mediatek/lvts_thermal.c
+@@ -305,7 +305,7 @@ static int lvts_set_trips(struct thermal
+ * 14-0 : Raw temperature for threshold
+ */
+ if (low != -INT_MAX) {
+- dev_dbg(&tz->device, "Setting low limit temperature interrupt: %d\n", low);
++ pr_debug("%s: Setting low limit temperature interrupt: %d\n", tz->type, low);
+ writel(raw_low, LVTS_H2NTHRE(base));
+ }
+
+@@ -318,7 +318,7 @@ static int lvts_set_trips(struct thermal
+ *
+ * 14-0 : Raw temperature for threshold
+ */
+- dev_dbg(&tz->device, "Setting high limit temperature interrupt: %d\n", high);
++ pr_debug("%s: Setting high limit temperature interrupt: %d\n", tz->type, high);
+ writel(raw_high, LVTS_HTHRE(base));
+
+ return 0;
+--- a/drivers/thermal/thermal_hwmon.c
++++ b/drivers/thermal/thermal_hwmon.c
+@@ -220,14 +220,14 @@ void thermal_remove_hwmon_sysfs(struct t
+ hwmon = thermal_hwmon_lookup_by_type(tz);
+ if (unlikely(!hwmon)) {
+ /* Should never happen... */
+- dev_dbg(&tz->device, "hwmon device lookup failed!\n");
++ dev_dbg(hwmon->device, "hwmon device lookup failed!\n");
+ return;
+ }
+
+ temp = thermal_hwmon_lookup_temp(hwmon, tz);
+ if (unlikely(!temp)) {
+ /* Should never happen... */
+- dev_dbg(&tz->device, "temperature input lookup failed!\n");
++ dev_dbg(hwmon->device, "temperature input lookup failed!\n");
+ return;
+ }
+
+--- a/drivers/thermal/ti-soc-thermal/ti-thermal-common.c
++++ b/drivers/thermal/ti-soc-thermal/ti-thermal-common.c
+@@ -43,7 +43,7 @@ static void ti_thermal_work(struct work_
+
+ thermal_zone_device_update(data->ti_thermal, THERMAL_EVENT_UNSPECIFIED);
+
+- dev_dbg(&data->ti_thermal->device, "updated thermal zone %s\n",
++ dev_dbg(data->bgp->dev, "updated thermal zone %s\n",
+ data->ti_thermal->type);
+ }
+
--- /dev/null
+From 66b3a292d3fc749e8ec7ac5278a17e8a5757ecbc Mon Sep 17 00:00:00 2001
+From: Daniel Lezcano <daniel.lezcano@linaro.org>
+Date: Wed, 1 Mar 2023 21:14:41 +0100
+Subject: [PATCH 10/42] thermal: Use thermal_zone_device_type() accessor
+
+Replace the accesses to 'tz->type' by its accessor version in order to
+self-encapsulate the thermal_zone_device structure.
+
+Signed-off-by: Daniel Lezcano <daniel.lezcano@linaro.org>
+Reviewed-by: Ido Schimmel <idosch@nvidia.com> #mlxsw
+Reviewed-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com> #MediaTek LVTS
+Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
+---
+ drivers/net/ethernet/mellanox/mlxsw/core_thermal.c | 2 +-
+ drivers/thermal/mediatek/lvts_thermal.c | 6 ++++--
+ drivers/thermal/ti-soc-thermal/ti-thermal-common.c | 2 +-
+ 3 files changed, 6 insertions(+), 4 deletions(-)
+
+--- a/drivers/net/ethernet/mellanox/mlxsw/core_thermal.c
++++ b/drivers/net/ethernet/mellanox/mlxsw/core_thermal.c
+@@ -168,7 +168,7 @@ mlxsw_thermal_module_trips_update(struct
+
+ if (crit_temp > emerg_temp) {
+ dev_warn(dev, "%s : Critical threshold %d is above emergency threshold %d\n",
+- tz->tzdev->type, crit_temp, emerg_temp);
++ thermal_zone_device_type(tz->tzdev), crit_temp, emerg_temp);
+ return 0;
+ }
+
+--- a/drivers/thermal/mediatek/lvts_thermal.c
++++ b/drivers/thermal/mediatek/lvts_thermal.c
+@@ -305,7 +305,8 @@ static int lvts_set_trips(struct thermal
+ * 14-0 : Raw temperature for threshold
+ */
+ if (low != -INT_MAX) {
+- pr_debug("%s: Setting low limit temperature interrupt: %d\n", tz->type, low);
++ pr_debug("%s: Setting low limit temperature interrupt: %d\n",
++ thermal_zone_device_type(tz), low);
+ writel(raw_low, LVTS_H2NTHRE(base));
+ }
+
+@@ -318,7 +319,8 @@ static int lvts_set_trips(struct thermal
+ *
+ * 14-0 : Raw temperature for threshold
+ */
+- pr_debug("%s: Setting high limit temperature interrupt: %d\n", tz->type, high);
++ pr_debug("%s: Setting high limit temperature interrupt: %d\n",
++ thermal_zone_device_type(tz), high);
+ writel(raw_high, LVTS_HTHRE(base));
+
+ return 0;
+--- a/drivers/thermal/ti-soc-thermal/ti-thermal-common.c
++++ b/drivers/thermal/ti-soc-thermal/ti-thermal-common.c
+@@ -44,7 +44,7 @@ static void ti_thermal_work(struct work_
+ thermal_zone_device_update(data->ti_thermal, THERMAL_EVENT_UNSPECIFIED);
+
+ dev_dbg(data->bgp->dev, "updated thermal zone %s\n",
+- data->ti_thermal->type);
++ thermal_zone_device_type(data->ti_thermal));
+ }
+
+ /**
--- /dev/null
+From f6658c1c4ae98477d6be00495226c0617354fe76 Mon Sep 17 00:00:00 2001
+From: Markus Schneider-Pargmann <msp@baylibre.com>
+Date: Fri, 27 Jan 2023 16:44:43 +0100
+Subject: [PATCH 11/42] thermal/drivers/mediatek: Control buffer enablement
+ tweaks
+
+Add logic in order to be able to turn on the control buffer on MT8365.
+This change now allows to have control buffer support for MTK_THERMAL_V1,
+and it allows to define the register offset, and mask used to enable it.
+
+Signed-off-by: Markus Schneider-Pargmann <msp@baylibre.com>
+Signed-off-by: Fabien Parent <fparent@baylibre.com>
+Signed-off-by: Amjad Ouled-Ameur <aouledameur@baylibre.com>
+Reviewed-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
+Link: https://lore.kernel.org/r/20221018-up-i350-thermal-bringup-v9-2-55a1ae14af74@baylibre.com
+Signed-off-by: Daniel Lezcano <daniel.lezcano@linaro.org>
+---
+ drivers/thermal/mediatek/auxadc_thermal.c | 28 +++++++++++++++--------
+ 1 file changed, 19 insertions(+), 9 deletions(-)
+
+--- a/drivers/thermal/mediatek/auxadc_thermal.c
++++ b/drivers/thermal/mediatek/auxadc_thermal.c
+@@ -307,6 +307,9 @@ struct mtk_thermal_data {
+ bool need_switch_bank;
+ struct thermal_bank_cfg bank_data[MAX_NUM_ZONES];
+ enum mtk_thermal_version version;
++ u32 apmixed_buffer_ctl_reg;
++ u32 apmixed_buffer_ctl_mask;
++ u32 apmixed_buffer_ctl_set;
+ };
+
+ struct mtk_thermal {
+@@ -560,6 +563,9 @@ static const struct mtk_thermal_data mt7
+ .adcpnp = mt7622_adcpnp,
+ .sensor_mux_values = mt7622_mux_values,
+ .version = MTK_THERMAL_V2,
++ .apmixed_buffer_ctl_reg = APMIXED_SYS_TS_CON1,
++ .apmixed_buffer_ctl_mask = GENMASK(31, 6) | BIT(3),
++ .apmixed_buffer_ctl_set = BIT(0),
+ };
+
+ /*
+@@ -1079,14 +1085,18 @@ static const struct of_device_id mtk_the
+ };
+ MODULE_DEVICE_TABLE(of, mtk_thermal_of_match);
+
+-static void mtk_thermal_turn_on_buffer(void __iomem *apmixed_base)
++static void mtk_thermal_turn_on_buffer(struct mtk_thermal *mt,
++ void __iomem *apmixed_base)
+ {
+- int tmp;
++ u32 tmp;
++
++ if (!mt->conf->apmixed_buffer_ctl_reg)
++ return;
+
+- tmp = readl(apmixed_base + APMIXED_SYS_TS_CON1);
+- tmp &= ~(0x37);
+- tmp |= 0x1;
+- writel(tmp, apmixed_base + APMIXED_SYS_TS_CON1);
++ tmp = readl(apmixed_base + mt->conf->apmixed_buffer_ctl_reg);
++ tmp &= mt->conf->apmixed_buffer_ctl_mask;
++ tmp |= mt->conf->apmixed_buffer_ctl_set;
++ writel(tmp, apmixed_base + mt->conf->apmixed_buffer_ctl_reg);
+ udelay(200);
+ }
+
+@@ -1184,10 +1194,10 @@ static int mtk_thermal_probe(struct plat
+ goto err_disable_clk_auxadc;
+ }
+
+- if (mt->conf->version != MTK_THERMAL_V1) {
+- mtk_thermal_turn_on_buffer(apmixed_base);
++ mtk_thermal_turn_on_buffer(mt, apmixed_base);
++
++ if (mt->conf->version != MTK_THERMAL_V2)
+ mtk_thermal_release_periodic_ts(mt, auxadc_base);
+- }
+
+ if (mt->conf->version == MTK_THERMAL_V1)
+ mt->raw_to_mcelsius = raw_to_mcelsius_v1;
--- /dev/null
+From c4eff784465f88218dc5eb51320320464db83d3f Mon Sep 17 00:00:00 2001
+From: Fabien Parent <fparent@baylibre.com>
+Date: Fri, 27 Jan 2023 16:44:44 +0100
+Subject: [PATCH 12/42] thermal/drivers/mediatek: Add support for MT8365 SoC
+
+MT8365 is similar to the other SoCs supported by the driver. It has only
+one bank and 3 actual sensors that can be multiplexed. There is another
+one sensor that does not have usable data.
+
+Signed-off-by: Fabien Parent <fparent@baylibre.com>
+Signed-off-by: Amjad Ouled-Ameur <aouledameur@baylibre.com>
+Reviewed-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
+Link: https://lore.kernel.org/r/20221018-up-i350-thermal-bringup-v9-3-55a1ae14af74@baylibre.com
+Signed-off-by: Daniel Lezcano <daniel.lezcano@linaro.org>
+---
+ drivers/thermal/mediatek/auxadc_thermal.c | 68 +++++++++++++++++++++++
+ 1 file changed, 68 insertions(+)
+
+--- a/drivers/thermal/mediatek/auxadc_thermal.c
++++ b/drivers/thermal/mediatek/auxadc_thermal.c
+@@ -31,6 +31,7 @@
+ #define AUXADC_CON2_V 0x010
+ #define AUXADC_DATA(channel) (0x14 + (channel) * 4)
+
++#define APMIXED_SYS_TS_CON0 0x600
+ #define APMIXED_SYS_TS_CON1 0x604
+
+ /* Thermal Controller Registers */
+@@ -281,6 +282,17 @@ enum mtk_thermal_version {
+ /* The calibration coefficient of sensor */
+ #define MT7986_CALIBRATION 165
+
++/* MT8365 */
++#define MT8365_TEMP_AUXADC_CHANNEL 11
++#define MT8365_CALIBRATION 164
++#define MT8365_NUM_CONTROLLER 1
++#define MT8365_NUM_BANKS 1
++#define MT8365_NUM_SENSORS 3
++#define MT8365_NUM_SENSORS_PER_ZONE 3
++#define MT8365_TS1 0
++#define MT8365_TS2 1
++#define MT8365_TS3 2
++
+ struct mtk_thermal;
+
+ struct thermal_bank_cfg {
+@@ -435,6 +447,24 @@ static const int mt7986_mux_values[MT798
+ static const int mt7986_vts_index[MT7986_NUM_SENSORS] = { VTS1 };
+ static const int mt7986_tc_offset[MT7986_NUM_CONTROLLER] = { 0x0, };
+
++/* MT8365 thermal sensor data */
++static const int mt8365_bank_data[MT8365_NUM_SENSORS] = {
++ MT8365_TS1, MT8365_TS2, MT8365_TS3
++};
++
++static const int mt8365_msr[MT8365_NUM_SENSORS_PER_ZONE] = {
++ TEMP_MSR0, TEMP_MSR1, TEMP_MSR2
++};
++
++static const int mt8365_adcpnp[MT8365_NUM_SENSORS_PER_ZONE] = {
++ TEMP_ADCPNP0, TEMP_ADCPNP1, TEMP_ADCPNP2
++};
++
++static const int mt8365_mux_values[MT8365_NUM_SENSORS] = { 0, 1, 2 };
++static const int mt8365_tc_offset[MT8365_NUM_CONTROLLER] = { 0 };
++
++static const int mt8365_vts_index[MT8365_NUM_SENSORS] = { VTS1, VTS2, VTS3 };
++
+ /*
+ * The MT8173 thermal controller has four banks. Each bank can read up to
+ * four temperature sensors simultaneously. The MT8173 has a total of 5
+@@ -510,6 +540,40 @@ static const struct mtk_thermal_data mt2
+ };
+
+ /*
++ * The MT8365 thermal controller has one bank, which can read up to
++ * four temperature sensors simultaneously. The MT8365 has a total of 3
++ * temperature sensors.
++ *
++ * The thermal core only gets the maximum temperature of this one bank,
++ * so the bank concept wouldn't be necessary here. However, the SVS (Smart
++ * Voltage Scaling) unit makes its decisions based on the same bank
++ * data.
++ */
++static const struct mtk_thermal_data mt8365_thermal_data = {
++ .auxadc_channel = MT8365_TEMP_AUXADC_CHANNEL,
++ .num_banks = MT8365_NUM_BANKS,
++ .num_sensors = MT8365_NUM_SENSORS,
++ .vts_index = mt8365_vts_index,
++ .cali_val = MT8365_CALIBRATION,
++ .num_controller = MT8365_NUM_CONTROLLER,
++ .controller_offset = mt8365_tc_offset,
++ .need_switch_bank = false,
++ .bank_data = {
++ {
++ .num_sensors = MT8365_NUM_SENSORS,
++ .sensors = mt8365_bank_data
++ },
++ },
++ .msr = mt8365_msr,
++ .adcpnp = mt8365_adcpnp,
++ .sensor_mux_values = mt8365_mux_values,
++ .version = MTK_THERMAL_V1,
++ .apmixed_buffer_ctl_reg = APMIXED_SYS_TS_CON0,
++ .apmixed_buffer_ctl_mask = (u32) ~GENMASK(29, 28),
++ .apmixed_buffer_ctl_set = 0,
++};
++
++/*
+ * The MT2712 thermal controller has one bank, which can read up to
+ * four temperature sensors simultaneously. The MT2712 has a total of 4
+ * temperature sensors.
+@@ -1080,6 +1144,10 @@ static const struct of_device_id mtk_the
+ {
+ .compatible = "mediatek,mt8183-thermal",
+ .data = (void *)&mt8183_thermal_data,
++ },
++ {
++ .compatible = "mediatek,mt8365-thermal",
++ .data = (void *)&mt8365_thermal_data,
+ }, {
+ },
+ };
--- /dev/null
+From 4eead70db74922bc61e9d0b4591524369a335751 Mon Sep 17 00:00:00 2001
+From: Amjad Ouled-Ameur <aouledameur@baylibre.com>
+Date: Fri, 27 Jan 2023 16:44:46 +0100
+Subject: [PATCH 13/42] thermal/drivers/mediatek: Add delay after thermal banks
+ initialization
+
+Thermal sensor reads performed immediately after thermal bank
+initialization returns bogus values. This is currently tackled by returning
+0 if the temperature is bogus (exceeding 200000).
+
+Instead, add a delay between the bank init and the thermal zone device
+register to properly fix this.
+
+Signed-off-by: Michael Kao <michael.kao@mediatek.com>
+Signed-off-by: Hsin-Yi Wang <hsinyi@chromium.org>
+Signed-off-by: Amjad Ouled-Ameur <aouledameur@baylibre.com>
+Reviewed-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
+Link: https://lore.kernel.org/r/20221018-up-i350-thermal-bringup-v9-5-55a1ae14af74@baylibre.com
+Signed-off-by: Daniel Lezcano <daniel.lezcano@linaro.org>
+---
+ drivers/thermal/mediatek/auxadc_thermal.c | 11 +++--------
+ 1 file changed, 3 insertions(+), 8 deletions(-)
+
+--- a/drivers/thermal/mediatek/auxadc_thermal.c
++++ b/drivers/thermal/mediatek/auxadc_thermal.c
+@@ -816,14 +816,6 @@ static int mtk_thermal_bank_temperature(
+ mt, conf->bank_data[bank->id].sensors[i], raw);
+
+
+- /*
+- * The first read of a sensor often contains very high bogus
+- * temperature value. Filter these out so that the system does
+- * not immediately shut down.
+- */
+- if (temp > 200000)
+- temp = 0;
+-
+ if (temp > max)
+ max = temp;
+ }
+@@ -1281,6 +1273,9 @@ static int mtk_thermal_probe(struct plat
+
+ platform_set_drvdata(pdev, mt);
+
++ /* Delay for thermal banks to be ready */
++ msleep(30);
++
+ tzdev = devm_thermal_of_zone_register(&pdev->dev, 0, mt,
+ &mtk_thermal_ops);
+ if (IS_ERR(tzdev)) {
--- /dev/null
+From ad9dc9e92367803a4f9576aea0dab110d03fc510 Mon Sep 17 00:00:00 2001
+From: Chen-Yu Tsai <wenst@chromium.org>
+Date: Tue, 28 Mar 2023 11:10:17 +0800
+Subject: [PATCH 14/42] thermal/drivers/mediatek/lvts_thermal: Fix sensor 1
+ interrupt status bitmask
+
+The binary representation for sensor 1 interrupt status was incorrectly
+assembled, when compared to the full table given in the same comment
+section. The conversion into hex was also incorrect, leading to
+incorrect interrupt status bitmask for sensor 1. This would cause the
+driver to incorrectly identify changes for sensor 1, when in fact it
+was sensor 0, or a sensor access time out.
+
+Fix the binary and hex representations in the comments, and the actual
+bitmask macro.
+
+Fixes: f5f633b18234 ("thermal/drivers/mediatek: Add the Low Voltage Thermal Sensor driver")
+Signed-off-by: Chen-Yu Tsai <wenst@chromium.org>
+Signed-off-by: Daniel Lezcano <daniel.lezcano@linaro.org>
+Link: https://lore.kernel.org/r/20230328031017.1360976-1-wenst@chromium.org
+---
+ drivers/thermal/mediatek/lvts_thermal.c | 6 +++---
+ 1 file changed, 3 insertions(+), 3 deletions(-)
+
+--- a/drivers/thermal/mediatek/lvts_thermal.c
++++ b/drivers/thermal/mediatek/lvts_thermal.c
+@@ -66,7 +66,7 @@
+ #define LVTS_MONINT_CONF 0x9FBF7BDE
+
+ #define LVTS_INT_SENSOR0 0x0009001F
+-#define LVTS_INT_SENSOR1 0X000881F0
++#define LVTS_INT_SENSOR1 0x001203E0
+ #define LVTS_INT_SENSOR2 0x00247C00
+ #define LVTS_INT_SENSOR3 0x1FC00000
+
+@@ -395,8 +395,8 @@ static irqreturn_t lvts_ctrl_irq_handler
+ * => 0x1FC00000
+ * sensor 2 interrupt: 0000 0000 0010 0100 0111 1100 0000 0000
+ * => 0x00247C00
+- * sensor 1 interrupt: 0000 0000 0001 0001 0000 0011 1110 0000
+- * => 0X000881F0
++ * sensor 1 interrupt: 0000 0000 0001 0010 0000 0011 1110 0000
++ * => 0X001203E0
+ * sensor 0 interrupt: 0000 0000 0000 1001 0000 0000 0001 1111
+ * => 0x0009001F
+ */
--- /dev/null
+From 9aad43ad3285fc21158fb416830a6156a9a31fa5 Mon Sep 17 00:00:00 2001
+From: Balsam CHIHI <bchihi@baylibre.com>
+Date: Tue, 7 Mar 2023 16:45:22 +0100
+Subject: [PATCH 15/42] thermal/drivers/mediatek/lvts_thermal: Add AP domain
+ for mt8195
+
+Add MT8195 AP Domain support to LVTS Driver.
+
+Take the opportunity to update the comments to show calibration data
+information related to the new domain.
+
+[dlezcano]: Massaged a bit the changelog
+
+Signed-off-by: Balsam CHIHI <bchihi@baylibre.com>
+Tested-by: Chen-Yu Tsai <wenst@chromium.org>
+Signed-off-by: Daniel Lezcano <daniel.lezcano@linaro.org>
+Link: https://lore.kernel.org/r/20230307154524.118541-3-bchihi@baylibre.com
+---
+ drivers/thermal/mediatek/lvts_thermal.c | 94 +++++++++++++++++++------
+ 1 file changed, 74 insertions(+), 20 deletions(-)
+
+--- a/drivers/thermal/mediatek/lvts_thermal.c
++++ b/drivers/thermal/mediatek/lvts_thermal.c
+@@ -530,29 +530,33 @@ static int lvts_sensor_init(struct devic
+ * The efuse blob values follows the sensor enumeration per thermal
+ * controller. The decoding of the stream is as follow:
+ *
+- * <--?-> <----big0 ???---> <-sensor0-> <-0->
+- * ------------------------------------------
+- * index in the stream: : | 0x0 | 0x1 | 0x2 | 0x3 | 0x4 | 0x5 | 0x6 |
+- * ------------------------------------------
++ * stream index map for MCU Domain :
+ *
+- * <--sensor1--><-0-> <----big1 ???---> <-sen
+- * ------------------------------------------
+- * | 0x7 | 0x8 | 0x9 | 0xA | 0xB | OxC | OxD |
+- * ------------------------------------------
++ * <-----mcu-tc#0-----> <-----sensor#0-----> <-----sensor#1----->
++ * 0x01 | 0x02 | 0x03 | 0x04 | 0x05 | 0x06 | 0x07 | 0x08 | 0x09
+ *
+- * sor0-> <-0-> <-sensor1-> <-0-> ..........
+- * ------------------------------------------
+- * | 0x7 | 0x8 | 0x9 | 0xA | 0xB | OxC | OxD |
+- * ------------------------------------------
++ * <-----mcu-tc#1-----> <-----sensor#2-----> <-----sensor#3----->
++ * 0x0A | 0x0B | 0x0C | 0x0D | 0x0E | 0x0F | 0x10 | 0x11 | 0x12
+ *
+- * And so on ...
++ * <-----mcu-tc#2-----> <-----sensor#4-----> <-----sensor#5-----> <-----sensor#6-----> <-----sensor#7----->
++ * 0x13 | 0x14 | 0x15 | 0x16 | 0x17 | 0x18 | 0x19 | 0x1A | 0x1B | 0x1C | 0x1D | 0x1E | 0x1F | 0x20 | 0x21
++ *
++ * stream index map for AP Domain :
++ *
++ * <-----ap--tc#0-----> <-----sensor#0-----> <-----sensor#1----->
++ * 0x22 | 0x23 | 0x24 | 0x25 | 0x26 | 0x27 | 0x28 | 0x29 | 0x2A
++ *
++ * <-----ap--tc#1-----> <-----sensor#2-----> <-----sensor#3----->
++ * 0x2B | 0x2C | 0x2D | 0x2E | 0x2F | 0x30 | 0x31 | 0x32 | 0x33
++ *
++ * <-----ap--tc#2-----> <-----sensor#4-----> <-----sensor#5-----> <-----sensor#6----->
++ * 0x34 | 0x35 | 0x36 | 0x37 | 0x38 | 0x39 | 0x3A | 0x3B | 0x3C | 0x3D | 0x3E | 0x3F
++ *
++ * <-----ap--tc#3-----> <-----sensor#7-----> <-----sensor#8----->
++ * 0x40 | 0x41 | 0x42 | 0x43 | 0x44 | 0x45 | 0x46 | 0x47 | 0x48
+ *
+ * The data description gives the offset of the calibration data in
+ * this bytes stream for each sensor.
+- *
+- * Each thermal controller can handle up to 4 sensors max, we don't
+- * care if there are less as the array of calibration is sized to 4
+- * anyway. The unused sensor slot will be zeroed.
+ */
+ static int lvts_calibration_init(struct device *dev, struct lvts_ctrl *lvts_ctrl,
+ const struct lvts_ctrl_data *lvts_ctrl_data,
+@@ -1165,7 +1169,7 @@ static int lvts_remove(struct platform_d
+ return 0;
+ }
+
+-static const struct lvts_ctrl_data mt8195_lvts_data_ctrl[] = {
++static const struct lvts_ctrl_data mt8195_lvts_mcu_data_ctrl[] = {
+ {
+ .cal_offset = { 0x04, 0x07 },
+ .lvts_sensor = {
+@@ -1200,13 +1204,63 @@ static const struct lvts_ctrl_data mt819
+ }
+ };
+
++static const struct lvts_ctrl_data mt8195_lvts_ap_data_ctrl[] = {
++ {
++ .cal_offset = { 0x25, 0x28 },
++ .lvts_sensor = {
++ { .dt_id = MT8195_AP_VPU0 },
++ { .dt_id = MT8195_AP_VPU1 }
++ },
++ .num_lvts_sensor = 2,
++ .offset = 0x0,
++ .hw_tshut_temp = LVTS_HW_SHUTDOWN_MT8195,
++ },
++ {
++ .cal_offset = { 0x2e, 0x31 },
++ .lvts_sensor = {
++ { .dt_id = MT8195_AP_GPU0 },
++ { .dt_id = MT8195_AP_GPU1 }
++ },
++ .num_lvts_sensor = 2,
++ .offset = 0x100,
++ .hw_tshut_temp = LVTS_HW_SHUTDOWN_MT8195,
++ },
++ {
++ .cal_offset = { 0x37, 0x3a, 0x3d },
++ .lvts_sensor = {
++ { .dt_id = MT8195_AP_VDEC },
++ { .dt_id = MT8195_AP_IMG },
++ { .dt_id = MT8195_AP_INFRA },
++ },
++ .num_lvts_sensor = 3,
++ .offset = 0x200,
++ .hw_tshut_temp = LVTS_HW_SHUTDOWN_MT8195,
++ },
++ {
++ .cal_offset = { 0x43, 0x46 },
++ .lvts_sensor = {
++ { .dt_id = MT8195_AP_CAM0 },
++ { .dt_id = MT8195_AP_CAM1 }
++ },
++ .num_lvts_sensor = 2,
++ .offset = 0x300,
++ .hw_tshut_temp = LVTS_HW_SHUTDOWN_MT8195,
++ }
++};
++
+ static const struct lvts_data mt8195_lvts_mcu_data = {
+- .lvts_ctrl = mt8195_lvts_data_ctrl,
+- .num_lvts_ctrl = ARRAY_SIZE(mt8195_lvts_data_ctrl),
++ .lvts_ctrl = mt8195_lvts_mcu_data_ctrl,
++ .num_lvts_ctrl = ARRAY_SIZE(mt8195_lvts_mcu_data_ctrl),
++};
++
++static const struct lvts_data mt8195_lvts_ap_data = {
++ .lvts_ctrl = mt8195_lvts_ap_data_ctrl,
++ .num_lvts_ctrl = ARRAY_SIZE(mt8195_lvts_ap_data_ctrl),
+ };
+
+ static const struct of_device_id lvts_of_match[] = {
+ { .compatible = "mediatek,mt8195-lvts-mcu", .data = &mt8195_lvts_mcu_data },
++ { .compatible = "mediatek,mt8195-lvts-ap", .data = &mt8195_lvts_ap_data },
+ {},
+ };
+ MODULE_DEVICE_TABLE(of, lvts_of_match);
--- /dev/null
+From 7105a86760bd9e4d107075cefc75016b693a5542 Mon Sep 17 00:00:00 2001
+From: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
+Date: Wed, 19 Apr 2023 08:11:45 +0200
+Subject: [PATCH 16/42] Revert "thermal/drivers/mediatek: Add delay after
+ thermal banks initialization"
+
+Some more testing revealed that this commit introduces a regression on some
+MT8173 Chromebooks and at least on one MT6795 Sony Xperia M5 smartphone due
+to the delay being apparently variable and machine specific.
+
+Another solution would be to delay for a bit more (~70ms) but this is not
+feasible for two reasons: first of all, we're adding an even bigger delay
+in a probe function; second, some machines need less, some may need even
+more, making the msleep at probe solution highly suboptimal.
+
+This reverts commit 10debf8c2da8011c8009dd4b3f6d0ab85891c81b.
+
+Fixes: 10debf8c2da8 ("thermal/drivers/mediatek: Add delay after thermal banks initialization")
+Reported-by: "kernelci.org bot" <bot@kernelci.org>
+Signed-off-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
+Signed-off-by: Daniel Lezcano <daniel.lezcano@linaro.org>
+Link: https://lore.kernel.org/r/20230419061146.22246-2-angelogioacchino.delregno@collabora.com
+---
+ drivers/thermal/mediatek/auxadc_thermal.c | 11 ++++++++---
+ 1 file changed, 8 insertions(+), 3 deletions(-)
+
+--- a/drivers/thermal/mediatek/auxadc_thermal.c
++++ b/drivers/thermal/mediatek/auxadc_thermal.c
+@@ -816,6 +816,14 @@ static int mtk_thermal_bank_temperature(
+ mt, conf->bank_data[bank->id].sensors[i], raw);
+
+
++ /*
++ * The first read of a sensor often contains very high bogus
++ * temperature value. Filter these out so that the system does
++ * not immediately shut down.
++ */
++ if (temp > 200000)
++ temp = 0;
++
+ if (temp > max)
+ max = temp;
+ }
+@@ -1273,9 +1281,6 @@ static int mtk_thermal_probe(struct plat
+
+ platform_set_drvdata(pdev, mt);
+
+- /* Delay for thermal banks to be ready */
+- msleep(30);
+-
+ tzdev = devm_thermal_of_zone_register(&pdev->dev, 0, mt,
+ &mtk_thermal_ops);
+ if (IS_ERR(tzdev)) {
--- /dev/null
+From 681b652c9dfc4037d4a55b2733e091a4e1a5de18 Mon Sep 17 00:00:00 2001
+From: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
+Date: Wed, 19 Apr 2023 08:11:46 +0200
+Subject: [PATCH 17/42] thermal/drivers/mediatek: Add temperature constraints
+ to validate read
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+The AUXADC thermal v1 allows reading temperature range between -20°C to
+150°C and any value out of this range is invalid.
+
+Add new definitions for MT8173_TEMP_{MIN_MAX} and a new small helper
+mtk_thermal_temp_is_valid() to check if new readings are in range: if
+not, we tell to the API that the reading is invalid by returning
+THERMAL_TEMP_INVALID.
+
+It was chosen to introduce the helper function because, even though this
+temperature range is realistically ok for all, it comes from a downstream
+kernel driver for version 1, but here we also support v2 and v3 which may
+may have wider constraints.
+
+Signed-off-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
+Signed-off-by: Daniel Lezcano <daniel.lezcano@linaro.org>
+Link: https://lore.kernel.org/r/20230419061146.22246-3-angelogioacchino.delregno@collabora.com
+---
+ drivers/thermal/mediatek/auxadc_thermal.c | 24 +++++++++++++++++------
+ 1 file changed, 18 insertions(+), 6 deletions(-)
+
+--- a/drivers/thermal/mediatek/auxadc_thermal.c
++++ b/drivers/thermal/mediatek/auxadc_thermal.c
+@@ -116,6 +116,10 @@
+ /* The calibration coefficient of sensor */
+ #define MT8173_CALIBRATION 165
+
++/* Valid temperatures range */
++#define MT8173_TEMP_MIN -20000
++#define MT8173_TEMP_MAX 150000
++
+ /*
+ * Layout of the fuses providing the calibration data
+ * These macros could be used for MT8183, MT8173, MT2701, and MT2712.
+@@ -689,6 +693,11 @@ static const struct mtk_thermal_data mt7
+ .version = MTK_THERMAL_V3,
+ };
+
++static bool mtk_thermal_temp_is_valid(int temp)
++{
++ return (temp >= MT8173_TEMP_MIN) && (temp <= MT8173_TEMP_MAX);
++}
++
+ /**
+ * raw_to_mcelsius_v1 - convert a raw ADC value to mcelsius
+ * @mt: The thermal controller
+@@ -815,14 +824,17 @@ static int mtk_thermal_bank_temperature(
+ temp = mt->raw_to_mcelsius(
+ mt, conf->bank_data[bank->id].sensors[i], raw);
+
+-
+ /*
+- * The first read of a sensor often contains very high bogus
+- * temperature value. Filter these out so that the system does
+- * not immediately shut down.
++ * Depending on the filt/sen intervals and ADC polling time,
++ * we may need up to 60 milliseconds after initialization: this
++ * will result in the first reading containing an out of range
++ * temperature value.
++ * Validate the reading to both address the aforementioned issue
++ * and to eventually avoid bogus readings during runtime in the
++ * event that the AUXADC gets unstable due to high EMI, etc.
+ */
+- if (temp > 200000)
+- temp = 0;
++ if (!mtk_thermal_temp_is_valid(temp))
++ temp = THERMAL_TEMP_INVALID;
+
+ if (temp > max)
+ max = temp;
--- /dev/null
+From 458fa1d508de3f17e49d974a0158d9aeff273a58 Mon Sep 17 00:00:00 2001
+From: Kang Chen <void0red@hust.edu.cn>
+Date: Wed, 19 Apr 2023 10:07:48 +0800
+Subject: [PATCH 18/42] thermal/drivers/mediatek: Use devm_of_iomap to avoid
+ resource leak in mtk_thermal_probe
+
+Smatch reports:
+1. mtk_thermal_probe() warn: 'apmixed_base' from of_iomap() not released.
+2. mtk_thermal_probe() warn: 'auxadc_base' from of_iomap() not released.
+
+The original code forgets to release iomap resource when handling errors,
+fix it by switch to devm_of_iomap.
+
+Fixes: 89945047b166 ("thermal: mediatek: Add tsensor support for V2 thermal system")
+Signed-off-by: Kang Chen <void0red@hust.edu.cn>
+Reviewed-by: Dongliang Mu <dzm91@hust.edu.cn>
+Reviewed-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
+Signed-off-by: Daniel Lezcano <daniel.lezcano@linaro.org>
+Link: https://lore.kernel.org/r/20230419020749.621257-1-void0red@hust.edu.cn
+---
+ drivers/thermal/mediatek/auxadc_thermal.c | 14 ++++++++++++--
+ 1 file changed, 12 insertions(+), 2 deletions(-)
+
+--- a/drivers/thermal/mediatek/auxadc_thermal.c
++++ b/drivers/thermal/mediatek/auxadc_thermal.c
+@@ -1232,7 +1232,12 @@ static int mtk_thermal_probe(struct plat
+ return -ENODEV;
+ }
+
+- auxadc_base = of_iomap(auxadc, 0);
++ auxadc_base = devm_of_iomap(&pdev->dev, auxadc, 0, NULL);
++ if (IS_ERR(auxadc_base)) {
++ of_node_put(auxadc);
++ return PTR_ERR(auxadc_base);
++ }
++
+ auxadc_phys_base = of_get_phys_base(auxadc);
+
+ of_node_put(auxadc);
+@@ -1248,7 +1253,12 @@ static int mtk_thermal_probe(struct plat
+ return -ENODEV;
+ }
+
+- apmixed_base = of_iomap(apmixedsys, 0);
++ apmixed_base = devm_of_iomap(&pdev->dev, apmixedsys, 0, NULL);
++ if (IS_ERR(apmixed_base)) {
++ of_node_put(apmixedsys);
++ return PTR_ERR(apmixed_base);
++ }
++
+ apmixed_phys_base = of_get_phys_base(apmixedsys);
+
+ of_node_put(apmixedsys);
--- /dev/null
+From 227d1856924ec00a4f5bdf5afcf77bc7f3f04e86 Mon Sep 17 00:00:00 2001
+From: Kang Chen <void0red@hust.edu.cn>
+Date: Wed, 19 Apr 2023 10:07:49 +0800
+Subject: [PATCH 19/42] thermal/drivers/mediatek: Change clk_prepare_enable to
+ devm_clk_get_enabled in mtk_thermal_probe
+
+Use devm_clk_get_enabled to do automatic resource management.
+Meanwhile, remove error handling labels in the probe function and
+the whole remove function.
+
+Signed-off-by: Kang Chen <void0red@hust.edu.cn>
+Reviewed-by: Dongliang Mu <dzm91@hust.edu.cn>
+Signed-off-by: Daniel Lezcano <daniel.lezcano@linaro.org>
+Link: https://lore.kernel.org/r/20230419020749.621257-2-void0red@hust.edu.cn
+---
+ drivers/thermal/mediatek/auxadc_thermal.c | 44 +++++------------------
+ 1 file changed, 9 insertions(+), 35 deletions(-)
+
+--- a/drivers/thermal/mediatek/auxadc_thermal.c
++++ b/drivers/thermal/mediatek/auxadc_thermal.c
+@@ -1206,14 +1206,6 @@ static int mtk_thermal_probe(struct plat
+
+ mt->conf = of_device_get_match_data(&pdev->dev);
+
+- mt->clk_peri_therm = devm_clk_get(&pdev->dev, "therm");
+- if (IS_ERR(mt->clk_peri_therm))
+- return PTR_ERR(mt->clk_peri_therm);
+-
+- mt->clk_auxadc = devm_clk_get(&pdev->dev, "auxadc");
+- if (IS_ERR(mt->clk_auxadc))
+- return PTR_ERR(mt->clk_auxadc);
+-
+ mt->thermal_base = devm_platform_get_and_ioremap_resource(pdev, 0, NULL);
+ if (IS_ERR(mt->thermal_base))
+ return PTR_ERR(mt->thermal_base);
+@@ -1272,16 +1264,18 @@ static int mtk_thermal_probe(struct plat
+ if (ret)
+ return ret;
+
+- ret = clk_prepare_enable(mt->clk_auxadc);
+- if (ret) {
++ mt->clk_auxadc = devm_clk_get_enabled(&pdev->dev, "auxadc");
++ if (IS_ERR(mt->clk_auxadc)) {
++ ret = PTR_ERR(mt->clk_auxadc);
+ dev_err(&pdev->dev, "Can't enable auxadc clk: %d\n", ret);
+ return ret;
+ }
+
+- ret = clk_prepare_enable(mt->clk_peri_therm);
+- if (ret) {
++ mt->clk_peri_therm = devm_clk_get_enabled(&pdev->dev, "therm");
++ if (IS_ERR(mt->clk_peri_therm)) {
++ ret = PTR_ERR(mt->clk_peri_therm);
+ dev_err(&pdev->dev, "Can't enable peri clk: %d\n", ret);
+- goto err_disable_clk_auxadc;
++ return ret;
+ }
+
+ mtk_thermal_turn_on_buffer(mt, apmixed_base);
+@@ -1305,38 +1299,18 @@ static int mtk_thermal_probe(struct plat
+
+ tzdev = devm_thermal_of_zone_register(&pdev->dev, 0, mt,
+ &mtk_thermal_ops);
+- if (IS_ERR(tzdev)) {
+- ret = PTR_ERR(tzdev);
+- goto err_disable_clk_peri_therm;
+- }
++ if (IS_ERR(tzdev))
++ return PTR_ERR(tzdev);
+
+ ret = devm_thermal_add_hwmon_sysfs(&pdev->dev, tzdev);
+ if (ret)
+ dev_warn(&pdev->dev, "error in thermal_add_hwmon_sysfs");
+
+ return 0;
+-
+-err_disable_clk_peri_therm:
+- clk_disable_unprepare(mt->clk_peri_therm);
+-err_disable_clk_auxadc:
+- clk_disable_unprepare(mt->clk_auxadc);
+-
+- return ret;
+-}
+-
+-static int mtk_thermal_remove(struct platform_device *pdev)
+-{
+- struct mtk_thermal *mt = platform_get_drvdata(pdev);
+-
+- clk_disable_unprepare(mt->clk_peri_therm);
+- clk_disable_unprepare(mt->clk_auxadc);
+-
+- return 0;
+ }
+
+ static struct platform_driver mtk_thermal_driver = {
+ .probe = mtk_thermal_probe,
+- .remove = mtk_thermal_remove,
+ .driver = {
+ .name = "mtk-thermal",
+ .of_match_table = mtk_thermal_of_match,
--- /dev/null
+From 655fe2533ac05323a07c19ba079bf2064e7741af Mon Sep 17 00:00:00 2001
+From: Rob Herring <robh@kernel.org>
+Date: Sun, 19 Mar 2023 11:32:31 -0500
+Subject: [PATCH 20/42] thermal/drivers/mediatek: Use of_address_to_resource()
+
+Replace of_get_address() and of_translate_address() calls with single
+call to of_address_to_resource().
+
+Signed-off-by: Rob Herring <robh@kernel.org>
+Reviewed-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
+Signed-off-by: Daniel Lezcano <daniel.lezcano@linaro.org>
+Link: https://lore.kernel.org/r/20230319163231.226738-1-robh@kernel.org
+---
+ drivers/thermal/mediatek/auxadc_thermal.c | 8 +++-----
+ 1 file changed, 3 insertions(+), 5 deletions(-)
+
+--- a/drivers/thermal/mediatek/auxadc_thermal.c
++++ b/drivers/thermal/mediatek/auxadc_thermal.c
+@@ -979,14 +979,12 @@ static void mtk_thermal_init_bank(struct
+
+ static u64 of_get_phys_base(struct device_node *np)
+ {
+- u64 size64;
+- const __be32 *regaddr_p;
++ struct resource res;
+
+- regaddr_p = of_get_address(np, 0, &size64, NULL);
+- if (!regaddr_p)
++ if (of_address_to_resource(np, 0, &res))
+ return OF_BAD_ADDR;
+
+- return of_translate_address(np, regaddr_p);
++ return res.start;
+ }
+
+ static int mtk_thermal_extract_efuse_v1(struct mtk_thermal *mt, u32 *buf)
--- /dev/null
+From 2c380d07215e6fce3ac66cc5af059bc2c2a69f7a Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Ricardo=20Ca=C3=B1uelo?= <ricardo.canuelo@collabora.com>
+Date: Thu, 25 May 2023 14:18:11 +0200
+Subject: [PATCH 21/42] Revert "thermal/drivers/mediatek: Use devm_of_iomap to
+ avoid resource leak in mtk_thermal_probe"
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+This reverts commit f05c7b7d9ea9477fcc388476c6f4ade8c66d2d26.
+
+That change was causing a regression in the generic-adc-thermal-probed
+bootrr test as reported in the kernelci-results list [1].
+A proper rework will take longer, so revert it for now.
+
+[1] https://groups.io/g/kernelci-results/message/42660
+
+Fixes: f05c7b7d9ea9 ("thermal/drivers/mediatek: Use devm_of_iomap to avoid resource leak in mtk_thermal_probe")
+Signed-off-by: Ricardo Cañuelo <ricardo.canuelo@collabora.com>
+Suggested-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
+Reviewed-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
+Signed-off-by: Daniel Lezcano <daniel.lezcano@linaro.org>
+Link: https://lore.kernel.org/r/20230525121811.3360268-1-ricardo.canuelo@collabora.com
+---
+ drivers/thermal/mediatek/auxadc_thermal.c | 14 ++------------
+ 1 file changed, 2 insertions(+), 12 deletions(-)
+
+--- a/drivers/thermal/mediatek/auxadc_thermal.c
++++ b/drivers/thermal/mediatek/auxadc_thermal.c
+@@ -1222,12 +1222,7 @@ static int mtk_thermal_probe(struct plat
+ return -ENODEV;
+ }
+
+- auxadc_base = devm_of_iomap(&pdev->dev, auxadc, 0, NULL);
+- if (IS_ERR(auxadc_base)) {
+- of_node_put(auxadc);
+- return PTR_ERR(auxadc_base);
+- }
+-
++ auxadc_base = of_iomap(auxadc, 0);
+ auxadc_phys_base = of_get_phys_base(auxadc);
+
+ of_node_put(auxadc);
+@@ -1243,12 +1238,7 @@ static int mtk_thermal_probe(struct plat
+ return -ENODEV;
+ }
+
+- apmixed_base = devm_of_iomap(&pdev->dev, apmixedsys, 0, NULL);
+- if (IS_ERR(apmixed_base)) {
+- of_node_put(apmixedsys);
+- return PTR_ERR(apmixed_base);
+- }
+-
++ apmixed_base = of_iomap(apmixedsys, 0);
+ apmixed_phys_base = of_get_phys_base(apmixedsys);
+
+ of_node_put(apmixedsys);
--- /dev/null
+From 496f4b08981d8a788ad5a2073fa1c65a2af1862b Mon Sep 17 00:00:00 2001
+From: Chen-Yu Tsai <wenst@chromium.org>
+Date: Tue, 13 Jun 2023 17:13:16 +0800
+Subject: [PATCH 22/42] thermal/drivers/mediatek/lvts_thermal: Register thermal
+ zones as hwmon sensors
+
+Register thermal zones as hwmon sensors to let userspace read
+temperatures using standard hwmon interface.
+
+Signed-off-by: Chen-Yu Tsai <wenst@chromium.org>
+Signed-off-by: Daniel Lezcano <daniel.lezcano@linaro.org>
+Link: https://lore.kernel.org/r/20230613091317.1691247-1-wenst@chromium.org
+---
+ drivers/thermal/mediatek/lvts_thermal.c | 5 +++++
+ 1 file changed, 5 insertions(+)
+
+--- a/drivers/thermal/mediatek/lvts_thermal.c
++++ b/drivers/thermal/mediatek/lvts_thermal.c
+@@ -19,6 +19,8 @@
+ #include <linux/thermal.h>
+ #include <dt-bindings/thermal/mediatek,lvts-thermal.h>
+
++#include "../thermal_hwmon.h"
++
+ #define LVTS_MONCTL0(__base) (__base + 0x0000)
+ #define LVTS_MONCTL1(__base) (__base + 0x0004)
+ #define LVTS_MONCTL2(__base) (__base + 0x0008)
+@@ -996,6 +998,9 @@ static int lvts_ctrl_start(struct device
+ return PTR_ERR(tz);
+ }
+
++ if (devm_thermal_add_hwmon_sysfs(dev, tz))
++ dev_warn(dev, "zone %d: Failed to add hwmon sysfs attributes\n", dt_id);
++
+ /*
+ * The thermal zone pointer will be needed in the
+ * interrupt handler, we store it in the sensor
--- /dev/null
+From 885b9768ce2a66ed5d250822aed53d5114c895da Mon Sep 17 00:00:00 2001
+From: Yangtao Li <frank.li@vivo.com>
+Date: Tue, 20 Jun 2023 17:07:31 +0800
+Subject: [PATCH 23/42] thermal/drivers/mediatek/lvts_thermal: Remove redundant
+ msg in lvts_ctrl_start()
+
+The upper-layer devm_thermal_add_hwmon_sysfs() function can directly
+print error information.
+
+Signed-off-by: Yangtao Li <frank.li@vivo.com>
+Signed-off-by: Daniel Lezcano <daniel.lezcano@linaro.org>
+Link: https://lore.kernel.org/r/20230620090732.50025-10-frank.li@vivo.com
+---
+ drivers/thermal/mediatek/lvts_thermal.c | 3 +--
+ 1 file changed, 1 insertion(+), 2 deletions(-)
+
+--- a/drivers/thermal/mediatek/lvts_thermal.c
++++ b/drivers/thermal/mediatek/lvts_thermal.c
+@@ -998,8 +998,7 @@ static int lvts_ctrl_start(struct device
+ return PTR_ERR(tz);
+ }
+
+- if (devm_thermal_add_hwmon_sysfs(dev, tz))
+- dev_warn(dev, "zone %d: Failed to add hwmon sysfs attributes\n", dt_id);
++ devm_thermal_add_hwmon_sysfs(dev, tz);
+
+ /*
+ * The thermal zone pointer will be needed in the
--- /dev/null
+From 27b389d9f62c2174f95fe4002b11e77d4cb3ce80 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?N=C3=ADcolas=20F=2E=20R=2E=20A=2E=20Prado?=
+ <nfraprado@collabora.com>
+Date: Thu, 6 Jul 2023 11:37:32 -0400
+Subject: [PATCH 25/42] thermal/drivers/mediatek/lvts_thermal: Handle IRQ on
+ all controllers
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+There is a single IRQ handler for each LVTS thermal domain, and it is
+supposed to check each of its underlying controllers for the origin of
+the interrupt and clear its status. However due to a typo, only the
+first controller was ever being handled, which resulted in the interrupt
+never being cleared when it happened on the other controllers. Add the
+missing index so interrupts are handled for all controllers.
+
+Fixes: f5f633b18234 ("thermal/drivers/mediatek: Add the Low Voltage Thermal Sensor driver")
+Reviewed-by: Matthias Brugger <matthias.bgg@gmail.com>
+Reviewed-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
+Tested-by: Chen-Yu Tsai <wenst@chromium.org>
+Signed-off-by: NÃcolas F. R. A. Prado <nfraprado@collabora.com>
+Reviewed-by: Alexandre Mergnat <amergnat@baylibre.com>
+Signed-off-by: Daniel Lezcano <daniel.lezcano@linaro.org>
+Link: https://lore.kernel.org/r/20230706153823.201943-2-nfraprado@collabora.com
+---
+ drivers/thermal/mediatek/lvts_thermal.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/drivers/thermal/mediatek/lvts_thermal.c
++++ b/drivers/thermal/mediatek/lvts_thermal.c
+@@ -451,7 +451,7 @@ static irqreturn_t lvts_irq_handler(int
+
+ for (i = 0; i < lvts_td->num_lvts_ctrl; i++) {
+
+- aux = lvts_ctrl_irq_handler(lvts_td->lvts_ctrl);
++ aux = lvts_ctrl_irq_handler(&lvts_td->lvts_ctrl[i]);
+ if (aux != IRQ_HANDLED)
+ continue;
+
--- /dev/null
+From 6d827142643ee10c13ff9a1d90f38fb399aa9fff Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?N=C3=ADcolas=20F=2E=20R=2E=20A=2E=20Prado?=
+ <nfraprado@collabora.com>
+Date: Thu, 6 Jul 2023 11:37:33 -0400
+Subject: [PATCH 26/42] thermal/drivers/mediatek/lvts_thermal: Honor sensors in
+ immediate mode
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Each controller can be configured to operate on immediate or filtered
+mode. On filtered mode, the sensors are enabled by setting the
+corresponding bits in MONCTL0, while on immediate mode, by setting
+MSRCTL1.
+
+Previously, the code would set MSRCTL1 for all four sensors when
+configured to immediate mode, but given that the controller might not
+have all four sensors connected, this would cause interrupts to trigger
+for non-existent sensors. Fix this by handling the MSRCTL1 register
+analogously to the MONCTL0: only enable the sensors that were declared.
+
+Fixes: f5f633b18234 ("thermal/drivers/mediatek: Add the Low Voltage Thermal Sensor driver")
+Reviewed-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
+Tested-by: Chen-Yu Tsai <wenst@chromium.org>
+Signed-off-by: NÃcolas F. R. A. Prado <nfraprado@collabora.com>
+Reviewed-by: Alexandre Mergnat <amergnat@baylibre.com>
+Signed-off-by: Daniel Lezcano <daniel.lezcano@linaro.org>
+Link: https://lore.kernel.org/r/20230706153823.201943-3-nfraprado@collabora.com
+---
+ drivers/thermal/mediatek/lvts_thermal.c | 57 ++++++++++++++-----------
+ 1 file changed, 33 insertions(+), 24 deletions(-)
+
+--- a/drivers/thermal/mediatek/lvts_thermal.c
++++ b/drivers/thermal/mediatek/lvts_thermal.c
+@@ -897,24 +897,6 @@ static int lvts_ctrl_configure(struct de
+ writel(value, LVTS_MSRCTL0(lvts_ctrl->base));
+
+ /*
+- * LVTS_MSRCTL1 : Measurement control
+- *
+- * Bits:
+- *
+- * 9: Ignore MSRCTL0 config and do immediate measurement on sensor3
+- * 6: Ignore MSRCTL0 config and do immediate measurement on sensor2
+- * 5: Ignore MSRCTL0 config and do immediate measurement on sensor1
+- * 4: Ignore MSRCTL0 config and do immediate measurement on sensor0
+- *
+- * That configuration will ignore the filtering and the delays
+- * introduced below in MONCTL1 and MONCTL2
+- */
+- if (lvts_ctrl->mode == LVTS_MSR_IMMEDIATE_MODE) {
+- value = BIT(9) | BIT(6) | BIT(5) | BIT(4);
+- writel(value, LVTS_MSRCTL1(lvts_ctrl->base));
+- }
+-
+- /*
+ * LVTS_MONCTL1 : Period unit and group interval configuration
+ *
+ * The clock source of LVTS thermal controller is 26MHz.
+@@ -979,6 +961,15 @@ static int lvts_ctrl_start(struct device
+ struct thermal_zone_device *tz;
+ u32 sensor_map = 0;
+ int i;
++ /*
++ * Bitmaps to enable each sensor on immediate and filtered modes, as
++ * described in MSRCTL1 and MONCTL0 registers below, respectively.
++ */
++ u32 sensor_imm_bitmap[] = { BIT(4), BIT(5), BIT(6), BIT(9) };
++ u32 sensor_filt_bitmap[] = { BIT(0), BIT(1), BIT(2), BIT(3) };
++
++ u32 *sensor_bitmap = lvts_ctrl->mode == LVTS_MSR_IMMEDIATE_MODE ?
++ sensor_imm_bitmap : sensor_filt_bitmap;
+
+ for (i = 0; i < lvts_ctrl->num_lvts_sensor; i++) {
+
+@@ -1016,20 +1007,38 @@ static int lvts_ctrl_start(struct device
+ * map, so we can enable the temperature monitoring in
+ * the hardware thermal controller.
+ */
+- sensor_map |= BIT(i);
++ sensor_map |= sensor_bitmap[i];
+ }
+
+ /*
+- * Bits:
+- * 9: Single point access flow
+- * 0-3: Enable sensing point 0-3
+- *
+ * The initialization of the thermal zones give us
+ * which sensor point to enable. If any thermal zone
+ * was not described in the device tree, it won't be
+ * enabled here in the sensor map.
+ */
+- writel(sensor_map | BIT(9), LVTS_MONCTL0(lvts_ctrl->base));
++ if (lvts_ctrl->mode == LVTS_MSR_IMMEDIATE_MODE) {
++ /*
++ * LVTS_MSRCTL1 : Measurement control
++ *
++ * Bits:
++ *
++ * 9: Ignore MSRCTL0 config and do immediate measurement on sensor3
++ * 6: Ignore MSRCTL0 config and do immediate measurement on sensor2
++ * 5: Ignore MSRCTL0 config and do immediate measurement on sensor1
++ * 4: Ignore MSRCTL0 config and do immediate measurement on sensor0
++ *
++ * That configuration will ignore the filtering and the delays
++ * introduced in MONCTL1 and MONCTL2
++ */
++ writel(sensor_map, LVTS_MSRCTL1(lvts_ctrl->base));
++ } else {
++ /*
++ * Bits:
++ * 9: Single point access flow
++ * 0-3: Enable sensing point 0-3
++ */
++ writel(sensor_map | BIT(9), LVTS_MONCTL0(lvts_ctrl->base));
++ }
+
+ return 0;
+ }
--- /dev/null
+From 93bb11dd19bdcc1fc97c7ceababd0db9fde128ad Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?N=C3=ADcolas=20F=2E=20R=2E=20A=2E=20Prado?=
+ <nfraprado@collabora.com>
+Date: Thu, 6 Jul 2023 11:37:34 -0400
+Subject: [PATCH 27/42] thermal/drivers/mediatek/lvts_thermal: Use offset
+ threshold for IRQ
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+There are two kinds of temperature monitoring interrupts available:
+* High Offset, Low Offset
+* Hot, Hot to normal, Cold
+
+The code currently uses the hot/h2n/cold interrupts, however in a way
+that doesn't work: the cold threshold is left uninitialized, which
+prevents the other thresholds from ever triggering, and the h2n
+interrupt is used as the lower threshold, which prevents the hot
+interrupt from triggering again after the thresholds are updated by the
+thermal framework, since a hot interrupt can only trigger again after
+the hot to normal interrupt has been triggered.
+
+But better yet than addressing those issues, is to use the high/low
+offset interrupts instead. This way only two thresholds need to be
+managed, which have a simpler state machine, making them a better match
+to the thermal framework's high and low thresholds.
+
+Fixes: f5f633b18234 ("thermal/drivers/mediatek: Add the Low Voltage Thermal Sensor driver")
+Signed-off-by: NÃcolas F. R. A. Prado <nfraprado@collabora.com>
+Reviewed-by: Alexandre Mergnat <amergnat@baylibre.com>
+Reviewed-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
+Signed-off-by: Daniel Lezcano <daniel.lezcano@linaro.org>
+Link: https://lore.kernel.org/r/20230706153823.201943-4-nfraprado@collabora.com
+---
+ drivers/thermal/mediatek/lvts_thermal.c | 12 ++++++------
+ 1 file changed, 6 insertions(+), 6 deletions(-)
+
+--- a/drivers/thermal/mediatek/lvts_thermal.c
++++ b/drivers/thermal/mediatek/lvts_thermal.c
+@@ -298,9 +298,9 @@ static int lvts_set_trips(struct thermal
+ u32 raw_high = lvts_temp_to_raw(high);
+
+ /*
+- * Hot to normal temperature threshold
++ * Low offset temperature threshold
+ *
+- * LVTS_H2NTHRE
++ * LVTS_OFFSETL
+ *
+ * Bits:
+ *
+@@ -309,13 +309,13 @@ static int lvts_set_trips(struct thermal
+ if (low != -INT_MAX) {
+ pr_debug("%s: Setting low limit temperature interrupt: %d\n",
+ thermal_zone_device_type(tz), low);
+- writel(raw_low, LVTS_H2NTHRE(base));
++ writel(raw_low, LVTS_OFFSETL(base));
+ }
+
+ /*
+- * Hot temperature threshold
++ * High offset temperature threshold
+ *
+- * LVTS_HTHRE
++ * LVTS_OFFSETH
+ *
+ * Bits:
+ *
+@@ -323,7 +323,7 @@ static int lvts_set_trips(struct thermal
+ */
+ pr_debug("%s: Setting high limit temperature interrupt: %d\n",
+ thermal_zone_device_type(tz), high);
+- writel(raw_high, LVTS_HTHRE(base));
++ writel(raw_high, LVTS_OFFSETH(base));
+
+ return 0;
+ }
--- /dev/null
+From 8f8cab9d3e90acf1db278ef44ad05f10aefb973f Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?N=C3=ADcolas=20F=2E=20R=2E=20A=2E=20Prado?=
+ <nfraprado@collabora.com>
+Date: Thu, 6 Jul 2023 11:37:35 -0400
+Subject: [PATCH 28/42] thermal/drivers/mediatek/lvts_thermal: Disable
+ undesired interrupts
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Out of the many interrupts supported by the hardware, the only ones of
+interest to the driver currently are:
+* The temperature went over the high offset threshold, for any of the
+ sensors
+* The temperature went below the low offset threshold, for any of the
+ sensors
+* The temperature went over the stage3 threshold
+
+These are the only thresholds configured by the driver through the
+OFFSETH, OFFSETL, and PROTTC registers, respectively.
+
+The current interrupt mask in LVTS_MONINT_CONF, enables many more
+interrupts, including data ready on sensors for both filtered and
+immediate mode. These are not only not handled by the driver, but they
+are also triggered too often, causing unneeded overhead. Disable these
+unnecessary interrupts.
+
+The meaning of each bit can be seen in the comment describing
+LVTS_MONINTST in the IRQ handler.
+
+Fixes: f5f633b18234 ("thermal/drivers/mediatek: Add the Low Voltage Thermal Sensor driver")
+Signed-off-by: NÃcolas F. R. A. Prado <nfraprado@collabora.com>
+Reviewed-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
+Reviewed-by: Alexandre Mergnat <amergnat@baylibre.com>
+Signed-off-by: Daniel Lezcano <daniel.lezcano@linaro.org>
+Link: https://lore.kernel.org/r/20230706153823.201943-5-nfraprado@collabora.com
+---
+ drivers/thermal/mediatek/lvts_thermal.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/drivers/thermal/mediatek/lvts_thermal.c
++++ b/drivers/thermal/mediatek/lvts_thermal.c
+@@ -65,7 +65,7 @@
+ #define LVTS_HW_FILTER 0x2
+ #define LVTS_TSSEL_CONF 0x13121110
+ #define LVTS_CALSCALE_CONF 0x300
+-#define LVTS_MONINT_CONF 0x9FBF7BDE
++#define LVTS_MONINT_CONF 0x8300318C
+
+ #define LVTS_INT_SENSOR0 0x0009001F
+ #define LVTS_INT_SENSOR1 0x001203E0
--- /dev/null
+From bd1ccf9408e6155564530af5e09b53ae497fe332 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?N=C3=ADcolas=20F=2E=20R=2E=20A=2E=20Prado?=
+ <nfraprado@collabora.com>
+Date: Thu, 6 Jul 2023 11:37:36 -0400
+Subject: [PATCH 29/42] thermal/drivers/mediatek/lvts_thermal: Don't leave
+ threshold zeroed
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+The thermal framework might leave the low threshold unset if there
+aren't any lower trip points. This leaves the register zeroed, which
+translates to a very high temperature for the low threshold. The
+interrupt for this threshold is then immediately triggered, and the
+state machine gets stuck, preventing any other temperature monitoring
+interrupts to ever trigger.
+
+(The same happens by not setting the Cold or Hot to Normal thresholds
+when using those)
+
+Set the unused threshold to a valid low value. This value was chosen so
+that for any valid golden temperature read from the efuse, when the
+value is converted to raw and back again to milliCelsius, the result
+doesn't underflow.
+
+Fixes: f5f633b18234 ("thermal/drivers/mediatek: Add the Low Voltage Thermal Sensor driver")
+Signed-off-by: NÃcolas F. R. A. Prado <nfraprado@collabora.com>
+Reviewed-by: Alexandre Mergnat <amergnat@baylibre.com>
+Reviewed-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
+Signed-off-by: Daniel Lezcano <daniel.lezcano@linaro.org>
+Link: https://lore.kernel.org/r/20230706153823.201943-6-nfraprado@collabora.com
+---
+ drivers/thermal/mediatek/lvts_thermal.c | 12 ++++++------
+ 1 file changed, 6 insertions(+), 6 deletions(-)
+
+--- a/drivers/thermal/mediatek/lvts_thermal.c
++++ b/drivers/thermal/mediatek/lvts_thermal.c
+@@ -83,6 +83,8 @@
+
+ #define LVTS_HW_SHUTDOWN_MT8195 105000
+
++#define LVTS_MINIMUM_THRESHOLD 20000
++
+ static int golden_temp = LVTS_GOLDEN_TEMP_DEFAULT;
+ static int coeff_b = LVTS_COEFF_B;
+
+@@ -294,7 +296,7 @@ static int lvts_set_trips(struct thermal
+ {
+ struct lvts_sensor *lvts_sensor = thermal_zone_device_priv(tz);
+ void __iomem *base = lvts_sensor->base;
+- u32 raw_low = lvts_temp_to_raw(low);
++ u32 raw_low = lvts_temp_to_raw(low != -INT_MAX ? low : LVTS_MINIMUM_THRESHOLD);
+ u32 raw_high = lvts_temp_to_raw(high);
+
+ /*
+@@ -306,11 +308,9 @@ static int lvts_set_trips(struct thermal
+ *
+ * 14-0 : Raw temperature for threshold
+ */
+- if (low != -INT_MAX) {
+- pr_debug("%s: Setting low limit temperature interrupt: %d\n",
+- thermal_zone_device_type(tz), low);
+- writel(raw_low, LVTS_OFFSETL(base));
+- }
++ pr_debug("%s: Setting low limit temperature interrupt: %d\n",
++ thermal_zone_device_type(tz), low);
++ writel(raw_low, LVTS_OFFSETL(base));
+
+ /*
+ * High offset temperature threshold
--- /dev/null
+From d4dd09968cab3249e6148e1c3fccb51824edb411 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?N=C3=ADcolas=20F=2E=20R=2E=20A=2E=20Prado?=
+ <nfraprado@collabora.com>
+Date: Thu, 6 Jul 2023 11:37:37 -0400
+Subject: [PATCH 30/42] thermal/drivers/mediatek/lvts_thermal: Manage threshold
+ between sensors
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Each LVTS thermal controller can have up to four sensors, each capable
+of triggering its own interrupt when its measured temperature crosses
+the configured threshold. The threshold for each sensor is handled
+separately by the thermal framework, since each one is registered with
+its own thermal zone and trips. However, the temperature thresholds are
+configured on the controller, and therefore are shared between all
+sensors on that controller.
+
+When the temperature measured by the sensors is different enough to
+cause the thermal framework to configure different thresholds for each
+one, interrupts start triggering on sensors outside the last threshold
+configured.
+
+To address the issue, track the thresholds required by each sensor and
+only actually set the highest one in the hardware, and disable
+interrupts for all sensors outside the current configured range.
+
+Fixes: f5f633b18234 ("thermal/drivers/mediatek: Add the Low Voltage Thermal Sensor driver")
+Signed-off-by: NÃcolas F. R. A. Prado <nfraprado@collabora.com>
+Reviewed-by: Alexandre Mergnat <amergnat@baylibre.com>
+Reviewed-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
+Signed-off-by: Daniel Lezcano <daniel.lezcano@linaro.org>
+Link: https://lore.kernel.org/r/20230706153823.201943-7-nfraprado@collabora.com
+---
+ drivers/thermal/mediatek/lvts_thermal.c | 69 +++++++++++++++++++++++++
+ 1 file changed, 69 insertions(+)
+
+--- a/drivers/thermal/mediatek/lvts_thermal.c
++++ b/drivers/thermal/mediatek/lvts_thermal.c
+@@ -67,6 +67,11 @@
+ #define LVTS_CALSCALE_CONF 0x300
+ #define LVTS_MONINT_CONF 0x8300318C
+
++#define LVTS_MONINT_OFFSET_SENSOR0 0xC
++#define LVTS_MONINT_OFFSET_SENSOR1 0x180
++#define LVTS_MONINT_OFFSET_SENSOR2 0x3000
++#define LVTS_MONINT_OFFSET_SENSOR3 0x3000000
++
+ #define LVTS_INT_SENSOR0 0x0009001F
+ #define LVTS_INT_SENSOR1 0x001203E0
+ #define LVTS_INT_SENSOR2 0x00247C00
+@@ -112,6 +117,8 @@ struct lvts_sensor {
+ void __iomem *base;
+ int id;
+ int dt_id;
++ int low_thresh;
++ int high_thresh;
+ };
+
+ struct lvts_ctrl {
+@@ -121,6 +128,8 @@ struct lvts_ctrl {
+ int num_lvts_sensor;
+ int mode;
+ void __iomem *base;
++ int low_thresh;
++ int high_thresh;
+ };
+
+ struct lvts_domain {
+@@ -292,12 +301,66 @@ static int lvts_get_temp(struct thermal_
+ return 0;
+ }
+
++static void lvts_update_irq_mask(struct lvts_ctrl *lvts_ctrl)
++{
++ u32 masks[] = {
++ LVTS_MONINT_OFFSET_SENSOR0,
++ LVTS_MONINT_OFFSET_SENSOR1,
++ LVTS_MONINT_OFFSET_SENSOR2,
++ LVTS_MONINT_OFFSET_SENSOR3,
++ };
++ u32 value = 0;
++ int i;
++
++ value = readl(LVTS_MONINT(lvts_ctrl->base));
++
++ for (i = 0; i < ARRAY_SIZE(masks); i++) {
++ if (lvts_ctrl->sensors[i].high_thresh == lvts_ctrl->high_thresh
++ && lvts_ctrl->sensors[i].low_thresh == lvts_ctrl->low_thresh)
++ value |= masks[i];
++ else
++ value &= ~masks[i];
++ }
++
++ writel(value, LVTS_MONINT(lvts_ctrl->base));
++}
++
++static bool lvts_should_update_thresh(struct lvts_ctrl *lvts_ctrl, int high)
++{
++ int i;
++
++ if (high > lvts_ctrl->high_thresh)
++ return true;
++
++ for (i = 0; i < lvts_ctrl->num_lvts_sensor; i++)
++ if (lvts_ctrl->sensors[i].high_thresh == lvts_ctrl->high_thresh
++ && lvts_ctrl->sensors[i].low_thresh == lvts_ctrl->low_thresh)
++ return false;
++
++ return true;
++}
++
+ static int lvts_set_trips(struct thermal_zone_device *tz, int low, int high)
+ {
+ struct lvts_sensor *lvts_sensor = thermal_zone_device_priv(tz);
++ struct lvts_ctrl *lvts_ctrl = container_of(lvts_sensor, struct lvts_ctrl, sensors[lvts_sensor->id]);
+ void __iomem *base = lvts_sensor->base;
+ u32 raw_low = lvts_temp_to_raw(low != -INT_MAX ? low : LVTS_MINIMUM_THRESHOLD);
+ u32 raw_high = lvts_temp_to_raw(high);
++ bool should_update_thresh;
++
++ lvts_sensor->low_thresh = low;
++ lvts_sensor->high_thresh = high;
++
++ should_update_thresh = lvts_should_update_thresh(lvts_ctrl, high);
++ if (should_update_thresh) {
++ lvts_ctrl->high_thresh = high;
++ lvts_ctrl->low_thresh = low;
++ }
++ lvts_update_irq_mask(lvts_ctrl);
++
++ if (!should_update_thresh)
++ return 0;
+
+ /*
+ * Low offset temperature threshold
+@@ -521,6 +584,9 @@ static int lvts_sensor_init(struct devic
+ */
+ lvts_sensor[i].msr = lvts_ctrl_data->mode == LVTS_MSR_IMMEDIATE_MODE ?
+ imm_regs[i] : msr_regs[i];
++
++ lvts_sensor[i].low_thresh = INT_MIN;
++ lvts_sensor[i].high_thresh = INT_MIN;
+ };
+
+ lvts_ctrl->num_lvts_sensor = lvts_ctrl_data->num_lvts_sensor;
+@@ -688,6 +754,9 @@ static int lvts_ctrl_init(struct device
+ */
+ lvts_ctrl[i].hw_tshut_raw_temp =
+ lvts_temp_to_raw(lvts_data->lvts_ctrl[i].hw_tshut_temp);
++
++ lvts_ctrl[i].low_thresh = INT_MIN;
++ lvts_ctrl[i].high_thresh = INT_MIN;
+ }
+
+ /*
--- /dev/null
+From 5af4904adc8b840987000724977c13c706d3b7d8 Mon Sep 17 00:00:00 2001
+From: Minjie Du <duminjie@vivo.com>
+Date: Thu, 13 Jul 2023 12:24:12 +0800
+Subject: [PATCH 31/42] thermal/drivers/mediatek/lvts: Fix parameter check in
+ lvts_debugfs_init()
+
+The documentation says "If an error occurs, ERR_PTR(-ERROR) will be
+returned" but the current code checks against a NULL pointer returned.
+
+Fix this by checking if IS_ERR().
+
+Signed-off-by: Minjie Du <duminjie@vivo.com>
+Signed-off-by: Daniel Lezcano <daniel.lezcano@linaro.org>
+Link: https://lore.kernel.org/r/20230713042413.2519-1-duminjie@vivo.com
+---
+ drivers/thermal/mediatek/lvts_thermal.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/drivers/thermal/mediatek/lvts_thermal.c
++++ b/drivers/thermal/mediatek/lvts_thermal.c
+@@ -201,7 +201,7 @@ static int lvts_debugfs_init(struct devi
+ int i;
+
+ lvts_td->dom_dentry = debugfs_create_dir(dev_name(dev), NULL);
+- if (!lvts_td->dom_dentry)
++ if (IS_ERR(lvts_td->dom_dentry))
+ return 0;
+
+ for (i = 0; i < lvts_td->num_lvts_ctrl; i++) {
--- /dev/null
+From 6186be80317d1dbda34d35c06c084a083938f2d3 Mon Sep 17 00:00:00 2001
+From: Chen Jiahao <chenjiahao16@huawei.com>
+Date: Wed, 2 Aug 2023 17:45:27 +0800
+Subject: [PATCH 32/42] thermal/drivers/mediatek: Clean up redundant
+ dev_err_probe()
+
+Referring to platform_get_irq()'s definition, the return value has
+already been checked if ret < 0, and printed via dev_err_probe().
+Calling dev_err_probe() one more time outside platform_get_irq()
+is obviously redundant.
+
+Removing dev_err_probe() outside platform_get_irq() to clean up
+above problem.
+
+Signed-off-by: Chen Jiahao <chenjiahao16@huawei.com>
+Reviewed-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
+Signed-off-by: Daniel Lezcano <daniel.lezcano@linaro.org>
+Link: https://lore.kernel.org/r/20230802094527.988842-1-chenjiahao16@huawei.com
+---
+ drivers/thermal/mediatek/lvts_thermal.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/drivers/thermal/mediatek/lvts_thermal.c
++++ b/drivers/thermal/mediatek/lvts_thermal.c
+@@ -1216,7 +1216,7 @@ static int lvts_probe(struct platform_de
+
+ irq = platform_get_irq(pdev, 0);
+ if (irq < 0)
+- return dev_err_probe(dev, irq, "No irq resource\n");
++ return irq;
+
+ ret = lvts_domain_init(dev, lvts_td, lvts_data);
+ if (ret)
--- /dev/null
+From c2ab54ab0425388e65901a7af2fbf69ead968708 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?N=C3=ADcolas=20F=2E=20R=2E=20A=2E=20Prado?=
+ <nfraprado@collabora.com>
+Date: Thu, 13 Jul 2023 11:42:37 -0400
+Subject: [PATCH 33/42] thermal/drivers/mediatek/lvts_thermal: Make readings
+ valid in filtered mode
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Currently, when a controller is configured to use filtered mode, thermal
+readings are valid only about 30% of the time.
+
+Upon testing, it was noticed that lowering any of the interval settings
+resulted in an improved rate of valid data. The same was observed when
+decreasing the number of samples for each sensor (which also results in
+quicker measurements).
+
+Retrying the read with a timeout longer than the time it takes to
+resample (about 344us with these settings and 4 sensors) also improves
+the rate.
+
+Lower all timing settings to the minimum, configure the filtering to
+single sample, and poll the measurement register for at least one period
+to improve the data validity on filtered mode. With these changes in
+place, out of 100000 reads, a single one failed, ie 99.999% of the data
+was valid.
+
+Reviewed-by: Chen-Yu Tsai <wenst@chromium.org>
+Tested-by: Chen-Yu Tsai <wenst@chromium.org>
+Signed-off-by: NÃcolas F. R. A. Prado <nfraprado@collabora.com>
+Reviewed-by: Alexandre Mergnat <amergnat@baylibre.com>
+Reviewed-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
+Signed-off-by: Daniel Lezcano <daniel.lezcano@linaro.org>
+Link: https://lore.kernel.org/r/20230713154743.611870-1-nfraprado@collabora.com
+---
+ drivers/thermal/mediatek/lvts_thermal.c | 19 ++++++++++++-------
+ 1 file changed, 12 insertions(+), 7 deletions(-)
+
+--- a/drivers/thermal/mediatek/lvts_thermal.c
++++ b/drivers/thermal/mediatek/lvts_thermal.c
+@@ -58,11 +58,11 @@
+ #define LVTS_PROTTC(__base) (__base + 0x00CC)
+ #define LVTS_CLKEN(__base) (__base + 0x00E4)
+
+-#define LVTS_PERIOD_UNIT ((118 * 1000) / (256 * 38))
+-#define LVTS_GROUP_INTERVAL 1
+-#define LVTS_FILTER_INTERVAL 1
+-#define LVTS_SENSOR_INTERVAL 1
+-#define LVTS_HW_FILTER 0x2
++#define LVTS_PERIOD_UNIT 0
++#define LVTS_GROUP_INTERVAL 0
++#define LVTS_FILTER_INTERVAL 0
++#define LVTS_SENSOR_INTERVAL 0
++#define LVTS_HW_FILTER 0x0
+ #define LVTS_TSSEL_CONF 0x13121110
+ #define LVTS_CALSCALE_CONF 0x300
+ #define LVTS_MONINT_CONF 0x8300318C
+@@ -86,6 +86,9 @@
+ #define LVTS_MSR_IMMEDIATE_MODE 0
+ #define LVTS_MSR_FILTERED_MODE 1
+
++#define LVTS_MSR_READ_TIMEOUT_US 400
++#define LVTS_MSR_READ_WAIT_US (LVTS_MSR_READ_TIMEOUT_US / 2)
++
+ #define LVTS_HW_SHUTDOWN_MT8195 105000
+
+ #define LVTS_MINIMUM_THRESHOLD 20000
+@@ -268,6 +271,7 @@ static int lvts_get_temp(struct thermal_
+ struct lvts_sensor *lvts_sensor = thermal_zone_device_priv(tz);
+ void __iomem *msr = lvts_sensor->msr;
+ u32 value;
++ int rc;
+
+ /*
+ * Measurement registers:
+@@ -280,7 +284,8 @@ static int lvts_get_temp(struct thermal_
+ * 16 : Valid temperature
+ * 15-0 : Raw temperature
+ */
+- value = readl(msr);
++ rc = readl_poll_timeout(msr, value, value & BIT(16),
++ LVTS_MSR_READ_WAIT_US, LVTS_MSR_READ_TIMEOUT_US);
+
+ /*
+ * As the thermal zone temperature will read before the
+@@ -293,7 +298,7 @@ static int lvts_get_temp(struct thermal_
+ * functionning temperature and directly jump to a system
+ * shutdown.
+ */
+- if (!(value & BIT(16)))
++ if (rc)
+ return -EAGAIN;
+
+ *temp = lvts_raw_to_temp(value & 0xFFFF);
--- /dev/null
+From c864ff9de3b225b43bb8e08dedb223632323e059 Mon Sep 17 00:00:00 2001
+From: Andrei Coardos <aboutphysycs@gmail.com>
+Date: Fri, 11 Aug 2023 22:28:47 +0300
+Subject: [PATCH 34/42] thermal/drivers/mediatek/auxadc_thermal: Removed call
+ to platform_set_drvdata()
+
+This function call was found to be unnecessary as there is no equivalent
+platform_get_drvdata() call to access the private data of the driver. Also,
+the private data is defined in this driver, so there is no risk of it being
+accessed outside of this driver file.
+
+Signed-off-by: Andrei Coardos <aboutphysycs@gmail.com>
+Reviewed-by: Alexandru Ardelean <alex@shruggie.ro>
+Signed-off-by: Daniel Lezcano <daniel.lezcano@linaro.org>
+Link: https://lore.kernel.org/r/20230811192847.3838-1-aboutphysycs@gmail.com
+---
+ drivers/thermal/mediatek/auxadc_thermal.c | 2 --
+ 1 file changed, 2 deletions(-)
+
+--- a/drivers/thermal/mediatek/auxadc_thermal.c
++++ b/drivers/thermal/mediatek/auxadc_thermal.c
+@@ -1283,8 +1283,6 @@ static int mtk_thermal_probe(struct plat
+ mtk_thermal_init_bank(mt, i, apmixed_phys_base,
+ auxadc_phys_base, ctrl_id);
+
+- platform_set_drvdata(pdev, mt);
+-
+ tzdev = devm_thermal_of_zone_register(&pdev->dev, 0, mt,
+ &mtk_thermal_ops);
+ if (IS_ERR(tzdev))
--- /dev/null
+From 6cf96078969ec00b873db99bae4e47001290685e Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= <u.kleine-koenig@pengutronix.de>
+Date: Wed, 27 Sep 2023 21:37:23 +0200
+Subject: [PATCH 35/42] thermal: lvts: Convert to platform remove callback
+ returning void
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+The .remove() callback for a platform driver returns an int which makes
+many driver authors wrongly assume it's possible to do error handling by
+returning an error code. However the value returned is ignored (apart
+from emitting a warning) and this typically results in resource leaks.
+
+To improve here there is a quest to make the remove callback return
+void. In the first step of this quest all drivers are converted to
+.remove_new(), which already returns void. Eventually after all drivers
+are converted, .remove_new() will be renamed to .remove().
+
+Trivially convert this driver from always returning zero in the remove
+callback to the void returning variant.
+
+Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
+Acked-by: Daniel Lezcano <daniel.lezcano@linaro.org>
+Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
+---
+ drivers/thermal/mediatek/lvts_thermal.c | 6 ++----
+ 1 file changed, 2 insertions(+), 4 deletions(-)
+
+--- a/drivers/thermal/mediatek/lvts_thermal.c
++++ b/drivers/thermal/mediatek/lvts_thermal.c
+@@ -1241,7 +1241,7 @@ static int lvts_probe(struct platform_de
+ return 0;
+ }
+
+-static int lvts_remove(struct platform_device *pdev)
++static void lvts_remove(struct platform_device *pdev)
+ {
+ struct lvts_domain *lvts_td;
+ int i;
+@@ -1252,8 +1252,6 @@ static int lvts_remove(struct platform_d
+ lvts_ctrl_set_enable(&lvts_td->lvts_ctrl[i], false);
+
+ lvts_debugfs_exit(lvts_td);
+-
+- return 0;
+ }
+
+ static const struct lvts_ctrl_data mt8195_lvts_mcu_data_ctrl[] = {
+@@ -1354,7 +1352,7 @@ MODULE_DEVICE_TABLE(of, lvts_of_match);
+
+ static struct platform_driver lvts_driver = {
+ .probe = lvts_probe,
+- .remove = lvts_remove,
++ .remove_new = lvts_remove,
+ .driver = {
+ .name = "mtk-lvts-thermal",
+ .of_match_table = lvts_of_match,
--- /dev/null
+From 26cc18a3d6d9eac21c4f4b4bb96147b2c6617c86 Mon Sep 17 00:00:00 2001
+From: Frank Wunderlich <frank-w@public-files.de>
+Date: Fri, 22 Sep 2023 07:50:19 +0200
+Subject: [PATCH 36/42] thermal/drivers/mediatek/lvts_thermal: Make coeff
+ configurable
+
+The upcoming mt7988 has different temperature coefficients so we
+cannot use constants in the functions lvts_golden_temp_init,
+lvts_golden_temp_init and lvts_raw_to_temp anymore.
+
+Add a field in the lvts_ctrl pointing to the lvts_data which now
+contains the soc-specific temperature coefficents.
+
+To make the code better readable, rename static int coeff_b to
+golden_temp_offset, COEFF_A to temp_factor and COEFF_B to temp_offset.
+
+Signed-off-by: Frank Wunderlich <frank-w@public-files.de>
+Reviewed-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
+Tested-by: Daniel Golle <daniel@makrotopia.org>
+Signed-off-by: Daniel Lezcano <daniel.lezcano@linaro.org>
+Link: https://lore.kernel.org/r/20230922055020.6436-4-linux@fw-web.de
+---
+ drivers/thermal/mediatek/lvts_thermal.c | 51 ++++++++++++++++---------
+ 1 file changed, 34 insertions(+), 17 deletions(-)
+
+--- a/drivers/thermal/mediatek/lvts_thermal.c
++++ b/drivers/thermal/mediatek/lvts_thermal.c
+@@ -80,8 +80,8 @@
+ #define LVTS_SENSOR_MAX 4
+ #define LVTS_GOLDEN_TEMP_MAX 62
+ #define LVTS_GOLDEN_TEMP_DEFAULT 50
+-#define LVTS_COEFF_A -250460
+-#define LVTS_COEFF_B 250460
++#define LVTS_COEFF_A_MT8195 -250460
++#define LVTS_COEFF_B_MT8195 250460
+
+ #define LVTS_MSR_IMMEDIATE_MODE 0
+ #define LVTS_MSR_FILTERED_MODE 1
+@@ -94,7 +94,7 @@
+ #define LVTS_MINIMUM_THRESHOLD 20000
+
+ static int golden_temp = LVTS_GOLDEN_TEMP_DEFAULT;
+-static int coeff_b = LVTS_COEFF_B;
++static int golden_temp_offset;
+
+ struct lvts_sensor_data {
+ int dt_id;
+@@ -112,6 +112,8 @@ struct lvts_ctrl_data {
+ struct lvts_data {
+ const struct lvts_ctrl_data *lvts_ctrl;
+ int num_lvts_ctrl;
++ int temp_factor;
++ int temp_offset;
+ };
+
+ struct lvts_sensor {
+@@ -126,6 +128,7 @@ struct lvts_sensor {
+
+ struct lvts_ctrl {
+ struct lvts_sensor sensors[LVTS_SENSOR_MAX];
++ const struct lvts_data *lvts_data;
+ u32 calibration[LVTS_SENSOR_MAX];
+ u32 hw_tshut_raw_temp;
+ int num_lvts_sensor;
+@@ -247,21 +250,21 @@ static void lvts_debugfs_exit(struct lvt
+
+ #endif
+
+-static int lvts_raw_to_temp(u32 raw_temp)
++static int lvts_raw_to_temp(u32 raw_temp, int temp_factor)
+ {
+ int temperature;
+
+- temperature = ((s64)(raw_temp & 0xFFFF) * LVTS_COEFF_A) >> 14;
+- temperature += coeff_b;
++ temperature = ((s64)(raw_temp & 0xFFFF) * temp_factor) >> 14;
++ temperature += golden_temp_offset;
+
+ return temperature;
+ }
+
+-static u32 lvts_temp_to_raw(int temperature)
++static u32 lvts_temp_to_raw(int temperature, int temp_factor)
+ {
+- u32 raw_temp = ((s64)(coeff_b - temperature)) << 14;
++ u32 raw_temp = ((s64)(golden_temp_offset - temperature)) << 14;
+
+- raw_temp = div_s64(raw_temp, -LVTS_COEFF_A);
++ raw_temp = div_s64(raw_temp, -temp_factor);
+
+ return raw_temp;
+ }
+@@ -269,6 +272,9 @@ static u32 lvts_temp_to_raw(int temperat
+ static int lvts_get_temp(struct thermal_zone_device *tz, int *temp)
+ {
+ struct lvts_sensor *lvts_sensor = thermal_zone_device_priv(tz);
++ struct lvts_ctrl *lvts_ctrl = container_of(lvts_sensor, struct lvts_ctrl,
++ sensors[lvts_sensor->id]);
++ const struct lvts_data *lvts_data = lvts_ctrl->lvts_data;
+ void __iomem *msr = lvts_sensor->msr;
+ u32 value;
+ int rc;
+@@ -301,7 +307,7 @@ static int lvts_get_temp(struct thermal_
+ if (rc)
+ return -EAGAIN;
+
+- *temp = lvts_raw_to_temp(value & 0xFFFF);
++ *temp = lvts_raw_to_temp(value & 0xFFFF, lvts_data->temp_factor);
+
+ return 0;
+ }
+@@ -348,10 +354,13 @@ static bool lvts_should_update_thresh(st
+ static int lvts_set_trips(struct thermal_zone_device *tz, int low, int high)
+ {
+ struct lvts_sensor *lvts_sensor = thermal_zone_device_priv(tz);
+- struct lvts_ctrl *lvts_ctrl = container_of(lvts_sensor, struct lvts_ctrl, sensors[lvts_sensor->id]);
++ struct lvts_ctrl *lvts_ctrl = container_of(lvts_sensor, struct lvts_ctrl,
++ sensors[lvts_sensor->id]);
++ const struct lvts_data *lvts_data = lvts_ctrl->lvts_data;
+ void __iomem *base = lvts_sensor->base;
+- u32 raw_low = lvts_temp_to_raw(low != -INT_MAX ? low : LVTS_MINIMUM_THRESHOLD);
+- u32 raw_high = lvts_temp_to_raw(high);
++ u32 raw_low = lvts_temp_to_raw(low != -INT_MAX ? low : LVTS_MINIMUM_THRESHOLD,
++ lvts_data->temp_factor);
++ u32 raw_high = lvts_temp_to_raw(high, lvts_data->temp_factor);
+ bool should_update_thresh;
+
+ lvts_sensor->low_thresh = low;
+@@ -692,7 +701,7 @@ static int lvts_calibration_read(struct
+ return 0;
+ }
+
+-static int lvts_golden_temp_init(struct device *dev, u32 *value)
++static int lvts_golden_temp_init(struct device *dev, u32 *value, int temp_offset)
+ {
+ u32 gt;
+
+@@ -701,7 +710,7 @@ static int lvts_golden_temp_init(struct
+ if (gt && gt < LVTS_GOLDEN_TEMP_MAX)
+ golden_temp = gt;
+
+- coeff_b = golden_temp * 500 + LVTS_COEFF_B;
++ golden_temp_offset = golden_temp * 500 + temp_offset;
+
+ return 0;
+ }
+@@ -724,7 +733,7 @@ static int lvts_ctrl_init(struct device
+ * The golden temp information is contained in the first chunk
+ * of efuse data.
+ */
+- ret = lvts_golden_temp_init(dev, (u32 *)lvts_td->calib);
++ ret = lvts_golden_temp_init(dev, (u32 *)lvts_td->calib, lvts_data->temp_offset);
+ if (ret)
+ return ret;
+
+@@ -735,6 +744,7 @@ static int lvts_ctrl_init(struct device
+ for (i = 0; i < lvts_data->num_lvts_ctrl; i++) {
+
+ lvts_ctrl[i].base = lvts_td->base + lvts_data->lvts_ctrl[i].offset;
++ lvts_ctrl[i].lvts_data = lvts_data;
+
+ ret = lvts_sensor_init(dev, &lvts_ctrl[i],
+ &lvts_data->lvts_ctrl[i]);
+@@ -758,7 +768,8 @@ static int lvts_ctrl_init(struct device
+ * after initializing the calibration.
+ */
+ lvts_ctrl[i].hw_tshut_raw_temp =
+- lvts_temp_to_raw(lvts_data->lvts_ctrl[i].hw_tshut_temp);
++ lvts_temp_to_raw(lvts_data->lvts_ctrl[i].hw_tshut_temp,
++ lvts_data->temp_factor);
+
+ lvts_ctrl[i].low_thresh = INT_MIN;
+ lvts_ctrl[i].high_thresh = INT_MIN;
+@@ -1223,6 +1234,8 @@ static int lvts_probe(struct platform_de
+ if (irq < 0)
+ return irq;
+
++ golden_temp_offset = lvts_data->temp_offset;
++
+ ret = lvts_domain_init(dev, lvts_td, lvts_data);
+ if (ret)
+ return dev_err_probe(dev, ret, "Failed to initialize the lvts domain\n");
+@@ -1336,11 +1349,15 @@ static const struct lvts_ctrl_data mt819
+ static const struct lvts_data mt8195_lvts_mcu_data = {
+ .lvts_ctrl = mt8195_lvts_mcu_data_ctrl,
+ .num_lvts_ctrl = ARRAY_SIZE(mt8195_lvts_mcu_data_ctrl),
++ .temp_factor = LVTS_COEFF_A_MT8195,
++ .temp_offset = LVTS_COEFF_B_MT8195,
+ };
+
+ static const struct lvts_data mt8195_lvts_ap_data = {
+ .lvts_ctrl = mt8195_lvts_ap_data_ctrl,
+ .num_lvts_ctrl = ARRAY_SIZE(mt8195_lvts_ap_data_ctrl),
++ .temp_factor = LVTS_COEFF_A_MT8195,
++ .temp_offset = LVTS_COEFF_B_MT8195,
+ };
+
+ static const struct of_device_id lvts_of_match[] = {
--- /dev/null
+From be2cc09bd5b46f13629d4fcdeac7ad1b18bb1a0b Mon Sep 17 00:00:00 2001
+From: Frank Wunderlich <frank-w@public-files.de>
+Date: Fri, 22 Sep 2023 07:50:18 +0200
+Subject: [PATCH] dt-bindings: thermal: mediatek: Add LVTS thermal sensors for
+ mt7988
+
+Add sensor constants for MT7988.
+
+Signed-off-by: Frank Wunderlich <frank-w@public-files.de>
+Reviewed-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
+Acked-by: Conor Dooley <conor.dooley@microchip.com>
+Signed-off-by: Daniel Lezcano <daniel.lezcano@linaro.org>
+Link: https://lore.kernel.org/r/20230922055020.6436-3-linux@fw-web.de
+---
+ include/dt-bindings/thermal/mediatek,lvts-thermal.h | 9 +++++++++
+ 1 file changed, 9 insertions(+)
+
+--- a/include/dt-bindings/thermal/mediatek,lvts-thermal.h
++++ b/include/dt-bindings/thermal/mediatek,lvts-thermal.h
+@@ -7,6 +7,15 @@
+ #ifndef __MEDIATEK_LVTS_DT_H
+ #define __MEDIATEK_LVTS_DT_H
+
++#define MT7988_CPU_0 0
++#define MT7988_CPU_1 1
++#define MT7988_ETH2P5G_0 2
++#define MT7988_ETH2P5G_1 3
++#define MT7988_TOPS_0 4
++#define MT7988_TOPS_1 5
++#define MT7988_ETHWARP_0 6
++#define MT7988_ETHWARP_1 7
++
+ #define MT8195_MCU_BIG_CPU0 0
+ #define MT8195_MCU_BIG_CPU1 1
+ #define MT8195_MCU_BIG_CPU2 2
--- /dev/null
+From 9924e9b91b43aaa1610a1d59c4caa43785948cf6 Mon Sep 17 00:00:00 2001
+From: Frank Wunderlich <frank-w@public-files.de>
+Date: Fri, 22 Sep 2023 07:50:20 +0200
+Subject: [PATCH 37/42] thermal/drivers/mediatek/lvts_thermal: Add mt7988
+ support
+
+Add Support for Mediatek Filogic 880/MT7988 LVTS.
+
+Signed-off-by: Frank Wunderlich <frank-w@public-files.de>
+Tested-by: Daniel Golle <daniel@makrotopia.org>
+Signed-off-by: Daniel Lezcano <daniel.lezcano@linaro.org>
+Link: https://lore.kernel.org/r/20230922055020.6436-5-linux@fw-web.de
+---
+ drivers/thermal/mediatek/lvts_thermal.c | 38 +++++++++++++++++++++++++
+ 1 file changed, 38 insertions(+)
+
+--- a/drivers/thermal/mediatek/lvts_thermal.c
++++ b/drivers/thermal/mediatek/lvts_thermal.c
+@@ -82,6 +82,8 @@
+ #define LVTS_GOLDEN_TEMP_DEFAULT 50
+ #define LVTS_COEFF_A_MT8195 -250460
+ #define LVTS_COEFF_B_MT8195 250460
++#define LVTS_COEFF_A_MT7988 -204650
++#define LVTS_COEFF_B_MT7988 204650
+
+ #define LVTS_MSR_IMMEDIATE_MODE 0
+ #define LVTS_MSR_FILTERED_MODE 1
+@@ -89,6 +91,7 @@
+ #define LVTS_MSR_READ_TIMEOUT_US 400
+ #define LVTS_MSR_READ_WAIT_US (LVTS_MSR_READ_TIMEOUT_US / 2)
+
++#define LVTS_HW_SHUTDOWN_MT7988 105000
+ #define LVTS_HW_SHUTDOWN_MT8195 105000
+
+ #define LVTS_MINIMUM_THRESHOLD 20000
+@@ -1267,6 +1270,33 @@ static void lvts_remove(struct platform_
+ lvts_debugfs_exit(lvts_td);
+ }
+
++static const struct lvts_ctrl_data mt7988_lvts_ap_data_ctrl[] = {
++ {
++ .cal_offset = { 0x00, 0x04, 0x08, 0x0c },
++ .lvts_sensor = {
++ { .dt_id = MT7988_CPU_0 },
++ { .dt_id = MT7988_CPU_1 },
++ { .dt_id = MT7988_ETH2P5G_0 },
++ { .dt_id = MT7988_ETH2P5G_1 }
++ },
++ .num_lvts_sensor = 4,
++ .offset = 0x0,
++ .hw_tshut_temp = LVTS_HW_SHUTDOWN_MT7988,
++ },
++ {
++ .cal_offset = { 0x14, 0x18, 0x1c, 0x20 },
++ .lvts_sensor = {
++ { .dt_id = MT7988_TOPS_0},
++ { .dt_id = MT7988_TOPS_1},
++ { .dt_id = MT7988_ETHWARP_0},
++ { .dt_id = MT7988_ETHWARP_1}
++ },
++ .num_lvts_sensor = 4,
++ .offset = 0x100,
++ .hw_tshut_temp = LVTS_HW_SHUTDOWN_MT7988,
++ }
++};
++
+ static const struct lvts_ctrl_data mt8195_lvts_mcu_data_ctrl[] = {
+ {
+ .cal_offset = { 0x04, 0x07 },
+@@ -1346,6 +1376,13 @@ static const struct lvts_ctrl_data mt819
+ }
+ };
+
++static const struct lvts_data mt7988_lvts_ap_data = {
++ .lvts_ctrl = mt7988_lvts_ap_data_ctrl,
++ .num_lvts_ctrl = ARRAY_SIZE(mt7988_lvts_ap_data_ctrl),
++ .temp_factor = LVTS_COEFF_A_MT7988,
++ .temp_offset = LVTS_COEFF_B_MT7988,
++};
++
+ static const struct lvts_data mt8195_lvts_mcu_data = {
+ .lvts_ctrl = mt8195_lvts_mcu_data_ctrl,
+ .num_lvts_ctrl = ARRAY_SIZE(mt8195_lvts_mcu_data_ctrl),
+@@ -1361,6 +1398,7 @@ static const struct lvts_data mt8195_lvt
+ };
+
+ static const struct of_device_id lvts_of_match[] = {
++ { .compatible = "mediatek,mt7988-lvts-ap", .data = &mt7988_lvts_ap_data },
+ { .compatible = "mediatek,mt8195-lvts-mcu", .data = &mt8195_lvts_mcu_data },
+ { .compatible = "mediatek,mt8195-lvts-ap", .data = &mt8195_lvts_ap_data },
+ {},
--- /dev/null
+From fb1bbb5b63e4e3c788a978724749ced57d208054 Mon Sep 17 00:00:00 2001
+From: Minjie Du <duminjie@vivo.com>
+Date: Thu, 21 Sep 2023 17:10:50 +0800
+Subject: [PATCH 38/42] thermal/drivers/mediatek/lvts_thermal: Fix error check
+ in lvts_debugfs_init()
+
+debugfs_create_dir() function returns an error value embedded in
+the pointer (PTR_ERR). Evaluate the return value using IS_ERR
+rather than checking for NULL.
+
+Signed-off-by: Minjie Du <duminjie@vivo.com>
+Reviewed-by: Alexandre Mergnat <amergnat@baylibre.com>
+Reviewed-by: Chen-Yu Tsai <wenst@chromium.org>
+Signed-off-by: Daniel Lezcano <daniel.lezcano@linaro.org>
+Link: https://lore.kernel.org/r/20230921091057.3812-1-duminjie@vivo.com
+---
+ drivers/thermal/mediatek/lvts_thermal.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/drivers/thermal/mediatek/lvts_thermal.c
++++ b/drivers/thermal/mediatek/lvts_thermal.c
+@@ -219,7 +219,7 @@ static int lvts_debugfs_init(struct devi
+
+ sprintf(name, "controller%d", i);
+ dentry = debugfs_create_dir(name, lvts_td->dom_dentry);
+- if (!dentry)
++ if (IS_ERR(dentry))
+ continue;
+
+ regset = devm_kzalloc(dev, sizeof(*regset), GFP_KERNEL);
--- /dev/null
+From e6f43063f2fe9f08b34797bc6d223f7d63b01910 Mon Sep 17 00:00:00 2001
+From: Markus Schneider-Pargmann <msp@baylibre.com>
+Date: Mon, 18 Sep 2023 12:07:06 +0200
+Subject: [PATCH 39/42] thermal/drivers/mediatek: Fix probe for THERMAL_V2
+
+Fix the probe function to call mtk_thermal_release_periodic_ts for
+everything != MTK_THERMAL_V1. This was accidentally changed from V1
+to V2 in the original patch.
+
+Reported-by: Frank Wunderlich <frank-w@public-files.de>
+Closes: https://lore.kernel.org/lkml/B0B3775B-B8D1-4284-814F-4F41EC22F532@public-files.de/
+Reported-by: Daniel Lezcano <daniel.lezcano@linaro.org>
+Closes: https://lore.kernel.org/lkml/07a569b9-e691-64ea-dd65-3b49842af33d@linaro.org/
+Fixes: 33140e668b10 ("thermal/drivers/mediatek: Control buffer enablement tweaks")
+Signed-off-by: Markus Schneider-Pargmann <msp@baylibre.com>
+Reviewed-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
+Signed-off-by: Daniel Lezcano <daniel.lezcano@linaro.org>
+Link: https://lore.kernel.org/r/20230918100706.1229239-1-msp@baylibre.com
+---
+ drivers/thermal/mediatek/auxadc_thermal.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/drivers/thermal/mediatek/auxadc_thermal.c
++++ b/drivers/thermal/mediatek/auxadc_thermal.c
+@@ -1268,7 +1268,7 @@ static int mtk_thermal_probe(struct plat
+
+ mtk_thermal_turn_on_buffer(mt, apmixed_base);
+
+- if (mt->conf->version != MTK_THERMAL_V2)
++ if (mt->conf->version != MTK_THERMAL_V1)
+ mtk_thermal_release_periodic_ts(mt, auxadc_base);
+
+ if (mt->conf->version == MTK_THERMAL_V1)
--- /dev/null
+From a1d874ef3376295ee8ed89b3b5315f4c840ff00b Mon Sep 17 00:00:00 2001
+From: Balsam CHIHI <bchihi@baylibre.com>
+Date: Tue, 17 Oct 2023 21:05:42 +0200
+Subject: [PATCH 40/42] thermal/drivers/mediatek/lvts_thermal: Add suspend and
+ resume
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Add suspend and resume support to LVTS driver.
+
+Signed-off-by: Balsam CHIHI <bchihi@baylibre.com>
+[bero@baylibre.com: suspend/resume in noirq phase]
+Co-developed-by: Bernhard Rosenkränzer <bero@baylibre.com>
+Signed-off-by: Bernhard Rosenkränzer <bero@baylibre.com>
+Reviewed-by: Matthias Brugger <matthias.bgg@gmail.com>
+Reviewed-by: Alexandre Mergnat <amergnat@baylibre.com>
+Reviewed-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
+Signed-off-by: Daniel Lezcano <daniel.lezcano@linaro.org>
+Link: https://lore.kernel.org/r/20231017190545.157282-3-bero@baylibre.com
+---
+ drivers/thermal/mediatek/lvts_thermal.c | 37 +++++++++++++++++++++++++
+ 1 file changed, 37 insertions(+)
+
+--- a/drivers/thermal/mediatek/lvts_thermal.c
++++ b/drivers/thermal/mediatek/lvts_thermal.c
+@@ -1297,6 +1297,38 @@ static const struct lvts_ctrl_data mt798
+ }
+ };
+
++static int lvts_suspend(struct device *dev)
++{
++ struct lvts_domain *lvts_td;
++ int i;
++
++ lvts_td = dev_get_drvdata(dev);
++
++ for (i = 0; i < lvts_td->num_lvts_ctrl; i++)
++ lvts_ctrl_set_enable(&lvts_td->lvts_ctrl[i], false);
++
++ clk_disable_unprepare(lvts_td->clk);
++
++ return 0;
++}
++
++static int lvts_resume(struct device *dev)
++{
++ struct lvts_domain *lvts_td;
++ int i, ret;
++
++ lvts_td = dev_get_drvdata(dev);
++
++ ret = clk_prepare_enable(lvts_td->clk);
++ if (ret)
++ return ret;
++
++ for (i = 0; i < lvts_td->num_lvts_ctrl; i++)
++ lvts_ctrl_set_enable(&lvts_td->lvts_ctrl[i], true);
++
++ return 0;
++}
++
+ static const struct lvts_ctrl_data mt8195_lvts_mcu_data_ctrl[] = {
+ {
+ .cal_offset = { 0x04, 0x07 },
+@@ -1405,12 +1437,17 @@ static const struct of_device_id lvts_of
+ };
+ MODULE_DEVICE_TABLE(of, lvts_of_match);
+
++static const struct dev_pm_ops lvts_pm_ops = {
++ NOIRQ_SYSTEM_SLEEP_PM_OPS(lvts_suspend, lvts_resume)
++};
++
+ static struct platform_driver lvts_driver = {
+ .probe = lvts_probe,
+ .remove_new = lvts_remove,
+ .driver = {
+ .name = "mtk-lvts-thermal",
+ .of_match_table = lvts_of_match,
++ .pm = &lvts_pm_ops,
+ },
+ };
+ module_platform_driver(lvts_driver);
--- /dev/null
+From 0bb4937b58ab712f158588376dbac97f8e9df68e Mon Sep 17 00:00:00 2001
+From: Balsam CHIHI <bchihi@baylibre.com>
+Date: Tue, 17 Oct 2023 21:05:41 +0200
+Subject: [PATCH] dt-bindings: thermal: mediatek: Add LVTS thermal controller
+ definition for mt8192
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Add LVTS thermal controller definition for MT8192.
+
+Signed-off-by: Balsam CHIHI <bchihi@baylibre.com>
+Reviewed-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
+Acked-by: Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>
+Signed-off-by: Bernhard Rosenkränzer <bero@baylibre.com>
+Reviewed-by: Matthias Brugger <matthias.bgg@gmail.com>
+Reviewed-by: Alexandre Mergnat <amergnat@baylibre.com>
+Signed-off-by: Daniel Lezcano <daniel.lezcano@linaro.org>
+Link: https://lore.kernel.org/r/20231017190545.157282-2-bero@baylibre.com
+---
+ .../thermal/mediatek,lvts-thermal.h | 19 +++++++++++++++++++
+ 1 file changed, 19 insertions(+)
+
+--- a/include/dt-bindings/thermal/mediatek,lvts-thermal.h
++++ b/include/dt-bindings/thermal/mediatek,lvts-thermal.h
+@@ -35,4 +35,23 @@
+ #define MT8195_AP_CAM0 15
+ #define MT8195_AP_CAM1 16
+
++#define MT8192_MCU_BIG_CPU0 0
++#define MT8192_MCU_BIG_CPU1 1
++#define MT8192_MCU_BIG_CPU2 2
++#define MT8192_MCU_BIG_CPU3 3
++#define MT8192_MCU_LITTLE_CPU0 4
++#define MT8192_MCU_LITTLE_CPU1 5
++#define MT8192_MCU_LITTLE_CPU2 6
++#define MT8192_MCU_LITTLE_CPU3 7
++
++#define MT8192_AP_VPU0 8
++#define MT8192_AP_VPU1 9
++#define MT8192_AP_GPU0 10
++#define MT8192_AP_GPU1 11
++#define MT8192_AP_INFRA 12
++#define MT8192_AP_CAM 13
++#define MT8192_AP_MD0 14
++#define MT8192_AP_MD1 15
++#define MT8192_AP_MD2 16
++
+ #endif /* __MEDIATEK_LVTS_DT_H */
--- /dev/null
+From 7d8b3864b38d881cf105328ff8569f47446811ad Mon Sep 17 00:00:00 2001
+From: Balsam CHIHI <bchihi@baylibre.com>
+Date: Tue, 17 Oct 2023 21:05:43 +0200
+Subject: [PATCH 41/42] thermal/drivers/mediatek/lvts_thermal: Add mt8192
+ support
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Add LVTS Driver support for MT8192.
+
+Co-developed-by: NÃcolas F. R. A. Prado <nfraprado@collabora.com>
+Signed-off-by: NÃcolas F. R. A. Prado <nfraprado@collabora.com>
+Signed-off-by: Balsam CHIHI <bchihi@baylibre.com>
+Reviewed-by: NÃcolas F. R. A. Prado <nfraprado@collabora.com>
+[bero@baylibre.com: cosmetic changes, rebase]
+Signed-off-by: Bernhard Rosenkränzer <bero@baylibre.com>
+Reviewed-by: Matthias Brugger <matthias.bgg@gmail.com>
+Reviewed-by: Alexandre Mergnat <amergnat@baylibre.com>
+Reviewed-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
+Signed-off-by: Daniel Lezcano <daniel.lezcano@linaro.org>
+Link: https://lore.kernel.org/r/20231017190545.157282-4-bero@baylibre.com
+---
+ drivers/thermal/mediatek/lvts_thermal.c | 95 +++++++++++++++++++++++++
+ 1 file changed, 95 insertions(+)
+
+--- a/drivers/thermal/mediatek/lvts_thermal.c
++++ b/drivers/thermal/mediatek/lvts_thermal.c
+@@ -92,6 +92,7 @@
+ #define LVTS_MSR_READ_WAIT_US (LVTS_MSR_READ_TIMEOUT_US / 2)
+
+ #define LVTS_HW_SHUTDOWN_MT7988 105000
++#define LVTS_HW_SHUTDOWN_MT8192 105000
+ #define LVTS_HW_SHUTDOWN_MT8195 105000
+
+ #define LVTS_MINIMUM_THRESHOLD 20000
+@@ -1329,6 +1330,88 @@ static int lvts_resume(struct device *de
+ return 0;
+ }
+
++static const struct lvts_ctrl_data mt8192_lvts_mcu_data_ctrl[] = {
++ {
++ .cal_offset = { 0x04, 0x08 },
++ .lvts_sensor = {
++ { .dt_id = MT8192_MCU_BIG_CPU0 },
++ { .dt_id = MT8192_MCU_BIG_CPU1 }
++ },
++ .num_lvts_sensor = 2,
++ .offset = 0x0,
++ .hw_tshut_temp = LVTS_HW_SHUTDOWN_MT8192,
++ .mode = LVTS_MSR_FILTERED_MODE,
++ },
++ {
++ .cal_offset = { 0x0c, 0x10 },
++ .lvts_sensor = {
++ { .dt_id = MT8192_MCU_BIG_CPU2 },
++ { .dt_id = MT8192_MCU_BIG_CPU3 }
++ },
++ .num_lvts_sensor = 2,
++ .offset = 0x100,
++ .hw_tshut_temp = LVTS_HW_SHUTDOWN_MT8192,
++ .mode = LVTS_MSR_FILTERED_MODE,
++ },
++ {
++ .cal_offset = { 0x14, 0x18, 0x1c, 0x20 },
++ .lvts_sensor = {
++ { .dt_id = MT8192_MCU_LITTLE_CPU0 },
++ { .dt_id = MT8192_MCU_LITTLE_CPU1 },
++ { .dt_id = MT8192_MCU_LITTLE_CPU2 },
++ { .dt_id = MT8192_MCU_LITTLE_CPU3 }
++ },
++ .num_lvts_sensor = 4,
++ .offset = 0x200,
++ .hw_tshut_temp = LVTS_HW_SHUTDOWN_MT8192,
++ .mode = LVTS_MSR_FILTERED_MODE,
++ }
++};
++
++static const struct lvts_ctrl_data mt8192_lvts_ap_data_ctrl[] = {
++ {
++ .cal_offset = { 0x24, 0x28 },
++ .lvts_sensor = {
++ { .dt_id = MT8192_AP_VPU0 },
++ { .dt_id = MT8192_AP_VPU1 }
++ },
++ .num_lvts_sensor = 2,
++ .offset = 0x0,
++ .hw_tshut_temp = LVTS_HW_SHUTDOWN_MT8192,
++ },
++ {
++ .cal_offset = { 0x2c, 0x30 },
++ .lvts_sensor = {
++ { .dt_id = MT8192_AP_GPU0 },
++ { .dt_id = MT8192_AP_GPU1 }
++ },
++ .num_lvts_sensor = 2,
++ .offset = 0x100,
++ .hw_tshut_temp = LVTS_HW_SHUTDOWN_MT8192,
++ },
++ {
++ .cal_offset = { 0x34, 0x38 },
++ .lvts_sensor = {
++ { .dt_id = MT8192_AP_INFRA },
++ { .dt_id = MT8192_AP_CAM },
++ },
++ .num_lvts_sensor = 2,
++ .offset = 0x200,
++ .hw_tshut_temp = LVTS_HW_SHUTDOWN_MT8192,
++ },
++ {
++ .cal_offset = { 0x3c, 0x40, 0x44 },
++ .lvts_sensor = {
++ { .dt_id = MT8192_AP_MD0 },
++ { .dt_id = MT8192_AP_MD1 },
++ { .dt_id = MT8192_AP_MD2 }
++ },
++ .num_lvts_sensor = 3,
++ .offset = 0x300,
++ .hw_tshut_temp = LVTS_HW_SHUTDOWN_MT8192,
++ }
++};
++
+ static const struct lvts_ctrl_data mt8195_lvts_mcu_data_ctrl[] = {
+ {
+ .cal_offset = { 0x04, 0x07 },
+@@ -1415,6 +1498,16 @@ static const struct lvts_data mt7988_lvt
+ .temp_offset = LVTS_COEFF_B_MT7988,
+ };
+
++static const struct lvts_data mt8192_lvts_mcu_data = {
++ .lvts_ctrl = mt8192_lvts_mcu_data_ctrl,
++ .num_lvts_ctrl = ARRAY_SIZE(mt8192_lvts_mcu_data_ctrl),
++};
++
++static const struct lvts_data mt8192_lvts_ap_data = {
++ .lvts_ctrl = mt8192_lvts_ap_data_ctrl,
++ .num_lvts_ctrl = ARRAY_SIZE(mt8192_lvts_ap_data_ctrl),
++};
++
+ static const struct lvts_data mt8195_lvts_mcu_data = {
+ .lvts_ctrl = mt8195_lvts_mcu_data_ctrl,
+ .num_lvts_ctrl = ARRAY_SIZE(mt8195_lvts_mcu_data_ctrl),
+@@ -1431,6 +1524,8 @@ static const struct lvts_data mt8195_lvt
+
+ static const struct of_device_id lvts_of_match[] = {
+ { .compatible = "mediatek,mt7988-lvts-ap", .data = &mt7988_lvts_ap_data },
++ { .compatible = "mediatek,mt8192-lvts-mcu", .data = &mt8192_lvts_mcu_data },
++ { .compatible = "mediatek,mt8192-lvts-ap", .data = &mt8192_lvts_ap_data },
+ { .compatible = "mediatek,mt8195-lvts-mcu", .data = &mt8195_lvts_mcu_data },
+ { .compatible = "mediatek,mt8195-lvts-ap", .data = &mt8195_lvts_ap_data },
+ {},
--- /dev/null
+From 5d126a3c87cf7964b28bacf3826eea4266265bce Mon Sep 17 00:00:00 2001
+From: Balsam CHIHI <bchihi@baylibre.com>
+Date: Tue, 17 Oct 2023 21:05:45 +0200
+Subject: [PATCH 42/42] thermal/drivers/mediatek/lvts_thermal: Update
+ calibration data documentation
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Update LVTS calibration data documentation for mt8192 and mt8195.
+
+Signed-off-by: Balsam CHIHI <bchihi@baylibre.com>
+Reviewed-by: NÃcolas F. R. A. Prado <nfraprado@collabora.com>
+[bero@baylibre.com: Fix issues pointed out by NÃcolas F. R. A. Prado <nfraprado@collabora.com>]
+Signed-off-by: Bernhard Rosenkränzer <bero@baylibre.com>
+Reviewed-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
+Reviewed-by: Alexandre Mergnat <amergnat@baylibre.com>
+Signed-off-by: Daniel Lezcano <daniel.lezcano@linaro.org>
+Link: https://lore.kernel.org/r/20231017190545.157282-6-bero@baylibre.com
+---
+ drivers/thermal/mediatek/lvts_thermal.c | 31 +++++++++++++++++++++++--
+ 1 file changed, 29 insertions(+), 2 deletions(-)
+
+--- a/drivers/thermal/mediatek/lvts_thermal.c
++++ b/drivers/thermal/mediatek/lvts_thermal.c
+@@ -616,7 +616,34 @@ static int lvts_sensor_init(struct devic
+ * The efuse blob values follows the sensor enumeration per thermal
+ * controller. The decoding of the stream is as follow:
+ *
+- * stream index map for MCU Domain :
++ * MT8192 :
++ * Stream index map for MCU Domain mt8192 :
++ *
++ * <-----mcu-tc#0-----> <-----sensor#0-----> <-----sensor#1----->
++ * 0x01 | 0x02 | 0x03 | 0x04 | 0x05 | 0x06 | 0x07 | 0x08 | 0x09 | 0x0A | 0x0B
++ *
++ * <-----sensor#2-----> <-----sensor#3----->
++ * 0x0C | 0x0D | 0x0E | 0x0F | 0x10 | 0x11 | 0x12 | 0x13
++ *
++ * <-----sensor#4-----> <-----sensor#5-----> <-----sensor#6-----> <-----sensor#7----->
++ * 0x14 | 0x15 | 0x16 | 0x17 | 0x18 | 0x19 | 0x1A | 0x1B | 0x1C | 0x1D | 0x1E | 0x1F | 0x20 | 0x21 | 0x22 | 0x23
++ *
++ * Stream index map for AP Domain mt8192 :
++ *
++ * <-----sensor#0-----> <-----sensor#1----->
++ * 0x24 | 0x25 | 0x26 | 0x27 | 0x28 | 0x29 | 0x2A | 0x2B
++ *
++ * <-----sensor#2-----> <-----sensor#3----->
++ * 0x2C | 0x2D | 0x2E | 0x2F | 0x30 | 0x31 | 0x32 | 0x33
++ *
++ * <-----sensor#4-----> <-----sensor#5----->
++ * 0x34 | 0x35 | 0x36 | 0x37 | 0x38 | 0x39 | 0x3A | 0x3B
++ *
++ * <-----sensor#6-----> <-----sensor#7-----> <-----sensor#8----->
++ * 0x3C | 0x3D | 0x3E | 0x3F | 0x40 | 0x41 | 0x42 | 0x43 | 0x44 | 0x45 | 0x46 | 0x47
++ *
++ * MT8195 :
++ * Stream index map for MCU Domain mt8195 :
+ *
+ * <-----mcu-tc#0-----> <-----sensor#0-----> <-----sensor#1----->
+ * 0x01 | 0x02 | 0x03 | 0x04 | 0x05 | 0x06 | 0x07 | 0x08 | 0x09
+@@ -627,7 +654,7 @@ static int lvts_sensor_init(struct devic
+ * <-----mcu-tc#2-----> <-----sensor#4-----> <-----sensor#5-----> <-----sensor#6-----> <-----sensor#7----->
+ * 0x13 | 0x14 | 0x15 | 0x16 | 0x17 | 0x18 | 0x19 | 0x1A | 0x1B | 0x1C | 0x1D | 0x1E | 0x1F | 0x20 | 0x21
+ *
+- * stream index map for AP Domain :
++ * Stream index map for AP Domain mt8195 :
+ *
+ * <-----ap--tc#0-----> <-----sensor#0-----> <-----sensor#1----->
+ * 0x22 | 0x23 | 0x24 | 0x25 | 0x26 | 0x27 | 0x28 | 0x29 | 0x2A
--- /dev/null
+From patchwork Thu Sep 7 11:20:18 2023
+Content-Type: text/plain; charset="utf-8"
+MIME-Version: 1.0
+Content-Transfer-Encoding: 7bit
+X-Patchwork-Submitter: Frank Wunderlich <linux@fw-web.de>
+X-Patchwork-Id: 13376356
+From: Frank Wunderlich <linux@fw-web.de>
+To: linux-mediatek@lists.infradead.org
+Subject: [PATCH] thermal/drivers/mediatek: Fix control buffer enablement on
+ MT7896
+Date: Thu, 7 Sep 2023 13:20:18 +0200
+Message-Id: <20230907112018.52811-1-linux@fw-web.de>
+X-Mailer: git-send-email 2.34.1
+MIME-Version: 1.0
+X-Mail-ID: e7eeb8e1-00de-41f6-a5df-ce2e9164136e
+X-BeenThere: linux-mediatek@lists.infradead.org
+X-Mailman-Version: 2.1.34
+Precedence: list
+List-Id: <linux-mediatek.lists.infradead.org>
+Cc: Daniel Lezcano <daniel.lezcano@linaro.org>,
+ "Rafael J. Wysocki" <rafael@kernel.org>, linux-pm@vger.kernel.org,
+ Amit Kucheria <amitk@kernel.org>, Daniel Golle <daniel@makrotopia.org>,
+ stable@vger.kernel.org, linux-kernel@vger.kernel.org,
+ Matthias Brugger <matthias.bgg@gmail.com>, Zhang Rui <rui.zhang@intel.com>,
+ linux-arm-kernel@lists.infradead.org,
+ AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
+Sender: "Linux-mediatek" <linux-mediatek-bounces@lists.infradead.org>
+
+From: Frank Wunderlich <frank-w@public-files.de>
+
+Reading thermal sensor on mt7986 devices returns invalid temperature:
+
+bpi-r3 ~ # cat /sys/class/thermal/thermal_zone0/temp
+ -274000
+
+Fix this by adding missing members in mtk_thermal_data struct which were
+used in mtk_thermal_turn_on_buffer after commit 33140e668b10.
+
+Cc: stable@vger.kernel.org
+Fixes: 33140e668b10 ("thermal/drivers/mediatek: Control buffer enablement tweaks")
+Signed-off-by: Frank Wunderlich <frank-w@public-files.de>
+Reviewed-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
+Reviewed-by: Markus Schneider-Pargmann <msp@baylibre.com>
+---
+ drivers/thermal/mediatek/auxadc_thermal.c | 3 +++
+ 1 file changed, 3 insertions(+)
+
+--- a/drivers/thermal/mediatek/auxadc_thermal.c
++++ b/drivers/thermal/mediatek/auxadc_thermal.c
+@@ -691,6 +691,9 @@ static const struct mtk_thermal_data mt7
+ .adcpnp = mt7986_adcpnp,
+ .sensor_mux_values = mt7986_mux_values,
+ .version = MTK_THERMAL_V3,
++ .apmixed_buffer_ctl_reg = APMIXED_SYS_TS_CON1,
++ .apmixed_buffer_ctl_mask = GENMASK(31, 6) | BIT(3),
++ .apmixed_buffer_ctl_set = BIT(0),
+ };
+
+ static bool mtk_thermal_temp_is_valid(int temp)
--- /dev/null
+From 11f9a0f4e51887ad7b4a2898a368fcd0c2984e89 Mon Sep 17 00:00:00 2001
+From: Frank Wunderlich <frank-w@public-files.de>
+Date: Sun, 9 Oct 2022 12:16:31 +0200
+Subject: [PATCH 12/16] i2c: mediatek: add mt7986 support
+
+Add i2c support for MT7986 SoC.
+
+Signed-off-by: Frank Wunderlich <frank-w@public-files.de>
+Reviewed-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
+Signed-off-by: Wolfram Sang <wsa@kernel.org>
+---
+ drivers/i2c/busses/i2c-mt65xx.c | 14 ++++++++++++++
+ 1 file changed, 14 insertions(+)
+
+--- a/drivers/i2c/busses/i2c-mt65xx.c
++++ b/drivers/i2c/busses/i2c-mt65xx.c
+@@ -431,6 +431,19 @@ static const struct mtk_i2c_compatible m
+ .max_dma_support = 33,
+ };
+
++static const struct mtk_i2c_compatible mt7986_compat = {
++ .quirks = &mt7622_i2c_quirks,
++ .regs = mt_i2c_regs_v1,
++ .pmic_i2c = 0,
++ .dcm = 1,
++ .auto_restart = 1,
++ .aux_len_reg = 1,
++ .timing_adjust = 0,
++ .dma_sync = 1,
++ .ltiming_adjust = 0,
++ .max_dma_support = 32,
++};
++
+ static const struct mtk_i2c_compatible mt8173_compat = {
+ .regs = mt_i2c_regs_v1,
+ .pmic_i2c = 0,
+@@ -503,6 +516,7 @@ static const struct of_device_id mtk_i2c
+ { .compatible = "mediatek,mt6577-i2c", .data = &mt6577_compat },
+ { .compatible = "mediatek,mt6589-i2c", .data = &mt6589_compat },
+ { .compatible = "mediatek,mt7622-i2c", .data = &mt7622_compat },
++ { .compatible = "mediatek,mt7986-i2c", .data = &mt7986_compat },
+ { .compatible = "mediatek,mt8168-i2c", .data = &mt8168_compat },
+ { .compatible = "mediatek,mt8173-i2c", .data = &mt8173_compat },
+ { .compatible = "mediatek,mt8183-i2c", .data = &mt8183_compat },
--- /dev/null
+From 98204ccafd45a8a6109ff2d60e2c179b95d92578 Mon Sep 17 00:00:00 2001
+From: ye xingchen <ye.xingchen@zte.com.cn>
+Date: Thu, 19 Jan 2023 17:19:58 +0800
+Subject: [PATCH 13/16] i2c: mt65xx: Use
+ devm_platform_get_and_ioremap_resource()
+
+Convert platform_get_resource(), devm_ioremap_resource() to a single
+call to devm_platform_get_and_ioremap_resource(), as this is exactly
+what this function does.
+
+Signed-off-by: ye xingchen <ye.xingchen@zte.com.cn>
+Reviewed-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
+Signed-off-by: Wolfram Sang <wsa@kernel.org>
+---
+ drivers/i2c/busses/i2c-mt65xx.c | 7 ++-----
+ 1 file changed, 2 insertions(+), 5 deletions(-)
+
+--- a/drivers/i2c/busses/i2c-mt65xx.c
++++ b/drivers/i2c/busses/i2c-mt65xx.c
+@@ -1366,20 +1366,17 @@ static int mtk_i2c_probe(struct platform
+ {
+ int ret = 0;
+ struct mtk_i2c *i2c;
+- struct resource *res;
+ int i, irq, speed_clk;
+
+ i2c = devm_kzalloc(&pdev->dev, sizeof(*i2c), GFP_KERNEL);
+ if (!i2c)
+ return -ENOMEM;
+
+- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+- i2c->base = devm_ioremap_resource(&pdev->dev, res);
++ i2c->base = devm_platform_get_and_ioremap_resource(pdev, 0, NULL);
+ if (IS_ERR(i2c->base))
+ return PTR_ERR(i2c->base);
+
+- res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+- i2c->pdmabase = devm_ioremap_resource(&pdev->dev, res);
++ i2c->pdmabase = devm_platform_get_and_ioremap_resource(pdev, 1, NULL);
+ if (IS_ERR(i2c->pdmabase))
+ return PTR_ERR(i2c->pdmabase);
+
--- /dev/null
+From 8106fa2e0ae6082833fe1df97829c46c0183eaea Mon Sep 17 00:00:00 2001
+From: Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>
+Date: Sat, 11 Mar 2023 12:16:54 +0100
+Subject: [PATCH 14/16] i2c: mt65xx: drop of_match_ptr for ID table
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+The driver can match only via the DT table so the table should be always
+used and the of_match_ptr does not have any sense (this also allows ACPI
+matching via PRP0001, even though it might not be relevant here).
+
+ drivers/i2c/busses/i2c-mt65xx.c:514:34: error: ‘mtk_i2c_of_match’ defined but not used [-Werror=unused-const-variable=]
+
+Signed-off-by: Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>
+Reviewed-by: Guenter Roeck <groeck@chromium.org>
+Reviewed-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
+Signed-off-by: Wolfram Sang <wsa@kernel.org>
+---
+ drivers/i2c/busses/i2c-mt65xx.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/drivers/i2c/busses/i2c-mt65xx.c
++++ b/drivers/i2c/busses/i2c-mt65xx.c
+@@ -1546,7 +1546,7 @@ static struct platform_driver mtk_i2c_dr
+ .driver = {
+ .name = I2C_DRV_NAME,
+ .pm = &mtk_i2c_pm,
+- .of_match_table = of_match_ptr(mtk_i2c_of_match),
++ .of_match_table = mtk_i2c_of_match,
+ },
+ };
+
--- /dev/null
+From f69f3d662ba3bf999c36d9ac1e684540c4487bc3 Mon Sep 17 00:00:00 2001
+From: Daniel Golle <daniel@makrotopia.org>
+Date: Mon, 10 Apr 2023 17:19:38 +0100
+Subject: [PATCH 15/16] i2c: mediatek: add support for MT7981 SoC
+
+Add support for the I2C units found in the MediaTek MT7981 and MT7988
+SoCs. Just like other recent MediaTek I2C units that also uses v3
+register offsets (which differ from v2 only by OFFSET_SLAVE_ADDR being
+0x94 instead of 0x4).
+
+Signed-off-by: Daniel Golle <daniel@makrotopia.org>
+Reviewed-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
+Reviewed-by: Alexandre Mergnat <amergnat@baylibre.com>
+Signed-off-by: Wolfram Sang <wsa@kernel.org>
+---
+ drivers/i2c/busses/i2c-mt65xx.c | 13 +++++++++++++
+ 1 file changed, 13 insertions(+)
+
+--- a/drivers/i2c/busses/i2c-mt65xx.c
++++ b/drivers/i2c/busses/i2c-mt65xx.c
+@@ -431,6 +431,18 @@ static const struct mtk_i2c_compatible m
+ .max_dma_support = 33,
+ };
+
++static const struct mtk_i2c_compatible mt7981_compat = {
++ .regs = mt_i2c_regs_v3,
++ .pmic_i2c = 0,
++ .dcm = 0,
++ .auto_restart = 1,
++ .aux_len_reg = 1,
++ .timing_adjust = 1,
++ .dma_sync = 1,
++ .ltiming_adjust = 1,
++ .max_dma_support = 33
++};
++
+ static const struct mtk_i2c_compatible mt7986_compat = {
+ .quirks = &mt7622_i2c_quirks,
+ .regs = mt_i2c_regs_v1,
+@@ -516,6 +528,7 @@ static const struct of_device_id mtk_i2c
+ { .compatible = "mediatek,mt6577-i2c", .data = &mt6577_compat },
+ { .compatible = "mediatek,mt6589-i2c", .data = &mt6589_compat },
+ { .compatible = "mediatek,mt7622-i2c", .data = &mt7622_compat },
++ { .compatible = "mediatek,mt7981-i2c", .data = &mt7981_compat },
+ { .compatible = "mediatek,mt7986-i2c", .data = &mt7986_compat },
+ { .compatible = "mediatek,mt8168-i2c", .data = &mt8168_compat },
+ { .compatible = "mediatek,mt8173-i2c", .data = &mt8173_compat },
--- /dev/null
+From 3bf827929a44c17bfb1bf1000b143c02ce26a929 Mon Sep 17 00:00:00 2001
+From: Daniel Golle <daniel@makrotopia.org>
+Date: Sat, 26 Aug 2023 21:56:51 +0100
+Subject: [PATCH] i2c: mt65xx: allow optional pmic clock
+
+Using the I2C host controller on the MT7981 SoC requires 4 clocks to
+be enabled. One of them, the pmic clk, is only enabled in case
+'mediatek,have-pmic' is also set which has other consequences which
+are not desired in this case.
+
+Allow defining a pmic clk even in case the 'mediatek,have-pmic' propterty
+is not present and the bus is not used to connect to a pmic, but may
+still require to enable the pmic clock.
+
+Signed-off-by: Daniel Golle <daniel@makrotopia.org>
+---
+ drivers/i2c/busses/i2c-mt65xx.c | 12 ++++++++----
+ 1 file changed, 8 insertions(+), 4 deletions(-)
+
+--- a/drivers/i2c/busses/i2c-mt65xx.c
++++ b/drivers/i2c/busses/i2c-mt65xx.c
+@@ -1444,15 +1444,19 @@ static int mtk_i2c_probe(struct platform
+ if (IS_ERR(i2c->clocks[I2C_MT65XX_CLK_ARB].clk))
+ return PTR_ERR(i2c->clocks[I2C_MT65XX_CLK_ARB].clk);
+
++ i2c->clocks[I2C_MT65XX_CLK_PMIC].clk = devm_clk_get_optional(&pdev->dev, "pmic");
++ if (IS_ERR(i2c->clocks[I2C_MT65XX_CLK_PMIC].clk)) {
++ dev_err(&pdev->dev, "cannot get pmic clock\n");
++ return PTR_ERR(i2c->clocks[I2C_MT65XX_CLK_PMIC].clk);
++ }
++
+ if (i2c->have_pmic) {
+- i2c->clocks[I2C_MT65XX_CLK_PMIC].clk = devm_clk_get(&pdev->dev, "pmic");
+- if (IS_ERR(i2c->clocks[I2C_MT65XX_CLK_PMIC].clk)) {
++ if (!i2c->clocks[I2C_MT65XX_CLK_PMIC].clk) {
+ dev_err(&pdev->dev, "cannot get pmic clock\n");
+- return PTR_ERR(i2c->clocks[I2C_MT65XX_CLK_PMIC].clk);
++ return -ENODEV;
+ }
+ speed_clk = I2C_MT65XX_CLK_PMIC;
+ } else {
+- i2c->clocks[I2C_MT65XX_CLK_PMIC].clk = NULL;
+ speed_clk = I2C_MT65XX_CLK_MAIN;
+ }
+
--- /dev/null
+From d35469096915f2551ed1d26da1ab12ff500fc963 Mon Sep 17 00:00:00 2001
+From: Maso Huang <maso.huang@mediatek.com>
+Date: Thu, 17 Aug 2023 18:13:33 +0800
+Subject: [PATCH 1/9] ASoC: mediatek: mt7986: add common header
+
+Add header files for register definition and structure.
+
+Signed-off-by: Maso Huang <maso.huang@mediatek.com>
+Reviewed-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
+Link: https://lore.kernel.org/r/20230817101338.18782-2-maso.huang@mediatek.com
+Signed-off-by: Mark Brown <broonie@kernel.org>
+---
+ sound/soc/mediatek/mt7986/mt7986-afe-common.h | 49 +++++
+ sound/soc/mediatek/mt7986/mt7986-reg.h | 196 ++++++++++++++++++
+ 2 files changed, 245 insertions(+)
+ create mode 100644 sound/soc/mediatek/mt7986/mt7986-afe-common.h
+ create mode 100644 sound/soc/mediatek/mt7986/mt7986-reg.h
+
+--- /dev/null
++++ b/sound/soc/mediatek/mt7986/mt7986-afe-common.h
+@@ -0,0 +1,49 @@
++/* SPDX-License-Identifier: GPL-2.0 */
++/*
++ * mt7986-afe-common.h -- MediaTek 7986 audio driver definitions
++ *
++ * Copyright (c) 2023 MediaTek Inc.
++ * Authors: Vic Wu <vic.wu@mediatek.com>
++ * Maso Huang <maso.huang@mediatek.com>
++ */
++
++#ifndef _MT_7986_AFE_COMMON_H_
++#define _MT_7986_AFE_COMMON_H_
++
++#include <sound/soc.h>
++#include <linux/clk.h>
++#include <linux/list.h>
++#include <linux/regmap.h>
++#include "../common/mtk-base-afe.h"
++
++enum {
++ MT7986_MEMIF_DL1,
++ MT7986_MEMIF_VUL12,
++ MT7986_MEMIF_NUM,
++ MT7986_DAI_ETDM = MT7986_MEMIF_NUM,
++ MT7986_DAI_NUM,
++};
++
++enum {
++ MT7986_IRQ_0,
++ MT7986_IRQ_1,
++ MT7986_IRQ_2,
++ MT7986_IRQ_NUM,
++};
++
++struct mt7986_afe_private {
++ struct clk_bulk_data *clks;
++ int num_clks;
++
++ int pm_runtime_bypass_reg_ctl;
++
++ /* dai */
++ void *dai_priv[MT7986_DAI_NUM];
++};
++
++unsigned int mt7986_afe_rate_transform(struct device *dev,
++ unsigned int rate);
++
++/* dai register */
++int mt7986_dai_etdm_register(struct mtk_base_afe *afe);
++#endif
+--- /dev/null
++++ b/sound/soc/mediatek/mt7986/mt7986-reg.h
+@@ -0,0 +1,196 @@
++/* SPDX-License-Identifier: GPL-2.0 */
++/*
++ * mt7986-reg.h -- MediaTek 7986 audio driver reg definition
++ *
++ * Copyright (c) 2023 MediaTek Inc.
++ * Authors: Vic Wu <vic.wu@mediatek.com>
++ * Maso Huang <maso.huang@mediatek.com>
++ */
++
++#ifndef _MT7986_REG_H_
++#define _MT7986_REG_H_
++
++#define AUDIO_TOP_CON2 0x0008
++#define AUDIO_TOP_CON4 0x0010
++#define AUDIO_ENGEN_CON0 0x0014
++#define AFE_IRQ_MCU_EN 0x0100
++#define AFE_IRQ_MCU_STATUS 0x0120
++#define AFE_IRQ_MCU_CLR 0x0128
++#define AFE_IRQ0_MCU_CFG0 0x0140
++#define AFE_IRQ0_MCU_CFG1 0x0144
++#define AFE_IRQ1_MCU_CFG0 0x0148
++#define AFE_IRQ1_MCU_CFG1 0x014c
++#define AFE_IRQ2_MCU_CFG0 0x0150
++#define AFE_IRQ2_MCU_CFG1 0x0154
++#define ETDM_IN5_CON0 0x13f0
++#define ETDM_IN5_CON1 0x13f4
++#define ETDM_IN5_CON2 0x13f8
++#define ETDM_IN5_CON3 0x13fc
++#define ETDM_IN5_CON4 0x1400
++#define ETDM_OUT5_CON0 0x1570
++#define ETDM_OUT5_CON4 0x1580
++#define ETDM_OUT5_CON5 0x1584
++#define ETDM_4_7_COWORK_CON0 0x15e0
++#define ETDM_4_7_COWORK_CON1 0x15e4
++#define AFE_CONN018_1 0x1b44
++#define AFE_CONN018_4 0x1b50
++#define AFE_CONN019_1 0x1b64
++#define AFE_CONN019_4 0x1b70
++#define AFE_CONN124_1 0x2884
++#define AFE_CONN124_4 0x2890
++#define AFE_CONN125_1 0x28a4
++#define AFE_CONN125_4 0x28b0
++#define AFE_CONN_RS_0 0x3920
++#define AFE_CONN_RS_3 0x392c
++#define AFE_CONN_16BIT_0 0x3960
++#define AFE_CONN_16BIT_3 0x396c
++#define AFE_CONN_24BIT_0 0x3980
++#define AFE_CONN_24BIT_3 0x398c
++#define AFE_MEMIF_CON0 0x3d98
++#define AFE_MEMIF_RD_MON 0x3da0
++#define AFE_MEMIF_WR_MON 0x3da4
++#define AFE_DL0_BASE_MSB 0x3e40
++#define AFE_DL0_BASE 0x3e44
++#define AFE_DL0_CUR_MSB 0x3e48
++#define AFE_DL0_CUR 0x3e4c
++#define AFE_DL0_END_MSB 0x3e50
++#define AFE_DL0_END 0x3e54
++#define AFE_DL0_RCH_MON 0x3e58
++#define AFE_DL0_LCH_MON 0x3e5c
++#define AFE_DL0_CON0 0x3e60
++#define AFE_VUL0_BASE_MSB 0x4220
++#define AFE_VUL0_BASE 0x4224
++#define AFE_VUL0_CUR_MSB 0x4228
++#define AFE_VUL0_CUR 0x422c
++#define AFE_VUL0_END_MSB 0x4230
++#define AFE_VUL0_END 0x4234
++#define AFE_VUL0_CON0 0x4238
++
++#define AFE_MAX_REGISTER AFE_VUL0_CON0
++#define AFE_IRQ_STATUS_BITS 0x7
++#define AFE_IRQ_CNT_SHIFT 0
++#define AFE_IRQ_CNT_MASK 0xffffff
++
++/* AUDIO_TOP_CON2 */
++#define CLK_OUT5_PDN BIT(14)
++#define CLK_OUT5_PDN_MASK BIT(14)
++#define CLK_IN5_PDN BIT(7)
++#define CLK_IN5_PDN_MASK BIT(7)
++
++/* AUDIO_TOP_CON4 */
++#define PDN_APLL_TUNER2 BIT(12)
++#define PDN_APLL_TUNER2_MASK BIT(12)
++
++/* AUDIO_ENGEN_CON0 */
++#define AUD_APLL2_EN BIT(3)
++#define AUD_APLL2_EN_MASK BIT(3)
++#define AUD_26M_EN BIT(0)
++#define AUD_26M_EN_MASK BIT(0)
++
++/* AFE_DL0_CON0 */
++#define DL0_ON_SFT 28
++#define DL0_ON_MASK 0x1
++#define DL0_ON_MASK_SFT BIT(28)
++#define DL0_MINLEN_SFT 20
++#define DL0_MINLEN_MASK 0xf
++#define DL0_MINLEN_MASK_SFT (0xf << 20)
++#define DL0_MODE_SFT 8
++#define DL0_MODE_MASK 0x1f
++#define DL0_MODE_MASK_SFT (0x1f << 8)
++#define DL0_PBUF_SIZE_SFT 5
++#define DL0_PBUF_SIZE_MASK 0x3
++#define DL0_PBUF_SIZE_MASK_SFT (0x3 << 5)
++#define DL0_MONO_SFT 4
++#define DL0_MONO_MASK 0x1
++#define DL0_MONO_MASK_SFT BIT(4)
++#define DL0_HALIGN_SFT 2
++#define DL0_HALIGN_MASK 0x1
++#define DL0_HALIGN_MASK_SFT BIT(2)
++#define DL0_HD_MODE_SFT 0
++#define DL0_HD_MODE_MASK 0x3
++#define DL0_HD_MODE_MASK_SFT (0x3 << 0)
++
++/* AFE_VUL0_CON0 */
++#define VUL0_ON_SFT 28
++#define VUL0_ON_MASK 0x1
++#define VUL0_ON_MASK_SFT BIT(28)
++#define VUL0_MODE_SFT 8
++#define VUL0_MODE_MASK 0x1f
++#define VUL0_MODE_MASK_SFT (0x1f << 8)
++#define VUL0_MONO_SFT 4
++#define VUL0_MONO_MASK 0x1
++#define VUL0_MONO_MASK_SFT BIT(4)
++#define VUL0_HALIGN_SFT 2
++#define VUL0_HALIGN_MASK 0x1
++#define VUL0_HALIGN_MASK_SFT BIT(2)
++#define VUL0_HD_MODE_SFT 0
++#define VUL0_HD_MODE_MASK 0x3
++#define VUL0_HD_MODE_MASK_SFT (0x3 << 0)
++
++/* AFE_IRQ_MCU_CON */
++#define IRQ_MCU_MODE_SFT 4
++#define IRQ_MCU_MODE_MASK 0x1f
++#define IRQ_MCU_MODE_MASK_SFT (0x1f << 4)
++#define IRQ_MCU_ON_SFT 0
++#define IRQ_MCU_ON_MASK 0x1
++#define IRQ_MCU_ON_MASK_SFT BIT(0)
++#define IRQ0_MCU_CLR_SFT 0
++#define IRQ0_MCU_CLR_MASK 0x1
++#define IRQ0_MCU_CLR_MASK_SFT BIT(0)
++#define IRQ1_MCU_CLR_SFT 1
++#define IRQ1_MCU_CLR_MASK 0x1
++#define IRQ1_MCU_CLR_MASK_SFT BIT(1)
++#define IRQ2_MCU_CLR_SFT 2
++#define IRQ2_MCU_CLR_MASK 0x1
++#define IRQ2_MCU_CLR_MASK_SFT BIT(2)
++
++/* ETDM_IN5_CON2 */
++#define IN_CLK_SRC(x) ((x) << 10)
++#define IN_CLK_SRC_SFT 10
++#define IN_CLK_SRC_MASK GENMASK(12, 10)
++
++/* ETDM_IN5_CON3 */
++#define IN_SEL_FS(x) ((x) << 26)
++#define IN_SEL_FS_SFT 26
++#define IN_SEL_FS_MASK GENMASK(30, 26)
++
++/* ETDM_IN5_CON4 */
++#define IN_RELATCH(x) ((x) << 20)
++#define IN_RELATCH_SFT 20
++#define IN_RELATCH_MASK GENMASK(24, 20)
++#define IN_CLK_INV BIT(18)
++#define IN_CLK_INV_MASK BIT(18)
++
++/* ETDM_IN5_CON0 & ETDM_OUT5_CON0 */
++#define RELATCH_SRC_MASK GENMASK(30, 28)
++#define ETDM_CH_NUM_MASK GENMASK(27, 23)
++#define ETDM_WRD_LEN_MASK GENMASK(20, 16)
++#define ETDM_BIT_LEN_MASK GENMASK(15, 11)
++#define ETDM_FMT_MASK GENMASK(8, 6)
++#define ETDM_SYNC BIT(1)
++#define ETDM_SYNC_MASK BIT(1)
++#define ETDM_EN BIT(0)
++#define ETDM_EN_MASK BIT(0)
++
++/* ETDM_OUT5_CON4 */
++#define OUT_RELATCH(x) ((x) << 24)
++#define OUT_RELATCH_SFT 24
++#define OUT_RELATCH_MASK GENMASK(28, 24)
++#define OUT_CLK_SRC(x) ((x) << 6)
++#define OUT_CLK_SRC_SFT 6
++#define OUT_CLK_SRC_MASK GENMASK(8, 6)
++#define OUT_SEL_FS(x) (x)
++#define OUT_SEL_FS_SFT 0
++#define OUT_SEL_FS_MASK GENMASK(4, 0)
++
++/* ETDM_OUT5_CON5 */
++#define ETDM_CLK_DIV BIT(12)
++#define ETDM_CLK_DIV_MASK BIT(12)
++#define OUT_CLK_INV BIT(9)
++#define OUT_CLK_INV_MASK BIT(9)
++
++/* ETDM_4_7_COWORK_CON0 */
++#define OUT_SEL(x) ((x) << 12)
++#define OUT_SEL_SFT 12
++#define OUT_SEL_MASK GENMASK(15, 12)
++#endif
--- /dev/null
+From 948a288897015fb3ee63b3f720b396b590c17fd7 Mon Sep 17 00:00:00 2001
+From: Maso Huang <maso.huang@mediatek.com>
+Date: Thu, 17 Aug 2023 18:13:34 +0800
+Subject: [PATCH 2/9] ASoC: mediatek: mt7986: support etdm in platform driver
+
+Add mt7986 etdm dai driver support.
+
+Signed-off-by: Maso Huang <maso.huang@mediatek.com>
+Reviewed-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
+Link: https://lore.kernel.org/r/20230817101338.18782-3-maso.huang@mediatek.com
+Signed-off-by: Mark Brown <broonie@kernel.org>
+---
+ sound/soc/mediatek/mt7986/mt7986-dai-etdm.c | 411 ++++++++++++++++++++
+ 1 file changed, 411 insertions(+)
+ create mode 100644 sound/soc/mediatek/mt7986/mt7986-dai-etdm.c
+
+--- /dev/null
++++ b/sound/soc/mediatek/mt7986/mt7986-dai-etdm.c
+@@ -0,0 +1,411 @@
++// SPDX-License-Identifier: GPL-2.0
++/*
++ * MediaTek ALSA SoC Audio DAI eTDM Control
++ *
++ * Copyright (c) 2023 MediaTek Inc.
++ * Authors: Vic Wu <vic.wu@mediatek.com>
++ * Maso Huang <maso.huang@mediatek.com>
++ */
++
++#include <linux/bitfield.h>
++#include <linux/bitops.h>
++#include <linux/regmap.h>
++#include <sound/pcm_params.h>
++#include "mt7986-afe-common.h"
++#include "mt7986-reg.h"
++
++#define HOPPING_CLK 0
++#define APLL_CLK 1
++#define MTK_DAI_ETDM_FORMAT_I2S 0
++#define MTK_DAI_ETDM_FORMAT_DSPA 4
++#define MTK_DAI_ETDM_FORMAT_DSPB 5
++
++enum {
++ MTK_ETDM_RATE_8K = 0,
++ MTK_ETDM_RATE_12K = 1,
++ MTK_ETDM_RATE_16K = 2,
++ MTK_ETDM_RATE_24K = 3,
++ MTK_ETDM_RATE_32K = 4,
++ MTK_ETDM_RATE_48K = 5,
++ MTK_ETDM_RATE_96K = 7,
++ MTK_ETDM_RATE_192K = 9,
++ MTK_ETDM_RATE_11K = 16,
++ MTK_ETDM_RATE_22K = 17,
++ MTK_ETDM_RATE_44K = 18,
++ MTK_ETDM_RATE_88K = 19,
++ MTK_ETDM_RATE_176K = 20,
++};
++
++struct mtk_dai_etdm_priv {
++ bool bck_inv;
++ bool lrck_inv;
++ bool slave_mode;
++ unsigned int format;
++};
++
++static unsigned int mt7986_etdm_rate_transform(struct device *dev, unsigned int rate)
++{
++ switch (rate) {
++ case 8000:
++ return MTK_ETDM_RATE_8K;
++ case 11025:
++ return MTK_ETDM_RATE_11K;
++ case 12000:
++ return MTK_ETDM_RATE_12K;
++ case 16000:
++ return MTK_ETDM_RATE_16K;
++ case 22050:
++ return MTK_ETDM_RATE_22K;
++ case 24000:
++ return MTK_ETDM_RATE_24K;
++ case 32000:
++ return MTK_ETDM_RATE_32K;
++ case 44100:
++ return MTK_ETDM_RATE_44K;
++ case 48000:
++ return MTK_ETDM_RATE_48K;
++ case 88200:
++ return MTK_ETDM_RATE_88K;
++ case 96000:
++ return MTK_ETDM_RATE_96K;
++ case 176400:
++ return MTK_ETDM_RATE_176K;
++ case 192000:
++ return MTK_ETDM_RATE_192K;
++ default:
++ dev_warn(dev, "%s(), rate %u invalid, using %d!!!\n",
++ __func__, rate, MTK_ETDM_RATE_48K);
++ return MTK_ETDM_RATE_48K;
++ }
++}
++
++static int get_etdm_wlen(unsigned int bitwidth)
++{
++ return bitwidth <= 16 ? 16 : 32;
++}
++
++/* dai component */
++/* interconnection */
++
++static const struct snd_kcontrol_new o124_mix[] = {
++ SOC_DAPM_SINGLE_AUTODISABLE("I032_Switch", AFE_CONN124_1, 0, 1, 0),
++};
++
++static const struct snd_kcontrol_new o125_mix[] = {
++ SOC_DAPM_SINGLE_AUTODISABLE("I033_Switch", AFE_CONN125_1, 1, 1, 0),
++};
++
++static const struct snd_soc_dapm_widget mtk_dai_etdm_widgets[] = {
++
++ /* DL */
++ SND_SOC_DAPM_MIXER("I150", SND_SOC_NOPM, 0, 0, NULL, 0),
++ SND_SOC_DAPM_MIXER("I151", SND_SOC_NOPM, 0, 0, NULL, 0),
++ /* UL */
++ SND_SOC_DAPM_MIXER("O124", SND_SOC_NOPM, 0, 0, o124_mix, ARRAY_SIZE(o124_mix)),
++ SND_SOC_DAPM_MIXER("O125", SND_SOC_NOPM, 0, 0, o125_mix, ARRAY_SIZE(o125_mix)),
++};
++
++static const struct snd_soc_dapm_route mtk_dai_etdm_routes[] = {
++ {"I150", NULL, "ETDM Capture"},
++ {"I151", NULL, "ETDM Capture"},
++ {"ETDM Playback", NULL, "O124"},
++ {"ETDM Playback", NULL, "O125"},
++ {"O124", "I032_Switch", "I032"},
++ {"O125", "I033_Switch", "I033"},
++};
++
++/* dai ops */
++static int mtk_dai_etdm_startup(struct snd_pcm_substream *substream,
++ struct snd_soc_dai *dai)
++{
++ struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
++ struct mt7986_afe_private *afe_priv = afe->platform_priv;
++ int ret;
++
++ ret = clk_bulk_prepare_enable(afe_priv->num_clks, afe_priv->clks);
++ if (ret)
++ return dev_err_probe(afe->dev, ret, "Failed to enable clocks\n");
++
++ regmap_update_bits(afe->regmap, AUDIO_TOP_CON2, CLK_OUT5_PDN_MASK, 0);
++ regmap_update_bits(afe->regmap, AUDIO_TOP_CON2, CLK_IN5_PDN_MASK, 0);
++
++ return 0;
++}
++
++static void mtk_dai_etdm_shutdown(struct snd_pcm_substream *substream,
++ struct snd_soc_dai *dai)
++{
++ struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
++ struct mt7986_afe_private *afe_priv = afe->platform_priv;
++
++ regmap_update_bits(afe->regmap, AUDIO_TOP_CON2, CLK_OUT5_PDN_MASK,
++ CLK_OUT5_PDN);
++ regmap_update_bits(afe->regmap, AUDIO_TOP_CON2, CLK_IN5_PDN_MASK,
++ CLK_IN5_PDN);
++
++ clk_bulk_disable_unprepare(afe_priv->num_clks, afe_priv->clks);
++}
++
++static unsigned int get_etdm_ch_fixup(unsigned int channels)
++{
++ if (channels > 16)
++ return 24;
++ else if (channels > 8)
++ return 16;
++ else if (channels > 4)
++ return 8;
++ else if (channels > 2)
++ return 4;
++ else
++ return 2;
++}
++
++static int mtk_dai_etdm_config(struct mtk_base_afe *afe,
++ struct snd_pcm_hw_params *params,
++ struct snd_soc_dai *dai,
++ int stream)
++{
++ struct mt7986_afe_private *afe_priv = afe->platform_priv;
++ struct mtk_dai_etdm_priv *etdm_data = afe_priv->dai_priv[dai->id];
++ unsigned int rate = params_rate(params);
++ unsigned int etdm_rate = mt7986_etdm_rate_transform(afe->dev, rate);
++ unsigned int afe_rate = mt7986_afe_rate_transform(afe->dev, rate);
++ unsigned int channels = params_channels(params);
++ unsigned int bit_width = params_width(params);
++ unsigned int wlen = get_etdm_wlen(bit_width);
++ unsigned int val = 0;
++ unsigned int mask = 0;
++
++ dev_dbg(afe->dev, "%s(), stream %d, rate %u, bitwidth %u\n",
++ __func__, stream, rate, bit_width);
++
++ /* CON0 */
++ mask |= ETDM_BIT_LEN_MASK;
++ val |= FIELD_PREP(ETDM_BIT_LEN_MASK, bit_width - 1);
++ mask |= ETDM_WRD_LEN_MASK;
++ val |= FIELD_PREP(ETDM_WRD_LEN_MASK, wlen - 1);
++ mask |= ETDM_FMT_MASK;
++ val |= FIELD_PREP(ETDM_FMT_MASK, etdm_data->format);
++ mask |= ETDM_CH_NUM_MASK;
++ val |= FIELD_PREP(ETDM_CH_NUM_MASK, get_etdm_ch_fixup(channels) - 1);
++ mask |= RELATCH_SRC_MASK;
++ val |= FIELD_PREP(RELATCH_SRC_MASK, APLL_CLK);
++
++ switch (stream) {
++ case SNDRV_PCM_STREAM_PLAYBACK:
++ /* set ETDM_OUT5_CON0 */
++ regmap_update_bits(afe->regmap, ETDM_OUT5_CON0, mask, val);
++
++ /* set ETDM_OUT5_CON4 */
++ regmap_update_bits(afe->regmap, ETDM_OUT5_CON4,
++ OUT_RELATCH_MASK, OUT_RELATCH(afe_rate));
++ regmap_update_bits(afe->regmap, ETDM_OUT5_CON4,
++ OUT_CLK_SRC_MASK, OUT_CLK_SRC(APLL_CLK));
++ regmap_update_bits(afe->regmap, ETDM_OUT5_CON4,
++ OUT_SEL_FS_MASK, OUT_SEL_FS(etdm_rate));
++
++ /* set ETDM_OUT5_CON5 */
++ regmap_update_bits(afe->regmap, ETDM_OUT5_CON5,
++ ETDM_CLK_DIV_MASK, ETDM_CLK_DIV);
++ break;
++ case SNDRV_PCM_STREAM_CAPTURE:
++ /* set ETDM_IN5_CON0 */
++ regmap_update_bits(afe->regmap, ETDM_IN5_CON0, mask, val);
++ regmap_update_bits(afe->regmap, ETDM_IN5_CON0,
++ ETDM_SYNC_MASK, ETDM_SYNC);
++
++ /* set ETDM_IN5_CON2 */
++ regmap_update_bits(afe->regmap, ETDM_IN5_CON2,
++ IN_CLK_SRC_MASK, IN_CLK_SRC(APLL_CLK));
++
++ /* set ETDM_IN5_CON3 */
++ regmap_update_bits(afe->regmap, ETDM_IN5_CON3,
++ IN_SEL_FS_MASK, IN_SEL_FS(etdm_rate));
++
++ /* set ETDM_IN5_CON4 */
++ regmap_update_bits(afe->regmap, ETDM_IN5_CON4,
++ IN_RELATCH_MASK, IN_RELATCH(afe_rate));
++ break;
++ default:
++ break;
++ }
++
++ return 0;
++}
++
++static int mtk_dai_etdm_hw_params(struct snd_pcm_substream *substream,
++ struct snd_pcm_hw_params *params,
++ struct snd_soc_dai *dai)
++{
++ struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
++
++ mtk_dai_etdm_config(afe, params, dai, SNDRV_PCM_STREAM_PLAYBACK);
++ mtk_dai_etdm_config(afe, params, dai, SNDRV_PCM_STREAM_CAPTURE);
++
++ return 0;
++}
++
++static int mtk_dai_etdm_trigger(struct snd_pcm_substream *substream, int cmd,
++ struct snd_soc_dai *dai)
++{
++ struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
++
++ dev_dbg(afe->dev, "%s(), cmd %d, dai id %d\n", __func__, cmd, dai->id);
++ switch (cmd) {
++ case SNDRV_PCM_TRIGGER_START:
++ case SNDRV_PCM_TRIGGER_RESUME:
++ regmap_update_bits(afe->regmap, ETDM_IN5_CON0, ETDM_EN_MASK,
++ ETDM_EN);
++ regmap_update_bits(afe->regmap, ETDM_OUT5_CON0, ETDM_EN_MASK,
++ ETDM_EN);
++ break;
++ case SNDRV_PCM_TRIGGER_STOP:
++ case SNDRV_PCM_TRIGGER_SUSPEND:
++ regmap_update_bits(afe->regmap, ETDM_IN5_CON0, ETDM_EN_MASK,
++ 0);
++ regmap_update_bits(afe->regmap, ETDM_OUT5_CON0, ETDM_EN_MASK,
++ 0);
++ break;
++ default:
++ break;
++ }
++
++ return 0;
++}
++
++static int mtk_dai_etdm_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
++{
++ struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
++ struct mt7986_afe_private *afe_priv = afe->platform_priv;
++ struct mtk_dai_etdm_priv *etdm_data;
++ void *priv_data;
++
++ switch (dai->id) {
++ case MT7986_DAI_ETDM:
++ break;
++ default:
++ dev_warn(afe->dev, "%s(), id %d not support\n",
++ __func__, dai->id);
++ return -EINVAL;
++ }
++
++ priv_data = devm_kzalloc(afe->dev, sizeof(struct mtk_dai_etdm_priv),
++ GFP_KERNEL);
++ if (!priv_data)
++ return -ENOMEM;
++
++ afe_priv->dai_priv[dai->id] = priv_data;
++ etdm_data = afe_priv->dai_priv[dai->id];
++
++ switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
++ case SND_SOC_DAIFMT_I2S:
++ etdm_data->format = MTK_DAI_ETDM_FORMAT_I2S;
++ break;
++ case SND_SOC_DAIFMT_DSP_A:
++ etdm_data->format = MTK_DAI_ETDM_FORMAT_DSPA;
++ break;
++ case SND_SOC_DAIFMT_DSP_B:
++ etdm_data->format = MTK_DAI_ETDM_FORMAT_DSPB;
++ break;
++ default:
++ return -EINVAL;
++ }
++
++ switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
++ case SND_SOC_DAIFMT_NB_NF:
++ etdm_data->bck_inv = false;
++ etdm_data->lrck_inv = false;
++ break;
++ case SND_SOC_DAIFMT_NB_IF:
++ etdm_data->bck_inv = false;
++ etdm_data->lrck_inv = true;
++ break;
++ case SND_SOC_DAIFMT_IB_NF:
++ etdm_data->bck_inv = true;
++ etdm_data->lrck_inv = false;
++ break;
++ case SND_SOC_DAIFMT_IB_IF:
++ etdm_data->bck_inv = true;
++ etdm_data->lrck_inv = true;
++ break;
++ default:
++ return -EINVAL;
++ }
++
++ switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
++ case SND_SOC_DAIFMT_CBM_CFM:
++ etdm_data->slave_mode = true;
++ break;
++ case SND_SOC_DAIFMT_CBS_CFS:
++ etdm_data->slave_mode = false;
++ break;
++ default:
++ return -EINVAL;
++ }
++
++ return 0;
++}
++
++static const struct snd_soc_dai_ops mtk_dai_etdm_ops = {
++ .startup = mtk_dai_etdm_startup,
++ .shutdown = mtk_dai_etdm_shutdown,
++ .hw_params = mtk_dai_etdm_hw_params,
++ .trigger = mtk_dai_etdm_trigger,
++ .set_fmt = mtk_dai_etdm_set_fmt,
++};
++
++/* dai driver */
++#define MTK_ETDM_RATES (SNDRV_PCM_RATE_8000_48000 |\
++ SNDRV_PCM_RATE_88200 |\
++ SNDRV_PCM_RATE_96000 |\
++ SNDRV_PCM_RATE_176400 |\
++ SNDRV_PCM_RATE_192000)
++
++#define MTK_ETDM_FORMATS (SNDRV_PCM_FMTBIT_S16_LE |\
++ SNDRV_PCM_FMTBIT_S24_LE |\
++ SNDRV_PCM_FMTBIT_S32_LE)
++
++static struct snd_soc_dai_driver mtk_dai_etdm_driver[] = {
++ {
++ .name = "ETDM",
++ .id = MT7986_DAI_ETDM,
++ .capture = {
++ .stream_name = "ETDM Capture",
++ .channels_min = 1,
++ .channels_max = 2,
++ .rates = MTK_ETDM_RATES,
++ .formats = MTK_ETDM_FORMATS,
++ },
++ .playback = {
++ .stream_name = "ETDM Playback",
++ .channels_min = 1,
++ .channels_max = 2,
++ .rates = MTK_ETDM_RATES,
++ .formats = MTK_ETDM_FORMATS,
++ },
++ .ops = &mtk_dai_etdm_ops,
++ .symmetric_rate = 1,
++ .symmetric_sample_bits = 1,
++ },
++};
++
++int mt7986_dai_etdm_register(struct mtk_base_afe *afe)
++{
++ struct mtk_base_afe_dai *dai;
++
++ dai = devm_kzalloc(afe->dev, sizeof(*dai), GFP_KERNEL);
++ if (!dai)
++ return -ENOMEM;
++
++ list_add(&dai->list, &afe->sub_dais);
++
++ dai->dai_drivers = mtk_dai_etdm_driver;
++ dai->num_dai_drivers = ARRAY_SIZE(mtk_dai_etdm_driver);
++
++ dai->dapm_widgets = mtk_dai_etdm_widgets;
++ dai->num_dapm_widgets = ARRAY_SIZE(mtk_dai_etdm_widgets);
++ dai->dapm_routes = mtk_dai_etdm_routes;
++ dai->num_dapm_routes = ARRAY_SIZE(mtk_dai_etdm_routes);
++
++ return 0;
++}
--- /dev/null
+From fc7776dee86bc07d22820a904760a95f49a2f12e Mon Sep 17 00:00:00 2001
+From: Maso Huang <maso.huang@mediatek.com>
+Date: Thu, 17 Aug 2023 18:13:35 +0800
+Subject: [PATCH 3/9] ASoC: mediatek: mt7986: add platform driver
+
+Add mt7986 platform driver.
+
+Signed-off-by: Maso Huang <maso.huang@mediatek.com>
+Reviewed-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
+Link: https://lore.kernel.org/r/20230817101338.18782-4-maso.huang@mediatek.com
+Signed-off-by: Mark Brown <broonie@kernel.org>
+---
+ sound/soc/mediatek/Kconfig | 10 +
+ sound/soc/mediatek/Makefile | 1 +
+ sound/soc/mediatek/mt7986/Makefile | 8 +
+ sound/soc/mediatek/mt7986/mt7986-afe-pcm.c | 622 +++++++++++++++++++++
+ 4 files changed, 641 insertions(+)
+ create mode 100644 sound/soc/mediatek/mt7986/Makefile
+ create mode 100644 sound/soc/mediatek/mt7986/mt7986-afe-pcm.c
+
+--- a/sound/soc/mediatek/Kconfig
++++ b/sound/soc/mediatek/Kconfig
+@@ -54,6 +54,16 @@ config SND_SOC_MT6797_MT6351
+ Select Y if you have such device.
+ If unsure select "N".
+
++config SND_SOC_MT7986
++ tristate "ASoC support for Mediatek MT7986 chip"
++ depends on ARCH_MEDIATEK
++ select SND_SOC_MEDIATEK
++ help
++ This adds ASoC platform driver support for MediaTek MT7986 chip
++ that can be used with other codecs.
++ Select Y if you have such device.
++ If unsure select "N".
++
+ config SND_SOC_MT8173
+ tristate "ASoC support for Mediatek MT8173 chip"
+ depends on ARCH_MEDIATEK
+--- a/sound/soc/mediatek/Makefile
++++ b/sound/soc/mediatek/Makefile
+@@ -2,6 +2,7 @@
+ obj-$(CONFIG_SND_SOC_MEDIATEK) += common/
+ obj-$(CONFIG_SND_SOC_MT2701) += mt2701/
+ obj-$(CONFIG_SND_SOC_MT6797) += mt6797/
++obj-$(CONFIG_SND_SOC_MT7986) += mt7986/
+ obj-$(CONFIG_SND_SOC_MT8173) += mt8173/
+ obj-$(CONFIG_SND_SOC_MT8183) += mt8183/
+ obj-$(CONFIG_SND_SOC_MT8186) += mt8186/
+--- /dev/null
++++ b/sound/soc/mediatek/mt7986/Makefile
+@@ -0,0 +1,8 @@
++# SPDX-License-Identifier: GPL-2.0
++
++# platform driver
++snd-soc-mt7986-afe-objs := \
++ mt7986-afe-pcm.o \
++ mt7986-dai-etdm.o
++
++obj-$(CONFIG_SND_SOC_MT7986) += snd-soc-mt7986-afe.o
+--- /dev/null
++++ b/sound/soc/mediatek/mt7986/mt7986-afe-pcm.c
+@@ -0,0 +1,622 @@
++// SPDX-License-Identifier: GPL-2.0
++/*
++ * MediaTek ALSA SoC AFE platform driver for MT7986
++ *
++ * Copyright (c) 2023 MediaTek Inc.
++ * Authors: Vic Wu <vic.wu@mediatek.com>
++ * Maso Huang <maso.huang@mediatek.com>
++ */
++
++#include <linux/clk.h>
++#include <linux/delay.h>
++#include <linux/module.h>
++#include <linux/of.h>
++#include <linux/of_address.h>
++#include <linux/pm_runtime.h>
++
++#include "mt7986-afe-common.h"
++#include "mt7986-reg.h"
++#include "../common/mtk-afe-platform-driver.h"
++#include "../common/mtk-afe-fe-dai.h"
++
++enum {
++ MTK_AFE_RATE_8K = 0,
++ MTK_AFE_RATE_11K = 1,
++ MTK_AFE_RATE_12K = 2,
++ MTK_AFE_RATE_16K = 4,
++ MTK_AFE_RATE_22K = 5,
++ MTK_AFE_RATE_24K = 6,
++ MTK_AFE_RATE_32K = 8,
++ MTK_AFE_RATE_44K = 9,
++ MTK_AFE_RATE_48K = 10,
++ MTK_AFE_RATE_88K = 13,
++ MTK_AFE_RATE_96K = 14,
++ MTK_AFE_RATE_176K = 17,
++ MTK_AFE_RATE_192K = 18,
++};
++
++enum {
++ CLK_INFRA_AUD_BUS_CK = 0,
++ CLK_INFRA_AUD_26M_CK,
++ CLK_INFRA_AUD_L_CK,
++ CLK_INFRA_AUD_AUD_CK,
++ CLK_INFRA_AUD_EG2_CK,
++ CLK_NUM
++};
++
++static const char *aud_clks[CLK_NUM] = {
++ [CLK_INFRA_AUD_BUS_CK] = "aud_bus_ck",
++ [CLK_INFRA_AUD_26M_CK] = "aud_26m_ck",
++ [CLK_INFRA_AUD_L_CK] = "aud_l_ck",
++ [CLK_INFRA_AUD_AUD_CK] = "aud_aud_ck",
++ [CLK_INFRA_AUD_EG2_CK] = "aud_eg2_ck",
++};
++
++unsigned int mt7986_afe_rate_transform(struct device *dev, unsigned int rate)
++{
++ switch (rate) {
++ case 8000:
++ return MTK_AFE_RATE_8K;
++ case 11025:
++ return MTK_AFE_RATE_11K;
++ case 12000:
++ return MTK_AFE_RATE_12K;
++ case 16000:
++ return MTK_AFE_RATE_16K;
++ case 22050:
++ return MTK_AFE_RATE_22K;
++ case 24000:
++ return MTK_AFE_RATE_24K;
++ case 32000:
++ return MTK_AFE_RATE_32K;
++ case 44100:
++ return MTK_AFE_RATE_44K;
++ case 48000:
++ return MTK_AFE_RATE_48K;
++ case 88200:
++ return MTK_AFE_RATE_88K;
++ case 96000:
++ return MTK_AFE_RATE_96K;
++ case 176400:
++ return MTK_AFE_RATE_176K;
++ case 192000:
++ return MTK_AFE_RATE_192K;
++ default:
++ dev_warn(dev, "%s(), rate %u invalid, using %d!!!\n",
++ __func__, rate, MTK_AFE_RATE_48K);
++ return MTK_AFE_RATE_48K;
++ }
++}
++
++static const struct snd_pcm_hardware mt7986_afe_hardware = {
++ .info = SNDRV_PCM_INFO_MMAP |
++ SNDRV_PCM_INFO_INTERLEAVED |
++ SNDRV_PCM_INFO_MMAP_VALID,
++ .formats = SNDRV_PCM_FMTBIT_S16_LE |
++ SNDRV_PCM_FMTBIT_S24_LE |
++ SNDRV_PCM_FMTBIT_S32_LE,
++ .period_bytes_min = 256,
++ .period_bytes_max = 4 * 48 * 1024,
++ .periods_min = 2,
++ .periods_max = 256,
++ .buffer_bytes_max = 8 * 48 * 1024,
++ .fifo_size = 0,
++};
++
++static int mt7986_memif_fs(struct snd_pcm_substream *substream,
++ unsigned int rate)
++{
++ struct snd_soc_pcm_runtime *rtd = substream->private_data;
++ struct snd_soc_component *component = snd_soc_rtdcom_lookup(rtd, AFE_PCM_NAME);
++ struct mtk_base_afe *afe = snd_soc_component_get_drvdata(component);
++
++ return mt7986_afe_rate_transform(afe->dev, rate);
++}
++
++static int mt7986_irq_fs(struct snd_pcm_substream *substream,
++ unsigned int rate)
++{
++ struct snd_soc_pcm_runtime *rtd = substream->private_data;
++ struct snd_soc_component *component = snd_soc_rtdcom_lookup(rtd, AFE_PCM_NAME);
++ struct mtk_base_afe *afe = snd_soc_component_get_drvdata(component);
++
++ return mt7986_afe_rate_transform(afe->dev, rate);
++}
++
++#define MTK_PCM_RATES (SNDRV_PCM_RATE_8000_48000 |\
++ SNDRV_PCM_RATE_88200 |\
++ SNDRV_PCM_RATE_96000 |\
++ SNDRV_PCM_RATE_176400 |\
++ SNDRV_PCM_RATE_192000)
++
++#define MTK_PCM_FORMATS (SNDRV_PCM_FMTBIT_S16_LE |\
++ SNDRV_PCM_FMTBIT_S24_LE |\
++ SNDRV_PCM_FMTBIT_S32_LE)
++
++static struct snd_soc_dai_driver mt7986_memif_dai_driver[] = {
++ /* FE DAIs: memory intefaces to CPU */
++ {
++ .name = "DL1",
++ .id = MT7986_MEMIF_DL1,
++ .playback = {
++ .stream_name = "DL1",
++ .channels_min = 1,
++ .channels_max = 2,
++ .rates = MTK_PCM_RATES,
++ .formats = MTK_PCM_FORMATS,
++ },
++ .ops = &mtk_afe_fe_ops,
++ },
++ {
++ .name = "UL1",
++ .id = MT7986_MEMIF_VUL12,
++ .capture = {
++ .stream_name = "UL1",
++ .channels_min = 1,
++ .channels_max = 2,
++ .rates = MTK_PCM_RATES,
++ .formats = MTK_PCM_FORMATS,
++ },
++ .ops = &mtk_afe_fe_ops,
++ },
++};
++
++static const struct snd_kcontrol_new o018_mix[] = {
++ SOC_DAPM_SINGLE_AUTODISABLE("I150_Switch", AFE_CONN018_4, 22, 1, 0),
++};
++
++static const struct snd_kcontrol_new o019_mix[] = {
++ SOC_DAPM_SINGLE_AUTODISABLE("I151_Switch", AFE_CONN019_4, 23, 1, 0),
++};
++
++static const struct snd_soc_dapm_widget mt7986_memif_widgets[] = {
++ /* DL */
++ SND_SOC_DAPM_MIXER("I032", SND_SOC_NOPM, 0, 0, NULL, 0),
++ SND_SOC_DAPM_MIXER("I033", SND_SOC_NOPM, 0, 0, NULL, 0),
++
++ /* UL */
++ SND_SOC_DAPM_MIXER("O018", SND_SOC_NOPM, 0, 0,
++ o018_mix, ARRAY_SIZE(o018_mix)),
++ SND_SOC_DAPM_MIXER("O019", SND_SOC_NOPM, 0, 0,
++ o019_mix, ARRAY_SIZE(o019_mix)),
++};
++
++static const struct snd_soc_dapm_route mt7986_memif_routes[] = {
++ {"I032", NULL, "DL1"},
++ {"I033", NULL, "DL1"},
++ {"UL1", NULL, "O018"},
++ {"UL1", NULL, "O019"},
++ {"O018", "I150_Switch", "I150"},
++ {"O019", "I151_Switch", "I151"},
++};
++
++static const struct snd_soc_component_driver mt7986_afe_pcm_dai_component = {
++ .name = "mt7986-afe-pcm-dai",
++};
++
++static const struct mtk_base_memif_data memif_data[MT7986_MEMIF_NUM] = {
++ [MT7986_MEMIF_DL1] = {
++ .name = "DL1",
++ .id = MT7986_MEMIF_DL1,
++ .reg_ofs_base = AFE_DL0_BASE,
++ .reg_ofs_cur = AFE_DL0_CUR,
++ .reg_ofs_end = AFE_DL0_END,
++ .reg_ofs_base_msb = AFE_DL0_BASE_MSB,
++ .reg_ofs_cur_msb = AFE_DL0_CUR_MSB,
++ .reg_ofs_end_msb = AFE_DL0_END_MSB,
++ .fs_reg = AFE_DL0_CON0,
++ .fs_shift = DL0_MODE_SFT,
++ .fs_maskbit = DL0_MODE_MASK,
++ .mono_reg = AFE_DL0_CON0,
++ .mono_shift = DL0_MONO_SFT,
++ .enable_reg = AFE_DL0_CON0,
++ .enable_shift = DL0_ON_SFT,
++ .hd_reg = AFE_DL0_CON0,
++ .hd_shift = DL0_HD_MODE_SFT,
++ .hd_align_reg = AFE_DL0_CON0,
++ .hd_align_mshift = DL0_HALIGN_SFT,
++ .pbuf_reg = AFE_DL0_CON0,
++ .pbuf_shift = DL0_PBUF_SIZE_SFT,
++ .minlen_reg = AFE_DL0_CON0,
++ .minlen_shift = DL0_MINLEN_SFT,
++ },
++ [MT7986_MEMIF_VUL12] = {
++ .name = "VUL12",
++ .id = MT7986_MEMIF_VUL12,
++ .reg_ofs_base = AFE_VUL0_BASE,
++ .reg_ofs_cur = AFE_VUL0_CUR,
++ .reg_ofs_end = AFE_VUL0_END,
++ .reg_ofs_base_msb = AFE_VUL0_BASE_MSB,
++ .reg_ofs_cur_msb = AFE_VUL0_CUR_MSB,
++ .reg_ofs_end_msb = AFE_VUL0_END_MSB,
++ .fs_reg = AFE_VUL0_CON0,
++ .fs_shift = VUL0_MODE_SFT,
++ .fs_maskbit = VUL0_MODE_MASK,
++ .mono_reg = AFE_VUL0_CON0,
++ .mono_shift = VUL0_MONO_SFT,
++ .enable_reg = AFE_VUL0_CON0,
++ .enable_shift = VUL0_ON_SFT,
++ .hd_reg = AFE_VUL0_CON0,
++ .hd_shift = VUL0_HD_MODE_SFT,
++ .hd_align_reg = AFE_VUL0_CON0,
++ .hd_align_mshift = VUL0_HALIGN_SFT,
++ },
++};
++
++static const struct mtk_base_irq_data irq_data[MT7986_IRQ_NUM] = {
++ [MT7986_IRQ_0] = {
++ .id = MT7986_IRQ_0,
++ .irq_cnt_reg = AFE_IRQ0_MCU_CFG1,
++ .irq_cnt_shift = AFE_IRQ_CNT_SHIFT,
++ .irq_cnt_maskbit = AFE_IRQ_CNT_MASK,
++ .irq_fs_reg = AFE_IRQ0_MCU_CFG0,
++ .irq_fs_shift = IRQ_MCU_MODE_SFT,
++ .irq_fs_maskbit = IRQ_MCU_MODE_MASK,
++ .irq_en_reg = AFE_IRQ0_MCU_CFG0,
++ .irq_en_shift = IRQ_MCU_ON_SFT,
++ .irq_clr_reg = AFE_IRQ_MCU_CLR,
++ .irq_clr_shift = IRQ0_MCU_CLR_SFT,
++ },
++ [MT7986_IRQ_1] = {
++ .id = MT7986_IRQ_1,
++ .irq_cnt_reg = AFE_IRQ1_MCU_CFG1,
++ .irq_cnt_shift = AFE_IRQ_CNT_SHIFT,
++ .irq_cnt_maskbit = AFE_IRQ_CNT_MASK,
++ .irq_fs_reg = AFE_IRQ1_MCU_CFG0,
++ .irq_fs_shift = IRQ_MCU_MODE_SFT,
++ .irq_fs_maskbit = IRQ_MCU_MODE_MASK,
++ .irq_en_reg = AFE_IRQ1_MCU_CFG0,
++ .irq_en_shift = IRQ_MCU_ON_SFT,
++ .irq_clr_reg = AFE_IRQ_MCU_CLR,
++ .irq_clr_shift = IRQ1_MCU_CLR_SFT,
++ },
++ [MT7986_IRQ_2] = {
++ .id = MT7986_IRQ_2,
++ .irq_cnt_reg = AFE_IRQ2_MCU_CFG1,
++ .irq_cnt_shift = AFE_IRQ_CNT_SHIFT,
++ .irq_cnt_maskbit = AFE_IRQ_CNT_MASK,
++ .irq_fs_reg = AFE_IRQ2_MCU_CFG0,
++ .irq_fs_shift = IRQ_MCU_MODE_SFT,
++ .irq_fs_maskbit = IRQ_MCU_MODE_MASK,
++ .irq_en_reg = AFE_IRQ2_MCU_CFG0,
++ .irq_en_shift = IRQ_MCU_ON_SFT,
++ .irq_clr_reg = AFE_IRQ_MCU_CLR,
++ .irq_clr_shift = IRQ2_MCU_CLR_SFT,
++ },
++};
++
++static bool mt7986_is_volatile_reg(struct device *dev, unsigned int reg)
++{
++ /*
++ * Those auto-gen regs are read-only, so put it as volatile because
++ * volatile registers cannot be cached, which means that they cannot
++ * be set when power is off
++ */
++
++ switch (reg) {
++ case AFE_DL0_CUR_MSB:
++ case AFE_DL0_CUR:
++ case AFE_DL0_RCH_MON:
++ case AFE_DL0_LCH_MON:
++ case AFE_VUL0_CUR_MSB:
++ case AFE_VUL0_CUR:
++ case AFE_IRQ_MCU_STATUS:
++ case AFE_MEMIF_RD_MON:
++ case AFE_MEMIF_WR_MON:
++ return true;
++ default:
++ return false;
++ };
++}
++
++static const struct regmap_config mt7986_afe_regmap_config = {
++ .reg_bits = 32,
++ .reg_stride = 4,
++ .val_bits = 32,
++ .volatile_reg = mt7986_is_volatile_reg,
++ .max_register = AFE_MAX_REGISTER,
++ .num_reg_defaults_raw = ((AFE_MAX_REGISTER / 4) + 1),
++};
++
++static int mt7986_init_clock(struct mtk_base_afe *afe)
++{
++ struct mt7986_afe_private *afe_priv = afe->platform_priv;
++ int ret, i;
++
++ afe_priv->clks = devm_kcalloc(afe->dev, CLK_NUM,
++ sizeof(*afe_priv->clks), GFP_KERNEL);
++ if (!afe_priv->clks)
++ return -ENOMEM;
++ afe_priv->num_clks = CLK_NUM;
++
++ for (i = 0; i < afe_priv->num_clks; i++)
++ afe_priv->clks[i].id = aud_clks[i];
++
++ ret = devm_clk_bulk_get(afe->dev, afe_priv->num_clks, afe_priv->clks);
++ if (ret)
++ return dev_err_probe(afe->dev, ret, "Failed to get clocks\n");
++
++ return 0;
++}
++
++static irqreturn_t mt7986_afe_irq_handler(int irq_id, void *dev)
++{
++ struct mtk_base_afe *afe = dev;
++ struct mtk_base_afe_irq *irq;
++ u32 mcu_en, status, status_mcu;
++ int i, ret;
++ irqreturn_t irq_ret = IRQ_HANDLED;
++
++ /* get irq that is sent to MCU */
++ regmap_read(afe->regmap, AFE_IRQ_MCU_EN, &mcu_en);
++
++ ret = regmap_read(afe->regmap, AFE_IRQ_MCU_STATUS, &status);
++ /* only care IRQ which is sent to MCU */
++ status_mcu = status & mcu_en & AFE_IRQ_STATUS_BITS;
++
++ if (ret || status_mcu == 0) {
++ dev_err(afe->dev, "%s(), irq status err, ret %d, status 0x%x, mcu_en 0x%x\n",
++ __func__, ret, status, mcu_en);
++
++ irq_ret = IRQ_NONE;
++ goto err_irq;
++ }
++
++ for (i = 0; i < MT7986_MEMIF_NUM; i++) {
++ struct mtk_base_afe_memif *memif = &afe->memif[i];
++
++ if (!memif->substream)
++ continue;
++
++ if (memif->irq_usage < 0)
++ continue;
++
++ irq = &afe->irqs[memif->irq_usage];
++
++ if (status_mcu & (1 << irq->irq_data->irq_en_shift))
++ snd_pcm_period_elapsed(memif->substream);
++ }
++
++err_irq:
++ /* clear irq */
++ regmap_write(afe->regmap, AFE_IRQ_MCU_CLR, status_mcu);
++
++ return irq_ret;
++}
++
++static int mt7986_afe_runtime_suspend(struct device *dev)
++{
++ struct mtk_base_afe *afe = dev_get_drvdata(dev);
++ struct mt7986_afe_private *afe_priv = afe->platform_priv;
++
++ if (!afe->regmap || afe_priv->pm_runtime_bypass_reg_ctl)
++ goto skip_regmap;
++
++ /* disable clk*/
++ regmap_update_bits(afe->regmap, AUDIO_TOP_CON4, 0x3fff, 0x3fff);
++ regmap_update_bits(afe->regmap, AUDIO_ENGEN_CON0, AUD_APLL2_EN_MASK, 0);
++ regmap_update_bits(afe->regmap, AUDIO_ENGEN_CON0, AUD_26M_EN_MASK, 0);
++
++ /* make sure all irq status are cleared, twice intended */
++ regmap_update_bits(afe->regmap, AFE_IRQ_MCU_CLR, 0xffff, 0xffff);
++
++skip_regmap:
++ clk_bulk_disable_unprepare(afe_priv->num_clks, afe_priv->clks);
++
++ return 0;
++}
++
++static int mt7986_afe_runtime_resume(struct device *dev)
++{
++ struct mtk_base_afe *afe = dev_get_drvdata(dev);
++ struct mt7986_afe_private *afe_priv = afe->platform_priv;
++ int ret;
++
++ ret = clk_bulk_prepare_enable(afe_priv->num_clks, afe_priv->clks);
++ if (ret)
++ return dev_err_probe(afe->dev, ret, "Failed to enable clocks\n");
++
++ if (!afe->regmap || afe_priv->pm_runtime_bypass_reg_ctl)
++ return 0;
++
++ /* enable clk*/
++ regmap_update_bits(afe->regmap, AUDIO_TOP_CON4, 0x3fff, 0);
++ regmap_update_bits(afe->regmap, AUDIO_ENGEN_CON0, AUD_APLL2_EN_MASK,
++ AUD_APLL2_EN);
++ regmap_update_bits(afe->regmap, AUDIO_ENGEN_CON0, AUD_26M_EN_MASK,
++ AUD_26M_EN);
++
++ return 0;
++}
++
++static int mt7986_afe_component_probe(struct snd_soc_component *component)
++{
++ return mtk_afe_add_sub_dai_control(component);
++}
++
++static const struct snd_soc_component_driver mt7986_afe_component = {
++ .name = AFE_PCM_NAME,
++ .probe = mt7986_afe_component_probe,
++ .pointer = mtk_afe_pcm_pointer,
++ .pcm_construct = mtk_afe_pcm_new,
++};
++
++static int mt7986_dai_memif_register(struct mtk_base_afe *afe)
++{
++ struct mtk_base_afe_dai *dai;
++
++ dai = devm_kzalloc(afe->dev, sizeof(*dai), GFP_KERNEL);
++ if (!dai)
++ return -ENOMEM;
++
++ list_add(&dai->list, &afe->sub_dais);
++
++ dai->dai_drivers = mt7986_memif_dai_driver;
++ dai->num_dai_drivers = ARRAY_SIZE(mt7986_memif_dai_driver);
++
++ dai->dapm_widgets = mt7986_memif_widgets;
++ dai->num_dapm_widgets = ARRAY_SIZE(mt7986_memif_widgets);
++ dai->dapm_routes = mt7986_memif_routes;
++ dai->num_dapm_routes = ARRAY_SIZE(mt7986_memif_routes);
++
++ return 0;
++}
++
++typedef int (*dai_register_cb)(struct mtk_base_afe *);
++static const dai_register_cb dai_register_cbs[] = {
++ mt7986_dai_etdm_register,
++ mt7986_dai_memif_register,
++};
++
++static int mt7986_afe_pcm_dev_probe(struct platform_device *pdev)
++{
++ struct mtk_base_afe *afe;
++ struct mt7986_afe_private *afe_priv;
++ struct device *dev;
++ int i, irq_id, ret;
++
++ afe = devm_kzalloc(&pdev->dev, sizeof(*afe), GFP_KERNEL);
++ if (!afe)
++ return -ENOMEM;
++ platform_set_drvdata(pdev, afe);
++
++ afe->platform_priv = devm_kzalloc(&pdev->dev, sizeof(*afe_priv),
++ GFP_KERNEL);
++ if (!afe->platform_priv)
++ return -ENOMEM;
++
++ afe_priv = afe->platform_priv;
++ afe->dev = &pdev->dev;
++ dev = afe->dev;
++
++ afe->base_addr = devm_platform_ioremap_resource(pdev, 0);
++ if (IS_ERR(afe->base_addr))
++ return PTR_ERR(afe->base_addr);
++
++ /* initial audio related clock */
++ ret = mt7986_init_clock(afe);
++ if (ret)
++ return dev_err_probe(dev, ret, "Cannot initialize clocks\n");
++
++ ret = devm_pm_runtime_enable(dev);
++ if (ret)
++ return ret;
++
++ /* enable clock for regcache get default value from hw */
++ afe_priv->pm_runtime_bypass_reg_ctl = true;
++ pm_runtime_get_sync(&pdev->dev);
++
++ afe->regmap = devm_regmap_init_mmio(&pdev->dev, afe->base_addr,
++ &mt7986_afe_regmap_config);
++
++ pm_runtime_put_sync(&pdev->dev);
++ if (IS_ERR(afe->regmap))
++ return PTR_ERR(afe->regmap);
++
++ afe_priv->pm_runtime_bypass_reg_ctl = false;
++
++ /* init memif */
++ afe->memif_size = MT7986_MEMIF_NUM;
++ afe->memif = devm_kcalloc(dev, afe->memif_size, sizeof(*afe->memif),
++ GFP_KERNEL);
++ if (!afe->memif)
++ return -ENOMEM;
++
++ for (i = 0; i < afe->memif_size; i++) {
++ afe->memif[i].data = &memif_data[i];
++ afe->memif[i].irq_usage = -1;
++ }
++
++ mutex_init(&afe->irq_alloc_lock);
++
++ /* irq initialize */
++ afe->irqs_size = MT7986_IRQ_NUM;
++ afe->irqs = devm_kcalloc(dev, afe->irqs_size, sizeof(*afe->irqs),
++ GFP_KERNEL);
++ if (!afe->irqs)
++ return -ENOMEM;
++
++ for (i = 0; i < afe->irqs_size; i++)
++ afe->irqs[i].irq_data = &irq_data[i];
++
++ /* request irq */
++ irq_id = platform_get_irq(pdev, 0);
++ if (irq_id < 0) {
++ ret = irq_id;
++ return dev_err_probe(dev, ret, "No irq found\n");
++ }
++ ret = devm_request_irq(dev, irq_id, mt7986_afe_irq_handler,
++ IRQF_TRIGGER_NONE, "asys-isr", (void *)afe);
++ if (ret)
++ return dev_err_probe(dev, ret, "Failed to request irq for asys-isr\n");
++
++ /* init sub_dais */
++ INIT_LIST_HEAD(&afe->sub_dais);
++
++ for (i = 0; i < ARRAY_SIZE(dai_register_cbs); i++) {
++ ret = dai_register_cbs[i](afe);
++ if (ret)
++ return dev_err_probe(dev, ret, "DAI register failed, i: %d\n", i);
++ }
++
++ /* init dai_driver and component_driver */
++ ret = mtk_afe_combine_sub_dai(afe);
++ if (ret)
++ return dev_err_probe(dev, ret, "mtk_afe_combine_sub_dai fail\n");
++
++ afe->mtk_afe_hardware = &mt7986_afe_hardware;
++ afe->memif_fs = mt7986_memif_fs;
++ afe->irq_fs = mt7986_irq_fs;
++
++ afe->runtime_resume = mt7986_afe_runtime_resume;
++ afe->runtime_suspend = mt7986_afe_runtime_suspend;
++
++ /* register component */
++ ret = devm_snd_soc_register_component(&pdev->dev,
++ &mt7986_afe_component,
++ NULL, 0);
++ if (ret)
++ return dev_err_probe(dev, ret, "Cannot register AFE component\n");
++
++ ret = devm_snd_soc_register_component(afe->dev,
++ &mt7986_afe_pcm_dai_component,
++ afe->dai_drivers,
++ afe->num_dai_drivers);
++ if (ret)
++ return dev_err_probe(dev, ret, "Cannot register PCM DAI component\n");
++
++ return 0;
++}
++
++static void mt7986_afe_pcm_dev_remove(struct platform_device *pdev)
++{
++ pm_runtime_disable(&pdev->dev);
++ if (!pm_runtime_status_suspended(&pdev->dev))
++ mt7986_afe_runtime_suspend(&pdev->dev);
++}
++
++static const struct of_device_id mt7986_afe_pcm_dt_match[] = {
++ { .compatible = "mediatek,mt7986-afe" },
++ { /* sentinel */ }
++};
++MODULE_DEVICE_TABLE(of, mt7986_afe_pcm_dt_match);
++
++static const struct dev_pm_ops mt7986_afe_pm_ops = {
++ SET_RUNTIME_PM_OPS(mt7986_afe_runtime_suspend,
++ mt7986_afe_runtime_resume, NULL)
++};
++
++static struct platform_driver mt7986_afe_pcm_driver = {
++ .driver = {
++ .name = "mt7986-audio",
++ .of_match_table = mt7986_afe_pcm_dt_match,
++ .pm = &mt7986_afe_pm_ops,
++ },
++ .probe = mt7986_afe_pcm_dev_probe,
++ .remove_new = mt7986_afe_pcm_dev_remove,
++};
++module_platform_driver(mt7986_afe_pcm_driver);
++
++MODULE_DESCRIPTION("MediaTek SoC AFE platform driver for ALSA MT7986");
++MODULE_AUTHOR("Vic Wu <vic.wu@mediatek.com>");
++MODULE_LICENSE("GPL");
--- /dev/null
+From ddf6abc1c78072f8ccad59166be95f0ca5af8ca4 Mon Sep 17 00:00:00 2001
+From: Maso Huang <maso.huang@mediatek.com>
+Date: Thu, 17 Aug 2023 18:13:36 +0800
+Subject: [PATCH 4/9] ASoC: mediatek: mt7986: add machine driver with wm8960
+
+Add support for mt7986 board with wm8960.
+
+Signed-off-by: Maso Huang <maso.huang@mediatek.com>
+Reviewed-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
+Link: https://lore.kernel.org/r/20230817101338.18782-5-maso.huang@mediatek.com
+Signed-off-by: Mark Brown <broonie@kernel.org>
+---
+ sound/soc/mediatek/Kconfig | 10 ++
+ sound/soc/mediatek/mt7986/Makefile | 1 +
+ sound/soc/mediatek/mt7986/mt7986-wm8960.c | 196 ++++++++++++++++++++++
+ 3 files changed, 207 insertions(+)
+ create mode 100644 sound/soc/mediatek/mt7986/mt7986-wm8960.c
+
+--- a/sound/soc/mediatek/Kconfig
++++ b/sound/soc/mediatek/Kconfig
+@@ -64,6 +64,16 @@ config SND_SOC_MT7986
+ Select Y if you have such device.
+ If unsure select "N".
+
++config SND_SOC_MT7986_WM8960
++ tristate "ASoc Audio driver for MT7986 with WM8960 codec"
++ depends on SND_SOC_MT7986 && I2C
++ select SND_SOC_WM8960
++ help
++ This adds support for ASoC machine driver for MediaTek MT7986
++ boards with the WM8960 codecs.
++ Select Y if you have such device.
++ If unsure select "N".
++
+ config SND_SOC_MT8173
+ tristate "ASoC support for Mediatek MT8173 chip"
+ depends on ARCH_MEDIATEK
+--- a/sound/soc/mediatek/mt7986/Makefile
++++ b/sound/soc/mediatek/mt7986/Makefile
+@@ -6,3 +6,4 @@ snd-soc-mt7986-afe-objs := \
+ mt7986-dai-etdm.o
+
+ obj-$(CONFIG_SND_SOC_MT7986) += snd-soc-mt7986-afe.o
++obj-$(CONFIG_SND_SOC_MT7986_WM8960) += mt7986-wm8960.o
+--- /dev/null
++++ b/sound/soc/mediatek/mt7986/mt7986-wm8960.c
+@@ -0,0 +1,196 @@
++// SPDX-License-Identifier: GPL-2.0
++/*
++ * mt7986-wm8960.c -- MT7986-WM8960 ALSA SoC machine driver
++ *
++ * Copyright (c) 2023 MediaTek Inc.
++ * Authors: Vic Wu <vic.wu@mediatek.com>
++ * Maso Huang <maso.huang@mediatek.com>
++ */
++
++#include <linux/module.h>
++#include <sound/soc.h>
++
++#include "mt7986-afe-common.h"
++
++struct mt7986_wm8960_priv {
++ struct device_node *platform_node;
++ struct device_node *codec_node;
++};
++
++static const struct snd_soc_dapm_widget mt7986_wm8960_widgets[] = {
++ SND_SOC_DAPM_HP("Headphone", NULL),
++ SND_SOC_DAPM_MIC("AMIC", NULL),
++};
++
++static const struct snd_kcontrol_new mt7986_wm8960_controls[] = {
++ SOC_DAPM_PIN_SWITCH("Headphone"),
++ SOC_DAPM_PIN_SWITCH("AMIC"),
++};
++
++SND_SOC_DAILINK_DEFS(playback,
++ DAILINK_COMP_ARRAY(COMP_CPU("DL1")),
++ DAILINK_COMP_ARRAY(COMP_DUMMY()),
++ DAILINK_COMP_ARRAY(COMP_EMPTY()));
++
++SND_SOC_DAILINK_DEFS(capture,
++ DAILINK_COMP_ARRAY(COMP_CPU("UL1")),
++ DAILINK_COMP_ARRAY(COMP_DUMMY()),
++ DAILINK_COMP_ARRAY(COMP_EMPTY()));
++
++SND_SOC_DAILINK_DEFS(codec,
++ DAILINK_COMP_ARRAY(COMP_CPU("ETDM")),
++ DAILINK_COMP_ARRAY(COMP_CODEC(NULL, "wm8960-hifi")),
++ DAILINK_COMP_ARRAY(COMP_EMPTY()));
++
++static struct snd_soc_dai_link mt7986_wm8960_dai_links[] = {
++ /* FE */
++ {
++ .name = "wm8960-playback",
++ .stream_name = "wm8960-playback",
++ .trigger = {SND_SOC_DPCM_TRIGGER_POST,
++ SND_SOC_DPCM_TRIGGER_POST},
++ .dynamic = 1,
++ .dpcm_playback = 1,
++ SND_SOC_DAILINK_REG(playback),
++ },
++ {
++ .name = "wm8960-capture",
++ .stream_name = "wm8960-capture",
++ .trigger = {SND_SOC_DPCM_TRIGGER_POST,
++ SND_SOC_DPCM_TRIGGER_POST},
++ .dynamic = 1,
++ .dpcm_capture = 1,
++ SND_SOC_DAILINK_REG(capture),
++ },
++ /* BE */
++ {
++ .name = "wm8960-codec",
++ .no_pcm = 1,
++ .dai_fmt = SND_SOC_DAIFMT_I2S |
++ SND_SOC_DAIFMT_NB_NF |
++ SND_SOC_DAIFMT_CBS_CFS |
++ SND_SOC_DAIFMT_GATED,
++ .dpcm_playback = 1,
++ .dpcm_capture = 1,
++ SND_SOC_DAILINK_REG(codec),
++ },
++};
++
++static struct snd_soc_card mt7986_wm8960_card = {
++ .name = "mt7986-wm8960",
++ .owner = THIS_MODULE,
++ .dai_link = mt7986_wm8960_dai_links,
++ .num_links = ARRAY_SIZE(mt7986_wm8960_dai_links),
++ .controls = mt7986_wm8960_controls,
++ .num_controls = ARRAY_SIZE(mt7986_wm8960_controls),
++ .dapm_widgets = mt7986_wm8960_widgets,
++ .num_dapm_widgets = ARRAY_SIZE(mt7986_wm8960_widgets),
++};
++
++static int mt7986_wm8960_machine_probe(struct platform_device *pdev)
++{
++ struct snd_soc_card *card = &mt7986_wm8960_card;
++ struct snd_soc_dai_link *dai_link;
++ struct device_node *platform, *codec;
++ struct mt7986_wm8960_priv *priv;
++ int ret, i;
++
++ priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
++ if (!priv)
++ return -ENOMEM;
++
++ platform = of_get_child_by_name(pdev->dev.of_node, "platform");
++
++ if (platform) {
++ priv->platform_node = of_parse_phandle(platform, "sound-dai", 0);
++ of_node_put(platform);
++
++ if (!priv->platform_node) {
++ dev_err(&pdev->dev, "Failed to parse platform/sound-dai property\n");
++ return -EINVAL;
++ }
++ } else {
++ dev_err(&pdev->dev, "Property 'platform' missing or invalid\n");
++ return -EINVAL;
++ }
++
++ for_each_card_prelinks(card, i, dai_link) {
++ if (dai_link->platforms->name)
++ continue;
++ dai_link->platforms->of_node = priv->platform_node;
++ }
++
++ card->dev = &pdev->dev;
++
++ codec = of_get_child_by_name(pdev->dev.of_node, "codec");
++
++ if (codec) {
++ priv->codec_node = of_parse_phandle(codec, "sound-dai", 0);
++ of_node_put(codec);
++
++ if (!priv->codec_node) {
++ of_node_put(priv->platform_node);
++ dev_err(&pdev->dev, "Failed to parse codec/sound-dai property\n");
++ return -EINVAL;
++ }
++ } else {
++ of_node_put(priv->platform_node);
++ dev_err(&pdev->dev, "Property 'codec' missing or invalid\n");
++ return -EINVAL;
++ }
++
++ for_each_card_prelinks(card, i, dai_link) {
++ if (dai_link->codecs->name)
++ continue;
++ dai_link->codecs->of_node = priv->codec_node;
++ }
++
++ ret = snd_soc_of_parse_audio_routing(card, "audio-routing");
++ if (ret) {
++ dev_err(&pdev->dev, "Failed to parse audio-routing: %d\n", ret);
++ goto err_of_node_put;
++ }
++
++ ret = devm_snd_soc_register_card(&pdev->dev, card);
++ if (ret) {
++ dev_err(&pdev->dev, "%s snd_soc_register_card fail: %d\n", __func__, ret);
++ goto err_of_node_put;
++ }
++
++err_of_node_put:
++ of_node_put(priv->codec_node);
++ of_node_put(priv->platform_node);
++ return ret;
++}
++
++static void mt7986_wm8960_machine_remove(struct platform_device *pdev)
++{
++ struct snd_soc_card *card = platform_get_drvdata(pdev);
++ struct mt7986_wm8960_priv *priv = snd_soc_card_get_drvdata(card);
++
++ of_node_put(priv->codec_node);
++ of_node_put(priv->platform_node);
++}
++
++static const struct of_device_id mt7986_wm8960_machine_dt_match[] = {
++ {.compatible = "mediatek,mt7986-wm8960-sound"},
++ { /* sentinel */ }
++};
++MODULE_DEVICE_TABLE(of, mt7986_wm8960_machine_dt_match);
++
++static struct platform_driver mt7986_wm8960_machine = {
++ .driver = {
++ .name = "mt7986-wm8960",
++ .of_match_table = mt7986_wm8960_machine_dt_match,
++ },
++ .probe = mt7986_wm8960_machine_probe,
++ .remove_new = mt7986_wm8960_machine_remove,
++};
++
++module_platform_driver(mt7986_wm8960_machine);
++
++/* Module information */
++MODULE_DESCRIPTION("MT7986 WM8960 ALSA SoC machine driver");
++MODULE_AUTHOR("Vic Wu <vic.wu@mediatek.com>");
++MODULE_LICENSE("GPL");
++MODULE_ALIAS("mt7986 wm8960 soc card");
--- /dev/null
+From 72469f950b629e57e60fbcbefed45e083619b986 Mon Sep 17 00:00:00 2001
+From: Maso Huang <maso.huang@mediatek.com>
+Date: Thu, 17 Aug 2023 18:13:37 +0800
+Subject: [PATCH 5/9] ASoC: dt-bindings: mediatek,mt7986-wm8960: add
+ mt7986-wm8960 document
+
+Add document for mt7986 board with wm8960.
+
+Signed-off-by: Maso Huang <maso.huang@mediatek.com>
+Reviewed-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
+Link: https://lore.kernel.org/r/20230817101338.18782-6-maso.huang@mediatek.com
+Signed-off-by: Mark Brown <broonie@kernel.org>
+---
+ .../sound/mediatek,mt7986-wm8960.yaml | 67 +++++++++++++++++++
+ 1 file changed, 67 insertions(+)
+ create mode 100644 Documentation/devicetree/bindings/sound/mediatek,mt7986-wm8960.yaml
+
+--- /dev/null
++++ b/Documentation/devicetree/bindings/sound/mediatek,mt7986-wm8960.yaml
+@@ -0,0 +1,67 @@
++# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
++%YAML 1.2
++---
++$id: http://devicetree.org/schemas/sound/mediatek,mt7986-wm8960.yaml#
++$schema: http://devicetree.org/meta-schemas/core.yaml#
++
++title: MediaTek MT7986 sound card with WM8960 codec
++
++maintainers:
++ - Maso Huang <maso.huang@mediatek.com>
++
++allOf:
++ - $ref: sound-card-common.yaml#
++
++properties:
++ compatible:
++ const: mediatek,mt7986-wm8960-sound
++
++ platform:
++ type: object
++ additionalProperties: false
++ properties:
++ sound-dai:
++ description: The phandle of MT7986 platform.
++ maxItems: 1
++ required:
++ - sound-dai
++
++ codec:
++ type: object
++ additionalProperties: false
++ properties:
++ sound-dai:
++ description: The phandle of wm8960 codec.
++ maxItems: 1
++ required:
++ - sound-dai
++
++unevaluatedProperties: false
++
++required:
++ - compatible
++ - audio-routing
++ - platform
++ - codec
++
++examples:
++ - |
++ sound {
++ compatible = "mediatek,mt7986-wm8960-sound";
++ model = "mt7986-wm8960";
++ audio-routing =
++ "Headphone", "HP_L",
++ "Headphone", "HP_R",
++ "LINPUT1", "AMIC",
++ "RINPUT1", "AMIC";
++
++ platform {
++ sound-dai = <&afe>;
++ };
++
++ codec {
++ sound-dai = <&wm8960>;
++ };
++ };
++
++...
--- /dev/null
+From d16202eb38585adbc16e32d11188dbc2127015de Mon Sep 17 00:00:00 2001
+From: Maso Huang <maso.huang@mediatek.com>
+Date: Thu, 17 Aug 2023 18:13:38 +0800
+Subject: [PATCH 6/9] ASoC: dt-bindings: mediatek,mt7986-afe: add audio afe
+ document
+
+Add mt7986 audio afe document.
+
+Signed-off-by: Maso Huang <maso.huang@mediatek.com>
+Reviewed-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
+Link: https://lore.kernel.org/r/20230817101338.18782-7-maso.huang@mediatek.com
+Signed-off-by: Mark Brown <broonie@kernel.org>
+---
+ .../bindings/sound/mediatek,mt7986-afe.yaml | 160 ++++++++++++++++++
+ 1 file changed, 160 insertions(+)
+ create mode 100644 Documentation/devicetree/bindings/sound/mediatek,mt7986-afe.yaml
+
+--- /dev/null
++++ b/Documentation/devicetree/bindings/sound/mediatek,mt7986-afe.yaml
+@@ -0,0 +1,160 @@
++# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
++%YAML 1.2
++---
++$id: http://devicetree.org/schemas/sound/mediatek,mt7986-afe.yaml#
++$schema: http://devicetree.org/meta-schemas/core.yaml#
++
++title: MediaTek AFE PCM controller for MT7986
++
++maintainers:
++ - Maso Huang <maso.huang@mediatek.com>
++
++properties:
++ compatible:
++ oneOf:
++ - const: mediatek,mt7986-afe
++ - items:
++ - enum:
++ - mediatek,mt7981-afe
++ - mediatek,mt7988-afe
++ - const: mediatek,mt7986-afe
++
++ reg:
++ maxItems: 1
++
++ interrupts:
++ maxItems: 1
++
++ clocks:
++ minItems: 5
++ items:
++ - description: audio bus clock
++ - description: audio 26M clock
++ - description: audio intbus clock
++ - description: audio hopping clock
++ - description: audio pll clock
++ - description: mux for pcm_mck
++ - description: audio i2s/pcm mck
++
++ clock-names:
++ minItems: 5
++ items:
++ - const: bus_ck
++ - const: 26m_ck
++ - const: l_ck
++ - const: aud_ck
++ - const: eg2_ck
++ - const: sel
++ - const: i2s_m
++
++required:
++ - compatible
++ - reg
++ - interrupts
++ - clocks
++ - clock-names
++
++allOf:
++ - if:
++ properties:
++ compatible:
++ contains:
++ const: mediatek,mt7986-afe
++ then:
++ properties:
++ clocks:
++ items:
++ - description: audio bus clock
++ - description: audio 26M clock
++ - description: audio intbus clock
++ - description: audio hopping clock
++ - description: audio pll clock
++ clock-names:
++ items:
++ - const: bus_ck
++ - const: 26m_ck
++ - const: l_ck
++ - const: aud_ck
++ - const: eg2_ck
++
++ - if:
++ properties:
++ compatible:
++ contains:
++ const: mediatek,mt7981-afe
++ then:
++ properties:
++ clocks:
++ items:
++ - description: audio bus clock
++ - description: audio 26M clock
++ - description: audio intbus clock
++ - description: audio hopping clock
++ - description: audio pll clock
++ - description: mux for pcm_mck
++ clock-names:
++ items:
++ - const: bus_ck
++ - const: 26m_ck
++ - const: l_ck
++ - const: aud_ck
++ - const: eg2_ck
++ - const: sel
++
++ - if:
++ properties:
++ compatible:
++ contains:
++ const: mediatek,mt7988-afe
++ then:
++ properties:
++ clocks:
++ items:
++ - description: audio bus clock
++ - description: audio 26M clock
++ - description: audio intbus clock
++ - description: audio hopping clock
++ - description: audio pll clock
++ - description: mux for pcm_mck
++ - description: audio i2s/pcm mck
++ clock-names:
++ items:
++ - const: bus_ck
++ - const: 26m_ck
++ - const: l_ck
++ - const: aud_ck
++ - const: eg2_ck
++ - const: sel
++ - const: i2s_m
++
++additionalProperties: false
++
++examples:
++ - |
++ #include <dt-bindings/interrupt-controller/arm-gic.h>
++ #include <dt-bindings/interrupt-controller/irq.h>
++ #include <dt-bindings/clock/mt7986-clk.h>
++
++ afe@11210000 {
++ compatible = "mediatek,mt7986-afe";
++ reg = <0x11210000 0x9000>;
++ interrupts = <GIC_SPI 106 IRQ_TYPE_LEVEL_HIGH>;
++ clocks = <&infracfg_ao CLK_INFRA_AUD_BUS_CK>,
++ <&infracfg_ao CLK_INFRA_AUD_26M_CK>,
++ <&infracfg_ao CLK_INFRA_AUD_L_CK>,
++ <&infracfg_ao CLK_INFRA_AUD_AUD_CK>,
++ <&infracfg_ao CLK_INFRA_AUD_EG2_CK>;
++ clock-names = "bus_ck",
++ "26m_ck",
++ "l_ck",
++ "aud_ck",
++ "eg2_ck";
++ assigned-clocks = <&topckgen CLK_TOP_A1SYS_SEL>,
++ <&topckgen CLK_TOP_AUD_L_SEL>,
++ <&topckgen CLK_TOP_A_TUNER_SEL>;
++ assigned-clock-parents = <&topckgen CLK_TOP_APLL2_D4>,
++ <&apmixedsys CLK_APMIXED_APLL2>,
++ <&topckgen CLK_TOP_APLL2_D4>;
++ };
++
++...
--- /dev/null
+From f3f0934e5c7b9c16e0cb2435be3555382e6293ad Mon Sep 17 00:00:00 2001
+From: Maso Huang <maso.huang@mediatek.com>
+Date: Tue, 24 Oct 2023 11:50:17 +0800
+Subject: [PATCH 7/9] ASoC: mediatek: mt7986: drop the remove callback of
+ mt7986_wm8960
+
+Drop the remove callback of mt7986_wm8960.
+
+Signed-off-by: Maso Huang <maso.huang@mediatek.com>
+Reviewed-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
+Link: https://lore.kernel.org/r/20231024035019.11732-2-maso.huang@mediatek.com
+Signed-off-by: Mark Brown <broonie@kernel.org>
+---
+ sound/soc/mediatek/mt7986/mt7986-wm8960.c | 10 ----------
+ 1 file changed, 10 deletions(-)
+
+--- a/sound/soc/mediatek/mt7986/mt7986-wm8960.c
++++ b/sound/soc/mediatek/mt7986/mt7986-wm8960.c
+@@ -163,15 +163,6 @@ err_of_node_put:
+ return ret;
+ }
+
+-static void mt7986_wm8960_machine_remove(struct platform_device *pdev)
+-{
+- struct snd_soc_card *card = platform_get_drvdata(pdev);
+- struct mt7986_wm8960_priv *priv = snd_soc_card_get_drvdata(card);
+-
+- of_node_put(priv->codec_node);
+- of_node_put(priv->platform_node);
+-}
+-
+ static const struct of_device_id mt7986_wm8960_machine_dt_match[] = {
+ {.compatible = "mediatek,mt7986-wm8960-sound"},
+ { /* sentinel */ }
+@@ -184,7 +175,6 @@ static struct platform_driver mt7986_wm8
+ .of_match_table = mt7986_wm8960_machine_dt_match,
+ },
+ .probe = mt7986_wm8960_machine_probe,
+- .remove_new = mt7986_wm8960_machine_remove,
+ };
+
+ module_platform_driver(mt7986_wm8960_machine);
--- /dev/null
+From 98b8fb2cb4fcab1903d0baf611bf0c3f822a08dc Mon Sep 17 00:00:00 2001
+From: Maso Huang <maso.huang@mediatek.com>
+Date: Tue, 24 Oct 2023 11:50:18 +0800
+Subject: [PATCH 8/9] ASoC: mediatek: mt7986: remove the mt7986_wm8960_priv
+ structure
+
+Remove the mt7986_wm8960_priv structure.
+
+Signed-off-by: Maso Huang <maso.huang@mediatek.com>
+Reviewed-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
+Link: https://lore.kernel.org/r/20231024035019.11732-3-maso.huang@mediatek.com
+Signed-off-by: Mark Brown <broonie@kernel.org>
+---
+ sound/soc/mediatek/mt7986/mt7986-wm8960.c | 33 +++++++++--------------
+ 1 file changed, 12 insertions(+), 21 deletions(-)
+
+--- a/sound/soc/mediatek/mt7986/mt7986-wm8960.c
++++ b/sound/soc/mediatek/mt7986/mt7986-wm8960.c
+@@ -12,11 +12,6 @@
+
+ #include "mt7986-afe-common.h"
+
+-struct mt7986_wm8960_priv {
+- struct device_node *platform_node;
+- struct device_node *codec_node;
+-};
+-
+ static const struct snd_soc_dapm_widget mt7986_wm8960_widgets[] = {
+ SND_SOC_DAPM_HP("Headphone", NULL),
+ SND_SOC_DAPM_MIC("AMIC", NULL),
+@@ -92,20 +87,18 @@ static int mt7986_wm8960_machine_probe(s
+ struct snd_soc_card *card = &mt7986_wm8960_card;
+ struct snd_soc_dai_link *dai_link;
+ struct device_node *platform, *codec;
+- struct mt7986_wm8960_priv *priv;
++ struct device_node *platform_dai_node, *codec_dai_node;
+ int ret, i;
+
+- priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
+- if (!priv)
+- return -ENOMEM;
++ card->dev = &pdev->dev;
+
+ platform = of_get_child_by_name(pdev->dev.of_node, "platform");
+
+ if (platform) {
+- priv->platform_node = of_parse_phandle(platform, "sound-dai", 0);
++ platform_dai_node = of_parse_phandle(platform, "sound-dai", 0);
+ of_node_put(platform);
+
+- if (!priv->platform_node) {
++ if (!platform_dai_node) {
+ dev_err(&pdev->dev, "Failed to parse platform/sound-dai property\n");
+ return -EINVAL;
+ }
+@@ -117,24 +110,22 @@ static int mt7986_wm8960_machine_probe(s
+ for_each_card_prelinks(card, i, dai_link) {
+ if (dai_link->platforms->name)
+ continue;
+- dai_link->platforms->of_node = priv->platform_node;
++ dai_link->platforms->of_node = platform_dai_node;
+ }
+
+- card->dev = &pdev->dev;
+-
+ codec = of_get_child_by_name(pdev->dev.of_node, "codec");
+
+ if (codec) {
+- priv->codec_node = of_parse_phandle(codec, "sound-dai", 0);
++ codec_dai_node = of_parse_phandle(codec, "sound-dai", 0);
+ of_node_put(codec);
+
+- if (!priv->codec_node) {
+- of_node_put(priv->platform_node);
++ if (!codec_dai_node) {
++ of_node_put(platform_dai_node);
+ dev_err(&pdev->dev, "Failed to parse codec/sound-dai property\n");
+ return -EINVAL;
+ }
+ } else {
+- of_node_put(priv->platform_node);
++ of_node_put(platform_dai_node);
+ dev_err(&pdev->dev, "Property 'codec' missing or invalid\n");
+ return -EINVAL;
+ }
+@@ -142,7 +133,7 @@ static int mt7986_wm8960_machine_probe(s
+ for_each_card_prelinks(card, i, dai_link) {
+ if (dai_link->codecs->name)
+ continue;
+- dai_link->codecs->of_node = priv->codec_node;
++ dai_link->codecs->of_node = codec_dai_node;
+ }
+
+ ret = snd_soc_of_parse_audio_routing(card, "audio-routing");
+@@ -158,8 +149,8 @@ static int mt7986_wm8960_machine_probe(s
+ }
+
+ err_of_node_put:
+- of_node_put(priv->codec_node);
+- of_node_put(priv->platform_node);
++ of_node_put(platform_dai_node);
++ of_node_put(codec_dai_node);
+ return ret;
+ }
+
--- /dev/null
+From 4e229f4264f4be7a6a554487714c0913ef59cf7f Mon Sep 17 00:00:00 2001
+From: Maso Huang <maso.huang@mediatek.com>
+Date: Tue, 24 Oct 2023 11:50:19 +0800
+Subject: [PATCH 9/9] ASoC: mediatek: mt7986: add sample rate checker
+
+mt7986 only supports 8/12/16/24/32/48/96/192 kHz
+
+Signed-off-by: Maso Huang <maso.huang@mediatek.com>
+Reviewed-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
+Link: https://lore.kernel.org/r/20231024035019.11732-4-maso.huang@mediatek.com
+Signed-off-by: Mark Brown <broonie@kernel.org>
+---
+ sound/soc/mediatek/mt7986/mt7986-dai-etdm.c | 23 +++++++++++++++++----
+ 1 file changed, 19 insertions(+), 4 deletions(-)
+
+--- a/sound/soc/mediatek/mt7986/mt7986-dai-etdm.c
++++ b/sound/soc/mediatek/mt7986/mt7986-dai-etdm.c
+@@ -237,12 +237,27 @@ static int mtk_dai_etdm_hw_params(struct
+ struct snd_pcm_hw_params *params,
+ struct snd_soc_dai *dai)
+ {
++ unsigned int rate = params_rate(params);
+ struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
+
+- mtk_dai_etdm_config(afe, params, dai, SNDRV_PCM_STREAM_PLAYBACK);
+- mtk_dai_etdm_config(afe, params, dai, SNDRV_PCM_STREAM_CAPTURE);
+-
+- return 0;
++ switch (rate) {
++ case 8000:
++ case 12000:
++ case 16000:
++ case 24000:
++ case 32000:
++ case 48000:
++ case 96000:
++ case 192000:
++ mtk_dai_etdm_config(afe, params, dai, SNDRV_PCM_STREAM_PLAYBACK);
++ mtk_dai_etdm_config(afe, params, dai, SNDRV_PCM_STREAM_CAPTURE);
++ return 0;
++ default:
++ dev_err(afe->dev,
++ "Sample rate %d invalid. Supported rates: 8/12/16/24/32/48/96/192 kHz\n",
++ rate);
++ return -EINVAL;
++ }
+ }
+
+ static int mtk_dai_etdm_trigger(struct snd_pcm_substream *substream, int cmd,
--- /dev/null
+From e4cde335d1771863a60b6931e51357b8470e85c4 Mon Sep 17 00:00:00 2001
+From: Daniel Golle <daniel@makrotopia.org>
+Date: Sun, 10 Dec 2023 22:41:39 +0000
+Subject: [PATCH] ASoC: mediatek: mt7986: silence error in case of
+ -EPROBE_DEFER
+
+If probe is defered no error should be printed. Mute it.
+
+Signed-off-by: Daniel Golle <daniel@makrotopia.org>
+---
+ sound/soc/mediatek/mt7986/mt7986-wm8960.c | 4 +++-
+ 1 file changed, 3 insertions(+), 1 deletion(-)
+
+--- a/sound/soc/mediatek/mt7986/mt7986-wm8960.c
++++ b/sound/soc/mediatek/mt7986/mt7986-wm8960.c
+@@ -144,7 +144,9 @@ static int mt7986_wm8960_machine_probe(s
+
+ ret = devm_snd_soc_register_card(&pdev->dev, card);
+ if (ret) {
+- dev_err(&pdev->dev, "%s snd_soc_register_card fail: %d\n", __func__, ret);
++ if (ret != -EPROBE_DEFER)
++ dev_err(&pdev->dev, "%s snd_soc_register_card fail: %d\n", __func__, ret);
++
+ goto err_of_node_put;
+ }
+
--- /dev/null
+From 1c09b694a1e9378931085e77d834a4d9786a5356 Mon Sep 17 00:00:00 2001
+From: Maso Huang <maso.huang@mediatek.com>
+Date: Thu, 7 Sep 2023 10:54:37 +0800
+Subject: [PATCH] arm64: dts: mt7986: add afe
+
+---
+ arch/arm64/boot/dts/mediatek/mt7986a.dtsi | 23 +++++++++++
+ 1 files changed, 23 insertions(+)
+
+--- a/arch/arm64/boot/dts/mediatek/mt7986a.dtsi
++++ b/arch/arm64/boot/dts/mediatek/mt7986a.dtsi
+@@ -248,6 +248,28 @@
+ status = "disabled";
+ };
+
++ afe: audio-controller@11210000 {
++ compatible = "mediatek,mt7986-afe";
++ reg = <0 0x11210000 0 0x9000>;
++ interrupts = <GIC_SPI 106 IRQ_TYPE_LEVEL_HIGH>;
++ clocks = <&infracfg CLK_INFRA_AUD_BUS_CK>,
++ <&infracfg CLK_INFRA_AUD_26M_CK>,
++ <&infracfg CLK_INFRA_AUD_L_CK>,
++ <&infracfg CLK_INFRA_AUD_AUD_CK>,
++ <&infracfg CLK_INFRA_AUD_EG2_CK>;
++ clock-names = "aud_bus_ck",
++ "aud_26m_ck",
++ "aud_l_ck",
++ "aud_aud_ck",
++ "aud_eg2_ck";
++ assigned-clocks = <&topckgen CLK_TOP_A1SYS_SEL>,
++ <&topckgen CLK_TOP_AUD_L_SEL>,
++ <&topckgen CLK_TOP_A_TUNER_SEL>;
++ assigned-clock-parents = <&topckgen CLK_TOP_APLL2_D4>,
++ <&apmixedsys CLK_APMIXED_APLL2>,
++ <&topckgen CLK_TOP_APLL2_D4>;
++ };
++
+ pwm: pwm@10048000 {
+ compatible = "mediatek,mt7986-pwm";
+ reg = <0 0x10048000 0 0x1000>;
--- /dev/null
+From 1c09b694a1e9378931085e77d834a4d9786a5356 Mon Sep 17 00:00:00 2001
+From: Maso Huang <maso.huang@mediatek.com>
+Date: Thu, 7 Sep 2023 10:54:37 +0800
+Subject: [PATCH] arm64: dts: mt7986: add sound wm8960
+
+---
+ .../dts/mediatek/mt7986a-rfb-spim-nand.dts | 39 +++++++++++++++++++
+ 1 files changed, 39 insertions(+)
+
+--- a/arch/arm64/boot/dts/mediatek/mt7986a-rfb-spim-nand.dts
++++ b/arch/arm64/boot/dts/mediatek/mt7986a-rfb-spim-nand.dts
+@@ -4,6 +4,35 @@
+
+ / {
+ compatible = "mediatek,mt7986a-rfb-snand";
++
++ sound_wm8960 {
++ compatible = "mediatek,mt7986-wm8960-sound";
++ audio-routing = "Headphone", "HP_L",
++ "Headphone", "HP_R",
++ "LINPUT1", "AMIC",
++ "RINPUT1", "AMIC";
++
++ status = "okay";
++
++ platform {
++ sound-dai = <&afe>;
++ };
++
++ codec {
++ sound-dai = <&wm8960>;
++ };
++ };
++};
++
++&i2c0 {
++ pinctrl-names = "default";
++ pinctrl-0 = <&i2c_pins>;
++ status = "okay";
++
++ wm8960: wm8960@1a {
++ compatible = "wlf,wm8960";
++ reg = <0x1a>;
++ };
+ };
+
+ &spi0 {
+@@ -50,3 +79,13 @@
+ &wifi {
+ mediatek,mtd-eeprom = <&factory 0>;
+ };
++
++&pio {
++ i2c_pins: i2c-pins-3-4 {
++ mux {
++ function = "i2c";
++ groups = "i2c";
++ };
++ };
++};
++
--- /dev/null
+--- /dev/null
++++ b/arch/arm64/boot/dts/mediatek/mt7986a-bananapi-bpi-r3-respeaker-2mics.dtso
+@@ -0,0 +1,62 @@
++// SPDX-License-Identifier: (GPL-2.0 OR MIT)
++/*
++ * Copyright (C) 2023 MediaTek Inc.
++ * Author: Maso Huang <Maso.Huang@mediatek.com>
++ */
++
++/dts-v1/;
++/plugin/;
++
++/ {
++ compatible = "bananapi,bpi-r3", "mediatek,mt7986a";
++
++ fragment@0 {
++ target-path = "/";
++ __overlay__ {
++ sound_wm8960 {
++ compatible = "mediatek,mt7986-wm8960-sound";
++ audio-routing = "Headphone", "HP_L",
++ "Headphone", "HP_R",
++ "LINPUT1", "AMIC",
++ "RINPUT1", "AMIC";
++
++ status = "okay";
++
++ platform {
++ sound-dai = <&afe>;
++ };
++
++ codec {
++ sound-dai = <&wm8960>;
++ };
++ };
++ };
++ };
++
++ fragment@1 {
++ target = <&i2c0>;
++ __overlay__ {
++ pinctrl-names = "default";
++ pinctrl-0 = <&i2c_pins>;
++ clock-frequency = <400000>;
++ status = "okay";
++
++ wm8960: wm8960@1a {
++ compatible = "wlf,wm8960";
++ reg = <0x1a>;
++ };
++ };
++ };
++
++ fragment@2 {
++ target = <&pio>;
++ __overlay__ {
++ i2c_pins: i2c-pins-3-4 {
++ mux {
++ function = "i2c";
++ groups = "i2c";
++ };
++ };
++ };
++ };
++};
+--- a/arch/arm64/boot/dts/mediatek/Makefile
++++ b/arch/arm64/boot/dts/mediatek/Makefile
+@@ -12,6 +12,7 @@ dtb-$(CONFIG_ARCH_MEDIATEK) += mt7986a-b
+ dtb-$(CONFIG_ARCH_MEDIATEK) += mt7986a-bananapi-bpi-r3-nand.dtbo
+ dtb-$(CONFIG_ARCH_MEDIATEK) += mt7986a-bananapi-bpi-r3-nor.dtbo
+ dtb-$(CONFIG_ARCH_MEDIATEK) += mt7986a-bananapi-bpi-r3-sd.dtbo
++dtb-$(CONFIG_ARCH_MEDIATEK) += mt7986a-bananapi-bpi-r3-respeaker-2mics.dtbo
+ dtb-$(CONFIG_ARCH_MEDIATEK) += mt7986a-rfb.dtb
+ dtb-$(CONFIG_ARCH_MEDIATEK) += mt7986b-rfb.dtb
+ dtb-$(CONFIG_ARCH_MEDIATEK) += mt8167-pumpkin.dtb
--- /dev/null
+--- a/arch/arm64/boot/dts/mediatek/mt7622-bananapi-bpi-r64.dts
++++ b/arch/arm64/boot/dts/mediatek/mt7622-bananapi-bpi-r64.dts
+@@ -312,7 +312,7 @@
+ /* Attention: GPIO 90 is used to switch between PCIe@1,0 and
+ * SATA functions. i.e. output-high: PCIe, output-low: SATA
+ */
+- asm_sel {
++ asmsel: asm_sel {
+ gpio-hog;
+ gpios = <90 GPIO_ACTIVE_HIGH>;
+ output-high;
+--- /dev/null
++++ b/arch/arm64/boot/dts/mediatek/mt7622-bananapi-bpi-r64-sata.dtso
+@@ -0,0 +1,31 @@
++/* SPDX-License-Identifier: (GPL-2.0-only OR MIT) */
++
++#include <dt-bindings/gpio/gpio.h>
++
++/dts-v1/;
++/plugin/;
++
++/ {
++ compatible = "bananapi,bpi-r64", "mediatek,mt7622";
++
++ fragment@0 {
++ target = <&asmsel>;
++ __overlay__ {
++ gpios = <90 GPIO_ACTIVE_LOW>;
++ };
++ };
++
++ fragment@1 {
++ target = <&sata>;
++ __overlay__ {
++ status = "okay";
++ };
++ };
++
++ fragment@2 {
++ target = <&sata_phy>;
++ __overlay__ {
++ status = "okay";
++ };
++ };
++};
+--- /dev/null
++++ b/arch/arm64/boot/dts/mediatek/mt7622-bananapi-bpi-r64-pcie1.dtso
+@@ -0,0 +1,17 @@
++/* SPDX-License-Identifier: (GPL-2.0-only OR MIT) */
++
++#include <dt-bindings/gpio/gpio.h>
++
++/dts-v1/;
++/plugin/;
++
++/ {
++ compatible = "bananapi,bpi-r64", "mediatek,mt7622";
++
++ fragment@0 {
++ target = <&asmsel>;
++ __overlay__ {
++ gpios = <90 GPIO_ACTIVE_HIGH>;
++ };
++ };
++};
--- /dev/null
+--- a/arch/arm/Kconfig
++++ b/arch/arm/Kconfig
+@@ -1589,6 +1589,14 @@ config ARM_ATAG_DTB_COMPAT_CMDLINE_EXTEN
+
+ endchoice
+
++config CMDLINE_OVERRIDE
++ bool "Use alternative cmdline from device tree"
++ help
++ Some bootloaders may have uneditable bootargs. While CMDLINE_FORCE can
++ be used, this is not a good option for kernels that are shared across
++ devices. This setting enables using "chosen/cmdline-override" as the
++ cmdline if it exists in the device tree.
++
+ config CMDLINE
+ string "Default kernel command string"
+ default ""
+--- a/drivers/of/fdt.c
++++ b/drivers/of/fdt.c
+@@ -1187,6 +1187,17 @@ int __init early_init_dt_scan_chosen(cha
+ if (p != NULL && l > 0)
+ strlcat(cmdline, p, min_t(int, strlen(cmdline) + (int)l, COMMAND_LINE_SIZE));
+
++ /* CONFIG_CMDLINE_OVERRIDE is used to fallback to a different
++ * device tree option of chosen/bootargs-override. This is
++ * helpful on boards where u-boot sets bootargs, and is unable
++ * to be modified.
++ */
++#ifdef CONFIG_CMDLINE_OVERRIDE
++ p = of_get_flat_dt_prop(node, "bootargs-override", &l);
++ if (p != NULL && l > 0)
++ strlcpy(cmdline, p, min((int)l, COMMAND_LINE_SIZE));
++#endif
++
+ handle_cmdline:
+ /*
+ * CONFIG_CMDLINE is meant to be a default in case nothing else
+--- a/arch/arm64/Kconfig
++++ b/arch/arm64/Kconfig
+@@ -2240,6 +2240,14 @@ config CMDLINE_FORCE
+
+ endchoice
+
++config CMDLINE_OVERRIDE
++ bool "Use alternative cmdline from device tree"
++ help
++ Some bootloaders may have uneditable bootargs. While CMDLINE_FORCE can
++ be used, this is not a good option for kernels that are shared across
++ devices. This setting enables using "chosen/cmdline-override" as the
++ cmdline if it exists in the device tree.
++
+ config EFI_STUB
+ bool
+
--- /dev/null
+--- a/arch/arm64/boot/dts/mediatek/mt7622-bananapi-bpi-r64.dts
++++ b/arch/arm64/boot/dts/mediatek/mt7622-bananapi-bpi-r64.dts
+@@ -639,5 +639,28 @@
+ };
+
+ &wmac {
++ mediatek,eeprom-data = <0x22760500 0x0 0x0 0x0
++ 0x0 0x0 0x0 0x0
++ 0x0 0x0 0x0 0x0
++ 0x0 0x44000020 0x0 0x10002000
++ 0x4400 0x4000000 0x0 0x0
++ 0x200000b3 0x40b6c3c3 0x26000000 0x41c42600
++ 0x41c4 0x26000000 0xc0c52600 0x0
++ 0x0 0x0 0x0 0x0
++ 0x0 0x0 0x0 0x0
++ 0x0 0x0 0x0 0x0
++ 0x0 0x0 0x0 0x0
++ 0x0 0x0 0x0 0xc6c6
++ 0xc3c3c2c1 0xc300c3 0x818181 0x83c1c182
++ 0x83838382 0x0 0x0 0x0
++ 0x0 0x0 0x0 0x0
++ 0x84002e00 0x90000087 0x8a000000 0x0
++ 0x0 0x0 0x0 0x0
++ 0x0 0x0 0x0 0x0
++ 0xb000009 0x0 0x0 0x0
++ 0x0 0x0 0x0 0x0
++ 0x0 0x0 0x0 0x0
++ 0x0 0x0 0x0 0x7707>;
++
+ status = "okay";
+ };
--- /dev/null
+--- a/arch/arm64/boot/dts/mediatek/mt7622-bananapi-bpi-r64.dts
++++ b/arch/arm64/boot/dts/mediatek/mt7622-bananapi-bpi-r64.dts
+@@ -32,6 +32,9 @@
+ chosen {
+ stdout-path = "serial0:115200n8";
+ bootargs = "earlycon=uart8250,mmio32,0x11002000 console=ttyS0,115200n1 swiotlb=512";
++ rootdisk-emmc = <&emmc_rootfs>;
++ rootdisk-sd = <&sd_rootfs>;
++ rootdisk-snfi = <&ubi_rootfs>;
+ };
+
+ cpus {
+@@ -233,6 +236,26 @@
+ assigned-clocks = <&topckgen CLK_TOP_MSDC30_0_SEL>;
+ assigned-clock-parents = <&topckgen CLK_TOP_UNIV48M>;
+ non-removable;
++
++ card@0 {
++ compatible = "mmc-card";
++ reg = <0>;
++
++ block {
++ compatible = "block-device";
++ partitions {
++ block-partition-env {
++ partname = "ubootenv";
++ nvmem-layout {
++ compatible = "u-boot,env-layout";
++ };
++ };
++ emmc_rootfs: block-partition-production {
++ partname = "production";
++ };
++ };
++ };
++ };
+ };
+
+ &mmc1 {
+@@ -249,6 +272,26 @@
+ vqmmc-supply = <®_3p3v>;
+ assigned-clocks = <&topckgen CLK_TOP_MSDC30_1_SEL>;
+ assigned-clock-parents = <&topckgen CLK_TOP_UNIV48M>;
++
++ card@0 {
++ compatible = "mmc-card";
++ reg = <0>;
++
++ block {
++ compatible = "block-device";
++ partitions {
++ block-partition-env {
++ partname = "ubootenv";
++ nvmem-layout {
++ compatible = "u-boot,env-layout";
++ };
++ };
++ sd_rootfs: block-partition-production {
++ partname = "production";
++ };
++ };
++ };
++ };
+ };
+
+ &nandc {
+@@ -283,14 +326,29 @@
+ };
+
+ partition@80000 {
+- label = "fip";
+- reg = <0x80000 0x200000>;
+- read-only;
+- };
+-
+- ubi: partition@280000 {
+ label = "ubi";
+- reg = <0x280000 0x7d80000>;
++ reg = <0x80000 0x7f80000>;
++ compatible = "linux,ubi";
++
++ volumes {
++ ubi-volume-ubootenv {
++ volname = "ubootenv";
++ nvmem-layout {
++ compatible = "u-boot,env-redundant-bool-layout";
++ };
++ };
++
++ ubi-volume-ubootenv2 {
++ volname = "ubootenv2";
++ nvmem-layout {
++ compatible = "u-boot,env-redundant-bool-layout";
++ };
++ };
++
++ ubi_rootfs: ubi-volume-fit {
++ volname = "fit";
++ };
++ };
+ };
+ };
+ };
--- /dev/null
+--- a/drivers/spi/spi-mt65xx.c
++++ b/drivers/spi/spi-mt65xx.c
+@@ -1225,8 +1225,15 @@ static int mtk_spi_probe(struct platform
+ if (ret < 0)
+ return dev_err_probe(dev, ret, "failed to enable hclk\n");
+
++ ret = clk_prepare_enable(mdata->sel_clk);
++ if (ret < 0) {
++ clk_disable_unprepare(mdata->spi_hclk);
++ return dev_err_probe(dev, ret, "failed to enable sel_clk\n");
++ }
++
+ ret = clk_prepare_enable(mdata->spi_clk);
+ if (ret < 0) {
++ clk_disable_unprepare(mdata->sel_clk);
+ clk_disable_unprepare(mdata->spi_hclk);
+ return dev_err_probe(dev, ret, "failed to enable spi_clk\n");
+ }
--- /dev/null
+From 3cf212c4ce6cd72c09bc47f35f539ba0afd4d106 Mon Sep 17 00:00:00 2001
+Message-Id: <3cf212c4ce6cd72c09bc47f35f539ba0afd4d106.1678716918.git.lorenzo@kernel.org>
+From: Lorenzo Bianconi <lorenzo@kernel.org>
+Date: Sun, 12 Mar 2023 16:40:31 +0100
+Subject: [PATCH net-next 1/2] net: ethernet: mtk_wed: rename
+ mtk_wed_get_memory_region in mtk_wed_get_reserved_memory_region
+
+This is a preliminary patch to move wed ilm/dlm and cpuboot properties in
+dedicated dts nodes.
+
+Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
+---
+ drivers/net/ethernet/mediatek/mtk_wed_mcu.c | 8 ++++----
+ 1 file changed, 4 insertions(+), 4 deletions(-)
+
+--- a/drivers/net/ethernet/mediatek/mtk_wed_mcu.c
++++ b/drivers/net/ethernet/mediatek/mtk_wed_mcu.c
+@@ -234,8 +234,8 @@ int mtk_wed_mcu_msg_update(struct mtk_we
+ }
+
+ static int
+-mtk_wed_get_memory_region(struct mtk_wed_hw *hw, int index,
+- struct mtk_wed_wo_memory_region *region)
++mtk_wed_get_reserved_memory_region(struct mtk_wed_hw *hw, int index,
++ struct mtk_wed_wo_memory_region *region)
+ {
+ struct reserved_mem *rmem;
+ struct device_node *np;
+@@ -321,7 +321,7 @@ mtk_wed_mcu_load_firmware(struct mtk_wed
+ if (index < 0)
+ continue;
+
+- ret = mtk_wed_get_memory_region(wo->hw, index, &mem_region[i]);
++ ret = mtk_wed_get_reserved_memory_region(wo->hw, index, &mem_region[i]);
+ if (ret)
+ return ret;
+ }
--- /dev/null
+From 247e566e3459481f1fa98733534bfed767e18b42 Mon Sep 17 00:00:00 2001
+Message-Id: <247e566e3459481f1fa98733534bfed767e18b42.1678620342.git.lorenzo@kernel.org>
+From: Lorenzo Bianconi <lorenzo@kernel.org>
+Date: Sat, 11 Mar 2023 16:32:41 +0100
+Subject: [PATCH net-next] arm64: dts: mt7986: move cpuboot in a dedicated node
+
+Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
+---
+ arch/arm64/boot/dts/mediatek/mt7986a.dtsi | 21 +++++++++++----------
+ 1 file changed, 11 insertions(+), 10 deletions(-)
+
+--- a/arch/arm64/boot/dts/mediatek/mt7986a.dtsi
++++ b/arch/arm64/boot/dts/mediatek/mt7986a.dtsi
+@@ -121,12 +121,6 @@
+ reg = <0 0x151f8000 0 0x2000>;
+ no-map;
+ };
+-
+- wo_boot: wo-boot@15194000 {
+- reg = <0 0x15194000 0 0x1000>;
+- no-map;
+- };
+-
+ };
+
+ timer {
+@@ -540,10 +534,11 @@
+ interrupt-parent = <&gic>;
+ interrupts = <GIC_SPI 205 IRQ_TYPE_LEVEL_HIGH>;
+ memory-region = <&wo_emi0>, <&wo_ilm0>, <&wo_dlm0>,
+- <&wo_data>, <&wo_boot>;
++ <&wo_data>;
+ memory-region-names = "wo-emi", "wo-ilm", "wo-dlm",
+- "wo-data", "wo-boot";
++ "wo-data";
+ mediatek,wo-ccif = <&wo_ccif0>;
++ mediatek,wo-cpuboot = <&wo_cpuboot>;
+ };
+
+ wed1: wed@15011000 {
+@@ -553,10 +548,11 @@
+ interrupt-parent = <&gic>;
+ interrupts = <GIC_SPI 206 IRQ_TYPE_LEVEL_HIGH>;
+ memory-region = <&wo_emi1>, <&wo_ilm1>, <&wo_dlm1>,
+- <&wo_data>, <&wo_boot>;
++ <&wo_data>;
+ memory-region-names = "wo-emi", "wo-ilm", "wo-dlm",
+- "wo-data", "wo-boot";
++ "wo-data";
+ mediatek,wo-ccif = <&wo_ccif1>;
++ mediatek,wo-cpuboot = <&wo_cpuboot>;
+ };
+
+ wo_ccif0: syscon@151a5000 {
+@@ -573,6 +569,11 @@
+ interrupts = <GIC_SPI 212 IRQ_TYPE_LEVEL_HIGH>;
+ };
+
++ wo_cpuboot: syscon@15194000 {
++ compatible = "mediatek,mt7986-wo-cpuboot", "syscon";
++ reg = <0 0x15194000 0 0x1000>;
++ };
++
+ eth: ethernet@15100000 {
+ compatible = "mediatek,mt7986-eth";
+ reg = <0 0x15100000 0 0x80000>;
--- /dev/null
+From f292d1bf83ec160bef2532b58aa08f5b71041923 Mon Sep 17 00:00:00 2001
+Message-Id: <f292d1bf83ec160bef2532b58aa08f5b71041923.1678716918.git.lorenzo@kernel.org>
+In-Reply-To: <3cf212c4ce6cd72c09bc47f35f539ba0afd4d106.1678716918.git.lorenzo@kernel.org>
+References: <3cf212c4ce6cd72c09bc47f35f539ba0afd4d106.1678716918.git.lorenzo@kernel.org>
+From: Lorenzo Bianconi <lorenzo@kernel.org>
+Date: Sat, 11 Mar 2023 18:13:04 +0100
+Subject: [PATCH net-next 2/2] net: ethernet: mtk_wed: move cpuboot in a
+ dedicated dts node
+
+Since the cpuboot memory region is not part of the RAM SoC, move cpuboot
+in a deidicated syscon node.
+This patch helps to keep backward-compatibility with older version of
+uboot codebase where we have a limit of 8 reserved-memory dts child
+nodes.
+Keep backward-compatibility with older dts version where cpuboot was
+defined as reserved-memory child node.
+
+Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
+---
+ drivers/net/ethernet/mediatek/mtk_wed_mcu.c | 34 +++++++++++++++++----
+ drivers/net/ethernet/mediatek/mtk_wed_wo.h | 3 +-
+ 2 files changed, 30 insertions(+), 7 deletions(-)
+
+--- a/drivers/net/ethernet/mediatek/mtk_wed_mcu.c
++++ b/drivers/net/ethernet/mediatek/mtk_wed_mcu.c
+@@ -34,12 +34,23 @@ static struct mtk_wed_wo_memory_region m
+
+ static u32 wo_r32(struct mtk_wed_wo *wo, u32 reg)
+ {
+- return readl(mem_region[MTK_WED_WO_REGION_BOOT].addr + reg);
++ u32 val;
++
++ if (!wo->boot_regmap)
++ return readl(mem_region[MTK_WED_WO_REGION_BOOT].addr + reg);
++
++ if (regmap_read(wo->boot_regmap, reg, &val))
++ val = ~0;
++
++ return val;
+ }
+
+ static void wo_w32(struct mtk_wed_wo *wo, u32 reg, u32 val)
+ {
+- writel(val, mem_region[MTK_WED_WO_REGION_BOOT].addr + reg);
++ if (wo->boot_regmap)
++ regmap_write(wo->boot_regmap, reg, val);
++ else
++ writel(val, mem_region[MTK_WED_WO_REGION_BOOT].addr + reg);
+ }
+
+ static struct sk_buff *
+@@ -313,6 +324,9 @@ mtk_wed_mcu_load_firmware(struct mtk_wed
+ u32 val, boot_cr;
+ int ret, i;
+
++ wo->boot_regmap = syscon_regmap_lookup_by_phandle(wo->hw->node,
++ "mediatek,wo-cpuboot");
++
+ /* load firmware region metadata */
+ for (i = 0; i < ARRAY_SIZE(mem_region); i++) {
+ int index = of_property_match_string(wo->hw->node,
+@@ -321,6 +335,9 @@ mtk_wed_mcu_load_firmware(struct mtk_wed
+ if (index < 0)
+ continue;
+
++ if (index == MTK_WED_WO_REGION_BOOT && !IS_ERR(wo->boot_regmap))
++ continue;
++
+ ret = mtk_wed_get_reserved_memory_region(wo->hw, index, &mem_region[i]);
+ if (ret)
+ return ret;
+--- a/drivers/net/ethernet/mediatek/mtk_wed_wo.h
++++ b/drivers/net/ethernet/mediatek/mtk_wed_wo.h
+@@ -231,6 +231,7 @@ struct mtk_wed_wo_queue {
+ struct mtk_wed_wo {
+ struct mtk_wed_hw *hw;
+
++ struct regmap *boot_regmap;
+ struct mtk_wed_wo_queue q_tx;
+ struct mtk_wed_wo_queue q_rx;
+
--- /dev/null
+From f3565e6c2276411275e707a5442d3f69cc111273 Mon Sep 17 00:00:00 2001
+Message-Id: <f3565e6c2276411275e707a5442d3f69cc111273.1678718888.git.lorenzo@kernel.org>
+From: Lorenzo Bianconi <lorenzo@kernel.org>
+Date: Sun, 12 Mar 2023 18:51:47 +0100
+Subject: [PATCH net-next 1/3] net: ethernet: mtk_wed: move ilm a dedicated dts
+ node
+
+Since the ilm memory region is not part of the RAM SoC, move ilm in a
+deidicated syscon node.
+This patch helps to keep backward-compatibility with older version of
+uboot codebase where we have a limit of 8 reserved-memory dts child
+nodes.
+Keep backward-compatibility with older dts version where ilm was defined
+as reserved-memory child node.
+
+Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
+---
+ drivers/net/ethernet/mediatek/mtk_wed_mcu.c | 55 ++++++++++++++++++---
+ 1 file changed, 49 insertions(+), 6 deletions(-)
+
+--- a/drivers/net/ethernet/mediatek/mtk_wed_mcu.c
++++ b/drivers/net/ethernet/mediatek/mtk_wed_mcu.c
+@@ -316,6 +316,39 @@ next:
+ }
+
+ static int
++mtk_wed_mcu_load_ilm(struct mtk_wed_wo *wo)
++{
++ struct mtk_wed_wo_memory_region *ilm_region;
++ struct resource res;
++ struct device_node *np;
++ int ret;
++
++ np = of_parse_phandle(wo->hw->node, "mediatek,wo-ilm", 0);
++ if (!np)
++ return 0;
++
++ ret = of_address_to_resource(np, 0, &res);
++ of_node_put(np);
++
++ if (ret < 0)
++ return ret;
++
++ ilm_region = &mem_region[MTK_WED_WO_REGION_ILM];
++ ilm_region->phy_addr = res.start;
++ ilm_region->size = resource_size(&res);
++ ilm_region->addr = devm_ioremap(wo->hw->dev, res.start,
++ resource_size(&res));
++
++ if (!IS_ERR(ilm_region->addr))
++ return 0;
++
++ ret = PTR_ERR(ilm_region->addr);
++ ilm_region->addr = NULL;
++
++ return ret;
++}
++
++static int
+ mtk_wed_mcu_load_firmware(struct mtk_wed_wo *wo)
+ {
+ const struct mtk_wed_fw_trailer *trailer;
+@@ -324,14 +357,20 @@ mtk_wed_mcu_load_firmware(struct mtk_wed
+ u32 val, boot_cr;
+ int ret, i;
+
++ mtk_wed_mcu_load_ilm(wo);
+ wo->boot_regmap = syscon_regmap_lookup_by_phandle(wo->hw->node,
+ "mediatek,wo-cpuboot");
+
+ /* load firmware region metadata */
+ for (i = 0; i < ARRAY_SIZE(mem_region); i++) {
+- int index = of_property_match_string(wo->hw->node,
+- "memory-region-names",
+- mem_region[i].name);
++ int index;
++
++ if (mem_region[i].addr)
++ continue;
++
++ index = of_property_match_string(wo->hw->node,
++ "memory-region-names",
++ mem_region[i].name);
+ if (index < 0)
+ continue;
+
--- /dev/null
+From b74ba226be2c45091b93bd49192bdd6d2178729e Mon Sep 17 00:00:00 2001
+Message-Id: <b74ba226be2c45091b93bd49192bdd6d2178729e.1678718888.git.lorenzo@kernel.org>
+In-Reply-To: <f3565e6c2276411275e707a5442d3f69cc111273.1678718888.git.lorenzo@kernel.org>
+References: <f3565e6c2276411275e707a5442d3f69cc111273.1678718888.git.lorenzo@kernel.org>
+From: Lorenzo Bianconi <lorenzo@kernel.org>
+Date: Mon, 13 Mar 2023 15:45:16 +0100
+Subject: [PATCH net-next 3/3] net: ethernet: mtk_wed: move dlm a dedicated dts
+ node
+
+Since the dlm memory region is not part of the RAM SoC, move dlm in a
+deidicated syscon node.
+This patch helps to keep backward-compatibility with older version of
+uboot codebase where we have a limit of 8 reserved-memory dts child
+nodes.
+Keep backward-compatibility with older dts version where dlm was defined
+as reserved-memory child node.
+
+Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
+---
+ drivers/net/ethernet/mediatek/mtk_wed.c | 19 +++++++++++++++++++
+ 1 file changed, 19 insertions(+)
+
+--- a/drivers/net/ethernet/mediatek/mtk_wed.c
++++ b/drivers/net/ethernet/mediatek/mtk_wed.c
+@@ -1320,6 +1320,24 @@ mtk_wed_rro_alloc(struct mtk_wed_device
+ struct device_node *np;
+ int index;
+
++ np = of_parse_phandle(dev->hw->node, "mediatek,wo-dlm", 0);
++ if (np) {
++ struct resource res;
++ int ret;
++
++ ret = of_address_to_resource(np, 0, &res);
++ of_node_put(np);
++
++ if (ret < 0)
++ return ret;
++
++ dev->rro.miod_phys = res.start;
++ goto out;
++ }
++
++ /* For backward compatibility, we need to check if DLM
++ * node is defined through reserved memory property.
++ */
+ index = of_property_match_string(dev->hw->node, "memory-region-names",
+ "wo-dlm");
+ if (index < 0)
+@@ -1336,6 +1354,7 @@ mtk_wed_rro_alloc(struct mtk_wed_device
+ return -ENODEV;
+
+ dev->rro.miod_phys = rmem->base;
++out:
+ dev->rro.fdbk_phys = MTK_WED_MIOD_COUNT + dev->rro.miod_phys;
+
+ return mtk_wed_rro_ring_alloc(dev, &dev->rro.ring,
--- /dev/null
+From 01561065af5bf1d2a4244896d897e3a1eafbcd46 Mon Sep 17 00:00:00 2001
+Message-Id: <01561065af5bf1d2a4244896d897e3a1eafbcd46.1678717704.git.lorenzo@kernel.org>
+From: Lorenzo Bianconi <lorenzo@kernel.org>
+Date: Mon, 13 Mar 2023 15:10:56 +0100
+Subject: [PATCH net-next] arm64: dts: mt7986: move ilm in a dedicated node
+
+Since the ilm memory region is not part of the RAM SoC, move ilm in a
+deidicated syscon node.
+This patch helps to keep backward-compatibility with older version of
+uboot codebase where we have a limit of 8 reserved-memory dts child
+nodes.
+
+Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
+---
+ arch/arm64/boot/dts/mediatek/mt7986a.dtsi | 34 +++++++++++------------
+ 1 file changed, 16 insertions(+), 18 deletions(-)
+
+--- a/arch/arm64/boot/dts/mediatek/mt7986a.dtsi
++++ b/arch/arm64/boot/dts/mediatek/mt7986a.dtsi
+@@ -97,16 +97,6 @@
+ no-map;
+ };
+
+- wo_ilm0: wo-ilm@151e0000 {
+- reg = <0 0x151e0000 0 0x8000>;
+- no-map;
+- };
+-
+- wo_ilm1: wo-ilm@151f0000 {
+- reg = <0 0x151f0000 0 0x8000>;
+- no-map;
+- };
+-
+ wo_data: wo-data@4fd80000 {
+ reg = <0 0x4fd80000 0 0x240000>;
+ no-map;
+@@ -533,11 +523,10 @@
+ reg = <0 0x15010000 0 0x1000>;
+ interrupt-parent = <&gic>;
+ interrupts = <GIC_SPI 205 IRQ_TYPE_LEVEL_HIGH>;
+- memory-region = <&wo_emi0>, <&wo_ilm0>, <&wo_dlm0>,
+- <&wo_data>;
+- memory-region-names = "wo-emi", "wo-ilm", "wo-dlm",
+- "wo-data";
++ memory-region = <&wo_emi0>, <&wo_dlm0>, <&wo_data>;
++ memory-region-names = "wo-emi", "wo-dlm", "wo-data";
+ mediatek,wo-ccif = <&wo_ccif0>;
++ mediatek,wo-ilm = <&wo_ilm0>;
+ mediatek,wo-cpuboot = <&wo_cpuboot>;
+ };
+
+@@ -547,11 +536,10 @@
+ reg = <0 0x15011000 0 0x1000>;
+ interrupt-parent = <&gic>;
+ interrupts = <GIC_SPI 206 IRQ_TYPE_LEVEL_HIGH>;
+- memory-region = <&wo_emi1>, <&wo_ilm1>, <&wo_dlm1>,
+- <&wo_data>;
+- memory-region-names = "wo-emi", "wo-ilm", "wo-dlm",
+- "wo-data";
++ memory-region = <&wo_emi1>, <&wo_dlm1>, <&wo_data>;
++ memory-region-names = "wo-emi", "wo-dlm", "wo-data";
+ mediatek,wo-ccif = <&wo_ccif1>;
++ mediatek,wo-ilm = <&wo_ilm1>;
+ mediatek,wo-cpuboot = <&wo_cpuboot>;
+ };
+
+@@ -569,6 +557,16 @@
+ interrupts = <GIC_SPI 212 IRQ_TYPE_LEVEL_HIGH>;
+ };
+
++ wo_ilm0: syscon@151e0000 {
++ compatible = "mediatek,mt7986-wo-ilm", "syscon";
++ reg = <0 0x151e0000 0 0x8000>;
++ };
++
++ wo_ilm1: syscon@151f0000 {
++ compatible = "mediatek,mt7986-wo-ilm", "syscon";
++ reg = <0 0x151f0000 0 0x8000>;
++ };
++
+ wo_cpuboot: syscon@15194000 {
+ compatible = "mediatek,mt7986-wo-cpuboot", "syscon";
+ reg = <0 0x15194000 0 0x1000>;
--- /dev/null
+From 9f76be683a8ec498563c294bc1cc279468058302 Mon Sep 17 00:00:00 2001
+Message-Id: <9f76be683a8ec498563c294bc1cc279468058302.1678719283.git.lorenzo@kernel.org>
+From: Lorenzo Bianconi <lorenzo@kernel.org>
+Date: Mon, 13 Mar 2023 15:53:30 +0100
+Subject: [PATCH net-next] arm64: dts: mt7986: move dlm in a dedicated node
+
+Since the dlm memory region is not part of the RAM SoC, move dlm in a
+deidicated syscon node.
+This patch helps to keep backward-compatibility with older version of
+uboot codebase where we have a limit of 8 reserved-memory dts child
+nodes.
+
+Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
+---
+ arch/arm64/boot/dts/mediatek/mt7986a.dtsi | 30 ++++++++++++-----------
+ 1 file changed, 16 insertions(+), 14 deletions(-)
+
+--- a/arch/arm64/boot/dts/mediatek/mt7986a.dtsi
++++ b/arch/arm64/boot/dts/mediatek/mt7986a.dtsi
+@@ -101,16 +101,6 @@
+ reg = <0 0x4fd80000 0 0x240000>;
+ no-map;
+ };
+-
+- wo_dlm0: wo-dlm@151e8000 {
+- reg = <0 0x151e8000 0 0x2000>;
+- no-map;
+- };
+-
+- wo_dlm1: wo-dlm@151f8000 {
+- reg = <0 0x151f8000 0 0x2000>;
+- no-map;
+- };
+ };
+
+ timer {
+@@ -523,10 +513,11 @@
+ reg = <0 0x15010000 0 0x1000>;
+ interrupt-parent = <&gic>;
+ interrupts = <GIC_SPI 205 IRQ_TYPE_LEVEL_HIGH>;
+- memory-region = <&wo_emi0>, <&wo_dlm0>, <&wo_data>;
+- memory-region-names = "wo-emi", "wo-dlm", "wo-data";
++ memory-region = <&wo_emi0>, <&wo_data>;
++ memory-region-names = "wo-emi", "wo-data";
+ mediatek,wo-ccif = <&wo_ccif0>;
+ mediatek,wo-ilm = <&wo_ilm0>;
++ mediatek,wo-dlm = <&wo_dlm0>;
+ mediatek,wo-cpuboot = <&wo_cpuboot>;
+ };
+
+@@ -536,10 +527,11 @@
+ reg = <0 0x15011000 0 0x1000>;
+ interrupt-parent = <&gic>;
+ interrupts = <GIC_SPI 206 IRQ_TYPE_LEVEL_HIGH>;
+- memory-region = <&wo_emi1>, <&wo_dlm1>, <&wo_data>;
+- memory-region-names = "wo-emi", "wo-dlm", "wo-data";
++ memory-region = <&wo_emi1>, <&wo_data>;
++ memory-region-names = "wo-emi", "wo-data";
+ mediatek,wo-ccif = <&wo_ccif1>;
+ mediatek,wo-ilm = <&wo_ilm1>;
++ mediatek,wo-dlm = <&wo_dlm1>;
+ mediatek,wo-cpuboot = <&wo_cpuboot>;
+ };
+
+@@ -567,6 +559,16 @@
+ reg = <0 0x151f0000 0 0x8000>;
+ };
+
++ wo_dlm0: syscon@151e8000 {
++ compatible = "mediatek,mt7986-wo-dlm", "syscon";
++ reg = <0 0x151e8000 0 0x2000>;
++ };
++
++ wo_dlm1: syscon@151f8000 {
++ compatible = "mediatek,mt7986-wo-dlm", "syscon";
++ reg = <0 0x151f8000 0 0x2000>;
++ };
++
+ wo_cpuboot: syscon@15194000 {
+ compatible = "mediatek,mt7986-wo-cpuboot", "syscon";
+ reg = <0 0x15194000 0 0x1000>;
--- /dev/null
+---
+ drivers/leds/Kconfig | 10 ++++++++++
+ drivers/leds/Makefile | 1 +
+ 2 files changed, 11 insertions(+)
+
+--- a/drivers/leds/Kconfig
++++ b/drivers/leds/Kconfig
+@@ -874,6 +874,16 @@ source "drivers/leds/flash/Kconfig"
+ comment "RGB LED drivers"
+ source "drivers/leds/rgb/Kconfig"
+
++config LEDS_SMARTRG_LED
++ tristate "LED support for Adtran SmartRG"
++ depends on LEDS_CLASS && I2C && OF
++ help
++ This option enables support for the Adtran SmartRG platform
++ system LED driver.
++
++ To compile this driver as a module, choose M here: the module
++ will be called leds-smartrg-system.
++
+ comment "LED Triggers"
+ source "drivers/leds/trigger/Kconfig"
+
+--- a/drivers/leds/Makefile
++++ b/drivers/leds/Makefile
+@@ -76,6 +76,7 @@ obj-$(CONFIG_LEDS_PWM) += leds-pwm.o
+ obj-$(CONFIG_LEDS_REGULATOR) += leds-regulator.o
+ obj-$(CONFIG_LEDS_S3C24XX) += leds-s3c24xx.o
+ obj-$(CONFIG_LEDS_SC27XX_BLTC) += leds-sc27xx-bltc.o
++obj-$(CONFIG_LEDS_SMARTRG_LED) += leds-smartrg-system.o
+ obj-$(CONFIG_LEDS_SUNFIRE) += leds-sunfire.o
+ obj-$(CONFIG_LEDS_SYSCON) += leds-syscon.o
+ obj-$(CONFIG_LEDS_TCA6507) += leds-tca6507.o
--- /dev/null
+From: Lorenzo Bianconi <lorenzo@kernel.org>
+Date: Thu, 2 Nov 2023 16:47:07 +0100
+Subject: [PATCH net-next 1/2] net: ethernet: mediatek: split tx and rx fields
+ in mtk_soc_data struct
+
+Split tx and rx fields in mtk_soc_data struct. This is a preliminary
+patch to roll back to QDMA for MT7986 SoC in order to fix a hw hang
+if the device receives a corrupted packet.
+
+Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
+---
+ drivers/net/ethernet/mediatek/mtk_eth_soc.c | 210 ++++++++++++--------
+ drivers/net/ethernet/mediatek/mtk_eth_soc.h | 29 +--
+ 2 files changed, 139 insertions(+), 100 deletions(-)
+
+--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c
++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
+@@ -1264,7 +1264,7 @@ static int mtk_init_fq_dma(struct mtk_et
+ eth->scratch_ring = eth->sram_base;
+ else
+ eth->scratch_ring = dma_alloc_coherent(eth->dma_dev,
+- cnt * soc->txrx.txd_size,
++ cnt * soc->tx.desc_size,
+ ð->phy_scratch_ring,
+ GFP_KERNEL);
+ if (unlikely(!eth->scratch_ring))
+@@ -1280,16 +1280,16 @@ static int mtk_init_fq_dma(struct mtk_et
+ if (unlikely(dma_mapping_error(eth->dma_dev, dma_addr)))
+ return -ENOMEM;
+
+- phy_ring_tail = eth->phy_scratch_ring + soc->txrx.txd_size * (cnt - 1);
++ phy_ring_tail = eth->phy_scratch_ring + soc->tx.desc_size * (cnt - 1);
+
+ for (i = 0; i < cnt; i++) {
+ struct mtk_tx_dma_v2 *txd;
+
+- txd = eth->scratch_ring + i * soc->txrx.txd_size;
++ txd = eth->scratch_ring + i * soc->tx.desc_size;
+ txd->txd1 = dma_addr + i * MTK_QDMA_PAGE_SIZE;
+ if (i < cnt - 1)
+ txd->txd2 = eth->phy_scratch_ring +
+- (i + 1) * soc->txrx.txd_size;
++ (i + 1) * soc->tx.desc_size;
+
+ txd->txd3 = TX_DMA_PLEN0(MTK_QDMA_PAGE_SIZE);
+ txd->txd4 = 0;
+@@ -1538,7 +1538,7 @@ static int mtk_tx_map(struct sk_buff *sk
+ if (itxd == ring->last_free)
+ return -ENOMEM;
+
+- itx_buf = mtk_desc_to_tx_buf(ring, itxd, soc->txrx.txd_size);
++ itx_buf = mtk_desc_to_tx_buf(ring, itxd, soc->tx.desc_size);
+ memset(itx_buf, 0, sizeof(*itx_buf));
+
+ txd_info.addr = dma_map_single(eth->dma_dev, skb->data, txd_info.size,
+@@ -1579,7 +1579,7 @@ static int mtk_tx_map(struct sk_buff *sk
+
+ memset(&txd_info, 0, sizeof(struct mtk_tx_dma_desc_info));
+ txd_info.size = min_t(unsigned int, frag_size,
+- soc->txrx.dma_max_len);
++ soc->tx.dma_max_len);
+ txd_info.qid = queue;
+ txd_info.last = i == skb_shinfo(skb)->nr_frags - 1 &&
+ !(frag_size - txd_info.size);
+@@ -1592,7 +1592,7 @@ static int mtk_tx_map(struct sk_buff *sk
+ mtk_tx_set_dma_desc(dev, txd, &txd_info);
+
+ tx_buf = mtk_desc_to_tx_buf(ring, txd,
+- soc->txrx.txd_size);
++ soc->tx.desc_size);
+ if (new_desc)
+ memset(tx_buf, 0, sizeof(*tx_buf));
+ tx_buf->data = (void *)MTK_DMA_DUMMY_DESC;
+@@ -1635,7 +1635,7 @@ static int mtk_tx_map(struct sk_buff *sk
+ } else {
+ int next_idx;
+
+- next_idx = NEXT_DESP_IDX(txd_to_idx(ring, txd, soc->txrx.txd_size),
++ next_idx = NEXT_DESP_IDX(txd_to_idx(ring, txd, soc->tx.desc_size),
+ ring->dma_size);
+ mtk_w32(eth, next_idx, MT7628_TX_CTX_IDX0);
+ }
+@@ -1644,7 +1644,7 @@ static int mtk_tx_map(struct sk_buff *sk
+
+ err_dma:
+ do {
+- tx_buf = mtk_desc_to_tx_buf(ring, itxd, soc->txrx.txd_size);
++ tx_buf = mtk_desc_to_tx_buf(ring, itxd, soc->tx.desc_size);
+
+ /* unmap dma */
+ mtk_tx_unmap(eth, tx_buf, NULL, false);
+@@ -1669,7 +1669,7 @@ static int mtk_cal_txd_req(struct mtk_et
+ for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) {
+ frag = &skb_shinfo(skb)->frags[i];
+ nfrags += DIV_ROUND_UP(skb_frag_size(frag),
+- eth->soc->txrx.dma_max_len);
++ eth->soc->tx.dma_max_len);
+ }
+ } else {
+ nfrags += skb_shinfo(skb)->nr_frags;
+@@ -1810,7 +1810,7 @@ static struct mtk_rx_ring *mtk_get_rx_ri
+
+ ring = ð->rx_ring[i];
+ idx = NEXT_DESP_IDX(ring->calc_idx, ring->dma_size);
+- rxd = ring->dma + idx * eth->soc->txrx.rxd_size;
++ rxd = ring->dma + idx * eth->soc->rx.desc_size;
+ if (rxd->rxd2 & RX_DMA_DONE) {
+ ring->calc_idx_update = true;
+ return ring;
+@@ -1978,7 +1978,7 @@ static int mtk_xdp_submit_frame(struct m
+ }
+ htxd = txd;
+
+- tx_buf = mtk_desc_to_tx_buf(ring, txd, soc->txrx.txd_size);
++ tx_buf = mtk_desc_to_tx_buf(ring, txd, soc->tx.desc_size);
+ memset(tx_buf, 0, sizeof(*tx_buf));
+ htx_buf = tx_buf;
+
+@@ -1997,7 +1997,7 @@ static int mtk_xdp_submit_frame(struct m
+ goto unmap;
+
+ tx_buf = mtk_desc_to_tx_buf(ring, txd,
+- soc->txrx.txd_size);
++ soc->tx.desc_size);
+ memset(tx_buf, 0, sizeof(*tx_buf));
+ n_desc++;
+ }
+@@ -2035,7 +2035,7 @@ static int mtk_xdp_submit_frame(struct m
+ } else {
+ int idx;
+
+- idx = txd_to_idx(ring, txd, soc->txrx.txd_size);
++ idx = txd_to_idx(ring, txd, soc->tx.desc_size);
+ mtk_w32(eth, NEXT_DESP_IDX(idx, ring->dma_size),
+ MT7628_TX_CTX_IDX0);
+ }
+@@ -2046,7 +2046,7 @@ static int mtk_xdp_submit_frame(struct m
+
+ unmap:
+ while (htxd != txd) {
+- tx_buf = mtk_desc_to_tx_buf(ring, htxd, soc->txrx.txd_size);
++ tx_buf = mtk_desc_to_tx_buf(ring, htxd, soc->tx.desc_size);
+ mtk_tx_unmap(eth, tx_buf, NULL, false);
+
+ htxd->txd3 = TX_DMA_LS0 | TX_DMA_OWNER_CPU;
+@@ -2177,7 +2177,7 @@ static int mtk_poll_rx(struct napi_struc
+ goto rx_done;
+
+ idx = NEXT_DESP_IDX(ring->calc_idx, ring->dma_size);
+- rxd = ring->dma + idx * eth->soc->txrx.rxd_size;
++ rxd = ring->dma + idx * eth->soc->rx.desc_size;
+ data = ring->data[idx];
+
+ if (!mtk_rx_get_desc(eth, &trxd, rxd))
+@@ -2312,7 +2312,7 @@ static int mtk_poll_rx(struct napi_struc
+ rxdcsum = &trxd.rxd4;
+ }
+
+- if (*rxdcsum & eth->soc->txrx.rx_dma_l4_valid)
++ if (*rxdcsum & eth->soc->rx.dma_l4_valid)
+ skb->ip_summed = CHECKSUM_UNNECESSARY;
+ else
+ skb_checksum_none_assert(skb);
+@@ -2436,7 +2436,7 @@ static int mtk_poll_tx_qdma(struct mtk_e
+ break;
+
+ tx_buf = mtk_desc_to_tx_buf(ring, desc,
+- eth->soc->txrx.txd_size);
++ eth->soc->tx.desc_size);
+ if (!tx_buf->data)
+ break;
+
+@@ -2487,7 +2487,7 @@ static int mtk_poll_tx_pdma(struct mtk_e
+ }
+ mtk_tx_unmap(eth, tx_buf, &bq, true);
+
+- desc = ring->dma + cpu * eth->soc->txrx.txd_size;
++ desc = ring->dma + cpu * eth->soc->tx.desc_size;
+ ring->last_free = desc;
+ atomic_inc(&ring->free_count);
+
+@@ -2577,7 +2577,7 @@ static int mtk_napi_rx(struct napi_struc
+ do {
+ int rx_done;
+
+- mtk_w32(eth, eth->soc->txrx.rx_irq_done_mask,
++ mtk_w32(eth, eth->soc->rx.irq_done_mask,
+ reg_map->pdma.irq_status);
+ rx_done = mtk_poll_rx(napi, budget - rx_done_total, eth);
+ rx_done_total += rx_done;
+@@ -2593,10 +2593,10 @@ static int mtk_napi_rx(struct napi_struc
+ return budget;
+
+ } while (mtk_r32(eth, reg_map->pdma.irq_status) &
+- eth->soc->txrx.rx_irq_done_mask);
++ eth->soc->rx.irq_done_mask);
+
+ if (napi_complete_done(napi, rx_done_total))
+- mtk_rx_irq_enable(eth, eth->soc->txrx.rx_irq_done_mask);
++ mtk_rx_irq_enable(eth, eth->soc->rx.irq_done_mask);
+
+ return rx_done_total;
+ }
+@@ -2605,7 +2605,7 @@ static int mtk_tx_alloc(struct mtk_eth *
+ {
+ const struct mtk_soc_data *soc = eth->soc;
+ struct mtk_tx_ring *ring = ð->tx_ring;
+- int i, sz = soc->txrx.txd_size;
++ int i, sz = soc->tx.desc_size;
+ struct mtk_tx_dma_v2 *txd;
+ int ring_size;
+ u32 ofs, val;
+@@ -2728,14 +2728,14 @@ static void mtk_tx_clean(struct mtk_eth
+ }
+ if (!MTK_HAS_CAPS(soc->caps, MTK_SRAM) && ring->dma) {
+ dma_free_coherent(eth->dma_dev,
+- ring->dma_size * soc->txrx.txd_size,
++ ring->dma_size * soc->tx.desc_size,
+ ring->dma, ring->phys);
+ ring->dma = NULL;
+ }
+
+ if (ring->dma_pdma) {
+ dma_free_coherent(eth->dma_dev,
+- ring->dma_size * soc->txrx.txd_size,
++ ring->dma_size * soc->tx.desc_size,
+ ring->dma_pdma, ring->phys_pdma);
+ ring->dma_pdma = NULL;
+ }
+@@ -2790,15 +2790,15 @@ static int mtk_rx_alloc(struct mtk_eth *
+ if (!MTK_HAS_CAPS(eth->soc->caps, MTK_SRAM) ||
+ rx_flag != MTK_RX_FLAGS_NORMAL) {
+ ring->dma = dma_alloc_coherent(eth->dma_dev,
+- rx_dma_size * eth->soc->txrx.rxd_size,
+- &ring->phys, GFP_KERNEL);
++ rx_dma_size * eth->soc->rx.desc_size,
++ &ring->phys, GFP_KERNEL);
+ } else {
+ struct mtk_tx_ring *tx_ring = ð->tx_ring;
+
+ ring->dma = tx_ring->dma + tx_ring_size *
+- eth->soc->txrx.txd_size * (ring_no + 1);
++ eth->soc->tx.desc_size * (ring_no + 1);
+ ring->phys = tx_ring->phys + tx_ring_size *
+- eth->soc->txrx.txd_size * (ring_no + 1);
++ eth->soc->tx.desc_size * (ring_no + 1);
+ }
+
+ if (!ring->dma)
+@@ -2809,7 +2809,7 @@ static int mtk_rx_alloc(struct mtk_eth *
+ dma_addr_t dma_addr;
+ void *data;
+
+- rxd = ring->dma + i * eth->soc->txrx.rxd_size;
++ rxd = ring->dma + i * eth->soc->rx.desc_size;
+ if (ring->page_pool) {
+ data = mtk_page_pool_get_buff(ring->page_pool,
+ &dma_addr, GFP_KERNEL);
+@@ -2900,7 +2900,7 @@ static void mtk_rx_clean(struct mtk_eth
+ if (!ring->data[i])
+ continue;
+
+- rxd = ring->dma + i * eth->soc->txrx.rxd_size;
++ rxd = ring->dma + i * eth->soc->rx.desc_size;
+ if (!rxd->rxd1)
+ continue;
+
+@@ -2917,7 +2917,7 @@ static void mtk_rx_clean(struct mtk_eth
+
+ if (!in_sram && ring->dma) {
+ dma_free_coherent(eth->dma_dev,
+- ring->dma_size * eth->soc->txrx.rxd_size,
++ ring->dma_size * eth->soc->rx.desc_size,
+ ring->dma, ring->phys);
+ ring->dma = NULL;
+ }
+@@ -3280,7 +3280,7 @@ static void mtk_dma_free(struct mtk_eth
+ netdev_reset_queue(eth->netdev[i]);
+ if (!MTK_HAS_CAPS(soc->caps, MTK_SRAM) && eth->scratch_ring) {
+ dma_free_coherent(eth->dma_dev,
+- MTK_QDMA_RING_SIZE * soc->txrx.txd_size,
++ MTK_QDMA_RING_SIZE * soc->tx.desc_size,
+ eth->scratch_ring, eth->phy_scratch_ring);
+ eth->scratch_ring = NULL;
+ eth->phy_scratch_ring = 0;
+@@ -3330,7 +3330,7 @@ static irqreturn_t mtk_handle_irq_rx(int
+
+ eth->rx_events++;
+ if (likely(napi_schedule_prep(ð->rx_napi))) {
+- mtk_rx_irq_disable(eth, eth->soc->txrx.rx_irq_done_mask);
++ mtk_rx_irq_disable(eth, eth->soc->rx.irq_done_mask);
+ __napi_schedule(ð->rx_napi);
+ }
+
+@@ -3356,9 +3356,9 @@ static irqreturn_t mtk_handle_irq(int ir
+ const struct mtk_reg_map *reg_map = eth->soc->reg_map;
+
+ if (mtk_r32(eth, reg_map->pdma.irq_mask) &
+- eth->soc->txrx.rx_irq_done_mask) {
++ eth->soc->rx.irq_done_mask) {
+ if (mtk_r32(eth, reg_map->pdma.irq_status) &
+- eth->soc->txrx.rx_irq_done_mask)
++ eth->soc->rx.irq_done_mask)
+ mtk_handle_irq_rx(irq, _eth);
+ }
+ if (mtk_r32(eth, reg_map->tx_irq_mask) & MTK_TX_DONE_INT) {
+@@ -3376,10 +3376,10 @@ static void mtk_poll_controller(struct n
+ struct mtk_eth *eth = mac->hw;
+
+ mtk_tx_irq_disable(eth, MTK_TX_DONE_INT);
+- mtk_rx_irq_disable(eth, eth->soc->txrx.rx_irq_done_mask);
++ mtk_rx_irq_disable(eth, eth->soc->rx.irq_done_mask);
+ mtk_handle_irq_rx(eth->irq[2], dev);
+ mtk_tx_irq_enable(eth, MTK_TX_DONE_INT);
+- mtk_rx_irq_enable(eth, eth->soc->txrx.rx_irq_done_mask);
++ mtk_rx_irq_enable(eth, eth->soc->rx.irq_done_mask);
+ }
+ #endif
+
+@@ -3545,7 +3545,7 @@ static int mtk_open(struct net_device *d
+ napi_enable(ð->tx_napi);
+ napi_enable(ð->rx_napi);
+ mtk_tx_irq_enable(eth, MTK_TX_DONE_INT);
+- mtk_rx_irq_enable(eth, soc->txrx.rx_irq_done_mask);
++ mtk_rx_irq_enable(eth, soc->rx.irq_done_mask);
+ refcount_set(ð->dma_refcnt, 1);
+ }
+ else
+@@ -3628,7 +3628,7 @@ static int mtk_stop(struct net_device *d
+ mtk_gdm_config(eth, MTK_GDMA_DROP_ALL);
+
+ mtk_tx_irq_disable(eth, MTK_TX_DONE_INT);
+- mtk_rx_irq_disable(eth, eth->soc->txrx.rx_irq_done_mask);
++ mtk_rx_irq_disable(eth, eth->soc->rx.irq_done_mask);
+ napi_disable(ð->tx_napi);
+ napi_disable(ð->rx_napi);
+
+@@ -4107,9 +4107,9 @@ static int mtk_hw_init(struct mtk_eth *e
+
+ /* FE int grouping */
+ mtk_w32(eth, MTK_TX_DONE_INT, reg_map->pdma.int_grp);
+- mtk_w32(eth, eth->soc->txrx.rx_irq_done_mask, reg_map->pdma.int_grp + 4);
++ mtk_w32(eth, eth->soc->rx.irq_done_mask, reg_map->pdma.int_grp + 4);
+ mtk_w32(eth, MTK_TX_DONE_INT, reg_map->qdma.int_grp);
+- mtk_w32(eth, eth->soc->txrx.rx_irq_done_mask, reg_map->qdma.int_grp + 4);
++ mtk_w32(eth, eth->soc->rx.irq_done_mask, reg_map->qdma.int_grp + 4);
+ mtk_w32(eth, 0x21021000, MTK_FE_INT_GRP);
+
+ if (mtk_is_netsys_v3_or_greater(eth)) {
+@@ -5270,11 +5270,15 @@ static const struct mtk_soc_data mt2701_
+ .required_clks = MT7623_CLKS_BITMAP,
+ .required_pctl = true,
+ .version = 1,
+- .txrx = {
+- .txd_size = sizeof(struct mtk_tx_dma),
+- .rxd_size = sizeof(struct mtk_rx_dma),
+- .rx_irq_done_mask = MTK_RX_DONE_INT,
+- .rx_dma_l4_valid = RX_DMA_L4_VALID,
++ .tx = {
++ .desc_size = sizeof(struct mtk_tx_dma),
++ .dma_max_len = MTK_TX_DMA_BUF_LEN,
++ .dma_len_offset = 16,
++ },
++ .rx = {
++ .desc_size = sizeof(struct mtk_rx_dma),
++ .irq_done_mask = MTK_RX_DONE_INT,
++ .dma_l4_valid = RX_DMA_L4_VALID,
+ .dma_max_len = MTK_TX_DMA_BUF_LEN,
+ .dma_len_offset = 16,
+ },
+@@ -5290,11 +5294,15 @@ static const struct mtk_soc_data mt7621_
+ .offload_version = 1,
+ .hash_offset = 2,
+ .foe_entry_size = MTK_FOE_ENTRY_V1_SIZE,
+- .txrx = {
+- .txd_size = sizeof(struct mtk_tx_dma),
+- .rxd_size = sizeof(struct mtk_rx_dma),
+- .rx_irq_done_mask = MTK_RX_DONE_INT,
+- .rx_dma_l4_valid = RX_DMA_L4_VALID,
++ .tx = {
++ .desc_size = sizeof(struct mtk_tx_dma),
++ .dma_max_len = MTK_TX_DMA_BUF_LEN,
++ .dma_len_offset = 16,
++ },
++ .rx = {
++ .desc_size = sizeof(struct mtk_rx_dma),
++ .irq_done_mask = MTK_RX_DONE_INT,
++ .dma_l4_valid = RX_DMA_L4_VALID,
+ .dma_max_len = MTK_TX_DMA_BUF_LEN,
+ .dma_len_offset = 16,
+ },
+@@ -5312,11 +5320,15 @@ static const struct mtk_soc_data mt7622_
+ .hash_offset = 2,
+ .has_accounting = true,
+ .foe_entry_size = MTK_FOE_ENTRY_V1_SIZE,
+- .txrx = {
+- .txd_size = sizeof(struct mtk_tx_dma),
+- .rxd_size = sizeof(struct mtk_rx_dma),
+- .rx_irq_done_mask = MTK_RX_DONE_INT,
+- .rx_dma_l4_valid = RX_DMA_L4_VALID,
++ .tx = {
++ .desc_size = sizeof(struct mtk_tx_dma),
++ .dma_max_len = MTK_TX_DMA_BUF_LEN,
++ .dma_len_offset = 16,
++ },
++ .rx = {
++ .desc_size = sizeof(struct mtk_rx_dma),
++ .irq_done_mask = MTK_RX_DONE_INT,
++ .dma_l4_valid = RX_DMA_L4_VALID,
+ .dma_max_len = MTK_TX_DMA_BUF_LEN,
+ .dma_len_offset = 16,
+ },
+@@ -5333,11 +5345,15 @@ static const struct mtk_soc_data mt7623_
+ .hash_offset = 2,
+ .foe_entry_size = MTK_FOE_ENTRY_V1_SIZE,
+ .disable_pll_modes = true,
+- .txrx = {
+- .txd_size = sizeof(struct mtk_tx_dma),
+- .rxd_size = sizeof(struct mtk_rx_dma),
+- .rx_irq_done_mask = MTK_RX_DONE_INT,
+- .rx_dma_l4_valid = RX_DMA_L4_VALID,
++ .tx = {
++ .desc_size = sizeof(struct mtk_tx_dma),
++ .dma_max_len = MTK_TX_DMA_BUF_LEN,
++ .dma_len_offset = 16,
++ },
++ .rx = {
++ .desc_size = sizeof(struct mtk_rx_dma),
++ .irq_done_mask = MTK_RX_DONE_INT,
++ .dma_l4_valid = RX_DMA_L4_VALID,
+ .dma_max_len = MTK_TX_DMA_BUF_LEN,
+ .dma_len_offset = 16,
+ },
+@@ -5352,11 +5368,15 @@ static const struct mtk_soc_data mt7629_
+ .required_pctl = false,
+ .has_accounting = true,
+ .version = 1,
+- .txrx = {
+- .txd_size = sizeof(struct mtk_tx_dma),
+- .rxd_size = sizeof(struct mtk_rx_dma),
+- .rx_irq_done_mask = MTK_RX_DONE_INT,
+- .rx_dma_l4_valid = RX_DMA_L4_VALID,
++ .tx = {
++ .desc_size = sizeof(struct mtk_tx_dma),
++ .dma_max_len = MTK_TX_DMA_BUF_LEN,
++ .dma_len_offset = 16,
++ },
++ .rx = {
++ .desc_size = sizeof(struct mtk_rx_dma),
++ .irq_done_mask = MTK_RX_DONE_INT,
++ .dma_l4_valid = RX_DMA_L4_VALID,
+ .dma_max_len = MTK_TX_DMA_BUF_LEN,
+ .dma_len_offset = 16,
+ },
+@@ -5374,11 +5394,15 @@ static const struct mtk_soc_data mt7981_
+ .hash_offset = 4,
+ .has_accounting = true,
+ .foe_entry_size = MTK_FOE_ENTRY_V2_SIZE,
+- .txrx = {
+- .txd_size = sizeof(struct mtk_tx_dma_v2),
+- .rxd_size = sizeof(struct mtk_rx_dma_v2),
+- .rx_irq_done_mask = MTK_RX_DONE_INT_V2,
+- .rx_dma_l4_valid = RX_DMA_L4_VALID_V2,
++ .tx = {
++ .desc_size = sizeof(struct mtk_tx_dma_v2),
++ .dma_max_len = MTK_TX_DMA_BUF_LEN_V2,
++ .dma_len_offset = 8,
++ },
++ .rx = {
++ .desc_size = sizeof(struct mtk_rx_dma_v2),
++ .irq_done_mask = MTK_RX_DONE_INT_V2,
++ .dma_l4_valid = RX_DMA_L4_VALID_V2,
+ .dma_max_len = MTK_TX_DMA_BUF_LEN_V2,
+ .dma_len_offset = 8,
+ },
+@@ -5396,11 +5420,15 @@ static const struct mtk_soc_data mt7986_
+ .hash_offset = 4,
+ .has_accounting = true,
+ .foe_entry_size = MTK_FOE_ENTRY_V2_SIZE,
+- .txrx = {
+- .txd_size = sizeof(struct mtk_tx_dma_v2),
+- .rxd_size = sizeof(struct mtk_rx_dma_v2),
+- .rx_irq_done_mask = MTK_RX_DONE_INT_V2,
+- .rx_dma_l4_valid = RX_DMA_L4_VALID_V2,
++ .tx = {
++ .desc_size = sizeof(struct mtk_tx_dma_v2),
++ .dma_max_len = MTK_TX_DMA_BUF_LEN_V2,
++ .dma_len_offset = 8,
++ },
++ .rx = {
++ .desc_size = sizeof(struct mtk_rx_dma_v2),
++ .irq_done_mask = MTK_RX_DONE_INT_V2,
++ .dma_l4_valid = RX_DMA_L4_VALID_V2,
+ .dma_max_len = MTK_TX_DMA_BUF_LEN_V2,
+ .dma_len_offset = 8,
+ },
+@@ -5418,11 +5446,15 @@ static const struct mtk_soc_data mt7988_
+ .hash_offset = 4,
+ .has_accounting = true,
+ .foe_entry_size = MTK_FOE_ENTRY_V3_SIZE,
+- .txrx = {
+- .txd_size = sizeof(struct mtk_tx_dma_v2),
+- .rxd_size = sizeof(struct mtk_rx_dma_v2),
+- .rx_irq_done_mask = MTK_RX_DONE_INT_V2,
+- .rx_dma_l4_valid = RX_DMA_L4_VALID_V2,
++ .tx = {
++ .desc_size = sizeof(struct mtk_tx_dma_v2),
++ .dma_max_len = MTK_TX_DMA_BUF_LEN_V2,
++ .dma_len_offset = 8,
++ },
++ .rx = {
++ .desc_size = sizeof(struct mtk_rx_dma_v2),
++ .irq_done_mask = MTK_RX_DONE_INT_V2,
++ .dma_l4_valid = RX_DMA_L4_VALID_V2,
+ .dma_max_len = MTK_TX_DMA_BUF_LEN_V2,
+ .dma_len_offset = 8,
+ },
+@@ -5435,11 +5467,15 @@ static const struct mtk_soc_data rt5350_
+ .required_clks = MT7628_CLKS_BITMAP,
+ .required_pctl = false,
+ .version = 1,
+- .txrx = {
+- .txd_size = sizeof(struct mtk_tx_dma),
+- .rxd_size = sizeof(struct mtk_rx_dma),
+- .rx_irq_done_mask = MTK_RX_DONE_INT,
+- .rx_dma_l4_valid = RX_DMA_L4_VALID_PDMA,
++ .tx = {
++ .desc_size = sizeof(struct mtk_tx_dma),
++ .dma_max_len = MTK_TX_DMA_BUF_LEN,
++ .dma_len_offset = 16,
++ },
++ .rx = {
++ .desc_size = sizeof(struct mtk_rx_dma),
++ .irq_done_mask = MTK_RX_DONE_INT,
++ .dma_l4_valid = RX_DMA_L4_VALID_PDMA,
+ .dma_max_len = MTK_TX_DMA_BUF_LEN,
+ .dma_len_offset = 16,
+ },
+--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h
++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h
+@@ -327,8 +327,8 @@
+ /* QDMA descriptor txd3 */
+ #define TX_DMA_OWNER_CPU BIT(31)
+ #define TX_DMA_LS0 BIT(30)
+-#define TX_DMA_PLEN0(x) (((x) & eth->soc->txrx.dma_max_len) << eth->soc->txrx.dma_len_offset)
+-#define TX_DMA_PLEN1(x) ((x) & eth->soc->txrx.dma_max_len)
++#define TX_DMA_PLEN0(x) (((x) & eth->soc->tx.dma_max_len) << eth->soc->tx.dma_len_offset)
++#define TX_DMA_PLEN1(x) ((x) & eth->soc->tx.dma_max_len)
+ #define TX_DMA_SWC BIT(14)
+ #define TX_DMA_PQID GENMASK(3, 0)
+ #define TX_DMA_ADDR64_MASK GENMASK(3, 0)
+@@ -348,8 +348,8 @@
+ /* QDMA descriptor rxd2 */
+ #define RX_DMA_DONE BIT(31)
+ #define RX_DMA_LSO BIT(30)
+-#define RX_DMA_PREP_PLEN0(x) (((x) & eth->soc->txrx.dma_max_len) << eth->soc->txrx.dma_len_offset)
+-#define RX_DMA_GET_PLEN0(x) (((x) >> eth->soc->txrx.dma_len_offset) & eth->soc->txrx.dma_max_len)
++#define RX_DMA_PREP_PLEN0(x) (((x) & eth->soc->rx.dma_max_len) << eth->soc->rx.dma_len_offset)
++#define RX_DMA_GET_PLEN0(x) (((x) >> eth->soc->rx.dma_len_offset) & eth->soc->rx.dma_max_len)
+ #define RX_DMA_VTAG BIT(15)
+ #define RX_DMA_ADDR64_MASK GENMASK(3, 0)
+ #if IS_ENABLED(CONFIG_64BIT)
+@@ -1209,10 +1209,9 @@ struct mtk_reg_map {
+ * @foe_entry_size Foe table entry size.
+ * @has_accounting Bool indicating support for accounting of
+ * offloaded flows.
+- * @txd_size Tx DMA descriptor size.
+- * @rxd_size Rx DMA descriptor size.
+- * @rx_irq_done_mask Rx irq done register mask.
+- * @rx_dma_l4_valid Rx DMA valid register mask.
++ * @desc_size Tx/Rx DMA descriptor size.
++ * @irq_done_mask Rx irq done register mask.
++ * @dma_l4_valid Rx DMA valid register mask.
+ * @dma_max_len Max DMA tx/rx buffer length.
+ * @dma_len_offset Tx/Rx DMA length field offset.
+ */
+@@ -1230,13 +1229,17 @@ struct mtk_soc_data {
+ bool has_accounting;
+ bool disable_pll_modes;
+ struct {
+- u32 txd_size;
+- u32 rxd_size;
+- u32 rx_irq_done_mask;
+- u32 rx_dma_l4_valid;
++ u32 desc_size;
+ u32 dma_max_len;
+ u32 dma_len_offset;
+- } txrx;
++ } tx;
++ struct {
++ u32 desc_size;
++ u32 irq_done_mask;
++ u32 dma_l4_valid;
++ u32 dma_max_len;
++ u32 dma_len_offset;
++ } rx;
+ };
+
+ #define MTK_DMA_MONITOR_TIMEOUT msecs_to_jiffies(1000)
--- /dev/null
+From: Daniel Golle <daniel@makrotopia.org>
+Date: Tue, 10 Oct 2023 21:06:43 +0200
+Subject: [PATCH net-next 2/2] net: ethernet: mediatek: use QDMA instead of
+ ADMAv2 on MT7981 and MT7986
+
+ADMA is plagued by RX hangs which can't easily detected and happen upon
+receival of a corrupted package.
+Use QDMA just like on netsys v1 which is also still present and usable, and
+doesn't suffer from that problem.
+
+Co-developed-by: Lorenzo Bianconi <lorenzo@kernel.org>
+Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
+Signed-off-by: Daniel Golle <daniel@makrotopia.org>
+---
+ drivers/net/ethernet/mediatek/mtk_eth_soc.c | 46 ++++++++++-----------
+ 1 file changed, 23 insertions(+), 23 deletions(-)
+
+--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c
++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
+@@ -110,16 +110,16 @@ static const struct mtk_reg_map mt7986_r
+ .tx_irq_mask = 0x461c,
+ .tx_irq_status = 0x4618,
+ .pdma = {
+- .rx_ptr = 0x6100,
+- .rx_cnt_cfg = 0x6104,
+- .pcrx_ptr = 0x6108,
+- .glo_cfg = 0x6204,
+- .rst_idx = 0x6208,
+- .delay_irq = 0x620c,
+- .irq_status = 0x6220,
+- .irq_mask = 0x6228,
+- .adma_rx_dbg0 = 0x6238,
+- .int_grp = 0x6250,
++ .rx_ptr = 0x4100,
++ .rx_cnt_cfg = 0x4104,
++ .pcrx_ptr = 0x4108,
++ .glo_cfg = 0x4204,
++ .rst_idx = 0x4208,
++ .delay_irq = 0x420c,
++ .irq_status = 0x4220,
++ .irq_mask = 0x4228,
++ .adma_rx_dbg0 = 0x4238,
++ .int_grp = 0x4250,
+ },
+ .qdma = {
+ .qtx_cfg = 0x4400,
+@@ -1232,7 +1232,7 @@ static bool mtk_rx_get_desc(struct mtk_e
+ rxd->rxd1 = READ_ONCE(dma_rxd->rxd1);
+ rxd->rxd3 = READ_ONCE(dma_rxd->rxd3);
+ rxd->rxd4 = READ_ONCE(dma_rxd->rxd4);
+- if (mtk_is_netsys_v2_or_greater(eth)) {
++ if (mtk_is_netsys_v3_or_greater(eth)) {
+ rxd->rxd5 = READ_ONCE(dma_rxd->rxd5);
+ rxd->rxd6 = READ_ONCE(dma_rxd->rxd6);
+ }
+@@ -2184,7 +2184,7 @@ static int mtk_poll_rx(struct napi_struc
+ break;
+
+ /* find out which mac the packet come from. values start at 1 */
+- if (mtk_is_netsys_v2_or_greater(eth)) {
++ if (mtk_is_netsys_v3_or_greater(eth)) {
+ u32 val = RX_DMA_GET_SPORT_V2(trxd.rxd5);
+
+ switch (val) {
+@@ -2296,7 +2296,7 @@ static int mtk_poll_rx(struct napi_struc
+ skb->dev = netdev;
+ bytes += skb->len;
+
+- if (mtk_is_netsys_v2_or_greater(eth)) {
++ if (mtk_is_netsys_v3_or_greater(eth)) {
+ reason = FIELD_GET(MTK_RXD5_PPE_CPU_REASON, trxd.rxd5);
+ hash = trxd.rxd5 & MTK_RXD5_FOE_ENTRY;
+ if (hash != MTK_RXD5_FOE_ENTRY)
+@@ -2846,7 +2846,7 @@ static int mtk_rx_alloc(struct mtk_eth *
+
+ rxd->rxd3 = 0;
+ rxd->rxd4 = 0;
+- if (mtk_is_netsys_v2_or_greater(eth)) {
++ if (mtk_is_netsys_v3_or_greater(eth)) {
+ rxd->rxd5 = 0;
+ rxd->rxd6 = 0;
+ rxd->rxd7 = 0;
+@@ -4053,7 +4053,7 @@ static int mtk_hw_init(struct mtk_eth *e
+ else
+ mtk_hw_reset(eth);
+
+- if (mtk_is_netsys_v2_or_greater(eth)) {
++ if (mtk_is_netsys_v3_or_greater(eth)) {
+ /* Set FE to PDMAv2 if necessary */
+ val = mtk_r32(eth, MTK_FE_GLO_MISC);
+ mtk_w32(eth, val | BIT(4), MTK_FE_GLO_MISC);
+@@ -5400,11 +5400,11 @@ static const struct mtk_soc_data mt7981_
+ .dma_len_offset = 8,
+ },
+ .rx = {
+- .desc_size = sizeof(struct mtk_rx_dma_v2),
+- .irq_done_mask = MTK_RX_DONE_INT_V2,
++ .desc_size = sizeof(struct mtk_rx_dma),
++ .irq_done_mask = MTK_RX_DONE_INT,
+ .dma_l4_valid = RX_DMA_L4_VALID_V2,
+- .dma_max_len = MTK_TX_DMA_BUF_LEN_V2,
+- .dma_len_offset = 8,
++ .dma_max_len = MTK_TX_DMA_BUF_LEN,
++ .dma_len_offset = 16,
+ },
+ };
+
+@@ -5426,11 +5426,11 @@ static const struct mtk_soc_data mt7986_
+ .dma_len_offset = 8,
+ },
+ .rx = {
+- .desc_size = sizeof(struct mtk_rx_dma_v2),
+- .irq_done_mask = MTK_RX_DONE_INT_V2,
++ .desc_size = sizeof(struct mtk_rx_dma),
++ .irq_done_mask = MTK_RX_DONE_INT,
+ .dma_l4_valid = RX_DMA_L4_VALID_V2,
+- .dma_max_len = MTK_TX_DMA_BUF_LEN_V2,
+- .dma_len_offset = 8,
++ .dma_max_len = MTK_TX_DMA_BUF_LEN,
++ .dma_len_offset = 16,
+ },
+ };
+
--- /dev/null
+From: Felix Fietkau <nbd@nbd.name>
+Date: Thu, 18 Jan 2024 12:51:32 +0100
+Subject: [PATCH] net: ethernet: mtk_eth_soc: fix WED + wifi reset
+
+The WLAN + WED reset sequence relies on being able to receive interrupts from
+the card, in order to synchronize individual steps with the firmware.
+When WED is stopped, leave interrupts running and rely on the driver turning
+off unwanted ones.
+WED DMA also needs to be disabled before resetting.
+
+Fixes: f78cd9c783e0 ("net: ethernet: mtk_wed: update mtk_wed_stop")
+Signed-off-by: Felix Fietkau <nbd@nbd.name>
+---
+
+--- a/drivers/net/ethernet/mediatek/mtk_wed.c
++++ b/drivers/net/ethernet/mediatek/mtk_wed.c
+@@ -1071,13 +1071,13 @@ mtk_wed_dma_disable(struct mtk_wed_devic
+ static void
+ mtk_wed_stop(struct mtk_wed_device *dev)
+ {
++ mtk_wed_dma_disable(dev);
+ mtk_wed_set_ext_int(dev, false);
+
+ wed_w32(dev, MTK_WED_WPDMA_INT_TRIGGER, 0);
+ wed_w32(dev, MTK_WED_WDMA_INT_TRIGGER, 0);
+ wdma_w32(dev, MTK_WDMA_INT_MASK, 0);
+ wdma_w32(dev, MTK_WDMA_INT_GRP2, 0);
+- wed_w32(dev, MTK_WED_WPDMA_INT_MASK, 0);
+
+ if (!mtk_wed_get_rx_capa(dev))
+ return;
+@@ -1090,7 +1090,6 @@ static void
+ mtk_wed_deinit(struct mtk_wed_device *dev)
+ {
+ mtk_wed_stop(dev);
+- mtk_wed_dma_disable(dev);
+
+ wed_clr(dev, MTK_WED_CTRL,
+ MTK_WED_CTRL_WDMA_INT_AGENT_EN |
+@@ -2621,9 +2620,6 @@ mtk_wed_irq_get(struct mtk_wed_device *d
+ static void
+ mtk_wed_irq_set_mask(struct mtk_wed_device *dev, u32 mask)
+ {
+- if (!dev->running)
+- return;
+-
+ mtk_wed_set_ext_int(dev, !!mask);
+ wed_w32(dev, MTK_WED_INT_MASK, mask);
+ }