summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--arch/arm/dts/Makefile5
-rw-r--r--arch/arm/dts/mt8189.dtsi325
-rw-r--r--arch/arm/dts/mt8371-genio-common-ufs.dtso18
-rw-r--r--arch/arm/dts/mt8371-genio-common.dtsi70
-rw-r--r--board/mediatek/MAINTAINERS8
-rw-r--r--configs/mt8189-ufs.config8
-rw-r--r--configs/mt8189.config8
-rw-r--r--configs/mt8195.config28
-rw-r--r--configs/mt8371_genio_520_evk_ufs_defconfig4
-rw-r--r--configs/mt8391_genio_720_evk_ufs_defconfig4
-rw-r--r--configs/mt8395_genio_1200_evk_defconfig26
-rw-r--r--configs/mt8395_genio_1200_evk_ufs_defconfig9
-rw-r--r--drivers/clk/mediatek/clk-mt8189.c44
-rw-r--r--drivers/clk/mediatek/clk-mtk.c24
-rw-r--r--drivers/phy/Kconfig11
-rw-r--r--drivers/phy/Makefile1
-rw-r--r--drivers/phy/phy-mtk-ufs.c128
-rw-r--r--drivers/phy/phy-mtk-xsphy.c600
-rw-r--r--drivers/pinctrl/mediatek/pinctrl-mt7981.c16
-rw-r--r--drivers/ufs/ufs-mediatek.c42
-rw-r--r--drivers/ufs/ufs-mediatek.h2
21 files changed, 1247 insertions, 134 deletions
diff --git a/arch/arm/dts/Makefile b/arch/arm/dts/Makefile
index 4085d4c2de1..bff341d6118 100644
--- a/arch/arm/dts/Makefile
+++ b/arch/arm/dts/Makefile
@@ -1105,6 +1105,9 @@ dtb-$(CONFIG_SOC_K3_AM62D2) += k3-am62d2-r5-evm.dtb
dtb-$(CONFIG_SOC_K3_AM62P5) += k3-am62p5-r5-sk.dtb \
k3-am62p5-verdin-r5.dtb
+mt8371-genio-520-evk-ufs-dtbs := mt8371-genio-520-evk.dtb mt8371-genio-common-ufs.dtbo
+mt8391-genio-720-evk-ufs-dtbs := mt8391-genio-720-evk.dtb mt8371-genio-common-ufs.dtbo
+
dtb-$(CONFIG_ARCH_MEDIATEK) += \
mt7622-rfb.dtb \
mt7623a-unielec-u7623-02-emmc.dtb \
@@ -1125,7 +1128,9 @@ dtb-$(CONFIG_ARCH_MEDIATEK) += \
mt7988-sd-rfb.dtb \
mt8183-pumpkin.dtb \
mt8371-genio-520-evk.dtb \
+ mt8371-genio-520-evk-ufs.dtb \
mt8391-genio-720-evk.dtb \
+ mt8391-genio-720-evk-ufs.dtb \
mt8512-bm1-emmc.dtb \
mt8516-pumpkin.dtb \
mt8518-ap1-emmc.dtb
diff --git a/arch/arm/dts/mt8189.dtsi b/arch/arm/dts/mt8189.dtsi
index d246be63293..e550745ac5d 100644
--- a/arch/arm/dts/mt8189.dtsi
+++ b/arch/arm/dts/mt8189.dtsi
@@ -7,6 +7,8 @@
#include <dt-bindings/clock/mediatek,mt8189-clk.h>
#include <dt-bindings/interrupt-controller/irq.h>
#include <dt-bindings/interrupt-controller/arm-gic.h>
+#include <dt-bindings/phy/phy.h>
+#include <dt-bindings/reset/ti-syscon.h>
/ {
compatible = "mediatek,mt8189";
@@ -179,6 +181,79 @@
status = "disabled";
};
+ xhci0: usb@11200000 {
+ compatible = "mediatek,mt8189-xhci", "mediatek,mtk-xhci";
+ reg = <0 0x11200000 0 0x1000>,
+ <0 0x11203e00 0 0x0100>;
+ reg-names = "mac", "ippc";
+ interrupts-extended = <&gic GIC_SPI 385 IRQ_TYPE_LEVEL_HIGH 0>,
+ <&pio 207 IRQ_TYPE_LEVEL_HIGH>;
+ interrupt-names = "host","wakeup";
+ phys = <&u2port0 PHY_TYPE_USB2>,
+ <&u3port0 PHY_TYPE_USB3>;
+ clocks = <&pericfg_ao_clk CLK_PERAO_SSUSB0_SYS>,
+ <&pericfg_ao_clk CLK_PERAO_SSUSB0_REF>,
+ <&pericfg_ao_clk CLK_PERAO_SSUSB0_H>,
+ <&pericfg_ao_clk CLK_PERAO_SSUSB0_F>,
+ <&pericfg_ao_clk CLK_PERAO_SSUSB0_XHCI>,
+ <&pericfg_ao_clk CLK_PERAO_SSUSB0_FRMCNT>;
+ clock-names = "sys_ck", "ref_ck", "mcu_ck",
+ "dma_ck", "xhci_ck", "frmcnt_ck";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ wakeup-source;
+ mediatek,syscon-wakeup = <&pericfg_ao_clk 0x214 110>;
+ status = "disabled";
+ };
+
+ xhci1: usb@11210000 {
+ compatible = "mediatek,mt8189-xhci", "mediatek,mtk-xhci";
+ reg = <0 0x11210000 0 0x1000>,
+ <0 0x11213e00 0 0x0100>;
+ reg-names = "mac", "ippc";
+ interrupts-extended = <&gic GIC_SPI 386 IRQ_TYPE_LEVEL_HIGH 0>,
+ <&pio 203 IRQ_TYPE_LEVEL_HIGH>;
+ interrupt-names = "host","wakeup";
+ phys = <&u2port1 PHY_TYPE_USB2>;
+ clocks = <&pericfg_ao_clk CLK_PERAO_SSUSB1_SYS>,
+ <&pericfg_ao_clk CLK_PERAO_SSUSB1_REF>,
+ <&pericfg_ao_clk CLK_PERAO_SSUSB1_H>,
+ <&pericfg_ao_clk CLK_PERAO_SSUSB1_F>,
+ <&pericfg_ao_clk CLK_PERAO_SSUSB1_XHCI>,
+ <&pericfg_ao_clk CLK_PERAO_SSUSB1_FRMCNT>;
+ clock-names = "sys_ck", "ref_ck","mcu_ck",
+ "dma_ck", "xhci_ck", "frmcnt_ck";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ wakeup-source;
+ mediatek,syscon-wakeup = <&pericfg_ao_clk 0x21c 110>;
+ status = "disabled";
+ };
+
+ xhci2: usb@11220000 {
+ compatible = "mediatek,mt8189-xhci", "mediatek,mtk-xhci";
+ reg = <0 0x11220000 0 0x1000>,
+ <0 0x11223e00 0 0x0100>;
+ reg-names = "mac", "ippc";
+ interrupts-extended = <&gic GIC_SPI 472 IRQ_TYPE_LEVEL_HIGH 0>,
+ <&pio 193 IRQ_TYPE_LEVEL_HIGH>;
+ interrupt-names = "host","wakeup";
+ phys = <&u2port2 PHY_TYPE_USB2>;
+ clocks = <&pericfg_ao_clk CLK_PERAO_SSUSB2_SYS>,
+ <&pericfg_ao_clk CLK_PERAO_SSUSB2_REF>,
+ <&pericfg_ao_clk CLK_PERAO_SSUSB2_H>,
+ <&pericfg_ao_clk CLK_PERAO_SSUSB2_F>,
+ <&pericfg_ao_clk CLK_PERAO_SSUSB2_XHCI>,
+ <&pericfg_ao_clk CLK_PERAO_SSUSB2_FRMCNT>;
+ clock-names = "sys_ck", "ref_ck","mcu_ck",
+ "dma_ck", "xhci_ck", "frmcnt_ck";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ wakeup-source;
+ mediatek,syscon-wakeup = <&pericfg_ao_clk 0x27c 110>;
+ status = "disabled";
+ };
+
mmc0: mmc@11230000 {
compatible = "mediatek,mt8189-mmc";
reg = <0 0x11230000 0 0x10000>,
@@ -203,6 +278,55 @@
status = "disabled";
};
+ xhci3: usb@11260000 {
+ compatible = "mediatek,mt8189-xhci", "mediatek,mtk-xhci";
+ reg = <0 0x11260000 0 0x2e00>,
+ <0 0x11263e00 0 0x0100>;
+ reg-names = "mac", "ippc";
+ interrupts-extended = <&gic GIC_SPI 473 IRQ_TYPE_LEVEL_HIGH 0>,
+ <&pio 188 IRQ_TYPE_LEVEL_HIGH>;
+ interrupt-names = "host","wakeup";
+ phys = <&u2port3 PHY_TYPE_USB2>,
+ <&u3port3 PHY_TYPE_USB3>;
+ clocks = <&pericfg_ao_clk CLK_PERAO_SSUSB3_SYS>,
+ <&pericfg_ao_clk CLK_PERAO_SSUSB3_REF>,
+ <&pericfg_ao_clk CLK_PERAO_SSUSB3_H>,
+ <&pericfg_ao_clk CLK_PERAO_SSUSB3_F>,
+ <&pericfg_ao_clk CLK_PERAO_SSUSB3_XHCI>,
+ <&pericfg_ao_clk CLK_PERAO_SSUSB3_FRMCNT>;
+ clock-names = "sys_ck", "ref_ck", "mcu_ck",
+ "dma_ck", "xhci_ck", "frmcnt_ck";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ wakeup-source;
+ mediatek,syscon-wakeup = <&pericfg_ao_clk 0x284 110>;
+ status = "disabled";
+ };
+
+ xhci4: usb@11270000 {
+ compatible = "mediatek,mt8189-xhci", "mediatek,mtk-xhci";
+ reg = <0 0x11270000 0 0x1000>,
+ <0 0x11273e00 0 0x0100>;
+ reg-names = "mac", "ippc";
+ interrupts-extended = <&gic GIC_SPI 474 IRQ_TYPE_LEVEL_HIGH 0>,
+ <&pio 184 IRQ_TYPE_LEVEL_HIGH>;
+ interrupt-names = "host","wakeup";
+ phys = <&u2port4 PHY_TYPE_USB2>;
+ clocks = <&pericfg_ao_clk CLK_PERAO_SSUSB4_SYS>,
+ <&pericfg_ao_clk CLK_PERAO_SSUSB4_REF>,
+ <&pericfg_ao_clk CLK_PERAO_SSUSB4_H>,
+ <&pericfg_ao_clk CLK_PERAO_SSUSB4_F>,
+ <&pericfg_ao_clk CLK_PERAO_SSUSB4_XHCI>,
+ <&pericfg_ao_clk CLK_PERAO_SSUSB4_FRMCNT>;
+ clock-names = "sys_ck", "ref_ck", "mcu_ck",
+ "dma_ck", "xhci_ck", "frmcnt_ck";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ wakeup-source;
+ mediatek,syscon-wakeup = <&pericfg_ao_clk 0x28c 110>;
+ status = "disabled";
+ };
+
clock-controller@1000c000 {
compatible = "mediatek,mt8189-apmixedsys", "syscon";
reg = <0 0x1000c000 0 0x1000>;
@@ -286,6 +410,207 @@
#interrupt-cells = <2>;
};
+ ufshci: ufshci@112b0000 {
+ compatible = "mediatek,mt8183-ufshci";
+ reg = <0 0x112b0000 0 0x2300>;
+ interrupts = <GIC_SPI 393 IRQ_TYPE_LEVEL_HIGH 0>;
+
+ clocks = <&topckgen_clk CLK_TOP_U_SEL>,
+ <&clk26m>,
+ <&topckgen_clk CLK_TOP_MSDCPLL_D2>,
+ <&topckgen_clk CLK_TOP_AES_UFSFDE_SEL>,
+ <&topckgen_clk CLK_TOP_U_MBIST_SEL>,
+ <&ufscfg_ao_reg_clk CLK_UFSCFG_AO_REG_UNIPRO_TX_SYM>,
+ <&ufscfg_ao_reg_clk CLK_UFSCFG_AO_REG_UNIPRO_RX_SYM0>,
+ <&ufscfg_ao_reg_clk CLK_UFSCFG_AO_REG_UNIPRO_RX_SYM1>,
+ <&ufscfg_ao_reg_clk CLK_UFSCFG_AO_REG_UNIPRO_SYS>,
+ <&ufscfg_ao_reg_clk CLK_UFSCFG_AO_REG_U_SAP_CFG>,
+ <&ufscfg_ao_reg_clk CLK_UFSCFG_AO_REG_U_PHY_TOP_AHB_S_BUS>,
+ <&ufscfg_pdn_reg_clk CLK_UFSCFG_REG_UFSHCI_UFS>,
+ <&ufscfg_pdn_reg_clk CLK_UFSCFG_REG_UFSHCI_AES>,
+ <&ufscfg_pdn_reg_clk CLK_UFSCFG_REG_UFSHCI_U_AHB>,
+ <&ufscfg_pdn_reg_clk CLK_UFSCFG_REG_UFSHCI_U_AXI>;
+
+ clock-names = "ufs_sel",
+ "ufs_sel_min_src",
+ "ufs_sel_max_src",
+ "ufs_fde",
+ "ufs_mbist",
+ "unipro_tx_sym",
+ "unipro_rx_sym0",
+ "unipro_rx_sym1",
+ "unipro_sys",
+ "unipro_phy_sap",
+ "phy_top_ahb_s_bus",
+ "ufshci_ufs",
+ "ufshci_aes",
+ "ufshci_ufs_ahb",
+ "ufshci_aes_axi";
+
+ freq-table-hz = <26000000 208000000>,
+ <0 0>,
+ <0 0>,
+ <0 0>,
+ <0 0>,
+ <0 0>,
+ <0 0>,
+ <0 0>,
+ <0 0>,
+ <0 0>,
+ <0 0>,
+ <0 0>,
+ <0 0>,
+ <0 0>,
+ <0 0>;
+
+ vcc-supply = <&mt6359_vemc_1_ldo_reg>;
+ vccq-supply = <&mt6359_vio18_ldo_reg>;
+ vccq2-supply = <&mt6359_vufs_ldo_reg>;
+
+ resets = <&ufscfgpdn_rst 0>,
+ <&ufscfgpdn_rst 1>,
+ <&ufscfgpdn_rst 2>;
+
+ reset-names = "unipro_rst",
+ "crypto_rst",
+ "hci_rst";
+
+ mediatek,ufs-disable-mcq;
+ mediatek,ufs-rtff-mtcmos;
+ mediatek,ufs-broken-vcc;
+
+ status = "disabled";
+ };
+
+ u3phy3: t-phy@11b00000 {
+ compatible = "mediatek,mt8189-tphy",
+ "mediatek,generic-tphy-v2";
+ reg = <0 0x11b00000 0 0x700>;
+ #address-cells = <2>;
+ #size-cells = <2>;
+ ranges;
+
+ u2port3: usb-phy@11b00000 {
+ reg = <0 0x11b00000 0 0x700>;
+ clocks = <&topckgen_clk CLK_TOP_USB2_PHY_RF_P3_EN>;
+ clock-names = "ref";
+ #phy-cells = <1>;
+ };
+
+ u3port3: usb-phy@11b00700 {
+ reg = <0 0x11b00700 0 0x700>;
+ clocks = <&topckgen_clk CLK_TOP_USB2_PHY_RF_P3_EN>;
+ clock-names = "ref";
+ #phy-cells = <1>;
+ };
+ };
+
+ u2phy4: xs-phy@11b10000 {
+ compatible = "mediatek,mt8189-xsphy", "mediatek,xsphy";
+ #address-cells = <2>;
+ #size-cells = <2>;
+ ranges;
+
+ u2port4: usb-phy@11b10000 {
+ reg = <0 0x11b10000 0 0x700>;
+ clocks = <&topckgen_clk CLK_TOP_USB2_PHY_RF_P4_EN>;
+ clock-names = "ref";
+ #phy-cells = <1>;
+ };
+ };
+
+ u3phy0: xs-phy@11e80000 {
+ compatible = "mediatek,mt8189-xsphy", "mediatek,xsphy";
+ reg = <0 0x11e83000 0 0x200>;
+ #address-cells = <2>;
+ #size-cells = <2>;
+ ranges;
+
+ u2port0: usb-phy@11e80000 {
+ reg = <0 0x11e80000 0 0x700>;
+ clocks = <&topckgen_clk CLK_TOP_USB2_PHY_RF_P0_EN>;
+ clock-names = "ref";
+ #phy-cells = <1>;
+ };
+
+ u3port0: usb-phy@11e83000 {
+ reg = <0 0x11e83400 0 0x500>;
+ clocks = <&topckgen_clk CLK_TOP_USB2_PHY_RF_P0_EN>;
+ clock-names = "ref";
+ #phy-cells = <1>;
+ };
+ };
+
+ u2phy1: xs-phy@11e90000 {
+ compatible = "mediatek,mt8189-xsphy", "mediatek,xsphy";
+ #address-cells = <2>;
+ #size-cells = <2>;
+ ranges;
+
+ u2port1: usb-phy@11e90000 {
+ reg = <0 0x11e90000 0 0x700>;
+ clocks = <&topckgen_clk CLK_TOP_USB2_PHY_RF_P1_EN>;
+ clock-names = "ref";
+ #phy-cells = <1>;
+ };
+ };
+
+ u2phy2: xs-phy@11ef0000 {
+ compatible = "mediatek,mt8189-xsphy", "mediatek,xsphy";
+ #address-cells = <2>;
+ #size-cells = <2>;
+ ranges;
+
+ u2port2: usb-phy@11ef0000 {
+ reg = <0 0x11ef0000 0 0x700>;
+ clocks = <&topckgen_clk CLK_TOP_USB2_PHY_RF_P2_EN>;
+ clock-names = "ref";
+ #phy-cells = <1>;
+ };
+ };
+
+ ufscfg_ao_reg_clk: syscon@112b8000 {
+ compatible = "mediatek,mt8189-ufscfg-ao", "syscon", "simple-mfd";
+ reg = <0 0x112b8000 0 0x1000>;
+ #clock-cells = <1>;
+
+ ufscfgao_rst: reset-controller {
+ compatible = "ti,syscon-reset";
+ #reset-cells = <1>;
+
+ ti,reset-bits = <
+ /* ufs mphy reset */
+ /* 8: mphy */
+ 0x48 8 0x4c 8 0 0
+ (ASSERT_SET | DEASSERT_SET | STATUS_NONE)
+ >;
+ };
+ };
+
+ ufscfg_pdn_reg_clk: syscon@112bb000 {
+ compatible = "mediatek,mt8189-ufscfg-pdn", "syscon", "simple-mfd";
+ reg = <0 0x112bb000 0 0x1000>;
+ #clock-cells = <1>;
+
+ ufscfgpdn_rst: reset-controller {
+ compatible = "ti,syscon-reset";
+ #reset-cells = <1>;
+
+ ti,reset-bits = <
+ /* ufs ufschi/crypto/unipro reset */
+ /* 0: unipro */
+ 0x48 0 0x4c 0 0 0
+ (ASSERT_SET | DEASSERT_SET | STATUS_NONE)
+ /* 1: ufs-crypto */
+ 0x48 1 0x4c 1 0 0
+ (ASSERT_SET | DEASSERT_SET | STATUS_NONE)
+ /* 2: ufshci */
+ 0x48 2 0x4c 2 0 0
+ (ASSERT_SET | DEASSERT_SET | STATUS_NONE)
+ >;
+ };
+ };
+
pwrap: pwrap@1cc04000 {
compatible = "mediatek,mt8189-pwrap", "mediatek,mt8195-pwrap", "syscon";
reg = <0 0x1cc04000 0 0x1000>;
diff --git a/arch/arm/dts/mt8371-genio-common-ufs.dtso b/arch/arm/dts/mt8371-genio-common-ufs.dtso
new file mode 100644
index 00000000000..b75fdafcf9b
--- /dev/null
+++ b/arch/arm/dts/mt8371-genio-common-ufs.dtso
@@ -0,0 +1,18 @@
+// SPDX-License-Identifier: (GPL-2.0 OR MIT)
+/*
+ * Copyright (C) 2026 MediaTek Inc.
+ *
+ * Adjusts for when boot DIP switches/jumpers on EVK are set for UFS boot
+ * instead of eMMC.
+ */
+
+/dts-v1/;
+/plugin/;
+
+&ufshci {
+ status = "okay";
+};
+
+&mmc0 {
+ status = "disabled";
+};
diff --git a/arch/arm/dts/mt8371-genio-common.dtsi b/arch/arm/dts/mt8371-genio-common.dtsi
index 58322193aef..046e9d57752 100644
--- a/arch/arm/dts/mt8371-genio-common.dtsi
+++ b/arch/arm/dts/mt8371-genio-common.dtsi
@@ -19,6 +19,51 @@
stdout-path = "serial0:921600n8";
};
+ usb_p0_vbus: regulator@0 {
+ compatible = "regulator-fixed";
+ regulator-name = "p0_vbus";
+ regulator-min-microvolt = <5000000>;
+ regulator-max-microvolt = <5000000>;
+ gpio = <&pio 82 0>;
+ enable-active-high;
+ };
+
+ usb_p1_vbus: regulator@1 {
+ compatible = "regulator-fixed";
+ regulator-name = "p1_vbus";
+ regulator-min-microvolt = <5000000>;
+ regulator-max-microvolt = <5000000>;
+ gpio = <&pio 84 0>;
+ enable-active-high;
+ };
+
+ usb_p2_vbus: regulator@2 {
+ compatible = "regulator-fixed";
+ regulator-name = "p2_vbus";
+ regulator-min-microvolt = <5000000>;
+ regulator-max-microvolt = <5000000>;
+ gpio = <&pio 85 0>;
+ enable-active-high;
+ };
+
+ usb_p3_vbus: regulator@3 {
+ compatible = "regulator-fixed";
+ regulator-name = "p3_vbus";
+ regulator-min-microvolt = <5000000>;
+ regulator-max-microvolt = <5000000>;
+ gpio = <&pio 86 0>;
+ enable-active-high;
+ };
+
+ usb_p4_vbus: regulator@4 {
+ compatible = "regulator-fixed";
+ regulator-name = "p4_vbus";
+ regulator-min-microvolt = <5000000>;
+ regulator-max-microvolt = <5000000>;
+ gpio = <&pio 87 0>;
+ enable-active-high;
+ };
+
firmware {
optee {
compatible = "linaro,optee-tz";
@@ -241,3 +286,28 @@
&pmic {
interrupts-extended = <&pio 194 IRQ_TYPE_LEVEL_HIGH>;
};
+
+&xhci0{
+ vbus-supply = <&usb_p0_vbus>;
+ status = "okay";
+};
+
+&xhci1{
+ vbus-supply = <&usb_p1_vbus>;
+ status = "okay";
+};
+
+&xhci2{
+ vbus-supply = <&usb_p2_vbus>;
+ status = "okay";
+};
+
+&xhci3{
+ vbus-supply = <&usb_p3_vbus>;
+ status = "okay";
+};
+
+&xhci4{
+ vbus-supply = <&usb_p4_vbus>;
+ status = "okay";
+};
diff --git a/board/mediatek/MAINTAINERS b/board/mediatek/MAINTAINERS
index c342ff24330..37ca35b4dd4 100644
--- a/board/mediatek/MAINTAINERS
+++ b/board/mediatek/MAINTAINERS
@@ -3,10 +3,14 @@ M: Macpaul Lin <[email protected]>
S: Maintained
F: arch/arm/dts/mt8371-genio-520-evk-u-boot.dtsi
F: arch/arm/dts/mt8371-genio-common-u-boot.dtsi
+F: arch/arm/dts/mt8371-genio-common-ufs.dtso
F: arch/arm/dts/mt8391-genio-720-evk-u-boot.dtsi
+F: configs/mt8189-ufs.config
F: configs/mt8189.config
F: configs/mt8371_genio_520_evk_defconfig
+F: configs/mt8371_genio_520_evk_ufs_defconfig
F: configs/mt8391_genio_720_evk_defconfig
+F: configs/mt8391_genio_720_evk_ufs_defconfig
MT8365 EVK
M: Julien Masson <[email protected]>
@@ -21,8 +25,10 @@ F: configs/mt8188.config
F: configs/mt8370_genio_510_evk_defconfig
F: configs/mt8390_genio_700_evk_defconfig
-MT8395
+MT8195/MT8395
M: Macpaul Lin <[email protected]>
M: Julien Stephan <[email protected]>
S: Maintained
+F: configs/mt8195.config
F: configs/mt8395_genio_1200_evk_defconfig
+F: configs/mt8395_genio_1200_evk_ufs_defconfig
diff --git a/configs/mt8189-ufs.config b/configs/mt8189-ufs.config
new file mode 100644
index 00000000000..8a7afb95b1b
--- /dev/null
+++ b/configs/mt8189-ufs.config
@@ -0,0 +1,8 @@
+#include <configs/mt8189.config>
+
+CONFIG_PHY=y
+CONFIG_PHY_MTK_UFS=y
+CONFIG_SCSI=y
+CONFIG_UFS=y
+CONFIG_UFS_MEDIATEK=y
+CONFIG_CMD_UFS=y
diff --git a/configs/mt8189.config b/configs/mt8189.config
index 55c2ccfc01f..ecf8c5f4b4b 100644
--- a/configs/mt8189.config
+++ b/configs/mt8189.config
@@ -16,21 +16,29 @@ CONFIG_CMD_CLK=y
CONFIG_CMD_GPIO=y
CONFIG_CMD_GPT=y
CONFIG_CMD_MMC=y
+CONFIG_CMD_USB=y
CONFIG_CMD_PMIC=y
CONFIG_CMD_REGULATOR=y
CONFIG_CLK=y
# CONFIG_MMC_QUIRKS is not set
CONFIG_MMC_HS200_SUPPORT=y
CONFIG_MMC_MTK=y
+CONFIG_PHY=y
+CONFIG_PHY_MTK_TPHY=y
+CONFIG_PHY_MTK_XSPHY=y
CONFIG_PINCTRL=y
CONFIG_PINCONF=y
CONFIG_PINCTRL_MT8189=y
CONFIG_DM_PMIC=y
CONFIG_DM_PMIC_MTK_PWRAP=y
CONFIG_DM_REGULATOR=y
+CONFIG_DM_REGULATOR_FIXED=y
CONFIG_DM_REGULATOR_MT6359=y
CONFIG_BAUDRATE=921600
CONFIG_DM_SERIAL=y
CONFIG_MTK_SERIAL=y
+CONFIG_USB=y
+CONFIG_USB_XHCI_HCD=y
+CONFIG_USB_XHCI_MTK=y
CONFIG_WDT=y
CONFIG_WDT_MTK=y
diff --git a/configs/mt8195.config b/configs/mt8195.config
new file mode 100644
index 00000000000..ed66ea22956
--- /dev/null
+++ b/configs/mt8195.config
@@ -0,0 +1,28 @@
+CONFIG_ARM=y
+CONFIG_COUNTER_FREQUENCY=13000000
+CONFIG_POSITION_INDEPENDENT=y
+CONFIG_ARCH_MEDIATEK=y
+CONFIG_TEXT_BASE=0x4c000000
+CONFIG_NR_DRAM_BANKS=1
+CONFIG_TARGET_MT8195=y
+CONFIG_SYS_LOAD_ADDR=0x60000000
+# CONFIG_BOARD_INIT is not set
+CONFIG_CMD_CLK=y
+CONFIG_CMD_GPT=y
+CONFIG_CMD_MMC=y
+CONFIG_CMD_PART=y
+CONFIG_OF_UPSTREAM=y
+CONFIG_CLK=y
+CONFIG_MMC_MTK=y
+CONFIG_PINCTRL=y
+CONFIG_PINCONF=y
+CONFIG_PINCTRL_MT8195=y
+CONFIG_DM_PMIC=y
+CONFIG_DM_PMIC_MTK_PWRAP=y
+CONFIG_DM_REGULATOR=y
+CONFIG_DM_REGULATOR_MT6359=y
+CONFIG_BAUDRATE=921600
+CONFIG_DM_SERIAL=y
+CONFIG_MTK_SERIAL=y
+CONFIG_WDT=y
+CONFIG_WDT_MTK=y
diff --git a/configs/mt8371_genio_520_evk_ufs_defconfig b/configs/mt8371_genio_520_evk_ufs_defconfig
new file mode 100644
index 00000000000..a0b365a86a2
--- /dev/null
+++ b/configs/mt8371_genio_520_evk_ufs_defconfig
@@ -0,0 +1,4 @@
+#include <configs/mt8189-ufs.config>
+
+CONFIG_DEFAULT_DEVICE_TREE="mt8371-genio-520-evk-ufs"
+CONFIG_DEFAULT_FDT_FILE="mt8371-genio-520-evk-ufs"
diff --git a/configs/mt8391_genio_720_evk_ufs_defconfig b/configs/mt8391_genio_720_evk_ufs_defconfig
new file mode 100644
index 00000000000..f1de9d5fa1e
--- /dev/null
+++ b/configs/mt8391_genio_720_evk_ufs_defconfig
@@ -0,0 +1,4 @@
+#include <configs/mt8189-ufs.config>
+
+CONFIG_DEFAULT_DEVICE_TREE="mt8391-genio-720-evk-ufs"
+CONFIG_DEFAULT_FDT_FILE="mt8391-genio-720-evk-ufs"
diff --git a/configs/mt8395_genio_1200_evk_defconfig b/configs/mt8395_genio_1200_evk_defconfig
index 2d73af353f7..47c10757c52 100644
--- a/configs/mt8395_genio_1200_evk_defconfig
+++ b/configs/mt8395_genio_1200_evk_defconfig
@@ -1,26 +1,4 @@
-CONFIG_ARM=y
-CONFIG_COUNTER_FREQUENCY=13000000
-CONFIG_POSITION_INDEPENDENT=y
-CONFIG_ARCH_MEDIATEK=y
-CONFIG_TEXT_BASE=0x4c000000
-CONFIG_NR_DRAM_BANKS=1
+#include <configs/mt8195.config>
+
CONFIG_DEFAULT_DEVICE_TREE="mediatek/mt8395-genio-1200-evk"
-CONFIG_TARGET_MT8195=y
-CONFIG_SYS_LOAD_ADDR=0x60000000
CONFIG_IDENT_STRING="mt8395-genio-1200-evk"
-# CONFIG_BOARD_INIT is not set
-CONFIG_CMD_CLK=y
-CONFIG_CMD_GPT=y
-CONFIG_CMD_MMC=y
-CONFIG_CMD_PART=y
-CONFIG_OF_UPSTREAM=y
-CONFIG_CLK=y
-CONFIG_MMC_MTK=y
-CONFIG_PINCTRL=y
-CONFIG_PINCONF=y
-CONFIG_PINCTRL_MT8195=y
-CONFIG_BAUDRATE=921600
-CONFIG_DM_SERIAL=y
-CONFIG_MTK_SERIAL=y
-CONFIG_WDT=y
-CONFIG_WDT_MTK=y
diff --git a/configs/mt8395_genio_1200_evk_ufs_defconfig b/configs/mt8395_genio_1200_evk_ufs_defconfig
new file mode 100644
index 00000000000..e927365a03a
--- /dev/null
+++ b/configs/mt8395_genio_1200_evk_ufs_defconfig
@@ -0,0 +1,9 @@
+#include <configs/mt8195.config>
+
+CONFIG_DEFAULT_DEVICE_TREE="mediatek/mt8395-genio-1200-evk-ufs"
+CONFIG_IDENT_STRING=" mt8395-genio-1200-evk-ufs"
+CONFIG_CMD_UFS=y
+CONFIG_PHY=y
+CONFIG_SCSI=y
+CONFIG_UFS=y
+CONFIG_UFS_MEDIATEK=y
diff --git a/drivers/clk/mediatek/clk-mt8189.c b/drivers/clk/mediatek/clk-mt8189.c
index 9e640059f11..d11947ee461 100644
--- a/drivers/clk/mediatek/clk-mt8189.c
+++ b/drivers/clk/mediatek/clk-mt8189.c
@@ -1641,6 +1641,46 @@ static const struct mtk_gate mminfra_config_clks[] = {
GATE_MMINFRA_CONFIG1(CLK_MMINFRA_GCE_26M, CLK_TOP_MMINFRA_SEL, 17),
};
+static const struct mtk_gate_regs ufscfg_ao_reg_cg_regs = {
+ .set_ofs = 0x8,
+ .clr_ofs = 0xc,
+ .sta_ofs = 0x4,
+};
+
+#define GATE_UFSCFG_AO_REG_EXT(_id, _parent, _shift) \
+ GATE_FLAGS(_id, _parent, &ufscfg_ao_reg_cg_regs, _shift, \
+ CLK_GATE_SETCLR | CLK_PARENT_EXT)
+
+#define GATE_UFSCFG_AO_REG_TOP(_id, _parent, _shift) \
+ GATE_FLAGS(_id, _parent, &ufscfg_ao_reg_cg_regs, _shift, \
+ CLK_GATE_SETCLR | CLK_PARENT_TOPCKGEN)
+
+static const struct mtk_gate ufs_config_ao_clks[] = {
+ GATE_UFSCFG_AO_REG_EXT(CLK_UFSCFG_AO_REG_UNIPRO_TX_SYM, CLK_PAD_CLK26M, 1),
+ GATE_UFSCFG_AO_REG_EXT(CLK_UFSCFG_AO_REG_UNIPRO_RX_SYM0, CLK_PAD_CLK26M, 2),
+ GATE_UFSCFG_AO_REG_EXT(CLK_UFSCFG_AO_REG_UNIPRO_RX_SYM1, CLK_PAD_CLK26M, 3),
+ GATE_UFSCFG_AO_REG_TOP(CLK_UFSCFG_AO_REG_UNIPRO_SYS, CLK_TOP_U_SEL, 4),
+ GATE_UFSCFG_AO_REG_EXT(CLK_UFSCFG_AO_REG_U_SAP_CFG, CLK_PAD_CLK26M, 5),
+ GATE_UFSCFG_AO_REG_TOP(CLK_UFSCFG_AO_REG_U_PHY_TOP_AHB_S_BUS, CLK_TOP_AXI_U_SEL, 6),
+};
+
+static const struct mtk_gate_regs ufscfg_pdn_reg_cg_regs = {
+ .set_ofs = 0x8,
+ .clr_ofs = 0xc,
+ .sta_ofs = 0x4,
+};
+
+#define GATE_UFSCFG_PDN_REG(_id, _parent, _shift) \
+ GATE_FLAGS(_id, _parent, &ufscfg_pdn_reg_cg_regs, _shift, \
+ CLK_GATE_SETCLR | CLK_PARENT_TOPCKGEN)
+
+static const struct mtk_gate ufs_config_pdn_clks[] = {
+ GATE_UFSCFG_PDN_REG(CLK_UFSCFG_REG_UFSHCI_UFS, CLK_TOP_U_SEL, 0),
+ GATE_UFSCFG_PDN_REG(CLK_UFSCFG_REG_UFSHCI_AES, CLK_TOP_AES_UFSFDE_SEL, 1),
+ GATE_UFSCFG_PDN_REG(CLK_UFSCFG_REG_UFSHCI_U_AHB, CLK_TOP_AXI_U_SEL, 3),
+ GATE_UFSCFG_PDN_REG(CLK_UFSCFG_REG_UFSHCI_U_AXI, CLK_TOP_MEM_SUB_U_SEL, 5),
+};
+
static const struct mtk_parent vlp_26m_oscd10_parents[] = {
EXT_PARENT(CLK_PAD_CLK26M),
TOP_PARENT(CLK_TOP_OSC_D10),
@@ -1955,6 +1995,8 @@ GATE_CLK_DATA(perao_clks);
GATE_CLK_DATA(imp_clks);
GATE_CLK_DATA(mm_clks);
GATE_CLK_DATA(mminfra_config_clks);
+GATE_CLK_DATA(ufs_config_ao_clks);
+GATE_CLK_DATA(ufs_config_pdn_clks);
GATE_CLK_DATA(vlpcfg_ao_clks);
static const struct udevice_id of_match_mt8189_clk_gate[] = {
@@ -1962,6 +2004,8 @@ static const struct udevice_id of_match_mt8189_clk_gate[] = {
{ .compatible = "mediatek,mt8189-iic-wrap", .data = (ulong)&imp_clks_data },
{ .compatible = "mediatek,mt8189-dispsys", .data = (ulong)&mm_clks_data },
{ .compatible = "mediatek,mt8189-mm-infra", .data = (ulong)&mminfra_config_clks_data },
+ { .compatible = "mediatek,mt8189-ufscfg-ao", .data = (ulong)&ufs_config_ao_clks_data },
+ { .compatible = "mediatek,mt8189-ufscfg-pdn", .data = (ulong)&ufs_config_pdn_clks_data },
{ .compatible = "mediatek,mt8189-vlpcfg-ao", .data = (ulong)&vlpcfg_ao_clks_data },
{ }
};
diff --git a/drivers/clk/mediatek/clk-mtk.c b/drivers/clk/mediatek/clk-mtk.c
index 3557aeac3d5..9d0a6cd79cf 100644
--- a/drivers/clk/mediatek/clk-mtk.c
+++ b/drivers/clk/mediatek/clk-mtk.c
@@ -204,10 +204,6 @@ static ulong mtk_clk_find_parent_rate(struct clk *clk, int id,
return clk_get_rate(&parent);
}
-const struct clk_ops mtk_clk_apmixedsys_ops;
-const struct clk_ops mtk_clk_topckgen_ops;
-const struct clk_ops mtk_clk_infrasys_ops;
-
static ulong mtk_find_parent_rate(struct mtk_clk_priv *priv, struct clk *clk,
const int parent, u16 flags)
{
@@ -216,15 +212,21 @@ static ulong mtk_find_parent_rate(struct mtk_clk_priv *priv, struct clk *clk,
switch (flags & CLK_PARENT_MASK) {
case CLK_PARENT_APMIXED:
/* APMIXEDSYS can be parent or grandparent. */
- if (dev_get_driver_ops(clk->dev) == &mtk_clk_apmixedsys_ops)
+ if (dev_get_driver_ops(clk->dev) == &mtk_clk_apmixedsys_ops ||
+ dev_get_driver_ops(clk->dev) == &mtk_clk_fixed_pll_ops) {
parent_dev = clk->dev;
- else if (dev_get_driver_ops(priv->parent) == &mtk_clk_apmixedsys_ops)
+ } else if (dev_get_driver_ops(priv->parent) == &mtk_clk_apmixedsys_ops ||
+ dev_get_driver_ops(priv->parent) == &mtk_clk_fixed_pll_ops) {
parent_dev = priv->parent;
- else if (dev_get_driver_ops(dev_get_parent(priv->parent)) == &mtk_clk_apmixedsys_ops)
- parent_dev = dev_get_parent(priv->parent);
- else
- return -EINVAL;
-
+ } else {
+ struct udevice *grandparent_dev = dev_get_parent(priv->parent);
+
+ if (dev_get_driver_ops(grandparent_dev) == &mtk_clk_apmixedsys_ops ||
+ dev_get_driver_ops(grandparent_dev) == &mtk_clk_fixed_pll_ops)
+ parent_dev = grandparent_dev;
+ else
+ return -EINVAL;
+ }
break;
case CLK_PARENT_TOPCKGEN:
if (dev_get_driver_ops(clk->dev) == &mtk_clk_topckgen_ops)
diff --git a/drivers/phy/Kconfig b/drivers/phy/Kconfig
index 09810b62b51..fc4daa00661 100644
--- a/drivers/phy/Kconfig
+++ b/drivers/phy/Kconfig
@@ -292,6 +292,17 @@ config PHY_MTK_UFS
initialization, power on and power off flow of
specified M-PHYs.
+config PHY_MTK_XSPHY
+ bool "MediaTek XS-PHY Driver"
+ depends on PHY
+ depends on ARCH_MEDIATEK
+ select REGMAP
+ select SYSCON
+ help
+ Enable this to support the SuperSpeedPlus XS-PHY transceiver for
+ USB3.1 GEN2 controllers on MediaTek chips. The driver supports
+ multiple USB2.0, USB3.1 GEN2 ports.
+
config PHY_NPCM_USB
bool "Nuvoton NPCM USB PHY support"
depends on PHY
diff --git a/drivers/phy/Makefile b/drivers/phy/Makefile
index 83102349669..684e9a99af8 100644
--- a/drivers/phy/Makefile
+++ b/drivers/phy/Makefile
@@ -38,6 +38,7 @@ obj-$(CONFIG_PHY_DA8XX_USB) += phy-da8xx-usb.o
obj-$(CONFIG_PHY_EXYNOS_USBDRD) += phy-exynos-usbdrd.o
obj-$(CONFIG_PHY_MTK_TPHY) += phy-mtk-tphy.o
obj-$(CONFIG_PHY_MTK_UFS) += phy-mtk-ufs.o
+obj-$(CONFIG_PHY_MTK_XSPHY) += phy-mtk-xsphy.o
obj-$(CONFIG_PHY_NPCM_USB) += phy-npcm-usb.o
obj-$(CONFIG_$(PHASE_)PHY_IMX8MQ_USB) += phy-imx8mq-usb.o
obj-$(CONFIG_PHY_IMX8M_PCIE) += phy-imx8m-pcie.o
diff --git a/drivers/phy/phy-mtk-ufs.c b/drivers/phy/phy-mtk-ufs.c
index 1eda3df858d..c4c214dcde0 100644
--- a/drivers/phy/phy-mtk-ufs.c
+++ b/drivers/phy/phy-mtk-ufs.c
@@ -6,52 +6,41 @@
* Copyright (c) 2025, Igor Belwon <[email protected]>
*/
-#include "dm/ofnode.h"
-#include "dm/read.h"
-#include <clk.h>
-#include <dm.h>
-#include <generic-phy.h>
-#include <malloc.h>
-#include <mapmem.h>
-#include <regmap.h>
-#include <syscon.h>
#include <asm/io.h>
+#include <clk.h>
+#include <dm/device.h>
#include <dm/device_compat.h>
-#include <dm/devres.h>
-#include <linux/bitfield.h>
+#include <dm/read.h>
+#include <generic-phy.h>
#include <linux/bitops.h>
#include <linux/delay.h>
-
-#include <dt-bindings/phy/phy.h>
+#include <mapmem.h>
/* mphy register and offsets */
-#define MP_GLB_DIG_8C 0x008C
-#define FRC_PLL_ISO_EN BIT(8)
-#define PLL_ISO_EN BIT(9)
-#define FRC_FRC_PWR_ON BIT(10)
-#define PLL_PWR_ON BIT(11)
-
-#define MP_LN_DIG_RX_9C 0xA09C
-#define FSM_DIFZ_FRC BIT(18)
+#define MP_GLB_DIG_8C 0x008C
+#define FRC_PLL_ISO_EN BIT(8)
+#define PLL_ISO_EN BIT(9)
+#define FRC_FRC_PWR_ON BIT(10)
+#define PLL_PWR_ON BIT(11)
-#define MP_LN_DIG_RX_AC 0xA0AC
-#define FRC_RX_SQ_EN BIT(0)
-#define RX_SQ_EN BIT(1)
+#define MP_LN_DIG_RX_9C 0xA09C
+#define FSM_DIFZ_FRC BIT(18)
-#define MP_LN_RX_44 0xB044
-#define FRC_CDR_PWR_ON BIT(17)
-#define CDR_PWR_ON BIT(18)
-#define FRC_CDR_ISO_EN BIT(19)
-#define CDR_ISO_EN BIT(20)
+#define MP_LN_DIG_RX_AC 0xA0AC
+#define FRC_RX_SQ_EN BIT(0)
+#define RX_SQ_EN BIT(1)
-#define UFSPHY_CLKS_CNT 2
+#define MP_LN_RX_44 0xB044
+#define FRC_CDR_PWR_ON BIT(17)
+#define CDR_PWR_ON BIT(18)
+#define FRC_CDR_ISO_EN BIT(19)
+#define CDR_ISO_EN BIT(20)
struct mtk_ufs_phy {
struct udevice *dev;
void __iomem *mmio;
- struct clk *unipro_clk;
- struct clk *mp_clk;
+ struct clk_bulk clk_bulk;
};
static void ufs_mtk_phy_set_active(struct mtk_ufs_phy *phy)
@@ -88,16 +77,9 @@ static int mtk_phy_power_on(struct phy *phy)
struct mtk_ufs_phy *ufs_phy = dev_get_priv(phy->dev);
int ret;
- ret = clk_enable(ufs_phy->mp_clk);
- if (ret < 0) {
- dev_err(phy->dev, "failed to enable mp_clk\n");
- return ret;
- }
-
- ret = clk_enable(ufs_phy->unipro_clk);
- if (ret < 0) {
- dev_err(phy->dev, "failed to enable unipro_clk %d\n", ret);
- clk_disable(ufs_phy->unipro_clk);
+ ret = clk_enable_bulk(&ufs_phy->clk_bulk);
+ if (ret) {
+ dev_err(phy->dev, "failed to enable clocks (ret=%d)\n", ret);
return ret;
}
@@ -106,34 +88,44 @@ static int mtk_phy_power_on(struct phy *phy)
return 0;
}
-static int mtk_phy_power_off(struct phy *phy)
+static void ufs_mtk_phy_set_inactive(struct mtk_ufs_phy *phy)
{
- struct mtk_ufs_phy *ufs_phy = dev_get_priv(phy->dev);
-
/* Set PHY to Deep Hibernate mode */
- setbits_le32(ufs_phy->mmio + MP_LN_DIG_RX_9C, FSM_DIFZ_FRC);
+ setbits_le32(phy->mmio + MP_LN_DIG_RX_9C, FSM_DIFZ_FRC);
/* force DA_MP_RX0_SQ_EN */
- setbits_le32(ufs_phy->mmio + MP_LN_DIG_RX_AC, FRC_RX_SQ_EN);
- clrbits_le32(ufs_phy->mmio + MP_LN_DIG_RX_AC, RX_SQ_EN);
+ setbits_le32(phy->mmio + MP_LN_DIG_RX_AC, FRC_RX_SQ_EN);
+ clrbits_le32(phy->mmio + MP_LN_DIG_RX_AC, RX_SQ_EN);
/* force DA_MP_CDR_ISO_EN */
- setbits_le32(ufs_phy->mmio + MP_LN_RX_44, FRC_CDR_ISO_EN);
- setbits_le32(ufs_phy->mmio + MP_LN_RX_44, CDR_ISO_EN);
+ setbits_le32(phy->mmio + MP_LN_RX_44, FRC_CDR_ISO_EN);
+ setbits_le32(phy->mmio + MP_LN_RX_44, CDR_ISO_EN);
/* force DA_MP_CDR_PWR_ON */
- setbits_le32(ufs_phy->mmio + MP_LN_RX_44, FRC_CDR_PWR_ON);
- clrbits_le32(ufs_phy->mmio + MP_LN_RX_44, CDR_PWR_ON);
+ setbits_le32(phy->mmio + MP_LN_RX_44, FRC_CDR_PWR_ON);
+ clrbits_le32(phy->mmio + MP_LN_RX_44, CDR_PWR_ON);
/* force DA_MP_PLL_ISO_EN */
- setbits_le32(ufs_phy->mmio + MP_GLB_DIG_8C, FRC_PLL_ISO_EN);
- setbits_le32(ufs_phy->mmio + MP_GLB_DIG_8C, PLL_ISO_EN);
+ setbits_le32(phy->mmio + MP_GLB_DIG_8C, FRC_PLL_ISO_EN);
+ setbits_le32(phy->mmio + MP_GLB_DIG_8C, PLL_ISO_EN);
/* force DA_MP_PLL_PWR_ON */
- setbits_le32(ufs_phy->mmio + MP_GLB_DIG_8C, FRC_FRC_PWR_ON);
- clrbits_le32(ufs_phy->mmio + MP_GLB_DIG_8C, PLL_PWR_ON);
+ setbits_le32(phy->mmio + MP_GLB_DIG_8C, FRC_FRC_PWR_ON);
+ clrbits_le32(phy->mmio + MP_GLB_DIG_8C, PLL_PWR_ON);
+}
- return 0;
+static int mtk_phy_power_off(struct phy *phy)
+{
+ struct mtk_ufs_phy *ufs_phy = dev_get_priv(phy->dev);
+ int ret;
+
+ ufs_mtk_phy_set_inactive(ufs_phy);
+
+ ret = clk_disable_bulk(&ufs_phy->clk_bulk);
+ if (ret)
+ dev_err(phy->dev, "failed to disable clocks (ret=%d)\n", ret);
+
+ return ret;
}
static const struct phy_ops mtk_ufs_phy_ops = {
@@ -147,10 +139,6 @@ static int mtk_ufs_phy_probe(struct udevice *dev)
fdt_addr_t addr;
int ret;
- phy = devm_kzalloc(dev, sizeof(*phy), GFP_KERNEL);
- if (!phy)
- return -ENOMEM;
-
addr = dev_read_addr(dev);
if (addr == FDT_ADDR_T_NONE)
return -ENOMEM;
@@ -158,21 +146,11 @@ static int mtk_ufs_phy_probe(struct udevice *dev)
phy->dev = dev;
phy->mmio = map_sysmem(addr, 0);
- phy->mp_clk = devm_clk_get(dev, "mp");
- if (IS_ERR(phy->mp_clk)) {
- ret = PTR_ERR(phy->mp_clk);
- dev_err(dev, "Failed to get mp clock (ret=%d)\n", ret);
- return ret;
- }
+ ret = clk_get_bulk(dev, &phy->clk_bulk);
+ if (ret)
+ dev_err(dev, "Failed to get clocks (ret=%d)\n", ret);
- phy->unipro_clk = devm_clk_get(dev, "unipro");
- if (IS_ERR(phy->unipro_clk)) {
- ret = PTR_ERR(phy->unipro_clk);
- dev_err(dev, "Failed to get unipro clock (ret=%d)\n", ret);
- return ret;
- }
-
- return 0;
+ return ret;
}
static const struct udevice_id mtk_ufs_phy_id_table[] = {
diff --git a/drivers/phy/phy-mtk-xsphy.c b/drivers/phy/phy-mtk-xsphy.c
new file mode 100644
index 00000000000..d3418ffb101
--- /dev/null
+++ b/drivers/phy/phy-mtk-xsphy.c
@@ -0,0 +1,600 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * MediaTek USB3.1 gen2 xsphy Driver
+ *
+ * Copyright (c) 2026 MediaTek Inc.
+ * Copyright (c) 2026 BayLibre, SAS
+ *
+ * Based on Linux mtk-xsphy driver:
+ * Copyright (c) 2018 MediaTek Inc.
+ * Author: Chunfeng Yun <[email protected]>
+ *
+ * And U-Boot mtk-tphy driver:
+ * Copyright (c) 2015 - 2019 MediaTek Inc.
+ * Author: Chunfeng Yun <[email protected]>
+ * Ryder Lee <[email protected]>
+ */
+
+#include <clk.h>
+#include <dm.h>
+#include <generic-phy.h>
+#include <malloc.h>
+#include <mapmem.h>
+#include <regmap.h>
+#include <syscon.h>
+
+#include <asm/io.h>
+#include <dm/device_compat.h>
+#include <dm/devres.h>
+#include <linux/bitfield.h>
+#include <linux/bitops.h>
+#include <linux/delay.h>
+#include <linux/iopoll.h>
+
+#include <dt-bindings/phy/phy.h>
+
+/* u2 phy banks */
+#define SSUSB_SIFSLV_MISC 0x000
+#define SSUSB_SIFSLV_U2FREQ 0x100
+#define SSUSB_SIFSLV_U2PHY_COM 0x300
+
+/* u3 phy shared banks */
+#define SSPXTP_SIFSLV_DIG_GLB 0x000
+#define SSPXTP_SIFSLV_PHYA_GLB 0x100
+
+/* u3 phy banks */
+#define SSPXTP_SIFSLV_DIG_LN_TOP 0x000
+#define SSPXTP_SIFSLV_DIG_LN_TX0 0x100
+#define SSPXTP_SIFSLV_DIG_LN_RX0 0x200
+#define SSPXTP_SIFSLV_DIG_LN_DAIF 0x300
+#define SSPXTP_SIFSLV_PHYA_LN 0x400
+
+#define XSP_U2FREQ_FMCR0 ((SSUSB_SIFSLV_U2FREQ) + 0x00)
+#define P2F_RG_FREQDET_EN BIT(24)
+#define P2F_RG_CYCLECNT GENMASK(23, 0)
+
+#define XSP_U2FREQ_MMONR0 ((SSUSB_SIFSLV_U2FREQ) + 0x0c)
+
+#define XSP_U2FREQ_FMMONR1 ((SSUSB_SIFSLV_U2FREQ) + 0x10)
+#define P2F_RG_FRCK_EN BIT(8)
+#define P2F_USB_FM_VALID BIT(0)
+
+#define XSP_USBPHYACR0 ((SSUSB_SIFSLV_U2PHY_COM) + 0x00)
+#define P2A0_RG_INTR_EN BIT(5)
+
+#define XSP_USBPHYACR1 ((SSUSB_SIFSLV_U2PHY_COM) + 0x04)
+#define P2A1_RG_INTR_CAL GENMASK(23, 19)
+#define P2A1_RG_VRT_SEL GENMASK(14, 12)
+#define P2A1_RG_TERM_SEL GENMASK(10, 8)
+
+#define XSP_USBPHYACR5 ((SSUSB_SIFSLV_U2PHY_COM) + 0x014)
+#define P2A5_RG_HSTX_SRCAL_EN BIT(15)
+#define P2A5_RG_HSTX_SRCTRL GENMASK(14, 12)
+
+#define XSP_USBPHYACR6 ((SSUSB_SIFSLV_U2PHY_COM) + 0x018)
+#define P2A6_RG_BC11_SW_EN BIT(23)
+#define P2A6_RG_OTG_VBUSCMP_EN BIT(20)
+
+#define XSP_U2PHYDTM1 ((SSUSB_SIFSLV_U2PHY_COM) + 0x06C)
+#define P2D_FORCE_IDDIG BIT(9)
+#define P2D_RG_VBUSVALID BIT(5)
+#define P2D_RG_SESSEND BIT(4)
+#define P2D_RG_AVALID BIT(2)
+#define P2D_RG_IDDIG BIT(1)
+
+#define SSPXTP_PHYA_GLB_00 ((SSPXTP_SIFSLV_PHYA_GLB) + 0x00)
+#define RG_XTP_GLB_BIAS_INTR_CTRL GENMASK(21, 16)
+
+#define SSPXTP_PHYA_LN_04 ((SSPXTP_SIFSLV_PHYA_LN) + 0x04)
+#define RG_XTP_LN0_TX_IMPSEL GENMASK(4, 0)
+
+#define SSPXTP_PHYA_LN_14 ((SSPXTP_SIFSLV_PHYA_LN) + 0x014)
+#define RG_XTP_LN0_RX_IMPSEL GENMASK(4, 0)
+
+#define XSP_REF_CLK_MHZ 26
+#define XSP_SLEW_RATE_COEF 17
+#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 mtk_xsphy_instance {
+ void __iomem *port_base;
+ struct device_node *np;
+ struct clk ref_clk; /* reference clock of analog phy */
+ u32 index;
+ u32 type;
+ struct regmap *type_sw;
+ u32 type_sw_reg;
+ u32 type_sw_index;
+ /* only for HQA test */
+ u32 efuse_intr;
+ u32 efuse_tx_imp;
+ u32 efuse_rx_imp;
+ /* u2 eye diagram */
+ u32 eye_src;
+ u32 eye_vrt;
+ u32 eye_term;
+};
+
+struct mtk_xsphy {
+ struct udevice *dev;
+ void __iomem *sif_base;
+ struct mtk_xsphy_instance **phys;
+ u32 nphys;
+ u32 src_ref_clk_mhz; /* reference clock for slew rate calibrate */
+ u32 src_coef; /* coefficient for slew rate calibrate */
+};
+
+static void mtk_xsphy_u2_slew_rate_calibrate(struct mtk_xsphy *xsphy,
+ struct mtk_xsphy_instance *instance)
+{
+ void __iomem *pbase = instance->port_base;
+ u32 calib_val;
+ u32 fm_out;
+ u32 tmp;
+
+ /* use force value */
+ if (instance->eye_src)
+ return;
+
+ /* enable USB ring oscillator */
+ setbits_le32(pbase + XSP_USBPHYACR5, P2A5_RG_HSTX_SRCAL_EN);
+ /* wait for clock to become stable */
+ udelay(1);
+
+ /* enable free run clock */
+ setbits_le32(pbase + XSP_U2FREQ_FMMONR1, P2F_RG_FRCK_EN);
+
+ /* set cycle count as 1024 */
+ clrsetbits_le32(pbase + XSP_U2FREQ_FMCR0, P2F_RG_CYCLECNT,
+ FIELD_PREP(P2F_RG_CYCLECNT, XSP_FM_DET_CYCLE_CNT));
+
+ /* enable frequency meter */
+ setbits_le32(pbase + XSP_U2FREQ_FMCR0, P2F_RG_FREQDET_EN);
+
+ /* ignore return value */
+ readl_poll_sleep_timeout(pbase + XSP_U2FREQ_FMMONR1, tmp,
+ (tmp & P2F_USB_FM_VALID), 10, 200);
+
+ fm_out = readl(pbase + XSP_U2FREQ_MMONR0);
+
+ /* disable frequency meter */
+ clrbits_le32(pbase + XSP_U2FREQ_FMCR0, P2F_RG_FREQDET_EN);
+
+ /* disable free run clock */
+ clrbits_le32(pbase + XSP_U2FREQ_FMMONR1, P2F_RG_FRCK_EN);
+
+ if (fm_out) {
+ /* (1024 / FM_OUT) x reference clock frequency x coefficient */
+ tmp = xsphy->src_ref_clk_mhz * xsphy->src_coef;
+ tmp = (tmp * XSP_FM_DET_CYCLE_CNT) / fm_out;
+ calib_val = DIV_ROUND_CLOSEST(tmp, XSP_SR_COEF_DIVISOR);
+ } else {
+ /* if FM detection fail, set default value */
+ calib_val = 3;
+ }
+ dev_dbg(xsphy->dev, "phy.%u, fm_out:%u, calib:%u (clk:%u, coef:%u)\n",
+ instance->index, fm_out, calib_val, xsphy->src_ref_clk_mhz,
+ xsphy->src_coef);
+
+ /* set HS slew rate */
+ clrsetbits_le32(pbase + XSP_USBPHYACR5, P2A5_RG_HSTX_SRCTRL,
+ FIELD_PREP(P2A5_RG_HSTX_SRCTRL, calib_val));
+
+ /* disable USB ring oscillator */
+ clrbits_le32(pbase + XSP_USBPHYACR5, P2A5_RG_HSTX_SRCAL_EN);
+}
+
+static void mtk_xsphy_u2_instance_init(struct mtk_xsphy *xsphy,
+ struct mtk_xsphy_instance *instance)
+{
+ void __iomem *pbase = instance->port_base;
+
+ /* DP/DM BC1.1 path Disable */
+ clrbits_le32(pbase + XSP_USBPHYACR6, P2A6_RG_BC11_SW_EN);
+
+ setbits_le32(pbase + XSP_USBPHYACR0, P2A0_RG_INTR_EN);
+}
+
+static void mtk_xsphy_u2_instance_power_on(struct mtk_xsphy *xsphy,
+ struct mtk_xsphy_instance *instance)
+{
+ void __iomem *pbase = instance->port_base;
+
+ setbits_le32(pbase + XSP_USBPHYACR6, P2A6_RG_OTG_VBUSCMP_EN);
+
+ clrsetbits_le32(pbase + XSP_U2PHYDTM1,
+ P2D_RG_VBUSVALID | P2D_RG_AVALID | P2D_RG_SESSEND,
+ P2D_RG_VBUSVALID | P2D_RG_AVALID);
+
+ dev_dbg(xsphy->dev, "%s(%u)\n", __func__, instance->index);
+}
+
+static void mtk_xsphy_u2_instance_power_off(struct mtk_xsphy *xsphy,
+ struct mtk_xsphy_instance *instance)
+{
+ void __iomem *pbase = instance->port_base;
+
+ clrbits_le32(pbase + XSP_USBPHYACR6, P2A6_RG_OTG_VBUSCMP_EN);
+
+ clrsetbits_le32(pbase + XSP_U2PHYDTM1,
+ P2D_RG_VBUSVALID | P2D_RG_AVALID | P2D_RG_SESSEND,
+ P2D_RG_SESSEND);
+
+ dev_dbg(xsphy->dev, "%s(%u)\n", __func__, instance->index);
+}
+
+static void mtk_xsphy_u2_instance_set_mode(struct mtk_xsphy *xsphy,
+ struct mtk_xsphy_instance *instance,
+ enum phy_mode mode)
+{
+ u32 tmp;
+
+ tmp = readl(instance->port_base + XSP_U2PHYDTM1);
+
+ switch (mode) {
+ case PHY_MODE_USB_DEVICE:
+ tmp |= P2D_FORCE_IDDIG | P2D_RG_IDDIG;
+ break;
+ case PHY_MODE_USB_HOST:
+ tmp |= P2D_FORCE_IDDIG;
+ tmp &= ~P2D_RG_IDDIG;
+ break;
+ case PHY_MODE_USB_OTG:
+ tmp &= ~(P2D_FORCE_IDDIG | P2D_RG_IDDIG);
+ break;
+ default:
+ return;
+ }
+
+ writel(tmp, instance->port_base + XSP_U2PHYDTM1);
+}
+
+static void mtk_xsphy_parse_property(struct mtk_xsphy *xsphy,
+ struct mtk_xsphy_instance *instance)
+{
+ ofnode node = np_to_ofnode(instance->np);
+
+ switch (instance->type) {
+ case PHY_TYPE_USB2:
+ ofnode_read_u32(node, "mediatek,efuse-intr", &instance->efuse_intr);
+ ofnode_read_u32(node, "mediatek,eye-src", &instance->eye_src);
+ ofnode_read_u32(node, "mediatek,eye-vrt", &instance->eye_vrt);
+ ofnode_read_u32(node, "mediatek,eye-term", &instance->eye_term);
+
+ dev_dbg(xsphy->dev, "intr:%u, src:%u, vrt:%u, term:%u\n",
+ instance->efuse_intr, instance->eye_src,
+ instance->eye_vrt, instance->eye_term);
+ return;
+ case PHY_TYPE_USB3:
+ ofnode_read_u32(node, "mediatek,efuse-intr", &instance->efuse_intr);
+ ofnode_read_u32(node, "mediatek,efuse-tx-imp", &instance->efuse_tx_imp);
+ ofnode_read_u32(node, "mediatek,efuse-rx-imp", &instance->efuse_rx_imp);
+
+ dev_dbg(xsphy->dev, "intr:%u, tx-imp:%u, rx-imp:%u\n",
+ instance->efuse_intr, instance->efuse_tx_imp,
+ instance->efuse_rx_imp);
+ return;
+ case PHY_TYPE_PCIE:
+ case PHY_TYPE_SGMII:
+ /* nothing to do */
+ return;
+ default:
+ dev_err(xsphy->dev, "incompatible PHY type\n");
+ return;
+ }
+}
+
+static void mtk_xsphy_u2_props_set(struct mtk_xsphy *xsphy,
+ struct mtk_xsphy_instance *instance)
+{
+ void __iomem *pbase = instance->port_base;
+
+ if (instance->efuse_intr)
+ clrsetbits_le32(pbase + XSP_USBPHYACR1, P2A1_RG_INTR_CAL,
+ FIELD_PREP(P2A1_RG_INTR_CAL, instance->efuse_intr));
+
+ if (instance->eye_src)
+ clrsetbits_le32(pbase + XSP_USBPHYACR5, P2A5_RG_HSTX_SRCTRL,
+ FIELD_PREP(P2A5_RG_HSTX_SRCTRL, instance->eye_src));
+
+ if (instance->eye_vrt)
+ clrsetbits_le32(pbase + XSP_USBPHYACR1, P2A1_RG_VRT_SEL,
+ FIELD_PREP(P2A1_RG_VRT_SEL, instance->eye_vrt));
+
+ if (instance->eye_term)
+ clrsetbits_le32(pbase + XSP_USBPHYACR1, P2A1_RG_TERM_SEL,
+ FIELD_PREP(P2A1_RG_TERM_SEL, instance->eye_term));
+}
+
+static void mtk_xsphy_u3_props_set(struct mtk_xsphy *xsphy,
+ struct mtk_xsphy_instance *instance)
+{
+ void __iomem *pbase = instance->port_base;
+
+ if (instance->efuse_intr)
+ clrsetbits_le32(xsphy->sif_base + SSPXTP_PHYA_GLB_00,
+ RG_XTP_GLB_BIAS_INTR_CTRL,
+ FIELD_PREP(RG_XTP_GLB_BIAS_INTR_CTRL, instance->efuse_intr));
+
+ if (instance->efuse_tx_imp)
+ clrsetbits_le32(pbase + SSPXTP_PHYA_LN_04, RG_XTP_LN0_TX_IMPSEL,
+ FIELD_PREP(RG_XTP_LN0_TX_IMPSEL, instance->efuse_tx_imp));
+
+ if (instance->efuse_rx_imp)
+ clrsetbits_le32(pbase + SSPXTP_PHYA_LN_14, RG_XTP_LN0_RX_IMPSEL,
+ FIELD_PREP(RG_XTP_LN0_RX_IMPSEL, instance->efuse_rx_imp));
+}
+
+/* type switch for usb3/pcie/sgmii */
+static int mtk_xsphy_type_syscon_get(struct udevice *dev,
+ struct mtk_xsphy_instance *instance,
+ ofnode dn)
+{
+ struct ofnode_phandle_args args;
+ int ret;
+
+ if (!ofnode_read_bool(dn, "mediatek,syscon-type"))
+ return 0;
+
+ ret = ofnode_parse_phandle_with_args(dn, "mediatek,syscon-type",
+ NULL, 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.node);
+ if (IS_ERR(instance->type_sw))
+ return PTR_ERR(instance->type_sw);
+
+ dev_dbg(dev, "phy-%s.%d: type_sw - reg %#x, index %d\n",
+ dev->name, instance->index, instance->type_sw_reg,
+ instance->type_sw_index);
+
+ return 0;
+}
+
+static int mtk_xsphy_type_set(struct mtk_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_xsphy_init(struct phy *phy)
+{
+ struct mtk_xsphy *xsphy = dev_get_priv(phy->dev);
+ struct mtk_xsphy_instance *instance = xsphy->phys[phy->id];
+ int ret;
+
+ ret = clk_enable(&instance->ref_clk);
+ if (ret) {
+ dev_err(xsphy->dev, "failed to enable ref_clk\n");
+ return ret;
+ }
+
+ switch (instance->type) {
+ case PHY_TYPE_USB2:
+ mtk_xsphy_u2_instance_init(xsphy, instance);
+ mtk_xsphy_u2_props_set(xsphy, instance);
+ break;
+ case PHY_TYPE_USB3:
+ mtk_xsphy_u3_props_set(xsphy, instance);
+ 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(&instance->ref_clk);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int mtk_xsphy_power_on(struct phy *phy)
+{
+ struct mtk_xsphy *xsphy = dev_get_priv(phy->dev);
+ struct mtk_xsphy_instance *instance = xsphy->phys[phy->id];
+
+ if (instance->type == PHY_TYPE_USB2) {
+ mtk_xsphy_u2_instance_power_on(xsphy, instance);
+ mtk_xsphy_u2_slew_rate_calibrate(xsphy, instance);
+ }
+
+ return 0;
+}
+
+static int mtk_xsphy_power_off(struct phy *phy)
+{
+ struct mtk_xsphy *xsphy = dev_get_priv(phy->dev);
+ struct mtk_xsphy_instance *instance = xsphy->phys[phy->id];
+
+ if (instance->type == PHY_TYPE_USB2)
+ mtk_xsphy_u2_instance_power_off(xsphy, instance);
+
+ return 0;
+}
+
+static int mtk_xsphy_exit(struct phy *phy)
+{
+ struct mtk_xsphy *xsphy = dev_get_priv(phy->dev);
+ struct mtk_xsphy_instance *instance = xsphy->phys[phy->id];
+
+ clk_disable(&instance->ref_clk);
+
+ return 0;
+}
+
+static int mtk_xsphy_set_mode(struct phy *phy, enum phy_mode mode, int submode)
+{
+ struct mtk_xsphy *xsphy = dev_get_priv(phy->dev);
+ struct mtk_xsphy_instance *instance = xsphy->phys[phy->id];
+
+ if (instance->type == PHY_TYPE_USB2)
+ mtk_xsphy_u2_instance_set_mode(xsphy, instance, mode);
+
+ return 0;
+}
+
+static int mtk_xsphy_xlate(struct phy *phy, struct ofnode_phandle_args *args)
+{
+ struct mtk_xsphy *xsphy = dev_get_priv(phy->dev);
+ struct mtk_xsphy_instance *instance = NULL;
+ const struct device_node *phy_np = ofnode_to_np(args->node);
+ u32 index;
+
+ if (!phy_np) {
+ dev_err(phy->dev, "null pointer phy node\n");
+ return -EINVAL;
+ }
+
+ if (args->args_count != 2) {
+ dev_err(phy->dev, "invalid number of cells in 'phy' property\n");
+ return -EINVAL;
+ }
+
+ for (index = 0; index < xsphy->nphys; index++)
+ if (phy_np == xsphy->phys[index]->np) {
+ instance = xsphy->phys[index];
+ break;
+ }
+
+ if (!instance) {
+ dev_err(phy->dev, "failed to find appropriate phy\n");
+ return -EINVAL;
+ }
+
+ phy->id = index;
+ instance->type = args->args[1];
+ if (!(instance->type == PHY_TYPE_USB2 ||
+ instance->type == PHY_TYPE_USB3 ||
+ instance->type == PHY_TYPE_PCIE ||
+ instance->type == PHY_TYPE_SGMII)) {
+ dev_err(phy->dev, "unsupported PHY type\n");
+ return -EINVAL;
+ }
+
+ mtk_xsphy_parse_property(xsphy, instance);
+ mtk_xsphy_type_set(instance);
+
+ return 0;
+}
+
+static const struct phy_ops mtk_xsphy_ops = {
+ .init = mtk_xsphy_init,
+ .exit = mtk_xsphy_exit,
+ .power_on = mtk_xsphy_power_on,
+ .power_off = mtk_xsphy_power_off,
+ .set_mode = mtk_xsphy_set_mode,
+ .of_xlate = mtk_xsphy_xlate,
+};
+
+static int mtk_xsphy_probe(struct udevice *dev)
+{
+ struct mtk_xsphy *xsphy = dev_get_priv(dev);
+ fdt_addr_t sif_addr;
+ ofnode subnode;
+ int index = 0;
+
+ xsphy->nphys = dev_get_child_count(dev);
+
+ xsphy->phys = devm_kcalloc(dev, xsphy->nphys, sizeof(*xsphy->phys),
+ GFP_KERNEL);
+ if (!xsphy->phys)
+ return -ENOMEM;
+
+ xsphy->dev = dev;
+
+ sif_addr = ofnode_get_addr(dev_ofnode(dev));
+ /* optional, may not exist if no u3 phys */
+ if (sif_addr != FDT_ADDR_T_NONE)
+ xsphy->sif_base = map_sysmem(sif_addr, 0);
+
+ xsphy->src_ref_clk_mhz = XSP_REF_CLK_MHZ;
+ xsphy->src_coef = XSP_SLEW_RATE_COEF;
+ /* update parameters of slew rate calibrate if exist */
+ ofnode_read_u32(dev_ofnode(dev), "mediatek,src-ref-clk-mhz",
+ &xsphy->src_ref_clk_mhz);
+ ofnode_read_u32(dev_ofnode(dev), "mediatek,src-coef", &xsphy->src_coef);
+
+ dev_for_each_subnode(subnode, dev) {
+ struct mtk_xsphy_instance *inst;
+ fdt_addr_t addr;
+ int ret;
+
+ inst = devm_kzalloc(dev, sizeof(*inst), GFP_KERNEL);
+ if (!inst)
+ return -ENOMEM;
+
+ xsphy->phys[index] = inst;
+
+ addr = ofnode_get_addr(subnode);
+ if (addr == FDT_ADDR_T_NONE)
+ return -EADDRNOTAVAIL;
+
+ inst->port_base = map_sysmem(addr, 0);
+ inst->index = index;
+ inst->np = ofnode_to_np(subnode);
+
+ ret = clk_get_by_name_nodev(subnode, "ref", &inst->ref_clk);
+ if (ret) {
+ dev_err(dev, "failed to get ref_clk(id-%d)\n", index);
+ return ret;
+ }
+
+ ret = mtk_xsphy_type_syscon_get(dev, inst, subnode);
+ if (ret)
+ return ret;
+
+ index++;
+ }
+
+ return 0;
+}
+
+static const struct udevice_id mtk_xsphy_id_table[] = {
+ { .compatible = "mediatek,xsphy" },
+ { }
+};
+
+U_BOOT_DRIVER(mtk_xsphy) = {
+ .name = "mtk-xsphy",
+ .id = UCLASS_PHY,
+ .of_match = mtk_xsphy_id_table,
+ .ops = &mtk_xsphy_ops,
+ .probe = mtk_xsphy_probe,
+ .priv_auto = sizeof(struct mtk_xsphy),
+};
diff --git a/drivers/pinctrl/mediatek/pinctrl-mt7981.c b/drivers/pinctrl/mediatek/pinctrl-mt7981.c
index 8875c276f36..5219b147797 100644
--- a/drivers/pinctrl/mediatek/pinctrl-mt7981.c
+++ b/drivers/pinctrl/mediatek/pinctrl-mt7981.c
@@ -106,7 +106,7 @@ static const struct mtk_pin_field_calc mt7981_pin_ies_range[] = {
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(11, 11, 5, 0x20, 0x10, 10, 1),
PIN_FIELD_BASE(12, 12, 5, 0x20, 0x10, 7, 1),
PIN_FIELD_BASE(13, 13, 5, 0x20, 0x10, 11, 1),
@@ -215,7 +215,7 @@ static const struct mtk_pin_field_calc mt7981_pin_smt_range[] = {
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(44, 44, 7, 0x70, 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),
@@ -279,8 +279,8 @@ static const struct mtk_pin_field_calc mt7981_pin_drv_range[] = {
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(3, 3, 4, 0x00, 0x10, 18, 3),
+ PIN_FIELD_BASE(4, 4, 4, 0x00, 0x10, 6, 3),
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),
@@ -288,9 +288,9 @@ static const struct mtk_pin_field_calc mt7981_pin_drv_range[] = {
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(11, 11, 5, 0x10, 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(13, 13, 5, 0x10, 0x10, 3, 3),
PIN_FIELD_BASE(14, 14, 4, 0x00, 0x10, 27, 3),
@@ -302,7 +302,7 @@ static const struct mtk_pin_field_calc mt7981_pin_drv_range[] = {
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(23, 23, 2, 0x10, 0x10, 0, 3),
PIN_FIELD_BASE(24, 24, 2, 0x00, 0x10, 27, 3),
PIN_FIELD_BASE(25, 25, 2, 0x00, 0x10, 24, 3),
@@ -368,7 +368,7 @@ static const struct mtk_pin_field_calc mt7981_pin_pupd_range[] = {
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(20, 20, 2, 0x30, 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),
diff --git a/drivers/ufs/ufs-mediatek.c b/drivers/ufs/ufs-mediatek.c
index e860d765eea..268627d5863 100644
--- a/drivers/ufs/ufs-mediatek.c
+++ b/drivers/ufs/ufs-mediatek.c
@@ -182,19 +182,15 @@ static int ufs_mtk_bind_mphy(struct ufs_hba *hba)
struct ufs_mtk_host *host = dev_get_priv(hba->dev);
int err = 0;
- err = generic_phy_get_by_index(hba->dev, 0, host->mphy);
+ err = generic_phy_get_by_index(hba->dev, 0, &host->mphy);
- if (IS_ERR(host->mphy)) {
- err = PTR_ERR(host->mphy);
- if (err != -ENODEV) {
- dev_info(hba->dev, "%s: Could NOT get a valid PHY %d\n", __func__,
- err);
- }
+ if (err) {
+ if (err == -ENOENT)
+ return 0; /* no PHY, nothing to do */
+ dev_err(hba->dev, "Failed to get PHY: %d.\n", err);
+ return err;
}
- if (err)
- host->mphy = NULL;
-
return err;
}
@@ -321,19 +317,35 @@ static int ufs_mtk_init(struct ufs_hba *hba)
ufs_mtk_init_reset(hba);
- // TODO: Clocking
+ err = clk_get_bulk(hba->dev, &priv->clks);
+ if (err) {
+ dev_err(hba->dev, "failed to initialize clocks, err:%d\n", err);
+ return err;
+ }
+
+ err = clk_enable_bulk(&priv->clks);
+ if (err) {
+ dev_err(hba->dev, "failed to enable clocks, err:%d\n", err);
+ goto err_clk_enable;
+ }
- err = generic_phy_power_on(priv->mphy);
+ err = generic_phy_power_on(&priv->mphy);
if (err) {
dev_err(hba->dev, "%s: phy init failed, err = %d\n",
__func__, err);
- return err;
+ goto err_phy_power_on;
}
ufs_mtk_setup_ref_clk(hba, true);
ufs_mtk_get_hw_ip_version(hba);
return 0;
+
+err_phy_power_on:
+ clk_disable_bulk(&priv->clks);
+err_clk_enable:
+ clk_release_bulk(&priv->clks);
+ return err;
}
static int ufs_mtk_device_reset(struct ufs_hba *hba)
@@ -383,7 +395,9 @@ static int ufs_mtk_probe(struct udevice *dev)
static const struct udevice_id ufs_mtk_ids[] = {
{ .compatible = "mediatek,mt6878-ufshci" },
- {},
+ { .compatible = "mediatek,mt8183-ufshci" },
+ { .compatible = "mediatek,mt8195-ufshci" },
+ { }
};
U_BOOT_DRIVER(mediatek_ufshci) = {
diff --git a/drivers/ufs/ufs-mediatek.h b/drivers/ufs/ufs-mediatek.h
index 11a83d34c5b..0ffd0483eff 100644
--- a/drivers/ufs/ufs-mediatek.h
+++ b/drivers/ufs/ufs-mediatek.h
@@ -154,7 +154,7 @@ struct ufs_mtk_mcq_intr_info {
};
struct ufs_mtk_host {
- struct phy *mphy;
+ struct phy mphy;
struct reset_ctl *unipro_reset;
struct reset_ctl *crypto_reset;
struct reset_ctl *hci_reset;