.. | .. |
---|
1 | 1 | // SPDX-License-Identifier: GPL-2.0 |
---|
2 | 2 | /* |
---|
3 | | - * Copyright (c) 2017, The Linux Foundation. All rights reserved. |
---|
| 3 | + * Copyright (c) 2017, 2019, The Linux Foundation. All rights reserved. |
---|
4 | 4 | */ |
---|
5 | 5 | |
---|
6 | 6 | #include <linux/clk.h> |
---|
.. | .. |
---|
66 | 66 | #define IMP_RES_OFFSET_MASK GENMASK(5, 0) |
---|
67 | 67 | #define IMP_RES_OFFSET_SHIFT 0x0 |
---|
68 | 68 | |
---|
| 69 | +/* QUSB2PHY_PLL_BIAS_CONTROL_2 register bits */ |
---|
| 70 | +#define BIAS_CTRL2_RES_OFFSET_MASK GENMASK(5, 0) |
---|
| 71 | +#define BIAS_CTRL2_RES_OFFSET_SHIFT 0x0 |
---|
| 72 | + |
---|
| 73 | +/* QUSB2PHY_CHG_CONTROL_2 register bits */ |
---|
| 74 | +#define CHG_CTRL2_OFFSET_MASK GENMASK(5, 4) |
---|
| 75 | +#define CHG_CTRL2_OFFSET_SHIFT 0x4 |
---|
| 76 | + |
---|
69 | 77 | /* QUSB2PHY_PORT_TUNE1 register bits */ |
---|
70 | 78 | #define HSTX_TRIM_MASK GENMASK(7, 4) |
---|
71 | 79 | #define HSTX_TRIM_SHIFT 0x4 |
---|
72 | 80 | #define PREEMPH_WIDTH_HALF_BIT BIT(2) |
---|
73 | 81 | #define PREEMPHASIS_EN_MASK GENMASK(1, 0) |
---|
74 | 82 | #define PREEMPHASIS_EN_SHIFT 0x0 |
---|
| 83 | + |
---|
| 84 | +/* QUSB2PHY_PORT_TUNE2 register bits */ |
---|
| 85 | +#define HSDISC_TRIM_MASK GENMASK(1, 0) |
---|
| 86 | +#define HSDISC_TRIM_SHIFT 0x0 |
---|
75 | 87 | |
---|
76 | 88 | #define QUSB2PHY_PLL_ANALOG_CONTROLS_TWO 0x04 |
---|
77 | 89 | #define QUSB2PHY_PLL_CLOCK_INVERTERS 0x18c |
---|
.. | .. |
---|
152 | 164 | QUSB2_PHY_INIT_CFG(QUSB2PHY_PLL_PWR_CTRL, 0x00), |
---|
153 | 165 | }; |
---|
154 | 166 | |
---|
155 | | -static const unsigned int sdm845_regs_layout[] = { |
---|
| 167 | +static const unsigned int msm8998_regs_layout[] = { |
---|
| 168 | + [QUSB2PHY_PLL_CORE_INPUT_OVERRIDE] = 0xa8, |
---|
| 169 | + [QUSB2PHY_PLL_STATUS] = 0x1a0, |
---|
| 170 | + [QUSB2PHY_PORT_TUNE1] = 0x23c, |
---|
| 171 | + [QUSB2PHY_PORT_TUNE2] = 0x240, |
---|
| 172 | + [QUSB2PHY_PORT_TUNE3] = 0x244, |
---|
| 173 | + [QUSB2PHY_PORT_TUNE4] = 0x248, |
---|
| 174 | + [QUSB2PHY_PORT_TEST1] = 0x24c, |
---|
| 175 | + [QUSB2PHY_PORT_TEST2] = 0x250, |
---|
| 176 | + [QUSB2PHY_PORT_POWERDOWN] = 0x210, |
---|
| 177 | + [QUSB2PHY_INTR_CTRL] = 0x22c, |
---|
| 178 | +}; |
---|
| 179 | + |
---|
| 180 | +static const struct qusb2_phy_init_tbl msm8998_init_tbl[] = { |
---|
| 181 | + QUSB2_PHY_INIT_CFG(QUSB2PHY_PLL_ANALOG_CONTROLS_TWO, 0x13), |
---|
| 182 | + QUSB2_PHY_INIT_CFG(QUSB2PHY_PLL_CLOCK_INVERTERS, 0x7c), |
---|
| 183 | + QUSB2_PHY_INIT_CFG(QUSB2PHY_PLL_CMODE, 0x80), |
---|
| 184 | + QUSB2_PHY_INIT_CFG(QUSB2PHY_PLL_LOCK_DELAY, 0x0a), |
---|
| 185 | + |
---|
| 186 | + QUSB2_PHY_INIT_CFG_L(QUSB2PHY_PORT_TUNE1, 0xa5), |
---|
| 187 | + QUSB2_PHY_INIT_CFG_L(QUSB2PHY_PORT_TUNE2, 0x09), |
---|
| 188 | + |
---|
| 189 | + QUSB2_PHY_INIT_CFG(QUSB2PHY_PLL_DIGITAL_TIMERS_TWO, 0x19), |
---|
| 190 | +}; |
---|
| 191 | + |
---|
| 192 | +static const unsigned int qusb2_v2_regs_layout[] = { |
---|
156 | 193 | [QUSB2PHY_PLL_CORE_INPUT_OVERRIDE] = 0xa8, |
---|
157 | 194 | [QUSB2PHY_PLL_STATUS] = 0x1a0, |
---|
158 | 195 | [QUSB2PHY_PORT_TUNE1] = 0x240, |
---|
.. | .. |
---|
166 | 203 | [QUSB2PHY_INTR_CTRL] = 0x230, |
---|
167 | 204 | }; |
---|
168 | 205 | |
---|
169 | | -static const struct qusb2_phy_init_tbl sdm845_init_tbl[] = { |
---|
| 206 | +static const struct qusb2_phy_init_tbl qusb2_v2_init_tbl[] = { |
---|
170 | 207 | QUSB2_PHY_INIT_CFG(QUSB2PHY_PLL_ANALOG_CONTROLS_TWO, 0x03), |
---|
171 | 208 | QUSB2_PHY_INIT_CFG(QUSB2PHY_PLL_CLOCK_INVERTERS, 0x7c), |
---|
172 | 209 | QUSB2_PHY_INIT_CFG(QUSB2PHY_PLL_CMODE, 0x80), |
---|
.. | .. |
---|
221 | 258 | .autoresume_en = BIT(3), |
---|
222 | 259 | }; |
---|
223 | 260 | |
---|
224 | | -static const struct qusb2_phy_cfg sdm845_phy_cfg = { |
---|
225 | | - .tbl = sdm845_init_tbl, |
---|
226 | | - .tbl_num = ARRAY_SIZE(sdm845_init_tbl), |
---|
227 | | - .regs = sdm845_regs_layout, |
---|
| 261 | +static const struct qusb2_phy_cfg msm8998_phy_cfg = { |
---|
| 262 | + .tbl = msm8998_init_tbl, |
---|
| 263 | + .tbl_num = ARRAY_SIZE(msm8998_init_tbl), |
---|
| 264 | + .regs = msm8998_regs_layout, |
---|
| 265 | + |
---|
| 266 | + .disable_ctrl = POWER_DOWN, |
---|
| 267 | + .mask_core_ready = CORE_READY_STATUS, |
---|
| 268 | + .has_pll_override = true, |
---|
| 269 | + .autoresume_en = BIT(0), |
---|
| 270 | + .update_tune1_with_efuse = true, |
---|
| 271 | +}; |
---|
| 272 | + |
---|
| 273 | +static const struct qusb2_phy_cfg qusb2_v2_phy_cfg = { |
---|
| 274 | + .tbl = qusb2_v2_init_tbl, |
---|
| 275 | + .tbl_num = ARRAY_SIZE(qusb2_v2_init_tbl), |
---|
| 276 | + .regs = qusb2_v2_regs_layout, |
---|
228 | 277 | |
---|
229 | 278 | .disable_ctrl = (PWR_CTRL1_VREF_SUPPLY_TRIM | PWR_CTRL1_CLAMP_N_EN | |
---|
230 | 279 | POWER_DOWN), |
---|
.. | .. |
---|
239 | 288 | }; |
---|
240 | 289 | |
---|
241 | 290 | #define QUSB2_NUM_VREGS ARRAY_SIZE(qusb2_phy_vreg_names) |
---|
| 291 | + |
---|
| 292 | +/* struct override_param - structure holding qusb2 v2 phy overriding param |
---|
| 293 | + * set override true if the device tree property exists and read and assign |
---|
| 294 | + * to value |
---|
| 295 | + */ |
---|
| 296 | +struct override_param { |
---|
| 297 | + bool override; |
---|
| 298 | + u8 value; |
---|
| 299 | +}; |
---|
| 300 | + |
---|
| 301 | +/*struct override_params - structure holding qusb2 v2 phy overriding params |
---|
| 302 | + * @imp_res_offset: rescode offset to be updated in IMP_CTRL1 register |
---|
| 303 | + * @hstx_trim: HSTX_TRIM to be updated in TUNE1 register |
---|
| 304 | + * @preemphasis: Amplitude Pre-Emphasis to be updated in TUNE1 register |
---|
| 305 | + * @preemphasis_width: half/full-width Pre-Emphasis updated via TUNE1 |
---|
| 306 | + * @bias_ctrl: bias ctrl to be updated in BIAS_CONTROL_2 register |
---|
| 307 | + * @charge_ctrl: charge ctrl to be updated in CHG_CTRL2 register |
---|
| 308 | + * @hsdisc_trim: disconnect threshold to be updated in TUNE2 register |
---|
| 309 | + */ |
---|
| 310 | +struct override_params { |
---|
| 311 | + struct override_param imp_res_offset; |
---|
| 312 | + struct override_param hstx_trim; |
---|
| 313 | + struct override_param preemphasis; |
---|
| 314 | + struct override_param preemphasis_width; |
---|
| 315 | + struct override_param bias_ctrl; |
---|
| 316 | + struct override_param charge_ctrl; |
---|
| 317 | + struct override_param hsdisc_trim; |
---|
| 318 | +}; |
---|
242 | 319 | |
---|
243 | 320 | /** |
---|
244 | 321 | * struct qusb2_phy - structure holding qusb2 phy attributes |
---|
.. | .. |
---|
255 | 332 | * @tcsr: TCSR syscon register map |
---|
256 | 333 | * @cell: nvmem cell containing phy tuning value |
---|
257 | 334 | * |
---|
258 | | - * @override_imp_res_offset: PHY should use different rescode offset |
---|
259 | | - * @imp_res_offset_value: rescode offset to be updated in IMP_CTRL1 register |
---|
260 | | - * @override_hstx_trim: PHY should use different HSTX o/p current value |
---|
261 | | - * @hstx_trim_value: HSTX_TRIM value to be updated in TUNE1 register |
---|
262 | | - * @override_preemphasis: PHY should use different pre-amphasis amplitude |
---|
263 | | - * @preemphasis_level: Amplitude Pre-Emphasis to be updated in TUNE1 register |
---|
264 | | - * @override_preemphasis_width: PHY should use different pre-emphasis duration |
---|
265 | | - * @preemphasis_width: half/full-width Pre-Emphasis updated via TUNE1 |
---|
| 335 | + * @overrides: pointer to structure for all overriding tuning params |
---|
266 | 336 | * |
---|
267 | 337 | * @cfg: phy config data |
---|
268 | 338 | * @has_se_clk_scheme: indicate if PHY has single-ended ref clock scheme |
---|
.. | .. |
---|
282 | 352 | struct regmap *tcsr; |
---|
283 | 353 | struct nvmem_cell *cell; |
---|
284 | 354 | |
---|
285 | | - bool override_imp_res_offset; |
---|
286 | | - u8 imp_res_offset_value; |
---|
287 | | - bool override_hstx_trim; |
---|
288 | | - u8 hstx_trim_value; |
---|
289 | | - bool override_preemphasis; |
---|
290 | | - u8 preemphasis_level; |
---|
291 | | - bool override_preemphasis_width; |
---|
292 | | - u8 preemphasis_width; |
---|
| 355 | + struct override_params overrides; |
---|
293 | 356 | |
---|
294 | 357 | const struct qusb2_phy_cfg *cfg; |
---|
295 | 358 | bool has_se_clk_scheme; |
---|
.. | .. |
---|
357 | 420 | static void qusb2_phy_override_phy_params(struct qusb2_phy *qphy) |
---|
358 | 421 | { |
---|
359 | 422 | const struct qusb2_phy_cfg *cfg = qphy->cfg; |
---|
| 423 | + struct override_params *or = &qphy->overrides; |
---|
360 | 424 | |
---|
361 | | - if (qphy->override_imp_res_offset) |
---|
| 425 | + if (or->imp_res_offset.override) |
---|
362 | 426 | qusb2_write_mask(qphy->base, QUSB2PHY_IMP_CTRL1, |
---|
363 | | - qphy->imp_res_offset_value << IMP_RES_OFFSET_SHIFT, |
---|
| 427 | + or->imp_res_offset.value << IMP_RES_OFFSET_SHIFT, |
---|
364 | 428 | IMP_RES_OFFSET_MASK); |
---|
365 | 429 | |
---|
366 | | - if (qphy->override_hstx_trim) |
---|
| 430 | + if (or->bias_ctrl.override) |
---|
| 431 | + qusb2_write_mask(qphy->base, QUSB2PHY_PLL_BIAS_CONTROL_2, |
---|
| 432 | + or->bias_ctrl.value << BIAS_CTRL2_RES_OFFSET_SHIFT, |
---|
| 433 | + BIAS_CTRL2_RES_OFFSET_MASK); |
---|
| 434 | + |
---|
| 435 | + if (or->charge_ctrl.override) |
---|
| 436 | + qusb2_write_mask(qphy->base, QUSB2PHY_CHG_CTRL2, |
---|
| 437 | + or->charge_ctrl.value << CHG_CTRL2_OFFSET_SHIFT, |
---|
| 438 | + CHG_CTRL2_OFFSET_MASK); |
---|
| 439 | + |
---|
| 440 | + if (or->hstx_trim.override) |
---|
367 | 441 | qusb2_write_mask(qphy->base, cfg->regs[QUSB2PHY_PORT_TUNE1], |
---|
368 | | - qphy->hstx_trim_value << HSTX_TRIM_SHIFT, |
---|
| 442 | + or->hstx_trim.value << HSTX_TRIM_SHIFT, |
---|
369 | 443 | HSTX_TRIM_MASK); |
---|
370 | 444 | |
---|
371 | | - if (qphy->override_preemphasis) |
---|
| 445 | + if (or->preemphasis.override) |
---|
372 | 446 | qusb2_write_mask(qphy->base, cfg->regs[QUSB2PHY_PORT_TUNE1], |
---|
373 | | - qphy->preemphasis_level << PREEMPHASIS_EN_SHIFT, |
---|
| 447 | + or->preemphasis.value << PREEMPHASIS_EN_SHIFT, |
---|
374 | 448 | PREEMPHASIS_EN_MASK); |
---|
375 | 449 | |
---|
376 | | - if (qphy->override_preemphasis_width) { |
---|
377 | | - if (qphy->preemphasis_width == |
---|
| 450 | + if (or->preemphasis_width.override) { |
---|
| 451 | + if (or->preemphasis_width.value == |
---|
378 | 452 | QUSB2_V2_PREEMPHASIS_WIDTH_HALF_BIT) |
---|
379 | 453 | qusb2_setbits(qphy->base, |
---|
380 | 454 | cfg->regs[QUSB2PHY_PORT_TUNE1], |
---|
.. | .. |
---|
384 | 458 | cfg->regs[QUSB2PHY_PORT_TUNE1], |
---|
385 | 459 | PREEMPH_WIDTH_HALF_BIT); |
---|
386 | 460 | } |
---|
| 461 | + |
---|
| 462 | + if (or->hsdisc_trim.override) |
---|
| 463 | + qusb2_write_mask(qphy->base, cfg->regs[QUSB2PHY_PORT_TUNE2], |
---|
| 464 | + or->hsdisc_trim.value << HSDISC_TRIM_SHIFT, |
---|
| 465 | + HSDISC_TRIM_MASK); |
---|
387 | 466 | } |
---|
388 | 467 | |
---|
389 | 468 | /* |
---|
.. | .. |
---|
429 | 508 | hstx_trim << HSTX_TRIM_SHIFT, HSTX_TRIM_MASK); |
---|
430 | 509 | } |
---|
431 | 510 | |
---|
432 | | -static int qusb2_phy_set_mode(struct phy *phy, enum phy_mode mode) |
---|
| 511 | +static int qusb2_phy_set_mode(struct phy *phy, |
---|
| 512 | + enum phy_mode mode, int submode) |
---|
433 | 513 | { |
---|
434 | 514 | struct qusb2_phy *qphy = phy_get_drvdata(phy); |
---|
435 | 515 | |
---|
.. | .. |
---|
734 | 814 | |
---|
735 | 815 | static const struct of_device_id qusb2_phy_of_match_table[] = { |
---|
736 | 816 | { |
---|
| 817 | + .compatible = "qcom,ipq8074-qusb2-phy", |
---|
| 818 | + .data = &msm8996_phy_cfg, |
---|
| 819 | + }, { |
---|
737 | 820 | .compatible = "qcom,msm8996-qusb2-phy", |
---|
738 | 821 | .data = &msm8996_phy_cfg, |
---|
739 | 822 | }, { |
---|
| 823 | + .compatible = "qcom,msm8998-qusb2-phy", |
---|
| 824 | + .data = &msm8998_phy_cfg, |
---|
| 825 | + }, { |
---|
| 826 | + /* |
---|
| 827 | + * Deprecated. Only here to support legacy device |
---|
| 828 | + * trees that didn't include "qcom,qusb2-v2-phy" |
---|
| 829 | + */ |
---|
740 | 830 | .compatible = "qcom,sdm845-qusb2-phy", |
---|
741 | | - .data = &sdm845_phy_cfg, |
---|
| 831 | + .data = &qusb2_v2_phy_cfg, |
---|
| 832 | + }, { |
---|
| 833 | + .compatible = "qcom,qusb2-v2-phy", |
---|
| 834 | + .data = &qusb2_v2_phy_cfg, |
---|
742 | 835 | }, |
---|
743 | 836 | { }, |
---|
744 | 837 | }; |
---|
.. | .. |
---|
759 | 852 | int ret, i; |
---|
760 | 853 | int num; |
---|
761 | 854 | u32 value; |
---|
| 855 | + struct override_params *or; |
---|
762 | 856 | |
---|
763 | 857 | qphy = devm_kzalloc(dev, sizeof(*qphy), GFP_KERNEL); |
---|
764 | 858 | if (!qphy) |
---|
765 | 859 | return -ENOMEM; |
---|
| 860 | + or = &qphy->overrides; |
---|
766 | 861 | |
---|
767 | 862 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
---|
768 | 863 | qphy->base = devm_ioremap_resource(dev, res); |
---|
.. | .. |
---|
785 | 880 | return ret; |
---|
786 | 881 | } |
---|
787 | 882 | |
---|
788 | | - qphy->iface_clk = devm_clk_get(dev, "iface"); |
---|
789 | | - if (IS_ERR(qphy->iface_clk)) { |
---|
790 | | - ret = PTR_ERR(qphy->iface_clk); |
---|
791 | | - if (ret == -EPROBE_DEFER) |
---|
792 | | - return ret; |
---|
793 | | - qphy->iface_clk = NULL; |
---|
794 | | - dev_dbg(dev, "failed to get iface clk, %d\n", ret); |
---|
795 | | - } |
---|
| 883 | + qphy->iface_clk = devm_clk_get_optional(dev, "iface"); |
---|
| 884 | + if (IS_ERR(qphy->iface_clk)) |
---|
| 885 | + return PTR_ERR(qphy->iface_clk); |
---|
796 | 886 | |
---|
797 | 887 | qphy->phy_reset = devm_reset_control_get_by_index(&pdev->dev, 0); |
---|
798 | 888 | if (IS_ERR(qphy->phy_reset)) { |
---|
.. | .. |
---|
806 | 896 | |
---|
807 | 897 | ret = devm_regulator_bulk_get(dev, num, qphy->vregs); |
---|
808 | 898 | if (ret) { |
---|
809 | | - dev_err(dev, "failed to get regulator supplies\n"); |
---|
| 899 | + if (ret != -EPROBE_DEFER) |
---|
| 900 | + dev_err(dev, "failed to get regulator supplies: %d\n", |
---|
| 901 | + ret); |
---|
810 | 902 | return ret; |
---|
811 | 903 | } |
---|
812 | 904 | |
---|
.. | .. |
---|
830 | 922 | |
---|
831 | 923 | if (!of_property_read_u32(dev->of_node, "qcom,imp-res-offset-value", |
---|
832 | 924 | &value)) { |
---|
833 | | - qphy->imp_res_offset_value = (u8)value; |
---|
834 | | - qphy->override_imp_res_offset = true; |
---|
| 925 | + or->imp_res_offset.value = (u8)value; |
---|
| 926 | + or->imp_res_offset.override = true; |
---|
| 927 | + } |
---|
| 928 | + |
---|
| 929 | + if (!of_property_read_u32(dev->of_node, "qcom,bias-ctrl-value", |
---|
| 930 | + &value)) { |
---|
| 931 | + or->bias_ctrl.value = (u8)value; |
---|
| 932 | + or->bias_ctrl.override = true; |
---|
| 933 | + } |
---|
| 934 | + |
---|
| 935 | + if (!of_property_read_u32(dev->of_node, "qcom,charge-ctrl-value", |
---|
| 936 | + &value)) { |
---|
| 937 | + or->charge_ctrl.value = (u8)value; |
---|
| 938 | + or->charge_ctrl.override = true; |
---|
835 | 939 | } |
---|
836 | 940 | |
---|
837 | 941 | if (!of_property_read_u32(dev->of_node, "qcom,hstx-trim-value", |
---|
838 | 942 | &value)) { |
---|
839 | | - qphy->hstx_trim_value = (u8)value; |
---|
840 | | - qphy->override_hstx_trim = true; |
---|
| 943 | + or->hstx_trim.value = (u8)value; |
---|
| 944 | + or->hstx_trim.override = true; |
---|
841 | 945 | } |
---|
842 | 946 | |
---|
843 | 947 | if (!of_property_read_u32(dev->of_node, "qcom,preemphasis-level", |
---|
844 | 948 | &value)) { |
---|
845 | | - qphy->preemphasis_level = (u8)value; |
---|
846 | | - qphy->override_preemphasis = true; |
---|
| 949 | + or->preemphasis.value = (u8)value; |
---|
| 950 | + or->preemphasis.override = true; |
---|
847 | 951 | } |
---|
848 | 952 | |
---|
849 | 953 | if (!of_property_read_u32(dev->of_node, "qcom,preemphasis-width", |
---|
850 | 954 | &value)) { |
---|
851 | | - qphy->preemphasis_width = (u8)value; |
---|
852 | | - qphy->override_preemphasis_width = true; |
---|
| 955 | + or->preemphasis_width.value = (u8)value; |
---|
| 956 | + or->preemphasis_width.override = true; |
---|
| 957 | + } |
---|
| 958 | + |
---|
| 959 | + if (!of_property_read_u32(dev->of_node, "qcom,hsdisc-trim-value", |
---|
| 960 | + &value)) { |
---|
| 961 | + or->hsdisc_trim.value = (u8)value; |
---|
| 962 | + or->hsdisc_trim.override = true; |
---|
853 | 963 | } |
---|
854 | 964 | |
---|
855 | 965 | pm_runtime_set_active(dev); |
---|