Skip to content

Commit

Permalink
net: phy: motorcomm: configure pad drive strength register
Browse files Browse the repository at this point in the history
This ports the pad drive strength register configuration which can be
already found in the Linux driver for this PHY.

Signed-off-by: Lukasz Tekieli <[email protected]>
Reviewed-by: Leo Yu-Chi Liang <[email protected]>
  • Loading branch information
ltekieli authored and Leo Yu-Chi Liang committed Jan 31, 2024
1 parent 36278b7 commit c025c8a
Showing 1 changed file with 130 additions and 0 deletions.
130 changes: 130 additions & 0 deletions drivers/net/phy/motorcomm.c
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,12 @@

#define YTPHY_SYNCE_CFG_REG 0xA012

#define YT8531_PAD_DRIVE_STRENGTH_CFG_REG 0xA010
#define YT8531_RGMII_RXC_DS_MASK GENMASK(15, 13)
#define YT8531_RGMII_RXD_DS_HI_MASK BIT(12) /* Bit 2 of rxd_ds */
#define YT8531_RGMII_RXD_DS_LOW_MASK GENMASK(5, 4) /* Bit 1/0 of rxd_ds */
#define YT8531_RGMII_RX_DS_DEFAULT 0x3

#define YTPHY_DTS_OUTPUT_CLK_DIS 0
#define YTPHY_DTS_OUTPUT_CLK_25M 25000000
#define YTPHY_DTS_OUTPUT_CLK_125M 125000000
Expand Down Expand Up @@ -114,6 +120,10 @@
#define YT8531_CCR_RXC_DLY_EN BIT(8)
#define YT8531_CCR_RXC_DLY_1_900_NS 1900

#define YT8531_CCR_CFG_LDO_MASK GENMASK(5, 4)
#define YT8531_CCR_CFG_LDO_3V3 0x0
#define YT8531_CCR_CFG_LDO_1V8 0x2

/* bits in struct ytphy_plat_priv->flag */
#define TX_CLK_ADJ_ENABLED BIT(0)
#define AUTO_SLEEP_DISABLED BIT(1)
Expand Down Expand Up @@ -224,6 +234,17 @@ static int ytphy_modify_ext(struct phy_device *phydev, u16 regnum, u16 mask,
return phy_modify(phydev, MDIO_DEVAD_NONE, YTPHY_PAGE_DATA, mask, set);
}

static int ytphy_read_ext(struct phy_device *phydev, u16 regnum)
{
int ret;

ret = phy_write(phydev, MDIO_DEVAD_NONE, YTPHY_PAGE_SELECT, regnum);
if (ret < 0)
return ret;

return phy_read(phydev, MDIO_DEVAD_NONE, YTPHY_PAGE_DATA);
}

static int ytphy_rgmii_clk_delay_config(struct phy_device *phydev)
{
struct ytphy_plat_priv *priv = phydev->priv;
Expand Down Expand Up @@ -425,6 +446,111 @@ static int yt8511_config(struct phy_device *phydev)
return 0;
}

/**
* struct ytphy_ldo_vol_map - map a current value to a register value
* @vol: ldo voltage
* @ds: value in the register
* @cur: value in device configuration
*/
struct ytphy_ldo_vol_map {
u32 vol;
u32 ds;
u32 cur;
};

