Skip to content

Commit 50675d8

Browse files
committed
Merge branch 'dsa-microchip-drive-strength-support'
Oleksij Rempel says: ==================== net: dsa: microchip: add drive strength support changes v5: - rename milliamp to microamp - do not expect negative error code on snprintf - set coma after last struct element - rename found to have_any_prop changes v4: - integrate microchip feedback to the ksz9477_drive_strengths comment. - add Reviewed-by: Rob Herring <[email protected]> changes v3: - yaml: use enum instead of min/max - do not use snprintf() on overlapping buffer. - unify ksz_drive_strength_to_reg() and ksz_drive_strength_error(). Make it usable for KSZ9477 and KSZ8830 variants. - use ksz_rmw8() in ksz9477_drive_strength_write() ==================== Signed-off-by: David S. Miller <[email protected]>
2 parents b6a7eeb + d67d724 commit 50675d8

File tree

5 files changed

+349
-27
lines changed

5 files changed

+349
-27
lines changed

Documentation/devicetree/bindings/net/dsa/microchip,ksz.yaml

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,26 @@ properties:
4949
Set if the output SYNCLKO clock should be disabled. Do not mix with
5050
microchip,synclko-125.
5151

52+
microchip,io-drive-strength-microamp:
53+
description:
54+
IO Pad Drive Strength
55+
enum: [8000, 16000]
56+
default: 16000
57+
58+
microchip,hi-drive-strength-microamp:
59+
description:
60+
High Speed Drive Strength. Controls drive strength of GMII / RGMII /
61+
MII / RMII (except TX_CLK/REFCLKI, COL and CRS) and CLKO_25_125 lines.
62+
enum: [2000, 4000, 8000, 12000, 16000, 20000, 24000, 28000]
63+
default: 24000
64+
65+
microchip,lo-drive-strength-microamp:
66+
description:
67+
Low Speed Drive Strength. Controls drive strength of TX_CLK / REFCLKI,
68+
COL, CRS, LEDs, PME_N, NTRP_N, SDO and SDI/SDA/MDIO lines.
69+
enum: [2000, 4000, 8000, 12000, 16000, 20000, 24000, 28000]
70+
default: 8000
71+
5272
interrupts:
5373
maxItems: 1
5474

drivers/net/dsa/microchip/ksz8795_reg.h

Lines changed: 0 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -442,20 +442,6 @@
442442
#define TOS_PRIO_M KS_PRIO_M
443443
#define TOS_PRIO_S KS_PRIO_S
444444

445-
#define REG_SW_CTRL_20 0xA3
446-
447-
#define SW_GMII_DRIVE_STRENGTH_S 4
448-
#define SW_DRIVE_STRENGTH_M 0x7
449-
#define SW_DRIVE_STRENGTH_2MA 0
450-
#define SW_DRIVE_STRENGTH_4MA 1
451-
#define SW_DRIVE_STRENGTH_8MA 2
452-
#define SW_DRIVE_STRENGTH_12MA 3
453-
#define SW_DRIVE_STRENGTH_16MA 4
454-
#define SW_DRIVE_STRENGTH_20MA 5
455-
#define SW_DRIVE_STRENGTH_24MA 6
456-
#define SW_DRIVE_STRENGTH_28MA 7
457-
#define SW_MII_DRIVE_STRENGTH_S 0
458-
459445
#define REG_SW_CTRL_21 0xA4
460446

461447
#define SW_IPV6_MLD_OPTION BIT(3)

drivers/net/dsa/microchip/ksz9477_reg.h

Lines changed: 0 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -112,19 +112,6 @@
112112

113113
#define REG_SW_IBA_SYNC__1 0x010C
114114

