1
0

Merge patch series "Enhance UFS Mediatek Driver"

Peter Wang <peter.wang@mediatek.com says>:

Improves the UFS Mediatek driver by correcting clock scaling with PM
QoS, and adjusting power management flows. It addresses
shutdown/suspend race conditions, and removes redundant
functions. Support for new platforms is added with the MMIO_OTSD_CTRL
register, and MT6991 performance is optimized with MRTT and random
improvements. These changes collectively enhance driver performance,
stability, and compatibility.

Changes since v1:

 1. Remove two patches that will be fixed in UFS core.
    - ufs: host: mediatek: Fix runtime suspend error deadlock
    - ufs: host: mediatek: Enable interrupts for MCQ mode
 2. Use hba->shutting_down instead of ufshcd_is_user_access_allowed

v1:
   https://patch.msgid.link/20250918104000.208856-1-peter.wang@mediatek.com

Link: https://patch.msgid.link/20250924094527.2992256-1-peter.wang@mediatek.com
Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
This commit is contained in:
Martin K. Petersen
2025-10-21 21:37:57 -04:00
6 changed files with 115 additions and 23 deletions

View File

@@ -235,7 +235,7 @@ static int ufshcd_ahit_to_us(u32 ahit)
}
/* Convert microseconds to Auto-Hibernate Idle Timer register value */
static u32 ufshcd_us_to_ahit(unsigned int timer)
u32 ufshcd_us_to_ahit(unsigned int timer)
{
unsigned int scale;
@@ -245,6 +245,7 @@ static u32 ufshcd_us_to_ahit(unsigned int timer)
return FIELD_PREP(UFSHCI_AHIBERN8_TIMER_MASK, timer) |
FIELD_PREP(UFSHCI_AHIBERN8_SCALE_MASK, scale);
}
EXPORT_SYMBOL_GPL(ufshcd_us_to_ahit);
static int ufshcd_read_hci_reg(struct ufs_hba *hba, u32 *val, unsigned int reg)
{

View File

@@ -1076,7 +1076,7 @@ void ufshcd_pm_qos_exit(struct ufs_hba *hba)
* @hba: per adapter instance
* @on: If True, vote for perf PM QoS mode otherwise power save mode
*/
static void ufshcd_pm_qos_update(struct ufs_hba *hba, bool on)
void ufshcd_pm_qos_update(struct ufs_hba *hba, bool on)
{
guard(mutex)(&hba->pm_qos_mutex);
@@ -1085,6 +1085,7 @@ static void ufshcd_pm_qos_update(struct ufs_hba *hba, bool on)
cpu_latency_qos_update_request(&hba->pm_qos_req, on ? 0 : PM_QOS_DEFAULT_VALUE);
}
EXPORT_SYMBOL_GPL(ufshcd_pm_qos_update);
/**
* ufshcd_set_clk_freq - set UFS controller clock frequencies

View File

@@ -279,12 +279,21 @@ static int ufs_mtk_hce_enable_notify(struct ufs_hba *hba,
ufshcd_readl(hba, REG_UFS_XOUFS_CTRL) | 0x80,
REG_UFS_XOUFS_CTRL);
if (host->legacy_ip_ver)
return 0;
/* DDR_EN setting */
if (host->ip_ver >= IP_VER_MT6989) {
ufshcd_rmwl(hba, UFS_MASK(0x7FFF, 8),
0x453000, REG_UFS_MMIO_OPT_CTRL_0);
}
if (host->ip_ver >= IP_VER_MT6991_A0) {
/* Enable multi-rtt */
ufshcd_rmwl(hba, MRTT_EN, MRTT_EN, REG_UFS_MMIO_OPT_CTRL_0);
/* Enable random performance improvement */
ufshcd_rmwl(hba, RDN_PFM_IMPV_DIS, 0, REG_UFS_MMIO_OPT_CTRL_0);
}
}
return 0;
@@ -404,7 +413,7 @@ static void ufs_mtk_dbg_sel(struct ufs_hba *hba)
{
struct ufs_mtk_host *host = ufshcd_get_variant(hba);
if (((host->ip_ver >> 16) & 0xFF) >= 0x36) {
if (!host->legacy_ip_ver && host->ip_ver >= IP_VER_MT6983) {
ufshcd_writel(hba, 0x820820, REG_UFS_DEBUG_SEL);
ufshcd_writel(hba, 0x0, REG_UFS_DEBUG_SEL_B0);
ufshcd_writel(hba, 0x55555555, REG_UFS_DEBUG_SEL_B1);
@@ -421,6 +430,7 @@ static int ufs_mtk_wait_idle_state(struct ufs_hba *hba,
u64 timeout, time_checked;
u32 val, sm;
bool wait_idle;
struct ufs_mtk_host *host = ufshcd_get_variant(hba);
/* cannot use plain ktime_get() in suspend */
timeout = ktime_get_mono_fast_ns() + retry_ms * 1000000UL;
@@ -431,8 +441,13 @@ static int ufs_mtk_wait_idle_state(struct ufs_hba *hba,
do {
time_checked = ktime_get_mono_fast_ns();
ufs_mtk_dbg_sel(hba);
val = ufshcd_readl(hba, REG_UFS_PROBE);
if (host->legacy_ip_ver || host->ip_ver < IP_VER_MT6899) {
ufs_mtk_dbg_sel(hba);
val = ufshcd_readl(hba, REG_UFS_PROBE);
} else {
val = ufshcd_readl(hba, REG_UFS_UFS_MMIO_OTSD_CTRL);
val = val >> 16;
}
sm = val & 0x1f;
@@ -464,13 +479,20 @@ static int ufs_mtk_wait_link_state(struct ufs_hba *hba, u32 state,
{
ktime_t timeout, time_checked;
u32 val;
struct ufs_mtk_host *host = ufshcd_get_variant(hba);
timeout = ktime_add_ms(ktime_get(), max_wait_ms);
do {
time_checked = ktime_get();
ufs_mtk_dbg_sel(hba);
val = ufshcd_readl(hba, REG_UFS_PROBE);
val = val >> 28;
if (host->legacy_ip_ver || host->ip_ver < IP_VER_MT6899) {
ufs_mtk_dbg_sel(hba);
val = ufshcd_readl(hba, REG_UFS_PROBE);
val = val >> 28;
} else {
val = ufshcd_readl(hba, REG_UFS_UFS_MMIO_OTSD_CTRL);
val = val >> 24;
}
if (val == state)
return 0;
@@ -1108,18 +1130,6 @@ static void ufs_mtk_setup_clk_gating(struct ufs_hba *hba)
}
}
/* Convert microseconds to Auto-Hibernate Idle Timer register value */
static u32 ufs_mtk_us_to_ahit(unsigned int timer)
{
unsigned int scale;
for (scale = 0; timer > UFSHCI_AHIBERN8_TIMER_MASK; ++scale)
timer /= UFSHCI_AHIBERN8_SCALE_FACTOR;
return FIELD_PREP(UFSHCI_AHIBERN8_TIMER_MASK, timer) |
FIELD_PREP(UFSHCI_AHIBERN8_SCALE_MASK, scale);
}
static void ufs_mtk_fix_ahit(struct ufs_hba *hba)
{
unsigned int us;
@@ -1142,7 +1152,7 @@ static void ufs_mtk_fix_ahit(struct ufs_hba *hba)
break;
}
hba->ahit = ufs_mtk_us_to_ahit(us);
hba->ahit = ufshcd_us_to_ahit(us);
}
ufs_mtk_setup_clk_gating(hba);
@@ -1331,6 +1341,36 @@ static bool ufs_mtk_pmc_via_fastauto(struct ufs_hba *hba,
return true;
}
static void ufs_mtk_adjust_sync_length(struct ufs_hba *hba)
{
int i;
u32 value;
u32 cnt, att, min;
struct attr_min {
u32 attr;
u32 min_value;
} pa_min_sync_length[] = {
{PA_TXHSG1SYNCLENGTH, 0x48},
{PA_TXHSG2SYNCLENGTH, 0x48},
{PA_TXHSG3SYNCLENGTH, 0x48},
{PA_TXHSG4SYNCLENGTH, 0x48},
{PA_TXHSG5SYNCLENGTH, 0x48}
};
cnt = sizeof(pa_min_sync_length) / sizeof(struct attr_min);
for (i = 0; i < cnt; i++) {
att = pa_min_sync_length[i].attr;
min = pa_min_sync_length[i].min_value;
ufshcd_dme_get(hba, UIC_ARG_MIB(att), &value);
if (value < min)
ufshcd_dme_set(hba, UIC_ARG_MIB(att), min);
ufshcd_dme_peer_get(hba, UIC_ARG_MIB(att), &value);
if (value < min)
ufshcd_dme_peer_set(hba, UIC_ARG_MIB(att), min);
}
}
static int ufs_mtk_pre_pwr_change(struct ufs_hba *hba,
const struct ufs_pa_layer_attr *dev_max_params,
struct ufs_pa_layer_attr *dev_req_params)
@@ -1354,6 +1394,8 @@ static int ufs_mtk_pre_pwr_change(struct ufs_hba *hba,
}
if (ufs_mtk_pmc_via_fastauto(hba, dev_req_params)) {
ufs_mtk_adjust_sync_length(hba);
ufshcd_dme_set(hba, UIC_ARG_MIB(PA_TXTERMINATION), true);
ufshcd_dme_set(hba, UIC_ARG_MIB(PA_TXGEAR), UFS_HS_G1);
@@ -1618,14 +1660,26 @@ static int ufs_mtk_device_reset(struct ufs_hba *hba)
static int ufs_mtk_link_set_hpm(struct ufs_hba *hba)
{
int err;
u32 val;
struct ufs_mtk_host *host = ufshcd_get_variant(hba);
err = ufshcd_hba_enable(hba);
if (err)
return err;
err = ufs_mtk_unipro_set_lpm(hba, false);
if (err)
if (err) {
if (host->ip_ver < IP_VER_MT6899) {
ufs_mtk_dbg_sel(hba);
val = ufshcd_readl(hba, REG_UFS_PROBE);
} else {
val = ufshcd_readl(hba, REG_UFS_UFS_MMIO_OTSD_CTRL);
}
ufshcd_update_evt_hist(hba, UFS_EVT_RESUME_ERR, (u32)val);
val = ufshcd_readl(hba, REG_INTERRUPT_STATUS);
ufshcd_update_evt_hist(hba, UFS_EVT_RESUME_ERR, (u32)val);
return err;
}
err = ufshcd_uic_hibern8_exit(hba);
if (err)
@@ -1743,6 +1797,7 @@ static int ufs_mtk_suspend(struct ufs_hba *hba, enum ufs_pm_op pm_op,
{
int err;
struct arm_smccc_res res;
struct ufs_mtk_host *host = ufshcd_get_variant(hba);
if (status == PRE_CHANGE) {
if (ufshcd_is_auto_hibern8_supported(hba))
@@ -1772,6 +1827,15 @@ static int ufs_mtk_suspend(struct ufs_hba *hba, enum ufs_pm_op pm_op,
ufs_mtk_sram_pwr_ctrl(false, res);
/* Release pm_qos/clk if in scale-up mode during suspend */
if (ufshcd_is_clkscaling_supported(hba) && (host->clk_scale_up)) {
ufshcd_pm_qos_update(hba, false);
_ufs_mtk_clk_scale(hba, false);
} else if ((!ufshcd_is_clkscaling_supported(hba) &&
hba->pwr_info.gear_rx >= UFS_HS_G5)) {
_ufs_mtk_clk_scale(hba, false);
}
return 0;
fail:
/*
@@ -1787,6 +1851,7 @@ static int ufs_mtk_resume(struct ufs_hba *hba, enum ufs_pm_op pm_op)
{
int err;
struct arm_smccc_res res;
struct ufs_mtk_host *host = ufshcd_get_variant(hba);
if (hba->ufshcd_state != UFSHCD_STATE_OPERATIONAL)
ufs_mtk_dev_vreg_set_lpm(hba, false);
@@ -1797,6 +1862,15 @@ static int ufs_mtk_resume(struct ufs_hba *hba, enum ufs_pm_op pm_op)
if (err)
goto fail;
/* Request pm_qos/clk if in scale-up mode after resume */
if (ufshcd_is_clkscaling_supported(hba) && (host->clk_scale_up)) {
ufshcd_pm_qos_update(hba, true);
_ufs_mtk_clk_scale(hba, true);
} else if ((!ufshcd_is_clkscaling_supported(hba) &&
hba->pwr_info.gear_rx >= UFS_HS_G5)) {
_ufs_mtk_clk_scale(hba, true);
}
if (ufshcd_is_link_hibern8(hba)) {
err = ufs_mtk_link_set_hpm(hba);
if (err)
@@ -2370,6 +2444,11 @@ static int ufs_mtk_system_suspend(struct device *dev)
struct arm_smccc_res res;
int ret;
if (hba->shutting_down) {
ret = -EBUSY;
goto out;
}
ret = ufshcd_system_suspend(dev);
if (ret)
goto out;

View File

@@ -20,6 +20,9 @@
#define MCQ_MULTI_INTR_EN BIT(2)
#define MCQ_CMB_INTR_EN BIT(3)
#define MCQ_AH8 BIT(4)
#define MON_EN BIT(5)
#define MRTT_EN BIT(25)
#define RDN_PFM_IMPV_DIS BIT(28)
#define MCQ_INTR_EN_MSK (MCQ_MULTI_INTR_EN | MCQ_CMB_INTR_EN)
@@ -28,6 +31,7 @@
*/
#define REG_UFS_XOUFS_CTRL 0x140
#define REG_UFS_REFCLK_CTRL 0x144
#define REG_UFS_UFS_MMIO_OTSD_CTRL 0x14C
#define REG_UFS_MMIO_OPT_CTRL_0 0x160
#define REG_UFS_EXTREG 0x2100
#define REG_UFS_MPHYCTRL 0x2200

View File

@@ -1489,5 +1489,7 @@ int ufshcd_write_ee_control(struct ufs_hba *hba);
int ufshcd_update_ee_control(struct ufs_hba *hba, u16 *mask,
const u16 *other_mask, u16 set, u16 clr);
void ufshcd_force_error_recovery(struct ufs_hba *hba);
void ufshcd_pm_qos_update(struct ufs_hba *hba, bool on);
u32 ufshcd_us_to_ahit(unsigned int timer);
#endif /* End of Header */

View File

@@ -111,6 +111,9 @@
#define PA_TXLINKSTARTUPHS 0x1544
#define PA_AVAILRXDATALANES 0x1540
#define PA_MINRXTRAILINGCLOCKS 0x1543
#define PA_TXHSG1SYNCLENGTH 0x1552
#define PA_TXHSG2SYNCLENGTH 0x1554
#define PA_TXHSG3SYNCLENGTH 0x1556
#define PA_LOCAL_TX_LCC_ENABLE 0x155E
#define PA_ACTIVETXDATALANES 0x1560
#define PA_CONNECTEDTXDATALANES 0x1561
@@ -160,7 +163,9 @@
#define PA_PACPFRAMECOUNT 0x15C0
#define PA_PACPERRORCOUNT 0x15C1
#define PA_PHYTESTCONTROL 0x15C2
#define PA_TXHSADAPTTYPE 0x15D4
#define PA_TXHSG4SYNCLENGTH 0x15D0
#define PA_TXHSADAPTTYPE 0x15D4
#define PA_TXHSG5SYNCLENGTH 0x15D6
/* Adpat type for PA_TXHSADAPTTYPE attribute */
#define PA_REFRESH_ADAPT 0x00