diff mbox series

[v1] scsi: ufs-mediatek: introduce new UFS4.0 HS-G5 mode

Message ID 20220512135654.3656-1-peter.wang@mediatek.com
State New
Headers show
Series [v1] scsi: ufs-mediatek: introduce new UFS4.0 HS-G5 mode | expand

Commit Message

Peter Wang May 12, 2022, 1:56 p.m. UTC
From: Peter Wang <peter.wang@mediatek.com>

Per UFS4.0 spec, HS-G5 is a new speed mode.
This patch introduce HS-G5 speed mode to mediatek.
Also add a host cap for power mode change via fastauto.

Co-Developed-by: CC Chou <cc.chou@mediatek.com>
Signed-off-by: CC Chou <cc.chou@mediatek.com>
Co-Developed-by: Eddie Huang <eddie.huang@mediatek.com>
Signed-off-by: Eddie Huang <eddie.huang@mediatek.com>
Co-Developed-by: Dennis Yu <tun-yu.yu@mediatek.com>
Signed-off-by: Dennis Yu <tun-yu.yu@mediatek.com>
Signed-off-by: Peter Wang <peter.wang@mediatek.com>
---
 drivers/scsi/ufs/ufs-mediatek.c | 60 +++++++++++++++++++++++++++++++--
 drivers/scsi/ufs/ufs-mediatek.h |  1 +
 drivers/scsi/ufs/ufshcd.c       |  3 +-
 drivers/scsi/ufs/ufshcd.h       |  1 +
 drivers/scsi/ufs/unipro.h       |  4 ++-
 5 files changed, 65 insertions(+), 4 deletions(-)

Comments

Martin K. Petersen May 17, 2022, 2 a.m. UTC | #1
Peter,

> @@ -4101,6 +4101,7 @@ static int ufshcd_uic_change_pwr_mode(struct ufs_hba *hba, u8 mode)
>  out:
>  	return ret;
>  }
> +EXPORT_SYMBOL(ufshcd_uic_change_pwr_mode);
>  
>  int ufshcd_link_recovery(struct ufs_hba *hba)
>  {

EXPORT_SYMBOL_GPL()?
Avri Altman May 17, 2022, 6:49 a.m. UTC | #2
Hi,
 
> From: Peter Wang <peter.wang@mediatek.com>
> 
> Per UFS4.0 spec, HS-G5 is a new speed mode.
> This patch introduce HS-G5 speed mode to mediatek.
> Also add a host cap for power mode change via fastauto.
Maybe better to wait a week or 2 to let Martin pick Bart's Split of the ufs directory ?

> 
> Co-Developed-by: CC Chou <cc.chou@mediatek.com>
> Signed-off-by: CC Chou <cc.chou@mediatek.com>
> Co-Developed-by: Eddie Huang <eddie.huang@mediatek.com>
> Signed-off-by: Eddie Huang <eddie.huang@mediatek.com>
> Co-Developed-by: Dennis Yu <tun-yu.yu@mediatek.com>
> Signed-off-by: Dennis Yu <tun-yu.yu@mediatek.com>
> Signed-off-by: Peter Wang <peter.wang@mediatek.com>
I think the signed-of-by suffices, not need the co-developed duplication?

> ---
>  drivers/scsi/ufs/ufs-mediatek.c | 60 +++++++++++++++++++++++++++++++--
> drivers/scsi/ufs/ufs-mediatek.h |  1 +
>  drivers/scsi/ufs/ufshcd.c       |  3 +-
>  drivers/scsi/ufs/ufshcd.h       |  1 +
>  drivers/scsi/ufs/unipro.h       |  4 ++-
>  5 files changed, 65 insertions(+), 4 deletions(-)
> 
> diff --git a/drivers/scsi/ufs/ufs-mediatek.c b/drivers/scsi/ufs/ufs-mediatek.c
> index 86a938075f30..8f2a3b03d244 100644
> --- a/drivers/scsi/ufs/ufs-mediatek.c
> +++ b/drivers/scsi/ufs/ufs-mediatek.c
> @@ -78,6 +78,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); }
Not sure that !! are needed

> +
>  static void ufs_mtk_cfg_unipro_cg(struct ufs_hba *hba, bool enable)  {
>         u32 tmp;
> @@ -580,6 +587,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);  }
> 
> @@ -755,6 +765,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) @@ -764,8
> +794,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, @@ -775,6 +805,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);
Other than setting G1 - all other are done anyway as part ufshcd_change_power_mode?
Maybe add instead an appropriate quirk and use it in ufshcd_change_power_mode?
 
