Hi Martin,
This series provides some fixes on MediaTek UFS platforms, please consider this patch series for kernel v5.20.
- Provide workaround for power mode change for HS-G5
- Fix and provide regulator features
Changes compared to v4:
- Add one patch to disable unused VCCQx
- Fix the invoking location of ufs_mtk_vreg_fix_vccqx()
Changes compared to v3:
- Rewrite and simplify SMC call wrappers
- Fix coding styles
Changes compared to v2:
- Add patches to support multiple VCC sources
Changes compared to v1:
- Add patches to fix and provide VCCQx low-power support
CC Chou (1):
scsi: ufs-mediatek: Introduce workaround for power mode change
Peter Wang (1):
scsi: ufs-mediatek: Support low-power mode for VCCQ
Po-Wen Kao (2):
scsi: ufs-mediatek: Fix the timing of configuring device regulators
scsi: ufs-mediatek: Prevent device regulators setting as LPM
incorrectly
Stanley Chu (7):
scsi: ufs: Export ufshcd_uic_change_pwr_mode()
scsi: ufs: Fix ADAPT logic for HS-G5
scsi: ufs-mediatek: Support flexible parameters for smc calls
scsi: ufs-mediatek: Support low-power mode for parents of VCCQx
scsi: ufs: Export regulator functions
scsi: ufs-mediatek: Support multiple VCC sources
scsi: ufs-mediatek: Disable unused VCCQx power rails
drivers/ufs/core/ufshcd.c | 8 +-
drivers/ufs/host/ufs-mediatek.c | 255 +++++++++++++++++++++++++++----
drivers/ufs/host/ufs-mediatek.h | 58 +++++++
drivers/ufs/host/ufshcd-pltfrm.c | 5 +-
drivers/ufs/host/ufshcd-pltfrm.h | 2 +
include/ufs/ufshcd.h | 3 +
include/ufs/unipro.h | 1 +
7 files changed, 295 insertions(+), 37 deletions(-)
--
2.18.0
Provide flexible number of parameters for UFS SMC calls to be
easily used for future SMC usages.
This is a preparation patch for the next patch.
Signed-off-by: Alice Chao <[email protected]>
Signed-off-by: Stanley Chu <[email protected]>
---
drivers/ufs/host/ufs-mediatek.c | 16 --------------
drivers/ufs/host/ufs-mediatek.h | 39 +++++++++++++++++++++++++++++++++
2 files changed, 39 insertions(+), 16 deletions(-)
diff --git a/drivers/ufs/host/ufs-mediatek.c b/drivers/ufs/host/ufs-mediatek.c
index 65a2a4185ef6..9c5d1213c290 100755
--- a/drivers/ufs/host/ufs-mediatek.c
+++ b/drivers/ufs/host/ufs-mediatek.c
@@ -30,22 +30,6 @@
#define CREATE_TRACE_POINTS
#include "ufs-mediatek-trace.h"
-#define ufs_mtk_smc(cmd, val, res) \
- arm_smccc_smc(MTK_SIP_UFS_CONTROL, \
- cmd, val, 0, 0, 0, 0, 0, &(res))
-
-#define ufs_mtk_va09_pwr_ctrl(res, on) \
- ufs_mtk_smc(UFS_MTK_SIP_VA09_PWR_CTRL, on, res)
-
-#define ufs_mtk_crypto_ctrl(res, enable) \
- ufs_mtk_smc(UFS_MTK_SIP_CRYPTO_CTRL, enable, res)
-
-#define ufs_mtk_ref_clk_notify(on, res) \
- ufs_mtk_smc(UFS_MTK_SIP_REF_CLK_NOTIFICATION, on, res)
-
-#define ufs_mtk_device_reset_ctrl(high, res) \
- ufs_mtk_smc(UFS_MTK_SIP_DEVICE_RESET, high, res)
-
static const struct ufs_dev_quirk ufs_mtk_dev_fixups[] = {
{ .wmanufacturerid = UFS_VENDOR_MICRON,
.model = UFS_ANY_MODEL,
diff --git a/drivers/ufs/host/ufs-mediatek.h b/drivers/ufs/host/ufs-mediatek.h
index 7e1913769671..bf6ca96cafb6 100755
--- a/drivers/ufs/host/ufs-mediatek.h
+++ b/drivers/ufs/host/ufs-mediatek.h
@@ -143,4 +143,43 @@ struct ufs_mtk_host {
u32 ip_ver;
};
+/*
+ * 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 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__})
+
+/*
+ * SMC call interface
+ */
+#define ufs_mtk_va09_pwr_ctrl(res, on) \
+ ufs_mtk_smc(UFS_MTK_SIP_VA09_PWR_CTRL, &(res), on)
+
+#define ufs_mtk_crypto_ctrl(res, enable) \
+ ufs_mtk_smc(UFS_MTK_SIP_CRYPTO_CTRL, &(res), enable)
+
+#define ufs_mtk_ref_clk_notify(on, res) \
+ ufs_mtk_smc(UFS_MTK_SIP_REF_CLK_NOTIFICATION, &(res), on)
+
+#define ufs_mtk_device_reset_ctrl(high, res) \
+ ufs_mtk_smc(UFS_MTK_SIP_DEVICE_RESET, &(res), high)
+
#endif /* !_UFS_MEDIATEK_H */
--
2.18.0
Some MediaTek UFS platforms support different VCCQx power rails,
for example, both 1.2v and 1.8v VCCQx, in a single kernel image.
To optimize the system power consumption, provide a way to disable
and release the unused power rail during the device probing.
Signed-off-by: Stanley Chu <[email protected]>
---
drivers/ufs/host/ufs-mediatek.c | 24 ++++++++++++++++++++++++
1 file changed, 24 insertions(+)
diff --git a/drivers/ufs/host/ufs-mediatek.c b/drivers/ufs/host/ufs-mediatek.c
index 34e51c094366..bfe04a4d1dce 100755
--- a/drivers/ufs/host/ufs-mediatek.c
+++ b/drivers/ufs/host/ufs-mediatek.c
@@ -712,6 +712,29 @@ static int ufs_mtk_vreg_fix_vcc(struct ufs_hba *hba)
return err;
}
+static void ufs_mtk_vreg_fix_vccqx(struct ufs_hba *hba)
+{
+ struct ufs_vreg_info *info = &hba->vreg_info;
+ struct ufs_vreg **vreg_on, **vreg_off;
+
+ if (hba->dev_info.wspecversion >= 0x0300) {
+ vreg_on = &info->vccq;
+ vreg_off = &info->vccq2;
+ } else {
+ vreg_on = &info->vccq2;
+ vreg_off = &info->vccq;
+ }
+
+ if (*vreg_on)
+ (*vreg_on)->always_on = true;
+
+ if (*vreg_off) {
+ regulator_disable((*vreg_off)->reg);
+ devm_kfree(hba->dev, (*vreg_off)->name);
+ devm_kfree(hba->dev, *vreg_off);
+ }
+}
+
/**
* ufs_mtk_init - find other essential mmio bases
* @hba: host controller instance
@@ -1241,6 +1264,7 @@ static void ufs_mtk_fixup_dev_quirks(struct ufs_hba *hba)
}
ufs_mtk_vreg_fix_vcc(hba);
+ ufs_mtk_vreg_fix_vccqx(hba);
}
static void ufs_mtk_event_notify(struct ufs_hba *hba,
--
2.18.0
From: CC Chou <[email protected]>
Some MediaTek SoC chips need special flow for power mode change,
especially for chips supporting HS-G5.
Enable the workaround by setting the host-specific capability.
Reviewed-by: Stanley Chu <[email protected]>
Signed-off-by: CC Chou <[email protected]>
Signed-off-by: Eddie Huang <[email protected]>
Signed-off-by: Dennis Yu <[email protected]>
Signed-off-by: Peter Wang <[email protected]>
Signed-off-by: Stanley Chu <[email protected]>
---
drivers/ufs/host/ufs-mediatek.c | 60 +++++++++++++++++++++++++++++++--
drivers/ufs/host/ufs-mediatek.h | 1 +
include/ufs/unipro.h | 1 +
3 files changed, 60 insertions(+), 2 deletions(-)
diff --git a/drivers/ufs/host/ufs-mediatek.c b/drivers/ufs/host/ufs-mediatek.c
index beabc3ccd30b..2931fd21e38a 100755
--- a/drivers/ufs/host/ufs-mediatek.c
+++ b/drivers/ufs/host/ufs-mediatek.c
@@ -82,6 +82,13 @@ static bool ufs_mtk_is_broken_vcc(struct ufs_hba *hba)
return !!(host->caps & UFS_MTK_CAP_BROKEN_VCC);
}
+static bool ufs_mtk_is_pmc_via_fastauto(struct ufs_hba *hba)
+{
+ struct ufs_mtk_host *host = ufshcd_get_variant(hba);
+
+ return (host->caps & UFS_MTK_CAP_PMC_VIA_FASTAUTO);
+}
+
static void ufs_mtk_cfg_unipro_cg(struct ufs_hba *hba, bool enable)
{
u32 tmp;
@@ -579,6 +586,9 @@ static void ufs_mtk_init_host_caps(struct ufs_hba *hba)
if (of_property_read_bool(np, "mediatek,ufs-broken-vcc"))
host->caps |= UFS_MTK_CAP_BROKEN_VCC;
+ if (of_property_read_bool(np, "mediatek,ufs-pmc-via-fastauto"))
+ host->caps |= UFS_MTK_CAP_PMC_VIA_FASTAUTO;
+
dev_info(hba->dev, "caps: 0x%x", host->caps);
}
@@ -754,6 +764,26 @@ static int ufs_mtk_init(struct ufs_hba *hba)
return err;
}
+static bool ufs_mtk_pmc_via_fastauto(struct ufs_hba *hba,
+ struct ufs_pa_layer_attr *dev_req_params)
+{
+ if (!ufs_mtk_is_pmc_via_fastauto(hba))
+ return false;
+
+ if (dev_req_params->hs_rate == hba->pwr_info.hs_rate)
+ return false;
+
+ if (dev_req_params->pwr_tx != FAST_MODE &&
+ dev_req_params->gear_tx < UFS_HS_G4)
+ return false;
+
+ if (dev_req_params->pwr_rx != FAST_MODE &&
+ dev_req_params->gear_rx < UFS_HS_G4)
+ return false;
+
+ return true;
+}
+
static int ufs_mtk_pre_pwr_change(struct ufs_hba *hba,
struct ufs_pa_layer_attr *dev_max_params,
struct ufs_pa_layer_attr *dev_req_params)
@@ -763,8 +793,8 @@ static int ufs_mtk_pre_pwr_change(struct ufs_hba *hba,
int ret;
ufshcd_init_pwr_dev_param(&host_cap);
- host_cap.hs_rx_gear = UFS_HS_G4;
- host_cap.hs_tx_gear = UFS_HS_G4;
+ host_cap.hs_rx_gear = UFS_HS_G5;
+ host_cap.hs_tx_gear = UFS_HS_G5;
ret = ufshcd_get_pwr_dev_param(&host_cap,
dev_max_params,
@@ -774,6 +804,32 @@ static int ufs_mtk_pre_pwr_change(struct ufs_hba *hba,
__func__);
}
+ if (ufs_mtk_pmc_via_fastauto(hba, dev_req_params)) {
+ ufshcd_dme_set(hba, UIC_ARG_MIB(PA_TXTERMINATION), true);
+ ufshcd_dme_set(hba, UIC_ARG_MIB(PA_TXGEAR), UFS_HS_G1);
+
+ ufshcd_dme_set(hba, UIC_ARG_MIB(PA_RXTERMINATION), true);
+ ufshcd_dme_set(hba, UIC_ARG_MIB(PA_RXGEAR), UFS_HS_G1);
+
+ ufshcd_dme_set(hba, UIC_ARG_MIB(PA_ACTIVETXDATALANES),
+ dev_req_params->lane_tx);
+ ufshcd_dme_set(hba, UIC_ARG_MIB(PA_ACTIVERXDATALANES),
+ dev_req_params->lane_rx);
+ ufshcd_dme_set(hba, UIC_ARG_MIB(PA_HSSERIES),
+ dev_req_params->hs_rate);
+
+ ufshcd_dme_set(hba, UIC_ARG_MIB(PA_TXHSADAPTTYPE),
+ PA_NO_ADAPT);
+
+ ret = ufshcd_uic_change_pwr_mode(hba,
+ FASTAUTO_MODE << 4 | FASTAUTO_MODE);
+
+ if (ret) {
+ dev_err(hba->dev, "%s: HSG1B FASTAUTO failed ret=%d\n",
+ __func__, ret);
+ }
+ }
+
if (host->hw_ver.major >= 3) {
ret = ufshcd_dme_configure_adapt(hba,
dev_req_params->gear_tx,
diff --git a/drivers/ufs/host/ufs-mediatek.h b/drivers/ufs/host/ufs-mediatek.h
index 414dca86c09f..7e1913769671 100755
--- a/drivers/ufs/host/ufs-mediatek.h
+++ b/drivers/ufs/host/ufs-mediatek.h
@@ -108,6 +108,7 @@ enum ufs_mtk_host_caps {
UFS_MTK_CAP_VA09_PWR_CTRL = 1 << 1,
UFS_MTK_CAP_DISABLE_AH8 = 1 << 2,
UFS_MTK_CAP_BROKEN_VCC = 1 << 3,
+ UFS_MTK_CAP_PMC_VIA_FASTAUTO = 1 << 6,
};
struct ufs_mtk_crypt_cfg {
diff --git a/include/ufs/unipro.h b/include/ufs/unipro.h
index 0521f887e3ac..4b13fbf8ee18 100755
--- a/include/ufs/unipro.h
+++ b/include/ufs/unipro.h
@@ -229,6 +229,7 @@ enum ufs_hs_gear_tag {
UFS_HS_G2, /* HS Gear 2 */
UFS_HS_G3, /* HS Gear 3 */
UFS_HS_G4, /* HS Gear 4 */
+ UFS_HS_G5 /* HS Gear 5 */
};
enum ufs_unipro_ver {
--
2.18.0
Support multiple VCC source in MediaTek UFS platforms.
Two options are provided and distinguished by specific
device tree attributes as below examples,
[Option 1: By numbering]
mediatek,ufs-vcc-by-num;
vcc-opt1-supply = <&mt6373_vbuck4_ufs>;
vcc-opt2-supply = <&mt6363_vemc>;
[Option 2: By UFS version]
mediatek,ufs-vcc-by-ver;
vcc-ufs3-supply = <&mt6373_vbuck4_ufs>;
Signed-off-by: Alice Chao <[email protected]>
Signed-off-by: Peter Wang <[email protected]>
Signed-off-by: Stanley Chu <[email protected]>
---
drivers/ufs/host/ufs-mediatek.c | 46 ++++++++++++++++++++++++++++++++-
drivers/ufs/host/ufs-mediatek.h | 14 ++++++++++
2 files changed, 59 insertions(+), 1 deletion(-)
diff --git a/drivers/ufs/host/ufs-mediatek.c b/drivers/ufs/host/ufs-mediatek.c
index e756aba45acd..34e51c094366 100755
--- a/drivers/ufs/host/ufs-mediatek.c
+++ b/drivers/ufs/host/ufs-mediatek.c
@@ -669,6 +669,49 @@ static u32 ufs_mtk_get_ufs_hci_version(struct ufs_hba *hba)
return hba->ufs_version;
}
+#define MAX_VCC_NAME 30
+static int ufs_mtk_vreg_fix_vcc(struct ufs_hba *hba)
+{
+ struct ufs_vreg_info *info = &hba->vreg_info;
+ struct device_node *np = hba->dev->of_node;
+ struct device *dev = hba->dev;
+ char vcc_name[MAX_VCC_NAME];
+ struct arm_smccc_res res;
+ int err, ver;
+
+ if (hba->vreg_info.vcc)
+ return 0;
+
+ if (of_property_read_bool(np, "mediatek,ufs-vcc-by-num")) {
+ ufs_mtk_get_vcc_num(res);
+ if (res.a1 > UFS_VCC_NONE && res.a1 < UFS_VCC_MAX)
+ snprintf(vcc_name, MAX_VCC_NAME, "vcc-opt%u", res.a1);
+ else
+ return -ENODEV;
+ } else if (of_property_read_bool(np, "mediatek,ufs-vcc-by-ver")) {
+ ver = (hba->dev_info.wspecversion & 0xF00) >> 8;
+ snprintf(vcc_name, MAX_VCC_NAME, "vcc-ufs%u", ver);
+ } else {
+ return 0;
+ }
+
+ err = ufshcd_populate_vreg(dev, vcc_name, &info->vcc);
+ if (err)
+ return err;
+
+ err = ufshcd_get_vreg(dev, info->vcc);
+ if (err)
+ return err;
+
+ err = regulator_enable(info->vcc->reg);
+ if (!err) {
+ info->vcc->enabled = true;
+ dev_info(dev, "%s: %s enabled\n", __func__, vcc_name);
+ }
+
+ return err;
+}
+
/**
* ufs_mtk_init - find other essential mmio bases
* @hba: host controller instance
@@ -1179,7 +1222,6 @@ static int ufs_mtk_apply_dev_quirks(struct ufs_hba *hba)
else
ufs_mtk_setup_ref_clk_wait_us(hba,
REFCLK_DEFAULT_WAIT_US);
-
return 0;
}
@@ -1197,6 +1239,8 @@ static void ufs_mtk_fixup_dev_quirks(struct ufs_hba *hba)
hba->dev_quirks &= ~(UFS_DEVICE_QUIRK_DELAY_BEFORE_LPM |
UFS_DEVICE_QUIRK_DELAY_AFTER_LPM);
}
+
+ ufs_mtk_vreg_fix_vcc(hba);
}
static void ufs_mtk_event_notify(struct ufs_hba *hba,
diff --git a/drivers/ufs/host/ufs-mediatek.h b/drivers/ufs/host/ufs-mediatek.h
index 5c6101ac518f..49a2137fb251 100755
--- a/drivers/ufs/host/ufs-mediatek.h
+++ b/drivers/ufs/host/ufs-mediatek.h
@@ -83,6 +83,7 @@ enum {
#define UFS_MTK_SIP_DEVICE_RESET BIT(1)
#define UFS_MTK_SIP_CRYPTO_CTRL BIT(2)
#define UFS_MTK_SIP_REF_CLK_NOTIFICATION BIT(3)
+#define UFS_MTK_SIP_GET_VCC_NUM BIT(6)
#define UFS_MTK_SIP_DEVICE_PWR_CTRL BIT(7)
/*
@@ -144,6 +145,16 @@ struct ufs_mtk_host {
u32 ip_ver;
};
+/*
+ * Multi-VCC by Numbering
+ */
+enum ufs_mtk_vcc_num {
+ UFS_VCC_NONE = 0,
+ UFS_VCC_1,
+ UFS_VCC_2,
+ UFS_VCC_MAX
+};
+
/*
* SMC call wrapper function
*/
@@ -183,6 +194,9 @@ static void _ufs_mtk_smc(struct ufs_mtk_smc_arg s)
#define ufs_mtk_device_reset_ctrl(high, res) \
ufs_mtk_smc(UFS_MTK_SIP_DEVICE_RESET, &(res), high)
+#define ufs_mtk_get_vcc_num(res) \
+ ufs_mtk_smc(UFS_MTK_SIP_GET_VCC_NUM, &(res))
+
#define ufs_mtk_device_pwr_ctrl(on, ufs_ver, res) \
ufs_mtk_smc(UFS_MTK_SIP_DEVICE_PWR_CTRL, &(res), on, ufs_ver)
--
2.18.0
From: Po-Wen Kao <[email protected]>
Currently the LPM configurations of device regulators
may not work since VCC is not disabled yet while
ufs_mtk_vreg_set_lpm() is executed.
Fix it by changing the timing of invoking
ufs_mtk_vreg_set_lpm().
Reviewed-by: Stanley Chu <[email protected]>
Signed-off-by: Po-Wen Kao <[email protected]>
Signed-off-by: Stanley Chu <[email protected]>
Change-Id: Ibbdb3a9a3557bb9e7e667da2c5a37e1e9f81450f
---
drivers/ufs/host/ufs-mediatek.c | 58 ++++++++++++++++++++++++++++++---
1 file changed, 53 insertions(+), 5 deletions(-)
diff --git a/drivers/ufs/host/ufs-mediatek.c b/drivers/ufs/host/ufs-mediatek.c
index 2931fd21e38a..817d957512a3 100755
--- a/drivers/ufs/host/ufs-mediatek.c
+++ b/drivers/ufs/host/ufs-mediatek.c
@@ -1082,7 +1082,6 @@ static int ufs_mtk_suspend(struct ufs_hba *hba, enum ufs_pm_op pm_op,
* ufshcd_suspend() re-enabling regulators while vreg is still
* in low-power mode.
*/
- ufs_mtk_vreg_set_lpm(hba, true);
err = ufs_mtk_mphy_power_on(hba, false);
if (err)
goto fail;
@@ -1106,12 +1105,13 @@ static int ufs_mtk_resume(struct ufs_hba *hba, enum ufs_pm_op pm_op)
{
int err;
+ if (hba->ufshcd_state != UFSHCD_STATE_OPERATIONAL)
+ ufs_mtk_vreg_set_lpm(hba, false);
+
err = ufs_mtk_mphy_power_on(hba, true);
if (err)
goto fail;
- ufs_mtk_vreg_set_lpm(hba, false);
-
if (ufshcd_is_link_hibern8(hba)) {
err = ufs_mtk_link_set_hpm(hba);
if (err)
@@ -1276,9 +1276,57 @@ static int ufs_mtk_remove(struct platform_device *pdev)
return 0;
}
+int ufs_mtk_system_suspend(struct device *dev)
+{
+ struct ufs_hba *hba = dev_get_drvdata(dev);
+ int ret;
+
+ ret = ufshcd_system_suspend(dev);
+ if (ret)
+ return ret;
+
+ ufs_mtk_vreg_set_lpm(hba, true);
+
+ return 0;
+}
+
+int ufs_mtk_system_resume(struct device *dev)
+{
+ struct ufs_hba *hba = dev_get_drvdata(dev);
+
+ ufs_mtk_vreg_set_lpm(hba, false);
+
+ return ufshcd_system_resume(dev);
+}
+
+int ufs_mtk_runtime_suspend(struct device *dev)
+{
+ struct ufs_hba *hba = dev_get_drvdata(dev);
+ int ret = 0;
+
+ ret = ufshcd_runtime_suspend(dev);
+ if (ret)
+ return ret;
+
+ ufs_mtk_vreg_set_lpm(hba, true);
+
+ return 0;
+}
+
+int ufs_mtk_runtime_resume(struct device *dev)
+{
+ struct ufs_hba *hba = dev_get_drvdata(dev);
+
+ ufs_mtk_vreg_set_lpm(hba, false);
+
+ return ufshcd_runtime_resume(dev);
+}
+
static const struct dev_pm_ops ufs_mtk_pm_ops = {
- SET_SYSTEM_SLEEP_PM_OPS(ufshcd_system_suspend, ufshcd_system_resume)
- SET_RUNTIME_PM_OPS(ufshcd_runtime_suspend, ufshcd_runtime_resume, NULL)
+ SET_SYSTEM_SLEEP_PM_OPS(ufs_mtk_system_suspend,
+ ufs_mtk_system_resume)
+ SET_RUNTIME_PM_OPS(ufs_mtk_runtime_suspend,
+ ufs_mtk_runtime_resume, NULL)
.prepare = ufshcd_suspend_prepare,
.complete = ufshcd_resume_complete,
};
--
2.18.0
Export below regulator functions to allow vendors to
customize regulator configuration in their own platforms.
int ufshcd_populate_vreg(struct device *dev, const char *name,
struct ufs_vreg **out_vreg);
int ufshcd_get_vreg(struct device *dev, struct ufs_vreg *vreg);
Signed-off-by: Stanley Chu <[email protected]>
---
drivers/ufs/core/ufshcd.c | 3 ++-
drivers/ufs/host/ufshcd-pltfrm.c | 5 +++--
drivers/ufs/host/ufshcd-pltfrm.h | 2 ++
include/ufs/ufshcd.h | 2 ++
4 files changed, 9 insertions(+), 3 deletions(-)
diff --git a/drivers/ufs/core/ufshcd.c b/drivers/ufs/core/ufshcd.c
index 0d16739c67bb..8131a75e41e5 100755
--- a/drivers/ufs/core/ufshcd.c
+++ b/drivers/ufs/core/ufshcd.c
@@ -8408,7 +8408,7 @@ static int ufshcd_setup_hba_vreg(struct ufs_hba *hba, bool on)
return ufshcd_toggle_vreg(hba->dev, info->vdd_hba, on);
}
-static int ufshcd_get_vreg(struct device *dev, struct ufs_vreg *vreg)
+int ufshcd_get_vreg(struct device *dev, struct ufs_vreg *vreg)
{
int ret = 0;
@@ -8424,6 +8424,7 @@ static int ufshcd_get_vreg(struct device *dev, struct ufs_vreg *vreg)
out:
return ret;
}
+EXPORT_SYMBOL_GPL(ufshcd_get_vreg);
static int ufshcd_init_vreg(struct ufs_hba *hba)
{
diff --git a/drivers/ufs/host/ufshcd-pltfrm.c b/drivers/ufs/host/ufshcd-pltfrm.c
index e7332cc65b1f..2dd9c660531b 100755
--- a/drivers/ufs/host/ufshcd-pltfrm.c
+++ b/drivers/ufs/host/ufshcd-pltfrm.c
@@ -109,8 +109,8 @@ static int ufshcd_parse_clock_info(struct ufs_hba *hba)
}
#define MAX_PROP_SIZE 32
-static int ufshcd_populate_vreg(struct device *dev, const char *name,
- struct ufs_vreg **out_vreg)
+int ufshcd_populate_vreg(struct device *dev, const char *name,
+ struct ufs_vreg **out_vreg)
{
char prop_name[MAX_PROP_SIZE];
struct ufs_vreg *vreg = NULL;
@@ -145,6 +145,7 @@ static int ufshcd_populate_vreg(struct device *dev, const char *name,
*out_vreg = vreg;
return 0;
}
+EXPORT_SYMBOL_GPL(ufshcd_populate_vreg);
/**
* ufshcd_parse_regulator_info - get regulator info from device tree
diff --git a/drivers/ufs/host/ufshcd-pltfrm.h b/drivers/ufs/host/ufshcd-pltfrm.h
index 43c2e412bd99..5130c9471dc2 100755
--- a/drivers/ufs/host/ufshcd-pltfrm.h
+++ b/drivers/ufs/host/ufshcd-pltfrm.h
@@ -32,5 +32,7 @@ void ufshcd_init_pwr_dev_param(struct ufs_dev_params *dev_param);
int ufshcd_pltfrm_init(struct platform_device *pdev,
const struct ufs_hba_variant_ops *vops);
void ufshcd_pltfrm_shutdown(struct platform_device *pdev);
+int ufshcd_populate_vreg(struct device *dev, const char *name,
+ struct ufs_vreg **out_vreg);
#endif /* UFSHCD_PLTFRM_H_ */
diff --git a/include/ufs/ufshcd.h b/include/ufs/ufshcd.h
index aa778418703f..18eb253cfd91 100755
--- a/include/ufs/ufshcd.h
+++ b/include/ufs/ufshcd.h
@@ -1187,6 +1187,8 @@ void ufshcd_map_desc_id_to_length(struct ufs_hba *hba, enum desc_idn desc_id,
u32 ufshcd_get_local_unipro_ver(struct ufs_hba *hba);
+int ufshcd_get_vreg(struct device *dev, struct ufs_vreg *vreg);
+
int ufshcd_send_uic_cmd(struct ufs_hba *hba, struct uic_command *uic_cmd);
int ufshcd_exec_raw_upiu_cmd(struct ufs_hba *hba,
--
2.18.0
Provide the facility to configure parents of VCCQx power rails
as low-power or full-power mode in MediaTek UFS platforms.
Signed-off-by: Alice Chao <[email protected]>
Signed-off-by: Stanley Chu <[email protected]>
---
drivers/ufs/host/ufs-mediatek.c | 46 +++++++++++++++++++++++----------
drivers/ufs/host/ufs-mediatek.h | 4 +++
2 files changed, 37 insertions(+), 13 deletions(-)
diff --git a/drivers/ufs/host/ufs-mediatek.c b/drivers/ufs/host/ufs-mediatek.c
index 9c5d1213c290..e756aba45acd 100755
--- a/drivers/ufs/host/ufs-mediatek.c
+++ b/drivers/ufs/host/ufs-mediatek.c
@@ -1013,10 +1013,30 @@ static int ufs_mtk_link_set_lpm(struct ufs_hba *hba)
return 0;
}
-static void ufs_mtk_vreg_set_lpm(struct ufs_hba *hba, bool lpm)
+static void ufs_mtk_vccqx_set_lpm(struct ufs_hba *hba, bool lpm)
{
struct ufs_vreg *vccqx = NULL;
+ if (hba->vreg_info.vccq)
+ vccqx = hba->vreg_info.vccq;
+ else
+ vccqx = hba->vreg_info.vccq2;
+
+ regulator_set_mode(vccqx->reg,
+ lpm ? REGULATOR_MODE_IDLE : REGULATOR_MODE_NORMAL);
+}
+
+static void ufs_mtk_vsx_set_lpm(struct ufs_hba *hba, bool lpm)
+{
+ struct arm_smccc_res res;
+
+ ufs_mtk_device_pwr_ctrl(!lpm,
+ (unsigned long)hba->dev_info.wspecversion,
+ res);
+}
+
+static void ufs_mtk_dev_vreg_set_lpm(struct ufs_hba *hba, bool lpm)
+{
if (!hba->vreg_info.vccq && !hba->vreg_info.vccq2)
return;
@@ -1032,13 +1052,13 @@ static void ufs_mtk_vreg_set_lpm(struct ufs_hba *hba, bool lpm)
if (lpm && hba->vreg_info.vcc->enabled)
return;
- if (hba->vreg_info.vccq)
- vccqx = hba->vreg_info.vccq;
- else
- vccqx = hba->vreg_info.vccq2;
-
- regulator_set_mode(vccqx->reg,
- lpm ? REGULATOR_MODE_IDLE : REGULATOR_MODE_NORMAL);
+ if (lpm) {
+ ufs_mtk_vccqx_set_lpm(hba, lpm);
+ ufs_mtk_vsx_set_lpm(hba, lpm);
+ } else {
+ ufs_mtk_vsx_set_lpm(hba, lpm);
+ ufs_mtk_vccqx_set_lpm(hba, lpm);
+ }
}
static void ufs_mtk_auto_hibern8_disable(struct ufs_hba *hba)
@@ -1105,7 +1125,7 @@ static int ufs_mtk_resume(struct ufs_hba *hba, enum ufs_pm_op pm_op)
int err;
if (hba->ufshcd_state != UFSHCD_STATE_OPERATIONAL)
- ufs_mtk_vreg_set_lpm(hba, false);
+ ufs_mtk_dev_vreg_set_lpm(hba, false);
err = ufs_mtk_mphy_power_on(hba, true);
if (err)
@@ -1284,7 +1304,7 @@ int ufs_mtk_system_suspend(struct device *dev)
if (ret)
return ret;
- ufs_mtk_vreg_set_lpm(hba, true);
+ ufs_mtk_dev_vreg_set_lpm(hba, true);
return 0;
}
@@ -1293,7 +1313,7 @@ int ufs_mtk_system_resume(struct device *dev)
{
struct ufs_hba *hba = dev_get_drvdata(dev);
- ufs_mtk_vreg_set_lpm(hba, false);
+ ufs_mtk_dev_vreg_set_lpm(hba, false);
return ufshcd_system_resume(dev);
}
@@ -1307,7 +1327,7 @@ int ufs_mtk_runtime_suspend(struct device *dev)
if (ret)
return ret;
- ufs_mtk_vreg_set_lpm(hba, true);
+ ufs_mtk_dev_vreg_set_lpm(hba, true);
return 0;
}
@@ -1316,7 +1336,7 @@ int ufs_mtk_runtime_resume(struct device *dev)
{
struct ufs_hba *hba = dev_get_drvdata(dev);
- ufs_mtk_vreg_set_lpm(hba, false);
+ ufs_mtk_dev_vreg_set_lpm(hba, false);
return ufshcd_runtime_resume(dev);
}
diff --git a/drivers/ufs/host/ufs-mediatek.h b/drivers/ufs/host/ufs-mediatek.h
index bf6ca96cafb6..5c6101ac518f 100755
--- a/drivers/ufs/host/ufs-mediatek.h
+++ b/drivers/ufs/host/ufs-mediatek.h
@@ -83,6 +83,7 @@ enum {
#define UFS_MTK_SIP_DEVICE_RESET BIT(1)
#define UFS_MTK_SIP_CRYPTO_CTRL BIT(2)
#define UFS_MTK_SIP_REF_CLK_NOTIFICATION BIT(3)
+#define UFS_MTK_SIP_DEVICE_PWR_CTRL BIT(7)
/*
* VS_DEBUGCLOCKENABLE
@@ -182,4 +183,7 @@ static void _ufs_mtk_smc(struct ufs_mtk_smc_arg s)
#define ufs_mtk_device_reset_ctrl(high, res) \
ufs_mtk_smc(UFS_MTK_SIP_DEVICE_RESET, &(res), high)
+#define ufs_mtk_device_pwr_ctrl(on, ufs_ver, res) \
+ ufs_mtk_smc(UFS_MTK_SIP_DEVICE_PWR_CTRL, &(res), on, ufs_ver)
+
#endif /* !_UFS_MEDIATEK_H */
--
2.18.0
Export ufshcd_uic_change_pwr_mode() to allow vendors to
use it for SoC-specific power mode change design limitation.
Reviewed-by: Bart Van Assche <[email protected]>
Signed-off-by: Stanley Chu <[email protected]>
---
drivers/ufs/core/ufshcd.c | 3 ++-
include/ufs/ufshcd.h | 1 +
2 files changed, 3 insertions(+), 1 deletion(-)
diff --git a/drivers/ufs/core/ufshcd.c b/drivers/ufs/core/ufshcd.c
index 936a6d5467c9..19e17c898319 100755
--- a/drivers/ufs/core/ufshcd.c
+++ b/drivers/ufs/core/ufshcd.c
@@ -4091,7 +4091,7 @@ static int ufshcd_uic_pwr_ctrl(struct ufs_hba *hba, struct uic_command *cmd)
*
* Returns 0 on success, non-zero value on failure
*/
-static int ufshcd_uic_change_pwr_mode(struct ufs_hba *hba, u8 mode)
+int ufshcd_uic_change_pwr_mode(struct ufs_hba *hba, u8 mode)
{
struct uic_command uic_cmd = {0};
int ret;
@@ -4116,6 +4116,7 @@ static int ufshcd_uic_change_pwr_mode(struct ufs_hba *hba, u8 mode)
out:
return ret;
}
+EXPORT_SYMBOL_GPL(ufshcd_uic_change_pwr_mode);
int ufshcd_link_recovery(struct ufs_hba *hba)
{
diff --git a/include/ufs/ufshcd.h b/include/ufs/ufshcd.h
index a92271421718..aa778418703f 100755
--- a/include/ufs/ufshcd.h
+++ b/include/ufs/ufshcd.h
@@ -1087,6 +1087,7 @@ extern int ufshcd_dme_get_attr(struct ufs_hba *hba, u32 attr_sel,
u32 *mib_val, u8 peer);
extern int ufshcd_config_pwr_mode(struct ufs_hba *hba,
struct ufs_pa_layer_attr *desired_pwr_mode);
+extern int ufshcd_uic_change_pwr_mode(struct ufs_hba *hba, u8 mode);
/* UIC command interfaces for DME primitives */
#define DME_LOCAL 0
--
2.18.0
From: Po-Wen Kao <[email protected]>
Device regulatrs are allowed to enter low-power mode
if neither device is not in active mode, nor VCC does not
keep on.
Simply fix this by adding conditions before LPM decision.
Reviewed-by: Stanley Chu <[email protected]>
Signed-off-by: Po-Wen Kao <[email protected]>
Signed-off-by: Stanley Chu <[email protected]>
---
drivers/ufs/host/ufs-mediatek.c | 12 ++++++++++--
1 file changed, 10 insertions(+), 2 deletions(-)
diff --git a/drivers/ufs/host/ufs-mediatek.c b/drivers/ufs/host/ufs-mediatek.c
index 817d957512a3..03762ecaaaf8 100755
--- a/drivers/ufs/host/ufs-mediatek.c
+++ b/drivers/ufs/host/ufs-mediatek.c
@@ -1034,10 +1034,18 @@ static void ufs_mtk_vreg_set_lpm(struct ufs_hba *hba, bool lpm)
if (!hba->vreg_info.vccq2 || !hba->vreg_info.vcc)
return;
- if (lpm && !hba->vreg_info.vcc->enabled)
+ /* Bypass LPM when device is still active */
+ if (lpm && ufshcd_is_ufs_dev_active(hba))
+ return;
+
+ /* Bypass LPM if VCC is enabled */
+ if (lpm && hba->vreg_info.vcc->enabled)
+ return;
+
+ if (lpm)
regulator_set_mode(hba->vreg_info.vccq2->reg,
REGULATOR_MODE_IDLE);
- else if (!lpm)
+ else
regulator_set_mode(hba->vreg_info.vccq2->reg,
REGULATOR_MODE_NORMAL);
}
--
2.18.0
Stanley,
> This series provides some fixes on MediaTek UFS platforms, please
> consider this patch series for kernel v5.20.
Applied to 5.20/scsi-staging, thanks!
--
Martin K. Petersen Oracle Linux Engineering
On 2022-06-16 13:37, Stanley Chu wrote:
> Support multiple VCC source in MediaTek UFS platforms.
>
> Two options are provided and distinguished by specific
> device tree attributes as below examples,
>
> [Option 1: By numbering]
> mediatek,ufs-vcc-by-num;
> vcc-opt1-supply = <&mt6373_vbuck4_ufs>;
> vcc-opt2-supply = <&mt6363_vemc>;
>
> [Option 2: By UFS version]
> mediatek,ufs-vcc-by-ver;
> vcc-ufs3-supply = <&mt6373_vbuck4_ufs>;
>
> Signed-off-by: Alice Chao <[email protected]>
> Signed-off-by: Peter Wang <[email protected]>
> Signed-off-by: Stanley Chu <[email protected]>
> ---
> drivers/ufs/host/ufs-mediatek.c | 46 ++++++++++++++++++++++++++++++++-
> drivers/ufs/host/ufs-mediatek.h | 14 ++++++++++
> 2 files changed, 59 insertions(+), 1 deletion(-)
>
> diff --git a/drivers/ufs/host/ufs-mediatek.c b/drivers/ufs/host/ufs-mediatek.c
> index e756aba45acd..34e51c094366 100755
> --- a/drivers/ufs/host/ufs-mediatek.c
> +++ b/drivers/ufs/host/ufs-mediatek.c
> @@ -669,6 +669,49 @@ static u32 ufs_mtk_get_ufs_hci_version(struct ufs_hba *hba)
> return hba->ufs_version;
> }
>
> +#define MAX_VCC_NAME 30
> +static int ufs_mtk_vreg_fix_vcc(struct ufs_hba *hba)
> +{
> + struct ufs_vreg_info *info = &hba->vreg_info;
> + struct device_node *np = hba->dev->of_node;
> + struct device *dev = hba->dev;
> + char vcc_name[MAX_VCC_NAME];
> + struct arm_smccc_res res;
> + int err, ver;
> +
> + if (hba->vreg_info.vcc)
> + return 0;
> +
> + if (of_property_read_bool(np, "mediatek,ufs-vcc-by-num")) {
> + ufs_mtk_get_vcc_num(res);
> + if (res.a1 > UFS_VCC_NONE && res.a1 < UFS_VCC_MAX)
> + snprintf(vcc_name, MAX_VCC_NAME, "vcc-opt%u", res.a1);
Building this showes the following build warning/error
drivers/ufs/host/ufs-mediatek.c: In function 'ufs_mtk_vreg_fix_vcc':
drivers/ufs/host/ufs-mediatek.c:688:67: error: format '%u' expects argument of type 'unsigned int', but argument 4 has type 'long unsigned int' [-Werror=format=]
688 | snprintf(vcc_name, MAX_VCC_NAME, "vcc-opt%u", res.a1);
| ~^ ~~~~~~
| | |
| | long unsigned int
| unsigned int
| %lu
cc1: all warnings being treated as errors
Cheers,
Anders
On Thu, 16 Jun 2022 13:37:14 +0800, Stanley Chu wrote:
> This series provides some fixes on MediaTek UFS platforms, please consider this patch series for kernel v5.20.
>
> - Provide workaround for power mode change for HS-G5
> - Fix and provide regulator features
>
> Changes compared to v4:
> - Add one patch to disable unused VCCQx
> - Fix the invoking location of ufs_mtk_vreg_fix_vccqx()
>
> [...]
Applied to 5.20/scsi-queue, thanks!
[01/11] scsi: ufs: Export ufshcd_uic_change_pwr_mode()
https://git.kernel.org/mkp/scsi/c/fc53683b45b0
[02/11] scsi: ufs: Fix ADAPT logic for HS-G5
https://git.kernel.org/mkp/scsi/c/d81c4c6f7170
[03/11] scsi: ufs-mediatek: Introduce workaround for power mode change
https://git.kernel.org/mkp/scsi/c/3f9b6cec12e2
[04/11] scsi: ufs-mediatek: Fix the timing of configuring device regulators
https://git.kernel.org/mkp/scsi/c/3fd23b8dfb54
[05/11] scsi: ufs-mediatek: Prevent device regulators setting as LPM incorrectly
https://git.kernel.org/mkp/scsi/c/005ffdf09cd3
[06/11] scsi: ufs-mediatek: Support low-power mode for VCCQ
https://git.kernel.org/mkp/scsi/c/0836cc252a52
[07/11] scsi: ufs-mediatek: Support flexible parameters for smc calls
https://git.kernel.org/mkp/scsi/c/bc602ae977f3
[08/11] scsi: ufs-mediatek: Support low-power mode for parents of VCCQx
https://git.kernel.org/mkp/scsi/c/42b1928360a3
[09/11] scsi: ufs: Export regulator functions
https://git.kernel.org/mkp/scsi/c/1d6f9decb60a
[10/11] scsi: ufs-mediatek: Support multiple VCC sources
https://git.kernel.org/mkp/scsi/c/ece418d02911
[11/11] scsi: ufs-mediatek: Disable unused VCCQx power rails
https://git.kernel.org/mkp/scsi/c/cb142b6d2f60
--
Martin K. Petersen Oracle Linux Engineering