static const struct ytphy_ldo_vol_map yt8531_ldo_vol[] = {
{.vol = YT8531_CCR_CFG_LDO_1V8, .ds = 0, .cur = 1200},
{.vol = YT8531_CCR_CFG_LDO_1V8, .ds = 1, .cur = 2100},
{.vol = YT8531_CCR_CFG_LDO_1V8, .ds = 2, .cur = 2700},
{.vol = YT8531_CCR_CFG_LDO_1V8, .ds = 3, .cur = 2910},
{.vol = YT8531_CCR_CFG_LDO_1V8, .ds = 4, .cur = 3110},
{.vol = YT8531_CCR_CFG_LDO_1V8, .ds = 5, .cur = 3600},
{.vol = YT8531_CCR_CFG_LDO_1V8, .ds = 6, .cur = 3970},
{.vol = YT8531_CCR_CFG_LDO_1V8, .ds = 7, .cur = 4350},
{.vol = YT8531_CCR_CFG_LDO_3V3, .ds = 0, .cur = 3070},
{.vol = YT8531_CCR_CFG_LDO_3V3, .ds = 1, .cur = 4080},
{.vol = YT8531_CCR_CFG_LDO_3V3, .ds = 2, .cur = 4370},
{.vol = YT8531_CCR_CFG_LDO_3V3, .ds = 3, .cur = 4680},
{.vol = YT8531_CCR_CFG_LDO_3V3, .ds = 4, .cur = 5020},
{.vol = YT8531_CCR_CFG_LDO_3V3, .ds = 5, .cur = 5450},
{.vol = YT8531_CCR_CFG_LDO_3V3, .ds = 6, .cur = 5740},
{.vol = YT8531_CCR_CFG_LDO_3V3, .ds = 7, .cur = 6140},
};

static u32 yt8531_get_ldo_vol(struct phy_device *phydev)
{
u32 val;

val = ytphy_read_ext(phydev, YT8531_CHIP_CONFIG_REG);
val = FIELD_GET(YT8531_CCR_CFG_LDO_MASK, val);

return val <= YT8531_CCR_CFG_LDO_1V8 ? val : YT8531_CCR_CFG_LDO_1V8;
}

static int yt8531_get_ds_map(struct phy_device *phydev, u32 cur)
{
u32 vol;
int i;

vol = yt8531_get_ldo_vol(phydev);
for (i = 0; i < ARRAY_SIZE(yt8531_ldo_vol); i++) {
if (yt8531_ldo_vol[i].vol == vol && yt8531_ldo_vol[i].cur == cur)
return yt8531_ldo_vol[i].ds;
}

return -EINVAL;
}

static int yt8531_set_ds(struct phy_device *phydev)
{
u32 ds_field_low, ds_field_hi, val;
int ret, ds;

/* set rgmii rx clk driver strength */
if (!ofnode_read_u32(phydev->node, "motorcomm,rx-clk-drv-microamp", &val)) {
ds = yt8531_get_ds_map(phydev, val);
if (ds < 0) {
pr_warn("No matching current value was found.");
return -EINVAL;
}
} else {
ds = YT8531_RGMII_RX_DS_DEFAULT;
}

ret = ytphy_modify_ext(phydev,
YT8531_PAD_DRIVE_STRENGTH_CFG_REG,
YT8531_RGMII_RXC_DS_MASK,
FIELD_PREP(YT8531_RGMII_RXC_DS_MASK, ds));
if (ret < 0)
return ret;

/* set rgmii rx data driver strength */
if (!ofnode_read_u32(phydev->node, "motorcomm,rx-data-drv-microamp", &val)) {
ds = yt8531_get_ds_map(phydev, val);
if (ds < 0) {
pr_warn("No matching current value was found.");
return -EINVAL;
}
} else {
ds = YT8531_RGMII_RX_DS_DEFAULT;
}

ds_field_hi = FIELD_GET(BIT(2), ds);
ds_field_hi = FIELD_PREP(YT8531_RGMII_RXD_DS_HI_MASK, ds_field_hi);

ds_field_low = FIELD_GET(GENMASK(1, 0), ds);
ds_field_low = FIELD_PREP(YT8531_RGMII_RXD_DS_LOW_MASK, ds_field_low);

ret = ytphy_modify_ext(phydev,
YT8531_PAD_DRIVE_STRENGTH_CFG_REG,
YT8531_RGMII_RXD_DS_LOW_MASK | YT8531_RGMII_RXD_DS_HI_MASK,
ds_field_low | ds_field_hi);
if (ret < 0)
return ret;

return 0;
}

static int yt8531_config(struct phy_device *phydev)
{
struct ytphy_plat_priv *priv = phydev->priv;
Expand Down Expand Up @@ -487,6 +613,10 @@ static int yt8531_config(struct phy_device *phydev)
return ret;
}

ret = yt8531_set_ds(phydev);
if (ret < 0)
return ret;

return 0;
}

Expand Down

0 comments on commit c025c8a

Please sign in to comment.