162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci/* $Date: 2005/10/24 23:18:13 $ $RCSfile: mv88e1xxx.c,v $ $Revision: 1.49 $ */
362306a36Sopenharmony_ci#include "common.h"
462306a36Sopenharmony_ci#include "mv88e1xxx.h"
562306a36Sopenharmony_ci#include "cphy.h"
662306a36Sopenharmony_ci#include "elmer0.h"
762306a36Sopenharmony_ci
862306a36Sopenharmony_ci/* MV88E1XXX MDI crossover register values */
962306a36Sopenharmony_ci#define CROSSOVER_MDI   0
1062306a36Sopenharmony_ci#define CROSSOVER_MDIX  1
1162306a36Sopenharmony_ci#define CROSSOVER_AUTO  3
1262306a36Sopenharmony_ci
1362306a36Sopenharmony_ci#define INTR_ENABLE_MASK 0x6CA0
1462306a36Sopenharmony_ci
1562306a36Sopenharmony_ci/*
1662306a36Sopenharmony_ci * Set the bits given by 'bitval' in PHY register 'reg'.
1762306a36Sopenharmony_ci */
1862306a36Sopenharmony_cistatic void mdio_set_bit(struct cphy *cphy, int reg, u32 bitval)
1962306a36Sopenharmony_ci{
2062306a36Sopenharmony_ci	u32 val;
2162306a36Sopenharmony_ci
2262306a36Sopenharmony_ci	(void) simple_mdio_read(cphy, reg, &val);
2362306a36Sopenharmony_ci	(void) simple_mdio_write(cphy, reg, val | bitval);
2462306a36Sopenharmony_ci}
2562306a36Sopenharmony_ci
2662306a36Sopenharmony_ci/*
2762306a36Sopenharmony_ci * Clear the bits given by 'bitval' in PHY register 'reg'.
2862306a36Sopenharmony_ci */
2962306a36Sopenharmony_cistatic void mdio_clear_bit(struct cphy *cphy, int reg, u32 bitval)
3062306a36Sopenharmony_ci{
3162306a36Sopenharmony_ci	u32 val;
3262306a36Sopenharmony_ci
3362306a36Sopenharmony_ci	(void) simple_mdio_read(cphy, reg, &val);
3462306a36Sopenharmony_ci	(void) simple_mdio_write(cphy, reg, val & ~bitval);
3562306a36Sopenharmony_ci}
3662306a36Sopenharmony_ci
3762306a36Sopenharmony_ci/*
3862306a36Sopenharmony_ci * NAME:   phy_reset
3962306a36Sopenharmony_ci *
4062306a36Sopenharmony_ci * DESC:   Reset the given PHY's port. NOTE: This is not a global
4162306a36Sopenharmony_ci *         chip reset.
4262306a36Sopenharmony_ci *
4362306a36Sopenharmony_ci * PARAMS: cphy     - Pointer to PHY instance data.
4462306a36Sopenharmony_ci *
4562306a36Sopenharmony_ci * RETURN:  0 - Successful reset.
4662306a36Sopenharmony_ci *         -1 - Timeout.
4762306a36Sopenharmony_ci */
4862306a36Sopenharmony_cistatic int mv88e1xxx_reset(struct cphy *cphy, int wait)
4962306a36Sopenharmony_ci{
5062306a36Sopenharmony_ci	u32 ctl;
5162306a36Sopenharmony_ci	int time_out = 1000;
5262306a36Sopenharmony_ci
5362306a36Sopenharmony_ci	mdio_set_bit(cphy, MII_BMCR, BMCR_RESET);
5462306a36Sopenharmony_ci
5562306a36Sopenharmony_ci	do {
5662306a36Sopenharmony_ci		(void) simple_mdio_read(cphy, MII_BMCR, &ctl);
5762306a36Sopenharmony_ci		ctl &= BMCR_RESET;
5862306a36Sopenharmony_ci		if (ctl)
5962306a36Sopenharmony_ci			udelay(1);
6062306a36Sopenharmony_ci	} while (ctl && --time_out);
6162306a36Sopenharmony_ci
6262306a36Sopenharmony_ci	return ctl ? -1 : 0;
6362306a36Sopenharmony_ci}
6462306a36Sopenharmony_ci
6562306a36Sopenharmony_cistatic int mv88e1xxx_interrupt_enable(struct cphy *cphy)
6662306a36Sopenharmony_ci{
6762306a36Sopenharmony_ci	/* Enable PHY interrupts. */
6862306a36Sopenharmony_ci	(void) simple_mdio_write(cphy, MV88E1XXX_INTERRUPT_ENABLE_REGISTER,
6962306a36Sopenharmony_ci		   INTR_ENABLE_MASK);
7062306a36Sopenharmony_ci
7162306a36Sopenharmony_ci	/* Enable Marvell interrupts through Elmer0. */
7262306a36Sopenharmony_ci	if (t1_is_asic(cphy->adapter)) {
7362306a36Sopenharmony_ci		u32 elmer;
7462306a36Sopenharmony_ci
7562306a36Sopenharmony_ci		t1_tpi_read(cphy->adapter, A_ELMER0_INT_ENABLE, &elmer);
7662306a36Sopenharmony_ci		elmer |= ELMER0_GP_BIT1;
7762306a36Sopenharmony_ci		if (is_T2(cphy->adapter))
7862306a36Sopenharmony_ci		    elmer |= ELMER0_GP_BIT2 | ELMER0_GP_BIT3 | ELMER0_GP_BIT4;
7962306a36Sopenharmony_ci		t1_tpi_write(cphy->adapter, A_ELMER0_INT_ENABLE, elmer);
8062306a36Sopenharmony_ci	}
8162306a36Sopenharmony_ci	return 0;
8262306a36Sopenharmony_ci}
8362306a36Sopenharmony_ci
8462306a36Sopenharmony_cistatic int mv88e1xxx_interrupt_disable(struct cphy *cphy)
8562306a36Sopenharmony_ci{
8662306a36Sopenharmony_ci	/* Disable all phy interrupts. */
8762306a36Sopenharmony_ci	(void) simple_mdio_write(cphy, MV88E1XXX_INTERRUPT_ENABLE_REGISTER, 0);
8862306a36Sopenharmony_ci
8962306a36Sopenharmony_ci	/* Disable Marvell interrupts through Elmer0. */
9062306a36Sopenharmony_ci	if (t1_is_asic(cphy->adapter)) {
9162306a36Sopenharmony_ci		u32 elmer;
9262306a36Sopenharmony_ci
9362306a36Sopenharmony_ci		t1_tpi_read(cphy->adapter, A_ELMER0_INT_ENABLE, &elmer);
9462306a36Sopenharmony_ci		elmer &= ~ELMER0_GP_BIT1;
9562306a36Sopenharmony_ci		if (is_T2(cphy->adapter))
9662306a36Sopenharmony_ci		    elmer &= ~(ELMER0_GP_BIT2|ELMER0_GP_BIT3|ELMER0_GP_BIT4);
9762306a36Sopenharmony_ci		t1_tpi_write(cphy->adapter, A_ELMER0_INT_ENABLE, elmer);
9862306a36Sopenharmony_ci	}
9962306a36Sopenharmony_ci	return 0;
10062306a36Sopenharmony_ci}
10162306a36Sopenharmony_ci
10262306a36Sopenharmony_cistatic int mv88e1xxx_interrupt_clear(struct cphy *cphy)
10362306a36Sopenharmony_ci{
10462306a36Sopenharmony_ci	u32 elmer;
10562306a36Sopenharmony_ci
10662306a36Sopenharmony_ci	/* Clear PHY interrupts by reading the register. */
10762306a36Sopenharmony_ci	(void) simple_mdio_read(cphy,
10862306a36Sopenharmony_ci			MV88E1XXX_INTERRUPT_STATUS_REGISTER, &elmer);
10962306a36Sopenharmony_ci
11062306a36Sopenharmony_ci	/* Clear Marvell interrupts through Elmer0. */
11162306a36Sopenharmony_ci	if (t1_is_asic(cphy->adapter)) {
11262306a36Sopenharmony_ci		t1_tpi_read(cphy->adapter, A_ELMER0_INT_CAUSE, &elmer);
11362306a36Sopenharmony_ci		elmer |= ELMER0_GP_BIT1;
11462306a36Sopenharmony_ci		if (is_T2(cphy->adapter))
11562306a36Sopenharmony_ci		    elmer |= ELMER0_GP_BIT2|ELMER0_GP_BIT3|ELMER0_GP_BIT4;
11662306a36Sopenharmony_ci		t1_tpi_write(cphy->adapter, A_ELMER0_INT_CAUSE, elmer);
11762306a36Sopenharmony_ci	}
11862306a36Sopenharmony_ci	return 0;
11962306a36Sopenharmony_ci}
12062306a36Sopenharmony_ci
12162306a36Sopenharmony_ci/*
12262306a36Sopenharmony_ci * Set the PHY speed and duplex.  This also disables auto-negotiation, except
12362306a36Sopenharmony_ci * for 1Gb/s, where auto-negotiation is mandatory.
12462306a36Sopenharmony_ci */
12562306a36Sopenharmony_cistatic int mv88e1xxx_set_speed_duplex(struct cphy *phy, int speed, int duplex)
12662306a36Sopenharmony_ci{
12762306a36Sopenharmony_ci	u32 ctl;
12862306a36Sopenharmony_ci
12962306a36Sopenharmony_ci	(void) simple_mdio_read(phy, MII_BMCR, &ctl);
13062306a36Sopenharmony_ci	if (speed >= 0) {
13162306a36Sopenharmony_ci		ctl &= ~(BMCR_SPEED100 | BMCR_SPEED1000 | BMCR_ANENABLE);
13262306a36Sopenharmony_ci		if (speed == SPEED_100)
13362306a36Sopenharmony_ci			ctl |= BMCR_SPEED100;
13462306a36Sopenharmony_ci		else if (speed == SPEED_1000)
13562306a36Sopenharmony_ci			ctl |= BMCR_SPEED1000;
13662306a36Sopenharmony_ci	}
13762306a36Sopenharmony_ci	if (duplex >= 0) {
13862306a36Sopenharmony_ci		ctl &= ~(BMCR_FULLDPLX | BMCR_ANENABLE);
13962306a36Sopenharmony_ci		if (duplex == DUPLEX_FULL)
14062306a36Sopenharmony_ci			ctl |= BMCR_FULLDPLX;
14162306a36Sopenharmony_ci	}
14262306a36Sopenharmony_ci	if (ctl & BMCR_SPEED1000)  /* auto-negotiation required for 1Gb/s */
14362306a36Sopenharmony_ci		ctl |= BMCR_ANENABLE;
14462306a36Sopenharmony_ci	(void) simple_mdio_write(phy, MII_BMCR, ctl);
14562306a36Sopenharmony_ci	return 0;
14662306a36Sopenharmony_ci}
14762306a36Sopenharmony_ci
14862306a36Sopenharmony_cistatic int mv88e1xxx_crossover_set(struct cphy *cphy, int crossover)
14962306a36Sopenharmony_ci{
15062306a36Sopenharmony_ci	u32 data32;
15162306a36Sopenharmony_ci
15262306a36Sopenharmony_ci	(void) simple_mdio_read(cphy,
15362306a36Sopenharmony_ci			MV88E1XXX_SPECIFIC_CNTRL_REGISTER, &data32);
15462306a36Sopenharmony_ci	data32 &= ~V_PSCR_MDI_XOVER_MODE(M_PSCR_MDI_XOVER_MODE);
15562306a36Sopenharmony_ci	data32 |= V_PSCR_MDI_XOVER_MODE(crossover);
15662306a36Sopenharmony_ci	(void) simple_mdio_write(cphy,
15762306a36Sopenharmony_ci			MV88E1XXX_SPECIFIC_CNTRL_REGISTER, data32);
15862306a36Sopenharmony_ci	return 0;
15962306a36Sopenharmony_ci}
16062306a36Sopenharmony_ci
16162306a36Sopenharmony_cistatic int mv88e1xxx_autoneg_enable(struct cphy *cphy)
16262306a36Sopenharmony_ci{
16362306a36Sopenharmony_ci	u32 ctl;
16462306a36Sopenharmony_ci
16562306a36Sopenharmony_ci	(void) mv88e1xxx_crossover_set(cphy, CROSSOVER_AUTO);
16662306a36Sopenharmony_ci
16762306a36Sopenharmony_ci	(void) simple_mdio_read(cphy, MII_BMCR, &ctl);
16862306a36Sopenharmony_ci	/* restart autoneg for change to take effect */
16962306a36Sopenharmony_ci	ctl |= BMCR_ANENABLE | BMCR_ANRESTART;
17062306a36Sopenharmony_ci	(void) simple_mdio_write(cphy, MII_BMCR, ctl);
17162306a36Sopenharmony_ci	return 0;
17262306a36Sopenharmony_ci}
17362306a36Sopenharmony_ci
17462306a36Sopenharmony_cistatic int mv88e1xxx_autoneg_disable(struct cphy *cphy)
17562306a36Sopenharmony_ci{
17662306a36Sopenharmony_ci	u32 ctl;
17762306a36Sopenharmony_ci
17862306a36Sopenharmony_ci	/*
17962306a36Sopenharmony_ci	 * Crossover *must* be set to manual in order to disable auto-neg.
18062306a36Sopenharmony_ci	 * The Alaska FAQs document highlights this point.
18162306a36Sopenharmony_ci	 */
18262306a36Sopenharmony_ci	(void) mv88e1xxx_crossover_set(cphy, CROSSOVER_MDI);
18362306a36Sopenharmony_ci
18462306a36Sopenharmony_ci	/*
18562306a36Sopenharmony_ci	 * Must include autoneg reset when disabling auto-neg. This
18662306a36Sopenharmony_ci	 * is described in the Alaska FAQ document.
18762306a36Sopenharmony_ci	 */
18862306a36Sopenharmony_ci	(void) simple_mdio_read(cphy, MII_BMCR, &ctl);
18962306a36Sopenharmony_ci	ctl &= ~BMCR_ANENABLE;
19062306a36Sopenharmony_ci	(void) simple_mdio_write(cphy, MII_BMCR, ctl | BMCR_ANRESTART);
19162306a36Sopenharmony_ci	return 0;
19262306a36Sopenharmony_ci}
19362306a36Sopenharmony_ci
19462306a36Sopenharmony_cistatic int mv88e1xxx_autoneg_restart(struct cphy *cphy)
19562306a36Sopenharmony_ci{
19662306a36Sopenharmony_ci	mdio_set_bit(cphy, MII_BMCR, BMCR_ANRESTART);
19762306a36Sopenharmony_ci	return 0;
19862306a36Sopenharmony_ci}
19962306a36Sopenharmony_ci
20062306a36Sopenharmony_cistatic int mv88e1xxx_advertise(struct cphy *phy, unsigned int advertise_map)
20162306a36Sopenharmony_ci{
20262306a36Sopenharmony_ci	u32 val = 0;
20362306a36Sopenharmony_ci
20462306a36Sopenharmony_ci	if (advertise_map &
20562306a36Sopenharmony_ci	    (ADVERTISED_1000baseT_Half | ADVERTISED_1000baseT_Full)) {
20662306a36Sopenharmony_ci		(void) simple_mdio_read(phy, MII_GBCR, &val);
20762306a36Sopenharmony_ci		val &= ~(GBCR_ADV_1000HALF | GBCR_ADV_1000FULL);
20862306a36Sopenharmony_ci		if (advertise_map & ADVERTISED_1000baseT_Half)
20962306a36Sopenharmony_ci			val |= GBCR_ADV_1000HALF;
21062306a36Sopenharmony_ci		if (advertise_map & ADVERTISED_1000baseT_Full)
21162306a36Sopenharmony_ci			val |= GBCR_ADV_1000FULL;
21262306a36Sopenharmony_ci	}
21362306a36Sopenharmony_ci	(void) simple_mdio_write(phy, MII_GBCR, val);
21462306a36Sopenharmony_ci
21562306a36Sopenharmony_ci	val = 1;
21662306a36Sopenharmony_ci	if (advertise_map & ADVERTISED_10baseT_Half)
21762306a36Sopenharmony_ci		val |= ADVERTISE_10HALF;
21862306a36Sopenharmony_ci	if (advertise_map & ADVERTISED_10baseT_Full)
21962306a36Sopenharmony_ci		val |= ADVERTISE_10FULL;
22062306a36Sopenharmony_ci	if (advertise_map & ADVERTISED_100baseT_Half)
22162306a36Sopenharmony_ci		val |= ADVERTISE_100HALF;
22262306a36Sopenharmony_ci	if (advertise_map & ADVERTISED_100baseT_Full)
22362306a36Sopenharmony_ci		val |= ADVERTISE_100FULL;
22462306a36Sopenharmony_ci	if (advertise_map & ADVERTISED_PAUSE)
22562306a36Sopenharmony_ci		val |= ADVERTISE_PAUSE;
22662306a36Sopenharmony_ci	if (advertise_map & ADVERTISED_ASYM_PAUSE)
22762306a36Sopenharmony_ci		val |= ADVERTISE_PAUSE_ASYM;
22862306a36Sopenharmony_ci	(void) simple_mdio_write(phy, MII_ADVERTISE, val);
22962306a36Sopenharmony_ci	return 0;
23062306a36Sopenharmony_ci}
23162306a36Sopenharmony_ci
23262306a36Sopenharmony_cistatic int mv88e1xxx_set_loopback(struct cphy *cphy, int on)
23362306a36Sopenharmony_ci{
23462306a36Sopenharmony_ci	if (on)
23562306a36Sopenharmony_ci		mdio_set_bit(cphy, MII_BMCR, BMCR_LOOPBACK);
23662306a36Sopenharmony_ci	else
23762306a36Sopenharmony_ci		mdio_clear_bit(cphy, MII_BMCR, BMCR_LOOPBACK);
23862306a36Sopenharmony_ci	return 0;
23962306a36Sopenharmony_ci}
24062306a36Sopenharmony_ci
24162306a36Sopenharmony_cistatic int mv88e1xxx_get_link_status(struct cphy *cphy, int *link_ok,
24262306a36Sopenharmony_ci				     int *speed, int *duplex, int *fc)
24362306a36Sopenharmony_ci{
24462306a36Sopenharmony_ci	u32 status;
24562306a36Sopenharmony_ci	int sp = -1, dplx = -1, pause = 0;
24662306a36Sopenharmony_ci
24762306a36Sopenharmony_ci	(void) simple_mdio_read(cphy,
24862306a36Sopenharmony_ci			MV88E1XXX_SPECIFIC_STATUS_REGISTER, &status);
24962306a36Sopenharmony_ci	if ((status & V_PSSR_STATUS_RESOLVED) != 0) {
25062306a36Sopenharmony_ci		if (status & V_PSSR_RX_PAUSE)
25162306a36Sopenharmony_ci			pause |= PAUSE_RX;
25262306a36Sopenharmony_ci		if (status & V_PSSR_TX_PAUSE)
25362306a36Sopenharmony_ci			pause |= PAUSE_TX;
25462306a36Sopenharmony_ci		dplx = (status & V_PSSR_DUPLEX) ? DUPLEX_FULL : DUPLEX_HALF;
25562306a36Sopenharmony_ci		sp = G_PSSR_SPEED(status);
25662306a36Sopenharmony_ci		if (sp == 0)
25762306a36Sopenharmony_ci			sp = SPEED_10;
25862306a36Sopenharmony_ci		else if (sp == 1)
25962306a36Sopenharmony_ci			sp = SPEED_100;
26062306a36Sopenharmony_ci		else
26162306a36Sopenharmony_ci			sp = SPEED_1000;
26262306a36Sopenharmony_ci	}
26362306a36Sopenharmony_ci	if (link_ok)
26462306a36Sopenharmony_ci		*link_ok = (status & V_PSSR_LINK) != 0;
26562306a36Sopenharmony_ci	if (speed)
26662306a36Sopenharmony_ci		*speed = sp;
26762306a36Sopenharmony_ci	if (duplex)
26862306a36Sopenharmony_ci		*duplex = dplx;
26962306a36Sopenharmony_ci	if (fc)
27062306a36Sopenharmony_ci		*fc = pause;
27162306a36Sopenharmony_ci	return 0;
27262306a36Sopenharmony_ci}
27362306a36Sopenharmony_ci
27462306a36Sopenharmony_cistatic int mv88e1xxx_downshift_set(struct cphy *cphy, int downshift_enable)
27562306a36Sopenharmony_ci{
27662306a36Sopenharmony_ci	u32 val;
27762306a36Sopenharmony_ci
27862306a36Sopenharmony_ci	(void) simple_mdio_read(cphy,
27962306a36Sopenharmony_ci		MV88E1XXX_EXT_PHY_SPECIFIC_CNTRL_REGISTER, &val);
28062306a36Sopenharmony_ci
28162306a36Sopenharmony_ci	/*
28262306a36Sopenharmony_ci	 * Set the downshift counter to 2 so we try to establish Gb link
28362306a36Sopenharmony_ci	 * twice before downshifting.
28462306a36Sopenharmony_ci	 */
28562306a36Sopenharmony_ci	val &= ~(V_DOWNSHIFT_ENABLE | V_DOWNSHIFT_CNT(M_DOWNSHIFT_CNT));
28662306a36Sopenharmony_ci
28762306a36Sopenharmony_ci	if (downshift_enable)
28862306a36Sopenharmony_ci		val |= V_DOWNSHIFT_ENABLE | V_DOWNSHIFT_CNT(2);
28962306a36Sopenharmony_ci	(void) simple_mdio_write(cphy,
29062306a36Sopenharmony_ci			MV88E1XXX_EXT_PHY_SPECIFIC_CNTRL_REGISTER, val);
29162306a36Sopenharmony_ci	return 0;
29262306a36Sopenharmony_ci}
29362306a36Sopenharmony_ci
29462306a36Sopenharmony_cistatic int mv88e1xxx_interrupt_handler(struct cphy *cphy)
29562306a36Sopenharmony_ci{
29662306a36Sopenharmony_ci	int cphy_cause = 0;
29762306a36Sopenharmony_ci	u32 status;
29862306a36Sopenharmony_ci
29962306a36Sopenharmony_ci	/*
30062306a36Sopenharmony_ci	 * Loop until cause reads zero. Need to handle bouncing interrupts.
30162306a36Sopenharmony_ci	 */
30262306a36Sopenharmony_ci	while (1) {
30362306a36Sopenharmony_ci		u32 cause;
30462306a36Sopenharmony_ci
30562306a36Sopenharmony_ci		(void) simple_mdio_read(cphy,
30662306a36Sopenharmony_ci				MV88E1XXX_INTERRUPT_STATUS_REGISTER,
30762306a36Sopenharmony_ci				&cause);
30862306a36Sopenharmony_ci		cause &= INTR_ENABLE_MASK;
30962306a36Sopenharmony_ci		if (!cause)
31062306a36Sopenharmony_ci			break;
31162306a36Sopenharmony_ci
31262306a36Sopenharmony_ci		if (cause & MV88E1XXX_INTR_LINK_CHNG) {
31362306a36Sopenharmony_ci			(void) simple_mdio_read(cphy,
31462306a36Sopenharmony_ci				MV88E1XXX_SPECIFIC_STATUS_REGISTER, &status);
31562306a36Sopenharmony_ci
31662306a36Sopenharmony_ci			if (status & MV88E1XXX_INTR_LINK_CHNG)
31762306a36Sopenharmony_ci				cphy->state |= PHY_LINK_UP;
31862306a36Sopenharmony_ci			else {
31962306a36Sopenharmony_ci				cphy->state &= ~PHY_LINK_UP;
32062306a36Sopenharmony_ci				if (cphy->state & PHY_AUTONEG_EN)
32162306a36Sopenharmony_ci					cphy->state &= ~PHY_AUTONEG_RDY;
32262306a36Sopenharmony_ci				cphy_cause |= cphy_cause_link_change;
32362306a36Sopenharmony_ci			}
32462306a36Sopenharmony_ci		}
32562306a36Sopenharmony_ci
32662306a36Sopenharmony_ci		if (cause & MV88E1XXX_INTR_AUTONEG_DONE)
32762306a36Sopenharmony_ci			cphy->state |= PHY_AUTONEG_RDY;
32862306a36Sopenharmony_ci
32962306a36Sopenharmony_ci		if ((cphy->state & (PHY_LINK_UP | PHY_AUTONEG_RDY)) ==
33062306a36Sopenharmony_ci			(PHY_LINK_UP | PHY_AUTONEG_RDY))
33162306a36Sopenharmony_ci				cphy_cause |= cphy_cause_link_change;
33262306a36Sopenharmony_ci	}
33362306a36Sopenharmony_ci	return cphy_cause;
33462306a36Sopenharmony_ci}
33562306a36Sopenharmony_ci
33662306a36Sopenharmony_cistatic void mv88e1xxx_destroy(struct cphy *cphy)
33762306a36Sopenharmony_ci{
33862306a36Sopenharmony_ci	kfree(cphy);
33962306a36Sopenharmony_ci}
34062306a36Sopenharmony_ci
34162306a36Sopenharmony_cistatic const struct cphy_ops mv88e1xxx_ops = {
34262306a36Sopenharmony_ci	.destroy              = mv88e1xxx_destroy,
34362306a36Sopenharmony_ci	.reset                = mv88e1xxx_reset,
34462306a36Sopenharmony_ci	.interrupt_enable     = mv88e1xxx_interrupt_enable,
34562306a36Sopenharmony_ci	.interrupt_disable    = mv88e1xxx_interrupt_disable,
34662306a36Sopenharmony_ci	.interrupt_clear      = mv88e1xxx_interrupt_clear,
34762306a36Sopenharmony_ci	.interrupt_handler    = mv88e1xxx_interrupt_handler,
34862306a36Sopenharmony_ci	.autoneg_enable       = mv88e1xxx_autoneg_enable,
34962306a36Sopenharmony_ci	.autoneg_disable      = mv88e1xxx_autoneg_disable,
35062306a36Sopenharmony_ci	.autoneg_restart      = mv88e1xxx_autoneg_restart,
35162306a36Sopenharmony_ci	.advertise            = mv88e1xxx_advertise,
35262306a36Sopenharmony_ci	.set_loopback         = mv88e1xxx_set_loopback,
35362306a36Sopenharmony_ci	.set_speed_duplex     = mv88e1xxx_set_speed_duplex,
35462306a36Sopenharmony_ci	.get_link_status      = mv88e1xxx_get_link_status,
35562306a36Sopenharmony_ci};
35662306a36Sopenharmony_ci
35762306a36Sopenharmony_cistatic struct cphy *mv88e1xxx_phy_create(struct net_device *dev, int phy_addr,
35862306a36Sopenharmony_ci					 const struct mdio_ops *mdio_ops)
35962306a36Sopenharmony_ci{
36062306a36Sopenharmony_ci	struct adapter *adapter = netdev_priv(dev);
36162306a36Sopenharmony_ci	struct cphy *cphy = kzalloc(sizeof(*cphy), GFP_KERNEL);
36262306a36Sopenharmony_ci
36362306a36Sopenharmony_ci	if (!cphy)
36462306a36Sopenharmony_ci		return NULL;
36562306a36Sopenharmony_ci
36662306a36Sopenharmony_ci	cphy_init(cphy, dev, phy_addr, &mv88e1xxx_ops, mdio_ops);
36762306a36Sopenharmony_ci
36862306a36Sopenharmony_ci	/* Configure particular PHY's to run in a different mode. */
36962306a36Sopenharmony_ci	if ((board_info(adapter)->caps & SUPPORTED_TP) &&
37062306a36Sopenharmony_ci	    board_info(adapter)->chip_phy == CHBT_PHY_88E1111) {
37162306a36Sopenharmony_ci		/*
37262306a36Sopenharmony_ci		 * Configure the PHY transmitter as class A to reduce EMI.
37362306a36Sopenharmony_ci		 */
37462306a36Sopenharmony_ci		(void) simple_mdio_write(cphy,
37562306a36Sopenharmony_ci				MV88E1XXX_EXTENDED_ADDR_REGISTER, 0xB);
37662306a36Sopenharmony_ci		(void) simple_mdio_write(cphy,
37762306a36Sopenharmony_ci				MV88E1XXX_EXTENDED_REGISTER, 0x8004);
37862306a36Sopenharmony_ci	}
37962306a36Sopenharmony_ci	(void) mv88e1xxx_downshift_set(cphy, 1);   /* Enable downshift */
38062306a36Sopenharmony_ci
38162306a36Sopenharmony_ci	/* LED */
38262306a36Sopenharmony_ci	if (is_T2(adapter)) {
38362306a36Sopenharmony_ci		(void) simple_mdio_write(cphy,
38462306a36Sopenharmony_ci				MV88E1XXX_LED_CONTROL_REGISTER, 0x1);
38562306a36Sopenharmony_ci	}
38662306a36Sopenharmony_ci
38762306a36Sopenharmony_ci	return cphy;
38862306a36Sopenharmony_ci}
38962306a36Sopenharmony_ci
39062306a36Sopenharmony_cistatic int mv88e1xxx_phy_reset(adapter_t* adapter)
39162306a36Sopenharmony_ci{
39262306a36Sopenharmony_ci	return 0;
39362306a36Sopenharmony_ci}
39462306a36Sopenharmony_ci
39562306a36Sopenharmony_ciconst struct gphy t1_mv88e1xxx_ops = {
39662306a36Sopenharmony_ci	.create = mv88e1xxx_phy_create,
39762306a36Sopenharmony_ci	.reset =  mv88e1xxx_phy_reset
39862306a36Sopenharmony_ci};
399