Skip to content

Commit 5b7b83a

Browse files
phy: cadence-torrent: add support for three or more links using 2 protocols
The Torrent SERDES can support at most two different protocols (PHY types). This only mandates that the device-tree sub-nodes used to represent 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 => Protocol 1 => Link 1 Lane 1 => Protocol 1 => Link 1 Lane 2 => Protocol 2 => Link 2 Lane 3 => Protocol 1 => Link 3 A 4-Link 2-Protocol configuration of the 4-Lane SERDES can be: Lane 0 => Protocol 1 => Link 1 Lane 1 => Protocol 2 => Link 2 Lane 2 => Protocol 1 => Link 3 Lane 3 => Protocol 2 => Link 4 Signed-off-by: Siddharth Vadapalli <[email protected]> Reviewed-by: Roger Quadros <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Vinod Koul <[email protected]>
1 parent 0f20e32 commit 5b7b83a

File tree

1 file changed

+172
-119
lines changed

1 file changed

+172
-119
lines changed

drivers/phy/cadence/phy-cadence-torrent.c

Lines changed: 172 additions & 119 deletions
Original file line numberDiff line numberDiff line change
@@ -351,6 +351,7 @@ struct cdns_torrent_phy {
351351
void __iomem *sd_base; /* SD0801 registers base */
352352
u32 max_bit_rate; /* Maximum link bit rate to use (in Mbps) */
353353
u32 dp_pll;
354+
u32 protocol_bitmask;
354355
struct reset_control *phy_rst;
355356
struct reset_control *apb_rst;
356357
struct device *dev;
@@ -2473,156 +2474,206 @@ int cdns_torrent_phy_configure_multilink(struct cdns_torrent_phy *cdns_phy)
24732474
enum cdns_torrent_phy_type phy_t1, phy_t2;
24742475
const struct cdns_reg_pairs *reg_pairs;
24752476
int i, j, node, mlane, num_lanes, ret;
2477+
struct device *dev = cdns_phy->dev;
24762478
enum cdns_torrent_ssc_mode ssc;
24772479
struct regmap *regmap;
2478-
u32 num_regs;
2480+
u32 num_regs, num_protocols, protocol;
24792481

2480-
/* Maximum 2 links (subnodes) are supported */
2481-
if (cdns_phy->nsubnodes != 2)
2482+
num_protocols = hweight32(cdns_phy->protocol_bitmask);
2483+
/* Maximum 2 protocols are supported */
2484+
if (num_protocols > 2) {
2485+
dev_err(dev, "at most 2 protocols are supported\n");
24822486
return -EINVAL;
2487+
}
2488+
2489+
2490+
/**
2491+
* Get PHY types directly from subnodes if only 2 subnodes exist.
2492+
* It is possible for phy_t1 to be the same as phy_t2 for special
2493+
* configurations such as PCIe Multilink.
2494+
*/
2495+
if (cdns_phy->nsubnodes == 2) {
2496+
phy_t1 = cdns_phy->phys[0].phy_type;
2497+
phy_t2 = cdns_phy->phys[1].phy_type;
2498+
} else {
2499+
/**
2500+
* Both PHY types / protocols should be unique.
2501+
* If they are the same, it should be expressed with either
2502+
* a) Single-Link (1 Sub-node) - handled via PHY APIs
2503+
* OR
2504+
* b) Double-Link (2 Sub-nodes) - handled above
2505+
*/
2506+
if (num_protocols != 2) {
2507+
dev_err(dev, "incorrect representation of link\n");
2508+
return -EINVAL;
2509+
}
24832510

2484-
phy_t1 = cdns_phy->phys[0].phy_type;
2485-
phy_t2 = cdns_phy->phys[1].phy_type;
2511+
phy_t1 = fns(cdns_phy->protocol_bitmask, 0);
2512+
phy_t2 = fns(cdns_phy->protocol_bitmask, 1);
2513+
}
24862514

24872515
/**
2488-
* First configure the PHY for first link with phy_t1. Get the array
2489-
* values as [phy_t1][phy_t2][ssc].
2516+
* Configure all links with the protocol phy_t1 first followed by
2517+
* configuring all links with the protocol phy_t2.
2518+
*
2519+
* When phy_t1 = phy_t2, it is a single protocol and configuration
2520+
* is performed with a single iteration of the protocol and multiple
2521+
* iterations over the sub-nodes (links).
2522+
*
2523+
* When phy_t1 != phy_t2, there are two protocols and configuration
2524+
* is performed by iterating over all sub-nodes matching the first
2525+
* protocol and configuring them first, followed by iterating over
2526+
* all sub-nodes matching the second protocol and configuring them
2527+
* next.
24902528
*/
2491-
for (node = 0; node < cdns_phy->nsubnodes; node++) {
2492-
if (node == 1) {
2529+
for (protocol = 0; protocol < num_protocols; protocol++) {
2530+
/**
2531+
* For the case where num_protocols is 1,
2532+
* phy_t1 = phy_t2 and the swap is unnecessary.
2533+
*
2534+
* Swapping phy_t1 and phy_t2 is only required when the
2535+
* number of protocols is 2 and there are 2 or more links.
2536+
*/
2537+
if (protocol == 1) {
24932538
/**
2494-
* If first link with phy_t1 is configured, then
2495-
* configure the PHY for second link with phy_t2.
2539+
* If first protocol with phy_t1 is configured, then
2540+
* configure the PHY for second protocol with phy_t2.
24962541
* Get the array values as [phy_t2][phy_t1][ssc].
24972542
*/
24982543
swap(phy_t1, phy_t2);
24992544
swap(ref_clk, ref_clk1);
25002545
}
25012546

2502-
mlane = cdns_phy->phys[node].mlane;
2503-
ssc = cdns_phy->phys[node].ssc_mode;
2504-
num_lanes = cdns_phy->phys[node].num_lanes;
2547+
for (node = 0; node < cdns_phy->nsubnodes; node++) {
2548+
if (cdns_phy->phys[node].phy_type != phy_t1)
2549+
continue;
25052550

2506-
/**
2507-
* PHY configuration specific registers:
2508-
* link_cmn_vals depend on combination of PHY types being
2509-
* configured and are common for both PHY types, so array
2510-
* values should be same for [phy_t1][phy_t2][ssc] and
2511-
* [phy_t2][phy_t1][ssc].
2512-
* xcvr_diag_vals also depend on combination of PHY types
2513-
* being configured, but these can be different for particular
2514-
* PHY type and are per lane.
2515-
*/
2516-
link_cmn_vals = cdns_torrent_get_tbl_vals(&init_data->link_cmn_vals_tbl,
2517-
CLK_ANY, CLK_ANY,
2518-
phy_t1, phy_t2, ANY_SSC);
2519-
if (link_cmn_vals) {
2520-
reg_pairs = link_cmn_vals->reg_pairs;
2521-
num_regs = link_cmn_vals->num_regs;
2522-
regmap = cdns_phy->regmap_common_cdb;
2551+
mlane = cdns_phy->phys[node].mlane;
2552+
ssc = cdns_phy->phys[node].ssc_mode;
2553+
num_lanes = cdns_phy->phys[node].num_lanes;
25232554

25242555
/**
2525-
* First array value in link_cmn_vals must be of
2526-
* PHY_PLL_CFG register
2556+
* PHY configuration specific registers:
2557+
* link_cmn_vals depend on combination of PHY types being
2558+
* configured and are common for both PHY types, so array
2559+
* values should be same for [phy_t1][phy_t2][ssc] and
2560+
* [phy_t2][phy_t1][ssc].
2561+
* xcvr_diag_vals also depend on combination of PHY types
2562+
* being configured, but these can be different for particular
2563+
* PHY type and are per lane.
25272564
*/
2528-
regmap_field_write(cdns_phy->phy_pll_cfg,
2529-
reg_pairs[0].val);
2565+
link_cmn_vals = cdns_torrent_get_tbl_vals(&init_data->link_cmn_vals_tbl,
2566+
CLK_ANY, CLK_ANY,
2567+
phy_t1, phy_t2, ANY_SSC);
2568+
if (link_cmn_vals) {
2569+
reg_pairs = link_cmn_vals->reg_pairs;
2570+
num_regs = link_cmn_vals->num_regs;
2571+
regmap = cdns_phy->regmap_common_cdb;
2572+
2573+
/**
2574+
* First array value in link_cmn_vals must be of
2575+
* PHY_PLL_CFG register
2576+
*/
2577+
regmap_field_write(cdns_phy->phy_pll_cfg,
2578+
reg_pairs[0].val);
2579+
2580+
for (i = 1; i < num_regs; i++)
2581+
regmap_write(regmap, reg_pairs[i].off,
2582+
reg_pairs[i].val);
2583+
}
25302584

2531-
for (i = 1; i < num_regs; i++)
2532-
regmap_write(regmap, reg_pairs[i].off,
2533-
reg_pairs[i].val);
2534-
}
2585+
xcvr_diag_vals = cdns_torrent_get_tbl_vals(&init_data->xcvr_diag_vals_tbl,
2586+
CLK_ANY, CLK_ANY,
2587+
phy_t1, phy_t2, ANY_SSC);
2588+
if (xcvr_diag_vals) {
2589+
reg_pairs = xcvr_diag_vals->reg_pairs;
2590+
num_regs = xcvr_diag_vals->num_regs;
2591+
for (i = 0; i < num_lanes; i++) {
2592+
regmap = cdns_phy->regmap_tx_lane_cdb[i + mlane];
2593+
for (j = 0; j < num_regs; j++)
2594+
regmap_write(regmap, reg_pairs[j].off,
2595+
reg_pairs[j].val);
2596+
}
2597+
}
25352598

2536-
xcvr_diag_vals = cdns_torrent_get_tbl_vals(&init_data->xcvr_diag_vals_tbl,
2537-
CLK_ANY, CLK_ANY,
2538-
phy_t1, phy_t2, ANY_SSC);
2539-
if (xcvr_diag_vals) {
2540-
reg_pairs = xcvr_diag_vals->reg_pairs;
2541-
num_regs = xcvr_diag_vals->num_regs;
2542-
for (i = 0; i < num_lanes; i++) {
2543-
regmap = cdns_phy->regmap_tx_lane_cdb[i + mlane];
2544-
for (j = 0; j < num_regs; j++)
2545-
regmap_write(regmap, reg_pairs[j].off,
2546-
reg_pairs[j].val);
2599+
/* PHY PCS common registers configurations */
2600+
pcs_cmn_vals = cdns_torrent_get_tbl_vals(&init_data->pcs_cmn_vals_tbl,
2601+
CLK_ANY, CLK_ANY,
2602+
phy_t1, phy_t2, ANY_SSC);
2603+
if (pcs_cmn_vals) {
2604+
reg_pairs = pcs_cmn_vals->reg_pairs;
2605+
num_regs = pcs_cmn_vals->num_regs;
2606+
regmap = cdns_phy->regmap_phy_pcs_common_cdb;
2607+
for (i = 0; i < num_regs; i++)
2608+
regmap_write(regmap, reg_pairs[i].off,
2609+
reg_pairs[i].val);
25472610
}
2548-
}
25492611

2550-
/* PHY PCS common registers configurations */
2551-
pcs_cmn_vals = cdns_torrent_get_tbl_vals(&init_data->pcs_cmn_vals_tbl,
2552-
CLK_ANY, CLK_ANY,
2553-
phy_t1, phy_t2, ANY_SSC);
2554-
if (pcs_cmn_vals) {
2555-
reg_pairs = pcs_cmn_vals->reg_pairs;
2556-
num_regs = pcs_cmn_vals->num_regs;
2557-
regmap = cdns_phy->regmap_phy_pcs_common_cdb;
2558-
for (i = 0; i < num_regs; i++)
2559-
regmap_write(regmap, reg_pairs[i].off,
2560-
reg_pairs[i].val);
2561-
}
2612+
/* PHY PMA common registers configurations */
2613+
phy_pma_cmn_vals =
2614+
cdns_torrent_get_tbl_vals(&init_data->phy_pma_cmn_vals_tbl,
2615+
CLK_ANY, CLK_ANY, phy_t1, phy_t2,
2616+
ANY_SSC);
2617+
if (phy_pma_cmn_vals) {
2618+
reg_pairs = phy_pma_cmn_vals->reg_pairs;
2619+
num_regs = phy_pma_cmn_vals->num_regs;
2620+
regmap = cdns_phy->regmap_phy_pma_common_cdb;
2621+
for (i = 0; i < num_regs; i++)
2622+
regmap_write(regmap, reg_pairs[i].off,
2623+
reg_pairs[i].val);
2624+
}
25622625

2563-
/* PHY PMA common registers configurations */
2564-
phy_pma_cmn_vals = cdns_torrent_get_tbl_vals(&init_data->phy_pma_cmn_vals_tbl,
2565-
CLK_ANY, CLK_ANY,
2566-
phy_t1, phy_t2, ANY_SSC);
2567-
if (phy_pma_cmn_vals) {
2568-
reg_pairs = phy_pma_cmn_vals->reg_pairs;
2569-
num_regs = phy_pma_cmn_vals->num_regs;
2570-
regmap = cdns_phy->regmap_phy_pma_common_cdb;
2571-
for (i = 0; i < num_regs; i++)
2572-
regmap_write(regmap, reg_pairs[i].off,
2573-
reg_pairs[i].val);
2574-
}
2626+
/* PMA common registers configurations */
2627+
cmn_vals = cdns_torrent_get_tbl_vals(&init_data->cmn_vals_tbl,
2628+
ref_clk, ref_clk1,
2629+
phy_t1, phy_t2, ssc);
2630+
if (cmn_vals) {
2631+
reg_pairs = cmn_vals->reg_pairs;
2632+
num_regs = cmn_vals->num_regs;
2633+
regmap = cdns_phy->regmap_common_cdb;
2634+
for (i = 0; i < num_regs; i++)
2635+
regmap_write(regmap, reg_pairs[i].off,
2636+
reg_pairs[i].val);
2637+
}
25752638

2576-
/* PMA common registers configurations */
2577-
cmn_vals = cdns_torrent_get_tbl_vals(&init_data->cmn_vals_tbl,
2578-
ref_clk, ref_clk1,
2579-
phy_t1, phy_t2, ssc);
2580-
if (cmn_vals) {
2581-
reg_pairs = cmn_vals->reg_pairs;
2582-
num_regs = cmn_vals->num_regs;
2583-
regmap = cdns_phy->regmap_common_cdb;
2584-
for (i = 0; i < num_regs; i++)
2585-
regmap_write(regmap, reg_pairs[i].off,
2586-
reg_pairs[i].val);
2587-
}
2639+
/* PMA TX lane registers configurations */
2640+
tx_ln_vals = cdns_torrent_get_tbl_vals(&init_data->tx_ln_vals_tbl,
2641+
ref_clk, ref_clk1,
2642+
phy_t1, phy_t2, ssc);
2643+
if (tx_ln_vals) {
2644+
reg_pairs = tx_ln_vals->reg_pairs;
2645+
num_regs = tx_ln_vals->num_regs;
2646+
for (i = 0; i < num_lanes; i++) {
2647+
regmap = cdns_phy->regmap_tx_lane_cdb[i + mlane];
2648+
for (j = 0; j < num_regs; j++)
2649+
regmap_write(regmap, reg_pairs[j].off,
2650+
reg_pairs[j].val);
2651+
}
2652+
}
25882653

2589-
/* PMA TX lane registers configurations */
2590-
tx_ln_vals = cdns_torrent_get_tbl_vals(&init_data->tx_ln_vals_tbl,
2591-
ref_clk, ref_clk1,
2592-
phy_t1, phy_t2, ssc);
2593-
if (tx_ln_vals) {
2594-
reg_pairs = tx_ln_vals->reg_pairs;
2595-
num_regs = tx_ln_vals->num_regs;
2596-
for (i = 0; i < num_lanes; i++) {
2597-
regmap = cdns_phy->regmap_tx_lane_cdb[i + mlane];
2598-
for (j = 0; j < num_regs; j++)
2599-
regmap_write(regmap, reg_pairs[j].off,
2600-
reg_pairs[j].val);
2654+
/* PMA RX lane registers configurations */
2655+
rx_ln_vals = cdns_torrent_get_tbl_vals(&init_data->rx_ln_vals_tbl,
2656+
ref_clk, ref_clk1,
2657+
phy_t1, phy_t2, ssc);
2658+
if (rx_ln_vals) {
2659+
reg_pairs = rx_ln_vals->reg_pairs;
2660+
num_regs = rx_ln_vals->num_regs;
2661+
for (i = 0; i < num_lanes; i++) {
2662+
regmap = cdns_phy->regmap_rx_lane_cdb[i + mlane];
2663+
for (j = 0; j < num_regs; j++)
2664+
regmap_write(regmap, reg_pairs[j].off,
2665+
reg_pairs[j].val);
2666+
}
26012667
}
2602-
}
26032668

2604-
/* PMA RX lane registers configurations */
2605-
rx_ln_vals = cdns_torrent_get_tbl_vals(&init_data->rx_ln_vals_tbl,
2606-
ref_clk, ref_clk1,
2607-
phy_t1, phy_t2, ssc);
2608-
if (rx_ln_vals) {
2609-
reg_pairs = rx_ln_vals->reg_pairs;
2610-
num_regs = rx_ln_vals->num_regs;
2611-
for (i = 0; i < num_lanes; i++) {
2612-
regmap = cdns_phy->regmap_rx_lane_cdb[i + mlane];
2613-
for (j = 0; j < num_regs; j++)
2614-
regmap_write(regmap, reg_pairs[j].off,
2615-
reg_pairs[j].val);
2669+
if (phy_t1 == TYPE_DP) {
2670+
ret = cdns_torrent_dp_get_pll(cdns_phy, phy_t2);
2671+
if (ret)
2672+
return ret;
26162673
}
2617-
}
26182674

2619-
if (phy_t1 == TYPE_DP) {
2620-
ret = cdns_torrent_dp_get_pll(cdns_phy, phy_t2);
2621-
if (ret)
2622-
return ret;
2675+
reset_control_deassert(cdns_phy->phys[node].lnk_rst);
26232676
}
2624-
2625-
reset_control_deassert(cdns_phy->phys[node].lnk_rst);
26262677
}
26272678

26282679
/* Take the PHY out of reset */
@@ -2826,6 +2877,7 @@ static int cdns_torrent_phy_probe(struct platform_device *pdev)
28262877
dev_set_drvdata(dev, cdns_phy);
28272878
cdns_phy->dev = dev;
28282879
cdns_phy->init_data = data;
2880+
cdns_phy->protocol_bitmask = 0;
28292881

28302882
cdns_phy->sd_base = devm_platform_ioremap_resource(pdev, 0);
28312883
if (IS_ERR(cdns_phy->sd_base))
@@ -3010,6 +3062,7 @@ static int cdns_torrent_phy_probe(struct platform_device *pdev)
30103062
}
30113063

30123064
cdns_phy->phys[node].phy = gphy;
3065+
cdns_phy->protocol_bitmask |= BIT(cdns_phy->phys[node].phy_type);
30133066
phy_set_drvdata(gphy, &cdns_phy->phys[node]);
30143067

30153068
node++;

0 commit comments

Comments
 (0)