Skip to content

Commit 926eae6

Browse files
Holger Brunckdavem330
authored andcommitted
dsa: mv88e6xxx: make serdes SGMII/Fiber tx amplitude configurable
The mv88e6352, mv88e6240 and mv88e6176 have a serdes interface. This patch allows to configure the output swing to a desired value in the phy-handle of the port. The value which is peak to peak has to be specified in microvolts. As the chips only supports eight dedicated values we return EINVAL if the value in the DTS does not match one of these values. Signed-off-by: Holger Brunck <[email protected]> Reviewed-by: Andrew Lunn <[email protected]> Reviewed-by: Marek Behún <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent 066c4b6 commit 926eae6

File tree

4 files changed

+70
-0
lines changed

4 files changed

+70
-0
lines changed

drivers/net/dsa/mv88e6xxx/chip.c

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2987,7 +2987,10 @@ static int mv88e6xxx_setup_upstream_port(struct mv88e6xxx_chip *chip, int port)
29872987

29882988
static int mv88e6xxx_setup_port(struct mv88e6xxx_chip *chip, int port)
29892989
{
2990+
struct device_node *phy_handle = NULL;
29902991
struct dsa_switch *ds = chip->ds;
2992+
struct dsa_port *dp;
2993+
int tx_amp;
29912994
int err;
29922995
u16 reg;
29932996

@@ -3178,6 +3181,23 @@ static int mv88e6xxx_setup_port(struct mv88e6xxx_chip *chip, int port)
31783181
return err;
31793182
}
31803183

3184+
if (chip->info->ops->serdes_set_tx_amplitude) {
3185+
dp = dsa_to_port(ds, port);
3186+
if (dp)
3187+
phy_handle = of_parse_phandle(dp->dn, "phy-handle", 0);
3188+
3189+
if (phy_handle && !of_property_read_u32(phy_handle,
3190+
"tx-p2p-microvolt",
3191+
&tx_amp))
3192+
err = chip->info->ops->serdes_set_tx_amplitude(chip,
3193+
port, tx_amp);
3194+
if (phy_handle) {
3195+
of_node_put(phy_handle);
3196+
if (err)
3197+
return err;
3198+
}
3199+
}
3200+
31813201
/* Port based VLAN map: give each port the same default address
31823202
* database, and allow bidirectional communication between the
31833203
* CPU and DSA port(s), and the other ports.
@@ -4246,6 +4266,7 @@ static const struct mv88e6xxx_ops mv88e6176_ops = {
42464266
.serdes_irq_status = mv88e6352_serdes_irq_status,
42474267
.serdes_get_regs_len = mv88e6352_serdes_get_regs_len,
42484268
.serdes_get_regs = mv88e6352_serdes_get_regs,
4269+
.serdes_set_tx_amplitude = mv88e6352_serdes_set_tx_amplitude,
42494270
.gpio_ops = &mv88e6352_gpio_ops,
42504271
.phylink_get_caps = mv88e6352_phylink_get_caps,
42514272
};
@@ -4526,6 +4547,7 @@ static const struct mv88e6xxx_ops mv88e6240_ops = {
45264547
.serdes_irq_status = mv88e6352_serdes_irq_status,
45274548
.serdes_get_regs_len = mv88e6352_serdes_get_regs_len,
45284549
.serdes_get_regs = mv88e6352_serdes_get_regs,
4550+
.serdes_set_tx_amplitude = mv88e6352_serdes_set_tx_amplitude,
45294551
.gpio_ops = &mv88e6352_gpio_ops,
45304552
.avb_ops = &mv88e6352_avb_ops,
45314553
.ptp_ops = &mv88e6352_ptp_ops,
@@ -4932,6 +4954,7 @@ static const struct mv88e6xxx_ops mv88e6352_ops = {
49324954
.serdes_get_stats = mv88e6352_serdes_get_stats,
49334955
.serdes_get_regs_len = mv88e6352_serdes_get_regs_len,
49344956
.serdes_get_regs = mv88e6352_serdes_get_regs,
4957+
.serdes_set_tx_amplitude = mv88e6352_serdes_set_tx_amplitude,
49354958
.phylink_get_caps = mv88e6352_phylink_get_caps,
49364959
};
49374960

drivers/net/dsa/mv88e6xxx/chip.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -588,6 +588,10 @@ struct mv88e6xxx_ops {
588588
void (*serdes_get_regs)(struct mv88e6xxx_chip *chip, int port,
589589
void *_p);
590590

591+
/* SERDES SGMII/Fiber Output Amplitude */
592+
int (*serdes_set_tx_amplitude)(struct mv88e6xxx_chip *chip, int port,
593+
int val);
594+
591595
/* Address Translation Unit operations */
592596
int (*atu_get_hash)(struct mv88e6xxx_chip *chip, u8 *hash);
593597
int (*atu_set_hash)(struct mv88e6xxx_chip *chip, u8 hash);

