Skip to content

Commit 03ce80a

Browse files
Mani-Sadhasivammartinkpetersen
authored andcommitted
scsi: ufs: qcom: Add support for scaling interconnects
Qcom SoCs require scaling the interconnect paths for proper working of the peripherals connected through interconnects. Even for accessing the UFS controller, someone should setup the interconnect paths. So far, the bootloaders used to setup the interconnect paths before booting Linux as they need to access the UFS storage for things like fetching boot firmware. But with the advent of multi boot options, bootloader nowadays like in SA8540p SoC do not setup the interconnect paths at all. So trying to configure UFS in the absence of the interconnect path configuration results in a boot crash. To fix this issue, and also to dynamically scale the interconnects (UFS-DDR and CPU-UFS), interconnect API support is added to the Qcom UFS driver. With this support, the interconnect paths are scaled dynamically based on the gear configuration. During the early stage of ufs_qcom_init(), ufs_qcom_icc_init() will setup the paths to max bandwidth to allow configuring the UFS registers. Touching the registers without configuring the icc paths would result in a crash. However, we don't really need to set max vote for the icc paths as any minimal vote would suffice. But the max value would allow initialization to be done faster. After init, the bandwidth will get updated using ufs_qcom_icc_update_bw() based on the gear and lane configuration. The bandwidth values defined in ufs_qcom_bw_table struct are taken from Qcom downstream vendor devicetree source and are calculated as per the UFS3.1 Spec, Section 6.4.1, HS Gear Rates. So it is fixed across platforms. Cc: Brian Masney <[email protected]> Signed-off-by: Manivannan Sadhasivam <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Martin K. Petersen <[email protected]>
1 parent e0d01da commit 03ce80a

File tree

2 files changed

+133
-1
lines changed

2 files changed

+133
-1
lines changed

drivers/ufs/host/ufs-qcom.c

Lines changed: 130 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
#include <linux/time.h>
88
#include <linux/clk.h>
99
#include <linux/delay.h>
10+
#include <linux/interconnect.h>
1011
#include <linux/module.h>
1112
#include <linux/of.h>
1213
#include <linux/platform_device.h>
@@ -46,6 +47,49 @@ enum {
4647
TSTBUS_MAX,
4748
};
4849

50+
#define QCOM_UFS_MAX_GEAR 4
51+
#define QCOM_UFS_MAX_LANE 2
52+
53+
enum {
54+
MODE_MIN,
55+
MODE_PWM,
56+
MODE_HS_RA,
57+
MODE_HS_RB,
58+
MODE_MAX,
59+
};
60+
61+
struct __ufs_qcom_bw_table {
62+
u32 mem_bw;
63+
u32 cfg_bw;
64+
} ufs_qcom_bw_table[MODE_MAX + 1][QCOM_UFS_MAX_GEAR + 1][QCOM_UFS_MAX_LANE + 1] = {
65+
[MODE_MIN][0][0] = { 0, 0 }, /* Bandwidth values in KB/s */
66+
[MODE_PWM][UFS_PWM_G1][UFS_LANE_1] = { 922, 1000 },
67+
[MODE_PWM][UFS_PWM_G2][UFS_LANE_1] = { 1844, 1000 },
68+
[MODE_PWM][UFS_PWM_G3][UFS_LANE_1] = { 3688, 1000 },
69+
[MODE_PWM][UFS_PWM_G4][UFS_LANE_1] = { 7376, 1000 },
70+
[MODE_PWM][UFS_PWM_G1][UFS_LANE_2] = { 1844, 1000 },
71+
[MODE_PWM][UFS_PWM_G2][UFS_LANE_2] = { 3688, 1000 },
72+
[MODE_PWM][UFS_PWM_G3][UFS_LANE_2] = { 7376, 1000 },
73+
[MODE_PWM][UFS_PWM_G4][UFS_LANE_2] = { 14752, 1000 },
74+
[MODE_HS_RA][UFS_HS_G1][UFS_LANE_1] = { 127796, 1000 },
75+
[MODE_HS_RA][UFS_HS_G2][UFS_LANE_1] = { 255591, 1000 },
76+
[MODE_HS_RA][UFS_HS_G3][UFS_LANE_1] = { 1492582, 102400 },
77+
[MODE_HS_RA][UFS_HS_G4][UFS_LANE_1] = { 2915200, 204800 },
78+
[MODE_HS_RA][UFS_HS_G1][UFS_LANE_2] = { 255591, 1000 },
79+
[MODE_HS_RA][UFS_HS_G2][UFS_LANE_2] = { 511181, 1000 },
80+
[MODE_HS_RA][UFS_HS_G3][UFS_LANE_2] = { 1492582, 204800 },
81+
[MODE_HS_RA][UFS_HS_G4][UFS_LANE_2] = { 2915200, 409600 },
82+
[MODE_HS_RB][UFS_HS_G1][UFS_LANE_1] = { 149422, 1000 },
83+
[MODE_HS_RB][UFS_HS_G2][UFS_LANE_1] = { 298189, 1000 },
84+
[MODE_HS_RB][UFS_HS_G3][UFS_LANE_1] = { 1492582, 102400 },
85+
[MODE_HS_RB][UFS_HS_G4][UFS_LANE_1] = { 2915200, 204800 },
86+
[MODE_HS_RB][UFS_HS_G1][UFS_LANE_2] = { 298189, 1000 },
87+
[MODE_HS_RB][UFS_HS_G2][UFS_LANE_2] = { 596378, 1000 },
88+
[MODE_HS_RB][UFS_HS_G3][UFS_LANE_2] = { 1492582, 204800 },
89+
[MODE_HS_RB][UFS_HS_G4][UFS_LANE_2] = { 2915200, 409600 },
90+
[MODE_MAX][0][0] = { 7643136, 307200 },
91+
};
92+
4993
static struct ufs_qcom_host *ufs_qcom_hosts[MAX_UFS_QCOM_HOSTS];
5094

