1/*-
2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3 *
4 * Copyright (c) 2009 M. Warner Losh <imp@FreeBSD.org>
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 *    notice unmodified, this list of conditions, and the following
11 *    disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 *    notice, this list of conditions and the following disclaimer in the
14 *    documentation and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 * SUCH DAMAGE.
27 */
28#include <sys/cdefs.h>
29__FBSDID("$FreeBSD$");
30
31/*
32 * driver for internal phy in the AX88x9x chips.
33 */
34
35#include <sys/param.h>
36#include <sys/systm.h>
37#include <sys/kernel.h>
38#include <sys/module.h>
39#include <sys/socket.h>
40#include <sys/bus.h>
41
42#include <net/if.h>
43#include <net/if_media.h>
44
45#include <dev/mii/mii.h>
46#include <dev/mii/miivar.h>
47#include "miidevs.h"
48
49#include "miibus_if.h"
50
51static int 	axphy_probe(device_t dev);
52static int 	axphy_attach(device_t dev);
53
54static device_method_t axphy_methods[] = {
55	/* device interface */
56	DEVMETHOD(device_probe,		axphy_probe),
57	DEVMETHOD(device_attach,	axphy_attach),
58	DEVMETHOD(device_detach,	mii_phy_detach),
59	DEVMETHOD(device_shutdown,	bus_generic_shutdown),
60	DEVMETHOD_END
61};
62
63static devclass_t axphy_devclass;
64
65static driver_t axphy_driver = {
66	"axphy",
67	axphy_methods,
68	sizeof(struct mii_softc)
69};
70
71DRIVER_MODULE(axphy, miibus, axphy_driver, axphy_devclass, 0, 0);
72
73static int	axphy_service(struct mii_softc *, struct mii_data *, int);
74static void	axphy_status(struct mii_softc *);
75
76static const struct mii_phydesc axphys[] = {
77	MII_PHY_DESC(xxASIX, AX88X9X),
78	MII_PHY_END
79};
80
81static const struct mii_phy_funcs axphy_funcs = {
82	axphy_service,
83	axphy_status,
84	mii_phy_reset
85};
86
87static int
88axphy_probe(device_t dev)
89{
90
91	return (mii_phy_dev_probe(dev, axphys, BUS_PROBE_DEFAULT));
92}
93
94static int
95axphy_attach(device_t dev)
96{
97	struct mii_softc *sc;
98
99	sc = device_get_softc(dev);
100
101	mii_phy_dev_attach(dev, MIIF_NOISOLATE | MIIF_NOMANPAUSE,
102	    &axphy_funcs, 1);
103	mii_phy_setmedia(sc);
104
105	return (0);
106}
107
108static int
109axphy_service(struct mii_softc *sc, struct mii_data *mii, int cmd)
110{
111
112	switch (cmd) {
113	case MII_POLLSTAT:
114		break;
115
116	case MII_MEDIACHG:
117		mii_phy_setmedia(sc);
118		break;
119
120	case MII_TICK:
121		if (mii_phy_tick(sc) == EJUSTRETURN)
122			return (0);
123		break;
124	}
125
126	/* Update the media status. */
127	PHY_STATUS(sc);
128
129	/* Callback if something changed. */
130	mii_phy_update(sc, cmd);
131	return (0);
132}
133
134static void
135axphy_status(struct mii_softc *sc)
136{
137	struct mii_data *mii = sc->mii_pdata;
138	struct ifmedia_entry *ife = mii->mii_media.ifm_cur;
139	int bmsr, bmcr;
140
141	mii->mii_media_status = IFM_AVALID;
142	mii->mii_media_active = IFM_ETHER;
143
144	bmsr = PHY_READ(sc, MII_BMSR) | PHY_READ(sc, MII_BMSR);
145	if (bmsr & BMSR_LINK)
146		mii->mii_media_status |= IFM_ACTIVE;
147
148	bmcr = PHY_READ(sc, MII_BMCR);
149	if (bmcr & BMCR_ISO) {
150		mii->mii_media_active |= IFM_NONE;
151		mii->mii_media_status = 0;
152		return;
153	}
154
155	if (bmcr & BMCR_LOOP)
156		mii->mii_media_active |= IFM_LOOP;
157
158	if (bmcr & BMCR_AUTOEN) {
159		if ((bmsr & BMSR_ACOMP) == 0) {
160			mii->mii_media_active |= IFM_NONE;
161			return;
162		}
163
164#if 0
165		scr = PHY_READ(sc, MII_AXPHY_SCR);
166		if (scr & SCR_S100)
167			mii->mii_media_active |= IFM_100_TX;
168		else
169			mii->mii_media_active |= IFM_10_T;
170		if (scr & SCR_FDX)
171			mii->mii_media_active |=
172			    IFM_FDX | mii_phy_flowstatus(sc);
173		else
174			mii->mii_media_active |= IFM_HDX;
175#endif
176	} else
177		mii->mii_media_active = ife->ifm_media;
178}
179