Skip to content

Commit 17d1194

Browse files
Merge patch series "scsi: ufs: qcom: Align programming sequence as per HW spec"
Nitin Rawat <[email protected]> says: This patch series adds programming support for Qualcomm UFS V4 and above to align avoid with Hardware Specification. This patch series will address stability and performance issues. In this patch series below changes are taken care. 1) Register layout for DME_VS_CORE_CLK_CTRL has changed for v4 and above. 2) Adds Support to configure PA_VS_CORE_CLK_40NS_CYCLES attibute for UFS V4 and above. 3) Adds Support to configure multiple unipro frequencies like 403MHz, 300MHz, 202MHz, 150 MHz, 75Mhz, 37.5 MHz for Qualcomm UFS Controller V4 and above. 4) Allow configuration of SYS1CLK_1US_REG for UFS V4 and above. Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Martin K. Petersen <[email protected]>
2 parents b0597fd + 5a738cf commit 17d1194

File tree

3 files changed

+187
-51
lines changed

3 files changed

+187
-51
lines changed

drivers/ufs/core/ufshcd.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8722,7 +8722,8 @@ static int ufshcd_probe_hba(struct ufs_hba *hba, bool init_dev_params)
87228722
if (ret)
87238723
goto out;
87248724

8725-
if (hba->quirks & UFSHCD_QUIRK_REINIT_AFTER_MAX_GEAR_SWITCH) {
8725+
if (!hba->pm_op_in_progress &&
8726+
(hba->quirks & UFSHCD_QUIRK_REINIT_AFTER_MAX_GEAR_SWITCH)) {
87268727
/* Reset the device and controller before doing reinit */
87278728
ufshcd_device_reset(hba);
87288729
ufshcd_hba_stop(hba);

drivers/ufs/host/ufs-qcom.c

Lines changed: 168 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -93,8 +93,7 @@ static const struct __ufs_qcom_bw_table {
9393
static struct ufs_qcom_host *ufs_qcom_hosts[MAX_UFS_QCOM_HOSTS];
9494

9595
static void ufs_qcom_get_default_testbus_cfg(struct ufs_qcom_host *host);
96-
static int ufs_qcom_set_dme_vs_core_clk_ctrl_clear_div(struct ufs_hba *hba,
97-
u32 clk_cycles);
96+
static int ufs_qcom_set_core_clk_ctrl(struct ufs_hba *hba, bool is_scale_up);
9897

9998
static struct ufs_qcom_host *rcdev_to_ufs_host(struct reset_controller_dev *rcd)
10099
{
@@ -460,7 +459,7 @@ static int ufs_qcom_power_up_sequence(struct ufs_hba *hba)
460459
return ret;
461460
}
462461

463-
phy_set_mode_ext(phy, PHY_MODE_UFS_HS_B, host->hs_gear);
462+
phy_set_mode_ext(phy, PHY_MODE_UFS_HS_B, host->phy_gear);
464463

465464
/* power on phy - start serdes and phy's power and clocks */
466465
ret = phy_power_on(phy);
@@ -528,11 +527,20 @@ static int ufs_qcom_hce_enable_notify(struct ufs_hba *hba,
528527
return err;
529528
}
530529

531-
/*
530+
/**
531+
* ufs_qcom_cfg_timers - Configure ufs qcom cfg timers
532+
*
533+
* @hba: host controller instance
534+
* @gear: Current operating gear
535+
* @hs: current power mode
536+
* @rate: current operating rate (A or B)
537+
* @update_link_startup_timer: indicate if link_start ongoing
538+
* @is_pre_scale_up: flag to check if pre scale up condition.
532539
* Return: zero for success and non-zero in case of a failure.
533540
*/
534541
static int ufs_qcom_cfg_timers(struct ufs_hba *hba, u32 gear,
535-
u32 hs, u32 rate, bool update_link_startup_timer)
542+
u32 hs, u32 rate, bool update_link_startup_timer,
543+
bool is_pre_scale_up)
536544
{
537545
struct ufs_qcom_host *host = ufshcd_get_variant(hba);
538546
struct ufs_clk_info *clki;
@@ -563,11 +571,14 @@ static int ufs_qcom_cfg_timers(struct ufs_hba *hba, u32 gear,
563571
/*
564572
* The Qunipro controller does not use following registers:
565573
* SYS1CLK_1US_REG, TX_SYMBOL_CLK_1US_REG, CLK_NS_REG &
566-
* UFS_REG_PA_LINK_STARTUP_TIMER
567-
* But UTP controller uses SYS1CLK_1US_REG register for Interrupt
574+
* UFS_REG_PA_LINK_STARTUP_TIMER.
575+
* However UTP controller uses SYS1CLK_1US_REG register for Interrupt
568576
* Aggregation logic.
569-
*/
570-
if (ufs_qcom_cap_qunipro(host) && !ufshcd_is_intr_aggr_allowed(hba))
577+
* It is mandatory to write SYS1CLK_1US_REG register on UFS host
578+
* controller V4.0.0 onwards.
579+
*/
580+
if (host->hw_ver.major < 4 && ufs_qcom_cap_qunipro(host) &&
581+
!ufshcd_is_intr_aggr_allowed(hba))
571582
return 0;
572583

573584
if (gear == 0) {
@@ -576,8 +587,14 @@ static int ufs_qcom_cfg_timers(struct ufs_hba *hba, u32 gear,
576587
}
577588

578589
list_for_each_entry(clki, &hba->clk_list_head, list) {
579-
if (!strcmp(clki->name, "core_clk"))
580-
core_clk_rate = clk_get_rate(clki->clk);
590+
if (!strcmp(clki->name, "core_clk")) {
591+
if (is_pre_scale_up)
592+
core_clk_rate = clki->max_freq;
593+
else
594+
core_clk_rate = clk_get_rate(clki->clk);
595+
break;
596+
}
597+
581598
}
582599

583600
/* If frequency is smaller than 1MHz, set to 1MHz */
@@ -679,20 +696,17 @@ static int ufs_qcom_link_startup_notify(struct ufs_hba *hba,
679696
switch (status) {
680697
case PRE_CHANGE:
681698
if (ufs_qcom_cfg_timers(hba, UFS_PWM_G1, SLOWAUTO_MODE,
682-
0, true)) {
699+
0, true, false)) {
683700
dev_err(hba->dev, "%s: ufs_qcom_cfg_timers() failed\n",
684701
__func__);
685702
return -EINVAL;
686703
}
687704

688-
if (ufs_qcom_cap_qunipro(host))
689-
/*
690-
* set unipro core clock cycles to 150 & clear clock
691-
* divider
692-
*/
693-
err = ufs_qcom_set_dme_vs_core_clk_ctrl_clear_div(hba,
694-
150);
695-
705+
if (ufs_qcom_cap_qunipro(host)) {
706+
err = ufs_qcom_set_core_clk_ctrl(hba, true);
707+
if (err)
708+
dev_err(hba->dev, "cfg core clk ctrl failed\n");
709+
}
696710
/*
697711
* Some UFS devices (and may be host) have issues if LCC is
698712
* enabled. So we are setting PA_Local_TX_LCC_Enable to 0
@@ -909,8 +923,13 @@ static int ufs_qcom_pwr_change_notify(struct ufs_hba *hba,
909923
return ret;
910924
}
911925

912-
/* Use the agreed gear */
913-
host->hs_gear = dev_req_params->gear_tx;
926+
/*
927+
* Update phy_gear only when the gears are scaled to a higher value. This is
928+
* because, the PHY gear settings are backwards compatible and we only need to
929+
* change the PHY gear settings while scaling to higher gears.
930+
*/
931+
if (dev_req_params->gear_tx > host->phy_gear)
932+
host->phy_gear = dev_req_params->gear_tx;
914933

915934
/* enable the device ref clock before changing to HS mode */
916935
if (!ufshcd_is_hs_mode(&hba->pwr_info) &&
@@ -926,7 +945,7 @@ static int ufs_qcom_pwr_change_notify(struct ufs_hba *hba,
926945
case POST_CHANGE:
927946
if (ufs_qcom_cfg_timers(hba, dev_req_params->gear_rx,
928947
dev_req_params->pwr_rx,
929-
dev_req_params->hs_rate, false)) {
948+
dev_req_params->hs_rate, false, false)) {
930949
dev_err(hba->dev, "%s: ufs_qcom_cfg_timers() failed\n",
931950
__func__);
932951
/*
@@ -1277,7 +1296,7 @@ static int ufs_qcom_init(struct ufs_hba *hba)
12771296
* Power up the PHY using the minimum supported gear (UFS_HS_G2).
12781297
* Switching to max gear will be performed during reinit if supported.
12791298
*/
1280-
host->hs_gear = UFS_HS_G2;
1299+
host->phy_gear = UFS_HS_G2;
12811300

12821301
return 0;
12831302

@@ -1296,47 +1315,155 @@ static void ufs_qcom_exit(struct ufs_hba *hba)
12961315
phy_exit(host->generic_phy);
12971316
}
12981317

1299-
static int ufs_qcom_set_dme_vs_core_clk_ctrl_clear_div(struct ufs_hba *hba,
1300-
u32 clk_cycles)
1318+
/**
1319+
* ufs_qcom_set_clk_40ns_cycles - Configure 40ns clk cycles
1320+
*
1321+
* @hba: host controller instance
1322+
* @cycles_in_1us: No of cycles in 1us to be configured
1323+
*
1324+
* Returns error if dme get/set configuration for 40ns fails
1325+
* and returns zero on success.
1326+
*/
1327+
static int ufs_qcom_set_clk_40ns_cycles(struct ufs_hba *hba,
1328+
u32 cycles_in_1us)
13011329
{
1330+
struct ufs_qcom_host *host = ufshcd_get_variant(hba);
1331+
u32 cycles_in_40ns;
1332+
u32 reg;
13021333
int err;
1303-
u32 core_clk_ctrl_reg;
13041334

1305-
if (clk_cycles > DME_VS_CORE_CLK_CTRL_MAX_CORE_CLK_1US_CYCLES_MASK)
1335+
/*
1336+
* UFS host controller V4.0.0 onwards needs to program
1337+
* PA_VS_CORE_CLK_40NS_CYCLES attribute per programmed
1338+
* frequency of unipro core clk of UFS host controller.
1339+
*/
1340+
if (host->hw_ver.major < 4)
1341+
return 0;
1342+
1343+
/*
1344+
* Generic formulae for cycles_in_40ns = (freq_unipro/25) is not
1345+
* applicable for all frequencies. For ex: ceil(37.5 MHz/25) will
1346+
* be 2 and ceil(403 MHZ/25) will be 17 whereas Hardware
1347+
* specification expect to be 16. Hence use exact hardware spec
1348+
* mandated value for cycles_in_40ns instead of calculating using
1349+
* generic formulae.
1350+
*/
1351+
switch (cycles_in_1us) {
1352+
case UNIPRO_CORE_CLK_FREQ_403_MHZ:
1353+
cycles_in_40ns = 16;
1354+
break;
1355+
case UNIPRO_CORE_CLK_FREQ_300_MHZ:
1356+
cycles_in_40ns = 12;
1357+
break;
1358+
case UNIPRO_CORE_CLK_FREQ_201_5_MHZ:
1359+
cycles_in_40ns = 8;
1360+
break;
1361+
case UNIPRO_CORE_CLK_FREQ_150_MHZ:
1362+
cycles_in_40ns = 6;
1363+
break;
1364+
case UNIPRO_CORE_CLK_FREQ_100_MHZ:
1365+
cycles_in_40ns = 4;
1366+
break;
1367+
case UNIPRO_CORE_CLK_FREQ_75_MHZ:
1368+
cycles_in_40ns = 3;
1369+
break;
1370+
case UNIPRO_CORE_CLK_FREQ_37_5_MHZ:
1371+
cycles_in_40ns = 2;
1372+
break;
1373+
default:
1374+
dev_err(hba->dev, "UNIPRO clk freq %u MHz not supported\n",
1375+
cycles_in_1us);
13061376
return -EINVAL;
1377+
}
1378+
1379+
err = ufshcd_dme_get(hba, UIC_ARG_MIB(PA_VS_CORE_CLK_40NS_CYCLES), &reg);
1380+
if (err)
1381+
return err;
1382+
1383+
reg &= ~PA_VS_CORE_CLK_40NS_CYCLES_MASK;
1384+
reg |= cycles_in_40ns;
1385+
1386+
return ufshcd_dme_set(hba, UIC_ARG_MIB(PA_VS_CORE_CLK_40NS_CYCLES), reg);
1387+
}
1388+
1389+
static int ufs_qcom_set_core_clk_ctrl(struct ufs_hba *hba, bool is_scale_up)
1390+
{
1391+
struct ufs_qcom_host *host = ufshcd_get_variant(hba);
1392+
struct list_head *head = &hba->clk_list_head;
1393+
struct ufs_clk_info *clki;
1394+
u32 cycles_in_1us;
1395+
u32 core_clk_ctrl_reg;
1396+
int err;
1397+
1398+
list_for_each_entry(clki, head, list) {
1399+
if (!IS_ERR_OR_NULL(clki->clk) &&
1400+
!strcmp(clki->name, "core_clk_unipro")) {
1401+
if (is_scale_up)
1402+
cycles_in_1us = ceil(clki->max_freq, (1000 * 1000));
1403+
else
1404+
cycles_in_1us = ceil(clk_get_rate(clki->clk), (1000 * 1000));
1405+
break;
1406+
}
1407+
}
13071408

13081409
err = ufshcd_dme_get(hba,
13091410
UIC_ARG_MIB(DME_VS_CORE_CLK_CTRL),
13101411
&core_clk_ctrl_reg);
13111412
if (err)
13121413
return err;
13131414

1314-
core_clk_ctrl_reg &= ~DME_VS_CORE_CLK_CTRL_MAX_CORE_CLK_1US_CYCLES_MASK;
1315-
core_clk_ctrl_reg |= clk_cycles;
1415+
/* Bit mask is different for UFS host controller V4.0.0 onwards */
1416+
if (host->hw_ver.major >= 4) {
1417+
if (!FIELD_FIT(CLK_1US_CYCLES_MASK_V4, cycles_in_1us))
1418+
return -ERANGE;
1419+
core_clk_ctrl_reg &= ~CLK_1US_CYCLES_MASK_V4;
1420+
core_clk_ctrl_reg |= FIELD_PREP(CLK_1US_CYCLES_MASK_V4, cycles_in_1us);
1421+
} else {
1422+
if (!FIELD_FIT(CLK_1US_CYCLES_MASK, cycles_in_1us))
1423+
return -ERANGE;
1424+
core_clk_ctrl_reg &= ~CLK_1US_CYCLES_MASK;
1425+
core_clk_ctrl_reg |= FIELD_PREP(CLK_1US_CYCLES_MASK, cycles_in_1us);
1426+
}
13161427

13171428
/* Clear CORE_CLK_DIV_EN */
13181429
core_clk_ctrl_reg &= ~DME_VS_CORE_CLK_CTRL_CORE_CLK_DIV_EN_BIT;
13191430

1320-
return ufshcd_dme_set(hba,
1431+
err = ufshcd_dme_set(hba,
13211432
UIC_ARG_MIB(DME_VS_CORE_CLK_CTRL),
13221433
core_clk_ctrl_reg);
1323-
}
1434+
if (err)
1435+
return err;
13241436

1325-
static int ufs_qcom_clk_scale_up_pre_change(struct ufs_hba *hba)
1326-
{
1327-
/* nothing to do as of now */
1328-
return 0;
1437+
/* Configure unipro core clk 40ns attribute */
1438+
return ufs_qcom_set_clk_40ns_cycles(hba, cycles_in_1us);
13291439
}
13301440

1331-
static int ufs_qcom_clk_scale_up_post_change(struct ufs_hba *hba)
1441+
static int ufs_qcom_clk_scale_up_pre_change(struct ufs_hba *hba)
13321442
{
13331443
struct ufs_qcom_host *host = ufshcd_get_variant(hba);
1444+
struct ufs_pa_layer_attr *attr = &host->dev_req_params;
1445+
int ret;
13341446

13351447
if (!ufs_qcom_cap_qunipro(host))
13361448
return 0;
13371449

1338-
/* set unipro core clock cycles to 150 and clear clock divider */
1339-
return ufs_qcom_set_dme_vs_core_clk_ctrl_clear_div(hba, 150);
1450+
if (attr) {
1451+
ret = ufs_qcom_cfg_timers(hba, attr->gear_rx,
1452+
attr->pwr_rx, attr->hs_rate,
1453+
false, true);
1454+
if (ret) {
1455+
dev_err(hba->dev, "%s ufs cfg timer failed\n",
1456+
__func__);
1457+
return ret;
1458+
}
1459+
}
1460+
/* set unipro core clock attributes and clear clock divider */
1461+
return ufs_qcom_set_core_clk_ctrl(hba, true);
1462+
}
1463+
1464+
static int ufs_qcom_clk_scale_up_post_change(struct ufs_hba *hba)
1465+
{
1466+
return 0;
13401467
}
13411468

13421469
static int ufs_qcom_clk_scale_down_pre_change(struct ufs_hba *hba)
@@ -1371,15 +1498,14 @@ static int ufs_qcom_clk_scale_down_post_change(struct ufs_hba *hba)
13711498
if (!ufs_qcom_cap_qunipro(host))
13721499
return 0;
13731500

1374-
/* set unipro core clock cycles to 75 and clear clock divider */
1375-
return ufs_qcom_set_dme_vs_core_clk_ctrl_clear_div(hba, 75);
1501+
/* set unipro core clock attributes and clear clock divider */
1502+
return ufs_qcom_set_core_clk_ctrl(hba, false);
13761503
}
13771504

13781505
static int ufs_qcom_clk_scale_notify(struct ufs_hba *hba,
13791506
bool scale_up, enum ufs_notify_change_status status)
13801507
{
13811508
struct ufs_qcom_host *host = ufshcd_get_variant(hba);
1382-
struct ufs_pa_layer_attr *dev_req_params = &host->dev_req_params;
13831509
int err = 0;
13841510

13851511
/* check the host controller state before sending hibern8 cmd */
@@ -1409,11 +1535,6 @@ static int ufs_qcom_clk_scale_notify(struct ufs_hba *hba,
14091535
return err;
14101536
}
14111537

1412-
ufs_qcom_cfg_timers(hba,
1413-
dev_req_params->gear_rx,
1414-
dev_req_params->pwr_rx,
1415-
dev_req_params->hs_rate,
1416-
false);
14171538
ufs_qcom_icc_update_bw(host);
14181539
ufshcd_uic_hibern8_exit(hba);
14191540
}

drivers/ufs/host/ufs-qcom.h

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -129,8 +129,21 @@ enum {
129129
#define PA_VS_CONFIG_REG1 0x9000
130130
#define DME_VS_CORE_CLK_CTRL 0xD002
131131
/* bit and mask definitions for DME_VS_CORE_CLK_CTRL attribute */
132-
#define DME_VS_CORE_CLK_CTRL_CORE_CLK_DIV_EN_BIT BIT(8)
133-
#define DME_VS_CORE_CLK_CTRL_MAX_CORE_CLK_1US_CYCLES_MASK 0xFF
132+
#define CLK_1US_CYCLES_MASK_V4 GENMASK(27, 16)
133+
#define CLK_1US_CYCLES_MASK GENMASK(7, 0)
134+
#define DME_VS_CORE_CLK_CTRL_CORE_CLK_DIV_EN_BIT BIT(8)
135+
#define PA_VS_CORE_CLK_40NS_CYCLES 0x9007
136+
#define PA_VS_CORE_CLK_40NS_CYCLES_MASK GENMASK(6, 0)
137+
138+
139+
/* QCOM UFS host controller core clk frequencies */
140+
#define UNIPRO_CORE_CLK_FREQ_37_5_MHZ 38
141+
#define UNIPRO_CORE_CLK_FREQ_75_MHZ 75
142+
#define UNIPRO_CORE_CLK_FREQ_100_MHZ 100
143+
#define UNIPRO_CORE_CLK_FREQ_150_MHZ 150
144+
#define UNIPRO_CORE_CLK_FREQ_300_MHZ 300
145+
#define UNIPRO_CORE_CLK_FREQ_201_5_MHZ 202
146+
#define UNIPRO_CORE_CLK_FREQ_403_MHZ 403
134147

135148
static inline void
136149
ufs_qcom_get_controller_revision(struct ufs_hba *hba,
@@ -227,7 +240,7 @@ struct ufs_qcom_host {
227240

228241
struct gpio_desc *device_reset;
229242

230-
u32 hs_gear;
243+
u32 phy_gear;
231244

232245
bool esi_enabled;
233246
};
@@ -244,6 +257,7 @@ ufs_qcom_get_debug_reg_offset(struct ufs_qcom_host *host, u32 reg)
244257
#define ufs_qcom_is_link_off(hba) ufshcd_is_link_off(hba)
245258
#define ufs_qcom_is_link_active(hba) ufshcd_is_link_active(hba)
246259
#define ufs_qcom_is_link_hibern8(hba) ufshcd_is_link_hibern8(hba)
260+
#define ceil(freq, div) ((freq) % (div) == 0 ? ((freq)/(div)) : ((freq)/(div) + 1))
247261

248262
int ufs_qcom_testbus_config(struct ufs_qcom_host *host);
249263

0 commit comments

Comments
 (0)