2 * Copyright (c) 2006, Pyun YongHyeon <yongari@FreeBSD.org>
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
8 * 1. Redistributions of source code must retain the above copyright
9 * notice unmodified, this list of conditions, and the following
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 * $FreeBSD: src/sys/dev/mii/ip1000phy.c,v 1.1 2006/07/25 00:16:09 yongari Exp $
31 * Driver for the IC Plus IP1000A 10/100/1000 PHY.
34 #include <sys/param.h>
36 #include <sys/kernel.h>
37 #include <sys/module.h>
38 #include <sys/socket.h>
39 #include <sys/sysctl.h>
42 #include <net/if_arp.h>
43 #include <net/if_media.h>
44 #include <net/if_poll.h>
46 #include <dev/netif/mii_layer/mii.h>
47 #include <dev/netif/mii_layer/miivar.h>
50 #include <dev/netif/mii_layer/ip1000phyreg.h>
52 #include "miibus_if.h"
54 #include <dev/netif/stge/if_stgereg.h>
55 #include <dev/netif/stge/if_stgevar.h>
57 static int ip1000phy_probe(device_t
);
58 static int ip1000phy_attach(device_t
);
59 static int ip1000phy_service(struct mii_softc
*, struct mii_data
*, int);
60 static void ip1000phy_status(struct mii_softc
*);
61 static void ip1000phy_reset(struct mii_softc
*);
62 static int ip1000phy_mii_phy_auto(struct mii_softc
*);
64 static device_method_t ip1000phy_methods
[] = {
65 /* device interface */
66 DEVMETHOD(device_probe
, ip1000phy_probe
),
67 DEVMETHOD(device_attach
, ip1000phy_attach
),
68 DEVMETHOD(device_detach
, ukphy_detach
),
69 DEVMETHOD(device_shutdown
, bus_generic_shutdown
),
73 static devclass_t ip1000phy_devclass
;
74 static driver_t ip1000phy_driver
= {
77 sizeof (struct mii_softc
)
80 DRIVER_MODULE(ip1000phy
, miibus
, ip1000phy_driver
, ip1000phy_devclass
, NULL
, NULL
);
82 static const struct mii_phydesc ip1000phys
[] = {
83 MII_PHYDESC(ICPLUS
, IP1000A
),
88 ip1000phy_probe(device_t dev
)
90 struct mii_attach_args
*ma
;
91 const struct mii_phydesc
*mpd
;
93 ma
= device_get_ivars(dev
);
94 mpd
= mii_phy_match(ma
, ip1000phys
);
96 device_set_desc(dev
, mpd
->mpd_name
);
104 ip1000phy_attach(device_t dev
)
106 struct mii_softc
*sc
;
107 struct mii_attach_args
*ma
;
108 struct mii_data
*mii
;
110 sc
= device_get_softc(dev
);
111 ma
= device_get_ivars(dev
);
112 mii_softc_init(sc
, ma
);
113 sc
->mii_dev
= device_get_parent(dev
);
114 mii
= device_get_softc(sc
->mii_dev
);
115 LIST_INSERT_HEAD(&mii
->mii_phys
, sc
, mii_list
);
117 sc
->mii_inst
= mii
->mii_instance
;
118 sc
->mii_service
= ip1000phy_service
;
121 sc
->mii_anegticks
= MII_ANEGTICKS_GIGE
;
122 sc
->mii_flags
|= MIIF_NOISOLATE
;
126 device_printf(dev
, " ");
128 #define ADD(m, c) ifmedia_add(&mii->mii_media, (m), (c), NULL)
130 ADD(IFM_MAKEWORD(IFM_ETHER
, IFM_NONE
, 0, sc
->mii_inst
),
133 ADD(IFM_MAKEWORD(IFM_ETHER
, IFM_10_T
, 0, sc
->mii_inst
),
135 kprintf("10baseT, ");
136 ADD(IFM_MAKEWORD(IFM_ETHER
, IFM_10_T
, IFM_FDX
, sc
->mii_inst
),
137 IP1000PHY_BMCR_10
| IP1000PHY_BMCR_FDX
);
138 kprintf("10baseT-FDX, ");
139 ADD(IFM_MAKEWORD(IFM_ETHER
, IFM_100_TX
, 0, sc
->mii_inst
),
141 kprintf("100baseTX, ");
142 ADD(IFM_MAKEWORD(IFM_ETHER
, IFM_100_TX
, IFM_FDX
, sc
->mii_inst
),
143 IP1000PHY_BMCR_100
| IP1000PHY_BMCR_FDX
);
144 kprintf("100baseTX-FDX, ");
145 /* 1000baseT half-duplex, really supported? */
146 ADD(IFM_MAKEWORD(IFM_ETHER
, IFM_1000_T
, 0, sc
->mii_inst
),
147 IP1000PHY_BMCR_1000
);
148 kprintf("1000baseT, ");
149 ADD(IFM_MAKEWORD(IFM_ETHER
, IFM_1000_T
, IFM_FDX
, sc
->mii_inst
),
150 IP1000PHY_BMCR_1000
| IP1000PHY_BMCR_FDX
);
151 kprintf("1000baseT-FDX, ");
152 ADD(IFM_MAKEWORD(IFM_ETHER
, IFM_AUTO
, 0, sc
->mii_inst
), 0);
158 MIIBUS_MEDIAINIT(sc
->mii_dev
);
163 ip1000phy_service(struct mii_softc
*sc
, struct mii_data
*mii
, int cmd
)
165 struct ifmedia_entry
*ife
= mii
->mii_media
.ifm_cur
;
166 uint32_t gig
, reg
, speed
;
171 * If we're not polling our PHY instance, just return.
173 if (IFM_INST(ife
->ifm_media
) != sc
->mii_inst
)
179 * If the media indicates a different PHY instance,
182 if (IFM_INST(ife
->ifm_media
) != sc
->mii_inst
) {
183 reg
= PHY_READ(sc
, IP1000PHY_MII_BMCR
);
184 PHY_WRITE(sc
, IP1000PHY_MII_BMCR
,
185 reg
| IP1000PHY_BMCR_ISO
);
190 * If the interface is not up, don't do anything.
192 if ((mii
->mii_ifp
->if_flags
& IFF_UP
) == 0)
196 switch (IFM_SUBTYPE(ife
->ifm_media
)) {
198 ip1000phy_mii_phy_auto(sc
);
204 * Manual 1000baseT setting doesn't seem to work.
206 speed
= IP1000PHY_BMCR_1000
;
210 speed
= IP1000PHY_BMCR_100
;
214 speed
= IP1000PHY_BMCR_10
;
221 if (((ife
->ifm_media
& IFM_GMASK
) & IFM_FDX
) != 0) {
222 speed
|= IP1000PHY_BMCR_FDX
;
223 gig
= IP1000PHY_1000CR_1000T_FDX
;
225 gig
= IP1000PHY_1000CR_1000T
;
228 PHY_WRITE(sc
, IP1000PHY_MII_1000CR
, 0);
229 PHY_WRITE(sc
, IP1000PHY_MII_BMCR
, speed
);
231 if (IFM_SUBTYPE(ife
->ifm_media
) != IFM_1000_T
)
234 PHY_WRITE(sc
, IP1000PHY_MII_1000CR
, gig
);
235 PHY_WRITE(sc
, IP1000PHY_MII_BMCR
, speed
);
238 * When settning the link manually, one side must
239 * be the master and the other the slave. However
240 * ifmedia doesn't give us a good way to specify
241 * this, so we fake it by using one of the LINK
242 * flags. If LINK0 is set, we program the PHY to
243 * be a master, otherwise it's a slave.
245 if ((mii
->mii_ifp
->if_flags
& IFF_LINK0
)) {
246 PHY_WRITE(sc
, IP1000PHY_MII_1000CR
, gig
|
247 IP1000PHY_1000CR_MASTER
|
248 IP1000PHY_1000CR_MMASTER
|
249 IP1000PHY_1000CR_MANUAL
);
251 PHY_WRITE(sc
, IP1000PHY_MII_1000CR
, gig
|
252 IP1000PHY_1000CR_MASTER
|
253 IP1000PHY_1000CR_MANUAL
);
261 * If we're not currently selected, just return.
263 if (IFM_INST(ife
->ifm_media
) != sc
->mii_inst
)
266 * Is the interface even up?
268 if ((mii
->mii_ifp
->if_flags
& IFF_UP
) == 0)
272 * Only used for autonegotiation.
274 if (IFM_SUBTYPE(ife
->ifm_media
) != IFM_AUTO
)
280 reg
= PHY_READ(sc
, MII_BMSR
) | PHY_READ(sc
, MII_BMSR
);
281 if (reg
& BMSR_LINK
) {
286 /* Announce link loss right after it happens */
287 if (sc
->mii_ticks
++ == 0)
291 * Only retry autonegotiation every mii_anegticks seconds.
293 if (sc
->mii_ticks
<= sc
->mii_anegticks
)
297 ip1000phy_mii_phy_auto(sc
);
301 /* Update the media status. */
302 ip1000phy_status(sc
);
304 /* Callback if something changed. */
305 mii_phy_update(sc
, cmd
);
310 ip1000phy_status(struct mii_softc
*sc
)
312 struct mii_data
*mii
= sc
->mii_pdata
;
313 uint32_t bmsr
, bmcr
, stat
;
316 mii
->mii_media_status
= IFM_AVALID
;
317 mii
->mii_media_active
= IFM_ETHER
;
319 bmsr
= PHY_READ(sc
, IP1000PHY_MII_BMSR
) |
320 PHY_READ(sc
, IP1000PHY_MII_BMSR
);
321 if ((bmsr
& IP1000PHY_BMSR_LINK
) != 0)
322 mii
->mii_media_status
|= IFM_ACTIVE
;
324 bmcr
= PHY_READ(sc
, IP1000PHY_MII_BMCR
);
325 if ((bmcr
& IP1000PHY_BMCR_LOOP
) != 0)
326 mii
->mii_media_active
|= IFM_LOOP
;
328 if ((bmcr
& IP1000PHY_BMCR_AUTOEN
) != 0) {
329 if ((bmsr
& IP1000PHY_BMSR_ANEGCOMP
) == 0) {
330 /* Erg, still trying, I guess... */
331 mii
->mii_media_active
|= IFM_NONE
;
336 stat
= PHY_READ(sc
, STGE_PhyCtrl
);
337 switch (PC_LinkSpeed(stat
)) {
338 case PC_LinkSpeed_Down
:
339 mii
->mii_media_active
|= IFM_NONE
;
341 case PC_LinkSpeed_10
:
342 mii
->mii_media_active
|= IFM_10_T
;
344 case PC_LinkSpeed_100
:
345 mii
->mii_media_active
|= IFM_100_TX
;
347 case PC_LinkSpeed_1000
:
348 mii
->mii_media_active
|= IFM_1000_T
;
351 if ((stat
& PC_PhyDuplexStatus
) != 0)
352 mii
->mii_media_active
|= IFM_FDX
;
354 mii
->mii_media_active
|= IFM_HDX
;
356 ar
= PHY_READ(sc
, IP1000PHY_MII_ANAR
);
357 lpar
= PHY_READ(sc
, IP1000PHY_MII_ANLPAR
);
360 * FLAG0 : Rx flow-control
361 * FLAG1 : Tx flow-control
363 if ((ar
& IP1000PHY_ANAR_PAUSE
) && (lpar
& IP1000PHY_ANLPAR_PAUSE
))
364 mii
->mii_media_active
|= IFM_FLAG0
| IFM_FLAG1
;
365 else if (!(ar
& IP1000PHY_ANAR_PAUSE
) && (ar
& IP1000PHY_ANAR_APAUSE
) &&
366 (lpar
& IP1000PHY_ANLPAR_PAUSE
) && (lpar
& IP1000PHY_ANLPAR_APAUSE
))
367 mii
->mii_media_active
|= IFM_FLAG1
;
368 else if ((ar
& IP1000PHY_ANAR_PAUSE
) && (ar
& IP1000PHY_ANAR_APAUSE
) &&
369 !(lpar
& IP1000PHY_ANLPAR_PAUSE
) &&
370 (lpar
& IP1000PHY_ANLPAR_APAUSE
)) {
371 mii
->mii_media_active
|= IFM_FLAG0
;
375 * FLAG2 : local PHY resolved to MASTER
377 if ((mii
->mii_media_active
& IFM_1000_T
) != 0) {
378 stat
= PHY_READ(sc
, IP1000PHY_MII_1000SR
);
379 if ((stat
& IP1000PHY_1000SR_MASTER
) != 0)
380 mii
->mii_media_active
|= IFM_FLAG2
;
385 ip1000phy_mii_phy_auto(struct mii_softc
*mii
)
389 PHY_WRITE(mii
, IP1000PHY_MII_ANAR
,
390 IP1000PHY_ANAR_10T
| IP1000PHY_ANAR_10T_FDX
|
391 IP1000PHY_ANAR_100TX
| IP1000PHY_ANAR_100TX_FDX
|
392 IP1000PHY_ANAR_PAUSE
| IP1000PHY_ANAR_APAUSE
);
393 reg
= IP1000PHY_1000CR_1000T
| IP1000PHY_1000CR_1000T_FDX
;
394 reg
|= IP1000PHY_1000CR_MASTER
;
395 PHY_WRITE(mii
, IP1000PHY_MII_1000CR
, reg
);
396 PHY_WRITE(mii
, IP1000PHY_MII_BMCR
, (IP1000PHY_BMCR_FDX
|
397 IP1000PHY_BMCR_AUTOEN
| IP1000PHY_BMCR_STARTNEG
));
399 return (EJUSTRETURN
);
403 ip1000phy_load_dspcode(struct mii_softc
*sc
)
406 PHY_WRITE(sc
, 31, 0x0001);
407 PHY_WRITE(sc
, 27, 0x01e0);
408 PHY_WRITE(sc
, 31, 0x0002);
409 PHY_WRITE(sc
, 27, 0xeb8e);
410 PHY_WRITE(sc
, 31, 0x0000);
411 PHY_WRITE(sc
, 30, 0x005e);
412 PHY_WRITE(sc
, 9, 0x0700);
418 ip1000phy_reset(struct mii_softc
*sc
)
420 struct stge_softc
*stge_sc
;
426 /* clear autoneg/full-duplex as we don't want it after reset */
427 reg
= PHY_READ(sc
, IP1000PHY_MII_BMCR
);
428 reg
&= ~(IP1000PHY_BMCR_AUTOEN
| IP1000PHY_BMCR_FDX
);
429 PHY_WRITE(sc
, MII_BMCR
, reg
);
432 * XXX There should be more general way to pass PHY specific
433 * data via mii interface.
435 parent
= device_get_parent(sc
->mii_dev
);
436 if (strncmp(device_get_name(parent
), "stge", 4) == 0) {
437 stge_sc
= device_get_softc(parent
);
438 if (stge_sc
->sc_rev
>= 0x40 && stge_sc
->sc_rev
<= 0x4e)
439 ip1000phy_load_dspcode(sc
);