> +
> +               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/scsi/ufs/ufs-mediatek.h b/drivers/scsi/ufs/ufs-mediatek.h index
> 414dca86c09f..3a31f03f3cb1 100644
> --- a/drivers/scsi/ufs/ufs-mediatek.h
> +++ b/drivers/scsi/ufs/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 << 4,
>  };
> 
>  struct ufs_mtk_crypt_cfg {
> diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c index
> 3f9caafa91bf..e750011d0de7 100644
> --- a/drivers/scsi/ufs/ufshcd.c
> +++ b/drivers/scsi/ufs/ufshcd.c
> @@ -4076,7 +4076,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;
> @@ -4101,6 +4101,7 @@ static int ufshcd_uic_change_pwr_mode(struct
> ufs_hba *hba, u8 mode)
>  out:
>         return ret;
>  }
> +EXPORT_SYMBOL(ufshcd_uic_change_pwr_mode);
> 
>  int ufshcd_link_recovery(struct ufs_hba *hba)  { diff --git
> a/drivers/scsi/ufs/ufshcd.h b/drivers/scsi/ufs/ufshcd.h index
> 94f545be183a..1cda0f211d72 100644
> --- a/drivers/scsi/ufs/ufshcd.h
> +++ b/drivers/scsi/ufs/ufshcd.h
> @@ -1101,6 +1101,7 @@ extern int ufshcd_dme_set_attr(struct ufs_hba *hba,
> u32 attr_sel,
>                                u8 attr_set, u32 mib_val, u8 peer);  extern int
> ufshcd_dme_get_attr(struct ufs_hba *hba, u32 attr_sel,
>                                u32 *mib_val, u8 peer);
> +extern int ufshcd_uic_change_pwr_mode(struct ufs_hba *hba, u8 mode);
>  extern int ufshcd_config_pwr_mode(struct ufs_hba *hba,
>                         struct ufs_pa_layer_attr *desired_pwr_mode);
> 
> diff --git a/drivers/scsi/ufs/unipro.h b/drivers/scsi/ufs/unipro.h index
> 8e9e486a4f7b..94d97f123e3a 100644
> --- a/drivers/scsi/ufs/unipro.h
> +++ b/drivers/scsi/ufs/unipro.h
> @@ -231,6 +231,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 {
> @@ -240,7 +241,8 @@ enum ufs_unipro_ver {
>         UFS_UNIPRO_VER_1_6  = 3, /* UniPro version 1.6 */
>         UFS_UNIPRO_VER_1_61 = 4, /* UniPro version 1.61 */
>         UFS_UNIPRO_VER_1_8  = 5, /* UniPro version 1.8 */
> -       UFS_UNIPRO_VER_MAX  = 6, /* UniPro unsupported version */
> +       UFS_UNIPRO_VER_2_0  = 6, /* UniPro version 2.0 */
Maybe use it now in ufs_mtk_get_controller_version to set host->hw_ver.major = 4?

Thanks,
Avri

> +       UFS_UNIPRO_VER_MAX  = 7, /* UniPro unsupported version */
>         /* UniPro version field mask in PA_LOCALVERINFO */
>         UFS_UNIPRO_VER_MASK = 0xF,
>  };
> --
> 2.18.0
Peter Wang May 17, 2022, 8:17 a.m. UTC | #3
Hi Martin,

OK. Will change next version.

Thanks for review.


On 5/17/22 10:00 AM, Martin K. Petersen wrote:
> Peter,
>
>> @@ -4101,6 +4101,7 @@ static int ufshcd_uic_change_pwr_mode(struct ufs_hba *hba, u8 mode)
>>   out:
>>   	return ret;
>>   }
>> +EXPORT_SYMBOL(ufshcd_uic_change_pwr_mode);
>>   
>>   int ufshcd_link_recovery(struct ufs_hba *hba)
>>   {
> EXPORT_SYMBOL_GPL()?
>
Peter Wang May 17, 2022, 8:41 a.m. UTC | #4
Hi Arvi,

On 5/17/22 2:49 PM, Avri Altman wrote:
> Hi,
>   
>> From: Peter Wang <peter.wang@mediatek.com>
>>
>> Per UFS4.0 spec, HS-G5 is a new speed mode.
>> This patch introduce HS-G5 speed mode to mediatek.
>> Also add a host cap for power mode change via fastauto.
> Maybe better to wait a week or 2 to let Martin pick Bart's Split of the ufs directory ?

This feature only modify < 100 line, it dosn't bother Bart's split?

>
>> Co-Developed-by: CC Chou <cc.chou@mediatek.com>
>> Signed-off-by: CC Chou <cc.chou@mediatek.com>
>> Co-Developed-by: Eddie Huang <eddie.huang@mediatek.com>
>> Signed-off-by: Eddie Huang <eddie.huang@mediatek.com>
>> Co-Developed-by: Dennis Yu <tun-yu.yu@mediatek.com>
>> Signed-off-by: Dennis Yu <tun-yu.yu@mediatek.com>
>> Signed-off-by: Peter Wang <peter.wang@mediatek.com>
> I think the signed-of-by suffices, not need the co-developed duplication?

ok, will remove co-developed next version.

>
>> ---
>>   drivers/scsi/ufs/ufs-mediatek.c | 60 +++++++++++++++++++++++++++++++--
>> drivers/scsi/ufs/ufs-mediatek.h |  1 +
>>   drivers/scsi/ufs/ufshcd.c       |  3 +-
>>   drivers/scsi/ufs/ufshcd.h       |  1 +
>>   drivers/scsi/ufs/unipro.h       |  4 ++-
>>   5 files changed, 65 insertions(+), 4 deletions(-)
>>
>> diff --git a/drivers/scsi/ufs/ufs-mediatek.c b/drivers/scsi/ufs/ufs-mediatek.c
>> index 86a938075f30..8f2a3b03d244 100644
>> --- a/drivers/scsi/ufs/ufs-mediatek.c
>> +++ b/drivers/scsi/ufs/ufs-mediatek.c
>> @@ -78,6 +78,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); }
> Not sure that !! are needed
just for same coding style.
>> +
>>   static void ufs_mtk_cfg_unipro_cg(struct ufs_hba *hba, bool enable)  {
>>          u32 tmp;
>> @@ -580,6 +587,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);  }
>>
>> @@ -755,6 +765,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) @@ -764,8
>> +794,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, @@ -775,6 +805,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);
> Other than setting G1 - all other are done anyway as part ufshcd_change_power_mode?
> Maybe add instead an appropriate quirk and use it in ufshcd_change_power_mode?

