Lines Matching +full:sc8280xp +full:- +full:qmp +full:- +full:usb43dp +full:- +full:phy
1 // SPDX-License-Identifier: GPL-2.0
7 #include <linux/clk-provider.h>
16 #include <linux/phy/phy.h>
24 #include <drm/bridge/aux-bridge.h>
26 #include <dt-bindings/phy/phy-qcom-qmp.h>
28 #include "phy-qcom-qmp-common.h"
30 #include "phy-qcom-qmp.h"
31 #include "phy-qcom-qmp-pcs-misc-v3.h"
32 #include "phy-qcom-qmp-pcs-usb-v4.h"
33 #include "phy-qcom-qmp-pcs-usb-v5.h"
34 #include "phy-qcom-qmp-pcs-usb-v6.h"
36 #include "phy-qcom-qmp-dp-com-v3.h"
38 #include "phy-qcom-qmp-dp-phy.h"
39 #include "phy-qcom-qmp-dp-phy-v3.h"
40 #include "phy-qcom-qmp-dp-phy-v4.h"
41 #include "phy-qcom-qmp-dp-phy-v5.h"
42 #include "phy-qcom-qmp-dp-phy-v6.h"
45 /* DP PHY soft reset */
47 /* mux to select DP PHY reset control, 0:HW control, 1: software reset */
49 /* USB3 PHY soft reset */
51 /* mux to select USB3 PHY reset control, 0:HW control, 1: software reset */
64 /* set of registers with offsets different per-PHY */
1435 { .name = "vdda-phy", .enable_load = 21800 },
1436 { .name = "vdda-pll", .enable_load = 36000 },
1551 /* Init sequence for PHY blocks - serdes, tx, rx, pcs */
1568 /* Init sequence for DP PHY block link rates */
1578 /* DP PHY swing and pre_emphasis tables */
1584 /* DP PHY callbacks */
1585 int (*configure_dp_phy)(struct qmp_combo *qmp);
1586 void (*configure_dp_tx)(struct qmp_combo *qmp);
1587 int (*calibrate_dp_phy)(struct qmp_combo *qmp);
1588 void (*dp_aux_init)(struct qmp_combo *qmp);
1600 /* true, if PHY needs delay after POWER_DOWN */
1638 struct phy *usb_phy;
1642 struct phy *dp_phy;
1655 static void qmp_v3_dp_aux_init(struct qmp_combo *qmp);
1656 static void qmp_v3_configure_dp_tx(struct qmp_combo *qmp);
1657 static int qmp_v3_configure_dp_phy(struct qmp_combo *qmp);
1658 static int qmp_v3_calibrate_dp_phy(struct qmp_combo *qmp);
1660 static void qmp_v4_dp_aux_init(struct qmp_combo *qmp);
1661 static void qmp_v4_configure_dp_tx(struct qmp_combo *qmp);
1662 static int qmp_v4_configure_dp_phy(struct qmp_combo *qmp);
1663 static int qmp_v4_calibrate_dp_phy(struct qmp_combo *qmp);
1689 /* list of clocks required by phy */
1696 "phy", "common",
1700 "phy",
2187 static int qmp_combo_dp_serdes_init(struct qmp_combo *qmp) in qmp_combo_dp_serdes_init() argument
2189 const struct qmp_phy_cfg *cfg = qmp->cfg; in qmp_combo_dp_serdes_init()
2190 void __iomem *serdes = qmp->dp_serdes; in qmp_combo_dp_serdes_init()
2191 const struct phy_configure_opts_dp *dp_opts = &qmp->dp_opts; in qmp_combo_dp_serdes_init()
2193 qmp_configure(qmp->dev, serdes, cfg->dp_serdes_tbl, in qmp_combo_dp_serdes_init()
2194 cfg->dp_serdes_tbl_num); in qmp_combo_dp_serdes_init()
2196 switch (dp_opts->link_rate) { in qmp_combo_dp_serdes_init()
2198 qmp_configure(qmp->dev, serdes, cfg->serdes_tbl_rbr, in qmp_combo_dp_serdes_init()
2199 cfg->serdes_tbl_rbr_num); in qmp_combo_dp_serdes_init()
2202 qmp_configure(qmp->dev, serdes, cfg->serdes_tbl_hbr, in qmp_combo_dp_serdes_init()
2203 cfg->serdes_tbl_hbr_num); in qmp_combo_dp_serdes_init()
2206 qmp_configure(qmp->dev, serdes, cfg->serdes_tbl_hbr2, in qmp_combo_dp_serdes_init()
2207 cfg->serdes_tbl_hbr2_num); in qmp_combo_dp_serdes_init()
2210 qmp_configure(qmp->dev, serdes, cfg->serdes_tbl_hbr3, in qmp_combo_dp_serdes_init()
2211 cfg->serdes_tbl_hbr3_num); in qmp_combo_dp_serdes_init()
2215 return -EINVAL; in qmp_combo_dp_serdes_init()
2221 static void qmp_v3_dp_aux_init(struct qmp_combo *qmp) in qmp_v3_dp_aux_init() argument
2223 const struct qmp_phy_cfg *cfg = qmp->cfg; in qmp_v3_dp_aux_init()
2227 qmp->dp_dp_phy + QSERDES_DP_PHY_PD_CTL); in qmp_v3_dp_aux_init()
2229 /* Turn on BIAS current for PHY/PLL */ in qmp_v3_dp_aux_init()
2232 qmp->dp_serdes + cfg->regs[QPHY_COM_BIAS_EN_CLKBUFLR_EN]); in qmp_v3_dp_aux_init()
2234 writel(DP_PHY_PD_CTL_PSR_PWRDN, qmp->dp_dp_phy + QSERDES_DP_PHY_PD_CTL); in qmp_v3_dp_aux_init()
2240 qmp->dp_dp_phy + QSERDES_DP_PHY_PD_CTL); in qmp_v3_dp_aux_init()
2246 qmp->dp_serdes + cfg->regs[QPHY_COM_BIAS_EN_CLKBUFLR_EN]); in qmp_v3_dp_aux_init()
2248 writel(0x00, qmp->dp_dp_phy + QSERDES_DP_PHY_AUX_CFG0); in qmp_v3_dp_aux_init()
2249 writel(0x13, qmp->dp_dp_phy + QSERDES_DP_PHY_AUX_CFG1); in qmp_v3_dp_aux_init()
2250 writel(0x24, qmp->dp_dp_phy + QSERDES_DP_PHY_AUX_CFG2); in qmp_v3_dp_aux_init()
2251 writel(0x00, qmp->dp_dp_phy + QSERDES_DP_PHY_AUX_CFG3); in qmp_v3_dp_aux_init()
2252 writel(0x0a, qmp->dp_dp_phy + QSERDES_DP_PHY_AUX_CFG4); in qmp_v3_dp_aux_init()
2253 writel(0x26, qmp->dp_dp_phy + QSERDES_DP_PHY_AUX_CFG5); in qmp_v3_dp_aux_init()
2254 writel(0x0a, qmp->dp_dp_phy + QSERDES_DP_PHY_AUX_CFG6); in qmp_v3_dp_aux_init()
2255 writel(0x03, qmp->dp_dp_phy + QSERDES_DP_PHY_AUX_CFG7); in qmp_v3_dp_aux_init()
2256 writel(0xbb, qmp->dp_dp_phy + QSERDES_DP_PHY_AUX_CFG8); in qmp_v3_dp_aux_init()
2257 writel(0x03, qmp->dp_dp_phy + QSERDES_DP_PHY_AUX_CFG9); in qmp_v3_dp_aux_init()
2258 qmp->dp_aux_cfg = 0; in qmp_v3_dp_aux_init()
2263 qmp->dp_dp_phy + QSERDES_V3_DP_PHY_AUX_INTERRUPT_MASK); in qmp_v3_dp_aux_init()
2266 static int qmp_combo_configure_dp_swing(struct qmp_combo *qmp) in qmp_combo_configure_dp_swing() argument
2268 const struct phy_configure_opts_dp *dp_opts = &qmp->dp_opts; in qmp_combo_configure_dp_swing()
2269 const struct qmp_phy_cfg *cfg = qmp->cfg; in qmp_combo_configure_dp_swing()
2274 for (i = 0; i < dp_opts->lanes; i++) { in qmp_combo_configure_dp_swing()
2275 v_level = max(v_level, dp_opts->voltage[i]); in qmp_combo_configure_dp_swing()
2276 p_level = max(p_level, dp_opts->pre[i]); in qmp_combo_configure_dp_swing()
2279 if (dp_opts->link_rate <= 2700) { in qmp_combo_configure_dp_swing()
2280 voltage_swing_cfg = (*cfg->swing_hbr_rbr)[v_level][p_level]; in qmp_combo_configure_dp_swing()
2281 pre_emphasis_cfg = (*cfg->pre_emphasis_hbr_rbr)[v_level][p_level]; in qmp_combo_configure_dp_swing()
2283 voltage_swing_cfg = (*cfg->swing_hbr3_hbr2)[v_level][p_level]; in qmp_combo_configure_dp_swing()
2284 pre_emphasis_cfg = (*cfg->pre_emphasis_hbr3_hbr2)[v_level][p_level]; in qmp_combo_configure_dp_swing()
2289 return -EINVAL; in qmp_combo_configure_dp_swing()
2295 writel(voltage_swing_cfg, qmp->dp_tx + cfg->regs[QPHY_TX_TX_DRV_LVL]); in qmp_combo_configure_dp_swing()
2296 writel(pre_emphasis_cfg, qmp->dp_tx + cfg->regs[QPHY_TX_TX_EMP_POST1_LVL]); in qmp_combo_configure_dp_swing()
2297 writel(voltage_swing_cfg, qmp->dp_tx2 + cfg->regs[QPHY_TX_TX_DRV_LVL]); in qmp_combo_configure_dp_swing()
2298 writel(pre_emphasis_cfg, qmp->dp_tx2 + cfg->regs[QPHY_TX_TX_EMP_POST1_LVL]); in qmp_combo_configure_dp_swing()
2303 static void qmp_v3_configure_dp_tx(struct qmp_combo *qmp) in qmp_v3_configure_dp_tx() argument
2305 const struct phy_configure_opts_dp *dp_opts = &qmp->dp_opts; in qmp_v3_configure_dp_tx()
2308 if (qmp_combo_configure_dp_swing(qmp) < 0) in qmp_v3_configure_dp_tx()
2311 if (dp_opts->lanes == 1) { in qmp_v3_configure_dp_tx()
2319 writel(drvr_en, qmp->dp_tx + QSERDES_V3_TX_HIGHZ_DRVR_EN); in qmp_v3_configure_dp_tx()
2320 writel(bias_en, qmp->dp_tx + QSERDES_V3_TX_TRANSCEIVER_BIAS_EN); in qmp_v3_configure_dp_tx()
2321 writel(drvr_en, qmp->dp_tx2 + QSERDES_V3_TX_HIGHZ_DRVR_EN); in qmp_v3_configure_dp_tx()
2322 writel(bias_en, qmp->dp_tx2 + QSERDES_V3_TX_TRANSCEIVER_BIAS_EN); in qmp_v3_configure_dp_tx()
2325 static bool qmp_combo_configure_dp_mode(struct qmp_combo *qmp) in qmp_combo_configure_dp_mode() argument
2327 bool reverse = (qmp->orientation == TYPEC_ORIENTATION_REVERSE); in qmp_combo_configure_dp_mode()
2328 const struct phy_configure_opts_dp *dp_opts = &qmp->dp_opts; in qmp_combo_configure_dp_mode()
2334 if (dp_opts->lanes == 4 || reverse) in qmp_combo_configure_dp_mode()
2336 if (dp_opts->lanes == 4 || !reverse) in qmp_combo_configure_dp_mode()
2339 writel(val, qmp->dp_dp_phy + QSERDES_DP_PHY_PD_CTL); in qmp_combo_configure_dp_mode()
2342 writel(0x4c, qmp->dp_dp_phy + QSERDES_DP_PHY_MODE); in qmp_combo_configure_dp_mode()
2344 writel(0x5c, qmp->dp_dp_phy + QSERDES_DP_PHY_MODE); in qmp_combo_configure_dp_mode()
2349 static int qmp_combo_configure_dp_clocks(struct qmp_combo *qmp) in qmp_combo_configure_dp_clocks() argument
2351 const struct phy_configure_opts_dp *dp_opts = &qmp->dp_opts; in qmp_combo_configure_dp_clocks()
2354 const struct qmp_phy_cfg *cfg = qmp->cfg; in qmp_combo_configure_dp_clocks()
2356 switch (dp_opts->link_rate) { in qmp_combo_configure_dp_clocks()
2375 return -EINVAL; in qmp_combo_configure_dp_clocks()
2377 writel(phy_vco_div, qmp->dp_dp_phy + cfg->regs[QPHY_DP_PHY_VCO_DIV]); in qmp_combo_configure_dp_clocks()
2379 clk_set_rate(qmp->dp_link_hw.clk, dp_opts->link_rate * 100000); in qmp_combo_configure_dp_clocks()
2380 clk_set_rate(qmp->dp_pixel_hw.clk, pixel_freq); in qmp_combo_configure_dp_clocks()
2385 static int qmp_v3_configure_dp_phy(struct qmp_combo *qmp) in qmp_v3_configure_dp_phy() argument
2387 const struct qmp_phy_cfg *cfg = qmp->cfg; in qmp_v3_configure_dp_phy()
2391 qmp_combo_configure_dp_mode(qmp); in qmp_v3_configure_dp_phy()
2393 writel(0x05, qmp->dp_dp_phy + QSERDES_V3_DP_PHY_TX0_TX1_LANE_CTL); in qmp_v3_configure_dp_phy()
2394 writel(0x05, qmp->dp_dp_phy + QSERDES_V3_DP_PHY_TX2_TX3_LANE_CTL); in qmp_v3_configure_dp_phy()
2396 ret = qmp_combo_configure_dp_clocks(qmp); in qmp_v3_configure_dp_phy()
2400 writel(0x04, qmp->dp_dp_phy + QSERDES_DP_PHY_AUX_CFG2); in qmp_v3_configure_dp_phy()
2401 writel(0x01, qmp->dp_dp_phy + QSERDES_DP_PHY_CFG); in qmp_v3_configure_dp_phy()
2402 writel(0x05, qmp->dp_dp_phy + QSERDES_DP_PHY_CFG); in qmp_v3_configure_dp_phy()
2403 writel(0x01, qmp->dp_dp_phy + QSERDES_DP_PHY_CFG); in qmp_v3_configure_dp_phy()
2404 writel(0x09, qmp->dp_dp_phy + QSERDES_DP_PHY_CFG); in qmp_v3_configure_dp_phy()
2406 writel(0x20, qmp->dp_serdes + cfg->regs[QPHY_COM_RESETSM_CNTRL]); in qmp_v3_configure_dp_phy()
2408 if (readl_poll_timeout(qmp->dp_serdes + cfg->regs[QPHY_COM_C_READY_STATUS], in qmp_v3_configure_dp_phy()
2413 return -ETIMEDOUT; in qmp_v3_configure_dp_phy()
2415 writel(0x19, qmp->dp_dp_phy + QSERDES_DP_PHY_CFG); in qmp_v3_configure_dp_phy()
2417 if (readl_poll_timeout(qmp->dp_dp_phy + cfg->regs[QPHY_DP_PHY_STATUS], in qmp_v3_configure_dp_phy()
2422 return -ETIMEDOUT; in qmp_v3_configure_dp_phy()
2424 writel(0x18, qmp->dp_dp_phy + QSERDES_DP_PHY_CFG); in qmp_v3_configure_dp_phy()
2426 writel(0x19, qmp->dp_dp_phy + QSERDES_DP_PHY_CFG); in qmp_v3_configure_dp_phy()
2428 return readl_poll_timeout(qmp->dp_dp_phy + cfg->regs[QPHY_DP_PHY_STATUS], in qmp_v3_configure_dp_phy()
2439 static int qmp_v3_calibrate_dp_phy(struct qmp_combo *qmp) in qmp_v3_calibrate_dp_phy() argument
2444 qmp->dp_aux_cfg++; in qmp_v3_calibrate_dp_phy()
2445 qmp->dp_aux_cfg %= ARRAY_SIZE(cfg1_settings); in qmp_v3_calibrate_dp_phy()
2446 val = cfg1_settings[qmp->dp_aux_cfg]; in qmp_v3_calibrate_dp_phy()
2448 writel(val, qmp->dp_dp_phy + QSERDES_DP_PHY_AUX_CFG1); in qmp_v3_calibrate_dp_phy()
2453 static void qmp_v4_dp_aux_init(struct qmp_combo *qmp) in qmp_v4_dp_aux_init() argument
2455 const struct qmp_phy_cfg *cfg = qmp->cfg; in qmp_v4_dp_aux_init()
2459 qmp->dp_dp_phy + QSERDES_DP_PHY_PD_CTL); in qmp_v4_dp_aux_init()
2461 /* Turn on BIAS current for PHY/PLL */ in qmp_v4_dp_aux_init()
2462 writel(0x17, qmp->dp_serdes + cfg->regs[QPHY_COM_BIAS_EN_CLKBUFLR_EN]); in qmp_v4_dp_aux_init()
2464 writel(0x00, qmp->dp_dp_phy + QSERDES_DP_PHY_AUX_CFG0); in qmp_v4_dp_aux_init()
2465 writel(0x13, qmp->dp_dp_phy + QSERDES_DP_PHY_AUX_CFG1); in qmp_v4_dp_aux_init()
2466 writel(0xa4, qmp->dp_dp_phy + QSERDES_DP_PHY_AUX_CFG2); in qmp_v4_dp_aux_init()
2467 writel(0x00, qmp->dp_dp_phy + QSERDES_DP_PHY_AUX_CFG3); in qmp_v4_dp_aux_init()
2468 writel(0x0a, qmp->dp_dp_phy + QSERDES_DP_PHY_AUX_CFG4); in qmp_v4_dp_aux_init()
2469 writel(0x26, qmp->dp_dp_phy + QSERDES_DP_PHY_AUX_CFG5); in qmp_v4_dp_aux_init()
2470 writel(0x0a, qmp->dp_dp_phy + QSERDES_DP_PHY_AUX_CFG6); in qmp_v4_dp_aux_init()
2471 writel(0x03, qmp->dp_dp_phy + QSERDES_DP_PHY_AUX_CFG7); in qmp_v4_dp_aux_init()
2472 writel(0xb7, qmp->dp_dp_phy + QSERDES_DP_PHY_AUX_CFG8); in qmp_v4_dp_aux_init()
2473 writel(0x03, qmp->dp_dp_phy + QSERDES_DP_PHY_AUX_CFG9); in qmp_v4_dp_aux_init()
2474 qmp->dp_aux_cfg = 0; in qmp_v4_dp_aux_init()
2479 qmp->dp_dp_phy + QSERDES_V4_DP_PHY_AUX_INTERRUPT_MASK); in qmp_v4_dp_aux_init()
2482 static void qmp_v4_configure_dp_tx(struct qmp_combo *qmp) in qmp_v4_configure_dp_tx() argument
2484 const struct qmp_phy_cfg *cfg = qmp->cfg; in qmp_v4_configure_dp_tx()
2487 writel(0x27, qmp->dp_tx + cfg->regs[QPHY_TX_TX_DRV_LVL]); in qmp_v4_configure_dp_tx()
2488 writel(0x27, qmp->dp_tx2 + cfg->regs[QPHY_TX_TX_DRV_LVL]); in qmp_v4_configure_dp_tx()
2490 writel(0x20, qmp->dp_tx + cfg->regs[QPHY_TX_TX_EMP_POST1_LVL]); in qmp_v4_configure_dp_tx()
2491 writel(0x20, qmp->dp_tx2 + cfg->regs[QPHY_TX_TX_EMP_POST1_LVL]); in qmp_v4_configure_dp_tx()
2493 qmp_combo_configure_dp_swing(qmp); in qmp_v4_configure_dp_tx()
2496 static int qmp_v456_configure_dp_phy(struct qmp_combo *qmp) in qmp_v456_configure_dp_phy() argument
2498 const struct qmp_phy_cfg *cfg = qmp->cfg; in qmp_v456_configure_dp_phy()
2502 writel(0x0f, qmp->dp_dp_phy + QSERDES_DP_PHY_CFG_1); in qmp_v456_configure_dp_phy()
2504 qmp_combo_configure_dp_mode(qmp); in qmp_v456_configure_dp_phy()
2506 writel(0x13, qmp->dp_dp_phy + QSERDES_DP_PHY_AUX_CFG1); in qmp_v456_configure_dp_phy()
2507 writel(0xa4, qmp->dp_dp_phy + QSERDES_DP_PHY_AUX_CFG2); in qmp_v456_configure_dp_phy()
2509 writel(0x05, qmp->dp_dp_phy + QSERDES_V4_DP_PHY_TX0_TX1_LANE_CTL); in qmp_v456_configure_dp_phy()
2510 writel(0x05, qmp->dp_dp_phy + QSERDES_V4_DP_PHY_TX2_TX3_LANE_CTL); in qmp_v456_configure_dp_phy()
2512 ret = qmp_combo_configure_dp_clocks(qmp); in qmp_v456_configure_dp_phy()
2516 writel(0x01, qmp->dp_dp_phy + QSERDES_DP_PHY_CFG); in qmp_v456_configure_dp_phy()
2517 writel(0x05, qmp->dp_dp_phy + QSERDES_DP_PHY_CFG); in qmp_v456_configure_dp_phy()
2518 writel(0x01, qmp->dp_dp_phy + QSERDES_DP_PHY_CFG); in qmp_v456_configure_dp_phy()
2519 writel(0x09, qmp->dp_dp_phy + QSERDES_DP_PHY_CFG); in qmp_v456_configure_dp_phy()
2521 writel(0x20, qmp->dp_serdes + cfg->regs[QPHY_COM_RESETSM_CNTRL]); in qmp_v456_configure_dp_phy()
2523 if (readl_poll_timeout(qmp->dp_serdes + cfg->regs[QPHY_COM_C_READY_STATUS], in qmp_v456_configure_dp_phy()
2528 return -ETIMEDOUT; in qmp_v456_configure_dp_phy()
2530 if (readl_poll_timeout(qmp->dp_serdes + cfg->regs[QPHY_COM_CMN_STATUS], in qmp_v456_configure_dp_phy()
2535 return -ETIMEDOUT; in qmp_v456_configure_dp_phy()
2537 if (readl_poll_timeout(qmp->dp_serdes + cfg->regs[QPHY_COM_CMN_STATUS], in qmp_v456_configure_dp_phy()
2542 return -ETIMEDOUT; in qmp_v456_configure_dp_phy()
2544 writel(0x19, qmp->dp_dp_phy + QSERDES_DP_PHY_CFG); in qmp_v456_configure_dp_phy()
2546 if (readl_poll_timeout(qmp->dp_dp_phy + cfg->regs[QPHY_DP_PHY_STATUS], in qmp_v456_configure_dp_phy()
2551 return -ETIMEDOUT; in qmp_v456_configure_dp_phy()
2553 if (readl_poll_timeout(qmp->dp_dp_phy + cfg->regs[QPHY_DP_PHY_STATUS], in qmp_v456_configure_dp_phy()
2558 return -ETIMEDOUT; in qmp_v456_configure_dp_phy()
2563 static int qmp_v4_configure_dp_phy(struct qmp_combo *qmp) in qmp_v4_configure_dp_phy() argument
2565 const struct qmp_phy_cfg *cfg = qmp->cfg; in qmp_v4_configure_dp_phy()
2566 bool reverse = (qmp->orientation == TYPEC_ORIENTATION_REVERSE); in qmp_v4_configure_dp_phy()
2567 const struct phy_configure_opts_dp *dp_opts = &qmp->dp_opts; in qmp_v4_configure_dp_phy()
2572 ret = qmp_v456_configure_dp_phy(qmp); in qmp_v4_configure_dp_phy()
2577 * At least for 7nm DP PHY this has to be done after enabling link in qmp_v4_configure_dp_phy()
2581 if (dp_opts->lanes == 1) { in qmp_v4_configure_dp_phy()
2586 } else if (dp_opts->lanes == 2) { in qmp_v4_configure_dp_phy()
2598 writel(drvr0_en, qmp->dp_tx + cfg->regs[QPHY_TX_HIGHZ_DRVR_EN]); in qmp_v4_configure_dp_phy()
2599 writel(bias0_en, qmp->dp_tx + cfg->regs[QPHY_TX_TRANSCEIVER_BIAS_EN]); in qmp_v4_configure_dp_phy()
2600 writel(drvr1_en, qmp->dp_tx2 + cfg->regs[QPHY_TX_HIGHZ_DRVR_EN]); in qmp_v4_configure_dp_phy()
2601 writel(bias1_en, qmp->dp_tx2 + cfg->regs[QPHY_TX_TRANSCEIVER_BIAS_EN]); in qmp_v4_configure_dp_phy()
2603 writel(0x18, qmp->dp_dp_phy + QSERDES_DP_PHY_CFG); in qmp_v4_configure_dp_phy()
2605 writel(0x19, qmp->dp_dp_phy + QSERDES_DP_PHY_CFG); in qmp_v4_configure_dp_phy()
2607 if (readl_poll_timeout(qmp->dp_dp_phy + cfg->regs[QPHY_DP_PHY_STATUS], in qmp_v4_configure_dp_phy()
2612 return -ETIMEDOUT; in qmp_v4_configure_dp_phy()
2614 writel(0x0a, qmp->dp_tx + cfg->regs[QPHY_TX_TX_POL_INV]); in qmp_v4_configure_dp_phy()
2615 writel(0x0a, qmp->dp_tx2 + cfg->regs[QPHY_TX_TX_POL_INV]); in qmp_v4_configure_dp_phy()
2617 writel(0x27, qmp->dp_tx + cfg->regs[QPHY_TX_TX_DRV_LVL]); in qmp_v4_configure_dp_phy()
2618 writel(0x27, qmp->dp_tx2 + cfg->regs[QPHY_TX_TX_DRV_LVL]); in qmp_v4_configure_dp_phy()
2620 writel(0x20, qmp->dp_tx + cfg->regs[QPHY_TX_TX_EMP_POST1_LVL]); in qmp_v4_configure_dp_phy()
2621 writel(0x20, qmp->dp_tx2 + cfg->regs[QPHY_TX_TX_EMP_POST1_LVL]); in qmp_v4_configure_dp_phy()
2630 static int qmp_v4_calibrate_dp_phy(struct qmp_combo *qmp) in qmp_v4_calibrate_dp_phy() argument
2635 qmp->dp_aux_cfg++; in qmp_v4_calibrate_dp_phy()
2636 qmp->dp_aux_cfg %= ARRAY_SIZE(cfg1_settings); in qmp_v4_calibrate_dp_phy()
2637 val = cfg1_settings[qmp->dp_aux_cfg]; in qmp_v4_calibrate_dp_phy()
2639 writel(val, qmp->dp_dp_phy + QSERDES_DP_PHY_AUX_CFG1); in qmp_v4_calibrate_dp_phy()
2644 static int qmp_combo_dp_configure(struct phy *phy, union phy_configure_opts *opts) in qmp_combo_dp_configure() argument
2646 const struct phy_configure_opts_dp *dp_opts = &opts->dp; in qmp_combo_dp_configure()
2647 struct qmp_combo *qmp = phy_get_drvdata(phy); in qmp_combo_dp_configure() local
2648 const struct qmp_phy_cfg *cfg = qmp->cfg; in qmp_combo_dp_configure()
2650 mutex_lock(&qmp->phy_mutex); in qmp_combo_dp_configure()
2652 memcpy(&qmp->dp_opts, dp_opts, sizeof(*dp_opts)); in qmp_combo_dp_configure()
2653 if (qmp->dp_opts.set_voltages) { in qmp_combo_dp_configure()
2654 cfg->configure_dp_tx(qmp); in qmp_combo_dp_configure()
2655 qmp->dp_opts.set_voltages = 0; in qmp_combo_dp_configure()
2658 mutex_unlock(&qmp->phy_mutex); in qmp_combo_dp_configure()
2663 static int qmp_combo_dp_calibrate(struct phy *phy) in qmp_combo_dp_calibrate() argument
2665 struct qmp_combo *qmp = phy_get_drvdata(phy); in qmp_combo_dp_calibrate() local
2666 const struct qmp_phy_cfg *cfg = qmp->cfg; in qmp_combo_dp_calibrate()
2669 mutex_lock(&qmp->phy_mutex); in qmp_combo_dp_calibrate()
2671 if (cfg->calibrate_dp_phy) in qmp_combo_dp_calibrate()
2672 ret = cfg->calibrate_dp_phy(qmp); in qmp_combo_dp_calibrate()
2674 mutex_unlock(&qmp->phy_mutex); in qmp_combo_dp_calibrate()
2679 static int qmp_combo_com_init(struct qmp_combo *qmp, bool force) in qmp_combo_com_init() argument
2681 const struct qmp_phy_cfg *cfg = qmp->cfg; in qmp_combo_com_init()
2682 void __iomem *com = qmp->com; in qmp_combo_com_init()
2686 if (!force && qmp->init_count++) in qmp_combo_com_init()
2689 ret = regulator_bulk_enable(cfg->num_vregs, qmp->vregs); in qmp_combo_com_init()
2691 dev_err(qmp->dev, "failed to enable regulators, err=%d\n", ret); in qmp_combo_com_init()
2695 ret = reset_control_bulk_assert(cfg->num_resets, qmp->resets); in qmp_combo_com_init()
2697 dev_err(qmp->dev, "reset assert failed\n"); in qmp_combo_com_init()
2701 ret = reset_control_bulk_deassert(cfg->num_resets, qmp->resets); in qmp_combo_com_init()
2703 dev_err(qmp->dev, "reset deassert failed\n"); in qmp_combo_com_init()
2707 ret = clk_bulk_prepare_enable(qmp->num_clks, qmp->clks); in qmp_combo_com_init()
2713 /* override hardware control for reset of qmp phy */ in qmp_combo_com_init()
2720 if (qmp->orientation == TYPEC_ORIENTATION_REVERSE) in qmp_combo_com_init()
2725 /* bring both QMP USB and QMP DP PHYs PCS block out of reset */ in qmp_combo_com_init()
2733 qphy_setbits(qmp->pcs, cfg->regs[QPHY_PCS_POWER_DOWN_CONTROL], in qmp_combo_com_init()
2739 reset_control_bulk_assert(cfg->num_resets, qmp->resets); in qmp_combo_com_init()
2741 regulator_bulk_disable(cfg->num_vregs, qmp->vregs); in qmp_combo_com_init()
2743 qmp->init_count--; in qmp_combo_com_init()
2748 static int qmp_combo_com_exit(struct qmp_combo *qmp, bool force) in qmp_combo_com_exit() argument
2750 const struct qmp_phy_cfg *cfg = qmp->cfg; in qmp_combo_com_exit()
2752 if (!force && --qmp->init_count) in qmp_combo_com_exit()
2755 reset_control_bulk_assert(cfg->num_resets, qmp->resets); in qmp_combo_com_exit()
2757 clk_bulk_disable_unprepare(qmp->num_clks, qmp->clks); in qmp_combo_com_exit()
2759 regulator_bulk_disable(cfg->num_vregs, qmp->vregs); in qmp_combo_com_exit()
2764 static int qmp_combo_dp_init(struct phy *phy) in qmp_combo_dp_init() argument
2766 struct qmp_combo *qmp = phy_get_drvdata(phy); in qmp_combo_dp_init() local
2767 const struct qmp_phy_cfg *cfg = qmp->cfg; in qmp_combo_dp_init()
2770 mutex_lock(&qmp->phy_mutex); in qmp_combo_dp_init()
2772 ret = qmp_combo_com_init(qmp, false); in qmp_combo_dp_init()
2776 cfg->dp_aux_init(qmp); in qmp_combo_dp_init()
2778 qmp->dp_init_count++; in qmp_combo_dp_init()
2781 mutex_unlock(&qmp->phy_mutex); in qmp_combo_dp_init()
2785 static int qmp_combo_dp_exit(struct phy *phy) in qmp_combo_dp_exit() argument
2787 struct qmp_combo *qmp = phy_get_drvdata(phy); in qmp_combo_dp_exit() local
2789 mutex_lock(&qmp->phy_mutex); in qmp_combo_dp_exit()
2791 qmp_combo_com_exit(qmp, false); in qmp_combo_dp_exit()
2793 qmp->dp_init_count--; in qmp_combo_dp_exit()
2795 mutex_unlock(&qmp->phy_mutex); in qmp_combo_dp_exit()
2800 static int qmp_combo_dp_power_on(struct phy *phy) in qmp_combo_dp_power_on() argument
2802 struct qmp_combo *qmp = phy_get_drvdata(phy); in qmp_combo_dp_power_on() local
2803 const struct qmp_phy_cfg *cfg = qmp->cfg; in qmp_combo_dp_power_on()
2804 void __iomem *tx = qmp->dp_tx; in qmp_combo_dp_power_on()
2805 void __iomem *tx2 = qmp->dp_tx2; in qmp_combo_dp_power_on()
2807 mutex_lock(&qmp->phy_mutex); in qmp_combo_dp_power_on()
2809 qmp_combo_dp_serdes_init(qmp); in qmp_combo_dp_power_on()
2811 qmp_configure_lane(qmp->dev, tx, cfg->dp_tx_tbl, cfg->dp_tx_tbl_num, 1); in qmp_combo_dp_power_on()
2812 qmp_configure_lane(qmp->dev, tx2, cfg->dp_tx_tbl, cfg->dp_tx_tbl_num, 2); in qmp_combo_dp_power_on()
2815 cfg->configure_dp_tx(qmp); in qmp_combo_dp_power_on()
2818 cfg->configure_dp_phy(qmp); in qmp_combo_dp_power_on()
2820 mutex_unlock(&qmp->phy_mutex); in qmp_combo_dp_power_on()
2825 static int qmp_combo_dp_power_off(struct phy *phy) in qmp_combo_dp_power_off() argument
2827 struct qmp_combo *qmp = phy_get_drvdata(phy); in qmp_combo_dp_power_off() local
2829 mutex_lock(&qmp->phy_mutex); in qmp_combo_dp_power_off()
2831 /* Assert DP PHY power down */ in qmp_combo_dp_power_off()
2832 writel(DP_PHY_PD_CTL_PSR_PWRDN, qmp->dp_dp_phy + QSERDES_DP_PHY_PD_CTL); in qmp_combo_dp_power_off()
2834 mutex_unlock(&qmp->phy_mutex); in qmp_combo_dp_power_off()
2839 static int qmp_combo_usb_power_on(struct phy *phy) in qmp_combo_usb_power_on() argument
2841 struct qmp_combo *qmp = phy_get_drvdata(phy); in qmp_combo_usb_power_on() local
2842 const struct qmp_phy_cfg *cfg = qmp->cfg; in qmp_combo_usb_power_on()
2843 void __iomem *serdes = qmp->serdes; in qmp_combo_usb_power_on()
2844 void __iomem *tx = qmp->tx; in qmp_combo_usb_power_on()
2845 void __iomem *rx = qmp->rx; in qmp_combo_usb_power_on()
2846 void __iomem *tx2 = qmp->tx2; in qmp_combo_usb_power_on()
2847 void __iomem *rx2 = qmp->rx2; in qmp_combo_usb_power_on()
2848 void __iomem *pcs = qmp->pcs; in qmp_combo_usb_power_on()
2849 void __iomem *pcs_usb = qmp->pcs_usb; in qmp_combo_usb_power_on()
2854 qmp_configure(qmp->dev, serdes, cfg->serdes_tbl, cfg->serdes_tbl_num); in qmp_combo_usb_power_on()
2856 ret = clk_prepare_enable(qmp->pipe_clk); in qmp_combo_usb_power_on()
2858 dev_err(qmp->dev, "pipe_clk enable failed err=%d\n", ret); in qmp_combo_usb_power_on()
2863 qmp_configure_lane(qmp->dev, tx, cfg->tx_tbl, cfg->tx_tbl_num, 1); in qmp_combo_usb_power_on()
2864 qmp_configure_lane(qmp->dev, tx2, cfg->tx_tbl, cfg->tx_tbl_num, 2); in qmp_combo_usb_power_on()
2866 qmp_configure_lane(qmp->dev, rx, cfg->rx_tbl, cfg->rx_tbl_num, 1); in qmp_combo_usb_power_on()
2867 qmp_configure_lane(qmp->dev, rx2, cfg->rx_tbl, cfg->rx_tbl_num, 2); in qmp_combo_usb_power_on()
2869 qmp_configure(qmp->dev, pcs, cfg->pcs_tbl, cfg->pcs_tbl_num); in qmp_combo_usb_power_on()
2872 qmp_configure(qmp->dev, pcs_usb, cfg->pcs_usb_tbl, in qmp_combo_usb_power_on()
2873 cfg->pcs_usb_tbl_num); in qmp_combo_usb_power_on()
2875 if (cfg->has_pwrdn_delay) in qmp_combo_usb_power_on()
2878 /* Pull PHY out of reset state */ in qmp_combo_usb_power_on()
2879 qphy_clrbits(pcs, cfg->regs[QPHY_SW_RESET], SW_RESET); in qmp_combo_usb_power_on()
2881 /* start SerDes and Phy-Coding-Sublayer */ in qmp_combo_usb_power_on()
2882 qphy_setbits(pcs, cfg->regs[QPHY_START_CTRL], SERDES_START | PCS_START); in qmp_combo_usb_power_on()
2884 status = pcs + cfg->regs[QPHY_PCS_STATUS]; in qmp_combo_usb_power_on()
2888 dev_err(qmp->dev, "phy initialization timed-out\n"); in qmp_combo_usb_power_on()
2895 clk_disable_unprepare(qmp->pipe_clk); in qmp_combo_usb_power_on()
2900 static int qmp_combo_usb_power_off(struct phy *phy) in qmp_combo_usb_power_off() argument
2902 struct qmp_combo *qmp = phy_get_drvdata(phy); in qmp_combo_usb_power_off() local
2903 const struct qmp_phy_cfg *cfg = qmp->cfg; in qmp_combo_usb_power_off()
2905 clk_disable_unprepare(qmp->pipe_clk); in qmp_combo_usb_power_off()
2907 /* PHY reset */ in qmp_combo_usb_power_off()
2908 qphy_setbits(qmp->pcs, cfg->regs[QPHY_SW_RESET], SW_RESET); in qmp_combo_usb_power_off()
2910 /* stop SerDes and Phy-Coding-Sublayer */ in qmp_combo_usb_power_off()
2911 qphy_clrbits(qmp->pcs, cfg->regs[QPHY_START_CTRL], in qmp_combo_usb_power_off()
2914 /* Put PHY into POWER DOWN state: active low */ in qmp_combo_usb_power_off()
2915 qphy_clrbits(qmp->pcs, cfg->regs[QPHY_PCS_POWER_DOWN_CONTROL], in qmp_combo_usb_power_off()
2921 static int qmp_combo_usb_init(struct phy *phy) in qmp_combo_usb_init() argument
2923 struct qmp_combo *qmp = phy_get_drvdata(phy); in qmp_combo_usb_init() local
2926 mutex_lock(&qmp->phy_mutex); in qmp_combo_usb_init()
2927 ret = qmp_combo_com_init(qmp, false); in qmp_combo_usb_init()
2931 ret = qmp_combo_usb_power_on(phy); in qmp_combo_usb_init()
2933 qmp_combo_com_exit(qmp, false); in qmp_combo_usb_init()
2937 qmp->usb_init_count++; in qmp_combo_usb_init()
2940 mutex_unlock(&qmp->phy_mutex); in qmp_combo_usb_init()
2944 static int qmp_combo_usb_exit(struct phy *phy) in qmp_combo_usb_exit() argument
2946 struct qmp_combo *qmp = phy_get_drvdata(phy); in qmp_combo_usb_exit() local
2949 mutex_lock(&qmp->phy_mutex); in qmp_combo_usb_exit()
2950 ret = qmp_combo_usb_power_off(phy); in qmp_combo_usb_exit()
2954 ret = qmp_combo_com_exit(qmp, false); in qmp_combo_usb_exit()
2958 qmp->usb_init_count--; in qmp_combo_usb_exit()
2961 mutex_unlock(&qmp->phy_mutex); in qmp_combo_usb_exit()
2965 static int qmp_combo_usb_set_mode(struct phy *phy, enum phy_mode mode, int submode) in qmp_combo_usb_set_mode() argument
2967 struct qmp_combo *qmp = phy_get_drvdata(phy); in qmp_combo_usb_set_mode() local
2969 qmp->mode = mode; in qmp_combo_usb_set_mode()
2991 static void qmp_combo_enable_autonomous_mode(struct qmp_combo *qmp) in qmp_combo_enable_autonomous_mode() argument
2993 const struct qmp_phy_cfg *cfg = qmp->cfg; in qmp_combo_enable_autonomous_mode()
2994 void __iomem *pcs_usb = qmp->pcs_usb ?: qmp->pcs; in qmp_combo_enable_autonomous_mode()
2995 void __iomem *pcs_misc = qmp->pcs_misc; in qmp_combo_enable_autonomous_mode()
2998 if (qmp->mode == PHY_MODE_USB_HOST_SS || in qmp_combo_enable_autonomous_mode()
2999 qmp->mode == PHY_MODE_USB_DEVICE_SS) in qmp_combo_enable_autonomous_mode()
3005 qphy_setbits(pcs_usb, cfg->regs[QPHY_PCS_LFPS_RXTERM_IRQ_CLEAR], IRQ_CLEAR); in qmp_combo_enable_autonomous_mode()
3007 qphy_clrbits(pcs_usb, cfg->regs[QPHY_PCS_LFPS_RXTERM_IRQ_CLEAR], IRQ_CLEAR); in qmp_combo_enable_autonomous_mode()
3009 qphy_clrbits(pcs_usb, cfg->regs[QPHY_PCS_AUTONOMOUS_MODE_CTRL], in qmp_combo_enable_autonomous_mode()
3012 /* Enable required PHY autonomous mode interrupts */ in qmp_combo_enable_autonomous_mode()
3013 qphy_setbits(pcs_usb, cfg->regs[QPHY_PCS_AUTONOMOUS_MODE_CTRL], intr_mask); in qmp_combo_enable_autonomous_mode()
3020 static void qmp_combo_disable_autonomous_mode(struct qmp_combo *qmp) in qmp_combo_disable_autonomous_mode() argument
3022 const struct qmp_phy_cfg *cfg = qmp->cfg; in qmp_combo_disable_autonomous_mode()
3023 void __iomem *pcs_usb = qmp->pcs_usb ?: qmp->pcs; in qmp_combo_disable_autonomous_mode()
3024 void __iomem *pcs_misc = qmp->pcs_misc; in qmp_combo_disable_autonomous_mode()
3030 qphy_clrbits(pcs_usb, cfg->regs[QPHY_PCS_AUTONOMOUS_MODE_CTRL], in qmp_combo_disable_autonomous_mode()
3033 qphy_setbits(pcs_usb, cfg->regs[QPHY_PCS_LFPS_RXTERM_IRQ_CLEAR], IRQ_CLEAR); in qmp_combo_disable_autonomous_mode()
3035 qphy_clrbits(pcs_usb, cfg->regs[QPHY_PCS_LFPS_RXTERM_IRQ_CLEAR], IRQ_CLEAR); in qmp_combo_disable_autonomous_mode()
3040 struct qmp_combo *qmp = dev_get_drvdata(dev); in qmp_combo_runtime_suspend() local
3042 dev_vdbg(dev, "Suspending QMP phy, mode:%d\n", qmp->mode); in qmp_combo_runtime_suspend()
3044 if (!qmp->init_count) { in qmp_combo_runtime_suspend()
3045 dev_vdbg(dev, "PHY not initialized, bailing out\n"); in qmp_combo_runtime_suspend()
3049 qmp_combo_enable_autonomous_mode(qmp); in qmp_combo_runtime_suspend()
3051 clk_disable_unprepare(qmp->pipe_clk); in qmp_combo_runtime_suspend()
3052 clk_bulk_disable_unprepare(qmp->num_clks, qmp->clks); in qmp_combo_runtime_suspend()
3059 struct qmp_combo *qmp = dev_get_drvdata(dev); in qmp_combo_runtime_resume() local
3062 dev_vdbg(dev, "Resuming QMP phy, mode:%d\n", qmp->mode); in qmp_combo_runtime_resume()
3064 if (!qmp->init_count) { in qmp_combo_runtime_resume()
3065 dev_vdbg(dev, "PHY not initialized, bailing out\n"); in qmp_combo_runtime_resume()
3069 ret = clk_bulk_prepare_enable(qmp->num_clks, qmp->clks); in qmp_combo_runtime_resume()
3073 ret = clk_prepare_enable(qmp->pipe_clk); in qmp_combo_runtime_resume()
3076 clk_bulk_disable_unprepare(qmp->num_clks, qmp->clks); in qmp_combo_runtime_resume()
3080 qmp_combo_disable_autonomous_mode(qmp); in qmp_combo_runtime_resume()
3090 static int qmp_combo_vreg_init(struct qmp_combo *qmp) in qmp_combo_vreg_init() argument
3092 const struct qmp_phy_cfg *cfg = qmp->cfg; in qmp_combo_vreg_init()
3093 struct device *dev = qmp->dev; in qmp_combo_vreg_init()
3094 int num = cfg->num_vregs; in qmp_combo_vreg_init()
3097 qmp->vregs = devm_kcalloc(dev, num, sizeof(*qmp->vregs), GFP_KERNEL); in qmp_combo_vreg_init()
3098 if (!qmp->vregs) in qmp_combo_vreg_init()
3099 return -ENOMEM; in qmp_combo_vreg_init()
3102 qmp->vregs[i].supply = cfg->vreg_list[i].name; in qmp_combo_vreg_init()
3104 ret = devm_regulator_bulk_get(dev, num, qmp->vregs); in qmp_combo_vreg_init()
3111 ret = regulator_set_load(qmp->vregs[i].consumer, in qmp_combo_vreg_init()
3112 cfg->vreg_list[i].enable_load); in qmp_combo_vreg_init()
3115 qmp->vregs[i].supply); in qmp_combo_vreg_init()
3123 static int qmp_combo_reset_init(struct qmp_combo *qmp) in qmp_combo_reset_init() argument
3125 const struct qmp_phy_cfg *cfg = qmp->cfg; in qmp_combo_reset_init()
3126 struct device *dev = qmp->dev; in qmp_combo_reset_init()
3130 qmp->resets = devm_kcalloc(dev, cfg->num_resets, in qmp_combo_reset_init()
3131 sizeof(*qmp->resets), GFP_KERNEL); in qmp_combo_reset_init()
3132 if (!qmp->resets) in qmp_combo_reset_init()
3133 return -ENOMEM; in qmp_combo_reset_init()
3135 for (i = 0; i < cfg->num_resets; i++) in qmp_combo_reset_init()
3136 qmp->resets[i].id = cfg->reset_list[i]; in qmp_combo_reset_init()
3138 ret = devm_reset_control_bulk_get_exclusive(dev, cfg->num_resets, qmp->resets); in qmp_combo_reset_init()
3145 static int qmp_combo_clk_init(struct qmp_combo *qmp) in qmp_combo_clk_init() argument
3147 struct device *dev = qmp->dev; in qmp_combo_clk_init()
3151 qmp->clks = devm_kcalloc(dev, num, sizeof(*qmp->clks), GFP_KERNEL); in qmp_combo_clk_init()
3152 if (!qmp->clks) in qmp_combo_clk_init()
3153 return -ENOMEM; in qmp_combo_clk_init()
3156 qmp->clks[i].id = qmp_combo_phy_clk_l[i]; in qmp_combo_clk_init()
3158 qmp->num_clks = num; in qmp_combo_clk_init()
3160 return devm_clk_bulk_get_optional(dev, num, qmp->clks); in qmp_combo_clk_init()
3171 * The <s>_pipe_clksrc generated by PHY goes to the GCC that gate
3173 * by the PHY driver for its operations.
3178 * +---------------+
3179 * | PHY block |<<---------------------------------------+
3181 * | +-------+ | +-----+ |
3182 * I/P---^-->| PLL |---^--->pipe_clksrc--->| GCC |--->pipe_clk---+
3183 * clk | +-------+ | +-----+
3184 * +---------------+
3186 static int phy_pipe_clk_register(struct qmp_combo *qmp, struct device_node *np) in phy_pipe_clk_register() argument
3188 struct clk_fixed_rate *fixed = &qmp->pipe_clk_fixed; in phy_pipe_clk_register()
3192 snprintf(name, sizeof(name), "%s::pipe_clk", dev_name(qmp->dev)); in phy_pipe_clk_register()
3196 /* controllers using QMP phys use 125MHz pipe clock interface */ in phy_pipe_clk_register()
3197 fixed->fixed_rate = 125000000; in phy_pipe_clk_register()
3198 fixed->hw.init = &init; in phy_pipe_clk_register()
3200 return devm_clk_hw_register(qmp->dev, &fixed->hw); in phy_pipe_clk_register()
3206 * +------------------------------+
3209 * | +-------------------+ |
3211 * | +---------+---------+ |
3213 * | +----------+-----------+ |
3215 * | +----------+-----------+ |
3216 * +------------------------------+
3218 * +---------<---------v------------>----------+
3220 * +--------v----------------+ |
3223 * +--------+----------------+ |
3232 * +--------<------------+-----------------+---<---+
3234 * +----v---------+ +--------v-----+ +--------v------+
3239 * +-------+------+ +-----+--------+ +--------+------+
3241 * v---->----------v-------------<------v
3243 * +----------+-----------------+
3245 * +---------+------------------+
3254 switch (req->rate) { in qmp_dp_pixel_clk_determine_rate()
3260 return -EINVAL; in qmp_dp_pixel_clk_determine_rate()
3266 const struct qmp_combo *qmp; in qmp_dp_pixel_clk_recalc_rate() local
3269 qmp = container_of(hw, struct qmp_combo, dp_pixel_hw); in qmp_dp_pixel_clk_recalc_rate()
3270 dp_opts = &qmp->dp_opts; in qmp_dp_pixel_clk_recalc_rate()
3272 switch (dp_opts->link_rate) { in qmp_dp_pixel_clk_recalc_rate()
3293 switch (req->rate) { in qmp_dp_link_clk_determine_rate()
3300 return -EINVAL; in qmp_dp_link_clk_determine_rate()
3306 const struct qmp_combo *qmp; in qmp_dp_link_clk_recalc_rate() local
3309 qmp = container_of(hw, struct qmp_combo, dp_link_hw); in qmp_dp_link_clk_recalc_rate()
3310 dp_opts = &qmp->dp_opts; in qmp_dp_link_clk_recalc_rate()
3312 switch (dp_opts->link_rate) { in qmp_dp_link_clk_recalc_rate()
3317 return dp_opts->link_rate * 100000; in qmp_dp_link_clk_recalc_rate()
3330 struct qmp_combo *qmp = data; in qmp_dp_clks_hw_get() local
3331 unsigned int idx = clkspec->args[0]; in qmp_dp_clks_hw_get()
3335 return ERR_PTR(-EINVAL); in qmp_dp_clks_hw_get()
3339 return &qmp->dp_link_hw; in qmp_dp_clks_hw_get()
3341 return &qmp->dp_pixel_hw; in qmp_dp_clks_hw_get()
3344 static int phy_dp_clks_register(struct qmp_combo *qmp, struct device_node *np) in phy_dp_clks_register() argument
3350 snprintf(name, sizeof(name), "%s::link_clk", dev_name(qmp->dev)); in phy_dp_clks_register()
3353 qmp->dp_link_hw.init = &init; in phy_dp_clks_register()
3354 ret = devm_clk_hw_register(qmp->dev, &qmp->dp_link_hw); in phy_dp_clks_register()
3358 snprintf(name, sizeof(name), "%s::vco_div_clk", dev_name(qmp->dev)); in phy_dp_clks_register()
3361 qmp->dp_pixel_hw.init = &init; in phy_dp_clks_register()
3362 ret = devm_clk_hw_register(qmp->dev, &qmp->dp_pixel_hw); in phy_dp_clks_register()
3371 struct qmp_combo *qmp = data; in qmp_combo_clk_hw_get() local
3373 switch (clkspec->args[0]) { in qmp_combo_clk_hw_get()
3375 return &qmp->pipe_clk_fixed.hw; in qmp_combo_clk_hw_get()
3377 return &qmp->dp_link_hw; in qmp_combo_clk_hw_get()
3379 return &qmp->dp_pixel_hw; in qmp_combo_clk_hw_get()
3382 return ERR_PTR(-EINVAL); in qmp_combo_clk_hw_get()
3385 static int qmp_combo_register_clocks(struct qmp_combo *qmp, struct device_node *usb_np, in qmp_combo_register_clocks() argument
3390 ret = phy_pipe_clk_register(qmp, usb_np); in qmp_combo_register_clocks()
3394 ret = phy_dp_clks_register(qmp, dp_np); in qmp_combo_register_clocks()
3401 if (usb_np == qmp->dev->of_node) in qmp_combo_register_clocks()
3402 return devm_of_clk_add_hw_provider(qmp->dev, qmp_combo_clk_hw_get, qmp); in qmp_combo_register_clocks()
3408 &qmp->pipe_clk_fixed.hw); in qmp_combo_register_clocks()
3416 ret = devm_add_action_or_reset(qmp->dev, phy_clk_release_provider, usb_np); in qmp_combo_register_clocks()
3420 ret = of_clk_add_hw_provider(dp_np, qmp_dp_clks_hw_get, qmp); in qmp_combo_register_clocks()
3424 return devm_add_action_or_reset(qmp->dev, phy_clk_release_provider, dp_np); in qmp_combo_register_clocks()
3431 struct qmp_combo *qmp = typec_switch_get_drvdata(sw); in qmp_combo_typec_switch_set() local
3432 const struct qmp_phy_cfg *cfg = qmp->cfg; in qmp_combo_typec_switch_set()
3434 if (orientation == qmp->orientation || orientation == TYPEC_ORIENTATION_NONE) in qmp_combo_typec_switch_set()
3437 mutex_lock(&qmp->phy_mutex); in qmp_combo_typec_switch_set()
3438 qmp->orientation = orientation; in qmp_combo_typec_switch_set()
3440 if (qmp->init_count) { in qmp_combo_typec_switch_set()
3441 if (qmp->usb_init_count) in qmp_combo_typec_switch_set()
3442 qmp_combo_usb_power_off(qmp->usb_phy); in qmp_combo_typec_switch_set()
3443 qmp_combo_com_exit(qmp, true); in qmp_combo_typec_switch_set()
3445 qmp_combo_com_init(qmp, true); in qmp_combo_typec_switch_set()
3446 if (qmp->usb_init_count) in qmp_combo_typec_switch_set()
3447 qmp_combo_usb_power_on(qmp->usb_phy); in qmp_combo_typec_switch_set()
3448 if (qmp->dp_init_count) in qmp_combo_typec_switch_set()
3449 cfg->dp_aux_init(qmp); in qmp_combo_typec_switch_set()
3451 mutex_unlock(&qmp->phy_mutex); in qmp_combo_typec_switch_set()
3458 struct qmp_combo *qmp = data; in qmp_combo_typec_unregister() local
3460 typec_switch_unregister(qmp->sw); in qmp_combo_typec_unregister()
3463 static int qmp_combo_typec_switch_register(struct qmp_combo *qmp) in qmp_combo_typec_switch_register() argument
3466 struct device *dev = qmp->dev; in qmp_combo_typec_switch_register()
3468 sw_desc.drvdata = qmp; in qmp_combo_typec_switch_register()
3469 sw_desc.fwnode = dev->fwnode; in qmp_combo_typec_switch_register()
3471 qmp->sw = typec_switch_register(dev, &sw_desc); in qmp_combo_typec_switch_register()
3472 if (IS_ERR(qmp->sw)) { in qmp_combo_typec_switch_register()
3473 dev_err(dev, "Unable to register typec switch: %pe\n", qmp->sw); in qmp_combo_typec_switch_register()
3474 return PTR_ERR(qmp->sw); in qmp_combo_typec_switch_register()
3477 return devm_add_action_or_reset(dev, qmp_combo_typec_unregister, qmp); in qmp_combo_typec_switch_register()
3480 static int qmp_combo_typec_switch_register(struct qmp_combo *qmp) in qmp_combo_typec_switch_register() argument
3486 static int qmp_combo_parse_dt_lecacy_dp(struct qmp_combo *qmp, struct device_node *np) in qmp_combo_parse_dt_lecacy_dp() argument
3488 struct device *dev = qmp->dev; in qmp_combo_parse_dt_lecacy_dp()
3492 * Resources are indexed as: tx -> 0; rx -> 1; pcs -> 2; in qmp_combo_parse_dt_lecacy_dp()
3493 * tx2 -> 3; rx2 -> 4 in qmp_combo_parse_dt_lecacy_dp()
3498 qmp->dp_tx = devm_of_iomap(dev, np, 0, NULL); in qmp_combo_parse_dt_lecacy_dp()
3499 if (IS_ERR(qmp->dp_tx)) in qmp_combo_parse_dt_lecacy_dp()
3500 return PTR_ERR(qmp->dp_tx); in qmp_combo_parse_dt_lecacy_dp()
3502 qmp->dp_dp_phy = devm_of_iomap(dev, np, 2, NULL); in qmp_combo_parse_dt_lecacy_dp()
3503 if (IS_ERR(qmp->dp_dp_phy)) in qmp_combo_parse_dt_lecacy_dp()
3504 return PTR_ERR(qmp->dp_dp_phy); in qmp_combo_parse_dt_lecacy_dp()
3506 qmp->dp_tx2 = devm_of_iomap(dev, np, 3, NULL); in qmp_combo_parse_dt_lecacy_dp()
3507 if (IS_ERR(qmp->dp_tx2)) in qmp_combo_parse_dt_lecacy_dp()
3508 return PTR_ERR(qmp->dp_tx2); in qmp_combo_parse_dt_lecacy_dp()
3513 static int qmp_combo_parse_dt_lecacy_usb(struct qmp_combo *qmp, struct device_node *np) in qmp_combo_parse_dt_lecacy_usb() argument
3515 const struct qmp_phy_cfg *cfg = qmp->cfg; in qmp_combo_parse_dt_lecacy_usb()
3516 struct device *dev = qmp->dev; in qmp_combo_parse_dt_lecacy_usb()
3520 * Resources are indexed as: tx -> 0; rx -> 1; pcs -> 2; in qmp_combo_parse_dt_lecacy_usb()
3521 * tx2 -> 3; rx2 -> 4; pcs_misc (optional) -> 5 in qmp_combo_parse_dt_lecacy_usb()
3523 qmp->tx = devm_of_iomap(dev, np, 0, NULL); in qmp_combo_parse_dt_lecacy_usb()
3524 if (IS_ERR(qmp->tx)) in qmp_combo_parse_dt_lecacy_usb()
3525 return PTR_ERR(qmp->tx); in qmp_combo_parse_dt_lecacy_usb()
3527 qmp->rx = devm_of_iomap(dev, np, 1, NULL); in qmp_combo_parse_dt_lecacy_usb()
3528 if (IS_ERR(qmp->rx)) in qmp_combo_parse_dt_lecacy_usb()
3529 return PTR_ERR(qmp->rx); in qmp_combo_parse_dt_lecacy_usb()
3531 qmp->pcs = devm_of_iomap(dev, np, 2, NULL); in qmp_combo_parse_dt_lecacy_usb()
3532 if (IS_ERR(qmp->pcs)) in qmp_combo_parse_dt_lecacy_usb()
3533 return PTR_ERR(qmp->pcs); in qmp_combo_parse_dt_lecacy_usb()
3535 if (cfg->pcs_usb_offset) in qmp_combo_parse_dt_lecacy_usb()
3536 qmp->pcs_usb = qmp->pcs + cfg->pcs_usb_offset; in qmp_combo_parse_dt_lecacy_usb()
3538 qmp->tx2 = devm_of_iomap(dev, np, 3, NULL); in qmp_combo_parse_dt_lecacy_usb()
3539 if (IS_ERR(qmp->tx2)) in qmp_combo_parse_dt_lecacy_usb()
3540 return PTR_ERR(qmp->tx2); in qmp_combo_parse_dt_lecacy_usb()
3542 qmp->rx2 = devm_of_iomap(dev, np, 4, NULL); in qmp_combo_parse_dt_lecacy_usb()
3543 if (IS_ERR(qmp->rx2)) in qmp_combo_parse_dt_lecacy_usb()
3544 return PTR_ERR(qmp->rx2); in qmp_combo_parse_dt_lecacy_usb()
3546 qmp->pcs_misc = devm_of_iomap(dev, np, 5, NULL); in qmp_combo_parse_dt_lecacy_usb()
3547 if (IS_ERR(qmp->pcs_misc)) { in qmp_combo_parse_dt_lecacy_usb()
3548 dev_vdbg(dev, "PHY pcs_misc-reg not used\n"); in qmp_combo_parse_dt_lecacy_usb()
3549 qmp->pcs_misc = NULL; in qmp_combo_parse_dt_lecacy_usb()
3552 qmp->pipe_clk = devm_get_clk_from_child(dev, np, NULL); in qmp_combo_parse_dt_lecacy_usb()
3553 if (IS_ERR(qmp->pipe_clk)) { in qmp_combo_parse_dt_lecacy_usb()
3554 return dev_err_probe(dev, PTR_ERR(qmp->pipe_clk), in qmp_combo_parse_dt_lecacy_usb()
3561 static int qmp_combo_parse_dt_legacy(struct qmp_combo *qmp, struct device_node *usb_np, in qmp_combo_parse_dt_legacy() argument
3564 struct platform_device *pdev = to_platform_device(qmp->dev); in qmp_combo_parse_dt_legacy()
3567 qmp->serdes = devm_platform_ioremap_resource(pdev, 0); in qmp_combo_parse_dt_legacy()
3568 if (IS_ERR(qmp->serdes)) in qmp_combo_parse_dt_legacy()
3569 return PTR_ERR(qmp->serdes); in qmp_combo_parse_dt_legacy()
3571 qmp->com = devm_platform_ioremap_resource(pdev, 1); in qmp_combo_parse_dt_legacy()
3572 if (IS_ERR(qmp->com)) in qmp_combo_parse_dt_legacy()
3573 return PTR_ERR(qmp->com); in qmp_combo_parse_dt_legacy()
3575 qmp->dp_serdes = devm_platform_ioremap_resource(pdev, 2); in qmp_combo_parse_dt_legacy()
3576 if (IS_ERR(qmp->dp_serdes)) in qmp_combo_parse_dt_legacy()
3577 return PTR_ERR(qmp->dp_serdes); in qmp_combo_parse_dt_legacy()
3579 ret = qmp_combo_parse_dt_lecacy_usb(qmp, usb_np); in qmp_combo_parse_dt_legacy()
3583 ret = qmp_combo_parse_dt_lecacy_dp(qmp, dp_np); in qmp_combo_parse_dt_legacy()
3587 ret = devm_clk_bulk_get_all(qmp->dev, &qmp->clks); in qmp_combo_parse_dt_legacy()
3591 qmp->num_clks = ret; in qmp_combo_parse_dt_legacy()
3596 static int qmp_combo_parse_dt(struct qmp_combo *qmp) in qmp_combo_parse_dt() argument
3598 struct platform_device *pdev = to_platform_device(qmp->dev); in qmp_combo_parse_dt()
3599 const struct qmp_phy_cfg *cfg = qmp->cfg; in qmp_combo_parse_dt()
3600 const struct qmp_combo_offsets *offs = cfg->offsets; in qmp_combo_parse_dt()
3601 struct device *dev = qmp->dev; in qmp_combo_parse_dt()
3606 return -EINVAL; in qmp_combo_parse_dt()
3612 qmp->com = base + offs->com; in qmp_combo_parse_dt()
3613 qmp->tx = base + offs->txa; in qmp_combo_parse_dt()
3614 qmp->rx = base + offs->rxa; in qmp_combo_parse_dt()
3615 qmp->tx2 = base + offs->txb; in qmp_combo_parse_dt()
3616 qmp->rx2 = base + offs->rxb; in qmp_combo_parse_dt()
3618 qmp->serdes = base + offs->usb3_serdes; in qmp_combo_parse_dt()
3619 qmp->pcs_misc = base + offs->usb3_pcs_misc; in qmp_combo_parse_dt()
3620 qmp->pcs = base + offs->usb3_pcs; in qmp_combo_parse_dt()
3621 qmp->pcs_usb = base + offs->usb3_pcs_usb; in qmp_combo_parse_dt()
3623 qmp->dp_serdes = base + offs->dp_serdes; in qmp_combo_parse_dt()
3624 if (offs->dp_txa) { in qmp_combo_parse_dt()
3625 qmp->dp_tx = base + offs->dp_txa; in qmp_combo_parse_dt()
3626 qmp->dp_tx2 = base + offs->dp_txb; in qmp_combo_parse_dt()
3628 qmp->dp_tx = base + offs->txa; in qmp_combo_parse_dt()
3629 qmp->dp_tx2 = base + offs->txb; in qmp_combo_parse_dt()
3631 qmp->dp_dp_phy = base + offs->dp_dp_phy; in qmp_combo_parse_dt()
3633 ret = qmp_combo_clk_init(qmp); in qmp_combo_parse_dt()
3637 qmp->pipe_clk = devm_clk_get(dev, "usb3_pipe"); in qmp_combo_parse_dt()
3638 if (IS_ERR(qmp->pipe_clk)) { in qmp_combo_parse_dt()
3639 return dev_err_probe(dev, PTR_ERR(qmp->pipe_clk), in qmp_combo_parse_dt()
3646 static struct phy *qmp_combo_phy_xlate(struct device *dev, const struct of_phandle_args *args) in qmp_combo_phy_xlate()
3648 struct qmp_combo *qmp = dev_get_drvdata(dev); in qmp_combo_phy_xlate() local
3650 if (args->args_count == 0) in qmp_combo_phy_xlate()
3651 return ERR_PTR(-EINVAL); in qmp_combo_phy_xlate()
3653 switch (args->args[0]) { in qmp_combo_phy_xlate()
3655 return qmp->usb_phy; in qmp_combo_phy_xlate()
3657 return qmp->dp_phy; in qmp_combo_phy_xlate()
3660 return ERR_PTR(-EINVAL); in qmp_combo_phy_xlate()
3665 struct qmp_combo *qmp; in qmp_combo_probe() local
3666 struct device *dev = &pdev->dev; in qmp_combo_probe()
3671 qmp = devm_kzalloc(dev, sizeof(*qmp), GFP_KERNEL); in qmp_combo_probe()
3672 if (!qmp) in qmp_combo_probe()
3673 return -ENOMEM; in qmp_combo_probe()
3675 qmp->dev = dev; in qmp_combo_probe()
3676 dev_set_drvdata(dev, qmp); in qmp_combo_probe()
3678 qmp->orientation = TYPEC_ORIENTATION_NORMAL; in qmp_combo_probe()
3680 qmp->cfg = of_device_get_match_data(dev); in qmp_combo_probe()
3681 if (!qmp->cfg) in qmp_combo_probe()
3682 return -EINVAL; in qmp_combo_probe()
3684 mutex_init(&qmp->phy_mutex); in qmp_combo_probe()
3686 ret = qmp_combo_reset_init(qmp); in qmp_combo_probe()
3690 ret = qmp_combo_vreg_init(qmp); in qmp_combo_probe()
3695 usb_np = of_get_child_by_name(dev->of_node, "usb3-phy"); in qmp_combo_probe()
3697 dp_np = of_get_child_by_name(dev->of_node, "dp-phy"); in qmp_combo_probe()
3700 return -EINVAL; in qmp_combo_probe()
3703 ret = qmp_combo_parse_dt_legacy(qmp, usb_np, dp_np); in qmp_combo_probe()
3705 usb_np = of_node_get(dev->of_node); in qmp_combo_probe()
3706 dp_np = of_node_get(dev->of_node); in qmp_combo_probe()
3708 ret = qmp_combo_parse_dt(qmp); in qmp_combo_probe()
3713 ret = qmp_combo_typec_switch_register(qmp); in qmp_combo_probe()
3731 ret = qmp_combo_register_clocks(qmp, usb_np, dp_np); in qmp_combo_probe()
3735 qmp->usb_phy = devm_phy_create(dev, usb_np, &qmp_combo_usb_phy_ops); in qmp_combo_probe()
3736 if (IS_ERR(qmp->usb_phy)) { in qmp_combo_probe()
3737 ret = PTR_ERR(qmp->usb_phy); in qmp_combo_probe()
3738 dev_err(dev, "failed to create USB PHY: %d\n", ret); in qmp_combo_probe()
3742 phy_set_drvdata(qmp->usb_phy, qmp); in qmp_combo_probe()
3744 qmp->dp_phy = devm_phy_create(dev, dp_np, &qmp_combo_dp_phy_ops); in qmp_combo_probe()
3745 if (IS_ERR(qmp->dp_phy)) { in qmp_combo_probe()
3746 ret = PTR_ERR(qmp->dp_phy); in qmp_combo_probe()
3747 dev_err(dev, "failed to create DP PHY: %d\n", ret); in qmp_combo_probe()
3751 phy_set_drvdata(qmp->dp_phy, qmp); in qmp_combo_probe()
3753 if (usb_np == dev->of_node) in qmp_combo_probe()
3771 .compatible = "qcom,sc7180-qmp-usb3-dp-phy",
3775 .compatible = "qcom,sc7280-qmp-usb3-dp-phy",
3779 .compatible = "qcom,sc8180x-qmp-usb3-dp-phy",
3783 .compatible = "qcom,sc8280xp-qmp-usb43dp-phy",
3787 .compatible = "qcom,sdm845-qmp-usb3-dp-phy",
3791 .compatible = "qcom,sm6350-qmp-usb3-dp-phy",
3795 .compatible = "qcom,sm8150-qmp-usb3-dp-phy",
3799 .compatible = "qcom,sm8250-qmp-usb3-dp-phy",
3803 .compatible = "qcom,sm8350-qmp-usb3-dp-phy",
3807 .compatible = "qcom,sm8450-qmp-usb3-dp-phy",
3811 .compatible = "qcom,sm8550-qmp-usb3-dp-phy",
3815 .compatible = "qcom,sm8650-qmp-usb3-dp-phy",
3819 .compatible = "qcom,x1e80100-qmp-usb3-dp-phy",
3829 .name = "qcom-qmp-combo-phy",
3838 MODULE_DESCRIPTION("Qualcomm QMP USB+DP combo PHY driver");