Commit 67a89767 authored by David S. Miller's avatar David S. Miller
Browse files

Merge branch 'phy-motorcomm-driver-strength'

Samin Guo says:

====================
Add motorcomm phy pad-driver-strength-cfg support

The motorcomm phy (YT8531) supports the ability to adjust the drive
strength of the rx_clk/rx_data, and the default strength may not be
suitable for all boards. So add configurable options to better match
the boards.(e.g. StarFive VisionFive 2)

The first patch adds a description of dt-bingding, and the second patch adds
YT8531's parsing and settings for pad-driver-strength-cfg.

Changes since v4:
Patch 1:
- Removed register-related DS(3b) values and added vol descriptions (by Andrew Lunn)
- Dropped the type and added '-microamp' suffix. (by Rob Herring)
Patch 2:
- Return -EINVAL if the value in DT but it is invalid (by Andrew Lunn)

Changes since v3:
Patch 1:
- Used current values instead of register values
- Added units and numerical descriptions of driver-strength
Patch 2:
- Added a lookup table to listing the valid values in the schema (by Andrew Lunn)

Changes since v2:
Patch 2:
- Readjusted the order of YT8531_RGMII_xxx to below YTPHY_PAD_DRIVE_STRENGTH_REG (by Frank Sae)
- Reversed Christmas tree, sort these longest first, shortest last (by Andrew Lunn)
- Rebased on tag v6.4

Changes since v1:
Patch 1:
- Renamed "rx-xxx-driver-strength" to "motorcomm,rx-xxx-driver-strength" (by Frank Sae)
Patch 2:
- Added default values for rxc/rxd driver strength (by Frank Sea/Andrew Lunn)
- Added range checking when val is in DT (by Frank Sea/Andrew Lunn)

Previous versions:
v1 - https://patchwork.kernel.org/project/netdevbpf/cover/20230426063541.15378-1-samin.guo@starfivetech.com
v2 - https://patchwork.kernel.org/project/netdevbpf/cover/20230505090558.2355-1-samin.guo@starfivetech.com
v3 - https://patchwork.kernel.org/project/netdevbpf/cover/20230526090502.29835-1-samin.guo@starfivetech.com
v4 - https://patchwork.kernel.org/project/netdevbpf/cover/20230714101406.17686-1-samin.guo@starfivetech.com


====================

Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents f5f80e32 7a561e93
Loading
Loading
Loading
Loading
+34 −0
Original line number Diff line number Diff line
@@ -52,6 +52,40 @@ properties:
      for a timer.
    type: boolean

  motorcomm,rx-clk-drv-microamp:
    description: |
      drive strength of rx_clk rgmii pad.
      The YT8531 RGMII LDO voltage supports 1.8V/3.3V, and the LDO voltage can
      be configured with hardware pull-up resistors to match the SOC voltage
      (usually 1.8V).
      The software can read the registers to obtain the LDO voltage and configure
      the legal drive strength(curren).
      =====================================================
      | voltage |        current Available (uA)           |
      |   1.8v  | 1200 2100 2700 2910 3110 3600 3970 4350 |
      |   3.3v  | 3070 4080 4370 4680 5020 5450 5740 6140 |
      =====================================================
    enum: [ 1200, 2100, 2700, 2910, 3070, 3110, 3600, 3970,
            4080, 4350, 4370, 4680, 5020, 5450, 5740, 6140 ]
    default: 2910

  motorcomm,rx-data-drv-microamp:
    description: |
      drive strength of rx_data/rx_ctl rgmii pad.
      The YT8531 RGMII LDO voltage supports 1.8V/3.3V, and the LDO voltage can
      be configured with hardware pull-up resistors to match the SOC voltage
      (usually 1.8V).
      The software can read the registers to obtain the LDO voltage and configure
      the legal drive strength(curren).
      =====================================================
      | voltage |        current Available (uA)           |
      |   1.8v  | 1200 2100 2700 2910 3110 3600 3970 4350 |
      |   3.3v  | 3070 4080 4370 4680 5020 5450 5740 6140 |
      =====================================================
    enum: [ 1200, 2100, 2700, 2910, 3070, 3110, 3600, 3970,
            4080, 4350, 4370, 4680, 5020, 5450, 5740, 6140 ]
    default: 2910

  motorcomm,tx-clk-adj-enabled:
    description: |
      This configuration is mainly to adapt to VF2 with JH7110 SoC.
