From nobody Wed Dec 17 12:09:59 2025 Received: from lelv0143.ext.ti.com (lelv0143.ext.ti.com [198.47.23.248]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 2740B7E58D for ; Wed, 10 Jul 2024 11:56:58 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=198.47.23.248 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1720612621; cv=none; b=rAzr+Y3vTcyapxOcjkeXtmuxTHyE6mhq6IH6V+BcjI8FACuyGFNQnmsbwG0iojoHaZzG9uhTwowQCR6sd+ln934VC3ow5m7VQLComQgRmvOv0MDdiTGMJLdU7lz5LKZGJwgSlkHvg+kvo7WEJNVLx4AvnfOTEyzWoVHiTbSuxpg= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1720612621; c=relaxed/simple; bh=9A2Q78TalcnVAkuJp03rxUOOiszGzNlvc6e5kPBpMl0=; h=From:To:CC:Subject:Date:Message-ID:MIME-Version:Content-Type; b=EMGYtoa7o2H4etag3ClZM37n863BNi6+R3aapAo1ZjJ9gHf4SDE8PAbBVPlWgMpKg7+KQ/5INtTprIGlGeMJbbGF1Jt28xYKdcHFv4mqcvfUjarNh50QW5l1MRaieslvg+KC0ZHd14qbKh7lCP0mFGNzNOBYKxmgcQ/xVpVdx5A= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=ti.com; spf=pass smtp.mailfrom=ti.com; dkim=pass (1024-bit key) header.d=ti.com header.i=@ti.com header.b=bqvfULnx; arc=none smtp.client-ip=198.47.23.248 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=ti.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=ti.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=ti.com header.i=@ti.com header.b="bqvfULnx" Received: from fllv0035.itg.ti.com ([10.64.41.0]) by lelv0143.ext.ti.com (8.15.2/8.15.2) with ESMTP id 46ABuUSS098258; Wed, 10 Jul 2024 06:56:30 -0500 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=ti.com; s=ti-com-17Q1; t=1720612590; bh=1IxapFT0FG4APMMHo9mZi3Qq4+oJ0bmI4Z6pyJJmsSA=; h=From:To:CC:Subject:Date; b=bqvfULnx002q7S1vLwO1lANhKMY/5KsnGJU2mHFN227LKwf2x2DErKxFXt/L208yx wRbYa0/AjHOtOqqiqDLo0KAIHqsYfS9gUnF9qTnGUKubS33Mje5xyiwCme7VpMGbig lprWnxCoRLjddzlHJnVM6VYmefKMlo5coCkUE89M= Received: from DLEE107.ent.ti.com (dlee107.ent.ti.com [157.170.170.37]) by fllv0035.itg.ti.com (8.15.2/8.15.2) with ESMTPS id 46ABuUin067659 (version=TLSv1.2 cipher=AES256-GCM-SHA384 bits=256 verify=FAIL); Wed, 10 Jul 2024 06:56:30 -0500 Received: from DLEE114.ent.ti.com (157.170.170.25) by DLEE107.ent.ti.com (157.170.170.37) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256_P256) id 15.1.2507.23; Wed, 10 Jul 2024 06:56:29 -0500 Received: from lelvsmtp6.itg.ti.com (10.180.75.249) by DLEE114.ent.ti.com (157.170.170.25) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256_P256) id 15.1.2507.23 via Frontend Transport; Wed, 10 Jul 2024 06:56:29 -0500 Received: from uda0492258.dhcp.ti.com (uda0492258.dhcp.ti.com [10.24.72.81]) by lelvsmtp6.itg.ti.com (8.15.2/8.15.2) with ESMTP id 46ABuPQx034083; Wed, 10 Jul 2024 06:56:25 -0500 From: Siddharth Vadapalli To: , , , , , , , CC: , , , , Subject: [PATCH v2] phy: cadence-torrent: add support for three or more links using 2 protocols Date: Wed, 10 Jul 2024 17:26:24 +0530 Message-ID: <20240710115624.3232925-1-s-vadapalli@ti.com> X-Mailer: git-send-email 2.40.1 Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-EXCLAIMER-MD-CONFIG: e1e8a2fd-e40a-4ac6-ac9b-f7e9cc9ee180 Content-Type: text/plain; charset="utf-8" The Torrent SERDES can support at most two different protocols. This only mandates that the device-tree sub-nodes expressing the configuration should describe links with at-most two different protocols. The existing implementation however imposes an artificial constraint that allows only two links (device-tree sub-nodes). As long as at-most two protocols are chosen, using more than two links to describe them in an alternating configuration is still a valid configuration of the Torrent SERDES. A 3-Link 2-Protocol configuration of the 4-Lane SERDES can be: Lane 0 =3D> Protocol 1 =3D> Link 1 Lane 1 =3D> Protocol 1 =3D> Link 1 Lane 2 =3D> Protocol 2 =3D> Link 2 Lane 3 =3D> Protocol 1 =3D> Link 3 A 4-Link 2-Protocol configuration of the 4-Lane SERDES can be: Lane 0 =3D> Protocol 1 =3D> Link 1 Lane 1 =3D> Protocol 2 =3D> Link 2 Lane 2 =3D> Protocol 1 =3D> Link 3 Lane 3 =3D> Protocol 2 =3D> Link 4 Signed-off-by: Siddharth Vadapalli --- Hello, This patch is based on linux-next tagged next-20240710. Patch has been sanity tested and tested for functionality in the following configurations with the Torrent SERDES0 on J7200-EVM: 1. PCIe (Lanes 0 and 1) + QSGMII (Lane 2) =3D> 2 protocols, 2 links 2. PCIe (Lane0 as 1 Link) + PCIe (Lane 1 as 1 Link) =3D> 1 protocol, 2 links 3. PCIe (Lanes 0 and 1) + QSGMII (Lane 2) + PCIe (Lane 3) =3D> 2 protocols, 3 links v1: https://lore.kernel.org/r/20240709120703.2716397-1-s-vadapalli@ti.com/ Changes since v1: - A multilink configuration doesn't necessarily imply two protocols since a single protocol may be split across links as follows: Lane 0 =3D> Protocol 1 Lane 1 =3D> Unused Lane 2 =3D> Protocol 1 Lane 3 =3D> Unused which corresponds to two links and therefore two sub-nodes. In such a case, treat it as two single-link configurations performed sequentially which happens to be the case prior to this patch. To address this, handle the case where cdns_torrent_phy_configure_multilink() can be invoked for a single protocol with multiple sub-nodes (links) by erroring out only when the number of protocols is strictly greater than two, followed by handling the configuration similar to how it was done prior to this patch. Regards, Siddharth. drivers/phy/cadence/phy-cadence-torrent.c | 252 ++++++++++++---------- 1 file changed, 136 insertions(+), 116 deletions(-) diff --git a/drivers/phy/cadence/phy-cadence-torrent.c b/drivers/phy/cadenc= e/phy-cadence-torrent.c index 56ce82a47f88..a6d0082e448d 100644 --- a/drivers/phy/cadence/phy-cadence-torrent.c +++ b/drivers/phy/cadence/phy-cadence-torrent.c @@ -351,6 +351,7 @@ struct cdns_torrent_phy { void __iomem *sd_base; /* SD0801 registers base */ u32 max_bit_rate; /* Maximum link bit rate to use (in Mbps) */ u32 dp_pll; + u32 protocol_bitmask; struct reset_control *phy_rst; struct reset_control *apb_rst; struct device *dev; @@ -2475,21 +2476,32 @@ int cdns_torrent_phy_configure_multilink(struct cdn= s_torrent_phy *cdns_phy) struct cdns_reg_pairs *reg_pairs; enum cdns_torrent_ssc_mode ssc; struct regmap *regmap; - u32 num_regs; + u32 num_regs, num_protocols, protocol; =20 - /* Maximum 2 links (subnodes) are supported */ - if (cdns_phy->nsubnodes !=3D 2) + num_protocols =3D hweight32(cdns_phy->protocol_bitmask); + /* Maximum 2 protocols are supported */ + if (num_protocols > 2) { return -EINVAL; - - phy_t1 =3D cdns_phy->phys[0].phy_type; - phy_t2 =3D cdns_phy->phys[1].phy_type; + } else if (num_protocols =3D=3D 2) { + phy_t1 =3D fns(cdns_phy->protocol_bitmask, 0); + phy_t2 =3D fns(cdns_phy->protocol_bitmask, 1); + } else { + phy_t1 =3D fns(cdns_phy->protocol_bitmask, 0); + /** + * For a single protocol split across multiple links, + * assign TYPE_NONE to phy_t2 for configuring each link + * identical to a single-link configuration with a single + * protocol. + */ + phy_t2 =3D TYPE_NONE; + } =20 /** * First configure the PHY for first link with phy_t1. Get the array * values as [phy_t1][phy_t2][ssc]. */ - for (node =3D 0; node < cdns_phy->nsubnodes; node++) { - if (node =3D=3D 1) { + for (protocol =3D 0; protocol < num_protocols; protocol++) { + if (protocol =3D=3D 1) { /** * If first link with phy_t1 is configured, then * configure the PHY for second link with phy_t2. @@ -2499,130 +2511,136 @@ int cdns_torrent_phy_configure_multilink(struct c= dns_torrent_phy *cdns_phy) swap(ref_clk, ref_clk1); } =20 - mlane =3D cdns_phy->phys[node].mlane; - ssc =3D cdns_phy->phys[node].ssc_mode; - num_lanes =3D cdns_phy->phys[node].num_lanes; + for (node =3D 0; node < cdns_phy->nsubnodes; node++) { + if (cdns_phy->phys[node].phy_type !=3D phy_t1) + continue; =20 - /** - * PHY configuration specific registers: - * link_cmn_vals depend on combination of PHY types being - * configured and are common for both PHY types, so array - * values should be same for [phy_t1][phy_t2][ssc] and - * [phy_t2][phy_t1][ssc]. - * xcvr_diag_vals also depend on combination of PHY types - * being configured, but these can be different for particular - * PHY type and are per lane. - */ - link_cmn_vals =3D cdns_torrent_get_tbl_vals(&init_data->link_cmn_vals_tb= l, - CLK_ANY, CLK_ANY, - phy_t1, phy_t2, ANY_SSC); - if (link_cmn_vals) { - reg_pairs =3D link_cmn_vals->reg_pairs; - num_regs =3D link_cmn_vals->num_regs; - regmap =3D cdns_phy->regmap_common_cdb; + mlane =3D cdns_phy->phys[node].mlane; + ssc =3D cdns_phy->phys[node].ssc_mode; + num_lanes =3D cdns_phy->phys[node].num_lanes; =20 /** - * First array value in link_cmn_vals must be of - * PHY_PLL_CFG register + * PHY configuration specific registers: + * link_cmn_vals depend on combination of PHY types being + * configured and are common for both PHY types, so array + * values should be same for [phy_t1][phy_t2][ssc] and + * [phy_t2][phy_t1][ssc]. + * xcvr_diag_vals also depend on combination of PHY types + * being configured, but these can be different for particular + * PHY type and are per lane. */ - regmap_field_write(cdns_phy->phy_pll_cfg, - reg_pairs[0].val); + link_cmn_vals =3D cdns_torrent_get_tbl_vals(&init_data->link_cmn_vals_t= bl, + CLK_ANY, CLK_ANY, + phy_t1, phy_t2, ANY_SSC); + if (link_cmn_vals) { + reg_pairs =3D link_cmn_vals->reg_pairs; + num_regs =3D link_cmn_vals->num_regs; + regmap =3D cdns_phy->regmap_common_cdb; =20 - for (i =3D 1; i < num_regs; i++) - regmap_write(regmap, reg_pairs[i].off, - reg_pairs[i].val); - } + /** + * First array value in link_cmn_vals must be of + * PHY_PLL_CFG register + */ + regmap_field_write(cdns_phy->phy_pll_cfg, + reg_pairs[0].val); =20 - xcvr_diag_vals =3D cdns_torrent_get_tbl_vals(&init_data->xcvr_diag_vals_= tbl, - CLK_ANY, CLK_ANY, - phy_t1, phy_t2, ANY_SSC); - if (xcvr_diag_vals) { - reg_pairs =3D xcvr_diag_vals->reg_pairs; - num_regs =3D xcvr_diag_vals->num_regs; - for (i =3D 0; i < num_lanes; i++) { - regmap =3D cdns_phy->regmap_tx_lane_cdb[i + mlane]; - for (j =3D 0; j < num_regs; j++) - regmap_write(regmap, reg_pairs[j].off, - reg_pairs[j].val); + for (i =3D 1; i < num_regs; i++) + regmap_write(regmap, reg_pairs[i].off, + reg_pairs[i].val); } - } =20 - /* PHY PCS common registers configurations */ - pcs_cmn_vals =3D cdns_torrent_get_tbl_vals(&init_data->pcs_cmn_vals_tbl, - CLK_ANY, CLK_ANY, - phy_t1, phy_t2, ANY_SSC); - if (pcs_cmn_vals) { - reg_pairs =3D pcs_cmn_vals->reg_pairs; - num_regs =3D pcs_cmn_vals->num_regs; - regmap =3D cdns_phy->regmap_phy_pcs_common_cdb; - for (i =3D 0; i < num_regs; i++) - regmap_write(regmap, reg_pairs[i].off, - reg_pairs[i].val); - } + xcvr_diag_vals =3D cdns_torrent_get_tbl_vals(&init_data->xcvr_diag_vals= _tbl, + CLK_ANY, CLK_ANY, + phy_t1, phy_t2, ANY_SSC); + if (xcvr_diag_vals) { + reg_pairs =3D xcvr_diag_vals->reg_pairs; + num_regs =3D xcvr_diag_vals->num_regs; + for (i =3D 0; i < num_lanes; i++) { + regmap =3D cdns_phy->regmap_tx_lane_cdb[i + mlane]; + for (j =3D 0; j < num_regs; j++) + regmap_write(regmap, reg_pairs[j].off, + reg_pairs[j].val); + } + } =20 - /* PHY PMA common registers configurations */ - phy_pma_cmn_vals =3D cdns_torrent_get_tbl_vals(&init_data->phy_pma_cmn_v= als_tbl, - CLK_ANY, CLK_ANY, - phy_t1, phy_t2, ANY_SSC); - if (phy_pma_cmn_vals) { - reg_pairs =3D phy_pma_cmn_vals->reg_pairs; - num_regs =3D phy_pma_cmn_vals->num_regs; - regmap =3D cdns_phy->regmap_phy_pma_common_cdb; - for (i =3D 0; i < num_regs; i++) - regmap_write(regmap, reg_pairs[i].off, - reg_pairs[i].val); - } + /* PHY PCS common registers configurations */ + pcs_cmn_vals =3D cdns_torrent_get_tbl_vals(&init_data->pcs_cmn_vals_tbl, + CLK_ANY, CLK_ANY, + phy_t1, phy_t2, ANY_SSC); + if (pcs_cmn_vals) { + reg_pairs =3D pcs_cmn_vals->reg_pairs; + num_regs =3D pcs_cmn_vals->num_regs; + regmap =3D cdns_phy->regmap_phy_pcs_common_cdb; + for (i =3D 0; i < num_regs; i++) + regmap_write(regmap, reg_pairs[i].off, + reg_pairs[i].val); + } =20 - /* PMA common registers configurations */ - cmn_vals =3D cdns_torrent_get_tbl_vals(&init_data->cmn_vals_tbl, - ref_clk, ref_clk1, - phy_t1, phy_t2, ssc); - if (cmn_vals) { - reg_pairs =3D cmn_vals->reg_pairs; - num_regs =3D cmn_vals->num_regs; - regmap =3D cdns_phy->regmap_common_cdb; - for (i =3D 0; i < num_regs; i++) - regmap_write(regmap, reg_pairs[i].off, - reg_pairs[i].val); - } + /* PHY PMA common registers configurations */ + phy_pma_cmn_vals =3D + cdns_torrent_get_tbl_vals(&init_data->phy_pma_cmn_vals_tbl, + CLK_ANY, CLK_ANY, phy_t1, phy_t2, + ANY_SSC); + if (phy_pma_cmn_vals) { + reg_pairs =3D phy_pma_cmn_vals->reg_pairs; + num_regs =3D phy_pma_cmn_vals->num_regs; + regmap =3D cdns_phy->regmap_phy_pma_common_cdb; + for (i =3D 0; i < num_regs; i++) + regmap_write(regmap, reg_pairs[i].off, + reg_pairs[i].val); + } =20 - /* PMA TX lane registers configurations */ - tx_ln_vals =3D cdns_torrent_get_tbl_vals(&init_data->tx_ln_vals_tbl, - ref_clk, ref_clk1, - phy_t1, phy_t2, ssc); - if (tx_ln_vals) { - reg_pairs =3D tx_ln_vals->reg_pairs; - num_regs =3D tx_ln_vals->num_regs; - for (i =3D 0; i < num_lanes; i++) { - regmap =3D cdns_phy->regmap_tx_lane_cdb[i + mlane]; - for (j =3D 0; j < num_regs; j++) - regmap_write(regmap, reg_pairs[j].off, - reg_pairs[j].val); + /* PMA common registers configurations */ + cmn_vals =3D cdns_torrent_get_tbl_vals(&init_data->cmn_vals_tbl, + ref_clk, ref_clk1, + phy_t1, phy_t2, ssc); + if (cmn_vals) { + reg_pairs =3D cmn_vals->reg_pairs; + num_regs =3D cmn_vals->num_regs; + regmap =3D cdns_phy->regmap_common_cdb; + for (i =3D 0; i < num_regs; i++) + regmap_write(regmap, reg_pairs[i].off, + reg_pairs[i].val); } - } =20 - /* PMA RX lane registers configurations */ - rx_ln_vals =3D cdns_torrent_get_tbl_vals(&init_data->rx_ln_vals_tbl, - ref_clk, ref_clk1, - phy_t1, phy_t2, ssc); - if (rx_ln_vals) { - reg_pairs =3D rx_ln_vals->reg_pairs; - num_regs =3D rx_ln_vals->num_regs; - for (i =3D 0; i < num_lanes; i++) { - regmap =3D cdns_phy->regmap_rx_lane_cdb[i + mlane]; - for (j =3D 0; j < num_regs; j++) - regmap_write(regmap, reg_pairs[j].off, - reg_pairs[j].val); + /* PMA TX lane registers configurations */ + tx_ln_vals =3D cdns_torrent_get_tbl_vals(&init_data->tx_ln_vals_tbl, + ref_clk, ref_clk1, + phy_t1, phy_t2, ssc); + if (tx_ln_vals) { + reg_pairs =3D tx_ln_vals->reg_pairs; + num_regs =3D tx_ln_vals->num_regs; + for (i =3D 0; i < num_lanes; i++) { + regmap =3D cdns_phy->regmap_tx_lane_cdb[i + mlane]; + for (j =3D 0; j < num_regs; j++) + regmap_write(regmap, reg_pairs[j].off, + reg_pairs[j].val); + } } - } =20 - if (phy_t1 =3D=3D TYPE_DP) { - ret =3D cdns_torrent_dp_get_pll(cdns_phy, phy_t2); - if (ret) - return ret; - } + /* PMA RX lane registers configurations */ + rx_ln_vals =3D cdns_torrent_get_tbl_vals(&init_data->rx_ln_vals_tbl, + ref_clk, ref_clk1, + phy_t1, phy_t2, ssc); + if (rx_ln_vals) { + reg_pairs =3D rx_ln_vals->reg_pairs; + num_regs =3D rx_ln_vals->num_regs; + for (i =3D 0; i < num_lanes; i++) { + regmap =3D cdns_phy->regmap_rx_lane_cdb[i + mlane]; + for (j =3D 0; j < num_regs; j++) + regmap_write(regmap, reg_pairs[j].off, + reg_pairs[j].val); + } + } =20 - reset_control_deassert(cdns_phy->phys[node].lnk_rst); + if (phy_t1 =3D=3D TYPE_DP) { + ret =3D cdns_torrent_dp_get_pll(cdns_phy, phy_t2); + if (ret) + return ret; + } + + reset_control_deassert(cdns_phy->phys[node].lnk_rst); + } } =20 /* Take the PHY out of reset */ @@ -2826,6 +2844,7 @@ static int cdns_torrent_phy_probe(struct platform_dev= ice *pdev) dev_set_drvdata(dev, cdns_phy); cdns_phy->dev =3D dev; cdns_phy->init_data =3D data; + cdns_phy->protocol_bitmask =3D 0; =20 cdns_phy->sd_base =3D devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(cdns_phy->sd_base)) @@ -3010,6 +3029,7 @@ static int cdns_torrent_phy_probe(struct platform_dev= ice *pdev) } =20 cdns_phy->phys[node].phy =3D gphy; + cdns_phy->protocol_bitmask |=3D BIT(cdns_phy->phys[node].phy_type); phy_set_drvdata(gphy, &cdns_phy->phys[node]); =20 node++; --=20 2.40.1