Re: [PATCH v1 1/4] scsi: ufs-mediatek: introduce reference clock control

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Fri, Dec 13, 2019 at 2:23 PM Stanley Chu <stanley.chu@xxxxxxxxxxxx> wrote:
>
> Introduce reference clock control in MediaTek Chipset in order
> to disable it if it is not necessary by UFS device to save system power.
>
> Currently reference clock can be disabled during system suspend, runtime
> suspend and clock-gating after link enters hibernate state.
>
> Signed-off-by: Stanley Chu <stanley.chu@xxxxxxxxxxxx>

Reviewed-by: Alim Akhtar <alim.akhtar@xxxxxxxxxxx>

> ---
>  drivers/scsi/ufs/ufs-mediatek.c | 64 ++++++++++++++++++++++++++++++---
>  drivers/scsi/ufs/ufs-mediatek.h | 20 +++++++++--
>  2 files changed, 78 insertions(+), 6 deletions(-)
>
> diff --git a/drivers/scsi/ufs/ufs-mediatek.c b/drivers/scsi/ufs/ufs-mediatek.c
> index 6a3ec11b16db..690483c78212 100644
> --- a/drivers/scsi/ufs/ufs-mediatek.c
> +++ b/drivers/scsi/ufs/ufs-mediatek.c
> @@ -18,6 +18,11 @@
>  #include "unipro.h"
>  #include "ufs-mediatek.h"
>
> +#define ufs_mtk_ref_clk_notify(on, res) \
> +       arm_smccc_smc(MTK_SIP_UFS_CONTROL, \
> +                     UFS_MTK_SIP_REF_CLK_NOTIFICATION, \
> +                     on, 0, 0, 0, 0, 0, &(res))
> +
>  static void ufs_mtk_cfg_unipro_cg(struct ufs_hba *hba, bool enable)
>  {
>         u32 tmp;
> @@ -83,6 +88,49 @@ static int ufs_mtk_bind_mphy(struct ufs_hba *hba)
>         return err;
>  }
>
> +static int ufs_mtk_setup_ref_clk(struct ufs_hba *hba, bool on)
> +{
> +       struct ufs_mtk_host *host = ufshcd_get_variant(hba);
> +       struct arm_smccc_res res;
> +       unsigned long timeout;
> +       u32 value;
> +
> +       if (host->ref_clk_enabled == on)
> +               return 0;
> +
> +       if (on) {
> +               ufs_mtk_ref_clk_notify(on, res);
> +               ufshcd_writel(hba, REFCLK_REQUEST, REG_UFS_REFCLK_CTRL);
> +       } else {
> +               ufshcd_writel(hba, REFCLK_RELEASE, REG_UFS_REFCLK_CTRL);
> +       }
> +
> +       /* Wait for ack */
> +       timeout = jiffies + msecs_to_jiffies(REFCLK_REQ_TIMEOUT_MS);
> +       do {
> +               value = ufshcd_readl(hba, REG_UFS_REFCLK_CTRL);
> +
> +               /* Wait until ack bit equals to req bit */
> +               if (((value & REFCLK_ACK) >> 1) == (value & REFCLK_REQUEST))
> +                       goto out;
> +
> +               usleep_range(100, 200);
> +       } while (time_before(jiffies, timeout));
> +
> +       dev_err(hba->dev, "missing ack of refclk req, reg: 0x%x\n", value);
> +
> +       ufs_mtk_ref_clk_notify(host->ref_clk_enabled, res);
> +
> +       return -ETIMEDOUT;
> +
> +out:
> +       host->ref_clk_enabled = on;
> +       if (!on)
> +               ufs_mtk_ref_clk_notify(on, res);
> +
> +       return 0;
> +}
> +
>  /**
>   * ufs_mtk_setup_clocks - enables/disable clocks
>   * @hba: host controller instance
> @@ -107,12 +155,16 @@ static int ufs_mtk_setup_clocks(struct ufs_hba *hba, bool on,
>
>         switch (status) {
>         case PRE_CHANGE:
> -               if (!on)
> +               if (!on) {
> +                       ufs_mtk_setup_ref_clk(hba, on);
>                         ret = phy_power_off(host->mphy);
> +               }
>                 break;
>         case POST_CHANGE:
> -               if (on)
> +               if (on) {
>                         ret = phy_power_on(host->mphy);
> +                       ufs_mtk_setup_ref_clk(hba, on);
> +               }
>                 break;
>         }
>
> @@ -299,8 +351,10 @@ static int ufs_mtk_suspend(struct ufs_hba *hba, enum ufs_pm_op pm_op)
>  {
>         struct ufs_mtk_host *host = ufshcd_get_variant(hba);
>
> -       if (ufshcd_is_link_hibern8(hba))
> +       if (ufshcd_is_link_hibern8(hba)) {
>                 phy_power_off(host->mphy);
> +               ufs_mtk_setup_ref_clk(hba, false);
> +       }
>
>         return 0;
>  }
> @@ -309,8 +363,10 @@ static int ufs_mtk_resume(struct ufs_hba *hba, enum ufs_pm_op pm_op)
>  {
>         struct ufs_mtk_host *host = ufshcd_get_variant(hba);
>
> -       if (ufshcd_is_link_hibern8(hba))
> +       if (ufshcd_is_link_hibern8(hba)) {
> +               ufs_mtk_setup_ref_clk(hba, true);
>                 phy_power_on(host->mphy);
> +       }
>
>         return 0;
>  }
> diff --git a/drivers/scsi/ufs/ufs-mediatek.h b/drivers/scsi/ufs/ufs-mediatek.h
> index b03f601d3a9e..14f8a8357c09 100644
> --- a/drivers/scsi/ufs/ufs-mediatek.h
> +++ b/drivers/scsi/ufs/ufs-mediatek.h
> @@ -6,7 +6,21 @@
>  #ifndef _UFS_MEDIATEK_H
>  #define _UFS_MEDIATEK_H
>
> -#include <linux/bitops.h>
> +/*
> + * Vendor specific UFSHCI Registers
> + */
> +#define REG_UFS_REFCLK_CTRL         0x144
> +
> +/*
> + * Ref-clk control
> + *
> + * Values for register REG_UFS_REFCLK_CTRL
> + */
> +#define REFCLK_RELEASE              0x0
> +#define REFCLK_REQUEST              BIT(0)
> +#define REFCLK_ACK                  BIT(1)
> +
> +#define REFCLK_REQ_TIMEOUT_MS       3
>
>  /*
>   * Vendor specific pre-defined parameters
> @@ -34,7 +48,8 @@
>  /*
>   * SiP commands
>   */
> -#define UFS_MTK_SIP_DEVICE_RESET    BIT(1)
> +#define UFS_MTK_SIP_DEVICE_RESET          BIT(1)
> +#define UFS_MTK_SIP_REF_CLK_NOTIFICATION  BIT(3)
>
>  /*
>   * VS_DEBUGCLOCKENABLE
> @@ -55,6 +70,7 @@ enum {
>  struct ufs_mtk_host {
>         struct ufs_hba *hba;
>         struct phy *mphy;
> +       bool ref_clk_enabled;
>  };
>
>  #endif /* !_UFS_MEDIATEK_H */
> --
> 2.18.0



-- 
Regards,
Alim



[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Index of Archives]     [SCSI Target Devel]     [Linux SCSI Target Infrastructure]     [Kernel Newbies]     [IDE]     [Security]     [Git]     [Netfilter]     [Bugtraq]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Linux ATA RAID]     [Linux IIO]     [Samba]     [Device Mapper]

  Powered by Linux