[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <CAGOxZ539Fr5Vxg8Zg=LpYhxTacwh81Ee+S9MWFybwbAPr5RgYQ@mail.gmail.com>
Date: Thu, 19 Dec 2019 23:47:59 +0530
From: Alim Akhtar <alim.akhtar@...il.com>
To: Stanley Chu <stanley.chu@...iatek.com>
Cc: linux-scsi@...r.kernel.org,
"Martin K. Petersen" <martin.petersen@...cle.com>,
Avri Altman <avri.altman@....com>,
Alim Akhtar <alim.akhtar@...sung.com>,
Pedro Sousa <pedrom.sousa@...opsys.com>,
"James E.J. Bottomley" <jejb@...ux.ibm.com>,
Matthias Brugger <matthias.bgg@...il.com>,
linux-mediatek@...ts.infradead.org,
linux-arm-kernel@...ts.infradead.org,
open list <linux-kernel@...r.kernel.org>,
"Bean Huo (beanhuo)" <beanhuo@...ron.com>,
Kuohong Wang <kuohong.wang@...iatek.com>,
peter.wang@...iatek.com, chun-hung.wu@...iatek.com,
andy.teng@...iatek.com
Subject: Re: [PATCH v1 1/4] scsi: ufs-mediatek: introduce reference clock control
On Fri, Dec 13, 2019 at 2:23 PM Stanley Chu <stanley.chu@...iatek.com> 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@...iatek.com>
Reviewed-by: Alim Akhtar <alim.akhtar@...sung.com>
> ---
> 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
Powered by blists - more mailing lists