Mediatek design change to fast mode(G1~G5) need via fast auto.

It is our design limitation.

And we are not sure add quirk is suitable for this limitation which may 
only mediatek have.

Or other company also need this quirk?

What do you think?


>   
>> +
>> +               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/scsi/ufs/ufs-mediatek.h b/drivers/scsi/ufs/ufs-mediatek.h index
>> 414dca86c09f..3a31f03f3cb1 100644
>> --- a/drivers/scsi/ufs/ufs-mediatek.h
>> +++ b/drivers/scsi/ufs/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 << 4,
>>   };
>>
>>   struct ufs_mtk_crypt_cfg {
>> diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c index
>> 3f9caafa91bf..e750011d0de7 100644
>> --- a/drivers/scsi/ufs/ufshcd.c
>> +++ b/drivers/scsi/ufs/ufshcd.c
>> @@ -4076,7 +4076,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;
>> @@ -4101,6 +4101,7 @@ static int ufshcd_uic_change_pwr_mode(struct
>> ufs_hba *hba, u8 mode)
>>   out:
>>          return ret;
>>   }
>> +EXPORT_SYMBOL(ufshcd_uic_change_pwr_mode);
>>
>>   int ufshcd_link_recovery(struct ufs_hba *hba)  { diff --git
>> a/drivers/scsi/ufs/ufshcd.h b/drivers/scsi/ufs/ufshcd.h index
>> 94f545be183a..1cda0f211d72 100644
>> --- a/drivers/scsi/ufs/ufshcd.h
>> +++ b/drivers/scsi/ufs/ufshcd.h
>> @@ -1101,6 +1101,7 @@ extern int ufshcd_dme_set_attr(struct ufs_hba *hba,
>> u32 attr_sel,
>>                                 u8 attr_set, u32 mib_val, u8 peer);  extern int
>> ufshcd_dme_get_attr(struct ufs_hba *hba, u32 attr_sel,
>>                                 u32 *mib_val, u8 peer);
>> +extern int ufshcd_uic_change_pwr_mode(struct ufs_hba *hba, u8 mode);
>>   extern int ufshcd_config_pwr_mode(struct ufs_hba *hba,
>>                          struct ufs_pa_layer_attr *desired_pwr_mode);
>>
>> diff --git a/drivers/scsi/ufs/unipro.h b/drivers/scsi/ufs/unipro.h index
>> 8e9e486a4f7b..94d97f123e3a 100644
>> --- a/drivers/scsi/ufs/unipro.h
>> +++ b/drivers/scsi/ufs/unipro.h
>> @@ -231,6 +231,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 {
>> @@ -240,7 +241,8 @@ enum ufs_unipro_ver {
>>          UFS_UNIPRO_VER_1_6  = 3, /* UniPro version 1.6 */
>>          UFS_UNIPRO_VER_1_61 = 4, /* UniPro version 1.61 */
>>          UFS_UNIPRO_VER_1_8  = 5, /* UniPro version 1.8 */
>> -       UFS_UNIPRO_VER_MAX  = 6, /* UniPro unsupported version */
>> +       UFS_UNIPRO_VER_2_0  = 6, /* UniPro version 2.0 */
> Maybe use it now in ufs_mtk_get_controller_version to set host->hw_ver.major = 4?
>
> Thanks,
> Avri

Yes, we may use it to set hw_ver, or other check, but now it is necessary.

Only add spec version define in this patch.


>> +       UFS_UNIPRO_VER_MAX  = 7, /* UniPro unsupported version */
>>          /* UniPro version field mask in PA_LOCALVERINFO */
>>          UFS_UNIPRO_VER_MASK = 0xF,
>>   };
>> --
>> 2.18.0
diff mbox series

Patch

diff --git a/drivers/scsi/ufs/ufs-mediatek.c b/drivers/scsi/ufs/ufs-mediatek.c
index 86a938075f30..8f2a3b03d244 100644
--- a/drivers/scsi/ufs/ufs-mediatek.c
+++ b/drivers/scsi/ufs/ufs-mediatek.c
@@ -78,6 +78,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;
@@ -580,6 +587,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);
 }
 