115-
#define REG_SW_IO_STRENGTH__1 0x010D
116-
#define SW_DRIVE_STRENGTH_M 0x7
117-
#define SW_DRIVE_STRENGTH_2MA 0
118-
#define SW_DRIVE_STRENGTH_4MA 1
119-
#define SW_DRIVE_STRENGTH_8MA 2
120-
#define SW_DRIVE_STRENGTH_12MA 3
121-
#define SW_DRIVE_STRENGTH_16MA 4
122-
#define SW_DRIVE_STRENGTH_20MA 5
123-
#define SW_DRIVE_STRENGTH_24MA 6
124-
#define SW_DRIVE_STRENGTH_28MA 7
125-
#define SW_HI_SPEED_DRIVE_STRENGTH_S 4
126-
#define SW_LO_SPEED_DRIVE_STRENGTH_S 0
127-
128115
#define REG_SW_IBA_STATUS__4 0x0110
129116

130117
#define SW_IBA_REQ BIT(31)

drivers/net/dsa/microchip/ksz_common.c

Lines changed: 309 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -186,6 +186,72 @@ static const struct ksz_mib_names ksz9477_mib_names[] = {
186186
{ 0x83, "tx_discards" },
187187
};
188188

189+
struct ksz_driver_strength_prop {
190+
const char *name;
191+
int offset;
192+
int value;
193+
};
194+
195+
enum ksz_driver_strength_type {
196+
KSZ_DRIVER_STRENGTH_HI,
197+
KSZ_DRIVER_STRENGTH_LO,
198+
KSZ_DRIVER_STRENGTH_IO,
199+
};
200+
201+
/**
202+
* struct ksz_drive_strength - drive strength mapping
203+
* @reg_val: register value
204+
* @microamp: microamp value
205+
*/
206+
struct ksz_drive_strength {
207+
u32 reg_val;
208+
u32 microamp;
209+
};
210+
211+
/* ksz9477_drive_strengths - Drive strength mapping for KSZ9477 variants
212+
*
213+
* This values are not documented in KSZ9477 variants but confirmed by
214+
* Microchip that KSZ9477, KSZ9567, KSZ8567, KSZ9897, KSZ9896, KSZ9563, KSZ9893
215+
* and KSZ8563 are using same register (drive strength) settings like KSZ8795.
216+
*
217+
* Documentation in KSZ8795CLX provides more information with some
218+
* recommendations:
219+
* - for high speed signals
220+
* 1. 4 mA or 8 mA is often used for MII, RMII, and SPI interface with using
221+
* 2.5V or 3.3V VDDIO.
222+
* 2. 12 mA or 16 mA is often used for MII, RMII, and SPI interface with
223+
* using 1.8V VDDIO.
224+
* 3. 20 mA or 24 mA is often used for GMII/RGMII interface with using 2.5V
225+
* or 3.3V VDDIO.
226+
* 4. 28 mA is often used for GMII/RGMII interface with using 1.8V VDDIO.
227+
* 5. In same interface, the heavy loading should use higher one of the
228+
* drive current strength.
229+
* - for low speed signals
230+
* 1. 3.3V VDDIO, use either 4 mA or 8 mA.
231+
* 2. 2.5V VDDIO, use either 8 mA or 12 mA.
232+
* 3. 1.8V VDDIO, use either 12 mA or 16 mA.
233+
* 4. If it is heavy loading, can use higher drive current strength.
234+
*/
235+
static const struct ksz_drive_strength ksz9477_drive_strengths[] = {
236+
{ SW_DRIVE_STRENGTH_2MA, 2000 },
237+
{ SW_DRIVE_STRENGTH_4MA, 4000 },
238+
{ SW_DRIVE_STRENGTH_8MA, 8000 },
239+
{ SW_DRIVE_STRENGTH_12MA, 12000 },
240+
{ SW_DRIVE_STRENGTH_16MA, 16000 },
241+
{ SW_DRIVE_STRENGTH_20MA, 20000 },
242+
{ SW_DRIVE_STRENGTH_24MA, 24000 },
243+
{ SW_DRIVE_STRENGTH_28MA, 28000 },
244+
};
245+
246+
/* ksz8830_drive_strengths - Drive strength mapping for KSZ8830, KSZ8873, ..
247+
* variants.
248+
* This values are documented in KSZ8873 and KSZ8863 datasheets.
249+
*/
250+
static const struct ksz_drive_strength ksz8830_drive_strengths[] = {
251+
{ 0, 8000 },
252+
{ KSZ8873_DRIVE_STRENGTH_16MA, 16000 },
253+
};
254+
189255
static const struct ksz_dev_ops ksz8_dev_ops = {
190256
.setup = ksz8_setup,
191257
.get_port_addr = ksz8_get_port_addr,
@@ -3530,6 +3596,245 @@ static void ksz_parse_rgmii_delay(struct ksz_device *dev, int port_num,
35303596
dev->ports[port_num].rgmii_tx_val = tx_delay;
35313597
}
35323598

3599+
/**
3600+
* ksz_drive_strength_to_reg() - Convert drive strength value to corresponding
3601+
* register value.
3602+
* @array: The array of drive strength values to search.
3603+
* @array_size: The size of the array.
3604+
* @microamp: The drive strength value in microamp to be converted.
3605+
*
3606+
* This function searches the array of drive strength values for the given
3607+
* microamp value and returns the corresponding register value for that drive.
3608+
*
3609+
* Returns: If found, the corresponding register value for that drive strength
3610+
* is returned. Otherwise, -EINVAL is returned indicating an invalid value.
3611+
*/
3612+
static int ksz_drive_strength_to_reg(const struct ksz_drive_strength *array,
3613+
size_t array_size, int microamp)
3614+
{
3615+
int i;
3616+
3617+
for (i = 0; i < array_size; i++) {
3618+
if (array[i].microamp == microamp)
3619+
return array[i].reg_val;
3620+
}
3621+
3622+
return -EINVAL;
3623+
}
3624+
3625+
/**
3626+
* ksz_drive_strength_error() - Report invalid drive strength value
3627+
* @dev: ksz device
3628+
* @array: The array of drive strength values to search.
3629+
* @array_size: The size of the array.
3630+
* @microamp: Invalid drive strength value in microamp
3631+
*
3632+
* This function logs an error message when an unsupported drive strength value
3633+
* is detected. It lists out all the supported drive strength values for
3634+
* reference in the error message.
3635+
*/
3636+
static void ksz_drive_strength_error(struct ksz_device *dev,
3637+
const struct ksz_drive_strength *array,
3638+
size_t array_size, int microamp)
3639+
{
3640+
char supported_values[100];
3641+
size_t remaining_size;
3642+
int added_len;
3643+
char *ptr;
3644+
int i;
3645+
3646+
remaining_size = sizeof(supported_values);
3647+
ptr = supported_values;
3648+
3649+
for (i = 0; i < array_size; i++) {
3650+
added_len = snprintf(ptr, remaining_size,
3651+
i == 0 ? "%d" : ", %d", array[i].microamp);
3652+
3653+
if (added_len >= remaining_size)
3654+
break;
3655+
3656+
ptr += added_len;
3657+
remaining_size -= added_len;
3658+
}
3659+
3660+
dev_err(dev->dev, "Invalid drive strength %d, supported values are %s\n",
3661+
microamp, supported_values);
3662+
}
3663+
3664+
/**
3665+
* ksz9477_drive_strength_write() - Set the drive strength for specific KSZ9477
3666+
* chip variants.
3667+
* @dev: ksz device
3668+
* @props: Array of drive strength properties to be applied
3669+
* @num_props: Number of properties in the array
3670+
*
3671+
* This function configures the drive strength for various KSZ9477 chip variants
3672+
* based on the provided properties. It handles chip-specific nuances and
3673+
* ensures only valid drive strengths are written to the respective chip.
3674+
*
3675+
* Return: 0 on successful configuration, a negative error code on failure.
3676+
*/
3677+
static int ksz9477_drive_strength_write(struct ksz_device *dev,
3678+
struct ksz_driver_strength_prop *props,
3679+
int num_props)
3680+
{
3681+
size_t array_size = ARRAY_SIZE(ksz9477_drive_strengths);
3682+
int i, ret, reg;
3683+
u8 mask = 0;
3684+
u8 val = 0;
3685+
3686+
if (props[KSZ_DRIVER_STRENGTH_IO].value != -1)
3687+
dev_warn(dev->dev, "%s is not supported by this chip variant\n",
3688+
props[KSZ_DRIVER_STRENGTH_IO].name);
3689+
3690+
if (dev->chip_id == KSZ8795_CHIP_ID ||
3691+
dev->chip_id == KSZ8794_CHIP_ID ||
3692+
dev->chip_id == KSZ8765_CHIP_ID)
3693+
reg = KSZ8795_REG_SW_CTRL_20;
3694+
else
3695+
reg = KSZ9477_REG_SW_IO_STRENGTH;
3696+
3697+
for (i = 0; i < num_props; i++) {
3698+
if (props[i].value == -1)
3699+
continue;
3700+
3701+
ret = ksz_drive_strength_to_reg(ksz9477_drive_strengths,
3702+
array_size, props[i].value);
3703+
if (ret < 0) {
3704+
ksz_drive_strength_error(dev, ksz9477_drive_strengths,
3705+
array_size, props[i].value);
3706+
return ret;
3707+
}
3708+
3709+
mask |= SW_DRIVE_STRENGTH_M << props[i].offset;
3710+
val |= ret << props[i].offset;
3711+
}
3712+
3713+
return ksz_rmw8(dev, reg, mask, val);
3714+
}
3715+
3716+
/**
3717+
* ksz8830_drive_strength_write() - Set the drive strength configuration for
3718+
* KSZ8830 compatible chip variants.
3719+
* @dev: ksz device
3720+
* @props: Array of drive strength properties to be set
3721+
* @num_props: Number of properties in the array
3722+
*
3723+
* This function applies the specified drive strength settings to KSZ8830 chip
3724+
* variants (KSZ8873, KSZ8863).
3725+
* It ensures the configurations align with what the chip variant supports and
3726+
* warns or errors out on unsupported settings.
3727+
*
3728+
* Return: 0 on success, error code otherwise
3729+
*/
3730+
static int ksz8830_drive_strength_write(struct ksz_device *dev,
3731+
struct ksz_driver_strength_prop *props,
3732+
int num_props)
3733+
{
3734+
size_t array_size = ARRAY_SIZE(ksz8830_drive_strengths);
3735+
int microamp;
3736+
int i, ret;
3737+
3738+
for (i = 0; i < num_props; i++) {
3739+
if (props[i].value == -1 || i == KSZ_DRIVER_STRENGTH_IO)
3740+
continue;
3741+
3742+
dev_warn(dev->dev, "%s is not supported by this chip variant\n",
3743+
props[i].name);
3744+
}
3745+
3746+
microamp = props[KSZ_DRIVER_STRENGTH_IO].value;
3747+
ret = ksz_drive_strength_to_reg(ksz8830_drive_strengths, array_size,
3748+
microamp);
3749+
if (ret < 0) {
3750+
ksz_drive_strength_error(dev, ksz8830_drive_strengths,
3751+
array_size, microamp);
3752+
return ret;
3753+
}
3754+
3755+
return ksz_rmw8(dev, KSZ8873_REG_GLOBAL_CTRL_12,
3756+
KSZ8873_DRIVE_STRENGTH_16MA, ret);
3757+
}
3758+
3759+
/**
3760+
* ksz_parse_drive_strength() - Extract and apply drive strength configurations
3761+
* from device tree properties.
3762+
* @dev: ksz device
3763+
*
3764+
* This function reads the specified drive strength properties from the
3765+
* device tree, validates against the supported chip variants, and sets
3766+
* them accordingly. An error should be critical here, as the drive strength
3767+
* settings are crucial for EMI compliance.
3768+
*
3769+
* Return: 0 on success, error code otherwise
3770+
*/
3771+
static int ksz_parse_drive_strength(struct ksz_device *dev)
3772+
{
3773+
struct ksz_driver_strength_prop of_props[] = {
3774+
[KSZ_DRIVER_STRENGTH_HI] = {
3775+
.name = "microchip,hi-drive-strength-microamp",
3776+
.offset = SW_HI_SPEED_DRIVE_STRENGTH_S,
3777+
.value = -1,
3778+
},
3779+
[KSZ_DRIVER_STRENGTH_LO] = {
3780+
.name = "microchip,lo-drive-strength-microamp",
3781+
.offset = SW_LO_SPEED_DRIVE_STRENGTH_S,
3782+
.value = -1,
3783+
},
3784+
[KSZ_DRIVER_STRENGTH_IO] = {
3785+
.name = "microchip,io-drive-strength-microamp",
3786+
.offset = 0, /* don't care */
3787+
.value = -1,
3788+
},
3789+
};
3790+
struct device_node *np = dev->dev->of_node;
3791+
bool have_any_prop = false;
3792+
int i, ret;
3793+
3794+
for (i = 0; i < ARRAY_SIZE(of_props); i++) {
3795+
ret = of_property_read_u32(np, of_props[i].name,
3796+
&of_props[i].value);
3797+
if (ret && ret != -EINVAL)
3798+
dev_warn(dev->dev, "Failed to read %s\n",
3799+
of_props[i].name);
3800+
if (ret)
3801+
continue;
3802+
3803+
have_any_prop = true;
3804+
}
3805+
3806+
if (!have_any_prop)
3807+
return 0;
3808+
3809+
switch (dev->chip_id) {
3810+
case KSZ8830_CHIP_ID:
3811+
return ksz8830_drive_strength_write(dev, of_props,
3812+
ARRAY_SIZE(of_props));
3813+
case KSZ8795_CHIP_ID:
3814+
case KSZ8794_CHIP_ID:
3815+
case KSZ8765_CHIP_ID:
3816+
case KSZ8563_CHIP_ID:
3817+
case KSZ9477_CHIP_ID:
3818+
case KSZ9563_CHIP_ID:
3819+
case KSZ9567_CHIP_ID:
3820+
case KSZ9893_CHIP_ID:
3821+
case KSZ9896_CHIP_ID:
3822+
case KSZ9897_CHIP_ID:
3823+
return ksz9477_drive_strength_write(dev, of_props,
3824+
ARRAY_SIZE(of_props));
3825+
default:
3826+
for (i = 0; i < ARRAY_SIZE(of_props); i++) {
3827+
if (of_props[i].value == -1)
3828+
continue;
3829+
3830+
dev_warn(dev->dev, "%s is not supported by this chip variant\n",
3831+
of_props[i].name);
3832+
}
3833+
}
3834+
3835+
return 0;
3836+
}
3837+
35333838
int ksz_switch_register(struct ksz_device *dev)
35343839
{
35353840
const struct ksz_chip_data *info;
@@ -3612,6 +3917,10 @@ int ksz_switch_register(struct ksz_device *dev)
36123917
for (port_num = 0; port_num < dev->info->port_cnt; ++port_num)
36133918
dev->ports[port_num].interface = PHY_INTERFACE_MODE_NA;
36143919
if (dev->dev->of_node) {
3920+
ret = ksz_parse_drive_strength(dev);
3921+
if (ret)
3922+
return ret;
3923+
36153924
ret = of_get_phy_mode(dev->dev->of_node, &interface);
36163925
if (ret == 0)
36173926
dev->compat_interface = interface;

0 commit comments

Comments
 (0)