Commit 645a7fe1 authored by David S. Miller's avatar David S. Miller
Browse files

Merge branch 'ksz886x-cable-test'



Oleksij Rempel says:

====================
provide cable test support for the ksz886x switch

changes v5:
- drop resume() patch
- add Reviewed-by tags.
- rework dsa_slave_phy_connect() patch

changes v4:
- use fallthrough;
- use EOPNOTSUPP instead of ENOTSUPP
- drop flags variable in dsa_slave_phy_connect patch
- extend description for the "net: phy: micrel: apply resume errat"
  patch
- fix "use consistent alignments" patch

changes v3:
- remove RFC tag

changes v2:
- use generic MII_* defines where possible
- rework phylink validate
- remove phylink get state function
- reorder cabletest patches to make PHY flag patch in the right order
- fix MDI-X detection

This patches provide support for cable testing on the ksz886x switches.
Since it has one special port, we needed to add phylink with validation
and extra quirk for the PHY to signal, that one port will not provide
valid cable testing reports.
====================

Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents ffa85b73 49011e0c
Loading
Loading
Loading
Loading
+155 −59
Original line number Diff line number Diff line
@@ -6,6 +6,7 @@
 *	Tristram Ha <Tristram.Ha@microchip.com>
 */

#include <linux/bitfield.h>
#include <linux/delay.h>
#include <linux/export.h>
#include <linux/gpio.h>
@@ -15,8 +16,10 @@
#include <linux/phy.h>
#include <linux/etherdevice.h>
#include <linux/if_bridge.h>
#include <linux/micrel_phy.h>
#include <net/dsa.h>
#include <net/switchdev.h>
#include <linux/phylink.h>

