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