Skip to content

Commit 8c5bcb3

Browse files
quic-cangmartinkpetersen
authored andcommitted
scsi: ufs: qcom: Map devfreq OPP freq to UniPro Core Clock freq
On some platforms, the devfreq OPP freq may be different than the unipro core clock freq. Implement ufs_qcom_opp_freq_to_clk_freq() and use it to find the unipro core clk freq. Fixes: c02fe9e ("scsi: ufs: qcom: Implement the freq_to_gear_speed() vop") Signed-off-by: Can Guo <quic_cang@quicinc.com> Co-developed-by: Ziqi Chen <quic_ziqichen@quicinc.com> Signed-off-by: Ziqi Chen <quic_ziqichen@quicinc.com> Link: https://lore.kernel.org/r/20250522021537.999107-3-quic_ziqichen@quicinc.com Reported-by: Luca Weiss <luca.weiss@fairphone.com> Closes: https://lore.kernel.org/linux-arm-msm/D9FZ9U3AEXW4.1I12FX3YQ3JPW@fairphone.com/ Tested-by: Luca Weiss <luca.weiss@fairphone.com> Reviewed-by: Bean Huo <beanhuo@micron.com> Tested-by: Loïc Minier <loic.minier@oss.qualcomm.com> Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
1 parent 663d0c1 commit 8c5bcb3

File tree

1 file changed

+71
-10
lines changed

1 file changed

+71
-10
lines changed

drivers/ufs/host/ufs-qcom.c

Lines changed: 71 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -122,7 +122,9 @@ static const struct {
122122
};
123123

124124
static void ufs_qcom_get_default_testbus_cfg(struct ufs_qcom_host *host);
125-
static int ufs_qcom_set_core_clk_ctrl(struct ufs_hba *hba, unsigned long freq);
125+
static unsigned long ufs_qcom_opp_freq_to_clk_freq(struct ufs_hba *hba,
126+
unsigned long freq, char *name);
127+
static int ufs_qcom_set_core_clk_ctrl(struct ufs_hba *hba, bool is_scale_up, unsigned long freq);
126128

127129
static struct ufs_qcom_host *rcdev_to_ufs_host(struct reset_controller_dev *rcd)
128130
{
@@ -656,7 +658,7 @@ static int ufs_qcom_link_startup_notify(struct ufs_hba *hba,
656658
return -EINVAL;
657659
}
658660

659-
err = ufs_qcom_set_core_clk_ctrl(hba, ULONG_MAX);
661+
err = ufs_qcom_set_core_clk_ctrl(hba, true, ULONG_MAX);
660662
if (err)
661663
dev_err(hba->dev, "cfg core clk ctrl failed\n");
662664
/*
@@ -1414,29 +1416,46 @@ static int ufs_qcom_set_clk_40ns_cycles(struct ufs_hba *hba,
14141416
return ufshcd_dme_set(hba, UIC_ARG_MIB(PA_VS_CORE_CLK_40NS_CYCLES), reg);
14151417
}
14161418

1417-
static int ufs_qcom_set_core_clk_ctrl(struct ufs_hba *hba, unsigned long freq)
1419+
static int ufs_qcom_set_core_clk_ctrl(struct ufs_hba *hba, bool is_scale_up, unsigned long freq)
14181420
{
14191421
struct ufs_qcom_host *host = ufshcd_get_variant(hba);
14201422
struct list_head *head = &hba->clk_list_head;
14211423
struct ufs_clk_info *clki;
14221424
u32 cycles_in_1us = 0;
14231425
u32 core_clk_ctrl_reg;
1426+
unsigned long clk_freq;
14241427
int err;
14251428

1429+
if (hba->use_pm_opp && freq != ULONG_MAX) {
1430+
clk_freq = ufs_qcom_opp_freq_to_clk_freq(hba, freq, "core_clk_unipro");
1431+
if (clk_freq) {
1432+
cycles_in_1us = ceil(clk_freq, HZ_PER_MHZ);
1433+
goto set_core_clk_ctrl;
1434+
}
1435+
}
1436+
14261437
list_for_each_entry(clki, head, list) {
14271438
if (!IS_ERR_OR_NULL(clki->clk) &&
14281439
!strcmp(clki->name, "core_clk_unipro")) {
1429-
if (!clki->max_freq)
1440+
if (!clki->max_freq) {
14301441
cycles_in_1us = 150; /* default for backwards compatibility */
1431-
else if (freq == ULONG_MAX)
1442+
break;
1443+
}
1444+
1445+
if (freq == ULONG_MAX) {
14321446
cycles_in_1us = ceil(clki->max_freq, HZ_PER_MHZ);
1433-
else
1434-
cycles_in_1us = ceil(freq, HZ_PER_MHZ);
1447+
break;
1448+
}
14351449

