162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0+ 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * drivers/net/phy/marvell.c 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Driver for Marvell PHYs 662306a36Sopenharmony_ci * 762306a36Sopenharmony_ci * Author: Andy Fleming 862306a36Sopenharmony_ci * 962306a36Sopenharmony_ci * Copyright (c) 2004 Freescale Semiconductor, Inc. 1062306a36Sopenharmony_ci * 1162306a36Sopenharmony_ci * Copyright (c) 2013 Michael Stapelberg <michael@stapelberg.de> 1262306a36Sopenharmony_ci */ 1362306a36Sopenharmony_ci#include <linux/kernel.h> 1462306a36Sopenharmony_ci#include <linux/string.h> 1562306a36Sopenharmony_ci#include <linux/ctype.h> 1662306a36Sopenharmony_ci#include <linux/errno.h> 1762306a36Sopenharmony_ci#include <linux/unistd.h> 1862306a36Sopenharmony_ci#include <linux/hwmon.h> 1962306a36Sopenharmony_ci#include <linux/interrupt.h> 2062306a36Sopenharmony_ci#include <linux/init.h> 2162306a36Sopenharmony_ci#include <linux/delay.h> 2262306a36Sopenharmony_ci#include <linux/netdevice.h> 2362306a36Sopenharmony_ci#include <linux/etherdevice.h> 2462306a36Sopenharmony_ci#include <linux/skbuff.h> 2562306a36Sopenharmony_ci#include <linux/spinlock.h> 2662306a36Sopenharmony_ci#include <linux/mm.h> 2762306a36Sopenharmony_ci#include <linux/module.h> 2862306a36Sopenharmony_ci#include <linux/mii.h> 2962306a36Sopenharmony_ci#include <linux/ethtool.h> 3062306a36Sopenharmony_ci#include <linux/ethtool_netlink.h> 3162306a36Sopenharmony_ci#include <linux/phy.h> 3262306a36Sopenharmony_ci#include <linux/marvell_phy.h> 3362306a36Sopenharmony_ci#include <linux/bitfield.h> 3462306a36Sopenharmony_ci#include <linux/of.h> 3562306a36Sopenharmony_ci#include <linux/sfp.h> 3662306a36Sopenharmony_ci 3762306a36Sopenharmony_ci#include <linux/io.h> 3862306a36Sopenharmony_ci#include <asm/irq.h> 3962306a36Sopenharmony_ci#include <linux/uaccess.h> 4062306a36Sopenharmony_ci 4162306a36Sopenharmony_ci#define MII_MARVELL_PHY_PAGE 22 4262306a36Sopenharmony_ci#define MII_MARVELL_COPPER_PAGE 0x00 4362306a36Sopenharmony_ci#define MII_MARVELL_FIBER_PAGE 0x01 4462306a36Sopenharmony_ci#define MII_MARVELL_MSCR_PAGE 0x02 4562306a36Sopenharmony_ci#define MII_MARVELL_LED_PAGE 0x03 4662306a36Sopenharmony_ci#define MII_MARVELL_VCT5_PAGE 0x05 4762306a36Sopenharmony_ci#define MII_MARVELL_MISC_TEST_PAGE 0x06 4862306a36Sopenharmony_ci#define MII_MARVELL_VCT7_PAGE 0x07 4962306a36Sopenharmony_ci#define MII_MARVELL_WOL_PAGE 0x11 5062306a36Sopenharmony_ci#define MII_MARVELL_MODE_PAGE 0x12 5162306a36Sopenharmony_ci 5262306a36Sopenharmony_ci#define MII_M1011_IEVENT 0x13 5362306a36Sopenharmony_ci#define MII_M1011_IEVENT_CLEAR 0x0000 5462306a36Sopenharmony_ci 5562306a36Sopenharmony_ci#define MII_M1011_IMASK 0x12 5662306a36Sopenharmony_ci#define MII_M1011_IMASK_INIT 0x6400 5762306a36Sopenharmony_ci#define MII_M1011_IMASK_CLEAR 0x0000 5862306a36Sopenharmony_ci 5962306a36Sopenharmony_ci#define MII_M1011_PHY_SCR 0x10 6062306a36Sopenharmony_ci#define MII_M1011_PHY_SCR_DOWNSHIFT_EN BIT(11) 6162306a36Sopenharmony_ci#define MII_M1011_PHY_SCR_DOWNSHIFT_MASK GENMASK(14, 12) 6262306a36Sopenharmony_ci#define MII_M1011_PHY_SCR_DOWNSHIFT_MAX 8 6362306a36Sopenharmony_ci#define MII_M1011_PHY_SCR_MDI (0x0 << 5) 6462306a36Sopenharmony_ci#define MII_M1011_PHY_SCR_MDI_X (0x1 << 5) 6562306a36Sopenharmony_ci#define MII_M1011_PHY_SCR_AUTO_CROSS (0x3 << 5) 6662306a36Sopenharmony_ci 6762306a36Sopenharmony_ci#define MII_M1011_PHY_SSR 0x11 6862306a36Sopenharmony_ci#define MII_M1011_PHY_SSR_DOWNSHIFT BIT(5) 6962306a36Sopenharmony_ci 7062306a36Sopenharmony_ci#define MII_M1111_PHY_LED_CONTROL 0x18 7162306a36Sopenharmony_ci#define MII_M1111_PHY_LED_DIRECT 0x4100 7262306a36Sopenharmony_ci#define MII_M1111_PHY_LED_COMBINE 0x411c 7362306a36Sopenharmony_ci#define MII_M1111_PHY_EXT_CR 0x14 7462306a36Sopenharmony_ci#define MII_M1111_PHY_EXT_CR_DOWNSHIFT_MASK GENMASK(11, 9) 7562306a36Sopenharmony_ci#define MII_M1111_PHY_EXT_CR_DOWNSHIFT_MAX 8 7662306a36Sopenharmony_ci#define MII_M1111_PHY_EXT_CR_DOWNSHIFT_EN BIT(8) 7762306a36Sopenharmony_ci#define MII_M1111_RGMII_RX_DELAY BIT(7) 7862306a36Sopenharmony_ci#define MII_M1111_RGMII_TX_DELAY BIT(1) 7962306a36Sopenharmony_ci#define MII_M1111_PHY_EXT_SR 0x1b 8062306a36Sopenharmony_ci 8162306a36Sopenharmony_ci#define MII_M1111_HWCFG_MODE_MASK 0xf 8262306a36Sopenharmony_ci#define MII_M1111_HWCFG_MODE_FIBER_RGMII 0x3 8362306a36Sopenharmony_ci#define MII_M1111_HWCFG_MODE_SGMII_NO_CLK 0x4 8462306a36Sopenharmony_ci#define MII_M1111_HWCFG_MODE_RTBI 0x7 8562306a36Sopenharmony_ci#define MII_M1111_HWCFG_MODE_COPPER_1000X_AN 0x8 8662306a36Sopenharmony_ci#define MII_M1111_HWCFG_MODE_COPPER_RTBI 0x9 8762306a36Sopenharmony_ci#define MII_M1111_HWCFG_MODE_COPPER_RGMII 0xb 8862306a36Sopenharmony_ci#define MII_M1111_HWCFG_MODE_COPPER_1000X_NOAN 0xc 8962306a36Sopenharmony_ci#define MII_M1111_HWCFG_SERIAL_AN_BYPASS BIT(12) 9062306a36Sopenharmony_ci#define MII_M1111_HWCFG_FIBER_COPPER_RES BIT(13) 9162306a36Sopenharmony_ci#define MII_M1111_HWCFG_FIBER_COPPER_AUTO BIT(15) 9262306a36Sopenharmony_ci 9362306a36Sopenharmony_ci#define MII_88E1121_PHY_MSCR_REG 21 9462306a36Sopenharmony_ci#define MII_88E1121_PHY_MSCR_RX_DELAY BIT(5) 9562306a36Sopenharmony_ci#define MII_88E1121_PHY_MSCR_TX_DELAY BIT(4) 9662306a36Sopenharmony_ci#define MII_88E1121_PHY_MSCR_DELAY_MASK (BIT(5) | BIT(4)) 9762306a36Sopenharmony_ci 9862306a36Sopenharmony_ci#define MII_88E1121_MISC_TEST 0x1a 9962306a36Sopenharmony_ci#define MII_88E1510_MISC_TEST_TEMP_THRESHOLD_MASK 0x1f00 10062306a36Sopenharmony_ci#define MII_88E1510_MISC_TEST_TEMP_THRESHOLD_SHIFT 8 10162306a36Sopenharmony_ci#define MII_88E1510_MISC_TEST_TEMP_IRQ_EN BIT(7) 10262306a36Sopenharmony_ci#define MII_88E1510_MISC_TEST_TEMP_IRQ BIT(6) 10362306a36Sopenharmony_ci#define MII_88E1121_MISC_TEST_TEMP_SENSOR_EN BIT(5) 10462306a36Sopenharmony_ci#define MII_88E1121_MISC_TEST_TEMP_MASK 0x1f 10562306a36Sopenharmony_ci 10662306a36Sopenharmony_ci#define MII_88E1510_TEMP_SENSOR 0x1b 10762306a36Sopenharmony_ci#define MII_88E1510_TEMP_SENSOR_MASK 0xff 10862306a36Sopenharmony_ci 10962306a36Sopenharmony_ci#define MII_88E1540_COPPER_CTRL3 0x1a 11062306a36Sopenharmony_ci#define MII_88E1540_COPPER_CTRL3_LINK_DOWN_DELAY_MASK GENMASK(11, 10) 11162306a36Sopenharmony_ci#define MII_88E1540_COPPER_CTRL3_LINK_DOWN_DELAY_00MS 0 11262306a36Sopenharmony_ci#define MII_88E1540_COPPER_CTRL3_LINK_DOWN_DELAY_10MS 1 11362306a36Sopenharmony_ci#define MII_88E1540_COPPER_CTRL3_LINK_DOWN_DELAY_20MS 2 11462306a36Sopenharmony_ci#define MII_88E1540_COPPER_CTRL3_LINK_DOWN_DELAY_40MS 3 11562306a36Sopenharmony_ci#define MII_88E1540_COPPER_CTRL3_FAST_LINK_DOWN BIT(9) 11662306a36Sopenharmony_ci 11762306a36Sopenharmony_ci#define MII_88E6390_MISC_TEST 0x1b 11862306a36Sopenharmony_ci#define MII_88E6390_MISC_TEST_TEMP_SENSOR_ENABLE_SAMPLE_1S (0x0 << 14) 11962306a36Sopenharmony_ci#define MII_88E6390_MISC_TEST_TEMP_SENSOR_ENABLE (0x1 << 14) 12062306a36Sopenharmony_ci#define MII_88E6390_MISC_TEST_TEMP_SENSOR_ENABLE_ONESHOT (0x2 << 14) 12162306a36Sopenharmony_ci#define MII_88E6390_MISC_TEST_TEMP_SENSOR_DISABLE (0x3 << 14) 12262306a36Sopenharmony_ci#define MII_88E6390_MISC_TEST_TEMP_SENSOR_MASK (0x3 << 14) 12362306a36Sopenharmony_ci#define MII_88E6393_MISC_TEST_SAMPLES_2048 (0x0 << 11) 12462306a36Sopenharmony_ci#define MII_88E6393_MISC_TEST_SAMPLES_4096 (0x1 << 11) 12562306a36Sopenharmony_ci#define MII_88E6393_MISC_TEST_SAMPLES_8192 (0x2 << 11) 12662306a36Sopenharmony_ci#define MII_88E6393_MISC_TEST_SAMPLES_16384 (0x3 << 11) 12762306a36Sopenharmony_ci#define MII_88E6393_MISC_TEST_SAMPLES_MASK (0x3 << 11) 12862306a36Sopenharmony_ci#define MII_88E6393_MISC_TEST_RATE_2_3MS (0x5 << 8) 12962306a36Sopenharmony_ci#define MII_88E6393_MISC_TEST_RATE_6_4MS (0x6 << 8) 13062306a36Sopenharmony_ci#define MII_88E6393_MISC_TEST_RATE_11_9MS (0x7 << 8) 13162306a36Sopenharmony_ci#define MII_88E6393_MISC_TEST_RATE_MASK (0x7 << 8) 13262306a36Sopenharmony_ci 13362306a36Sopenharmony_ci#define MII_88E6390_TEMP_SENSOR 0x1c 13462306a36Sopenharmony_ci#define MII_88E6393_TEMP_SENSOR_THRESHOLD_MASK 0xff00 13562306a36Sopenharmony_ci#define MII_88E6393_TEMP_SENSOR_THRESHOLD_SHIFT 8 13662306a36Sopenharmony_ci#define MII_88E6390_TEMP_SENSOR_MASK 0xff 13762306a36Sopenharmony_ci#define MII_88E6390_TEMP_SENSOR_SAMPLES 10 13862306a36Sopenharmony_ci 13962306a36Sopenharmony_ci#define MII_88E1318S_PHY_MSCR1_REG 16 14062306a36Sopenharmony_ci#define MII_88E1318S_PHY_MSCR1_PAD_ODD BIT(6) 14162306a36Sopenharmony_ci 14262306a36Sopenharmony_ci/* Copper Specific Interrupt Enable Register */ 14362306a36Sopenharmony_ci#define MII_88E1318S_PHY_CSIER 0x12 14462306a36Sopenharmony_ci/* WOL Event Interrupt Enable */ 14562306a36Sopenharmony_ci#define MII_88E1318S_PHY_CSIER_WOL_EIE BIT(7) 14662306a36Sopenharmony_ci 14762306a36Sopenharmony_ci#define MII_88E1318S_PHY_LED_FUNC 0x10 14862306a36Sopenharmony_ci#define MII_88E1318S_PHY_LED_FUNC_OFF (0x8) 14962306a36Sopenharmony_ci#define MII_88E1318S_PHY_LED_FUNC_ON (0x9) 15062306a36Sopenharmony_ci#define MII_88E1318S_PHY_LED_FUNC_HI_Z (0xa) 15162306a36Sopenharmony_ci#define MII_88E1318S_PHY_LED_FUNC_BLINK (0xb) 15262306a36Sopenharmony_ci#define MII_88E1318S_PHY_LED_TCR 0x12 15362306a36Sopenharmony_ci#define MII_88E1318S_PHY_LED_TCR_FORCE_INT BIT(15) 15462306a36Sopenharmony_ci#define MII_88E1318S_PHY_LED_TCR_INTn_ENABLE BIT(7) 15562306a36Sopenharmony_ci#define MII_88E1318S_PHY_LED_TCR_INT_ACTIVE_LOW BIT(11) 15662306a36Sopenharmony_ci 15762306a36Sopenharmony_ci/* Magic Packet MAC address registers */ 15862306a36Sopenharmony_ci#define MII_88E1318S_PHY_MAGIC_PACKET_WORD2 0x17 15962306a36Sopenharmony_ci#define MII_88E1318S_PHY_MAGIC_PACKET_WORD1 0x18 16062306a36Sopenharmony_ci#define MII_88E1318S_PHY_MAGIC_PACKET_WORD0 0x19 16162306a36Sopenharmony_ci 16262306a36Sopenharmony_ci#define MII_88E1318S_PHY_WOL_CTRL 0x10 16362306a36Sopenharmony_ci#define MII_88E1318S_PHY_WOL_CTRL_CLEAR_WOL_STATUS BIT(12) 16462306a36Sopenharmony_ci#define MII_88E1318S_PHY_WOL_CTRL_LINK_UP_ENABLE BIT(13) 16562306a36Sopenharmony_ci#define MII_88E1318S_PHY_WOL_CTRL_MAGIC_PACKET_MATCH_ENABLE BIT(14) 16662306a36Sopenharmony_ci 16762306a36Sopenharmony_ci#define MII_PHY_LED_CTRL 16 16862306a36Sopenharmony_ci#define MII_88E1121_PHY_LED_DEF 0x0030 16962306a36Sopenharmony_ci#define MII_88E1510_PHY_LED_DEF 0x1177 17062306a36Sopenharmony_ci#define MII_88E1510_PHY_LED0_LINK_LED1_ACTIVE 0x1040 17162306a36Sopenharmony_ci 17262306a36Sopenharmony_ci#define MII_M1011_PHY_STATUS 0x11 17362306a36Sopenharmony_ci#define MII_M1011_PHY_STATUS_1000 0x8000 17462306a36Sopenharmony_ci#define MII_M1011_PHY_STATUS_100 0x4000 17562306a36Sopenharmony_ci#define MII_M1011_PHY_STATUS_SPD_MASK 0xc000 17662306a36Sopenharmony_ci#define MII_M1011_PHY_STATUS_FULLDUPLEX 0x2000 17762306a36Sopenharmony_ci#define MII_M1011_PHY_STATUS_RESOLVED 0x0800 17862306a36Sopenharmony_ci#define MII_M1011_PHY_STATUS_LINK 0x0400 17962306a36Sopenharmony_ci 18062306a36Sopenharmony_ci#define MII_88E3016_PHY_SPEC_CTRL 0x10 18162306a36Sopenharmony_ci#define MII_88E3016_DISABLE_SCRAMBLER 0x0200 18262306a36Sopenharmony_ci#define MII_88E3016_AUTO_MDIX_CROSSOVER 0x0030 18362306a36Sopenharmony_ci 18462306a36Sopenharmony_ci#define MII_88E1510_GEN_CTRL_REG_1 0x14 18562306a36Sopenharmony_ci#define MII_88E1510_GEN_CTRL_REG_1_MODE_MASK 0x7 18662306a36Sopenharmony_ci#define MII_88E1510_GEN_CTRL_REG_1_MODE_RGMII 0x0 /* RGMII to copper */ 18762306a36Sopenharmony_ci#define MII_88E1510_GEN_CTRL_REG_1_MODE_SGMII 0x1 /* SGMII to copper */ 18862306a36Sopenharmony_ci/* RGMII to 1000BASE-X */ 18962306a36Sopenharmony_ci#define MII_88E1510_GEN_CTRL_REG_1_MODE_RGMII_1000X 0x2 19062306a36Sopenharmony_ci/* RGMII to 100BASE-FX */ 19162306a36Sopenharmony_ci#define MII_88E1510_GEN_CTRL_REG_1_MODE_RGMII_100FX 0x3 19262306a36Sopenharmony_ci/* RGMII to SGMII */ 19362306a36Sopenharmony_ci#define MII_88E1510_GEN_CTRL_REG_1_MODE_RGMII_SGMII 0x4 19462306a36Sopenharmony_ci#define MII_88E1510_GEN_CTRL_REG_1_RESET 0x8000 /* Soft reset */ 19562306a36Sopenharmony_ci 19662306a36Sopenharmony_ci#define MII_88E1510_MSCR_2 0x15 19762306a36Sopenharmony_ci 19862306a36Sopenharmony_ci#define MII_VCT5_TX_RX_MDI0_COUPLING 0x10 19962306a36Sopenharmony_ci#define MII_VCT5_TX_RX_MDI1_COUPLING 0x11 20062306a36Sopenharmony_ci#define MII_VCT5_TX_RX_MDI2_COUPLING 0x12 20162306a36Sopenharmony_ci#define MII_VCT5_TX_RX_MDI3_COUPLING 0x13 20262306a36Sopenharmony_ci#define MII_VCT5_TX_RX_AMPLITUDE_MASK 0x7f00 20362306a36Sopenharmony_ci#define MII_VCT5_TX_RX_AMPLITUDE_SHIFT 8 20462306a36Sopenharmony_ci#define MII_VCT5_TX_RX_COUPLING_POSITIVE_REFLECTION BIT(15) 20562306a36Sopenharmony_ci 20662306a36Sopenharmony_ci#define MII_VCT5_CTRL 0x17 20762306a36Sopenharmony_ci#define MII_VCT5_CTRL_ENABLE BIT(15) 20862306a36Sopenharmony_ci#define MII_VCT5_CTRL_COMPLETE BIT(14) 20962306a36Sopenharmony_ci#define MII_VCT5_CTRL_TX_SAME_CHANNEL (0x0 << 11) 21062306a36Sopenharmony_ci#define MII_VCT5_CTRL_TX0_CHANNEL (0x4 << 11) 21162306a36Sopenharmony_ci#define MII_VCT5_CTRL_TX1_CHANNEL (0x5 << 11) 21262306a36Sopenharmony_ci#define MII_VCT5_CTRL_TX2_CHANNEL (0x6 << 11) 21362306a36Sopenharmony_ci#define MII_VCT5_CTRL_TX3_CHANNEL (0x7 << 11) 21462306a36Sopenharmony_ci#define MII_VCT5_CTRL_SAMPLES_2 (0x0 << 8) 21562306a36Sopenharmony_ci#define MII_VCT5_CTRL_SAMPLES_4 (0x1 << 8) 21662306a36Sopenharmony_ci#define MII_VCT5_CTRL_SAMPLES_8 (0x2 << 8) 21762306a36Sopenharmony_ci#define MII_VCT5_CTRL_SAMPLES_16 (0x3 << 8) 21862306a36Sopenharmony_ci#define MII_VCT5_CTRL_SAMPLES_32 (0x4 << 8) 21962306a36Sopenharmony_ci#define MII_VCT5_CTRL_SAMPLES_64 (0x5 << 8) 22062306a36Sopenharmony_ci#define MII_VCT5_CTRL_SAMPLES_128 (0x6 << 8) 22162306a36Sopenharmony_ci#define MII_VCT5_CTRL_SAMPLES_DEFAULT (0x6 << 8) 22262306a36Sopenharmony_ci#define MII_VCT5_CTRL_SAMPLES_256 (0x7 << 8) 22362306a36Sopenharmony_ci#define MII_VCT5_CTRL_SAMPLES_SHIFT 8 22462306a36Sopenharmony_ci#define MII_VCT5_CTRL_MODE_MAXIMUM_PEEK (0x0 << 6) 22562306a36Sopenharmony_ci#define MII_VCT5_CTRL_MODE_FIRST_LAST_PEEK (0x1 << 6) 22662306a36Sopenharmony_ci#define MII_VCT5_CTRL_MODE_OFFSET (0x2 << 6) 22762306a36Sopenharmony_ci#define MII_VCT5_CTRL_SAMPLE_POINT (0x3 << 6) 22862306a36Sopenharmony_ci#define MII_VCT5_CTRL_PEEK_HYST_DEFAULT 3 22962306a36Sopenharmony_ci 23062306a36Sopenharmony_ci#define MII_VCT5_SAMPLE_POINT_DISTANCE 0x18 23162306a36Sopenharmony_ci#define MII_VCT5_SAMPLE_POINT_DISTANCE_MAX 511 23262306a36Sopenharmony_ci#define MII_VCT5_TX_PULSE_CTRL 0x1c 23362306a36Sopenharmony_ci#define MII_VCT5_TX_PULSE_CTRL_DONT_WAIT_LINK_DOWN BIT(12) 23462306a36Sopenharmony_ci#define MII_VCT5_TX_PULSE_CTRL_PULSE_WIDTH_128nS (0x0 << 10) 23562306a36Sopenharmony_ci#define MII_VCT5_TX_PULSE_CTRL_PULSE_WIDTH_96nS (0x1 << 10) 23662306a36Sopenharmony_ci#define MII_VCT5_TX_PULSE_CTRL_PULSE_WIDTH_64nS (0x2 << 10) 23762306a36Sopenharmony_ci#define MII_VCT5_TX_PULSE_CTRL_PULSE_WIDTH_32nS (0x3 << 10) 23862306a36Sopenharmony_ci#define MII_VCT5_TX_PULSE_CTRL_PULSE_WIDTH_SHIFT 10 23962306a36Sopenharmony_ci#define MII_VCT5_TX_PULSE_CTRL_PULSE_AMPLITUDE_1000mV (0x0 << 8) 24062306a36Sopenharmony_ci#define MII_VCT5_TX_PULSE_CTRL_PULSE_AMPLITUDE_750mV (0x1 << 8) 24162306a36Sopenharmony_ci#define MII_VCT5_TX_PULSE_CTRL_PULSE_AMPLITUDE_500mV (0x2 << 8) 24262306a36Sopenharmony_ci#define MII_VCT5_TX_PULSE_CTRL_PULSE_AMPLITUDE_250mV (0x3 << 8) 24362306a36Sopenharmony_ci#define MII_VCT5_TX_PULSE_CTRL_PULSE_AMPLITUDE_SHIFT 8 24462306a36Sopenharmony_ci#define MII_VCT5_TX_PULSE_CTRL_MAX_AMP BIT(7) 24562306a36Sopenharmony_ci#define MII_VCT5_TX_PULSE_CTRL_GT_140m_46_86mV (0x6 << 0) 24662306a36Sopenharmony_ci 24762306a36Sopenharmony_ci/* For TDR measurements less than 11 meters, a short pulse should be 24862306a36Sopenharmony_ci * used. 24962306a36Sopenharmony_ci */ 25062306a36Sopenharmony_ci#define TDR_SHORT_CABLE_LENGTH 11 25162306a36Sopenharmony_ci 25262306a36Sopenharmony_ci#define MII_VCT7_PAIR_0_DISTANCE 0x10 25362306a36Sopenharmony_ci#define MII_VCT7_PAIR_1_DISTANCE 0x11 25462306a36Sopenharmony_ci#define MII_VCT7_PAIR_2_DISTANCE 0x12 25562306a36Sopenharmony_ci#define MII_VCT7_PAIR_3_DISTANCE 0x13 25662306a36Sopenharmony_ci 25762306a36Sopenharmony_ci#define MII_VCT7_RESULTS 0x14 25862306a36Sopenharmony_ci#define MII_VCT7_RESULTS_PAIR3_MASK 0xf000 25962306a36Sopenharmony_ci#define MII_VCT7_RESULTS_PAIR2_MASK 0x0f00 26062306a36Sopenharmony_ci#define MII_VCT7_RESULTS_PAIR1_MASK 0x00f0 26162306a36Sopenharmony_ci#define MII_VCT7_RESULTS_PAIR0_MASK 0x000f 26262306a36Sopenharmony_ci#define MII_VCT7_RESULTS_PAIR3_SHIFT 12 26362306a36Sopenharmony_ci#define MII_VCT7_RESULTS_PAIR2_SHIFT 8 26462306a36Sopenharmony_ci#define MII_VCT7_RESULTS_PAIR1_SHIFT 4 26562306a36Sopenharmony_ci#define MII_VCT7_RESULTS_PAIR0_SHIFT 0 26662306a36Sopenharmony_ci#define MII_VCT7_RESULTS_INVALID 0 26762306a36Sopenharmony_ci#define MII_VCT7_RESULTS_OK 1 26862306a36Sopenharmony_ci#define MII_VCT7_RESULTS_OPEN 2 26962306a36Sopenharmony_ci#define MII_VCT7_RESULTS_SAME_SHORT 3 27062306a36Sopenharmony_ci#define MII_VCT7_RESULTS_CROSS_SHORT 4 27162306a36Sopenharmony_ci#define MII_VCT7_RESULTS_BUSY 9 27262306a36Sopenharmony_ci 27362306a36Sopenharmony_ci#define MII_VCT7_CTRL 0x15 27462306a36Sopenharmony_ci#define MII_VCT7_CTRL_RUN_NOW BIT(15) 27562306a36Sopenharmony_ci#define MII_VCT7_CTRL_RUN_ANEG BIT(14) 27662306a36Sopenharmony_ci#define MII_VCT7_CTRL_DISABLE_CROSS BIT(13) 27762306a36Sopenharmony_ci#define MII_VCT7_CTRL_RUN_AFTER_BREAK_LINK BIT(12) 27862306a36Sopenharmony_ci#define MII_VCT7_CTRL_IN_PROGRESS BIT(11) 27962306a36Sopenharmony_ci#define MII_VCT7_CTRL_METERS BIT(10) 28062306a36Sopenharmony_ci#define MII_VCT7_CTRL_CENTIMETERS 0 28162306a36Sopenharmony_ci 28262306a36Sopenharmony_ci#define LPA_PAUSE_FIBER 0x180 28362306a36Sopenharmony_ci#define LPA_PAUSE_ASYM_FIBER 0x100 28462306a36Sopenharmony_ci 28562306a36Sopenharmony_ci#define NB_FIBER_STATS 1 28662306a36Sopenharmony_ci 28762306a36Sopenharmony_ciMODULE_DESCRIPTION("Marvell PHY driver"); 28862306a36Sopenharmony_ciMODULE_AUTHOR("Andy Fleming"); 28962306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 29062306a36Sopenharmony_ci 29162306a36Sopenharmony_cistruct marvell_hw_stat { 29262306a36Sopenharmony_ci const char *string; 29362306a36Sopenharmony_ci u8 page; 29462306a36Sopenharmony_ci u8 reg; 29562306a36Sopenharmony_ci u8 bits; 29662306a36Sopenharmony_ci}; 29762306a36Sopenharmony_ci 29862306a36Sopenharmony_cistatic struct marvell_hw_stat marvell_hw_stats[] = { 29962306a36Sopenharmony_ci { "phy_receive_errors_copper", 0, 21, 16}, 30062306a36Sopenharmony_ci { "phy_idle_errors", 0, 10, 8 }, 30162306a36Sopenharmony_ci { "phy_receive_errors_fiber", 1, 21, 16}, 30262306a36Sopenharmony_ci}; 30362306a36Sopenharmony_ci 30462306a36Sopenharmony_cistruct marvell_priv { 30562306a36Sopenharmony_ci u64 stats[ARRAY_SIZE(marvell_hw_stats)]; 30662306a36Sopenharmony_ci char *hwmon_name; 30762306a36Sopenharmony_ci struct device *hwmon_dev; 30862306a36Sopenharmony_ci bool cable_test_tdr; 30962306a36Sopenharmony_ci u32 first; 31062306a36Sopenharmony_ci u32 last; 31162306a36Sopenharmony_ci u32 step; 31262306a36Sopenharmony_ci s8 pair; 31362306a36Sopenharmony_ci}; 31462306a36Sopenharmony_ci 31562306a36Sopenharmony_cistatic int marvell_read_page(struct phy_device *phydev) 31662306a36Sopenharmony_ci{ 31762306a36Sopenharmony_ci return __phy_read(phydev, MII_MARVELL_PHY_PAGE); 31862306a36Sopenharmony_ci} 31962306a36Sopenharmony_ci 32062306a36Sopenharmony_cistatic int marvell_write_page(struct phy_device *phydev, int page) 32162306a36Sopenharmony_ci{ 32262306a36Sopenharmony_ci return __phy_write(phydev, MII_MARVELL_PHY_PAGE, page); 32362306a36Sopenharmony_ci} 32462306a36Sopenharmony_ci 32562306a36Sopenharmony_cistatic int marvell_set_page(struct phy_device *phydev, int page) 32662306a36Sopenharmony_ci{ 32762306a36Sopenharmony_ci return phy_write(phydev, MII_MARVELL_PHY_PAGE, page); 32862306a36Sopenharmony_ci} 32962306a36Sopenharmony_ci 33062306a36Sopenharmony_cistatic int marvell_ack_interrupt(struct phy_device *phydev) 33162306a36Sopenharmony_ci{ 33262306a36Sopenharmony_ci int err; 33362306a36Sopenharmony_ci 33462306a36Sopenharmony_ci /* Clear the interrupts by reading the reg */ 33562306a36Sopenharmony_ci err = phy_read(phydev, MII_M1011_IEVENT); 33662306a36Sopenharmony_ci 33762306a36Sopenharmony_ci if (err < 0) 33862306a36Sopenharmony_ci return err; 33962306a36Sopenharmony_ci 34062306a36Sopenharmony_ci return 0; 34162306a36Sopenharmony_ci} 34262306a36Sopenharmony_ci 34362306a36Sopenharmony_cistatic int marvell_config_intr(struct phy_device *phydev) 34462306a36Sopenharmony_ci{ 34562306a36Sopenharmony_ci int err; 34662306a36Sopenharmony_ci 34762306a36Sopenharmony_ci if (phydev->interrupts == PHY_INTERRUPT_ENABLED) { 34862306a36Sopenharmony_ci err = marvell_ack_interrupt(phydev); 34962306a36Sopenharmony_ci if (err) 35062306a36Sopenharmony_ci return err; 35162306a36Sopenharmony_ci 35262306a36Sopenharmony_ci err = phy_write(phydev, MII_M1011_IMASK, 35362306a36Sopenharmony_ci MII_M1011_IMASK_INIT); 35462306a36Sopenharmony_ci } else { 35562306a36Sopenharmony_ci err = phy_write(phydev, MII_M1011_IMASK, 35662306a36Sopenharmony_ci MII_M1011_IMASK_CLEAR); 35762306a36Sopenharmony_ci if (err) 35862306a36Sopenharmony_ci return err; 35962306a36Sopenharmony_ci 36062306a36Sopenharmony_ci err = marvell_ack_interrupt(phydev); 36162306a36Sopenharmony_ci } 36262306a36Sopenharmony_ci 36362306a36Sopenharmony_ci return err; 36462306a36Sopenharmony_ci} 36562306a36Sopenharmony_ci 36662306a36Sopenharmony_cistatic irqreturn_t marvell_handle_interrupt(struct phy_device *phydev) 36762306a36Sopenharmony_ci{ 36862306a36Sopenharmony_ci int irq_status; 36962306a36Sopenharmony_ci 37062306a36Sopenharmony_ci irq_status = phy_read(phydev, MII_M1011_IEVENT); 37162306a36Sopenharmony_ci if (irq_status < 0) { 37262306a36Sopenharmony_ci phy_error(phydev); 37362306a36Sopenharmony_ci return IRQ_NONE; 37462306a36Sopenharmony_ci } 37562306a36Sopenharmony_ci 37662306a36Sopenharmony_ci if (!(irq_status & MII_M1011_IMASK_INIT)) 37762306a36Sopenharmony_ci return IRQ_NONE; 37862306a36Sopenharmony_ci 37962306a36Sopenharmony_ci phy_trigger_machine(phydev); 38062306a36Sopenharmony_ci 38162306a36Sopenharmony_ci return IRQ_HANDLED; 38262306a36Sopenharmony_ci} 38362306a36Sopenharmony_ci 38462306a36Sopenharmony_cistatic int marvell_set_polarity(struct phy_device *phydev, int polarity) 38562306a36Sopenharmony_ci{ 38662306a36Sopenharmony_ci u16 val; 38762306a36Sopenharmony_ci 38862306a36Sopenharmony_ci switch (polarity) { 38962306a36Sopenharmony_ci case ETH_TP_MDI: 39062306a36Sopenharmony_ci val = MII_M1011_PHY_SCR_MDI; 39162306a36Sopenharmony_ci break; 39262306a36Sopenharmony_ci case ETH_TP_MDI_X: 39362306a36Sopenharmony_ci val = MII_M1011_PHY_SCR_MDI_X; 39462306a36Sopenharmony_ci break; 39562306a36Sopenharmony_ci case ETH_TP_MDI_AUTO: 39662306a36Sopenharmony_ci case ETH_TP_MDI_INVALID: 39762306a36Sopenharmony_ci default: 39862306a36Sopenharmony_ci val = MII_M1011_PHY_SCR_AUTO_CROSS; 39962306a36Sopenharmony_ci break; 40062306a36Sopenharmony_ci } 40162306a36Sopenharmony_ci 40262306a36Sopenharmony_ci return phy_modify_changed(phydev, MII_M1011_PHY_SCR, 40362306a36Sopenharmony_ci MII_M1011_PHY_SCR_AUTO_CROSS, val); 40462306a36Sopenharmony_ci} 40562306a36Sopenharmony_ci 40662306a36Sopenharmony_cistatic int marvell_config_aneg(struct phy_device *phydev) 40762306a36Sopenharmony_ci{ 40862306a36Sopenharmony_ci int changed = 0; 40962306a36Sopenharmony_ci int err; 41062306a36Sopenharmony_ci 41162306a36Sopenharmony_ci err = marvell_set_polarity(phydev, phydev->mdix_ctrl); 41262306a36Sopenharmony_ci if (err < 0) 41362306a36Sopenharmony_ci return err; 41462306a36Sopenharmony_ci 41562306a36Sopenharmony_ci changed = err; 41662306a36Sopenharmony_ci 41762306a36Sopenharmony_ci err = phy_write(phydev, MII_M1111_PHY_LED_CONTROL, 41862306a36Sopenharmony_ci MII_M1111_PHY_LED_DIRECT); 41962306a36Sopenharmony_ci if (err < 0) 42062306a36Sopenharmony_ci return err; 42162306a36Sopenharmony_ci 42262306a36Sopenharmony_ci err = genphy_config_aneg(phydev); 42362306a36Sopenharmony_ci if (err < 0) 42462306a36Sopenharmony_ci return err; 42562306a36Sopenharmony_ci 42662306a36Sopenharmony_ci if (phydev->autoneg != AUTONEG_ENABLE || changed) { 42762306a36Sopenharmony_ci /* A write to speed/duplex bits (that is performed by 42862306a36Sopenharmony_ci * genphy_config_aneg() call above) must be followed by 42962306a36Sopenharmony_ci * a software reset. Otherwise, the write has no effect. 43062306a36Sopenharmony_ci */ 43162306a36Sopenharmony_ci err = genphy_soft_reset(phydev); 43262306a36Sopenharmony_ci if (err < 0) 43362306a36Sopenharmony_ci return err; 43462306a36Sopenharmony_ci } 43562306a36Sopenharmony_ci 43662306a36Sopenharmony_ci return 0; 43762306a36Sopenharmony_ci} 43862306a36Sopenharmony_ci 43962306a36Sopenharmony_cistatic int m88e1101_config_aneg(struct phy_device *phydev) 44062306a36Sopenharmony_ci{ 44162306a36Sopenharmony_ci int err; 44262306a36Sopenharmony_ci 44362306a36Sopenharmony_ci /* This Marvell PHY has an errata which requires 44462306a36Sopenharmony_ci * that certain registers get written in order 44562306a36Sopenharmony_ci * to restart autonegotiation 44662306a36Sopenharmony_ci */ 44762306a36Sopenharmony_ci err = genphy_soft_reset(phydev); 44862306a36Sopenharmony_ci if (err < 0) 44962306a36Sopenharmony_ci return err; 45062306a36Sopenharmony_ci 45162306a36Sopenharmony_ci err = phy_write(phydev, 0x1d, 0x1f); 45262306a36Sopenharmony_ci if (err < 0) 45362306a36Sopenharmony_ci return err; 45462306a36Sopenharmony_ci 45562306a36Sopenharmony_ci err = phy_write(phydev, 0x1e, 0x200c); 45662306a36Sopenharmony_ci if (err < 0) 45762306a36Sopenharmony_ci return err; 45862306a36Sopenharmony_ci 45962306a36Sopenharmony_ci err = phy_write(phydev, 0x1d, 0x5); 46062306a36Sopenharmony_ci if (err < 0) 46162306a36Sopenharmony_ci return err; 46262306a36Sopenharmony_ci 46362306a36Sopenharmony_ci err = phy_write(phydev, 0x1e, 0); 46462306a36Sopenharmony_ci if (err < 0) 46562306a36Sopenharmony_ci return err; 46662306a36Sopenharmony_ci 46762306a36Sopenharmony_ci err = phy_write(phydev, 0x1e, 0x100); 46862306a36Sopenharmony_ci if (err < 0) 46962306a36Sopenharmony_ci return err; 47062306a36Sopenharmony_ci 47162306a36Sopenharmony_ci return marvell_config_aneg(phydev); 47262306a36Sopenharmony_ci} 47362306a36Sopenharmony_ci 47462306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_OF_MDIO) 47562306a36Sopenharmony_ci/* Set and/or override some configuration registers based on the 47662306a36Sopenharmony_ci * marvell,reg-init property stored in the of_node for the phydev. 47762306a36Sopenharmony_ci * 47862306a36Sopenharmony_ci * marvell,reg-init = <reg-page reg mask value>,...; 47962306a36Sopenharmony_ci * 48062306a36Sopenharmony_ci * There may be one or more sets of <reg-page reg mask value>: 48162306a36Sopenharmony_ci * 48262306a36Sopenharmony_ci * reg-page: which register bank to use. 48362306a36Sopenharmony_ci * reg: the register. 48462306a36Sopenharmony_ci * mask: if non-zero, ANDed with existing register value. 48562306a36Sopenharmony_ci * value: ORed with the masked value and written to the regiser. 48662306a36Sopenharmony_ci * 48762306a36Sopenharmony_ci */ 48862306a36Sopenharmony_cistatic int marvell_of_reg_init(struct phy_device *phydev) 48962306a36Sopenharmony_ci{ 49062306a36Sopenharmony_ci const __be32 *paddr; 49162306a36Sopenharmony_ci int len, i, saved_page, current_page, ret = 0; 49262306a36Sopenharmony_ci 49362306a36Sopenharmony_ci if (!phydev->mdio.dev.of_node) 49462306a36Sopenharmony_ci return 0; 49562306a36Sopenharmony_ci 49662306a36Sopenharmony_ci paddr = of_get_property(phydev->mdio.dev.of_node, 49762306a36Sopenharmony_ci "marvell,reg-init", &len); 49862306a36Sopenharmony_ci if (!paddr || len < (4 * sizeof(*paddr))) 49962306a36Sopenharmony_ci return 0; 50062306a36Sopenharmony_ci 50162306a36Sopenharmony_ci saved_page = phy_save_page(phydev); 50262306a36Sopenharmony_ci if (saved_page < 0) 50362306a36Sopenharmony_ci goto err; 50462306a36Sopenharmony_ci current_page = saved_page; 50562306a36Sopenharmony_ci 50662306a36Sopenharmony_ci len /= sizeof(*paddr); 50762306a36Sopenharmony_ci for (i = 0; i < len - 3; i += 4) { 50862306a36Sopenharmony_ci u16 page = be32_to_cpup(paddr + i); 50962306a36Sopenharmony_ci u16 reg = be32_to_cpup(paddr + i + 1); 51062306a36Sopenharmony_ci u16 mask = be32_to_cpup(paddr + i + 2); 51162306a36Sopenharmony_ci u16 val_bits = be32_to_cpup(paddr + i + 3); 51262306a36Sopenharmony_ci int val; 51362306a36Sopenharmony_ci 51462306a36Sopenharmony_ci if (page != current_page) { 51562306a36Sopenharmony_ci current_page = page; 51662306a36Sopenharmony_ci ret = marvell_write_page(phydev, page); 51762306a36Sopenharmony_ci if (ret < 0) 51862306a36Sopenharmony_ci goto err; 51962306a36Sopenharmony_ci } 52062306a36Sopenharmony_ci 52162306a36Sopenharmony_ci val = 0; 52262306a36Sopenharmony_ci if (mask) { 52362306a36Sopenharmony_ci val = __phy_read(phydev, reg); 52462306a36Sopenharmony_ci if (val < 0) { 52562306a36Sopenharmony_ci ret = val; 52662306a36Sopenharmony_ci goto err; 52762306a36Sopenharmony_ci } 52862306a36Sopenharmony_ci val &= mask; 52962306a36Sopenharmony_ci } 53062306a36Sopenharmony_ci val |= val_bits; 53162306a36Sopenharmony_ci 53262306a36Sopenharmony_ci ret = __phy_write(phydev, reg, val); 53362306a36Sopenharmony_ci if (ret < 0) 53462306a36Sopenharmony_ci goto err; 53562306a36Sopenharmony_ci } 53662306a36Sopenharmony_cierr: 53762306a36Sopenharmony_ci return phy_restore_page(phydev, saved_page, ret); 53862306a36Sopenharmony_ci} 53962306a36Sopenharmony_ci#else 54062306a36Sopenharmony_cistatic int marvell_of_reg_init(struct phy_device *phydev) 54162306a36Sopenharmony_ci{ 54262306a36Sopenharmony_ci return 0; 54362306a36Sopenharmony_ci} 54462306a36Sopenharmony_ci#endif /* CONFIG_OF_MDIO */ 54562306a36Sopenharmony_ci 54662306a36Sopenharmony_cistatic int m88e1121_config_aneg_rgmii_delays(struct phy_device *phydev) 54762306a36Sopenharmony_ci{ 54862306a36Sopenharmony_ci int mscr; 54962306a36Sopenharmony_ci 55062306a36Sopenharmony_ci if (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID) 55162306a36Sopenharmony_ci mscr = MII_88E1121_PHY_MSCR_RX_DELAY | 55262306a36Sopenharmony_ci MII_88E1121_PHY_MSCR_TX_DELAY; 55362306a36Sopenharmony_ci else if (phydev->interface == PHY_INTERFACE_MODE_RGMII_RXID) 55462306a36Sopenharmony_ci mscr = MII_88E1121_PHY_MSCR_RX_DELAY; 55562306a36Sopenharmony_ci else if (phydev->interface == PHY_INTERFACE_MODE_RGMII_TXID) 55662306a36Sopenharmony_ci mscr = MII_88E1121_PHY_MSCR_TX_DELAY; 55762306a36Sopenharmony_ci else 55862306a36Sopenharmony_ci mscr = 0; 55962306a36Sopenharmony_ci 56062306a36Sopenharmony_ci return phy_modify_paged_changed(phydev, MII_MARVELL_MSCR_PAGE, 56162306a36Sopenharmony_ci MII_88E1121_PHY_MSCR_REG, 56262306a36Sopenharmony_ci MII_88E1121_PHY_MSCR_DELAY_MASK, mscr); 56362306a36Sopenharmony_ci} 56462306a36Sopenharmony_ci 56562306a36Sopenharmony_cistatic int m88e1121_config_aneg(struct phy_device *phydev) 56662306a36Sopenharmony_ci{ 56762306a36Sopenharmony_ci int changed = 0; 56862306a36Sopenharmony_ci int err = 0; 56962306a36Sopenharmony_ci 57062306a36Sopenharmony_ci if (phy_interface_is_rgmii(phydev)) { 57162306a36Sopenharmony_ci err = m88e1121_config_aneg_rgmii_delays(phydev); 57262306a36Sopenharmony_ci if (err < 0) 57362306a36Sopenharmony_ci return err; 57462306a36Sopenharmony_ci } 57562306a36Sopenharmony_ci 57662306a36Sopenharmony_ci changed = err; 57762306a36Sopenharmony_ci 57862306a36Sopenharmony_ci err = marvell_set_polarity(phydev, phydev->mdix_ctrl); 57962306a36Sopenharmony_ci if (err < 0) 58062306a36Sopenharmony_ci return err; 58162306a36Sopenharmony_ci 58262306a36Sopenharmony_ci changed |= err; 58362306a36Sopenharmony_ci 58462306a36Sopenharmony_ci err = genphy_config_aneg(phydev); 58562306a36Sopenharmony_ci if (err < 0) 58662306a36Sopenharmony_ci return err; 58762306a36Sopenharmony_ci 58862306a36Sopenharmony_ci if (phydev->autoneg != AUTONEG_ENABLE || changed) { 58962306a36Sopenharmony_ci /* A software reset is used to ensure a "commit" of the 59062306a36Sopenharmony_ci * changes is done. 59162306a36Sopenharmony_ci */ 59262306a36Sopenharmony_ci err = genphy_soft_reset(phydev); 59362306a36Sopenharmony_ci if (err < 0) 59462306a36Sopenharmony_ci return err; 59562306a36Sopenharmony_ci } 59662306a36Sopenharmony_ci 59762306a36Sopenharmony_ci return 0; 59862306a36Sopenharmony_ci} 59962306a36Sopenharmony_ci 60062306a36Sopenharmony_cistatic int m88e1318_config_aneg(struct phy_device *phydev) 60162306a36Sopenharmony_ci{ 60262306a36Sopenharmony_ci int err; 60362306a36Sopenharmony_ci 60462306a36Sopenharmony_ci err = phy_modify_paged(phydev, MII_MARVELL_MSCR_PAGE, 60562306a36Sopenharmony_ci MII_88E1318S_PHY_MSCR1_REG, 60662306a36Sopenharmony_ci 0, MII_88E1318S_PHY_MSCR1_PAD_ODD); 60762306a36Sopenharmony_ci if (err < 0) 60862306a36Sopenharmony_ci return err; 60962306a36Sopenharmony_ci 61062306a36Sopenharmony_ci return m88e1121_config_aneg(phydev); 61162306a36Sopenharmony_ci} 61262306a36Sopenharmony_ci 61362306a36Sopenharmony_ci/** 61462306a36Sopenharmony_ci * linkmode_adv_to_fiber_adv_t 61562306a36Sopenharmony_ci * @advertise: the linkmode advertisement settings 61662306a36Sopenharmony_ci * 61762306a36Sopenharmony_ci * A small helper function that translates linkmode advertisement 61862306a36Sopenharmony_ci * settings to phy autonegotiation advertisements for the MII_ADV 61962306a36Sopenharmony_ci * register for fiber link. 62062306a36Sopenharmony_ci */ 62162306a36Sopenharmony_cistatic inline u32 linkmode_adv_to_fiber_adv_t(unsigned long *advertise) 62262306a36Sopenharmony_ci{ 62362306a36Sopenharmony_ci u32 result = 0; 62462306a36Sopenharmony_ci 62562306a36Sopenharmony_ci if (linkmode_test_bit(ETHTOOL_LINK_MODE_1000baseT_Half_BIT, advertise)) 62662306a36Sopenharmony_ci result |= ADVERTISE_1000XHALF; 62762306a36Sopenharmony_ci if (linkmode_test_bit(ETHTOOL_LINK_MODE_1000baseT_Full_BIT, advertise)) 62862306a36Sopenharmony_ci result |= ADVERTISE_1000XFULL; 62962306a36Sopenharmony_ci 63062306a36Sopenharmony_ci if (linkmode_test_bit(ETHTOOL_LINK_MODE_Asym_Pause_BIT, advertise) && 63162306a36Sopenharmony_ci linkmode_test_bit(ETHTOOL_LINK_MODE_Pause_BIT, advertise)) 63262306a36Sopenharmony_ci result |= ADVERTISE_1000XPSE_ASYM; 63362306a36Sopenharmony_ci else if (linkmode_test_bit(ETHTOOL_LINK_MODE_Pause_BIT, advertise)) 63462306a36Sopenharmony_ci result |= ADVERTISE_1000XPAUSE; 63562306a36Sopenharmony_ci 63662306a36Sopenharmony_ci return result; 63762306a36Sopenharmony_ci} 63862306a36Sopenharmony_ci 63962306a36Sopenharmony_ci/** 64062306a36Sopenharmony_ci * marvell_config_aneg_fiber - restart auto-negotiation or write BMCR 64162306a36Sopenharmony_ci * @phydev: target phy_device struct 64262306a36Sopenharmony_ci * 64362306a36Sopenharmony_ci * Description: If auto-negotiation is enabled, we configure the 64462306a36Sopenharmony_ci * advertising, and then restart auto-negotiation. If it is not 64562306a36Sopenharmony_ci * enabled, then we write the BMCR. Adapted for fiber link in 64662306a36Sopenharmony_ci * some Marvell's devices. 64762306a36Sopenharmony_ci */ 64862306a36Sopenharmony_cistatic int marvell_config_aneg_fiber(struct phy_device *phydev) 64962306a36Sopenharmony_ci{ 65062306a36Sopenharmony_ci int changed = 0; 65162306a36Sopenharmony_ci int err; 65262306a36Sopenharmony_ci u16 adv; 65362306a36Sopenharmony_ci 65462306a36Sopenharmony_ci if (phydev->autoneg != AUTONEG_ENABLE) 65562306a36Sopenharmony_ci return genphy_setup_forced(phydev); 65662306a36Sopenharmony_ci 65762306a36Sopenharmony_ci /* Only allow advertising what this PHY supports */ 65862306a36Sopenharmony_ci linkmode_and(phydev->advertising, phydev->advertising, 65962306a36Sopenharmony_ci phydev->supported); 66062306a36Sopenharmony_ci 66162306a36Sopenharmony_ci adv = linkmode_adv_to_fiber_adv_t(phydev->advertising); 66262306a36Sopenharmony_ci 66362306a36Sopenharmony_ci /* Setup fiber advertisement */ 66462306a36Sopenharmony_ci err = phy_modify_changed(phydev, MII_ADVERTISE, 66562306a36Sopenharmony_ci ADVERTISE_1000XHALF | ADVERTISE_1000XFULL | 66662306a36Sopenharmony_ci ADVERTISE_1000XPAUSE | ADVERTISE_1000XPSE_ASYM, 66762306a36Sopenharmony_ci adv); 66862306a36Sopenharmony_ci if (err < 0) 66962306a36Sopenharmony_ci return err; 67062306a36Sopenharmony_ci if (err > 0) 67162306a36Sopenharmony_ci changed = 1; 67262306a36Sopenharmony_ci 67362306a36Sopenharmony_ci return genphy_check_and_restart_aneg(phydev, changed); 67462306a36Sopenharmony_ci} 67562306a36Sopenharmony_ci 67662306a36Sopenharmony_cistatic int m88e1111_config_aneg(struct phy_device *phydev) 67762306a36Sopenharmony_ci{ 67862306a36Sopenharmony_ci int extsr = phy_read(phydev, MII_M1111_PHY_EXT_SR); 67962306a36Sopenharmony_ci int err; 68062306a36Sopenharmony_ci 68162306a36Sopenharmony_ci if (extsr < 0) 68262306a36Sopenharmony_ci return extsr; 68362306a36Sopenharmony_ci 68462306a36Sopenharmony_ci /* If not using SGMII or copper 1000BaseX modes, use normal process. 68562306a36Sopenharmony_ci * Steps below are only required for these modes. 68662306a36Sopenharmony_ci */ 68762306a36Sopenharmony_ci if (phydev->interface != PHY_INTERFACE_MODE_SGMII && 68862306a36Sopenharmony_ci (extsr & MII_M1111_HWCFG_MODE_MASK) != 68962306a36Sopenharmony_ci MII_M1111_HWCFG_MODE_COPPER_1000X_AN) 69062306a36Sopenharmony_ci return marvell_config_aneg(phydev); 69162306a36Sopenharmony_ci 69262306a36Sopenharmony_ci err = marvell_set_page(phydev, MII_MARVELL_COPPER_PAGE); 69362306a36Sopenharmony_ci if (err < 0) 69462306a36Sopenharmony_ci goto error; 69562306a36Sopenharmony_ci 69662306a36Sopenharmony_ci /* Configure the copper link first */ 69762306a36Sopenharmony_ci err = marvell_config_aneg(phydev); 69862306a36Sopenharmony_ci if (err < 0) 69962306a36Sopenharmony_ci goto error; 70062306a36Sopenharmony_ci 70162306a36Sopenharmony_ci /* Then the fiber link */ 70262306a36Sopenharmony_ci err = marvell_set_page(phydev, MII_MARVELL_FIBER_PAGE); 70362306a36Sopenharmony_ci if (err < 0) 70462306a36Sopenharmony_ci goto error; 70562306a36Sopenharmony_ci 70662306a36Sopenharmony_ci if (phydev->interface == PHY_INTERFACE_MODE_SGMII) 70762306a36Sopenharmony_ci /* Do not touch the fiber advertisement if we're in copper->sgmii mode. 70862306a36Sopenharmony_ci * Just ensure that SGMII-side autonegotiation is enabled. 70962306a36Sopenharmony_ci * If we switched from some other mode to SGMII it may not be. 71062306a36Sopenharmony_ci */ 71162306a36Sopenharmony_ci err = genphy_check_and_restart_aneg(phydev, false); 71262306a36Sopenharmony_ci else 71362306a36Sopenharmony_ci err = marvell_config_aneg_fiber(phydev); 71462306a36Sopenharmony_ci if (err < 0) 71562306a36Sopenharmony_ci goto error; 71662306a36Sopenharmony_ci 71762306a36Sopenharmony_ci return marvell_set_page(phydev, MII_MARVELL_COPPER_PAGE); 71862306a36Sopenharmony_ci 71962306a36Sopenharmony_cierror: 72062306a36Sopenharmony_ci marvell_set_page(phydev, MII_MARVELL_COPPER_PAGE); 72162306a36Sopenharmony_ci return err; 72262306a36Sopenharmony_ci} 72362306a36Sopenharmony_ci 72462306a36Sopenharmony_cistatic int m88e1510_config_aneg(struct phy_device *phydev) 72562306a36Sopenharmony_ci{ 72662306a36Sopenharmony_ci int err; 72762306a36Sopenharmony_ci 72862306a36Sopenharmony_ci err = marvell_set_page(phydev, MII_MARVELL_COPPER_PAGE); 72962306a36Sopenharmony_ci if (err < 0) 73062306a36Sopenharmony_ci goto error; 73162306a36Sopenharmony_ci 73262306a36Sopenharmony_ci /* Configure the copper link first */ 73362306a36Sopenharmony_ci err = m88e1318_config_aneg(phydev); 73462306a36Sopenharmony_ci if (err < 0) 73562306a36Sopenharmony_ci goto error; 73662306a36Sopenharmony_ci 73762306a36Sopenharmony_ci /* Do not touch the fiber page if we're in copper->sgmii mode */ 73862306a36Sopenharmony_ci if (phydev->interface == PHY_INTERFACE_MODE_SGMII) 73962306a36Sopenharmony_ci return 0; 74062306a36Sopenharmony_ci 74162306a36Sopenharmony_ci /* Then the fiber link */ 74262306a36Sopenharmony_ci err = marvell_set_page(phydev, MII_MARVELL_FIBER_PAGE); 74362306a36Sopenharmony_ci if (err < 0) 74462306a36Sopenharmony_ci goto error; 74562306a36Sopenharmony_ci 74662306a36Sopenharmony_ci err = marvell_config_aneg_fiber(phydev); 74762306a36Sopenharmony_ci if (err < 0) 74862306a36Sopenharmony_ci goto error; 74962306a36Sopenharmony_ci 75062306a36Sopenharmony_ci return marvell_set_page(phydev, MII_MARVELL_COPPER_PAGE); 75162306a36Sopenharmony_ci 75262306a36Sopenharmony_cierror: 75362306a36Sopenharmony_ci marvell_set_page(phydev, MII_MARVELL_COPPER_PAGE); 75462306a36Sopenharmony_ci return err; 75562306a36Sopenharmony_ci} 75662306a36Sopenharmony_ci 75762306a36Sopenharmony_cistatic void marvell_config_led(struct phy_device *phydev) 75862306a36Sopenharmony_ci{ 75962306a36Sopenharmony_ci u16 def_config; 76062306a36Sopenharmony_ci int err; 76162306a36Sopenharmony_ci 76262306a36Sopenharmony_ci switch (MARVELL_PHY_FAMILY_ID(phydev->phy_id)) { 76362306a36Sopenharmony_ci /* Default PHY LED config: LED[0] .. Link, LED[1] .. Activity */ 76462306a36Sopenharmony_ci case MARVELL_PHY_FAMILY_ID(MARVELL_PHY_ID_88E1121R): 76562306a36Sopenharmony_ci case MARVELL_PHY_FAMILY_ID(MARVELL_PHY_ID_88E1318S): 76662306a36Sopenharmony_ci def_config = MII_88E1121_PHY_LED_DEF; 76762306a36Sopenharmony_ci break; 76862306a36Sopenharmony_ci /* Default PHY LED config: 76962306a36Sopenharmony_ci * LED[0] .. 1000Mbps Link 77062306a36Sopenharmony_ci * LED[1] .. 100Mbps Link 77162306a36Sopenharmony_ci * LED[2] .. Blink, Activity 77262306a36Sopenharmony_ci */ 77362306a36Sopenharmony_ci case MARVELL_PHY_FAMILY_ID(MARVELL_PHY_ID_88E1510): 77462306a36Sopenharmony_ci if (phydev->dev_flags & MARVELL_PHY_LED0_LINK_LED1_ACTIVE) 77562306a36Sopenharmony_ci def_config = MII_88E1510_PHY_LED0_LINK_LED1_ACTIVE; 77662306a36Sopenharmony_ci else 77762306a36Sopenharmony_ci def_config = MII_88E1510_PHY_LED_DEF; 77862306a36Sopenharmony_ci break; 77962306a36Sopenharmony_ci default: 78062306a36Sopenharmony_ci return; 78162306a36Sopenharmony_ci } 78262306a36Sopenharmony_ci 78362306a36Sopenharmony_ci err = phy_write_paged(phydev, MII_MARVELL_LED_PAGE, MII_PHY_LED_CTRL, 78462306a36Sopenharmony_ci def_config); 78562306a36Sopenharmony_ci if (err < 0) 78662306a36Sopenharmony_ci phydev_warn(phydev, "Fail to config marvell phy LED.\n"); 78762306a36Sopenharmony_ci} 78862306a36Sopenharmony_ci 78962306a36Sopenharmony_cistatic int marvell_config_init(struct phy_device *phydev) 79062306a36Sopenharmony_ci{ 79162306a36Sopenharmony_ci /* Set default LED */ 79262306a36Sopenharmony_ci marvell_config_led(phydev); 79362306a36Sopenharmony_ci 79462306a36Sopenharmony_ci /* Set registers from marvell,reg-init DT property */ 79562306a36Sopenharmony_ci return marvell_of_reg_init(phydev); 79662306a36Sopenharmony_ci} 79762306a36Sopenharmony_ci 79862306a36Sopenharmony_cistatic int m88e3016_config_init(struct phy_device *phydev) 79962306a36Sopenharmony_ci{ 80062306a36Sopenharmony_ci int ret; 80162306a36Sopenharmony_ci 80262306a36Sopenharmony_ci /* Enable Scrambler and Auto-Crossover */ 80362306a36Sopenharmony_ci ret = phy_modify(phydev, MII_88E3016_PHY_SPEC_CTRL, 80462306a36Sopenharmony_ci MII_88E3016_DISABLE_SCRAMBLER, 80562306a36Sopenharmony_ci MII_88E3016_AUTO_MDIX_CROSSOVER); 80662306a36Sopenharmony_ci if (ret < 0) 80762306a36Sopenharmony_ci return ret; 80862306a36Sopenharmony_ci 80962306a36Sopenharmony_ci return marvell_config_init(phydev); 81062306a36Sopenharmony_ci} 81162306a36Sopenharmony_ci 81262306a36Sopenharmony_cistatic int m88e1111_config_init_hwcfg_mode(struct phy_device *phydev, 81362306a36Sopenharmony_ci u16 mode, 81462306a36Sopenharmony_ci int fibre_copper_auto) 81562306a36Sopenharmony_ci{ 81662306a36Sopenharmony_ci if (fibre_copper_auto) 81762306a36Sopenharmony_ci mode |= MII_M1111_HWCFG_FIBER_COPPER_AUTO; 81862306a36Sopenharmony_ci 81962306a36Sopenharmony_ci return phy_modify(phydev, MII_M1111_PHY_EXT_SR, 82062306a36Sopenharmony_ci MII_M1111_HWCFG_MODE_MASK | 82162306a36Sopenharmony_ci MII_M1111_HWCFG_FIBER_COPPER_AUTO | 82262306a36Sopenharmony_ci MII_M1111_HWCFG_FIBER_COPPER_RES, 82362306a36Sopenharmony_ci mode); 82462306a36Sopenharmony_ci} 82562306a36Sopenharmony_ci 82662306a36Sopenharmony_cistatic int m88e1111_config_init_rgmii_delays(struct phy_device *phydev) 82762306a36Sopenharmony_ci{ 82862306a36Sopenharmony_ci int delay; 82962306a36Sopenharmony_ci 83062306a36Sopenharmony_ci switch (phydev->interface) { 83162306a36Sopenharmony_ci case PHY_INTERFACE_MODE_RGMII_ID: 83262306a36Sopenharmony_ci delay = MII_M1111_RGMII_RX_DELAY | MII_M1111_RGMII_TX_DELAY; 83362306a36Sopenharmony_ci break; 83462306a36Sopenharmony_ci case PHY_INTERFACE_MODE_RGMII_RXID: 83562306a36Sopenharmony_ci delay = MII_M1111_RGMII_RX_DELAY; 83662306a36Sopenharmony_ci break; 83762306a36Sopenharmony_ci case PHY_INTERFACE_MODE_RGMII_TXID: 83862306a36Sopenharmony_ci delay = MII_M1111_RGMII_TX_DELAY; 83962306a36Sopenharmony_ci break; 84062306a36Sopenharmony_ci default: 84162306a36Sopenharmony_ci delay = 0; 84262306a36Sopenharmony_ci break; 84362306a36Sopenharmony_ci } 84462306a36Sopenharmony_ci 84562306a36Sopenharmony_ci return phy_modify(phydev, MII_M1111_PHY_EXT_CR, 84662306a36Sopenharmony_ci MII_M1111_RGMII_RX_DELAY | MII_M1111_RGMII_TX_DELAY, 84762306a36Sopenharmony_ci delay); 84862306a36Sopenharmony_ci} 84962306a36Sopenharmony_ci 85062306a36Sopenharmony_cistatic int m88e1111_config_init_rgmii(struct phy_device *phydev) 85162306a36Sopenharmony_ci{ 85262306a36Sopenharmony_ci int temp; 85362306a36Sopenharmony_ci int err; 85462306a36Sopenharmony_ci 85562306a36Sopenharmony_ci err = m88e1111_config_init_rgmii_delays(phydev); 85662306a36Sopenharmony_ci if (err < 0) 85762306a36Sopenharmony_ci return err; 85862306a36Sopenharmony_ci 85962306a36Sopenharmony_ci temp = phy_read(phydev, MII_M1111_PHY_EXT_SR); 86062306a36Sopenharmony_ci if (temp < 0) 86162306a36Sopenharmony_ci return temp; 86262306a36Sopenharmony_ci 86362306a36Sopenharmony_ci temp &= ~(MII_M1111_HWCFG_MODE_MASK); 86462306a36Sopenharmony_ci 86562306a36Sopenharmony_ci if (temp & MII_M1111_HWCFG_FIBER_COPPER_RES) 86662306a36Sopenharmony_ci temp |= MII_M1111_HWCFG_MODE_FIBER_RGMII; 86762306a36Sopenharmony_ci else 86862306a36Sopenharmony_ci temp |= MII_M1111_HWCFG_MODE_COPPER_RGMII; 86962306a36Sopenharmony_ci 87062306a36Sopenharmony_ci return phy_write(phydev, MII_M1111_PHY_EXT_SR, temp); 87162306a36Sopenharmony_ci} 87262306a36Sopenharmony_ci 87362306a36Sopenharmony_cistatic int m88e1111_config_init_sgmii(struct phy_device *phydev) 87462306a36Sopenharmony_ci{ 87562306a36Sopenharmony_ci int err; 87662306a36Sopenharmony_ci 87762306a36Sopenharmony_ci err = m88e1111_config_init_hwcfg_mode( 87862306a36Sopenharmony_ci phydev, 87962306a36Sopenharmony_ci MII_M1111_HWCFG_MODE_SGMII_NO_CLK, 88062306a36Sopenharmony_ci MII_M1111_HWCFG_FIBER_COPPER_AUTO); 88162306a36Sopenharmony_ci if (err < 0) 88262306a36Sopenharmony_ci return err; 88362306a36Sopenharmony_ci 88462306a36Sopenharmony_ci /* make sure copper is selected */ 88562306a36Sopenharmony_ci return marvell_set_page(phydev, MII_MARVELL_COPPER_PAGE); 88662306a36Sopenharmony_ci} 88762306a36Sopenharmony_ci 88862306a36Sopenharmony_cistatic int m88e1111_config_init_rtbi(struct phy_device *phydev) 88962306a36Sopenharmony_ci{ 89062306a36Sopenharmony_ci int err; 89162306a36Sopenharmony_ci 89262306a36Sopenharmony_ci err = m88e1111_config_init_rgmii_delays(phydev); 89362306a36Sopenharmony_ci if (err < 0) 89462306a36Sopenharmony_ci return err; 89562306a36Sopenharmony_ci 89662306a36Sopenharmony_ci err = m88e1111_config_init_hwcfg_mode( 89762306a36Sopenharmony_ci phydev, 89862306a36Sopenharmony_ci MII_M1111_HWCFG_MODE_RTBI, 89962306a36Sopenharmony_ci MII_M1111_HWCFG_FIBER_COPPER_AUTO); 90062306a36Sopenharmony_ci if (err < 0) 90162306a36Sopenharmony_ci return err; 90262306a36Sopenharmony_ci 90362306a36Sopenharmony_ci /* soft reset */ 90462306a36Sopenharmony_ci err = genphy_soft_reset(phydev); 90562306a36Sopenharmony_ci if (err < 0) 90662306a36Sopenharmony_ci return err; 90762306a36Sopenharmony_ci 90862306a36Sopenharmony_ci return m88e1111_config_init_hwcfg_mode( 90962306a36Sopenharmony_ci phydev, 91062306a36Sopenharmony_ci MII_M1111_HWCFG_MODE_RTBI, 91162306a36Sopenharmony_ci MII_M1111_HWCFG_FIBER_COPPER_AUTO); 91262306a36Sopenharmony_ci} 91362306a36Sopenharmony_ci 91462306a36Sopenharmony_cistatic int m88e1111_config_init_1000basex(struct phy_device *phydev) 91562306a36Sopenharmony_ci{ 91662306a36Sopenharmony_ci int extsr = phy_read(phydev, MII_M1111_PHY_EXT_SR); 91762306a36Sopenharmony_ci int err, mode; 91862306a36Sopenharmony_ci 91962306a36Sopenharmony_ci if (extsr < 0) 92062306a36Sopenharmony_ci return extsr; 92162306a36Sopenharmony_ci 92262306a36Sopenharmony_ci /* If using copper mode, ensure 1000BaseX auto-negotiation is enabled */ 92362306a36Sopenharmony_ci mode = extsr & MII_M1111_HWCFG_MODE_MASK; 92462306a36Sopenharmony_ci if (mode == MII_M1111_HWCFG_MODE_COPPER_1000X_NOAN) { 92562306a36Sopenharmony_ci err = phy_modify(phydev, MII_M1111_PHY_EXT_SR, 92662306a36Sopenharmony_ci MII_M1111_HWCFG_MODE_MASK | 92762306a36Sopenharmony_ci MII_M1111_HWCFG_SERIAL_AN_BYPASS, 92862306a36Sopenharmony_ci MII_M1111_HWCFG_MODE_COPPER_1000X_AN | 92962306a36Sopenharmony_ci MII_M1111_HWCFG_SERIAL_AN_BYPASS); 93062306a36Sopenharmony_ci if (err < 0) 93162306a36Sopenharmony_ci return err; 93262306a36Sopenharmony_ci } 93362306a36Sopenharmony_ci return 0; 93462306a36Sopenharmony_ci} 93562306a36Sopenharmony_ci 93662306a36Sopenharmony_cistatic int m88e1111_config_init(struct phy_device *phydev) 93762306a36Sopenharmony_ci{ 93862306a36Sopenharmony_ci int err; 93962306a36Sopenharmony_ci 94062306a36Sopenharmony_ci if (phy_interface_is_rgmii(phydev)) { 94162306a36Sopenharmony_ci err = m88e1111_config_init_rgmii(phydev); 94262306a36Sopenharmony_ci if (err < 0) 94362306a36Sopenharmony_ci return err; 94462306a36Sopenharmony_ci } 94562306a36Sopenharmony_ci 94662306a36Sopenharmony_ci if (phydev->interface == PHY_INTERFACE_MODE_SGMII) { 94762306a36Sopenharmony_ci err = m88e1111_config_init_sgmii(phydev); 94862306a36Sopenharmony_ci if (err < 0) 94962306a36Sopenharmony_ci return err; 95062306a36Sopenharmony_ci } 95162306a36Sopenharmony_ci 95262306a36Sopenharmony_ci if (phydev->interface == PHY_INTERFACE_MODE_RTBI) { 95362306a36Sopenharmony_ci err = m88e1111_config_init_rtbi(phydev); 95462306a36Sopenharmony_ci if (err < 0) 95562306a36Sopenharmony_ci return err; 95662306a36Sopenharmony_ci } 95762306a36Sopenharmony_ci 95862306a36Sopenharmony_ci if (phydev->interface == PHY_INTERFACE_MODE_1000BASEX) { 95962306a36Sopenharmony_ci err = m88e1111_config_init_1000basex(phydev); 96062306a36Sopenharmony_ci if (err < 0) 96162306a36Sopenharmony_ci return err; 96262306a36Sopenharmony_ci } 96362306a36Sopenharmony_ci 96462306a36Sopenharmony_ci err = marvell_of_reg_init(phydev); 96562306a36Sopenharmony_ci if (err < 0) 96662306a36Sopenharmony_ci return err; 96762306a36Sopenharmony_ci 96862306a36Sopenharmony_ci err = genphy_soft_reset(phydev); 96962306a36Sopenharmony_ci if (err < 0) 97062306a36Sopenharmony_ci return err; 97162306a36Sopenharmony_ci 97262306a36Sopenharmony_ci if (phydev->interface == PHY_INTERFACE_MODE_SGMII) { 97362306a36Sopenharmony_ci /* If the HWCFG_MODE was changed from another mode (such as 97462306a36Sopenharmony_ci * 1000BaseX) to SGMII, the state of the support bits may have 97562306a36Sopenharmony_ci * also changed now that the PHY has been reset. 97662306a36Sopenharmony_ci * Update the PHY abilities accordingly. 97762306a36Sopenharmony_ci */ 97862306a36Sopenharmony_ci err = genphy_read_abilities(phydev); 97962306a36Sopenharmony_ci linkmode_or(phydev->advertising, phydev->advertising, 98062306a36Sopenharmony_ci phydev->supported); 98162306a36Sopenharmony_ci } 98262306a36Sopenharmony_ci return err; 98362306a36Sopenharmony_ci} 98462306a36Sopenharmony_ci 98562306a36Sopenharmony_cistatic int m88e1111_get_downshift(struct phy_device *phydev, u8 *data) 98662306a36Sopenharmony_ci{ 98762306a36Sopenharmony_ci int val, cnt, enable; 98862306a36Sopenharmony_ci 98962306a36Sopenharmony_ci val = phy_read(phydev, MII_M1111_PHY_EXT_CR); 99062306a36Sopenharmony_ci if (val < 0) 99162306a36Sopenharmony_ci return val; 99262306a36Sopenharmony_ci 99362306a36Sopenharmony_ci enable = FIELD_GET(MII_M1111_PHY_EXT_CR_DOWNSHIFT_EN, val); 99462306a36Sopenharmony_ci cnt = FIELD_GET(MII_M1111_PHY_EXT_CR_DOWNSHIFT_MASK, val) + 1; 99562306a36Sopenharmony_ci 99662306a36Sopenharmony_ci *data = enable ? cnt : DOWNSHIFT_DEV_DISABLE; 99762306a36Sopenharmony_ci 99862306a36Sopenharmony_ci return 0; 99962306a36Sopenharmony_ci} 100062306a36Sopenharmony_ci 100162306a36Sopenharmony_cistatic int m88e1111_set_downshift(struct phy_device *phydev, u8 cnt) 100262306a36Sopenharmony_ci{ 100362306a36Sopenharmony_ci int val, err; 100462306a36Sopenharmony_ci 100562306a36Sopenharmony_ci if (cnt > MII_M1111_PHY_EXT_CR_DOWNSHIFT_MAX) 100662306a36Sopenharmony_ci return -E2BIG; 100762306a36Sopenharmony_ci 100862306a36Sopenharmony_ci if (!cnt) { 100962306a36Sopenharmony_ci err = phy_clear_bits(phydev, MII_M1111_PHY_EXT_CR, 101062306a36Sopenharmony_ci MII_M1111_PHY_EXT_CR_DOWNSHIFT_EN); 101162306a36Sopenharmony_ci } else { 101262306a36Sopenharmony_ci val = MII_M1111_PHY_EXT_CR_DOWNSHIFT_EN; 101362306a36Sopenharmony_ci val |= FIELD_PREP(MII_M1111_PHY_EXT_CR_DOWNSHIFT_MASK, cnt - 1); 101462306a36Sopenharmony_ci 101562306a36Sopenharmony_ci err = phy_modify(phydev, MII_M1111_PHY_EXT_CR, 101662306a36Sopenharmony_ci MII_M1111_PHY_EXT_CR_DOWNSHIFT_EN | 101762306a36Sopenharmony_ci MII_M1111_PHY_EXT_CR_DOWNSHIFT_MASK, 101862306a36Sopenharmony_ci val); 101962306a36Sopenharmony_ci } 102062306a36Sopenharmony_ci 102162306a36Sopenharmony_ci if (err < 0) 102262306a36Sopenharmony_ci return err; 102362306a36Sopenharmony_ci 102462306a36Sopenharmony_ci return genphy_soft_reset(phydev); 102562306a36Sopenharmony_ci} 102662306a36Sopenharmony_ci 102762306a36Sopenharmony_cistatic int m88e1111_get_tunable(struct phy_device *phydev, 102862306a36Sopenharmony_ci struct ethtool_tunable *tuna, void *data) 102962306a36Sopenharmony_ci{ 103062306a36Sopenharmony_ci switch (tuna->id) { 103162306a36Sopenharmony_ci case ETHTOOL_PHY_DOWNSHIFT: 103262306a36Sopenharmony_ci return m88e1111_get_downshift(phydev, data); 103362306a36Sopenharmony_ci default: 103462306a36Sopenharmony_ci return -EOPNOTSUPP; 103562306a36Sopenharmony_ci } 103662306a36Sopenharmony_ci} 103762306a36Sopenharmony_ci 103862306a36Sopenharmony_cistatic int m88e1111_set_tunable(struct phy_device *phydev, 103962306a36Sopenharmony_ci struct ethtool_tunable *tuna, const void *data) 104062306a36Sopenharmony_ci{ 104162306a36Sopenharmony_ci switch (tuna->id) { 104262306a36Sopenharmony_ci case ETHTOOL_PHY_DOWNSHIFT: 104362306a36Sopenharmony_ci return m88e1111_set_downshift(phydev, *(const u8 *)data); 104462306a36Sopenharmony_ci default: 104562306a36Sopenharmony_ci return -EOPNOTSUPP; 104662306a36Sopenharmony_ci } 104762306a36Sopenharmony_ci} 104862306a36Sopenharmony_ci 104962306a36Sopenharmony_cistatic int m88e1011_get_downshift(struct phy_device *phydev, u8 *data) 105062306a36Sopenharmony_ci{ 105162306a36Sopenharmony_ci int val, cnt, enable; 105262306a36Sopenharmony_ci 105362306a36Sopenharmony_ci val = phy_read(phydev, MII_M1011_PHY_SCR); 105462306a36Sopenharmony_ci if (val < 0) 105562306a36Sopenharmony_ci return val; 105662306a36Sopenharmony_ci 105762306a36Sopenharmony_ci enable = FIELD_GET(MII_M1011_PHY_SCR_DOWNSHIFT_EN, val); 105862306a36Sopenharmony_ci cnt = FIELD_GET(MII_M1011_PHY_SCR_DOWNSHIFT_MASK, val) + 1; 105962306a36Sopenharmony_ci 106062306a36Sopenharmony_ci *data = enable ? cnt : DOWNSHIFT_DEV_DISABLE; 106162306a36Sopenharmony_ci 106262306a36Sopenharmony_ci return 0; 106362306a36Sopenharmony_ci} 106462306a36Sopenharmony_ci 106562306a36Sopenharmony_cistatic int m88e1011_set_downshift(struct phy_device *phydev, u8 cnt) 106662306a36Sopenharmony_ci{ 106762306a36Sopenharmony_ci int val, err; 106862306a36Sopenharmony_ci 106962306a36Sopenharmony_ci if (cnt > MII_M1011_PHY_SCR_DOWNSHIFT_MAX) 107062306a36Sopenharmony_ci return -E2BIG; 107162306a36Sopenharmony_ci 107262306a36Sopenharmony_ci if (!cnt) { 107362306a36Sopenharmony_ci err = phy_clear_bits(phydev, MII_M1011_PHY_SCR, 107462306a36Sopenharmony_ci MII_M1011_PHY_SCR_DOWNSHIFT_EN); 107562306a36Sopenharmony_ci } else { 107662306a36Sopenharmony_ci val = MII_M1011_PHY_SCR_DOWNSHIFT_EN; 107762306a36Sopenharmony_ci val |= FIELD_PREP(MII_M1011_PHY_SCR_DOWNSHIFT_MASK, cnt - 1); 107862306a36Sopenharmony_ci 107962306a36Sopenharmony_ci err = phy_modify(phydev, MII_M1011_PHY_SCR, 108062306a36Sopenharmony_ci MII_M1011_PHY_SCR_DOWNSHIFT_EN | 108162306a36Sopenharmony_ci MII_M1011_PHY_SCR_DOWNSHIFT_MASK, 108262306a36Sopenharmony_ci val); 108362306a36Sopenharmony_ci } 108462306a36Sopenharmony_ci 108562306a36Sopenharmony_ci if (err < 0) 108662306a36Sopenharmony_ci return err; 108762306a36Sopenharmony_ci 108862306a36Sopenharmony_ci return genphy_soft_reset(phydev); 108962306a36Sopenharmony_ci} 109062306a36Sopenharmony_ci 109162306a36Sopenharmony_cistatic int m88e1011_get_tunable(struct phy_device *phydev, 109262306a36Sopenharmony_ci struct ethtool_tunable *tuna, void *data) 109362306a36Sopenharmony_ci{ 109462306a36Sopenharmony_ci switch (tuna->id) { 109562306a36Sopenharmony_ci case ETHTOOL_PHY_DOWNSHIFT: 109662306a36Sopenharmony_ci return m88e1011_get_downshift(phydev, data); 109762306a36Sopenharmony_ci default: 109862306a36Sopenharmony_ci return -EOPNOTSUPP; 109962306a36Sopenharmony_ci } 110062306a36Sopenharmony_ci} 110162306a36Sopenharmony_ci 110262306a36Sopenharmony_cistatic int m88e1011_set_tunable(struct phy_device *phydev, 110362306a36Sopenharmony_ci struct ethtool_tunable *tuna, const void *data) 110462306a36Sopenharmony_ci{ 110562306a36Sopenharmony_ci switch (tuna->id) { 110662306a36Sopenharmony_ci case ETHTOOL_PHY_DOWNSHIFT: 110762306a36Sopenharmony_ci return m88e1011_set_downshift(phydev, *(const u8 *)data); 110862306a36Sopenharmony_ci default: 110962306a36Sopenharmony_ci return -EOPNOTSUPP; 111062306a36Sopenharmony_ci } 111162306a36Sopenharmony_ci} 111262306a36Sopenharmony_ci 111362306a36Sopenharmony_cistatic int m88e1112_config_init(struct phy_device *phydev) 111462306a36Sopenharmony_ci{ 111562306a36Sopenharmony_ci int err; 111662306a36Sopenharmony_ci 111762306a36Sopenharmony_ci err = m88e1011_set_downshift(phydev, 3); 111862306a36Sopenharmony_ci if (err < 0) 111962306a36Sopenharmony_ci return err; 112062306a36Sopenharmony_ci 112162306a36Sopenharmony_ci return m88e1111_config_init(phydev); 112262306a36Sopenharmony_ci} 112362306a36Sopenharmony_ci 112462306a36Sopenharmony_cistatic int m88e1111gbe_config_init(struct phy_device *phydev) 112562306a36Sopenharmony_ci{ 112662306a36Sopenharmony_ci int err; 112762306a36Sopenharmony_ci 112862306a36Sopenharmony_ci err = m88e1111_set_downshift(phydev, 3); 112962306a36Sopenharmony_ci if (err < 0) 113062306a36Sopenharmony_ci return err; 113162306a36Sopenharmony_ci 113262306a36Sopenharmony_ci return m88e1111_config_init(phydev); 113362306a36Sopenharmony_ci} 113462306a36Sopenharmony_ci 113562306a36Sopenharmony_cistatic int marvell_1011gbe_config_init(struct phy_device *phydev) 113662306a36Sopenharmony_ci{ 113762306a36Sopenharmony_ci int err; 113862306a36Sopenharmony_ci 113962306a36Sopenharmony_ci err = m88e1011_set_downshift(phydev, 3); 114062306a36Sopenharmony_ci if (err < 0) 114162306a36Sopenharmony_ci return err; 114262306a36Sopenharmony_ci 114362306a36Sopenharmony_ci return marvell_config_init(phydev); 114462306a36Sopenharmony_ci} 114562306a36Sopenharmony_cistatic int m88e1116r_config_init(struct phy_device *phydev) 114662306a36Sopenharmony_ci{ 114762306a36Sopenharmony_ci int err; 114862306a36Sopenharmony_ci 114962306a36Sopenharmony_ci err = genphy_soft_reset(phydev); 115062306a36Sopenharmony_ci if (err < 0) 115162306a36Sopenharmony_ci return err; 115262306a36Sopenharmony_ci 115362306a36Sopenharmony_ci msleep(500); 115462306a36Sopenharmony_ci 115562306a36Sopenharmony_ci err = marvell_set_page(phydev, MII_MARVELL_COPPER_PAGE); 115662306a36Sopenharmony_ci if (err < 0) 115762306a36Sopenharmony_ci return err; 115862306a36Sopenharmony_ci 115962306a36Sopenharmony_ci err = marvell_set_polarity(phydev, phydev->mdix_ctrl); 116062306a36Sopenharmony_ci if (err < 0) 116162306a36Sopenharmony_ci return err; 116262306a36Sopenharmony_ci 116362306a36Sopenharmony_ci err = m88e1011_set_downshift(phydev, 8); 116462306a36Sopenharmony_ci if (err < 0) 116562306a36Sopenharmony_ci return err; 116662306a36Sopenharmony_ci 116762306a36Sopenharmony_ci if (phy_interface_is_rgmii(phydev)) { 116862306a36Sopenharmony_ci err = m88e1121_config_aneg_rgmii_delays(phydev); 116962306a36Sopenharmony_ci if (err < 0) 117062306a36Sopenharmony_ci return err; 117162306a36Sopenharmony_ci } 117262306a36Sopenharmony_ci 117362306a36Sopenharmony_ci err = genphy_soft_reset(phydev); 117462306a36Sopenharmony_ci if (err < 0) 117562306a36Sopenharmony_ci return err; 117662306a36Sopenharmony_ci 117762306a36Sopenharmony_ci return marvell_config_init(phydev); 117862306a36Sopenharmony_ci} 117962306a36Sopenharmony_ci 118062306a36Sopenharmony_cistatic int m88e1318_config_init(struct phy_device *phydev) 118162306a36Sopenharmony_ci{ 118262306a36Sopenharmony_ci if (phy_interrupt_is_valid(phydev)) { 118362306a36Sopenharmony_ci int err = phy_modify_paged( 118462306a36Sopenharmony_ci phydev, MII_MARVELL_LED_PAGE, 118562306a36Sopenharmony_ci MII_88E1318S_PHY_LED_TCR, 118662306a36Sopenharmony_ci MII_88E1318S_PHY_LED_TCR_FORCE_INT, 118762306a36Sopenharmony_ci MII_88E1318S_PHY_LED_TCR_INTn_ENABLE | 118862306a36Sopenharmony_ci MII_88E1318S_PHY_LED_TCR_INT_ACTIVE_LOW); 118962306a36Sopenharmony_ci if (err < 0) 119062306a36Sopenharmony_ci return err; 119162306a36Sopenharmony_ci } 119262306a36Sopenharmony_ci 119362306a36Sopenharmony_ci return marvell_config_init(phydev); 119462306a36Sopenharmony_ci} 119562306a36Sopenharmony_ci 119662306a36Sopenharmony_cistatic int m88e1510_config_init(struct phy_device *phydev) 119762306a36Sopenharmony_ci{ 119862306a36Sopenharmony_ci static const struct { 119962306a36Sopenharmony_ci u16 reg17, reg16; 120062306a36Sopenharmony_ci } errata_vals[] = { 120162306a36Sopenharmony_ci { 0x214b, 0x2144 }, 120262306a36Sopenharmony_ci { 0x0c28, 0x2146 }, 120362306a36Sopenharmony_ci { 0xb233, 0x214d }, 120462306a36Sopenharmony_ci { 0xcc0c, 0x2159 }, 120562306a36Sopenharmony_ci }; 120662306a36Sopenharmony_ci int err; 120762306a36Sopenharmony_ci int i; 120862306a36Sopenharmony_ci 120962306a36Sopenharmony_ci /* As per Marvell Release Notes - Alaska 88E1510/88E1518/88E1512/ 121062306a36Sopenharmony_ci * 88E1514 Rev A0, Errata Section 5.1: 121162306a36Sopenharmony_ci * If EEE is intended to be used, the following register writes 121262306a36Sopenharmony_ci * must be done once after every hardware reset. 121362306a36Sopenharmony_ci */ 121462306a36Sopenharmony_ci err = marvell_set_page(phydev, 0x00FF); 121562306a36Sopenharmony_ci if (err < 0) 121662306a36Sopenharmony_ci return err; 121762306a36Sopenharmony_ci 121862306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(errata_vals); ++i) { 121962306a36Sopenharmony_ci err = phy_write(phydev, 17, errata_vals[i].reg17); 122062306a36Sopenharmony_ci if (err) 122162306a36Sopenharmony_ci return err; 122262306a36Sopenharmony_ci err = phy_write(phydev, 16, errata_vals[i].reg16); 122362306a36Sopenharmony_ci if (err) 122462306a36Sopenharmony_ci return err; 122562306a36Sopenharmony_ci } 122662306a36Sopenharmony_ci 122762306a36Sopenharmony_ci err = marvell_set_page(phydev, 0x00FB); 122862306a36Sopenharmony_ci if (err < 0) 122962306a36Sopenharmony_ci return err; 123062306a36Sopenharmony_ci err = phy_write(phydev, 07, 0xC00D); 123162306a36Sopenharmony_ci if (err < 0) 123262306a36Sopenharmony_ci return err; 123362306a36Sopenharmony_ci err = marvell_set_page(phydev, MII_MARVELL_COPPER_PAGE); 123462306a36Sopenharmony_ci if (err < 0) 123562306a36Sopenharmony_ci return err; 123662306a36Sopenharmony_ci 123762306a36Sopenharmony_ci /* SGMII-to-Copper mode initialization */ 123862306a36Sopenharmony_ci if (phydev->interface == PHY_INTERFACE_MODE_SGMII) { 123962306a36Sopenharmony_ci /* Select page 18 */ 124062306a36Sopenharmony_ci err = marvell_set_page(phydev, 18); 124162306a36Sopenharmony_ci if (err < 0) 124262306a36Sopenharmony_ci return err; 124362306a36Sopenharmony_ci 124462306a36Sopenharmony_ci /* In reg 20, write MODE[2:0] = 0x1 (SGMII to Copper) */ 124562306a36Sopenharmony_ci err = phy_modify(phydev, MII_88E1510_GEN_CTRL_REG_1, 124662306a36Sopenharmony_ci MII_88E1510_GEN_CTRL_REG_1_MODE_MASK, 124762306a36Sopenharmony_ci MII_88E1510_GEN_CTRL_REG_1_MODE_SGMII); 124862306a36Sopenharmony_ci if (err < 0) 124962306a36Sopenharmony_ci return err; 125062306a36Sopenharmony_ci 125162306a36Sopenharmony_ci /* PHY reset is necessary after changing MODE[2:0] */ 125262306a36Sopenharmony_ci err = phy_set_bits(phydev, MII_88E1510_GEN_CTRL_REG_1, 125362306a36Sopenharmony_ci MII_88E1510_GEN_CTRL_REG_1_RESET); 125462306a36Sopenharmony_ci if (err < 0) 125562306a36Sopenharmony_ci return err; 125662306a36Sopenharmony_ci 125762306a36Sopenharmony_ci /* Reset page selection */ 125862306a36Sopenharmony_ci err = marvell_set_page(phydev, MII_MARVELL_COPPER_PAGE); 125962306a36Sopenharmony_ci if (err < 0) 126062306a36Sopenharmony_ci return err; 126162306a36Sopenharmony_ci } 126262306a36Sopenharmony_ci err = m88e1011_set_downshift(phydev, 3); 126362306a36Sopenharmony_ci if (err < 0) 126462306a36Sopenharmony_ci return err; 126562306a36Sopenharmony_ci 126662306a36Sopenharmony_ci return m88e1318_config_init(phydev); 126762306a36Sopenharmony_ci} 126862306a36Sopenharmony_ci 126962306a36Sopenharmony_cistatic int m88e1118_config_aneg(struct phy_device *phydev) 127062306a36Sopenharmony_ci{ 127162306a36Sopenharmony_ci int err; 127262306a36Sopenharmony_ci 127362306a36Sopenharmony_ci err = marvell_set_polarity(phydev, phydev->mdix_ctrl); 127462306a36Sopenharmony_ci if (err < 0) 127562306a36Sopenharmony_ci return err; 127662306a36Sopenharmony_ci 127762306a36Sopenharmony_ci err = genphy_config_aneg(phydev); 127862306a36Sopenharmony_ci if (err < 0) 127962306a36Sopenharmony_ci return err; 128062306a36Sopenharmony_ci 128162306a36Sopenharmony_ci return genphy_soft_reset(phydev); 128262306a36Sopenharmony_ci} 128362306a36Sopenharmony_ci 128462306a36Sopenharmony_cistatic int m88e1118_config_init(struct phy_device *phydev) 128562306a36Sopenharmony_ci{ 128662306a36Sopenharmony_ci u16 leds; 128762306a36Sopenharmony_ci int err; 128862306a36Sopenharmony_ci 128962306a36Sopenharmony_ci /* Enable 1000 Mbit */ 129062306a36Sopenharmony_ci err = phy_write_paged(phydev, MII_MARVELL_MSCR_PAGE, 129162306a36Sopenharmony_ci MII_88E1121_PHY_MSCR_REG, 0x1070); 129262306a36Sopenharmony_ci if (err < 0) 129362306a36Sopenharmony_ci return err; 129462306a36Sopenharmony_ci 129562306a36Sopenharmony_ci if (phy_interface_is_rgmii(phydev)) { 129662306a36Sopenharmony_ci err = m88e1121_config_aneg_rgmii_delays(phydev); 129762306a36Sopenharmony_ci if (err < 0) 129862306a36Sopenharmony_ci return err; 129962306a36Sopenharmony_ci } 130062306a36Sopenharmony_ci 130162306a36Sopenharmony_ci /* Adjust LED Control */ 130262306a36Sopenharmony_ci if (phydev->dev_flags & MARVELL_PHY_M1118_DNS323_LEDS) 130362306a36Sopenharmony_ci leds = 0x1100; 130462306a36Sopenharmony_ci else 130562306a36Sopenharmony_ci leds = 0x021e; 130662306a36Sopenharmony_ci 130762306a36Sopenharmony_ci err = phy_write_paged(phydev, MII_MARVELL_LED_PAGE, 0x10, leds); 130862306a36Sopenharmony_ci if (err < 0) 130962306a36Sopenharmony_ci return err; 131062306a36Sopenharmony_ci 131162306a36Sopenharmony_ci err = marvell_of_reg_init(phydev); 131262306a36Sopenharmony_ci if (err < 0) 131362306a36Sopenharmony_ci return err; 131462306a36Sopenharmony_ci 131562306a36Sopenharmony_ci /* Reset page register */ 131662306a36Sopenharmony_ci err = marvell_set_page(phydev, MII_MARVELL_COPPER_PAGE); 131762306a36Sopenharmony_ci if (err < 0) 131862306a36Sopenharmony_ci return err; 131962306a36Sopenharmony_ci 132062306a36Sopenharmony_ci return genphy_soft_reset(phydev); 132162306a36Sopenharmony_ci} 132262306a36Sopenharmony_ci 132362306a36Sopenharmony_cistatic int m88e1149_config_init(struct phy_device *phydev) 132462306a36Sopenharmony_ci{ 132562306a36Sopenharmony_ci int err; 132662306a36Sopenharmony_ci 132762306a36Sopenharmony_ci /* Change address */ 132862306a36Sopenharmony_ci err = marvell_set_page(phydev, MII_MARVELL_MSCR_PAGE); 132962306a36Sopenharmony_ci if (err < 0) 133062306a36Sopenharmony_ci return err; 133162306a36Sopenharmony_ci 133262306a36Sopenharmony_ci /* Enable 1000 Mbit */ 133362306a36Sopenharmony_ci err = phy_write(phydev, 0x15, 0x1048); 133462306a36Sopenharmony_ci if (err < 0) 133562306a36Sopenharmony_ci return err; 133662306a36Sopenharmony_ci 133762306a36Sopenharmony_ci err = marvell_of_reg_init(phydev); 133862306a36Sopenharmony_ci if (err < 0) 133962306a36Sopenharmony_ci return err; 134062306a36Sopenharmony_ci 134162306a36Sopenharmony_ci /* Reset address */ 134262306a36Sopenharmony_ci err = marvell_set_page(phydev, MII_MARVELL_COPPER_PAGE); 134362306a36Sopenharmony_ci if (err < 0) 134462306a36Sopenharmony_ci return err; 134562306a36Sopenharmony_ci 134662306a36Sopenharmony_ci return genphy_soft_reset(phydev); 134762306a36Sopenharmony_ci} 134862306a36Sopenharmony_ci 134962306a36Sopenharmony_cistatic int m88e1145_config_init_rgmii(struct phy_device *phydev) 135062306a36Sopenharmony_ci{ 135162306a36Sopenharmony_ci int err; 135262306a36Sopenharmony_ci 135362306a36Sopenharmony_ci err = m88e1111_config_init_rgmii_delays(phydev); 135462306a36Sopenharmony_ci if (err < 0) 135562306a36Sopenharmony_ci return err; 135662306a36Sopenharmony_ci 135762306a36Sopenharmony_ci if (phydev->dev_flags & MARVELL_PHY_M1145_FLAGS_RESISTANCE) { 135862306a36Sopenharmony_ci err = phy_write(phydev, 0x1d, 0x0012); 135962306a36Sopenharmony_ci if (err < 0) 136062306a36Sopenharmony_ci return err; 136162306a36Sopenharmony_ci 136262306a36Sopenharmony_ci err = phy_modify(phydev, 0x1e, 0x0fc0, 136362306a36Sopenharmony_ci 2 << 9 | /* 36 ohm */ 136462306a36Sopenharmony_ci 2 << 6); /* 39 ohm */ 136562306a36Sopenharmony_ci if (err < 0) 136662306a36Sopenharmony_ci return err; 136762306a36Sopenharmony_ci 136862306a36Sopenharmony_ci err = phy_write(phydev, 0x1d, 0x3); 136962306a36Sopenharmony_ci if (err < 0) 137062306a36Sopenharmony_ci return err; 137162306a36Sopenharmony_ci 137262306a36Sopenharmony_ci err = phy_write(phydev, 0x1e, 0x8000); 137362306a36Sopenharmony_ci } 137462306a36Sopenharmony_ci return err; 137562306a36Sopenharmony_ci} 137662306a36Sopenharmony_ci 137762306a36Sopenharmony_cistatic int m88e1145_config_init_sgmii(struct phy_device *phydev) 137862306a36Sopenharmony_ci{ 137962306a36Sopenharmony_ci return m88e1111_config_init_hwcfg_mode( 138062306a36Sopenharmony_ci phydev, MII_M1111_HWCFG_MODE_SGMII_NO_CLK, 138162306a36Sopenharmony_ci MII_M1111_HWCFG_FIBER_COPPER_AUTO); 138262306a36Sopenharmony_ci} 138362306a36Sopenharmony_ci 138462306a36Sopenharmony_cistatic int m88e1145_config_init(struct phy_device *phydev) 138562306a36Sopenharmony_ci{ 138662306a36Sopenharmony_ci int err; 138762306a36Sopenharmony_ci 138862306a36Sopenharmony_ci /* Take care of errata E0 & E1 */ 138962306a36Sopenharmony_ci err = phy_write(phydev, 0x1d, 0x001b); 139062306a36Sopenharmony_ci if (err < 0) 139162306a36Sopenharmony_ci return err; 139262306a36Sopenharmony_ci 139362306a36Sopenharmony_ci err = phy_write(phydev, 0x1e, 0x418f); 139462306a36Sopenharmony_ci if (err < 0) 139562306a36Sopenharmony_ci return err; 139662306a36Sopenharmony_ci 139762306a36Sopenharmony_ci err = phy_write(phydev, 0x1d, 0x0016); 139862306a36Sopenharmony_ci if (err < 0) 139962306a36Sopenharmony_ci return err; 140062306a36Sopenharmony_ci 140162306a36Sopenharmony_ci err = phy_write(phydev, 0x1e, 0xa2da); 140262306a36Sopenharmony_ci if (err < 0) 140362306a36Sopenharmony_ci return err; 140462306a36Sopenharmony_ci 140562306a36Sopenharmony_ci if (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID) { 140662306a36Sopenharmony_ci err = m88e1145_config_init_rgmii(phydev); 140762306a36Sopenharmony_ci if (err < 0) 140862306a36Sopenharmony_ci return err; 140962306a36Sopenharmony_ci } 141062306a36Sopenharmony_ci 141162306a36Sopenharmony_ci if (phydev->interface == PHY_INTERFACE_MODE_SGMII) { 141262306a36Sopenharmony_ci err = m88e1145_config_init_sgmii(phydev); 141362306a36Sopenharmony_ci if (err < 0) 141462306a36Sopenharmony_ci return err; 141562306a36Sopenharmony_ci } 141662306a36Sopenharmony_ci err = m88e1111_set_downshift(phydev, 3); 141762306a36Sopenharmony_ci if (err < 0) 141862306a36Sopenharmony_ci return err; 141962306a36Sopenharmony_ci 142062306a36Sopenharmony_ci err = marvell_of_reg_init(phydev); 142162306a36Sopenharmony_ci if (err < 0) 142262306a36Sopenharmony_ci return err; 142362306a36Sopenharmony_ci 142462306a36Sopenharmony_ci return 0; 142562306a36Sopenharmony_ci} 142662306a36Sopenharmony_ci 142762306a36Sopenharmony_cistatic int m88e1540_get_fld(struct phy_device *phydev, u8 *msecs) 142862306a36Sopenharmony_ci{ 142962306a36Sopenharmony_ci int val; 143062306a36Sopenharmony_ci 143162306a36Sopenharmony_ci val = phy_read(phydev, MII_88E1540_COPPER_CTRL3); 143262306a36Sopenharmony_ci if (val < 0) 143362306a36Sopenharmony_ci return val; 143462306a36Sopenharmony_ci 143562306a36Sopenharmony_ci if (!(val & MII_88E1540_COPPER_CTRL3_FAST_LINK_DOWN)) { 143662306a36Sopenharmony_ci *msecs = ETHTOOL_PHY_FAST_LINK_DOWN_OFF; 143762306a36Sopenharmony_ci return 0; 143862306a36Sopenharmony_ci } 143962306a36Sopenharmony_ci 144062306a36Sopenharmony_ci val = FIELD_GET(MII_88E1540_COPPER_CTRL3_LINK_DOWN_DELAY_MASK, val); 144162306a36Sopenharmony_ci 144262306a36Sopenharmony_ci switch (val) { 144362306a36Sopenharmony_ci case MII_88E1540_COPPER_CTRL3_LINK_DOWN_DELAY_00MS: 144462306a36Sopenharmony_ci *msecs = 0; 144562306a36Sopenharmony_ci break; 144662306a36Sopenharmony_ci case MII_88E1540_COPPER_CTRL3_LINK_DOWN_DELAY_10MS: 144762306a36Sopenharmony_ci *msecs = 10; 144862306a36Sopenharmony_ci break; 144962306a36Sopenharmony_ci case MII_88E1540_COPPER_CTRL3_LINK_DOWN_DELAY_20MS: 145062306a36Sopenharmony_ci *msecs = 20; 145162306a36Sopenharmony_ci break; 145262306a36Sopenharmony_ci case MII_88E1540_COPPER_CTRL3_LINK_DOWN_DELAY_40MS: 145362306a36Sopenharmony_ci *msecs = 40; 145462306a36Sopenharmony_ci break; 145562306a36Sopenharmony_ci default: 145662306a36Sopenharmony_ci return -EINVAL; 145762306a36Sopenharmony_ci } 145862306a36Sopenharmony_ci 145962306a36Sopenharmony_ci return 0; 146062306a36Sopenharmony_ci} 146162306a36Sopenharmony_ci 146262306a36Sopenharmony_cistatic int m88e1540_set_fld(struct phy_device *phydev, const u8 *msecs) 146362306a36Sopenharmony_ci{ 146462306a36Sopenharmony_ci struct ethtool_eee eee; 146562306a36Sopenharmony_ci int val, ret; 146662306a36Sopenharmony_ci 146762306a36Sopenharmony_ci if (*msecs == ETHTOOL_PHY_FAST_LINK_DOWN_OFF) 146862306a36Sopenharmony_ci return phy_clear_bits(phydev, MII_88E1540_COPPER_CTRL3, 146962306a36Sopenharmony_ci MII_88E1540_COPPER_CTRL3_FAST_LINK_DOWN); 147062306a36Sopenharmony_ci 147162306a36Sopenharmony_ci /* According to the Marvell data sheet EEE must be disabled for 147262306a36Sopenharmony_ci * Fast Link Down detection to work properly 147362306a36Sopenharmony_ci */ 147462306a36Sopenharmony_ci ret = genphy_c45_ethtool_get_eee(phydev, &eee); 147562306a36Sopenharmony_ci if (!ret && eee.eee_enabled) { 147662306a36Sopenharmony_ci phydev_warn(phydev, "Fast Link Down detection requires EEE to be disabled!\n"); 147762306a36Sopenharmony_ci return -EBUSY; 147862306a36Sopenharmony_ci } 147962306a36Sopenharmony_ci 148062306a36Sopenharmony_ci if (*msecs <= 5) 148162306a36Sopenharmony_ci val = MII_88E1540_COPPER_CTRL3_LINK_DOWN_DELAY_00MS; 148262306a36Sopenharmony_ci else if (*msecs <= 15) 148362306a36Sopenharmony_ci val = MII_88E1540_COPPER_CTRL3_LINK_DOWN_DELAY_10MS; 148462306a36Sopenharmony_ci else if (*msecs <= 30) 148562306a36Sopenharmony_ci val = MII_88E1540_COPPER_CTRL3_LINK_DOWN_DELAY_20MS; 148662306a36Sopenharmony_ci else 148762306a36Sopenharmony_ci val = MII_88E1540_COPPER_CTRL3_LINK_DOWN_DELAY_40MS; 148862306a36Sopenharmony_ci 148962306a36Sopenharmony_ci val = FIELD_PREP(MII_88E1540_COPPER_CTRL3_LINK_DOWN_DELAY_MASK, val); 149062306a36Sopenharmony_ci 149162306a36Sopenharmony_ci ret = phy_modify(phydev, MII_88E1540_COPPER_CTRL3, 149262306a36Sopenharmony_ci MII_88E1540_COPPER_CTRL3_LINK_DOWN_DELAY_MASK, val); 149362306a36Sopenharmony_ci if (ret) 149462306a36Sopenharmony_ci return ret; 149562306a36Sopenharmony_ci 149662306a36Sopenharmony_ci return phy_set_bits(phydev, MII_88E1540_COPPER_CTRL3, 149762306a36Sopenharmony_ci MII_88E1540_COPPER_CTRL3_FAST_LINK_DOWN); 149862306a36Sopenharmony_ci} 149962306a36Sopenharmony_ci 150062306a36Sopenharmony_cistatic int m88e1540_get_tunable(struct phy_device *phydev, 150162306a36Sopenharmony_ci struct ethtool_tunable *tuna, void *data) 150262306a36Sopenharmony_ci{ 150362306a36Sopenharmony_ci switch (tuna->id) { 150462306a36Sopenharmony_ci case ETHTOOL_PHY_FAST_LINK_DOWN: 150562306a36Sopenharmony_ci return m88e1540_get_fld(phydev, data); 150662306a36Sopenharmony_ci case ETHTOOL_PHY_DOWNSHIFT: 150762306a36Sopenharmony_ci return m88e1011_get_downshift(phydev, data); 150862306a36Sopenharmony_ci default: 150962306a36Sopenharmony_ci return -EOPNOTSUPP; 151062306a36Sopenharmony_ci } 151162306a36Sopenharmony_ci} 151262306a36Sopenharmony_ci 151362306a36Sopenharmony_cistatic int m88e1540_set_tunable(struct phy_device *phydev, 151462306a36Sopenharmony_ci struct ethtool_tunable *tuna, const void *data) 151562306a36Sopenharmony_ci{ 151662306a36Sopenharmony_ci switch (tuna->id) { 151762306a36Sopenharmony_ci case ETHTOOL_PHY_FAST_LINK_DOWN: 151862306a36Sopenharmony_ci return m88e1540_set_fld(phydev, data); 151962306a36Sopenharmony_ci case ETHTOOL_PHY_DOWNSHIFT: 152062306a36Sopenharmony_ci return m88e1011_set_downshift(phydev, *(const u8 *)data); 152162306a36Sopenharmony_ci default: 152262306a36Sopenharmony_ci return -EOPNOTSUPP; 152362306a36Sopenharmony_ci } 152462306a36Sopenharmony_ci} 152562306a36Sopenharmony_ci 152662306a36Sopenharmony_ci/* The VOD can be out of specification on link up. Poke an 152762306a36Sopenharmony_ci * undocumented register, in an undocumented page, with a magic value 152862306a36Sopenharmony_ci * to fix this. 152962306a36Sopenharmony_ci */ 153062306a36Sopenharmony_cistatic int m88e6390_errata(struct phy_device *phydev) 153162306a36Sopenharmony_ci{ 153262306a36Sopenharmony_ci int err; 153362306a36Sopenharmony_ci 153462306a36Sopenharmony_ci err = phy_write(phydev, MII_BMCR, 153562306a36Sopenharmony_ci BMCR_ANENABLE | BMCR_SPEED1000 | BMCR_FULLDPLX); 153662306a36Sopenharmony_ci if (err) 153762306a36Sopenharmony_ci return err; 153862306a36Sopenharmony_ci 153962306a36Sopenharmony_ci usleep_range(300, 400); 154062306a36Sopenharmony_ci 154162306a36Sopenharmony_ci err = phy_write_paged(phydev, 0xf8, 0x08, 0x36); 154262306a36Sopenharmony_ci if (err) 154362306a36Sopenharmony_ci return err; 154462306a36Sopenharmony_ci 154562306a36Sopenharmony_ci return genphy_soft_reset(phydev); 154662306a36Sopenharmony_ci} 154762306a36Sopenharmony_ci 154862306a36Sopenharmony_cistatic int m88e6390_config_aneg(struct phy_device *phydev) 154962306a36Sopenharmony_ci{ 155062306a36Sopenharmony_ci int err; 155162306a36Sopenharmony_ci 155262306a36Sopenharmony_ci err = m88e6390_errata(phydev); 155362306a36Sopenharmony_ci if (err) 155462306a36Sopenharmony_ci return err; 155562306a36Sopenharmony_ci 155662306a36Sopenharmony_ci return m88e1510_config_aneg(phydev); 155762306a36Sopenharmony_ci} 155862306a36Sopenharmony_ci 155962306a36Sopenharmony_ci/** 156062306a36Sopenharmony_ci * fiber_lpa_mod_linkmode_lpa_t 156162306a36Sopenharmony_ci * @advertising: the linkmode advertisement settings 156262306a36Sopenharmony_ci * @lpa: value of the MII_LPA register for fiber link 156362306a36Sopenharmony_ci * 156462306a36Sopenharmony_ci * A small helper function that translates MII_LPA bits to linkmode LP 156562306a36Sopenharmony_ci * advertisement settings. Other bits in advertising are left 156662306a36Sopenharmony_ci * unchanged. 156762306a36Sopenharmony_ci */ 156862306a36Sopenharmony_cistatic void fiber_lpa_mod_linkmode_lpa_t(unsigned long *advertising, u32 lpa) 156962306a36Sopenharmony_ci{ 157062306a36Sopenharmony_ci linkmode_mod_bit(ETHTOOL_LINK_MODE_1000baseT_Half_BIT, 157162306a36Sopenharmony_ci advertising, lpa & LPA_1000XHALF); 157262306a36Sopenharmony_ci 157362306a36Sopenharmony_ci linkmode_mod_bit(ETHTOOL_LINK_MODE_1000baseT_Full_BIT, 157462306a36Sopenharmony_ci advertising, lpa & LPA_1000XFULL); 157562306a36Sopenharmony_ci} 157662306a36Sopenharmony_ci 157762306a36Sopenharmony_cistatic int marvell_read_status_page_an(struct phy_device *phydev, 157862306a36Sopenharmony_ci int fiber, int status) 157962306a36Sopenharmony_ci{ 158062306a36Sopenharmony_ci int lpa; 158162306a36Sopenharmony_ci int err; 158262306a36Sopenharmony_ci 158362306a36Sopenharmony_ci if (!(status & MII_M1011_PHY_STATUS_RESOLVED)) { 158462306a36Sopenharmony_ci phydev->link = 0; 158562306a36Sopenharmony_ci return 0; 158662306a36Sopenharmony_ci } 158762306a36Sopenharmony_ci 158862306a36Sopenharmony_ci if (status & MII_M1011_PHY_STATUS_FULLDUPLEX) 158962306a36Sopenharmony_ci phydev->duplex = DUPLEX_FULL; 159062306a36Sopenharmony_ci else 159162306a36Sopenharmony_ci phydev->duplex = DUPLEX_HALF; 159262306a36Sopenharmony_ci 159362306a36Sopenharmony_ci switch (status & MII_M1011_PHY_STATUS_SPD_MASK) { 159462306a36Sopenharmony_ci case MII_M1011_PHY_STATUS_1000: 159562306a36Sopenharmony_ci phydev->speed = SPEED_1000; 159662306a36Sopenharmony_ci break; 159762306a36Sopenharmony_ci 159862306a36Sopenharmony_ci case MII_M1011_PHY_STATUS_100: 159962306a36Sopenharmony_ci phydev->speed = SPEED_100; 160062306a36Sopenharmony_ci break; 160162306a36Sopenharmony_ci 160262306a36Sopenharmony_ci default: 160362306a36Sopenharmony_ci phydev->speed = SPEED_10; 160462306a36Sopenharmony_ci break; 160562306a36Sopenharmony_ci } 160662306a36Sopenharmony_ci 160762306a36Sopenharmony_ci if (!fiber) { 160862306a36Sopenharmony_ci err = genphy_read_lpa(phydev); 160962306a36Sopenharmony_ci if (err < 0) 161062306a36Sopenharmony_ci return err; 161162306a36Sopenharmony_ci 161262306a36Sopenharmony_ci phy_resolve_aneg_pause(phydev); 161362306a36Sopenharmony_ci } else { 161462306a36Sopenharmony_ci lpa = phy_read(phydev, MII_LPA); 161562306a36Sopenharmony_ci if (lpa < 0) 161662306a36Sopenharmony_ci return lpa; 161762306a36Sopenharmony_ci 161862306a36Sopenharmony_ci /* The fiber link is only 1000M capable */ 161962306a36Sopenharmony_ci fiber_lpa_mod_linkmode_lpa_t(phydev->lp_advertising, lpa); 162062306a36Sopenharmony_ci 162162306a36Sopenharmony_ci if (phydev->duplex == DUPLEX_FULL) { 162262306a36Sopenharmony_ci if (!(lpa & LPA_PAUSE_FIBER)) { 162362306a36Sopenharmony_ci phydev->pause = 0; 162462306a36Sopenharmony_ci phydev->asym_pause = 0; 162562306a36Sopenharmony_ci } else if ((lpa & LPA_PAUSE_ASYM_FIBER)) { 162662306a36Sopenharmony_ci phydev->pause = 1; 162762306a36Sopenharmony_ci phydev->asym_pause = 1; 162862306a36Sopenharmony_ci } else { 162962306a36Sopenharmony_ci phydev->pause = 1; 163062306a36Sopenharmony_ci phydev->asym_pause = 0; 163162306a36Sopenharmony_ci } 163262306a36Sopenharmony_ci } 163362306a36Sopenharmony_ci } 163462306a36Sopenharmony_ci 163562306a36Sopenharmony_ci return 0; 163662306a36Sopenharmony_ci} 163762306a36Sopenharmony_ci 163862306a36Sopenharmony_ci/* marvell_read_status_page 163962306a36Sopenharmony_ci * 164062306a36Sopenharmony_ci * Description: 164162306a36Sopenharmony_ci * Check the link, then figure out the current state 164262306a36Sopenharmony_ci * by comparing what we advertise with what the link partner 164362306a36Sopenharmony_ci * advertises. Start by checking the gigabit possibilities, 164462306a36Sopenharmony_ci * then move on to 10/100. 164562306a36Sopenharmony_ci */ 164662306a36Sopenharmony_cistatic int marvell_read_status_page(struct phy_device *phydev, int page) 164762306a36Sopenharmony_ci{ 164862306a36Sopenharmony_ci int status; 164962306a36Sopenharmony_ci int fiber; 165062306a36Sopenharmony_ci int err; 165162306a36Sopenharmony_ci 165262306a36Sopenharmony_ci status = phy_read(phydev, MII_M1011_PHY_STATUS); 165362306a36Sopenharmony_ci if (status < 0) 165462306a36Sopenharmony_ci return status; 165562306a36Sopenharmony_ci 165662306a36Sopenharmony_ci /* Use the generic register for copper link status, 165762306a36Sopenharmony_ci * and the PHY status register for fiber link status. 165862306a36Sopenharmony_ci */ 165962306a36Sopenharmony_ci if (page == MII_MARVELL_FIBER_PAGE) { 166062306a36Sopenharmony_ci phydev->link = !!(status & MII_M1011_PHY_STATUS_LINK); 166162306a36Sopenharmony_ci } else { 166262306a36Sopenharmony_ci err = genphy_update_link(phydev); 166362306a36Sopenharmony_ci if (err) 166462306a36Sopenharmony_ci return err; 166562306a36Sopenharmony_ci } 166662306a36Sopenharmony_ci 166762306a36Sopenharmony_ci if (page == MII_MARVELL_FIBER_PAGE) 166862306a36Sopenharmony_ci fiber = 1; 166962306a36Sopenharmony_ci else 167062306a36Sopenharmony_ci fiber = 0; 167162306a36Sopenharmony_ci 167262306a36Sopenharmony_ci linkmode_zero(phydev->lp_advertising); 167362306a36Sopenharmony_ci phydev->pause = 0; 167462306a36Sopenharmony_ci phydev->asym_pause = 0; 167562306a36Sopenharmony_ci phydev->speed = SPEED_UNKNOWN; 167662306a36Sopenharmony_ci phydev->duplex = DUPLEX_UNKNOWN; 167762306a36Sopenharmony_ci phydev->port = fiber ? PORT_FIBRE : PORT_TP; 167862306a36Sopenharmony_ci 167962306a36Sopenharmony_ci if (phydev->autoneg == AUTONEG_ENABLE) 168062306a36Sopenharmony_ci err = marvell_read_status_page_an(phydev, fiber, status); 168162306a36Sopenharmony_ci else 168262306a36Sopenharmony_ci err = genphy_read_status_fixed(phydev); 168362306a36Sopenharmony_ci 168462306a36Sopenharmony_ci return err; 168562306a36Sopenharmony_ci} 168662306a36Sopenharmony_ci 168762306a36Sopenharmony_ci/* marvell_read_status 168862306a36Sopenharmony_ci * 168962306a36Sopenharmony_ci * Some Marvell's phys have two modes: fiber and copper. 169062306a36Sopenharmony_ci * Both need status checked. 169162306a36Sopenharmony_ci * Description: 169262306a36Sopenharmony_ci * First, check the fiber link and status. 169362306a36Sopenharmony_ci * If the fiber link is down, check the copper link and status which 169462306a36Sopenharmony_ci * will be the default value if both link are down. 169562306a36Sopenharmony_ci */ 169662306a36Sopenharmony_cistatic int marvell_read_status(struct phy_device *phydev) 169762306a36Sopenharmony_ci{ 169862306a36Sopenharmony_ci int err; 169962306a36Sopenharmony_ci 170062306a36Sopenharmony_ci /* Check the fiber mode first */ 170162306a36Sopenharmony_ci if (linkmode_test_bit(ETHTOOL_LINK_MODE_FIBRE_BIT, 170262306a36Sopenharmony_ci phydev->supported) && 170362306a36Sopenharmony_ci phydev->interface != PHY_INTERFACE_MODE_SGMII) { 170462306a36Sopenharmony_ci err = marvell_set_page(phydev, MII_MARVELL_FIBER_PAGE); 170562306a36Sopenharmony_ci if (err < 0) 170662306a36Sopenharmony_ci goto error; 170762306a36Sopenharmony_ci 170862306a36Sopenharmony_ci err = marvell_read_status_page(phydev, MII_MARVELL_FIBER_PAGE); 170962306a36Sopenharmony_ci if (err < 0) 171062306a36Sopenharmony_ci goto error; 171162306a36Sopenharmony_ci 171262306a36Sopenharmony_ci /* If the fiber link is up, it is the selected and 171362306a36Sopenharmony_ci * used link. In this case, we need to stay in the 171462306a36Sopenharmony_ci * fiber page. Please to be careful about that, avoid 171562306a36Sopenharmony_ci * to restore Copper page in other functions which 171662306a36Sopenharmony_ci * could break the behaviour for some fiber phy like 171762306a36Sopenharmony_ci * 88E1512. 171862306a36Sopenharmony_ci */ 171962306a36Sopenharmony_ci if (phydev->link) 172062306a36Sopenharmony_ci return 0; 172162306a36Sopenharmony_ci 172262306a36Sopenharmony_ci /* If fiber link is down, check and save copper mode state */ 172362306a36Sopenharmony_ci err = marvell_set_page(phydev, MII_MARVELL_COPPER_PAGE); 172462306a36Sopenharmony_ci if (err < 0) 172562306a36Sopenharmony_ci goto error; 172662306a36Sopenharmony_ci } 172762306a36Sopenharmony_ci 172862306a36Sopenharmony_ci return marvell_read_status_page(phydev, MII_MARVELL_COPPER_PAGE); 172962306a36Sopenharmony_ci 173062306a36Sopenharmony_cierror: 173162306a36Sopenharmony_ci marvell_set_page(phydev, MII_MARVELL_COPPER_PAGE); 173262306a36Sopenharmony_ci return err; 173362306a36Sopenharmony_ci} 173462306a36Sopenharmony_ci 173562306a36Sopenharmony_ci/* marvell_suspend 173662306a36Sopenharmony_ci * 173762306a36Sopenharmony_ci * Some Marvell's phys have two modes: fiber and copper. 173862306a36Sopenharmony_ci * Both need to be suspended 173962306a36Sopenharmony_ci */ 174062306a36Sopenharmony_cistatic int marvell_suspend(struct phy_device *phydev) 174162306a36Sopenharmony_ci{ 174262306a36Sopenharmony_ci int err; 174362306a36Sopenharmony_ci 174462306a36Sopenharmony_ci /* Suspend the fiber mode first */ 174562306a36Sopenharmony_ci if (linkmode_test_bit(ETHTOOL_LINK_MODE_FIBRE_BIT, 174662306a36Sopenharmony_ci phydev->supported)) { 174762306a36Sopenharmony_ci err = marvell_set_page(phydev, MII_MARVELL_FIBER_PAGE); 174862306a36Sopenharmony_ci if (err < 0) 174962306a36Sopenharmony_ci goto error; 175062306a36Sopenharmony_ci 175162306a36Sopenharmony_ci /* With the page set, use the generic suspend */ 175262306a36Sopenharmony_ci err = genphy_suspend(phydev); 175362306a36Sopenharmony_ci if (err < 0) 175462306a36Sopenharmony_ci goto error; 175562306a36Sopenharmony_ci 175662306a36Sopenharmony_ci /* Then, the copper link */ 175762306a36Sopenharmony_ci err = marvell_set_page(phydev, MII_MARVELL_COPPER_PAGE); 175862306a36Sopenharmony_ci if (err < 0) 175962306a36Sopenharmony_ci goto error; 176062306a36Sopenharmony_ci } 176162306a36Sopenharmony_ci 176262306a36Sopenharmony_ci /* With the page set, use the generic suspend */ 176362306a36Sopenharmony_ci return genphy_suspend(phydev); 176462306a36Sopenharmony_ci 176562306a36Sopenharmony_cierror: 176662306a36Sopenharmony_ci marvell_set_page(phydev, MII_MARVELL_COPPER_PAGE); 176762306a36Sopenharmony_ci return err; 176862306a36Sopenharmony_ci} 176962306a36Sopenharmony_ci 177062306a36Sopenharmony_ci/* marvell_resume 177162306a36Sopenharmony_ci * 177262306a36Sopenharmony_ci * Some Marvell's phys have two modes: fiber and copper. 177362306a36Sopenharmony_ci * Both need to be resumed 177462306a36Sopenharmony_ci */ 177562306a36Sopenharmony_cistatic int marvell_resume(struct phy_device *phydev) 177662306a36Sopenharmony_ci{ 177762306a36Sopenharmony_ci int err; 177862306a36Sopenharmony_ci 177962306a36Sopenharmony_ci /* Resume the fiber mode first */ 178062306a36Sopenharmony_ci if (linkmode_test_bit(ETHTOOL_LINK_MODE_FIBRE_BIT, 178162306a36Sopenharmony_ci phydev->supported)) { 178262306a36Sopenharmony_ci err = marvell_set_page(phydev, MII_MARVELL_FIBER_PAGE); 178362306a36Sopenharmony_ci if (err < 0) 178462306a36Sopenharmony_ci goto error; 178562306a36Sopenharmony_ci 178662306a36Sopenharmony_ci /* With the page set, use the generic resume */ 178762306a36Sopenharmony_ci err = genphy_resume(phydev); 178862306a36Sopenharmony_ci if (err < 0) 178962306a36Sopenharmony_ci goto error; 179062306a36Sopenharmony_ci 179162306a36Sopenharmony_ci /* Then, the copper link */ 179262306a36Sopenharmony_ci err = marvell_set_page(phydev, MII_MARVELL_COPPER_PAGE); 179362306a36Sopenharmony_ci if (err < 0) 179462306a36Sopenharmony_ci goto error; 179562306a36Sopenharmony_ci } 179662306a36Sopenharmony_ci 179762306a36Sopenharmony_ci /* With the page set, use the generic resume */ 179862306a36Sopenharmony_ci return genphy_resume(phydev); 179962306a36Sopenharmony_ci 180062306a36Sopenharmony_cierror: 180162306a36Sopenharmony_ci marvell_set_page(phydev, MII_MARVELL_COPPER_PAGE); 180262306a36Sopenharmony_ci return err; 180362306a36Sopenharmony_ci} 180462306a36Sopenharmony_ci 180562306a36Sopenharmony_cistatic int marvell_aneg_done(struct phy_device *phydev) 180662306a36Sopenharmony_ci{ 180762306a36Sopenharmony_ci int retval = phy_read(phydev, MII_M1011_PHY_STATUS); 180862306a36Sopenharmony_ci 180962306a36Sopenharmony_ci return (retval < 0) ? retval : (retval & MII_M1011_PHY_STATUS_RESOLVED); 181062306a36Sopenharmony_ci} 181162306a36Sopenharmony_ci 181262306a36Sopenharmony_cistatic void m88e1318_get_wol(struct phy_device *phydev, 181362306a36Sopenharmony_ci struct ethtool_wolinfo *wol) 181462306a36Sopenharmony_ci{ 181562306a36Sopenharmony_ci int ret; 181662306a36Sopenharmony_ci 181762306a36Sopenharmony_ci wol->supported = WAKE_MAGIC | WAKE_PHY; 181862306a36Sopenharmony_ci wol->wolopts = 0; 181962306a36Sopenharmony_ci 182062306a36Sopenharmony_ci ret = phy_read_paged(phydev, MII_MARVELL_WOL_PAGE, 182162306a36Sopenharmony_ci MII_88E1318S_PHY_WOL_CTRL); 182262306a36Sopenharmony_ci if (ret < 0) 182362306a36Sopenharmony_ci return; 182462306a36Sopenharmony_ci 182562306a36Sopenharmony_ci if (ret & MII_88E1318S_PHY_WOL_CTRL_MAGIC_PACKET_MATCH_ENABLE) 182662306a36Sopenharmony_ci wol->wolopts |= WAKE_MAGIC; 182762306a36Sopenharmony_ci 182862306a36Sopenharmony_ci if (ret & MII_88E1318S_PHY_WOL_CTRL_LINK_UP_ENABLE) 182962306a36Sopenharmony_ci wol->wolopts |= WAKE_PHY; 183062306a36Sopenharmony_ci} 183162306a36Sopenharmony_ci 183262306a36Sopenharmony_cistatic int m88e1318_set_wol(struct phy_device *phydev, 183362306a36Sopenharmony_ci struct ethtool_wolinfo *wol) 183462306a36Sopenharmony_ci{ 183562306a36Sopenharmony_ci int err = 0, oldpage; 183662306a36Sopenharmony_ci 183762306a36Sopenharmony_ci oldpage = phy_save_page(phydev); 183862306a36Sopenharmony_ci if (oldpage < 0) 183962306a36Sopenharmony_ci goto error; 184062306a36Sopenharmony_ci 184162306a36Sopenharmony_ci if (wol->wolopts & (WAKE_MAGIC | WAKE_PHY)) { 184262306a36Sopenharmony_ci /* Explicitly switch to page 0x00, just to be sure */ 184362306a36Sopenharmony_ci err = marvell_write_page(phydev, MII_MARVELL_COPPER_PAGE); 184462306a36Sopenharmony_ci if (err < 0) 184562306a36Sopenharmony_ci goto error; 184662306a36Sopenharmony_ci 184762306a36Sopenharmony_ci /* If WOL event happened once, the LED[2] interrupt pin 184862306a36Sopenharmony_ci * will not be cleared unless we reading the interrupt status 184962306a36Sopenharmony_ci * register. If interrupts are in use, the normal interrupt 185062306a36Sopenharmony_ci * handling will clear the WOL event. Clear the WOL event 185162306a36Sopenharmony_ci * before enabling it if !phy_interrupt_is_valid() 185262306a36Sopenharmony_ci */ 185362306a36Sopenharmony_ci if (!phy_interrupt_is_valid(phydev)) 185462306a36Sopenharmony_ci __phy_read(phydev, MII_M1011_IEVENT); 185562306a36Sopenharmony_ci 185662306a36Sopenharmony_ci /* Enable the WOL interrupt */ 185762306a36Sopenharmony_ci err = __phy_set_bits(phydev, MII_88E1318S_PHY_CSIER, 185862306a36Sopenharmony_ci MII_88E1318S_PHY_CSIER_WOL_EIE); 185962306a36Sopenharmony_ci if (err < 0) 186062306a36Sopenharmony_ci goto error; 186162306a36Sopenharmony_ci 186262306a36Sopenharmony_ci err = marvell_write_page(phydev, MII_MARVELL_LED_PAGE); 186362306a36Sopenharmony_ci if (err < 0) 186462306a36Sopenharmony_ci goto error; 186562306a36Sopenharmony_ci 186662306a36Sopenharmony_ci /* Setup LED[2] as interrupt pin (active low) */ 186762306a36Sopenharmony_ci err = __phy_modify(phydev, MII_88E1318S_PHY_LED_TCR, 186862306a36Sopenharmony_ci MII_88E1318S_PHY_LED_TCR_FORCE_INT, 186962306a36Sopenharmony_ci MII_88E1318S_PHY_LED_TCR_INTn_ENABLE | 187062306a36Sopenharmony_ci MII_88E1318S_PHY_LED_TCR_INT_ACTIVE_LOW); 187162306a36Sopenharmony_ci if (err < 0) 187262306a36Sopenharmony_ci goto error; 187362306a36Sopenharmony_ci } 187462306a36Sopenharmony_ci 187562306a36Sopenharmony_ci if (wol->wolopts & WAKE_MAGIC) { 187662306a36Sopenharmony_ci err = marvell_write_page(phydev, MII_MARVELL_WOL_PAGE); 187762306a36Sopenharmony_ci if (err < 0) 187862306a36Sopenharmony_ci goto error; 187962306a36Sopenharmony_ci 188062306a36Sopenharmony_ci /* Store the device address for the magic packet */ 188162306a36Sopenharmony_ci err = __phy_write(phydev, MII_88E1318S_PHY_MAGIC_PACKET_WORD2, 188262306a36Sopenharmony_ci ((phydev->attached_dev->dev_addr[5] << 8) | 188362306a36Sopenharmony_ci phydev->attached_dev->dev_addr[4])); 188462306a36Sopenharmony_ci if (err < 0) 188562306a36Sopenharmony_ci goto error; 188662306a36Sopenharmony_ci err = __phy_write(phydev, MII_88E1318S_PHY_MAGIC_PACKET_WORD1, 188762306a36Sopenharmony_ci ((phydev->attached_dev->dev_addr[3] << 8) | 188862306a36Sopenharmony_ci phydev->attached_dev->dev_addr[2])); 188962306a36Sopenharmony_ci if (err < 0) 189062306a36Sopenharmony_ci goto error; 189162306a36Sopenharmony_ci err = __phy_write(phydev, MII_88E1318S_PHY_MAGIC_PACKET_WORD0, 189262306a36Sopenharmony_ci ((phydev->attached_dev->dev_addr[1] << 8) | 189362306a36Sopenharmony_ci phydev->attached_dev->dev_addr[0])); 189462306a36Sopenharmony_ci if (err < 0) 189562306a36Sopenharmony_ci goto error; 189662306a36Sopenharmony_ci 189762306a36Sopenharmony_ci /* Clear WOL status and enable magic packet matching */ 189862306a36Sopenharmony_ci err = __phy_set_bits(phydev, MII_88E1318S_PHY_WOL_CTRL, 189962306a36Sopenharmony_ci MII_88E1318S_PHY_WOL_CTRL_CLEAR_WOL_STATUS | 190062306a36Sopenharmony_ci MII_88E1318S_PHY_WOL_CTRL_MAGIC_PACKET_MATCH_ENABLE); 190162306a36Sopenharmony_ci if (err < 0) 190262306a36Sopenharmony_ci goto error; 190362306a36Sopenharmony_ci } else { 190462306a36Sopenharmony_ci err = marvell_write_page(phydev, MII_MARVELL_WOL_PAGE); 190562306a36Sopenharmony_ci if (err < 0) 190662306a36Sopenharmony_ci goto error; 190762306a36Sopenharmony_ci 190862306a36Sopenharmony_ci /* Clear WOL status and disable magic packet matching */ 190962306a36Sopenharmony_ci err = __phy_modify(phydev, MII_88E1318S_PHY_WOL_CTRL, 191062306a36Sopenharmony_ci MII_88E1318S_PHY_WOL_CTRL_MAGIC_PACKET_MATCH_ENABLE, 191162306a36Sopenharmony_ci MII_88E1318S_PHY_WOL_CTRL_CLEAR_WOL_STATUS); 191262306a36Sopenharmony_ci if (err < 0) 191362306a36Sopenharmony_ci goto error; 191462306a36Sopenharmony_ci } 191562306a36Sopenharmony_ci 191662306a36Sopenharmony_ci if (wol->wolopts & WAKE_PHY) { 191762306a36Sopenharmony_ci err = marvell_write_page(phydev, MII_MARVELL_WOL_PAGE); 191862306a36Sopenharmony_ci if (err < 0) 191962306a36Sopenharmony_ci goto error; 192062306a36Sopenharmony_ci 192162306a36Sopenharmony_ci /* Clear WOL status and enable link up event */ 192262306a36Sopenharmony_ci err = __phy_modify(phydev, MII_88E1318S_PHY_WOL_CTRL, 0, 192362306a36Sopenharmony_ci MII_88E1318S_PHY_WOL_CTRL_CLEAR_WOL_STATUS | 192462306a36Sopenharmony_ci MII_88E1318S_PHY_WOL_CTRL_LINK_UP_ENABLE); 192562306a36Sopenharmony_ci if (err < 0) 192662306a36Sopenharmony_ci goto error; 192762306a36Sopenharmony_ci } else { 192862306a36Sopenharmony_ci err = marvell_write_page(phydev, MII_MARVELL_WOL_PAGE); 192962306a36Sopenharmony_ci if (err < 0) 193062306a36Sopenharmony_ci goto error; 193162306a36Sopenharmony_ci 193262306a36Sopenharmony_ci /* Clear WOL status and disable link up event */ 193362306a36Sopenharmony_ci err = __phy_modify(phydev, MII_88E1318S_PHY_WOL_CTRL, 193462306a36Sopenharmony_ci MII_88E1318S_PHY_WOL_CTRL_LINK_UP_ENABLE, 193562306a36Sopenharmony_ci MII_88E1318S_PHY_WOL_CTRL_CLEAR_WOL_STATUS); 193662306a36Sopenharmony_ci if (err < 0) 193762306a36Sopenharmony_ci goto error; 193862306a36Sopenharmony_ci } 193962306a36Sopenharmony_ci 194062306a36Sopenharmony_cierror: 194162306a36Sopenharmony_ci return phy_restore_page(phydev, oldpage, err); 194262306a36Sopenharmony_ci} 194362306a36Sopenharmony_ci 194462306a36Sopenharmony_cistatic int marvell_get_sset_count(struct phy_device *phydev) 194562306a36Sopenharmony_ci{ 194662306a36Sopenharmony_ci if (linkmode_test_bit(ETHTOOL_LINK_MODE_FIBRE_BIT, 194762306a36Sopenharmony_ci phydev->supported)) 194862306a36Sopenharmony_ci return ARRAY_SIZE(marvell_hw_stats); 194962306a36Sopenharmony_ci else 195062306a36Sopenharmony_ci return ARRAY_SIZE(marvell_hw_stats) - NB_FIBER_STATS; 195162306a36Sopenharmony_ci} 195262306a36Sopenharmony_ci 195362306a36Sopenharmony_cistatic void marvell_get_strings(struct phy_device *phydev, u8 *data) 195462306a36Sopenharmony_ci{ 195562306a36Sopenharmony_ci int count = marvell_get_sset_count(phydev); 195662306a36Sopenharmony_ci int i; 195762306a36Sopenharmony_ci 195862306a36Sopenharmony_ci for (i = 0; i < count; i++) { 195962306a36Sopenharmony_ci strscpy(data + i * ETH_GSTRING_LEN, 196062306a36Sopenharmony_ci marvell_hw_stats[i].string, ETH_GSTRING_LEN); 196162306a36Sopenharmony_ci } 196262306a36Sopenharmony_ci} 196362306a36Sopenharmony_ci 196462306a36Sopenharmony_cistatic u64 marvell_get_stat(struct phy_device *phydev, int i) 196562306a36Sopenharmony_ci{ 196662306a36Sopenharmony_ci struct marvell_hw_stat stat = marvell_hw_stats[i]; 196762306a36Sopenharmony_ci struct marvell_priv *priv = phydev->priv; 196862306a36Sopenharmony_ci int val; 196962306a36Sopenharmony_ci u64 ret; 197062306a36Sopenharmony_ci 197162306a36Sopenharmony_ci val = phy_read_paged(phydev, stat.page, stat.reg); 197262306a36Sopenharmony_ci if (val < 0) { 197362306a36Sopenharmony_ci ret = U64_MAX; 197462306a36Sopenharmony_ci } else { 197562306a36Sopenharmony_ci val = val & ((1 << stat.bits) - 1); 197662306a36Sopenharmony_ci priv->stats[i] += val; 197762306a36Sopenharmony_ci ret = priv->stats[i]; 197862306a36Sopenharmony_ci } 197962306a36Sopenharmony_ci 198062306a36Sopenharmony_ci return ret; 198162306a36Sopenharmony_ci} 198262306a36Sopenharmony_ci 198362306a36Sopenharmony_cistatic void marvell_get_stats(struct phy_device *phydev, 198462306a36Sopenharmony_ci struct ethtool_stats *stats, u64 *data) 198562306a36Sopenharmony_ci{ 198662306a36Sopenharmony_ci int count = marvell_get_sset_count(phydev); 198762306a36Sopenharmony_ci int i; 198862306a36Sopenharmony_ci 198962306a36Sopenharmony_ci for (i = 0; i < count; i++) 199062306a36Sopenharmony_ci data[i] = marvell_get_stat(phydev, i); 199162306a36Sopenharmony_ci} 199262306a36Sopenharmony_ci 199362306a36Sopenharmony_cistatic int m88e1510_loopback(struct phy_device *phydev, bool enable) 199462306a36Sopenharmony_ci{ 199562306a36Sopenharmony_ci int err; 199662306a36Sopenharmony_ci 199762306a36Sopenharmony_ci if (enable) { 199862306a36Sopenharmony_ci u16 bmcr_ctl, mscr2_ctl = 0; 199962306a36Sopenharmony_ci 200062306a36Sopenharmony_ci bmcr_ctl = mii_bmcr_encode_fixed(phydev->speed, phydev->duplex); 200162306a36Sopenharmony_ci 200262306a36Sopenharmony_ci err = phy_write(phydev, MII_BMCR, bmcr_ctl); 200362306a36Sopenharmony_ci if (err < 0) 200462306a36Sopenharmony_ci return err; 200562306a36Sopenharmony_ci 200662306a36Sopenharmony_ci if (phydev->speed == SPEED_1000) 200762306a36Sopenharmony_ci mscr2_ctl = BMCR_SPEED1000; 200862306a36Sopenharmony_ci else if (phydev->speed == SPEED_100) 200962306a36Sopenharmony_ci mscr2_ctl = BMCR_SPEED100; 201062306a36Sopenharmony_ci 201162306a36Sopenharmony_ci err = phy_modify_paged(phydev, MII_MARVELL_MSCR_PAGE, 201262306a36Sopenharmony_ci MII_88E1510_MSCR_2, BMCR_SPEED1000 | 201362306a36Sopenharmony_ci BMCR_SPEED100, mscr2_ctl); 201462306a36Sopenharmony_ci if (err < 0) 201562306a36Sopenharmony_ci return err; 201662306a36Sopenharmony_ci 201762306a36Sopenharmony_ci /* Need soft reset to have speed configuration takes effect */ 201862306a36Sopenharmony_ci err = genphy_soft_reset(phydev); 201962306a36Sopenharmony_ci if (err < 0) 202062306a36Sopenharmony_ci return err; 202162306a36Sopenharmony_ci 202262306a36Sopenharmony_ci err = phy_modify(phydev, MII_BMCR, BMCR_LOOPBACK, 202362306a36Sopenharmony_ci BMCR_LOOPBACK); 202462306a36Sopenharmony_ci 202562306a36Sopenharmony_ci if (!err) { 202662306a36Sopenharmony_ci /* It takes some time for PHY device to switch 202762306a36Sopenharmony_ci * into/out-of loopback mode. 202862306a36Sopenharmony_ci */ 202962306a36Sopenharmony_ci msleep(1000); 203062306a36Sopenharmony_ci } 203162306a36Sopenharmony_ci return err; 203262306a36Sopenharmony_ci } else { 203362306a36Sopenharmony_ci err = phy_modify(phydev, MII_BMCR, BMCR_LOOPBACK, 0); 203462306a36Sopenharmony_ci if (err < 0) 203562306a36Sopenharmony_ci return err; 203662306a36Sopenharmony_ci 203762306a36Sopenharmony_ci return phy_config_aneg(phydev); 203862306a36Sopenharmony_ci } 203962306a36Sopenharmony_ci} 204062306a36Sopenharmony_ci 204162306a36Sopenharmony_cistatic int marvell_vct5_wait_complete(struct phy_device *phydev) 204262306a36Sopenharmony_ci{ 204362306a36Sopenharmony_ci int i; 204462306a36Sopenharmony_ci int val; 204562306a36Sopenharmony_ci 204662306a36Sopenharmony_ci for (i = 0; i < 32; i++) { 204762306a36Sopenharmony_ci val = __phy_read(phydev, MII_VCT5_CTRL); 204862306a36Sopenharmony_ci if (val < 0) 204962306a36Sopenharmony_ci return val; 205062306a36Sopenharmony_ci 205162306a36Sopenharmony_ci if (val & MII_VCT5_CTRL_COMPLETE) 205262306a36Sopenharmony_ci return 0; 205362306a36Sopenharmony_ci } 205462306a36Sopenharmony_ci 205562306a36Sopenharmony_ci phydev_err(phydev, "Timeout while waiting for cable test to finish\n"); 205662306a36Sopenharmony_ci return -ETIMEDOUT; 205762306a36Sopenharmony_ci} 205862306a36Sopenharmony_ci 205962306a36Sopenharmony_cistatic int marvell_vct5_amplitude(struct phy_device *phydev, int pair) 206062306a36Sopenharmony_ci{ 206162306a36Sopenharmony_ci int amplitude; 206262306a36Sopenharmony_ci int val; 206362306a36Sopenharmony_ci int reg; 206462306a36Sopenharmony_ci 206562306a36Sopenharmony_ci reg = MII_VCT5_TX_RX_MDI0_COUPLING + pair; 206662306a36Sopenharmony_ci val = __phy_read(phydev, reg); 206762306a36Sopenharmony_ci 206862306a36Sopenharmony_ci if (val < 0) 206962306a36Sopenharmony_ci return 0; 207062306a36Sopenharmony_ci 207162306a36Sopenharmony_ci amplitude = (val & MII_VCT5_TX_RX_AMPLITUDE_MASK) >> 207262306a36Sopenharmony_ci MII_VCT5_TX_RX_AMPLITUDE_SHIFT; 207362306a36Sopenharmony_ci 207462306a36Sopenharmony_ci if (!(val & MII_VCT5_TX_RX_COUPLING_POSITIVE_REFLECTION)) 207562306a36Sopenharmony_ci amplitude = -amplitude; 207662306a36Sopenharmony_ci 207762306a36Sopenharmony_ci return 1000 * amplitude / 128; 207862306a36Sopenharmony_ci} 207962306a36Sopenharmony_ci 208062306a36Sopenharmony_cistatic u32 marvell_vct5_distance2cm(int distance) 208162306a36Sopenharmony_ci{ 208262306a36Sopenharmony_ci return distance * 805 / 10; 208362306a36Sopenharmony_ci} 208462306a36Sopenharmony_ci 208562306a36Sopenharmony_cistatic u32 marvell_vct5_cm2distance(int cm) 208662306a36Sopenharmony_ci{ 208762306a36Sopenharmony_ci return cm * 10 / 805; 208862306a36Sopenharmony_ci} 208962306a36Sopenharmony_ci 209062306a36Sopenharmony_cistatic int marvell_vct5_amplitude_distance(struct phy_device *phydev, 209162306a36Sopenharmony_ci int distance, int pair) 209262306a36Sopenharmony_ci{ 209362306a36Sopenharmony_ci u16 reg; 209462306a36Sopenharmony_ci int err; 209562306a36Sopenharmony_ci int mV; 209662306a36Sopenharmony_ci int i; 209762306a36Sopenharmony_ci 209862306a36Sopenharmony_ci err = __phy_write(phydev, MII_VCT5_SAMPLE_POINT_DISTANCE, 209962306a36Sopenharmony_ci distance); 210062306a36Sopenharmony_ci if (err) 210162306a36Sopenharmony_ci return err; 210262306a36Sopenharmony_ci 210362306a36Sopenharmony_ci reg = MII_VCT5_CTRL_ENABLE | 210462306a36Sopenharmony_ci MII_VCT5_CTRL_TX_SAME_CHANNEL | 210562306a36Sopenharmony_ci MII_VCT5_CTRL_SAMPLES_DEFAULT | 210662306a36Sopenharmony_ci MII_VCT5_CTRL_SAMPLE_POINT | 210762306a36Sopenharmony_ci MII_VCT5_CTRL_PEEK_HYST_DEFAULT; 210862306a36Sopenharmony_ci err = __phy_write(phydev, MII_VCT5_CTRL, reg); 210962306a36Sopenharmony_ci if (err) 211062306a36Sopenharmony_ci return err; 211162306a36Sopenharmony_ci 211262306a36Sopenharmony_ci err = marvell_vct5_wait_complete(phydev); 211362306a36Sopenharmony_ci if (err) 211462306a36Sopenharmony_ci return err; 211562306a36Sopenharmony_ci 211662306a36Sopenharmony_ci for (i = 0; i < 4; i++) { 211762306a36Sopenharmony_ci if (pair != PHY_PAIR_ALL && i != pair) 211862306a36Sopenharmony_ci continue; 211962306a36Sopenharmony_ci 212062306a36Sopenharmony_ci mV = marvell_vct5_amplitude(phydev, i); 212162306a36Sopenharmony_ci ethnl_cable_test_amplitude(phydev, i, mV); 212262306a36Sopenharmony_ci } 212362306a36Sopenharmony_ci 212462306a36Sopenharmony_ci return 0; 212562306a36Sopenharmony_ci} 212662306a36Sopenharmony_ci 212762306a36Sopenharmony_cistatic int marvell_vct5_amplitude_graph(struct phy_device *phydev) 212862306a36Sopenharmony_ci{ 212962306a36Sopenharmony_ci struct marvell_priv *priv = phydev->priv; 213062306a36Sopenharmony_ci int distance; 213162306a36Sopenharmony_ci u16 width; 213262306a36Sopenharmony_ci int page; 213362306a36Sopenharmony_ci int err; 213462306a36Sopenharmony_ci u16 reg; 213562306a36Sopenharmony_ci 213662306a36Sopenharmony_ci if (priv->first <= TDR_SHORT_CABLE_LENGTH) 213762306a36Sopenharmony_ci width = MII_VCT5_TX_PULSE_CTRL_PULSE_WIDTH_32nS; 213862306a36Sopenharmony_ci else 213962306a36Sopenharmony_ci width = MII_VCT5_TX_PULSE_CTRL_PULSE_WIDTH_128nS; 214062306a36Sopenharmony_ci 214162306a36Sopenharmony_ci reg = MII_VCT5_TX_PULSE_CTRL_GT_140m_46_86mV | 214262306a36Sopenharmony_ci MII_VCT5_TX_PULSE_CTRL_DONT_WAIT_LINK_DOWN | 214362306a36Sopenharmony_ci MII_VCT5_TX_PULSE_CTRL_MAX_AMP | width; 214462306a36Sopenharmony_ci 214562306a36Sopenharmony_ci err = phy_write_paged(phydev, MII_MARVELL_VCT5_PAGE, 214662306a36Sopenharmony_ci MII_VCT5_TX_PULSE_CTRL, reg); 214762306a36Sopenharmony_ci if (err) 214862306a36Sopenharmony_ci return err; 214962306a36Sopenharmony_ci 215062306a36Sopenharmony_ci /* Reading the TDR data is very MDIO heavy. We need to optimize 215162306a36Sopenharmony_ci * access to keep the time to a minimum. So lock the bus once, 215262306a36Sopenharmony_ci * and don't release it until complete. We can then avoid having 215362306a36Sopenharmony_ci * to change the page for every access, greatly speeding things 215462306a36Sopenharmony_ci * up. 215562306a36Sopenharmony_ci */ 215662306a36Sopenharmony_ci page = phy_select_page(phydev, MII_MARVELL_VCT5_PAGE); 215762306a36Sopenharmony_ci if (page < 0) 215862306a36Sopenharmony_ci goto restore_page; 215962306a36Sopenharmony_ci 216062306a36Sopenharmony_ci for (distance = priv->first; 216162306a36Sopenharmony_ci distance <= priv->last; 216262306a36Sopenharmony_ci distance += priv->step) { 216362306a36Sopenharmony_ci err = marvell_vct5_amplitude_distance(phydev, distance, 216462306a36Sopenharmony_ci priv->pair); 216562306a36Sopenharmony_ci if (err) 216662306a36Sopenharmony_ci goto restore_page; 216762306a36Sopenharmony_ci 216862306a36Sopenharmony_ci if (distance > TDR_SHORT_CABLE_LENGTH && 216962306a36Sopenharmony_ci width == MII_VCT5_TX_PULSE_CTRL_PULSE_WIDTH_32nS) { 217062306a36Sopenharmony_ci width = MII_VCT5_TX_PULSE_CTRL_PULSE_WIDTH_128nS; 217162306a36Sopenharmony_ci reg = MII_VCT5_TX_PULSE_CTRL_GT_140m_46_86mV | 217262306a36Sopenharmony_ci MII_VCT5_TX_PULSE_CTRL_DONT_WAIT_LINK_DOWN | 217362306a36Sopenharmony_ci MII_VCT5_TX_PULSE_CTRL_MAX_AMP | width; 217462306a36Sopenharmony_ci err = __phy_write(phydev, MII_VCT5_TX_PULSE_CTRL, reg); 217562306a36Sopenharmony_ci if (err) 217662306a36Sopenharmony_ci goto restore_page; 217762306a36Sopenharmony_ci } 217862306a36Sopenharmony_ci } 217962306a36Sopenharmony_ci 218062306a36Sopenharmony_cirestore_page: 218162306a36Sopenharmony_ci return phy_restore_page(phydev, page, err); 218262306a36Sopenharmony_ci} 218362306a36Sopenharmony_ci 218462306a36Sopenharmony_cistatic int marvell_cable_test_start_common(struct phy_device *phydev) 218562306a36Sopenharmony_ci{ 218662306a36Sopenharmony_ci int bmcr, bmsr, ret; 218762306a36Sopenharmony_ci 218862306a36Sopenharmony_ci /* If auto-negotiation is enabled, but not complete, the cable 218962306a36Sopenharmony_ci * test never completes. So disable auto-neg. 219062306a36Sopenharmony_ci */ 219162306a36Sopenharmony_ci bmcr = phy_read(phydev, MII_BMCR); 219262306a36Sopenharmony_ci if (bmcr < 0) 219362306a36Sopenharmony_ci return bmcr; 219462306a36Sopenharmony_ci 219562306a36Sopenharmony_ci bmsr = phy_read(phydev, MII_BMSR); 219662306a36Sopenharmony_ci 219762306a36Sopenharmony_ci if (bmsr < 0) 219862306a36Sopenharmony_ci return bmsr; 219962306a36Sopenharmony_ci 220062306a36Sopenharmony_ci if (bmcr & BMCR_ANENABLE) { 220162306a36Sopenharmony_ci ret = phy_clear_bits(phydev, MII_BMCR, BMCR_ANENABLE); 220262306a36Sopenharmony_ci if (ret < 0) 220362306a36Sopenharmony_ci return ret; 220462306a36Sopenharmony_ci ret = genphy_soft_reset(phydev); 220562306a36Sopenharmony_ci if (ret < 0) 220662306a36Sopenharmony_ci return ret; 220762306a36Sopenharmony_ci } 220862306a36Sopenharmony_ci 220962306a36Sopenharmony_ci /* If the link is up, allow it some time to go down */ 221062306a36Sopenharmony_ci if (bmsr & BMSR_LSTATUS) 221162306a36Sopenharmony_ci msleep(1500); 221262306a36Sopenharmony_ci 221362306a36Sopenharmony_ci return 0; 221462306a36Sopenharmony_ci} 221562306a36Sopenharmony_ci 221662306a36Sopenharmony_cistatic int marvell_vct7_cable_test_start(struct phy_device *phydev) 221762306a36Sopenharmony_ci{ 221862306a36Sopenharmony_ci struct marvell_priv *priv = phydev->priv; 221962306a36Sopenharmony_ci int ret; 222062306a36Sopenharmony_ci 222162306a36Sopenharmony_ci ret = marvell_cable_test_start_common(phydev); 222262306a36Sopenharmony_ci if (ret) 222362306a36Sopenharmony_ci return ret; 222462306a36Sopenharmony_ci 222562306a36Sopenharmony_ci priv->cable_test_tdr = false; 222662306a36Sopenharmony_ci 222762306a36Sopenharmony_ci /* Reset the VCT5 API control to defaults, otherwise 222862306a36Sopenharmony_ci * VCT7 does not work correctly. 222962306a36Sopenharmony_ci */ 223062306a36Sopenharmony_ci ret = phy_write_paged(phydev, MII_MARVELL_VCT5_PAGE, 223162306a36Sopenharmony_ci MII_VCT5_CTRL, 223262306a36Sopenharmony_ci MII_VCT5_CTRL_TX_SAME_CHANNEL | 223362306a36Sopenharmony_ci MII_VCT5_CTRL_SAMPLES_DEFAULT | 223462306a36Sopenharmony_ci MII_VCT5_CTRL_MODE_MAXIMUM_PEEK | 223562306a36Sopenharmony_ci MII_VCT5_CTRL_PEEK_HYST_DEFAULT); 223662306a36Sopenharmony_ci if (ret) 223762306a36Sopenharmony_ci return ret; 223862306a36Sopenharmony_ci 223962306a36Sopenharmony_ci ret = phy_write_paged(phydev, MII_MARVELL_VCT5_PAGE, 224062306a36Sopenharmony_ci MII_VCT5_SAMPLE_POINT_DISTANCE, 0); 224162306a36Sopenharmony_ci if (ret) 224262306a36Sopenharmony_ci return ret; 224362306a36Sopenharmony_ci 224462306a36Sopenharmony_ci return phy_write_paged(phydev, MII_MARVELL_VCT7_PAGE, 224562306a36Sopenharmony_ci MII_VCT7_CTRL, 224662306a36Sopenharmony_ci MII_VCT7_CTRL_RUN_NOW | 224762306a36Sopenharmony_ci MII_VCT7_CTRL_CENTIMETERS); 224862306a36Sopenharmony_ci} 224962306a36Sopenharmony_ci 225062306a36Sopenharmony_cistatic int marvell_vct5_cable_test_tdr_start(struct phy_device *phydev, 225162306a36Sopenharmony_ci const struct phy_tdr_config *cfg) 225262306a36Sopenharmony_ci{ 225362306a36Sopenharmony_ci struct marvell_priv *priv = phydev->priv; 225462306a36Sopenharmony_ci int ret; 225562306a36Sopenharmony_ci 225662306a36Sopenharmony_ci priv->cable_test_tdr = true; 225762306a36Sopenharmony_ci priv->first = marvell_vct5_cm2distance(cfg->first); 225862306a36Sopenharmony_ci priv->last = marvell_vct5_cm2distance(cfg->last); 225962306a36Sopenharmony_ci priv->step = marvell_vct5_cm2distance(cfg->step); 226062306a36Sopenharmony_ci priv->pair = cfg->pair; 226162306a36Sopenharmony_ci 226262306a36Sopenharmony_ci if (priv->first > MII_VCT5_SAMPLE_POINT_DISTANCE_MAX) 226362306a36Sopenharmony_ci return -EINVAL; 226462306a36Sopenharmony_ci 226562306a36Sopenharmony_ci if (priv->last > MII_VCT5_SAMPLE_POINT_DISTANCE_MAX) 226662306a36Sopenharmony_ci return -EINVAL; 226762306a36Sopenharmony_ci 226862306a36Sopenharmony_ci /* Disable VCT7 */ 226962306a36Sopenharmony_ci ret = phy_write_paged(phydev, MII_MARVELL_VCT7_PAGE, 227062306a36Sopenharmony_ci MII_VCT7_CTRL, 0); 227162306a36Sopenharmony_ci if (ret) 227262306a36Sopenharmony_ci return ret; 227362306a36Sopenharmony_ci 227462306a36Sopenharmony_ci ret = marvell_cable_test_start_common(phydev); 227562306a36Sopenharmony_ci if (ret) 227662306a36Sopenharmony_ci return ret; 227762306a36Sopenharmony_ci 227862306a36Sopenharmony_ci ret = ethnl_cable_test_pulse(phydev, 1000); 227962306a36Sopenharmony_ci if (ret) 228062306a36Sopenharmony_ci return ret; 228162306a36Sopenharmony_ci 228262306a36Sopenharmony_ci return ethnl_cable_test_step(phydev, 228362306a36Sopenharmony_ci marvell_vct5_distance2cm(priv->first), 228462306a36Sopenharmony_ci marvell_vct5_distance2cm(priv->last), 228562306a36Sopenharmony_ci marvell_vct5_distance2cm(priv->step)); 228662306a36Sopenharmony_ci} 228762306a36Sopenharmony_ci 228862306a36Sopenharmony_cistatic int marvell_vct7_distance_to_length(int distance, bool meter) 228962306a36Sopenharmony_ci{ 229062306a36Sopenharmony_ci if (meter) 229162306a36Sopenharmony_ci distance *= 100; 229262306a36Sopenharmony_ci 229362306a36Sopenharmony_ci return distance; 229462306a36Sopenharmony_ci} 229562306a36Sopenharmony_ci 229662306a36Sopenharmony_cistatic bool marvell_vct7_distance_valid(int result) 229762306a36Sopenharmony_ci{ 229862306a36Sopenharmony_ci switch (result) { 229962306a36Sopenharmony_ci case MII_VCT7_RESULTS_OPEN: 230062306a36Sopenharmony_ci case MII_VCT7_RESULTS_SAME_SHORT: 230162306a36Sopenharmony_ci case MII_VCT7_RESULTS_CROSS_SHORT: 230262306a36Sopenharmony_ci return true; 230362306a36Sopenharmony_ci } 230462306a36Sopenharmony_ci return false; 230562306a36Sopenharmony_ci} 230662306a36Sopenharmony_ci 230762306a36Sopenharmony_cistatic int marvell_vct7_report_length(struct phy_device *phydev, 230862306a36Sopenharmony_ci int pair, bool meter) 230962306a36Sopenharmony_ci{ 231062306a36Sopenharmony_ci int length; 231162306a36Sopenharmony_ci int ret; 231262306a36Sopenharmony_ci 231362306a36Sopenharmony_ci ret = phy_read_paged(phydev, MII_MARVELL_VCT7_PAGE, 231462306a36Sopenharmony_ci MII_VCT7_PAIR_0_DISTANCE + pair); 231562306a36Sopenharmony_ci if (ret < 0) 231662306a36Sopenharmony_ci return ret; 231762306a36Sopenharmony_ci 231862306a36Sopenharmony_ci length = marvell_vct7_distance_to_length(ret, meter); 231962306a36Sopenharmony_ci 232062306a36Sopenharmony_ci ethnl_cable_test_fault_length(phydev, pair, length); 232162306a36Sopenharmony_ci 232262306a36Sopenharmony_ci return 0; 232362306a36Sopenharmony_ci} 232462306a36Sopenharmony_ci 232562306a36Sopenharmony_cistatic int marvell_vct7_cable_test_report_trans(int result) 232662306a36Sopenharmony_ci{ 232762306a36Sopenharmony_ci switch (result) { 232862306a36Sopenharmony_ci case MII_VCT7_RESULTS_OK: 232962306a36Sopenharmony_ci return ETHTOOL_A_CABLE_RESULT_CODE_OK; 233062306a36Sopenharmony_ci case MII_VCT7_RESULTS_OPEN: 233162306a36Sopenharmony_ci return ETHTOOL_A_CABLE_RESULT_CODE_OPEN; 233262306a36Sopenharmony_ci case MII_VCT7_RESULTS_SAME_SHORT: 233362306a36Sopenharmony_ci return ETHTOOL_A_CABLE_RESULT_CODE_SAME_SHORT; 233462306a36Sopenharmony_ci case MII_VCT7_RESULTS_CROSS_SHORT: 233562306a36Sopenharmony_ci return ETHTOOL_A_CABLE_RESULT_CODE_CROSS_SHORT; 233662306a36Sopenharmony_ci default: 233762306a36Sopenharmony_ci return ETHTOOL_A_CABLE_RESULT_CODE_UNSPEC; 233862306a36Sopenharmony_ci } 233962306a36Sopenharmony_ci} 234062306a36Sopenharmony_ci 234162306a36Sopenharmony_cistatic int marvell_vct7_cable_test_report(struct phy_device *phydev) 234262306a36Sopenharmony_ci{ 234362306a36Sopenharmony_ci int pair0, pair1, pair2, pair3; 234462306a36Sopenharmony_ci bool meter; 234562306a36Sopenharmony_ci int ret; 234662306a36Sopenharmony_ci 234762306a36Sopenharmony_ci ret = phy_read_paged(phydev, MII_MARVELL_VCT7_PAGE, 234862306a36Sopenharmony_ci MII_VCT7_RESULTS); 234962306a36Sopenharmony_ci if (ret < 0) 235062306a36Sopenharmony_ci return ret; 235162306a36Sopenharmony_ci 235262306a36Sopenharmony_ci pair3 = (ret & MII_VCT7_RESULTS_PAIR3_MASK) >> 235362306a36Sopenharmony_ci MII_VCT7_RESULTS_PAIR3_SHIFT; 235462306a36Sopenharmony_ci pair2 = (ret & MII_VCT7_RESULTS_PAIR2_MASK) >> 235562306a36Sopenharmony_ci MII_VCT7_RESULTS_PAIR2_SHIFT; 235662306a36Sopenharmony_ci pair1 = (ret & MII_VCT7_RESULTS_PAIR1_MASK) >> 235762306a36Sopenharmony_ci MII_VCT7_RESULTS_PAIR1_SHIFT; 235862306a36Sopenharmony_ci pair0 = (ret & MII_VCT7_RESULTS_PAIR0_MASK) >> 235962306a36Sopenharmony_ci MII_VCT7_RESULTS_PAIR0_SHIFT; 236062306a36Sopenharmony_ci 236162306a36Sopenharmony_ci ethnl_cable_test_result(phydev, ETHTOOL_A_CABLE_PAIR_A, 236262306a36Sopenharmony_ci marvell_vct7_cable_test_report_trans(pair0)); 236362306a36Sopenharmony_ci ethnl_cable_test_result(phydev, ETHTOOL_A_CABLE_PAIR_B, 236462306a36Sopenharmony_ci marvell_vct7_cable_test_report_trans(pair1)); 236562306a36Sopenharmony_ci ethnl_cable_test_result(phydev, ETHTOOL_A_CABLE_PAIR_C, 236662306a36Sopenharmony_ci marvell_vct7_cable_test_report_trans(pair2)); 236762306a36Sopenharmony_ci ethnl_cable_test_result(phydev, ETHTOOL_A_CABLE_PAIR_D, 236862306a36Sopenharmony_ci marvell_vct7_cable_test_report_trans(pair3)); 236962306a36Sopenharmony_ci 237062306a36Sopenharmony_ci ret = phy_read_paged(phydev, MII_MARVELL_VCT7_PAGE, MII_VCT7_CTRL); 237162306a36Sopenharmony_ci if (ret < 0) 237262306a36Sopenharmony_ci return ret; 237362306a36Sopenharmony_ci 237462306a36Sopenharmony_ci meter = ret & MII_VCT7_CTRL_METERS; 237562306a36Sopenharmony_ci 237662306a36Sopenharmony_ci if (marvell_vct7_distance_valid(pair0)) 237762306a36Sopenharmony_ci marvell_vct7_report_length(phydev, 0, meter); 237862306a36Sopenharmony_ci if (marvell_vct7_distance_valid(pair1)) 237962306a36Sopenharmony_ci marvell_vct7_report_length(phydev, 1, meter); 238062306a36Sopenharmony_ci if (marvell_vct7_distance_valid(pair2)) 238162306a36Sopenharmony_ci marvell_vct7_report_length(phydev, 2, meter); 238262306a36Sopenharmony_ci if (marvell_vct7_distance_valid(pair3)) 238362306a36Sopenharmony_ci marvell_vct7_report_length(phydev, 3, meter); 238462306a36Sopenharmony_ci 238562306a36Sopenharmony_ci return 0; 238662306a36Sopenharmony_ci} 238762306a36Sopenharmony_ci 238862306a36Sopenharmony_cistatic int marvell_vct7_cable_test_get_status(struct phy_device *phydev, 238962306a36Sopenharmony_ci bool *finished) 239062306a36Sopenharmony_ci{ 239162306a36Sopenharmony_ci struct marvell_priv *priv = phydev->priv; 239262306a36Sopenharmony_ci int ret; 239362306a36Sopenharmony_ci 239462306a36Sopenharmony_ci if (priv->cable_test_tdr) { 239562306a36Sopenharmony_ci ret = marvell_vct5_amplitude_graph(phydev); 239662306a36Sopenharmony_ci *finished = true; 239762306a36Sopenharmony_ci return ret; 239862306a36Sopenharmony_ci } 239962306a36Sopenharmony_ci 240062306a36Sopenharmony_ci *finished = false; 240162306a36Sopenharmony_ci 240262306a36Sopenharmony_ci ret = phy_read_paged(phydev, MII_MARVELL_VCT7_PAGE, 240362306a36Sopenharmony_ci MII_VCT7_CTRL); 240462306a36Sopenharmony_ci 240562306a36Sopenharmony_ci if (ret < 0) 240662306a36Sopenharmony_ci return ret; 240762306a36Sopenharmony_ci 240862306a36Sopenharmony_ci if (!(ret & MII_VCT7_CTRL_IN_PROGRESS)) { 240962306a36Sopenharmony_ci *finished = true; 241062306a36Sopenharmony_ci 241162306a36Sopenharmony_ci return marvell_vct7_cable_test_report(phydev); 241262306a36Sopenharmony_ci } 241362306a36Sopenharmony_ci 241462306a36Sopenharmony_ci return 0; 241562306a36Sopenharmony_ci} 241662306a36Sopenharmony_ci 241762306a36Sopenharmony_ci#ifdef CONFIG_HWMON 241862306a36Sopenharmony_cistruct marvell_hwmon_ops { 241962306a36Sopenharmony_ci int (*config)(struct phy_device *phydev); 242062306a36Sopenharmony_ci int (*get_temp)(struct phy_device *phydev, long *temp); 242162306a36Sopenharmony_ci int (*get_temp_critical)(struct phy_device *phydev, long *temp); 242262306a36Sopenharmony_ci int (*set_temp_critical)(struct phy_device *phydev, long temp); 242362306a36Sopenharmony_ci int (*get_temp_alarm)(struct phy_device *phydev, long *alarm); 242462306a36Sopenharmony_ci}; 242562306a36Sopenharmony_ci 242662306a36Sopenharmony_cistatic const struct marvell_hwmon_ops * 242762306a36Sopenharmony_cito_marvell_hwmon_ops(const struct phy_device *phydev) 242862306a36Sopenharmony_ci{ 242962306a36Sopenharmony_ci return phydev->drv->driver_data; 243062306a36Sopenharmony_ci} 243162306a36Sopenharmony_ci 243262306a36Sopenharmony_cistatic int m88e1121_get_temp(struct phy_device *phydev, long *temp) 243362306a36Sopenharmony_ci{ 243462306a36Sopenharmony_ci int oldpage; 243562306a36Sopenharmony_ci int ret = 0; 243662306a36Sopenharmony_ci int val; 243762306a36Sopenharmony_ci 243862306a36Sopenharmony_ci *temp = 0; 243962306a36Sopenharmony_ci 244062306a36Sopenharmony_ci oldpage = phy_select_page(phydev, MII_MARVELL_MISC_TEST_PAGE); 244162306a36Sopenharmony_ci if (oldpage < 0) 244262306a36Sopenharmony_ci goto error; 244362306a36Sopenharmony_ci 244462306a36Sopenharmony_ci /* Enable temperature sensor */ 244562306a36Sopenharmony_ci ret = __phy_read(phydev, MII_88E1121_MISC_TEST); 244662306a36Sopenharmony_ci if (ret < 0) 244762306a36Sopenharmony_ci goto error; 244862306a36Sopenharmony_ci 244962306a36Sopenharmony_ci ret = __phy_write(phydev, MII_88E1121_MISC_TEST, 245062306a36Sopenharmony_ci ret | MII_88E1121_MISC_TEST_TEMP_SENSOR_EN); 245162306a36Sopenharmony_ci if (ret < 0) 245262306a36Sopenharmony_ci goto error; 245362306a36Sopenharmony_ci 245462306a36Sopenharmony_ci /* Wait for temperature to stabilize */ 245562306a36Sopenharmony_ci usleep_range(10000, 12000); 245662306a36Sopenharmony_ci 245762306a36Sopenharmony_ci val = __phy_read(phydev, MII_88E1121_MISC_TEST); 245862306a36Sopenharmony_ci if (val < 0) { 245962306a36Sopenharmony_ci ret = val; 246062306a36Sopenharmony_ci goto error; 246162306a36Sopenharmony_ci } 246262306a36Sopenharmony_ci 246362306a36Sopenharmony_ci /* Disable temperature sensor */ 246462306a36Sopenharmony_ci ret = __phy_write(phydev, MII_88E1121_MISC_TEST, 246562306a36Sopenharmony_ci ret & ~MII_88E1121_MISC_TEST_TEMP_SENSOR_EN); 246662306a36Sopenharmony_ci if (ret < 0) 246762306a36Sopenharmony_ci goto error; 246862306a36Sopenharmony_ci 246962306a36Sopenharmony_ci *temp = ((val & MII_88E1121_MISC_TEST_TEMP_MASK) - 5) * 5000; 247062306a36Sopenharmony_ci 247162306a36Sopenharmony_cierror: 247262306a36Sopenharmony_ci return phy_restore_page(phydev, oldpage, ret); 247362306a36Sopenharmony_ci} 247462306a36Sopenharmony_ci 247562306a36Sopenharmony_cistatic int m88e1510_get_temp(struct phy_device *phydev, long *temp) 247662306a36Sopenharmony_ci{ 247762306a36Sopenharmony_ci int ret; 247862306a36Sopenharmony_ci 247962306a36Sopenharmony_ci *temp = 0; 248062306a36Sopenharmony_ci 248162306a36Sopenharmony_ci ret = phy_read_paged(phydev, MII_MARVELL_MISC_TEST_PAGE, 248262306a36Sopenharmony_ci MII_88E1510_TEMP_SENSOR); 248362306a36Sopenharmony_ci if (ret < 0) 248462306a36Sopenharmony_ci return ret; 248562306a36Sopenharmony_ci 248662306a36Sopenharmony_ci *temp = ((ret & MII_88E1510_TEMP_SENSOR_MASK) - 25) * 1000; 248762306a36Sopenharmony_ci 248862306a36Sopenharmony_ci return 0; 248962306a36Sopenharmony_ci} 249062306a36Sopenharmony_ci 249162306a36Sopenharmony_cistatic int m88e1510_get_temp_critical(struct phy_device *phydev, long *temp) 249262306a36Sopenharmony_ci{ 249362306a36Sopenharmony_ci int ret; 249462306a36Sopenharmony_ci 249562306a36Sopenharmony_ci *temp = 0; 249662306a36Sopenharmony_ci 249762306a36Sopenharmony_ci ret = phy_read_paged(phydev, MII_MARVELL_MISC_TEST_PAGE, 249862306a36Sopenharmony_ci MII_88E1121_MISC_TEST); 249962306a36Sopenharmony_ci if (ret < 0) 250062306a36Sopenharmony_ci return ret; 250162306a36Sopenharmony_ci 250262306a36Sopenharmony_ci *temp = (((ret & MII_88E1510_MISC_TEST_TEMP_THRESHOLD_MASK) >> 250362306a36Sopenharmony_ci MII_88E1510_MISC_TEST_TEMP_THRESHOLD_SHIFT) * 5) - 25; 250462306a36Sopenharmony_ci /* convert to mC */ 250562306a36Sopenharmony_ci *temp *= 1000; 250662306a36Sopenharmony_ci 250762306a36Sopenharmony_ci return 0; 250862306a36Sopenharmony_ci} 250962306a36Sopenharmony_ci 251062306a36Sopenharmony_cistatic int m88e1510_set_temp_critical(struct phy_device *phydev, long temp) 251162306a36Sopenharmony_ci{ 251262306a36Sopenharmony_ci temp = temp / 1000; 251362306a36Sopenharmony_ci temp = clamp_val(DIV_ROUND_CLOSEST(temp, 5) + 5, 0, 0x1f); 251462306a36Sopenharmony_ci 251562306a36Sopenharmony_ci return phy_modify_paged(phydev, MII_MARVELL_MISC_TEST_PAGE, 251662306a36Sopenharmony_ci MII_88E1121_MISC_TEST, 251762306a36Sopenharmony_ci MII_88E1510_MISC_TEST_TEMP_THRESHOLD_MASK, 251862306a36Sopenharmony_ci temp << MII_88E1510_MISC_TEST_TEMP_THRESHOLD_SHIFT); 251962306a36Sopenharmony_ci} 252062306a36Sopenharmony_ci 252162306a36Sopenharmony_cistatic int m88e1510_get_temp_alarm(struct phy_device *phydev, long *alarm) 252262306a36Sopenharmony_ci{ 252362306a36Sopenharmony_ci int ret; 252462306a36Sopenharmony_ci 252562306a36Sopenharmony_ci *alarm = false; 252662306a36Sopenharmony_ci 252762306a36Sopenharmony_ci ret = phy_read_paged(phydev, MII_MARVELL_MISC_TEST_PAGE, 252862306a36Sopenharmony_ci MII_88E1121_MISC_TEST); 252962306a36Sopenharmony_ci if (ret < 0) 253062306a36Sopenharmony_ci return ret; 253162306a36Sopenharmony_ci 253262306a36Sopenharmony_ci *alarm = !!(ret & MII_88E1510_MISC_TEST_TEMP_IRQ); 253362306a36Sopenharmony_ci 253462306a36Sopenharmony_ci return 0; 253562306a36Sopenharmony_ci} 253662306a36Sopenharmony_ci 253762306a36Sopenharmony_cistatic int m88e6390_get_temp(struct phy_device *phydev, long *temp) 253862306a36Sopenharmony_ci{ 253962306a36Sopenharmony_ci int sum = 0; 254062306a36Sopenharmony_ci int oldpage; 254162306a36Sopenharmony_ci int ret = 0; 254262306a36Sopenharmony_ci int i; 254362306a36Sopenharmony_ci 254462306a36Sopenharmony_ci *temp = 0; 254562306a36Sopenharmony_ci 254662306a36Sopenharmony_ci oldpage = phy_select_page(phydev, MII_MARVELL_MISC_TEST_PAGE); 254762306a36Sopenharmony_ci if (oldpage < 0) 254862306a36Sopenharmony_ci goto error; 254962306a36Sopenharmony_ci 255062306a36Sopenharmony_ci /* Enable temperature sensor */ 255162306a36Sopenharmony_ci ret = __phy_read(phydev, MII_88E6390_MISC_TEST); 255262306a36Sopenharmony_ci if (ret < 0) 255362306a36Sopenharmony_ci goto error; 255462306a36Sopenharmony_ci 255562306a36Sopenharmony_ci ret &= ~MII_88E6390_MISC_TEST_TEMP_SENSOR_MASK; 255662306a36Sopenharmony_ci ret |= MII_88E6390_MISC_TEST_TEMP_SENSOR_ENABLE_SAMPLE_1S; 255762306a36Sopenharmony_ci 255862306a36Sopenharmony_ci ret = __phy_write(phydev, MII_88E6390_MISC_TEST, ret); 255962306a36Sopenharmony_ci if (ret < 0) 256062306a36Sopenharmony_ci goto error; 256162306a36Sopenharmony_ci 256262306a36Sopenharmony_ci /* Wait for temperature to stabilize */ 256362306a36Sopenharmony_ci usleep_range(10000, 12000); 256462306a36Sopenharmony_ci 256562306a36Sopenharmony_ci /* Reading the temperature sense has an errata. You need to read 256662306a36Sopenharmony_ci * a number of times and take an average. 256762306a36Sopenharmony_ci */ 256862306a36Sopenharmony_ci for (i = 0; i < MII_88E6390_TEMP_SENSOR_SAMPLES; i++) { 256962306a36Sopenharmony_ci ret = __phy_read(phydev, MII_88E6390_TEMP_SENSOR); 257062306a36Sopenharmony_ci if (ret < 0) 257162306a36Sopenharmony_ci goto error; 257262306a36Sopenharmony_ci sum += ret & MII_88E6390_TEMP_SENSOR_MASK; 257362306a36Sopenharmony_ci } 257462306a36Sopenharmony_ci 257562306a36Sopenharmony_ci sum /= MII_88E6390_TEMP_SENSOR_SAMPLES; 257662306a36Sopenharmony_ci *temp = (sum - 75) * 1000; 257762306a36Sopenharmony_ci 257862306a36Sopenharmony_ci /* Disable temperature sensor */ 257962306a36Sopenharmony_ci ret = __phy_read(phydev, MII_88E6390_MISC_TEST); 258062306a36Sopenharmony_ci if (ret < 0) 258162306a36Sopenharmony_ci goto error; 258262306a36Sopenharmony_ci 258362306a36Sopenharmony_ci ret = ret & ~MII_88E6390_MISC_TEST_TEMP_SENSOR_MASK; 258462306a36Sopenharmony_ci ret |= MII_88E6390_MISC_TEST_TEMP_SENSOR_DISABLE; 258562306a36Sopenharmony_ci 258662306a36Sopenharmony_ci ret = __phy_write(phydev, MII_88E6390_MISC_TEST, ret); 258762306a36Sopenharmony_ci 258862306a36Sopenharmony_cierror: 258962306a36Sopenharmony_ci phy_restore_page(phydev, oldpage, ret); 259062306a36Sopenharmony_ci 259162306a36Sopenharmony_ci return ret; 259262306a36Sopenharmony_ci} 259362306a36Sopenharmony_ci 259462306a36Sopenharmony_cistatic int m88e6393_get_temp(struct phy_device *phydev, long *temp) 259562306a36Sopenharmony_ci{ 259662306a36Sopenharmony_ci int err; 259762306a36Sopenharmony_ci 259862306a36Sopenharmony_ci err = m88e1510_get_temp(phydev, temp); 259962306a36Sopenharmony_ci 260062306a36Sopenharmony_ci /* 88E1510 measures T + 25, while the PHY on 88E6393X switch 260162306a36Sopenharmony_ci * T + 75, so we have to subtract another 50 260262306a36Sopenharmony_ci */ 260362306a36Sopenharmony_ci *temp -= 50000; 260462306a36Sopenharmony_ci 260562306a36Sopenharmony_ci return err; 260662306a36Sopenharmony_ci} 260762306a36Sopenharmony_ci 260862306a36Sopenharmony_cistatic int m88e6393_get_temp_critical(struct phy_device *phydev, long *temp) 260962306a36Sopenharmony_ci{ 261062306a36Sopenharmony_ci int ret; 261162306a36Sopenharmony_ci 261262306a36Sopenharmony_ci *temp = 0; 261362306a36Sopenharmony_ci 261462306a36Sopenharmony_ci ret = phy_read_paged(phydev, MII_MARVELL_MISC_TEST_PAGE, 261562306a36Sopenharmony_ci MII_88E6390_TEMP_SENSOR); 261662306a36Sopenharmony_ci if (ret < 0) 261762306a36Sopenharmony_ci return ret; 261862306a36Sopenharmony_ci 261962306a36Sopenharmony_ci *temp = (((ret & MII_88E6393_TEMP_SENSOR_THRESHOLD_MASK) >> 262062306a36Sopenharmony_ci MII_88E6393_TEMP_SENSOR_THRESHOLD_SHIFT) - 75) * 1000; 262162306a36Sopenharmony_ci 262262306a36Sopenharmony_ci return 0; 262362306a36Sopenharmony_ci} 262462306a36Sopenharmony_ci 262562306a36Sopenharmony_cistatic int m88e6393_set_temp_critical(struct phy_device *phydev, long temp) 262662306a36Sopenharmony_ci{ 262762306a36Sopenharmony_ci temp = (temp / 1000) + 75; 262862306a36Sopenharmony_ci 262962306a36Sopenharmony_ci return phy_modify_paged(phydev, MII_MARVELL_MISC_TEST_PAGE, 263062306a36Sopenharmony_ci MII_88E6390_TEMP_SENSOR, 263162306a36Sopenharmony_ci MII_88E6393_TEMP_SENSOR_THRESHOLD_MASK, 263262306a36Sopenharmony_ci temp << MII_88E6393_TEMP_SENSOR_THRESHOLD_SHIFT); 263362306a36Sopenharmony_ci} 263462306a36Sopenharmony_ci 263562306a36Sopenharmony_cistatic int m88e6393_hwmon_config(struct phy_device *phydev) 263662306a36Sopenharmony_ci{ 263762306a36Sopenharmony_ci int err; 263862306a36Sopenharmony_ci 263962306a36Sopenharmony_ci err = m88e6393_set_temp_critical(phydev, 100000); 264062306a36Sopenharmony_ci if (err) 264162306a36Sopenharmony_ci return err; 264262306a36Sopenharmony_ci 264362306a36Sopenharmony_ci return phy_modify_paged(phydev, MII_MARVELL_MISC_TEST_PAGE, 264462306a36Sopenharmony_ci MII_88E6390_MISC_TEST, 264562306a36Sopenharmony_ci MII_88E6390_MISC_TEST_TEMP_SENSOR_MASK | 264662306a36Sopenharmony_ci MII_88E6393_MISC_TEST_SAMPLES_MASK | 264762306a36Sopenharmony_ci MII_88E6393_MISC_TEST_RATE_MASK, 264862306a36Sopenharmony_ci MII_88E6390_MISC_TEST_TEMP_SENSOR_ENABLE | 264962306a36Sopenharmony_ci MII_88E6393_MISC_TEST_SAMPLES_2048 | 265062306a36Sopenharmony_ci MII_88E6393_MISC_TEST_RATE_2_3MS); 265162306a36Sopenharmony_ci} 265262306a36Sopenharmony_ci 265362306a36Sopenharmony_cistatic int marvell_hwmon_read(struct device *dev, enum hwmon_sensor_types type, 265462306a36Sopenharmony_ci u32 attr, int channel, long *temp) 265562306a36Sopenharmony_ci{ 265662306a36Sopenharmony_ci struct phy_device *phydev = dev_get_drvdata(dev); 265762306a36Sopenharmony_ci const struct marvell_hwmon_ops *ops = to_marvell_hwmon_ops(phydev); 265862306a36Sopenharmony_ci int err = -EOPNOTSUPP; 265962306a36Sopenharmony_ci 266062306a36Sopenharmony_ci switch (attr) { 266162306a36Sopenharmony_ci case hwmon_temp_input: 266262306a36Sopenharmony_ci if (ops->get_temp) 266362306a36Sopenharmony_ci err = ops->get_temp(phydev, temp); 266462306a36Sopenharmony_ci break; 266562306a36Sopenharmony_ci case hwmon_temp_crit: 266662306a36Sopenharmony_ci if (ops->get_temp_critical) 266762306a36Sopenharmony_ci err = ops->get_temp_critical(phydev, temp); 266862306a36Sopenharmony_ci break; 266962306a36Sopenharmony_ci case hwmon_temp_max_alarm: 267062306a36Sopenharmony_ci if (ops->get_temp_alarm) 267162306a36Sopenharmony_ci err = ops->get_temp_alarm(phydev, temp); 267262306a36Sopenharmony_ci break; 267362306a36Sopenharmony_ci } 267462306a36Sopenharmony_ci 267562306a36Sopenharmony_ci return err; 267662306a36Sopenharmony_ci} 267762306a36Sopenharmony_ci 267862306a36Sopenharmony_cistatic int marvell_hwmon_write(struct device *dev, enum hwmon_sensor_types type, 267962306a36Sopenharmony_ci u32 attr, int channel, long temp) 268062306a36Sopenharmony_ci{ 268162306a36Sopenharmony_ci struct phy_device *phydev = dev_get_drvdata(dev); 268262306a36Sopenharmony_ci const struct marvell_hwmon_ops *ops = to_marvell_hwmon_ops(phydev); 268362306a36Sopenharmony_ci int err = -EOPNOTSUPP; 268462306a36Sopenharmony_ci 268562306a36Sopenharmony_ci switch (attr) { 268662306a36Sopenharmony_ci case hwmon_temp_crit: 268762306a36Sopenharmony_ci if (ops->set_temp_critical) 268862306a36Sopenharmony_ci err = ops->set_temp_critical(phydev, temp); 268962306a36Sopenharmony_ci break; 269062306a36Sopenharmony_ci } 269162306a36Sopenharmony_ci 269262306a36Sopenharmony_ci return err; 269362306a36Sopenharmony_ci} 269462306a36Sopenharmony_ci 269562306a36Sopenharmony_cistatic umode_t marvell_hwmon_is_visible(const void *data, 269662306a36Sopenharmony_ci enum hwmon_sensor_types type, 269762306a36Sopenharmony_ci u32 attr, int channel) 269862306a36Sopenharmony_ci{ 269962306a36Sopenharmony_ci const struct phy_device *phydev = data; 270062306a36Sopenharmony_ci const struct marvell_hwmon_ops *ops = to_marvell_hwmon_ops(phydev); 270162306a36Sopenharmony_ci 270262306a36Sopenharmony_ci if (type != hwmon_temp) 270362306a36Sopenharmony_ci return 0; 270462306a36Sopenharmony_ci 270562306a36Sopenharmony_ci switch (attr) { 270662306a36Sopenharmony_ci case hwmon_temp_input: 270762306a36Sopenharmony_ci return ops->get_temp ? 0444 : 0; 270862306a36Sopenharmony_ci case hwmon_temp_max_alarm: 270962306a36Sopenharmony_ci return ops->get_temp_alarm ? 0444 : 0; 271062306a36Sopenharmony_ci case hwmon_temp_crit: 271162306a36Sopenharmony_ci return (ops->get_temp_critical ? 0444 : 0) | 271262306a36Sopenharmony_ci (ops->set_temp_critical ? 0200 : 0); 271362306a36Sopenharmony_ci default: 271462306a36Sopenharmony_ci return 0; 271562306a36Sopenharmony_ci } 271662306a36Sopenharmony_ci} 271762306a36Sopenharmony_ci 271862306a36Sopenharmony_cistatic u32 marvell_hwmon_chip_config[] = { 271962306a36Sopenharmony_ci HWMON_C_REGISTER_TZ, 272062306a36Sopenharmony_ci 0 272162306a36Sopenharmony_ci}; 272262306a36Sopenharmony_ci 272362306a36Sopenharmony_cistatic const struct hwmon_channel_info marvell_hwmon_chip = { 272462306a36Sopenharmony_ci .type = hwmon_chip, 272562306a36Sopenharmony_ci .config = marvell_hwmon_chip_config, 272662306a36Sopenharmony_ci}; 272762306a36Sopenharmony_ci 272862306a36Sopenharmony_ci/* we can define HWMON_T_CRIT and HWMON_T_MAX_ALARM even though these are not 272962306a36Sopenharmony_ci * defined for all PHYs, because the hwmon code checks whether the attributes 273062306a36Sopenharmony_ci * exists via the .is_visible method 273162306a36Sopenharmony_ci */ 273262306a36Sopenharmony_cistatic u32 marvell_hwmon_temp_config[] = { 273362306a36Sopenharmony_ci HWMON_T_INPUT | HWMON_T_CRIT | HWMON_T_MAX_ALARM, 273462306a36Sopenharmony_ci 0 273562306a36Sopenharmony_ci}; 273662306a36Sopenharmony_ci 273762306a36Sopenharmony_cistatic const struct hwmon_channel_info marvell_hwmon_temp = { 273862306a36Sopenharmony_ci .type = hwmon_temp, 273962306a36Sopenharmony_ci .config = marvell_hwmon_temp_config, 274062306a36Sopenharmony_ci}; 274162306a36Sopenharmony_ci 274262306a36Sopenharmony_cistatic const struct hwmon_channel_info * const marvell_hwmon_info[] = { 274362306a36Sopenharmony_ci &marvell_hwmon_chip, 274462306a36Sopenharmony_ci &marvell_hwmon_temp, 274562306a36Sopenharmony_ci NULL 274662306a36Sopenharmony_ci}; 274762306a36Sopenharmony_ci 274862306a36Sopenharmony_cistatic const struct hwmon_ops marvell_hwmon_hwmon_ops = { 274962306a36Sopenharmony_ci .is_visible = marvell_hwmon_is_visible, 275062306a36Sopenharmony_ci .read = marvell_hwmon_read, 275162306a36Sopenharmony_ci .write = marvell_hwmon_write, 275262306a36Sopenharmony_ci}; 275362306a36Sopenharmony_ci 275462306a36Sopenharmony_cistatic const struct hwmon_chip_info marvell_hwmon_chip_info = { 275562306a36Sopenharmony_ci .ops = &marvell_hwmon_hwmon_ops, 275662306a36Sopenharmony_ci .info = marvell_hwmon_info, 275762306a36Sopenharmony_ci}; 275862306a36Sopenharmony_ci 275962306a36Sopenharmony_cistatic int marvell_hwmon_name(struct phy_device *phydev) 276062306a36Sopenharmony_ci{ 276162306a36Sopenharmony_ci struct marvell_priv *priv = phydev->priv; 276262306a36Sopenharmony_ci struct device *dev = &phydev->mdio.dev; 276362306a36Sopenharmony_ci const char *devname = dev_name(dev); 276462306a36Sopenharmony_ci size_t len = strlen(devname); 276562306a36Sopenharmony_ci int i, j; 276662306a36Sopenharmony_ci 276762306a36Sopenharmony_ci priv->hwmon_name = devm_kzalloc(dev, len, GFP_KERNEL); 276862306a36Sopenharmony_ci if (!priv->hwmon_name) 276962306a36Sopenharmony_ci return -ENOMEM; 277062306a36Sopenharmony_ci 277162306a36Sopenharmony_ci for (i = j = 0; i < len && devname[i]; i++) { 277262306a36Sopenharmony_ci if (isalnum(devname[i])) 277362306a36Sopenharmony_ci priv->hwmon_name[j++] = devname[i]; 277462306a36Sopenharmony_ci } 277562306a36Sopenharmony_ci 277662306a36Sopenharmony_ci return 0; 277762306a36Sopenharmony_ci} 277862306a36Sopenharmony_ci 277962306a36Sopenharmony_cistatic int marvell_hwmon_probe(struct phy_device *phydev) 278062306a36Sopenharmony_ci{ 278162306a36Sopenharmony_ci const struct marvell_hwmon_ops *ops = to_marvell_hwmon_ops(phydev); 278262306a36Sopenharmony_ci struct marvell_priv *priv = phydev->priv; 278362306a36Sopenharmony_ci struct device *dev = &phydev->mdio.dev; 278462306a36Sopenharmony_ci int err; 278562306a36Sopenharmony_ci 278662306a36Sopenharmony_ci if (!ops) 278762306a36Sopenharmony_ci return 0; 278862306a36Sopenharmony_ci 278962306a36Sopenharmony_ci err = marvell_hwmon_name(phydev); 279062306a36Sopenharmony_ci if (err) 279162306a36Sopenharmony_ci return err; 279262306a36Sopenharmony_ci 279362306a36Sopenharmony_ci priv->hwmon_dev = devm_hwmon_device_register_with_info( 279462306a36Sopenharmony_ci dev, priv->hwmon_name, phydev, &marvell_hwmon_chip_info, NULL); 279562306a36Sopenharmony_ci if (IS_ERR(priv->hwmon_dev)) 279662306a36Sopenharmony_ci return PTR_ERR(priv->hwmon_dev); 279762306a36Sopenharmony_ci 279862306a36Sopenharmony_ci if (ops->config) 279962306a36Sopenharmony_ci err = ops->config(phydev); 280062306a36Sopenharmony_ci 280162306a36Sopenharmony_ci return err; 280262306a36Sopenharmony_ci} 280362306a36Sopenharmony_ci 280462306a36Sopenharmony_cistatic const struct marvell_hwmon_ops m88e1121_hwmon_ops = { 280562306a36Sopenharmony_ci .get_temp = m88e1121_get_temp, 280662306a36Sopenharmony_ci}; 280762306a36Sopenharmony_ci 280862306a36Sopenharmony_cistatic const struct marvell_hwmon_ops m88e1510_hwmon_ops = { 280962306a36Sopenharmony_ci .get_temp = m88e1510_get_temp, 281062306a36Sopenharmony_ci .get_temp_critical = m88e1510_get_temp_critical, 281162306a36Sopenharmony_ci .set_temp_critical = m88e1510_set_temp_critical, 281262306a36Sopenharmony_ci .get_temp_alarm = m88e1510_get_temp_alarm, 281362306a36Sopenharmony_ci}; 281462306a36Sopenharmony_ci 281562306a36Sopenharmony_cistatic const struct marvell_hwmon_ops m88e6390_hwmon_ops = { 281662306a36Sopenharmony_ci .get_temp = m88e6390_get_temp, 281762306a36Sopenharmony_ci}; 281862306a36Sopenharmony_ci 281962306a36Sopenharmony_cistatic const struct marvell_hwmon_ops m88e6393_hwmon_ops = { 282062306a36Sopenharmony_ci .config = m88e6393_hwmon_config, 282162306a36Sopenharmony_ci .get_temp = m88e6393_get_temp, 282262306a36Sopenharmony_ci .get_temp_critical = m88e6393_get_temp_critical, 282362306a36Sopenharmony_ci .set_temp_critical = m88e6393_set_temp_critical, 282462306a36Sopenharmony_ci .get_temp_alarm = m88e1510_get_temp_alarm, 282562306a36Sopenharmony_ci}; 282662306a36Sopenharmony_ci 282762306a36Sopenharmony_ci#define DEF_MARVELL_HWMON_OPS(s) (&(s)) 282862306a36Sopenharmony_ci 282962306a36Sopenharmony_ci#else 283062306a36Sopenharmony_ci 283162306a36Sopenharmony_ci#define DEF_MARVELL_HWMON_OPS(s) NULL 283262306a36Sopenharmony_ci 283362306a36Sopenharmony_cistatic int marvell_hwmon_probe(struct phy_device *phydev) 283462306a36Sopenharmony_ci{ 283562306a36Sopenharmony_ci return 0; 283662306a36Sopenharmony_ci} 283762306a36Sopenharmony_ci#endif 283862306a36Sopenharmony_ci 283962306a36Sopenharmony_cistatic int m88e1318_led_brightness_set(struct phy_device *phydev, 284062306a36Sopenharmony_ci u8 index, enum led_brightness value) 284162306a36Sopenharmony_ci{ 284262306a36Sopenharmony_ci int reg; 284362306a36Sopenharmony_ci 284462306a36Sopenharmony_ci reg = phy_read_paged(phydev, MII_MARVELL_LED_PAGE, 284562306a36Sopenharmony_ci MII_88E1318S_PHY_LED_FUNC); 284662306a36Sopenharmony_ci if (reg < 0) 284762306a36Sopenharmony_ci return reg; 284862306a36Sopenharmony_ci 284962306a36Sopenharmony_ci switch (index) { 285062306a36Sopenharmony_ci case 0: 285162306a36Sopenharmony_ci case 1: 285262306a36Sopenharmony_ci case 2: 285362306a36Sopenharmony_ci reg &= ~(0xf << (4 * index)); 285462306a36Sopenharmony_ci if (value == LED_OFF) 285562306a36Sopenharmony_ci reg |= MII_88E1318S_PHY_LED_FUNC_OFF << (4 * index); 285662306a36Sopenharmony_ci else 285762306a36Sopenharmony_ci reg |= MII_88E1318S_PHY_LED_FUNC_ON << (4 * index); 285862306a36Sopenharmony_ci break; 285962306a36Sopenharmony_ci default: 286062306a36Sopenharmony_ci return -EINVAL; 286162306a36Sopenharmony_ci } 286262306a36Sopenharmony_ci 286362306a36Sopenharmony_ci return phy_write_paged(phydev, MII_MARVELL_LED_PAGE, 286462306a36Sopenharmony_ci MII_88E1318S_PHY_LED_FUNC, reg); 286562306a36Sopenharmony_ci} 286662306a36Sopenharmony_ci 286762306a36Sopenharmony_cistatic int m88e1318_led_blink_set(struct phy_device *phydev, u8 index, 286862306a36Sopenharmony_ci unsigned long *delay_on, 286962306a36Sopenharmony_ci unsigned long *delay_off) 287062306a36Sopenharmony_ci{ 287162306a36Sopenharmony_ci int reg; 287262306a36Sopenharmony_ci 287362306a36Sopenharmony_ci reg = phy_read_paged(phydev, MII_MARVELL_LED_PAGE, 287462306a36Sopenharmony_ci MII_88E1318S_PHY_LED_FUNC); 287562306a36Sopenharmony_ci if (reg < 0) 287662306a36Sopenharmony_ci return reg; 287762306a36Sopenharmony_ci 287862306a36Sopenharmony_ci switch (index) { 287962306a36Sopenharmony_ci case 0: 288062306a36Sopenharmony_ci case 1: 288162306a36Sopenharmony_ci case 2: 288262306a36Sopenharmony_ci reg &= ~(0xf << (4 * index)); 288362306a36Sopenharmony_ci reg |= MII_88E1318S_PHY_LED_FUNC_BLINK << (4 * index); 288462306a36Sopenharmony_ci /* Reset default is 84ms */ 288562306a36Sopenharmony_ci *delay_on = 84 / 2; 288662306a36Sopenharmony_ci *delay_off = 84 / 2; 288762306a36Sopenharmony_ci break; 288862306a36Sopenharmony_ci default: 288962306a36Sopenharmony_ci return -EINVAL; 289062306a36Sopenharmony_ci } 289162306a36Sopenharmony_ci 289262306a36Sopenharmony_ci return phy_write_paged(phydev, MII_MARVELL_LED_PAGE, 289362306a36Sopenharmony_ci MII_88E1318S_PHY_LED_FUNC, reg); 289462306a36Sopenharmony_ci} 289562306a36Sopenharmony_ci 289662306a36Sopenharmony_cistruct marvell_led_rules { 289762306a36Sopenharmony_ci int mode; 289862306a36Sopenharmony_ci unsigned long rules; 289962306a36Sopenharmony_ci}; 290062306a36Sopenharmony_ci 290162306a36Sopenharmony_cistatic const struct marvell_led_rules marvell_led0[] = { 290262306a36Sopenharmony_ci { 290362306a36Sopenharmony_ci .mode = 0, 290462306a36Sopenharmony_ci .rules = BIT(TRIGGER_NETDEV_LINK), 290562306a36Sopenharmony_ci }, 290662306a36Sopenharmony_ci { 290762306a36Sopenharmony_ci .mode = 1, 290862306a36Sopenharmony_ci .rules = (BIT(TRIGGER_NETDEV_LINK) | 290962306a36Sopenharmony_ci BIT(TRIGGER_NETDEV_RX) | 291062306a36Sopenharmony_ci BIT(TRIGGER_NETDEV_TX)), 291162306a36Sopenharmony_ci }, 291262306a36Sopenharmony_ci { 291362306a36Sopenharmony_ci .mode = 3, 291462306a36Sopenharmony_ci .rules = (BIT(TRIGGER_NETDEV_RX) | 291562306a36Sopenharmony_ci BIT(TRIGGER_NETDEV_TX)), 291662306a36Sopenharmony_ci }, 291762306a36Sopenharmony_ci { 291862306a36Sopenharmony_ci .mode = 4, 291962306a36Sopenharmony_ci .rules = (BIT(TRIGGER_NETDEV_RX) | 292062306a36Sopenharmony_ci BIT(TRIGGER_NETDEV_TX)), 292162306a36Sopenharmony_ci }, 292262306a36Sopenharmony_ci { 292362306a36Sopenharmony_ci .mode = 5, 292462306a36Sopenharmony_ci .rules = BIT(TRIGGER_NETDEV_TX), 292562306a36Sopenharmony_ci }, 292662306a36Sopenharmony_ci { 292762306a36Sopenharmony_ci .mode = 6, 292862306a36Sopenharmony_ci .rules = BIT(TRIGGER_NETDEV_LINK), 292962306a36Sopenharmony_ci }, 293062306a36Sopenharmony_ci { 293162306a36Sopenharmony_ci .mode = 7, 293262306a36Sopenharmony_ci .rules = BIT(TRIGGER_NETDEV_LINK_1000), 293362306a36Sopenharmony_ci }, 293462306a36Sopenharmony_ci { 293562306a36Sopenharmony_ci .mode = 8, 293662306a36Sopenharmony_ci .rules = 0, 293762306a36Sopenharmony_ci }, 293862306a36Sopenharmony_ci}; 293962306a36Sopenharmony_ci 294062306a36Sopenharmony_cistatic const struct marvell_led_rules marvell_led1[] = { 294162306a36Sopenharmony_ci { 294262306a36Sopenharmony_ci .mode = 1, 294362306a36Sopenharmony_ci .rules = (BIT(TRIGGER_NETDEV_LINK) | 294462306a36Sopenharmony_ci BIT(TRIGGER_NETDEV_RX) | 294562306a36Sopenharmony_ci BIT(TRIGGER_NETDEV_TX)), 294662306a36Sopenharmony_ci }, 294762306a36Sopenharmony_ci { 294862306a36Sopenharmony_ci .mode = 2, 294962306a36Sopenharmony_ci .rules = (BIT(TRIGGER_NETDEV_LINK) | 295062306a36Sopenharmony_ci BIT(TRIGGER_NETDEV_RX)), 295162306a36Sopenharmony_ci }, 295262306a36Sopenharmony_ci { 295362306a36Sopenharmony_ci .mode = 3, 295462306a36Sopenharmony_ci .rules = (BIT(TRIGGER_NETDEV_RX) | 295562306a36Sopenharmony_ci BIT(TRIGGER_NETDEV_TX)), 295662306a36Sopenharmony_ci }, 295762306a36Sopenharmony_ci { 295862306a36Sopenharmony_ci .mode = 4, 295962306a36Sopenharmony_ci .rules = (BIT(TRIGGER_NETDEV_RX) | 296062306a36Sopenharmony_ci BIT(TRIGGER_NETDEV_TX)), 296162306a36Sopenharmony_ci }, 296262306a36Sopenharmony_ci { 296362306a36Sopenharmony_ci .mode = 6, 296462306a36Sopenharmony_ci .rules = (BIT(TRIGGER_NETDEV_LINK_100) | 296562306a36Sopenharmony_ci BIT(TRIGGER_NETDEV_LINK_1000)), 296662306a36Sopenharmony_ci }, 296762306a36Sopenharmony_ci { 296862306a36Sopenharmony_ci .mode = 7, 296962306a36Sopenharmony_ci .rules = BIT(TRIGGER_NETDEV_LINK_100), 297062306a36Sopenharmony_ci }, 297162306a36Sopenharmony_ci { 297262306a36Sopenharmony_ci .mode = 8, 297362306a36Sopenharmony_ci .rules = 0, 297462306a36Sopenharmony_ci }, 297562306a36Sopenharmony_ci}; 297662306a36Sopenharmony_ci 297762306a36Sopenharmony_cistatic const struct marvell_led_rules marvell_led2[] = { 297862306a36Sopenharmony_ci { 297962306a36Sopenharmony_ci .mode = 0, 298062306a36Sopenharmony_ci .rules = BIT(TRIGGER_NETDEV_LINK), 298162306a36Sopenharmony_ci }, 298262306a36Sopenharmony_ci { 298362306a36Sopenharmony_ci .mode = 1, 298462306a36Sopenharmony_ci .rules = (BIT(TRIGGER_NETDEV_LINK) | 298562306a36Sopenharmony_ci BIT(TRIGGER_NETDEV_RX) | 298662306a36Sopenharmony_ci BIT(TRIGGER_NETDEV_TX)), 298762306a36Sopenharmony_ci }, 298862306a36Sopenharmony_ci { 298962306a36Sopenharmony_ci .mode = 3, 299062306a36Sopenharmony_ci .rules = (BIT(TRIGGER_NETDEV_RX) | 299162306a36Sopenharmony_ci BIT(TRIGGER_NETDEV_TX)), 299262306a36Sopenharmony_ci }, 299362306a36Sopenharmony_ci { 299462306a36Sopenharmony_ci .mode = 4, 299562306a36Sopenharmony_ci .rules = (BIT(TRIGGER_NETDEV_RX) | 299662306a36Sopenharmony_ci BIT(TRIGGER_NETDEV_TX)), 299762306a36Sopenharmony_ci }, 299862306a36Sopenharmony_ci { 299962306a36Sopenharmony_ci .mode = 5, 300062306a36Sopenharmony_ci .rules = BIT(TRIGGER_NETDEV_TX), 300162306a36Sopenharmony_ci }, 300262306a36Sopenharmony_ci { 300362306a36Sopenharmony_ci .mode = 6, 300462306a36Sopenharmony_ci .rules = (BIT(TRIGGER_NETDEV_LINK_10) | 300562306a36Sopenharmony_ci BIT(TRIGGER_NETDEV_LINK_1000)), 300662306a36Sopenharmony_ci }, 300762306a36Sopenharmony_ci { 300862306a36Sopenharmony_ci .mode = 7, 300962306a36Sopenharmony_ci .rules = BIT(TRIGGER_NETDEV_LINK_10), 301062306a36Sopenharmony_ci }, 301162306a36Sopenharmony_ci { 301262306a36Sopenharmony_ci .mode = 8, 301362306a36Sopenharmony_ci .rules = 0, 301462306a36Sopenharmony_ci }, 301562306a36Sopenharmony_ci}; 301662306a36Sopenharmony_ci 301762306a36Sopenharmony_cistatic int marvell_find_led_mode(unsigned long rules, 301862306a36Sopenharmony_ci const struct marvell_led_rules *marvell_rules, 301962306a36Sopenharmony_ci int count, 302062306a36Sopenharmony_ci int *mode) 302162306a36Sopenharmony_ci{ 302262306a36Sopenharmony_ci int i; 302362306a36Sopenharmony_ci 302462306a36Sopenharmony_ci for (i = 0; i < count; i++) { 302562306a36Sopenharmony_ci if (marvell_rules[i].rules == rules) { 302662306a36Sopenharmony_ci *mode = marvell_rules[i].mode; 302762306a36Sopenharmony_ci return 0; 302862306a36Sopenharmony_ci } 302962306a36Sopenharmony_ci } 303062306a36Sopenharmony_ci return -EOPNOTSUPP; 303162306a36Sopenharmony_ci} 303262306a36Sopenharmony_ci 303362306a36Sopenharmony_cistatic int marvell_get_led_mode(u8 index, unsigned long rules, int *mode) 303462306a36Sopenharmony_ci{ 303562306a36Sopenharmony_ci int ret; 303662306a36Sopenharmony_ci 303762306a36Sopenharmony_ci switch (index) { 303862306a36Sopenharmony_ci case 0: 303962306a36Sopenharmony_ci ret = marvell_find_led_mode(rules, marvell_led0, 304062306a36Sopenharmony_ci ARRAY_SIZE(marvell_led0), mode); 304162306a36Sopenharmony_ci break; 304262306a36Sopenharmony_ci case 1: 304362306a36Sopenharmony_ci ret = marvell_find_led_mode(rules, marvell_led1, 304462306a36Sopenharmony_ci ARRAY_SIZE(marvell_led1), mode); 304562306a36Sopenharmony_ci break; 304662306a36Sopenharmony_ci case 2: 304762306a36Sopenharmony_ci ret = marvell_find_led_mode(rules, marvell_led2, 304862306a36Sopenharmony_ci ARRAY_SIZE(marvell_led2), mode); 304962306a36Sopenharmony_ci break; 305062306a36Sopenharmony_ci default: 305162306a36Sopenharmony_ci ret = -EINVAL; 305262306a36Sopenharmony_ci } 305362306a36Sopenharmony_ci 305462306a36Sopenharmony_ci return ret; 305562306a36Sopenharmony_ci} 305662306a36Sopenharmony_ci 305762306a36Sopenharmony_cistatic int marvell_find_led_rules(unsigned long *rules, 305862306a36Sopenharmony_ci const struct marvell_led_rules *marvell_rules, 305962306a36Sopenharmony_ci int count, 306062306a36Sopenharmony_ci int mode) 306162306a36Sopenharmony_ci{ 306262306a36Sopenharmony_ci int i; 306362306a36Sopenharmony_ci 306462306a36Sopenharmony_ci for (i = 0; i < count; i++) { 306562306a36Sopenharmony_ci if (marvell_rules[i].mode == mode) { 306662306a36Sopenharmony_ci *rules = marvell_rules[i].rules; 306762306a36Sopenharmony_ci return 0; 306862306a36Sopenharmony_ci } 306962306a36Sopenharmony_ci } 307062306a36Sopenharmony_ci return -EOPNOTSUPP; 307162306a36Sopenharmony_ci} 307262306a36Sopenharmony_ci 307362306a36Sopenharmony_cistatic int marvell_get_led_rules(u8 index, unsigned long *rules, int mode) 307462306a36Sopenharmony_ci{ 307562306a36Sopenharmony_ci int ret; 307662306a36Sopenharmony_ci 307762306a36Sopenharmony_ci switch (index) { 307862306a36Sopenharmony_ci case 0: 307962306a36Sopenharmony_ci ret = marvell_find_led_rules(rules, marvell_led0, 308062306a36Sopenharmony_ci ARRAY_SIZE(marvell_led0), mode); 308162306a36Sopenharmony_ci break; 308262306a36Sopenharmony_ci case 1: 308362306a36Sopenharmony_ci ret = marvell_find_led_rules(rules, marvell_led1, 308462306a36Sopenharmony_ci ARRAY_SIZE(marvell_led1), mode); 308562306a36Sopenharmony_ci break; 308662306a36Sopenharmony_ci case 2: 308762306a36Sopenharmony_ci ret = marvell_find_led_rules(rules, marvell_led2, 308862306a36Sopenharmony_ci ARRAY_SIZE(marvell_led2), mode); 308962306a36Sopenharmony_ci break; 309062306a36Sopenharmony_ci default: 309162306a36Sopenharmony_ci ret = -EOPNOTSUPP; 309262306a36Sopenharmony_ci } 309362306a36Sopenharmony_ci 309462306a36Sopenharmony_ci return ret; 309562306a36Sopenharmony_ci} 309662306a36Sopenharmony_ci 309762306a36Sopenharmony_cistatic int m88e1318_led_hw_is_supported(struct phy_device *phydev, u8 index, 309862306a36Sopenharmony_ci unsigned long rules) 309962306a36Sopenharmony_ci{ 310062306a36Sopenharmony_ci int mode, ret; 310162306a36Sopenharmony_ci 310262306a36Sopenharmony_ci switch (index) { 310362306a36Sopenharmony_ci case 0: 310462306a36Sopenharmony_ci case 1: 310562306a36Sopenharmony_ci case 2: 310662306a36Sopenharmony_ci ret = marvell_get_led_mode(index, rules, &mode); 310762306a36Sopenharmony_ci break; 310862306a36Sopenharmony_ci default: 310962306a36Sopenharmony_ci ret = -EINVAL; 311062306a36Sopenharmony_ci } 311162306a36Sopenharmony_ci 311262306a36Sopenharmony_ci return ret; 311362306a36Sopenharmony_ci} 311462306a36Sopenharmony_ci 311562306a36Sopenharmony_cistatic int m88e1318_led_hw_control_set(struct phy_device *phydev, u8 index, 311662306a36Sopenharmony_ci unsigned long rules) 311762306a36Sopenharmony_ci{ 311862306a36Sopenharmony_ci int mode, ret, reg; 311962306a36Sopenharmony_ci 312062306a36Sopenharmony_ci switch (index) { 312162306a36Sopenharmony_ci case 0: 312262306a36Sopenharmony_ci case 1: 312362306a36Sopenharmony_ci case 2: 312462306a36Sopenharmony_ci ret = marvell_get_led_mode(index, rules, &mode); 312562306a36Sopenharmony_ci break; 312662306a36Sopenharmony_ci default: 312762306a36Sopenharmony_ci ret = -EINVAL; 312862306a36Sopenharmony_ci } 312962306a36Sopenharmony_ci 313062306a36Sopenharmony_ci if (ret < 0) 313162306a36Sopenharmony_ci return ret; 313262306a36Sopenharmony_ci 313362306a36Sopenharmony_ci reg = phy_read_paged(phydev, MII_MARVELL_LED_PAGE, 313462306a36Sopenharmony_ci MII_88E1318S_PHY_LED_FUNC); 313562306a36Sopenharmony_ci if (reg < 0) 313662306a36Sopenharmony_ci return reg; 313762306a36Sopenharmony_ci 313862306a36Sopenharmony_ci reg &= ~(0xf << (4 * index)); 313962306a36Sopenharmony_ci reg |= mode << (4 * index); 314062306a36Sopenharmony_ci return phy_write_paged(phydev, MII_MARVELL_LED_PAGE, 314162306a36Sopenharmony_ci MII_88E1318S_PHY_LED_FUNC, reg); 314262306a36Sopenharmony_ci} 314362306a36Sopenharmony_ci 314462306a36Sopenharmony_cistatic int m88e1318_led_hw_control_get(struct phy_device *phydev, u8 index, 314562306a36Sopenharmony_ci unsigned long *rules) 314662306a36Sopenharmony_ci{ 314762306a36Sopenharmony_ci int mode, reg; 314862306a36Sopenharmony_ci 314962306a36Sopenharmony_ci if (index > 2) 315062306a36Sopenharmony_ci return -EINVAL; 315162306a36Sopenharmony_ci 315262306a36Sopenharmony_ci reg = phy_read_paged(phydev, MII_MARVELL_LED_PAGE, 315362306a36Sopenharmony_ci MII_88E1318S_PHY_LED_FUNC); 315462306a36Sopenharmony_ci if (reg < 0) 315562306a36Sopenharmony_ci return reg; 315662306a36Sopenharmony_ci 315762306a36Sopenharmony_ci mode = (reg >> (4 * index)) & 0xf; 315862306a36Sopenharmony_ci 315962306a36Sopenharmony_ci return marvell_get_led_rules(index, rules, mode); 316062306a36Sopenharmony_ci} 316162306a36Sopenharmony_ci 316262306a36Sopenharmony_cistatic int marvell_probe(struct phy_device *phydev) 316362306a36Sopenharmony_ci{ 316462306a36Sopenharmony_ci struct marvell_priv *priv; 316562306a36Sopenharmony_ci 316662306a36Sopenharmony_ci priv = devm_kzalloc(&phydev->mdio.dev, sizeof(*priv), GFP_KERNEL); 316762306a36Sopenharmony_ci if (!priv) 316862306a36Sopenharmony_ci return -ENOMEM; 316962306a36Sopenharmony_ci 317062306a36Sopenharmony_ci phydev->priv = priv; 317162306a36Sopenharmony_ci 317262306a36Sopenharmony_ci return marvell_hwmon_probe(phydev); 317362306a36Sopenharmony_ci} 317462306a36Sopenharmony_ci 317562306a36Sopenharmony_cistatic int m88e1510_sfp_insert(void *upstream, const struct sfp_eeprom_id *id) 317662306a36Sopenharmony_ci{ 317762306a36Sopenharmony_ci DECLARE_PHY_INTERFACE_MASK(interfaces); 317862306a36Sopenharmony_ci struct phy_device *phydev = upstream; 317962306a36Sopenharmony_ci phy_interface_t interface; 318062306a36Sopenharmony_ci struct device *dev; 318162306a36Sopenharmony_ci int oldpage; 318262306a36Sopenharmony_ci int ret = 0; 318362306a36Sopenharmony_ci u16 mode; 318462306a36Sopenharmony_ci 318562306a36Sopenharmony_ci __ETHTOOL_DECLARE_LINK_MODE_MASK(supported) = { 0, }; 318662306a36Sopenharmony_ci 318762306a36Sopenharmony_ci dev = &phydev->mdio.dev; 318862306a36Sopenharmony_ci 318962306a36Sopenharmony_ci sfp_parse_support(phydev->sfp_bus, id, supported, interfaces); 319062306a36Sopenharmony_ci interface = sfp_select_interface(phydev->sfp_bus, supported); 319162306a36Sopenharmony_ci 319262306a36Sopenharmony_ci dev_info(dev, "%s SFP module inserted\n", phy_modes(interface)); 319362306a36Sopenharmony_ci 319462306a36Sopenharmony_ci switch (interface) { 319562306a36Sopenharmony_ci case PHY_INTERFACE_MODE_1000BASEX: 319662306a36Sopenharmony_ci mode = MII_88E1510_GEN_CTRL_REG_1_MODE_RGMII_1000X; 319762306a36Sopenharmony_ci 319862306a36Sopenharmony_ci break; 319962306a36Sopenharmony_ci case PHY_INTERFACE_MODE_100BASEX: 320062306a36Sopenharmony_ci mode = MII_88E1510_GEN_CTRL_REG_1_MODE_RGMII_100FX; 320162306a36Sopenharmony_ci 320262306a36Sopenharmony_ci break; 320362306a36Sopenharmony_ci case PHY_INTERFACE_MODE_SGMII: 320462306a36Sopenharmony_ci mode = MII_88E1510_GEN_CTRL_REG_1_MODE_RGMII_SGMII; 320562306a36Sopenharmony_ci 320662306a36Sopenharmony_ci break; 320762306a36Sopenharmony_ci default: 320862306a36Sopenharmony_ci dev_err(dev, "Incompatible SFP module inserted\n"); 320962306a36Sopenharmony_ci 321062306a36Sopenharmony_ci return -EINVAL; 321162306a36Sopenharmony_ci } 321262306a36Sopenharmony_ci 321362306a36Sopenharmony_ci oldpage = phy_select_page(phydev, MII_MARVELL_MODE_PAGE); 321462306a36Sopenharmony_ci if (oldpage < 0) 321562306a36Sopenharmony_ci goto error; 321662306a36Sopenharmony_ci 321762306a36Sopenharmony_ci ret = __phy_modify(phydev, MII_88E1510_GEN_CTRL_REG_1, 321862306a36Sopenharmony_ci MII_88E1510_GEN_CTRL_REG_1_MODE_MASK, mode); 321962306a36Sopenharmony_ci if (ret < 0) 322062306a36Sopenharmony_ci goto error; 322162306a36Sopenharmony_ci 322262306a36Sopenharmony_ci ret = __phy_set_bits(phydev, MII_88E1510_GEN_CTRL_REG_1, 322362306a36Sopenharmony_ci MII_88E1510_GEN_CTRL_REG_1_RESET); 322462306a36Sopenharmony_ci 322562306a36Sopenharmony_cierror: 322662306a36Sopenharmony_ci return phy_restore_page(phydev, oldpage, ret); 322762306a36Sopenharmony_ci} 322862306a36Sopenharmony_ci 322962306a36Sopenharmony_cistatic void m88e1510_sfp_remove(void *upstream) 323062306a36Sopenharmony_ci{ 323162306a36Sopenharmony_ci struct phy_device *phydev = upstream; 323262306a36Sopenharmony_ci int oldpage; 323362306a36Sopenharmony_ci int ret = 0; 323462306a36Sopenharmony_ci 323562306a36Sopenharmony_ci oldpage = phy_select_page(phydev, MII_MARVELL_MODE_PAGE); 323662306a36Sopenharmony_ci if (oldpage < 0) 323762306a36Sopenharmony_ci goto error; 323862306a36Sopenharmony_ci 323962306a36Sopenharmony_ci ret = __phy_modify(phydev, MII_88E1510_GEN_CTRL_REG_1, 324062306a36Sopenharmony_ci MII_88E1510_GEN_CTRL_REG_1_MODE_MASK, 324162306a36Sopenharmony_ci MII_88E1510_GEN_CTRL_REG_1_MODE_RGMII); 324262306a36Sopenharmony_ci if (ret < 0) 324362306a36Sopenharmony_ci goto error; 324462306a36Sopenharmony_ci 324562306a36Sopenharmony_ci ret = __phy_set_bits(phydev, MII_88E1510_GEN_CTRL_REG_1, 324662306a36Sopenharmony_ci MII_88E1510_GEN_CTRL_REG_1_RESET); 324762306a36Sopenharmony_ci 324862306a36Sopenharmony_cierror: 324962306a36Sopenharmony_ci phy_restore_page(phydev, oldpage, ret); 325062306a36Sopenharmony_ci} 325162306a36Sopenharmony_ci 325262306a36Sopenharmony_cistatic const struct sfp_upstream_ops m88e1510_sfp_ops = { 325362306a36Sopenharmony_ci .module_insert = m88e1510_sfp_insert, 325462306a36Sopenharmony_ci .module_remove = m88e1510_sfp_remove, 325562306a36Sopenharmony_ci .attach = phy_sfp_attach, 325662306a36Sopenharmony_ci .detach = phy_sfp_detach, 325762306a36Sopenharmony_ci}; 325862306a36Sopenharmony_ci 325962306a36Sopenharmony_cistatic int m88e1510_probe(struct phy_device *phydev) 326062306a36Sopenharmony_ci{ 326162306a36Sopenharmony_ci int err; 326262306a36Sopenharmony_ci 326362306a36Sopenharmony_ci err = marvell_probe(phydev); 326462306a36Sopenharmony_ci if (err) 326562306a36Sopenharmony_ci return err; 326662306a36Sopenharmony_ci 326762306a36Sopenharmony_ci return phy_sfp_probe(phydev, &m88e1510_sfp_ops); 326862306a36Sopenharmony_ci} 326962306a36Sopenharmony_ci 327062306a36Sopenharmony_cistatic struct phy_driver marvell_drivers[] = { 327162306a36Sopenharmony_ci { 327262306a36Sopenharmony_ci .phy_id = MARVELL_PHY_ID_88E1101, 327362306a36Sopenharmony_ci .phy_id_mask = MARVELL_PHY_ID_MASK, 327462306a36Sopenharmony_ci .name = "Marvell 88E1101", 327562306a36Sopenharmony_ci /* PHY_GBIT_FEATURES */ 327662306a36Sopenharmony_ci .probe = marvell_probe, 327762306a36Sopenharmony_ci .config_init = marvell_config_init, 327862306a36Sopenharmony_ci .config_aneg = m88e1101_config_aneg, 327962306a36Sopenharmony_ci .config_intr = marvell_config_intr, 328062306a36Sopenharmony_ci .handle_interrupt = marvell_handle_interrupt, 328162306a36Sopenharmony_ci .resume = genphy_resume, 328262306a36Sopenharmony_ci .suspend = genphy_suspend, 328362306a36Sopenharmony_ci .read_page = marvell_read_page, 328462306a36Sopenharmony_ci .write_page = marvell_write_page, 328562306a36Sopenharmony_ci .get_sset_count = marvell_get_sset_count, 328662306a36Sopenharmony_ci .get_strings = marvell_get_strings, 328762306a36Sopenharmony_ci .get_stats = marvell_get_stats, 328862306a36Sopenharmony_ci }, 328962306a36Sopenharmony_ci { 329062306a36Sopenharmony_ci .phy_id = MARVELL_PHY_ID_88E1112, 329162306a36Sopenharmony_ci .phy_id_mask = MARVELL_PHY_ID_MASK, 329262306a36Sopenharmony_ci .name = "Marvell 88E1112", 329362306a36Sopenharmony_ci /* PHY_GBIT_FEATURES */ 329462306a36Sopenharmony_ci .probe = marvell_probe, 329562306a36Sopenharmony_ci .config_init = m88e1112_config_init, 329662306a36Sopenharmony_ci .config_aneg = marvell_config_aneg, 329762306a36Sopenharmony_ci .config_intr = marvell_config_intr, 329862306a36Sopenharmony_ci .handle_interrupt = marvell_handle_interrupt, 329962306a36Sopenharmony_ci .resume = genphy_resume, 330062306a36Sopenharmony_ci .suspend = genphy_suspend, 330162306a36Sopenharmony_ci .read_page = marvell_read_page, 330262306a36Sopenharmony_ci .write_page = marvell_write_page, 330362306a36Sopenharmony_ci .get_sset_count = marvell_get_sset_count, 330462306a36Sopenharmony_ci .get_strings = marvell_get_strings, 330562306a36Sopenharmony_ci .get_stats = marvell_get_stats, 330662306a36Sopenharmony_ci .get_tunable = m88e1011_get_tunable, 330762306a36Sopenharmony_ci .set_tunable = m88e1011_set_tunable, 330862306a36Sopenharmony_ci }, 330962306a36Sopenharmony_ci { 331062306a36Sopenharmony_ci .phy_id = MARVELL_PHY_ID_88E1111, 331162306a36Sopenharmony_ci .phy_id_mask = MARVELL_PHY_ID_MASK, 331262306a36Sopenharmony_ci .name = "Marvell 88E1111", 331362306a36Sopenharmony_ci /* PHY_GBIT_FEATURES */ 331462306a36Sopenharmony_ci .probe = marvell_probe, 331562306a36Sopenharmony_ci .config_init = m88e1111gbe_config_init, 331662306a36Sopenharmony_ci .config_aneg = m88e1111_config_aneg, 331762306a36Sopenharmony_ci .read_status = marvell_read_status, 331862306a36Sopenharmony_ci .config_intr = marvell_config_intr, 331962306a36Sopenharmony_ci .handle_interrupt = marvell_handle_interrupt, 332062306a36Sopenharmony_ci .resume = genphy_resume, 332162306a36Sopenharmony_ci .suspend = genphy_suspend, 332262306a36Sopenharmony_ci .read_page = marvell_read_page, 332362306a36Sopenharmony_ci .write_page = marvell_write_page, 332462306a36Sopenharmony_ci .get_sset_count = marvell_get_sset_count, 332562306a36Sopenharmony_ci .get_strings = marvell_get_strings, 332662306a36Sopenharmony_ci .get_stats = marvell_get_stats, 332762306a36Sopenharmony_ci .get_tunable = m88e1111_get_tunable, 332862306a36Sopenharmony_ci .set_tunable = m88e1111_set_tunable, 332962306a36Sopenharmony_ci }, 333062306a36Sopenharmony_ci { 333162306a36Sopenharmony_ci .phy_id = MARVELL_PHY_ID_88E1111_FINISAR, 333262306a36Sopenharmony_ci .phy_id_mask = MARVELL_PHY_ID_MASK, 333362306a36Sopenharmony_ci .name = "Marvell 88E1111 (Finisar)", 333462306a36Sopenharmony_ci /* PHY_GBIT_FEATURES */ 333562306a36Sopenharmony_ci .probe = marvell_probe, 333662306a36Sopenharmony_ci .config_init = m88e1111gbe_config_init, 333762306a36Sopenharmony_ci .config_aneg = m88e1111_config_aneg, 333862306a36Sopenharmony_ci .read_status = marvell_read_status, 333962306a36Sopenharmony_ci .config_intr = marvell_config_intr, 334062306a36Sopenharmony_ci .handle_interrupt = marvell_handle_interrupt, 334162306a36Sopenharmony_ci .resume = genphy_resume, 334262306a36Sopenharmony_ci .suspend = genphy_suspend, 334362306a36Sopenharmony_ci .read_page = marvell_read_page, 334462306a36Sopenharmony_ci .write_page = marvell_write_page, 334562306a36Sopenharmony_ci .get_sset_count = marvell_get_sset_count, 334662306a36Sopenharmony_ci .get_strings = marvell_get_strings, 334762306a36Sopenharmony_ci .get_stats = marvell_get_stats, 334862306a36Sopenharmony_ci .get_tunable = m88e1111_get_tunable, 334962306a36Sopenharmony_ci .set_tunable = m88e1111_set_tunable, 335062306a36Sopenharmony_ci }, 335162306a36Sopenharmony_ci { 335262306a36Sopenharmony_ci .phy_id = MARVELL_PHY_ID_88E1118, 335362306a36Sopenharmony_ci .phy_id_mask = MARVELL_PHY_ID_MASK, 335462306a36Sopenharmony_ci .name = "Marvell 88E1118", 335562306a36Sopenharmony_ci /* PHY_GBIT_FEATURES */ 335662306a36Sopenharmony_ci .probe = marvell_probe, 335762306a36Sopenharmony_ci .config_init = m88e1118_config_init, 335862306a36Sopenharmony_ci .config_aneg = m88e1118_config_aneg, 335962306a36Sopenharmony_ci .config_intr = marvell_config_intr, 336062306a36Sopenharmony_ci .handle_interrupt = marvell_handle_interrupt, 336162306a36Sopenharmony_ci .resume = genphy_resume, 336262306a36Sopenharmony_ci .suspend = genphy_suspend, 336362306a36Sopenharmony_ci .read_page = marvell_read_page, 336462306a36Sopenharmony_ci .write_page = marvell_write_page, 336562306a36Sopenharmony_ci .get_sset_count = marvell_get_sset_count, 336662306a36Sopenharmony_ci .get_strings = marvell_get_strings, 336762306a36Sopenharmony_ci .get_stats = marvell_get_stats, 336862306a36Sopenharmony_ci }, 336962306a36Sopenharmony_ci { 337062306a36Sopenharmony_ci .phy_id = MARVELL_PHY_ID_88E1121R, 337162306a36Sopenharmony_ci .phy_id_mask = MARVELL_PHY_ID_MASK, 337262306a36Sopenharmony_ci .name = "Marvell 88E1121R", 337362306a36Sopenharmony_ci .driver_data = DEF_MARVELL_HWMON_OPS(m88e1121_hwmon_ops), 337462306a36Sopenharmony_ci /* PHY_GBIT_FEATURES */ 337562306a36Sopenharmony_ci .probe = marvell_probe, 337662306a36Sopenharmony_ci .config_init = marvell_1011gbe_config_init, 337762306a36Sopenharmony_ci .config_aneg = m88e1121_config_aneg, 337862306a36Sopenharmony_ci .read_status = marvell_read_status, 337962306a36Sopenharmony_ci .config_intr = marvell_config_intr, 338062306a36Sopenharmony_ci .handle_interrupt = marvell_handle_interrupt, 338162306a36Sopenharmony_ci .resume = genphy_resume, 338262306a36Sopenharmony_ci .suspend = genphy_suspend, 338362306a36Sopenharmony_ci .read_page = marvell_read_page, 338462306a36Sopenharmony_ci .write_page = marvell_write_page, 338562306a36Sopenharmony_ci .get_sset_count = marvell_get_sset_count, 338662306a36Sopenharmony_ci .get_strings = marvell_get_strings, 338762306a36Sopenharmony_ci .get_stats = marvell_get_stats, 338862306a36Sopenharmony_ci .get_tunable = m88e1011_get_tunable, 338962306a36Sopenharmony_ci .set_tunable = m88e1011_set_tunable, 339062306a36Sopenharmony_ci }, 339162306a36Sopenharmony_ci { 339262306a36Sopenharmony_ci .phy_id = MARVELL_PHY_ID_88E1318S, 339362306a36Sopenharmony_ci .phy_id_mask = MARVELL_PHY_ID_MASK, 339462306a36Sopenharmony_ci .name = "Marvell 88E1318S", 339562306a36Sopenharmony_ci /* PHY_GBIT_FEATURES */ 339662306a36Sopenharmony_ci .probe = marvell_probe, 339762306a36Sopenharmony_ci .config_init = m88e1318_config_init, 339862306a36Sopenharmony_ci .config_aneg = m88e1318_config_aneg, 339962306a36Sopenharmony_ci .read_status = marvell_read_status, 340062306a36Sopenharmony_ci .config_intr = marvell_config_intr, 340162306a36Sopenharmony_ci .handle_interrupt = marvell_handle_interrupt, 340262306a36Sopenharmony_ci .get_wol = m88e1318_get_wol, 340362306a36Sopenharmony_ci .set_wol = m88e1318_set_wol, 340462306a36Sopenharmony_ci .resume = genphy_resume, 340562306a36Sopenharmony_ci .suspend = genphy_suspend, 340662306a36Sopenharmony_ci .read_page = marvell_read_page, 340762306a36Sopenharmony_ci .write_page = marvell_write_page, 340862306a36Sopenharmony_ci .get_sset_count = marvell_get_sset_count, 340962306a36Sopenharmony_ci .get_strings = marvell_get_strings, 341062306a36Sopenharmony_ci .get_stats = marvell_get_stats, 341162306a36Sopenharmony_ci .led_brightness_set = m88e1318_led_brightness_set, 341262306a36Sopenharmony_ci .led_blink_set = m88e1318_led_blink_set, 341362306a36Sopenharmony_ci .led_hw_is_supported = m88e1318_led_hw_is_supported, 341462306a36Sopenharmony_ci .led_hw_control_set = m88e1318_led_hw_control_set, 341562306a36Sopenharmony_ci .led_hw_control_get = m88e1318_led_hw_control_get, 341662306a36Sopenharmony_ci }, 341762306a36Sopenharmony_ci { 341862306a36Sopenharmony_ci .phy_id = MARVELL_PHY_ID_88E1145, 341962306a36Sopenharmony_ci .phy_id_mask = MARVELL_PHY_ID_MASK, 342062306a36Sopenharmony_ci .name = "Marvell 88E1145", 342162306a36Sopenharmony_ci /* PHY_GBIT_FEATURES */ 342262306a36Sopenharmony_ci .probe = marvell_probe, 342362306a36Sopenharmony_ci .config_init = m88e1145_config_init, 342462306a36Sopenharmony_ci .config_aneg = m88e1101_config_aneg, 342562306a36Sopenharmony_ci .config_intr = marvell_config_intr, 342662306a36Sopenharmony_ci .handle_interrupt = marvell_handle_interrupt, 342762306a36Sopenharmony_ci .resume = genphy_resume, 342862306a36Sopenharmony_ci .suspend = genphy_suspend, 342962306a36Sopenharmony_ci .read_page = marvell_read_page, 343062306a36Sopenharmony_ci .write_page = marvell_write_page, 343162306a36Sopenharmony_ci .get_sset_count = marvell_get_sset_count, 343262306a36Sopenharmony_ci .get_strings = marvell_get_strings, 343362306a36Sopenharmony_ci .get_stats = marvell_get_stats, 343462306a36Sopenharmony_ci .get_tunable = m88e1111_get_tunable, 343562306a36Sopenharmony_ci .set_tunable = m88e1111_set_tunable, 343662306a36Sopenharmony_ci }, 343762306a36Sopenharmony_ci { 343862306a36Sopenharmony_ci .phy_id = MARVELL_PHY_ID_88E1149R, 343962306a36Sopenharmony_ci .phy_id_mask = MARVELL_PHY_ID_MASK, 344062306a36Sopenharmony_ci .name = "Marvell 88E1149R", 344162306a36Sopenharmony_ci /* PHY_GBIT_FEATURES */ 344262306a36Sopenharmony_ci .probe = marvell_probe, 344362306a36Sopenharmony_ci .config_init = m88e1149_config_init, 344462306a36Sopenharmony_ci .config_aneg = m88e1118_config_aneg, 344562306a36Sopenharmony_ci .config_intr = marvell_config_intr, 344662306a36Sopenharmony_ci .handle_interrupt = marvell_handle_interrupt, 344762306a36Sopenharmony_ci .resume = genphy_resume, 344862306a36Sopenharmony_ci .suspend = genphy_suspend, 344962306a36Sopenharmony_ci .read_page = marvell_read_page, 345062306a36Sopenharmony_ci .write_page = marvell_write_page, 345162306a36Sopenharmony_ci .get_sset_count = marvell_get_sset_count, 345262306a36Sopenharmony_ci .get_strings = marvell_get_strings, 345362306a36Sopenharmony_ci .get_stats = marvell_get_stats, 345462306a36Sopenharmony_ci }, 345562306a36Sopenharmony_ci { 345662306a36Sopenharmony_ci .phy_id = MARVELL_PHY_ID_88E1240, 345762306a36Sopenharmony_ci .phy_id_mask = MARVELL_PHY_ID_MASK, 345862306a36Sopenharmony_ci .name = "Marvell 88E1240", 345962306a36Sopenharmony_ci /* PHY_GBIT_FEATURES */ 346062306a36Sopenharmony_ci .probe = marvell_probe, 346162306a36Sopenharmony_ci .config_init = m88e1112_config_init, 346262306a36Sopenharmony_ci .config_aneg = marvell_config_aneg, 346362306a36Sopenharmony_ci .config_intr = marvell_config_intr, 346462306a36Sopenharmony_ci .handle_interrupt = marvell_handle_interrupt, 346562306a36Sopenharmony_ci .resume = genphy_resume, 346662306a36Sopenharmony_ci .suspend = genphy_suspend, 346762306a36Sopenharmony_ci .read_page = marvell_read_page, 346862306a36Sopenharmony_ci .write_page = marvell_write_page, 346962306a36Sopenharmony_ci .get_sset_count = marvell_get_sset_count, 347062306a36Sopenharmony_ci .get_strings = marvell_get_strings, 347162306a36Sopenharmony_ci .get_stats = marvell_get_stats, 347262306a36Sopenharmony_ci .get_tunable = m88e1011_get_tunable, 347362306a36Sopenharmony_ci .set_tunable = m88e1011_set_tunable, 347462306a36Sopenharmony_ci }, 347562306a36Sopenharmony_ci { 347662306a36Sopenharmony_ci .phy_id = MARVELL_PHY_ID_88E1116R, 347762306a36Sopenharmony_ci .phy_id_mask = MARVELL_PHY_ID_MASK, 347862306a36Sopenharmony_ci .name = "Marvell 88E1116R", 347962306a36Sopenharmony_ci /* PHY_GBIT_FEATURES */ 348062306a36Sopenharmony_ci .probe = marvell_probe, 348162306a36Sopenharmony_ci .config_init = m88e1116r_config_init, 348262306a36Sopenharmony_ci .config_intr = marvell_config_intr, 348362306a36Sopenharmony_ci .handle_interrupt = marvell_handle_interrupt, 348462306a36Sopenharmony_ci .resume = genphy_resume, 348562306a36Sopenharmony_ci .suspend = genphy_suspend, 348662306a36Sopenharmony_ci .read_page = marvell_read_page, 348762306a36Sopenharmony_ci .write_page = marvell_write_page, 348862306a36Sopenharmony_ci .get_sset_count = marvell_get_sset_count, 348962306a36Sopenharmony_ci .get_strings = marvell_get_strings, 349062306a36Sopenharmony_ci .get_stats = marvell_get_stats, 349162306a36Sopenharmony_ci .get_tunable = m88e1011_get_tunable, 349262306a36Sopenharmony_ci .set_tunable = m88e1011_set_tunable, 349362306a36Sopenharmony_ci }, 349462306a36Sopenharmony_ci { 349562306a36Sopenharmony_ci .phy_id = MARVELL_PHY_ID_88E1510, 349662306a36Sopenharmony_ci .phy_id_mask = MARVELL_PHY_ID_MASK, 349762306a36Sopenharmony_ci .name = "Marvell 88E1510", 349862306a36Sopenharmony_ci .driver_data = DEF_MARVELL_HWMON_OPS(m88e1510_hwmon_ops), 349962306a36Sopenharmony_ci .features = PHY_GBIT_FIBRE_FEATURES, 350062306a36Sopenharmony_ci .flags = PHY_POLL_CABLE_TEST, 350162306a36Sopenharmony_ci .probe = m88e1510_probe, 350262306a36Sopenharmony_ci .config_init = m88e1510_config_init, 350362306a36Sopenharmony_ci .config_aneg = m88e1510_config_aneg, 350462306a36Sopenharmony_ci .read_status = marvell_read_status, 350562306a36Sopenharmony_ci .config_intr = marvell_config_intr, 350662306a36Sopenharmony_ci .handle_interrupt = marvell_handle_interrupt, 350762306a36Sopenharmony_ci .get_wol = m88e1318_get_wol, 350862306a36Sopenharmony_ci .set_wol = m88e1318_set_wol, 350962306a36Sopenharmony_ci .resume = marvell_resume, 351062306a36Sopenharmony_ci .suspend = marvell_suspend, 351162306a36Sopenharmony_ci .read_page = marvell_read_page, 351262306a36Sopenharmony_ci .write_page = marvell_write_page, 351362306a36Sopenharmony_ci .get_sset_count = marvell_get_sset_count, 351462306a36Sopenharmony_ci .get_strings = marvell_get_strings, 351562306a36Sopenharmony_ci .get_stats = marvell_get_stats, 351662306a36Sopenharmony_ci .set_loopback = m88e1510_loopback, 351762306a36Sopenharmony_ci .get_tunable = m88e1011_get_tunable, 351862306a36Sopenharmony_ci .set_tunable = m88e1011_set_tunable, 351962306a36Sopenharmony_ci .cable_test_start = marvell_vct7_cable_test_start, 352062306a36Sopenharmony_ci .cable_test_tdr_start = marvell_vct5_cable_test_tdr_start, 352162306a36Sopenharmony_ci .cable_test_get_status = marvell_vct7_cable_test_get_status, 352262306a36Sopenharmony_ci .led_brightness_set = m88e1318_led_brightness_set, 352362306a36Sopenharmony_ci .led_blink_set = m88e1318_led_blink_set, 352462306a36Sopenharmony_ci .led_hw_is_supported = m88e1318_led_hw_is_supported, 352562306a36Sopenharmony_ci .led_hw_control_set = m88e1318_led_hw_control_set, 352662306a36Sopenharmony_ci .led_hw_control_get = m88e1318_led_hw_control_get, 352762306a36Sopenharmony_ci }, 352862306a36Sopenharmony_ci { 352962306a36Sopenharmony_ci .phy_id = MARVELL_PHY_ID_88E1540, 353062306a36Sopenharmony_ci .phy_id_mask = MARVELL_PHY_ID_MASK, 353162306a36Sopenharmony_ci .name = "Marvell 88E1540", 353262306a36Sopenharmony_ci .driver_data = DEF_MARVELL_HWMON_OPS(m88e1510_hwmon_ops), 353362306a36Sopenharmony_ci /* PHY_GBIT_FEATURES */ 353462306a36Sopenharmony_ci .flags = PHY_POLL_CABLE_TEST, 353562306a36Sopenharmony_ci .probe = marvell_probe, 353662306a36Sopenharmony_ci .config_init = marvell_1011gbe_config_init, 353762306a36Sopenharmony_ci .config_aneg = m88e1510_config_aneg, 353862306a36Sopenharmony_ci .read_status = marvell_read_status, 353962306a36Sopenharmony_ci .config_intr = marvell_config_intr, 354062306a36Sopenharmony_ci .handle_interrupt = marvell_handle_interrupt, 354162306a36Sopenharmony_ci .resume = genphy_resume, 354262306a36Sopenharmony_ci .suspend = genphy_suspend, 354362306a36Sopenharmony_ci .read_page = marvell_read_page, 354462306a36Sopenharmony_ci .write_page = marvell_write_page, 354562306a36Sopenharmony_ci .get_sset_count = marvell_get_sset_count, 354662306a36Sopenharmony_ci .get_strings = marvell_get_strings, 354762306a36Sopenharmony_ci .get_stats = marvell_get_stats, 354862306a36Sopenharmony_ci .get_tunable = m88e1540_get_tunable, 354962306a36Sopenharmony_ci .set_tunable = m88e1540_set_tunable, 355062306a36Sopenharmony_ci .cable_test_start = marvell_vct7_cable_test_start, 355162306a36Sopenharmony_ci .cable_test_tdr_start = marvell_vct5_cable_test_tdr_start, 355262306a36Sopenharmony_ci .cable_test_get_status = marvell_vct7_cable_test_get_status, 355362306a36Sopenharmony_ci .led_brightness_set = m88e1318_led_brightness_set, 355462306a36Sopenharmony_ci .led_blink_set = m88e1318_led_blink_set, 355562306a36Sopenharmony_ci .led_hw_is_supported = m88e1318_led_hw_is_supported, 355662306a36Sopenharmony_ci .led_hw_control_set = m88e1318_led_hw_control_set, 355762306a36Sopenharmony_ci .led_hw_control_get = m88e1318_led_hw_control_get, 355862306a36Sopenharmony_ci }, 355962306a36Sopenharmony_ci { 356062306a36Sopenharmony_ci .phy_id = MARVELL_PHY_ID_88E1545, 356162306a36Sopenharmony_ci .phy_id_mask = MARVELL_PHY_ID_MASK, 356262306a36Sopenharmony_ci .name = "Marvell 88E1545", 356362306a36Sopenharmony_ci .driver_data = DEF_MARVELL_HWMON_OPS(m88e1510_hwmon_ops), 356462306a36Sopenharmony_ci .probe = marvell_probe, 356562306a36Sopenharmony_ci /* PHY_GBIT_FEATURES */ 356662306a36Sopenharmony_ci .flags = PHY_POLL_CABLE_TEST, 356762306a36Sopenharmony_ci .config_init = marvell_1011gbe_config_init, 356862306a36Sopenharmony_ci .config_aneg = m88e1510_config_aneg, 356962306a36Sopenharmony_ci .read_status = marvell_read_status, 357062306a36Sopenharmony_ci .config_intr = marvell_config_intr, 357162306a36Sopenharmony_ci .handle_interrupt = marvell_handle_interrupt, 357262306a36Sopenharmony_ci .resume = genphy_resume, 357362306a36Sopenharmony_ci .suspend = genphy_suspend, 357462306a36Sopenharmony_ci .read_page = marvell_read_page, 357562306a36Sopenharmony_ci .write_page = marvell_write_page, 357662306a36Sopenharmony_ci .get_sset_count = marvell_get_sset_count, 357762306a36Sopenharmony_ci .get_strings = marvell_get_strings, 357862306a36Sopenharmony_ci .get_stats = marvell_get_stats, 357962306a36Sopenharmony_ci .get_tunable = m88e1540_get_tunable, 358062306a36Sopenharmony_ci .set_tunable = m88e1540_set_tunable, 358162306a36Sopenharmony_ci .cable_test_start = marvell_vct7_cable_test_start, 358262306a36Sopenharmony_ci .cable_test_tdr_start = marvell_vct5_cable_test_tdr_start, 358362306a36Sopenharmony_ci .cable_test_get_status = marvell_vct7_cable_test_get_status, 358462306a36Sopenharmony_ci .led_brightness_set = m88e1318_led_brightness_set, 358562306a36Sopenharmony_ci .led_blink_set = m88e1318_led_blink_set, 358662306a36Sopenharmony_ci .led_hw_is_supported = m88e1318_led_hw_is_supported, 358762306a36Sopenharmony_ci .led_hw_control_set = m88e1318_led_hw_control_set, 358862306a36Sopenharmony_ci .led_hw_control_get = m88e1318_led_hw_control_get, 358962306a36Sopenharmony_ci }, 359062306a36Sopenharmony_ci { 359162306a36Sopenharmony_ci .phy_id = MARVELL_PHY_ID_88E3016, 359262306a36Sopenharmony_ci .phy_id_mask = MARVELL_PHY_ID_MASK, 359362306a36Sopenharmony_ci .name = "Marvell 88E3016", 359462306a36Sopenharmony_ci /* PHY_BASIC_FEATURES */ 359562306a36Sopenharmony_ci .probe = marvell_probe, 359662306a36Sopenharmony_ci .config_init = m88e3016_config_init, 359762306a36Sopenharmony_ci .aneg_done = marvell_aneg_done, 359862306a36Sopenharmony_ci .read_status = marvell_read_status, 359962306a36Sopenharmony_ci .config_intr = marvell_config_intr, 360062306a36Sopenharmony_ci .handle_interrupt = marvell_handle_interrupt, 360162306a36Sopenharmony_ci .resume = genphy_resume, 360262306a36Sopenharmony_ci .suspend = genphy_suspend, 360362306a36Sopenharmony_ci .read_page = marvell_read_page, 360462306a36Sopenharmony_ci .write_page = marvell_write_page, 360562306a36Sopenharmony_ci .get_sset_count = marvell_get_sset_count, 360662306a36Sopenharmony_ci .get_strings = marvell_get_strings, 360762306a36Sopenharmony_ci .get_stats = marvell_get_stats, 360862306a36Sopenharmony_ci }, 360962306a36Sopenharmony_ci { 361062306a36Sopenharmony_ci .phy_id = MARVELL_PHY_ID_88E6341_FAMILY, 361162306a36Sopenharmony_ci .phy_id_mask = MARVELL_PHY_ID_MASK, 361262306a36Sopenharmony_ci .name = "Marvell 88E6341 Family", 361362306a36Sopenharmony_ci .driver_data = DEF_MARVELL_HWMON_OPS(m88e1510_hwmon_ops), 361462306a36Sopenharmony_ci /* PHY_GBIT_FEATURES */ 361562306a36Sopenharmony_ci .flags = PHY_POLL_CABLE_TEST, 361662306a36Sopenharmony_ci .probe = marvell_probe, 361762306a36Sopenharmony_ci .config_init = marvell_1011gbe_config_init, 361862306a36Sopenharmony_ci .config_aneg = m88e6390_config_aneg, 361962306a36Sopenharmony_ci .read_status = marvell_read_status, 362062306a36Sopenharmony_ci .config_intr = marvell_config_intr, 362162306a36Sopenharmony_ci .handle_interrupt = marvell_handle_interrupt, 362262306a36Sopenharmony_ci .resume = genphy_resume, 362362306a36Sopenharmony_ci .suspend = genphy_suspend, 362462306a36Sopenharmony_ci .read_page = marvell_read_page, 362562306a36Sopenharmony_ci .write_page = marvell_write_page, 362662306a36Sopenharmony_ci .get_sset_count = marvell_get_sset_count, 362762306a36Sopenharmony_ci .get_strings = marvell_get_strings, 362862306a36Sopenharmony_ci .get_stats = marvell_get_stats, 362962306a36Sopenharmony_ci .get_tunable = m88e1540_get_tunable, 363062306a36Sopenharmony_ci .set_tunable = m88e1540_set_tunable, 363162306a36Sopenharmony_ci .cable_test_start = marvell_vct7_cable_test_start, 363262306a36Sopenharmony_ci .cable_test_tdr_start = marvell_vct5_cable_test_tdr_start, 363362306a36Sopenharmony_ci .cable_test_get_status = marvell_vct7_cable_test_get_status, 363462306a36Sopenharmony_ci }, 363562306a36Sopenharmony_ci { 363662306a36Sopenharmony_ci .phy_id = MARVELL_PHY_ID_88E6390_FAMILY, 363762306a36Sopenharmony_ci .phy_id_mask = MARVELL_PHY_ID_MASK, 363862306a36Sopenharmony_ci .name = "Marvell 88E6390 Family", 363962306a36Sopenharmony_ci .driver_data = DEF_MARVELL_HWMON_OPS(m88e6390_hwmon_ops), 364062306a36Sopenharmony_ci /* PHY_GBIT_FEATURES */ 364162306a36Sopenharmony_ci .flags = PHY_POLL_CABLE_TEST, 364262306a36Sopenharmony_ci .probe = marvell_probe, 364362306a36Sopenharmony_ci .config_init = marvell_1011gbe_config_init, 364462306a36Sopenharmony_ci .config_aneg = m88e6390_config_aneg, 364562306a36Sopenharmony_ci .read_status = marvell_read_status, 364662306a36Sopenharmony_ci .config_intr = marvell_config_intr, 364762306a36Sopenharmony_ci .handle_interrupt = marvell_handle_interrupt, 364862306a36Sopenharmony_ci .resume = genphy_resume, 364962306a36Sopenharmony_ci .suspend = genphy_suspend, 365062306a36Sopenharmony_ci .read_page = marvell_read_page, 365162306a36Sopenharmony_ci .write_page = marvell_write_page, 365262306a36Sopenharmony_ci .get_sset_count = marvell_get_sset_count, 365362306a36Sopenharmony_ci .get_strings = marvell_get_strings, 365462306a36Sopenharmony_ci .get_stats = marvell_get_stats, 365562306a36Sopenharmony_ci .get_tunable = m88e1540_get_tunable, 365662306a36Sopenharmony_ci .set_tunable = m88e1540_set_tunable, 365762306a36Sopenharmony_ci .cable_test_start = marvell_vct7_cable_test_start, 365862306a36Sopenharmony_ci .cable_test_tdr_start = marvell_vct5_cable_test_tdr_start, 365962306a36Sopenharmony_ci .cable_test_get_status = marvell_vct7_cable_test_get_status, 366062306a36Sopenharmony_ci }, 366162306a36Sopenharmony_ci { 366262306a36Sopenharmony_ci .phy_id = MARVELL_PHY_ID_88E6393_FAMILY, 366362306a36Sopenharmony_ci .phy_id_mask = MARVELL_PHY_ID_MASK, 366462306a36Sopenharmony_ci .name = "Marvell 88E6393 Family", 366562306a36Sopenharmony_ci .driver_data = DEF_MARVELL_HWMON_OPS(m88e6393_hwmon_ops), 366662306a36Sopenharmony_ci /* PHY_GBIT_FEATURES */ 366762306a36Sopenharmony_ci .flags = PHY_POLL_CABLE_TEST, 366862306a36Sopenharmony_ci .probe = marvell_probe, 366962306a36Sopenharmony_ci .config_init = marvell_1011gbe_config_init, 367062306a36Sopenharmony_ci .config_aneg = m88e1510_config_aneg, 367162306a36Sopenharmony_ci .read_status = marvell_read_status, 367262306a36Sopenharmony_ci .config_intr = marvell_config_intr, 367362306a36Sopenharmony_ci .handle_interrupt = marvell_handle_interrupt, 367462306a36Sopenharmony_ci .resume = genphy_resume, 367562306a36Sopenharmony_ci .suspend = genphy_suspend, 367662306a36Sopenharmony_ci .read_page = marvell_read_page, 367762306a36Sopenharmony_ci .write_page = marvell_write_page, 367862306a36Sopenharmony_ci .get_sset_count = marvell_get_sset_count, 367962306a36Sopenharmony_ci .get_strings = marvell_get_strings, 368062306a36Sopenharmony_ci .get_stats = marvell_get_stats, 368162306a36Sopenharmony_ci .get_tunable = m88e1540_get_tunable, 368262306a36Sopenharmony_ci .set_tunable = m88e1540_set_tunable, 368362306a36Sopenharmony_ci .cable_test_start = marvell_vct7_cable_test_start, 368462306a36Sopenharmony_ci .cable_test_tdr_start = marvell_vct5_cable_test_tdr_start, 368562306a36Sopenharmony_ci .cable_test_get_status = marvell_vct7_cable_test_get_status, 368662306a36Sopenharmony_ci }, 368762306a36Sopenharmony_ci { 368862306a36Sopenharmony_ci .phy_id = MARVELL_PHY_ID_88E1340S, 368962306a36Sopenharmony_ci .phy_id_mask = MARVELL_PHY_ID_MASK, 369062306a36Sopenharmony_ci .name = "Marvell 88E1340S", 369162306a36Sopenharmony_ci .driver_data = DEF_MARVELL_HWMON_OPS(m88e1510_hwmon_ops), 369262306a36Sopenharmony_ci .probe = marvell_probe, 369362306a36Sopenharmony_ci /* PHY_GBIT_FEATURES */ 369462306a36Sopenharmony_ci .config_init = marvell_1011gbe_config_init, 369562306a36Sopenharmony_ci .config_aneg = m88e1510_config_aneg, 369662306a36Sopenharmony_ci .read_status = marvell_read_status, 369762306a36Sopenharmony_ci .config_intr = marvell_config_intr, 369862306a36Sopenharmony_ci .handle_interrupt = marvell_handle_interrupt, 369962306a36Sopenharmony_ci .resume = genphy_resume, 370062306a36Sopenharmony_ci .suspend = genphy_suspend, 370162306a36Sopenharmony_ci .read_page = marvell_read_page, 370262306a36Sopenharmony_ci .write_page = marvell_write_page, 370362306a36Sopenharmony_ci .get_sset_count = marvell_get_sset_count, 370462306a36Sopenharmony_ci .get_strings = marvell_get_strings, 370562306a36Sopenharmony_ci .get_stats = marvell_get_stats, 370662306a36Sopenharmony_ci .get_tunable = m88e1540_get_tunable, 370762306a36Sopenharmony_ci .set_tunable = m88e1540_set_tunable, 370862306a36Sopenharmony_ci }, 370962306a36Sopenharmony_ci { 371062306a36Sopenharmony_ci .phy_id = MARVELL_PHY_ID_88E1548P, 371162306a36Sopenharmony_ci .phy_id_mask = MARVELL_PHY_ID_MASK, 371262306a36Sopenharmony_ci .name = "Marvell 88E1548P", 371362306a36Sopenharmony_ci .driver_data = DEF_MARVELL_HWMON_OPS(m88e1510_hwmon_ops), 371462306a36Sopenharmony_ci .probe = marvell_probe, 371562306a36Sopenharmony_ci .features = PHY_GBIT_FIBRE_FEATURES, 371662306a36Sopenharmony_ci .config_init = marvell_1011gbe_config_init, 371762306a36Sopenharmony_ci .config_aneg = m88e1510_config_aneg, 371862306a36Sopenharmony_ci .read_status = marvell_read_status, 371962306a36Sopenharmony_ci .config_intr = marvell_config_intr, 372062306a36Sopenharmony_ci .handle_interrupt = marvell_handle_interrupt, 372162306a36Sopenharmony_ci .resume = genphy_resume, 372262306a36Sopenharmony_ci .suspend = genphy_suspend, 372362306a36Sopenharmony_ci .read_page = marvell_read_page, 372462306a36Sopenharmony_ci .write_page = marvell_write_page, 372562306a36Sopenharmony_ci .get_sset_count = marvell_get_sset_count, 372662306a36Sopenharmony_ci .get_strings = marvell_get_strings, 372762306a36Sopenharmony_ci .get_stats = marvell_get_stats, 372862306a36Sopenharmony_ci .get_tunable = m88e1540_get_tunable, 372962306a36Sopenharmony_ci .set_tunable = m88e1540_set_tunable, 373062306a36Sopenharmony_ci .led_brightness_set = m88e1318_led_brightness_set, 373162306a36Sopenharmony_ci .led_blink_set = m88e1318_led_blink_set, 373262306a36Sopenharmony_ci .led_hw_is_supported = m88e1318_led_hw_is_supported, 373362306a36Sopenharmony_ci .led_hw_control_set = m88e1318_led_hw_control_set, 373462306a36Sopenharmony_ci .led_hw_control_get = m88e1318_led_hw_control_get, 373562306a36Sopenharmony_ci }, 373662306a36Sopenharmony_ci}; 373762306a36Sopenharmony_ci 373862306a36Sopenharmony_cimodule_phy_driver(marvell_drivers); 373962306a36Sopenharmony_ci 374062306a36Sopenharmony_cistatic struct mdio_device_id __maybe_unused marvell_tbl[] = { 374162306a36Sopenharmony_ci { MARVELL_PHY_ID_88E1101, MARVELL_PHY_ID_MASK }, 374262306a36Sopenharmony_ci { MARVELL_PHY_ID_88E1112, MARVELL_PHY_ID_MASK }, 374362306a36Sopenharmony_ci { MARVELL_PHY_ID_88E1111, MARVELL_PHY_ID_MASK }, 374462306a36Sopenharmony_ci { MARVELL_PHY_ID_88E1111_FINISAR, MARVELL_PHY_ID_MASK }, 374562306a36Sopenharmony_ci { MARVELL_PHY_ID_88E1118, MARVELL_PHY_ID_MASK }, 374662306a36Sopenharmony_ci { MARVELL_PHY_ID_88E1121R, MARVELL_PHY_ID_MASK }, 374762306a36Sopenharmony_ci { MARVELL_PHY_ID_88E1145, MARVELL_PHY_ID_MASK }, 374862306a36Sopenharmony_ci { MARVELL_PHY_ID_88E1149R, MARVELL_PHY_ID_MASK }, 374962306a36Sopenharmony_ci { MARVELL_PHY_ID_88E1240, MARVELL_PHY_ID_MASK }, 375062306a36Sopenharmony_ci { MARVELL_PHY_ID_88E1318S, MARVELL_PHY_ID_MASK }, 375162306a36Sopenharmony_ci { MARVELL_PHY_ID_88E1116R, MARVELL_PHY_ID_MASK }, 375262306a36Sopenharmony_ci { MARVELL_PHY_ID_88E1510, MARVELL_PHY_ID_MASK }, 375362306a36Sopenharmony_ci { MARVELL_PHY_ID_88E1540, MARVELL_PHY_ID_MASK }, 375462306a36Sopenharmony_ci { MARVELL_PHY_ID_88E1545, MARVELL_PHY_ID_MASK }, 375562306a36Sopenharmony_ci { MARVELL_PHY_ID_88E3016, MARVELL_PHY_ID_MASK }, 375662306a36Sopenharmony_ci { MARVELL_PHY_ID_88E6341_FAMILY, MARVELL_PHY_ID_MASK }, 375762306a36Sopenharmony_ci { MARVELL_PHY_ID_88E6390_FAMILY, MARVELL_PHY_ID_MASK }, 375862306a36Sopenharmony_ci { MARVELL_PHY_ID_88E6393_FAMILY, MARVELL_PHY_ID_MASK }, 375962306a36Sopenharmony_ci { MARVELL_PHY_ID_88E1340S, MARVELL_PHY_ID_MASK }, 376062306a36Sopenharmony_ci { MARVELL_PHY_ID_88E1548P, MARVELL_PHY_ID_MASK }, 376162306a36Sopenharmony_ci { } 376262306a36Sopenharmony_ci}; 376362306a36Sopenharmony_ci 376462306a36Sopenharmony_ciMODULE_DEVICE_TABLE(mdio, marvell_tbl); 3765