]> git.ipfire.org Git - thirdparty/u-boot.git/commitdiff
ufs: Add MediaTek UFS driver
authorIgor Belwon <igor.belwon@mentallysanemainliners.org>
Sat, 11 Oct 2025 19:10:06 +0000 (21:10 +0200)
committerNeil Armstrong <neil.armstrong@linaro.org>
Tue, 28 Oct 2025 16:22:52 +0000 (17:22 +0100)
Add the UFS driver for MediaTek platforms.

Loosely based on the Linux driver, this UFS driver can successfully get a
link and R/W access to the UFS chip on the MediaTek MT6878 mobile SoC,
when U-Boot is running as lk, or as the kernel (Secure world access is
not tested)

Signed-off-by: Igor Belwon <igor.belwon@mentallysanemainliners.org>
Link: https://patch.msgid.link/20251011-mtk-ufs-uboot-v1-3-a05f991ee150@mentallysanemainliners.org
Signed-off-by: Neil Armstrong <neil.armstrong@linaro.org>
drivers/ufs/Kconfig
drivers/ufs/Makefile
drivers/ufs/ufs-mediatek-sip.h [new file with mode: 0644]
drivers/ufs/ufs-mediatek.c [new file with mode: 0644]
drivers/ufs/ufs-mediatek.h [new file with mode: 0644]

index 3d367855173ce277ceeb2884c5546d1ded0de26b..b030a972b98bb84489301376c3a7bf099adf8d8b 100644 (file)
@@ -15,6 +15,20 @@ config CADENCE_UFS
          This selects the platform driver for the Cadence UFS host
          controller present on present TI's J721e devices.
 
+config UFS_MEDIATEK
+       tristate "MediaTek UFS Host Controller Driver"
+       depends on UFS && ARCH_MEDIATEK
+       select PHY_MTK_UFS
+       help
+         This selects the MediaTek specific additions to UFSHCD platform driver.
+         UFS host on Mediatek needs some vendor specific configuration before
+         accessing the hardware which includes PHY configuration and vendor
+         specific registers.
+
+         Select this if you have UFS controller on MediaTek chipset.
+
+         If unsure, say N.
+
 config UFS_PCI
        bool "PCI bus based UFS Controller support"
        depends on PCI && UFS
index 41e910cfc515b80f6b1bc630f2f1e32be37cd3d1..bbee66caa8a407f0ce85cc981395534789069cda 100644 (file)
@@ -5,6 +5,7 @@
 
 obj-$(CONFIG_UFS) += ufs.o ufs-uclass.o
 obj-$(CONFIG_CADENCE_UFS) += cdns-platform.o
+obj-$(CONFIG_UFS_MEDIATEK) += ufs-mediatek.o
 obj-$(CONFIG_QCOM_UFS) += ufs-qcom.o
 obj-$(CONFIG_TI_J721E_UFS) += ti-j721e-ufs.o
 obj-$(CONFIG_UFS_PCI) += ufs-pci.o
