int cdns_torrent_phy_configure_multilink()

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;
}