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

phy: qcom-qmp: Utilize fully-specified DT registers

Utilize the newly fixed up DT bindings to get the tx2 and rx2 register
regions for the second lane of dual-lane PHYs. Before this change,
the driver was simply using lane one's register region and adding
0x400, which reached well beyond the DT-specified register
allocation. This would have been a crash were it not for the page size
on ARM64. Fix the driver not to rely on the magic of virtual memory by
using the newly specified DT register regions for tx2 and rx2.

In order to support existing device trees, this change also contains a
fallback mode for when those new register regions don't exist, which
reverts to the original behavior of overreaching and prints a complaint.

Signed-off-by: Evan Green <evgreen@chromium.org>
Reviewed-by: Douglas Anderson <dianders@chromium.org>
Signed-off-by: Kishon Vijay Abraham I <kishon@ti.com>

authored by

Evan Green and committed by
Kishon Vijay Abraham I
5e17b95d 2517d09b

+38 -13
+38 -13
drivers/phy/qualcomm/phy-qcom-qmp.c
··· 72 72 73 73 #define MAX_PROP_NAME 32 74 74 75 + /* Define the assumed distance between lanes for underspecified device trees. */ 76 + #define QMP_PHY_LEGACY_LANE_STRIDE 0x400 77 + 75 78 struct qmp_phy_init_tbl { 76 79 unsigned int offset; 77 80 unsigned int val; ··· 736 733 bool has_phy_dp_com_ctrl; 737 734 /* true, if PHY has secondary tx/rx lanes to be configured */ 738 735 bool is_dual_lane_phy; 739 - /* Register offset of secondary tx/rx lanes for USB DP combo PHY */ 740 - unsigned int tx_b_lane_offset; 741 - unsigned int rx_b_lane_offset; 742 736 743 737 /* true, if PCS block has no separate SW_RESET register */ 744 738 bool no_pcs_sw_reset; ··· 748 748 * @tx: iomapped memory space for lane's tx 749 749 * @rx: iomapped memory space for lane's rx 750 750 * @pcs: iomapped memory space for lane's pcs 751 + * @tx2: iomapped memory space for second lane's tx (in dual lane PHYs) 752 + * @rx2: iomapped memory space for second lane's rx (in dual lane PHYs) 751 753 * @pcs_misc: iomapped memory space for lane's pcs_misc 752 754 * @pipe_clk: pipe lock 753 755 * @index: lane index ··· 761 759 void __iomem *tx; 762 760 void __iomem *rx; 763 761 void __iomem *pcs; 762 + void __iomem *tx2; 763 + void __iomem *rx2; 764 764 void __iomem *pcs_misc; 765 765 struct clk *pipe_clk; 766 766 unsigned int index; ··· 979 975 980 976 .has_phy_dp_com_ctrl = true, 981 977 .is_dual_lane_phy = true, 982 - .tx_b_lane_offset = 0x400, 983 - .rx_b_lane_offset = 0x400, 984 978 }; 985 979 986 980 static const struct qmp_phy_cfg qmp_v3_usb3_uniphy_cfg = { ··· 1033 1031 .mask_pcs_ready = PCS_READY, 1034 1032 1035 1033 .is_dual_lane_phy = true, 1036 - .tx_b_lane_offset = 0x400, 1037 - .rx_b_lane_offset = 0x400, 1038 - 1039 1034 .no_pcs_sw_reset = true, 1040 1035 }; 1041 1036 ··· 1237 1238 qcom_qmp_phy_configure(tx, cfg->regs, cfg->tx_tbl, cfg->tx_tbl_num); 1238 1239 /* Configuration for other LANE for USB-DP combo PHY */ 1239 1240 if (cfg->is_dual_lane_phy) 1240 - qcom_qmp_phy_configure(tx + cfg->tx_b_lane_offset, cfg->regs, 1241 + qcom_qmp_phy_configure(qphy->tx2, cfg->regs, 1241 1242 cfg->tx_tbl, cfg->tx_tbl_num); 1242 1243 1243 1244 qcom_qmp_phy_configure(rx, cfg->regs, cfg->rx_tbl, cfg->rx_tbl_num); 1244 1245 if (cfg->is_dual_lane_phy) 1245 - qcom_qmp_phy_configure(rx + cfg->rx_b_lane_offset, cfg->regs, 1246 + qcom_qmp_phy_configure(qphy->rx2, cfg->regs, 1246 1247 cfg->rx_tbl, cfg->rx_tbl_num); 1247 1248 1248 1249 qcom_qmp_phy_configure(pcs, cfg->regs, cfg->pcs_tbl, cfg->pcs_tbl_num); ··· 1614 1615 1615 1616 /* 1616 1617 * Get memory resources for each phy lane: 1617 - * Resources are indexed as: tx -> 0; rx -> 1; pcs -> 2; and 1618 - * pcs_misc (optional) -> 3. 1618 + * Resources are indexed as: tx -> 0; rx -> 1; pcs -> 2. 1619 + * For dual lane PHYs: tx2 -> 3, rx2 -> 4, pcs_misc (optional) -> 5 1620 + * For single lane PHYs: pcs_misc (optional) -> 3. 1619 1621 */ 1620 1622 qphy->tx = of_iomap(np, 0); 1621 1623 if (!qphy->tx) ··· 1630 1630 if (!qphy->pcs) 1631 1631 return -ENOMEM; 1632 1632 1633 - qphy->pcs_misc = of_iomap(np, 3); 1633 + /* 1634 + * If this is a dual-lane PHY, then there should be registers for the 1635 + * second lane. Some old device trees did not specify this, so fall 1636 + * back to old legacy behavior of assuming they can be reached at an 1637 + * offset from the first lane. 1638 + */ 1639 + if (qmp->cfg->is_dual_lane_phy) { 1640 + qphy->tx2 = of_iomap(np, 3); 1641 + qphy->rx2 = of_iomap(np, 4); 1642 + if (!qphy->tx2 || !qphy->rx2) { 1643 + dev_warn(dev, 1644 + "Underspecified device tree, falling back to legacy register regions\n"); 1645 + 1646 + /* In the old version, pcs_misc is at index 3. */ 1647 + qphy->pcs_misc = qphy->tx2; 1648 + qphy->tx2 = qphy->tx + QMP_PHY_LEGACY_LANE_STRIDE; 1649 + qphy->rx2 = qphy->rx + QMP_PHY_LEGACY_LANE_STRIDE; 1650 + 1651 + } else { 1652 + qphy->pcs_misc = of_iomap(np, 5); 1653 + } 1654 + 1655 + } else { 1656 + qphy->pcs_misc = of_iomap(np, 3); 1657 + } 1658 + 1634 1659 if (!qphy->pcs_misc) 1635 1660 dev_vdbg(dev, "PHY pcs_misc-reg not used\n"); 1636 1661