net: dsa: microchip: move the drive strength config out of the common section

The drive strength configuration is done during the setup of all
switches through a common function that then has specific behavior
depending on the switch identity.

Split the common configuration in two functions: one is dedicated to the
KSZ8 family, the other is dedicated to the KSZ9477 family.
Remove the drive strength configuration from the lan937x_setup since
the LAN937x family doesn't support it.

Signed-off-by: Bastien Curutchet (Schneider Electric) <bastien.curutchet@bootlin.com>
Link: https://patch.msgid.link/20260702-clean-ksz-4th-v1-10-93441e695fa4@bootlin.com
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
This commit is contained in:
Bastien Curutchet (Schneider Electric) 2026-07-02 11:07:32 +02:00 committed by Paolo Abeni
parent da466bf62b
commit 90c676dd4b
5 changed files with 218 additions and 170 deletions

View File

@ -36,6 +36,15 @@
#include "ksz8_reg.h"
#include "ksz8.h"
/* ksz88x3_drive_strengths - Drive strength mapping for KSZ8863, KSZ8873, ..
* variants.
* This values are documented in KSZ8873 and KSZ8863 datasheets.
*/
static const struct ksz_drive_strength ksz88x3_drive_strengths[] = {
{ 0, 8000 },
{ KSZ8873_DRIVE_STRENGTH_16MA, 16000 },
};
struct ksz88xx_stats_raw {
u64 rx;
u64 rx_hi;
@ -2291,6 +2300,122 @@ static void ksz88xx_r_mib_stats64(struct ksz_device *dev, int port)
spin_unlock(&mib->stats64_lock);
}
/**
* ksz88x3_drive_strength_write() - Set the drive strength configuration for
* KSZ8863 compatible chip variants.
* @dev: ksz device
* @props: Array of drive strength properties to be set
* @num_props: Number of properties in the array
*
* This function applies the specified drive strength settings to KSZ88X3 chip
* variants (KSZ8873, KSZ8863).
* It ensures the configurations align with what the chip variant supports and
* warns or errors out on unsupported settings.
*
* Return: 0 on success, error code otherwise
*/
static int ksz88x3_drive_strength_write(struct ksz_device *dev,
struct ksz_driver_strength_prop *props,
int num_props)
{
size_t array_size = ARRAY_SIZE(ksz88x3_drive_strengths);
int microamp;
int i, ret;
for (i = 0; i < num_props; i++) {
if (props[i].value == -1 || i == KSZ_DRIVER_STRENGTH_IO)
continue;
dev_warn(dev->dev, "%s is not supported by this chip variant\n",
props[i].name);
}
microamp = props[KSZ_DRIVER_STRENGTH_IO].value;
ret = ksz_drive_strength_to_reg(ksz88x3_drive_strengths, array_size,
microamp);
if (ret < 0) {
ksz_drive_strength_error(dev, ksz88x3_drive_strengths,
array_size, microamp);
return ret;
}
return ksz_rmw8(dev, KSZ8873_REG_GLOBAL_CTRL_12,
KSZ8873_DRIVE_STRENGTH_16MA, ret);
}
/**
* ksz8_parse_drive_strength() - Extract and apply drive strength configurations
* from device tree properties.
* @dev: ksz device
*
* This function reads the specified drive strength properties from the
* device tree, validates against the supported chip variants, and sets
* them accordingly. An error should be critical here, as the drive strength
* settings are crucial for EMI compliance.
*
* Return: 0 on success, error code otherwise
*/
static int ksz8_parse_drive_strength(struct ksz_device *dev)
{
struct ksz_driver_strength_prop of_props[] = {
[KSZ_DRIVER_STRENGTH_HI] = {
.name = "microchip,hi-drive-strength-microamp",
.offset = SW_HI_SPEED_DRIVE_STRENGTH_S,
.value = -1,
},
[KSZ_DRIVER_STRENGTH_LO] = {
.name = "microchip,lo-drive-strength-microamp",
.offset = SW_LO_SPEED_DRIVE_STRENGTH_S,
.value = -1,
},
[KSZ_DRIVER_STRENGTH_IO] = {
.name = "microchip,io-drive-strength-microamp",
.offset = 0, /* don't care */
.value = -1,
},
};
struct device_node *np = dev->dev->of_node;
bool have_any_prop = false;
int i, ret;
for (i = 0; i < ARRAY_SIZE(of_props); i++) {
ret = of_property_read_u32(np, of_props[i].name,
&of_props[i].value);
if (ret && ret != -EINVAL)
dev_warn(dev->dev, "Failed to read %s\n",
of_props[i].name);
if (ret)
continue;
have_any_prop = true;
}
if (!have_any_prop)
return 0;
switch (dev->chip_id) {
case KSZ88X3_CHIP_ID:
return ksz88x3_drive_strength_write(dev, of_props,
ARRAY_SIZE(of_props));
case KSZ8795_CHIP_ID:
case KSZ8794_CHIP_ID:
case KSZ8765_CHIP_ID:
return ksz_drive_strength_write(dev, of_props,
ARRAY_SIZE(of_props));
default:
/* KSZ8864, KSZ8895 */
for (i = 0; i < ARRAY_SIZE(of_props); i++) {
if (of_props[i].value == -1)
continue;
dev_warn(dev->dev, "%s is not supported by this chip variant\n",
of_props[i].name);
}
}
return 0;
}
static int ksz8_setup(struct dsa_switch *ds)
{
struct ksz_device *dev = ds->priv;
@ -2313,7 +2438,7 @@ static int ksz8_setup(struct dsa_switch *ds)
return ret;
}
ret = ksz_parse_drive_strength(dev);
ret = ksz8_parse_drive_strength(dev);
if (ret)
return ret;

