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-qmp-pcie: add support for sc8280xp 4-lane PHYs

The PCIe2 and PCIe3 controllers and PHYs on SC8280XP can be used in
4-lane mode or as separate controllers and PHYs in 2-lane mode (e.g. as
PCIe2A and PCIe2B).

Add support for fetching the 4-lane configuration from the TCSR and
programming the lane registers of the second port when in 4-lane mode.

Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
Signed-off-by: Johan Hovold <johan+linaro@kernel.org>
Link: https://lore.kernel.org/r/20221105145939.20318-17-johan+linaro@kernel.org
Signed-off-by: Vinod Koul <vkoul@kernel.org>

authored by

Johan Hovold and committed by
Vinod Koul
6c37a02b d0a846ba

+118
+1
drivers/phy/qualcomm/Kconfig
··· 54 54 tristate "Qualcomm QMP PHY Driver" 55 55 depends on OF && COMMON_CLK && (ARCH_QCOM || COMPILE_TEST) 56 56 select GENERIC_PHY 57 + select MFD_SYSCON 57 58 help 58 59 Enable this to support the QMP PHY transceiver that is used 59 60 with controllers such as PCIe, UFS, and USB on Qualcomm chips.
+117
drivers/phy/qualcomm/phy-qcom-qmp-pcie.c
··· 10 10 #include <linux/io.h> 11 11 #include <linux/iopoll.h> 12 12 #include <linux/kernel.h> 13 + #include <linux/mfd/syscon.h> 13 14 #include <linux/module.h> 14 15 #include <linux/of.h> 15 16 #include <linux/of_device.h> ··· 18 17 #include <linux/phy/pcie.h> 19 18 #include <linux/phy/phy.h> 20 19 #include <linux/platform_device.h> 20 + #include <linux/regmap.h> 21 21 #include <linux/regulator/consumer.h> 22 22 #include <linux/reset.h> 23 23 #include <linux/slab.h> ··· 888 886 QMP_PHY_INIT_CFG(QSERDES_V5_COM_BIAS_EN_CLKBUFLR_EN, 0x14), 889 887 }; 890 888 889 + static const struct qmp_phy_init_tbl sc8280xp_qmp_gen3x4_pcie_serdes_4ln_tbl[] = { 890 + QMP_PHY_INIT_CFG(QSERDES_V5_COM_BIAS_EN_CLKBUFLR_EN, 0x1c), 891 + }; 892 + 891 893 static const struct qmp_phy_init_tbl sc8280xp_qmp_gen3x1_pcie_tx_tbl[] = { 892 894 QMP_PHY_INIT_CFG(QSERDES_V5_TX_PI_QEC_CTRL, 0x20), 893 895 QMP_PHY_INIT_CFG(QSERDES_V5_TX_LANE_MODE_1, 0x75), ··· 1497 1491 const struct qmp_phy_cfg_tbls *tbls_rc; 1498 1492 const struct qmp_phy_cfg_tbls *tbls_ep; 1499 1493 1494 + const struct qmp_phy_init_tbl *serdes_4ln_tbl; 1495 + int serdes_4ln_num; 1496 + 1500 1497 /* clock ids to be requested */ 1501 1498 const char * const *clk_list; 1502 1499 int num_clks; ··· 1527 1518 struct device *dev; 1528 1519 1529 1520 const struct qmp_phy_cfg *cfg; 1521 + bool tcsr_4ln_config; 1530 1522 1531 1523 void __iomem *serdes; 1532 1524 void __iomem *pcs; ··· 1536 1526 void __iomem *rx; 1537 1527 void __iomem *tx2; 1538 1528 void __iomem *rx2; 1529 + 1530 + void __iomem *port_b; 1539 1531 1540 1532 struct clk_bulk_data *clks; 1541 1533 struct clk_bulk_data pipe_clks[2]; ··· 1944 1932 .phy_status = PHYSTATUS, 1945 1933 }; 1946 1934 1935 + static const struct qmp_phy_cfg sc8280xp_qmp_gen3x4_pciephy_cfg = { 1936 + .lanes = 4, 1937 + 1938 + .offsets = &qmp_pcie_offsets_v5, 1939 + 1940 + .tbls = { 1941 + .serdes = sc8280xp_qmp_pcie_serdes_tbl, 1942 + .serdes_num = ARRAY_SIZE(sc8280xp_qmp_pcie_serdes_tbl), 1943 + .tx = sc8280xp_qmp_gen3x2_pcie_tx_tbl, 1944 + .tx_num = ARRAY_SIZE(sc8280xp_qmp_gen3x2_pcie_tx_tbl), 1945 + .rx = sc8280xp_qmp_gen3x2_pcie_rx_tbl, 1946 + .rx_num = ARRAY_SIZE(sc8280xp_qmp_gen3x2_pcie_rx_tbl), 1947 + .pcs = sc8280xp_qmp_gen3x2_pcie_pcs_tbl, 1948 + .pcs_num = ARRAY_SIZE(sc8280xp_qmp_gen3x2_pcie_pcs_tbl), 1949 + .pcs_misc = sc8280xp_qmp_gen3x2_pcie_pcs_misc_tbl, 1950 + .pcs_misc_num = ARRAY_SIZE(sc8280xp_qmp_gen3x2_pcie_pcs_misc_tbl), 1951 + }, 1952 + 1953 + .tbls_rc = &(const struct qmp_phy_cfg_tbls) { 1954 + .serdes = sc8280xp_qmp_gen3x2_pcie_rc_serdes_tbl, 1955 + .serdes_num = ARRAY_SIZE(sc8280xp_qmp_gen3x2_pcie_rc_serdes_tbl), 1956 + }, 1957 + 1958 + .serdes_4ln_tbl = sc8280xp_qmp_gen3x4_pcie_serdes_4ln_tbl, 1959 + .serdes_4ln_num = ARRAY_SIZE(sc8280xp_qmp_gen3x4_pcie_serdes_4ln_tbl), 1960 + 1961 + .clk_list = sc8280xp_pciephy_clk_l, 1962 + .num_clks = ARRAY_SIZE(sc8280xp_pciephy_clk_l), 1963 + .reset_list = sdm845_pciephy_reset_l, 1964 + .num_resets = ARRAY_SIZE(sdm845_pciephy_reset_l), 1965 + .vreg_list = qmp_phy_vreg_l, 1966 + .num_vregs = ARRAY_SIZE(qmp_phy_vreg_l), 1967 + .regs = sm8250_pcie_regs_layout, 1968 + 1969 + .pwrdn_ctrl = SW_PWRDN | REFCLK_DRV_DSBL, 1970 + .phy_status = PHYSTATUS, 1971 + }; 1972 + 1947 1973 static const struct qmp_phy_cfg sdx55_qmp_pciephy_cfg = { 1948 1974 .lanes = 2, 1949 1975 ··· 2104 2054 qmp_pcie_configure_lane(base, tbl, num, 0xff); 2105 2055 } 2106 2056 2057 + static void qmp_pcie_init_port_b(struct qmp_pcie *qmp, const struct qmp_phy_cfg_tbls *tbls) 2058 + { 2059 + const struct qmp_phy_cfg *cfg = qmp->cfg; 2060 + const struct qmp_pcie_offsets *offs = cfg->offsets; 2061 + void __iomem *tx3, *rx3, *tx4, *rx4; 2062 + 2063 + tx3 = qmp->port_b + offs->tx; 2064 + rx3 = qmp->port_b + offs->rx; 2065 + tx4 = qmp->port_b + offs->tx2; 2066 + rx4 = qmp->port_b + offs->rx2; 2067 + 2068 + qmp_pcie_configure_lane(tx3, tbls->tx, tbls->tx_num, 1); 2069 + qmp_pcie_configure_lane(rx3, tbls->rx, tbls->rx_num, 1); 2070 + 2071 + qmp_pcie_configure_lane(tx4, tbls->tx, tbls->tx_num, 2); 2072 + qmp_pcie_configure_lane(rx4, tbls->rx, tbls->rx_num, 2); 2073 + } 2074 + 2107 2075 static void qmp_pcie_init_registers(struct qmp_pcie *qmp, const struct qmp_phy_cfg_tbls *tbls) 2108 2076 { 2109 2077 const struct qmp_phy_cfg *cfg = qmp->cfg; ··· 2148 2080 2149 2081 qmp_pcie_configure(pcs, tbls->pcs, tbls->pcs_num); 2150 2082 qmp_pcie_configure(pcs_misc, tbls->pcs_misc, tbls->pcs_misc_num); 2083 + 2084 + if (cfg->lanes >= 4 && qmp->tcsr_4ln_config) { 2085 + qmp_pcie_configure(serdes, cfg->serdes_4ln_tbl, cfg->serdes_4ln_num); 2086 + qmp_pcie_init_port_b(qmp, tbls); 2087 + } 2151 2088 } 2152 2089 2153 2090 static int qmp_pcie_init(struct phy *phy) ··· 2525 2452 return 0; 2526 2453 } 2527 2454 2455 + static int qmp_pcie_get_4ln_config(struct qmp_pcie *qmp) 2456 + { 2457 + struct regmap *tcsr; 2458 + unsigned int args[2]; 2459 + int ret; 2460 + 2461 + tcsr = syscon_regmap_lookup_by_phandle_args(qmp->dev->of_node, 2462 + "qcom,4ln-config-sel", 2463 + ARRAY_SIZE(args), args); 2464 + if (IS_ERR(tcsr)) { 2465 + ret = PTR_ERR(tcsr); 2466 + if (ret == -ENOENT) 2467 + return 0; 2468 + 2469 + dev_err(qmp->dev, "failed to lookup syscon: %d\n", ret); 2470 + return ret; 2471 + } 2472 + 2473 + ret = regmap_test_bits(tcsr, args[0], BIT(args[1])); 2474 + if (ret < 0) { 2475 + dev_err(qmp->dev, "failed to read tcsr: %d\n", ret); 2476 + return ret; 2477 + } 2478 + 2479 + qmp->tcsr_4ln_config = ret; 2480 + 2481 + dev_dbg(qmp->dev, "4ln_config_sel = %d\n", qmp->tcsr_4ln_config); 2482 + 2483 + return 0; 2484 + } 2485 + 2528 2486 static int qmp_pcie_parse_dt(struct qmp_pcie *qmp) 2529 2487 { 2530 2488 struct platform_device *pdev = to_platform_device(qmp->dev); ··· 2567 2463 2568 2464 if (!offs) 2569 2465 return -EINVAL; 2466 + 2467 + ret = qmp_pcie_get_4ln_config(qmp); 2468 + if (ret) 2469 + return ret; 2570 2470 2571 2471 base = devm_platform_ioremap_resource(pdev, 0); 2572 2472 if (IS_ERR(base)) ··· 2585 2477 if (cfg->lanes >= 2) { 2586 2478 qmp->tx2 = base + offs->tx2; 2587 2479 qmp->rx2 = base + offs->rx2; 2480 + } 2481 + 2482 + if (qmp->cfg->lanes >= 4 && qmp->tcsr_4ln_config) { 2483 + qmp->port_b = devm_platform_ioremap_resource(pdev, 1); 2484 + if (IS_ERR(qmp->port_b)) 2485 + return PTR_ERR(qmp->port_b); 2588 2486 } 2589 2487 2590 2488 qmp->num_pipe_clks = 2; ··· 2696 2582 }, { 2697 2583 .compatible = "qcom,sc8280xp-qmp-gen3x2-pcie-phy", 2698 2584 .data = &sc8280xp_qmp_gen3x2_pciephy_cfg, 2585 + }, { 2586 + .compatible = "qcom,sc8280xp-qmp-gen3x4-pcie-phy", 2587 + .data = &sc8280xp_qmp_gen3x4_pciephy_cfg, 2699 2588 }, { 2700 2589 .compatible = "qcom,sdm845-qhp-pcie-phy", 2701 2590 .data = &sdm845_qhp_pciephy_cfg,