Changeset View
Changeset View
Standalone View
Standalone View
sys/dev/mii/rgephy.c
Show All 33 Lines | |||||
#include <sys/cdefs.h> | #include <sys/cdefs.h> | ||||
__FBSDID("$FreeBSD$"); | __FBSDID("$FreeBSD$"); | ||||
/* | /* | ||||
* Driver for the RealTek 8169S/8110S/8211B/8211C internal 10/100/1000 PHY. | * Driver for the RealTek 8169S/8110S/8211B/8211C internal 10/100/1000 PHY. | ||||
*/ | */ | ||||
#include "opt_platform.h" | |||||
#include <sys/param.h> | #include <sys/param.h> | ||||
#include <sys/systm.h> | #include <sys/systm.h> | ||||
#include <sys/kernel.h> | #include <sys/kernel.h> | ||||
#include <sys/module.h> | #include <sys/module.h> | ||||
#include <sys/socket.h> | #include <sys/socket.h> | ||||
#include <sys/taskqueue.h> | #include <sys/taskqueue.h> | ||||
#include <sys/bus.h> | #include <sys/bus.h> | ||||
#include <net/if.h> | #include <net/if.h> | ||||
#include <net/if_var.h> | #include <net/if_var.h> | ||||
#include <net/if_arp.h> | #include <net/if_arp.h> | ||||
#include <net/if_media.h> | #include <net/if_media.h> | ||||
#include <dev/mii/mii.h> | #include <dev/mii/mii.h> | ||||
#include <dev/mii/miivar.h> | #include <dev/mii/miivar.h> | ||||
#include "miidevs.h" | #include "miidevs.h" | ||||
#include <dev/mii/rgephyreg.h> | #include <dev/mii/rgephyreg.h> | ||||
#include "miibus_if.h" | #include "miibus_if.h" | ||||
#ifdef FDT | |||||
#include <dev/ofw/openfirm.h> | |||||
#include <dev/ofw/ofw_bus.h> | |||||
#include <dev/ofw/ofw_bus_subr.h> | |||||
#include <dev/mii/mii_fdt.h> | |||||
#endif | |||||
#include <machine/bus.h> | #include <machine/bus.h> | ||||
#include <dev/rl/if_rlreg.h> | #include <dev/rl/if_rlreg.h> | ||||
#define RGEPHY_QUIRK_PINE64_CONFREG 1 | |||||
struct rgephy_softc { | |||||
mii_softc_t mii_sc; | |||||
device_t dev; | |||||
mii_contype_t contype; | |||||
int quirks; | |||||
}; | |||||
static int rgephy_probe(device_t); | static int rgephy_probe(device_t); | ||||
static int rgephy_attach(device_t); | static int rgephy_attach(device_t); | ||||
static device_method_t rgephy_methods[] = { | static device_method_t rgephy_methods[] = { | ||||
/* device interface */ | /* device interface */ | ||||
DEVMETHOD(device_probe, rgephy_probe), | DEVMETHOD(device_probe, rgephy_probe), | ||||
DEVMETHOD(device_attach, rgephy_attach), | DEVMETHOD(device_attach, rgephy_attach), | ||||
DEVMETHOD(device_detach, mii_phy_detach), | DEVMETHOD(device_detach, mii_phy_detach), | ||||
DEVMETHOD(device_shutdown, bus_generic_shutdown), | DEVMETHOD(device_shutdown, bus_generic_shutdown), | ||||
DEVMETHOD_END | DEVMETHOD_END | ||||
}; | }; | ||||
static devclass_t rgephy_devclass; | static devclass_t rgephy_devclass; | ||||
static driver_t rgephy_driver = { | static driver_t rgephy_driver = { | ||||
"rgephy", | "rgephy", | ||||
rgephy_methods, | rgephy_methods, | ||||
sizeof(struct mii_softc) | sizeof(struct rgephy_softc) | ||||
}; | }; | ||||
DRIVER_MODULE(rgephy, miibus, rgephy_driver, rgephy_devclass, 0, 0); | DRIVER_MODULE(rgephy, miibus, rgephy_driver, rgephy_devclass, 0, 0); | ||||
#ifdef FDT | |||||
static void rgephy_fdt_get_config(struct rgephy_softc *); | |||||
#endif | |||||
static int rgephy_service(struct mii_softc *, struct mii_data *, int); | static int rgephy_service(struct mii_softc *, struct mii_data *, int); | ||||
static void rgephy_status(struct mii_softc *); | static void rgephy_status(struct mii_softc *); | ||||
static int rgephy_mii_phy_auto(struct mii_softc *, int); | static int rgephy_mii_phy_auto(struct mii_softc *, int); | ||||
static void rgephy_reset(struct mii_softc *); | static void rgephy_reset(struct mii_softc *); | ||||
static int rgephy_linkup(struct mii_softc *); | static int rgephy_linkup(struct mii_softc *); | ||||
static void rgephy_loop(struct mii_softc *); | static void rgephy_loop(struct mii_softc *); | ||||
static void rgephy_load_dspcode(struct mii_softc *); | static void rgephy_load_dspcode(struct mii_softc *); | ||||
static void rgephy_disable_eee(struct mii_softc *); | static void rgephy_disable_eee(struct mii_softc *); | ||||
static const struct mii_phydesc rgephys[] = { | static const struct mii_phydesc rgephys[] = { | ||||
MII_PHY_DESC(REALTEK, RTL8169S), | MII_PHY_DESC(REALTEK, RTL8169S), | ||||
MII_PHY_DESC(REALTEK, RTL8251), | MII_PHY_DESC(REALTEK, RTL8251), | ||||
MII_PHY_END | MII_PHY_END | ||||
}; | }; | ||||
static const struct mii_phy_funcs rgephy_funcs = { | static const struct mii_phy_funcs rgephy_funcs = { | ||||
rgephy_service, | rgephy_service, | ||||
rgephy_status, | rgephy_status, | ||||
rgephy_reset | rgephy_reset | ||||
}; | }; | ||||
#ifdef FDT | |||||
static void | |||||
rgephy_fdt_get_config(struct rgephy_softc *sc) | |||||
{ | |||||
mii_fdt_phy_config_t *cfg; | |||||
cfg = mii_fdt_get_config(sc->dev); | |||||
sc->contype = cfg->con_type; | |||||
mii_fdt_free_config(cfg); | |||||
} | |||||
#endif | |||||
static int | static int | ||||
rgephy_probe(device_t dev) | rgephy_probe(device_t dev) | ||||
{ | { | ||||
return (mii_phy_dev_probe(dev, rgephys, BUS_PROBE_DEFAULT)); | return (mii_phy_dev_probe(dev, rgephys, BUS_PROBE_DEFAULT)); | ||||
} | } | ||||
static int | static int | ||||
rgephy_attach(device_t dev) | rgephy_attach(device_t dev) | ||||
{ | { | ||||
#ifdef FDT | |||||
phandle_t root; | |||||
#endif | |||||
struct rgephy_softc *rsc; | |||||
struct mii_softc *sc; | struct mii_softc *sc; | ||||
u_int flags; | u_int flags; | ||||
sc = device_get_softc(dev); | rsc = device_get_softc(dev); | ||||
rsc->dev = dev; | |||||
sc = &rsc->mii_sc; | |||||
flags = 0; | flags = 0; | ||||
if (mii_dev_mac_match(dev, "re")) | if (mii_dev_mac_match(dev, "re")) | ||||
flags |= MIIF_PHYPRIV0; | flags |= MIIF_PHYPRIV0; | ||||
else if (mii_dev_mac_match(dev, "ure")) | else if (mii_dev_mac_match(dev, "ure")) | ||||
flags |= MIIF_PHYPRIV1; | flags |= MIIF_PHYPRIV1; | ||||
#ifdef FDT | |||||
rgephy_fdt_get_config(rsc); | |||||
if ((root = OF_finddevice("/")) != -1 && | |||||
ofw_bus_node_is_compatible(root, "pine64,pine64-plus") && | |||||
mii_contype_is_rgmii(rsc->contype)) | |||||
rsc->quirks |= RGEPHY_QUIRK_PINE64_CONFREG; | |||||
#endif | |||||
mii_phy_dev_attach(dev, flags, &rgephy_funcs, 0); | mii_phy_dev_attach(dev, flags, &rgephy_funcs, 0); | ||||
/* RTL8169S do not report auto-sense; add manually. */ | /* RTL8169S do not report auto-sense; add manually. */ | ||||
sc->mii_capabilities = (PHY_READ(sc, MII_BMSR) | BMSR_ANEG) & | sc->mii_capabilities = (PHY_READ(sc, MII_BMSR) | BMSR_ANEG) & | ||||
sc->mii_capmask; | sc->mii_capmask; | ||||
if (sc->mii_capabilities & BMSR_EXTSTAT) | if (sc->mii_capabilities & BMSR_EXTSTAT) | ||||
sc->mii_extcapabilities = PHY_READ(sc, MII_EXTSR); | sc->mii_extcapabilities = PHY_READ(sc, MII_EXTSR); | ||||
device_printf(dev, " "); | device_printf(dev, " "); | ||||
▲ Show 20 Lines • Show All 382 Lines • ▼ Show 20 Lines | rgephy_load_dspcode(struct mii_softc *sc) | ||||
PHY_WRITE(sc, 31, 0x0000); | PHY_WRITE(sc, 31, 0x0000); | ||||
DELAY(40); | DELAY(40); | ||||
} | } | ||||
static void | static void | ||||
rgephy_reset(struct mii_softc *sc) | rgephy_reset(struct mii_softc *sc) | ||||
{ | { | ||||
struct rgephy_softc *rsc; | |||||
int confreg; | |||||
uint16_t pcr, ssr; | uint16_t pcr, ssr; | ||||
rsc = (struct rgephy_softc *)sc; | |||||
switch (sc->mii_mpd_rev) { | switch (sc->mii_mpd_rev) { | ||||
case RGEPHY_8211F: | case RGEPHY_8211F: | ||||
pcr = PHY_READ(sc, RGEPHY_F_MII_PCR1); | pcr = PHY_READ(sc, RGEPHY_F_MII_PCR1); | ||||
pcr &= ~(RGEPHY_F_PCR1_MDI_MM | RGEPHY_F_PCR1_ALDPS_EN); | pcr &= ~(RGEPHY_F_PCR1_MDI_MM | RGEPHY_F_PCR1_ALDPS_EN); | ||||
PHY_WRITE(sc, RGEPHY_F_MII_PCR1, pcr); | PHY_WRITE(sc, RGEPHY_F_MII_PCR1, pcr); | ||||
rgephy_disable_eee(sc); | rgephy_disable_eee(sc); | ||||
break; | break; | ||||
case RGEPHY_8211C: | case RGEPHY_8211C: | ||||
Show All 15 Lines | if (sc->mii_mpd_rev >= RGEPHY_8211B) { | ||||
PHY_WRITE(sc, RGEPHY_MII_PCR, pcr); | PHY_WRITE(sc, RGEPHY_MII_PCR, pcr); | ||||
} | } | ||||
} | } | ||||
break; | break; | ||||
} | } | ||||
mii_phy_reset(sc); | mii_phy_reset(sc); | ||||
DELAY(1000); | DELAY(1000); | ||||
/* | |||||
* This sequence was obtained from Pine64 engineering; we need to | |||||
* ensure that TXD/RXD are disabled and some magic undocumented | |||||
* bits in the CONFREG register need to be flipped. | |||||
*/ | |||||
if (rsc->quirks & RGEPHY_QUIRK_PINE64_CONFREG) { | |||||
PHY_WRITE(sc, RGEPHY_E_PAGSEL, 0x7); | |||||
PHY_WRITE(sc, RGEPHY_E_EPAGSR, 0xa4); | |||||
confreg = PHY_READ(sc, RGEPHY_E_CONFREG); | |||||
confreg &= ~(RGEPHY_E_CONFREG_TXD | RGEPHY_E_CONFREG_RXD); | |||||
confreg |= RGEPHY_E_CONFREG_MAGIC; | |||||
PHY_WRITE(sc, RGEPHY_E_CONFREG, confreg); | |||||
PHY_WRITE(sc, RGEPHY_E_PAGSEL, 0); | |||||
} | |||||
rgephy_load_dspcode(sc); | rgephy_load_dspcode(sc); | ||||
} | } | ||||
static void | static void | ||||
rgephy_disable_eee(struct mii_softc *sc) | rgephy_disable_eee(struct mii_softc *sc) | ||||
{ | { | ||||
uint16_t anar; | uint16_t anar; | ||||
Show All 20 Lines |