mirror of
https://github.com/torvalds/linux.git
synced 2026-05-27 16:44:58 +02:00
Merge patch series "ufs: host: mediatek: Provide features and fixes in MediaTek platforms"
peter.wang@mediatek.com says: This series fixes some defects and provide features in MediaTek UFS drivers. Link: https://lore.kernel.org/r/20250811131423.3444014-1-peter.wang@mediatek.com Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
This commit is contained in:
commit
da81027950
|
|
@ -29,6 +29,7 @@
|
|||
#include "ufs-mediatek-sip.h"
|
||||
|
||||
static int ufs_mtk_config_mcq(struct ufs_hba *hba, bool irq);
|
||||
static void _ufs_mtk_clk_scale(struct ufs_hba *hba, bool scale_up);
|
||||
|
||||
#define CREATE_TRACE_POINTS
|
||||
#include "ufs-mediatek-trace.h"
|
||||
|
|
@ -798,8 +799,14 @@ static int ufs_mtk_setup_clocks(struct ufs_hba *hba, bool on,
|
|||
clk_pwr_off = true;
|
||||
}
|
||||
|
||||
if (clk_pwr_off)
|
||||
if (clk_pwr_off) {
|
||||
ufs_mtk_pwr_ctrl(hba, false);
|
||||
} else {
|
||||
dev_warn(hba->dev, "Clock is not turned off, hba->ahit = 0x%x, AHIT = 0x%x\n",
|
||||
hba->ahit,
|
||||
ufshcd_readl(hba,
|
||||
REG_AUTO_HIBERNATE_IDLE_TIMER));
|
||||
}
|
||||
ufs_mtk_mcq_disable_irq(hba);
|
||||
} else if (on && status == POST_CHANGE) {
|
||||
ufs_mtk_pwr_ctrl(hba, true);
|
||||
|
|
@ -1018,7 +1025,7 @@ static int ufs_mtk_vreg_fix_vcc(struct ufs_hba *hba)
|
|||
struct arm_smccc_res res;
|
||||
int err, ver;
|
||||
|
||||
if (hba->vreg_info.vcc)
|
||||
if (info->vcc)
|
||||
return 0;
|
||||
|
||||
if (of_property_read_bool(np, "mediatek,ufs-vcc-by-num")) {
|
||||
|
|
@ -1075,6 +1082,80 @@ static void ufs_mtk_vreg_fix_vccqx(struct ufs_hba *hba)
|
|||
}
|
||||
}
|
||||
|
||||
static void ufs_mtk_setup_clk_gating(struct ufs_hba *hba)
|
||||
{
|
||||
unsigned long flags;
|
||||
u32 ah_ms = 10;
|
||||
u32 ah_scale, ah_timer;
|
||||
u32 scale_us[] = {1, 10, 100, 1000, 10000, 100000};
|
||||
|
||||
if (ufshcd_is_clkgating_allowed(hba)) {
|
||||
if (ufshcd_is_auto_hibern8_supported(hba) && hba->ahit) {
|
||||
ah_scale = FIELD_GET(UFSHCI_AHIBERN8_SCALE_MASK,
|
||||
hba->ahit);
|
||||
ah_timer = FIELD_GET(UFSHCI_AHIBERN8_TIMER_MASK,
|
||||
hba->ahit);
|
||||
if (ah_scale <= 5)
|
||||
ah_ms = ah_timer * scale_us[ah_scale] / 1000;
|
||||
}
|
||||
|
||||
spin_lock_irqsave(hba->host->host_lock, flags);
|
||||
hba->clk_gating.delay_ms = max(ah_ms, 10U);
|
||||
spin_unlock_irqrestore(hba->host->host_lock, flags);
|
||||
}
|
||||
}
|
||||
|
||||
/* 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;
|
||||
|
||||
if (ufshcd_is_auto_hibern8_supported(hba)) {
|
||||
switch (hba->dev_info.wmanufacturerid) {
|
||||
case UFS_VENDOR_SAMSUNG:
|
||||
/* configure auto-hibern8 timer to 3.5 ms */
|
||||
us = 3500;
|
||||
break;
|
||||
|
||||
case UFS_VENDOR_MICRON:
|
||||
/* configure auto-hibern8 timer to 2 ms */
|
||||
us = 2000;
|
||||
break;
|
||||
|
||||
default:
|
||||
/* configure auto-hibern8 timer to 1 ms */
|
||||
us = 1000;
|
||||
break;
|
||||
}
|
||||
|
||||
hba->ahit = ufs_mtk_us_to_ahit(us);
|
||||
}
|
||||
|
||||
ufs_mtk_setup_clk_gating(hba);
|
||||
}
|
||||
|
||||
static void ufs_mtk_fix_clock_scaling(struct ufs_hba *hba)
|
||||
{
|
||||
/* UFS version is below 4.0, clock scaling is not necessary */
|
||||
if ((hba->dev_info.wspecversion < 0x0400) &&
|
||||
ufs_mtk_is_clk_scale_ready(hba)) {
|
||||
hba->caps &= ~UFSHCD_CAP_CLK_SCALING;
|
||||
|
||||
_ufs_mtk_clk_scale(hba, false);
|
||||
}
|
||||
}
|
||||
|
||||
static void ufs_mtk_init_mcq_irq(struct ufs_hba *hba)
|
||||
{
|
||||
struct ufs_mtk_host *host = ufshcd_get_variant(hba);
|
||||
|
|
@ -1240,6 +1321,10 @@ static bool ufs_mtk_pmc_via_fastauto(struct ufs_hba *hba,
|
|||
dev_req_params->gear_rx < UFS_HS_G4)
|
||||
return false;
|
||||
|
||||
if (dev_req_params->pwr_tx == SLOW_MODE ||
|
||||
dev_req_params->pwr_rx == SLOW_MODE)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
@ -1255,6 +1340,10 @@ static int ufs_mtk_pre_pwr_change(struct ufs_hba *hba,
|
|||
host_params.hs_rx_gear = UFS_HS_G5;
|
||||
host_params.hs_tx_gear = UFS_HS_G5;
|
||||
|
||||
if (dev_max_params->pwr_rx == SLOW_MODE ||
|
||||
dev_max_params->pwr_tx == SLOW_MODE)
|
||||
host_params.desired_working_mode = UFS_PWM_MODE;
|
||||
|
||||
ret = ufshcd_negotiate_pwr_params(&host_params, dev_max_params, dev_req_params);
|
||||
if (ret) {
|
||||
pr_info("%s: failed to determine capabilities\n",
|
||||
|
|
@ -1278,6 +1367,28 @@ static int ufs_mtk_pre_pwr_change(struct ufs_hba *hba,
|
|||
ufshcd_dme_set(hba, UIC_ARG_MIB(PA_TXHSADAPTTYPE),
|
||||
PA_NO_ADAPT);
|
||||
|
||||
if (!(hba->quirks & UFSHCD_QUIRK_SKIP_DEF_UNIPRO_TIMEOUT_SETTING)) {
|
||||
ufshcd_dme_set(hba, UIC_ARG_MIB(PA_PWRMODEUSERDATA0),
|
||||
DL_FC0ProtectionTimeOutVal_Default);
|
||||
ufshcd_dme_set(hba, UIC_ARG_MIB(PA_PWRMODEUSERDATA1),
|
||||
DL_TC0ReplayTimeOutVal_Default);
|
||||
ufshcd_dme_set(hba, UIC_ARG_MIB(PA_PWRMODEUSERDATA2),
|
||||
DL_AFC0ReqTimeOutVal_Default);
|
||||
ufshcd_dme_set(hba, UIC_ARG_MIB(PA_PWRMODEUSERDATA3),
|
||||
DL_FC1ProtectionTimeOutVal_Default);
|
||||
ufshcd_dme_set(hba, UIC_ARG_MIB(PA_PWRMODEUSERDATA4),
|
||||
DL_TC1ReplayTimeOutVal_Default);
|
||||
ufshcd_dme_set(hba, UIC_ARG_MIB(PA_PWRMODEUSERDATA5),
|
||||
DL_AFC1ReqTimeOutVal_Default);
|
||||
|
||||
ufshcd_dme_set(hba, UIC_ARG_MIB(DME_LocalFC0ProtectionTimeOutVal),
|
||||
DL_FC0ProtectionTimeOutVal_Default);
|
||||
ufshcd_dme_set(hba, UIC_ARG_MIB(DME_LocalTC0ReplayTimeOutVal),
|
||||
DL_TC0ReplayTimeOutVal_Default);
|
||||
ufshcd_dme_set(hba, UIC_ARG_MIB(DME_LocalAFC0ReqTimeOutVal),
|
||||
DL_AFC0ReqTimeOutVal_Default);
|
||||
}
|
||||
|
||||
ret = ufshcd_uic_change_pwr_mode(hba,
|
||||
FASTAUTO_MODE << 4 | FASTAUTO_MODE);
|
||||
|
||||
|
|
@ -1287,10 +1398,32 @@ static int ufs_mtk_pre_pwr_change(struct ufs_hba *hba,
|
|||
}
|
||||
}
|
||||
|
||||
if (host->hw_ver.major >= 3) {
|
||||
/* if already configured to the requested pwr_mode, skip adapt */
|
||||
if (dev_req_params->gear_rx == hba->pwr_info.gear_rx &&
|
||||
dev_req_params->gear_tx == hba->pwr_info.gear_tx &&
|
||||
dev_req_params->lane_rx == hba->pwr_info.lane_rx &&
|
||||
dev_req_params->lane_tx == hba->pwr_info.lane_tx &&
|
||||
dev_req_params->pwr_rx == hba->pwr_info.pwr_rx &&
|
||||
dev_req_params->pwr_tx == hba->pwr_info.pwr_tx &&
|
||||
dev_req_params->hs_rate == hba->pwr_info.hs_rate) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (dev_req_params->pwr_rx == FAST_MODE ||
|
||||
dev_req_params->pwr_rx == FASTAUTO_MODE) {
|
||||
if (host->hw_ver.major >= 3) {
|
||||
ret = ufshcd_dme_configure_adapt(hba,
|
||||
dev_req_params->gear_tx,
|
||||
PA_INITIAL_ADAPT);
|
||||
} else {
|
||||
ret = ufshcd_dme_configure_adapt(hba,
|
||||
dev_req_params->gear_tx,
|
||||
PA_NO_ADAPT);
|
||||
}
|
||||
} else {
|
||||
ret = ufshcd_dme_configure_adapt(hba,
|
||||
dev_req_params->gear_tx,
|
||||
PA_INITIAL_ADAPT);
|
||||
dev_req_params->gear_tx,
|
||||
PA_NO_ADAPT);
|
||||
}
|
||||
|
||||
return ret;
|
||||
|
|
@ -1342,6 +1475,7 @@ static int ufs_mtk_pre_link(struct ufs_hba *hba)
|
|||
{
|
||||
int ret;
|
||||
u32 tmp;
|
||||
struct ufs_mtk_host *host = ufshcd_get_variant(hba);
|
||||
|
||||
ufs_mtk_get_controller_version(hba);
|
||||
|
||||
|
|
@ -1367,34 +1501,22 @@ static int ufs_mtk_pre_link(struct ufs_hba *hba)
|
|||
|
||||
ret = ufshcd_dme_set(hba, UIC_ARG_MIB(VS_SAVEPOWERCONTROL), tmp);
|
||||
|
||||
/* Enable the 1144 functions setting */
|
||||
if (host->ip_ver == IP_VER_MT6989) {
|
||||
ret = ufshcd_dme_get(hba, UIC_ARG_MIB(VS_DEBUGOMC), &tmp);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
tmp |= 0x10;
|
||||
ret = ufshcd_dme_set(hba, UIC_ARG_MIB(VS_DEBUGOMC), tmp);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void ufs_mtk_setup_clk_gating(struct ufs_hba *hba)
|
||||
{
|
||||
u32 ah_ms;
|
||||
|
||||
if (ufshcd_is_clkgating_allowed(hba)) {
|
||||
if (ufshcd_is_auto_hibern8_supported(hba) && hba->ahit)
|
||||
ah_ms = FIELD_GET(UFSHCI_AHIBERN8_TIMER_MASK,
|
||||
hba->ahit);
|
||||
else
|
||||
ah_ms = 10;
|
||||
ufshcd_clkgate_delay_set(hba->dev, ah_ms + 5);
|
||||
}
|
||||
}
|
||||
|
||||
static void ufs_mtk_post_link(struct ufs_hba *hba)
|
||||
{
|
||||
/* enable unipro clock gating feature */
|
||||
ufs_mtk_cfg_unipro_cg(hba, true);
|
||||
|
||||
/* will be configured during probe hba */
|
||||
if (ufshcd_is_auto_hibern8_supported(hba))
|
||||
hba->ahit = FIELD_PREP(UFSHCI_AHIBERN8_TIMER_MASK, 10) |
|
||||
FIELD_PREP(UFSHCI_AHIBERN8_SCALE_MASK, 3);
|
||||
|
||||
ufs_mtk_setup_clk_gating(hba);
|
||||
}
|
||||
|
||||
static int ufs_mtk_link_startup_notify(struct ufs_hba *hba,
|
||||
|
|
@ -1421,11 +1543,11 @@ static int ufs_mtk_device_reset(struct ufs_hba *hba)
|
|||
{
|
||||
struct arm_smccc_res res;
|
||||
|
||||
/* disable hba before device reset */
|
||||
ufshcd_hba_stop(hba);
|
||||
|
||||
ufs_mtk_device_reset_ctrl(0, res);
|
||||
|
||||
/* disable hba in middle of device reset */
|
||||
ufshcd_hba_stop(hba);
|
||||
|
||||
/*
|
||||
* The reset signal is active low. UFS devices shall detect
|
||||
* more than or equal to 1us of positive or negative RST_n
|
||||
|
|
@ -1507,6 +1629,9 @@ static void ufs_mtk_vccqx_set_lpm(struct ufs_hba *hba, bool lpm)
|
|||
{
|
||||
struct ufs_vreg *vccqx = NULL;
|
||||
|
||||
if (!hba->vreg_info.vccq && !hba->vreg_info.vccq2)
|
||||
return;
|
||||
|
||||
if (hba->vreg_info.vccq)
|
||||
vccqx = hba->vreg_info.vccq;
|
||||
else
|
||||
|
|
@ -1726,6 +1851,8 @@ static void ufs_mtk_fixup_dev_quirks(struct ufs_hba *hba)
|
|||
|
||||
ufs_mtk_vreg_fix_vcc(hba);
|
||||
ufs_mtk_vreg_fix_vccqx(hba);
|
||||
ufs_mtk_fix_ahit(hba);
|
||||
ufs_mtk_fix_clock_scaling(hba);
|
||||
}
|
||||
|
||||
static void ufs_mtk_event_notify(struct ufs_hba *hba,
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user