1 /* $NetBSD: tlphy.c,v 1.4 1997/11/17 09:07:32 thorpej Exp $ */ 2 3 /* 4 * Copyright (c) 1997 Manuel Bouyer. All rights reserved. 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, this list of conditions and the following disclaimer. 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. 14 * 3. All advertising materials mentioning features or use of this software 15 * must display the following acknowledgement: 16 * This product includes software developed by Manuel Bouyer. 17 * 4. The name of the author may not be used to endorse or promote products 18 * derived from this software without specific prior written permission. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 21 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 22 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 23 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 24 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 25 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 26 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 27 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 28 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 29 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 */ 31 32 /* Driver for Texas Instruments's ThunderLAN internal PHY */ 33 34 #include <sys/param.h> 35 #include <sys/systm.h> 36 #include <sys/kernel.h> 37 #include <sys/device.h> 38 #include <sys/malloc.h> 39 #include <sys/proc.h> 40 #include <sys/socket.h> 41 #include <net/if.h> 42 #include <net/if_media.h> 43 44 45 #include <dev/mii/mii_adapter.h> 46 #include <dev/mii/mii_adapters_id.h> 47 #include <dev/mii/mii_phy.h> 48 #include <dev/mii/generic_phy.h> 49 #include <dev/mii/tlphy.h> 50 51 static int tlphy_up __P((struct phy_softc *sc)); 52 void tlphy_pdown __P((void *v)); 53 int tlphy_media_set __P((int, void *)); 54 int tlphy_media_set_aui __P((struct phy_softc *)); 55 int tlphy_status __P((int, void*)); 56 57 #ifdef __BROKEN_INDIRECT_CONFIG 58 int tlphymatch __P((struct device *, void *, void *)); 59 #else 60 int tlphymatch __P((struct device *, struct cfdata *, void *)); 61 #endif 62 void tlphyattach __P((struct device *, struct device *, void *)); 63 64 struct cfattach tlphy_ca = { 65 sizeof(struct phy_softc), tlphymatch, tlphyattach 66 }; 67 68 struct cfdriver tlphy_cd = { 69 NULL, "tlphy", DV_IFNET 70 }; 71 72 int 73 tlphymatch(parent, match, aux) 74 struct device *parent; 75 #ifdef __BROKEN_INDIRECT_CONFIG 76 void *match; 77 #else 78 struct cfdata *match; 79 #endif 80 void *aux; 81 { 82 mii_phy_t *phy = aux; 83 84 if (phy->phy_id == 0x40005013 || phy->phy_id == 0x40005014 || 85 phy->phy_id == 0x40005015) 86 return (1); 87 return (0); 88 } 89 90 void 91 tlphyattach(parent, self, aux) 92 struct device *parent, *self; 93 void *aux; 94 { 95 struct phy_softc *sc = (struct phy_softc *)self; 96 97 sc->phy_link = aux; 98 sc->phy_link->phy_softc = sc; 99 sc->phy_link->phy_media_set = tlphy_media_set; 100 sc->phy_link->phy_status = tlphy_status; 101 sc->phy_link->phy_pdown = tlphy_pdown; 102 103 phy_reset(sc); 104 105 switch (sc->phy_link->adapter_id) { 106 case COMPAQ_INT_NETLIGENT_10_100: 107 sc->phy_link->phy_media = PHY_BNC; 108 break; 109 case COMPAQ_NETLIGENT_10_100: 110 sc->phy_link->phy_media = 0; 111 break; 112 case COMPAQ_INT_NETFLEX: 113 case COMPAQ_NETFLEX_BNC: 114 sc->phy_link->phy_media = PHY_BNC | PHY_10baseT; 115 break; 116 case TI_TLAN: 117 sc->phy_link->phy_media = PHY_10baseT; 118 break; 119 default: 120 sc->phy_link->phy_media = PHY_AUI; 121 if (phy_media_probe(sc) != 0) { 122 printf(" (autoconfig failed)"); 123 break; 124 } 125 } 126 127 if (sc->phy_link->phy_media) { 128 printf(": "); 129 phy_media_print(sc->phy_link->phy_media); 130 } 131 printf("\n"); 132 } 133 134 void 135 tlphy_pdown(v) 136 void *v; 137 { 138 struct phy_softc *sc = v; 139 mii_phy_t *phy_link = sc->phy_link; 140 141 mii_writereg(phy_link->mii_softc, phy_link->dev, PHY_CONTROL, 142 CTRL_ISO | CTRL_PDOWN); 143 } 144 145 static int 146 tlphy_up(sc) 147 struct phy_softc *sc; 148 { 149 int s; 150 mii_phy_t *phy_link = sc->phy_link; 151 int control, i; 152 153 s = splnet(); 154 155 /* set control registers to a reasonable value, wait for power_up */ 156 mii_writereg(phy_link->mii_softc, phy_link->dev, PHY_CONTROL, 157 CTRL_LOOPBK); 158 mii_writereg(phy_link->mii_softc, phy_link->dev, PHY_TL_CTRL, 0); 159 i = 0; 160 do { 161 DELAY(100000); 162 control = mii_readreg(phy_link->mii_softc, phy_link->dev, 163 PHY_TL_ST); 164 } while ((control < 0 || (control & TL_ST_PHOK) == 0) && ++i < 10); 165 if (control < 0 || (control & TL_ST_PHOK) == 0) { 166 splx(s); 167 printf("%s: power-up failed\n", sc->sc_dev.dv_xname); 168 return (0); 169 } 170 if (phy_reset(sc) == 0) { 171 splx(s); 172 return (0); 173 } 174 splx(s); 175 return (1); 176 } 177 178 int 179 tlphy_media_set(media, v) 180 int media; 181 void *v; 182 { 183 struct phy_softc *sc = v; 184 int subtype; 185 186 if (IFM_TYPE(media) != IFM_ETHER) 187 return (EINVAL); 188 189 if (tlphy_up(sc) == 0) 190 return (EIO); 191 192 subtype = IFM_SUBTYPE(media); 193 switch (subtype) { 194 case IFM_10_2: 195 case IFM_10_5: 196 if ((subtype == IFM_10_2 && 197 (sc->phy_link->phy_media & PHY_BNC)) || 198 (subtype == IFM_10_5 && 199 (sc->phy_link->phy_media & PHY_AUI))) 200 return (tlphy_media_set_aui(sc)); 201 else 202 return (EINVAL); 203 case IFM_10_T: 204 return (phy_media_set_10_100(sc, media)); 205 case IFM_AUTO: 206 return (ENODEV); 207 default: 208 return (EINVAL); 209 } 210 } 211 212 int 213 tlphy_media_set_aui(sc) 214 struct phy_softc *sc; 215 { 216 mii_phy_t *phy_link = sc->phy_link; 217 218 mii_writereg(phy_link->mii_softc, phy_link->dev, 219 PHY_CONTROL, 0); 220 mii_writereg(phy_link->mii_softc, phy_link->dev, 221 PHY_TL_CTRL, TL_CTRL_AUISEL); 222 DELAY(100000); 223 return (0); 224 } 225 226 int 227 tlphy_status(media, v) 228 int media; 229 void *v; 230 { 231 struct phy_softc *sc = v; 232 int reg; 233 234 if (IFM_SUBTYPE(media) == IFM_10_T) 235 return (phy_status(media, sc)); 236 reg = mii_readreg(sc->phy_link->mii_softc, sc->phy_link->dev, 237 PHY_TL_ST); 238 if ((reg & PHY_TL_ST) == 0) 239 return (ENETDOWN); 240 return (0); 241 } 242