1d39a76e7Sxw /*
2d39a76e7Sxw * CDDL HEADER START
3d39a76e7Sxw *
4d39a76e7Sxw * The contents of this file are subject to the terms of the
5d39a76e7Sxw * Common Development and Distribution License (the "License").
6d39a76e7Sxw * You may not use this file except in compliance with the License.
7d39a76e7Sxw *
8d39a76e7Sxw * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9d39a76e7Sxw * or http://www.opensolaris.org/os/licensing.
10d39a76e7Sxw * See the License for the specific language governing permissions
11d39a76e7Sxw * and limitations under the License.
12d39a76e7Sxw *
13d39a76e7Sxw * When distributing Covered Code, include this CDDL HEADER in each
14d39a76e7Sxw * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15d39a76e7Sxw * If applicable, add the following below this CDDL HEADER, with the
16d39a76e7Sxw * fields enclosed by brackets "[]" replaced with your own identifying
17d39a76e7Sxw * information: Portions Copyright [yyyy] [name of copyright owner]
18d39a76e7Sxw *
19d39a76e7Sxw * CDDL HEADER END
20d39a76e7Sxw */
21d39a76e7Sxw
22d39a76e7Sxw /*
23d39a76e7Sxw * Copyright (C) 2003-2005 Chelsio Communications. All rights reserved.
24d39a76e7Sxw */
25d39a76e7Sxw
26d39a76e7Sxw #include "common.h"
27d39a76e7Sxw #include "mv88e1xxx.h"
28d39a76e7Sxw #include "cphy.h"
29d39a76e7Sxw #include "elmer0.h"
30d39a76e7Sxw
31d39a76e7Sxw /* MV88E1XXX MDI crossover register values */
32d39a76e7Sxw #define CROSSOVER_MDI 0
33d39a76e7Sxw #define CROSSOVER_MDIX 1
34d39a76e7Sxw #define CROSSOVER_AUTO 3
35d39a76e7Sxw
36d39a76e7Sxw #define INTR_ENABLE_MASK 0x6CA0
37d39a76e7Sxw
38d39a76e7Sxw /*
39d39a76e7Sxw * Set the bits given by 'bitval' in PHY register 'reg'.
40d39a76e7Sxw */
mdio_set_bit(struct cphy * cphy,int reg,u32 bitval)41d39a76e7Sxw static void mdio_set_bit(struct cphy *cphy, int reg, u32 bitval)
42d39a76e7Sxw {
43d39a76e7Sxw u32 val;
44d39a76e7Sxw
45d39a76e7Sxw (void) simple_mdio_read(cphy, reg, &val);
46d39a76e7Sxw (void) simple_mdio_write(cphy, reg, val | bitval);
47d39a76e7Sxw }
48d39a76e7Sxw
49d39a76e7Sxw /*
50d39a76e7Sxw * Clear the bits given by 'bitval' in PHY register 'reg'.
51d39a76e7Sxw */
mdio_clear_bit(struct cphy * cphy,int reg,u32 bitval)52d39a76e7Sxw static void mdio_clear_bit(struct cphy *cphy, int reg, u32 bitval)
53d39a76e7Sxw {
54d39a76e7Sxw u32 val;
55d39a76e7Sxw
56d39a76e7Sxw (void) simple_mdio_read(cphy, reg, &val);
57d39a76e7Sxw (void) simple_mdio_write(cphy, reg, val & ~bitval);
58d39a76e7Sxw }
59d39a76e7Sxw
60d39a76e7Sxw /*
61d39a76e7Sxw * NAME: phy_reset
62d39a76e7Sxw *
63d39a76e7Sxw * DESC: Reset the given PHY's port. NOTE: This is not a global
64d39a76e7Sxw * chip reset.
65d39a76e7Sxw *
66d39a76e7Sxw * PARAMS: cphy - Pointer to PHY instance data.
67*2d6eb4a5SToomas Soome *
68d39a76e7Sxw * RETURN: 0 - Successfull reset.
69d39a76e7Sxw * -1 - Timeout.
70d39a76e7Sxw */
71d39a76e7Sxw /* ARGSUSED */
mv88e1xxx_reset(struct cphy * cphy,int wait)72d39a76e7Sxw static int mv88e1xxx_reset(struct cphy *cphy, int wait)
73d39a76e7Sxw {
74d39a76e7Sxw u32 ctl;
75d39a76e7Sxw int time_out = 1000;
76d39a76e7Sxw
77d39a76e7Sxw mdio_set_bit(cphy, MII_BMCR, BMCR_RESET);
78d39a76e7Sxw
79d39a76e7Sxw do {
80d39a76e7Sxw (void) simple_mdio_read(cphy, MII_BMCR, &ctl);
81d39a76e7Sxw ctl &= BMCR_RESET;
82d39a76e7Sxw if (ctl)
83d39a76e7Sxw DELAY_US(1);
84d39a76e7Sxw } while (ctl && --time_out);
85d39a76e7Sxw
86d39a76e7Sxw return ctl ? -1 : 0;
87d39a76e7Sxw }
88d39a76e7Sxw
mv88e1xxx_interrupt_enable(struct cphy * cphy)89d39a76e7Sxw static int mv88e1xxx_interrupt_enable(struct cphy *cphy)
90d39a76e7Sxw {
91d39a76e7Sxw /* Enable PHY interrupts. */
92d39a76e7Sxw (void) simple_mdio_write(cphy, MV88E1XXX_INTERRUPT_ENABLE_REGISTER,
93d39a76e7Sxw INTR_ENABLE_MASK);
94d39a76e7Sxw
95d39a76e7Sxw /* Enable Marvell interrupts through Elmer0. */
96d39a76e7Sxw if (t1_is_asic(cphy->adapter)) {
97d39a76e7Sxw u32 elmer;
98d39a76e7Sxw
99d39a76e7Sxw (void) t1_tpi_read(cphy->adapter, A_ELMER0_INT_ENABLE, &elmer);
100d39a76e7Sxw elmer |= ELMER0_GP_BIT1;
101d39a76e7Sxw if (is_T2(cphy->adapter)) {
102d39a76e7Sxw elmer |= ELMER0_GP_BIT2|ELMER0_GP_BIT3|ELMER0_GP_BIT4;
103d39a76e7Sxw }
104d39a76e7Sxw (void) t1_tpi_write(cphy->adapter, A_ELMER0_INT_ENABLE, elmer);
105d39a76e7Sxw }
106d39a76e7Sxw return 0;
107d39a76e7Sxw }
108d39a76e7Sxw
mv88e1xxx_interrupt_disable(struct cphy * cphy)109d39a76e7Sxw static int mv88e1xxx_interrupt_disable(struct cphy *cphy)
110d39a76e7Sxw {
111d39a76e7Sxw /* Disable all phy interrupts. */
112d39a76e7Sxw (void) simple_mdio_write(cphy, MV88E1XXX_INTERRUPT_ENABLE_REGISTER, 0);
113d39a76e7Sxw
114d39a76e7Sxw /* Disable Marvell interrupts through Elmer0. */
115d39a76e7Sxw if (t1_is_asic(cphy->adapter)) {
116d39a76e7Sxw u32 elmer;
117d39a76e7Sxw
118d39a76e7Sxw (void) t1_tpi_read(cphy->adapter, A_ELMER0_INT_ENABLE, &elmer);
119d39a76e7Sxw elmer &= ~ELMER0_GP_BIT1;
120d39a76e7Sxw if (is_T2(cphy->adapter)) {
121d39a76e7Sxw elmer &= ~(ELMER0_GP_BIT2|ELMER0_GP_BIT3|ELMER0_GP_BIT4);
122d39a76e7Sxw }
123d39a76e7Sxw (void) t1_tpi_write(cphy->adapter, A_ELMER0_INT_ENABLE, elmer);
124d39a76e7Sxw }
125d39a76e7Sxw return 0;
126d39a76e7Sxw }
127d39a76e7Sxw
mv88e1xxx_interrupt_clear(struct cphy * cphy)128d39a76e7Sxw static int mv88e1xxx_interrupt_clear(struct cphy *cphy)
129d39a76e7Sxw {
130d39a76e7Sxw u32 elmer;
131d39a76e7Sxw
132d39a76e7Sxw /* Clear PHY interrupts by reading the register. */
133d39a76e7Sxw (void) simple_mdio_read(cphy, MV88E1XXX_INTERRUPT_STATUS_REGISTER, &elmer);
134d39a76e7Sxw
135d39a76e7Sxw /* Clear Marvell interrupts through Elmer0. */
136d39a76e7Sxw if (t1_is_asic(cphy->adapter)) {
137d39a76e7Sxw (void) t1_tpi_read(cphy->adapter, A_ELMER0_INT_CAUSE, &elmer);
138d39a76e7Sxw elmer |= ELMER0_GP_BIT1;
139d39a76e7Sxw if (is_T2(cphy->adapter)) {
140d39a76e7Sxw elmer |= ELMER0_GP_BIT2|ELMER0_GP_BIT3|ELMER0_GP_BIT4;
141d39a76e7Sxw }
142d39a76e7Sxw (void) t1_tpi_write(cphy->adapter, A_ELMER0_INT_CAUSE, elmer);
143d39a76e7Sxw }
144d39a76e7Sxw return 0;
145d39a76e7Sxw }
146d39a76e7Sxw
147d39a76e7Sxw /*
148d39a76e7Sxw * Set the PHY speed and duplex. This also disables auto-negotiation, except
149d39a76e7Sxw * for 1Gb/s, where auto-negotiation is mandatory.
150d39a76e7Sxw */
mv88e1xxx_set_speed_duplex(struct cphy * phy,int speed,int duplex)151d39a76e7Sxw static int mv88e1xxx_set_speed_duplex(struct cphy *phy, int speed, int duplex)
152d39a76e7Sxw {
153d39a76e7Sxw u32 ctl;
154d39a76e7Sxw
155d39a76e7Sxw (void) simple_mdio_read(phy, MII_BMCR, &ctl);
156d39a76e7Sxw if (speed >= 0) {
157d39a76e7Sxw ctl &= ~(BMCR_SPEED100 | BMCR_SPEED1000 | BMCR_ANENABLE);
158d39a76e7Sxw if (speed == SPEED_100)
159d39a76e7Sxw ctl |= BMCR_SPEED100;
160d39a76e7Sxw else if (speed == SPEED_1000)
161d39a76e7Sxw ctl |= BMCR_SPEED1000;
162d39a76e7Sxw }
163d39a76e7Sxw if (duplex >= 0) {
164d39a76e7Sxw ctl &= ~(BMCR_FULLDPLX | BMCR_ANENABLE);
165d39a76e7Sxw if (duplex == DUPLEX_FULL)
166d39a76e7Sxw ctl |= BMCR_FULLDPLX;
167d39a76e7Sxw }
168d39a76e7Sxw if (ctl & BMCR_SPEED1000) /* auto-negotiation required for 1Gb/s */
169d39a76e7Sxw ctl |= BMCR_ANENABLE;
170d39a76e7Sxw (void) simple_mdio_write(phy, MII_BMCR, ctl);
171d39a76e7Sxw return 0;
172d39a76e7Sxw }
173d39a76e7Sxw
mv88e1xxx_crossover_set(struct cphy * cphy,int crossover)174d39a76e7Sxw static int mv88e1xxx_crossover_set(struct cphy *cphy, int crossover)
175d39a76e7Sxw {
176d39a76e7Sxw u32 data32;
177d39a76e7Sxw
178d39a76e7Sxw (void) simple_mdio_read(cphy, MV88E1XXX_SPECIFIC_CNTRL_REGISTER, &data32);
179d39a76e7Sxw data32 &= ~V_PSCR_MDI_XOVER_MODE(M_PSCR_MDI_XOVER_MODE);
180d39a76e7Sxw data32 |= V_PSCR_MDI_XOVER_MODE(crossover);
181d39a76e7Sxw (void) simple_mdio_write(cphy, MV88E1XXX_SPECIFIC_CNTRL_REGISTER, data32);
182d39a76e7Sxw return 0;
183d39a76e7Sxw }
184d39a76e7Sxw
mv88e1xxx_autoneg_enable(struct cphy * cphy)185d39a76e7Sxw static int mv88e1xxx_autoneg_enable(struct cphy *cphy)
186d39a76e7Sxw {
187d39a76e7Sxw u32 ctl;
188d39a76e7Sxw
189d39a76e7Sxw (void) mv88e1xxx_crossover_set(cphy, CROSSOVER_AUTO);
190d39a76e7Sxw
191d39a76e7Sxw (void) simple_mdio_read(cphy, MII_BMCR, &ctl);
192d39a76e7Sxw /* restart autoneg for change to take effect */
193d39a76e7Sxw ctl |= BMCR_ANENABLE | BMCR_ANRESTART;
194d39a76e7Sxw (void) simple_mdio_write(cphy, MII_BMCR, ctl);
195d39a76e7Sxw return 0;
196d39a76e7Sxw }
197d39a76e7Sxw
mv88e1xxx_autoneg_disable(struct cphy * cphy)198d39a76e7Sxw static int mv88e1xxx_autoneg_disable(struct cphy *cphy)
199d39a76e7Sxw {
200d39a76e7Sxw u32 ctl;
201d39a76e7Sxw
202d39a76e7Sxw /*
203d39a76e7Sxw * Crossover *must* be set to manual in order to disable auto-neg.
204d39a76e7Sxw * The Alaska FAQs document highlights this point.
205d39a76e7Sxw */
206d39a76e7Sxw (void) mv88e1xxx_crossover_set(cphy, CROSSOVER_MDI);
207d39a76e7Sxw
208d39a76e7Sxw /*
209d39a76e7Sxw * Must include autoneg reset when disabling auto-neg. This
210d39a76e7Sxw * is described in the Alaska FAQ document.
211d39a76e7Sxw */
212d39a76e7Sxw (void) simple_mdio_read(cphy, MII_BMCR, &ctl);
213d39a76e7Sxw ctl &= ~BMCR_ANENABLE;
214d39a76e7Sxw (void) simple_mdio_write(cphy, MII_BMCR, ctl | BMCR_ANRESTART);
215d39a76e7Sxw return 0;
216d39a76e7Sxw }
217d39a76e7Sxw
mv88e1xxx_autoneg_restart(struct cphy * cphy)218d39a76e7Sxw static int mv88e1xxx_autoneg_restart(struct cphy *cphy)
219d39a76e7Sxw {
220d39a76e7Sxw mdio_set_bit(cphy, MII_BMCR, BMCR_ANRESTART);
221d39a76e7Sxw return 0;
222d39a76e7Sxw }
223d39a76e7Sxw
mv88e1xxx_advertise(struct cphy * phy,unsigned int advertise_map)224d39a76e7Sxw static int mv88e1xxx_advertise(struct cphy *phy, unsigned int advertise_map)
225d39a76e7Sxw {
226d39a76e7Sxw u32 val = 0;
227d39a76e7Sxw
228d39a76e7Sxw if (advertise_map &
229d39a76e7Sxw (ADVERTISED_1000baseT_Half | ADVERTISED_1000baseT_Full)) {
230d39a76e7Sxw (void) simple_mdio_read(phy, MII_GBCR, &val);
231d39a76e7Sxw val &= ~(GBCR_ADV_1000HALF | GBCR_ADV_1000FULL);
232d39a76e7Sxw if (advertise_map & ADVERTISED_1000baseT_Half)
233d39a76e7Sxw val |= GBCR_ADV_1000HALF;
234d39a76e7Sxw if (advertise_map & ADVERTISED_1000baseT_Full)
235d39a76e7Sxw val |= GBCR_ADV_1000FULL;
236d39a76e7Sxw }
237d39a76e7Sxw (void) simple_mdio_write(phy, MII_GBCR, val);
238d39a76e7Sxw
239d39a76e7Sxw val = 1;
240d39a76e7Sxw if (advertise_map & ADVERTISED_10baseT_Half)
241d39a76e7Sxw val |= ADVERTISE_10HALF;
242d39a76e7Sxw if (advertise_map & ADVERTISED_10baseT_Full)
243d39a76e7Sxw val |= ADVERTISE_10FULL;
244d39a76e7Sxw if (advertise_map & ADVERTISED_100baseT_Half)
245d39a76e7Sxw val |= ADVERTISE_100HALF;
246d39a76e7Sxw if (advertise_map & ADVERTISED_100baseT_Full)
247d39a76e7Sxw val |= ADVERTISE_100FULL;
248d39a76e7Sxw if (advertise_map & ADVERTISED_PAUSE)
249d39a76e7Sxw val |= ADVERTISE_PAUSE;
250d39a76e7Sxw if (advertise_map & ADVERTISED_ASYM_PAUSE)
251d39a76e7Sxw val |= ADVERTISE_PAUSE_ASYM;
252d39a76e7Sxw (void) simple_mdio_write(phy, MII_ADVERTISE, val);
253d39a76e7Sxw return 0;
254d39a76e7Sxw }
255d39a76e7Sxw
mv88e1xxx_set_loopback(struct cphy * cphy,int on)256d39a76e7Sxw static int mv88e1xxx_set_loopback(struct cphy *cphy, int on)
257d39a76e7Sxw {
258d39a76e7Sxw if (on)
259d39a76e7Sxw mdio_set_bit(cphy, MII_BMCR, BMCR_LOOPBACK);
260d39a76e7Sxw else
261d39a76e7Sxw mdio_clear_bit(cphy, MII_BMCR, BMCR_LOOPBACK);
262d39a76e7Sxw return 0;
263d39a76e7Sxw }
264d39a76e7Sxw
mv88e1xxx_get_link_status(struct cphy * cphy,int * link_ok,int * speed,int * duplex,int * fc)265d39a76e7Sxw static int mv88e1xxx_get_link_status(struct cphy *cphy, int *link_ok,
266d39a76e7Sxw int *speed, int *duplex, int *fc)
267d39a76e7Sxw {
268d39a76e7Sxw u32 status;
269d39a76e7Sxw int sp = -1, dplx = -1, pause = 0;
270d39a76e7Sxw
271d39a76e7Sxw (void) simple_mdio_read(cphy, MV88E1XXX_SPECIFIC_STATUS_REGISTER, &status);
272d39a76e7Sxw if ((status & V_PSSR_STATUS_RESOLVED) != 0) {
273d39a76e7Sxw if (status & V_PSSR_RX_PAUSE)
274d39a76e7Sxw pause |= PAUSE_RX;
275d39a76e7Sxw if (status & V_PSSR_TX_PAUSE)
276d39a76e7Sxw pause |= PAUSE_TX;
277d39a76e7Sxw dplx = (status & V_PSSR_DUPLEX) ? DUPLEX_FULL : DUPLEX_HALF;
278d39a76e7Sxw sp = G_PSSR_SPEED(status);
279d39a76e7Sxw if (sp == 0)
280d39a76e7Sxw sp = SPEED_10;
281d39a76e7Sxw else if (sp == 1)
282d39a76e7Sxw sp = SPEED_100;
283d39a76e7Sxw else
284d39a76e7Sxw sp = SPEED_1000;
285d39a76e7Sxw }
286d39a76e7Sxw if (link_ok)
287d39a76e7Sxw *link_ok = (status & V_PSSR_LINK) != 0;
288d39a76e7Sxw if (speed)
289d39a76e7Sxw *speed = sp;
290d39a76e7Sxw if (duplex)
291d39a76e7Sxw *duplex = dplx;
292d39a76e7Sxw if (fc)
293d39a76e7Sxw *fc = pause;
294d39a76e7Sxw return 0;
295d39a76e7Sxw }
296d39a76e7Sxw
mv88e1xxx_downshift_set(struct cphy * cphy,int downshift_enable)297d39a76e7Sxw static int mv88e1xxx_downshift_set(struct cphy *cphy, int downshift_enable)
298d39a76e7Sxw {
299d39a76e7Sxw u32 val;
300d39a76e7Sxw
301d39a76e7Sxw (void) simple_mdio_read(cphy, MV88E1XXX_EXT_PHY_SPECIFIC_CNTRL_REGISTER, &val);
302d39a76e7Sxw
303d39a76e7Sxw /*
304d39a76e7Sxw * Set the downshift counter to 2 so we try to establish Gb link
305d39a76e7Sxw * twice before downshifting.
306d39a76e7Sxw */
307d39a76e7Sxw val &= ~(V_DOWNSHIFT_ENABLE | V_DOWNSHIFT_CNT(M_DOWNSHIFT_CNT));
308*2d6eb4a5SToomas Soome
309d39a76e7Sxw if (downshift_enable)
310d39a76e7Sxw val |= V_DOWNSHIFT_ENABLE | V_DOWNSHIFT_CNT(2);
311d39a76e7Sxw (void) simple_mdio_write(cphy, MV88E1XXX_EXT_PHY_SPECIFIC_CNTRL_REGISTER, val);
312d39a76e7Sxw return 0;
313d39a76e7Sxw }
314d39a76e7Sxw
mv88e1xxx_interrupt_handler(struct cphy * cphy)315d39a76e7Sxw static int mv88e1xxx_interrupt_handler(struct cphy *cphy)
316d39a76e7Sxw {
317d39a76e7Sxw int cphy_cause = 0;
318d39a76e7Sxw u32 status;
319d39a76e7Sxw
320d39a76e7Sxw /*
321d39a76e7Sxw * Loop until cause reads zero. Need to handle bouncing interrupts.
322*2d6eb4a5SToomas Soome */
323d39a76e7Sxw /*CONSTCOND*/
324d39a76e7Sxw while (1) {
325d39a76e7Sxw u32 cause;
326d39a76e7Sxw
327d39a76e7Sxw (void) simple_mdio_read(cphy, MV88E1XXX_INTERRUPT_STATUS_REGISTER,
328d39a76e7Sxw &cause);
329d39a76e7Sxw cause &= INTR_ENABLE_MASK;
330d39a76e7Sxw if (!cause) break;
331d39a76e7Sxw
332d39a76e7Sxw if (cause & MV88E1XXX_INTR_LINK_CHNG) {
333d39a76e7Sxw (void) simple_mdio_read(cphy,
334d39a76e7Sxw MV88E1XXX_SPECIFIC_STATUS_REGISTER, &status);
335d39a76e7Sxw
336d39a76e7Sxw if (status & MV88E1XXX_INTR_LINK_CHNG) {
337d39a76e7Sxw cphy->state |= PHY_LINK_UP;
338d39a76e7Sxw } else {
339d39a76e7Sxw cphy->state &= ~PHY_LINK_UP;
340d39a76e7Sxw if (cphy->state & PHY_AUTONEG_EN)
341d39a76e7Sxw cphy->state &= ~PHY_AUTONEG_RDY;
342d39a76e7Sxw cphy_cause |= cphy_cause_link_change;
343d39a76e7Sxw }
344d39a76e7Sxw }
345d39a76e7Sxw
346d39a76e7Sxw if (cause & MV88E1XXX_INTR_AUTONEG_DONE)
347d39a76e7Sxw cphy->state |= PHY_AUTONEG_RDY;
348d39a76e7Sxw
349d39a76e7Sxw if ((cphy->state & (PHY_LINK_UP | PHY_AUTONEG_RDY)) ==
350d39a76e7Sxw (PHY_LINK_UP | PHY_AUTONEG_RDY))
351d39a76e7Sxw cphy_cause |= cphy_cause_link_change;
352d39a76e7Sxw }
353d39a76e7Sxw return cphy_cause;
354d39a76e7Sxw }
355d39a76e7Sxw
mv88e1xxx_destroy(struct cphy * cphy)356d39a76e7Sxw static void mv88e1xxx_destroy(struct cphy *cphy)
357d39a76e7Sxw {
358d39a76e7Sxw t1_os_free((void *)cphy, sizeof(*cphy));
359d39a76e7Sxw }
360d39a76e7Sxw
361d39a76e7Sxw #ifdef C99_NOT_SUPPORTED
362d39a76e7Sxw static struct cphy_ops mv88e1xxx_ops = {
363d39a76e7Sxw mv88e1xxx_destroy,
364d39a76e7Sxw mv88e1xxx_reset,
365d39a76e7Sxw mv88e1xxx_interrupt_enable,
366d39a76e7Sxw mv88e1xxx_interrupt_disable,
367d39a76e7Sxw mv88e1xxx_interrupt_clear,
368d39a76e7Sxw mv88e1xxx_interrupt_handler,
369d39a76e7Sxw mv88e1xxx_autoneg_enable,
370d39a76e7Sxw mv88e1xxx_autoneg_disable,
371d39a76e7Sxw mv88e1xxx_autoneg_restart,
372d39a76e7Sxw mv88e1xxx_advertise,
373d39a76e7Sxw mv88e1xxx_set_loopback,
374d39a76e7Sxw mv88e1xxx_set_speed_duplex,
375d39a76e7Sxw mv88e1xxx_get_link_status,
376d39a76e7Sxw };
377d39a76e7Sxw #else
378d39a76e7Sxw static struct cphy_ops mv88e1xxx_ops = {
379d39a76e7Sxw .destroy = mv88e1xxx_destroy,
380d39a76e7Sxw .reset = mv88e1xxx_reset,
381d39a76e7Sxw .interrupt_enable = mv88e1xxx_interrupt_enable,
382d39a76e7Sxw .interrupt_disable = mv88e1xxx_interrupt_disable,
383d39a76e7Sxw .interrupt_clear = mv88e1xxx_interrupt_clear,
384d39a76e7Sxw .interrupt_handler = mv88e1xxx_interrupt_handler,
385d39a76e7Sxw .autoneg_enable = mv88e1xxx_autoneg_enable,
386d39a76e7Sxw .autoneg_disable = mv88e1xxx_autoneg_disable,
387d39a76e7Sxw .autoneg_restart = mv88e1xxx_autoneg_restart,
388d39a76e7Sxw .advertise = mv88e1xxx_advertise,
389d39a76e7Sxw .set_loopback = mv88e1xxx_set_loopback,
390d39a76e7Sxw .set_speed_duplex = mv88e1xxx_set_speed_duplex,
391d39a76e7Sxw .get_link_status = mv88e1xxx_get_link_status,
392d39a76e7Sxw };
393d39a76e7Sxw #endif
394d39a76e7Sxw
mv88e1xxx_phy_create(adapter_t * adapter,int phy_addr,struct mdio_ops * mdio_ops)395d39a76e7Sxw static struct cphy *mv88e1xxx_phy_create(adapter_t *adapter, int phy_addr,
396d39a76e7Sxw struct mdio_ops *mdio_ops)
397d39a76e7Sxw {
398d39a76e7Sxw struct cphy *cphy = t1_os_malloc_wait_zero(sizeof(*cphy));
399d39a76e7Sxw
400d39a76e7Sxw if (!cphy) return NULL;
401d39a76e7Sxw
402d39a76e7Sxw cphy_init(cphy, adapter, phy_addr, &mv88e1xxx_ops, mdio_ops);
403d39a76e7Sxw
404d39a76e7Sxw /* Configure particular PHY's to run in a different mode. */
405d39a76e7Sxw if ((board_info(adapter)->caps & SUPPORTED_TP) &&
406d39a76e7Sxw board_info(adapter)->chip_phy == CHBT_PHY_88E1111) {
407d39a76e7Sxw /*
408d39a76e7Sxw * Configure the PHY transmitter as class A to reduce EMI.
409d39a76e7Sxw */
410d39a76e7Sxw (void) simple_mdio_write(cphy, MV88E1XXX_EXTENDED_ADDR_REGISTER, 0xB);
411d39a76e7Sxw (void) simple_mdio_write(cphy, MV88E1XXX_EXTENDED_REGISTER, 0x8004);
412d39a76e7Sxw }
413d39a76e7Sxw (void) mv88e1xxx_downshift_set(cphy, 1); /* Enable downshift */
414d39a76e7Sxw
415d39a76e7Sxw /* LED */
416d39a76e7Sxw if (is_T2(adapter)) {
417d39a76e7Sxw (void) simple_mdio_write(cphy,
418d39a76e7Sxw MV88E1XXX_LED_CONTROL_REGISTER, 0x1);
419d39a76e7Sxw }
420d39a76e7Sxw
421d39a76e7Sxw return cphy;
422d39a76e7Sxw }
423d39a76e7Sxw
424d39a76e7Sxw /* ARGSUSED */
mv88e1xxx_phy_reset(adapter_t * adapter)425d39a76e7Sxw static int mv88e1xxx_phy_reset(adapter_t* adapter)
426d39a76e7Sxw {
427d39a76e7Sxw return 0;
428d39a76e7Sxw }
429d39a76e7Sxw
430d39a76e7Sxw struct gphy t1_mv88e1xxx_ops = {
431d39a76e7Sxw mv88e1xxx_phy_create,
432d39a76e7Sxw mv88e1xxx_phy_reset
433d39a76e7Sxw };
434