in cadence/phy-cadence-torrent.c [2275:2411]
int cdns_torrent_phy_configure_multilink(struct cdns_torrent_phy *cdns_phy)
{
const struct cdns_torrent_data *init_data = cdns_phy->init_data;
struct cdns_torrent_vals *cmn_vals, *tx_ln_vals, *rx_ln_vals;
enum cdns_torrent_ref_clk ref_clk = cdns_phy->ref_clk_rate;
struct cdns_torrent_vals *link_cmn_vals, *xcvr_diag_vals;
enum cdns_torrent_phy_type phy_t1, phy_t2;
struct cdns_torrent_vals *pcs_cmn_vals;
int i, j, node, mlane, num_lanes, ret;
struct cdns_reg_pairs *reg_pairs;
enum cdns_torrent_ssc_mode ssc;
struct regmap *regmap;
u32 num_regs;
/* Maximum 2 links (subnodes) are supported */
if (cdns_phy->nsubnodes != 2)
return -EINVAL;
phy_t1 = cdns_phy->phys[0].phy_type;
phy_t2 = cdns_phy->phys[1].phy_type;
/**
* First configure the PHY for first link with phy_t1. Get the array
* values as [phy_t1][phy_t2][ssc].
*/
for (node = 0; node < cdns_phy->nsubnodes; node++) {
if (node == 1) {
/**
* If first link with phy_t1 is configured, then
* configure the PHY for second link with phy_t2.
* Get the array values as [phy_t2][phy_t1][ssc].
*/
swap(phy_t1, phy_t2);
}
mlane = cdns_phy->phys[node].mlane;
ssc = cdns_phy->phys[node].ssc_mode;
num_lanes = cdns_phy->phys[node].num_lanes;
/**
* 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 = init_data->link_cmn_vals[phy_t1][phy_t2][ssc];
if (link_cmn_vals) {
reg_pairs = link_cmn_vals->reg_pairs;
num_regs = link_cmn_vals->num_regs;
regmap = cdns_phy->regmap_common_cdb;
/**
* 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);
for (i = 1; i < num_regs; i++)
regmap_write(regmap, reg_pairs[i].off,
reg_pairs[i].val);
}
xcvr_diag_vals = init_data->xcvr_diag_vals[phy_t1][phy_t2][ssc];
if (xcvr_diag_vals) {
reg_pairs = xcvr_diag_vals->reg_pairs;
num_regs = xcvr_diag_vals->num_regs;
for (i = 0; i < num_lanes; i++) {
regmap = cdns_phy->regmap_tx_lane_cdb[i + mlane];
for (j = 0; j < num_regs; j++)
regmap_write(regmap, reg_pairs[j].off,
reg_pairs[j].val);
}
}
/* PHY PCS common registers configurations */
pcs_cmn_vals = init_data->pcs_cmn_vals[phy_t1][phy_t2][ssc];
if (pcs_cmn_vals) {
reg_pairs = pcs_cmn_vals->reg_pairs;
num_regs = pcs_cmn_vals->num_regs;
regmap = cdns_phy->regmap_phy_pcs_common_cdb;
for (i = 0; i < num_regs; i++)
regmap_write(regmap, reg_pairs[i].off,
reg_pairs[i].val);
}
/* PMA common registers configurations */
cmn_vals = init_data->cmn_vals[ref_clk][phy_t1][phy_t2][ssc];
if (cmn_vals) {
reg_pairs = cmn_vals->reg_pairs;
num_regs = cmn_vals->num_regs;
regmap = cdns_phy->regmap_common_cdb;
for (i = 0; i < num_regs; i++)
regmap_write(regmap, reg_pairs[i].off,
reg_pairs[i].val);
}
/* PMA TX lane registers configurations */
tx_ln_vals = init_data->tx_ln_vals[ref_clk][phy_t1][phy_t2][ssc];
if (tx_ln_vals) {
reg_pairs = tx_ln_vals->reg_pairs;
num_regs = tx_ln_vals->num_regs;
for (i = 0; i < num_lanes; i++) {
regmap = cdns_phy->regmap_tx_lane_cdb[i + mlane];
for (j = 0; j < num_regs; j++)
regmap_write(regmap, reg_pairs[j].off,
reg_pairs[j].val);
}
}
/* PMA RX lane registers configurations */
rx_ln_vals = init_data->rx_ln_vals[ref_clk][phy_t1][phy_t2][ssc];
if (rx_ln_vals) {
reg_pairs = rx_ln_vals->reg_pairs;
num_regs = rx_ln_vals->num_regs;
for (i = 0; i < num_lanes; i++) {
regmap = cdns_phy->regmap_rx_lane_cdb[i + mlane];
for (j = 0; j < num_regs; j++)
regmap_write(regmap, reg_pairs[j].off,
reg_pairs[j].val);
}
}
reset_control_deassert(cdns_phy->phys[node].lnk_rst);
}
/* Take the PHY out of reset */
ret = reset_control_deassert(cdns_phy->phy_rst);
if (ret)
return ret;
return 0;
}