From: Stanley Chu <stanley.chu@mediatek.com>
To: <linux-scsi@vger.kernel.org>, <linux-kernel@vger.kernel.org>,
<martin.petersen@oracle.com>, <avri.altman@wdc.com>,
<alim.akhtar@samsung.com>, <jejb@linux.ibm.com>,
<bvanassche@acm.org>
Cc: <peter.wang@mediatek.com>, <chun-hung.wu@mediatek.com>,
<alice.chao@mediatek.com>, <powen.kao@mediatek.com>,
<mason.zhang@mediatek.com>, <qilin.tan@mediatek.com>,
<lin.gui@mediatek.com>, <eddie.huang@mediatek.com>,
<tun-yu.yu@mediatek.com>, <cc.chou@mediatek.com>,
<chaotian.jing@mediatek.com>, <jiajie.hao@mediatek.com>,
<stanley.chu@mediatek.com>
Subject: [PATCH v5 5/5] scsi: ufs: ufs-mediatek: Support clk-scaling to optimize power consumption
Date: Wed, 3 Aug 2022 07:54:37 +0800 [thread overview]
Message-ID: <20220802235437.4547-6-stanley.chu@mediatek.com> (raw)
In-Reply-To: <20220802235437.4547-1-stanley.chu@mediatek.com>
From: Po-Wen Kao <powen.kao@mediatek.com>
Provide clk-scaling feature in MediaTek UFS platforms.
MediaTek platform supports clk-scaling by switching parent clock
mux of UFSHCI main clocks: ufs_sel.
The driver needs to prevent changing the rate of ufs_sel because
its parent PLL clock may be shared between multiple IPs. In order
to achieve this goal, the maximum and minimum clock rates of ufs_sel
defined in dts should match the rate of "ufs_sel_max_src" and
"ufs_sel_min_src" respectively.
Reviewed-by: Stanley Chu <stanley.chu@mediatek.com>
Signed-off-by: Po-Wen Kao <powen.kao@mediatek.com>
Signed-off-by: Stanley Chu <stanley.chu@mediatek.com>
---
drivers/ufs/host/ufs-mediatek-trace.h | 27 +++++-
drivers/ufs/host/ufs-mediatek.c | 121 ++++++++++++++++++++++++++
drivers/ufs/host/ufs-mediatek.h | 7 ++
3 files changed, 153 insertions(+), 2 deletions(-)
diff --git a/drivers/ufs/host/ufs-mediatek-trace.h b/drivers/ufs/host/ufs-mediatek-trace.h
index 7e010848dc99..b5f2ec314074 100644
--- a/drivers/ufs/host/ufs-mediatek-trace.h
+++ b/drivers/ufs/host/ufs-mediatek-trace.h
@@ -24,9 +24,32 @@ TRACE_EVENT(ufs_mtk_event,
__entry->data = data;
),
- TP_printk("ufs:event=%u data=%u",
+ TP_printk("ufs: event=%u data=%u",
__entry->type, __entry->data)
- );
+);
+
+TRACE_EVENT(ufs_mtk_clk_scale,
+ TP_PROTO(const char *name, bool scale_up, unsigned long clk_rate),
+ TP_ARGS(name, scale_up, clk_rate),
+
+ TP_STRUCT__entry(
+ __field(const char*, name)
+ __field(bool, scale_up)
+ __field(unsigned long, clk_rate)
+ ),
+
+ TP_fast_assign(
+ __entry->name = name;
+ __entry->scale_up = scale_up;
+ __entry->clk_rate = clk_rate;
+ ),
+
+ TP_printk("ufs: clk (%s) scaled %s @ %lu",
+ __entry->name,
+ __entry->scale_up ? "up" : "down",
+ __entry->clk_rate)
+);
+
#endif
#undef TRACE_INCLUDE_PATH
diff --git a/drivers/ufs/host/ufs-mediatek.c b/drivers/ufs/host/ufs-mediatek.c
index e1f131a93792..7309f3f87eac 100644
--- a/drivers/ufs/host/ufs-mediatek.c
+++ b/drivers/ufs/host/ufs-mediatek.c
@@ -738,6 +738,46 @@ static u32 ufs_mtk_get_ufs_hci_version(struct ufs_hba *hba)
return hba->ufs_version;
}
+/**
+ * ufs_mtk_init_clocks - Init mtk driver private clocks
+ *
+ * @hba: per adapter instance
+ */
+static void ufs_mtk_init_clocks(struct ufs_hba *hba)
+{
+ struct ufs_mtk_host *host = ufshcd_get_variant(hba);
+ struct list_head *head = &hba->clk_list_head;
+ struct ufs_mtk_clk *mclk = &host->mclk;
+ struct ufs_clk_info *clki, *clki_tmp;
+
+ /*
+ * Find private clocks and store them in struct ufs_mtk_clk.
+ * Remove "ufs_sel_min_src" and "ufs_sel_min_src" from list to avoid
+ * being switched on/off in clock gating.
+ */
+ list_for_each_entry_safe(clki, clki_tmp, head, list) {
+ if (!strcmp(clki->name, "ufs_sel")) {
+ host->mclk.ufs_sel_clki = clki;
+ } else if (!strcmp(clki->name, "ufs_sel_max_src")) {
+ host->mclk.ufs_sel_max_clki = clki;
+ clk_disable_unprepare(clki->clk);
+ list_del(&clki->list);
+ } else if (!strcmp(clki->name, "ufs_sel_min_src")) {
+ host->mclk.ufs_sel_min_clki = clki;
+ clk_disable_unprepare(clki->clk);
+ list_del(&clki->list);
+ }
+ }
+
+ if (!mclk->ufs_sel_clki || !mclk->ufs_sel_max_clki ||
+ !mclk->ufs_sel_min_clki) {
+ hba->caps &= ~UFSHCD_CAP_CLK_SCALING;
+ dev_info(hba->dev,
+ "%s: Clk-scaling not ready. Feature disabled.",
+ __func__);
+ }
+}
+
#define MAX_VCC_NAME 30
static int ufs_mtk_vreg_fix_vcc(struct ufs_hba *hba)
{
@@ -858,12 +898,18 @@ static int ufs_mtk_init(struct ufs_hba *hba)
/* Enable WriteBooster */
hba->caps |= UFSHCD_CAP_WB_EN;
+
+ /* Enable clk scaling*/
+ hba->caps |= UFSHCD_CAP_CLK_SCALING;
+
hba->quirks |= UFSHCI_QUIRK_SKIP_MANUAL_WB_FLUSH_CTRL;
hba->vps->wb_flush_threshold = UFS_WB_BUF_REMAIN_PERCENT(80);
if (host->caps & UFS_MTK_CAP_DISABLE_AH8)
hba->caps |= UFSHCD_CAP_HIBERN8_WITH_CLK_GATING;
+ ufs_mtk_init_clocks(hba);
+
/*
* ufshcd_vops_init() is invoked after
* ufshcd_setup_clock(true) in ufshcd_hba_init() thus
@@ -1384,6 +1430,79 @@ static void ufs_mtk_event_notify(struct ufs_hba *hba,
}
}
+static void ufs_mtk_config_scaling_param(struct ufs_hba *hba,
+ struct devfreq_dev_profile *profile,
+ struct devfreq_simple_ondemand_data *data)
+{
+ /* Customize min gear in clk scaling */
+ hba->clk_scaling.min_gear = UFS_HS_G4;
+
+ hba->vps->devfreq_profile.polling_ms = 200;
+ hba->vps->ondemand_data.upthreshold = 50;
+ hba->vps->ondemand_data.downdifferential = 20;
+}
+
+/**
+ * ufs_mtk_clk_scale - Internal clk scaling operation
+ *
+ * MTK platform supports clk scaling by switching parent of ufs_sel(mux).
+ * The ufs_sel downstream to ufs_ck which feeds directly to UFS hardware.
+ * Max and min clocks rate of ufs_sel defined in dts should match rate of
+ * "ufs_sel_max_src" and "ufs_sel_min_src" respectively.
+ * This prevent changing rate of pll clock that is shared between modules.
+ *
+ * @hba: per adapter instance
+ * @scale_up: True for scaling up and false for scaling down
+ */
+static void ufs_mtk_clk_scale(struct ufs_hba *hba, bool scale_up)
+{
+ struct ufs_mtk_host *host = ufshcd_get_variant(hba);
+ struct ufs_mtk_clk *mclk = &host->mclk;
+ struct ufs_clk_info *clki = mclk->ufs_sel_clki;
+ int ret = 0;
+
+ ret = clk_prepare_enable(clki->clk);
+ if (ret) {
+ dev_info(hba->dev,
+ "clk_prepare_enable() fail, ret: %d\n", ret);
+ return;
+ }
+
+ if (scale_up) {
+ ret = clk_set_parent(clki->clk, mclk->ufs_sel_max_clki->clk);
+ clki->curr_freq = clki->max_freq;
+ } else {
+ ret = clk_set_parent(clki->clk, mclk->ufs_sel_min_clki->clk);
+ clki->curr_freq = clki->min_freq;
+ }
+
+ if (ret) {
+ dev_info(hba->dev,
+ "Failed to set ufs_sel_clki, ret: %d\n", ret);
+ }
+
+ clk_disable_unprepare(clki->clk);
+
+ trace_ufs_mtk_clk_scale(clki->name, scale_up, clk_get_rate(clki->clk));
+}
+
+static int ufs_mtk_clk_scale_notify(struct ufs_hba *hba, bool scale_up,
+ enum ufs_notify_change_status status)
+{
+ if (!ufshcd_is_clkscaling_supported(hba))
+ return 0;
+
+ if (status == PRE_CHANGE) {
+ /* Switch parent before clk_set_rate() */
+ ufs_mtk_clk_scale(hba, scale_up);
+ } else {
+ /* Request interrupt latency QoS accordingly */
+ ufs_mtk_scale_perf(hba, scale_up);
+ }
+
+ return 0;
+}
+
/*
* struct ufs_hba_mtk_vops - UFS MTK specific variant operations
*
@@ -1405,6 +1524,8 @@ static const struct ufs_hba_variant_ops ufs_hba_mtk_vops = {
.dbg_register_dump = ufs_mtk_dbg_register_dump,
.device_reset = ufs_mtk_device_reset,
.event_notify = ufs_mtk_event_notify,
+ .config_scaling_param = ufs_mtk_config_scaling_param,
+ .clk_scale_notify = ufs_mtk_clk_scale_notify,
};
/**
diff --git a/drivers/ufs/host/ufs-mediatek.h b/drivers/ufs/host/ufs-mediatek.h
index aa26d415527b..2fc6d7b87694 100644
--- a/drivers/ufs/host/ufs-mediatek.h
+++ b/drivers/ufs/host/ufs-mediatek.h
@@ -124,6 +124,12 @@ struct ufs_mtk_crypt_cfg {
int vcore_volt;
};
+struct ufs_mtk_clk {
+ struct ufs_clk_info *ufs_sel_clki; /* Mux */
+ struct ufs_clk_info *ufs_sel_max_clki; /* Max src */
+ struct ufs_clk_info *ufs_sel_min_clki; /* Min src */
+};
+
struct ufs_mtk_hw_ver {
u8 step;
u8 minor;
@@ -139,6 +145,7 @@ struct ufs_mtk_host {
struct reset_control *crypto_reset;
struct ufs_hba *hba;
struct ufs_mtk_crypt_cfg *crypt;
+ struct ufs_mtk_clk mclk;
struct ufs_mtk_hw_ver hw_ver;
enum ufs_mtk_host_caps caps;
bool mphy_powered_on;
--
2.18.0
next prev parent reply other threads:[~2022-08-02 23:55 UTC|newest]
Thread overview: 7+ messages / expand[flat|nested] mbox.gz Atom feed top
2022-08-02 23:54 [PATCH v5 0/5] scsi: ufs-mediatek: Provide features and fixes in MediaTek platforms Stanley Chu
2022-08-02 23:54 ` [PATCH v5 1/5] scsi: ufs: ufs-mediatek: Remove redundant header files Stanley Chu
2022-08-02 23:54 ` [PATCH v5 2/5] scsi: ufs: ufs-mediatek: Provide detailed description for UIC errors Stanley Chu
2022-08-02 23:54 ` [PATCH v5 3/5] scsi: ufs: ufs-mediatek: Dump more registers Stanley Chu
2022-08-02 23:54 ` [PATCH v5 4/5] scsi: ufs: ufs-mediatek: Fix performance scaling Stanley Chu
2022-08-02 23:54 ` Stanley Chu [this message]
2022-08-23 2:59 ` [PATCH v5 0/5] scsi: ufs-mediatek: Provide features and fixes in MediaTek platforms Martin K. Petersen
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20220802235437.4547-6-stanley.chu@mediatek.com \
--to=stanley.chu@mediatek.com \
--cc=alice.chao@mediatek.com \
--cc=alim.akhtar@samsung.com \
--cc=avri.altman@wdc.com \
--cc=bvanassche@acm.org \
--cc=cc.chou@mediatek.com \
--cc=chaotian.jing@mediatek.com \
--cc=chun-hung.wu@mediatek.com \
--cc=eddie.huang@mediatek.com \
--cc=jejb@linux.ibm.com \
--cc=jiajie.hao@mediatek.com \
--cc=lin.gui@mediatek.com \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-scsi@vger.kernel.org \
--cc=martin.petersen@oracle.com \
--cc=mason.zhang@mediatek.com \
--cc=peter.wang@mediatek.com \
--cc=powen.kao@mediatek.com \
--cc=qilin.tan@mediatek.com \
--cc=tun-yu.yu@mediatek.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).