1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * Synopsys G210 Test Chip driver 4 * 5 * Copyright (C) 2015-2016 Synopsys, Inc. (www.synopsys.com) 6 * 7 * Authors: Joao Pinto <jpinto@synopsys.com> 8 */ 9 10 #include <linux/module.h> 11 12 #include <ufs/ufshcd.h> 13 #include <ufs/unipro.h> 14 15 #include "ufshcd-dwc.h" 16 #include "ufshci-dwc.h" 17 #include "tc-dwc-g210.h" 18 19 /** 20 * tc_dwc_g210_setup_40bit_rmmi() 21 * This function configures Synopsys TC specific atributes (40-bit RMMI) 22 * @hba: Pointer to drivers structure 23 * 24 * Returns 0 on success or non-zero value on failure 25 */ 26 static int tc_dwc_g210_setup_40bit_rmmi(struct ufs_hba *hba) 27 { 28 static const struct ufshcd_dme_attr_val setup_attrs[] = { 29 { UIC_ARG_MIB(TX_GLOBALHIBERNATE), 0x00, DME_LOCAL }, 30 { UIC_ARG_MIB(REFCLKMODE), 0x01, DME_LOCAL }, 31 { UIC_ARG_MIB(CDIRECTCTRL6), 0x80, DME_LOCAL }, 32 { UIC_ARG_MIB(CBDIVFACTOR), 0x08, DME_LOCAL }, 33 { UIC_ARG_MIB(CBDCOCTRL5), 0x64, DME_LOCAL }, 34 { UIC_ARG_MIB(CBPRGTUNING), 0x09, DME_LOCAL }, 35 { UIC_ARG_MIB(RTOBSERVESELECT), 0x00, DME_LOCAL }, 36 { UIC_ARG_MIB_SEL(TX_REFCLKFREQ, SELIND_LN0_TX), 0x01, 37 DME_LOCAL }, 38 { UIC_ARG_MIB_SEL(TX_CFGCLKFREQVAL, SELIND_LN0_TX), 0x19, 39 DME_LOCAL }, 40 { UIC_ARG_MIB_SEL(CFGEXTRATTR, SELIND_LN0_TX), 0x14, 41 DME_LOCAL }, 42 { UIC_ARG_MIB_SEL(DITHERCTRL2, SELIND_LN0_TX), 0xd6, 43 DME_LOCAL }, 44 { UIC_ARG_MIB_SEL(RX_REFCLKFREQ, SELIND_LN0_RX), 0x01, 45 DME_LOCAL }, 46 { UIC_ARG_MIB_SEL(RX_CFGCLKFREQVAL, SELIND_LN0_RX), 0x19, 47 DME_LOCAL }, 48 { UIC_ARG_MIB_SEL(CFGWIDEINLN, SELIND_LN0_RX), 4, 49 DME_LOCAL }, 50 { UIC_ARG_MIB_SEL(CFGRXCDR8, SELIND_LN0_RX), 0x80, 51 DME_LOCAL }, 52 { UIC_ARG_MIB(DIRECTCTRL10), 0x04, DME_LOCAL }, 53 { UIC_ARG_MIB(DIRECTCTRL19), 0x02, DME_LOCAL }, 54 { UIC_ARG_MIB_SEL(CFGRXCDR8, SELIND_LN0_RX), 0x80, 55 DME_LOCAL }, 56 { UIC_ARG_MIB_SEL(ENARXDIRECTCFG4, SELIND_LN0_RX), 0x03, 57 DME_LOCAL }, 58 { UIC_ARG_MIB_SEL(CFGRXOVR8, SELIND_LN0_RX), 0x16, 59 DME_LOCAL }, 60 { UIC_ARG_MIB_SEL(RXDIRECTCTRL2, SELIND_LN0_RX), 0x42, 61 DME_LOCAL }, 62 { UIC_ARG_MIB_SEL(ENARXDIRECTCFG3, SELIND_LN0_RX), 0xa4, 63 DME_LOCAL }, 64 { UIC_ARG_MIB_SEL(RXCALCTRL, SELIND_LN0_RX), 0x01, 65 DME_LOCAL }, 66 { UIC_ARG_MIB_SEL(ENARXDIRECTCFG2, SELIND_LN0_RX), 0x01, 67 DME_LOCAL }, 68 { UIC_ARG_MIB_SEL(CFGRXOVR4, SELIND_LN0_RX), 0x28, 69 DME_LOCAL }, 70 { UIC_ARG_MIB_SEL(RXSQCTRL, SELIND_LN0_RX), 0x1E, 71 DME_LOCAL }, 72 { UIC_ARG_MIB_SEL(CFGRXOVR6, SELIND_LN0_RX), 0x2f, 73 DME_LOCAL }, 74 { UIC_ARG_MIB_SEL(CFGRXOVR6, SELIND_LN0_RX), 0x2f, 75 DME_LOCAL }, 76 { UIC_ARG_MIB(CBPRGPLL2), 0x00, DME_LOCAL }, 77 }; 78 79 return ufshcd_dwc_dme_set_attrs(hba, setup_attrs, 80 ARRAY_SIZE(setup_attrs)); 81 } 82 83 /** 84 * tc_dwc_g210_setup_20bit_rmmi_lane0() 85 * This function configures Synopsys TC 20-bit RMMI Lane 0 86 * @hba: Pointer to drivers structure 87 * 88 * Returns 0 on success or non-zero value on failure 89 */ 90 static int tc_dwc_g210_setup_20bit_rmmi_lane0(struct ufs_hba *hba) 91 { 92 static const struct ufshcd_dme_attr_val setup_attrs[] = { 93 { UIC_ARG_MIB_SEL(TX_REFCLKFREQ, SELIND_LN0_TX), 0x01, 94 DME_LOCAL }, 95 { UIC_ARG_MIB_SEL(TX_CFGCLKFREQVAL, SELIND_LN0_TX), 0x19, 96 DME_LOCAL }, 97 { UIC_ARG_MIB_SEL(RX_CFGCLKFREQVAL, SELIND_LN0_RX), 0x19, 98 DME_LOCAL }, 99 { UIC_ARG_MIB_SEL(CFGEXTRATTR, SELIND_LN0_TX), 0x12, 100 DME_LOCAL }, 101 { UIC_ARG_MIB_SEL(DITHERCTRL2, SELIND_LN0_TX), 0xd6, 102 DME_LOCAL }, 103 { UIC_ARG_MIB_SEL(RX_REFCLKFREQ, SELIND_LN0_RX), 0x01, 104 DME_LOCAL }, 105 { UIC_ARG_MIB_SEL(CFGWIDEINLN, SELIND_LN0_RX), 2, 106 DME_LOCAL }, 107 { UIC_ARG_MIB_SEL(CFGRXCDR8, SELIND_LN0_RX), 0x80, 108 DME_LOCAL }, 109 { UIC_ARG_MIB(DIRECTCTRL10), 0x04, DME_LOCAL }, 110 { UIC_ARG_MIB(DIRECTCTRL19), 0x02, DME_LOCAL }, 111 { UIC_ARG_MIB_SEL(ENARXDIRECTCFG4, SELIND_LN0_RX), 0x03, 112 DME_LOCAL }, 113 { UIC_ARG_MIB_SEL(CFGRXOVR8, SELIND_LN0_RX), 0x16, 114 DME_LOCAL }, 115 { UIC_ARG_MIB_SEL(RXDIRECTCTRL2, SELIND_LN0_RX), 0x42, 116 DME_LOCAL }, 117 { UIC_ARG_MIB_SEL(ENARXDIRECTCFG3, SELIND_LN0_RX), 0xa4, 118 DME_LOCAL }, 119 { UIC_ARG_MIB_SEL(RXCALCTRL, SELIND_LN0_RX), 0x01, 120 DME_LOCAL }, 121 { UIC_ARG_MIB_SEL(ENARXDIRECTCFG2, SELIND_LN0_RX), 0x01, 122 DME_LOCAL }, 123 { UIC_ARG_MIB_SEL(CFGRXOVR4, SELIND_LN0_RX), 0x28, 124 DME_LOCAL }, 125 { UIC_ARG_MIB_SEL(RXSQCTRL, SELIND_LN0_RX), 0x1E, 126 DME_LOCAL }, 127 { UIC_ARG_MIB_SEL(CFGRXOVR6, SELIND_LN0_RX), 0x2f, 128 DME_LOCAL }, 129 { UIC_ARG_MIB(CBPRGPLL2), 0x00, DME_LOCAL }, 130 }; 131 132 return ufshcd_dwc_dme_set_attrs(hba, setup_attrs, 133 ARRAY_SIZE(setup_attrs)); 134 } 135 136 /** 137 * tc_dwc_g210_setup_20bit_rmmi_lane1() 138 * This function configures Synopsys TC 20-bit RMMI Lane 1 139 * @hba: Pointer to drivers structure 140 * 141 * Returns 0 on success or non-zero value on failure 142 */ 143 static int tc_dwc_g210_setup_20bit_rmmi_lane1(struct ufs_hba *hba) 144 { 145 int connected_rx_lanes = 0; 146 int connected_tx_lanes = 0; 147 int ret = 0; 148 149 static const struct ufshcd_dme_attr_val setup_tx_attrs[] = { 150 { UIC_ARG_MIB_SEL(TX_REFCLKFREQ, SELIND_LN1_TX), 0x0d, 151 DME_LOCAL }, 152 { UIC_ARG_MIB_SEL(TX_CFGCLKFREQVAL, SELIND_LN1_TX), 0x19, 153 DME_LOCAL }, 154 { UIC_ARG_MIB_SEL(CFGEXTRATTR, SELIND_LN1_TX), 0x12, 155 DME_LOCAL }, 156 { UIC_ARG_MIB_SEL(DITHERCTRL2, SELIND_LN0_TX), 0xd6, 157 DME_LOCAL }, 158 }; 159 160 static const struct ufshcd_dme_attr_val setup_rx_attrs[] = { 161 { UIC_ARG_MIB_SEL(RX_REFCLKFREQ, SELIND_LN1_RX), 0x01, 162 DME_LOCAL }, 163 { UIC_ARG_MIB_SEL(RX_CFGCLKFREQVAL, SELIND_LN1_RX), 0x19, 164 DME_LOCAL }, 165 { UIC_ARG_MIB_SEL(CFGWIDEINLN, SELIND_LN1_RX), 2, 166 DME_LOCAL }, 167 { UIC_ARG_MIB_SEL(CFGRXCDR8, SELIND_LN1_RX), 0x80, 168 DME_LOCAL }, 169 { UIC_ARG_MIB_SEL(ENARXDIRECTCFG4, SELIND_LN1_RX), 0x03, 170 DME_LOCAL }, 171 { UIC_ARG_MIB_SEL(CFGRXOVR8, SELIND_LN1_RX), 0x16, 172 DME_LOCAL }, 173 { UIC_ARG_MIB_SEL(RXDIRECTCTRL2, SELIND_LN1_RX), 0x42, 174 DME_LOCAL }, 175 { UIC_ARG_MIB_SEL(ENARXDIRECTCFG3, SELIND_LN1_RX), 0xa4, 176 DME_LOCAL }, 177 { UIC_ARG_MIB_SEL(RXCALCTRL, SELIND_LN1_RX), 0x01, 178 DME_LOCAL }, 179 { UIC_ARG_MIB_SEL(ENARXDIRECTCFG2, SELIND_LN1_RX), 0x01, 180 DME_LOCAL }, 181 { UIC_ARG_MIB_SEL(CFGRXOVR4, SELIND_LN1_RX), 0x28, 182 DME_LOCAL }, 183 { UIC_ARG_MIB_SEL(RXSQCTRL, SELIND_LN1_RX), 0x1E, 184 DME_LOCAL }, 185 { UIC_ARG_MIB_SEL(CFGRXOVR6, SELIND_LN1_RX), 0x2f, 186 DME_LOCAL }, 187 }; 188 189 /* Get the available lane count */ 190 ufshcd_dme_get(hba, UIC_ARG_MIB(PA_AVAILRXDATALANES), 191 &connected_rx_lanes); 192 ufshcd_dme_get(hba, UIC_ARG_MIB(PA_AVAILTXDATALANES), 193 &connected_tx_lanes); 194 195 if (connected_tx_lanes == 2) { 196 197 ret = ufshcd_dwc_dme_set_attrs(hba, setup_tx_attrs, 198 ARRAY_SIZE(setup_tx_attrs)); 199 200 if (ret) 201 goto out; 202 } 203 204 if (connected_rx_lanes == 2) { 205 ret = ufshcd_dwc_dme_set_attrs(hba, setup_rx_attrs, 206 ARRAY_SIZE(setup_rx_attrs)); 207 } 208 209 out: 210 return ret; 211 } 212 213 /** 214 * tc_dwc_g210_setup_20bit_rmmi() 215 * This function configures Synopsys TC specific atributes (20-bit RMMI) 216 * @hba: Pointer to drivers structure 217 * 218 * Returns 0 on success or non-zero value on failure 219 */ 220 static int tc_dwc_g210_setup_20bit_rmmi(struct ufs_hba *hba) 221 { 222 int ret = 0; 223 224 static const struct ufshcd_dme_attr_val setup_attrs[] = { 225 { UIC_ARG_MIB(TX_GLOBALHIBERNATE), 0x00, DME_LOCAL }, 226 { UIC_ARG_MIB(REFCLKMODE), 0x01, DME_LOCAL }, 227 { UIC_ARG_MIB(CDIRECTCTRL6), 0xc0, DME_LOCAL }, 228 { UIC_ARG_MIB(CBDIVFACTOR), 0x44, DME_LOCAL }, 229 { UIC_ARG_MIB(CBDCOCTRL5), 0x64, DME_LOCAL }, 230 { UIC_ARG_MIB(CBPRGTUNING), 0x09, DME_LOCAL }, 231 { UIC_ARG_MIB(RTOBSERVESELECT), 0x00, DME_LOCAL }, 232 }; 233 234 ret = ufshcd_dwc_dme_set_attrs(hba, setup_attrs, 235 ARRAY_SIZE(setup_attrs)); 236 if (ret) 237 goto out; 238 239 /* Lane 0 configuration*/ 240 ret = tc_dwc_g210_setup_20bit_rmmi_lane0(hba); 241 if (ret) 242 goto out; 243 244 /* Lane 1 configuration*/ 245 ret = tc_dwc_g210_setup_20bit_rmmi_lane1(hba); 246 if (ret) 247 goto out; 248 249 out: 250 return ret; 251 } 252 253 /** 254 * tc_dwc_g210_config_40_bit() 255 * This function configures Local (host) Synopsys 40-bit TC specific attributes 256 * 257 * @hba: Pointer to drivers structure 258 * 259 * Returns 0 on success non-zero value on failure 260 */ 261 int tc_dwc_g210_config_40_bit(struct ufs_hba *hba) 262 { 263 int ret = 0; 264 265 dev_info(hba->dev, "Configuring Test Chip 40-bit RMMI\n"); 266 ret = tc_dwc_g210_setup_40bit_rmmi(hba); 267 if (ret) { 268 dev_err(hba->dev, "Configuration failed\n"); 269 goto out; 270 } 271 272 /* To write Shadow register bank to effective configuration block */ 273 ret = ufshcd_dme_set(hba, UIC_ARG_MIB(VS_MPHYCFGUPDT), 0x01); 274 if (ret) 275 goto out; 276 277 /* To configure Debug OMC */ 278 ret = ufshcd_dme_set(hba, UIC_ARG_MIB(VS_DEBUGOMC), 0x01); 279 280 out: 281 return ret; 282 } 283 EXPORT_SYMBOL(tc_dwc_g210_config_40_bit); 284 285 /** 286 * tc_dwc_g210_config_20_bit() 287 * This function configures Local (host) Synopsys 20-bit TC specific attributes 288 * 289 * @hba: Pointer to drivers structure 290 * 291 * Returns 0 on success non-zero value on failure 292 */ 293 int tc_dwc_g210_config_20_bit(struct ufs_hba *hba) 294 { 295 int ret = 0; 296 297 dev_info(hba->dev, "Configuring Test Chip 20-bit RMMI\n"); 298 ret = tc_dwc_g210_setup_20bit_rmmi(hba); 299 if (ret) { 300 dev_err(hba->dev, "Configuration failed\n"); 301 goto out; 302 } 303 304 /* To write Shadow register bank to effective configuration block */ 305 ret = ufshcd_dme_set(hba, UIC_ARG_MIB(VS_MPHYCFGUPDT), 0x01); 306 if (ret) 307 goto out; 308 309 /* To configure Debug OMC */ 310 ret = ufshcd_dme_set(hba, UIC_ARG_MIB(VS_DEBUGOMC), 0x01); 311 312 out: 313 return ret; 314 } 315 EXPORT_SYMBOL(tc_dwc_g210_config_20_bit); 316 317 MODULE_AUTHOR("Joao Pinto <Joao.Pinto@synopsys.com>"); 318 MODULE_DESCRIPTION("Synopsys G210 Test Chip driver"); 319 MODULE_LICENSE("Dual BSD/GPL"); 320