#include "ksz_common.h"
#include "ksz8795_reg.h"
@@ -727,92 +730,114 @@ static void ksz8_r_phy(struct ksz_device *dev, u16 phy, u16 reg, u16 *val)
	u8 restart, speed, ctrl, link;
	const u8 *regs = ksz8->regs;
	int processed = true;
	u8 val1, val2;
	u16 data = 0;
	u8 p = phy;

	switch (reg) {
	case PHY_REG_CTRL:
	case MII_BMCR:
		ksz_pread8(dev, p, regs[P_NEG_RESTART_CTRL], &restart);
		ksz_pread8(dev, p, regs[P_SPEED_STATUS], &speed);
		ksz_pread8(dev, p, regs[P_FORCE_CTRL], &ctrl);
		if (restart & PORT_PHY_LOOPBACK)
			data |= PHY_LOOPBACK;
			data |= BMCR_LOOPBACK;
		if (ctrl & PORT_FORCE_100_MBIT)
			data |= PHY_SPEED_100MBIT;
			data |= BMCR_SPEED100;
		if (ksz_is_ksz88x3(dev)) {
			if ((ctrl & PORT_AUTO_NEG_ENABLE))
				data |= PHY_AUTO_NEG_ENABLE;
				data |= BMCR_ANENABLE;
		} else {
			if (!(ctrl & PORT_AUTO_NEG_DISABLE))
				data |= PHY_AUTO_NEG_ENABLE;
				data |= BMCR_ANENABLE;
		}
		if (restart & PORT_POWER_DOWN)
			data |= PHY_POWER_DOWN;
			data |= BMCR_PDOWN;
		if (restart & PORT_AUTO_NEG_RESTART)
			data |= PHY_AUTO_NEG_RESTART;
			data |= BMCR_ANRESTART;
		if (ctrl & PORT_FORCE_FULL_DUPLEX)
			data |= PHY_FULL_DUPLEX;
			data |= BMCR_FULLDPLX;
		if (speed & PORT_HP_MDIX)
			data |= PHY_HP_MDIX;
			data |= KSZ886X_BMCR_HP_MDIX;
		if (restart & PORT_FORCE_MDIX)
			data |= PHY_FORCE_MDIX;
			data |= KSZ886X_BMCR_FORCE_MDI;
		if (restart & PORT_AUTO_MDIX_DISABLE)
			data |= PHY_AUTO_MDIX_DISABLE;
			data |= KSZ886X_BMCR_DISABLE_AUTO_MDIX;
		if (restart & PORT_TX_DISABLE)
			data |= PHY_TRANSMIT_DISABLE;
			data |= KSZ886X_BMCR_DISABLE_TRANSMIT;
		if (restart & PORT_LED_OFF)
			data |= PHY_LED_DISABLE;
			data |= KSZ886X_BMCR_DISABLE_LED;
		break;
	case PHY_REG_STATUS:
	case MII_BMSR:
		ksz_pread8(dev, p, regs[P_LINK_STATUS], &link);
		data = PHY_100BTX_FD_CAPABLE |
		       PHY_100BTX_CAPABLE |
		       PHY_10BT_FD_CAPABLE |
		       PHY_10BT_CAPABLE |
		       PHY_AUTO_NEG_CAPABLE;
		data = BMSR_100FULL |
		       BMSR_100HALF |
		       BMSR_10FULL |
		       BMSR_10HALF |
		       BMSR_ANEGCAPABLE;
		if (link & PORT_AUTO_NEG_COMPLETE)
			data |= PHY_AUTO_NEG_ACKNOWLEDGE;
			data |= BMSR_ANEGCOMPLETE;
		if (link & PORT_STAT_LINK_GOOD)
			data |= PHY_LINK_STATUS;
			data |= BMSR_LSTATUS;
		break;
	case PHY_REG_ID_1:
	case MII_PHYSID1:
		data = KSZ8795_ID_HI;
		break;
	case PHY_REG_ID_2:
	case MII_PHYSID2:
		if (ksz_is_ksz88x3(dev))
			data = KSZ8863_ID_LO;
		else
			data = KSZ8795_ID_LO;
		break;
	case PHY_REG_AUTO_NEGOTIATION:
	case MII_ADVERTISE:
		ksz_pread8(dev, p, regs[P_LOCAL_CTRL], &ctrl);
		data = PHY_AUTO_NEG_802_3;
		data = ADVERTISE_CSMA;
		if (ctrl & PORT_AUTO_NEG_SYM_PAUSE)
			data |= PHY_AUTO_NEG_SYM_PAUSE;
			data |= ADVERTISE_PAUSE_CAP;
		if (ctrl & PORT_AUTO_NEG_100BTX_FD)
			data |= PHY_AUTO_NEG_100BTX_FD;
			data |= ADVERTISE_100FULL;
		if (ctrl & PORT_AUTO_NEG_100BTX)
			data |= PHY_AUTO_NEG_100BTX;
			data |= ADVERTISE_100HALF;
		if (ctrl & PORT_AUTO_NEG_10BT_FD)
			data |= PHY_AUTO_NEG_10BT_FD;
			data |= ADVERTISE_10FULL;
		if (ctrl & PORT_AUTO_NEG_10BT)
			data |= PHY_AUTO_NEG_10BT;
			data |= ADVERTISE_10HALF;
		break;
	case PHY_REG_REMOTE_CAPABILITY:
	case MII_LPA:
		ksz_pread8(dev, p, regs[P_REMOTE_STATUS], &link);
		data = PHY_AUTO_NEG_802_3;
		data = LPA_SLCT;
		if (link & PORT_REMOTE_SYM_PAUSE)
			data |= PHY_AUTO_NEG_SYM_PAUSE;
			data |= LPA_PAUSE_CAP;
		if (link & PORT_REMOTE_100BTX_FD)
			data |= PHY_AUTO_NEG_100BTX_FD;
			data |= LPA_100FULL;
		if (link & PORT_REMOTE_100BTX)
			data |= PHY_AUTO_NEG_100BTX;
			data |= LPA_100HALF;
		if (link & PORT_REMOTE_10BT_FD)
			data |= PHY_AUTO_NEG_10BT_FD;
			data |= LPA_10FULL;
		if (link & PORT_REMOTE_10BT)
			data |= PHY_AUTO_NEG_10BT;
		if (data & ~PHY_AUTO_NEG_802_3)
			data |= PHY_REMOTE_ACKNOWLEDGE_NOT;
			data |= LPA_10HALF;
		if (data & ~LPA_SLCT)
			data |= LPA_LPACK;
		break;
	case PHY_REG_LINK_MD:
		ksz_pread8(dev, p, REG_PORT_LINK_MD_CTRL, &val1);
		ksz_pread8(dev, p, REG_PORT_LINK_MD_RESULT, &val2);
		if (val1 & PORT_START_CABLE_DIAG)
			data |= PHY_START_CABLE_DIAG;

		if (val1 & PORT_CABLE_10M_SHORT)
			data |= PHY_CABLE_10M_SHORT;

		data |= FIELD_PREP(PHY_CABLE_DIAG_RESULT_M,
				FIELD_GET(PORT_CABLE_DIAG_RESULT_M, val1));

		data |= FIELD_PREP(PHY_CABLE_FAULT_COUNTER_M,
				(FIELD_GET(PORT_CABLE_FAULT_COUNTER_H, val1) << 8) |
				FIELD_GET(PORT_CABLE_FAULT_COUNTER_L, val2));
		break;
	case PHY_REG_PHY_CTRL:
		ksz_pread8(dev, p, regs[P_LINK_STATUS], &link);
		if (link & PORT_MDIX_STATUS)
			data |= KSZ886X_CTRL_MDIX_STAT;
		break;
	default:
		processed = false;
@@ -830,14 +855,14 @@ static void ksz8_w_phy(struct ksz_device *dev, u16 phy, u16 reg, u16 val)
	u8 p = phy;

	switch (reg) {
	case PHY_REG_CTRL:
	case MII_BMCR:

		/* Do not support PHY reset function. */
		if (val & PHY_RESET)
		if (val & BMCR_RESET)
			break;
		ksz_pread8(dev, p, regs[P_SPEED_STATUS], &speed);
		data = speed;
		if (val & PHY_HP_MDIX)
		if (val & KSZ886X_BMCR_HP_MDIX)
			data |= PORT_HP_MDIX;
		else
			data &= ~PORT_HP_MDIX;
@@ -846,12 +871,12 @@ static void ksz8_w_phy(struct ksz_device *dev, u16 phy, u16 reg, u16 val)
		ksz_pread8(dev, p, regs[P_FORCE_CTRL], &ctrl);
		data = ctrl;
		if (ksz_is_ksz88x3(dev)) {
			if ((val & PHY_AUTO_NEG_ENABLE))
			if ((val & BMCR_ANENABLE))
				data |= PORT_AUTO_NEG_ENABLE;
			else
				data &= ~PORT_AUTO_NEG_ENABLE;
		} else {
			if (!(val & PHY_AUTO_NEG_ENABLE))
			if (!(val & BMCR_ANENABLE))
				data |= PORT_AUTO_NEG_DISABLE;
			else
				data &= ~PORT_AUTO_NEG_DISABLE;
@@ -861,11 +886,11 @@ static void ksz8_w_phy(struct ksz_device *dev, u16 phy, u16 reg, u16 val)
				data |= PORT_AUTO_NEG_DISABLE;
		}

		if (val & PHY_SPEED_100MBIT)
		if (val & BMCR_SPEED100)
			data |= PORT_FORCE_100_MBIT;
		else
			data &= ~PORT_FORCE_100_MBIT;
		if (val & PHY_FULL_DUPLEX)
		if (val & BMCR_FULLDPLX)
			data |= PORT_FORCE_FULL_DUPLEX;
		else
			data &= ~PORT_FORCE_FULL_DUPLEX;
@@ -873,38 +898,38 @@ static void ksz8_w_phy(struct ksz_device *dev, u16 phy, u16 reg, u16 val)
			ksz_pwrite8(dev, p, regs[P_FORCE_CTRL], data);
		ksz_pread8(dev, p, regs[P_NEG_RESTART_CTRL], &restart);
		data = restart;
		if (val & PHY_LED_DISABLE)
		if (val & KSZ886X_BMCR_DISABLE_LED)
			data |= PORT_LED_OFF;
		else
			data &= ~PORT_LED_OFF;
		if (val & PHY_TRANSMIT_DISABLE)
		if (val & KSZ886X_BMCR_DISABLE_TRANSMIT)
			data |= PORT_TX_DISABLE;
		else
			data &= ~PORT_TX_DISABLE;
		if (val & PHY_AUTO_NEG_RESTART)
		if (val & BMCR_ANRESTART)
			data |= PORT_AUTO_NEG_RESTART;
		else
			data &= ~(PORT_AUTO_NEG_RESTART);
		if (val & PHY_POWER_DOWN)
		if (val & BMCR_PDOWN)
			data |= PORT_POWER_DOWN;
		else
			data &= ~PORT_POWER_DOWN;
		if (val & PHY_AUTO_MDIX_DISABLE)
		if (val & KSZ886X_BMCR_DISABLE_AUTO_MDIX)
			data |= PORT_AUTO_MDIX_DISABLE;
		else
			data &= ~PORT_AUTO_MDIX_DISABLE;
		if (val & PHY_FORCE_MDIX)
		if (val & KSZ886X_BMCR_FORCE_MDI)
			data |= PORT_FORCE_MDIX;
		else
			data &= ~PORT_FORCE_MDIX;
		if (val & PHY_LOOPBACK)
		if (val & BMCR_LOOPBACK)
			data |= PORT_PHY_LOOPBACK;
		else
			data &= ~PORT_PHY_LOOPBACK;
		if (data != restart)
			ksz_pwrite8(dev, p, regs[P_NEG_RESTART_CTRL], data);
		break;
	case PHY_REG_AUTO_NEGOTIATION:
	case MII_ADVERTISE:
		ksz_pread8(dev, p, regs[P_LOCAL_CTRL], &ctrl);
		data = ctrl;
		data &= ~(PORT_AUTO_NEG_SYM_PAUSE |
@@ -912,19 +937,23 @@ static void ksz8_w_phy(struct ksz_device *dev, u16 phy, u16 reg, u16 val)
			  PORT_AUTO_NEG_100BTX |
			  PORT_AUTO_NEG_10BT_FD |
			  PORT_AUTO_NEG_10BT);
		if (val & PHY_AUTO_NEG_SYM_PAUSE)
		if (val & ADVERTISE_PAUSE_CAP)
			data |= PORT_AUTO_NEG_SYM_PAUSE;
		if (val & PHY_AUTO_NEG_100BTX_FD)
		if (val & ADVERTISE_100FULL)
			data |= PORT_AUTO_NEG_100BTX_FD;
		if (val & PHY_AUTO_NEG_100BTX)
		if (val & ADVERTISE_100HALF)
			data |= PORT_AUTO_NEG_100BTX;
		if (val & PHY_AUTO_NEG_10BT_FD)
		if (val & ADVERTISE_10FULL)
			data |= PORT_AUTO_NEG_10BT_FD;
		if (val & PHY_AUTO_NEG_10BT)
		if (val & ADVERTISE_10HALF)
			data |= PORT_AUTO_NEG_10BT;
		if (data != ctrl)
			ksz_pwrite8(dev, p, regs[P_LOCAL_CTRL], data);
		break;
	case PHY_REG_LINK_MD:
		if (val & PHY_START_CABLE_DIAG)
			ksz_port_cfg(dev, p, REG_PORT_LINK_MD_CTRL, PORT_START_CABLE_DIAG, true);
		break;
	default:
		break;
	}
@@ -941,6 +970,18 @@ static enum dsa_tag_protocol ksz8_get_tag_protocol(struct dsa_switch *ds,
		DSA_TAG_PROTO_KSZ9893 : DSA_TAG_PROTO_KSZ8795;
}

static u32 ksz8_sw_get_phy_flags(struct dsa_switch *ds, int port)
{
	/* Silicon Errata Sheet (DS80000830A):
	 * Port 1 does not work with LinkMD Cable-Testing.
	 * Port 1 does not respond to received PAUSE control frames.
	 */
	if (!port)
		return MICREL_KSZ8_P1_ERRATA;

	return 0;
}

static void ksz8_get_strings(struct dsa_switch *ds, int port,
			     u32 stringset, uint8_t *buf)
{
@@ -1419,11 +1460,66 @@ static int ksz8_setup(struct dsa_switch *ds)
	return 0;
}

static void ksz8_validate(struct dsa_switch *ds, int port,
			  unsigned long *supported,
			  struct phylink_link_state *state)
{
	__ETHTOOL_DECLARE_LINK_MODE_MASK(mask) = { 0, };
	struct ksz_device *dev = ds->priv;

	if (port == dev->cpu_port) {
		if (state->interface != PHY_INTERFACE_MODE_RMII &&
		    state->interface != PHY_INTERFACE_MODE_MII &&
		    state->interface != PHY_INTERFACE_MODE_NA)
			goto unsupported;
	} else {
		if (state->interface != PHY_INTERFACE_MODE_INTERNAL &&
		    state->interface != PHY_INTERFACE_MODE_NA)
			goto unsupported;
	}

	/* Allow all the expected bits */
	phylink_set_port_modes(mask);
	phylink_set(mask, Autoneg);

	/* Silicon Errata Sheet (DS80000830A):
	 * "Port 1 does not respond to received flow control PAUSE frames"
	 * So, disable Pause support on "Port 1" (port == 0) for all ksz88x3
	 * switches.
	 */
	if (!ksz_is_ksz88x3(dev) || port)
		phylink_set(mask, Pause);

	/* Asym pause is not supported on KSZ8863 and KSZ8873 */
	if (!ksz_is_ksz88x3(dev))
		phylink_set(mask, Asym_Pause);

	/* 10M and 100M are only supported */
	phylink_set(mask, 10baseT_Half);
	phylink_set(mask, 10baseT_Full);
	phylink_set(mask, 100baseT_Half);
	phylink_set(mask, 100baseT_Full);

	bitmap_and(supported, supported, mask,
		   __ETHTOOL_LINK_MODE_MASK_NBITS);
	bitmap_and(state->advertising, state->advertising, mask,
		   __ETHTOOL_LINK_MODE_MASK_NBITS);

	return;

unsupported:
	bitmap_zero(supported, __ETHTOOL_LINK_MODE_MASK_NBITS);
	dev_err(ds->dev, "Unsupported interface: %s, port: %d\n",
		phy_modes(state->interface), port);
}

static const struct dsa_switch_ops ksz8_switch_ops = {
	.get_tag_protocol	= ksz8_get_tag_protocol,
	.get_phy_flags		= ksz8_sw_get_phy_flags,
	.setup			= ksz8_setup,
	.phy_read		= ksz_phy_read16,
	.phy_write		= ksz_phy_write16,
	.phylink_validate	= ksz8_validate,
	.phylink_mac_link_down	= ksz_mac_link_down,
	.port_enable		= ksz_enable_port,
	.get_strings		= ksz8_get_strings,
+3 −64
Original line number Diff line number Diff line
@@ -249,7 +249,7 @@
#define REG_PORT_4_LINK_MD_CTRL		0x4A

#define PORT_CABLE_10M_SHORT		BIT(7)
#define PORT_CABLE_DIAG_RESULT_M	0x3
#define PORT_CABLE_DIAG_RESULT_M	GENMASK(6, 5)
#define PORT_CABLE_DIAG_RESULT_S	5
#define PORT_CABLE_STAT_NORMAL		0
#define PORT_CABLE_STAT_OPEN		1
@@ -744,68 +744,6 @@

#define PORT_ACL_FORCE_DLR_MISS		BIT(0)

#ifndef PHY_REG_CTRL
#define PHY_REG_CTRL			0

#define PHY_RESET			BIT(15)
#define PHY_LOOPBACK			BIT(14)
#define PHY_SPEED_100MBIT		BIT(13)
#define PHY_AUTO_NEG_ENABLE		BIT(12)
#define PHY_POWER_DOWN			BIT(11)
#define PHY_MII_DISABLE			BIT(10)
#define PHY_AUTO_NEG_RESTART		BIT(9)
#define PHY_FULL_DUPLEX			BIT(8)
#define PHY_COLLISION_TEST_NOT		BIT(7)
#define PHY_HP_MDIX			BIT(5)
#define PHY_FORCE_MDIX			BIT(4)
#define PHY_AUTO_MDIX_DISABLE		BIT(3)
#define PHY_REMOTE_FAULT_DISABLE	BIT(2)
#define PHY_TRANSMIT_DISABLE		BIT(1)
#define PHY_LED_DISABLE			BIT(0)

#define PHY_REG_STATUS			1

#define PHY_100BT4_CAPABLE		BIT(15)
#define PHY_100BTX_FD_CAPABLE		BIT(14)
#define PHY_100BTX_CAPABLE		BIT(13)
#define PHY_10BT_FD_CAPABLE		BIT(12)
#define PHY_10BT_CAPABLE		BIT(11)
#define PHY_MII_SUPPRESS_CAPABLE_NOT	BIT(6)
#define PHY_AUTO_NEG_ACKNOWLEDGE	BIT(5)
#define PHY_REMOTE_FAULT		BIT(4)
#define PHY_AUTO_NEG_CAPABLE		BIT(3)
#define PHY_LINK_STATUS			BIT(2)
#define PHY_JABBER_DETECT_NOT		BIT(1)
#define PHY_EXTENDED_CAPABILITY		BIT(0)

#define PHY_REG_ID_1			2
#define PHY_REG_ID_2			3

#define PHY_REG_AUTO_NEGOTIATION	4

#define PHY_AUTO_NEG_NEXT_PAGE_NOT	BIT(15)
#define PHY_AUTO_NEG_REMOTE_FAULT_NOT	BIT(13)
#define PHY_AUTO_NEG_SYM_PAUSE		BIT(10)
#define PHY_AUTO_NEG_100BT4		BIT(9)
#define PHY_AUTO_NEG_100BTX_FD		BIT(8)
#define PHY_AUTO_NEG_100BTX		BIT(7)
#define PHY_AUTO_NEG_10BT_FD		BIT(6)
#define PHY_AUTO_NEG_10BT		BIT(5)
#define PHY_AUTO_NEG_SELECTOR		0x001F
#define PHY_AUTO_NEG_802_3		0x0001

#define PHY_REG_REMOTE_CAPABILITY	5

#define PHY_REMOTE_NEXT_PAGE_NOT	BIT(15)
#define PHY_REMOTE_ACKNOWLEDGE_NOT	BIT(14)
#define PHY_REMOTE_REMOTE_FAULT_NOT	BIT(13)
#define PHY_REMOTE_SYM_PAUSE		BIT(10)
#define PHY_REMOTE_100BTX_FD		BIT(8)
#define PHY_REMOTE_100BTX		BIT(7)
#define PHY_REMOTE_10BT_FD		BIT(6)
#define PHY_REMOTE_10BT			BIT(5)
#endif

#define KSZ8795_ID_HI			0x0022
#define KSZ8795_ID_LO			0x1550
#define KSZ8863_ID_LO			0x1430
@@ -815,13 +753,14 @@
#define PHY_REG_LINK_MD			0x1D

#define PHY_START_CABLE_DIAG		BIT(15)
#define PHY_CABLE_DIAG_RESULT_M		GENMASK(14, 13)
#define PHY_CABLE_DIAG_RESULT		0x6000
#define PHY_CABLE_STAT_NORMAL		0x0000
#define PHY_CABLE_STAT_OPEN		0x2000
#define PHY_CABLE_STAT_SHORT		0x4000
#define PHY_CABLE_STAT_FAILED		0x6000
#define PHY_CABLE_10M_SHORT		BIT(12)
#define PHY_CABLE_FAULT_COUNTER		0x01FF
#define PHY_CABLE_FAULT_COUNTER_M	GENMASK(8, 0)

#define PHY_REG_PHY_CTRL		0x1F

+15 −90
Original line number Diff line number Diff line
@@ -25,6 +25,7 @@
#include <linux/crc32.h>
#include <linux/sched.h>
#include <linux/slab.h>
#include <linux/micrel_phy.h>


/* DMA Registers */
@@ -271,84 +272,15 @@

#define KS884X_PHY_CTRL_OFFSET		0x00

/* Mode Control Register */
#define PHY_REG_CTRL			0

#define PHY_RESET			0x8000
#define PHY_LOOPBACK			0x4000
#define PHY_SPEED_100MBIT		0x2000
#define PHY_AUTO_NEG_ENABLE		0x1000
#define PHY_POWER_DOWN			0x0800
#define PHY_MII_DISABLE			0x0400
#define PHY_AUTO_NEG_RESTART		0x0200
#define PHY_FULL_DUPLEX			0x0100
#define PHY_COLLISION_TEST		0x0080
#define PHY_HP_MDIX			0x0020
#define PHY_FORCE_MDIX			0x0010
#define PHY_AUTO_MDIX_DISABLE		0x0008
#define PHY_REMOTE_FAULT_DISABLE	0x0004
#define PHY_TRANSMIT_DISABLE		0x0002
#define PHY_LED_DISABLE			0x0001

#define KS884X_PHY_STATUS_OFFSET	0x02

/* Mode Status Register */
#define PHY_REG_STATUS			1

#define PHY_100BT4_CAPABLE		0x8000
#define PHY_100BTX_FD_CAPABLE		0x4000
#define PHY_100BTX_CAPABLE		0x2000
#define PHY_10BT_FD_CAPABLE		0x1000
#define PHY_10BT_CAPABLE		0x0800
#define PHY_MII_SUPPRESS_CAPABLE	0x0040
#define PHY_AUTO_NEG_ACKNOWLEDGE	0x0020
#define PHY_REMOTE_FAULT		0x0010
#define PHY_AUTO_NEG_CAPABLE		0x0008
#define PHY_LINK_STATUS			0x0004
#define PHY_JABBER_DETECT		0x0002
#define PHY_EXTENDED_CAPABILITY		0x0001

#define KS884X_PHY_ID_1_OFFSET		0x04
#define KS884X_PHY_ID_2_OFFSET		0x06

/* PHY Identifier Registers */
#define PHY_REG_ID_1			2
#define PHY_REG_ID_2			3

#define KS884X_PHY_AUTO_NEG_OFFSET	0x08

/* Auto-Negotiation Advertisement Register */
#define PHY_REG_AUTO_NEGOTIATION	4

#define PHY_AUTO_NEG_NEXT_PAGE		0x8000
#define PHY_AUTO_NEG_REMOTE_FAULT	0x2000
/* Not supported. */
#define PHY_AUTO_NEG_ASYM_PAUSE		0x0800
#define PHY_AUTO_NEG_SYM_PAUSE		0x0400
#define PHY_AUTO_NEG_100BT4		0x0200
#define PHY_AUTO_NEG_100BTX_FD		0x0100
#define PHY_AUTO_NEG_100BTX		0x0080
#define PHY_AUTO_NEG_10BT_FD		0x0040
#define PHY_AUTO_NEG_10BT		0x0020
#define PHY_AUTO_NEG_SELECTOR		0x001F
#define PHY_AUTO_NEG_802_3		0x0001

#define PHY_AUTO_NEG_PAUSE  (PHY_AUTO_NEG_SYM_PAUSE | PHY_AUTO_NEG_ASYM_PAUSE)

#define KS884X_PHY_REMOTE_CAP_OFFSET	0x0A

/* Auto-Negotiation Link Partner Ability Register */
#define PHY_REG_REMOTE_CAPABILITY	5

#define PHY_REMOTE_NEXT_PAGE		0x8000
#define PHY_REMOTE_ACKNOWLEDGE		0x4000
#define PHY_REMOTE_REMOTE_FAULT		0x2000
#define PHY_REMOTE_SYM_PAUSE		0x0400
#define PHY_REMOTE_100BTX_FD		0x0100
#define PHY_REMOTE_100BTX		0x0080
#define PHY_REMOTE_10BT_FD		0x0040
#define PHY_REMOTE_10BT			0x0020

/* P1VCT */
#define KS884X_P1VCT_P			0x04F0
#define KS884X_P1PHYCTRL_P		0x04F2
@@ -2886,15 +2818,6 @@ static void sw_block_addr(struct ksz_hw *hw)
	}
}

