1352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemminger/* $Date: 2005/10/24 23:18:13 $ $RCSfile: mv88e1xxx.c,v $ $Revision: 1.49 $ */
2352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemminger#include "common.h"
3352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemminger#include "mv88e1xxx.h"
4352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemminger#include "cphy.h"
5352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemminger#include "elmer0.h"
6352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemminger
7352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemminger/* MV88E1XXX MDI crossover register values */
8352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemminger#define CROSSOVER_MDI   0
9352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemminger#define CROSSOVER_MDIX  1
10352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemminger#define CROSSOVER_AUTO  3
11352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemminger
12352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemminger#define INTR_ENABLE_MASK 0x6CA0
13352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemminger
14352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemminger/*
15352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemminger * Set the bits given by 'bitval' in PHY register 'reg'.
16352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemminger */
17352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemmingerstatic void mdio_set_bit(struct cphy *cphy, int reg, u32 bitval)
18352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemminger{
19352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemminger	u32 val;
20352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemminger
21352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemminger	(void) simple_mdio_read(cphy, reg, &val);
22352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemminger	(void) simple_mdio_write(cphy, reg, val | bitval);
23352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemminger}
24352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemminger
25352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemminger/*
26352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemminger * Clear the bits given by 'bitval' in PHY register 'reg'.
27352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemminger */
28352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemmingerstatic void mdio_clear_bit(struct cphy *cphy, int reg, u32 bitval)
29352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemminger{
30352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemminger	u32 val;
31352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemminger
32352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemminger	(void) simple_mdio_read(cphy, reg, &val);
33352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemminger	(void) simple_mdio_write(cphy, reg, val & ~bitval);
34352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemminger}
35352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemminger
36352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemminger/*
37352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemminger * NAME:   phy_reset
38352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemminger *
39352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemminger * DESC:   Reset the given PHY's port. NOTE: This is not a global
40352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemminger *         chip reset.
41352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemminger *
42352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemminger * PARAMS: cphy     - Pointer to PHY instance data.
43352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemminger *
4425985edcedea6396277003854657b5f3cb31a628Lucas De Marchi * RETURN:  0 - Successful reset.
45352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemminger *         -1 - Timeout.
46352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemminger */
47352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemmingerstatic int mv88e1xxx_reset(struct cphy *cphy, int wait)
48352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemminger{
49352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemminger	u32 ctl;
50352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemminger	int time_out = 1000;
51352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemminger
52352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemminger	mdio_set_bit(cphy, MII_BMCR, BMCR_RESET);
53352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemminger
54352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemminger	do {
55352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemminger		(void) simple_mdio_read(cphy, MII_BMCR, &ctl);
56352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemminger		ctl &= BMCR_RESET;
57352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemminger		if (ctl)
58352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemminger			udelay(1);
59352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemminger	} while (ctl && --time_out);
60352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemminger
61352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemminger	return ctl ? -1 : 0;
62352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemminger}
63352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemminger
64352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemmingerstatic int mv88e1xxx_interrupt_enable(struct cphy *cphy)
65352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemminger{
66352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemminger	/* Enable PHY interrupts. */
67352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemminger	(void) simple_mdio_write(cphy, MV88E1XXX_INTERRUPT_ENABLE_REGISTER,
68352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemminger		   INTR_ENABLE_MASK);
69352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemminger
70352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemminger	/* Enable Marvell interrupts through Elmer0. */
71352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemminger	if (t1_is_asic(cphy->adapter)) {
72352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemminger		u32 elmer;
73352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemminger
74352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemminger		t1_tpi_read(cphy->adapter, A_ELMER0_INT_ENABLE, &elmer);
75352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemminger		elmer |= ELMER0_GP_BIT1;
76356bd1460d1e1c4e433e4114fdac02139bddf17cFrancois Romieu		if (is_T2(cphy->adapter))
77356bd1460d1e1c4e433e4114fdac02139bddf17cFrancois Romieu		    elmer |= ELMER0_GP_BIT2 | ELMER0_GP_BIT3 | ELMER0_GP_BIT4;
78352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemminger		t1_tpi_write(cphy->adapter, A_ELMER0_INT_ENABLE, elmer);
79352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemminger	}
80352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemminger	return 0;
81352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemminger}
82352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemminger
83352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemmingerstatic int mv88e1xxx_interrupt_disable(struct cphy *cphy)
84352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemminger{
85352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemminger	/* Disable all phy interrupts. */
86352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemminger	(void) simple_mdio_write(cphy, MV88E1XXX_INTERRUPT_ENABLE_REGISTER, 0);
87352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemminger
88352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemminger	/* Disable Marvell interrupts through Elmer0. */
89352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemminger	if (t1_is_asic(cphy->adapter)) {
90352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemminger		u32 elmer;
91352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemminger
92352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemminger		t1_tpi_read(cphy->adapter, A_ELMER0_INT_ENABLE, &elmer);
93352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemminger		elmer &= ~ELMER0_GP_BIT1;
94356bd1460d1e1c4e433e4114fdac02139bddf17cFrancois Romieu		if (is_T2(cphy->adapter))
95352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemminger		    elmer &= ~(ELMER0_GP_BIT2|ELMER0_GP_BIT3|ELMER0_GP_BIT4);
96352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemminger		t1_tpi_write(cphy->adapter, A_ELMER0_INT_ENABLE, elmer);
97352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemminger	}
98352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemminger	return 0;
99352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemminger}
100352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemminger
101352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemmingerstatic int mv88e1xxx_interrupt_clear(struct cphy *cphy)
102352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemminger{
103352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemminger	u32 elmer;
104352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemminger
105352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemminger	/* Clear PHY interrupts by reading the register. */
106352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemminger	(void) simple_mdio_read(cphy,
107352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemminger			MV88E1XXX_INTERRUPT_STATUS_REGISTER, &elmer);
108352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemminger
109352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemminger	/* Clear Marvell interrupts through Elmer0. */
110352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemminger	if (t1_is_asic(cphy->adapter)) {
111352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemminger		t1_tpi_read(cphy->adapter, A_ELMER0_INT_CAUSE, &elmer);
112352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemminger		elmer |= ELMER0_GP_BIT1;
113356bd1460d1e1c4e433e4114fdac02139bddf17cFrancois Romieu		if (is_T2(cphy->adapter))
114352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemminger		    elmer |= ELMER0_GP_BIT2|ELMER0_GP_BIT3|ELMER0_GP_BIT4;
115352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemminger		t1_tpi_write(cphy->adapter, A_ELMER0_INT_CAUSE, elmer);
116352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemminger	}
117352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemminger	return 0;
118352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemminger}
119352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemminger
120352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemminger/*
121352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemminger * Set the PHY speed and duplex.  This also disables auto-negotiation, except
122352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemminger * for 1Gb/s, where auto-negotiation is mandatory.
123352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemminger */
124352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemmingerstatic int mv88e1xxx_set_speed_duplex(struct cphy *phy, int speed, int duplex)
125352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemminger{
126352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemminger	u32 ctl;
127352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemminger
128352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemminger	(void) simple_mdio_read(phy, MII_BMCR, &ctl);
129352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemminger	if (speed >= 0) {
130352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemminger		ctl &= ~(BMCR_SPEED100 | BMCR_SPEED1000 | BMCR_ANENABLE);
131352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemminger		if (speed == SPEED_100)
132352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemminger			ctl |= BMCR_SPEED100;
133352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemminger		else if (speed == SPEED_1000)
134352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemminger			ctl |= BMCR_SPEED1000;
135352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemminger	}
136352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemminger	if (duplex >= 0) {
137352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemminger		ctl &= ~(BMCR_FULLDPLX | BMCR_ANENABLE);
138352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemminger		if (duplex == DUPLEX_FULL)
139352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemminger			ctl |= BMCR_FULLDPLX;
140352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemminger	}
141352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemminger	if (ctl & BMCR_SPEED1000)  /* auto-negotiation required for 1Gb/s */
142352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemminger		ctl |= BMCR_ANENABLE;
143352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemminger	(void) simple_mdio_write(phy, MII_BMCR, ctl);
144352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemminger	return 0;
145352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemminger}
146352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemminger
147352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemmingerstatic int mv88e1xxx_crossover_set(struct cphy *cphy, int crossover)
148352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemminger{
149352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemminger	u32 data32;
150352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemminger
151352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemminger	(void) simple_mdio_read(cphy,
152352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemminger			MV88E1XXX_SPECIFIC_CNTRL_REGISTER, &data32);
153352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemminger	data32 &= ~V_PSCR_MDI_XOVER_MODE(M_PSCR_MDI_XOVER_MODE);
154352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemminger	data32 |= V_PSCR_MDI_XOVER_MODE(crossover);
155352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemminger	(void) simple_mdio_write(cphy,
156352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemminger			MV88E1XXX_SPECIFIC_CNTRL_REGISTER, data32);
157352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemminger	return 0;
158352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemminger}
159352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemminger
160352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemmingerstatic int mv88e1xxx_autoneg_enable(struct cphy *cphy)
161352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemminger{
162352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemminger	u32 ctl;
163352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemminger
164352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemminger	(void) mv88e1xxx_crossover_set(cphy, CROSSOVER_AUTO);
165352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemminger
166352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemminger	(void) simple_mdio_read(cphy, MII_BMCR, &ctl);
167352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemminger	/* restart autoneg for change to take effect */
168352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemminger	ctl |= BMCR_ANENABLE | BMCR_ANRESTART;
169352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemminger	(void) simple_mdio_write(cphy, MII_BMCR, ctl);
170352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemminger	return 0;
171352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemminger}
172352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemminger
173352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemmingerstatic int mv88e1xxx_autoneg_disable(struct cphy *cphy)
174352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemminger{
175352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemminger	u32 ctl;
176352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemminger
177352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemminger	/*
178352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemminger	 * Crossover *must* be set to manual in order to disable auto-neg.
179352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemminger	 * The Alaska FAQs document highlights this point.
180352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemminger	 */
181352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemminger	(void) mv88e1xxx_crossover_set(cphy, CROSSOVER_MDI);
182352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemminger
183352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemminger	/*
184352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemminger	 * Must include autoneg reset when disabling auto-neg. This
185352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemminger	 * is described in the Alaska FAQ document.
186352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemminger	 */
187352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemminger	(void) simple_mdio_read(cphy, MII_BMCR, &ctl);
188352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemminger	ctl &= ~BMCR_ANENABLE;
189352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemminger	(void) simple_mdio_write(cphy, MII_BMCR, ctl | BMCR_ANRESTART);
190352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemminger	return 0;
191352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemminger}
192352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemminger
193352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemmingerstatic int mv88e1xxx_autoneg_restart(struct cphy *cphy)
194352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemminger{
195352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemminger	mdio_set_bit(cphy, MII_BMCR, BMCR_ANRESTART);
196352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemminger	return 0;
197352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemminger}
198352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemminger
199352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemmingerstatic int mv88e1xxx_advertise(struct cphy *phy, unsigned int advertise_map)
200352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemminger{
201352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemminger	u32 val = 0;
202352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemminger
203352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemminger	if (advertise_map &
204352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemminger	    (ADVERTISED_1000baseT_Half | ADVERTISED_1000baseT_Full)) {
205352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemminger		(void) simple_mdio_read(phy, MII_GBCR, &val);
206352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemminger		val &= ~(GBCR_ADV_1000HALF | GBCR_ADV_1000FULL);
207352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemminger		if (advertise_map & ADVERTISED_1000baseT_Half)
208352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemminger			val |= GBCR_ADV_1000HALF;
209352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemminger		if (advertise_map & ADVERTISED_1000baseT_Full)
210352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemminger			val |= GBCR_ADV_1000FULL;
211352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemminger	}
212352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemminger	(void) simple_mdio_write(phy, MII_GBCR, val);
213352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemminger
214352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemminger	val = 1;
215352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemminger	if (advertise_map & ADVERTISED_10baseT_Half)
216352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemminger		val |= ADVERTISE_10HALF;
217352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemminger	if (advertise_map & ADVERTISED_10baseT_Full)
218352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemminger		val |= ADVERTISE_10FULL;
219352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemminger	if (advertise_map & ADVERTISED_100baseT_Half)
220352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemminger		val |= ADVERTISE_100HALF;
221352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemminger	if (advertise_map & ADVERTISED_100baseT_Full)
222352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemminger		val |= ADVERTISE_100FULL;
223352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemminger	if (advertise_map & ADVERTISED_PAUSE)
224352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemminger		val |= ADVERTISE_PAUSE;
225352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemminger	if (advertise_map & ADVERTISED_ASYM_PAUSE)
226352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemminger		val |= ADVERTISE_PAUSE_ASYM;
227352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemminger	(void) simple_mdio_write(phy, MII_ADVERTISE, val);
228352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemminger	return 0;
229352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemminger}
230352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemminger
231352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemmingerstatic int mv88e1xxx_set_loopback(struct cphy *cphy, int on)
232352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemminger{
233352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemminger	if (on)
234352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemminger		mdio_set_bit(cphy, MII_BMCR, BMCR_LOOPBACK);
235352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemminger	else
236352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemminger		mdio_clear_bit(cphy, MII_BMCR, BMCR_LOOPBACK);
237352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemminger	return 0;
238352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemminger}
239352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemminger
240352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemmingerstatic int mv88e1xxx_get_link_status(struct cphy *cphy, int *link_ok,
241352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemminger				     int *speed, int *duplex, int *fc)
242352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemminger{
243352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemminger	u32 status;
244352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemminger	int sp = -1, dplx = -1, pause = 0;
245352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemminger
246352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemminger	(void) simple_mdio_read(cphy,
247352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemminger			MV88E1XXX_SPECIFIC_STATUS_REGISTER, &status);
248352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemminger	if ((status & V_PSSR_STATUS_RESOLVED) != 0) {
249352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemminger		if (status & V_PSSR_RX_PAUSE)
250352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemminger			pause |= PAUSE_RX;
251352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemminger		if (status & V_PSSR_TX_PAUSE)
252352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemminger			pause |= PAUSE_TX;
253352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemminger		dplx = (status & V_PSSR_DUPLEX) ? DUPLEX_FULL : DUPLEX_HALF;
254352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemminger		sp = G_PSSR_SPEED(status);
255352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemminger		if (sp == 0)
256352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemminger			sp = SPEED_10;
257352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemminger		else if (sp == 1)
258352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemminger			sp = SPEED_100;
259352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemminger		else
260352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemminger			sp = SPEED_1000;
261352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemminger	}
262352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemminger	if (link_ok)
263352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemminger		*link_ok = (status & V_PSSR_LINK) != 0;
264352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemminger	if (speed)
265352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemminger		*speed = sp;
266352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemminger	if (duplex)
267352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemminger		*duplex = dplx;
268352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemminger	if (fc)
269352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemminger		*fc = pause;
270352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemminger	return 0;
271352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemminger}
272352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemminger
273352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemmingerstatic int mv88e1xxx_downshift_set(struct cphy *cphy, int downshift_enable)
274352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemminger{
275352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemminger	u32 val;
276352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemminger
277352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemminger	(void) simple_mdio_read(cphy,
278352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemminger		MV88E1XXX_EXT_PHY_SPECIFIC_CNTRL_REGISTER, &val);
279352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemminger
280352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemminger	/*
281352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemminger	 * Set the downshift counter to 2 so we try to establish Gb link
282352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemminger	 * twice before downshifting.
283352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemminger	 */
284352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemminger	val &= ~(V_DOWNSHIFT_ENABLE | V_DOWNSHIFT_CNT(M_DOWNSHIFT_CNT));
285352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemminger
286352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemminger	if (downshift_enable)
287352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemminger		val |= V_DOWNSHIFT_ENABLE | V_DOWNSHIFT_CNT(2);
288352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemminger	(void) simple_mdio_write(cphy,
289352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemminger			MV88E1XXX_EXT_PHY_SPECIFIC_CNTRL_REGISTER, val);
290352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemminger	return 0;
291352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemminger}
292352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemminger
293352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemmingerstatic int mv88e1xxx_interrupt_handler(struct cphy *cphy)
294352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemminger{
295352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemminger	int cphy_cause = 0;
296352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemminger	u32 status;
297352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemminger
298352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemminger	/*
299352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemminger	 * Loop until cause reads zero. Need to handle bouncing interrupts.
300356bd1460d1e1c4e433e4114fdac02139bddf17cFrancois Romieu	 */
301352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemminger	while (1) {
302352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemminger		u32 cause;
303352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemminger
304352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemminger		(void) simple_mdio_read(cphy,
305352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemminger				MV88E1XXX_INTERRUPT_STATUS_REGISTER,
306352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemminger				&cause);
307352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemminger		cause &= INTR_ENABLE_MASK;
308c697f83e8c880a1e69fb2a45a6e4aa0670e10602Francois Romieu		if (!cause)
309c697f83e8c880a1e69fb2a45a6e4aa0670e10602Francois Romieu			break;
310352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemminger
311352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemminger		if (cause & MV88E1XXX_INTR_LINK_CHNG) {
312352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemminger			(void) simple_mdio_read(cphy,
313352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemminger				MV88E1XXX_SPECIFIC_STATUS_REGISTER, &status);
314352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemminger
315d7487421b629c5ca71ce23b10461ef0c3ad2c741Francois Romieu			if (status & MV88E1XXX_INTR_LINK_CHNG)
316352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemminger				cphy->state |= PHY_LINK_UP;
317d7487421b629c5ca71ce23b10461ef0c3ad2c741Francois Romieu			else {
318352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemminger				cphy->state &= ~PHY_LINK_UP;
319352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemminger				if (cphy->state & PHY_AUTONEG_EN)
320352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemminger					cphy->state &= ~PHY_AUTONEG_RDY;
321352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemminger				cphy_cause |= cphy_cause_link_change;
322352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemminger			}
323352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemminger		}
324352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemminger
325352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemminger		if (cause & MV88E1XXX_INTR_AUTONEG_DONE)
326352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemminger			cphy->state |= PHY_AUTONEG_RDY;
327352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemminger
328352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemminger		if ((cphy->state & (PHY_LINK_UP | PHY_AUTONEG_RDY)) ==
329352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemminger			(PHY_LINK_UP | PHY_AUTONEG_RDY))
330352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemminger				cphy_cause |= cphy_cause_link_change;
331352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemminger	}
332352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemminger	return cphy_cause;
333352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemminger}
334352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemminger
335352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemmingerstatic void mv88e1xxx_destroy(struct cphy *cphy)
336352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemminger{
337352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemminger	kfree(cphy);
338352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemminger}
339352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemminger
340352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemmingerstatic struct cphy_ops mv88e1xxx_ops = {
341352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemminger	.destroy              = mv88e1xxx_destroy,
342352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemminger	.reset                = mv88e1xxx_reset,
343352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemminger	.interrupt_enable     = mv88e1xxx_interrupt_enable,
344352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemminger	.interrupt_disable    = mv88e1xxx_interrupt_disable,
345352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemminger	.interrupt_clear      = mv88e1xxx_interrupt_clear,
346352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemminger	.interrupt_handler    = mv88e1xxx_interrupt_handler,
347352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemminger	.autoneg_enable       = mv88e1xxx_autoneg_enable,
348352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemminger	.autoneg_disable      = mv88e1xxx_autoneg_disable,
349352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemminger	.autoneg_restart      = mv88e1xxx_autoneg_restart,
350352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemminger	.advertise            = mv88e1xxx_advertise,
351352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemminger	.set_loopback         = mv88e1xxx_set_loopback,
352352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemminger	.set_speed_duplex     = mv88e1xxx_set_speed_duplex,
353352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemminger	.get_link_status      = mv88e1xxx_get_link_status,
354352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemminger};
355352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemminger
356703cebabd173a7fe533d6f21df0347b1f2a9a1e1Divy Le Raystatic struct cphy *mv88e1xxx_phy_create(struct net_device *dev, int phy_addr,
357459e536b1ddfd217ec8a3437a3214968a98223c7Stephen Hemminger					 const struct mdio_ops *mdio_ops)
358352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemminger{
359703cebabd173a7fe533d6f21df0347b1f2a9a1e1Divy Le Ray	struct adapter *adapter = netdev_priv(dev);
360352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemminger	struct cphy *cphy = kzalloc(sizeof(*cphy), GFP_KERNEL);
361352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemminger
362c697f83e8c880a1e69fb2a45a6e4aa0670e10602Francois Romieu	if (!cphy)
363c697f83e8c880a1e69fb2a45a6e4aa0670e10602Francois Romieu		return NULL;
364352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemminger
365703cebabd173a7fe533d6f21df0347b1f2a9a1e1Divy Le Ray	cphy_init(cphy, dev, phy_addr, &mv88e1xxx_ops, mdio_ops);
366352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemminger
367352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemminger	/* Configure particular PHY's to run in a different mode. */
368352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemminger	if ((board_info(adapter)->caps & SUPPORTED_TP) &&
369352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemminger	    board_info(adapter)->chip_phy == CHBT_PHY_88E1111) {
370352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemminger		/*
371352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemminger		 * Configure the PHY transmitter as class A to reduce EMI.
372352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemminger		 */
373352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemminger		(void) simple_mdio_write(cphy,
374352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemminger				MV88E1XXX_EXTENDED_ADDR_REGISTER, 0xB);
375352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemminger		(void) simple_mdio_write(cphy,
376352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemminger				MV88E1XXX_EXTENDED_REGISTER, 0x8004);
377352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemminger	}
378352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemminger	(void) mv88e1xxx_downshift_set(cphy, 1);   /* Enable downshift */
379352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemminger
380356bd1460d1e1c4e433e4114fdac02139bddf17cFrancois Romieu	/* LED */
381352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemminger	if (is_T2(adapter)) {
382352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemminger		(void) simple_mdio_write(cphy,
383352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemminger				MV88E1XXX_LED_CONTROL_REGISTER, 0x1);
384356bd1460d1e1c4e433e4114fdac02139bddf17cFrancois Romieu	}
385352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemminger
386352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemminger	return cphy;
387352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemminger}
388352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemminger
389352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemmingerstatic int mv88e1xxx_phy_reset(adapter_t* adapter)
390352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemminger{
391352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemminger	return 0;
392352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemminger}
393352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemminger
394459e536b1ddfd217ec8a3437a3214968a98223c7Stephen Hemmingerconst struct gphy t1_mv88e1xxx_ops = {
395459e536b1ddfd217ec8a3437a3214968a98223c7Stephen Hemminger	.create = mv88e1xxx_phy_create,
396459e536b1ddfd217ec8a3437a3214968a98223c7Stephen Hemminger	.reset =  mv88e1xxx_phy_reset
397352c417ddb593de757f0ee1fa490cb5444778c41Stephen Hemminger};
398