Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

phy: qcom-snps: Add support for overriding phy tuning parameters

Add support for overriding electrical signal tuning parameters for
SNPS HS Phy.

Signed-off-by: Krishna Kurapati <quic_kriskura@quicinc.com>
Reviewed-by: Bjorn Andersson <andersson@kernel.org>
Link: https://lore.kernel.org/r/1662480933-12326-3-git-send-email-quic_kriskura@quicinc.com
Signed-off-by: Vinod Koul <vkoul@kernel.org>

authored by

Krishna Kurapati and committed by
Vinod Koul
df2217ff ba136ce3

+253 -2
+253 -2
drivers/phy/qualcomm/phy-qcom-snps-femto-v2.c
··· 52 52 #define USB2_SUSPEND_N BIT(2) 53 53 #define USB2_SUSPEND_N_SEL BIT(3) 54 54 55 + #define USB2_PHY_USB_PHY_HS_PHY_OVERRIDE_X0 (0x6c) 56 + #define USB2_PHY_USB_PHY_HS_PHY_OVERRIDE_X1 (0x70) 57 + #define USB2_PHY_USB_PHY_HS_PHY_OVERRIDE_X2 (0x74) 58 + #define USB2_PHY_USB_PHY_HS_PHY_OVERRIDE_X3 (0x78) 59 + #define PARAM_OVRD_MASK 0xFF 60 + 55 61 #define USB2_PHY_USB_PHY_CFG0 (0x94) 56 62 #define UTMI_PHY_DATAPATH_CTRL_OVERRIDE_EN BIT(0) 57 63 #define UTMI_PHY_CMN_CTRL_OVERRIDE_EN BIT(1) ··· 66 60 #define REFCLK_SEL_MASK GENMASK(1, 0) 67 61 #define REFCLK_SEL_DEFAULT (0x2 << 0) 68 62 63 + #define HS_DISCONNECT_MASK GENMASK(2, 0) 64 + #define SQUELCH_DETECTOR_MASK GENMASK(7, 5) 65 + 66 + #define HS_AMPLITUDE_MASK GENMASK(3, 0) 67 + #define PREEMPHASIS_DURATION_MASK BIT(5) 68 + #define PREEMPHASIS_AMPLITUDE_MASK GENMASK(7, 6) 69 + 70 + #define HS_RISE_FALL_MASK GENMASK(1, 0) 71 + #define HS_CROSSOVER_VOLTAGE_MASK GENMASK(3, 2) 72 + #define HS_OUTPUT_IMPEDANCE_MASK GENMASK(5, 4) 73 + 74 + #define LS_FS_OUTPUT_IMPEDANCE_MASK GENMASK(3, 0) 75 + 69 76 static const char * const qcom_snps_hsphy_vreg_names[] = { 70 77 "vdda-pll", "vdda33", "vdda18", 71 78 }; 72 79 73 80 #define SNPS_HS_NUM_VREGS ARRAY_SIZE(qcom_snps_hsphy_vreg_names) 81 + 82 + struct override_param { 83 + s32 value; 84 + u8 reg_val; 85 + }; 86 + 87 + struct override_param_map { 88 + const char *prop_name; 89 + const struct override_param *param_table; 90 + u8 table_size; 91 + u8 reg_offset; 92 + u8 param_mask; 93 + }; 94 + 95 + struct phy_override_seq { 96 + bool need_update; 97 + u8 offset; 98 + u8 value; 99 + u8 mask; 100 + }; 101 + 102 + #define NUM_HSPHY_TUNING_PARAMS (9) 74 103 75 104 /** 76 105 * struct qcom_snps_hsphy - snps hs phy attributes ··· 132 91 133 92 bool phy_initialized; 134 93 enum phy_mode mode; 94 + struct phy_override_seq update_seq_cfg[NUM_HSPHY_TUNING_PARAMS]; 135 95 }; 136 96 137 97 static inline void qcom_snps_hsphy_write_mask(void __iomem *base, u32 offset, ··· 215 173 return 0; 216 174 } 217 175 176 + static const struct override_param hs_disconnect_sc7280[] = { 177 + { -272, 0 }, 178 + { 0, 1 }, 179 + { 317, 2 }, 180 + { 630, 3 }, 181 + { 973, 4 }, 182 + { 1332, 5 }, 183 + { 1743, 6 }, 184 + { 2156, 7 }, 185 + }; 186 + 187 + static const struct override_param squelch_det_threshold_sc7280[] = { 188 + { -2090, 7 }, 189 + { -1560, 6 }, 190 + { -1030, 5 }, 191 + { -530, 4 }, 192 + { 0, 3 }, 193 + { 530, 2 }, 194 + { 1060, 1 }, 195 + { 1590, 0 }, 196 + }; 197 + 198 + static const struct override_param hs_amplitude_sc7280[] = { 199 + { -660, 0 }, 200 + { -440, 1 }, 201 + { -220, 2 }, 202 + { 0, 3 }, 203 + { 230, 4 }, 204 + { 440, 5 }, 205 + { 650, 6 }, 206 + { 890, 7 }, 207 + { 1110, 8 }, 208 + { 1330, 9 }, 209 + { 1560, 10 }, 210 + { 1780, 11 }, 211 + { 2000, 12 }, 212 + { 2220, 13 }, 213 + { 2430, 14 }, 214 + { 2670, 15 }, 215 + }; 216 + 217 + static const struct override_param preemphasis_duration_sc7280[] = { 218 + { 10000, 1 }, 219 + { 20000, 0 }, 220 + }; 221 + 222 + static const struct override_param preemphasis_amplitude_sc7280[] = { 223 + { 10000, 1 }, 224 + { 20000, 2 }, 225 + { 30000, 3 }, 226 + { 40000, 0 }, 227 + }; 228 + 229 + static const struct override_param hs_rise_fall_time_sc7280[] = { 230 + { -4100, 3 }, 231 + { 0, 2 }, 232 + { 2810, 1 }, 233 + { 5430, 0 }, 234 + }; 235 + 236 + static const struct override_param hs_crossover_voltage_sc7280[] = { 237 + { -31000, 1 }, 238 + { 0, 3 }, 239 + { 28000, 2 }, 240 + }; 241 + 242 + static const struct override_param hs_output_impedance_sc7280[] = { 243 + { -2300000, 3 }, 244 + { 0, 2 }, 245 + { 2600000, 1 }, 246 + { 6100000, 0 }, 247 + }; 248 + 249 + static const struct override_param ls_fs_output_impedance_sc7280[] = { 250 + { -1053, 15 }, 251 + { -557, 7 }, 252 + { 0, 3 }, 253 + { 612, 1 }, 254 + { 1310, 0 }, 255 + }; 256 + 257 + static const struct override_param_map sc7280_snps_7nm_phy[] = { 258 + { 259 + "qcom,hs-disconnect-bp", 260 + hs_disconnect_sc7280, 261 + ARRAY_SIZE(hs_disconnect_sc7280), 262 + USB2_PHY_USB_PHY_HS_PHY_OVERRIDE_X0, 263 + HS_DISCONNECT_MASK 264 + }, 265 + { 266 + "qcom,squelch-detector-bp", 267 + squelch_det_threshold_sc7280, 268 + ARRAY_SIZE(squelch_det_threshold_sc7280), 269 + USB2_PHY_USB_PHY_HS_PHY_OVERRIDE_X0, 270 + SQUELCH_DETECTOR_MASK 271 + }, 272 + { 273 + "qcom,hs-amplitude-bp", 274 + hs_amplitude_sc7280, 275 + ARRAY_SIZE(hs_amplitude_sc7280), 276 + USB2_PHY_USB_PHY_HS_PHY_OVERRIDE_X1, 277 + HS_AMPLITUDE_MASK 278 + }, 279 + { 280 + "qcom,pre-emphasis-duration-bp", 281 + preemphasis_duration_sc7280, 282 + ARRAY_SIZE(preemphasis_duration_sc7280), 283 + USB2_PHY_USB_PHY_HS_PHY_OVERRIDE_X1, 284 + PREEMPHASIS_DURATION_MASK, 285 + }, 286 + { 287 + "qcom,pre-emphasis-amplitude-bp", 288 + preemphasis_amplitude_sc7280, 289 + ARRAY_SIZE(preemphasis_amplitude_sc7280), 290 + USB2_PHY_USB_PHY_HS_PHY_OVERRIDE_X1, 291 + PREEMPHASIS_AMPLITUDE_MASK, 292 + }, 293 + { 294 + "qcom,hs-rise-fall-time-bp", 295 + hs_rise_fall_time_sc7280, 296 + ARRAY_SIZE(hs_rise_fall_time_sc7280), 297 + USB2_PHY_USB_PHY_HS_PHY_OVERRIDE_X2, 298 + HS_RISE_FALL_MASK 299 + }, 300 + { 301 + "qcom,hs-crossover-voltage-microvolt", 302 + hs_crossover_voltage_sc7280, 303 + ARRAY_SIZE(hs_crossover_voltage_sc7280), 304 + USB2_PHY_USB_PHY_HS_PHY_OVERRIDE_X2, 305 + HS_CROSSOVER_VOLTAGE_MASK 306 + }, 307 + { 308 + "qcom,hs-output-impedance-micro-ohms", 309 + hs_output_impedance_sc7280, 310 + ARRAY_SIZE(hs_output_impedance_sc7280), 311 + USB2_PHY_USB_PHY_HS_PHY_OVERRIDE_X2, 312 + HS_OUTPUT_IMPEDANCE_MASK, 313 + }, 314 + { 315 + "qcom,ls-fs-output-impedance-bp", 316 + ls_fs_output_impedance_sc7280, 317 + ARRAY_SIZE(ls_fs_output_impedance_sc7280), 318 + USB2_PHY_USB_PHY_HS_PHY_OVERRIDE_X3, 319 + LS_FS_OUTPUT_IMPEDANCE_MASK, 320 + }, 321 + {}, 322 + }; 323 + 218 324 static int qcom_snps_hsphy_init(struct phy *phy) 219 325 { 220 326 struct qcom_snps_hsphy *hsphy = phy_get_drvdata(phy); 221 - int ret; 327 + int ret, i; 222 328 223 329 dev_vdbg(&phy->dev, "%s(): Initializing SNPS HS phy\n", __func__); 224 330 ··· 412 222 VBUSVLDEXTSEL0, VBUSVLDEXTSEL0); 413 223 qcom_snps_hsphy_write_mask(hsphy->base, USB2_PHY_USB_PHY_HS_PHY_CTRL1, 414 224 VBUSVLDEXT0, VBUSVLDEXT0); 225 + 226 + for (i = 0; i < ARRAY_SIZE(hsphy->update_seq_cfg); i++) { 227 + if (hsphy->update_seq_cfg[i].need_update) 228 + qcom_snps_hsphy_write_mask(hsphy->base, 229 + hsphy->update_seq_cfg[i].offset, 230 + hsphy->update_seq_cfg[i].mask, 231 + hsphy->update_seq_cfg[i].value); 232 + } 415 233 416 234 qcom_snps_hsphy_write_mask(hsphy->base, 417 235 USB2_PHY_USB_PHY_HS_PHY_CTRL_COMMON2, ··· 478 280 static const struct of_device_id qcom_snps_hsphy_of_match_table[] = { 479 281 { .compatible = "qcom,sm8150-usb-hs-phy", }, 480 282 { .compatible = "qcom,usb-snps-hs-5nm-phy", }, 481 - { .compatible = "qcom,usb-snps-hs-7nm-phy", }, 283 + { 284 + .compatible = "qcom,usb-snps-hs-7nm-phy", 285 + .data = &sc7280_snps_7nm_phy, 286 + }, 482 287 { .compatible = "qcom,usb-snps-femto-v2-phy", }, 483 288 { } 484 289 }; ··· 491 290 SET_RUNTIME_PM_OPS(qcom_snps_hsphy_runtime_suspend, 492 291 qcom_snps_hsphy_runtime_resume, NULL) 493 292 }; 293 + 294 + static void qcom_snps_hsphy_override_param_update_val( 295 + const struct override_param_map map, 296 + s32 dt_val, struct phy_override_seq *seq_entry) 297 + { 298 + int i; 299 + 300 + /* 301 + * Param table for each param is in increasing order 302 + * of dt values. We need to iterate over the list to 303 + * select the entry that matches the dt value and pick 304 + * up the corresponding register value. 305 + */ 306 + for (i = 0; i < map.table_size - 1; i++) { 307 + if (map.param_table[i].value == dt_val) 308 + break; 309 + } 310 + 311 + seq_entry->need_update = true; 312 + seq_entry->offset = map.reg_offset; 313 + seq_entry->mask = map.param_mask; 314 + seq_entry->value = map.param_table[i].reg_val << __ffs(map.param_mask); 315 + } 316 + 317 + static void qcom_snps_hsphy_read_override_param_seq(struct device *dev) 318 + { 319 + struct device_node *node = dev->of_node; 320 + s32 val; 321 + int ret, i; 322 + struct qcom_snps_hsphy *hsphy; 323 + const struct override_param_map *cfg = of_device_get_match_data(dev); 324 + 325 + if (!cfg) 326 + return; 327 + 328 + hsphy = dev_get_drvdata(dev); 329 + 330 + for (i = 0; cfg[i].prop_name != NULL; i++) { 331 + ret = of_property_read_s32(node, cfg[i].prop_name, &val); 332 + if (ret) 333 + continue; 334 + 335 + qcom_snps_hsphy_override_param_update_val(cfg[i], val, 336 + &hsphy->update_seq_cfg[i]); 337 + dev_dbg(&hsphy->phy->dev, "Read param: %s dt_val: %d reg_val: 0x%x\n", 338 + cfg[i].prop_name, val, hsphy->update_seq_cfg[i].value); 339 + 340 + } 341 + } 494 342 495 343 static int qcom_snps_hsphy_probe(struct platform_device *pdev) 496 344 { ··· 602 352 603 353 dev_set_drvdata(dev, hsphy); 604 354 phy_set_drvdata(generic_phy, hsphy); 355 + qcom_snps_hsphy_read_override_param_seq(dev); 605 356 606 357 phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate); 607 358 if (!IS_ERR(phy_provider))