1450+
if (is_scale_up)
1451+
cycles_in_1us = ceil(clki->max_freq, HZ_PER_MHZ);
1452+
else
1453+
cycles_in_1us = ceil(clk_get_rate(clki->clk), HZ_PER_MHZ);
14361454
break;
14371455
}
14381456
}
14391457

1458+
set_core_clk_ctrl:
14401459
err = ufshcd_dme_get(hba,
14411460
UIC_ARG_MIB(DME_VS_CORE_CLK_CTRL),
14421461
&core_clk_ctrl_reg);
@@ -1479,7 +1498,7 @@ static int ufs_qcom_clk_scale_up_pre_change(struct ufs_hba *hba, unsigned long f
14791498
return ret;
14801499
}
14811500
/* set unipro core clock attributes and clear clock divider */
1482-
return ufs_qcom_set_core_clk_ctrl(hba, freq);
1501+
return ufs_qcom_set_core_clk_ctrl(hba, true, freq);
14831502
}
14841503

14851504
static int ufs_qcom_clk_scale_up_post_change(struct ufs_hba *hba)
@@ -1511,7 +1530,7 @@ static int ufs_qcom_clk_scale_down_pre_change(struct ufs_hba *hba)
15111530
static int ufs_qcom_clk_scale_down_post_change(struct ufs_hba *hba, unsigned long freq)
15121531
{
15131532
/* set unipro core clock attributes and clear clock divider */
1514-
return ufs_qcom_set_core_clk_ctrl(hba, freq);
1533+
return ufs_qcom_set_core_clk_ctrl(hba, false, freq);
15151534
}
15161535

15171536
static int ufs_qcom_clk_scale_notify(struct ufs_hba *hba, bool scale_up,
@@ -2081,11 +2100,53 @@ static int ufs_qcom_config_esi(struct ufs_hba *hba)
20812100
return ret;
20822101
}
20832102

2103+
static unsigned long ufs_qcom_opp_freq_to_clk_freq(struct ufs_hba *hba,
2104+
unsigned long freq, char *name)
2105+
{
2106+
struct ufs_clk_info *clki;
2107+
struct dev_pm_opp *opp;
2108+
unsigned long clk_freq;
2109+
int idx = 0;
2110+
bool found = false;
2111+
2112+
opp = dev_pm_opp_find_freq_exact_indexed(hba->dev, freq, 0, true);
2113+
if (IS_ERR(opp)) {
2114+
dev_err(hba->dev, "Failed to find OPP for exact frequency %lu\n", freq);
2115+
return 0;
2116+
}
2117+
2118+
list_for_each_entry(clki, &hba->clk_list_head, list) {
2119+
if (!strcmp(clki->name, name)) {
2120+
found = true;
2121+
break;
2122+
}
2123+
2124+
idx++;
2125+
}
2126+
2127+
if (!found) {
2128+
dev_err(hba->dev, "Failed to find clock '%s' in clk list\n", name);
2129+
dev_pm_opp_put(opp);
2130+
return 0;
2131+
}
2132+
2133+
clk_freq = dev_pm_opp_get_freq_indexed(opp, idx);
2134+
2135+
dev_pm_opp_put(opp);
2136+
2137+
return clk_freq;
2138+
}
2139+
20842140
static u32 ufs_qcom_freq_to_gear_speed(struct ufs_hba *hba, unsigned long freq)
20852141
{
20862142
u32 gear = UFS_HS_DONT_CHANGE;
2143+
unsigned long unipro_freq;
2144+
2145+
if (!hba->use_pm_opp)
2146+
return gear;
20872147

2088-
switch (freq) {
2148+
unipro_freq = ufs_qcom_opp_freq_to_clk_freq(hba, freq, "core_clk_unipro");
2149+
switch (unipro_freq) {
20892150
case 403000000:
20902151
gear = UFS_HS_G5;
20912152
break;

0 commit comments

Comments
 (0)