From fa3dca8251c4fff88da9f64ba931942638ab0c00 Mon Sep 17 00:00:00 2001 From: Can Guo Date: Sat, 2 Dec 2023 04:36:07 -0800 Subject: scsi: ufs: host: Rename structure ufs_dev_params to ufs_host_params Structure ufs_dev_params is actually used in UFS host drivers to declare host specific power mode parameters, like ufs__params or host_cap, which makes the code not very straightforward to read. Rename the structure ufs_dev_params to ufs_host_params and unify the declarations in all drivers to host_params. In addition, rename the two functions ufshcd_init_pwr_dev_param() and ufshcd_get_pwr_dev_param() which work based on the ufs_host_params to ufshcd_init_host_params() and ufshcd_negotiate_pwr_params() respectively to avoid confusions. This change does not change any functionalities or logic. Acked-by: Andrew Halaney Reviewed-by: Nitin Rawat Reviewed-by: Manivannan Sadhasivam Reviewed-by: Bart Van Assche Signed-off-by: Can Guo Link: https://lore.kernel.org/r/1701520577-31163-2-git-send-email-quic_cang@quicinc.com Reviewed-by: Peter Wang Tested-by: Neil Armstrong # on SM8550-QRD Signed-off-by: Martin K. Petersen --- drivers/ufs/host/ufs-exynos.c | 7 ++-- drivers/ufs/host/ufs-hisi.c | 11 +++---- drivers/ufs/host/ufs-mediatek.c | 12 +++---- drivers/ufs/host/ufs-qcom.c | 12 +++---- drivers/ufs/host/ufshcd-pltfrm.c | 69 ++++++++++++++++++++-------------------- drivers/ufs/host/ufshcd-pltfrm.h | 10 +++--- 6 files changed, 57 insertions(+), 64 deletions(-) (limited to 'drivers/ufs') diff --git a/drivers/ufs/host/ufs-exynos.c b/drivers/ufs/host/ufs-exynos.c index 71bd6dbc0547..734d40f99e31 100644 --- a/drivers/ufs/host/ufs-exynos.c +++ b/drivers/ufs/host/ufs-exynos.c @@ -765,7 +765,7 @@ static int exynos_ufs_pre_pwr_mode(struct ufs_hba *hba, { struct exynos_ufs *ufs = ufshcd_get_variant(hba); struct phy *generic_phy = ufs->phy; - struct ufs_dev_params ufs_exynos_cap; + struct ufs_host_params host_params; int ret; if (!dev_req_params) { @@ -774,10 +774,9 @@ static int exynos_ufs_pre_pwr_mode(struct ufs_hba *hba, goto out; } - ufshcd_init_pwr_dev_param(&ufs_exynos_cap); + ufshcd_init_host_params(&host_params); - ret = ufshcd_get_pwr_dev_param(&ufs_exynos_cap, - dev_max_params, dev_req_params); + ret = ufshcd_negotiate_pwr_params(&host_params, dev_max_params, dev_req_params); if (ret) { pr_err("%s: failed to determine capabilities\n", __func__); goto out; diff --git a/drivers/ufs/host/ufs-hisi.c b/drivers/ufs/host/ufs-hisi.c index 0229ac0a8dbe..5ee73ff05251 100644 --- a/drivers/ufs/host/ufs-hisi.c +++ b/drivers/ufs/host/ufs-hisi.c @@ -293,9 +293,9 @@ static int ufs_hisi_link_startup_notify(struct ufs_hba *hba, return err; } -static void ufs_hisi_set_dev_cap(struct ufs_dev_params *hisi_param) +static void ufs_hisi_set_dev_cap(struct ufs_host_params *host_params) { - ufshcd_init_pwr_dev_param(hisi_param); + ufshcd_init_host_params(host_params); } static void ufs_hisi_pwr_change_pre_change(struct ufs_hba *hba) @@ -365,7 +365,7 @@ static int ufs_hisi_pwr_change_notify(struct ufs_hba *hba, struct ufs_pa_layer_attr *dev_max_params, struct ufs_pa_layer_attr *dev_req_params) { - struct ufs_dev_params ufs_hisi_cap; + struct ufs_host_params host_params; int ret = 0; if (!dev_req_params) { @@ -377,9 +377,8 @@ static int ufs_hisi_pwr_change_notify(struct ufs_hba *hba, switch (status) { case PRE_CHANGE: - ufs_hisi_set_dev_cap(&ufs_hisi_cap); - ret = ufshcd_get_pwr_dev_param(&ufs_hisi_cap, - dev_max_params, dev_req_params); + ufs_hisi_set_dev_cap(&host_params); + ret = ufshcd_negotiate_pwr_params(&host_params, dev_max_params, dev_req_params); if (ret) { dev_err(hba->dev, "%s: failed to determine capabilities\n", __func__); diff --git a/drivers/ufs/host/ufs-mediatek.c b/drivers/ufs/host/ufs-mediatek.c index fc61790d289b..776bca4f70c8 100644 --- a/drivers/ufs/host/ufs-mediatek.c +++ b/drivers/ufs/host/ufs-mediatek.c @@ -996,16 +996,14 @@ static int ufs_mtk_pre_pwr_change(struct ufs_hba *hba, struct ufs_pa_layer_attr *dev_req_params) { struct ufs_mtk_host *host = ufshcd_get_variant(hba); - struct ufs_dev_params host_cap; + struct ufs_host_params host_params; int ret; - ufshcd_init_pwr_dev_param(&host_cap); - host_cap.hs_rx_gear = UFS_HS_G5; - host_cap.hs_tx_gear = UFS_HS_G5; + ufshcd_init_host_params(&host_params); + host_params.hs_rx_gear = UFS_HS_G5; + host_params.hs_tx_gear = UFS_HS_G5; - ret = ufshcd_get_pwr_dev_param(&host_cap, - dev_max_params, - dev_req_params); + ret = ufshcd_negotiate_pwr_params(&host_params, dev_max_params, dev_req_params); if (ret) { pr_info("%s: failed to determine capabilities\n", __func__); diff --git a/drivers/ufs/host/ufs-qcom.c b/drivers/ufs/host/ufs-qcom.c index 96cb8b5b4e66..197c5a5ab136 100644 --- a/drivers/ufs/host/ufs-qcom.c +++ b/drivers/ufs/host/ufs-qcom.c @@ -898,7 +898,7 @@ static int ufs_qcom_pwr_change_notify(struct ufs_hba *hba, struct ufs_pa_layer_attr *dev_req_params) { struct ufs_qcom_host *host = ufshcd_get_variant(hba); - struct ufs_dev_params ufs_qcom_cap; + struct ufs_host_params host_params; int ret = 0; if (!dev_req_params) { @@ -908,15 +908,13 @@ static int ufs_qcom_pwr_change_notify(struct ufs_hba *hba, switch (status) { case PRE_CHANGE: - ufshcd_init_pwr_dev_param(&ufs_qcom_cap); - ufs_qcom_cap.hs_rate = UFS_QCOM_LIMIT_HS_RATE; + ufshcd_init_host_params(&host_params); + host_params.hs_rate = UFS_QCOM_LIMIT_HS_RATE; /* This driver only supports symmetic gear setting i.e., hs_tx_gear == hs_rx_gear */ - ufs_qcom_cap.hs_tx_gear = ufs_qcom_cap.hs_rx_gear = ufs_qcom_get_hs_gear(hba); + host_params.hs_tx_gear = host_params.hs_rx_gear = ufs_qcom_get_hs_gear(hba); - ret = ufshcd_get_pwr_dev_param(&ufs_qcom_cap, - dev_max_params, - dev_req_params); + ret = ufshcd_negotiate_pwr_params(&host_params, dev_max_params, dev_req_params); if (ret) { dev_err(hba->dev, "%s: failed to determine capabilities\n", __func__); diff --git a/drivers/ufs/host/ufshcd-pltfrm.c b/drivers/ufs/host/ufshcd-pltfrm.c index da2558e274b4..1633edc65689 100644 --- a/drivers/ufs/host/ufshcd-pltfrm.c +++ b/drivers/ufs/host/ufshcd-pltfrm.c @@ -285,61 +285,60 @@ static int ufshcd_parse_operating_points(struct ufs_hba *hba) } /** - * ufshcd_get_pwr_dev_param - get finally agreed attributes for - * power mode change - * @pltfrm_param: pointer to platform parameters + * ufshcd_negotiate_pwr_params - find power mode settings that are supported by + both the controller and the device + * @host_params: pointer to host parameters * @dev_max: pointer to device attributes * @agreed_pwr: returned agreed attributes * * Return: 0 on success, non-zero value on failure. */ -int ufshcd_get_pwr_dev_param(const struct ufs_dev_params *pltfrm_param, - const struct ufs_pa_layer_attr *dev_max, - struct ufs_pa_layer_attr *agreed_pwr) +int ufshcd_negotiate_pwr_params(const struct ufs_host_params *host_params, + const struct ufs_pa_layer_attr *dev_max, + struct ufs_pa_layer_attr *agreed_pwr) { - int min_pltfrm_gear; + int min_host_gear; int min_dev_gear; bool is_dev_sup_hs = false; - bool is_pltfrm_max_hs = false; + bool is_host_max_hs = false; if (dev_max->pwr_rx == FAST_MODE) is_dev_sup_hs = true; - if (pltfrm_param->desired_working_mode == UFS_HS_MODE) { - is_pltfrm_max_hs = true; - min_pltfrm_gear = min_t(u32, pltfrm_param->hs_rx_gear, - pltfrm_param->hs_tx_gear); + if (host_params->desired_working_mode == UFS_HS_MODE) { + is_host_max_hs = true; + min_host_gear = min_t(u32, host_params->hs_rx_gear, + host_params->hs_tx_gear); } else { - min_pltfrm_gear = min_t(u32, pltfrm_param->pwm_rx_gear, - pltfrm_param->pwm_tx_gear); + min_host_gear = min_t(u32, host_params->pwm_rx_gear, + host_params->pwm_tx_gear); } /* - * device doesn't support HS but - * pltfrm_param->desired_working_mode is HS, - * thus device and pltfrm_param don't agree + * device doesn't support HS but host_params->desired_working_mode is HS, + * thus device and host_params don't agree */ - if (!is_dev_sup_hs && is_pltfrm_max_hs) { + if (!is_dev_sup_hs && is_host_max_hs) { pr_info("%s: device doesn't support HS\n", __func__); return -ENOTSUPP; - } else if (is_dev_sup_hs && is_pltfrm_max_hs) { + } else if (is_dev_sup_hs && is_host_max_hs) { /* * since device supports HS, it supports FAST_MODE. - * since pltfrm_param->desired_working_mode is also HS + * since host_params->desired_working_mode is also HS * then final decision (FAST/FASTAUTO) is done according * to pltfrm_params as it is the restricting factor */ - agreed_pwr->pwr_rx = pltfrm_param->rx_pwr_hs; + agreed_pwr->pwr_rx = host_params->rx_pwr_hs; agreed_pwr->pwr_tx = agreed_pwr->pwr_rx; } else { /* - * here pltfrm_param->desired_working_mode is PWM. + * here host_params->desired_working_mode is PWM. * it doesn't matter whether device supports HS or PWM, - * in both cases pltfrm_param->desired_working_mode will + * in both cases host_params->desired_working_mode will * determine the mode */ - agreed_pwr->pwr_rx = pltfrm_param->rx_pwr_pwm; + agreed_pwr->pwr_rx = host_params->rx_pwr_pwm; agreed_pwr->pwr_tx = agreed_pwr->pwr_rx; } @@ -349,9 +348,9 @@ int ufshcd_get_pwr_dev_param(const struct ufs_dev_params *pltfrm_param, * the same decision will be made for rx */ agreed_pwr->lane_tx = min_t(u32, dev_max->lane_tx, - pltfrm_param->tx_lanes); + host_params->tx_lanes); agreed_pwr->lane_rx = min_t(u32, dev_max->lane_rx, - pltfrm_param->rx_lanes); + host_params->rx_lanes); /* device maximum gear is the minimum between device rx and tx gears */ min_dev_gear = min_t(u32, dev_max->gear_rx, dev_max->gear_tx); @@ -364,26 +363,26 @@ int ufshcd_get_pwr_dev_param(const struct ufs_dev_params *pltfrm_param, * what is the gear, as it is the one that also decided previously what * pwr the device will be configured to. */ - if ((is_dev_sup_hs && is_pltfrm_max_hs) || - (!is_dev_sup_hs && !is_pltfrm_max_hs)) { + if ((is_dev_sup_hs && is_host_max_hs) || + (!is_dev_sup_hs && !is_host_max_hs)) { agreed_pwr->gear_rx = - min_t(u32, min_dev_gear, min_pltfrm_gear); + min_t(u32, min_dev_gear, min_host_gear); } else if (!is_dev_sup_hs) { agreed_pwr->gear_rx = min_dev_gear; } else { - agreed_pwr->gear_rx = min_pltfrm_gear; + agreed_pwr->gear_rx = min_host_gear; } agreed_pwr->gear_tx = agreed_pwr->gear_rx; - agreed_pwr->hs_rate = pltfrm_param->hs_rate; + agreed_pwr->hs_rate = host_params->hs_rate; return 0; } -EXPORT_SYMBOL_GPL(ufshcd_get_pwr_dev_param); +EXPORT_SYMBOL_GPL(ufshcd_negotiate_pwr_params); -void ufshcd_init_pwr_dev_param(struct ufs_dev_params *dev_param) +void ufshcd_init_host_params(struct ufs_host_params *host_params) { - *dev_param = (struct ufs_dev_params){ + *host_params = (struct ufs_host_params){ .tx_lanes = UFS_LANE_2, .rx_lanes = UFS_LANE_2, .hs_rx_gear = UFS_HS_G3, @@ -398,7 +397,7 @@ void ufshcd_init_pwr_dev_param(struct ufs_dev_params *dev_param) .desired_working_mode = UFS_HS_MODE, }; } -EXPORT_SYMBOL_GPL(ufshcd_init_pwr_dev_param); +EXPORT_SYMBOL_GPL(ufshcd_init_host_params); /** * ufshcd_pltfrm_init - probe routine of the driver diff --git a/drivers/ufs/host/ufshcd-pltfrm.h b/drivers/ufs/host/ufshcd-pltfrm.h index a86a3ada4bef..df387be5216b 100644 --- a/drivers/ufs/host/ufshcd-pltfrm.h +++ b/drivers/ufs/host/ufshcd-pltfrm.h @@ -10,7 +10,7 @@ #define UFS_PWM_MODE 1 #define UFS_HS_MODE 2 -struct ufs_dev_params { +struct ufs_host_params { u32 pwm_rx_gear; /* pwm rx gear to work in */ u32 pwm_tx_gear; /* pwm tx gear to work in */ u32 hs_rx_gear; /* hs rx gear to work in */ @@ -25,10 +25,10 @@ struct ufs_dev_params { u32 desired_working_mode; }; -int ufshcd_get_pwr_dev_param(const struct ufs_dev_params *dev_param, - const struct ufs_pa_layer_attr *dev_max, - struct ufs_pa_layer_attr *agreed_pwr); -void ufshcd_init_pwr_dev_param(struct ufs_dev_params *dev_param); +int ufshcd_negotiate_pwr_params(const struct ufs_host_params *host_params, + const struct ufs_pa_layer_attr *dev_max, + struct ufs_pa_layer_attr *agreed_pwr); +void ufshcd_init_host_params(struct ufs_host_params *host_params); int ufshcd_pltfrm_init(struct platform_device *pdev, const struct ufs_hba_variant_ops *vops); int ufshcd_populate_vreg(struct device *dev, const char *name, -- cgit v1.2.3 From dc604b4c9d6007c0a03ad90296e849bc38c0d2cc Mon Sep 17 00:00:00 2001 From: Can Guo Date: Sat, 2 Dec 2023 04:36:08 -0800 Subject: scsi: ufs: ufs-qcom: No need to set hs_rate after ufshcd_init_host_param() In ufs_qcom_pwr_change_notify(), host_params.hs_rate has been set to PA_HS_MODE_B by ufshcd_init_host_param(), hence remove the duplicated line of work. Meanwhile, removed the macro UFS_QCOM_LIMIT_HS_RATE as it is only used here. Reviewed-by: Nitin Rawat Reviewed-by: Manivannan Sadhasivam Reviewed-by: Andrew Halaney Signed-off-by: Can Guo Link: https://lore.kernel.org/r/1701520577-31163-3-git-send-email-quic_cang@quicinc.com Tested-by: Neil Armstrong # on SM8550-QRD Signed-off-by: Martin K. Petersen --- drivers/ufs/host/ufs-qcom.c | 1 - drivers/ufs/host/ufs-qcom.h | 2 -- 2 files changed, 3 deletions(-) (limited to 'drivers/ufs') diff --git a/drivers/ufs/host/ufs-qcom.c b/drivers/ufs/host/ufs-qcom.c index 197c5a5ab136..c21ff2cd7aa6 100644 --- a/drivers/ufs/host/ufs-qcom.c +++ b/drivers/ufs/host/ufs-qcom.c @@ -909,7 +909,6 @@ static int ufs_qcom_pwr_change_notify(struct ufs_hba *hba, switch (status) { case PRE_CHANGE: ufshcd_init_host_params(&host_params); - host_params.hs_rate = UFS_QCOM_LIMIT_HS_RATE; /* This driver only supports symmetic gear setting i.e., hs_tx_gear == hs_rx_gear */ host_params.hs_tx_gear = host_params.hs_rx_gear = ufs_qcom_get_hs_gear(hba); diff --git a/drivers/ufs/host/ufs-qcom.h b/drivers/ufs/host/ufs-qcom.h index 9950a0089475..82cd1436f42d 100644 --- a/drivers/ufs/host/ufs-qcom.h +++ b/drivers/ufs/host/ufs-qcom.h @@ -27,8 +27,6 @@ #define SLOW 1 #define FAST 2 -#define UFS_QCOM_LIMIT_HS_RATE PA_HS_MODE_B - /* QCOM UFS host controller vendor specific registers */ enum { REG_UFS_SYS1CLK_1US = 0xC0, -- cgit v1.2.3 From 55820a7f2cb9b9a4b603cc22dcf0ca5331f86d25 Mon Sep 17 00:00:00 2001 From: Can Guo Date: Sat, 2 Dec 2023 04:36:09 -0800 Subject: scsi: ufs: ufs-qcom: Setup host power mode during init Setup host power mode and its limitations during UFS host driver init to avoid repetitive work during every power mode change. Acked-by: Andrew Halaney Reviewed-by: Nitin Rawat Reviewed-by: Manivannan Sadhasivam Co-developed-by: Bao D. Nguyen Signed-off-by: Bao D. Nguyen Signed-off-by: Can Guo Link: https://lore.kernel.org/r/1701520577-31163-4-git-send-email-quic_cang@quicinc.com Tested-by: Neil Armstrong # on SM8550-QRD Signed-off-by: Martin K. Petersen --- drivers/ufs/host/ufs-qcom.c | 21 ++++++++++++++------- drivers/ufs/host/ufs-qcom.h | 1 + 2 files changed, 15 insertions(+), 7 deletions(-) (limited to 'drivers/ufs') diff --git a/drivers/ufs/host/ufs-qcom.c b/drivers/ufs/host/ufs-qcom.c index c21ff2cd7aa6..9a900196509f 100644 --- a/drivers/ufs/host/ufs-qcom.c +++ b/drivers/ufs/host/ufs-qcom.c @@ -898,7 +898,7 @@ static int ufs_qcom_pwr_change_notify(struct ufs_hba *hba, struct ufs_pa_layer_attr *dev_req_params) { struct ufs_qcom_host *host = ufshcd_get_variant(hba); - struct ufs_host_params host_params; + struct ufs_host_params *host_params = &host->host_params; int ret = 0; if (!dev_req_params) { @@ -908,12 +908,7 @@ static int ufs_qcom_pwr_change_notify(struct ufs_hba *hba, switch (status) { case PRE_CHANGE: - ufshcd_init_host_params(&host_params); - - /* This driver only supports symmetic gear setting i.e., hs_tx_gear == hs_rx_gear */ - host_params.hs_tx_gear = host_params.hs_rx_gear = ufs_qcom_get_hs_gear(hba); - - ret = ufshcd_negotiate_pwr_params(&host_params, dev_max_params, dev_req_params); + ret = ufshcd_negotiate_pwr_params(host_params, dev_max_params, dev_req_params); if (ret) { dev_err(hba->dev, "%s: failed to determine capabilities\n", __func__); @@ -1048,6 +1043,17 @@ static void ufs_qcom_advertise_quirks(struct ufs_hba *hba) hba->quirks |= UFSHCD_QUIRK_REINIT_AFTER_MAX_GEAR_SWITCH; } +static void ufs_qcom_set_host_params(struct ufs_hba *hba) +{ + struct ufs_qcom_host *host = ufshcd_get_variant(hba); + struct ufs_host_params *host_params = &host->host_params; + + ufshcd_init_host_params(host_params); + + /* This driver only supports symmetic gear setting i.e., hs_tx_gear == hs_rx_gear */ + host_params->hs_tx_gear = host_params->hs_rx_gear = ufs_qcom_get_hs_gear(hba); +} + static void ufs_qcom_set_caps(struct ufs_hba *hba) { struct ufs_qcom_host *host = ufshcd_get_variant(hba); @@ -1272,6 +1278,7 @@ static int ufs_qcom_init(struct ufs_hba *hba) ufs_qcom_set_caps(hba); ufs_qcom_advertise_quirks(hba); + ufs_qcom_set_host_params(hba); err = ufs_qcom_ice_init(host); if (err) diff --git a/drivers/ufs/host/ufs-qcom.h b/drivers/ufs/host/ufs-qcom.h index 82cd1436f42d..11419ebd2082 100644 --- a/drivers/ufs/host/ufs-qcom.h +++ b/drivers/ufs/host/ufs-qcom.h @@ -238,6 +238,7 @@ struct ufs_qcom_host { struct gpio_desc *device_reset; + struct ufs_host_params host_params; u32 phy_gear; bool esi_enabled; -- cgit v1.2.3 From 743e1f596cccd371e7467fe585a1836773fbd922 Mon Sep 17 00:00:00 2001 From: Can Guo Date: Sat, 2 Dec 2023 04:36:10 -0800 Subject: scsi: ufs: ufs-qcom: Allow the first init start with the maximum supported gear During host driver init, the phy_gear is set to the minimum supported gear (HS_G2). Then, during the first power mode change, the negotiated gear, say HS-G4, is updated to the phy_gear variable so that in the second init the updated phy_gear can be used to program the PHY. But the current code only allows update the phy_gear to a higher value. If one wants to start the first init with the maximum support gear, say HS-G4, the phy_gear is not updated to HS-G3 if the device only supports HS-G3. The original check added there is intend to make sure the phy_gear won't be updated when gear is scaled down (during clock scaling). Update the check so that one can start the first init with the maximum support gear without breaking the original fix by checking the ufshcd_state, that is, allow update to phy_gear only if power mode change is invoked from ufshcd_probe_hba(). Reviewed-by: Manivannan Sadhasivam Reviewed-by: Nitin Rawat Signed-off-by: Can Guo Link: https://lore.kernel.org/r/1701520577-31163-5-git-send-email-quic_cang@quicinc.com Tested-by: Neil Armstrong # on SM8550-QRD Signed-off-by: Martin K. Petersen --- drivers/ufs/host/ufs-qcom.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) (limited to 'drivers/ufs') diff --git a/drivers/ufs/host/ufs-qcom.c b/drivers/ufs/host/ufs-qcom.c index 9a900196509f..81056b9f9c5d 100644 --- a/drivers/ufs/host/ufs-qcom.c +++ b/drivers/ufs/host/ufs-qcom.c @@ -916,11 +916,12 @@ static int ufs_qcom_pwr_change_notify(struct ufs_hba *hba, } /* - * Update phy_gear only when the gears are scaled to a higher value. This is - * because, the PHY gear settings are backwards compatible and we only need to - * change the PHY gear settings while scaling to higher gears. + * During UFS driver probe, always update the PHY gear to match the negotiated + * gear, so that, if quirk UFSHCD_QUIRK_REINIT_AFTER_MAX_GEAR_SWITCH is enabled, + * the second init can program the optimal PHY settings. This allows one to start + * the first init with either the minimum or the maximum support gear. */ - if (dev_req_params->gear_tx > host->phy_gear) + if (hba->ufshcd_state == UFSHCD_STATE_RESET) host->phy_gear = dev_req_params->gear_tx; /* enable the device ref clock before changing to HS mode */ -- cgit v1.2.3 From 9d8528a833fc0b4f47f7e43481c037390dd9ed71 Mon Sep 17 00:00:00 2001 From: Can Guo Date: Sat, 2 Dec 2023 04:36:11 -0800 Subject: scsi: ufs: ufs-qcom: Limit HS-G5 Rate-A to hosts with HW version 5 Qcom UFS hosts, with HW ver 5, can only support up to HS-G5 Rate-A due to HW limitations. If the HS-G5 PHY gear is used, update host_params->hs_rate to Rate-A, so that the subsequent power mode changes shall stick to Rate-A. Reviewed-by: Nitin Rawat Reviewed-by: Manivannan Sadhasivam Signed-off-by: Can Guo Link: https://lore.kernel.org/r/1701520577-31163-6-git-send-email-quic_cang@quicinc.com Tested-by: Neil Armstrong # on SM8550-QRD Signed-off-by: Martin K. Petersen --- drivers/ufs/host/ufs-qcom.c | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) (limited to 'drivers/ufs') diff --git a/drivers/ufs/host/ufs-qcom.c b/drivers/ufs/host/ufs-qcom.c index 81056b9f9c5d..aca619986c78 100644 --- a/drivers/ufs/host/ufs-qcom.c +++ b/drivers/ufs/host/ufs-qcom.c @@ -442,9 +442,25 @@ static u32 ufs_qcom_get_hs_gear(struct ufs_hba *hba) static int ufs_qcom_power_up_sequence(struct ufs_hba *hba) { struct ufs_qcom_host *host = ufshcd_get_variant(hba); + struct ufs_host_params *host_params = &host->host_params; struct phy *phy = host->generic_phy; + enum phy_mode mode; int ret; + /* + * HW ver 5 can only support up to HS-G5 Rate-A due to HW limitations. + * If the HS-G5 PHY gear is used, update host_params->hs_rate to Rate-A, + * so that the subsequent power mode change shall stick to Rate-A. + */ + if (host->hw_ver.major == 0x5) { + if (host->phy_gear == UFS_HS_G5) + host_params->hs_rate = PA_HS_MODE_A; + else + host_params->hs_rate = PA_HS_MODE_B; + } + + mode = host_params->hs_rate == PA_HS_MODE_B ? PHY_MODE_UFS_HS_B : PHY_MODE_UFS_HS_A; + /* Reset UFS Host Controller and PHY */ ret = ufs_qcom_host_reset(hba); if (ret) @@ -459,7 +475,7 @@ static int ufs_qcom_power_up_sequence(struct ufs_hba *hba) return ret; } - phy_set_mode_ext(phy, PHY_MODE_UFS_HS_B, host->phy_gear); + phy_set_mode_ext(phy, mode, host->phy_gear); /* power on phy - start serdes and phy's power and clocks */ ret = phy_power_on(phy); -- cgit v1.2.3 From 0bd3cb895d195cdd44da9186bb5b3e0333f1d381 Mon Sep 17 00:00:00 2001 From: Can Guo Date: Sat, 2 Dec 2023 04:36:12 -0800 Subject: scsi: ufs: ufs-qcom: Set initial PHY gear to max HS gear for HW ver 4 and newer Since HW ver 4, max HS gear can be get from UFS host controller's register, use the max HS gear as the initial PHY gear instead of UFS_HS_G2, so that we don't need to update the hard code for newer targets in future. Reviewed-by: Nitin Rawat Reviewed-by: Manivannan Sadhasivam Signed-off-by: Can Guo Link: https://lore.kernel.org/r/1701520577-31163-7-git-send-email-quic_cang@quicinc.com Tested-by: Neil Armstrong # on SM8550-QRD Signed-off-by: Martin K. Petersen --- drivers/ufs/host/ufs-qcom.c | 23 +++++++++++++++++------ 1 file changed, 17 insertions(+), 6 deletions(-) (limited to 'drivers/ufs') diff --git a/drivers/ufs/host/ufs-qcom.c b/drivers/ufs/host/ufs-qcom.c index aca619986c78..543939c4c463 100644 --- a/drivers/ufs/host/ufs-qcom.c +++ b/drivers/ufs/host/ufs-qcom.c @@ -1060,6 +1060,22 @@ static void ufs_qcom_advertise_quirks(struct ufs_hba *hba) hba->quirks |= UFSHCD_QUIRK_REINIT_AFTER_MAX_GEAR_SWITCH; } +static void ufs_qcom_set_phy_gear(struct ufs_qcom_host *host) +{ + struct ufs_host_params *host_params = &host->host_params; + + host->phy_gear = host_params->hs_tx_gear; + + /* + * For controllers whose major HW version is < 4, power up the PHY using + * minimum supported gear (UFS_HS_G2). Switching to max gear will be + * performed during reinit if supported. For newer controllers, whose + * major HW version is >= 4, power up the PHY using max supported gear. + */ + if (host->hw_ver.major < 0x4) + host->phy_gear = UFS_HS_G2; +} + static void ufs_qcom_set_host_params(struct ufs_hba *hba) { struct ufs_qcom_host *host = ufshcd_get_variant(hba); @@ -1296,6 +1312,7 @@ static int ufs_qcom_init(struct ufs_hba *hba) ufs_qcom_set_caps(hba); ufs_qcom_advertise_quirks(hba); ufs_qcom_set_host_params(hba); + ufs_qcom_set_phy_gear(host); err = ufs_qcom_ice_init(host); if (err) @@ -1313,12 +1330,6 @@ static int ufs_qcom_init(struct ufs_hba *hba) dev_warn(dev, "%s: failed to configure the testbus %d\n", __func__, err); - /* - * Power up the PHY using the minimum supported gear (UFS_HS_G2). - * Switching to max gear will be performed during reinit if supported. - */ - host->phy_gear = UFS_HS_G2; - return 0; out_variant_clear: -- cgit v1.2.3 From a68abdadfe13fa95a306363fa284b5cf0b79776d Mon Sep 17 00:00:00 2001 From: Can Guo Date: Sat, 2 Dec 2023 04:36:13 -0800 Subject: scsi: ufs: ufs-qcom: Check return value of phy_set_mode_ext() In ufs_qcom_power_up_sequence(), check return value of phy_set_mode_ext() and stop proceeding if phy_set_mode_ext() fails. Reviewed-by: Nitin Rawat Reviewed-by: Manivannan Sadhasivam Signed-off-by: Can Guo Link: https://lore.kernel.org/r/1701520577-31163-8-git-send-email-quic_cang@quicinc.com Tested-by: Neil Armstrong # on SM8550-QRD Signed-off-by: Martin K. Petersen --- drivers/ufs/host/ufs-qcom.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers/ufs') diff --git a/drivers/ufs/host/ufs-qcom.c b/drivers/ufs/host/ufs-qcom.c index 543939c4c463..ee3f07a9e624 100644 --- a/drivers/ufs/host/ufs-qcom.c +++ b/drivers/ufs/host/ufs-qcom.c @@ -475,7 +475,9 @@ static int ufs_qcom_power_up_sequence(struct ufs_hba *hba) return ret; } - phy_set_mode_ext(phy, mode, host->phy_gear); + ret = phy_set_mode_ext(phy, mode, host->phy_gear); + if (ret) + goto out_disable_phy; /* power on phy - start serdes and phy's power and clocks */ ret = phy_power_on(phy); -- cgit v1.2.3 From dc7c948d74e12ed9f40328696b301860243a1ae8 Mon Sep 17 00:00:00 2001 From: "Bao D. Nguyen" Date: Sat, 2 Dec 2023 04:36:14 -0800 Subject: scsi: ufs: ufs-qcom: Add support for UFS device version detection Start from HW ver 5, a spare register in UFS host controller is added and used to indicate the UFS device version. The spare register is populated by bootloader for now, but in future it will be populated by HW automatically during link startup with its best efforts in any boot stage prior to Linux. During host driver init, read the spare register, if it is not populated with a UFS device version, go ahead with the dual init mechanism. If a UFS device version is in there, use the UFS device version together with host controller's HW version to decide the proper PHY gear which should be used to configure the UFS PHY without going through the second init. Signed-off-by: Bao D. Nguyen Signed-off-by: Can Guo Link: https://lore.kernel.org/r/1701520577-31163-9-git-send-email-quic_cang@quicinc.com Reviewed-by: Manivannan Sadhasivam Reviewed-by: Nitin Rawat Tested-by: Neil Armstrong # on SM8550-QRD Signed-off-by: Martin K. Petersen --- drivers/ufs/host/ufs-qcom.c | 35 ++++++++++++++++++++++++++++------- drivers/ufs/host/ufs-qcom.h | 4 ++++ 2 files changed, 32 insertions(+), 7 deletions(-) (limited to 'drivers/ufs') diff --git a/drivers/ufs/host/ufs-qcom.c b/drivers/ufs/host/ufs-qcom.c index ee3f07a9e624..968a4c00b5ec 100644 --- a/drivers/ufs/host/ufs-qcom.c +++ b/drivers/ufs/host/ufs-qcom.c @@ -1065,17 +1065,38 @@ static void ufs_qcom_advertise_quirks(struct ufs_hba *hba) static void ufs_qcom_set_phy_gear(struct ufs_qcom_host *host) { struct ufs_host_params *host_params = &host->host_params; + u32 val, dev_major; host->phy_gear = host_params->hs_tx_gear; - /* - * For controllers whose major HW version is < 4, power up the PHY using - * minimum supported gear (UFS_HS_G2). Switching to max gear will be - * performed during reinit if supported. For newer controllers, whose - * major HW version is >= 4, power up the PHY using max supported gear. - */ - if (host->hw_ver.major < 0x4) + if (host->hw_ver.major < 0x4) { + /* + * For controllers whose major HW version is < 4, power up the + * PHY using minimum supported gear (UFS_HS_G2). Switching to + * max gear will be performed during reinit if supported. + * For newer controllers, whose major HW version is >= 4, power + * up the PHY using max supported gear. + */ host->phy_gear = UFS_HS_G2; + } else if (host->hw_ver.major >= 0x5) { + val = ufshcd_readl(host->hba, REG_UFS_DEBUG_SPARE_CFG); + dev_major = FIELD_GET(UFS_DEV_VER_MAJOR_MASK, val); + + /* + * Since the UFS device version is populated, let's remove the + * REINIT quirk as the negotiated gear won't change during boot. + * So there is no need to do reinit. + */ + if (dev_major != 0x0) + host->hba->quirks &= ~UFSHCD_QUIRK_REINIT_AFTER_MAX_GEAR_SWITCH; + + /* + * For UFS 3.1 device and older, power up the PHY using HS-G4 + * PHY gear to save power. + */ + if (dev_major > 0x0 && dev_major < 0x4) + host->phy_gear = UFS_HS_G4; + } } static void ufs_qcom_set_host_params(struct ufs_hba *hba) diff --git a/drivers/ufs/host/ufs-qcom.h b/drivers/ufs/host/ufs-qcom.h index 11419ebd2082..32e51d90e8e7 100644 --- a/drivers/ufs/host/ufs-qcom.h +++ b/drivers/ufs/host/ufs-qcom.h @@ -23,6 +23,8 @@ #define UFS_HW_VER_MINOR_MASK GENMASK(27, 16) #define UFS_HW_VER_STEP_MASK GENMASK(15, 0) +#define UFS_DEV_VER_MAJOR_MASK GENMASK(7, 4) + /* vendor specific pre-defined parameters */ #define SLOW 1 #define FAST 2 @@ -54,6 +56,8 @@ enum { UFS_AH8_CFG = 0xFC, REG_UFS_CFG3 = 0x271C, + + REG_UFS_DEBUG_SPARE_CFG = 0x284C, }; /* QCOM UFS host controller vendor specific debug registers */ -- cgit v1.2.3