diff --git a/drivers/ufs/ufs-mediatek-sip.h b/drivers/ufs/ufs-mediatek-sip.h
new file mode 100644 (file)
index 0000000..6a61f7b
--- /dev/null
@@ -0,0 +1,56 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (C) 2022 MediaTek Inc.
+ * Copyright (c) 2025, Igor Belwon <igor.belwon@mentallysanemainliners.org>
+ *
+ * Slimmed down header from Linux: drivers/ufs/host/ufs-mediatek-sip.h
+ */
+
+#ifndef _UFS_MEDIATEK_SIP_H
+#define _UFS_MEDIATEK_SIP_H
+
+#include <linux/arm-smccc.h>
+
+/*
+ * SiP (Slicon Partner) commands
+ */
+#define MTK_SIP_UFS_CONTROL                    ARM_SMCCC_CALL_VAL(ARM_SMCCC_FAST_CALL, \
+                                                                  ARM_SMCCC_SMC_64, \
+                                                                  ARM_SMCCC_OWNER_SIP, 0x276)
+#define UFS_MTK_SIP_DEVICE_RESET               BIT(1)
+#define UFS_MTK_SIP_REF_CLK_NOTIFICATION       BIT(3)
+
+/*
+ * SMC call wrapper function
+ */
+struct ufs_mtk_smc_arg {
+       unsigned long cmd;
+       struct arm_smccc_res *res;
+       unsigned long v1;
+       unsigned long v2;
+       unsigned long v3;
+       unsigned long v4;
+       unsigned long v5;
+       unsigned long v6;
+       unsigned long v7;
+};
+
+static inline void _ufs_mtk_smc(struct ufs_mtk_smc_arg s)
+{
+       arm_smccc_smc(MTK_SIP_UFS_CONTROL,
+                     s.cmd,
+                     s.v1, s.v2, s.v3, s.v4, s.v5, s.v6, s.res);
+}
+
+#define ufs_mtk_smc(...) \
+       _ufs_mtk_smc((struct ufs_mtk_smc_arg) {__VA_ARGS__})
+
+/* SIP interface */
+
+#define ufs_mtk_ref_clk_notify(on, stage, res) \
+       ufs_mtk_smc(UFS_MTK_SIP_REF_CLK_NOTIFICATION, &(res), on, stage)
+
+#define ufs_mtk_device_reset_ctrl(high, res) \
+       ufs_mtk_smc(UFS_MTK_SIP_DEVICE_RESET, &(res), high)
+
+#endif /* !_UFS_MEDIATEK_SIP_H */
diff --git a/drivers/ufs/ufs-mediatek.c b/drivers/ufs/ufs-mediatek.c
new file mode 100644 (file)
index 0000000..10e7990
--- /dev/null
@@ -0,0 +1,403 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (c) 2025, Igor Belwon <igor.belwon@mentallysanemainliners.org>
+ *
+ * Loosely based on Linux driver: drivers/ufs/host/ufs-mediatek.c
+ */
+
+#include <asm/io.h>
+#include <clk.h>
+#include <dm.h>
+#include <dm/device_compat.h>
+#include <generic-phy.h>
+#include <ufs.h>
+#include <asm/gpio.h>
+#include <reset.h>
+
+#include <linux/arm-smccc.h>
+#include <linux/bitfield.h>
+#include <linux/bitops.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+
+#include "ufs.h"
+#include "ufs-mediatek.h"
+#include "ufs-mediatek-sip.h"
+
+static void ufs_mtk_advertise_quirks(struct ufs_hba *hba)
+{
+       hba->quirks |= UFSHCI_QUIRK_SKIP_MANUAL_WB_FLUSH_CTRL |
+                                  UFSHCD_QUIRK_MCQ_BROKEN_INTR |
+                                  UFSHCD_QUIRK_BROKEN_LSDBS_CAP;
+}
+
+static int ufs_mtk_hce_enable_notify(struct ufs_hba *hba,
+                                    enum ufs_notify_change_status status)
+{
+       struct ufs_mtk_host *host = dev_get_priv(hba->dev);
+
+       if (status == PRE_CHANGE) {
+               if (host->caps & UFS_MTK_CAP_DISABLE_AH8) {
+                       ufshcd_writel(hba, 0,
+                                     REG_AUTO_HIBERNATE_IDLE_TIMER);
+                       hba->capabilities &= ~MASK_AUTO_HIBERN8_SUPPORT;
+               }
+
+               /*
+                * Turn on CLK_CG early to bypass abnormal ERR_CHK signal
+                * to prevent host hang issue
+                */
+               ufshcd_writel(hba,
+                             ufshcd_readl(hba, REG_UFS_XOUFS_CTRL) | 0x80,
+                             REG_UFS_XOUFS_CTRL);
+
+               /* DDR_EN setting */
+               if (host->ip_ver >= IP_VER_MT6989) {
+                       ufshcd_rmwl(hba, UFS_MASK(0x7FFF, 8),
+                                   0x453000, REG_UFS_MMIO_OPT_CTRL_0);
+               }
+       }
+
+       return 0;
+}
+
+static int ufs_mtk_unipro_set_lpm(struct ufs_hba *hba, bool lpm)
+{
+       int ret;
+       struct ufs_mtk_host *host = dev_get_priv(hba->dev);
+
+       ret = ufshcd_dme_set(hba,
+                            UIC_ARG_MIB_SEL(VS_UNIPROPOWERDOWNCONTROL, 0),
+                            lpm ? 1 : 0);
+       if (!ret || !lpm) {
+               /*
+                * Forcibly set as non-LPM mode if UIC commands is failed
+                * to use default hba_enable_delay_us value for re-enabling
+                * the host.
+                */
+               host->unipro_lpm = lpm;
+       }
+
+       return ret;
+}
+
+static int ufs_mtk_pre_link(struct ufs_hba *hba)
+{
+       int ret;
+       u32 tmp;
+
+       ret = ufs_mtk_unipro_set_lpm(hba, false);
+       if (ret)
+               return ret;
+
+       /*
+        * Setting PA_Local_TX_LCC_Enable to 0 before link startup
+        * to make sure that both host and device TX LCC are disabled
+        * once link startup is completed.
+        */
+       ret = ufshcd_dme_set(hba, UIC_ARG_MIB(PA_LOCAL_TX_LCC_ENABLE), 0);
+       if (ret)
+               return ret;
+
+       /* disable deep stall */
+       ret = ufshcd_dme_get(hba, UIC_ARG_MIB(VS_SAVEPOWERCONTROL), &tmp);
+       if (ret)
+               return ret;
+
+       tmp &= ~(1 << 6);
+
+       ret = ufshcd_dme_set(hba, UIC_ARG_MIB(VS_SAVEPOWERCONTROL), tmp);
+       if (ret)
+               return ret;
+
+       ret = ufshcd_dme_set(hba, UIC_ARG_MIB(PA_SCRAMBLING), tmp);
+
+       return ret;
+}
+
+static void ufs_mtk_cfg_unipro_cg(struct ufs_hba *hba, bool enable)
+{
+       u32 tmp;
+
+       if (enable) {
+               ufshcd_dme_get(hba,
+                              UIC_ARG_MIB(VS_SAVEPOWERCONTROL), &tmp);
+               tmp = tmp |
+                     (1 << RX_SYMBOL_CLK_GATE_EN) |
+                     (1 << SYS_CLK_GATE_EN) |
+                     (1 << TX_CLK_GATE_EN);
+               ufshcd_dme_set(hba,
+                              UIC_ARG_MIB(VS_SAVEPOWERCONTROL), tmp);
+
+               ufshcd_dme_get(hba,
+                              UIC_ARG_MIB(VS_DEBUGCLOCKENABLE), &tmp);
+               tmp = tmp & ~(1 << TX_SYMBOL_CLK_REQ_FORCE);
+               ufshcd_dme_set(hba,
+                              UIC_ARG_MIB(VS_DEBUGCLOCKENABLE), tmp);
+       } else {
+               ufshcd_dme_get(hba,
+                              UIC_ARG_MIB(VS_SAVEPOWERCONTROL), &tmp);
+               tmp = tmp & ~((1 << RX_SYMBOL_CLK_GATE_EN) |
+                            (1 << SYS_CLK_GATE_EN) |
+                            (1 << TX_CLK_GATE_EN));
+               ufshcd_dme_set(hba,
+                              UIC_ARG_MIB(VS_SAVEPOWERCONTROL), tmp);
+
+               ufshcd_dme_get(hba,
+                              UIC_ARG_MIB(VS_DEBUGCLOCKENABLE), &tmp);
+               tmp = tmp | (1 << TX_SYMBOL_CLK_REQ_FORCE);
+               ufshcd_dme_set(hba,
+                              UIC_ARG_MIB(VS_DEBUGCLOCKENABLE), tmp);
+       }
+}
+
+static void ufs_mtk_post_link(struct ufs_hba *hba)
+{
+       /* enable unipro clock gating feature */
+       ufs_mtk_cfg_unipro_cg(hba, true);
+}
+
+static int ufs_mtk_link_startup_notify(struct ufs_hba *hba,
+                                      enum ufs_notify_change_status status)
+{
+       int ret = 0;
+
+       switch (status) {
+       case PRE_CHANGE:
+                       ret = ufs_mtk_pre_link(hba);
+                       break;
+       case POST_CHANGE:
+                       ufs_mtk_post_link(hba);
+                       break;
+       default:
+                       ret = -EINVAL;
+                       break;
+       }
+
+       return ret;
+}
+
+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);
+
+       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)
+               host->mphy = NULL;
+
+       return err;
+}
+
+static void ufs_mtk_init_reset_control(struct ufs_hba *hba,
+                                      struct reset_ctl **rc,
+                                      char *str)
+{
+       *rc = devm_reset_control_get(hba->dev, str);
+       if (IS_ERR(*rc)) {
+               dev_info(hba->dev, "Failed to get reset control %s: %ld\n",
+                        str, PTR_ERR(*rc));
+               *rc = NULL;
+       }
+}
+
+static void ufs_mtk_init_reset(struct ufs_hba *hba)
+{
+       struct ufs_mtk_host *host = dev_get_priv(hba->dev);
+
+       ufs_mtk_init_reset_control(hba, &host->hci_reset,
+                                  "hci_rst");
+       ufs_mtk_init_reset_control(hba, &host->unipro_reset,
+                                  "unipro_rst");
+       ufs_mtk_init_reset_control(hba, &host->crypto_reset,
+                                  "crypto_rst");
+}
+
+static void ufs_mtk_get_hw_ip_version(struct ufs_hba *hba)
+{
+       struct ufs_mtk_host *host = dev_get_priv(hba->dev);
+       u32 hw_ip_ver;
+
+       hw_ip_ver = ufshcd_readl(hba, REG_UFS_MTK_IP_VER);
+
+       if (((hw_ip_ver & (0xFF << 24)) == (0x1 << 24)) ||
+           ((hw_ip_ver & (0xFF << 24)) == 0)) {
+               hw_ip_ver &= ~(0xFF << 24);
+               hw_ip_ver |= (0x1 << 28);
+       }
+
+       host->ip_ver = hw_ip_ver;
+
+       dev_info(hba->dev, "MediaTek UFS IP Version: 0x%x\n", hw_ip_ver);
+}
+
+static int ufs_mtk_setup_ref_clk(struct ufs_hba *hba, bool on)
+{
+       struct ufs_mtk_host *host = dev_get_priv(hba->dev);
+       struct arm_smccc_res res;
+       int timeout, time_checked = 0;
+       u32 value;
+
+       if (host->ref_clk_enabled == on)
+               return 0;
+
+       ufs_mtk_ref_clk_notify(on, PRE_CHANGE, res);
+
+       if (on) {
+               ufshcd_writel(hba, REFCLK_REQUEST, REG_UFS_REFCLK_CTRL);
+       } else {
+               udelay(10);
+               ufshcd_writel(hba, REFCLK_RELEASE, REG_UFS_REFCLK_CTRL);
+       }
+
+       /* Wait for ack */
+       timeout = REFCLK_REQ_TIMEOUT_US;
+       do {
+               value = ufshcd_readl(hba, REG_UFS_REFCLK_CTRL);
+
+               /* Wait until ack bit equals to req bit */
+               if (((value & REFCLK_ACK) >> 1) == (value & REFCLK_REQUEST))
+                       goto out;
+
+               udelay(200);
+               time_checked += 200;
+       } while (time_checked != timeout);
+
+       dev_err(hba->dev, "missing ack of refclk req, reg: 0x%x\n", value);
+
+       /*
+        * If clock on timeout, assume clock is off, notify tfa do clock
+        * off setting.(keep DIFN disable, release resource)
+        * If clock off timeout, assume clock will off finally,
+        * set ref_clk_enabled directly.(keep DIFN disable, keep resource)
+        */
+       if (on)
+               ufs_mtk_ref_clk_notify(false, POST_CHANGE, res);
+       else
+               host->ref_clk_enabled = false;
+
+       return -ETIMEDOUT;
+
+out:
+       host->ref_clk_enabled = on;
+       if (on)
+               udelay(10);
+
+       ufs_mtk_ref_clk_notify(on, POST_CHANGE, res);
+
+       return 0;
+}
+
+/**
+ * ufs_mtk_init - bind phy with controller
+ * @hba: host controller instance
+ *
+ * Powers up PHY enabling clocks and regulators.
+ *
+ * Returns -ENODEV if binding fails, returns negative error
+ * on phy power up failure and returns zero on success.
+ */
+static int ufs_mtk_init(struct ufs_hba *hba)
+{
+       struct ufs_mtk_host *priv = dev_get_priv(hba->dev);
+       int err;
+
+       priv->hba = hba;
+
+       err = ufs_mtk_bind_mphy(hba);
+       if (err)
+               return -ENODEV;
+
+       ufs_mtk_advertise_quirks(hba);
+
+       ufs_mtk_init_reset(hba);
+
+       // TODO: Clocking
+
+       err = generic_phy_power_on(priv->mphy);
+       if (err) {
+               dev_err(hba->dev, "%s: phy init failed, err = %d\n",
+                       __func__, err);
+               return err;
+       }
+
+       ufs_mtk_setup_ref_clk(hba, true);
+       ufs_mtk_get_hw_ip_version(hba);
+
+       return 0;
+}
+
+static int ufs_mtk_device_reset(struct ufs_hba *hba)
+{
+       struct arm_smccc_res res;
+
+       ufs_mtk_device_reset_ctrl(0, res);
+
+       /*
+        * The reset signal is active low. UFS devices shall detect
+        * more than or equal to 1us of positive or negative RST_n
+        * pulse width.
+        *
+        * To be on safe side, keep the reset low for at least 10us.
+        */
+       udelay(13);
+
+       ufs_mtk_device_reset_ctrl(1, res);
+
+       /* Some devices may need time to respond to rst_n */
+       mdelay(13);
+
+       dev_dbg(hba->dev, "device reset done\n");
+
+       return 0;
+}
+
+static struct ufs_hba_ops ufs_mtk_hba_ops = {
+       .init                   = ufs_mtk_init,
+       .hce_enable_notify      = ufs_mtk_hce_enable_notify,
+       .link_startup_notify    = ufs_mtk_link_startup_notify,
+       .device_reset           = ufs_mtk_device_reset,
+};
+
+static int ufs_mtk_probe(struct udevice *dev)
+{
+       int ret;
+
+       ret = ufshcd_probe(dev, &ufs_mtk_hba_ops);
+       if (ret) {
+               dev_err(dev, "ufshcd_probe() failed, ret:%d\n", ret);
+               return ret;
+       }
+
+       return 0;
+}
+
+static int ufs_mtk_bind(struct udevice *dev)
+{
+       struct udevice *scsi_dev;
+
+       return ufs_scsi_bind(dev, &scsi_dev);
+}
+
+static const struct udevice_id ufs_mtk_ids[] = {
+       { .compatible = "mediatek,mt6878-ufshci" },
+       {},
+};
+
+U_BOOT_DRIVER(mediatek_ufshci) = {
+       .name           = "mediatek-ufshci",
+       .id             = UCLASS_UFS,
+       .of_match       = ufs_mtk_ids,
+       .probe          = ufs_mtk_probe,
+       .bind           = ufs_mtk_bind,
+       .priv_auto      = sizeof(struct ufs_mtk_host),
+};
diff --git a/drivers/ufs/ufs-mediatek.h b/drivers/ufs/ufs-mediatek.h
new file mode 100644 (file)
index 0000000..11a83d3
--- /dev/null
@@ -0,0 +1,210 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (C) 2019 MediaTek Inc.
+ * Copyright (c) 2025, Igor Belwon <igor.belwon@mentallysanemainliners.org>
+ *
+ * Slimmed down header from Linux: drivers/ufs/host/ufs-mediatek.h
+ */
+
+#ifndef _UFS_MEDIATEK_H
+#define _UFS_MEDIATEK_H
+
+#include <clk.h>
+#include <linux/bitops.h>
+
+/*
+ * MCQ define and struct
+ */
+#define UFSHCD_MAX_Q_NR 8
+#define MTK_MCQ_INVALID_IRQ    0xFFFF
+
+/* REG_UFS_MMIO_OPT_CTRL_0 160h */
+#define EHS_EN                  BIT(0)
+#define PFM_IMPV                BIT(1)
+#define MCQ_MULTI_INTR_EN       BIT(2)
+#define MCQ_CMB_INTR_EN         BIT(3)
+#define MCQ_AH8                 BIT(4)
+
+#define MCQ_INTR_EN_MSK         (MCQ_MULTI_INTR_EN | MCQ_CMB_INTR_EN)
+
+/*
+ * Vendor specific UFSHCI Registers
+ */
+#define REG_UFS_XOUFS_CTRL          0x140
+#define REG_UFS_REFCLK_CTRL         0x144
+#define REG_UFS_MMIO_OPT_CTRL_0     0x160
+#define REG_UFS_EXTREG              0x2100
+#define REG_UFS_MPHYCTRL            0x2200
+#define REG_UFS_MTK_IP_VER          0x2240
+#define REG_UFS_REJECT_MON          0x22AC
+#define REG_UFS_DEBUG_SEL           0x22C0
+#define REG_UFS_PROBE               0x22C8
+#define REG_UFS_DEBUG_SEL_B0        0x22D0
+#define REG_UFS_DEBUG_SEL_B1        0x22D4
+#define REG_UFS_DEBUG_SEL_B2        0x22D8
+#define REG_UFS_DEBUG_SEL_B3        0x22DC
+
+#define REG_UFS_MTK_SQD             0x2800
+#define REG_UFS_MTK_SQIS            0x2814
+#define REG_UFS_MTK_CQD             0x281C
+#define REG_UFS_MTK_CQIS            0x2824
+
+#define REG_UFS_MCQ_STRIDE          0x30
+
+/*
+ * Ref-clk control
+ *
+ * Values for register REG_UFS_REFCLK_CTRL
+ */
+#define REFCLK_RELEASE              0x0
+#define REFCLK_REQUEST              BIT(0)
+#define REFCLK_ACK                  BIT(1)
+
+#define REFCLK_REQ_TIMEOUT_US       3000
+#define REFCLK_DEFAULT_WAIT_US      32
+
+/*
+ * Other attributes
+ */
+#define VS_DEBUGCLOCKENABLE         0xD0A1
+#define VS_SAVEPOWERCONTROL         0xD0A6
+#define VS_UNIPROPOWERDOWNCONTROL   0xD0A8
+
+/*
+ * Vendor specific link state
+ */
+enum {
+       VS_LINK_DISABLED            = 0,
+       VS_LINK_DOWN                = 1,
+       VS_LINK_UP                  = 2,
+       VS_LINK_HIBERN8             = 3,
+       VS_LINK_LOST                = 4,
+       VS_LINK_CFG                 = 5,
+};
+
+/*
+ * Vendor specific host controller state
+ */
+enum {
+       VS_HCE_RESET                = 0,
+       VS_HCE_BASE                 = 1,
+       VS_HCE_OOCPR_WAIT           = 2,
+       VS_HCE_DME_RESET            = 3,
+       VS_HCE_MIDDLE               = 4,
+       VS_HCE_DME_ENABLE           = 5,
+       VS_HCE_DEFAULTS             = 6,
+       VS_HIB_IDLEEN               = 7,
+       VS_HIB_ENTER                = 8,
+       VS_HIB_ENTER_CONF           = 9,
+       VS_HIB_MIDDLE               = 10,
+       VS_HIB_WAITTIMER            = 11,
+       VS_HIB_EXIT_CONF            = 12,
+       VS_HIB_EXIT                 = 13,
+};
+
+/*
+ * VS_DEBUGCLOCKENABLE
+ */
+enum {
+       TX_SYMBOL_CLK_REQ_FORCE = 5,
+};
+
+/*
+ * VS_SAVEPOWERCONTROL
+ */
+enum {
+       RX_SYMBOL_CLK_GATE_EN   = 0,
+       SYS_CLK_GATE_EN         = 2,
+       TX_CLK_GATE_EN          = 3,
+};
+
+/*
+ * Host capability
+ */
+enum ufs_mtk_host_caps {
+       UFS_MTK_CAP_BOOST_CRYPT_ENGINE         = 1 << 0,
+       UFS_MTK_CAP_VA09_PWR_CTRL              = 1 << 1,
+       UFS_MTK_CAP_DISABLE_AH8                = 1 << 2,
+       UFS_MTK_CAP_BROKEN_VCC                 = 1 << 3,
+
+       /*
+        * Override UFS_MTK_CAP_BROKEN_VCC's behavior to
+        * allow vccqx upstream to enter LPM
+        */
+       UFS_MTK_CAP_ALLOW_VCCQX_LPM            = 1 << 5,
+       UFS_MTK_CAP_PMC_VIA_FASTAUTO           = 1 << 6,
+       UFS_MTK_CAP_TX_SKEW_FIX                = 1 << 7,
+       UFS_MTK_CAP_DISABLE_MCQ                = 1 << 8,
+       /* Control MTCMOS with RTFF */
+       UFS_MTK_CAP_RTFF_MTCMOS                = 1 << 9,
+
+       UFS_MTK_CAP_MCQ_BROKEN_RTC             = 1 << 10,
+};
+
+struct ufs_mtk_hw_ver {
+       u8 step;
+       u8 minor;
+       u8 major;
+};
+
+struct ufs_mtk_mcq_intr_info {
+       struct ufs_hba *hba;
+       u32 irq;
+       u8 qid;
+};
+
+struct ufs_mtk_host {
+       struct phy *mphy;
+       struct reset_ctl *unipro_reset;
+       struct reset_ctl *crypto_reset;
+       struct reset_ctl *hci_reset;
+       struct ufs_hba *hba;
+       struct ufs_mtk_crypt_cfg *crypt;
+       struct clk_bulk clks;
+       struct ufs_mtk_hw_ver hw_ver;
+       enum ufs_mtk_host_caps caps;
+       bool mphy_powered_on;
+       bool unipro_lpm;
+       bool ref_clk_enabled;
+       bool is_clks_enabled;
+       u16 ref_clk_ungating_wait_us;
+       u16 ref_clk_gating_wait_us;
+       u32 ip_ver;
+       bool legacy_ip_ver;
+
+       bool mcq_set_intr;
+       bool is_mcq_intr_enabled;
+       int mcq_nr_intr;
+       struct ufs_mtk_mcq_intr_info mcq_intr_info[UFSHCD_MAX_Q_NR];
+};
+
+/* MTK delay of autosuspend: 500 ms */
+#define MTK_RPM_AUTOSUSPEND_DELAY_MS 500
+
+/* MTK RTT support number */
+#define MTK_MAX_NUM_RTT 2
+
+/* UFSHCI MTK ip version value */
+enum {
+       /* UFSHCI 3.1 */
+       IP_VER_MT6983    = 0x10360000,
+       IP_VER_MT6878    = 0x10420200,
+
+       /* UFSHCI 4.0 */
+       IP_VER_MT6897    = 0x10440000,
+       IP_VER_MT6989    = 0x10450000,
+       IP_VER_MT6899    = 0x10450100,
+       IP_VER_MT6991_A0 = 0x10460000,
+       IP_VER_MT6991_B0 = 0x10470000,
+       IP_VER_MT6993    = 0x10480000,
+
+       IP_VER_NONE      = 0xFFFFFFFF
+};
+
+enum ip_ver_legacy {
+       IP_LEGACY_VER_MT6781 = 0x10380000,
+       IP_LEGACY_VER_MT6879 = 0x10360000,
+       IP_LEGACY_VER_MT6893 = 0x20160706
+};
+
+#endif /* !_UFS_MEDIATEK_H */