5195
static void ufs_qcom_get_default_testbus_cfg(struct ufs_qcom_host *host);
@@ -789,6 +833,51 @@ static void ufs_qcom_dev_ref_clk_ctrl(struct ufs_qcom_host *host, bool enable)
789833
}
790834
}
791835

836+
static int ufs_qcom_icc_set_bw(struct ufs_qcom_host *host, u32 mem_bw, u32 cfg_bw)
837+
{
838+
struct device *dev = host->hba->dev;
839+
int ret;
840+
841+
ret = icc_set_bw(host->icc_ddr, 0, mem_bw);
842+
if (ret < 0) {
843+
dev_err(dev, "failed to set bandwidth request: %d\n", ret);
844+
return ret;
845+
}
846+
847+
ret = icc_set_bw(host->icc_cpu, 0, cfg_bw);
848+
if (ret < 0) {
849+
dev_err(dev, "failed to set bandwidth request: %d\n", ret);
850+
return ret;
851+
}
852+
853+
return 0;
854+
}
855+
856+
static struct __ufs_qcom_bw_table ufs_qcom_get_bw_table(struct ufs_qcom_host *host)
857+
{
858+
struct ufs_pa_layer_attr *p = &host->dev_req_params;
859+
int gear = max_t(u32, p->gear_rx, p->gear_tx);
860+
int lane = max_t(u32, p->lane_rx, p->lane_tx);
861+
862+
if (ufshcd_is_hs_mode(p)) {
863+
if (p->hs_rate == PA_HS_MODE_B)
864+
return ufs_qcom_bw_table[MODE_HS_RB][gear][lane];
865+
else
866+
return ufs_qcom_bw_table[MODE_HS_RA][gear][lane];
867+
} else {
868+
return ufs_qcom_bw_table[MODE_PWM][gear][lane];
869+
}
870+
}
871+
872+
static int ufs_qcom_icc_update_bw(struct ufs_qcom_host *host)
873+
{
874+
struct __ufs_qcom_bw_table bw_table;
875+
876+
bw_table = ufs_qcom_get_bw_table(host);
877+
878+
return ufs_qcom_icc_set_bw(host, bw_table.mem_bw, bw_table.cfg_bw);
879+
}
880+
792881
static int ufs_qcom_pwr_change_notify(struct ufs_hba *hba,
793882
enum ufs_notify_change_status status,
794883
struct ufs_pa_layer_attr *dev_max_params,
@@ -852,6 +941,8 @@ static int ufs_qcom_pwr_change_notify(struct ufs_hba *hba,
852941
memcpy(&host->dev_req_params,
853942
dev_req_params, sizeof(*dev_req_params));
854943

944+
ufs_qcom_icc_update_bw(host);
945+
855946
/* disable the device ref clock if entered PWM mode */
856947
if (ufshcd_is_hs_mode(&hba->pwr_info) &&
857948
!ufshcd_is_hs_mode(dev_req_params))
@@ -981,7 +1072,9 @@ static int ufs_qcom_setup_clocks(struct ufs_hba *hba, bool on,
9811072

9821073
switch (status) {
9831074
case PRE_CHANGE:
984-
if (!on) {
1075+
if (on) {
1076+
ufs_qcom_icc_update_bw(host);
1077+
} else {
9851078
if (!ufs_qcom_is_link_active(hba)) {
9861079
/* disable device ref_clk */
9871080
ufs_qcom_dev_ref_clk_ctrl(host, false);
@@ -993,6 +1086,9 @@ static int ufs_qcom_setup_clocks(struct ufs_hba *hba, bool on,
9931086
/* enable the device ref clock for HS mode*/
9941087
if (ufshcd_is_hs_mode(&hba->pwr_info))
9951088
ufs_qcom_dev_ref_clk_ctrl(host, true);
1089+
} else {
1090+
ufs_qcom_icc_set_bw(host, ufs_qcom_bw_table[MODE_MIN][0][0].mem_bw,
1091+
ufs_qcom_bw_table[MODE_MIN][0][0].cfg_bw);
9961092
}
9971093
break;
9981094
}
@@ -1031,6 +1127,34 @@ static const struct reset_control_ops ufs_qcom_reset_ops = {
10311127
.deassert = ufs_qcom_reset_deassert,
10321128
};
10331129

1130+
static int ufs_qcom_icc_init(struct ufs_qcom_host *host)
1131+
{
1132+
struct device *dev = host->hba->dev;
1133+
int ret;
1134+
1135+
host->icc_ddr = devm_of_icc_get(dev, "ufs-ddr");
1136+
if (IS_ERR(host->icc_ddr))
1137+
return dev_err_probe(dev, PTR_ERR(host->icc_ddr),
1138+
"failed to acquire interconnect path\n");
1139+
1140+
host->icc_cpu = devm_of_icc_get(dev, "cpu-ufs");
1141+
if (IS_ERR(host->icc_cpu))
1142+
return dev_err_probe(dev, PTR_ERR(host->icc_cpu),
1143+
"failed to acquire interconnect path\n");
1144+
1145+
/*
1146+
* Set Maximum bandwidth vote before initializing the UFS controller and
1147+
* device. Ideally, a minimal interconnect vote would suffice for the
1148+
* initialization, but a max vote would allow faster initialization.
1149+
*/
1150+
ret = ufs_qcom_icc_set_bw(host, ufs_qcom_bw_table[MODE_MAX][0][0].mem_bw,
1151+
ufs_qcom_bw_table[MODE_MAX][0][0].cfg_bw);
1152+
if (ret < 0)
1153+
return dev_err_probe(dev, ret, "failed to set bandwidth request\n");
1154+
1155+
return 0;
1156+
}
1157+
10341158
/**
10351159
* ufs_qcom_init - bind phy with controller
10361160
* @hba: host controller instance
@@ -1085,6 +1209,10 @@ static int ufs_qcom_init(struct ufs_hba *hba)
10851209
}
10861210
}
10871211

1212+
err = ufs_qcom_icc_init(host);
1213+
if (err)
1214+
goto out_variant_clear;
1215+
10881216
host->device_reset = devm_gpiod_get_optional(dev, "reset",
10891217
GPIOD_OUT_HIGH);
10901218
if (IS_ERR(host->device_reset)) {
@@ -1282,6 +1410,7 @@ static int ufs_qcom_clk_scale_notify(struct ufs_hba *hba,
12821410
dev_req_params->pwr_rx,
12831411
dev_req_params->hs_rate,
12841412
false);
1413+
ufs_qcom_icc_update_bw(host);
12851414
ufshcd_uic_hibern8_exit(hba);
12861415
}
12871416

drivers/ufs/host/ufs-qcom.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -206,6 +206,9 @@ struct ufs_qcom_host {
206206
struct clk *tx_l1_sync_clk;
207207
bool is_lane_clks_enabled;
208208

209+
struct icc_path *icc_ddr;
210+
struct icc_path *icc_cpu;
211+
209212
#ifdef CONFIG_SCSI_UFS_CRYPTO
210213
struct qcom_ice *ice;
211214
#endif

0 commit comments

Comments
 (0)