View File

@ -1615,6 +1615,58 @@ int ksz9477_enable_stp_addr(struct ksz_device *dev)
return 0;
}
/**
* ksz9477_parse_drive_strength() - Extract and apply drive strength
* configurations from device tree properties.
* @dev: ksz device
*
* This function reads the specified drive strength properties from the
* device tree, validates against the supported chip variants, and sets
* them accordingly. An error should be critical here, as the drive strength
* settings are crucial for EMI compliance.
*
* Return: 0 on success, error code otherwise
*/
static int ksz9477_parse_drive_strength(struct ksz_device *dev)
{
struct ksz_driver_strength_prop of_props[] = {
[KSZ_DRIVER_STRENGTH_HI] = {
.name = "microchip,hi-drive-strength-microamp",
.offset = SW_HI_SPEED_DRIVE_STRENGTH_S,
.value = -1,
},
[KSZ_DRIVER_STRENGTH_LO] = {
.name = "microchip,lo-drive-strength-microamp",
.offset = SW_LO_SPEED_DRIVE_STRENGTH_S,
.value = -1,
},
[KSZ_DRIVER_STRENGTH_IO] = {
.name = "microchip,io-drive-strength-microamp",
.offset = 0, /* don't care */
.value = -1,
},
};
struct device_node *np = dev->dev->of_node;
bool have_any_prop = false;
int i, ret;
for (i = 0; i < ARRAY_SIZE(of_props); i++) {
ret = of_property_read_u32(np, of_props[i].name,
&of_props[i].value);
if (ret && ret != -EINVAL)
dev_warn(dev->dev, "Failed to read %s\n",
of_props[i].name);
if (ret)
continue;
have_any_prop = true;
}
if (!have_any_prop)
return 0;
return ksz_drive_strength_write(dev, of_props, ARRAY_SIZE(of_props));
}
static int ksz9477_setup(struct dsa_switch *ds)
{
struct ksz_device *dev = ds->priv;
@ -1637,7 +1689,7 @@ static int ksz9477_setup(struct dsa_switch *ds)
return ret;
}
ret = ksz_parse_drive_strength(dev);
ret = ksz9477_parse_drive_strength(dev);
if (ret)
return ret;

View File

