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

phy: qcom-qusb2: Add QUSB2 PHYs support for sdm845

There are two QUSB2 PHYs present on sdm845. In order
to improve eye diagram for both the PHYs some parameters
need to be changed. Provide device tree properties to
override these from board specific device tree files.

Signed-off-by: Manu Gautam <mgautam@codeaurora.org>
Reviewed-by: Douglas Anderson <dianders@chromium.org>
Signed-off-by: Kishon Vijay Abraham I <kishon@ti.com>

authored by

Manu Gautam and committed by
Kishon Vijay Abraham I
ef17f6e2 a8b70ccf

+118 -8
+118 -8
drivers/phy/qualcomm/phy-qcom-qusb2.c
··· 20 20 #include <linux/reset.h> 21 21 #include <linux/slab.h> 22 22 23 + #include <dt-bindings/phy/phy-qcom-qusb2.h> 24 + 23 25 #define QUSB2PHY_PLL_TEST 0x04 24 26 #define CLK_REF_SEL BIT(7) 25 27 ··· 61 59 #define CORE_PLL_EN_FROM_RESET BIT(4) 62 60 #define CORE_RESET BIT(5) 63 61 #define CORE_RESET_MUX BIT(6) 62 + 63 + /* QUSB2PHY_IMP_CTRL1 register bits */ 64 + #define IMP_RES_OFFSET_MASK GENMASK(5, 0) 65 + #define IMP_RES_OFFSET_SHIFT 0x0 66 + 67 + /* QUSB2PHY_PORT_TUNE1 register bits */ 68 + #define HSTX_TRIM_MASK GENMASK(7, 4) 69 + #define HSTX_TRIM_SHIFT 0x4 70 + #define PREEMPH_WIDTH_HALF_BIT BIT(2) 71 + #define PREEMPHASIS_EN_MASK GENMASK(1, 0) 72 + #define PREEMPHASIS_EN_SHIFT 0x0 64 73 65 74 #define QUSB2PHY_PLL_ANALOG_CONTROLS_TWO 0x04 66 75 #define QUSB2PHY_PLL_CLOCK_INVERTERS 0x18c ··· 152 139 QUSB2_PHY_INIT_CFG(QUSB2PHY_PLL_PWR_CTRL, 0x00), 153 140 }; 154 141 155 - static const unsigned int qusb2_v2_regs_layout[] = { 142 + static const unsigned int sdm845_regs_layout[] = { 156 143 [QUSB2PHY_PLL_CORE_INPUT_OVERRIDE] = 0xa8, 157 144 [QUSB2PHY_PLL_STATUS] = 0x1a0, 158 145 [QUSB2PHY_PORT_TUNE1] = 0x240, ··· 166 153 [QUSB2PHY_INTR_CTRL] = 0x230, 167 154 }; 168 155 169 - static const struct qusb2_phy_init_tbl qusb2_v2_init_tbl[] = { 156 + static const struct qusb2_phy_init_tbl sdm845_init_tbl[] = { 170 157 QUSB2_PHY_INIT_CFG(QUSB2PHY_PLL_ANALOG_CONTROLS_TWO, 0x03), 171 158 QUSB2_PHY_INIT_CFG(QUSB2PHY_PLL_CLOCK_INVERTERS, 0x7c), 172 159 QUSB2_PHY_INIT_CFG(QUSB2PHY_PLL_CMODE, 0x80), ··· 221 208 .autoresume_en = BIT(3), 222 209 }; 223 210 224 - static const struct qusb2_phy_cfg qusb2_v2_phy_cfg = { 225 - .tbl = qusb2_v2_init_tbl, 226 - .tbl_num = ARRAY_SIZE(qusb2_v2_init_tbl), 227 - .regs = qusb2_v2_regs_layout, 211 + static const struct qusb2_phy_cfg sdm845_phy_cfg = { 212 + .tbl = sdm845_init_tbl, 213 + .tbl_num = ARRAY_SIZE(sdm845_init_tbl), 214 + .regs = sdm845_regs_layout, 228 215 229 216 .disable_ctrl = (PWR_CTRL1_VREF_SUPPLY_TRIM | PWR_CTRL1_CLAMP_N_EN | 230 217 POWER_DOWN), ··· 254 241 * @tcsr: TCSR syscon register map 255 242 * @cell: nvmem cell containing phy tuning value 256 243 * 244 + * @override_imp_res_offset: PHY should use different rescode offset 245 + * @imp_res_offset_value: rescode offset to be updated in IMP_CTRL1 register 246 + * @override_hstx_trim: PHY should use different HSTX o/p current value 247 + * @hstx_trim_value: HSTX_TRIM value to be updated in TUNE1 register 248 + * @override_preemphasis: PHY should use different pre-amphasis amplitude 249 + * @preemphasis_level: Amplitude Pre-Emphasis to be updated in TUNE1 register 250 + * @override_preemphasis_width: PHY should use different pre-emphasis duration 251 + * @preemphasis_width: half/full-width Pre-Emphasis updated via TUNE1 252 + * 257 253 * @cfg: phy config data 258 254 * @has_se_clk_scheme: indicate if PHY has single-ended ref clock scheme 259 255 * @phy_initialized: indicate if PHY has been initialized ··· 281 259 struct regmap *tcsr; 282 260 struct nvmem_cell *cell; 283 261 262 + bool override_imp_res_offset; 263 + u8 imp_res_offset_value; 264 + bool override_hstx_trim; 265 + u8 hstx_trim_value; 266 + bool override_preemphasis; 267 + u8 preemphasis_level; 268 + bool override_preemphasis_width; 269 + u8 preemphasis_width; 270 + 284 271 const struct qusb2_phy_cfg *cfg; 285 272 bool has_se_clk_scheme; 286 273 bool phy_initialized; 287 274 enum phy_mode mode; 288 275 }; 276 + 277 + static inline void qusb2_write_mask(void __iomem *base, u32 offset, 278 + u32 val, u32 mask) 279 + { 280 + u32 reg; 281 + 282 + reg = readl(base + offset); 283 + reg &= ~mask; 284 + reg |= val & mask; 285 + writel(reg, base + offset); 286 + 287 + /* Ensure above write is completed */ 288 + readl(base + offset); 289 + } 289 290 290 291 static inline void qusb2_setbits(void __iomem *base, u32 offset, u32 val) 291 292 { ··· 346 301 writel(tbl[i].val, base + regs[tbl[i].offset]); 347 302 else 348 303 writel(tbl[i].val, base + tbl[i].offset); 304 + } 305 + } 306 + 307 + /* 308 + * Update board specific PHY tuning override values if specified from 309 + * device tree. 310 + */ 311 + static void qusb2_phy_override_phy_params(struct qusb2_phy *qphy) 312 + { 313 + const struct qusb2_phy_cfg *cfg = qphy->cfg; 314 + 315 + if (qphy->override_imp_res_offset) 316 + qusb2_write_mask(qphy->base, QUSB2PHY_IMP_CTRL1, 317 + qphy->imp_res_offset_value << IMP_RES_OFFSET_SHIFT, 318 + IMP_RES_OFFSET_MASK); 319 + 320 + if (qphy->override_hstx_trim) 321 + qusb2_write_mask(qphy->base, cfg->regs[QUSB2PHY_PORT_TUNE1], 322 + qphy->hstx_trim_value << HSTX_TRIM_SHIFT, 323 + HSTX_TRIM_MASK); 324 + 325 + if (qphy->override_preemphasis) 326 + qusb2_write_mask(qphy->base, cfg->regs[QUSB2PHY_PORT_TUNE1], 327 + qphy->preemphasis_level << PREEMPHASIS_EN_SHIFT, 328 + PREEMPHASIS_EN_MASK); 329 + 330 + if (qphy->override_preemphasis_width) { 331 + if (qphy->preemphasis_width == 332 + QUSB2_V2_PREEMPHASIS_WIDTH_HALF_BIT) 333 + qusb2_setbits(qphy->base, 334 + cfg->regs[QUSB2PHY_PORT_TUNE1], 335 + PREEMPH_WIDTH_HALF_BIT); 336 + else 337 + qusb2_clrbits(qphy->base, 338 + cfg->regs[QUSB2PHY_PORT_TUNE1], 339 + PREEMPH_WIDTH_HALF_BIT); 349 340 } 350 341 } 351 342 ··· 606 525 qcom_qusb2_phy_configure(qphy->base, cfg->regs, cfg->tbl, 607 526 cfg->tbl_num); 608 527 528 + /* Override board specific PHY tuning values */ 529 + qusb2_phy_override_phy_params(qphy); 530 + 609 531 /* Set efuse value for tuning the PHY */ 610 532 qusb2_phy_set_tune2_param(qphy); 611 533 ··· 731 647 .compatible = "qcom,msm8996-qusb2-phy", 732 648 .data = &msm8996_phy_cfg, 733 649 }, { 734 - .compatible = "qcom,qusb2-v2-phy", 735 - .data = &qusb2_v2_phy_cfg, 650 + .compatible = "qcom,sdm845-qusb2-phy", 651 + .data = &sdm845_phy_cfg, 736 652 }, 737 653 { }, 738 654 }; ··· 752 668 struct resource *res; 753 669 int ret, i; 754 670 int num; 671 + u32 value; 755 672 756 673 qphy = devm_kzalloc(dev, sizeof(*qphy), GFP_KERNEL); 757 674 if (!qphy) ··· 821 736 qphy->cell = NULL; 822 737 dev_dbg(dev, "failed to lookup tune2 hstx trim value\n"); 823 738 } 739 + 740 + if (!of_property_read_u32(dev->of_node, "qcom,imp-res-offset-value", 741 + &value)) { 742 + qphy->imp_res_offset_value = (u8)value; 743 + qphy->override_imp_res_offset = true; 744 + } 745 + 746 + if (!of_property_read_u32(dev->of_node, "qcom,hstx-trim-value", 747 + &value)) { 748 + qphy->hstx_trim_value = (u8)value; 749 + qphy->override_hstx_trim = true; 750 + } 751 + 752 + if (!of_property_read_u32(dev->of_node, "qcom,preemphasis-level", 753 + &value)) { 754 + qphy->preemphasis_level = (u8)value; 755 + qphy->override_preemphasis = true; 756 + } 757 + 758 + if (!of_property_read_u32(dev->of_node, "qcom,preemphasis-width", 759 + &value)) { 760 + qphy->preemphasis_width = (u8)value; 761 + qphy->override_preemphasis_width = true; 762 + } 763 + 824 764 pm_runtime_set_active(dev); 825 765 pm_runtime_enable(dev); 826 766 /*