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: 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 <s-vadapalli@ti.com>
Reviewed-by: Roger Quadros <rogerq@kernel.org>
Link: https://lore.kernel.org/r/20240805092607.143869-1-s-vadapalli@ti.com
Signed-off-by: Vinod Koul <vkoul@kernel.org>

authored by

Siddharth Vadapalli and committed by
Vinod Koul
5b7b83a9 0f20e326

+175 -122
+175 -122
drivers/phy/cadence/phy-cadence-torrent.c
··· 351 351 void __iomem *sd_base; /* SD0801 registers base */ 352 352 u32 max_bit_rate; /* Maximum link bit rate to use (in Mbps) */ 353 353 u32 dp_pll; 354 + u32 protocol_bitmask; 354 355 struct reset_control *phy_rst; 355 356 struct reset_control *apb_rst; 356 357 struct device *dev; ··· 2474 2473 enum cdns_torrent_phy_type phy_t1, phy_t2; 2475 2474 const struct cdns_reg_pairs *reg_pairs; 2476 2475 int i, j, node, mlane, num_lanes, ret; 2476 + struct device *dev = cdns_phy->dev; 2477 2477 enum cdns_torrent_ssc_mode ssc; 2478 2478 struct regmap *regmap; 2479 - u32 num_regs; 2479 + u32 num_regs, num_protocols, protocol; 2480 2480 2481 - /* Maximum 2 links (subnodes) are supported */ 2482 - if (cdns_phy->nsubnodes != 2) 2481 + num_protocols = hweight32(cdns_phy->protocol_bitmask); 2482 + /* Maximum 2 protocols are supported */ 2483 + if (num_protocols > 2) { 2484 + dev_err(dev, "at most 2 protocols are supported\n"); 2483 2485 return -EINVAL; 2486 + } 2484 2487 2485 - phy_t1 = cdns_phy->phys[0].phy_type; 2486 - phy_t2 = cdns_phy->phys[1].phy_type; 2487 2488 2488 2489 /** 2489 - * First configure the PHY for first link with phy_t1. Get the array 2490 - * values as [phy_t1][phy_t2][ssc]. 2490 + * Get PHY types directly from subnodes if only 2 subnodes exist. 2491 + * It is possible for phy_t1 to be the same as phy_t2 for special 2492 + * configurations such as PCIe Multilink. 2491 2493 */ 2492 - for (node = 0; node < cdns_phy->nsubnodes; node++) { 2493 - if (node == 1) { 2494 + if (cdns_phy->nsubnodes == 2) { 2495 + phy_t1 = cdns_phy->phys[0].phy_type; 2496 + phy_t2 = cdns_phy->phys[1].phy_type; 2497 + } else { 2498 + /** 2499 + * Both PHY types / protocols should be unique. 2500 + * If they are the same, it should be expressed with either 2501 + * a) Single-Link (1 Sub-node) - handled via PHY APIs 2502 + * OR 2503 + * b) Double-Link (2 Sub-nodes) - handled above 2504 + */ 2505 + if (num_protocols != 2) { 2506 + dev_err(dev, "incorrect representation of link\n"); 2507 + return -EINVAL; 2508 + } 2509 + 2510 + phy_t1 = fns(cdns_phy->protocol_bitmask, 0); 2511 + phy_t2 = fns(cdns_phy->protocol_bitmask, 1); 2512 + } 2513 + 2514 + /** 2515 + * Configure all links with the protocol phy_t1 first followed by 2516 + * configuring all links with the protocol phy_t2. 2517 + * 2518 + * When phy_t1 = phy_t2, it is a single protocol and configuration 2519 + * is performed with a single iteration of the protocol and multiple 2520 + * iterations over the sub-nodes (links). 2521 + * 2522 + * When phy_t1 != phy_t2, there are two protocols and configuration 2523 + * is performed by iterating over all sub-nodes matching the first 2524 + * protocol and configuring them first, followed by iterating over 2525 + * all sub-nodes matching the second protocol and configuring them 2526 + * next. 2527 + */ 2528 + for (protocol = 0; protocol < num_protocols; protocol++) { 2529 + /** 2530 + * For the case where num_protocols is 1, 2531 + * phy_t1 = phy_t2 and the swap is unnecessary. 2532 + * 2533 + * Swapping phy_t1 and phy_t2 is only required when the 2534 + * number of protocols is 2 and there are 2 or more links. 2535 + */ 2536 + if (protocol == 1) { 2494 2537 /** 2495 - * If first link with phy_t1 is configured, then 2496 - * configure the PHY for second link with phy_t2. 2538 + * If first protocol with phy_t1 is configured, then 2539 + * configure the PHY for second protocol with phy_t2. 2497 2540 * Get the array values as [phy_t2][phy_t1][ssc]. 2498 2541 */ 2499 2542 swap(phy_t1, phy_t2); 2500 2543 swap(ref_clk, ref_clk1); 2501 2544 } 2502 2545 2503 - mlane = cdns_phy->phys[node].mlane; 2504 - ssc = cdns_phy->phys[node].ssc_mode; 2505 - num_lanes = cdns_phy->phys[node].num_lanes; 2546 + for (node = 0; node < cdns_phy->nsubnodes; node++) { 2547 + if (cdns_phy->phys[node].phy_type != phy_t1) 2548 + continue; 2506 2549 2507 - /** 2508 - * PHY configuration specific registers: 2509 - * link_cmn_vals depend on combination of PHY types being 2510 - * configured and are common for both PHY types, so array 2511 - * values should be same for [phy_t1][phy_t2][ssc] and 2512 - * [phy_t2][phy_t1][ssc]. 2513 - * xcvr_diag_vals also depend on combination of PHY types 2514 - * being configured, but these can be different for particular 2515 - * PHY type and are per lane. 2516 - */ 2517 - link_cmn_vals = cdns_torrent_get_tbl_vals(&init_data->link_cmn_vals_tbl, 2518 - CLK_ANY, CLK_ANY, 2519 - phy_t1, phy_t2, ANY_SSC); 2520 - if (link_cmn_vals) { 2521 - reg_pairs = link_cmn_vals->reg_pairs; 2522 - num_regs = link_cmn_vals->num_regs; 2523 - regmap = cdns_phy->regmap_common_cdb; 2550 + mlane = cdns_phy->phys[node].mlane; 2551 + ssc = cdns_phy->phys[node].ssc_mode; 2552 + num_lanes = cdns_phy->phys[node].num_lanes; 2524 2553 2525 2554 /** 2526 - * First array value in link_cmn_vals must be of 2527 - * PHY_PLL_CFG register 2555 + * PHY configuration specific registers: 2556 + * link_cmn_vals depend on combination of PHY types being 2557 + * configured and are common for both PHY types, so array 2558 + * values should be same for [phy_t1][phy_t2][ssc] and 2559 + * [phy_t2][phy_t1][ssc]. 2560 + * xcvr_diag_vals also depend on combination of PHY types 2561 + * being configured, but these can be different for particular 2562 + * PHY type and are per lane. 2528 2563 */ 2529 - regmap_field_write(cdns_phy->phy_pll_cfg, 2530 - reg_pairs[0].val); 2564 + link_cmn_vals = cdns_torrent_get_tbl_vals(&init_data->link_cmn_vals_tbl, 2565 + CLK_ANY, CLK_ANY, 2566 + phy_t1, phy_t2, ANY_SSC); 2567 + if (link_cmn_vals) { 2568 + reg_pairs = link_cmn_vals->reg_pairs; 2569 + num_regs = link_cmn_vals->num_regs; 2570 + regmap = cdns_phy->regmap_common_cdb; 2531 2571 2532 - for (i = 1; i < num_regs; i++) 2533 - regmap_write(regmap, reg_pairs[i].off, 2534 - reg_pairs[i].val); 2535 - } 2572 + /** 2573 + * First array value in link_cmn_vals must be of 2574 + * PHY_PLL_CFG register 2575 + */ 2576 + regmap_field_write(cdns_phy->phy_pll_cfg, 2577 + reg_pairs[0].val); 2536 2578 2537 - xcvr_diag_vals = cdns_torrent_get_tbl_vals(&init_data->xcvr_diag_vals_tbl, 2538 - CLK_ANY, CLK_ANY, 2539 - phy_t1, phy_t2, ANY_SSC); 2540 - if (xcvr_diag_vals) { 2541 - reg_pairs = xcvr_diag_vals->reg_pairs; 2542 - num_regs = xcvr_diag_vals->num_regs; 2543 - for (i = 0; i < num_lanes; i++) { 2544 - regmap = cdns_phy->regmap_tx_lane_cdb[i + mlane]; 2545 - for (j = 0; j < num_regs; j++) 2546 - regmap_write(regmap, reg_pairs[j].off, 2547 - reg_pairs[j].val); 2579 + for (i = 1; i < num_regs; i++) 2580 + regmap_write(regmap, reg_pairs[i].off, 2581 + reg_pairs[i].val); 2548 2582 } 2549 - } 2550 2583 2551 - /* PHY PCS common registers configurations */ 2552 - pcs_cmn_vals = cdns_torrent_get_tbl_vals(&init_data->pcs_cmn_vals_tbl, 2553 - CLK_ANY, CLK_ANY, 2554 - phy_t1, phy_t2, ANY_SSC); 2555 - if (pcs_cmn_vals) { 2556 - reg_pairs = pcs_cmn_vals->reg_pairs; 2557 - num_regs = pcs_cmn_vals->num_regs; 2558 - regmap = cdns_phy->regmap_phy_pcs_common_cdb; 2559 - for (i = 0; i < num_regs; i++) 2560 - regmap_write(regmap, reg_pairs[i].off, 2561 - reg_pairs[i].val); 2562 - } 2563 - 2564 - /* PHY PMA common registers configurations */ 2565 - phy_pma_cmn_vals = cdns_torrent_get_tbl_vals(&init_data->phy_pma_cmn_vals_tbl, 2566 - CLK_ANY, CLK_ANY, 2567 - phy_t1, phy_t2, ANY_SSC); 2568 - if (phy_pma_cmn_vals) { 2569 - reg_pairs = phy_pma_cmn_vals->reg_pairs; 2570 - num_regs = phy_pma_cmn_vals->num_regs; 2571 - regmap = cdns_phy->regmap_phy_pma_common_cdb; 2572 - for (i = 0; i < num_regs; i++) 2573 - regmap_write(regmap, reg_pairs[i].off, 2574 - reg_pairs[i].val); 2575 - } 2576 - 2577 - /* PMA common registers configurations */ 2578 - cmn_vals = cdns_torrent_get_tbl_vals(&init_data->cmn_vals_tbl, 2579 - ref_clk, ref_clk1, 2580 - phy_t1, phy_t2, ssc); 2581 - if (cmn_vals) { 2582 - reg_pairs = cmn_vals->reg_pairs; 2583 - num_regs = cmn_vals->num_regs; 2584 - regmap = cdns_phy->regmap_common_cdb; 2585 - for (i = 0; i < num_regs; i++) 2586 - regmap_write(regmap, reg_pairs[i].off, 2587 - reg_pairs[i].val); 2588 - } 2589 - 2590 - /* PMA TX lane registers configurations */ 2591 - tx_ln_vals = cdns_torrent_get_tbl_vals(&init_data->tx_ln_vals_tbl, 2592 - ref_clk, ref_clk1, 2593 - phy_t1, phy_t2, ssc); 2594 - if (tx_ln_vals) { 2595 - reg_pairs = tx_ln_vals->reg_pairs; 2596 - num_regs = tx_ln_vals->num_regs; 2597 - for (i = 0; i < num_lanes; i++) { 2598 - regmap = cdns_phy->regmap_tx_lane_cdb[i + mlane]; 2599 - for (j = 0; j < num_regs; j++) 2600 - regmap_write(regmap, reg_pairs[j].off, 2601 - reg_pairs[j].val); 2584 + xcvr_diag_vals = cdns_torrent_get_tbl_vals(&init_data->xcvr_diag_vals_tbl, 2585 + CLK_ANY, CLK_ANY, 2586 + phy_t1, phy_t2, ANY_SSC); 2587 + if (xcvr_diag_vals) { 2588 + reg_pairs = xcvr_diag_vals->reg_pairs; 2589 + num_regs = xcvr_diag_vals->num_regs; 2590 + for (i = 0; i < num_lanes; i++) { 2591 + regmap = cdns_phy->regmap_tx_lane_cdb[i + mlane]; 2592 + for (j = 0; j < num_regs; j++) 2593 + regmap_write(regmap, reg_pairs[j].off, 2594 + reg_pairs[j].val); 2595 + } 2602 2596 } 2603 - } 2604 2597 2605 - /* PMA RX lane registers configurations */ 2606 - rx_ln_vals = cdns_torrent_get_tbl_vals(&init_data->rx_ln_vals_tbl, 2607 - ref_clk, ref_clk1, 2608 - phy_t1, phy_t2, ssc); 2609 - if (rx_ln_vals) { 2610 - reg_pairs = rx_ln_vals->reg_pairs; 2611 - num_regs = rx_ln_vals->num_regs; 2612 - for (i = 0; i < num_lanes; i++) { 2613 - regmap = cdns_phy->regmap_rx_lane_cdb[i + mlane]; 2614 - for (j = 0; j < num_regs; j++) 2615 - regmap_write(regmap, reg_pairs[j].off, 2616 - reg_pairs[j].val); 2598 + /* PHY PCS common registers configurations */ 2599 + pcs_cmn_vals = cdns_torrent_get_tbl_vals(&init_data->pcs_cmn_vals_tbl, 2600 + CLK_ANY, CLK_ANY, 2601 + phy_t1, phy_t2, ANY_SSC); 2602 + if (pcs_cmn_vals) { 2603 + reg_pairs = pcs_cmn_vals->reg_pairs; 2604 + num_regs = pcs_cmn_vals->num_regs; 2605 + regmap = cdns_phy->regmap_phy_pcs_common_cdb; 2606 + for (i = 0; i < num_regs; i++) 2607 + regmap_write(regmap, reg_pairs[i].off, 2608 + reg_pairs[i].val); 2617 2609 } 2618 - } 2619 2610 2620 - if (phy_t1 == TYPE_DP) { 2621 - ret = cdns_torrent_dp_get_pll(cdns_phy, phy_t2); 2622 - if (ret) 2623 - return ret; 2624 - } 2611 + /* PHY PMA common registers configurations */ 2612 + phy_pma_cmn_vals = 2613 + cdns_torrent_get_tbl_vals(&init_data->phy_pma_cmn_vals_tbl, 2614 + CLK_ANY, CLK_ANY, phy_t1, phy_t2, 2615 + ANY_SSC); 2616 + if (phy_pma_cmn_vals) { 2617 + reg_pairs = phy_pma_cmn_vals->reg_pairs; 2618 + num_regs = phy_pma_cmn_vals->num_regs; 2619 + regmap = cdns_phy->regmap_phy_pma_common_cdb; 2620 + for (i = 0; i < num_regs; i++) 2621 + regmap_write(regmap, reg_pairs[i].off, 2622 + reg_pairs[i].val); 2623 + } 2625 2624 2626 - reset_control_deassert(cdns_phy->phys[node].lnk_rst); 2625 + /* PMA common registers configurations */ 2626 + cmn_vals = cdns_torrent_get_tbl_vals(&init_data->cmn_vals_tbl, 2627 + ref_clk, ref_clk1, 2628 + phy_t1, phy_t2, ssc); 2629 + if (cmn_vals) { 2630 + reg_pairs = cmn_vals->reg_pairs; 2631 + num_regs = cmn_vals->num_regs; 2632 + regmap = cdns_phy->regmap_common_cdb; 2633 + for (i = 0; i < num_regs; i++) 2634 + regmap_write(regmap, reg_pairs[i].off, 2635 + reg_pairs[i].val); 2636 + } 2637 + 2638 + /* PMA TX lane registers configurations */ 2639 + tx_ln_vals = cdns_torrent_get_tbl_vals(&init_data->tx_ln_vals_tbl, 2640 + ref_clk, ref_clk1, 2641 + phy_t1, phy_t2, ssc); 2642 + if (tx_ln_vals) { 2643 + reg_pairs = tx_ln_vals->reg_pairs; 2644 + num_regs = tx_ln_vals->num_regs; 2645 + for (i = 0; i < num_lanes; i++) { 2646 + regmap = cdns_phy->regmap_tx_lane_cdb[i + mlane]; 2647 + for (j = 0; j < num_regs; j++) 2648 + regmap_write(regmap, reg_pairs[j].off, 2649 + reg_pairs[j].val); 2650 + } 2651 + } 2652 + 2653 + /* PMA RX lane registers configurations */ 2654 + rx_ln_vals = cdns_torrent_get_tbl_vals(&init_data->rx_ln_vals_tbl, 2655 + ref_clk, ref_clk1, 2656 + phy_t1, phy_t2, ssc); 2657 + if (rx_ln_vals) { 2658 + reg_pairs = rx_ln_vals->reg_pairs; 2659 + num_regs = rx_ln_vals->num_regs; 2660 + for (i = 0; i < num_lanes; i++) { 2661 + regmap = cdns_phy->regmap_rx_lane_cdb[i + mlane]; 2662 + for (j = 0; j < num_regs; j++) 2663 + regmap_write(regmap, reg_pairs[j].off, 2664 + reg_pairs[j].val); 2665 + } 2666 + } 2667 + 2668 + if (phy_t1 == TYPE_DP) { 2669 + ret = cdns_torrent_dp_get_pll(cdns_phy, phy_t2); 2670 + if (ret) 2671 + return ret; 2672 + } 2673 + 2674 + reset_control_deassert(cdns_phy->phys[node].lnk_rst); 2675 + } 2627 2676 } 2628 2677 2629 2678 /* Take the PHY out of reset */ ··· 2877 2826 dev_set_drvdata(dev, cdns_phy); 2878 2827 cdns_phy->dev = dev; 2879 2828 cdns_phy->init_data = data; 2829 + cdns_phy->protocol_bitmask = 0; 2880 2830 2881 2831 cdns_phy->sd_base = devm_platform_ioremap_resource(pdev, 0); 2882 2832 if (IS_ERR(cdns_phy->sd_base)) ··· 3062 3010 } 3063 3011 3064 3012 cdns_phy->phys[node].phy = gphy; 3013 + cdns_phy->protocol_bitmask |= BIT(cdns_phy->phys[node].phy_type); 3065 3014 phy_set_drvdata(gphy, &cdns_phy->phys[node]); 3066 3015 3067 3016 node++;