summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/scsi/ufs/ufshcd.c42
-rw-r--r--drivers/scsi/ufs/ufshcd.h8
-rw-r--r--drivers/scsi/ufs/ufshci.h3
3 files changed, 53 insertions, 0 deletions
diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index 9641bcb90cd2..3e57cca1ef33 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -2640,6 +2640,42 @@ static int ufshcd_hba_enable(struct ufs_hba *hba)
2640 return 0; 2640 return 0;
2641} 2641}
2642 2642
2643static int ufshcd_disable_tx_lcc(struct ufs_hba *hba, bool peer)
2644{
2645 int tx_lanes, i, err = 0;
2646
2647 if (!peer)
2648 ufshcd_dme_get(hba, UIC_ARG_MIB(PA_CONNECTEDTXDATALANES),
2649 &tx_lanes);
2650 else
2651 ufshcd_dme_peer_get(hba, UIC_ARG_MIB(PA_CONNECTEDTXDATALANES),
2652 &tx_lanes);
2653 for (i = 0; i < tx_lanes; i++) {
2654 if (!peer)
2655 err = ufshcd_dme_set(hba,
2656 UIC_ARG_MIB_SEL(TX_LCC_ENABLE,
2657 UIC_ARG_MPHY_TX_GEN_SEL_INDEX(i)),
2658 0);
2659 else
2660 err = ufshcd_dme_peer_set(hba,
2661 UIC_ARG_MIB_SEL(TX_LCC_ENABLE,
2662 UIC_ARG_MPHY_TX_GEN_SEL_INDEX(i)),
2663 0);
2664 if (err) {
2665 dev_err(hba->dev, "%s: TX LCC Disable failed, peer = %d, lane = %d, err = %d",
2666 __func__, peer, i, err);
2667 break;
2668 }
2669 }
2670
2671 return err;
2672}
2673
2674static inline int ufshcd_disable_device_tx_lcc(struct ufs_hba *hba)
2675{
2676 return ufshcd_disable_tx_lcc(hba, true);
2677}
2678
2643/** 2679/**
2644 * ufshcd_link_startup - Initialize unipro link startup 2680 * ufshcd_link_startup - Initialize unipro link startup
2645 * @hba: per adapter instance 2681 * @hba: per adapter instance
@@ -2677,6 +2713,12 @@ static int ufshcd_link_startup(struct ufs_hba *hba)
2677 /* failed to get the link up... retire */ 2713 /* failed to get the link up... retire */
2678 goto out; 2714 goto out;
2679 2715
2716 if (hba->quirks & UFSHCD_QUIRK_BROKEN_LCC) {
2717 ret = ufshcd_disable_device_tx_lcc(hba);
2718 if (ret)
2719 goto out;
2720 }
2721
2680 /* Include any host controller configuration via UIC commands */ 2722 /* Include any host controller configuration via UIC commands */
2681 if (hba->vops && hba->vops->link_startup_notify) { 2723 if (hba->vops && hba->vops->link_startup_notify) {
2682 ret = hba->vops->link_startup_notify(hba, POST_CHANGE); 2724 ret = hba->vops->link_startup_notify(hba, POST_CHANGE);
diff --git a/drivers/scsi/ufs/ufshcd.h b/drivers/scsi/ufs/ufshcd.h
index fc8bec9960b1..b845f1535f29 100644
--- a/drivers/scsi/ufs/ufshcd.h
+++ b/drivers/scsi/ufs/ufshcd.h
@@ -426,6 +426,14 @@ struct ufs_hba {
426 */ 426 */
427 #define UFSHCD_QUIRK_DELAY_BEFORE_DME_CMDS UFS_BIT(1) 427 #define UFSHCD_QUIRK_DELAY_BEFORE_DME_CMDS UFS_BIT(1)
428 428
429 /*
430 * If UFS host controller is having issue in processing LCC (Line
431 * Control Command) coming from device then enable this quirk.
432 * When this quirk is enabled, host controller driver should disable
433 * the LCC transmission on UFS device (by clearing TX_LCC_ENABLE
434 * attribute of device to 0).
435 */
436 #define UFSHCD_QUIRK_BROKEN_LCC UFS_BIT(2)
429 437
430 unsigned int quirks; /* Deviations from standard UFSHCI spec. */ 438 unsigned int quirks; /* Deviations from standard UFSHCI spec. */
431 439
diff --git a/drivers/scsi/ufs/ufshci.h b/drivers/scsi/ufs/ufshci.h
index d5721199e9cc..f8909ece2171 100644
--- a/drivers/scsi/ufs/ufshci.h
+++ b/drivers/scsi/ufs/ufshci.h
@@ -206,6 +206,9 @@ enum {
206#define CONFIG_RESULT_CODE_MASK 0xFF 206#define CONFIG_RESULT_CODE_MASK 0xFF
207#define GENERIC_ERROR_CODE_MASK 0xFF 207#define GENERIC_ERROR_CODE_MASK 0xFF
208 208
209/* GenSelectorIndex calculation macros for M-PHY attributes */
210#define UIC_ARG_MPHY_TX_GEN_SEL_INDEX(lane) (lane)
211
209#define UIC_ARG_MIB_SEL(attr, sel) ((((attr) & 0xFFFF) << 16) |\ 212#define UIC_ARG_MIB_SEL(attr, sel) ((((attr) & 0xFFFF) << 16) |\
210 ((sel) & 0xFFFF)) 213 ((sel) & 0xFFFF))
211#define UIC_ARG_MIB(attr) UIC_ARG_MIB_SEL(attr, 0) 214#define UIC_ARG_MIB(attr) UIC_ARG_MIB_SEL(attr, 0)