+118 −0
Original line number Diff line number Diff line
@@ -163,6 +163,10 @@

#define YT8521_CHIP_CONFIG_REG			0xA001
#define YT8521_CCR_SW_RST			BIT(15)
#define YT8531_RGMII_LDO_VOL_MASK		GENMASK(5, 4)
#define YT8531_LDO_VOL_3V3			0x0
#define YT8531_LDO_VOL_1V8			0x2

/* 1b0 disable 1.9ns rxc clock delay  *default*
 * 1b1 enable 1.9ns rxc clock delay
 */
@@ -236,6 +240,12 @@
 */
#define YTPHY_WCR_TYPE_PULSE			BIT(0)

#define YTPHY_PAD_DRIVE_STRENGTH_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_SYNCE_CFG_REG			0xA012
#define YT8521_SCR_SYNCE_ENABLE			BIT(5)
/* 1b0 output 25m clock
@@ -834,6 +844,110 @@ static int ytphy_rgmii_clk_delay_config_with_lock(struct phy_device *phydev)
	return ret;
}

/**
 * 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_LDO_VOL_1V8, .ds = 0, .cur = 1200},
	{.vol = YT8531_LDO_VOL_1V8, .ds = 1, .cur = 2100},
	{.vol = YT8531_LDO_VOL_1V8, .ds = 2, .cur = 2700},
	{.vol = YT8531_LDO_VOL_1V8, .ds = 3, .cur = 2910},
	{.vol = YT8531_LDO_VOL_1V8, .ds = 4, .cur = 3110},
	{.vol = YT8531_LDO_VOL_1V8, .ds = 5, .cur = 3600},
	{.vol = YT8531_LDO_VOL_1V8, .ds = 6, .cur = 3970},
	{.vol = YT8531_LDO_VOL_1V8, .ds = 7, .cur = 4350},
	{.vol = YT8531_LDO_VOL_3V3, .ds = 0, .cur = 3070},
	{.vol = YT8531_LDO_VOL_3V3, .ds = 1, .cur = 4080},
	{.vol = YT8531_LDO_VOL_3V3, .ds = 2, .cur = 4370},
	{.vol = YT8531_LDO_VOL_3V3, .ds = 3, .cur = 4680},
	{.vol = YT8531_LDO_VOL_3V3, .ds = 4, .cur = 5020},
	{.vol = YT8531_LDO_VOL_3V3, .ds = 5, .cur = 5450},
	{.vol = YT8531_LDO_VOL_3V3, .ds = 6, .cur = 5740},
	{.vol = YT8531_LDO_VOL_3V3, .ds = 7, .cur = 6140},
};

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

	val = ytphy_read_ext_with_lock(phydev, YT8521_CHIP_CONFIG_REG);
	val = FIELD_GET(YT8531_RGMII_LDO_VOL_MASK, val);

	return val <= YT8531_LDO_VOL_1V8 ? val : YT8531_LDO_VOL_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)
{
	struct device_node *node = phydev->mdio.dev.of_node;
	u32 ds_field_low, ds_field_hi, val;
	int ret, ds;

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

	ret = ytphy_modify_ext_with_lock(phydev,
					 YTPHY_PAD_DRIVE_STRENGTH_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 (!of_property_read_u32(node, "motorcomm,rx-data-drv-microamp", &val)) {
		ds = yt8531_get_ds_map(phydev, val);
		if (ds < 0)
			return dev_err_probe(&phydev->mdio.dev, ds,
					     "No matching current value was found.\n");
	} 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_with_lock(phydev,
					 YTPHY_PAD_DRIVE_STRENGTH_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;
}

/**
 * yt8521_probe() - read chip config then set suitable polling_mode
 * @phydev: a pointer to a &struct phy_device
@@ -1518,6 +1632,10 @@ static int yt8531_config_init(struct phy_device *phydev)
			return ret;
	}

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

	return 0;
}