diff options
-rw-r--r-- | drivers/scsi/ufs/ufs-qcom.c | 640 | ||||
-rw-r--r-- | drivers/scsi/ufs/ufs-qcom.h | 31 | ||||
-rw-r--r-- | drivers/scsi/ufs/ufshcd.c | 8 | ||||
-rw-r--r-- | drivers/scsi/ufs/ufshcd.h | 27 |
4 files changed, 525 insertions, 181 deletions
diff --git a/drivers/scsi/ufs/ufs-qcom.c b/drivers/scsi/ufs/ufs-qcom.c index 16338083b0d3..4f38d008bfb4 100644 --- a/drivers/scsi/ufs/ufs-qcom.c +++ b/drivers/scsi/ufs/ufs-qcom.c | |||
@@ -44,11 +44,11 @@ enum { | |||
44 | 44 | ||
45 | static struct ufs_qcom_host *ufs_qcom_hosts[MAX_UFS_QCOM_HOSTS]; | 45 | static struct ufs_qcom_host *ufs_qcom_hosts[MAX_UFS_QCOM_HOSTS]; |
46 | 46 | ||
47 | static void ufs_qcom_get_speed_mode(struct ufs_pa_layer_attr *p, char *result); | ||
48 | static int ufs_qcom_get_bus_vote(struct ufs_qcom_host *host, | ||
49 | const char *speed_mode); | ||
50 | static int ufs_qcom_set_bus_vote(struct ufs_qcom_host *host, int vote); | 47 | static int ufs_qcom_set_bus_vote(struct ufs_qcom_host *host, int vote); |
51 | static void ufs_qcom_get_default_testbus_cfg(struct ufs_qcom_host *host); | 48 | static void ufs_qcom_get_default_testbus_cfg(struct ufs_qcom_host *host); |
49 | static int ufs_qcom_set_dme_vs_core_clk_ctrl_clear_div(struct ufs_hba *hba, | ||
50 | u32 clk_cycles); | ||
51 | |||
52 | static void ufs_qcom_dump_regs(struct ufs_hba *hba, int offset, int len, | 52 | static void ufs_qcom_dump_regs(struct ufs_hba *hba, int offset, int len, |
53 | char *prefix) | 53 | char *prefix) |
54 | { | 54 | { |
@@ -177,6 +177,7 @@ static int ufs_qcom_init_lane_clks(struct ufs_qcom_host *host) | |||
177 | 177 | ||
178 | err = ufs_qcom_host_clk_get(dev, "tx_lane1_sync_clk", | 178 | err = ufs_qcom_host_clk_get(dev, "tx_lane1_sync_clk", |
179 | &host->tx_l1_sync_clk); | 179 | &host->tx_l1_sync_clk); |
180 | |||
180 | out: | 181 | out: |
181 | return err; | 182 | return err; |
182 | } | 183 | } |
@@ -209,7 +210,9 @@ static int ufs_qcom_check_hibern8(struct ufs_hba *hba) | |||
209 | 210 | ||
210 | do { | 211 | do { |
211 | err = ufshcd_dme_get(hba, | 212 | err = ufshcd_dme_get(hba, |
212 | UIC_ARG_MIB(MPHY_TX_FSM_STATE), &tx_fsm_val); | 213 | UIC_ARG_MIB_SEL(MPHY_TX_FSM_STATE, |
214 | UIC_ARG_MPHY_TX_GEN_SEL_INDEX(0)), | ||
215 | &tx_fsm_val); | ||
213 | if (err || tx_fsm_val == TX_FSM_HIBERN8) | 216 | if (err || tx_fsm_val == TX_FSM_HIBERN8) |
214 | break; | 217 | break; |
215 | 218 | ||
@@ -223,7 +226,9 @@ static int ufs_qcom_check_hibern8(struct ufs_hba *hba) | |||
223 | */ | 226 | */ |
224 | if (time_after(jiffies, timeout)) | 227 | if (time_after(jiffies, timeout)) |
225 | err = ufshcd_dme_get(hba, | 228 | err = ufshcd_dme_get(hba, |
226 | UIC_ARG_MIB(MPHY_TX_FSM_STATE), &tx_fsm_val); | 229 | UIC_ARG_MIB_SEL(MPHY_TX_FSM_STATE, |
230 | UIC_ARG_MPHY_TX_GEN_SEL_INDEX(0)), | ||
231 | &tx_fsm_val); | ||
227 | 232 | ||
228 | if (err) { | 233 | if (err) { |
229 | dev_err(hba->dev, "%s: unable to get TX_FSM_STATE, err %d\n", | 234 | dev_err(hba->dev, "%s: unable to get TX_FSM_STATE, err %d\n", |
@@ -237,6 +242,15 @@ static int ufs_qcom_check_hibern8(struct ufs_hba *hba) | |||
237 | return err; | 242 | return err; |
238 | } | 243 | } |
239 | 244 | ||
245 | static void ufs_qcom_select_unipro_mode(struct ufs_qcom_host *host) | ||
246 | { | ||
247 | ufshcd_rmwl(host->hba, QUNIPRO_SEL, | ||
248 | ufs_qcom_cap_qunipro(host) ? QUNIPRO_SEL : 0, | ||
249 | REG_UFS_CFG1); | ||
250 | /* make sure above configuration is applied before we return */ | ||
251 | mb(); | ||
252 | } | ||
253 | |||
240 | static int ufs_qcom_power_up_sequence(struct ufs_hba *hba) | 254 | static int ufs_qcom_power_up_sequence(struct ufs_hba *hba) |
241 | { | 255 | { |
242 | struct ufs_qcom_host *host = ufshcd_get_variant(hba); | 256 | struct ufs_qcom_host *host = ufshcd_get_variant(hba); |
@@ -251,9 +265,11 @@ static int ufs_qcom_power_up_sequence(struct ufs_hba *hba) | |||
251 | usleep_range(1000, 1100); | 265 | usleep_range(1000, 1100); |
252 | 266 | ||
253 | ret = ufs_qcom_phy_calibrate_phy(phy, is_rate_B); | 267 | ret = ufs_qcom_phy_calibrate_phy(phy, is_rate_B); |
268 | |||
254 | if (ret) { | 269 | if (ret) { |
255 | dev_err(hba->dev, "%s: ufs_qcom_phy_calibrate_phy() failed, ret = %d\n", | 270 | dev_err(hba->dev, |
256 | __func__, ret); | 271 | "%s: ufs_qcom_phy_calibrate_phy()failed, ret = %d\n", |
272 | __func__, ret); | ||
257 | goto out; | 273 | goto out; |
258 | } | 274 | } |
259 | 275 | ||
@@ -274,9 +290,12 @@ static int ufs_qcom_power_up_sequence(struct ufs_hba *hba) | |||
274 | 290 | ||
275 | ret = ufs_qcom_phy_is_pcs_ready(phy); | 291 | ret = ufs_qcom_phy_is_pcs_ready(phy); |
276 | if (ret) | 292 | if (ret) |
277 | dev_err(hba->dev, "%s: is_physical_coding_sublayer_ready() failed, ret = %d\n", | 293 | dev_err(hba->dev, |
294 | "%s: is_physical_coding_sublayer_ready() failed, ret = %d\n", | ||
278 | __func__, ret); | 295 | __func__, ret); |
279 | 296 | ||
297 | ufs_qcom_select_unipro_mode(host); | ||
298 | |||
280 | out: | 299 | out: |
281 | return ret; | 300 | return ret; |
282 | } | 301 | } |
@@ -299,7 +318,8 @@ static void ufs_qcom_enable_hw_clk_gating(struct ufs_hba *hba) | |||
299 | mb(); | 318 | mb(); |
300 | } | 319 | } |
301 | 320 | ||
302 | static int ufs_qcom_hce_enable_notify(struct ufs_hba *hba, bool status) | 321 | static int ufs_qcom_hce_enable_notify(struct ufs_hba *hba, |
322 | enum ufs_notify_change_status status) | ||
303 | { | 323 | { |
304 | struct ufs_qcom_host *host = ufshcd_get_variant(hba); | 324 | struct ufs_qcom_host *host = ufshcd_get_variant(hba); |
305 | int err = 0; | 325 | int err = 0; |
@@ -329,12 +349,12 @@ static int ufs_qcom_hce_enable_notify(struct ufs_hba *hba, bool status) | |||
329 | } | 349 | } |
330 | 350 | ||
331 | /** | 351 | /** |
332 | * Returns non-zero for success (which rate of core_clk) and 0 | 352 | * Returns zero for success and non-zero in case of a failure |
333 | * in case of a failure | ||
334 | */ | 353 | */ |
335 | static unsigned long | 354 | static int ufs_qcom_cfg_timers(struct ufs_hba *hba, u32 gear, |
336 | ufs_qcom_cfg_timers(struct ufs_hba *hba, u32 gear, u32 hs, u32 rate) | 355 | u32 hs, u32 rate, bool update_link_startup_timer) |
337 | { | 356 | { |
357 | int ret = 0; | ||
338 | struct ufs_qcom_host *host = ufshcd_get_variant(hba); | 358 | struct ufs_qcom_host *host = ufshcd_get_variant(hba); |
339 | struct ufs_clk_info *clki; | 359 | struct ufs_clk_info *clki; |
340 | u32 core_clk_period_in_ns; | 360 | u32 core_clk_period_in_ns; |
@@ -352,11 +372,13 @@ ufs_qcom_cfg_timers(struct ufs_hba *hba, u32 gear, u32 hs, u32 rate) | |||
352 | static u32 hs_fr_table_rA[][2] = { | 372 | static u32 hs_fr_table_rA[][2] = { |
353 | {UFS_HS_G1, 0x1F}, | 373 | {UFS_HS_G1, 0x1F}, |
354 | {UFS_HS_G2, 0x3e}, | 374 | {UFS_HS_G2, 0x3e}, |
375 | {UFS_HS_G3, 0x7D}, | ||
355 | }; | 376 | }; |
356 | 377 | ||
357 | static u32 hs_fr_table_rB[][2] = { | 378 | static u32 hs_fr_table_rB[][2] = { |
358 | {UFS_HS_G1, 0x24}, | 379 | {UFS_HS_G1, 0x24}, |
359 | {UFS_HS_G2, 0x49}, | 380 | {UFS_HS_G2, 0x49}, |
381 | {UFS_HS_G3, 0x92}, | ||
360 | }; | 382 | }; |
361 | 383 | ||
362 | /* | 384 | /* |
@@ -384,7 +406,17 @@ ufs_qcom_cfg_timers(struct ufs_hba *hba, u32 gear, u32 hs, u32 rate) | |||
384 | core_clk_rate = DEFAULT_CLK_RATE_HZ; | 406 | core_clk_rate = DEFAULT_CLK_RATE_HZ; |
385 | 407 | ||
386 | core_clk_cycles_per_us = core_clk_rate / USEC_PER_SEC; | 408 | core_clk_cycles_per_us = core_clk_rate / USEC_PER_SEC; |
387 | ufshcd_writel(hba, core_clk_cycles_per_us, REG_UFS_SYS1CLK_1US); | 409 | if (ufshcd_readl(hba, REG_UFS_SYS1CLK_1US) != core_clk_cycles_per_us) { |
410 | ufshcd_writel(hba, core_clk_cycles_per_us, REG_UFS_SYS1CLK_1US); | ||
411 | /* | ||
412 | * make sure above write gets applied before we return from | ||
413 | * this function. | ||
414 | */ | ||
415 | mb(); | ||
416 | } | ||
417 | |||
418 | if (ufs_qcom_cap_qunipro(host)) | ||
419 | goto out; | ||
388 | 420 | ||
389 | core_clk_period_in_ns = NSEC_PER_SEC / core_clk_rate; | 421 | core_clk_period_in_ns = NSEC_PER_SEC / core_clk_rate; |
390 | core_clk_period_in_ns <<= OFFSET_CLK_NS_REG; | 422 | core_clk_period_in_ns <<= OFFSET_CLK_NS_REG; |
@@ -434,35 +466,59 @@ ufs_qcom_cfg_timers(struct ufs_hba *hba, u32 gear, u32 hs, u32 rate) | |||
434 | goto out_error; | 466 | goto out_error; |
435 | } | 467 | } |
436 | 468 | ||
437 | /* this register 2 fields shall be written at once */ | 469 | if (ufshcd_readl(hba, REG_UFS_TX_SYMBOL_CLK_NS_US) != |
438 | ufshcd_writel(hba, core_clk_period_in_ns | tx_clk_cycles_per_us, | 470 | (core_clk_period_in_ns | tx_clk_cycles_per_us)) { |
439 | REG_UFS_TX_SYMBOL_CLK_NS_US); | 471 | /* this register 2 fields shall be written at once */ |
472 | ufshcd_writel(hba, core_clk_period_in_ns | tx_clk_cycles_per_us, | ||
473 | REG_UFS_TX_SYMBOL_CLK_NS_US); | ||
474 | /* | ||
475 | * make sure above write gets applied before we return from | ||
476 | * this function. | ||
477 | */ | ||
478 | mb(); | ||
479 | } | ||
480 | |||
481 | if (update_link_startup_timer) { | ||
482 | ufshcd_writel(hba, ((core_clk_rate / MSEC_PER_SEC) * 100), | ||
483 | REG_UFS_PA_LINK_STARTUP_TIMER); | ||
484 | /* | ||
485 | * make sure that this configuration is applied before | ||
486 | * we return | ||
487 | */ | ||
488 | mb(); | ||
489 | } | ||
440 | goto out; | 490 | goto out; |
441 | 491 | ||
442 | out_error: | 492 | out_error: |
443 | core_clk_rate = 0; | 493 | ret = -EINVAL; |
444 | out: | 494 | out: |
445 | return core_clk_rate; | 495 | return ret; |
446 | } | 496 | } |
447 | 497 | ||
448 | static int ufs_qcom_link_startup_notify(struct ufs_hba *hba, bool status) | 498 | static int ufs_qcom_link_startup_notify(struct ufs_hba *hba, |
499 | enum ufs_notify_change_status status) | ||
449 | { | 500 | { |
450 | unsigned long core_clk_rate = 0; | 501 | int err = 0; |
451 | u32 core_clk_cycles_per_100ms; | 502 | struct ufs_qcom_host *host = ufshcd_get_variant(hba); |
452 | 503 | ||
453 | switch (status) { | 504 | switch (status) { |
454 | case PRE_CHANGE: | 505 | case PRE_CHANGE: |
455 | core_clk_rate = ufs_qcom_cfg_timers(hba, UFS_PWM_G1, | 506 | if (ufs_qcom_cfg_timers(hba, UFS_PWM_G1, SLOWAUTO_MODE, |
456 | SLOWAUTO_MODE, 0); | 507 | 0, true)) { |
457 | if (!core_clk_rate) { | ||
458 | dev_err(hba->dev, "%s: ufs_qcom_cfg_timers() failed\n", | 508 | dev_err(hba->dev, "%s: ufs_qcom_cfg_timers() failed\n", |
459 | __func__); | 509 | __func__); |
460 | return -EINVAL; | 510 | err = -EINVAL; |
511 | goto out; | ||
461 | } | 512 | } |
462 | core_clk_cycles_per_100ms = | 513 | |
463 | (core_clk_rate / MSEC_PER_SEC) * 100; | 514 | if (ufs_qcom_cap_qunipro(host)) |
464 | ufshcd_writel(hba, core_clk_cycles_per_100ms, | 515 | /* |
465 | REG_UFS_PA_LINK_STARTUP_TIMER); | 516 | * set unipro core clock cycles to 150 & clear clock |
517 | * divider | ||
518 | */ | ||
519 | err = ufs_qcom_set_dme_vs_core_clk_ctrl_clear_div(hba, | ||
520 | 150); | ||
521 | |||
466 | break; | 522 | break; |
467 | case POST_CHANGE: | 523 | case POST_CHANGE: |
468 | ufs_qcom_link_startup_post_change(hba); | 524 | ufs_qcom_link_startup_post_change(hba); |
@@ -471,7 +527,8 @@ static int ufs_qcom_link_startup_notify(struct ufs_hba *hba, bool status) | |||
471 | break; | 527 | break; |
472 | } | 528 | } |
473 | 529 | ||
474 | return 0; | 530 | out: |
531 | return err; | ||
475 | } | 532 | } |
476 | 533 | ||
477 | static int ufs_qcom_suspend(struct ufs_hba *hba, enum ufs_pm_op pm_op) | 534 | static int ufs_qcom_suspend(struct ufs_hba *hba, enum ufs_pm_op pm_op) |
@@ -498,8 +555,10 @@ static int ufs_qcom_suspend(struct ufs_hba *hba, enum ufs_pm_op pm_op) | |||
498 | * If UniPro link is not active, PHY ref_clk, main PHY analog power | 555 | * If UniPro link is not active, PHY ref_clk, main PHY analog power |
499 | * rail and low noise analog power rail for PLL can be switched off. | 556 | * rail and low noise analog power rail for PLL can be switched off. |
500 | */ | 557 | */ |
501 | if (!ufs_qcom_is_link_active(hba)) | 558 | if (!ufs_qcom_is_link_active(hba)) { |
559 | ufs_qcom_disable_lane_clks(host); | ||
502 | phy_power_off(phy); | 560 | phy_power_off(phy); |
561 | } | ||
503 | 562 | ||
504 | out: | 563 | out: |
505 | return ret; | 564 | return ret; |
@@ -518,6 +577,10 @@ static int ufs_qcom_resume(struct ufs_hba *hba, enum ufs_pm_op pm_op) | |||
518 | goto out; | 577 | goto out; |
519 | } | 578 | } |
520 | 579 | ||
580 | err = ufs_qcom_enable_lane_clks(host); | ||
581 | if (err) | ||
582 | goto out; | ||
583 | |||
521 | hba->is_sys_suspended = false; | 584 | hba->is_sys_suspended = false; |
522 | 585 | ||
523 | out: | 586 | out: |
@@ -622,6 +685,81 @@ static int ufs_qcom_get_pwr_dev_param(struct ufs_qcom_dev_params *qcom_param, | |||
622 | return 0; | 685 | return 0; |
623 | } | 686 | } |
624 | 687 | ||
688 | #ifdef CONFIG_MSM_BUS_SCALING | ||
689 | static int ufs_qcom_get_bus_vote(struct ufs_qcom_host *host, | ||
690 | const char *speed_mode) | ||
691 | { | ||
692 | struct device *dev = host->hba->dev; | ||
693 | struct device_node *np = dev->of_node; | ||
694 | int err; | ||
695 | const char *key = "qcom,bus-vector-names"; | ||
696 | |||
697 | if (!speed_mode) { | ||
698 | err = -EINVAL; | ||
699 | goto out; | ||
700 | } | ||
701 | |||
702 | if (host->bus_vote.is_max_bw_needed && !!strcmp(speed_mode, "MIN")) | ||
703 | err = of_property_match_string(np, key, "MAX"); | ||
704 | else | ||
705 | err = of_property_match_string(np, key, speed_mode); | ||
706 | |||
707 | out: | ||
708 | if (err < 0) | ||
709 | dev_err(dev, "%s: Invalid %s mode %d\n", | ||
710 | __func__, speed_mode, err); | ||
711 | return err; | ||
712 | } | ||
713 | |||
714 | static void ufs_qcom_get_speed_mode(struct ufs_pa_layer_attr *p, char *result) | ||
715 | { | ||
716 | int gear = max_t(u32, p->gear_rx, p->gear_tx); | ||
717 | int lanes = max_t(u32, p->lane_rx, p->lane_tx); | ||
718 | int pwr; | ||
719 | |||
720 | /* default to PWM Gear 1, Lane 1 if power mode is not initialized */ | ||
721 | if (!gear) | ||
722 | gear = 1; | ||
723 | |||
724 | if (!lanes) | ||
725 | lanes = 1; | ||
726 | |||
727 | if (!p->pwr_rx && !p->pwr_tx) { | ||
728 | pwr = SLOWAUTO_MODE; | ||
729 | snprintf(result, BUS_VECTOR_NAME_LEN, "MIN"); | ||
730 | } else if (p->pwr_rx == FAST_MODE || p->pwr_rx == FASTAUTO_MODE || | ||
731 | p->pwr_tx == FAST_MODE || p->pwr_tx == FASTAUTO_MODE) { | ||
732 | pwr = FAST_MODE; | ||
733 | snprintf(result, BUS_VECTOR_NAME_LEN, "%s_R%s_G%d_L%d", "HS", | ||
734 | p->hs_rate == PA_HS_MODE_B ? "B" : "A", gear, lanes); | ||
735 | } else { | ||
736 | pwr = SLOW_MODE; | ||
737 | snprintf(result, BUS_VECTOR_NAME_LEN, "%s_G%d_L%d", | ||
738 | "PWM", gear, lanes); | ||
739 | } | ||
740 | } | ||
741 | |||
742 | static int ufs_qcom_set_bus_vote(struct ufs_qcom_host *host, int vote) | ||
743 | { | ||
744 | int err = 0; | ||
745 | |||
746 | if (vote != host->bus_vote.curr_vote) { | ||
747 | err = msm_bus_scale_client_update_request( | ||
748 | host->bus_vote.client_handle, vote); | ||
749 | if (err) { | ||
750 | dev_err(host->hba->dev, | ||
751 | "%s: msm_bus_scale_client_update_request() failed: bus_client_handle=0x%x, vote=%d, err=%d\n", | ||
752 | __func__, host->bus_vote.client_handle, | ||
753 | vote, err); | ||
754 | goto out; | ||
755 | } | ||
756 | |||
757 | host->bus_vote.curr_vote = vote; | ||
758 | } | ||
759 | out: | ||
760 | return err; | ||
761 | } | ||
762 | |||
625 | static int ufs_qcom_update_bus_bw_vote(struct ufs_qcom_host *host) | 763 | static int ufs_qcom_update_bus_bw_vote(struct ufs_qcom_host *host) |
626 | { | 764 | { |
627 | int vote; | 765 | int vote; |
@@ -643,8 +781,132 @@ static int ufs_qcom_update_bus_bw_vote(struct ufs_qcom_host *host) | |||
643 | return err; | 781 | return err; |
644 | } | 782 | } |
645 | 783 | ||
784 | static ssize_t | ||
785 | show_ufs_to_mem_max_bus_bw(struct device *dev, struct device_attribute *attr, | ||
786 | char *buf) | ||
787 | { | ||
788 | struct ufs_hba *hba = dev_get_drvdata(dev); | ||
789 | struct ufs_qcom_host *host = ufshcd_get_variant(hba); | ||
790 | |||
791 | return snprintf(buf, PAGE_SIZE, "%u\n", | ||
792 | host->bus_vote.is_max_bw_needed); | ||
793 | } | ||
794 | |||
795 | static ssize_t | ||
796 | store_ufs_to_mem_max_bus_bw(struct device *dev, struct device_attribute *attr, | ||
797 | const char *buf, size_t count) | ||
798 | { | ||
799 | struct ufs_hba *hba = dev_get_drvdata(dev); | ||
800 | struct ufs_qcom_host *host = ufshcd_get_variant(hba); | ||
801 | uint32_t value; | ||
802 | |||
803 | if (!kstrtou32(buf, 0, &value)) { | ||
804 | host->bus_vote.is_max_bw_needed = !!value; | ||
805 | ufs_qcom_update_bus_bw_vote(host); | ||
806 | } | ||
807 | |||
808 | return count; | ||
809 | } | ||
810 | |||
811 | static int ufs_qcom_bus_register(struct ufs_qcom_host *host) | ||
812 | { | ||
813 | int err; | ||
814 | struct msm_bus_scale_pdata *bus_pdata; | ||
815 | struct device *dev = host->hba->dev; | ||
816 | struct platform_device *pdev = to_platform_device(dev); | ||
817 | struct device_node *np = dev->of_node; | ||
818 | |||
819 | bus_pdata = msm_bus_cl_get_pdata(pdev); | ||
820 | if (!bus_pdata) { | ||
821 | dev_err(dev, "%s: failed to get bus vectors\n", __func__); | ||
822 | err = -ENODATA; | ||
823 | goto out; | ||
824 | } | ||
825 | |||
826 | err = of_property_count_strings(np, "qcom,bus-vector-names"); | ||
827 | if (err < 0 || err != bus_pdata->num_usecases) { | ||
828 | dev_err(dev, "%s: qcom,bus-vector-names not specified correctly %d\n", | ||
829 | __func__, err); | ||
830 | goto out; | ||
831 | } | ||
832 | |||
833 | host->bus_vote.client_handle = msm_bus_scale_register_client(bus_pdata); | ||
834 | if (!host->bus_vote.client_handle) { | ||
835 | dev_err(dev, "%s: msm_bus_scale_register_client failed\n", | ||
836 | __func__); | ||
837 | err = -EFAULT; | ||
838 | goto out; | ||
839 | } | ||
840 | |||
841 | /* cache the vote index for minimum and maximum bandwidth */ | ||
842 | host->bus_vote.min_bw_vote = ufs_qcom_get_bus_vote(host, "MIN"); | ||
843 | host->bus_vote.max_bw_vote = ufs_qcom_get_bus_vote(host, "MAX"); | ||
844 | |||
845 | host->bus_vote.max_bus_bw.show = show_ufs_to_mem_max_bus_bw; | ||
846 | host->bus_vote.max_bus_bw.store = store_ufs_to_mem_max_bus_bw; | ||
847 | sysfs_attr_init(&host->bus_vote.max_bus_bw.attr); | ||
848 | host->bus_vote.max_bus_bw.attr.name = "max_bus_bw"; | ||
849 | host->bus_vote.max_bus_bw.attr.mode = S_IRUGO | S_IWUSR; | ||
850 | err = device_create_file(dev, &host->bus_vote.max_bus_bw); | ||
851 | out: | ||
852 | return err; | ||
853 | } | ||
854 | #else /* CONFIG_MSM_BUS_SCALING */ | ||
855 | static int ufs_qcom_update_bus_bw_vote(struct ufs_qcom_host *host) | ||
856 | { | ||
857 | return 0; | ||
858 | } | ||
859 | |||
860 | static int ufs_qcom_set_bus_vote(struct ufs_qcom_host *host, int vote) | ||
861 | { | ||
862 | return 0; | ||
863 | } | ||
864 | |||
865 | static int ufs_qcom_bus_register(struct ufs_qcom_host *host) | ||
866 | { | ||
867 | return 0; | ||
868 | } | ||
869 | #endif /* CONFIG_MSM_BUS_SCALING */ | ||
870 | |||
871 | static void ufs_qcom_dev_ref_clk_ctrl(struct ufs_qcom_host *host, bool enable) | ||
872 | { | ||
873 | if (host->dev_ref_clk_ctrl_mmio && | ||
874 | (enable ^ host->is_dev_ref_clk_enabled)) { | ||
875 | u32 temp = readl_relaxed(host->dev_ref_clk_ctrl_mmio); | ||
876 | |||
877 | if (enable) | ||
878 | temp |= host->dev_ref_clk_en_mask; | ||
879 | else | ||
880 | temp &= ~host->dev_ref_clk_en_mask; | ||
881 | |||
882 | /* | ||
883 | * If we are here to disable this clock it might be immediately | ||
884 | * after entering into hibern8 in which case we need to make | ||
885 | * sure that device ref_clk is active at least 1us after the | ||
886 | * hibern8 enter. | ||
887 | */ | ||
888 | if (!enable) | ||
889 | udelay(1); | ||
890 | |||
891 | writel_relaxed(temp, host->dev_ref_clk_ctrl_mmio); | ||
892 | |||
893 | /* ensure that ref_clk is enabled/disabled before we return */ | ||
894 | wmb(); | ||
895 | |||
896 | /* | ||
897 | * If we call hibern8 exit after this, we need to make sure that | ||
898 | * device ref_clk is stable for at least 1us before the hibern8 | ||
899 | * exit command. | ||
900 | */ | ||
901 | if (enable) | ||
902 | udelay(1); | ||
903 | |||
904 | host->is_dev_ref_clk_enabled = enable; | ||
905 | } | ||
906 | } | ||
907 | |||
646 | static int ufs_qcom_pwr_change_notify(struct ufs_hba *hba, | 908 | static int ufs_qcom_pwr_change_notify(struct ufs_hba *hba, |
647 | bool status, | 909 | enum ufs_notify_change_status status, |
648 | struct ufs_pa_layer_attr *dev_max_params, | 910 | struct ufs_pa_layer_attr *dev_max_params, |
649 | struct ufs_pa_layer_attr *dev_req_params) | 911 | struct ufs_pa_layer_attr *dev_req_params) |
650 | { | 912 | { |
@@ -677,6 +939,20 @@ static int ufs_qcom_pwr_change_notify(struct ufs_hba *hba, | |||
677 | ufs_qcom_cap.desired_working_mode = | 939 | ufs_qcom_cap.desired_working_mode = |
678 | UFS_QCOM_LIMIT_DESIRED_MODE; | 940 | UFS_QCOM_LIMIT_DESIRED_MODE; |
679 | 941 | ||
942 | if (host->hw_ver.major == 0x1) { | ||
943 | /* | ||
944 | * HS-G3 operations may not reliably work on legacy QCOM | ||
945 | * UFS host controller hardware even though capability | ||
946 | * exchange during link startup phase may end up | ||
947 | * negotiating maximum supported gear as G3. | ||
948 | * Hence downgrade the maximum supported gear to HS-G2. | ||
949 | */ | ||
950 | if (ufs_qcom_cap.hs_tx_gear > UFS_HS_G2) | ||
951 | ufs_qcom_cap.hs_tx_gear = UFS_HS_G2; | ||
952 | if (ufs_qcom_cap.hs_rx_gear > UFS_HS_G2) | ||
953 | ufs_qcom_cap.hs_rx_gear = UFS_HS_G2; | ||
954 | } | ||
955 | |||
680 | ret = ufs_qcom_get_pwr_dev_param(&ufs_qcom_cap, | 956 | ret = ufs_qcom_get_pwr_dev_param(&ufs_qcom_cap, |
681 | dev_max_params, | 957 | dev_max_params, |
682 | dev_req_params); | 958 | dev_req_params); |
@@ -688,9 +964,9 @@ static int ufs_qcom_pwr_change_notify(struct ufs_hba *hba, | |||
688 | 964 | ||
689 | break; | 965 | break; |
690 | case POST_CHANGE: | 966 | case POST_CHANGE: |
691 | if (!ufs_qcom_cfg_timers(hba, dev_req_params->gear_rx, | 967 | if (ufs_qcom_cfg_timers(hba, dev_req_params->gear_rx, |
692 | dev_req_params->pwr_rx, | 968 | dev_req_params->pwr_rx, |
693 | dev_req_params->hs_rate)) { | 969 | dev_req_params->hs_rate, false)) { |
694 | dev_err(hba->dev, "%s: ufs_qcom_cfg_timers() failed\n", | 970 | dev_err(hba->dev, "%s: ufs_qcom_cfg_timers() failed\n", |
695 | __func__); | 971 | __func__); |
696 | /* | 972 | /* |
@@ -752,10 +1028,11 @@ static void ufs_qcom_advertise_quirks(struct ufs_hba *hba) | |||
752 | 1028 | ||
753 | if (host->hw_ver.minor == 0x0001 && host->hw_ver.step == 0x0001) | 1029 | if (host->hw_ver.minor == 0x0001 && host->hw_ver.step == 0x0001) |
754 | hba->quirks |= UFSHCD_QUIRK_BROKEN_INTR_AGGR; | 1030 | hba->quirks |= UFSHCD_QUIRK_BROKEN_INTR_AGGR; |
1031 | |||
1032 | hba->quirks |= UFSHCD_QUIRK_BROKEN_LCC; | ||
755 | } | 1033 | } |
756 | 1034 | ||
757 | if (host->hw_ver.major >= 0x2) { | 1035 | if (host->hw_ver.major >= 0x2) { |
758 | hba->quirks |= UFSHCD_QUIRK_BROKEN_LCC; | ||
759 | hba->quirks |= UFSHCD_QUIRK_BROKEN_UFS_HCI_VERSION; | 1036 | hba->quirks |= UFSHCD_QUIRK_BROKEN_UFS_HCI_VERSION; |
760 | 1037 | ||
761 | if (!ufs_qcom_cap_qunipro(host)) | 1038 | if (!ufs_qcom_cap_qunipro(host)) |
@@ -770,77 +1047,27 @@ static void ufs_qcom_set_caps(struct ufs_hba *hba) | |||
770 | { | 1047 | { |
771 | struct ufs_qcom_host *host = ufshcd_get_variant(hba); | 1048 | struct ufs_qcom_host *host = ufshcd_get_variant(hba); |
772 | 1049 | ||
773 | if (host->hw_ver.major >= 0x2) | 1050 | hba->caps |= UFSHCD_CAP_CLK_GATING | UFSHCD_CAP_HIBERN8_WITH_CLK_GATING; |
774 | host->caps = UFS_QCOM_CAP_QUNIPRO; | 1051 | hba->caps |= UFSHCD_CAP_CLK_SCALING; |
775 | } | 1052 | hba->caps |= UFSHCD_CAP_AUTO_BKOPS_SUSPEND; |
776 | |||
777 | static int ufs_qcom_get_bus_vote(struct ufs_qcom_host *host, | ||
778 | const char *speed_mode) | ||
779 | { | ||
780 | struct device *dev = host->hba->dev; | ||
781 | struct device_node *np = dev->of_node; | ||
782 | int err; | ||
783 | const char *key = "qcom,bus-vector-names"; | ||
784 | |||
785 | if (!speed_mode) { | ||
786 | err = -EINVAL; | ||
787 | goto out; | ||
788 | } | ||
789 | |||
790 | if (host->bus_vote.is_max_bw_needed && !!strcmp(speed_mode, "MIN")) | ||
791 | err = of_property_match_string(np, key, "MAX"); | ||
792 | else | ||
793 | err = of_property_match_string(np, key, speed_mode); | ||
794 | |||
795 | out: | ||
796 | if (err < 0) | ||
797 | dev_err(dev, "%s: Invalid %s mode %d\n", | ||
798 | __func__, speed_mode, err); | ||
799 | return err; | ||
800 | } | ||
801 | |||
802 | static int ufs_qcom_set_bus_vote(struct ufs_qcom_host *host, int vote) | ||
803 | { | ||
804 | int err = 0; | ||
805 | |||
806 | if (vote != host->bus_vote.curr_vote) | ||
807 | host->bus_vote.curr_vote = vote; | ||
808 | |||
809 | return err; | ||
810 | } | ||
811 | |||
812 | static void ufs_qcom_get_speed_mode(struct ufs_pa_layer_attr *p, char *result) | ||
813 | { | ||
814 | int gear = max_t(u32, p->gear_rx, p->gear_tx); | ||
815 | int lanes = max_t(u32, p->lane_rx, p->lane_tx); | ||
816 | int pwr; | ||
817 | |||
818 | /* default to PWM Gear 1, Lane 1 if power mode is not initialized */ | ||
819 | if (!gear) | ||
820 | gear = 1; | ||
821 | |||
822 | if (!lanes) | ||
823 | lanes = 1; | ||
824 | 1053 | ||
825 | if (!p->pwr_rx && !p->pwr_tx) { | 1054 | if (host->hw_ver.major >= 0x2) { |
826 | pwr = SLOWAUTO_MODE; | 1055 | host->caps = UFS_QCOM_CAP_QUNIPRO | |
827 | snprintf(result, BUS_VECTOR_NAME_LEN, "MIN"); | 1056 | UFS_QCOM_CAP_RETAIN_SEC_CFG_AFTER_PWR_COLLAPSE; |
828 | } else if (p->pwr_rx == FAST_MODE || p->pwr_rx == FASTAUTO_MODE || | ||
829 | p->pwr_tx == FAST_MODE || p->pwr_tx == FASTAUTO_MODE) { | ||
830 | pwr = FAST_MODE; | ||
831 | snprintf(result, BUS_VECTOR_NAME_LEN, "%s_R%s_G%d_L%d", "HS", | ||
832 | p->hs_rate == PA_HS_MODE_B ? "B" : "A", gear, lanes); | ||
833 | } else { | ||
834 | pwr = SLOW_MODE; | ||
835 | snprintf(result, BUS_VECTOR_NAME_LEN, "%s_G%d_L%d", | ||
836 | "PWM", gear, lanes); | ||
837 | } | 1057 | } |
838 | } | 1058 | } |
839 | 1059 | ||
1060 | /** | ||
1061 | * ufs_qcom_setup_clocks - enables/disable clocks | ||
1062 | * @hba: host controller instance | ||
1063 | * @on: If true, enable clocks else disable them. | ||
1064 | * | ||
1065 | * Returns 0 on success, non-zero on failure. | ||
1066 | */ | ||
840 | static int ufs_qcom_setup_clocks(struct ufs_hba *hba, bool on) | 1067 | static int ufs_qcom_setup_clocks(struct ufs_hba *hba, bool on) |
841 | { | 1068 | { |
842 | struct ufs_qcom_host *host = ufshcd_get_variant(hba); | 1069 | struct ufs_qcom_host *host = ufshcd_get_variant(hba); |
843 | int err = 0; | 1070 | int err; |
844 | int vote = 0; | 1071 | int vote = 0; |
845 | 1072 | ||
846 | /* | 1073 | /* |
@@ -863,20 +1090,18 @@ static int ufs_qcom_setup_clocks(struct ufs_hba *hba, bool on) | |||
863 | ufs_qcom_phy_disable_iface_clk(host->generic_phy); | 1090 | ufs_qcom_phy_disable_iface_clk(host->generic_phy); |
864 | goto out; | 1091 | goto out; |
865 | } | 1092 | } |
866 | /* enable the device ref clock */ | ||
867 | ufs_qcom_phy_enable_dev_ref_clk(host->generic_phy); | ||
868 | vote = host->bus_vote.saved_vote; | 1093 | vote = host->bus_vote.saved_vote; |
869 | if (vote == host->bus_vote.min_bw_vote) | 1094 | if (vote == host->bus_vote.min_bw_vote) |
870 | ufs_qcom_update_bus_bw_vote(host); | 1095 | ufs_qcom_update_bus_bw_vote(host); |
1096 | |||
871 | } else { | 1097 | } else { |
1098 | |||
872 | /* M-PHY RMMI interface clocks can be turned off */ | 1099 | /* M-PHY RMMI interface clocks can be turned off */ |
873 | ufs_qcom_phy_disable_iface_clk(host->generic_phy); | 1100 | ufs_qcom_phy_disable_iface_clk(host->generic_phy); |
874 | if (!ufs_qcom_is_link_active(hba)) { | 1101 | if (!ufs_qcom_is_link_active(hba)) |
875 | /* turn off UFS local PHY ref_clk */ | ||
876 | ufs_qcom_phy_disable_ref_clk(host->generic_phy); | ||
877 | /* disable device ref_clk */ | 1102 | /* disable device ref_clk */ |
878 | ufs_qcom_phy_disable_dev_ref_clk(host->generic_phy); | 1103 | ufs_qcom_dev_ref_clk_ctrl(host, false); |
879 | } | 1104 | |
880 | vote = host->bus_vote.min_bw_vote; | 1105 | vote = host->bus_vote.min_bw_vote; |
881 | } | 1106 | } |
882 | 1107 | ||
@@ -889,60 +1114,6 @@ out: | |||
889 | return err; | 1114 | return err; |
890 | } | 1115 | } |
891 | 1116 | ||
892 | static ssize_t | ||
893 | show_ufs_to_mem_max_bus_bw(struct device *dev, struct device_attribute *attr, | ||
894 | char *buf) | ||
895 | { | ||
896 | struct ufs_hba *hba = dev_get_drvdata(dev); | ||
897 | struct ufs_qcom_host *host = ufshcd_get_variant(hba); | ||
898 | |||
899 | return snprintf(buf, PAGE_SIZE, "%u\n", | ||
900 | host->bus_vote.is_max_bw_needed); | ||
901 | } | ||
902 | |||
903 | static ssize_t | ||
904 | store_ufs_to_mem_max_bus_bw(struct device *dev, struct device_attribute *attr, | ||
905 | const char *buf, size_t count) | ||
906 | { | ||
907 | struct ufs_hba *hba = dev_get_drvdata(dev); | ||
908 | struct ufs_qcom_host *host = ufshcd_get_variant(hba); | ||
909 | uint32_t value; | ||
910 | |||
911 | if (!kstrtou32(buf, 0, &value)) { | ||
912 | host->bus_vote.is_max_bw_needed = !!value; | ||
913 | ufs_qcom_update_bus_bw_vote(host); | ||
914 | } | ||
915 | |||
916 | return count; | ||
917 | } | ||
918 | |||
919 | static int ufs_qcom_bus_register(struct ufs_qcom_host *host) | ||
920 | { | ||
921 | int err; | ||
922 | struct device *dev = host->hba->dev; | ||
923 | struct device_node *np = dev->of_node; | ||
924 | |||
925 | err = of_property_count_strings(np, "qcom,bus-vector-names"); | ||
926 | if (err < 0 ) { | ||
927 | dev_err(dev, "%s: qcom,bus-vector-names not specified correctly %d\n", | ||
928 | __func__, err); | ||
929 | goto out; | ||
930 | } | ||
931 | |||
932 | /* cache the vote index for minimum and maximum bandwidth */ | ||
933 | host->bus_vote.min_bw_vote = ufs_qcom_get_bus_vote(host, "MIN"); | ||
934 | host->bus_vote.max_bw_vote = ufs_qcom_get_bus_vote(host, "MAX"); | ||
935 | |||
936 | host->bus_vote.max_bus_bw.show = show_ufs_to_mem_max_bus_bw; | ||
937 | host->bus_vote.max_bus_bw.store = store_ufs_to_mem_max_bus_bw; | ||
938 | sysfs_attr_init(&host->bus_vote.max_bus_bw.attr); | ||
939 | host->bus_vote.max_bus_bw.attr.name = "max_bus_bw"; | ||
940 | host->bus_vote.max_bus_bw.attr.mode = S_IRUGO | S_IWUSR; | ||
941 | err = device_create_file(dev, &host->bus_vote.max_bus_bw); | ||
942 | out: | ||
943 | return err; | ||
944 | } | ||
945 | |||
946 | #define ANDROID_BOOT_DEV_MAX 30 | 1117 | #define ANDROID_BOOT_DEV_MAX 30 |
947 | static char android_boot_dev[ANDROID_BOOT_DEV_MAX]; | 1118 | static char android_boot_dev[ANDROID_BOOT_DEV_MAX]; |
948 | 1119 | ||
@@ -969,7 +1140,9 @@ static int ufs_qcom_init(struct ufs_hba *hba) | |||
969 | { | 1140 | { |
970 | int err; | 1141 | int err; |
971 | struct device *dev = hba->dev; | 1142 | struct device *dev = hba->dev; |
1143 | struct platform_device *pdev = to_platform_device(dev); | ||
972 | struct ufs_qcom_host *host; | 1144 | struct ufs_qcom_host *host; |
1145 | struct resource *res; | ||
973 | 1146 | ||
974 | if (strlen(android_boot_dev) && strcmp(android_boot_dev, dev_name(dev))) | 1147 | if (strlen(android_boot_dev) && strcmp(android_boot_dev, dev_name(dev))) |
975 | return -ENODEV; | 1148 | return -ENODEV; |
@@ -981,9 +1154,15 @@ static int ufs_qcom_init(struct ufs_hba *hba) | |||
981 | goto out; | 1154 | goto out; |
982 | } | 1155 | } |
983 | 1156 | ||
1157 | /* Make a two way bind between the qcom host and the hba */ | ||
984 | host->hba = hba; | 1158 | host->hba = hba; |
985 | ufshcd_set_variant(hba, host); | 1159 | ufshcd_set_variant(hba, host); |
986 | 1160 | ||
1161 | /* | ||
1162 | * voting/devoting device ref_clk source is time consuming hence | ||
1163 | * skip devoting it during aggressive clock gating. This clock | ||
1164 | * will still be gated off during runtime suspend. | ||
1165 | */ | ||
987 | host->generic_phy = devm_phy_get(dev, "ufsphy"); | 1166 | host->generic_phy = devm_phy_get(dev, "ufsphy"); |
988 | 1167 | ||
989 | if (IS_ERR(host->generic_phy)) { | 1168 | if (IS_ERR(host->generic_phy)) { |
@@ -999,6 +1178,30 @@ static int ufs_qcom_init(struct ufs_hba *hba) | |||
999 | ufs_qcom_get_controller_revision(hba, &host->hw_ver.major, | 1178 | ufs_qcom_get_controller_revision(hba, &host->hw_ver.major, |
1000 | &host->hw_ver.minor, &host->hw_ver.step); | 1179 | &host->hw_ver.minor, &host->hw_ver.step); |
1001 | 1180 | ||
1181 | /* | ||
1182 | * for newer controllers, device reference clock control bit has | ||
1183 | * moved inside UFS controller register address space itself. | ||
1184 | */ | ||
1185 | if (host->hw_ver.major >= 0x02) { | ||
1186 | host->dev_ref_clk_ctrl_mmio = hba->mmio_base + REG_UFS_CFG1; | ||
1187 | host->dev_ref_clk_en_mask = BIT(26); | ||
1188 | } else { | ||
1189 | /* "dev_ref_clk_ctrl_mem" is optional resource */ | ||
1190 | res = platform_get_resource(pdev, IORESOURCE_MEM, 1); | ||
1191 | if (res) { | ||
1192 | host->dev_ref_clk_ctrl_mmio = | ||
1193 | devm_ioremap_resource(dev, res); | ||
1194 | if (IS_ERR(host->dev_ref_clk_ctrl_mmio)) { | ||
1195 | dev_warn(dev, | ||
1196 | "%s: could not map dev_ref_clk_ctrl_mmio, err %ld\n", | ||
1197 | __func__, | ||
1198 | PTR_ERR(host->dev_ref_clk_ctrl_mmio)); | ||
1199 | host->dev_ref_clk_ctrl_mmio = NULL; | ||
1200 | } | ||
1201 | host->dev_ref_clk_en_mask = BIT(5); | ||
1202 | } | ||
1203 | } | ||
1204 | |||
1002 | /* update phy revision information before calling phy_init() */ | 1205 | /* update phy revision information before calling phy_init() */ |
1003 | ufs_qcom_phy_save_controller_version(host->generic_phy, | 1206 | ufs_qcom_phy_save_controller_version(host->generic_phy, |
1004 | host->hw_ver.major, host->hw_ver.minor, host->hw_ver.step); | 1207 | host->hw_ver.major, host->hw_ver.minor, host->hw_ver.step); |
@@ -1015,9 +1218,6 @@ static int ufs_qcom_init(struct ufs_hba *hba) | |||
1015 | ufs_qcom_set_caps(hba); | 1218 | ufs_qcom_set_caps(hba); |
1016 | ufs_qcom_advertise_quirks(hba); | 1219 | ufs_qcom_advertise_quirks(hba); |
1017 | 1220 | ||
1018 | hba->caps |= UFSHCD_CAP_CLK_GATING | UFSHCD_CAP_CLK_SCALING; | ||
1019 | hba->caps |= UFSHCD_CAP_AUTO_BKOPS_SUSPEND; | ||
1020 | |||
1021 | ufs_qcom_setup_clocks(hba, true); | 1221 | ufs_qcom_setup_clocks(hba, true); |
1022 | 1222 | ||
1023 | if (hba->dev->id < MAX_UFS_QCOM_HOSTS) | 1223 | if (hba->dev->id < MAX_UFS_QCOM_HOSTS) |
@@ -1053,14 +1253,118 @@ static void ufs_qcom_exit(struct ufs_hba *hba) | |||
1053 | phy_power_off(host->generic_phy); | 1253 | phy_power_off(host->generic_phy); |
1054 | } | 1254 | } |
1055 | 1255 | ||
1056 | static | 1256 | static int ufs_qcom_set_dme_vs_core_clk_ctrl_clear_div(struct ufs_hba *hba, |
1057 | void ufs_qcom_clk_scale_notify(struct ufs_hba *hba) | 1257 | u32 clk_cycles) |
1258 | { | ||
1259 | int err; | ||
1260 | u32 core_clk_ctrl_reg; | ||
1261 | |||
1262 | if (clk_cycles > DME_VS_CORE_CLK_CTRL_MAX_CORE_CLK_1US_CYCLES_MASK) | ||
1263 | return -EINVAL; | ||
1264 | |||
1265 | err = ufshcd_dme_get(hba, | ||
1266 | UIC_ARG_MIB(DME_VS_CORE_CLK_CTRL), | ||
1267 | &core_clk_ctrl_reg); | ||
1268 | if (err) | ||
1269 | goto out; | ||
1270 | |||
1271 | core_clk_ctrl_reg &= ~DME_VS_CORE_CLK_CTRL_MAX_CORE_CLK_1US_CYCLES_MASK; | ||
1272 | core_clk_ctrl_reg |= clk_cycles; | ||
1273 | |||
1274 | /* Clear CORE_CLK_DIV_EN */ | ||
1275 | core_clk_ctrl_reg &= ~DME_VS_CORE_CLK_CTRL_CORE_CLK_DIV_EN_BIT; | ||
1276 | |||
1277 | err = ufshcd_dme_set(hba, | ||
1278 | UIC_ARG_MIB(DME_VS_CORE_CLK_CTRL), | ||
1279 | core_clk_ctrl_reg); | ||
1280 | out: | ||
1281 | return err; | ||
1282 | } | ||
1283 | |||
1284 | static int ufs_qcom_clk_scale_up_pre_change(struct ufs_hba *hba) | ||
1285 | { | ||
1286 | /* nothing to do as of now */ | ||
1287 | return 0; | ||
1288 | } | ||
1289 | |||
1290 | static int ufs_qcom_clk_scale_up_post_change(struct ufs_hba *hba) | ||
1291 | { | ||
1292 | struct ufs_qcom_host *host = ufshcd_get_variant(hba); | ||
1293 | |||
1294 | if (!ufs_qcom_cap_qunipro(host)) | ||
1295 | return 0; | ||
1296 | |||
1297 | /* set unipro core clock cycles to 150 and clear clock divider */ | ||
1298 | return ufs_qcom_set_dme_vs_core_clk_ctrl_clear_div(hba, 150); | ||
1299 | } | ||
1300 | |||
1301 | static int ufs_qcom_clk_scale_down_pre_change(struct ufs_hba *hba) | ||
1302 | { | ||
1303 | struct ufs_qcom_host *host = ufshcd_get_variant(hba); | ||
1304 | int err; | ||
1305 | u32 core_clk_ctrl_reg; | ||
1306 | |||
1307 | if (!ufs_qcom_cap_qunipro(host)) | ||
1308 | return 0; | ||
1309 | |||
1310 | err = ufshcd_dme_get(hba, | ||
1311 | UIC_ARG_MIB(DME_VS_CORE_CLK_CTRL), | ||
1312 | &core_clk_ctrl_reg); | ||
1313 | |||
1314 | /* make sure CORE_CLK_DIV_EN is cleared */ | ||
1315 | if (!err && | ||
1316 | (core_clk_ctrl_reg & DME_VS_CORE_CLK_CTRL_CORE_CLK_DIV_EN_BIT)) { | ||
1317 | core_clk_ctrl_reg &= ~DME_VS_CORE_CLK_CTRL_CORE_CLK_DIV_EN_BIT; | ||
1318 | err = ufshcd_dme_set(hba, | ||
1319 | UIC_ARG_MIB(DME_VS_CORE_CLK_CTRL), | ||
1320 | core_clk_ctrl_reg); | ||
1321 | } | ||
1322 | |||
1323 | return err; | ||
1324 | } | ||
1325 | |||
1326 | static int ufs_qcom_clk_scale_down_post_change(struct ufs_hba *hba) | ||
1327 | { | ||
1328 | struct ufs_qcom_host *host = ufshcd_get_variant(hba); | ||
1329 | |||
1330 | if (!ufs_qcom_cap_qunipro(host)) | ||
1331 | return 0; | ||
1332 | |||
1333 | /* set unipro core clock cycles to 75 and clear clock divider */ | ||
1334 | return ufs_qcom_set_dme_vs_core_clk_ctrl_clear_div(hba, 75); | ||
1335 | } | ||
1336 | |||
1337 | static int ufs_qcom_clk_scale_notify(struct ufs_hba *hba, | ||
1338 | bool scale_up, enum ufs_notify_change_status status) | ||
1058 | { | 1339 | { |
1059 | struct ufs_qcom_host *host = ufshcd_get_variant(hba); | 1340 | struct ufs_qcom_host *host = ufshcd_get_variant(hba); |
1060 | struct ufs_pa_layer_attr *dev_req_params = &host->dev_req_params; | 1341 | struct ufs_pa_layer_attr *dev_req_params = &host->dev_req_params; |
1342 | int err = 0; | ||
1061 | 1343 | ||
1062 | if (!dev_req_params) | 1344 | if (status == PRE_CHANGE) { |
1063 | return; | 1345 | if (scale_up) |
1346 | err = ufs_qcom_clk_scale_up_pre_change(hba); | ||
1347 | else | ||
1348 | err = ufs_qcom_clk_scale_down_pre_change(hba); | ||
1349 | } else { | ||
1350 | if (scale_up) | ||
1351 | err = ufs_qcom_clk_scale_up_post_change(hba); | ||
1352 | else | ||
1353 | err = ufs_qcom_clk_scale_down_post_change(hba); | ||
1354 | |||
1355 | if (err || !dev_req_params) | ||
1356 | goto out; | ||
1357 | |||
1358 | ufs_qcom_cfg_timers(hba, | ||
1359 | dev_req_params->gear_rx, | ||
1360 | dev_req_params->pwr_rx, | ||
1361 | dev_req_params->hs_rate, | ||
1362 | false); | ||
1363 | ufs_qcom_update_bus_bw_vote(host); | ||
1364 | } | ||
1365 | |||
1366 | out: | ||
1367 | return err; | ||
1064 | } | 1368 | } |
1065 | 1369 | ||
1066 | static void ufs_qcom_get_default_testbus_cfg(struct ufs_qcom_host *host) | 1370 | static void ufs_qcom_get_default_testbus_cfg(struct ufs_qcom_host *host) |
diff --git a/drivers/scsi/ufs/ufs-qcom.h b/drivers/scsi/ufs/ufs-qcom.h index 1b71a1b0be9f..36249b35f858 100644 --- a/drivers/scsi/ufs/ufs-qcom.h +++ b/drivers/scsi/ufs/ufs-qcom.h | |||
@@ -35,8 +35,8 @@ | |||
35 | 35 | ||
36 | #define UFS_QCOM_LIMIT_NUM_LANES_RX 2 | 36 | #define UFS_QCOM_LIMIT_NUM_LANES_RX 2 |
37 | #define UFS_QCOM_LIMIT_NUM_LANES_TX 2 | 37 | #define UFS_QCOM_LIMIT_NUM_LANES_TX 2 |
38 | #define UFS_QCOM_LIMIT_HSGEAR_RX UFS_HS_G2 | 38 | #define UFS_QCOM_LIMIT_HSGEAR_RX UFS_HS_G3 |
39 | #define UFS_QCOM_LIMIT_HSGEAR_TX UFS_HS_G2 | 39 | #define UFS_QCOM_LIMIT_HSGEAR_TX UFS_HS_G3 |
40 | #define UFS_QCOM_LIMIT_PWMGEAR_RX UFS_PWM_G4 | 40 | #define UFS_QCOM_LIMIT_PWMGEAR_RX UFS_PWM_G4 |
41 | #define UFS_QCOM_LIMIT_PWMGEAR_TX UFS_PWM_G4 | 41 | #define UFS_QCOM_LIMIT_PWMGEAR_TX UFS_PWM_G4 |
42 | #define UFS_QCOM_LIMIT_RX_PWR_PWM SLOW_MODE | 42 | #define UFS_QCOM_LIMIT_RX_PWR_PWM SLOW_MODE |
@@ -64,6 +64,11 @@ enum { | |||
64 | UFS_TEST_BUS_CTRL_2 = 0xF4, | 64 | UFS_TEST_BUS_CTRL_2 = 0xF4, |
65 | UFS_UNIPRO_CFG = 0xF8, | 65 | UFS_UNIPRO_CFG = 0xF8, |
66 | 66 | ||
67 | /* | ||
68 | * QCOM UFS host controller vendor specific registers | ||
69 | * added in HW Version 3.0.0 | ||
70 | */ | ||
71 | UFS_AH8_CFG = 0xFC, | ||
67 | }; | 72 | }; |
68 | 73 | ||
69 | /* QCOM UFS host controller vendor specific debug registers */ | 74 | /* QCOM UFS host controller vendor specific debug registers */ |
@@ -83,6 +88,11 @@ enum { | |||
83 | UFS_UFS_DBG_RD_EDTL_RAM = 0x1900, | 88 | UFS_UFS_DBG_RD_EDTL_RAM = 0x1900, |
84 | }; | 89 | }; |
85 | 90 | ||
91 | #define UFS_CNTLR_2_x_x_VEN_REGS_OFFSET(x) (0x000 + x) | ||
92 | #define UFS_CNTLR_3_x_x_VEN_REGS_OFFSET(x) (0x400 + x) | ||
93 | |||
94 | /* bit definitions for REG_UFS_CFG1 register */ | ||
95 | #define QUNIPRO_SEL UFS_BIT(0) | ||
86 | #define TEST_BUS_EN BIT(18) | 96 | #define TEST_BUS_EN BIT(18) |
87 | #define TEST_BUS_SEL GENMASK(22, 19) | 97 | #define TEST_BUS_SEL GENMASK(22, 19) |
88 | 98 | ||
@@ -131,6 +141,12 @@ enum ufs_qcom_phy_init_type { | |||
131 | (UFS_QCOM_DBG_PRINT_REGS_EN | UFS_QCOM_DBG_PRINT_ICE_REGS_EN | \ | 141 | (UFS_QCOM_DBG_PRINT_REGS_EN | UFS_QCOM_DBG_PRINT_ICE_REGS_EN | \ |
132 | UFS_QCOM_DBG_PRINT_TEST_BUS_EN) | 142 | UFS_QCOM_DBG_PRINT_TEST_BUS_EN) |
133 | 143 | ||
144 | /* QUniPro Vendor specific attributes */ | ||
145 | #define DME_VS_CORE_CLK_CTRL 0xD002 | ||
146 | /* bit and mask definitions for DME_VS_CORE_CLK_CTRL attribute */ | ||
147 | #define DME_VS_CORE_CLK_CTRL_CORE_CLK_DIV_EN_BIT BIT(8) | ||
148 | #define DME_VS_CORE_CLK_CTRL_MAX_CORE_CLK_1US_CYCLES_MASK 0xFF | ||
149 | |||
134 | static inline void | 150 | static inline void |
135 | ufs_qcom_get_controller_revision(struct ufs_hba *hba, | 151 | ufs_qcom_get_controller_revision(struct ufs_hba *hba, |
136 | u8 *major, u16 *minor, u16 *step) | 152 | u8 *major, u16 *minor, u16 *step) |
@@ -196,6 +212,12 @@ struct ufs_qcom_host { | |||
196 | * controller supports the QUniPro mode. | 212 | * controller supports the QUniPro mode. |
197 | */ | 213 | */ |
198 | #define UFS_QCOM_CAP_QUNIPRO UFS_BIT(0) | 214 | #define UFS_QCOM_CAP_QUNIPRO UFS_BIT(0) |
215 | |||
216 | /* | ||
217 | * Set this capability if host controller can retain the secure | ||
218 | * configuration even after UFS controller core power collapse. | ||
219 | */ | ||
220 | #define UFS_QCOM_CAP_RETAIN_SEC_CFG_AFTER_PWR_COLLAPSE UFS_BIT(1) | ||
199 | u32 caps; | 221 | u32 caps; |
200 | 222 | ||
201 | struct phy *generic_phy; | 223 | struct phy *generic_phy; |
@@ -208,7 +230,12 @@ struct ufs_qcom_host { | |||
208 | struct clk *tx_l1_sync_clk; | 230 | struct clk *tx_l1_sync_clk; |
209 | bool is_lane_clks_enabled; | 231 | bool is_lane_clks_enabled; |
210 | 232 | ||
233 | void __iomem *dev_ref_clk_ctrl_mmio; | ||
234 | bool is_dev_ref_clk_enabled; | ||
211 | struct ufs_hw_version hw_ver; | 235 | struct ufs_hw_version hw_ver; |
236 | |||
237 | u32 dev_ref_clk_en_mask; | ||
238 | |||
212 | /* Bitmask for enabling debug prints */ | 239 | /* Bitmask for enabling debug prints */ |
213 | u32 dbg_print_en; | 240 | u32 dbg_print_en; |
214 | struct ufs_qcom_testbus testbus; | 241 | struct ufs_qcom_testbus testbus; |
diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c index 52f9dad96fd1..131c72038bf8 100644 --- a/drivers/scsi/ufs/ufshcd.c +++ b/drivers/scsi/ufs/ufshcd.c | |||
@@ -5420,6 +5420,10 @@ static int ufshcd_scale_clks(struct ufs_hba *hba, bool scale_up) | |||
5420 | if (!head || list_empty(head)) | 5420 | if (!head || list_empty(head)) |
5421 | goto out; | 5421 | goto out; |
5422 | 5422 | ||
5423 | ret = ufshcd_vops_clk_scale_notify(hba, scale_up, PRE_CHANGE); | ||
5424 | if (ret) | ||
5425 | return ret; | ||
5426 | |||
5423 | list_for_each_entry(clki, head, list) { | 5427 | list_for_each_entry(clki, head, list) { |
5424 | if (!IS_ERR_OR_NULL(clki->clk)) { | 5428 | if (!IS_ERR_OR_NULL(clki->clk)) { |
5425 | if (scale_up && clki->max_freq) { | 5429 | if (scale_up && clki->max_freq) { |
@@ -5450,7 +5454,9 @@ static int ufshcd_scale_clks(struct ufs_hba *hba, bool scale_up) | |||
5450 | dev_dbg(hba->dev, "%s: clk: %s, rate: %lu\n", __func__, | 5454 | dev_dbg(hba->dev, "%s: clk: %s, rate: %lu\n", __func__, |
5451 | clki->name, clk_get_rate(clki->clk)); | 5455 | clki->name, clk_get_rate(clki->clk)); |
5452 | } | 5456 | } |
5453 | ufshcd_vops_clk_scale_notify(hba); | 5457 | |
5458 | ret = ufshcd_vops_clk_scale_notify(hba, scale_up, POST_CHANGE); | ||
5459 | |||
5454 | out: | 5460 | out: |
5455 | return ret; | 5461 | return ret; |
5456 | } | 5462 | } |
diff --git a/drivers/scsi/ufs/ufshcd.h b/drivers/scsi/ufs/ufshcd.h index 471c667a1fb4..2570d9477b37 100644 --- a/drivers/scsi/ufs/ufshcd.h +++ b/drivers/scsi/ufs/ufshcd.h | |||
@@ -223,8 +223,10 @@ struct ufs_clk_info { | |||
223 | bool enabled; | 223 | bool enabled; |
224 | }; | 224 | }; |
225 | 225 | ||
226 | #define PRE_CHANGE 0 | 226 | enum ufs_notify_change_status { |
227 | #define POST_CHANGE 1 | 227 | PRE_CHANGE, |
228 | POST_CHANGE, | ||
229 | }; | ||
228 | 230 | ||
229 | struct ufs_pa_layer_attr { | 231 | struct ufs_pa_layer_attr { |
230 | u32 gear_rx; | 232 | u32 gear_rx; |
@@ -266,13 +268,17 @@ struct ufs_hba_variant_ops { | |||
266 | int (*init)(struct ufs_hba *); | 268 | int (*init)(struct ufs_hba *); |
267 | void (*exit)(struct ufs_hba *); | 269 | void (*exit)(struct ufs_hba *); |
268 | u32 (*get_ufs_hci_version)(struct ufs_hba *); | 270 | u32 (*get_ufs_hci_version)(struct ufs_hba *); |
269 | void (*clk_scale_notify)(struct ufs_hba *); | 271 | int (*clk_scale_notify)(struct ufs_hba *, bool, |
270 | int (*setup_clocks)(struct ufs_hba *, bool); | 272 | enum ufs_notify_change_status); |
273 | int (*setup_clocks)(struct ufs_hba *, bool); | ||
271 | int (*setup_regulators)(struct ufs_hba *, bool); | 274 | int (*setup_regulators)(struct ufs_hba *, bool); |
272 | int (*hce_enable_notify)(struct ufs_hba *, bool); | 275 | int (*hce_enable_notify)(struct ufs_hba *, |
273 | int (*link_startup_notify)(struct ufs_hba *, bool); | 276 | enum ufs_notify_change_status); |
277 | int (*link_startup_notify)(struct ufs_hba *, | ||
278 | enum ufs_notify_change_status); | ||
274 | int (*pwr_change_notify)(struct ufs_hba *, | 279 | int (*pwr_change_notify)(struct ufs_hba *, |
275 | bool, struct ufs_pa_layer_attr *, | 280 | enum ufs_notify_change_status status, |
281 | struct ufs_pa_layer_attr *, | ||
276 | struct ufs_pa_layer_attr *); | 282 | struct ufs_pa_layer_attr *); |
277 | int (*suspend)(struct ufs_hba *, enum ufs_pm_op); | 283 | int (*suspend)(struct ufs_hba *, enum ufs_pm_op); |
278 | int (*resume)(struct ufs_hba *, enum ufs_pm_op); | 284 | int (*resume)(struct ufs_hba *, enum ufs_pm_op); |
@@ -708,17 +714,18 @@ static inline u32 ufshcd_vops_get_ufs_hci_version(struct ufs_hba *hba) | |||
708 | return ufshcd_readl(hba, REG_UFS_VERSION); | 714 | return ufshcd_readl(hba, REG_UFS_VERSION); |
709 | } | 715 | } |
710 | 716 | ||
711 | static inline void ufshcd_vops_clk_scale_notify(struct ufs_hba *hba) | 717 | static inline int ufshcd_vops_clk_scale_notify(struct ufs_hba *hba, |
718 | bool up, enum ufs_notify_change_status status) | ||
712 | { | 719 | { |
713 | if (hba->vops && hba->vops->clk_scale_notify) | 720 | if (hba->vops && hba->vops->clk_scale_notify) |
714 | return hba->vops->clk_scale_notify(hba); | 721 | return hba->vops->clk_scale_notify(hba, up, status); |
722 | return 0; | ||
715 | } | 723 | } |
716 | 724 | ||
717 | static inline int ufshcd_vops_setup_clocks(struct ufs_hba *hba, bool on) | 725 | static inline int ufshcd_vops_setup_clocks(struct ufs_hba *hba, bool on) |
718 | { | 726 | { |
719 | if (hba->vops && hba->vops->setup_clocks) | 727 | if (hba->vops && hba->vops->setup_clocks) |
720 | return hba->vops->setup_clocks(hba, on); | 728 | return hba->vops->setup_clocks(hba, on); |
721 | |||
722 | return 0; | 729 | return 0; |
723 | } | 730 | } |
724 | 731 | ||