#define MAX_PROP_NAME 32
+/* Define the assumed distance between lanes for underspecified device trees. */
+#define QMP_PHY_LEGACY_LANE_STRIDE 0x400
+
struct qmp_phy_init_tbl {
unsigned int offset;
unsigned int val;
bool has_phy_dp_com_ctrl;
/* true, if PHY has secondary tx/rx lanes to be configured */
bool is_dual_lane_phy;
- /* Register offset of secondary tx/rx lanes for USB DP combo PHY */
- unsigned int tx_b_lane_offset;
- unsigned int rx_b_lane_offset;
/* true, if PCS block has no separate SW_RESET register */
bool no_pcs_sw_reset;
* @tx: iomapped memory space for lane's tx
* @rx: iomapped memory space for lane's rx
* @pcs: iomapped memory space for lane's pcs
+ * @tx2: iomapped memory space for second lane's tx (in dual lane PHYs)
+ * @rx2: iomapped memory space for second lane's rx (in dual lane PHYs)
* @pcs_misc: iomapped memory space for lane's pcs_misc
* @pipe_clk: pipe lock
* @index: lane index
void __iomem *tx;
void __iomem *rx;
void __iomem *pcs;
+ void __iomem *tx2;
+ void __iomem *rx2;
void __iomem *pcs_misc;
struct clk *pipe_clk;
unsigned int index;
.has_phy_dp_com_ctrl = true,
.is_dual_lane_phy = true,
- .tx_b_lane_offset = 0x400,
- .rx_b_lane_offset = 0x400,
};
static const struct qmp_phy_cfg qmp_v3_usb3_uniphy_cfg = {
.mask_pcs_ready = PCS_READY,
.is_dual_lane_phy = true,
- .tx_b_lane_offset = 0x400,
- .rx_b_lane_offset = 0x400,
-
.no_pcs_sw_reset = true,
};
qcom_qmp_phy_configure(tx, cfg->regs, cfg->tx_tbl, cfg->tx_tbl_num);
/* Configuration for other LANE for USB-DP combo PHY */
if (cfg->is_dual_lane_phy)
- qcom_qmp_phy_configure(tx + cfg->tx_b_lane_offset, cfg->regs,
+ qcom_qmp_phy_configure(qphy->tx2, cfg->regs,
cfg->tx_tbl, cfg->tx_tbl_num);
qcom_qmp_phy_configure(rx, cfg->regs, cfg->rx_tbl, cfg->rx_tbl_num);
if (cfg->is_dual_lane_phy)
- qcom_qmp_phy_configure(rx + cfg->rx_b_lane_offset, cfg->regs,
+ qcom_qmp_phy_configure(qphy->rx2, cfg->regs,
cfg->rx_tbl, cfg->rx_tbl_num);
qcom_qmp_phy_configure(pcs, cfg->regs, cfg->pcs_tbl, cfg->pcs_tbl_num);
/*
* Get memory resources for each phy lane:
- * Resources are indexed as: tx -> 0; rx -> 1; pcs -> 2; and
- * pcs_misc (optional) -> 3.
+ * Resources are indexed as: tx -> 0; rx -> 1; pcs -> 2.
+ * For dual lane PHYs: tx2 -> 3, rx2 -> 4, pcs_misc (optional) -> 5
+ * For single lane PHYs: pcs_misc (optional) -> 3.
*/
qphy->tx = of_iomap(np, 0);
if (!qphy->tx)
if (!qphy->pcs)
return -ENOMEM;
- qphy->pcs_misc = of_iomap(np, 3);
+ /*
+ * If this is a dual-lane PHY, then there should be registers for the
+ * second lane. Some old device trees did not specify this, so fall
+ * back to old legacy behavior of assuming they can be reached at an
+ * offset from the first lane.
+ */
+ if (qmp->cfg->is_dual_lane_phy) {
+ qphy->tx2 = of_iomap(np, 3);
+ qphy->rx2 = of_iomap(np, 4);
+ if (!qphy->tx2 || !qphy->rx2) {
+ dev_warn(dev,
+ "Underspecified device tree, falling back to legacy register regions\n");
+
+ /* In the old version, pcs_misc is at index 3. */
+ qphy->pcs_misc = qphy->tx2;
+ qphy->tx2 = qphy->tx + QMP_PHY_LEGACY_LANE_STRIDE;
+ qphy->rx2 = qphy->rx + QMP_PHY_LEGACY_LANE_STRIDE;
+
+ } else {
+ qphy->pcs_misc = of_iomap(np, 5);
+ }
+
+ } else {
+ qphy->pcs_misc = of_iomap(np, 3);
+ }
+
if (!qphy->pcs_misc)
dev_vdbg(dev, "PHY pcs_misc-reg not used\n");