@@ -755,6 +765,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)
@@ -764,8 +794,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,
@@ -775,6 +805,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/scsi/ufs/ufs-mediatek.h b/drivers/scsi/ufs/ufs-mediatek.h
index 414dca86c09f..3a31f03f3cb1 100644
--- a/drivers/scsi/ufs/ufs-mediatek.h
+++ b/drivers/scsi/ufs/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 << 4,
 };
 
 struct ufs_mtk_crypt_cfg {
diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index 3f9caafa91bf..e750011d0de7 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -4076,7 +4076,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;
@@ -4101,6 +4101,7 @@  static int ufshcd_uic_change_pwr_mode(struct ufs_hba *hba, u8 mode)
 out:
 	return ret;
 }
+EXPORT_SYMBOL(ufshcd_uic_change_pwr_mode);
 
 int ufshcd_link_recovery(struct ufs_hba *hba)
 {
diff --git a/drivers/scsi/ufs/ufshcd.h b/drivers/scsi/ufs/ufshcd.h
index 94f545be183a..1cda0f211d72 100644
--- a/drivers/scsi/ufs/ufshcd.h
+++ b/drivers/scsi/ufs/ufshcd.h
@@ -1101,6 +1101,7 @@  extern int ufshcd_dme_set_attr(struct ufs_hba *hba, u32 attr_sel,
 			       u8 attr_set, u32 mib_val, u8 peer);
 extern int ufshcd_dme_get_attr(struct ufs_hba *hba, u32 attr_sel,
 			       u32 *mib_val, u8 peer);
+extern int ufshcd_uic_change_pwr_mode(struct ufs_hba *hba, u8 mode);
 extern int ufshcd_config_pwr_mode(struct ufs_hba *hba,
 			struct ufs_pa_layer_attr *desired_pwr_mode);
 
diff --git a/drivers/scsi/ufs/unipro.h b/drivers/scsi/ufs/unipro.h
index 8e9e486a4f7b..94d97f123e3a 100644
--- a/drivers/scsi/ufs/unipro.h
+++ b/drivers/scsi/ufs/unipro.h
@@ -231,6 +231,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 {
@@ -240,7 +241,8 @@  enum ufs_unipro_ver {
 	UFS_UNIPRO_VER_1_6  = 3, /* UniPro version 1.6 */
 	UFS_UNIPRO_VER_1_61 = 4, /* UniPro version 1.61 */
 	UFS_UNIPRO_VER_1_8  = 5, /* UniPro version 1.8 */
-	UFS_UNIPRO_VER_MAX  = 6, /* UniPro unsupported version */
+	UFS_UNIPRO_VER_2_0  = 6, /* UniPro version 2.0 */
+	UFS_UNIPRO_VER_MAX  = 7, /* UniPro unsupported version */
 	/* UniPro version field mask in PA_LOCALVERINFO */
 	UFS_UNIPRO_VER_MASK = 0xF,
 };