summaryrefslogtreecommitdiffstats
path: root/drivers/scsi
diff options
context:
space:
mode:
authorYaniv Gardi <ygardi@codeaurora.org>2015-10-28 07:15:50 -0400
committerMartin K. Petersen <martin.petersen@oracle.com>2015-11-09 18:01:58 -0500
commit6e3fd44d7b7638e0f7e3331eaf7f90f3a629f3e7 (patch)
treeed87dbce836a6775e30974c591804d82aa0dd4e7 /drivers/scsi
parent47555a5c8a11a423e6767f942941c745766c99a2 (diff)
scsi: ufs-qcom: add debug prints for test bus
Adds support for configuring and reading the test bus and debug registers. This change also adds another vops in order to print the debug registers. Reviewed-by: Subhash Jadavani <subhashj@codeaurora.org> Reviewed-by: Gilad Broner <gbroner@codeaurora.org> Signed-off-by: Yaniv Gardi <ygardi@codeaurora.org> Reviewed-by: Hannes Reinecke <hare@suse.de> Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
Diffstat (limited to 'drivers/scsi')
-rw-r--r--drivers/scsi/ufs/ufs-qcom.c165
-rw-r--r--drivers/scsi/ufs/ufs-qcom.h37
-rw-r--r--drivers/scsi/ufs/ufshcd.c2
-rw-r--r--drivers/scsi/ufs/ufshcd.h8
4 files changed, 208 insertions, 4 deletions
diff --git a/drivers/scsi/ufs/ufs-qcom.c b/drivers/scsi/ufs/ufs-qcom.c
index b275a9a3b4d5..16338083b0d3 100644
--- a/drivers/scsi/ufs/ufs-qcom.c
+++ b/drivers/scsi/ufs/ufs-qcom.c
@@ -23,6 +23,24 @@
23#include "unipro.h" 23#include "unipro.h"
24#include "ufs-qcom.h" 24#include "ufs-qcom.h"
25#include "ufshci.h" 25#include "ufshci.h"
26#define UFS_QCOM_DEFAULT_DBG_PRINT_EN \
27 (UFS_QCOM_DBG_PRINT_REGS_EN | UFS_QCOM_DBG_PRINT_TEST_BUS_EN)
28
29enum {
30 TSTBUS_UAWM,
31 TSTBUS_UARM,
32 TSTBUS_TXUC,
33 TSTBUS_RXUC,
34 TSTBUS_DFC,
35 TSTBUS_TRLUT,
36 TSTBUS_TMRLUT,
37 TSTBUS_OCSC,
38 TSTBUS_UTP_HCI,
39 TSTBUS_COMBINED,
40 TSTBUS_WRAPPER,
41 TSTBUS_UNIPRO,
42 TSTBUS_MAX,
43};
26 44
27static struct ufs_qcom_host *ufs_qcom_hosts[MAX_UFS_QCOM_HOSTS]; 45static struct ufs_qcom_host *ufs_qcom_hosts[MAX_UFS_QCOM_HOSTS];
28 46
@@ -30,6 +48,15 @@ static void ufs_qcom_get_speed_mode(struct ufs_pa_layer_attr *p, char *result);
30static int ufs_qcom_get_bus_vote(struct ufs_qcom_host *host, 48static int ufs_qcom_get_bus_vote(struct ufs_qcom_host *host,
31 const char *speed_mode); 49 const char *speed_mode);
32static int ufs_qcom_set_bus_vote(struct ufs_qcom_host *host, int vote); 50static int ufs_qcom_set_bus_vote(struct ufs_qcom_host *host, int vote);
51static void ufs_qcom_get_default_testbus_cfg(struct ufs_qcom_host *host);
52static void ufs_qcom_dump_regs(struct ufs_hba *hba, int offset, int len,
53 char *prefix)
54{
55 print_hex_dump(KERN_ERR, prefix,
56 len > 4 ? DUMP_PREFIX_OFFSET : DUMP_PREFIX_NONE,
57 16, 4, (void __force *)hba->mmio_base + offset,
58 len * 4, false);
59}
33 60
34static int ufs_qcom_get_connected_tx_lanes(struct ufs_hba *hba, u32 *tx_lanes) 61static int ufs_qcom_get_connected_tx_lanes(struct ufs_hba *hba, u32 *tx_lanes)
35{ 62{
@@ -996,6 +1023,15 @@ static int ufs_qcom_init(struct ufs_hba *hba)
996 if (hba->dev->id < MAX_UFS_QCOM_HOSTS) 1023 if (hba->dev->id < MAX_UFS_QCOM_HOSTS)
997 ufs_qcom_hosts[hba->dev->id] = host; 1024 ufs_qcom_hosts[hba->dev->id] = host;
998 1025
1026 host->dbg_print_en |= UFS_QCOM_DEFAULT_DBG_PRINT_EN;
1027 ufs_qcom_get_default_testbus_cfg(host);
1028 err = ufs_qcom_testbus_config(host);
1029 if (err) {
1030 dev_warn(dev, "%s: failed to configure the testbus %d\n",
1031 __func__, err);
1032 err = 0;
1033 }
1034
999 goto out; 1035 goto out;
1000 1036
1001out_disable_phy: 1037out_disable_phy:
@@ -1025,12 +1061,134 @@ void ufs_qcom_clk_scale_notify(struct ufs_hba *hba)
1025 1061
1026 if (!dev_req_params) 1062 if (!dev_req_params)
1027 return; 1063 return;
1064}
1065
1066static void ufs_qcom_get_default_testbus_cfg(struct ufs_qcom_host *host)
1067{
1068 /* provide a legal default configuration */
1069 host->testbus.select_major = TSTBUS_UAWM;
1070 host->testbus.select_minor = 1;
1071}
1072
1073static bool ufs_qcom_testbus_cfg_is_ok(struct ufs_qcom_host *host)
1074{
1075 if (host->testbus.select_major >= TSTBUS_MAX) {
1076 dev_err(host->hba->dev,
1077 "%s: UFS_CFG1[TEST_BUS_SEL} may not equal 0x%05X\n",
1078 __func__, host->testbus.select_major);
1079 return false;
1080 }
1081
1082 /*
1083 * Not performing check for each individual select_major
1084 * mappings of select_minor, since there is no harm in
1085 * configuring a non-existent select_minor
1086 */
1087 if (host->testbus.select_minor > 0x1F) {
1088 dev_err(host->hba->dev,
1089 "%s: 0x%05X is not a legal testbus option\n",
1090 __func__, host->testbus.select_minor);
1091 return false;
1092 }
1093
1094 return true;
1095}
1096
1097int ufs_qcom_testbus_config(struct ufs_qcom_host *host)
1098{
1099 int reg;
1100 int offset;
1101 u32 mask = TEST_BUS_SUB_SEL_MASK;
1102
1103 if (!host)
1104 return -EINVAL;
1028 1105
1029 ufs_qcom_cfg_timers(hba, dev_req_params->gear_rx, 1106 if (!ufs_qcom_testbus_cfg_is_ok(host))
1030 dev_req_params->pwr_rx, 1107 return -EPERM;
1031 dev_req_params->hs_rate); 1108
1109 switch (host->testbus.select_major) {
1110 case TSTBUS_UAWM:
1111 reg = UFS_TEST_BUS_CTRL_0;
1112 offset = 24;
1113 break;
1114 case TSTBUS_UARM:
1115 reg = UFS_TEST_BUS_CTRL_0;
1116 offset = 16;
1117 break;
1118 case TSTBUS_TXUC:
1119 reg = UFS_TEST_BUS_CTRL_0;
1120 offset = 8;
1121 break;
1122 case TSTBUS_RXUC:
1123 reg = UFS_TEST_BUS_CTRL_0;
1124 offset = 0;
1125 break;
1126 case TSTBUS_DFC:
1127 reg = UFS_TEST_BUS_CTRL_1;
1128 offset = 24;
1129 break;
1130 case TSTBUS_TRLUT:
1131 reg = UFS_TEST_BUS_CTRL_1;
1132 offset = 16;
1133 break;
1134 case TSTBUS_TMRLUT:
1135 reg = UFS_TEST_BUS_CTRL_1;
1136 offset = 8;
1137 break;
1138 case TSTBUS_OCSC:
1139 reg = UFS_TEST_BUS_CTRL_1;
1140 offset = 0;
1141 break;
1142 case TSTBUS_WRAPPER:
1143 reg = UFS_TEST_BUS_CTRL_2;
1144 offset = 16;
1145 break;
1146 case TSTBUS_COMBINED:
1147 reg = UFS_TEST_BUS_CTRL_2;
1148 offset = 8;
1149 break;
1150 case TSTBUS_UTP_HCI:
1151 reg = UFS_TEST_BUS_CTRL_2;
1152 offset = 0;
1153 break;
1154 case TSTBUS_UNIPRO:
1155 reg = UFS_UNIPRO_CFG;
1156 offset = 1;
1157 break;
1158 /*
1159 * No need for a default case, since
1160 * ufs_qcom_testbus_cfg_is_ok() checks that the configuration
1161 * is legal
1162 */
1163 }
1164 mask <<= offset;
1165
1166 pm_runtime_get_sync(host->hba->dev);
1167 ufshcd_hold(host->hba, false);
1168 ufshcd_rmwl(host->hba, TEST_BUS_SEL,
1169 (u32)host->testbus.select_major << 19,
1170 REG_UFS_CFG1);
1171 ufshcd_rmwl(host->hba, mask,
1172 (u32)host->testbus.select_minor << offset,
1173 reg);
1174 ufshcd_release(host->hba);
1175 pm_runtime_put_sync(host->hba->dev);
1176
1177 return 0;
1032} 1178}
1033 1179
1180static void ufs_qcom_testbus_read(struct ufs_hba *hba)
1181{
1182 ufs_qcom_dump_regs(hba, UFS_TEST_BUS, 1, "UFS_TEST_BUS ");
1183}
1184
1185static void ufs_qcom_dump_dbg_regs(struct ufs_hba *hba)
1186{
1187 ufs_qcom_dump_regs(hba, REG_UFS_SYS1CLK_1US, 16,
1188 "HCI Vendor Specific Registers ");
1189
1190 ufs_qcom_testbus_read(hba);
1191}
1034/** 1192/**
1035 * struct ufs_hba_qcom_vops - UFS QCOM specific variant operations 1193 * struct ufs_hba_qcom_vops - UFS QCOM specific variant operations
1036 * 1194 *
@@ -1049,6 +1207,7 @@ static struct ufs_hba_variant_ops ufs_hba_qcom_vops = {
1049 .pwr_change_notify = ufs_qcom_pwr_change_notify, 1207 .pwr_change_notify = ufs_qcom_pwr_change_notify,
1050 .suspend = ufs_qcom_suspend, 1208 .suspend = ufs_qcom_suspend,
1051 .resume = ufs_qcom_resume, 1209 .resume = ufs_qcom_resume,
1210 .dbg_register_dump = ufs_qcom_dump_dbg_regs,
1052}; 1211};
1053 1212
1054/** 1213/**
diff --git a/drivers/scsi/ufs/ufs-qcom.h b/drivers/scsi/ufs/ufs-qcom.h
index db2c0a00e846..1b71a1b0be9f 100644
--- a/drivers/scsi/ufs/ufs-qcom.h
+++ b/drivers/scsi/ufs/ufs-qcom.h
@@ -58,6 +58,16 @@ enum {
58 REG_UFS_CFG2 = 0xE0, 58 REG_UFS_CFG2 = 0xE0,
59 REG_UFS_HW_VERSION = 0xE4, 59 REG_UFS_HW_VERSION = 0xE4,
60 60
61 UFS_TEST_BUS = 0xE8,
62 UFS_TEST_BUS_CTRL_0 = 0xEC,
63 UFS_TEST_BUS_CTRL_1 = 0xF0,
64 UFS_TEST_BUS_CTRL_2 = 0xF4,
65 UFS_UNIPRO_CFG = 0xF8,
66
67};
68
69/* QCOM UFS host controller vendor specific debug registers */
70enum {
61 UFS_DBG_RD_REG_UAWM = 0x100, 71 UFS_DBG_RD_REG_UAWM = 0x100,
62 UFS_DBG_RD_REG_UARM = 0x200, 72 UFS_DBG_RD_REG_UARM = 0x200,
63 UFS_DBG_RD_REG_TXUC = 0x300, 73 UFS_DBG_RD_REG_TXUC = 0x300,
@@ -73,6 +83,9 @@ enum {
73 UFS_UFS_DBG_RD_EDTL_RAM = 0x1900, 83 UFS_UFS_DBG_RD_EDTL_RAM = 0x1900,
74}; 84};
75 85
86#define TEST_BUS_EN BIT(18)
87#define TEST_BUS_SEL GENMASK(22, 19)
88
76/* bit definitions for REG_UFS_CFG2 register */ 89/* bit definitions for REG_UFS_CFG2 register */
77#define UAWM_HW_CGC_EN (1 << 0) 90#define UAWM_HW_CGC_EN (1 << 0)
78#define UARM_HW_CGC_EN (1 << 1) 91#define UARM_HW_CGC_EN (1 << 1)
@@ -83,6 +96,9 @@ enum {
83#define TMRLUT_HW_CGC_EN (1 << 6) 96#define TMRLUT_HW_CGC_EN (1 << 6)
84#define OCSC_HW_CGC_EN (1 << 7) 97#define OCSC_HW_CGC_EN (1 << 7)
85 98
99/* bit definition for UFS_UFS_TEST_BUS_CTRL_n */
100#define TEST_BUS_SUB_SEL_MASK 0x1F /* All XXX_SEL fields are 5 bits wide */
101
86#define REG_UFS_CFG2_CGC_EN_ALL (UAWM_HW_CGC_EN | UARM_HW_CGC_EN |\ 102#define REG_UFS_CFG2_CGC_EN_ALL (UAWM_HW_CGC_EN | UARM_HW_CGC_EN |\
87 TXUC_HW_CGC_EN | RXUC_HW_CGC_EN |\ 103 TXUC_HW_CGC_EN | RXUC_HW_CGC_EN |\
88 DFC_HW_CGC_EN | TRLUT_HW_CGC_EN |\ 104 DFC_HW_CGC_EN | TRLUT_HW_CGC_EN |\
@@ -106,6 +122,15 @@ enum ufs_qcom_phy_init_type {
106 UFS_PHY_INIT_CFG_RESTORE, 122 UFS_PHY_INIT_CFG_RESTORE,
107}; 123};
108 124
125/* QCOM UFS debug print bit mask */
126#define UFS_QCOM_DBG_PRINT_REGS_EN BIT(0)
127#define UFS_QCOM_DBG_PRINT_ICE_REGS_EN BIT(1)
128#define UFS_QCOM_DBG_PRINT_TEST_BUS_EN BIT(2)
129
130#define UFS_QCOM_DBG_PRINT_ALL \
131 (UFS_QCOM_DBG_PRINT_REGS_EN | UFS_QCOM_DBG_PRINT_ICE_REGS_EN | \
132 UFS_QCOM_DBG_PRINT_TEST_BUS_EN)
133
109static inline void 134static inline void
110ufs_qcom_get_controller_revision(struct ufs_hba *hba, 135ufs_qcom_get_controller_revision(struct ufs_hba *hba,
111 u8 *major, u16 *minor, u16 *step) 136 u8 *major, u16 *minor, u16 *step)
@@ -157,8 +182,13 @@ struct ufs_hw_version {
157 u16 minor; 182 u16 minor;
158 u8 major; 183 u8 major;
159}; 184};
160struct ufs_qcom_host {
161 185
186struct ufs_qcom_testbus {
187 u8 select_major;
188 u8 select_minor;
189};
190
191struct ufs_qcom_host {
162 /* 192 /*
163 * Set this capability if host controller supports the QUniPro mode 193 * Set this capability if host controller supports the QUniPro mode
164 * and if driver wants the Host controller to operate in QUniPro mode. 194 * and if driver wants the Host controller to operate in QUniPro mode.
@@ -179,12 +209,17 @@ struct ufs_qcom_host {
179 bool is_lane_clks_enabled; 209 bool is_lane_clks_enabled;
180 210
181 struct ufs_hw_version hw_ver; 211 struct ufs_hw_version hw_ver;
212 /* Bitmask for enabling debug prints */
213 u32 dbg_print_en;
214 struct ufs_qcom_testbus testbus;
182}; 215};
183 216
184#define ufs_qcom_is_link_off(hba) ufshcd_is_link_off(hba) 217#define ufs_qcom_is_link_off(hba) ufshcd_is_link_off(hba)
185#define ufs_qcom_is_link_active(hba) ufshcd_is_link_active(hba) 218#define ufs_qcom_is_link_active(hba) ufshcd_is_link_active(hba)
186#define ufs_qcom_is_link_hibern8(hba) ufshcd_is_link_hibern8(hba) 219#define ufs_qcom_is_link_hibern8(hba) ufshcd_is_link_hibern8(hba)
187 220
221int ufs_qcom_testbus_config(struct ufs_qcom_host *host);
222
188static inline bool ufs_qcom_cap_qunipro(struct ufs_qcom_host *host) 223static inline bool ufs_qcom_cap_qunipro(struct ufs_qcom_host *host)
189{ 224{
190 if (host->caps & UFS_QCOM_CAP_QUNIPRO) 225 if (host->caps & UFS_QCOM_CAP_QUNIPRO)
diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index 2ef98346dc6e..52f9dad96fd1 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -625,6 +625,7 @@ start:
625out: 625out:
626 return rc; 626 return rc;
627} 627}
628EXPORT_SYMBOL_GPL(ufshcd_hold);
628 629
629static void ufshcd_gate_work(struct work_struct *work) 630static void ufshcd_gate_work(struct work_struct *work)
630{ 631{
@@ -712,6 +713,7 @@ void ufshcd_release(struct ufs_hba *hba)
712 __ufshcd_release(hba); 713 __ufshcd_release(hba);
713 spin_unlock_irqrestore(hba->host->host_lock, flags); 714 spin_unlock_irqrestore(hba->host->host_lock, flags);
714} 715}
716EXPORT_SYMBOL_GPL(ufshcd_release);
715 717
716static ssize_t ufshcd_clkgate_delay_show(struct device *dev, 718static ssize_t ufshcd_clkgate_delay_show(struct device *dev,
717 struct device_attribute *attr, char *buf) 719 struct device_attribute *attr, char *buf)
diff --git a/drivers/scsi/ufs/ufshcd.h b/drivers/scsi/ufs/ufshcd.h
index f2aa47e15b13..471c667a1fb4 100644
--- a/drivers/scsi/ufs/ufshcd.h
+++ b/drivers/scsi/ufs/ufshcd.h
@@ -259,6 +259,7 @@ struct ufs_pwr_mode_info {
259 * to be set. 259 * to be set.
260 * @suspend: called during host controller PM callback 260 * @suspend: called during host controller PM callback
261 * @resume: called during host controller PM callback 261 * @resume: called during host controller PM callback
262 * @dbg_register_dump: used to dump controller debug information
262 */ 263 */
263struct ufs_hba_variant_ops { 264struct ufs_hba_variant_ops {
264 const char *name; 265 const char *name;
@@ -275,6 +276,7 @@ struct ufs_hba_variant_ops {
275 struct ufs_pa_layer_attr *); 276 struct ufs_pa_layer_attr *);
276 int (*suspend)(struct ufs_hba *, enum ufs_pm_op); 277 int (*suspend)(struct ufs_hba *, enum ufs_pm_op);
277 int (*resume)(struct ufs_hba *, enum ufs_pm_op); 278 int (*resume)(struct ufs_hba *, enum ufs_pm_op);
279 void (*dbg_register_dump)(struct ufs_hba *hba);
278}; 280};
279 281
280/* clock gating state */ 282/* clock gating state */
@@ -773,4 +775,10 @@ static inline int ufshcd_vops_resume(struct ufs_hba *hba, enum ufs_pm_op op)
773 return 0; 775 return 0;
774} 776}
775 777
778static inline void ufshcd_vops_dbg_register_dump(struct ufs_hba *hba)
779{
780 if (hba->vops && hba->vops->dbg_register_dump)
781 hba->vops->dbg_register_dump(hba);
782}
783
776#endif /* End of Header */ 784#endif /* End of Header */