@ -113,28 +113,6 @@ static const struct ksz_mib_names ksz9477_mib_names[] = {
{ 0x83, "tx_discards" },
};
struct ksz_driver_strength_prop {
const char *name;
int offset;
int value;
};
enum ksz_driver_strength_type {
KSZ_DRIVER_STRENGTH_HI,
KSZ_DRIVER_STRENGTH_LO,
KSZ_DRIVER_STRENGTH_IO,
};
/**
* struct ksz_drive_strength - drive strength mapping
* @reg_val: register value
* @microamp: microamp value
*/
struct ksz_drive_strength {
u32 reg_val;
u32 microamp;
};
/* ksz9477_drive_strengths - Drive strength mapping for KSZ9477 variants
*
* This values are not documented in KSZ9477 variants but confirmed by
@ -170,15 +148,6 @@ static const struct ksz_drive_strength ksz9477_drive_strengths[] = {
{ SW_DRIVE_STRENGTH_28MA, 28000 },
};
/* ksz88x3_drive_strengths - Drive strength mapping for KSZ8863, KSZ8873, ..
* variants.
* This values are documented in KSZ8873 and KSZ8863 datasheets.
*/
static const struct ksz_drive_strength ksz88x3_drive_strengths[] = {
{ 0, 8000 },
{ KSZ8873_DRIVE_STRENGTH_16MA, 16000 },
};
/**
* ksz_phylink_mac_disable_tx_lpi() - Callback to signal LPI support (Dummy)
* @config: phylink config structure
@ -3785,8 +3754,8 @@ static void ksz_parse_rgmii_delay(struct ksz_device *dev, int port_num,
* Returns: If found, the corresponding register value for that drive strength
* is returned. Otherwise, -EINVAL is returned indicating an invalid value.
*/
static int ksz_drive_strength_to_reg(const struct ksz_drive_strength *array,
size_t array_size, int microamp)
int ksz_drive_strength_to_reg(const struct ksz_drive_strength *array,
size_t array_size, int microamp)
{
int i;
@ -3809,9 +3778,9 @@ static int ksz_drive_strength_to_reg(const struct ksz_drive_strength *array,
* is detected. It lists out all the supported drive strength values for
* reference in the error message.
*/
static void ksz_drive_strength_error(struct ksz_device *dev,
const struct ksz_drive_strength *array,
size_t array_size, int microamp)
void ksz_drive_strength_error(struct ksz_device *dev,
const struct ksz_drive_strength *array,
size_t array_size, int microamp)
{
char supported_values[100];
size_t remaining_size;
@ -3850,9 +3819,9 @@ static void ksz_drive_strength_error(struct ksz_device *dev,
*
* Return: 0 on successful configuration, a negative error code on failure.
*/
static int ksz_drive_strength_write(struct ksz_device *dev,
struct ksz_driver_strength_prop *props,
int num_props)
int ksz_drive_strength_write(struct ksz_device *dev,
struct ksz_driver_strength_prop *props,
int num_props)
{
size_t array_size = ARRAY_SIZE(ksz9477_drive_strengths);
int i, ret, reg;
@ -3889,130 +3858,6 @@ static int ksz_drive_strength_write(struct ksz_device *dev,
return ksz_rmw8(dev, reg, mask, val);
}
/**
* ksz88x3_drive_strength_write() - Set the drive strength configuration for
* KSZ8863 compatible chip variants.
* @dev: ksz device
* @props: Array of drive strength properties to be set
* @num_props: Number of properties in the array
*
* This function applies the specified drive strength settings to KSZ88X3 chip
* variants (KSZ8873, KSZ8863).
* It ensures the configurations align with what the chip variant supports and
* warns or errors out on unsupported settings.
*
* Return: 0 on success, error code otherwise
*/
static int ksz88x3_drive_strength_write(struct ksz_device *dev,
struct ksz_driver_strength_prop *props,
int num_props)
{
size_t array_size = ARRAY_SIZE(ksz88x3_drive_strengths);
int microamp;
int i, ret;
for (i = 0; i < num_props; i++) {
if (props[i].value == -1 || i == KSZ_DRIVER_STRENGTH_IO)
continue;
dev_warn(dev->dev, "%s is not supported by this chip variant\n",
props[i].name);
}
microamp = props[KSZ_DRIVER_STRENGTH_IO].value;
ret = ksz_drive_strength_to_reg(ksz88x3_drive_strengths, array_size,
microamp);
if (ret < 0) {
ksz_drive_strength_error(dev, ksz88x3_drive_strengths,
array_size, microamp);
return ret;
}
return ksz_rmw8(dev, KSZ8873_REG_GLOBAL_CTRL_12,
KSZ8873_DRIVE_STRENGTH_16MA, ret);
}
/**
* ksz_parse_drive_strength() - Extract and apply drive strength configurations
* from device tree properties.
* @dev: ksz device
*
* This function reads the specified drive strength properties from the
* device tree, validates against the supported chip variants, and sets
* them accordingly. An error should be critical here, as the drive strength
* settings are crucial for EMI compliance.
*
* Return: 0 on success, error code otherwise
*/
int ksz_parse_drive_strength(struct ksz_device *dev)
{
struct ksz_driver_strength_prop of_props[] = {
[KSZ_DRIVER_STRENGTH_HI] = {
.name = "microchip,hi-drive-strength-microamp",
.offset = SW_HI_SPEED_DRIVE_STRENGTH_S,
.value = -1,
},
[KSZ_DRIVER_STRENGTH_LO] = {
.name = "microchip,lo-drive-strength-microamp",
.offset = SW_LO_SPEED_DRIVE_STRENGTH_S,
.value = -1,
},
[KSZ_DRIVER_STRENGTH_IO] = {
.name = "microchip,io-drive-strength-microamp",
.offset = 0, /* don't care */
.value = -1,
},
};
struct device_node *np = dev->dev->of_node;
bool have_any_prop = false;
int i, ret;
for (i = 0; i < ARRAY_SIZE(of_props); i++) {
ret = of_property_read_u32(np, of_props[i].name,
&of_props[i].value);
if (ret && ret != -EINVAL)
dev_warn(dev->dev, "Failed to read %s\n",
of_props[i].name);
if (ret)
continue;
have_any_prop = true;
}
if (!have_any_prop)
return 0;
switch (dev->chip_id) {
case KSZ88X3_CHIP_ID:
return ksz88x3_drive_strength_write(dev, of_props,
ARRAY_SIZE(of_props));
case KSZ8795_CHIP_ID:
case KSZ8794_CHIP_ID:
case KSZ8765_CHIP_ID:
case KSZ8563_CHIP_ID:
case KSZ8567_CHIP_ID:
case KSZ9477_CHIP_ID:
case KSZ9563_CHIP_ID:
case KSZ9567_CHIP_ID:
case KSZ9893_CHIP_ID:
case KSZ9896_CHIP_ID:
case KSZ9897_CHIP_ID:
case LAN9646_CHIP_ID:
return ksz_drive_strength_write(dev, of_props,
ARRAY_SIZE(of_props));
default:
for (i = 0; i < ARRAY_SIZE(of_props); i++) {
if (of_props[i].value == -1)
continue;
dev_warn(dev->dev, "%s is not supported by this chip variant\n",
of_props[i].name);
}
}
return 0;
}
static int ksz8463_configure_straps_spi(struct ksz_device *dev)
{
struct pinctrl *pinctrl;

View File

@ -511,7 +511,37 @@ int ksz_mdio_register(struct ksz_device *dev);
int ksz_pirq_setup(struct ksz_device *dev, u8 p);
int ksz_girq_setup(struct ksz_device *dev);
void ksz_irq_free(struct ksz_irq *kirq);
int ksz_parse_drive_strength(struct ksz_device *dev);
struct ksz_driver_strength_prop {
const char *name;
int offset;
int value;
};
enum ksz_driver_strength_type {
KSZ_DRIVER_STRENGTH_HI,
KSZ_DRIVER_STRENGTH_LO,
KSZ_DRIVER_STRENGTH_IO,
};
/**
* struct ksz_drive_strength - drive strength mapping
* @reg_val: register value
* @microamp: microamp value
*/
struct ksz_drive_strength {
u32 reg_val;
u32 microamp;
};
void ksz_drive_strength_error(struct ksz_device *dev,
const struct ksz_drive_strength *array,
size_t array_size, int microamp);
int ksz_drive_strength_to_reg(const struct ksz_drive_strength *array,
size_t array_size, int microamp);
int ksz_drive_strength_write(struct ksz_device *dev,
struct ksz_driver_strength_prop *props,
int num_props);
/* Common register access functions */
static inline struct regmap *ksz_regmap_8(struct ksz_device *dev)

View File

@ -787,10 +787,6 @@ static int lan937x_setup(struct dsa_switch *ds)
return ret;
}
ret = ksz_parse_drive_strength(dev);
if (ret)
return ret;
/* set broadcast storm protection 10% rate */
storm_mask = BROADCAST_STORM_RATE;
storm_rate = (BROADCAST_STORM_VALUE * BROADCAST_STORM_PROT_RATE) / 100;