phy: cadence: Sierra: Add support for PHY multilink configurations
Add support for multilink configuration of Sierra PHY. Currently, maximum two links are supported. Signed-off-by: Swapnil Jakhade <sjakhade@cadence.com> Signed-off-by: Aswath Govindraju <a-govindraju@ti.com>
This commit is contained in:
parent
960efc5edc
commit
168fbf79db
@ -29,7 +29,7 @@
|
||||
#include <regmap.h>
|
||||
|
||||
#define NUM_SSC_MODE 3
|
||||
#define NUM_PHY_TYPE 3
|
||||
#define NUM_PHY_TYPE 4
|
||||
|
||||
/* PHY register offsets */
|
||||
#define SIERRA_COMMON_CDB_OFFSET 0x0
|
||||
@ -183,6 +183,11 @@
|
||||
(0xD000 + ((ln) * (0x800 >> (3 - (offset)))))
|
||||
#define SIERRA_PHY_ISO_LINK_CTRL 0xB
|
||||
|
||||
/* PHY PMA lane registers */
|
||||
#define SIERRA_PHY_PMA_LANE_CDB_OFFSET(ln, offset) \
|
||||
(0xF000 + ((ln) * (0x800 >> (3 - (offset)))))
|
||||
#define SIERRA_PHY_PMA_XCVR_CTRL 0x000
|
||||
|
||||
#define SIERRA_MACRO_ID 0x00007364
|
||||
#define SIERRA_MAX_LANES 16
|
||||
#define PLL_LOCK_TIME 100
|
||||
@ -288,6 +293,8 @@ struct cdns_sierra_data {
|
||||
u8 reg_offset_shift;
|
||||
struct cdns_sierra_vals *pcs_cmn_vals[NUM_PHY_TYPE][NUM_PHY_TYPE]
|
||||
[NUM_SSC_MODE];
|
||||
struct cdns_sierra_vals *phy_pma_ln_vals[NUM_PHY_TYPE][NUM_PHY_TYPE]
|
||||
[NUM_SSC_MODE];
|
||||
struct cdns_sierra_vals *pma_cmn_vals[NUM_PHY_TYPE][NUM_PHY_TYPE]
|
||||
[NUM_SSC_MODE];
|
||||
struct cdns_sierra_vals *pma_ln_vals[NUM_PHY_TYPE][NUM_PHY_TYPE]
|
||||
@ -306,6 +313,7 @@ struct cdns_sierra_phy {
|
||||
struct regmap *regmap_phy_pcs_common_cdb;
|
||||
struct regmap *regmap_phy_pcs_lane_cdb[SIERRA_MAX_LANES];
|
||||
struct regmap *regmap_phy_pma_common_cdb;
|
||||
struct regmap *regmap_phy_pma_lane_cdb[SIERRA_MAX_LANES];
|
||||
struct regmap *regmap_common_cdb;
|
||||
struct regmap_field *macro_id_type;
|
||||
struct regmap_field *phy_pll_cfg_1;
|
||||
@ -361,6 +369,7 @@ static int cdns_sierra_phy_init(struct phy *gphy)
|
||||
struct cdns_sierra_vals *pma_cmn_vals, *pma_ln_vals;
|
||||
enum cdns_sierra_phy_type phy_type = ins->phy_type;
|
||||
enum cdns_sierra_ssc_mode ssc = ins->ssc_mode;
|
||||
struct cdns_sierra_vals *phy_pma_ln_vals;
|
||||
const struct cdns_reg_pairs *reg_pairs;
|
||||
struct cdns_sierra_vals *pcs_cmn_vals;
|
||||
struct regmap *regmap = phy->regmap;
|
||||
@ -368,7 +377,7 @@ static int cdns_sierra_phy_init(struct phy *gphy)
|
||||
int i, j;
|
||||
|
||||
/* Initialise the PHY registers, unless auto configured */
|
||||
if (phy->autoconf)
|
||||
if (phy->autoconf || phy->nsubnodes > 1)
|
||||
return 0;
|
||||
|
||||
clk_set_rate(phy->input_clks[CMN_REFCLK_DIG_DIV], 25000000);
|
||||
@ -384,6 +393,18 @@ static int cdns_sierra_phy_init(struct phy *gphy)
|
||||
regmap_write(regmap, reg_pairs[i].off, reg_pairs[i].val);
|
||||
}
|
||||
|
||||
/* PHY PMA lane registers configurations */
|
||||
phy_pma_ln_vals = init_data->phy_pma_ln_vals[phy_type][TYPE_NONE][ssc];
|
||||
if (phy_pma_ln_vals) {
|
||||
reg_pairs = phy_pma_ln_vals->reg_pairs;
|
||||
num_regs = phy_pma_ln_vals->num_regs;
|
||||
for (i = 0; i < ins->num_lanes; i++) {
|
||||
regmap = phy->regmap_phy_pma_lane_cdb[i + ins->mlane];
|
||||
for (j = 0; j < num_regs; j++)
|
||||
regmap_write(regmap, reg_pairs[j].off, reg_pairs[j].val);
|
||||
}
|
||||
}
|
||||
|
||||
/* PMA common registers configurations */
|
||||
pma_cmn_vals = init_data->pma_cmn_vals[phy_type][TYPE_NONE][ssc];
|
||||
if (pma_cmn_vals) {
|
||||
@ -417,10 +438,13 @@ static int cdns_sierra_phy_on(struct phy *gphy)
|
||||
u32 val;
|
||||
int ret;
|
||||
|
||||
ret = reset_control_deassert(sp->phy_rst);
|
||||
if (ret) {
|
||||
dev_err(dev, "Failed to take the PHY out of reset\n");
|
||||
return ret;
|
||||
if (sp->nsubnodes == 1) {
|
||||
/* Take the PHY out of reset */
|
||||
ret = reset_control_deassert(sp->phy_rst);
|
||||
if (ret) {
|
||||
dev_err(dev, "Failed to take the PHY out of reset\n");
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
/* Take the PHY lane group out of reset */
|
||||
@ -776,6 +800,116 @@ static int cdns_regmap_init_blocks(struct cdns_sierra_phy *sp,
|
||||
}
|
||||
sp->regmap_phy_pma_common_cdb = regmap;
|
||||
|
||||
for (i = 0; i < SIERRA_MAX_LANES; i++) {
|
||||
block_offset = SIERRA_PHY_PMA_LANE_CDB_OFFSET(i, reg_offset_shift);
|
||||
regmap = cdns_regmap_init(dev, base, block_offset,
|
||||
block_offset_shift, reg_offset_shift);
|
||||
if (IS_ERR(regmap)) {
|
||||
dev_err(dev, "Failed to init PHY PMA lane CDB regmap\n");
|
||||
return PTR_ERR(regmap);
|
||||
}
|
||||
sp->regmap_phy_pma_lane_cdb[i] = regmap;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cdns_sierra_phy_configure_multilink(struct cdns_sierra_phy *sp)
|
||||
{
|
||||
const struct cdns_sierra_data *init_data = sp->init_data;
|
||||
enum cdns_sierra_phy_type phy_t1, phy_t2, tmp_phy_type;
|
||||
struct cdns_sierra_vals *pma_cmn_vals, *pma_ln_vals;
|
||||
struct cdns_sierra_vals *phy_pma_ln_vals;
|
||||
const struct cdns_reg_pairs *reg_pairs;
|
||||
struct cdns_sierra_vals *pcs_cmn_vals;
|
||||
int i, j, node, mlane, num_lanes, ret;
|
||||
enum cdns_sierra_ssc_mode ssc;
|
||||
struct regmap *regmap;
|
||||
u32 num_regs;
|
||||
|
||||
/* Maximum 2 links (subnodes) are supported */
|
||||
if (sp->nsubnodes != 2)
|
||||
return -EINVAL;
|
||||
|
||||
clk_set_rate(sp->input_clks[CMN_REFCLK_DIG_DIV], 25000000);
|
||||
clk_set_rate(sp->input_clks[CMN_REFCLK1_DIG_DIV], 25000000);
|
||||
|
||||
/* PHY configured to use both PLL LC and LC1 */
|
||||
regmap_field_write(sp->phy_pll_cfg_1, 0x1);
|
||||
|
||||
phy_t1 = sp->phys[0]->phy_type;
|
||||
phy_t2 = sp->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 < sp->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].
|
||||
*/
|
||||
tmp_phy_type = phy_t1;
|
||||
phy_t1 = phy_t2;
|
||||
phy_t2 = tmp_phy_type;
|
||||
}
|
||||
|
||||
mlane = sp->phys[node]->mlane;
|
||||
ssc = sp->phys[node]->ssc_mode;
|
||||
num_lanes = sp->phys[node]->num_lanes;
|
||||
|
||||
/* 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 = sp->regmap_phy_pcs_common_cdb;
|
||||
for (i = 0; i < num_regs; i++)
|
||||
regmap_write(regmap, reg_pairs[i].off, reg_pairs[i].val);
|
||||
}
|
||||
|
||||
/* PHY PMA lane registers configurations */
|
||||
phy_pma_ln_vals = init_data->phy_pma_ln_vals[phy_t1][phy_t2][ssc];
|
||||
if (phy_pma_ln_vals) {
|
||||
reg_pairs = phy_pma_ln_vals->reg_pairs;
|
||||
num_regs = phy_pma_ln_vals->num_regs;
|
||||
for (i = 0; i < num_lanes; i++) {
|
||||
regmap = sp->regmap_phy_pma_lane_cdb[i + mlane];
|
||||
for (j = 0; j < num_regs; j++)
|
||||
regmap_write(regmap, reg_pairs[j].off, reg_pairs[j].val);
|
||||
}
|
||||
}
|
||||
|
||||
/* PMA common registers configurations */
|
||||
pma_cmn_vals = init_data->pma_cmn_vals[phy_t1][phy_t2][ssc];
|
||||
if (pma_cmn_vals) {
|
||||
reg_pairs = pma_cmn_vals->reg_pairs;
|
||||
num_regs = pma_cmn_vals->num_regs;
|
||||
regmap = sp->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 */
|
||||
pma_ln_vals = init_data->pma_ln_vals[phy_t1][phy_t2][ssc];
|
||||
if (pma_ln_vals) {
|
||||
reg_pairs = pma_ln_vals->reg_pairs;
|
||||
num_regs = pma_ln_vals->num_regs;
|
||||
for (i = 0; i < num_lanes; i++) {
|
||||
regmap = sp->regmap_lane_cdb[i + mlane];
|
||||
for (j = 0; j < num_regs; j++)
|
||||
regmap_write(regmap, reg_pairs[j].off, reg_pairs[j].val);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Take the PHY out of reset */
|
||||
ret = reset_control_deassert(sp->phy_rst);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -896,8 +1030,11 @@ static int cdns_sierra_link_probe(struct udevice *dev)
|
||||
sp->num_lanes += inst->num_lanes;
|
||||
|
||||
/* If more than one subnode, configure the PHY as multilink */
|
||||
if (!sp->autoconf && sp->nsubnodes > 1)
|
||||
regmap_field_write(sp->phy_pll_cfg_1, 0x1);
|
||||
if (!sp->autoconf && sp->nsubnodes > 1) {
|
||||
ret = cdns_sierra_phy_configure_multilink(sp);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user