16d91782fSAndrew Lunn /* 26d91782fSAndrew Lunn * Marvell 88E6xxx SERDES manipulation, via SMI bus 36d91782fSAndrew Lunn * 46d91782fSAndrew Lunn * Copyright (c) 2008 Marvell Semiconductor 56d91782fSAndrew Lunn * 66d91782fSAndrew Lunn * Copyright (c) 2017 Andrew Lunn <andrew@lunn.ch> 76d91782fSAndrew Lunn * 86d91782fSAndrew Lunn * This program is free software; you can redistribute it and/or modify 96d91782fSAndrew Lunn * it under the terms of the GNU General Public License as published by 106d91782fSAndrew Lunn * the Free Software Foundation; either version 2 of the License, or 116d91782fSAndrew Lunn * (at your option) any later version. 126d91782fSAndrew Lunn */ 136d91782fSAndrew Lunn 146d91782fSAndrew Lunn #include <linux/mii.h> 156d91782fSAndrew Lunn 164d5f2ba7SVivien Didelot #include "chip.h" 176335e9f2SAndrew Lunn #include "global2.h" 186d91782fSAndrew Lunn #include "phy.h" 196d91782fSAndrew Lunn #include "port.h" 206d91782fSAndrew Lunn #include "serdes.h" 216d91782fSAndrew Lunn 226d91782fSAndrew Lunn static int mv88e6352_serdes_read(struct mv88e6xxx_chip *chip, int reg, 236d91782fSAndrew Lunn u16 *val) 246d91782fSAndrew Lunn { 256d91782fSAndrew Lunn return mv88e6xxx_phy_page_read(chip, MV88E6352_ADDR_SERDES, 266d91782fSAndrew Lunn MV88E6352_SERDES_PAGE_FIBER, 276d91782fSAndrew Lunn reg, val); 286d91782fSAndrew Lunn } 296d91782fSAndrew Lunn 306d91782fSAndrew Lunn static int mv88e6352_serdes_write(struct mv88e6xxx_chip *chip, int reg, 316d91782fSAndrew Lunn u16 val) 326d91782fSAndrew Lunn { 336d91782fSAndrew Lunn return mv88e6xxx_phy_page_write(chip, MV88E6352_ADDR_SERDES, 346d91782fSAndrew Lunn MV88E6352_SERDES_PAGE_FIBER, 356d91782fSAndrew Lunn reg, val); 366d91782fSAndrew Lunn } 376d91782fSAndrew Lunn 386d91782fSAndrew Lunn static int mv88e6352_serdes_power_set(struct mv88e6xxx_chip *chip, bool on) 396d91782fSAndrew Lunn { 406d91782fSAndrew Lunn u16 val, new_val; 416d91782fSAndrew Lunn int err; 426d91782fSAndrew Lunn 436d91782fSAndrew Lunn err = mv88e6352_serdes_read(chip, MII_BMCR, &val); 446d91782fSAndrew Lunn if (err) 456d91782fSAndrew Lunn return err; 466d91782fSAndrew Lunn 476d91782fSAndrew Lunn if (on) 486d91782fSAndrew Lunn new_val = val & ~BMCR_PDOWN; 496d91782fSAndrew Lunn else 506d91782fSAndrew Lunn new_val = val | BMCR_PDOWN; 516d91782fSAndrew Lunn 526d91782fSAndrew Lunn if (val != new_val) 536d91782fSAndrew Lunn err = mv88e6352_serdes_write(chip, MII_BMCR, new_val); 546d91782fSAndrew Lunn 556d91782fSAndrew Lunn return err; 566d91782fSAndrew Lunn } 576d91782fSAndrew Lunn 58eb755c3fSAndrew Lunn static bool mv88e6352_port_has_serdes(struct mv88e6xxx_chip *chip, int port) 596d91782fSAndrew Lunn { 606d91782fSAndrew Lunn u8 cmode; 61eb755c3fSAndrew Lunn int err; 626d91782fSAndrew Lunn 636d91782fSAndrew Lunn err = mv88e6xxx_port_get_cmode(chip, port, &cmode); 64eb755c3fSAndrew Lunn if (err) { 65eb755c3fSAndrew Lunn dev_err(chip->dev, "failed to read cmode\n"); 66b1312b85SFengguang Wu return false; 67eb755c3fSAndrew Lunn } 686d91782fSAndrew Lunn 695f83dc93SVivien Didelot if ((cmode == MV88E6XXX_PORT_STS_CMODE_100BASE_X) || 705f83dc93SVivien Didelot (cmode == MV88E6XXX_PORT_STS_CMODE_1000BASE_X) || 71eb755c3fSAndrew Lunn (cmode == MV88E6XXX_PORT_STS_CMODE_SGMII)) 72b1312b85SFengguang Wu return true; 73eb755c3fSAndrew Lunn 74b1312b85SFengguang Wu return false; 75eb755c3fSAndrew Lunn } 76eb755c3fSAndrew Lunn 77eb755c3fSAndrew Lunn int mv88e6352_serdes_power(struct mv88e6xxx_chip *chip, int port, bool on) 78eb755c3fSAndrew Lunn { 79eb755c3fSAndrew Lunn int err; 80eb755c3fSAndrew Lunn 81eb755c3fSAndrew Lunn if (mv88e6352_port_has_serdes(chip, port)) { 826d91782fSAndrew Lunn err = mv88e6352_serdes_power_set(chip, on); 836d91782fSAndrew Lunn if (err < 0) 846d91782fSAndrew Lunn return err; 856d91782fSAndrew Lunn } 866d91782fSAndrew Lunn 876d91782fSAndrew Lunn return 0; 886d91782fSAndrew Lunn } 896335e9f2SAndrew Lunn 90cda9f4aaSAndrew Lunn struct mv88e6352_serdes_hw_stat { 91cda9f4aaSAndrew Lunn char string[ETH_GSTRING_LEN]; 92cda9f4aaSAndrew Lunn int sizeof_stat; 93cda9f4aaSAndrew Lunn int reg; 94cda9f4aaSAndrew Lunn }; 95cda9f4aaSAndrew Lunn 96cda9f4aaSAndrew Lunn static struct mv88e6352_serdes_hw_stat mv88e6352_serdes_hw_stats[] = { 97cda9f4aaSAndrew Lunn { "serdes_fibre_rx_error", 16, 21 }, 98cda9f4aaSAndrew Lunn { "serdes_PRBS_error", 32, 24 }, 99cda9f4aaSAndrew Lunn }; 100cda9f4aaSAndrew Lunn 101cda9f4aaSAndrew Lunn int mv88e6352_serdes_get_sset_count(struct mv88e6xxx_chip *chip, int port) 102cda9f4aaSAndrew Lunn { 103cda9f4aaSAndrew Lunn if (mv88e6352_port_has_serdes(chip, port)) 104cda9f4aaSAndrew Lunn return ARRAY_SIZE(mv88e6352_serdes_hw_stats); 105cda9f4aaSAndrew Lunn 106cda9f4aaSAndrew Lunn return 0; 107cda9f4aaSAndrew Lunn } 108cda9f4aaSAndrew Lunn 10965f60e45SAndrew Lunn int mv88e6352_serdes_get_strings(struct mv88e6xxx_chip *chip, 110cda9f4aaSAndrew Lunn int port, uint8_t *data) 111cda9f4aaSAndrew Lunn { 112cda9f4aaSAndrew Lunn struct mv88e6352_serdes_hw_stat *stat; 113cda9f4aaSAndrew Lunn int i; 114cda9f4aaSAndrew Lunn 115cda9f4aaSAndrew Lunn if (!mv88e6352_port_has_serdes(chip, port)) 11665f60e45SAndrew Lunn return 0; 117cda9f4aaSAndrew Lunn 118cda9f4aaSAndrew Lunn for (i = 0; i < ARRAY_SIZE(mv88e6352_serdes_hw_stats); i++) { 119cda9f4aaSAndrew Lunn stat = &mv88e6352_serdes_hw_stats[i]; 120cda9f4aaSAndrew Lunn memcpy(data + i * ETH_GSTRING_LEN, stat->string, 121cda9f4aaSAndrew Lunn ETH_GSTRING_LEN); 122cda9f4aaSAndrew Lunn } 12365f60e45SAndrew Lunn return ARRAY_SIZE(mv88e6352_serdes_hw_stats); 124cda9f4aaSAndrew Lunn } 125cda9f4aaSAndrew Lunn 126cda9f4aaSAndrew Lunn static uint64_t mv88e6352_serdes_get_stat(struct mv88e6xxx_chip *chip, 127cda9f4aaSAndrew Lunn struct mv88e6352_serdes_hw_stat *stat) 128cda9f4aaSAndrew Lunn { 129cda9f4aaSAndrew Lunn u64 val = 0; 130cda9f4aaSAndrew Lunn u16 reg; 131cda9f4aaSAndrew Lunn int err; 132cda9f4aaSAndrew Lunn 133cda9f4aaSAndrew Lunn err = mv88e6352_serdes_read(chip, stat->reg, ®); 134cda9f4aaSAndrew Lunn if (err) { 135cda9f4aaSAndrew Lunn dev_err(chip->dev, "failed to read statistic\n"); 136cda9f4aaSAndrew Lunn return 0; 137cda9f4aaSAndrew Lunn } 138cda9f4aaSAndrew Lunn 139cda9f4aaSAndrew Lunn val = reg; 140cda9f4aaSAndrew Lunn 141cda9f4aaSAndrew Lunn if (stat->sizeof_stat == 32) { 142cda9f4aaSAndrew Lunn err = mv88e6352_serdes_read(chip, stat->reg + 1, ®); 143cda9f4aaSAndrew Lunn if (err) { 144cda9f4aaSAndrew Lunn dev_err(chip->dev, "failed to read statistic\n"); 145cda9f4aaSAndrew Lunn return 0; 146cda9f4aaSAndrew Lunn } 147cda9f4aaSAndrew Lunn val = val << 16 | reg; 148cda9f4aaSAndrew Lunn } 149cda9f4aaSAndrew Lunn 150cda9f4aaSAndrew Lunn return val; 151cda9f4aaSAndrew Lunn } 152cda9f4aaSAndrew Lunn 15365f60e45SAndrew Lunn int mv88e6352_serdes_get_stats(struct mv88e6xxx_chip *chip, int port, 154cda9f4aaSAndrew Lunn uint64_t *data) 155cda9f4aaSAndrew Lunn { 156cda9f4aaSAndrew Lunn struct mv88e6xxx_port *mv88e6xxx_port = &chip->ports[port]; 157cda9f4aaSAndrew Lunn struct mv88e6352_serdes_hw_stat *stat; 158cda9f4aaSAndrew Lunn u64 value; 159cda9f4aaSAndrew Lunn int i; 160cda9f4aaSAndrew Lunn 161cda9f4aaSAndrew Lunn if (!mv88e6352_port_has_serdes(chip, port)) 16265f60e45SAndrew Lunn return 0; 163cda9f4aaSAndrew Lunn 164cda9f4aaSAndrew Lunn BUILD_BUG_ON(ARRAY_SIZE(mv88e6352_serdes_hw_stats) > 165cda9f4aaSAndrew Lunn ARRAY_SIZE(mv88e6xxx_port->serdes_stats)); 166cda9f4aaSAndrew Lunn 167cda9f4aaSAndrew Lunn for (i = 0; i < ARRAY_SIZE(mv88e6352_serdes_hw_stats); i++) { 168cda9f4aaSAndrew Lunn stat = &mv88e6352_serdes_hw_stats[i]; 169cda9f4aaSAndrew Lunn value = mv88e6352_serdes_get_stat(chip, stat); 170cda9f4aaSAndrew Lunn mv88e6xxx_port->serdes_stats[i] += value; 171cda9f4aaSAndrew Lunn data[i] = mv88e6xxx_port->serdes_stats[i]; 172cda9f4aaSAndrew Lunn } 17365f60e45SAndrew Lunn 17465f60e45SAndrew Lunn return ARRAY_SIZE(mv88e6352_serdes_hw_stats); 175cda9f4aaSAndrew Lunn } 176cda9f4aaSAndrew Lunn 177a8c01c0dSAndrew Lunn /* Return the SERDES lane address a port is using. Ports 9 and 10 can 178a8c01c0dSAndrew Lunn * use multiple lanes. If so, return the first lane the port uses. 179a8c01c0dSAndrew Lunn * Returns -ENODEV if a port does not have a lane. 180a8c01c0dSAndrew Lunn */ 181a8c01c0dSAndrew Lunn static int mv88e6390_serdes_get_lane(struct mv88e6xxx_chip *chip, int port) 182a8c01c0dSAndrew Lunn { 183a8c01c0dSAndrew Lunn u8 cmode_port9, cmode_port10, cmode_port; 184a8c01c0dSAndrew Lunn int err; 185a8c01c0dSAndrew Lunn 186a8c01c0dSAndrew Lunn err = mv88e6xxx_port_get_cmode(chip, 9, &cmode_port9); 187a8c01c0dSAndrew Lunn if (err) 188a8c01c0dSAndrew Lunn return err; 189a8c01c0dSAndrew Lunn 190a8c01c0dSAndrew Lunn err = mv88e6xxx_port_get_cmode(chip, 10, &cmode_port10); 191a8c01c0dSAndrew Lunn if (err) 192a8c01c0dSAndrew Lunn return err; 193a8c01c0dSAndrew Lunn 194a8c01c0dSAndrew Lunn err = mv88e6xxx_port_get_cmode(chip, port, &cmode_port); 195a8c01c0dSAndrew Lunn if (err) 196a8c01c0dSAndrew Lunn return err; 197a8c01c0dSAndrew Lunn 198a8c01c0dSAndrew Lunn switch (port) { 199a8c01c0dSAndrew Lunn case 2: 200a8c01c0dSAndrew Lunn if (cmode_port9 == MV88E6XXX_PORT_STS_CMODE_1000BASE_X || 201a8c01c0dSAndrew Lunn cmode_port9 == MV88E6XXX_PORT_STS_CMODE_SGMII || 202a8c01c0dSAndrew Lunn cmode_port9 == MV88E6XXX_PORT_STS_CMODE_2500BASEX) 203a8c01c0dSAndrew Lunn if (cmode_port == MV88E6XXX_PORT_STS_CMODE_1000BASE_X) 204a8c01c0dSAndrew Lunn return MV88E6390_PORT9_LANE1; 205a8c01c0dSAndrew Lunn return -ENODEV; 206a8c01c0dSAndrew Lunn case 3: 207a8c01c0dSAndrew Lunn if (cmode_port9 == MV88E6XXX_PORT_STS_CMODE_1000BASE_X || 208a8c01c0dSAndrew Lunn cmode_port9 == MV88E6XXX_PORT_STS_CMODE_SGMII || 209a8c01c0dSAndrew Lunn cmode_port9 == MV88E6XXX_PORT_STS_CMODE_2500BASEX || 210a8c01c0dSAndrew Lunn cmode_port9 == MV88E6XXX_PORT_STS_CMODE_RXAUI) 211a8c01c0dSAndrew Lunn if (cmode_port == MV88E6XXX_PORT_STS_CMODE_1000BASE_X) 212a8c01c0dSAndrew Lunn return MV88E6390_PORT9_LANE2; 213a8c01c0dSAndrew Lunn return -ENODEV; 214a8c01c0dSAndrew Lunn case 4: 215a8c01c0dSAndrew Lunn if (cmode_port9 == MV88E6XXX_PORT_STS_CMODE_1000BASE_X || 216a8c01c0dSAndrew Lunn cmode_port9 == MV88E6XXX_PORT_STS_CMODE_SGMII || 217a8c01c0dSAndrew Lunn cmode_port9 == MV88E6XXX_PORT_STS_CMODE_2500BASEX || 218a8c01c0dSAndrew Lunn cmode_port9 == MV88E6XXX_PORT_STS_CMODE_RXAUI) 219a8c01c0dSAndrew Lunn if (cmode_port == MV88E6XXX_PORT_STS_CMODE_1000BASE_X) 220a8c01c0dSAndrew Lunn return MV88E6390_PORT9_LANE3; 221a8c01c0dSAndrew Lunn return -ENODEV; 222a8c01c0dSAndrew Lunn case 5: 223a8c01c0dSAndrew Lunn if (cmode_port10 == MV88E6XXX_PORT_STS_CMODE_1000BASE_X || 224a8c01c0dSAndrew Lunn cmode_port10 == MV88E6XXX_PORT_STS_CMODE_SGMII || 225a8c01c0dSAndrew Lunn cmode_port10 == MV88E6XXX_PORT_STS_CMODE_2500BASEX) 226a8c01c0dSAndrew Lunn if (cmode_port == MV88E6XXX_PORT_STS_CMODE_1000BASE_X) 227a8c01c0dSAndrew Lunn return MV88E6390_PORT10_LANE1; 228a8c01c0dSAndrew Lunn return -ENODEV; 229a8c01c0dSAndrew Lunn case 6: 230a8c01c0dSAndrew Lunn if (cmode_port10 == MV88E6XXX_PORT_STS_CMODE_1000BASE_X || 231a8c01c0dSAndrew Lunn cmode_port10 == MV88E6XXX_PORT_STS_CMODE_SGMII || 232a8c01c0dSAndrew Lunn cmode_port10 == MV88E6XXX_PORT_STS_CMODE_2500BASEX || 233a8c01c0dSAndrew Lunn cmode_port10 == MV88E6XXX_PORT_STS_CMODE_RXAUI) 234a8c01c0dSAndrew Lunn if (cmode_port == MV88E6XXX_PORT_STS_CMODE_1000BASE_X) 235a8c01c0dSAndrew Lunn return MV88E6390_PORT10_LANE2; 236a8c01c0dSAndrew Lunn return -ENODEV; 237a8c01c0dSAndrew Lunn case 7: 238a8c01c0dSAndrew Lunn if (cmode_port10 == MV88E6XXX_PORT_STS_CMODE_1000BASE_X || 239a8c01c0dSAndrew Lunn cmode_port10 == MV88E6XXX_PORT_STS_CMODE_SGMII || 240a8c01c0dSAndrew Lunn cmode_port10 == MV88E6XXX_PORT_STS_CMODE_2500BASEX || 241a8c01c0dSAndrew Lunn cmode_port10 == MV88E6XXX_PORT_STS_CMODE_RXAUI) 242a8c01c0dSAndrew Lunn if (cmode_port == MV88E6XXX_PORT_STS_CMODE_1000BASE_X) 243a8c01c0dSAndrew Lunn return MV88E6390_PORT10_LANE3; 244a8c01c0dSAndrew Lunn return -ENODEV; 245a8c01c0dSAndrew Lunn case 9: 246a8c01c0dSAndrew Lunn if (cmode_port9 == MV88E6XXX_PORT_STS_CMODE_1000BASE_X || 247a8c01c0dSAndrew Lunn cmode_port9 == MV88E6XXX_PORT_STS_CMODE_SGMII || 248a8c01c0dSAndrew Lunn cmode_port9 == MV88E6XXX_PORT_STS_CMODE_2500BASEX || 249a8c01c0dSAndrew Lunn cmode_port9 == MV88E6XXX_PORT_STS_CMODE_XAUI || 250a8c01c0dSAndrew Lunn cmode_port9 == MV88E6XXX_PORT_STS_CMODE_RXAUI) 251a8c01c0dSAndrew Lunn return MV88E6390_PORT9_LANE0; 252a8c01c0dSAndrew Lunn return -ENODEV; 253a8c01c0dSAndrew Lunn case 10: 254a8c01c0dSAndrew Lunn if (cmode_port10 == MV88E6XXX_PORT_STS_CMODE_1000BASE_X || 255a8c01c0dSAndrew Lunn cmode_port10 == MV88E6XXX_PORT_STS_CMODE_SGMII || 256a8c01c0dSAndrew Lunn cmode_port10 == MV88E6XXX_PORT_STS_CMODE_2500BASEX || 257a8c01c0dSAndrew Lunn cmode_port10 == MV88E6XXX_PORT_STS_CMODE_XAUI || 258a8c01c0dSAndrew Lunn cmode_port10 == MV88E6XXX_PORT_STS_CMODE_RXAUI) 259a8c01c0dSAndrew Lunn return MV88E6390_PORT10_LANE0; 260a8c01c0dSAndrew Lunn return -ENODEV; 261a8c01c0dSAndrew Lunn default: 262a8c01c0dSAndrew Lunn return -ENODEV; 263a8c01c0dSAndrew Lunn } 264a8c01c0dSAndrew Lunn } 265a8c01c0dSAndrew Lunn 2666335e9f2SAndrew Lunn /* Set the power on/off for 10GBASE-R and 10GBASE-X4/X2 */ 267a8c01c0dSAndrew Lunn static int mv88e6390_serdes_10g(struct mv88e6xxx_chip *chip, int lane, bool on) 2686335e9f2SAndrew Lunn { 2696335e9f2SAndrew Lunn u16 val, new_val; 2706335e9f2SAndrew Lunn int reg_c45; 2716335e9f2SAndrew Lunn int err; 2726335e9f2SAndrew Lunn 2736335e9f2SAndrew Lunn reg_c45 = MII_ADDR_C45 | MV88E6390_SERDES_DEVICE | 2746335e9f2SAndrew Lunn MV88E6390_PCS_CONTROL_1; 275a8c01c0dSAndrew Lunn err = mv88e6xxx_phy_read(chip, lane, reg_c45, &val); 2766335e9f2SAndrew Lunn if (err) 2776335e9f2SAndrew Lunn return err; 2786335e9f2SAndrew Lunn 2796335e9f2SAndrew Lunn if (on) 2806335e9f2SAndrew Lunn new_val = val & ~(MV88E6390_PCS_CONTROL_1_RESET | 2816335e9f2SAndrew Lunn MV88E6390_PCS_CONTROL_1_LOOPBACK | 2826335e9f2SAndrew Lunn MV88E6390_PCS_CONTROL_1_PDOWN); 2836335e9f2SAndrew Lunn else 2846335e9f2SAndrew Lunn new_val = val | MV88E6390_PCS_CONTROL_1_PDOWN; 2856335e9f2SAndrew Lunn 2866335e9f2SAndrew Lunn if (val != new_val) 287a8c01c0dSAndrew Lunn err = mv88e6xxx_phy_write(chip, lane, reg_c45, new_val); 2886335e9f2SAndrew Lunn 2896335e9f2SAndrew Lunn return err; 2906335e9f2SAndrew Lunn } 2916335e9f2SAndrew Lunn 292a8c01c0dSAndrew Lunn /* Set the power on/off for SGMII and 1000Base-X */ 293a8c01c0dSAndrew Lunn static int mv88e6390_serdes_sgmii(struct mv88e6xxx_chip *chip, int lane, 2946335e9f2SAndrew Lunn bool on) 2956335e9f2SAndrew Lunn { 2966335e9f2SAndrew Lunn u16 val, new_val; 2976335e9f2SAndrew Lunn int reg_c45; 2986335e9f2SAndrew Lunn int err; 2996335e9f2SAndrew Lunn 3006335e9f2SAndrew Lunn reg_c45 = MII_ADDR_C45 | MV88E6390_SERDES_DEVICE | 3016335e9f2SAndrew Lunn MV88E6390_SGMII_CONTROL; 302a8c01c0dSAndrew Lunn err = mv88e6xxx_phy_read(chip, lane, reg_c45, &val); 3036335e9f2SAndrew Lunn if (err) 3046335e9f2SAndrew Lunn return err; 3056335e9f2SAndrew Lunn 3066335e9f2SAndrew Lunn if (on) 3076335e9f2SAndrew Lunn new_val = val & ~(MV88E6390_SGMII_CONTROL_RESET | 3086335e9f2SAndrew Lunn MV88E6390_SGMII_CONTROL_LOOPBACK | 3096335e9f2SAndrew Lunn MV88E6390_SGMII_CONTROL_PDOWN); 3106335e9f2SAndrew Lunn else 3116335e9f2SAndrew Lunn new_val = val | MV88E6390_SGMII_CONTROL_PDOWN; 3126335e9f2SAndrew Lunn 3136335e9f2SAndrew Lunn if (val != new_val) 314a8c01c0dSAndrew Lunn err = mv88e6xxx_phy_write(chip, lane, reg_c45, new_val); 3156335e9f2SAndrew Lunn 3166335e9f2SAndrew Lunn return err; 3176335e9f2SAndrew Lunn } 3186335e9f2SAndrew Lunn 319a8c01c0dSAndrew Lunn static int mv88e6390_serdes_power_lane(struct mv88e6xxx_chip *chip, int port, 320a8c01c0dSAndrew Lunn int lane, bool on) 3216335e9f2SAndrew Lunn { 3226335e9f2SAndrew Lunn u8 cmode; 3236335e9f2SAndrew Lunn int err; 3246335e9f2SAndrew Lunn 3256335e9f2SAndrew Lunn err = mv88e6xxx_port_get_cmode(chip, port, &cmode); 3266335e9f2SAndrew Lunn if (err) 32764b2f726SDan Carpenter return err; 3286335e9f2SAndrew Lunn 329a8c01c0dSAndrew Lunn switch (cmode) { 330a8c01c0dSAndrew Lunn case MV88E6XXX_PORT_STS_CMODE_SGMII: 331a8c01c0dSAndrew Lunn case MV88E6XXX_PORT_STS_CMODE_1000BASE_X: 332a8c01c0dSAndrew Lunn return mv88e6390_serdes_sgmii(chip, lane, on); 333a8c01c0dSAndrew Lunn case MV88E6XXX_PORT_STS_CMODE_XAUI: 334a8c01c0dSAndrew Lunn case MV88E6XXX_PORT_STS_CMODE_RXAUI: 335a8c01c0dSAndrew Lunn case MV88E6XXX_PORT_STS_CMODE_2500BASEX: 336a8c01c0dSAndrew Lunn return mv88e6390_serdes_10g(chip, lane, on); 337a8c01c0dSAndrew Lunn } 338a8c01c0dSAndrew Lunn 339a8c01c0dSAndrew Lunn return 0; 340a8c01c0dSAndrew Lunn } 341a8c01c0dSAndrew Lunn 342a8c01c0dSAndrew Lunn int mv88e6390_serdes_power(struct mv88e6xxx_chip *chip, int port, bool on) 343a8c01c0dSAndrew Lunn { 344a8c01c0dSAndrew Lunn int lane; 345a8c01c0dSAndrew Lunn 346a8c01c0dSAndrew Lunn lane = mv88e6390_serdes_get_lane(chip, port); 347a8c01c0dSAndrew Lunn if (lane == -ENODEV) 348a8c01c0dSAndrew Lunn return 0; 349a8c01c0dSAndrew Lunn 350a8c01c0dSAndrew Lunn if (lane < 0) 351a8c01c0dSAndrew Lunn return lane; 352a8c01c0dSAndrew Lunn 3536335e9f2SAndrew Lunn switch (port) { 354a8c01c0dSAndrew Lunn case 2 ... 4: 355a8c01c0dSAndrew Lunn case 5 ... 7: 356a8c01c0dSAndrew Lunn case 9 ... 10: 357a8c01c0dSAndrew Lunn return mv88e6390_serdes_power_lane(chip, port, lane, on); 3586335e9f2SAndrew Lunn } 3596335e9f2SAndrew Lunn 3606335e9f2SAndrew Lunn return 0; 3616335e9f2SAndrew Lunn } 3625bafeb6eSMarek Behún 3635bafeb6eSMarek Behún int mv88e6341_serdes_power(struct mv88e6xxx_chip *chip, int port, bool on) 3645bafeb6eSMarek Behún { 3655bafeb6eSMarek Behún int err; 3665bafeb6eSMarek Behún u8 cmode; 3675bafeb6eSMarek Behún 3685bafeb6eSMarek Behún if (port != 5) 3695bafeb6eSMarek Behún return 0; 3705bafeb6eSMarek Behún 3715bafeb6eSMarek Behún err = mv88e6xxx_port_get_cmode(chip, port, &cmode); 3725bafeb6eSMarek Behún if (err) 3735bafeb6eSMarek Behún return err; 3745bafeb6eSMarek Behún 3755bafeb6eSMarek Behún if (cmode == MV88E6XXX_PORT_STS_CMODE_1000BASE_X || 3765bafeb6eSMarek Behún cmode == MV88E6XXX_PORT_STS_CMODE_SGMII || 3775bafeb6eSMarek Behún cmode == MV88E6XXX_PORT_STS_CMODE_2500BASEX) 3785bafeb6eSMarek Behún return mv88e6390_serdes_sgmii(chip, MV88E6341_ADDR_SERDES, on); 3795bafeb6eSMarek Behún 3805bafeb6eSMarek Behún return 0; 3815bafeb6eSMarek Behún } 382