#define PHY_LINK_SUPPORT		\
	(PHY_AUTO_NEG_ASYM_PAUSE |	\
	PHY_AUTO_NEG_SYM_PAUSE |	\
	PHY_AUTO_NEG_100BT4 |		\
	PHY_AUTO_NEG_100BTX_FD |	\
	PHY_AUTO_NEG_100BTX |		\
	PHY_AUTO_NEG_10BT_FD |		\
	PHY_AUTO_NEG_10BT)

static inline void hw_r_phy_ctrl(struct ksz_hw *hw, int phy, u16 *data)
{
	*data = readw(hw->io + phy + KS884X_PHY_CTRL_OFFSET);
@@ -3238,16 +3161,18 @@ static void determine_flow_ctrl(struct ksz_hw *hw, struct ksz_port *port,
	rx = tx = 0;
	if (port->force_link)
		rx = tx = 1;
	if (remote & PHY_AUTO_NEG_SYM_PAUSE) {
		if (local & PHY_AUTO_NEG_SYM_PAUSE) {
	if (remote & LPA_PAUSE_CAP) {
		if (local & ADVERTISE_PAUSE_CAP) {
			rx = tx = 1;
		} else if ((remote & PHY_AUTO_NEG_ASYM_PAUSE) &&
				(local & PHY_AUTO_NEG_PAUSE) ==
				PHY_AUTO_NEG_ASYM_PAUSE) {
		} else if ((remote & LPA_PAUSE_ASYM) &&
			   (local &
			    (ADVERTISE_PAUSE_CAP | ADVERTISE_PAUSE_ASYM)) ==
			   ADVERTISE_PAUSE_ASYM) {
			tx = 1;
		}
	} else if (remote & PHY_AUTO_NEG_ASYM_PAUSE) {
		if ((local & PHY_AUTO_NEG_PAUSE) == PHY_AUTO_NEG_PAUSE)
	} else if (remote & LPA_PAUSE_ASYM) {
		if ((local & (ADVERTISE_PAUSE_CAP | ADVERTISE_PAUSE_ASYM))
		    == (ADVERTISE_PAUSE_CAP | ADVERTISE_PAUSE_ASYM))
			rx = 1;
	}
	if (!hw->ksz_switch)
@@ -3428,16 +3353,16 @@ static void port_force_link_speed(struct ksz_port *port)
		phy = KS884X_PHY_1_CTRL_OFFSET + p * PHY_CTRL_INTERVAL;
		hw_r_phy_ctrl(hw, phy, &data);

		data &= ~PHY_AUTO_NEG_ENABLE;
		data &= ~BMCR_ANENABLE;

		if (10 == port->speed)
			data &= ~PHY_SPEED_100MBIT;
			data &= ~BMCR_SPEED100;
		else if (100 == port->speed)
			data |= PHY_SPEED_100MBIT;
			data |= BMCR_SPEED100;
		if (1 == port->duplex)
			data &= ~PHY_FULL_DUPLEX;
			data &= ~BMCR_FULLDPLX;
		else if (2 == port->duplex)
			data |= PHY_FULL_DUPLEX;
			data |= BMCR_FULLDPLX;
		hw_w_phy_ctrl(hw, phy, data);
	}
}
+379 −22

File changed.

Preview size limit exceeded, changes collapsed.

+16 −0
Original line number Diff line number Diff line
@@ -39,10 +39,26 @@
/* struct phy_device dev_flags definitions */
#define MICREL_PHY_50MHZ_CLK	0x00000001
#define MICREL_PHY_FXEN		0x00000002
#define MICREL_KSZ8_P1_ERRATA	0x00000003

#define MICREL_KSZ9021_EXTREG_CTRL	0xB
#define MICREL_KSZ9021_EXTREG_DATA_WRITE	0xC
#define MICREL_KSZ9021_RGMII_CLK_CTRL_PAD_SCEW	0x104
#define MICREL_KSZ9021_RGMII_RX_DATA_PAD_SCEW	0x105

/* Device specific MII_BMCR (Reg 0) bits */
/* 1 = HP Auto MDI/MDI-X mode, 0 = Microchip Auto MDI/MDI-X mode */
#define KSZ886X_BMCR_HP_MDIX			BIT(5)
/* 1 = Force MDI (transmit on RXP/RXM pins), 0 = Normal operation
 * (transmit on TXP/TXM pins)
 */
#define KSZ886X_BMCR_FORCE_MDI			BIT(4)
/* 1 = Disable auto MDI-X */
#define KSZ886X_BMCR_DISABLE_AUTO_MDIX		BIT(3)
#define KSZ886X_BMCR_DISABLE_FAR_END_FAULT	BIT(2)
#define KSZ886X_BMCR_DISABLE_TRANSMIT		BIT(1)
#define KSZ886X_BMCR_DISABLE_LED		BIT(0)

#define KSZ886X_CTRL_MDIX_STAT			BIT(4)

#endif /* _MICREL_PHY_H */
Loading