drivers/net/dsa/mv88e6xxx/serdes.c

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1313,6 +1313,44 @@ void mv88e6390_serdes_get_regs(struct mv88e6xxx_chip *chip, int port, void *_p)
13131313
}
13141314
}
13151315

1316+
static const int mv88e6352_serdes_p2p_to_reg[] = {
1317+
/* Index of value in microvolts corresponds to the register value */
1318+
14000, 112000, 210000, 308000, 406000, 504000, 602000, 700000,
1319+
};
1320+
1321+
int mv88e6352_serdes_set_tx_amplitude(struct mv88e6xxx_chip *chip, int port,
1322+
int val)
1323+
{
1324+
bool found = false;
1325+
u16 ctrl, reg;
1326+
int err;
1327+
int i;
1328+
1329+
err = mv88e6352_g2_scratch_port_has_serdes(chip, port);
1330+
if (err <= 0)
1331+
return err;
1332+
1333+
for (i = 0; i < ARRAY_SIZE(mv88e6352_serdes_p2p_to_reg); ++i) {
1334+
if (mv88e6352_serdes_p2p_to_reg[i] == val) {
1335+
reg = i;
1336+
found = true;
1337+
break;
1338+
}
1339+
}
1340+
1341+
if (!found)
1342+
return -EINVAL;
1343+
1344+
err = mv88e6352_serdes_read(chip, MV88E6352_SERDES_SPEC_CTRL2, &ctrl);
1345+
if (err)
1346+
return err;
1347+
1348+
ctrl &= ~MV88E6352_SERDES_OUT_AMP_MASK;
1349+
ctrl |= reg;
1350+
1351+
return mv88e6352_serdes_write(chip, MV88E6352_SERDES_SPEC_CTRL2, ctrl);
1352+
}
1353+
13161354
static int mv88e6393x_serdes_power_lane(struct mv88e6xxx_chip *chip, int lane,
13171355
bool on)
13181356
{

drivers/net/dsa/mv88e6xxx/serdes.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,8 @@
2727
#define MV88E6352_SERDES_INT_FIBRE_ENERGY BIT(4)
2828
#define MV88E6352_SERDES_INT_STATUS 0x13
2929

30+
#define MV88E6352_SERDES_SPEC_CTRL2 0x1a
31+
#define MV88E6352_SERDES_OUT_AMP_MASK 0x0007
3032

3133
#define MV88E6341_PORT5_LANE 0x15
3234

@@ -176,6 +178,9 @@ void mv88e6352_serdes_get_regs(struct mv88e6xxx_chip *chip, int port, void *_p);
176178
int mv88e6390_serdes_get_regs_len(struct mv88e6xxx_chip *chip, int port);
177179
void mv88e6390_serdes_get_regs(struct mv88e6xxx_chip *chip, int port, void *_p);
178180

181+
int mv88e6352_serdes_set_tx_amplitude(struct mv88e6xxx_chip *chip, int port,
182+
int val);
183+
179184
/* Return the (first) SERDES lane address a port is using, -errno otherwise. */
180185
static inline int mv88e6xxx_serdes_get_lane(struct mv88e6xxx_chip *chip,
181186
int port)

0 commit comments

Comments
 (0)