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:
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user