4163 lines · c
1// SPDX-License-Identifier: GPL-2.0+2/*3 * drivers/net/phy/marvell.c4 *5 * Driver for Marvell PHYs6 *7 * Author: Andy Fleming8 *9 * Copyright (c) 2004 Freescale Semiconductor, Inc.10 *11 * Copyright (c) 2013 Michael Stapelberg <michael@stapelberg.de>12 */13#include <linux/kernel.h>14#include <linux/string.h>15#include <linux/ctype.h>16#include <linux/errno.h>17#include <linux/unistd.h>18#include <linux/hwmon.h>19#include <linux/interrupt.h>20#include <linux/init.h>21#include <linux/delay.h>22#include <linux/netdevice.h>23#include <linux/etherdevice.h>24#include <linux/skbuff.h>25#include <linux/spinlock.h>26#include <linux/mm.h>27#include <linux/module.h>28#include <linux/mii.h>29#include <linux/ethtool.h>30#include <linux/ethtool_netlink.h>31#include <linux/phy.h>32#include <linux/marvell_phy.h>33#include <linux/bitfield.h>34#include <linux/of.h>35#include <linux/sfp.h>36 37#include <linux/io.h>38#include <asm/irq.h>39#include <linux/uaccess.h>40 41#define MII_MARVELL_PHY_PAGE 2242#define MII_MARVELL_COPPER_PAGE 0x0043#define MII_MARVELL_FIBER_PAGE 0x0144#define MII_MARVELL_MSCR_PAGE 0x0245#define MII_MARVELL_LED_PAGE 0x0346#define MII_MARVELL_VCT5_PAGE 0x0547#define MII_MARVELL_MISC_TEST_PAGE 0x0648#define MII_MARVELL_VCT7_PAGE 0x0749#define MII_MARVELL_WOL_PAGE 0x1150#define MII_MARVELL_MODE_PAGE 0x1251 52#define MII_M1011_IEVENT 0x1353#define MII_M1011_IEVENT_CLEAR 0x000054 55#define MII_M1011_IMASK 0x1256#define MII_M1011_IMASK_INIT 0x640057#define MII_M1011_IMASK_CLEAR 0x000058 59#define MII_M1011_PHY_SCR 0x1060#define MII_M1011_PHY_SCR_DOWNSHIFT_EN BIT(11)61#define MII_M1011_PHY_SCR_DOWNSHIFT_MASK GENMASK(14, 12)62#define MII_M1011_PHY_SCR_DOWNSHIFT_MAX 863#define MII_M1011_PHY_SCR_MDI (0x0 << 5)64#define MII_M1011_PHY_SCR_MDI_X (0x1 << 5)65#define MII_M1011_PHY_SCR_AUTO_CROSS (0x3 << 5)66 67#define MII_M1011_PHY_SSR 0x1168#define MII_M1011_PHY_SSR_DOWNSHIFT BIT(5)69 70#define MII_M1111_PHY_LED_CONTROL 0x1871#define MII_M1111_PHY_LED_DIRECT 0x410072#define MII_M1111_PHY_LED_COMBINE 0x411c73#define MII_M1111_PHY_EXT_CR 0x1474#define MII_M1111_PHY_EXT_CR_DOWNSHIFT_MASK GENMASK(11, 9)75#define MII_M1111_PHY_EXT_CR_DOWNSHIFT_MAX 876#define MII_M1111_PHY_EXT_CR_DOWNSHIFT_EN BIT(8)77#define MII_M1111_RGMII_RX_DELAY BIT(7)78#define MII_M1111_RGMII_TX_DELAY BIT(1)79#define MII_M1111_PHY_EXT_SR 0x1b80 81#define MII_M1111_HWCFG_MODE_MASK 0xf82#define MII_M1111_HWCFG_MODE_FIBER_RGMII 0x383#define MII_M1111_HWCFG_MODE_SGMII_NO_CLK 0x484#define MII_M1111_HWCFG_MODE_RTBI 0x785#define MII_M1111_HWCFG_MODE_COPPER_1000X_AN 0x886#define MII_M1111_HWCFG_MODE_COPPER_RTBI 0x987#define MII_M1111_HWCFG_MODE_COPPER_RGMII 0xb88#define MII_M1111_HWCFG_MODE_COPPER_1000X_NOAN 0xc89#define MII_M1111_HWCFG_SERIAL_AN_BYPASS BIT(12)90#define MII_M1111_HWCFG_FIBER_COPPER_RES BIT(13)91#define MII_M1111_HWCFG_FIBER_COPPER_AUTO BIT(15)92 93#define MII_88E1121_PHY_MSCR_REG 2194#define MII_88E1121_PHY_MSCR_RX_DELAY BIT(5)95#define MII_88E1121_PHY_MSCR_TX_DELAY BIT(4)96#define MII_88E1121_PHY_MSCR_DELAY_MASK (BIT(5) | BIT(4))97 98#define MII_88E1121_MISC_TEST 0x1a99#define MII_88E1510_MISC_TEST_TEMP_THRESHOLD_MASK 0x1f00100#define MII_88E1510_MISC_TEST_TEMP_THRESHOLD_SHIFT 8101#define MII_88E1510_MISC_TEST_TEMP_IRQ_EN BIT(7)102#define MII_88E1510_MISC_TEST_TEMP_IRQ BIT(6)103#define MII_88E1121_MISC_TEST_TEMP_SENSOR_EN BIT(5)104#define MII_88E1121_MISC_TEST_TEMP_MASK 0x1f105 106#define MII_88E1510_TEMP_SENSOR 0x1b107#define MII_88E1510_TEMP_SENSOR_MASK 0xff108 109#define MII_88E1540_COPPER_CTRL3 0x1a110#define MII_88E1540_COPPER_CTRL3_LINK_DOWN_DELAY_MASK GENMASK(11, 10)111#define MII_88E1540_COPPER_CTRL3_LINK_DOWN_DELAY_00MS 0112#define MII_88E1540_COPPER_CTRL3_LINK_DOWN_DELAY_10MS 1113#define MII_88E1540_COPPER_CTRL3_LINK_DOWN_DELAY_20MS 2114#define MII_88E1540_COPPER_CTRL3_LINK_DOWN_DELAY_40MS 3115#define MII_88E1540_COPPER_CTRL3_FAST_LINK_DOWN BIT(9)116 117#define MII_88E6390_MISC_TEST 0x1b118#define MII_88E6390_MISC_TEST_TEMP_SENSOR_ENABLE_SAMPLE_1S (0x0 << 14)119#define MII_88E6390_MISC_TEST_TEMP_SENSOR_ENABLE (0x1 << 14)120#define MII_88E6390_MISC_TEST_TEMP_SENSOR_ENABLE_ONESHOT (0x2 << 14)121#define MII_88E6390_MISC_TEST_TEMP_SENSOR_DISABLE (0x3 << 14)122#define MII_88E6390_MISC_TEST_TEMP_SENSOR_MASK (0x3 << 14)123#define MII_88E6393_MISC_TEST_SAMPLES_2048 (0x0 << 11)124#define MII_88E6393_MISC_TEST_SAMPLES_4096 (0x1 << 11)125#define MII_88E6393_MISC_TEST_SAMPLES_8192 (0x2 << 11)126#define MII_88E6393_MISC_TEST_SAMPLES_16384 (0x3 << 11)127#define MII_88E6393_MISC_TEST_SAMPLES_MASK (0x3 << 11)128#define MII_88E6393_MISC_TEST_RATE_2_3MS (0x5 << 8)129#define MII_88E6393_MISC_TEST_RATE_6_4MS (0x6 << 8)130#define MII_88E6393_MISC_TEST_RATE_11_9MS (0x7 << 8)131#define MII_88E6393_MISC_TEST_RATE_MASK (0x7 << 8)132 133#define MII_88E6390_TEMP_SENSOR 0x1c134#define MII_88E6393_TEMP_SENSOR_THRESHOLD_MASK 0xff00135#define MII_88E6393_TEMP_SENSOR_THRESHOLD_SHIFT 8136#define MII_88E6390_TEMP_SENSOR_MASK 0xff137#define MII_88E6390_TEMP_SENSOR_SAMPLES 10138 139#define MII_88E1318S_PHY_MSCR1_REG 16140#define MII_88E1318S_PHY_MSCR1_PAD_ODD BIT(6)141 142/* Copper Specific Interrupt Enable Register */143#define MII_88E1318S_PHY_CSIER 0x12144/* WOL Event Interrupt Enable */145#define MII_88E1318S_PHY_CSIER_WOL_EIE BIT(7)146 147#define MII_88E1318S_PHY_LED_FUNC 0x10148#define MII_88E1318S_PHY_LED_FUNC_OFF (0x8)149#define MII_88E1318S_PHY_LED_FUNC_ON (0x9)150#define MII_88E1318S_PHY_LED_FUNC_HI_Z (0xa)151#define MII_88E1318S_PHY_LED_FUNC_BLINK (0xb)152#define MII_88E1318S_PHY_LED_TCR 0x12153#define MII_88E1318S_PHY_LED_TCR_FORCE_INT BIT(15)154#define MII_88E1318S_PHY_LED_TCR_INTn_ENABLE BIT(7)155#define MII_88E1318S_PHY_LED_TCR_INT_ACTIVE_LOW BIT(11)156 157/* Magic Packet MAC address registers */158#define MII_88E1318S_PHY_MAGIC_PACKET_WORD2 0x17159#define MII_88E1318S_PHY_MAGIC_PACKET_WORD1 0x18160#define MII_88E1318S_PHY_MAGIC_PACKET_WORD0 0x19161 162#define MII_88E1318S_PHY_WOL_CTRL 0x10163#define MII_88E1318S_PHY_WOL_CTRL_CLEAR_WOL_STATUS BIT(12)164#define MII_88E1318S_PHY_WOL_CTRL_LINK_UP_ENABLE BIT(13)165#define MII_88E1318S_PHY_WOL_CTRL_MAGIC_PACKET_MATCH_ENABLE BIT(14)166 167#define MII_PHY_LED_CTRL 16168#define MII_88E1121_PHY_LED_DEF 0x0030169#define MII_88E1510_PHY_LED_DEF 0x1177170#define MII_88E1510_PHY_LED0_LINK_LED1_ACTIVE 0x1040171 172#define MII_M1011_PHY_STATUS 0x11173#define MII_M1011_PHY_STATUS_1000 0x8000174#define MII_M1011_PHY_STATUS_100 0x4000175#define MII_M1011_PHY_STATUS_SPD_MASK 0xc000176#define MII_M1011_PHY_STATUS_FULLDUPLEX 0x2000177#define MII_M1011_PHY_STATUS_RESOLVED 0x0800178#define MII_M1011_PHY_STATUS_LINK 0x0400179 180#define MII_88E3016_PHY_SPEC_CTRL 0x10181#define MII_88E3016_DISABLE_SCRAMBLER 0x0200182#define MII_88E3016_AUTO_MDIX_CROSSOVER 0x0030183 184#define MII_88E1510_GEN_CTRL_REG_1 0x14185#define MII_88E1510_GEN_CTRL_REG_1_MODE_MASK 0x7186#define MII_88E1510_GEN_CTRL_REG_1_MODE_RGMII 0x0 /* RGMII to copper */187#define MII_88E1510_GEN_CTRL_REG_1_MODE_SGMII 0x1 /* SGMII to copper */188/* RGMII to 1000BASE-X */189#define MII_88E1510_GEN_CTRL_REG_1_MODE_RGMII_1000X 0x2190/* RGMII to 100BASE-FX */191#define MII_88E1510_GEN_CTRL_REG_1_MODE_RGMII_100FX 0x3192/* RGMII to SGMII */193#define MII_88E1510_GEN_CTRL_REG_1_MODE_RGMII_SGMII 0x4194#define MII_88E1510_GEN_CTRL_REG_1_RESET 0x8000 /* Soft reset */195 196#define MII_88E1510_MSCR_2 0x15197 198#define MII_VCT5_TX_RX_MDI0_COUPLING 0x10199#define MII_VCT5_TX_RX_MDI1_COUPLING 0x11200#define MII_VCT5_TX_RX_MDI2_COUPLING 0x12201#define MII_VCT5_TX_RX_MDI3_COUPLING 0x13202#define MII_VCT5_TX_RX_AMPLITUDE_MASK 0x7f00203#define MII_VCT5_TX_RX_AMPLITUDE_SHIFT 8204#define MII_VCT5_TX_RX_COUPLING_POSITIVE_REFLECTION BIT(15)205 206#define MII_VCT5_CTRL 0x17207#define MII_VCT5_CTRL_ENABLE BIT(15)208#define MII_VCT5_CTRL_COMPLETE BIT(14)209#define MII_VCT5_CTRL_TX_SAME_CHANNEL (0x0 << 11)210#define MII_VCT5_CTRL_TX0_CHANNEL (0x4 << 11)211#define MII_VCT5_CTRL_TX1_CHANNEL (0x5 << 11)212#define MII_VCT5_CTRL_TX2_CHANNEL (0x6 << 11)213#define MII_VCT5_CTRL_TX3_CHANNEL (0x7 << 11)214#define MII_VCT5_CTRL_SAMPLES_2 (0x0 << 8)215#define MII_VCT5_CTRL_SAMPLES_4 (0x1 << 8)216#define MII_VCT5_CTRL_SAMPLES_8 (0x2 << 8)217#define MII_VCT5_CTRL_SAMPLES_16 (0x3 << 8)218#define MII_VCT5_CTRL_SAMPLES_32 (0x4 << 8)219#define MII_VCT5_CTRL_SAMPLES_64 (0x5 << 8)220#define MII_VCT5_CTRL_SAMPLES_128 (0x6 << 8)221#define MII_VCT5_CTRL_SAMPLES_DEFAULT (0x6 << 8)222#define MII_VCT5_CTRL_SAMPLES_256 (0x7 << 8)223#define MII_VCT5_CTRL_SAMPLES_SHIFT 8224#define MII_VCT5_CTRL_MODE_MAXIMUM_PEEK (0x0 << 6)225#define MII_VCT5_CTRL_MODE_FIRST_LAST_PEEK (0x1 << 6)226#define MII_VCT5_CTRL_MODE_OFFSET (0x2 << 6)227#define MII_VCT5_CTRL_SAMPLE_POINT (0x3 << 6)228#define MII_VCT5_CTRL_PEEK_HYST_DEFAULT 3229 230#define MII_VCT5_SAMPLE_POINT_DISTANCE 0x18231#define MII_VCT5_SAMPLE_POINT_DISTANCE_MAX 511232#define MII_VCT5_TX_PULSE_CTRL 0x1c233#define MII_VCT5_TX_PULSE_CTRL_DONT_WAIT_LINK_DOWN BIT(12)234#define MII_VCT5_TX_PULSE_CTRL_PULSE_WIDTH_128nS (0x0 << 10)235#define MII_VCT5_TX_PULSE_CTRL_PULSE_WIDTH_96nS (0x1 << 10)236#define MII_VCT5_TX_PULSE_CTRL_PULSE_WIDTH_64nS (0x2 << 10)237#define MII_VCT5_TX_PULSE_CTRL_PULSE_WIDTH_32nS (0x3 << 10)238#define MII_VCT5_TX_PULSE_CTRL_PULSE_WIDTH_SHIFT 10239#define MII_VCT5_TX_PULSE_CTRL_PULSE_AMPLITUDE_1000mV (0x0 << 8)240#define MII_VCT5_TX_PULSE_CTRL_PULSE_AMPLITUDE_750mV (0x1 << 8)241#define MII_VCT5_TX_PULSE_CTRL_PULSE_AMPLITUDE_500mV (0x2 << 8)242#define MII_VCT5_TX_PULSE_CTRL_PULSE_AMPLITUDE_250mV (0x3 << 8)243#define MII_VCT5_TX_PULSE_CTRL_PULSE_AMPLITUDE_SHIFT 8244#define MII_VCT5_TX_PULSE_CTRL_MAX_AMP BIT(7)245#define MII_VCT5_TX_PULSE_CTRL_GT_140m_46_86mV (0x6 << 0)246 247/* For TDR measurements less than 11 meters, a short pulse should be248 * used.249 */250#define TDR_SHORT_CABLE_LENGTH 11251 252#define MII_VCT7_PAIR_0_DISTANCE 0x10253#define MII_VCT7_PAIR_1_DISTANCE 0x11254#define MII_VCT7_PAIR_2_DISTANCE 0x12255#define MII_VCT7_PAIR_3_DISTANCE 0x13256 257#define MII_VCT7_RESULTS 0x14258#define MII_VCT7_RESULTS_PAIR3_MASK 0xf000259#define MII_VCT7_RESULTS_PAIR2_MASK 0x0f00260#define MII_VCT7_RESULTS_PAIR1_MASK 0x00f0261#define MII_VCT7_RESULTS_PAIR0_MASK 0x000f262#define MII_VCT7_RESULTS_PAIR3_SHIFT 12263#define MII_VCT7_RESULTS_PAIR2_SHIFT 8264#define MII_VCT7_RESULTS_PAIR1_SHIFT 4265#define MII_VCT7_RESULTS_PAIR0_SHIFT 0266#define MII_VCT7_RESULTS_INVALID 0267#define MII_VCT7_RESULTS_OK 1268#define MII_VCT7_RESULTS_OPEN 2269#define MII_VCT7_RESULTS_SAME_SHORT 3270#define MII_VCT7_RESULTS_CROSS_SHORT 4271#define MII_VCT7_RESULTS_BUSY 9272 273#define MII_VCT7_CTRL 0x15274#define MII_VCT7_CTRL_RUN_NOW BIT(15)275#define MII_VCT7_CTRL_RUN_ANEG BIT(14)276#define MII_VCT7_CTRL_DISABLE_CROSS BIT(13)277#define MII_VCT7_CTRL_RUN_AFTER_BREAK_LINK BIT(12)278#define MII_VCT7_CTRL_IN_PROGRESS BIT(11)279#define MII_VCT7_CTRL_METERS BIT(10)280#define MII_VCT7_CTRL_CENTIMETERS 0281 282#define MII_VCT_TXPINS 0x1A283#define MII_VCT_RXPINS 0x1B284#define MII_VCT_SR 0x1C285#define MII_VCT_TXPINS_ENVCT BIT(15)286#define MII_VCT_TXRXPINS_VCTTST GENMASK(14, 13)287#define MII_VCT_TXRXPINS_VCTTST_SHIFT 13288#define MII_VCT_TXRXPINS_VCTTST_OK 0289#define MII_VCT_TXRXPINS_VCTTST_SHORT 1290#define MII_VCT_TXRXPINS_VCTTST_OPEN 2291#define MII_VCT_TXRXPINS_VCTTST_FAIL 3292#define MII_VCT_TXRXPINS_AMPRFLN GENMASK(12, 8)293#define MII_VCT_TXRXPINS_AMPRFLN_SHIFT 8294#define MII_VCT_TXRXPINS_DISTRFLN GENMASK(7, 0)295#define MII_VCT_TXRXPINS_DISTRFLN_MAX 0xff296 297#define M88E3082_PAIR_A BIT(0)298#define M88E3082_PAIR_B BIT(1)299 300#define LPA_PAUSE_FIBER 0x180301#define LPA_PAUSE_ASYM_FIBER 0x100302 303#define NB_FIBER_STATS 1304#define NB_STAT_MAX 3305 306MODULE_DESCRIPTION("Marvell PHY driver");307MODULE_AUTHOR("Andy Fleming");308MODULE_LICENSE("GPL");309 310struct marvell_hw_stat {311 const char *string;312 u8 page;313 u8 reg;314 u8 bits;315};316 317static const struct marvell_hw_stat marvell_hw_stats[] = {318 { "phy_receive_errors_copper", 0, 21, 16},319 { "phy_idle_errors", 0, 10, 8 },320 { "phy_receive_errors_fiber", 1, 21, 16},321};322 323static_assert(ARRAY_SIZE(marvell_hw_stats) <= NB_STAT_MAX);324 325/* "simple" stat list + corresponding marvell_get_*_simple functions are used326 * on PHYs without a page register327 */328struct marvell_hw_stat_simple {329 const char *string;330 u8 reg;331 u8 bits;332};333 334static const struct marvell_hw_stat_simple marvell_hw_stats_simple[] = {335 { "phy_receive_errors", 21, 16},336};337 338static_assert(ARRAY_SIZE(marvell_hw_stats_simple) <= NB_STAT_MAX);339 340enum {341 M88E3082_VCT_OFF,342 M88E3082_VCT_PHASE1,343 M88E3082_VCT_PHASE2,344};345 346struct marvell_priv {347 u64 stats[NB_STAT_MAX];348 char *hwmon_name;349 struct device *hwmon_dev;350 bool cable_test_tdr;351 u32 first;352 u32 last;353 u32 step;354 s8 pair;355 u8 vct_phase;356};357 358static int marvell_read_page(struct phy_device *phydev)359{360 return __phy_read(phydev, MII_MARVELL_PHY_PAGE);361}362 363static int marvell_write_page(struct phy_device *phydev, int page)364{365 return __phy_write(phydev, MII_MARVELL_PHY_PAGE, page);366}367 368static int marvell_set_page(struct phy_device *phydev, int page)369{370 return phy_write(phydev, MII_MARVELL_PHY_PAGE, page);371}372 373static int marvell_ack_interrupt(struct phy_device *phydev)374{375 int err;376 377 /* Clear the interrupts by reading the reg */378 err = phy_read(phydev, MII_M1011_IEVENT);379 380 if (err < 0)381 return err;382 383 return 0;384}385 386static int marvell_config_intr(struct phy_device *phydev)387{388 int err;389 390 if (phydev->interrupts == PHY_INTERRUPT_ENABLED) {391 err = marvell_ack_interrupt(phydev);392 if (err)393 return err;394 395 err = phy_write(phydev, MII_M1011_IMASK,396 MII_M1011_IMASK_INIT);397 } else {398 err = phy_write(phydev, MII_M1011_IMASK,399 MII_M1011_IMASK_CLEAR);400 if (err)401 return err;402 403 err = marvell_ack_interrupt(phydev);404 }405 406 return err;407}408 409static irqreturn_t marvell_handle_interrupt(struct phy_device *phydev)410{411 int irq_status;412 413 irq_status = phy_read(phydev, MII_M1011_IEVENT);414 if (irq_status < 0) {415 phy_error(phydev);416 return IRQ_NONE;417 }418 419 if (!(irq_status & MII_M1011_IMASK_INIT))420 return IRQ_NONE;421 422 phy_trigger_machine(phydev);423 424 return IRQ_HANDLED;425}426 427static int marvell_set_polarity(struct phy_device *phydev, int polarity)428{429 u16 val;430 431 switch (polarity) {432 case ETH_TP_MDI:433 val = MII_M1011_PHY_SCR_MDI;434 break;435 case ETH_TP_MDI_X:436 val = MII_M1011_PHY_SCR_MDI_X;437 break;438 case ETH_TP_MDI_AUTO:439 case ETH_TP_MDI_INVALID:440 default:441 val = MII_M1011_PHY_SCR_AUTO_CROSS;442 break;443 }444 445 return phy_modify_changed(phydev, MII_M1011_PHY_SCR,446 MII_M1011_PHY_SCR_AUTO_CROSS, val);447}448 449static int marvell_config_aneg(struct phy_device *phydev)450{451 int changed = 0;452 int err;453 454 err = marvell_set_polarity(phydev, phydev->mdix_ctrl);455 if (err < 0)456 return err;457 458 changed = err;459 460 err = phy_write(phydev, MII_M1111_PHY_LED_CONTROL,461 MII_M1111_PHY_LED_DIRECT);462 if (err < 0)463 return err;464 465 err = genphy_config_aneg(phydev);466 if (err < 0)467 return err;468 469 if (phydev->autoneg != AUTONEG_ENABLE || changed) {470 /* A write to speed/duplex bits (that is performed by471 * genphy_config_aneg() call above) must be followed by472 * a software reset. Otherwise, the write has no effect.473 */474 err = genphy_soft_reset(phydev);475 if (err < 0)476 return err;477 }478 479 return 0;480}481 482static int m88e1101_config_aneg(struct phy_device *phydev)483{484 int err;485 486 /* This Marvell PHY has an errata which requires487 * that certain registers get written in order488 * to restart autonegotiation489 */490 err = genphy_soft_reset(phydev);491 if (err < 0)492 return err;493 494 err = phy_write(phydev, 0x1d, 0x1f);495 if (err < 0)496 return err;497 498 err = phy_write(phydev, 0x1e, 0x200c);499 if (err < 0)500 return err;501 502 err = phy_write(phydev, 0x1d, 0x5);503 if (err < 0)504 return err;505 506 err = phy_write(phydev, 0x1e, 0);507 if (err < 0)508 return err;509 510 err = phy_write(phydev, 0x1e, 0x100);511 if (err < 0)512 return err;513 514 return marvell_config_aneg(phydev);515}516 517#if IS_ENABLED(CONFIG_OF_MDIO)518/* Set and/or override some configuration registers based on the519 * marvell,reg-init property stored in the of_node for the phydev.520 *521 * marvell,reg-init = <reg-page reg mask value>,...;522 *523 * There may be one or more sets of <reg-page reg mask value>:524 *525 * reg-page: which register bank to use.526 * reg: the register.527 * mask: if non-zero, ANDed with existing register value.528 * value: ORed with the masked value and written to the regiser.529 *530 */531static int marvell_of_reg_init(struct phy_device *phydev)532{533 const __be32 *paddr;534 int len, i, saved_page, current_page, ret = 0;535 536 if (!phydev->mdio.dev.of_node)537 return 0;538 539 paddr = of_get_property(phydev->mdio.dev.of_node,540 "marvell,reg-init", &len);541 if (!paddr || len < (4 * sizeof(*paddr)))542 return 0;543 544 saved_page = phy_save_page(phydev);545 if (saved_page < 0)546 goto err;547 current_page = saved_page;548 549 len /= sizeof(*paddr);550 for (i = 0; i < len - 3; i += 4) {551 u16 page = be32_to_cpup(paddr + i);552 u16 reg = be32_to_cpup(paddr + i + 1);553 u16 mask = be32_to_cpup(paddr + i + 2);554 u16 val_bits = be32_to_cpup(paddr + i + 3);555 int val;556 557 if (page != current_page) {558 current_page = page;559 ret = marvell_write_page(phydev, page);560 if (ret < 0)561 goto err;562 }563 564 val = 0;565 if (mask) {566 val = __phy_read(phydev, reg);567 if (val < 0) {568 ret = val;569 goto err;570 }571 val &= mask;572 }573 val |= val_bits;574 575 ret = __phy_write(phydev, reg, val);576 if (ret < 0)577 goto err;578 }579err:580 return phy_restore_page(phydev, saved_page, ret);581}582#else583static int marvell_of_reg_init(struct phy_device *phydev)584{585 return 0;586}587#endif /* CONFIG_OF_MDIO */588 589static int m88e1121_config_aneg_rgmii_delays(struct phy_device *phydev)590{591 int mscr;592 593 if (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID)594 mscr = MII_88E1121_PHY_MSCR_RX_DELAY |595 MII_88E1121_PHY_MSCR_TX_DELAY;596 else if (phydev->interface == PHY_INTERFACE_MODE_RGMII_RXID)597 mscr = MII_88E1121_PHY_MSCR_RX_DELAY;598 else if (phydev->interface == PHY_INTERFACE_MODE_RGMII_TXID)599 mscr = MII_88E1121_PHY_MSCR_TX_DELAY;600 else601 mscr = 0;602 603 return phy_modify_paged_changed(phydev, MII_MARVELL_MSCR_PAGE,604 MII_88E1121_PHY_MSCR_REG,605 MII_88E1121_PHY_MSCR_DELAY_MASK, mscr);606}607 608static int m88e1121_config_aneg(struct phy_device *phydev)609{610 int changed = 0;611 int err = 0;612 613 if (phy_interface_is_rgmii(phydev)) {614 err = m88e1121_config_aneg_rgmii_delays(phydev);615 if (err < 0)616 return err;617 }618 619 changed = err;620 621 err = marvell_set_polarity(phydev, phydev->mdix_ctrl);622 if (err < 0)623 return err;624 625 changed |= err;626 627 err = genphy_config_aneg(phydev);628 if (err < 0)629 return err;630 631 if (phydev->autoneg != AUTONEG_ENABLE || changed) {632 /* A software reset is used to ensure a "commit" of the633 * changes is done.634 */635 err = genphy_soft_reset(phydev);636 if (err < 0)637 return err;638 }639 640 return 0;641}642 643static int m88e1318_config_aneg(struct phy_device *phydev)644{645 int err;646 647 err = phy_modify_paged(phydev, MII_MARVELL_MSCR_PAGE,648 MII_88E1318S_PHY_MSCR1_REG,649 0, MII_88E1318S_PHY_MSCR1_PAD_ODD);650 if (err < 0)651 return err;652 653 return m88e1121_config_aneg(phydev);654}655 656/**657 * linkmode_adv_to_fiber_adv_t658 * @advertise: the linkmode advertisement settings659 *660 * A small helper function that translates linkmode advertisement661 * settings to phy autonegotiation advertisements for the MII_ADV662 * register for fiber link.663 */664static inline u32 linkmode_adv_to_fiber_adv_t(unsigned long *advertise)665{666 u32 result = 0;667 668 if (linkmode_test_bit(ETHTOOL_LINK_MODE_1000baseT_Half_BIT, advertise))669 result |= ADVERTISE_1000XHALF;670 if (linkmode_test_bit(ETHTOOL_LINK_MODE_1000baseT_Full_BIT, advertise))671 result |= ADVERTISE_1000XFULL;672 673 if (linkmode_test_bit(ETHTOOL_LINK_MODE_Asym_Pause_BIT, advertise) &&674 linkmode_test_bit(ETHTOOL_LINK_MODE_Pause_BIT, advertise))675 result |= ADVERTISE_1000XPSE_ASYM;676 else if (linkmode_test_bit(ETHTOOL_LINK_MODE_Pause_BIT, advertise))677 result |= ADVERTISE_1000XPAUSE;678 679 return result;680}681 682/**683 * marvell_config_aneg_fiber - restart auto-negotiation or write BMCR684 * @phydev: target phy_device struct685 *686 * Description: If auto-negotiation is enabled, we configure the687 * advertising, and then restart auto-negotiation. If it is not688 * enabled, then we write the BMCR. Adapted for fiber link in689 * some Marvell's devices.690 */691static int marvell_config_aneg_fiber(struct phy_device *phydev)692{693 int changed = 0;694 int err;695 u16 adv;696 697 if (phydev->autoneg != AUTONEG_ENABLE)698 return genphy_setup_forced(phydev);699 700 /* Only allow advertising what this PHY supports */701 linkmode_and(phydev->advertising, phydev->advertising,702 phydev->supported);703 704 adv = linkmode_adv_to_fiber_adv_t(phydev->advertising);705 706 /* Setup fiber advertisement */707 err = phy_modify_changed(phydev, MII_ADVERTISE,708 ADVERTISE_1000XHALF | ADVERTISE_1000XFULL |709 ADVERTISE_1000XPAUSE | ADVERTISE_1000XPSE_ASYM,710 adv);711 if (err < 0)712 return err;713 if (err > 0)714 changed = 1;715 716 return genphy_check_and_restart_aneg(phydev, changed);717}718 719static int m88e1111_config_aneg(struct phy_device *phydev)720{721 int extsr = phy_read(phydev, MII_M1111_PHY_EXT_SR);722 int err;723 724 if (extsr < 0)725 return extsr;726 727 /* If not using SGMII or copper 1000BaseX modes, use normal process.728 * Steps below are only required for these modes.729 */730 if (phydev->interface != PHY_INTERFACE_MODE_SGMII &&731 (extsr & MII_M1111_HWCFG_MODE_MASK) !=732 MII_M1111_HWCFG_MODE_COPPER_1000X_AN)733 return marvell_config_aneg(phydev);734 735 err = marvell_set_page(phydev, MII_MARVELL_COPPER_PAGE);736 if (err < 0)737 goto error;738 739 /* Configure the copper link first */740 err = marvell_config_aneg(phydev);741 if (err < 0)742 goto error;743 744 /* Then the fiber link */745 err = marvell_set_page(phydev, MII_MARVELL_FIBER_PAGE);746 if (err < 0)747 goto error;748 749 if (phydev->interface == PHY_INTERFACE_MODE_SGMII)750 /* Do not touch the fiber advertisement if we're in copper->sgmii mode.751 * Just ensure that SGMII-side autonegotiation is enabled.752 * If we switched from some other mode to SGMII it may not be.753 */754 err = genphy_check_and_restart_aneg(phydev, false);755 else756 err = marvell_config_aneg_fiber(phydev);757 if (err < 0)758 goto error;759 760 return marvell_set_page(phydev, MII_MARVELL_COPPER_PAGE);761 762error:763 marvell_set_page(phydev, MII_MARVELL_COPPER_PAGE);764 return err;765}766 767static int m88e1510_config_aneg(struct phy_device *phydev)768{769 int err;770 771 err = marvell_set_page(phydev, MII_MARVELL_COPPER_PAGE);772 if (err < 0)773 goto error;774 775 /* Configure the copper link first */776 err = m88e1318_config_aneg(phydev);777 if (err < 0)778 goto error;779 780 /* Do not touch the fiber page if we're in copper->sgmii mode */781 if (phydev->interface == PHY_INTERFACE_MODE_SGMII)782 return 0;783 784 /* Then the fiber link */785 err = marvell_set_page(phydev, MII_MARVELL_FIBER_PAGE);786 if (err < 0)787 goto error;788 789 err = marvell_config_aneg_fiber(phydev);790 if (err < 0)791 goto error;792 793 return marvell_set_page(phydev, MII_MARVELL_COPPER_PAGE);794 795error:796 marvell_set_page(phydev, MII_MARVELL_COPPER_PAGE);797 return err;798}799 800static void marvell_config_led(struct phy_device *phydev)801{802 u16 def_config;803 int err;804 805 switch (MARVELL_PHY_FAMILY_ID(phydev->phy_id)) {806 /* Default PHY LED config: LED[0] .. Link, LED[1] .. Activity */807 case MARVELL_PHY_FAMILY_ID(MARVELL_PHY_ID_88E1121R):808 case MARVELL_PHY_FAMILY_ID(MARVELL_PHY_ID_88E1318S):809 def_config = MII_88E1121_PHY_LED_DEF;810 break;811 /* Default PHY LED config:812 * LED[0] .. 1000Mbps Link813 * LED[1] .. 100Mbps Link814 * LED[2] .. Blink, Activity815 */816 case MARVELL_PHY_FAMILY_ID(MARVELL_PHY_ID_88E1510):817 if (phydev->dev_flags & MARVELL_PHY_LED0_LINK_LED1_ACTIVE)818 def_config = MII_88E1510_PHY_LED0_LINK_LED1_ACTIVE;819 else820 def_config = MII_88E1510_PHY_LED_DEF;821 break;822 default:823 return;824 }825 826 err = phy_write_paged(phydev, MII_MARVELL_LED_PAGE, MII_PHY_LED_CTRL,827 def_config);828 if (err < 0)829 phydev_warn(phydev, "Fail to config marvell phy LED.\n");830}831 832static int marvell_config_init(struct phy_device *phydev)833{834 /* Set default LED */835 marvell_config_led(phydev);836 837 /* Set registers from marvell,reg-init DT property */838 return marvell_of_reg_init(phydev);839}840 841static int m88e3016_config_init(struct phy_device *phydev)842{843 int ret;844 845 /* Enable Scrambler and Auto-Crossover */846 ret = phy_modify(phydev, MII_88E3016_PHY_SPEC_CTRL,847 MII_88E3016_DISABLE_SCRAMBLER,848 MII_88E3016_AUTO_MDIX_CROSSOVER);849 if (ret < 0)850 return ret;851 852 return marvell_config_init(phydev);853}854 855static int m88e1111_config_init_hwcfg_mode(struct phy_device *phydev,856 u16 mode,857 int fibre_copper_auto)858{859 if (fibre_copper_auto)860 mode |= MII_M1111_HWCFG_FIBER_COPPER_AUTO;861 862 return phy_modify(phydev, MII_M1111_PHY_EXT_SR,863 MII_M1111_HWCFG_MODE_MASK |864 MII_M1111_HWCFG_FIBER_COPPER_AUTO |865 MII_M1111_HWCFG_FIBER_COPPER_RES,866 mode);867}868 869static int m88e1111_config_init_rgmii_delays(struct phy_device *phydev)870{871 int delay;872 873 switch (phydev->interface) {874 case PHY_INTERFACE_MODE_RGMII_ID:875 delay = MII_M1111_RGMII_RX_DELAY | MII_M1111_RGMII_TX_DELAY;876 break;877 case PHY_INTERFACE_MODE_RGMII_RXID:878 delay = MII_M1111_RGMII_RX_DELAY;879 break;880 case PHY_INTERFACE_MODE_RGMII_TXID:881 delay = MII_M1111_RGMII_TX_DELAY;882 break;883 default:884 delay = 0;885 break;886 }887 888 return phy_modify(phydev, MII_M1111_PHY_EXT_CR,889 MII_M1111_RGMII_RX_DELAY | MII_M1111_RGMII_TX_DELAY,890 delay);891}892 893static int m88e1111_config_init_rgmii(struct phy_device *phydev)894{895 int temp;896 int err;897 898 err = m88e1111_config_init_rgmii_delays(phydev);899 if (err < 0)900 return err;901 902 temp = phy_read(phydev, MII_M1111_PHY_EXT_SR);903 if (temp < 0)904 return temp;905 906 temp &= ~(MII_M1111_HWCFG_MODE_MASK);907 908 if (temp & MII_M1111_HWCFG_FIBER_COPPER_RES)909 temp |= MII_M1111_HWCFG_MODE_FIBER_RGMII;910 else911 temp |= MII_M1111_HWCFG_MODE_COPPER_RGMII;912 913 return phy_write(phydev, MII_M1111_PHY_EXT_SR, temp);914}915 916static int m88e1111_config_init_sgmii(struct phy_device *phydev)917{918 int err;919 920 err = m88e1111_config_init_hwcfg_mode(921 phydev,922 MII_M1111_HWCFG_MODE_SGMII_NO_CLK,923 MII_M1111_HWCFG_FIBER_COPPER_AUTO);924 if (err < 0)925 return err;926 927 /* make sure copper is selected */928 return marvell_set_page(phydev, MII_MARVELL_COPPER_PAGE);929}930 931static int m88e1111_config_init_rtbi(struct phy_device *phydev)932{933 int err;934 935 err = m88e1111_config_init_rgmii_delays(phydev);936 if (err < 0)937 return err;938 939 err = m88e1111_config_init_hwcfg_mode(940 phydev,941 MII_M1111_HWCFG_MODE_RTBI,942 MII_M1111_HWCFG_FIBER_COPPER_AUTO);943 if (err < 0)944 return err;945 946 /* soft reset */947 err = genphy_soft_reset(phydev);948 if (err < 0)949 return err;950 951 return m88e1111_config_init_hwcfg_mode(952 phydev,953 MII_M1111_HWCFG_MODE_RTBI,954 MII_M1111_HWCFG_FIBER_COPPER_AUTO);955}956 957static int m88e1111_config_init_1000basex(struct phy_device *phydev)958{959 int extsr = phy_read(phydev, MII_M1111_PHY_EXT_SR);960 int err, mode;961 962 if (extsr < 0)963 return extsr;964 965 /* If using copper mode, ensure 1000BaseX auto-negotiation is enabled.966 * FIXME: this does not actually enable 1000BaseX auto-negotiation if967 * it was previously disabled in the Fiber BMCR!968 */969 mode = extsr & MII_M1111_HWCFG_MODE_MASK;970 if (mode == MII_M1111_HWCFG_MODE_COPPER_1000X_NOAN) {971 err = phy_modify(phydev, MII_M1111_PHY_EXT_SR,972 MII_M1111_HWCFG_MODE_MASK |973 MII_M1111_HWCFG_SERIAL_AN_BYPASS,974 MII_M1111_HWCFG_MODE_COPPER_1000X_AN |975 MII_M1111_HWCFG_SERIAL_AN_BYPASS);976 if (err < 0)977 return err;978 }979 return 0;980}981 982static int m88e1111_config_init(struct phy_device *phydev)983{984 int err;985 986 if (phy_interface_is_rgmii(phydev)) {987 err = m88e1111_config_init_rgmii(phydev);988 if (err < 0)989 return err;990 }991 992 if (phydev->interface == PHY_INTERFACE_MODE_SGMII) {993 err = m88e1111_config_init_sgmii(phydev);994 if (err < 0)995 return err;996 }997 998 if (phydev->interface == PHY_INTERFACE_MODE_RTBI) {999 err = m88e1111_config_init_rtbi(phydev);1000 if (err < 0)1001 return err;1002 }1003 1004 if (phydev->interface == PHY_INTERFACE_MODE_1000BASEX) {1005 err = m88e1111_config_init_1000basex(phydev);1006 if (err < 0)1007 return err;1008 }1009 1010 err = marvell_of_reg_init(phydev);1011 if (err < 0)1012 return err;1013 1014 err = genphy_soft_reset(phydev);1015 if (err < 0)1016 return err;1017 1018 if (phydev->interface == PHY_INTERFACE_MODE_SGMII) {1019 /* If the HWCFG_MODE was changed from another mode (such as1020 * 1000BaseX) to SGMII, the state of the support bits may have1021 * also changed now that the PHY has been reset.1022 * Update the PHY abilities accordingly.1023 */1024 err = genphy_read_abilities(phydev);1025 linkmode_or(phydev->advertising, phydev->advertising,1026 phydev->supported);1027 }1028 return err;1029}1030 1031static int m88e1111_get_downshift(struct phy_device *phydev, u8 *data)1032{1033 int val, cnt, enable;1034 1035 val = phy_read(phydev, MII_M1111_PHY_EXT_CR);1036 if (val < 0)1037 return val;1038 1039 enable = FIELD_GET(MII_M1111_PHY_EXT_CR_DOWNSHIFT_EN, val);1040 cnt = FIELD_GET(MII_M1111_PHY_EXT_CR_DOWNSHIFT_MASK, val) + 1;1041 1042 *data = enable ? cnt : DOWNSHIFT_DEV_DISABLE;1043 1044 return 0;1045}1046 1047static int m88e1111_set_downshift(struct phy_device *phydev, u8 cnt)1048{1049 int val, err;1050 1051 if (cnt > MII_M1111_PHY_EXT_CR_DOWNSHIFT_MAX)1052 return -E2BIG;1053 1054 if (!cnt) {1055 err = phy_clear_bits(phydev, MII_M1111_PHY_EXT_CR,1056 MII_M1111_PHY_EXT_CR_DOWNSHIFT_EN);1057 } else {1058 val = MII_M1111_PHY_EXT_CR_DOWNSHIFT_EN;1059 val |= FIELD_PREP(MII_M1111_PHY_EXT_CR_DOWNSHIFT_MASK, cnt - 1);1060 1061 err = phy_modify(phydev, MII_M1111_PHY_EXT_CR,1062 MII_M1111_PHY_EXT_CR_DOWNSHIFT_EN |1063 MII_M1111_PHY_EXT_CR_DOWNSHIFT_MASK,1064 val);1065 }1066 1067 if (err < 0)1068 return err;1069 1070 return genphy_soft_reset(phydev);1071}1072 1073static int m88e1111_get_tunable(struct phy_device *phydev,1074 struct ethtool_tunable *tuna, void *data)1075{1076 switch (tuna->id) {1077 case ETHTOOL_PHY_DOWNSHIFT:1078 return m88e1111_get_downshift(phydev, data);1079 default:1080 return -EOPNOTSUPP;1081 }1082}1083 1084static int m88e1111_set_tunable(struct phy_device *phydev,1085 struct ethtool_tunable *tuna, const void *data)1086{1087 switch (tuna->id) {1088 case ETHTOOL_PHY_DOWNSHIFT:1089 return m88e1111_set_downshift(phydev, *(const u8 *)data);1090 default:1091 return -EOPNOTSUPP;1092 }1093}1094 1095static int m88e1011_get_downshift(struct phy_device *phydev, u8 *data)1096{1097 int val, cnt, enable;1098 1099 val = phy_read(phydev, MII_M1011_PHY_SCR);1100 if (val < 0)1101 return val;1102 1103 enable = FIELD_GET(MII_M1011_PHY_SCR_DOWNSHIFT_EN, val);1104 cnt = FIELD_GET(MII_M1011_PHY_SCR_DOWNSHIFT_MASK, val) + 1;1105 1106 *data = enable ? cnt : DOWNSHIFT_DEV_DISABLE;1107 1108 return 0;1109}1110 1111static int m88e1011_set_downshift(struct phy_device *phydev, u8 cnt)1112{1113 int val, err;1114 1115 if (cnt > MII_M1011_PHY_SCR_DOWNSHIFT_MAX)1116 return -E2BIG;1117 1118 if (!cnt) {1119 err = phy_clear_bits(phydev, MII_M1011_PHY_SCR,1120 MII_M1011_PHY_SCR_DOWNSHIFT_EN);1121 } else {1122 val = MII_M1011_PHY_SCR_DOWNSHIFT_EN;1123 val |= FIELD_PREP(MII_M1011_PHY_SCR_DOWNSHIFT_MASK, cnt - 1);1124 1125 err = phy_modify(phydev, MII_M1011_PHY_SCR,1126 MII_M1011_PHY_SCR_DOWNSHIFT_EN |1127 MII_M1011_PHY_SCR_DOWNSHIFT_MASK,1128 val);1129 }1130 1131 if (err < 0)1132 return err;1133 1134 return genphy_soft_reset(phydev);1135}1136 1137static int m88e1011_get_tunable(struct phy_device *phydev,1138 struct ethtool_tunable *tuna, void *data)1139{1140 switch (tuna->id) {1141 case ETHTOOL_PHY_DOWNSHIFT:1142 return m88e1011_get_downshift(phydev, data);1143 default:1144 return -EOPNOTSUPP;1145 }1146}1147 1148static int m88e1011_set_tunable(struct phy_device *phydev,1149 struct ethtool_tunable *tuna, const void *data)1150{1151 switch (tuna->id) {1152 case ETHTOOL_PHY_DOWNSHIFT:1153 return m88e1011_set_downshift(phydev, *(const u8 *)data);1154 default:1155 return -EOPNOTSUPP;1156 }1157}1158 1159static int m88e1112_config_init(struct phy_device *phydev)1160{1161 int err;1162 1163 err = m88e1011_set_downshift(phydev, 3);1164 if (err < 0)1165 return err;1166 1167 return m88e1111_config_init(phydev);1168}1169 1170static int m88e1111gbe_config_init(struct phy_device *phydev)1171{1172 int err;1173 1174 err = m88e1111_set_downshift(phydev, 3);1175 if (err < 0)1176 return err;1177 1178 return m88e1111_config_init(phydev);1179}1180 1181static int marvell_1011gbe_config_init(struct phy_device *phydev)1182{1183 int err;1184 1185 err = m88e1011_set_downshift(phydev, 3);1186 if (err < 0)1187 return err;1188 1189 return marvell_config_init(phydev);1190}1191static int m88e1116r_config_init(struct phy_device *phydev)1192{1193 int err;1194 1195 err = genphy_soft_reset(phydev);1196 if (err < 0)1197 return err;1198 1199 msleep(500);1200 1201 err = marvell_set_page(phydev, MII_MARVELL_COPPER_PAGE);1202 if (err < 0)1203 return err;1204 1205 err = marvell_set_polarity(phydev, phydev->mdix_ctrl);1206 if (err < 0)1207 return err;1208 1209 err = m88e1011_set_downshift(phydev, 8);1210 if (err < 0)1211 return err;1212 1213 if (phy_interface_is_rgmii(phydev)) {1214 err = m88e1121_config_aneg_rgmii_delays(phydev);1215 if (err < 0)1216 return err;1217 }1218 1219 err = genphy_soft_reset(phydev);1220 if (err < 0)1221 return err;1222 1223 return marvell_config_init(phydev);1224}1225 1226static int m88e1318_config_init(struct phy_device *phydev)1227{1228 if (phy_interrupt_is_valid(phydev)) {1229 int err = phy_modify_paged(1230 phydev, MII_MARVELL_LED_PAGE,1231 MII_88E1318S_PHY_LED_TCR,1232 MII_88E1318S_PHY_LED_TCR_FORCE_INT,1233 MII_88E1318S_PHY_LED_TCR_INTn_ENABLE |1234 MII_88E1318S_PHY_LED_TCR_INT_ACTIVE_LOW);1235 if (err < 0)1236 return err;1237 }1238 1239 return marvell_config_init(phydev);1240}1241 1242static int m88e1510_config_init(struct phy_device *phydev)1243{1244 static const struct {1245 u16 reg17, reg16;1246 } errata_vals[] = {1247 { 0x214b, 0x2144 },1248 { 0x0c28, 0x2146 },1249 { 0xb233, 0x214d },1250 { 0xcc0c, 0x2159 },1251 };1252 int err;1253 int i;1254 1255 /* As per Marvell Release Notes - Alaska 88E1510/88E1518/88E1512/1256 * 88E1514 Rev A0, Errata Section 5.1:1257 * If EEE is intended to be used, the following register writes1258 * must be done once after every hardware reset.1259 */1260 err = marvell_set_page(phydev, 0x00FF);1261 if (err < 0)1262 return err;1263 1264 for (i = 0; i < ARRAY_SIZE(errata_vals); ++i) {1265 err = phy_write(phydev, 17, errata_vals[i].reg17);1266 if (err)1267 return err;1268 err = phy_write(phydev, 16, errata_vals[i].reg16);1269 if (err)1270 return err;1271 }1272 1273 err = marvell_set_page(phydev, 0x00FB);1274 if (err < 0)1275 return err;1276 err = phy_write(phydev, 07, 0xC00D);1277 if (err < 0)1278 return err;1279 err = marvell_set_page(phydev, MII_MARVELL_COPPER_PAGE);1280 if (err < 0)1281 return err;1282 1283 /* SGMII-to-Copper mode initialization */1284 if (phydev->interface == PHY_INTERFACE_MODE_SGMII) {1285 /* Select page 18 */1286 err = marvell_set_page(phydev, 18);1287 if (err < 0)1288 return err;1289 1290 /* In reg 20, write MODE[2:0] = 0x1 (SGMII to Copper) */1291 err = phy_modify(phydev, MII_88E1510_GEN_CTRL_REG_1,1292 MII_88E1510_GEN_CTRL_REG_1_MODE_MASK,1293 MII_88E1510_GEN_CTRL_REG_1_MODE_SGMII);1294 if (err < 0)1295 return err;1296 1297 /* PHY reset is necessary after changing MODE[2:0] */1298 err = phy_set_bits(phydev, MII_88E1510_GEN_CTRL_REG_1,1299 MII_88E1510_GEN_CTRL_REG_1_RESET);1300 if (err < 0)1301 return err;1302 1303 /* Reset page selection */1304 err = marvell_set_page(phydev, MII_MARVELL_COPPER_PAGE);1305 if (err < 0)1306 return err;1307 }1308 err = m88e1011_set_downshift(phydev, 3);1309 if (err < 0)1310 return err;1311 1312 return m88e1318_config_init(phydev);1313}1314 1315static int m88e1118_config_aneg(struct phy_device *phydev)1316{1317 int err;1318 1319 err = marvell_set_polarity(phydev, phydev->mdix_ctrl);1320 if (err < 0)1321 return err;1322 1323 err = genphy_config_aneg(phydev);1324 if (err < 0)1325 return err;1326 1327 return genphy_soft_reset(phydev);1328}1329 1330static int m88e1118_config_init(struct phy_device *phydev)1331{1332 u16 leds;1333 int err;1334 1335 /* Enable 1000 Mbit */1336 err = phy_write_paged(phydev, MII_MARVELL_MSCR_PAGE,1337 MII_88E1121_PHY_MSCR_REG, 0x1070);1338 if (err < 0)1339 return err;1340 1341 if (phy_interface_is_rgmii(phydev)) {1342 err = m88e1121_config_aneg_rgmii_delays(phydev);1343 if (err < 0)1344 return err;1345 }1346 1347 /* Adjust LED Control */1348 if (phydev->dev_flags & MARVELL_PHY_M1118_DNS323_LEDS)1349 leds = 0x1100;1350 else1351 leds = 0x021e;1352 1353 err = phy_write_paged(phydev, MII_MARVELL_LED_PAGE, 0x10, leds);1354 if (err < 0)1355 return err;1356 1357 err = marvell_of_reg_init(phydev);1358 if (err < 0)1359 return err;1360 1361 /* Reset page register */1362 err = marvell_set_page(phydev, MII_MARVELL_COPPER_PAGE);1363 if (err < 0)1364 return err;1365 1366 return genphy_soft_reset(phydev);1367}1368 1369static int m88e1149_config_init(struct phy_device *phydev)1370{1371 int err;1372 1373 /* Change address */1374 err = marvell_set_page(phydev, MII_MARVELL_MSCR_PAGE);1375 if (err < 0)1376 return err;1377 1378 /* Enable 1000 Mbit */1379 err = phy_write(phydev, 0x15, 0x1048);1380 if (err < 0)1381 return err;1382 1383 err = marvell_of_reg_init(phydev);1384 if (err < 0)1385 return err;1386 1387 /* Reset address */1388 err = marvell_set_page(phydev, MII_MARVELL_COPPER_PAGE);1389 if (err < 0)1390 return err;1391 1392 return genphy_soft_reset(phydev);1393}1394 1395static int m88e1145_config_init_rgmii(struct phy_device *phydev)1396{1397 int err;1398 1399 err = m88e1111_config_init_rgmii_delays(phydev);1400 if (err < 0)1401 return err;1402 1403 if (phydev->dev_flags & MARVELL_PHY_M1145_FLAGS_RESISTANCE) {1404 err = phy_write(phydev, 0x1d, 0x0012);1405 if (err < 0)1406 return err;1407 1408 err = phy_modify(phydev, 0x1e, 0x0fc0,1409 2 << 9 | /* 36 ohm */1410 2 << 6); /* 39 ohm */1411 if (err < 0)1412 return err;1413 1414 err = phy_write(phydev, 0x1d, 0x3);1415 if (err < 0)1416 return err;1417 1418 err = phy_write(phydev, 0x1e, 0x8000);1419 }1420 return err;1421}1422 1423static int m88e1145_config_init_sgmii(struct phy_device *phydev)1424{1425 return m88e1111_config_init_hwcfg_mode(1426 phydev, MII_M1111_HWCFG_MODE_SGMII_NO_CLK,1427 MII_M1111_HWCFG_FIBER_COPPER_AUTO);1428}1429 1430static int m88e1145_config_init(struct phy_device *phydev)1431{1432 int err;1433 1434 /* Take care of errata E0 & E1 */1435 err = phy_write(phydev, 0x1d, 0x001b);1436 if (err < 0)1437 return err;1438 1439 err = phy_write(phydev, 0x1e, 0x418f);1440 if (err < 0)1441 return err;1442 1443 err = phy_write(phydev, 0x1d, 0x0016);1444 if (err < 0)1445 return err;1446 1447 err = phy_write(phydev, 0x1e, 0xa2da);1448 if (err < 0)1449 return err;1450 1451 if (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID) {1452 err = m88e1145_config_init_rgmii(phydev);1453 if (err < 0)1454 return err;1455 }1456 1457 if (phydev->interface == PHY_INTERFACE_MODE_SGMII) {1458 err = m88e1145_config_init_sgmii(phydev);1459 if (err < 0)1460 return err;1461 }1462 err = m88e1111_set_downshift(phydev, 3);1463 if (err < 0)1464 return err;1465 1466 err = marvell_of_reg_init(phydev);1467 if (err < 0)1468 return err;1469 1470 return 0;1471}1472 1473static int m88e1540_get_fld(struct phy_device *phydev, u8 *msecs)1474{1475 int val;1476 1477 val = phy_read(phydev, MII_88E1540_COPPER_CTRL3);1478 if (val < 0)1479 return val;1480 1481 if (!(val & MII_88E1540_COPPER_CTRL3_FAST_LINK_DOWN)) {1482 *msecs = ETHTOOL_PHY_FAST_LINK_DOWN_OFF;1483 return 0;1484 }1485 1486 val = FIELD_GET(MII_88E1540_COPPER_CTRL3_LINK_DOWN_DELAY_MASK, val);1487 1488 switch (val) {1489 case MII_88E1540_COPPER_CTRL3_LINK_DOWN_DELAY_00MS:1490 *msecs = 0;1491 break;1492 case MII_88E1540_COPPER_CTRL3_LINK_DOWN_DELAY_10MS:1493 *msecs = 10;1494 break;1495 case MII_88E1540_COPPER_CTRL3_LINK_DOWN_DELAY_20MS:1496 *msecs = 20;1497 break;1498 case MII_88E1540_COPPER_CTRL3_LINK_DOWN_DELAY_40MS:1499 *msecs = 40;1500 break;1501 default:1502 return -EINVAL;1503 }1504 1505 return 0;1506}1507 1508static int m88e1540_set_fld(struct phy_device *phydev, const u8 *msecs)1509{1510 struct ethtool_keee eee;1511 int val, ret;1512 1513 if (*msecs == ETHTOOL_PHY_FAST_LINK_DOWN_OFF)1514 return phy_clear_bits(phydev, MII_88E1540_COPPER_CTRL3,1515 MII_88E1540_COPPER_CTRL3_FAST_LINK_DOWN);1516 1517 /* According to the Marvell data sheet EEE must be disabled for1518 * Fast Link Down detection to work properly1519 */1520 ret = genphy_c45_ethtool_get_eee(phydev, &eee);1521 if (!ret && eee.eee_enabled) {1522 phydev_warn(phydev, "Fast Link Down detection requires EEE to be disabled!\n");1523 return -EBUSY;1524 }1525 1526 if (*msecs <= 5)1527 val = MII_88E1540_COPPER_CTRL3_LINK_DOWN_DELAY_00MS;1528 else if (*msecs <= 15)1529 val = MII_88E1540_COPPER_CTRL3_LINK_DOWN_DELAY_10MS;1530 else if (*msecs <= 30)1531 val = MII_88E1540_COPPER_CTRL3_LINK_DOWN_DELAY_20MS;1532 else1533 val = MII_88E1540_COPPER_CTRL3_LINK_DOWN_DELAY_40MS;1534 1535 val = FIELD_PREP(MII_88E1540_COPPER_CTRL3_LINK_DOWN_DELAY_MASK, val);1536 1537 ret = phy_modify(phydev, MII_88E1540_COPPER_CTRL3,1538 MII_88E1540_COPPER_CTRL3_LINK_DOWN_DELAY_MASK, val);1539 if (ret)1540 return ret;1541 1542 return phy_set_bits(phydev, MII_88E1540_COPPER_CTRL3,1543 MII_88E1540_COPPER_CTRL3_FAST_LINK_DOWN);1544}1545 1546static int m88e1540_get_tunable(struct phy_device *phydev,1547 struct ethtool_tunable *tuna, void *data)1548{1549 switch (tuna->id) {1550 case ETHTOOL_PHY_FAST_LINK_DOWN:1551 return m88e1540_get_fld(phydev, data);1552 case ETHTOOL_PHY_DOWNSHIFT:1553 return m88e1011_get_downshift(phydev, data);1554 default:1555 return -EOPNOTSUPP;1556 }1557}1558 1559static int m88e1540_set_tunable(struct phy_device *phydev,1560 struct ethtool_tunable *tuna, const void *data)1561{1562 switch (tuna->id) {1563 case ETHTOOL_PHY_FAST_LINK_DOWN:1564 return m88e1540_set_fld(phydev, data);1565 case ETHTOOL_PHY_DOWNSHIFT:1566 return m88e1011_set_downshift(phydev, *(const u8 *)data);1567 default:1568 return -EOPNOTSUPP;1569 }1570}1571 1572/* The VOD can be out of specification on link up. Poke an1573 * undocumented register, in an undocumented page, with a magic value1574 * to fix this.1575 */1576static int m88e6390_errata(struct phy_device *phydev)1577{1578 int err;1579 1580 err = phy_write(phydev, MII_BMCR,1581 BMCR_ANENABLE | BMCR_SPEED1000 | BMCR_FULLDPLX);1582 if (err)1583 return err;1584 1585 usleep_range(300, 400);1586 1587 err = phy_write_paged(phydev, 0xf8, 0x08, 0x36);1588 if (err)1589 return err;1590 1591 return genphy_soft_reset(phydev);1592}1593 1594static int m88e6390_config_aneg(struct phy_device *phydev)1595{1596 int err;1597 1598 err = m88e6390_errata(phydev);1599 if (err)1600 return err;1601 1602 return m88e1510_config_aneg(phydev);1603}1604 1605/**1606 * fiber_lpa_mod_linkmode_lpa_t1607 * @advertising: the linkmode advertisement settings1608 * @lpa: value of the MII_LPA register for fiber link1609 *1610 * A small helper function that translates MII_LPA bits to linkmode LP1611 * advertisement settings. Other bits in advertising are left1612 * unchanged.1613 */1614static void fiber_lpa_mod_linkmode_lpa_t(unsigned long *advertising, u32 lpa)1615{1616 linkmode_mod_bit(ETHTOOL_LINK_MODE_1000baseT_Half_BIT,1617 advertising, lpa & LPA_1000XHALF);1618 1619 linkmode_mod_bit(ETHTOOL_LINK_MODE_1000baseT_Full_BIT,1620 advertising, lpa & LPA_1000XFULL);1621}1622 1623static int marvell_read_status_page_an(struct phy_device *phydev,1624 int fiber, int status)1625{1626 int lpa;1627 int err;1628 1629 if (!(status & MII_M1011_PHY_STATUS_RESOLVED)) {1630 phydev->link = 0;1631 return 0;1632 }1633 1634 if (status & MII_M1011_PHY_STATUS_FULLDUPLEX)1635 phydev->duplex = DUPLEX_FULL;1636 else1637 phydev->duplex = DUPLEX_HALF;1638 1639 switch (status & MII_M1011_PHY_STATUS_SPD_MASK) {1640 case MII_M1011_PHY_STATUS_1000:1641 phydev->speed = SPEED_1000;1642 break;1643 1644 case MII_M1011_PHY_STATUS_100:1645 phydev->speed = SPEED_100;1646 break;1647 1648 default:1649 phydev->speed = SPEED_10;1650 break;1651 }1652 1653 if (!fiber) {1654 err = genphy_read_lpa(phydev);1655 if (err < 0)1656 return err;1657 1658 phy_resolve_aneg_pause(phydev);1659 } else {1660 lpa = phy_read(phydev, MII_LPA);1661 if (lpa < 0)1662 return lpa;1663 1664 /* The fiber link is only 1000M capable */1665 fiber_lpa_mod_linkmode_lpa_t(phydev->lp_advertising, lpa);1666 1667 if (phydev->duplex == DUPLEX_FULL) {1668 if (!(lpa & LPA_PAUSE_FIBER)) {1669 phydev->pause = 0;1670 phydev->asym_pause = 0;1671 } else if ((lpa & LPA_PAUSE_ASYM_FIBER)) {1672 phydev->pause = 1;1673 phydev->asym_pause = 1;1674 } else {1675 phydev->pause = 1;1676 phydev->asym_pause = 0;1677 }1678 }1679 }1680 1681 return 0;1682}1683 1684/* marvell_read_status_page1685 *1686 * Description:1687 * Check the link, then figure out the current state1688 * by comparing what we advertise with what the link partner1689 * advertises. Start by checking the gigabit possibilities,1690 * then move on to 10/100.1691 */1692static int marvell_read_status_page(struct phy_device *phydev, int page)1693{1694 int status;1695 int fiber;1696 int err;1697 1698 status = phy_read(phydev, MII_M1011_PHY_STATUS);1699 if (status < 0)1700 return status;1701 1702 /* Use the generic register for copper link status,1703 * and the PHY status register for fiber link status.1704 */1705 if (page == MII_MARVELL_FIBER_PAGE) {1706 phydev->link = !!(status & MII_M1011_PHY_STATUS_LINK);1707 } else {1708 err = genphy_update_link(phydev);1709 if (err)1710 return err;1711 }1712 1713 if (page == MII_MARVELL_FIBER_PAGE)1714 fiber = 1;1715 else1716 fiber = 0;1717 1718 linkmode_zero(phydev->lp_advertising);1719 phydev->pause = 0;1720 phydev->asym_pause = 0;1721 phydev->speed = SPEED_UNKNOWN;1722 phydev->duplex = DUPLEX_UNKNOWN;1723 phydev->port = fiber ? PORT_FIBRE : PORT_TP;1724 1725 if (phydev->autoneg == AUTONEG_ENABLE)1726 err = marvell_read_status_page_an(phydev, fiber, status);1727 else1728 err = genphy_read_status_fixed(phydev);1729 1730 return err;1731}1732 1733/* marvell_read_status1734 *1735 * Some Marvell's phys have two modes: fiber and copper.1736 * Both need status checked.1737 * Description:1738 * First, check the fiber link and status.1739 * If the fiber link is down, check the copper link and status which1740 * will be the default value if both link are down.1741 */1742static int marvell_read_status(struct phy_device *phydev)1743{1744 int err;1745 1746 /* Check the fiber mode first */1747 if (linkmode_test_bit(ETHTOOL_LINK_MODE_FIBRE_BIT,1748 phydev->supported) &&1749 phydev->interface != PHY_INTERFACE_MODE_SGMII) {1750 err = marvell_set_page(phydev, MII_MARVELL_FIBER_PAGE);1751 if (err < 0)1752 goto error;1753 1754 err = marvell_read_status_page(phydev, MII_MARVELL_FIBER_PAGE);1755 if (err < 0)1756 goto error;1757 1758 /* If the fiber link is up, it is the selected and1759 * used link. In this case, we need to stay in the1760 * fiber page. Please to be careful about that, avoid1761 * to restore Copper page in other functions which1762 * could break the behaviour for some fiber phy like1763 * 88E1512.1764 */1765 if (phydev->link)1766 return 0;1767 1768 /* If fiber link is down, check and save copper mode state */1769 err = marvell_set_page(phydev, MII_MARVELL_COPPER_PAGE);1770 if (err < 0)1771 goto error;1772 }1773 1774 return marvell_read_status_page(phydev, MII_MARVELL_COPPER_PAGE);1775 1776error:1777 marvell_set_page(phydev, MII_MARVELL_COPPER_PAGE);1778 return err;1779}1780 1781/* marvell_suspend1782 *1783 * Some Marvell's phys have two modes: fiber and copper.1784 * Both need to be suspended1785 */1786static int marvell_suspend(struct phy_device *phydev)1787{1788 int err;1789 1790 /* Suspend the fiber mode first */1791 if (linkmode_test_bit(ETHTOOL_LINK_MODE_FIBRE_BIT,1792 phydev->supported)) {1793 err = marvell_set_page(phydev, MII_MARVELL_FIBER_PAGE);1794 if (err < 0)1795 goto error;1796 1797 /* With the page set, use the generic suspend */1798 err = genphy_suspend(phydev);1799 if (err < 0)1800 goto error;1801 1802 /* Then, the copper link */1803 err = marvell_set_page(phydev, MII_MARVELL_COPPER_PAGE);1804 if (err < 0)1805 goto error;1806 }1807 1808 /* With the page set, use the generic suspend */1809 return genphy_suspend(phydev);1810 1811error:1812 marvell_set_page(phydev, MII_MARVELL_COPPER_PAGE);1813 return err;1814}1815 1816/* marvell_resume1817 *1818 * Some Marvell's phys have two modes: fiber and copper.1819 * Both need to be resumed1820 */1821static int marvell_resume(struct phy_device *phydev)1822{1823 int err;1824 1825 /* Resume the fiber mode first */1826 if (linkmode_test_bit(ETHTOOL_LINK_MODE_FIBRE_BIT,1827 phydev->supported)) {1828 err = marvell_set_page(phydev, MII_MARVELL_FIBER_PAGE);1829 if (err < 0)1830 goto error;1831 1832 /* With the page set, use the generic resume */1833 err = genphy_resume(phydev);1834 if (err < 0)1835 goto error;1836 1837 /* Then, the copper link */1838 err = marvell_set_page(phydev, MII_MARVELL_COPPER_PAGE);1839 if (err < 0)1840 goto error;1841 }1842 1843 /* With the page set, use the generic resume */1844 return genphy_resume(phydev);1845 1846error:1847 marvell_set_page(phydev, MII_MARVELL_COPPER_PAGE);1848 return err;1849}1850 1851static int marvell_aneg_done(struct phy_device *phydev)1852{1853 int retval = phy_read(phydev, MII_M1011_PHY_STATUS);1854 1855 return (retval < 0) ? retval : (retval & MII_M1011_PHY_STATUS_RESOLVED);1856}1857 1858static void m88e1318_get_wol(struct phy_device *phydev,1859 struct ethtool_wolinfo *wol)1860{1861 int ret;1862 1863 wol->supported = WAKE_MAGIC | WAKE_PHY;1864 wol->wolopts = 0;1865 1866 ret = phy_read_paged(phydev, MII_MARVELL_WOL_PAGE,1867 MII_88E1318S_PHY_WOL_CTRL);1868 if (ret < 0)1869 return;1870 1871 if (ret & MII_88E1318S_PHY_WOL_CTRL_MAGIC_PACKET_MATCH_ENABLE)1872 wol->wolopts |= WAKE_MAGIC;1873 1874 if (ret & MII_88E1318S_PHY_WOL_CTRL_LINK_UP_ENABLE)1875 wol->wolopts |= WAKE_PHY;1876}1877 1878static int m88e1318_set_wol(struct phy_device *phydev,1879 struct ethtool_wolinfo *wol)1880{1881 int err = 0, oldpage;1882 1883 oldpage = phy_save_page(phydev);1884 if (oldpage < 0)1885 goto error;1886 1887 if (wol->wolopts & (WAKE_MAGIC | WAKE_PHY)) {1888 /* Explicitly switch to page 0x00, just to be sure */1889 err = marvell_write_page(phydev, MII_MARVELL_COPPER_PAGE);1890 if (err < 0)1891 goto error;1892 1893 /* If WOL event happened once, the LED[2] interrupt pin1894 * will not be cleared unless we reading the interrupt status1895 * register. If interrupts are in use, the normal interrupt1896 * handling will clear the WOL event. Clear the WOL event1897 * before enabling it if !phy_interrupt_is_valid()1898 */1899 if (!phy_interrupt_is_valid(phydev))1900 __phy_read(phydev, MII_M1011_IEVENT);1901 1902 /* Enable the WOL interrupt */1903 err = __phy_set_bits(phydev, MII_88E1318S_PHY_CSIER,1904 MII_88E1318S_PHY_CSIER_WOL_EIE);1905 if (err < 0)1906 goto error;1907 1908 err = marvell_write_page(phydev, MII_MARVELL_LED_PAGE);1909 if (err < 0)1910 goto error;1911 1912 /* Setup LED[2] as interrupt pin (active low) */1913 err = __phy_modify(phydev, MII_88E1318S_PHY_LED_TCR,1914 MII_88E1318S_PHY_LED_TCR_FORCE_INT,1915 MII_88E1318S_PHY_LED_TCR_INTn_ENABLE |1916 MII_88E1318S_PHY_LED_TCR_INT_ACTIVE_LOW);1917 if (err < 0)1918 goto error;1919 }1920 1921 if (wol->wolopts & WAKE_MAGIC) {1922 err = marvell_write_page(phydev, MII_MARVELL_WOL_PAGE);1923 if (err < 0)1924 goto error;1925 1926 /* Store the device address for the magic packet */1927 err = __phy_write(phydev, MII_88E1318S_PHY_MAGIC_PACKET_WORD2,1928 ((phydev->attached_dev->dev_addr[5] << 8) |1929 phydev->attached_dev->dev_addr[4]));1930 if (err < 0)1931 goto error;1932 err = __phy_write(phydev, MII_88E1318S_PHY_MAGIC_PACKET_WORD1,1933 ((phydev->attached_dev->dev_addr[3] << 8) |1934 phydev->attached_dev->dev_addr[2]));1935 if (err < 0)1936 goto error;1937 err = __phy_write(phydev, MII_88E1318S_PHY_MAGIC_PACKET_WORD0,1938 ((phydev->attached_dev->dev_addr[1] << 8) |1939 phydev->attached_dev->dev_addr[0]));1940 if (err < 0)1941 goto error;1942 1943 /* Clear WOL status and enable magic packet matching */1944 err = __phy_set_bits(phydev, MII_88E1318S_PHY_WOL_CTRL,1945 MII_88E1318S_PHY_WOL_CTRL_CLEAR_WOL_STATUS |1946 MII_88E1318S_PHY_WOL_CTRL_MAGIC_PACKET_MATCH_ENABLE);1947 if (err < 0)1948 goto error;1949 } else {1950 err = marvell_write_page(phydev, MII_MARVELL_WOL_PAGE);1951 if (err < 0)1952 goto error;1953 1954 /* Clear WOL status and disable magic packet matching */1955 err = __phy_modify(phydev, MII_88E1318S_PHY_WOL_CTRL,1956 MII_88E1318S_PHY_WOL_CTRL_MAGIC_PACKET_MATCH_ENABLE,1957 MII_88E1318S_PHY_WOL_CTRL_CLEAR_WOL_STATUS);1958 if (err < 0)1959 goto error;1960 }1961 1962 if (wol->wolopts & WAKE_PHY) {1963 err = marvell_write_page(phydev, MII_MARVELL_WOL_PAGE);1964 if (err < 0)1965 goto error;1966 1967 /* Clear WOL status and enable link up event */1968 err = __phy_modify(phydev, MII_88E1318S_PHY_WOL_CTRL, 0,1969 MII_88E1318S_PHY_WOL_CTRL_CLEAR_WOL_STATUS |1970 MII_88E1318S_PHY_WOL_CTRL_LINK_UP_ENABLE);1971 if (err < 0)1972 goto error;1973 } else {1974 err = marvell_write_page(phydev, MII_MARVELL_WOL_PAGE);1975 if (err < 0)1976 goto error;1977 1978 /* Clear WOL status and disable link up event */1979 err = __phy_modify(phydev, MII_88E1318S_PHY_WOL_CTRL,1980 MII_88E1318S_PHY_WOL_CTRL_LINK_UP_ENABLE,1981 MII_88E1318S_PHY_WOL_CTRL_CLEAR_WOL_STATUS);1982 if (err < 0)1983 goto error;1984 }1985 1986error:1987 return phy_restore_page(phydev, oldpage, err);1988}1989 1990static int marvell_get_sset_count(struct phy_device *phydev)1991{1992 if (linkmode_test_bit(ETHTOOL_LINK_MODE_FIBRE_BIT,1993 phydev->supported))1994 return ARRAY_SIZE(marvell_hw_stats);1995 else1996 return ARRAY_SIZE(marvell_hw_stats) - NB_FIBER_STATS;1997}1998 1999static int marvell_get_sset_count_simple(struct phy_device *phydev)2000{2001 return ARRAY_SIZE(marvell_hw_stats_simple);2002}2003 2004static void marvell_get_strings(struct phy_device *phydev, u8 *data)2005{2006 int count = marvell_get_sset_count(phydev);2007 int i;2008 2009 for (i = 0; i < count; i++) {2010 strscpy(data + i * ETH_GSTRING_LEN,2011 marvell_hw_stats[i].string, ETH_GSTRING_LEN);2012 }2013}2014 2015static void marvell_get_strings_simple(struct phy_device *phydev, u8 *data)2016{2017 int count = marvell_get_sset_count_simple(phydev);2018 int i;2019 2020 for (i = 0; i < count; i++) {2021 strscpy(data + i * ETH_GSTRING_LEN,2022 marvell_hw_stats_simple[i].string, ETH_GSTRING_LEN);2023 }2024}2025 2026static u64 marvell_get_stat(struct phy_device *phydev, int i)2027{2028 struct marvell_hw_stat stat = marvell_hw_stats[i];2029 struct marvell_priv *priv = phydev->priv;2030 int val;2031 u64 ret;2032 2033 val = phy_read_paged(phydev, stat.page, stat.reg);2034 if (val < 0) {2035 ret = U64_MAX;2036 } else {2037 val = val & ((1 << stat.bits) - 1);2038 priv->stats[i] += val;2039 ret = priv->stats[i];2040 }2041 2042 return ret;2043}2044 2045static u64 marvell_get_stat_simple(struct phy_device *phydev, int i)2046{2047 struct marvell_hw_stat_simple stat = marvell_hw_stats_simple[i];2048 struct marvell_priv *priv = phydev->priv;2049 int val;2050 u64 ret;2051 2052 val = phy_read(phydev, stat.reg);2053 if (val < 0) {2054 ret = U64_MAX;2055 } else {2056 val = val & ((1 << stat.bits) - 1);2057 priv->stats[i] += val;2058 ret = priv->stats[i];2059 }2060 2061 return ret;2062}2063 2064static void marvell_get_stats(struct phy_device *phydev,2065 struct ethtool_stats *stats, u64 *data)2066{2067 int count = marvell_get_sset_count(phydev);2068 int i;2069 2070 for (i = 0; i < count; i++)2071 data[i] = marvell_get_stat(phydev, i);2072}2073 2074static void marvell_get_stats_simple(struct phy_device *phydev,2075 struct ethtool_stats *stats, u64 *data)2076{2077 int count = marvell_get_sset_count_simple(phydev);2078 int i;2079 2080 for (i = 0; i < count; i++)2081 data[i] = marvell_get_stat_simple(phydev, i);2082}2083 2084static int m88e1510_loopback(struct phy_device *phydev, bool enable)2085{2086 int err;2087 2088 if (enable) {2089 u16 bmcr_ctl, mscr2_ctl = 0;2090 2091 bmcr_ctl = mii_bmcr_encode_fixed(phydev->speed, phydev->duplex);2092 2093 err = phy_write(phydev, MII_BMCR, bmcr_ctl);2094 if (err < 0)2095 return err;2096 2097 if (phydev->speed == SPEED_1000)2098 mscr2_ctl = BMCR_SPEED1000;2099 else if (phydev->speed == SPEED_100)2100 mscr2_ctl = BMCR_SPEED100;2101 2102 err = phy_modify_paged(phydev, MII_MARVELL_MSCR_PAGE,2103 MII_88E1510_MSCR_2, BMCR_SPEED1000 |2104 BMCR_SPEED100, mscr2_ctl);2105 if (err < 0)2106 return err;2107 2108 /* Need soft reset to have speed configuration takes effect */2109 err = genphy_soft_reset(phydev);2110 if (err < 0)2111 return err;2112 2113 err = phy_modify(phydev, MII_BMCR, BMCR_LOOPBACK,2114 BMCR_LOOPBACK);2115 2116 if (!err) {2117 /* It takes some time for PHY device to switch2118 * into/out-of loopback mode.2119 */2120 msleep(1000);2121 }2122 return err;2123 } else {2124 err = phy_modify(phydev, MII_BMCR, BMCR_LOOPBACK, 0);2125 if (err < 0)2126 return err;2127 2128 return phy_config_aneg(phydev);2129 }2130}2131 2132static int marvell_vct5_wait_complete(struct phy_device *phydev)2133{2134 int i;2135 int val;2136 2137 for (i = 0; i < 32; i++) {2138 val = __phy_read(phydev, MII_VCT5_CTRL);2139 if (val < 0)2140 return val;2141 2142 if (val & MII_VCT5_CTRL_COMPLETE)2143 return 0;2144 }2145 2146 phydev_err(phydev, "Timeout while waiting for cable test to finish\n");2147 return -ETIMEDOUT;2148}2149 2150static int marvell_vct5_amplitude(struct phy_device *phydev, int pair)2151{2152 int amplitude;2153 int val;2154 int reg;2155 2156 reg = MII_VCT5_TX_RX_MDI0_COUPLING + pair;2157 val = __phy_read(phydev, reg);2158 2159 if (val < 0)2160 return 0;2161 2162 amplitude = (val & MII_VCT5_TX_RX_AMPLITUDE_MASK) >>2163 MII_VCT5_TX_RX_AMPLITUDE_SHIFT;2164 2165 if (!(val & MII_VCT5_TX_RX_COUPLING_POSITIVE_REFLECTION))2166 amplitude = -amplitude;2167 2168 return 1000 * amplitude / 128;2169}2170 2171static u32 marvell_vct5_distance2cm(int distance)2172{2173 return distance * 805 / 10;2174}2175 2176static u32 marvell_vct5_cm2distance(int cm)2177{2178 return cm * 10 / 805;2179}2180 2181static int marvell_vct5_amplitude_distance(struct phy_device *phydev,2182 int distance, int pair)2183{2184 u16 reg;2185 int err;2186 int mV;2187 int i;2188 2189 err = __phy_write(phydev, MII_VCT5_SAMPLE_POINT_DISTANCE,2190 distance);2191 if (err)2192 return err;2193 2194 reg = MII_VCT5_CTRL_ENABLE |2195 MII_VCT5_CTRL_TX_SAME_CHANNEL |2196 MII_VCT5_CTRL_SAMPLES_DEFAULT |2197 MII_VCT5_CTRL_SAMPLE_POINT |2198 MII_VCT5_CTRL_PEEK_HYST_DEFAULT;2199 err = __phy_write(phydev, MII_VCT5_CTRL, reg);2200 if (err)2201 return err;2202 2203 err = marvell_vct5_wait_complete(phydev);2204 if (err)2205 return err;2206 2207 for (i = 0; i < 4; i++) {2208 if (pair != PHY_PAIR_ALL && i != pair)2209 continue;2210 2211 mV = marvell_vct5_amplitude(phydev, i);2212 ethnl_cable_test_amplitude(phydev, i, mV);2213 }2214 2215 return 0;2216}2217 2218static int marvell_vct5_amplitude_graph(struct phy_device *phydev)2219{2220 struct marvell_priv *priv = phydev->priv;2221 int distance;2222 u16 width;2223 int page;2224 int err;2225 u16 reg;2226 2227 if (priv->first <= TDR_SHORT_CABLE_LENGTH)2228 width = MII_VCT5_TX_PULSE_CTRL_PULSE_WIDTH_32nS;2229 else2230 width = MII_VCT5_TX_PULSE_CTRL_PULSE_WIDTH_128nS;2231 2232 reg = MII_VCT5_TX_PULSE_CTRL_GT_140m_46_86mV |2233 MII_VCT5_TX_PULSE_CTRL_DONT_WAIT_LINK_DOWN |2234 MII_VCT5_TX_PULSE_CTRL_MAX_AMP | width;2235 2236 err = phy_write_paged(phydev, MII_MARVELL_VCT5_PAGE,2237 MII_VCT5_TX_PULSE_CTRL, reg);2238 if (err)2239 return err;2240 2241 /* Reading the TDR data is very MDIO heavy. We need to optimize2242 * access to keep the time to a minimum. So lock the bus once,2243 * and don't release it until complete. We can then avoid having2244 * to change the page for every access, greatly speeding things2245 * up.2246 */2247 page = phy_select_page(phydev, MII_MARVELL_VCT5_PAGE);2248 if (page < 0)2249 goto restore_page;2250 2251 for (distance = priv->first;2252 distance <= priv->last;2253 distance += priv->step) {2254 err = marvell_vct5_amplitude_distance(phydev, distance,2255 priv->pair);2256 if (err)2257 goto restore_page;2258 2259 if (distance > TDR_SHORT_CABLE_LENGTH &&2260 width == MII_VCT5_TX_PULSE_CTRL_PULSE_WIDTH_32nS) {2261 width = MII_VCT5_TX_PULSE_CTRL_PULSE_WIDTH_128nS;2262 reg = MII_VCT5_TX_PULSE_CTRL_GT_140m_46_86mV |2263 MII_VCT5_TX_PULSE_CTRL_DONT_WAIT_LINK_DOWN |2264 MII_VCT5_TX_PULSE_CTRL_MAX_AMP | width;2265 err = __phy_write(phydev, MII_VCT5_TX_PULSE_CTRL, reg);2266 if (err)2267 goto restore_page;2268 }2269 }2270 2271restore_page:2272 return phy_restore_page(phydev, page, err);2273}2274 2275static int marvell_cable_test_start_common(struct phy_device *phydev)2276{2277 int bmcr, bmsr, ret;2278 2279 /* If auto-negotiation is enabled, but not complete, the cable2280 * test never completes. So disable auto-neg.2281 */2282 bmcr = phy_read(phydev, MII_BMCR);2283 if (bmcr < 0)2284 return bmcr;2285 2286 bmsr = phy_read(phydev, MII_BMSR);2287 2288 if (bmsr < 0)2289 return bmsr;2290 2291 if (bmcr & BMCR_ANENABLE) {2292 ret = phy_clear_bits(phydev, MII_BMCR, BMCR_ANENABLE);2293 if (ret < 0)2294 return ret;2295 ret = genphy_soft_reset(phydev);2296 if (ret < 0)2297 return ret;2298 }2299 2300 /* If the link is up, allow it some time to go down */2301 if (bmsr & BMSR_LSTATUS)2302 msleep(1500);2303 2304 return 0;2305}2306 2307static int marvell_vct7_cable_test_start(struct phy_device *phydev)2308{2309 struct marvell_priv *priv = phydev->priv;2310 int ret;2311 2312 ret = marvell_cable_test_start_common(phydev);2313 if (ret)2314 return ret;2315 2316 priv->cable_test_tdr = false;2317 2318 /* Reset the VCT5 API control to defaults, otherwise2319 * VCT7 does not work correctly.2320 */2321 ret = phy_write_paged(phydev, MII_MARVELL_VCT5_PAGE,2322 MII_VCT5_CTRL,2323 MII_VCT5_CTRL_TX_SAME_CHANNEL |2324 MII_VCT5_CTRL_SAMPLES_DEFAULT |2325 MII_VCT5_CTRL_MODE_MAXIMUM_PEEK |2326 MII_VCT5_CTRL_PEEK_HYST_DEFAULT);2327 if (ret)2328 return ret;2329 2330 ret = phy_write_paged(phydev, MII_MARVELL_VCT5_PAGE,2331 MII_VCT5_SAMPLE_POINT_DISTANCE, 0);2332 if (ret)2333 return ret;2334 2335 return phy_write_paged(phydev, MII_MARVELL_VCT7_PAGE,2336 MII_VCT7_CTRL,2337 MII_VCT7_CTRL_RUN_NOW |2338 MII_VCT7_CTRL_CENTIMETERS);2339}2340 2341static int marvell_vct5_cable_test_tdr_start(struct phy_device *phydev,2342 const struct phy_tdr_config *cfg)2343{2344 struct marvell_priv *priv = phydev->priv;2345 int ret;2346 2347 priv->cable_test_tdr = true;2348 priv->first = marvell_vct5_cm2distance(cfg->first);2349 priv->last = marvell_vct5_cm2distance(cfg->last);2350 priv->step = marvell_vct5_cm2distance(cfg->step);2351 priv->pair = cfg->pair;2352 2353 if (priv->first > MII_VCT5_SAMPLE_POINT_DISTANCE_MAX)2354 return -EINVAL;2355 2356 if (priv->last > MII_VCT5_SAMPLE_POINT_DISTANCE_MAX)2357 return -EINVAL;2358 2359 /* Disable VCT7 */2360 ret = phy_write_paged(phydev, MII_MARVELL_VCT7_PAGE,2361 MII_VCT7_CTRL, 0);2362 if (ret)2363 return ret;2364 2365 ret = marvell_cable_test_start_common(phydev);2366 if (ret)2367 return ret;2368 2369 ret = ethnl_cable_test_pulse(phydev, 1000);2370 if (ret)2371 return ret;2372 2373 return ethnl_cable_test_step(phydev,2374 marvell_vct5_distance2cm(priv->first),2375 marvell_vct5_distance2cm(priv->last),2376 marvell_vct5_distance2cm(priv->step));2377}2378 2379static int marvell_vct7_distance_to_length(int distance, bool meter)2380{2381 if (meter)2382 distance *= 100;2383 2384 return distance;2385}2386 2387static bool marvell_vct7_distance_valid(int result)2388{2389 switch (result) {2390 case MII_VCT7_RESULTS_OPEN:2391 case MII_VCT7_RESULTS_SAME_SHORT:2392 case MII_VCT7_RESULTS_CROSS_SHORT:2393 return true;2394 }2395 return false;2396}2397 2398static int marvell_vct7_report_length(struct phy_device *phydev,2399 int pair, bool meter)2400{2401 int length;2402 int ret;2403 2404 ret = phy_read_paged(phydev, MII_MARVELL_VCT7_PAGE,2405 MII_VCT7_PAIR_0_DISTANCE + pair);2406 if (ret < 0)2407 return ret;2408 2409 length = marvell_vct7_distance_to_length(ret, meter);2410 2411 ethnl_cable_test_fault_length(phydev, pair, length);2412 2413 return 0;2414}2415 2416static int marvell_vct7_cable_test_report_trans(int result)2417{2418 switch (result) {2419 case MII_VCT7_RESULTS_OK:2420 return ETHTOOL_A_CABLE_RESULT_CODE_OK;2421 case MII_VCT7_RESULTS_OPEN:2422 return ETHTOOL_A_CABLE_RESULT_CODE_OPEN;2423 case MII_VCT7_RESULTS_SAME_SHORT:2424 return ETHTOOL_A_CABLE_RESULT_CODE_SAME_SHORT;2425 case MII_VCT7_RESULTS_CROSS_SHORT:2426 return ETHTOOL_A_CABLE_RESULT_CODE_CROSS_SHORT;2427 default:2428 return ETHTOOL_A_CABLE_RESULT_CODE_UNSPEC;2429 }2430}2431 2432static int marvell_vct7_cable_test_report(struct phy_device *phydev)2433{2434 int pair0, pair1, pair2, pair3;2435 bool meter;2436 int ret;2437 2438 ret = phy_read_paged(phydev, MII_MARVELL_VCT7_PAGE,2439 MII_VCT7_RESULTS);2440 if (ret < 0)2441 return ret;2442 2443 pair3 = (ret & MII_VCT7_RESULTS_PAIR3_MASK) >>2444 MII_VCT7_RESULTS_PAIR3_SHIFT;2445 pair2 = (ret & MII_VCT7_RESULTS_PAIR2_MASK) >>2446 MII_VCT7_RESULTS_PAIR2_SHIFT;2447 pair1 = (ret & MII_VCT7_RESULTS_PAIR1_MASK) >>2448 MII_VCT7_RESULTS_PAIR1_SHIFT;2449 pair0 = (ret & MII_VCT7_RESULTS_PAIR0_MASK) >>2450 MII_VCT7_RESULTS_PAIR0_SHIFT;2451 2452 ethnl_cable_test_result(phydev, ETHTOOL_A_CABLE_PAIR_A,2453 marvell_vct7_cable_test_report_trans(pair0));2454 ethnl_cable_test_result(phydev, ETHTOOL_A_CABLE_PAIR_B,2455 marvell_vct7_cable_test_report_trans(pair1));2456 ethnl_cable_test_result(phydev, ETHTOOL_A_CABLE_PAIR_C,2457 marvell_vct7_cable_test_report_trans(pair2));2458 ethnl_cable_test_result(phydev, ETHTOOL_A_CABLE_PAIR_D,2459 marvell_vct7_cable_test_report_trans(pair3));2460 2461 ret = phy_read_paged(phydev, MII_MARVELL_VCT7_PAGE, MII_VCT7_CTRL);2462 if (ret < 0)2463 return ret;2464 2465 meter = ret & MII_VCT7_CTRL_METERS;2466 2467 if (marvell_vct7_distance_valid(pair0))2468 marvell_vct7_report_length(phydev, 0, meter);2469 if (marvell_vct7_distance_valid(pair1))2470 marvell_vct7_report_length(phydev, 1, meter);2471 if (marvell_vct7_distance_valid(pair2))2472 marvell_vct7_report_length(phydev, 2, meter);2473 if (marvell_vct7_distance_valid(pair3))2474 marvell_vct7_report_length(phydev, 3, meter);2475 2476 return 0;2477}2478 2479static int marvell_vct7_cable_test_get_status(struct phy_device *phydev,2480 bool *finished)2481{2482 struct marvell_priv *priv = phydev->priv;2483 int ret;2484 2485 if (priv->cable_test_tdr) {2486 ret = marvell_vct5_amplitude_graph(phydev);2487 *finished = true;2488 return ret;2489 }2490 2491 *finished = false;2492 2493 ret = phy_read_paged(phydev, MII_MARVELL_VCT7_PAGE,2494 MII_VCT7_CTRL);2495 2496 if (ret < 0)2497 return ret;2498 2499 if (!(ret & MII_VCT7_CTRL_IN_PROGRESS)) {2500 *finished = true;2501 2502 return marvell_vct7_cable_test_report(phydev);2503 }2504 2505 return 0;2506}2507 2508static int m88e3082_vct_cable_test_start(struct phy_device *phydev)2509{2510 struct marvell_priv *priv = phydev->priv;2511 int ret;2512 2513 /* It needs some magic workarounds described in VCT manual for this PHY.2514 */2515 ret = phy_write(phydev, 29, 0x0003);2516 if (ret < 0)2517 return ret;2518 2519 ret = phy_write(phydev, 30, 0x6440);2520 if (ret < 0)2521 return ret;2522 2523 if (priv->vct_phase == M88E3082_VCT_PHASE1) {2524 ret = phy_write(phydev, 29, 0x000a);2525 if (ret < 0)2526 return ret;2527 2528 ret = phy_write(phydev, 30, 0x0002);2529 if (ret < 0)2530 return ret;2531 }2532 2533 ret = phy_write(phydev, MII_BMCR,2534 BMCR_RESET | BMCR_SPEED100 | BMCR_FULLDPLX);2535 if (ret < 0)2536 return ret;2537 2538 ret = phy_write(phydev, MII_VCT_TXPINS, MII_VCT_TXPINS_ENVCT);2539 if (ret < 0)2540 return ret;2541 2542 ret = phy_write(phydev, 29, 0x0003);2543 if (ret < 0)2544 return ret;2545 2546 ret = phy_write(phydev, 30, 0x0);2547 if (ret < 0)2548 return ret;2549 2550 if (priv->vct_phase == M88E3082_VCT_OFF) {2551 priv->vct_phase = M88E3082_VCT_PHASE1;2552 priv->pair = 0;2553 2554 return 0;2555 }2556 2557 ret = phy_write(phydev, 29, 0x000a);2558 if (ret < 0)2559 return ret;2560 2561 ret = phy_write(phydev, 30, 0x0);2562 if (ret < 0)2563 return ret;2564 2565 priv->vct_phase = M88E3082_VCT_PHASE2;2566 2567 return 0;2568}2569 2570static int m88e3082_vct_cable_test_report_trans(int result, u8 distance)2571{2572 switch (result) {2573 case MII_VCT_TXRXPINS_VCTTST_OK:2574 if (distance == MII_VCT_TXRXPINS_DISTRFLN_MAX)2575 return ETHTOOL_A_CABLE_RESULT_CODE_OK;2576 return ETHTOOL_A_CABLE_RESULT_CODE_IMPEDANCE_MISMATCH;2577 case MII_VCT_TXRXPINS_VCTTST_SHORT:2578 return ETHTOOL_A_CABLE_RESULT_CODE_SAME_SHORT;2579 case MII_VCT_TXRXPINS_VCTTST_OPEN:2580 return ETHTOOL_A_CABLE_RESULT_CODE_OPEN;2581 default:2582 return ETHTOOL_A_CABLE_RESULT_CODE_UNSPEC;2583 }2584}2585 2586static u32 m88e3082_vct_distrfln_2_cm(u8 distrfln)2587{2588 if (distrfln < 24)2589 return 0;2590 2591 /* Original function for meters: y = 0.7861x - 18.862 */2592 return (7861 * distrfln - 188620) / 100;2593}2594 2595static int m88e3082_vct_cable_test_get_status(struct phy_device *phydev,2596 bool *finished)2597{2598 u8 tx_vcttst_res, rx_vcttst_res, tx_distrfln, rx_distrfln;2599 struct marvell_priv *priv = phydev->priv;2600 int ret, tx_result, rx_result;2601 bool done_phase = true;2602 2603 *finished = false;2604 2605 ret = phy_read(phydev, MII_VCT_TXPINS);2606 if (ret < 0)2607 return ret;2608 else if (ret & MII_VCT_TXPINS_ENVCT)2609 return 0;2610 2611 tx_distrfln = ret & MII_VCT_TXRXPINS_DISTRFLN;2612 tx_vcttst_res = (ret & MII_VCT_TXRXPINS_VCTTST) >>2613 MII_VCT_TXRXPINS_VCTTST_SHIFT;2614 2615 ret = phy_read(phydev, MII_VCT_RXPINS);2616 if (ret < 0)2617 return ret;2618 2619 rx_distrfln = ret & MII_VCT_TXRXPINS_DISTRFLN;2620 rx_vcttst_res = (ret & MII_VCT_TXRXPINS_VCTTST) >>2621 MII_VCT_TXRXPINS_VCTTST_SHIFT;2622 2623 *finished = true;2624 2625 switch (priv->vct_phase) {2626 case M88E3082_VCT_PHASE1:2627 tx_result = m88e3082_vct_cable_test_report_trans(tx_vcttst_res,2628 tx_distrfln);2629 rx_result = m88e3082_vct_cable_test_report_trans(rx_vcttst_res,2630 rx_distrfln);2631 2632 ethnl_cable_test_result(phydev, ETHTOOL_A_CABLE_PAIR_A,2633 tx_result);2634 ethnl_cable_test_result(phydev, ETHTOOL_A_CABLE_PAIR_B,2635 rx_result);2636 2637 if (tx_vcttst_res == MII_VCT_TXRXPINS_VCTTST_OPEN) {2638 done_phase = false;2639 priv->pair |= M88E3082_PAIR_A;2640 } else if (tx_distrfln < MII_VCT_TXRXPINS_DISTRFLN_MAX) {2641 u8 pair = ETHTOOL_A_CABLE_PAIR_A;2642 u32 cm = m88e3082_vct_distrfln_2_cm(tx_distrfln);2643 2644 ethnl_cable_test_fault_length(phydev, pair, cm);2645 }2646 2647 if (rx_vcttst_res == MII_VCT_TXRXPINS_VCTTST_OPEN) {2648 done_phase = false;2649 priv->pair |= M88E3082_PAIR_B;2650 } else if (rx_distrfln < MII_VCT_TXRXPINS_DISTRFLN_MAX) {2651 u8 pair = ETHTOOL_A_CABLE_PAIR_B;2652 u32 cm = m88e3082_vct_distrfln_2_cm(rx_distrfln);2653 2654 ethnl_cable_test_fault_length(phydev, pair, cm);2655 }2656 2657 break;2658 case M88E3082_VCT_PHASE2:2659 if (priv->pair & M88E3082_PAIR_A &&2660 tx_vcttst_res == MII_VCT_TXRXPINS_VCTTST_OPEN &&2661 tx_distrfln < MII_VCT_TXRXPINS_DISTRFLN_MAX) {2662 u8 pair = ETHTOOL_A_CABLE_PAIR_A;2663 u32 cm = m88e3082_vct_distrfln_2_cm(tx_distrfln);2664 2665 ethnl_cable_test_fault_length(phydev, pair, cm);2666 }2667 if (priv->pair & M88E3082_PAIR_B &&2668 rx_vcttst_res == MII_VCT_TXRXPINS_VCTTST_OPEN &&2669 rx_distrfln < MII_VCT_TXRXPINS_DISTRFLN_MAX) {2670 u8 pair = ETHTOOL_A_CABLE_PAIR_B;2671 u32 cm = m88e3082_vct_distrfln_2_cm(rx_distrfln);2672 2673 ethnl_cable_test_fault_length(phydev, pair, cm);2674 }2675 2676 break;2677 default:2678 return -EINVAL;2679 }2680 2681 if (!done_phase) {2682 *finished = false;2683 return m88e3082_vct_cable_test_start(phydev);2684 }2685 if (*finished)2686 priv->vct_phase = M88E3082_VCT_OFF;2687 return 0;2688}2689 2690static int m88e1111_vct_cable_test_start(struct phy_device *phydev)2691{2692 int ret;2693 2694 ret = marvell_cable_test_start_common(phydev);2695 if (ret)2696 return ret;2697 2698 /* It needs some magic workarounds described in VCT manual for this PHY.2699 */2700 ret = phy_write(phydev, 29, 0x0018);2701 if (ret < 0)2702 return ret;2703 2704 ret = phy_write(phydev, 30, 0x00c2);2705 if (ret < 0)2706 return ret;2707 2708 ret = phy_write(phydev, 30, 0x00ca);2709 if (ret < 0)2710 return ret;2711 2712 ret = phy_write(phydev, 30, 0x00c2);2713 if (ret < 0)2714 return ret;2715 2716 ret = phy_write_paged(phydev, MII_MARVELL_COPPER_PAGE, MII_VCT_SR,2717 MII_VCT_TXPINS_ENVCT);2718 if (ret < 0)2719 return ret;2720 2721 ret = phy_write(phydev, 29, 0x0018);2722 if (ret < 0)2723 return ret;2724 2725 ret = phy_write(phydev, 30, 0x0042);2726 if (ret < 0)2727 return ret;2728 2729 return 0;2730}2731 2732static u32 m88e1111_vct_distrfln_2_cm(u8 distrfln)2733{2734 if (distrfln < 36)2735 return 0;2736 2737 /* Original function for meters: y = 0.8018x - 28.751 */2738 return (8018 * distrfln - 287510) / 100;2739}2740 2741static int m88e1111_vct_cable_test_get_status(struct phy_device *phydev,2742 bool *finished)2743{2744 u8 vcttst_res, distrfln;2745 int ret, result;2746 2747 *finished = false;2748 2749 /* Each pair use one page: A-0, B-1, C-2, D-3 */2750 for (u8 i = 0; i < 4; i++) {2751 ret = phy_read_paged(phydev, i, MII_VCT_SR);2752 if (ret < 0)2753 return ret;2754 else if (i == 0 && ret & MII_VCT_TXPINS_ENVCT)2755 return 0;2756 2757 distrfln = ret & MII_VCT_TXRXPINS_DISTRFLN;2758 vcttst_res = (ret & MII_VCT_TXRXPINS_VCTTST) >>2759 MII_VCT_TXRXPINS_VCTTST_SHIFT;2760 2761 result = m88e3082_vct_cable_test_report_trans(vcttst_res,2762 distrfln);2763 ethnl_cable_test_result(phydev, i, result);2764 2765 if (distrfln < MII_VCT_TXRXPINS_DISTRFLN_MAX) {2766 u32 cm = m88e1111_vct_distrfln_2_cm(distrfln);2767 2768 ethnl_cable_test_fault_length(phydev, i, cm);2769 }2770 }2771 2772 *finished = true;2773 return 0;2774}2775 2776#ifdef CONFIG_HWMON2777struct marvell_hwmon_ops {2778 int (*config)(struct phy_device *phydev);2779 int (*get_temp)(struct phy_device *phydev, long *temp);2780 int (*get_temp_critical)(struct phy_device *phydev, long *temp);2781 int (*set_temp_critical)(struct phy_device *phydev, long temp);2782 int (*get_temp_alarm)(struct phy_device *phydev, long *alarm);2783};2784 2785static const struct marvell_hwmon_ops *2786to_marvell_hwmon_ops(const struct phy_device *phydev)2787{2788 return phydev->drv->driver_data;2789}2790 2791static int m88e1121_get_temp(struct phy_device *phydev, long *temp)2792{2793 int oldpage;2794 int ret = 0;2795 int val;2796 2797 *temp = 0;2798 2799 oldpage = phy_select_page(phydev, MII_MARVELL_MISC_TEST_PAGE);2800 if (oldpage < 0)2801 goto error;2802 2803 /* Enable temperature sensor */2804 ret = __phy_read(phydev, MII_88E1121_MISC_TEST);2805 if (ret < 0)2806 goto error;2807 2808 ret = __phy_write(phydev, MII_88E1121_MISC_TEST,2809 ret | MII_88E1121_MISC_TEST_TEMP_SENSOR_EN);2810 if (ret < 0)2811 goto error;2812 2813 /* Wait for temperature to stabilize */2814 usleep_range(10000, 12000);2815 2816 val = __phy_read(phydev, MII_88E1121_MISC_TEST);2817 if (val < 0) {2818 ret = val;2819 goto error;2820 }2821 2822 /* Disable temperature sensor */2823 ret = __phy_write(phydev, MII_88E1121_MISC_TEST,2824 ret & ~MII_88E1121_MISC_TEST_TEMP_SENSOR_EN);2825 if (ret < 0)2826 goto error;2827 2828 *temp = ((val & MII_88E1121_MISC_TEST_TEMP_MASK) - 5) * 5000;2829 2830error:2831 return phy_restore_page(phydev, oldpage, ret);2832}2833 2834static int m88e1510_get_temp(struct phy_device *phydev, long *temp)2835{2836 int ret;2837 2838 *temp = 0;2839 2840 ret = phy_read_paged(phydev, MII_MARVELL_MISC_TEST_PAGE,2841 MII_88E1510_TEMP_SENSOR);2842 if (ret < 0)2843 return ret;2844 2845 *temp = ((ret & MII_88E1510_TEMP_SENSOR_MASK) - 25) * 1000;2846 2847 return 0;2848}2849 2850static int m88e1510_get_temp_critical(struct phy_device *phydev, long *temp)2851{2852 int ret;2853 2854 *temp = 0;2855 2856 ret = phy_read_paged(phydev, MII_MARVELL_MISC_TEST_PAGE,2857 MII_88E1121_MISC_TEST);2858 if (ret < 0)2859 return ret;2860 2861 *temp = (((ret & MII_88E1510_MISC_TEST_TEMP_THRESHOLD_MASK) >>2862 MII_88E1510_MISC_TEST_TEMP_THRESHOLD_SHIFT) * 5) - 25;2863 /* convert to mC */2864 *temp *= 1000;2865 2866 return 0;2867}2868 2869static int m88e1510_set_temp_critical(struct phy_device *phydev, long temp)2870{2871 temp = temp / 1000;2872 temp = clamp_val(DIV_ROUND_CLOSEST(temp, 5) + 5, 0, 0x1f);2873 2874 return phy_modify_paged(phydev, MII_MARVELL_MISC_TEST_PAGE,2875 MII_88E1121_MISC_TEST,2876 MII_88E1510_MISC_TEST_TEMP_THRESHOLD_MASK,2877 temp << MII_88E1510_MISC_TEST_TEMP_THRESHOLD_SHIFT);2878}2879 2880static int m88e1510_get_temp_alarm(struct phy_device *phydev, long *alarm)2881{2882 int ret;2883 2884 *alarm = false;2885 2886 ret = phy_read_paged(phydev, MII_MARVELL_MISC_TEST_PAGE,2887 MII_88E1121_MISC_TEST);2888 if (ret < 0)2889 return ret;2890 2891 *alarm = !!(ret & MII_88E1510_MISC_TEST_TEMP_IRQ);2892 2893 return 0;2894}2895 2896static int m88e6390_get_temp(struct phy_device *phydev, long *temp)2897{2898 int sum = 0;2899 int oldpage;2900 int ret = 0;2901 int i;2902 2903 *temp = 0;2904 2905 oldpage = phy_select_page(phydev, MII_MARVELL_MISC_TEST_PAGE);2906 if (oldpage < 0)2907 goto error;2908 2909 /* Enable temperature sensor */2910 ret = __phy_read(phydev, MII_88E6390_MISC_TEST);2911 if (ret < 0)2912 goto error;2913 2914 ret &= ~MII_88E6390_MISC_TEST_TEMP_SENSOR_MASK;2915 ret |= MII_88E6390_MISC_TEST_TEMP_SENSOR_ENABLE_SAMPLE_1S;2916 2917 ret = __phy_write(phydev, MII_88E6390_MISC_TEST, ret);2918 if (ret < 0)2919 goto error;2920 2921 /* Wait for temperature to stabilize */2922 usleep_range(10000, 12000);2923 2924 /* Reading the temperature sense has an errata. You need to read2925 * a number of times and take an average.2926 */2927 for (i = 0; i < MII_88E6390_TEMP_SENSOR_SAMPLES; i++) {2928 ret = __phy_read(phydev, MII_88E6390_TEMP_SENSOR);2929 if (ret < 0)2930 goto error;2931 sum += ret & MII_88E6390_TEMP_SENSOR_MASK;2932 }2933 2934 sum /= MII_88E6390_TEMP_SENSOR_SAMPLES;2935 *temp = (sum - 75) * 1000;2936 2937 /* Disable temperature sensor */2938 ret = __phy_read(phydev, MII_88E6390_MISC_TEST);2939 if (ret < 0)2940 goto error;2941 2942 ret = ret & ~MII_88E6390_MISC_TEST_TEMP_SENSOR_MASK;2943 ret |= MII_88E6390_MISC_TEST_TEMP_SENSOR_DISABLE;2944 2945 ret = __phy_write(phydev, MII_88E6390_MISC_TEST, ret);2946 2947error:2948 phy_restore_page(phydev, oldpage, ret);2949 2950 return ret;2951}2952 2953static int m88e6393_get_temp(struct phy_device *phydev, long *temp)2954{2955 int err;2956 2957 err = m88e1510_get_temp(phydev, temp);2958 2959 /* 88E1510 measures T + 25, while the PHY on 88E6393X switch2960 * T + 75, so we have to subtract another 502961 */2962 *temp -= 50000;2963 2964 return err;2965}2966 2967static int m88e6393_get_temp_critical(struct phy_device *phydev, long *temp)2968{2969 int ret;2970 2971 *temp = 0;2972 2973 ret = phy_read_paged(phydev, MII_MARVELL_MISC_TEST_PAGE,2974 MII_88E6390_TEMP_SENSOR);2975 if (ret < 0)2976 return ret;2977 2978 *temp = (((ret & MII_88E6393_TEMP_SENSOR_THRESHOLD_MASK) >>2979 MII_88E6393_TEMP_SENSOR_THRESHOLD_SHIFT) - 75) * 1000;2980 2981 return 0;2982}2983 2984static int m88e6393_set_temp_critical(struct phy_device *phydev, long temp)2985{2986 temp = (temp / 1000) + 75;2987 2988 return phy_modify_paged(phydev, MII_MARVELL_MISC_TEST_PAGE,2989 MII_88E6390_TEMP_SENSOR,2990 MII_88E6393_TEMP_SENSOR_THRESHOLD_MASK,2991 temp << MII_88E6393_TEMP_SENSOR_THRESHOLD_SHIFT);2992}2993 2994static int m88e6393_hwmon_config(struct phy_device *phydev)2995{2996 int err;2997 2998 err = m88e6393_set_temp_critical(phydev, 100000);2999 if (err)3000 return err;3001 3002 return phy_modify_paged(phydev, MII_MARVELL_MISC_TEST_PAGE,3003 MII_88E6390_MISC_TEST,3004 MII_88E6390_MISC_TEST_TEMP_SENSOR_MASK |3005 MII_88E6393_MISC_TEST_SAMPLES_MASK |3006 MII_88E6393_MISC_TEST_RATE_MASK,3007 MII_88E6390_MISC_TEST_TEMP_SENSOR_ENABLE |3008 MII_88E6393_MISC_TEST_SAMPLES_2048 |3009 MII_88E6393_MISC_TEST_RATE_2_3MS);3010}3011 3012static int marvell_hwmon_read(struct device *dev, enum hwmon_sensor_types type,3013 u32 attr, int channel, long *temp)3014{3015 struct phy_device *phydev = dev_get_drvdata(dev);3016 const struct marvell_hwmon_ops *ops = to_marvell_hwmon_ops(phydev);3017 int err = -EOPNOTSUPP;3018 3019 switch (attr) {3020 case hwmon_temp_input:3021 if (ops->get_temp)3022 err = ops->get_temp(phydev, temp);3023 break;3024 case hwmon_temp_crit:3025 if (ops->get_temp_critical)3026 err = ops->get_temp_critical(phydev, temp);3027 break;3028 case hwmon_temp_max_alarm:3029 if (ops->get_temp_alarm)3030 err = ops->get_temp_alarm(phydev, temp);3031 break;3032 }3033 3034 return err;3035}3036 3037static int marvell_hwmon_write(struct device *dev, enum hwmon_sensor_types type,3038 u32 attr, int channel, long temp)3039{3040 struct phy_device *phydev = dev_get_drvdata(dev);3041 const struct marvell_hwmon_ops *ops = to_marvell_hwmon_ops(phydev);3042 int err = -EOPNOTSUPP;3043 3044 switch (attr) {3045 case hwmon_temp_crit:3046 if (ops->set_temp_critical)3047 err = ops->set_temp_critical(phydev, temp);3048 break;3049 }3050 3051 return err;3052}3053 3054static umode_t marvell_hwmon_is_visible(const void *data,3055 enum hwmon_sensor_types type,3056 u32 attr, int channel)3057{3058 const struct phy_device *phydev = data;3059 const struct marvell_hwmon_ops *ops = to_marvell_hwmon_ops(phydev);3060 3061 if (type != hwmon_temp)3062 return 0;3063 3064 switch (attr) {3065 case hwmon_temp_input:3066 return ops->get_temp ? 0444 : 0;3067 case hwmon_temp_max_alarm:3068 return ops->get_temp_alarm ? 0444 : 0;3069 case hwmon_temp_crit:3070 return (ops->get_temp_critical ? 0444 : 0) |3071 (ops->set_temp_critical ? 0200 : 0);3072 default:3073 return 0;3074 }3075}3076 3077static u32 marvell_hwmon_chip_config[] = {3078 HWMON_C_REGISTER_TZ,3079 03080};3081 3082static const struct hwmon_channel_info marvell_hwmon_chip = {3083 .type = hwmon_chip,3084 .config = marvell_hwmon_chip_config,3085};3086 3087/* we can define HWMON_T_CRIT and HWMON_T_MAX_ALARM even though these are not3088 * defined for all PHYs, because the hwmon code checks whether the attributes3089 * exists via the .is_visible method3090 */3091static u32 marvell_hwmon_temp_config[] = {3092 HWMON_T_INPUT | HWMON_T_CRIT | HWMON_T_MAX_ALARM,3093 03094};3095 3096static const struct hwmon_channel_info marvell_hwmon_temp = {3097 .type = hwmon_temp,3098 .config = marvell_hwmon_temp_config,3099};3100 3101static const struct hwmon_channel_info * const marvell_hwmon_info[] = {3102 &marvell_hwmon_chip,3103 &marvell_hwmon_temp,3104 NULL3105};3106 3107static const struct hwmon_ops marvell_hwmon_hwmon_ops = {3108 .is_visible = marvell_hwmon_is_visible,3109 .read = marvell_hwmon_read,3110 .write = marvell_hwmon_write,3111};3112 3113static const struct hwmon_chip_info marvell_hwmon_chip_info = {3114 .ops = &marvell_hwmon_hwmon_ops,3115 .info = marvell_hwmon_info,3116};3117 3118static int marvell_hwmon_name(struct phy_device *phydev)3119{3120 struct marvell_priv *priv = phydev->priv;3121 struct device *dev = &phydev->mdio.dev;3122 const char *devname = dev_name(dev);3123 size_t len = strlen(devname);3124 int i, j;3125 3126 priv->hwmon_name = devm_kzalloc(dev, len, GFP_KERNEL);3127 if (!priv->hwmon_name)3128 return -ENOMEM;3129 3130 for (i = j = 0; i < len && devname[i]; i++) {3131 if (isalnum(devname[i]))3132 priv->hwmon_name[j++] = devname[i];3133 }3134 3135 return 0;3136}3137 3138static int marvell_hwmon_probe(struct phy_device *phydev)3139{3140 const struct marvell_hwmon_ops *ops = to_marvell_hwmon_ops(phydev);3141 struct marvell_priv *priv = phydev->priv;3142 struct device *dev = &phydev->mdio.dev;3143 int err;3144 3145 if (!ops)3146 return 0;3147 3148 err = marvell_hwmon_name(phydev);3149 if (err)3150 return err;3151 3152 priv->hwmon_dev = devm_hwmon_device_register_with_info(3153 dev, priv->hwmon_name, phydev, &marvell_hwmon_chip_info, NULL);3154 if (IS_ERR(priv->hwmon_dev))3155 return PTR_ERR(priv->hwmon_dev);3156 3157 if (ops->config)3158 err = ops->config(phydev);3159 3160 return err;3161}3162 3163static const struct marvell_hwmon_ops m88e1121_hwmon_ops = {3164 .get_temp = m88e1121_get_temp,3165};3166 3167static const struct marvell_hwmon_ops m88e1510_hwmon_ops = {3168 .get_temp = m88e1510_get_temp,3169 .get_temp_critical = m88e1510_get_temp_critical,3170 .set_temp_critical = m88e1510_set_temp_critical,3171 .get_temp_alarm = m88e1510_get_temp_alarm,3172};3173 3174static const struct marvell_hwmon_ops m88e6390_hwmon_ops = {3175 .get_temp = m88e6390_get_temp,3176};3177 3178static const struct marvell_hwmon_ops m88e6393_hwmon_ops = {3179 .config = m88e6393_hwmon_config,3180 .get_temp = m88e6393_get_temp,3181 .get_temp_critical = m88e6393_get_temp_critical,3182 .set_temp_critical = m88e6393_set_temp_critical,3183 .get_temp_alarm = m88e1510_get_temp_alarm,3184};3185 3186#define DEF_MARVELL_HWMON_OPS(s) (&(s))3187 3188#else3189 3190#define DEF_MARVELL_HWMON_OPS(s) NULL3191 3192static int marvell_hwmon_probe(struct phy_device *phydev)3193{3194 return 0;3195}3196#endif3197 3198static int m88e1318_led_brightness_set(struct phy_device *phydev,3199 u8 index, enum led_brightness value)3200{3201 int reg;3202 3203 reg = phy_read_paged(phydev, MII_MARVELL_LED_PAGE,3204 MII_88E1318S_PHY_LED_FUNC);3205 if (reg < 0)3206 return reg;3207 3208 switch (index) {3209 case 0:3210 case 1:3211 case 2:3212 reg &= ~(0xf << (4 * index));3213 if (value == LED_OFF)3214 reg |= MII_88E1318S_PHY_LED_FUNC_OFF << (4 * index);3215 else3216 reg |= MII_88E1318S_PHY_LED_FUNC_ON << (4 * index);3217 break;3218 default:3219 return -EINVAL;3220 }3221 3222 return phy_write_paged(phydev, MII_MARVELL_LED_PAGE,3223 MII_88E1318S_PHY_LED_FUNC, reg);3224}3225 3226static int m88e1318_led_blink_set(struct phy_device *phydev, u8 index,3227 unsigned long *delay_on,3228 unsigned long *delay_off)3229{3230 int reg;3231 3232 reg = phy_read_paged(phydev, MII_MARVELL_LED_PAGE,3233 MII_88E1318S_PHY_LED_FUNC);3234 if (reg < 0)3235 return reg;3236 3237 switch (index) {3238 case 0:3239 case 1:3240 case 2:3241 reg &= ~(0xf << (4 * index));3242 reg |= MII_88E1318S_PHY_LED_FUNC_BLINK << (4 * index);3243 /* Reset default is 84ms */3244 *delay_on = 84 / 2;3245 *delay_off = 84 / 2;3246 break;3247 default:3248 return -EINVAL;3249 }3250 3251 return phy_write_paged(phydev, MII_MARVELL_LED_PAGE,3252 MII_88E1318S_PHY_LED_FUNC, reg);3253}3254 3255struct marvell_led_rules {3256 int mode;3257 unsigned long rules;3258};3259 3260static const struct marvell_led_rules marvell_led0[] = {3261 {3262 .mode = 0,3263 .rules = BIT(TRIGGER_NETDEV_LINK),3264 },3265 {3266 .mode = 1,3267 .rules = (BIT(TRIGGER_NETDEV_LINK) |3268 BIT(TRIGGER_NETDEV_RX) |3269 BIT(TRIGGER_NETDEV_TX)),3270 },3271 {3272 .mode = 3,3273 .rules = (BIT(TRIGGER_NETDEV_RX) |3274 BIT(TRIGGER_NETDEV_TX)),3275 },3276 {3277 .mode = 4,3278 .rules = (BIT(TRIGGER_NETDEV_RX) |3279 BIT(TRIGGER_NETDEV_TX)),3280 },3281 {3282 .mode = 5,3283 .rules = BIT(TRIGGER_NETDEV_TX),3284 },3285 {3286 .mode = 6,3287 .rules = BIT(TRIGGER_NETDEV_LINK),3288 },3289 {3290 .mode = 7,3291 .rules = BIT(TRIGGER_NETDEV_LINK_1000),3292 },3293 {3294 .mode = 8,3295 .rules = 0,3296 },3297};3298 3299static const struct marvell_led_rules marvell_led1[] = {3300 {3301 .mode = 1,3302 .rules = (BIT(TRIGGER_NETDEV_LINK) |3303 BIT(TRIGGER_NETDEV_RX) |3304 BIT(TRIGGER_NETDEV_TX)),3305 },3306 {3307 .mode = 2,3308 .rules = (BIT(TRIGGER_NETDEV_LINK) |3309 BIT(TRIGGER_NETDEV_RX)),3310 },3311 {3312 .mode = 3,3313 .rules = (BIT(TRIGGER_NETDEV_RX) |3314 BIT(TRIGGER_NETDEV_TX)),3315 },3316 {3317 .mode = 4,3318 .rules = (BIT(TRIGGER_NETDEV_RX) |3319 BIT(TRIGGER_NETDEV_TX)),3320 },3321 {3322 .mode = 6,3323 .rules = (BIT(TRIGGER_NETDEV_LINK_100) |3324 BIT(TRIGGER_NETDEV_LINK_1000)),3325 },3326 {3327 .mode = 7,3328 .rules = BIT(TRIGGER_NETDEV_LINK_100),3329 },3330 {3331 .mode = 8,3332 .rules = 0,3333 },3334};3335 3336static const struct marvell_led_rules marvell_led2[] = {3337 {3338 .mode = 0,3339 .rules = BIT(TRIGGER_NETDEV_LINK),3340 },3341 {3342 .mode = 1,3343 .rules = (BIT(TRIGGER_NETDEV_LINK) |3344 BIT(TRIGGER_NETDEV_RX) |3345 BIT(TRIGGER_NETDEV_TX)),3346 },3347 {3348 .mode = 3,3349 .rules = (BIT(TRIGGER_NETDEV_RX) |3350 BIT(TRIGGER_NETDEV_TX)),3351 },3352 {3353 .mode = 4,3354 .rules = (BIT(TRIGGER_NETDEV_RX) |3355 BIT(TRIGGER_NETDEV_TX)),3356 },3357 {3358 .mode = 5,3359 .rules = BIT(TRIGGER_NETDEV_TX),3360 },3361 {3362 .mode = 6,3363 .rules = (BIT(TRIGGER_NETDEV_LINK_10) |3364 BIT(TRIGGER_NETDEV_LINK_1000)),3365 },3366 {3367 .mode = 7,3368 .rules = BIT(TRIGGER_NETDEV_LINK_10),3369 },3370 {3371 .mode = 8,3372 .rules = 0,3373 },3374};3375 3376static int marvell_find_led_mode(unsigned long rules,3377 const struct marvell_led_rules *marvell_rules,3378 int count,3379 int *mode)3380{3381 int i;3382 3383 for (i = 0; i < count; i++) {3384 if (marvell_rules[i].rules == rules) {3385 *mode = marvell_rules[i].mode;3386 return 0;3387 }3388 }3389 return -EOPNOTSUPP;3390}3391 3392static int marvell_get_led_mode(u8 index, unsigned long rules, int *mode)3393{3394 int ret;3395 3396 switch (index) {3397 case 0:3398 ret = marvell_find_led_mode(rules, marvell_led0,3399 ARRAY_SIZE(marvell_led0), mode);3400 break;3401 case 1:3402 ret = marvell_find_led_mode(rules, marvell_led1,3403 ARRAY_SIZE(marvell_led1), mode);3404 break;3405 case 2:3406 ret = marvell_find_led_mode(rules, marvell_led2,3407 ARRAY_SIZE(marvell_led2), mode);3408 break;3409 default:3410 ret = -EINVAL;3411 }3412 3413 return ret;3414}3415 3416static int marvell_find_led_rules(unsigned long *rules,3417 const struct marvell_led_rules *marvell_rules,3418 int count,3419 int mode)3420{3421 int i;3422 3423 for (i = 0; i < count; i++) {3424 if (marvell_rules[i].mode == mode) {3425 *rules = marvell_rules[i].rules;3426 return 0;3427 }3428 }3429 return -EOPNOTSUPP;3430}3431 3432static int marvell_get_led_rules(u8 index, unsigned long *rules, int mode)3433{3434 int ret;3435 3436 switch (index) {3437 case 0:3438 ret = marvell_find_led_rules(rules, marvell_led0,3439 ARRAY_SIZE(marvell_led0), mode);3440 break;3441 case 1:3442 ret = marvell_find_led_rules(rules, marvell_led1,3443 ARRAY_SIZE(marvell_led1), mode);3444 break;3445 case 2:3446 ret = marvell_find_led_rules(rules, marvell_led2,3447 ARRAY_SIZE(marvell_led2), mode);3448 break;3449 default:3450 ret = -EOPNOTSUPP;3451 }3452 3453 return ret;3454}3455 3456static int m88e1318_led_hw_is_supported(struct phy_device *phydev, u8 index,3457 unsigned long rules)3458{3459 int mode, ret;3460 3461 switch (index) {3462 case 0:3463 case 1:3464 case 2:3465 ret = marvell_get_led_mode(index, rules, &mode);3466 break;3467 default:3468 ret = -EINVAL;3469 }3470 3471 return ret;3472}3473 3474static int m88e1318_led_hw_control_set(struct phy_device *phydev, u8 index,3475 unsigned long rules)3476{3477 int mode, ret, reg;3478 3479 switch (index) {3480 case 0:3481 case 1:3482 case 2:3483 ret = marvell_get_led_mode(index, rules, &mode);3484 break;3485 default:3486 ret = -EINVAL;3487 }3488 3489 if (ret < 0)3490 return ret;3491 3492 reg = phy_read_paged(phydev, MII_MARVELL_LED_PAGE,3493 MII_88E1318S_PHY_LED_FUNC);3494 if (reg < 0)3495 return reg;3496 3497 reg &= ~(0xf << (4 * index));3498 reg |= mode << (4 * index);3499 return phy_write_paged(phydev, MII_MARVELL_LED_PAGE,3500 MII_88E1318S_PHY_LED_FUNC, reg);3501}3502 3503static int m88e1318_led_hw_control_get(struct phy_device *phydev, u8 index,3504 unsigned long *rules)3505{3506 int mode, reg;3507 3508 if (index > 2)3509 return -EINVAL;3510 3511 reg = phy_read_paged(phydev, MII_MARVELL_LED_PAGE,3512 MII_88E1318S_PHY_LED_FUNC);3513 if (reg < 0)3514 return reg;3515 3516 mode = (reg >> (4 * index)) & 0xf;3517 3518 return marvell_get_led_rules(index, rules, mode);3519}3520 3521static int marvell_probe(struct phy_device *phydev)3522{3523 struct marvell_priv *priv;3524 3525 priv = devm_kzalloc(&phydev->mdio.dev, sizeof(*priv), GFP_KERNEL);3526 if (!priv)3527 return -ENOMEM;3528 3529 phydev->priv = priv;3530 3531 return marvell_hwmon_probe(phydev);3532}3533 3534static int m88e1510_sfp_insert(void *upstream, const struct sfp_eeprom_id *id)3535{3536 DECLARE_PHY_INTERFACE_MASK(interfaces);3537 struct phy_device *phydev = upstream;3538 phy_interface_t interface;3539 struct device *dev;3540 int oldpage;3541 int ret = 0;3542 u16 mode;3543 3544 __ETHTOOL_DECLARE_LINK_MODE_MASK(supported) = { 0, };3545 3546 dev = &phydev->mdio.dev;3547 3548 sfp_parse_support(phydev->sfp_bus, id, supported, interfaces);3549 interface = sfp_select_interface(phydev->sfp_bus, supported);3550 3551 dev_info(dev, "%s SFP module inserted\n", phy_modes(interface));3552 3553 switch (interface) {3554 case PHY_INTERFACE_MODE_1000BASEX:3555 mode = MII_88E1510_GEN_CTRL_REG_1_MODE_RGMII_1000X;3556 3557 break;3558 case PHY_INTERFACE_MODE_100BASEX:3559 mode = MII_88E1510_GEN_CTRL_REG_1_MODE_RGMII_100FX;3560 3561 break;3562 case PHY_INTERFACE_MODE_SGMII:3563 mode = MII_88E1510_GEN_CTRL_REG_1_MODE_RGMII_SGMII;3564 3565 break;3566 default:3567 dev_err(dev, "Incompatible SFP module inserted\n");3568 3569 return -EINVAL;3570 }3571 3572 oldpage = phy_select_page(phydev, MII_MARVELL_MODE_PAGE);3573 if (oldpage < 0)3574 goto error;3575 3576 ret = __phy_modify(phydev, MII_88E1510_GEN_CTRL_REG_1,3577 MII_88E1510_GEN_CTRL_REG_1_MODE_MASK, mode);3578 if (ret < 0)3579 goto error;3580 3581 ret = __phy_set_bits(phydev, MII_88E1510_GEN_CTRL_REG_1,3582 MII_88E1510_GEN_CTRL_REG_1_RESET);3583 3584error:3585 return phy_restore_page(phydev, oldpage, ret);3586}3587 3588static void m88e1510_sfp_remove(void *upstream)3589{3590 struct phy_device *phydev = upstream;3591 int oldpage;3592 int ret = 0;3593 3594 oldpage = phy_select_page(phydev, MII_MARVELL_MODE_PAGE);3595 if (oldpage < 0)3596 goto error;3597 3598 ret = __phy_modify(phydev, MII_88E1510_GEN_CTRL_REG_1,3599 MII_88E1510_GEN_CTRL_REG_1_MODE_MASK,3600 MII_88E1510_GEN_CTRL_REG_1_MODE_RGMII);3601 if (ret < 0)3602 goto error;3603 3604 ret = __phy_set_bits(phydev, MII_88E1510_GEN_CTRL_REG_1,3605 MII_88E1510_GEN_CTRL_REG_1_RESET);3606 3607error:3608 phy_restore_page(phydev, oldpage, ret);3609}3610 3611static const struct sfp_upstream_ops m88e1510_sfp_ops = {3612 .module_insert = m88e1510_sfp_insert,3613 .module_remove = m88e1510_sfp_remove,3614 .attach = phy_sfp_attach,3615 .detach = phy_sfp_detach,3616 .connect_phy = phy_sfp_connect_phy,3617 .disconnect_phy = phy_sfp_disconnect_phy,3618};3619 3620static int m88e1510_probe(struct phy_device *phydev)3621{3622 int err;3623 3624 err = marvell_probe(phydev);3625 if (err)3626 return err;3627 3628 return phy_sfp_probe(phydev, &m88e1510_sfp_ops);3629}3630 3631static struct phy_driver marvell_drivers[] = {3632 {3633 .phy_id = MARVELL_PHY_ID_88E1101,3634 .phy_id_mask = MARVELL_PHY_ID_MASK,3635 .name = "Marvell 88E1101",3636 /* PHY_GBIT_FEATURES */3637 .probe = marvell_probe,3638 .config_init = marvell_config_init,3639 .config_aneg = m88e1101_config_aneg,3640 .config_intr = marvell_config_intr,3641 .handle_interrupt = marvell_handle_interrupt,3642 .resume = genphy_resume,3643 .suspend = genphy_suspend,3644 .read_page = marvell_read_page,3645 .write_page = marvell_write_page,3646 .get_sset_count = marvell_get_sset_count,3647 .get_strings = marvell_get_strings,3648 .get_stats = marvell_get_stats,3649 },3650 {3651 .phy_id = MARVELL_PHY_ID_88E3082,3652 .phy_id_mask = MARVELL_PHY_ID_MASK,3653 .name = "Marvell 88E308X/88E609X Family",3654 /* PHY_BASIC_FEATURES */3655 .probe = marvell_probe,3656 .config_init = marvell_config_init,3657 .aneg_done = marvell_aneg_done,3658 .read_status = marvell_read_status,3659 .resume = genphy_resume,3660 .suspend = genphy_suspend,3661 .cable_test_start = m88e3082_vct_cable_test_start,3662 .cable_test_get_status = m88e3082_vct_cable_test_get_status,3663 },3664 {3665 .phy_id = MARVELL_PHY_ID_88E1112,3666 .phy_id_mask = MARVELL_PHY_ID_MASK,3667 .name = "Marvell 88E1112",3668 /* PHY_GBIT_FEATURES */3669 .probe = marvell_probe,3670 .config_init = m88e1112_config_init,3671 .config_aneg = marvell_config_aneg,3672 .config_intr = marvell_config_intr,3673 .handle_interrupt = marvell_handle_interrupt,3674 .resume = genphy_resume,3675 .suspend = genphy_suspend,3676 .read_page = marvell_read_page,3677 .write_page = marvell_write_page,3678 .get_sset_count = marvell_get_sset_count,3679 .get_strings = marvell_get_strings,3680 .get_stats = marvell_get_stats,3681 .get_tunable = m88e1011_get_tunable,3682 .set_tunable = m88e1011_set_tunable,3683 },3684 {3685 .phy_id = MARVELL_PHY_ID_88E1111,3686 .phy_id_mask = MARVELL_PHY_ID_MASK,3687 .name = "Marvell 88E1111",3688 /* PHY_GBIT_FEATURES */3689 .flags = PHY_POLL_CABLE_TEST,3690 .probe = marvell_probe,3691 .config_init = m88e1111gbe_config_init,3692 .config_aneg = m88e1111_config_aneg,3693 .read_status = marvell_read_status,3694 .config_intr = marvell_config_intr,3695 .handle_interrupt = marvell_handle_interrupt,3696 .resume = genphy_resume,3697 .suspend = genphy_suspend,3698 .read_page = marvell_read_page,3699 .write_page = marvell_write_page,3700 .get_sset_count = marvell_get_sset_count,3701 .get_strings = marvell_get_strings,3702 .get_stats = marvell_get_stats,3703 .get_tunable = m88e1111_get_tunable,3704 .set_tunable = m88e1111_set_tunable,3705 .cable_test_start = m88e1111_vct_cable_test_start,3706 .cable_test_get_status = m88e1111_vct_cable_test_get_status,3707 },3708 {3709 .phy_id = MARVELL_PHY_ID_88E1111_FINISAR,3710 .phy_id_mask = MARVELL_PHY_ID_MASK,3711 .name = "Marvell 88E1111 (Finisar)",3712 /* PHY_GBIT_FEATURES */3713 .probe = marvell_probe,3714 .config_init = m88e1111gbe_config_init,3715 .config_aneg = m88e1111_config_aneg,3716 .read_status = marvell_read_status,3717 .config_intr = marvell_config_intr,3718 .handle_interrupt = marvell_handle_interrupt,3719 .resume = genphy_resume,3720 .suspend = genphy_suspend,3721 .read_page = marvell_read_page,3722 .write_page = marvell_write_page,3723 .get_sset_count = marvell_get_sset_count,3724 .get_strings = marvell_get_strings,3725 .get_stats = marvell_get_stats,3726 .get_tunable = m88e1111_get_tunable,3727 .set_tunable = m88e1111_set_tunable,3728 },3729 {3730 .phy_id = MARVELL_PHY_ID_88E1118,3731 .phy_id_mask = MARVELL_PHY_ID_MASK,3732 .name = "Marvell 88E1118",3733 /* PHY_GBIT_FEATURES */3734 .probe = marvell_probe,3735 .config_init = m88e1118_config_init,3736 .config_aneg = m88e1118_config_aneg,3737 .config_intr = marvell_config_intr,3738 .handle_interrupt = marvell_handle_interrupt,3739 .resume = genphy_resume,3740 .suspend = genphy_suspend,3741 .read_page = marvell_read_page,3742 .write_page = marvell_write_page,3743 .get_sset_count = marvell_get_sset_count,3744 .get_strings = marvell_get_strings,3745 .get_stats = marvell_get_stats,3746 },3747 {3748 .phy_id = MARVELL_PHY_ID_88E1121R,3749 .phy_id_mask = MARVELL_PHY_ID_MASK,3750 .name = "Marvell 88E1121R",3751 .driver_data = DEF_MARVELL_HWMON_OPS(m88e1121_hwmon_ops),3752 /* PHY_GBIT_FEATURES */3753 .probe = marvell_probe,3754 .config_init = marvell_1011gbe_config_init,3755 .config_aneg = m88e1121_config_aneg,3756 .read_status = marvell_read_status,3757 .config_intr = marvell_config_intr,3758 .handle_interrupt = marvell_handle_interrupt,3759 .resume = genphy_resume,3760 .suspend = genphy_suspend,3761 .read_page = marvell_read_page,3762 .write_page = marvell_write_page,3763 .get_sset_count = marvell_get_sset_count,3764 .get_strings = marvell_get_strings,3765 .get_stats = marvell_get_stats,3766 .get_tunable = m88e1011_get_tunable,3767 .set_tunable = m88e1011_set_tunable,3768 },3769 {3770 .phy_id = MARVELL_PHY_ID_88E1318S,3771 .phy_id_mask = MARVELL_PHY_ID_MASK,3772 .name = "Marvell 88E1318S",3773 /* PHY_GBIT_FEATURES */3774 .probe = marvell_probe,3775 .config_init = m88e1318_config_init,3776 .config_aneg = m88e1318_config_aneg,3777 .read_status = marvell_read_status,3778 .config_intr = marvell_config_intr,3779 .handle_interrupt = marvell_handle_interrupt,3780 .get_wol = m88e1318_get_wol,3781 .set_wol = m88e1318_set_wol,3782 .resume = genphy_resume,3783 .suspend = genphy_suspend,3784 .read_page = marvell_read_page,3785 .write_page = marvell_write_page,3786 .get_sset_count = marvell_get_sset_count,3787 .get_strings = marvell_get_strings,3788 .get_stats = marvell_get_stats,3789 .led_brightness_set = m88e1318_led_brightness_set,3790 .led_blink_set = m88e1318_led_blink_set,3791 .led_hw_is_supported = m88e1318_led_hw_is_supported,3792 .led_hw_control_set = m88e1318_led_hw_control_set,3793 .led_hw_control_get = m88e1318_led_hw_control_get,3794 },3795 {3796 .phy_id = MARVELL_PHY_ID_88E1145,3797 .phy_id_mask = MARVELL_PHY_ID_MASK,3798 .name = "Marvell 88E1145",3799 /* PHY_GBIT_FEATURES */3800 .flags = PHY_POLL_CABLE_TEST,3801 .probe = marvell_probe,3802 .config_init = m88e1145_config_init,3803 .config_aneg = m88e1101_config_aneg,3804 .config_intr = marvell_config_intr,3805 .handle_interrupt = marvell_handle_interrupt,3806 .resume = genphy_resume,3807 .suspend = genphy_suspend,3808 .read_page = marvell_read_page,3809 .write_page = marvell_write_page,3810 .get_sset_count = marvell_get_sset_count,3811 .get_strings = marvell_get_strings,3812 .get_stats = marvell_get_stats,3813 .get_tunable = m88e1111_get_tunable,3814 .set_tunable = m88e1111_set_tunable,3815 .cable_test_start = m88e1111_vct_cable_test_start,3816 .cable_test_get_status = m88e1111_vct_cable_test_get_status,3817 },3818 {3819 .phy_id = MARVELL_PHY_ID_88E1149R,3820 .phy_id_mask = MARVELL_PHY_ID_MASK,3821 .name = "Marvell 88E1149R",3822 /* PHY_GBIT_FEATURES */3823 .probe = marvell_probe,3824 .config_init = m88e1149_config_init,3825 .config_aneg = m88e1118_config_aneg,3826 .config_intr = marvell_config_intr,3827 .handle_interrupt = marvell_handle_interrupt,3828 .resume = genphy_resume,3829 .suspend = genphy_suspend,3830 .read_page = marvell_read_page,3831 .write_page = marvell_write_page,3832 .get_sset_count = marvell_get_sset_count,3833 .get_strings = marvell_get_strings,3834 .get_stats = marvell_get_stats,3835 },3836 {3837 .phy_id = MARVELL_PHY_ID_88E1240,3838 .phy_id_mask = MARVELL_PHY_ID_MASK,3839 .name = "Marvell 88E1240",3840 /* PHY_GBIT_FEATURES */3841 .probe = marvell_probe,3842 .config_init = m88e1112_config_init,3843 .config_aneg = marvell_config_aneg,3844 .config_intr = marvell_config_intr,3845 .handle_interrupt = marvell_handle_interrupt,3846 .resume = genphy_resume,3847 .suspend = genphy_suspend,3848 .read_page = marvell_read_page,3849 .write_page = marvell_write_page,3850 .get_sset_count = marvell_get_sset_count,3851 .get_strings = marvell_get_strings,3852 .get_stats = marvell_get_stats,3853 .get_tunable = m88e1011_get_tunable,3854 .set_tunable = m88e1011_set_tunable,3855 },3856 {3857 .phy_id = MARVELL_PHY_ID_88E1116R,3858 .phy_id_mask = MARVELL_PHY_ID_MASK,3859 .name = "Marvell 88E1116R",3860 /* PHY_GBIT_FEATURES */3861 .probe = marvell_probe,3862 .config_init = m88e1116r_config_init,3863 .config_intr = marvell_config_intr,3864 .handle_interrupt = marvell_handle_interrupt,3865 .resume = genphy_resume,3866 .suspend = genphy_suspend,3867 .read_page = marvell_read_page,3868 .write_page = marvell_write_page,3869 .get_sset_count = marvell_get_sset_count,3870 .get_strings = marvell_get_strings,3871 .get_stats = marvell_get_stats,3872 .get_tunable = m88e1011_get_tunable,3873 .set_tunable = m88e1011_set_tunable,3874 },3875 {3876 .phy_id = MARVELL_PHY_ID_88E1510,3877 .phy_id_mask = MARVELL_PHY_ID_MASK,3878 .name = "Marvell 88E1510",3879 .driver_data = DEF_MARVELL_HWMON_OPS(m88e1510_hwmon_ops),3880 .features = PHY_GBIT_FIBRE_FEATURES,3881 .flags = PHY_POLL_CABLE_TEST,3882 .probe = m88e1510_probe,3883 .config_init = m88e1510_config_init,3884 .config_aneg = m88e1510_config_aneg,3885 .read_status = marvell_read_status,3886 .config_intr = marvell_config_intr,3887 .handle_interrupt = marvell_handle_interrupt,3888 .get_wol = m88e1318_get_wol,3889 .set_wol = m88e1318_set_wol,3890 .resume = marvell_resume,3891 .suspend = marvell_suspend,3892 .read_page = marvell_read_page,3893 .write_page = marvell_write_page,3894 .get_sset_count = marvell_get_sset_count,3895 .get_strings = marvell_get_strings,3896 .get_stats = marvell_get_stats,3897 .set_loopback = m88e1510_loopback,3898 .get_tunable = m88e1011_get_tunable,3899 .set_tunable = m88e1011_set_tunable,3900 .cable_test_start = marvell_vct7_cable_test_start,3901 .cable_test_tdr_start = marvell_vct5_cable_test_tdr_start,3902 .cable_test_get_status = marvell_vct7_cable_test_get_status,3903 .led_brightness_set = m88e1318_led_brightness_set,3904 .led_blink_set = m88e1318_led_blink_set,3905 .led_hw_is_supported = m88e1318_led_hw_is_supported,3906 .led_hw_control_set = m88e1318_led_hw_control_set,3907 .led_hw_control_get = m88e1318_led_hw_control_get,3908 },3909 {3910 .phy_id = MARVELL_PHY_ID_88E1540,3911 .phy_id_mask = MARVELL_PHY_ID_MASK,3912 .name = "Marvell 88E1540",3913 .driver_data = DEF_MARVELL_HWMON_OPS(m88e1510_hwmon_ops),3914 /* PHY_GBIT_FEATURES */3915 .flags = PHY_POLL_CABLE_TEST,3916 .probe = marvell_probe,3917 .config_init = marvell_1011gbe_config_init,3918 .config_aneg = m88e1510_config_aneg,3919 .read_status = marvell_read_status,3920 .config_intr = marvell_config_intr,3921 .handle_interrupt = marvell_handle_interrupt,3922 .resume = genphy_resume,3923 .suspend = genphy_suspend,3924 .read_page = marvell_read_page,3925 .write_page = marvell_write_page,3926 .get_sset_count = marvell_get_sset_count,3927 .get_strings = marvell_get_strings,3928 .get_stats = marvell_get_stats,3929 .get_tunable = m88e1540_get_tunable,3930 .set_tunable = m88e1540_set_tunable,3931 .cable_test_start = marvell_vct7_cable_test_start,3932 .cable_test_tdr_start = marvell_vct5_cable_test_tdr_start,3933 .cable_test_get_status = marvell_vct7_cable_test_get_status,3934 .led_brightness_set = m88e1318_led_brightness_set,3935 .led_blink_set = m88e1318_led_blink_set,3936 .led_hw_is_supported = m88e1318_led_hw_is_supported,3937 .led_hw_control_set = m88e1318_led_hw_control_set,3938 .led_hw_control_get = m88e1318_led_hw_control_get,3939 },3940 {3941 .phy_id = MARVELL_PHY_ID_88E1545,3942 .phy_id_mask = MARVELL_PHY_ID_MASK,3943 .name = "Marvell 88E1545",3944 .driver_data = DEF_MARVELL_HWMON_OPS(m88e1510_hwmon_ops),3945 .probe = marvell_probe,3946 /* PHY_GBIT_FEATURES */3947 .flags = PHY_POLL_CABLE_TEST,3948 .config_init = marvell_1011gbe_config_init,3949 .config_aneg = m88e1510_config_aneg,3950 .read_status = marvell_read_status,3951 .config_intr = marvell_config_intr,3952 .handle_interrupt = marvell_handle_interrupt,3953 .resume = genphy_resume,3954 .suspend = genphy_suspend,3955 .read_page = marvell_read_page,3956 .write_page = marvell_write_page,3957 .get_sset_count = marvell_get_sset_count,3958 .get_strings = marvell_get_strings,3959 .get_stats = marvell_get_stats,3960 .get_tunable = m88e1540_get_tunable,3961 .set_tunable = m88e1540_set_tunable,3962 .cable_test_start = marvell_vct7_cable_test_start,3963 .cable_test_tdr_start = marvell_vct5_cable_test_tdr_start,3964 .cable_test_get_status = marvell_vct7_cable_test_get_status,3965 .led_brightness_set = m88e1318_led_brightness_set,3966 .led_blink_set = m88e1318_led_blink_set,3967 .led_hw_is_supported = m88e1318_led_hw_is_supported,3968 .led_hw_control_set = m88e1318_led_hw_control_set,3969 .led_hw_control_get = m88e1318_led_hw_control_get,3970 },3971 {3972 .phy_id = MARVELL_PHY_ID_88E3016,3973 .phy_id_mask = MARVELL_PHY_ID_MASK,3974 .name = "Marvell 88E3016",3975 /* PHY_BASIC_FEATURES */3976 .probe = marvell_probe,3977 .config_init = m88e3016_config_init,3978 .aneg_done = marvell_aneg_done,3979 .read_status = marvell_read_status,3980 .config_intr = marvell_config_intr,3981 .handle_interrupt = marvell_handle_interrupt,3982 .resume = genphy_resume,3983 .suspend = genphy_suspend,3984 .read_page = marvell_read_page,3985 .write_page = marvell_write_page,3986 .get_sset_count = marvell_get_sset_count,3987 .get_strings = marvell_get_strings,3988 .get_stats = marvell_get_stats,3989 },3990 {3991 .phy_id = MARVELL_PHY_ID_88E6250_FAMILY,3992 .phy_id_mask = MARVELL_PHY_ID_MASK,3993 .name = "Marvell 88E6250 Family",3994 /* PHY_BASIC_FEATURES */3995 .probe = marvell_probe,3996 .aneg_done = marvell_aneg_done,3997 .config_intr = marvell_config_intr,3998 .handle_interrupt = marvell_handle_interrupt,3999 .resume = genphy_resume,4000 .suspend = genphy_suspend,4001 .get_sset_count = marvell_get_sset_count_simple,4002 .get_strings = marvell_get_strings_simple,4003 .get_stats = marvell_get_stats_simple,4004 },4005 {4006 .phy_id = MARVELL_PHY_ID_88E6341_FAMILY,4007 .phy_id_mask = MARVELL_PHY_ID_MASK,4008 .name = "Marvell 88E6341 Family",4009 .driver_data = DEF_MARVELL_HWMON_OPS(m88e1510_hwmon_ops),4010 /* PHY_GBIT_FEATURES */4011 .flags = PHY_POLL_CABLE_TEST,4012 .probe = marvell_probe,4013 .config_init = marvell_1011gbe_config_init,4014 .config_aneg = m88e6390_config_aneg,4015 .read_status = marvell_read_status,4016 .config_intr = marvell_config_intr,4017 .handle_interrupt = marvell_handle_interrupt,4018 .resume = genphy_resume,4019 .suspend = genphy_suspend,4020 .read_page = marvell_read_page,4021 .write_page = marvell_write_page,4022 .get_sset_count = marvell_get_sset_count,4023 .get_strings = marvell_get_strings,4024 .get_stats = marvell_get_stats,4025 .get_tunable = m88e1540_get_tunable,4026 .set_tunable = m88e1540_set_tunable,4027 .cable_test_start = marvell_vct7_cable_test_start,4028 .cable_test_tdr_start = marvell_vct5_cable_test_tdr_start,4029 .cable_test_get_status = marvell_vct7_cable_test_get_status,4030 },4031 {4032 .phy_id = MARVELL_PHY_ID_88E6390_FAMILY,4033 .phy_id_mask = MARVELL_PHY_ID_MASK,4034 .name = "Marvell 88E6390 Family",4035 .driver_data = DEF_MARVELL_HWMON_OPS(m88e6390_hwmon_ops),4036 /* PHY_GBIT_FEATURES */4037 .flags = PHY_POLL_CABLE_TEST,4038 .probe = marvell_probe,4039 .config_init = marvell_1011gbe_config_init,4040 .config_aneg = m88e6390_config_aneg,4041 .read_status = marvell_read_status,4042 .config_intr = marvell_config_intr,4043 .handle_interrupt = marvell_handle_interrupt,4044 .resume = genphy_resume,4045 .suspend = genphy_suspend,4046 .read_page = marvell_read_page,4047 .write_page = marvell_write_page,4048 .get_sset_count = marvell_get_sset_count,4049 .get_strings = marvell_get_strings,4050 .get_stats = marvell_get_stats,4051 .get_tunable = m88e1540_get_tunable,4052 .set_tunable = m88e1540_set_tunable,4053 .cable_test_start = marvell_vct7_cable_test_start,4054 .cable_test_tdr_start = marvell_vct5_cable_test_tdr_start,4055 .cable_test_get_status = marvell_vct7_cable_test_get_status,4056 },4057 {4058 .phy_id = MARVELL_PHY_ID_88E6393_FAMILY,4059 .phy_id_mask = MARVELL_PHY_ID_MASK,4060 .name = "Marvell 88E6393 Family",4061 .driver_data = DEF_MARVELL_HWMON_OPS(m88e6393_hwmon_ops),4062 /* PHY_GBIT_FEATURES */4063 .flags = PHY_POLL_CABLE_TEST,4064 .probe = marvell_probe,4065 .config_init = marvell_1011gbe_config_init,4066 .config_aneg = m88e1510_config_aneg,4067 .read_status = marvell_read_status,4068 .config_intr = marvell_config_intr,4069 .handle_interrupt = marvell_handle_interrupt,4070 .resume = genphy_resume,4071 .suspend = genphy_suspend,4072 .read_page = marvell_read_page,4073 .write_page = marvell_write_page,4074 .get_sset_count = marvell_get_sset_count,4075 .get_strings = marvell_get_strings,4076 .get_stats = marvell_get_stats,4077 .get_tunable = m88e1540_get_tunable,4078 .set_tunable = m88e1540_set_tunable,4079 .cable_test_start = marvell_vct7_cable_test_start,4080 .cable_test_tdr_start = marvell_vct5_cable_test_tdr_start,4081 .cable_test_get_status = marvell_vct7_cable_test_get_status,4082 },4083 {4084 .phy_id = MARVELL_PHY_ID_88E1340S,4085 .phy_id_mask = MARVELL_PHY_ID_MASK,4086 .name = "Marvell 88E1340S",4087 .driver_data = DEF_MARVELL_HWMON_OPS(m88e1510_hwmon_ops),4088 .probe = marvell_probe,4089 /* PHY_GBIT_FEATURES */4090 .config_init = marvell_1011gbe_config_init,4091 .config_aneg = m88e1510_config_aneg,4092 .read_status = marvell_read_status,4093 .config_intr = marvell_config_intr,4094 .handle_interrupt = marvell_handle_interrupt,4095 .resume = genphy_resume,4096 .suspend = genphy_suspend,4097 .read_page = marvell_read_page,4098 .write_page = marvell_write_page,4099 .get_sset_count = marvell_get_sset_count,4100 .get_strings = marvell_get_strings,4101 .get_stats = marvell_get_stats,4102 .get_tunable = m88e1540_get_tunable,4103 .set_tunable = m88e1540_set_tunable,4104 },4105 {4106 .phy_id = MARVELL_PHY_ID_88E1548P,4107 .phy_id_mask = MARVELL_PHY_ID_MASK,4108 .name = "Marvell 88E1548P",4109 .driver_data = DEF_MARVELL_HWMON_OPS(m88e1510_hwmon_ops),4110 .probe = marvell_probe,4111 .features = PHY_GBIT_FIBRE_FEATURES,4112 .config_init = marvell_1011gbe_config_init,4113 .config_aneg = m88e1510_config_aneg,4114 .read_status = marvell_read_status,4115 .config_intr = marvell_config_intr,4116 .handle_interrupt = marvell_handle_interrupt,4117 .resume = genphy_resume,4118 .suspend = genphy_suspend,4119 .read_page = marvell_read_page,4120 .write_page = marvell_write_page,4121 .get_sset_count = marvell_get_sset_count,4122 .get_strings = marvell_get_strings,4123 .get_stats = marvell_get_stats,4124 .get_tunable = m88e1540_get_tunable,4125 .set_tunable = m88e1540_set_tunable,4126 .led_brightness_set = m88e1318_led_brightness_set,4127 .led_blink_set = m88e1318_led_blink_set,4128 .led_hw_is_supported = m88e1318_led_hw_is_supported,4129 .led_hw_control_set = m88e1318_led_hw_control_set,4130 .led_hw_control_get = m88e1318_led_hw_control_get,4131 },4132};4133 4134module_phy_driver(marvell_drivers);4135 4136static struct mdio_device_id __maybe_unused marvell_tbl[] = {4137 { MARVELL_PHY_ID_88E1101, MARVELL_PHY_ID_MASK },4138 { MARVELL_PHY_ID_88E3082, MARVELL_PHY_ID_MASK },4139 { MARVELL_PHY_ID_88E1112, MARVELL_PHY_ID_MASK },4140 { MARVELL_PHY_ID_88E1111, MARVELL_PHY_ID_MASK },4141 { MARVELL_PHY_ID_88E1111_FINISAR, MARVELL_PHY_ID_MASK },4142 { MARVELL_PHY_ID_88E1118, MARVELL_PHY_ID_MASK },4143 { MARVELL_PHY_ID_88E1121R, MARVELL_PHY_ID_MASK },4144 { MARVELL_PHY_ID_88E1145, MARVELL_PHY_ID_MASK },4145 { MARVELL_PHY_ID_88E1149R, MARVELL_PHY_ID_MASK },4146 { MARVELL_PHY_ID_88E1240, MARVELL_PHY_ID_MASK },4147 { MARVELL_PHY_ID_88E1318S, MARVELL_PHY_ID_MASK },4148 { MARVELL_PHY_ID_88E1116R, MARVELL_PHY_ID_MASK },4149 { MARVELL_PHY_ID_88E1510, MARVELL_PHY_ID_MASK },4150 { MARVELL_PHY_ID_88E1540, MARVELL_PHY_ID_MASK },4151 { MARVELL_PHY_ID_88E1545, MARVELL_PHY_ID_MASK },4152 { MARVELL_PHY_ID_88E3016, MARVELL_PHY_ID_MASK },4153 { MARVELL_PHY_ID_88E6250_FAMILY, MARVELL_PHY_ID_MASK },4154 { MARVELL_PHY_ID_88E6341_FAMILY, MARVELL_PHY_ID_MASK },4155 { MARVELL_PHY_ID_88E6390_FAMILY, MARVELL_PHY_ID_MASK },4156 { MARVELL_PHY_ID_88E6393_FAMILY, MARVELL_PHY_ID_MASK },4157 { MARVELL_PHY_ID_88E1340S, MARVELL_PHY_ID_MASK },4158 { MARVELL_PHY_ID_88E1548P, MARVELL_PHY_ID_MASK },4159 { }4160};4161 4162MODULE_DEVICE_TABLE(mdio, marvell_tbl);4163