| @@ -1,683 +1,689 @@ | | | @@ -1,683 +1,689 @@ |
1 | /* $NetBSD: rgephy.c,v 1.56 2019/10/11 03:40:01 msaitoh Exp $ */ | | 1 | /* $NetBSD: rgephy.c,v 1.57 2019/10/11 09:29:04 msaitoh Exp $ */ |
2 | | | 2 | |
3 | /* | | 3 | /* |
4 | * Copyright (c) 2003 | | 4 | * Copyright (c) 2003 |
5 | * Bill Paul <wpaul@windriver.com>. All rights reserved. | | 5 | * Bill Paul <wpaul@windriver.com>. All rights reserved. |
6 | * | | 6 | * |
7 | * Redistribution and use in source and binary forms, with or without | | 7 | * Redistribution and use in source and binary forms, with or without |
8 | * modification, are permitted provided that the following conditions | | 8 | * modification, are permitted provided that the following conditions |
9 | * are met: | | 9 | * are met: |
10 | * 1. Redistributions of source code must retain the above copyright | | 10 | * 1. Redistributions of source code must retain the above copyright |
11 | * notice, this list of conditions and the following disclaimer. | | 11 | * notice, this list of conditions and the following disclaimer. |
12 | * 2. Redistributions in binary form must reproduce the above copyright | | 12 | * 2. Redistributions in binary form must reproduce the above copyright |
13 | * notice, this list of conditions and the following disclaimer in the | | 13 | * notice, this list of conditions and the following disclaimer in the |
14 | * documentation and/or other materials provided with the distribution. | | 14 | * documentation and/or other materials provided with the distribution. |
15 | * 3. All advertising materials mentioning features or use of this software | | 15 | * 3. All advertising materials mentioning features or use of this software |
16 | * must display the following acknowledgement: | | 16 | * must display the following acknowledgement: |
17 | * This product includes software developed by Bill Paul. | | 17 | * This product includes software developed by Bill Paul. |
18 | * 4. Neither the name of the author nor the names of any co-contributors | | 18 | * 4. Neither the name of the author nor the names of any co-contributors |
19 | * may be used to endorse or promote products derived from this software | | 19 | * may be used to endorse or promote products derived from this software |
20 | * without specific prior written permission. | | 20 | * without specific prior written permission. |
21 | * | | 21 | * |
22 | * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND | | 22 | * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND |
23 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | | 23 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
24 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | | 24 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
25 | * ARE DISCLAIMED. IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD | | 25 | * ARE DISCLAIMED. IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD |
26 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | | 26 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
27 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | | 27 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
28 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | | 28 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
29 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN | | 29 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
30 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | | 30 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
31 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF | | 31 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF |
32 | * THE POSSIBILITY OF SUCH DAMAGE. | | 32 | * THE POSSIBILITY OF SUCH DAMAGE. |
33 | */ | | 33 | */ |
34 | | | 34 | |
35 | #include <sys/cdefs.h> | | 35 | #include <sys/cdefs.h> |
36 | __KERNEL_RCSID(0, "$NetBSD: rgephy.c,v 1.56 2019/10/11 03:40:01 msaitoh Exp $"); | | 36 | __KERNEL_RCSID(0, "$NetBSD: rgephy.c,v 1.57 2019/10/11 09:29:04 msaitoh Exp $"); |
37 | | | 37 | |
38 | | | 38 | |
39 | /* | | 39 | /* |
40 | * Driver for the RealTek 8169S/8110S internal 10/100/1000 PHY. | | 40 | * Driver for the RealTek 8169S/8110S internal 10/100/1000 PHY. |
41 | */ | | 41 | */ |
42 | | | 42 | |
43 | #include <sys/param.h> | | 43 | #include <sys/param.h> |
44 | #include <sys/systm.h> | | 44 | #include <sys/systm.h> |
45 | #include <sys/kernel.h> | | 45 | #include <sys/kernel.h> |
46 | #include <sys/device.h> | | 46 | #include <sys/device.h> |
47 | #include <sys/socket.h> | | 47 | #include <sys/socket.h> |
48 | | | 48 | |
49 | | | 49 | |
50 | #include <net/if.h> | | 50 | #include <net/if.h> |
51 | #include <net/if_media.h> | | 51 | #include <net/if_media.h> |
52 | | | 52 | |
53 | #include <dev/mii/mii.h> | | 53 | #include <dev/mii/mii.h> |
54 | #include <dev/mii/mdio.h> | | 54 | #include <dev/mii/mdio.h> |
55 | #include <dev/mii/miivar.h> | | 55 | #include <dev/mii/miivar.h> |
56 | #include <dev/mii/miidevs.h> | | 56 | #include <dev/mii/miidevs.h> |
57 | | | 57 | |
58 | #include <dev/mii/rgephyreg.h> | | 58 | #include <dev/mii/rgephyreg.h> |
59 | | | 59 | |
60 | #include <dev/ic/rtl81x9reg.h> | | 60 | #include <dev/ic/rtl81x9reg.h> |
61 | | | 61 | |
62 | static int rgephy_match(device_t, cfdata_t, void *); | | 62 | static int rgephy_match(device_t, cfdata_t, void *); |
63 | static void rgephy_attach(device_t, device_t, void *); | | 63 | static void rgephy_attach(device_t, device_t, void *); |
64 | | | 64 | |
65 | struct rgephy_softc { | | 65 | struct rgephy_softc { |
66 | struct mii_softc mii_sc; | | 66 | struct mii_softc mii_sc; |
67 | bool mii_no_rx_delay; | | 67 | bool mii_no_rx_delay; |
68 | }; | | 68 | }; |
69 | | | 69 | |
70 | CFATTACH_DECL_NEW(rgephy, sizeof(struct rgephy_softc), | | 70 | CFATTACH_DECL_NEW(rgephy, sizeof(struct rgephy_softc), |
71 | rgephy_match, rgephy_attach, mii_phy_detach, mii_phy_activate); | | 71 | rgephy_match, rgephy_attach, mii_phy_detach, mii_phy_activate); |
72 | | | 72 | |
73 | | | 73 | |
74 | static int rgephy_service(struct mii_softc *, struct mii_data *, int); | | 74 | static int rgephy_service(struct mii_softc *, struct mii_data *, int); |
75 | static void rgephy_status(struct mii_softc *); | | 75 | static void rgephy_status(struct mii_softc *); |
76 | static int rgephy_mii_phy_auto(struct mii_softc *); | | 76 | static int rgephy_mii_phy_auto(struct mii_softc *); |
77 | static void rgephy_reset(struct mii_softc *); | | 77 | static void rgephy_reset(struct mii_softc *); |
78 | static bool rgephy_linkup(struct mii_softc *); | | 78 | static bool rgephy_linkup(struct mii_softc *); |
79 | static void rgephy_loop(struct mii_softc *); | | 79 | static void rgephy_loop(struct mii_softc *); |
80 | static void rgephy_load_dspcode(struct mii_softc *); | | 80 | static void rgephy_load_dspcode(struct mii_softc *); |
81 | | | 81 | |
82 | static const struct mii_phy_funcs rgephy_funcs = { | | 82 | static const struct mii_phy_funcs rgephy_funcs = { |
83 | rgephy_service, rgephy_status, rgephy_reset, | | 83 | rgephy_service, rgephy_status, rgephy_reset, |
84 | }; | | 84 | }; |
85 | | | 85 | |
86 | static const struct mii_phydesc rgephys[] = { | | 86 | static const struct mii_phydesc rgephys[] = { |
87 | MII_PHY_DESC(xxREALTEK, RTL8169S), | | 87 | MII_PHY_DESC(xxREALTEK, RTL8169S), |
88 | MII_PHY_DESC(REALTEK, RTL8169S), | | 88 | MII_PHY_DESC(REALTEK, RTL8169S), |
89 | MII_PHY_DESC(REALTEK, RTL8251), | | 89 | MII_PHY_DESC(REALTEK, RTL8251), |
90 | MII_PHY_END, | | 90 | MII_PHY_END, |
91 | }; | | 91 | }; |
92 | | | 92 | |
93 | static int | | 93 | static int |
94 | rgephy_match(device_t parent, cfdata_t match, void *aux) | | 94 | rgephy_match(device_t parent, cfdata_t match, void *aux) |
95 | { | | 95 | { |
96 | struct mii_attach_args *ma = aux; | | 96 | struct mii_attach_args *ma = aux; |
97 | | | 97 | |
98 | if (mii_phy_match(ma, rgephys) != NULL) | | 98 | if (mii_phy_match(ma, rgephys) != NULL) |
99 | return 10; | | 99 | return 10; |
100 | | | 100 | |
101 | return 0; | | 101 | return 0; |
102 | } | | 102 | } |
103 | | | 103 | |
104 | static void | | 104 | static void |
105 | rgephy_attach(device_t parent, device_t self, void *aux) | | 105 | rgephy_attach(device_t parent, device_t self, void *aux) |
106 | { | | 106 | { |
107 | struct rgephy_softc *rsc = device_private(self); | | 107 | struct rgephy_softc *rsc = device_private(self); |
108 | prop_dictionary_t prop = device_properties(self); | | 108 | prop_dictionary_t prop = device_properties(self); |
109 | struct mii_softc *sc = &rsc->mii_sc; | | 109 | struct mii_softc *sc = &rsc->mii_sc; |
110 | struct mii_attach_args *ma = aux; | | 110 | struct mii_attach_args *ma = aux; |
111 | struct mii_data *mii = ma->mii_data; | | 111 | struct mii_data *mii = ma->mii_data; |
112 | const struct mii_phydesc *mpd; | | 112 | const struct mii_phydesc *mpd; |
113 | int rev; | | 113 | int rev; |
114 | const char *sep = ""; | | 114 | const char *sep = ""; |
115 | | | 115 | |
116 | rev = MII_REV(ma->mii_id2); | | 116 | rev = MII_REV(ma->mii_id2); |
117 | mpd = mii_phy_match(ma, rgephys); | | 117 | mpd = mii_phy_match(ma, rgephys); |
118 | aprint_naive(": Media interface\n"); | | 118 | aprint_naive(": Media interface\n"); |
119 | | | 119 | |
120 | sc->mii_dev = self; | | 120 | sc->mii_dev = self; |
121 | sc->mii_inst = mii->mii_instance; | | 121 | sc->mii_inst = mii->mii_instance; |
122 | sc->mii_phy = ma->mii_phyno; | | 122 | sc->mii_phy = ma->mii_phyno; |
123 | sc->mii_mpd_oui = MII_OUI(ma->mii_id1, ma->mii_id2); | | 123 | sc->mii_mpd_oui = MII_OUI(ma->mii_id1, ma->mii_id2); |
124 | sc->mii_mpd_model = MII_MODEL(ma->mii_id2); | | 124 | sc->mii_mpd_model = MII_MODEL(ma->mii_id2); |
125 | sc->mii_mpd_rev = MII_REV(ma->mii_id2); | | 125 | sc->mii_mpd_rev = MII_REV(ma->mii_id2); |
126 | | | 126 | |
127 | if (sc->mii_mpd_model == MII_MODEL_REALTEK_RTL8169S) { | | 127 | if (sc->mii_mpd_model == MII_MODEL_REALTEK_RTL8169S) { |
128 | aprint_normal(": RTL8211"); | | 128 | aprint_normal(": RTL8211"); |
129 | if (sc->mii_mpd_rev != 0) | | 129 | if (sc->mii_mpd_rev != 0) |
130 | aprint_normal("%c",'@' + sc->mii_mpd_rev); | | 130 | aprint_normal("%c",'@' + sc->mii_mpd_rev); |
131 | aprint_normal(" 1000BASE-T media interface\n"); | | 131 | aprint_normal(" 1000BASE-T media interface\n"); |
132 | } else | | 132 | } else |
133 | aprint_normal(": %s, rev. %d\n", mpd->mpd_name, rev); | | 133 | aprint_normal(": %s, rev. %d\n", mpd->mpd_name, rev); |
134 | | | 134 | |
135 | sc->mii_pdata = mii; | | 135 | sc->mii_pdata = mii; |
136 | sc->mii_flags = ma->mii_flags; | | 136 | sc->mii_flags = ma->mii_flags; |
137 | sc->mii_anegticks = MII_ANEGTICKS_GIGE; | | 137 | sc->mii_anegticks = MII_ANEGTICKS_GIGE; |
138 | | | 138 | |
139 | sc->mii_funcs = &rgephy_funcs; | | 139 | sc->mii_funcs = &rgephy_funcs; |
140 | | | 140 | |
141 | prop_dictionary_get_bool(prop, "no-rx-delay", &rsc->mii_no_rx_delay); | | 141 | prop_dictionary_get_bool(prop, "no-rx-delay", &rsc->mii_no_rx_delay); |
142 | | | 142 | |
143 | #define ADD(m, c) ifmedia_add(&mii->mii_media, (m), (c), NULL) | | 143 | #define ADD(m, c) ifmedia_add(&mii->mii_media, (m), (c), NULL) |
144 | #define PRINT(n) aprint_normal("%s%s", sep, (n)); sep = ", " | | 144 | #define PRINT(n) aprint_normal("%s%s", sep, (n)); sep = ", " |
145 | | | 145 | |
146 | #ifdef __FreeBSD__ | | 146 | #ifdef __FreeBSD__ |
147 | ADD(IFM_MAKEWORD(IFM_ETHER, IFM_100_TX, IFM_LOOP, sc->mii_inst), | | 147 | ADD(IFM_MAKEWORD(IFM_ETHER, IFM_100_TX, IFM_LOOP, sc->mii_inst), |
148 | BMCR_LOOP | BMCR_S100); | | 148 | BMCR_LOOP | BMCR_S100); |
149 | #endif | | 149 | #endif |
150 | | | 150 | |
151 | PHY_READ(sc, MII_BMSR, &sc->mii_capabilities); | | 151 | PHY_READ(sc, MII_BMSR, &sc->mii_capabilities); |
152 | sc->mii_capabilities &= ma->mii_capmask; | | 152 | sc->mii_capabilities &= ma->mii_capmask; |
153 | sc->mii_capabilities &= ~BMSR_ANEG; | | 153 | sc->mii_capabilities &= ~BMSR_ANEG; |
154 | | | 154 | |
155 | /* | | 155 | /* |
156 | * FreeBSD does not check EXSTAT, but instead adds gigabit | | 156 | * FreeBSD does not check EXSTAT, but instead adds gigabit |
157 | * media explicitly. Why? | | 157 | * media explicitly. Why? |
158 | */ | | 158 | */ |
159 | aprint_normal_dev(self, ""); | | 159 | aprint_normal_dev(self, ""); |
160 | if (sc->mii_capabilities & BMSR_EXTSTAT) | | 160 | if (sc->mii_capabilities & BMSR_EXTSTAT) |
161 | PHY_READ(sc, MII_EXTSR, &sc->mii_extcapabilities); | | 161 | PHY_READ(sc, MII_EXTSR, &sc->mii_extcapabilities); |
162 | | | 162 | |
163 | mii_phy_add_media(sc); | | 163 | mii_phy_add_media(sc); |
164 | | | 164 | |
165 | /* rtl8169S does not report auto-sense; add manually. */ | | 165 | /* rtl8169S does not report auto-sense; add manually. */ |
166 | ADD(IFM_MAKEWORD(IFM_ETHER, IFM_AUTO, 0, sc->mii_inst), MII_NMEDIA); | | 166 | ADD(IFM_MAKEWORD(IFM_ETHER, IFM_AUTO, 0, sc->mii_inst), MII_NMEDIA); |
167 | sep =", "; | | 167 | sep =", "; |
168 | PRINT("auto"); | | 168 | PRINT("auto"); |
169 | | | 169 | |
170 | #undef ADD | | 170 | #undef ADD |
171 | #undef PRINT | | 171 | #undef PRINT |
172 | | | 172 | |
173 | rgephy_reset(sc); | | 173 | rgephy_reset(sc); |
174 | aprint_normal("\n"); | | 174 | aprint_normal("\n"); |
175 | } | | 175 | } |
176 | | | 176 | |
177 | static int | | 177 | static int |
178 | rgephy_service(struct mii_softc *sc, struct mii_data *mii, int cmd) | | 178 | rgephy_service(struct mii_softc *sc, struct mii_data *mii, int cmd) |
179 | { | | 179 | { |
180 | struct ifmedia_entry *ife = mii->mii_media.ifm_cur; | | 180 | struct ifmedia_entry *ife = mii->mii_media.ifm_cur; |
181 | uint16_t reg, speed, gig, anar; | | 181 | uint16_t reg, speed, gig, anar; |
182 | | | 182 | |
183 | switch (cmd) { | | 183 | switch (cmd) { |
184 | case MII_POLLSTAT: | | 184 | case MII_POLLSTAT: |
185 | /* If we're not polling our PHY instance, just return. */ | | 185 | /* If we're not polling our PHY instance, just return. */ |
186 | if (IFM_INST(ife->ifm_media) != sc->mii_inst) | | 186 | if (IFM_INST(ife->ifm_media) != sc->mii_inst) |
187 | return 0; | | 187 | return 0; |
188 | break; | | 188 | break; |
189 | | | 189 | |
190 | case MII_MEDIACHG: | | 190 | case MII_MEDIACHG: |
191 | /* | | 191 | /* |
192 | * If the media indicates a different PHY instance, | | 192 | * If the media indicates a different PHY instance, |
193 | * isolate ourselves. | | 193 | * isolate ourselves. |
194 | */ | | 194 | */ |
195 | if (IFM_INST(ife->ifm_media) != sc->mii_inst) { | | 195 | if (IFM_INST(ife->ifm_media) != sc->mii_inst) { |
196 | PHY_READ(sc, MII_BMCR, ®); | | 196 | PHY_READ(sc, MII_BMCR, ®); |
197 | PHY_WRITE(sc, MII_BMCR, reg | BMCR_ISO); | | 197 | PHY_WRITE(sc, MII_BMCR, reg | BMCR_ISO); |
198 | return 0; | | 198 | return 0; |
199 | } | | 199 | } |
200 | | | 200 | |
201 | /* If the interface is not up, don't do anything. */ | | 201 | /* If the interface is not up, don't do anything. */ |
202 | if ((mii->mii_ifp->if_flags & IFF_UP) == 0) | | 202 | if ((mii->mii_ifp->if_flags & IFF_UP) == 0) |
203 | break; | | 203 | break; |
204 | | | 204 | |
205 | rgephy_reset(sc); /* XXX hardware bug work-around */ | | 205 | rgephy_reset(sc); /* XXX hardware bug work-around */ |
206 | | | 206 | |
207 | PHY_READ(sc, MII_ANAR, &anar); | | 207 | PHY_READ(sc, MII_ANAR, &anar); |
208 | anar &= ~(ANAR_TX_FD | ANAR_TX | ANAR_10_FD | ANAR_10); | | 208 | anar &= ~(ANAR_TX_FD | ANAR_TX | ANAR_10_FD | ANAR_10); |
209 | | | 209 | |
210 | switch (IFM_SUBTYPE(ife->ifm_media)) { | | 210 | switch (IFM_SUBTYPE(ife->ifm_media)) { |
211 | case IFM_AUTO: | | 211 | case IFM_AUTO: |
212 | #ifdef foo | | 212 | #ifdef foo |
213 | /* If we're already in auto mode, just return. */ | | 213 | /* If we're already in auto mode, just return. */ |
214 | PHY_READ(sc, MII_BMCR, ®); | | 214 | PHY_READ(sc, MII_BMCR, ®); |
215 | if (reg & BMCR_AUTOEN) | | 215 | if (reg & BMCR_AUTOEN) |
216 | return 0; | | 216 | return 0; |
217 | #endif | | 217 | #endif |
218 | (void)rgephy_mii_phy_auto(sc); | | 218 | (void)rgephy_mii_phy_auto(sc); |
219 | break; | | 219 | break; |
220 | case IFM_1000_T: | | 220 | case IFM_1000_T: |
221 | speed = BMCR_S1000; | | 221 | speed = BMCR_S1000; |
222 | goto setit; | | 222 | goto setit; |
223 | case IFM_100_TX: | | 223 | case IFM_100_TX: |
224 | speed = BMCR_S100; | | 224 | speed = BMCR_S100; |
225 | anar |= ANAR_TX_FD | ANAR_TX; | | 225 | anar |= ANAR_TX_FD | ANAR_TX; |
226 | goto setit; | | 226 | goto setit; |
227 | case IFM_10_T: | | 227 | case IFM_10_T: |
228 | speed = BMCR_S10; | | 228 | speed = BMCR_S10; |
229 | anar |= ANAR_10_FD | ANAR_10; | | 229 | anar |= ANAR_10_FD | ANAR_10; |
230 | setit: | | 230 | setit: |
231 | rgephy_loop(sc); | | 231 | rgephy_loop(sc); |
232 | if ((ife->ifm_media & IFM_FDX) != 0) { | | 232 | if ((ife->ifm_media & IFM_FDX) != 0) { |
233 | speed |= BMCR_FDX; | | 233 | speed |= BMCR_FDX; |
234 | gig = GTCR_ADV_1000TFDX; | | 234 | gig = GTCR_ADV_1000TFDX; |
235 | anar &= ~(ANAR_TX | ANAR_10); | | 235 | anar &= ~(ANAR_TX | ANAR_10); |
236 | } else { | | 236 | } else { |
237 | gig = GTCR_ADV_1000THDX; | | 237 | gig = GTCR_ADV_1000THDX; |
238 | anar &= ~(ANAR_TX_FD | ANAR_10_FD); | | 238 | anar &= ~(ANAR_TX_FD | ANAR_10_FD); |
239 | } | | 239 | } |
240 | | | 240 | |
241 | if (IFM_SUBTYPE(ife->ifm_media) != IFM_1000_T) { | | 241 | if (IFM_SUBTYPE(ife->ifm_media) != IFM_1000_T) { |
242 | PHY_WRITE(sc, MII_100T2CR, 0); | | 242 | PHY_WRITE(sc, MII_100T2CR, 0); |
243 | PHY_WRITE(sc, MII_ANAR, anar); | | 243 | PHY_WRITE(sc, MII_ANAR, anar); |
244 | PHY_WRITE(sc, MII_BMCR, | | 244 | PHY_WRITE(sc, MII_BMCR, |
245 | speed | BMCR_AUTOEN | BMCR_STARTNEG); | | 245 | speed | BMCR_AUTOEN | BMCR_STARTNEG); |
246 | break; | | 246 | break; |
247 | } | | 247 | } |
248 | | | 248 | |
249 | /* | | 249 | /* |
250 | * When setting the link manually, one side must be the | | 250 | * When setting the link manually, one side must be the |
251 | * master and the other the slave. However ifmedia | | 251 | * master and the other the slave. However ifmedia |
252 | * doesn't give us a good way to specify this, so we | | 252 | * doesn't give us a good way to specify this, so we |
253 | * fake it by using one of the LINK flags. If LINK0 is | | 253 | * fake it by using one of the LINK flags. If LINK0 is |
254 | * set, we program the PHY to be a master, otherwise | | 254 | * set, we program the PHY to be a master, otherwise |
255 | * it's a slave. | | 255 | * it's a slave. |
256 | */ | | 256 | */ |
257 | if ((mii->mii_ifp->if_flags & IFF_LINK0)) { | | 257 | if ((mii->mii_ifp->if_flags & IFF_LINK0)) { |
258 | PHY_WRITE(sc, MII_100T2CR, | | 258 | PHY_WRITE(sc, MII_100T2CR, |
259 | gig | GTCR_MAN_MS | GTCR_ADV_MS); | | 259 | gig | GTCR_MAN_MS | GTCR_ADV_MS); |
260 | } else | | 260 | } else |
261 | PHY_WRITE(sc, MII_100T2CR, gig | GTCR_MAN_MS); | | 261 | PHY_WRITE(sc, MII_100T2CR, gig | GTCR_MAN_MS); |
262 | PHY_WRITE(sc, MII_BMCR, | | 262 | PHY_WRITE(sc, MII_BMCR, |
263 | speed | BMCR_AUTOEN | BMCR_STARTNEG); | | 263 | speed | BMCR_AUTOEN | BMCR_STARTNEG); |
264 | break; | | 264 | break; |
265 | case IFM_NONE: | | 265 | case IFM_NONE: |
266 | PHY_WRITE(sc, MII_BMCR, BMCR_ISO | BMCR_PDOWN); | | 266 | PHY_WRITE(sc, MII_BMCR, BMCR_ISO | BMCR_PDOWN); |
267 | break; | | 267 | break; |
268 | case IFM_100_T4: | | 268 | case IFM_100_T4: |
269 | default: | | 269 | default: |
270 | return EINVAL; | | 270 | return EINVAL; |
271 | } | | 271 | } |
272 | break; | | 272 | break; |
273 | | | 273 | |
274 | case MII_TICK: | | 274 | case MII_TICK: |
275 | /* If we're not currently selected, just return. */ | | 275 | /* If we're not currently selected, just return. */ |
276 | if (IFM_INST(ife->ifm_media) != sc->mii_inst) | | 276 | if (IFM_INST(ife->ifm_media) != sc->mii_inst) |
277 | return 0; | | 277 | return 0; |
278 | | | 278 | |
279 | /* Is the interface even up? */ | | 279 | /* Is the interface even up? */ |
280 | if ((mii->mii_ifp->if_flags & IFF_UP) == 0) | | 280 | if ((mii->mii_ifp->if_flags & IFF_UP) == 0) |
281 | return 0; | | 281 | return 0; |
282 | | | 282 | |
283 | /* Only used for autonegotiation. */ | | 283 | /* Only used for autonegotiation. */ |
284 | if ((IFM_SUBTYPE(ife->ifm_media) != IFM_AUTO) && | | 284 | if ((IFM_SUBTYPE(ife->ifm_media) != IFM_AUTO) && |
285 | (IFM_SUBTYPE(ife->ifm_media) != IFM_1000_T)) { | | 285 | (IFM_SUBTYPE(ife->ifm_media) != IFM_1000_T)) { |
286 | /* | | 286 | /* |
287 | * Reset autonegotiation timer to 0 to make sure | | 287 | * Reset autonegotiation timer to 0 to make sure |
288 | * the future autonegotiation start with 0. | | 288 | * the future autonegotiation start with 0. |
289 | */ | | 289 | */ |
290 | sc->mii_ticks = 0; | | 290 | sc->mii_ticks = 0; |
291 | break; | | 291 | break; |
292 | } | | 292 | } |
293 | | | 293 | |
294 | /* | | 294 | /* |
295 | * Check to see if we have link. If we do, we don't | | 295 | * Check to see if we have link. If we do, we don't |
296 | * need to restart the autonegotiation process. Read | | 296 | * need to restart the autonegotiation process. Read |
297 | * the BMSR twice in case it's latched. | | 297 | * the BMSR twice in case it's latched. |
298 | */ | | 298 | */ |
299 | if (rgephy_linkup(sc)) { | | 299 | if (rgephy_linkup(sc)) { |
300 | sc->mii_ticks = 0; | | 300 | sc->mii_ticks = 0; |
301 | break; | | 301 | break; |
302 | } | | 302 | } |
303 | | | 303 | |
304 | /* Announce link loss right after it happens. */ | | 304 | /* Announce link loss right after it happens. */ |
305 | if (sc->mii_ticks++ == 0) | | 305 | if (sc->mii_ticks++ == 0) |
306 | break; | | 306 | break; |
307 | | | 307 | |
308 | /* Only retry autonegotiation every mii_anegticks seconds. */ | | 308 | /* Only retry autonegotiation every mii_anegticks seconds. */ |
309 | if (sc->mii_ticks <= sc->mii_anegticks) | | 309 | if (sc->mii_ticks <= sc->mii_anegticks) |
310 | return 0; | | 310 | return 0; |
311 | | | 311 | |
312 | rgephy_mii_phy_auto(sc); | | 312 | rgephy_mii_phy_auto(sc); |
313 | break; | | 313 | break; |
314 | } | | 314 | } |
315 | | | 315 | |
316 | /* Update the media status. */ | | 316 | /* Update the media status. */ |
317 | rgephy_status(sc); | | 317 | rgephy_status(sc); |
318 | | | 318 | |
319 | /* | | 319 | /* |
320 | * Callback if something changed. Note that we need to poke | | 320 | * Callback if something changed. Note that we need to poke |
321 | * the DSP on the RealTek PHYs if the media changes. | | 321 | * the DSP on the RealTek PHYs if the media changes. |
322 | */ | | 322 | */ |
323 | if (sc->mii_media_active != mii->mii_media_active || | | 323 | if (sc->mii_media_active != mii->mii_media_active || |
324 | sc->mii_media_status != mii->mii_media_status || | | 324 | sc->mii_media_status != mii->mii_media_status || |
325 | cmd == MII_MEDIACHG) { | | 325 | cmd == MII_MEDIACHG) { |
326 | rgephy_load_dspcode(sc); | | 326 | rgephy_load_dspcode(sc); |
327 | } | | 327 | } |
328 | mii_phy_update(sc, cmd); | | 328 | mii_phy_update(sc, cmd); |
329 | return 0; | | 329 | return 0; |
330 | } | | 330 | } |
331 | | | 331 | |
332 | static bool | | 332 | static bool |
333 | rgephy_linkup(struct mii_softc *sc) | | 333 | rgephy_linkup(struct mii_softc *sc) |
334 | { | | 334 | { |
335 | bool linkup = false; | | 335 | bool linkup = false; |
336 | uint16_t reg; | | 336 | uint16_t reg; |
337 | | | 337 | |
338 | if (sc->mii_mpd_rev >= RGEPHY_8211F) { | | 338 | if (sc->mii_mpd_rev >= RGEPHY_8211F) { |
339 | PHY_READ(sc, RGEPHY_MII_PHYSR, ®); | | 339 | PHY_READ(sc, RGEPHY_MII_PHYSR, ®); |
340 | if (reg & RGEPHY_PHYSR_LINK) | | 340 | if (reg & RGEPHY_PHYSR_LINK) |
341 | linkup = true; | | 341 | linkup = true; |
342 | } else if (sc->mii_mpd_rev >= RGEPHY_8211B) { | | 342 | } else if (sc->mii_mpd_rev >= RGEPHY_8211B) { |
343 | PHY_READ(sc, RGEPHY_MII_SSR, ®); | | 343 | PHY_READ(sc, RGEPHY_MII_SSR, ®); |
344 | if (reg & RGEPHY_SSR_LINK) | | 344 | if (reg & RGEPHY_SSR_LINK) |
345 | linkup = true; | | 345 | linkup = true; |
346 | } else { | | 346 | } else { |
347 | PHY_READ(sc, RTK_GMEDIASTAT, ®); | | 347 | PHY_READ(sc, RTK_GMEDIASTAT, ®); |
348 | if ((reg & RTK_GMEDIASTAT_LINK) != 0) | | 348 | if ((reg & RTK_GMEDIASTAT_LINK) != 0) |
349 | linkup = true; | | 349 | linkup = true; |
350 | } | | 350 | } |
351 | | | 351 | |
352 | return linkup; | | 352 | return linkup; |
353 | } | | 353 | } |
354 | | | 354 | |
355 | static void | | 355 | static void |
356 | rgephy_status(struct mii_softc *sc) | | 356 | rgephy_status(struct mii_softc *sc) |
357 | { | | 357 | { |
358 | struct mii_data *mii = sc->mii_pdata; | | 358 | struct mii_data *mii = sc->mii_pdata; |
359 | uint16_t gstat, bmsr, bmcr, physr, ssr; | | 359 | uint16_t gstat, bmsr, bmcr, gtsr, physr, ssr; |
360 | | | 360 | |
361 | mii->mii_media_status = IFM_AVALID; | | 361 | mii->mii_media_status = IFM_AVALID; |
362 | mii->mii_media_active = IFM_ETHER; | | 362 | mii->mii_media_active = IFM_ETHER; |
363 | | | 363 | |
364 | if (rgephy_linkup(sc)) | | 364 | if (rgephy_linkup(sc)) |
365 | mii->mii_media_status |= IFM_ACTIVE; | | 365 | mii->mii_media_status |= IFM_ACTIVE; |
366 | | | 366 | |
367 | PHY_READ(sc, MII_BMSR, &bmsr); | | 367 | PHY_READ(sc, MII_BMSR, &bmsr); |
368 | PHY_READ(sc, MII_BMCR, &bmcr); | | 368 | PHY_READ(sc, MII_BMCR, &bmcr); |
369 | | | 369 | |
370 | if ((bmcr & BMCR_ISO) != 0) { | | 370 | if ((bmcr & BMCR_ISO) != 0) { |
371 | mii->mii_media_active |= IFM_NONE; | | 371 | mii->mii_media_active |= IFM_NONE; |
372 | mii->mii_media_status = 0; | | 372 | mii->mii_media_status = 0; |
373 | return; | | 373 | return; |
374 | } | | 374 | } |
375 | | | 375 | |
376 | if ((bmcr & BMCR_LOOP) != 0) | | 376 | if ((bmcr & BMCR_LOOP) != 0) |
377 | mii->mii_media_active |= IFM_LOOP; | | 377 | mii->mii_media_active |= IFM_LOOP; |
378 | | | 378 | |
379 | if ((bmcr & BMCR_AUTOEN) != 0) { | | 379 | if ((bmcr & BMCR_AUTOEN) != 0) { |
380 | if ((bmsr & BMSR_ACOMP) == 0) { | | 380 | if ((bmsr & BMSR_ACOMP) == 0) { |
381 | /* Erg, still trying, I guess... */ | | 381 | /* Erg, still trying, I guess... */ |
382 | mii->mii_media_active |= IFM_NONE; | | 382 | mii->mii_media_active |= IFM_NONE; |
383 | return; | | 383 | return; |
384 | } | | 384 | } |
385 | } | | 385 | } |
386 | | | 386 | |
387 | if (sc->mii_mpd_rev >= RGEPHY_8211F) { | | 387 | if (sc->mii_mpd_rev >= RGEPHY_8211F) { |
388 | PHY_READ(sc, RGEPHY_MII_PHYSR, &physr); | | 388 | PHY_READ(sc, RGEPHY_MII_PHYSR, &physr); |
389 | switch (__SHIFTOUT(physr, RGEPHY_PHYSR_SPEED)) { | | 389 | switch (__SHIFTOUT(physr, RGEPHY_PHYSR_SPEED)) { |
390 | case RGEPHY_PHYSR_SPEED_1000: | | 390 | case RGEPHY_PHYSR_SPEED_1000: |
391 | mii->mii_media_active |= IFM_1000_T; | | 391 | mii->mii_media_active |= IFM_1000_T; |
392 | break; | | 392 | break; |
393 | case RGEPHY_PHYSR_SPEED_100: | | 393 | case RGEPHY_PHYSR_SPEED_100: |
394 | mii->mii_media_active |= IFM_100_TX; | | 394 | mii->mii_media_active |= IFM_100_TX; |
395 | break; | | 395 | break; |
396 | case RGEPHY_PHYSR_SPEED_10: | | 396 | case RGEPHY_PHYSR_SPEED_10: |
397 | mii->mii_media_active |= IFM_10_T; | | 397 | mii->mii_media_active |= IFM_10_T; |
398 | break; | | 398 | break; |
399 | default: | | 399 | default: |
400 | mii->mii_media_active |= IFM_NONE; | | 400 | mii->mii_media_active |= IFM_NONE; |
401 | break; | | 401 | break; |
402 | } | | 402 | } |
403 | if (physr & RGEPHY_PHYSR_DUPLEX) | | 403 | if (physr & RGEPHY_PHYSR_DUPLEX) |
404 | mii->mii_media_active |= mii_phy_flowstatus(sc) | | | 404 | mii->mii_media_active |= mii_phy_flowstatus(sc) | |
405 | IFM_FDX; | | 405 | IFM_FDX; |
406 | else | | 406 | else |
407 | mii->mii_media_active |= IFM_HDX; | | 407 | mii->mii_media_active |= IFM_HDX; |
408 | } else if (sc->mii_mpd_rev >= RGEPHY_8211B) { | | 408 | } else if (sc->mii_mpd_rev >= RGEPHY_8211B) { |
409 | PHY_READ(sc, RGEPHY_MII_SSR, &ssr); | | 409 | PHY_READ(sc, RGEPHY_MII_SSR, &ssr); |
410 | switch (ssr & RGEPHY_SSR_SPD_MASK) { | | 410 | switch (ssr & RGEPHY_SSR_SPD_MASK) { |
411 | case RGEPHY_SSR_S1000: | | 411 | case RGEPHY_SSR_S1000: |
412 | mii->mii_media_active |= IFM_1000_T; | | 412 | mii->mii_media_active |= IFM_1000_T; |
413 | break; | | 413 | break; |
414 | case RGEPHY_SSR_S100: | | 414 | case RGEPHY_SSR_S100: |
415 | mii->mii_media_active |= IFM_100_TX; | | 415 | mii->mii_media_active |= IFM_100_TX; |
416 | break; | | 416 | break; |
417 | case RGEPHY_SSR_S10: | | 417 | case RGEPHY_SSR_S10: |
418 | mii->mii_media_active |= IFM_10_T; | | 418 | mii->mii_media_active |= IFM_10_T; |
419 | break; | | 419 | break; |
420 | default: | | 420 | default: |
421 | mii->mii_media_active |= IFM_NONE; | | 421 | mii->mii_media_active |= IFM_NONE; |
422 | break; | | 422 | break; |
423 | } | | 423 | } |
424 | if (ssr & RGEPHY_SSR_FDX) | | 424 | if (ssr & RGEPHY_SSR_FDX) |
425 | mii->mii_media_active |= mii_phy_flowstatus(sc) | | | 425 | mii->mii_media_active |= mii_phy_flowstatus(sc) | |
426 | IFM_FDX; | | 426 | IFM_FDX; |
427 | else | | 427 | else |
428 | mii->mii_media_active |= IFM_HDX; | | 428 | mii->mii_media_active |= IFM_HDX; |
429 | } else { | | 429 | } else { |
430 | PHY_READ(sc, RTK_GMEDIASTAT, &gstat); | | 430 | PHY_READ(sc, RTK_GMEDIASTAT, &gstat); |
431 | if ((gstat & RTK_GMEDIASTAT_1000MBPS) != 0) | | 431 | if ((gstat & RTK_GMEDIASTAT_1000MBPS) != 0) |
432 | mii->mii_media_active |= IFM_1000_T; | | 432 | mii->mii_media_active |= IFM_1000_T; |
433 | else if ((gstat & RTK_GMEDIASTAT_100MBPS) != 0) | | 433 | else if ((gstat & RTK_GMEDIASTAT_100MBPS) != 0) |
434 | mii->mii_media_active |= IFM_100_TX; | | 434 | mii->mii_media_active |= IFM_100_TX; |
435 | else if ((gstat & RTK_GMEDIASTAT_10MBPS) != 0) | | 435 | else if ((gstat & RTK_GMEDIASTAT_10MBPS) != 0) |
436 | mii->mii_media_active |= IFM_10_T; | | 436 | mii->mii_media_active |= IFM_10_T; |
437 | else | | 437 | else |
438 | mii->mii_media_active |= IFM_NONE; | | 438 | mii->mii_media_active |= IFM_NONE; |
439 | if ((gstat & RTK_GMEDIASTAT_FDX) != 0) | | 439 | if ((gstat & RTK_GMEDIASTAT_FDX) != 0) |
440 | mii->mii_media_active |= mii_phy_flowstatus(sc) | | | 440 | mii->mii_media_active |= mii_phy_flowstatus(sc) | |
441 | IFM_FDX; | | 441 | IFM_FDX; |
442 | else | | 442 | else |
443 | mii->mii_media_active |= IFM_HDX; | | 443 | mii->mii_media_active |= IFM_HDX; |
444 | } | | 444 | } |
| | | 445 | |
| | | 446 | if (IFM_SUBTYPE(mii->mii_media_active) == IFM_1000_T) { |
| | | 447 | PHY_READ(sc, MII_GTSR, >sr); |
| | | 448 | if ((gtsr & GTSR_MS_RES) != 0) |
| | | 449 | mii->mii_media_active |= IFM_ETH_MASTER; |
| | | 450 | } |
445 | } | | 451 | } |
446 | | | 452 | |
447 | static int | | 453 | static int |
448 | rgephy_mii_phy_auto(struct mii_softc *mii) | | 454 | rgephy_mii_phy_auto(struct mii_softc *mii) |
449 | { | | 455 | { |
450 | int anar; | | 456 | int anar; |
451 | | | 457 | |
452 | mii->mii_ticks = 0; | | 458 | mii->mii_ticks = 0; |
453 | rgephy_loop(mii); | | 459 | rgephy_loop(mii); |
454 | rgephy_reset(mii); | | 460 | rgephy_reset(mii); |
455 | | | 461 | |
456 | anar = BMSR_MEDIA_TO_ANAR(mii->mii_capabilities) | ANAR_CSMA; | | 462 | anar = BMSR_MEDIA_TO_ANAR(mii->mii_capabilities) | ANAR_CSMA; |
457 | if (mii->mii_flags & MIIF_DOPAUSE) | | 463 | if (mii->mii_flags & MIIF_DOPAUSE) |
458 | anar |= ANAR_FC | ANAR_PAUSE_ASYM; | | 464 | anar |= ANAR_FC | ANAR_PAUSE_ASYM; |
459 | | | 465 | |
460 | PHY_WRITE(mii, MII_ANAR, anar); | | 466 | PHY_WRITE(mii, MII_ANAR, anar); |
461 | DELAY(1000); | | 467 | DELAY(1000); |
462 | PHY_WRITE(mii, MII_100T2CR, GTCR_ADV_1000THDX | GTCR_ADV_1000TFDX); | | 468 | PHY_WRITE(mii, MII_100T2CR, GTCR_ADV_1000THDX | GTCR_ADV_1000TFDX); |
463 | DELAY(1000); | | 469 | DELAY(1000); |
464 | PHY_WRITE(mii, MII_BMCR, BMCR_AUTOEN | BMCR_STARTNEG); | | 470 | PHY_WRITE(mii, MII_BMCR, BMCR_AUTOEN | BMCR_STARTNEG); |
465 | DELAY(100); | | 471 | DELAY(100); |
466 | | | 472 | |
467 | return EJUSTRETURN; | | 473 | return EJUSTRETURN; |
468 | } | | 474 | } |
469 | | | 475 | |
470 | static void | | 476 | static void |
471 | rgephy_loop(struct mii_softc *sc) | | 477 | rgephy_loop(struct mii_softc *sc) |
472 | { | | 478 | { |
473 | uint16_t bmsr; | | 479 | uint16_t bmsr; |
474 | int i; | | 480 | int i; |
475 | | | 481 | |
476 | if (sc->mii_mpd_model != MII_MODEL_REALTEK_RTL8251 && | | 482 | if (sc->mii_mpd_model != MII_MODEL_REALTEK_RTL8251 && |
477 | sc->mii_mpd_rev < RGEPHY_8211B) { | | 483 | sc->mii_mpd_rev < RGEPHY_8211B) { |
478 | PHY_WRITE(sc, MII_BMCR, BMCR_PDOWN); | | 484 | PHY_WRITE(sc, MII_BMCR, BMCR_PDOWN); |
479 | DELAY(1000); | | 485 | DELAY(1000); |
480 | } | | 486 | } |
481 | | | 487 | |
482 | for (i = 0; i < 15000; i++) { | | 488 | for (i = 0; i < 15000; i++) { |
483 | PHY_READ(sc, MII_BMSR, &bmsr); | | 489 | PHY_READ(sc, MII_BMSR, &bmsr); |
484 | if ((bmsr & BMSR_LINK) == 0) { | | 490 | if ((bmsr & BMSR_LINK) == 0) { |
485 | #if 0 | | 491 | #if 0 |
486 | device_printf(sc->mii_dev, "looped %d\n", i); | | 492 | device_printf(sc->mii_dev, "looped %d\n", i); |
487 | #endif | | 493 | #endif |
488 | break; | | 494 | break; |
489 | } | | 495 | } |
490 | DELAY(10); | | 496 | DELAY(10); |
491 | } | | 497 | } |
492 | } | | 498 | } |
493 | | | 499 | |
494 | static inline int | | 500 | static inline int |
495 | PHY_SETBIT(struct mii_softc *sc, int y, uint16_t z) | | 501 | PHY_SETBIT(struct mii_softc *sc, int y, uint16_t z) |
496 | { | | 502 | { |
497 | uint16_t _tmp; | | 503 | uint16_t _tmp; |
498 | int rv; | | 504 | int rv; |
499 | | | 505 | |
500 | if ((rv = PHY_READ(sc, y, &_tmp)) != 0) | | 506 | if ((rv = PHY_READ(sc, y, &_tmp)) != 0) |
501 | return rv; | | 507 | return rv; |
502 | return PHY_WRITE(sc, y, _tmp | z); | | 508 | return PHY_WRITE(sc, y, _tmp | z); |
503 | } | | 509 | } |
504 | | | 510 | |
505 | static inline int | | 511 | static inline int |
506 | PHY_CLRBIT(struct mii_softc *sc, int y, uint16_t z) | | 512 | PHY_CLRBIT(struct mii_softc *sc, int y, uint16_t z) |
507 | { | | 513 | { |
508 | uint16_t _tmp; | | 514 | uint16_t _tmp; |
509 | int rv; | | 515 | int rv; |
510 | | | 516 | |
511 | if ((rv = PHY_READ(sc, y, &_tmp)) != 0) | | 517 | if ((rv = PHY_READ(sc, y, &_tmp)) != 0) |
512 | return rv; | | 518 | return rv; |
513 | return PHY_WRITE(sc, y, _tmp & ~z); | | 519 | return PHY_WRITE(sc, y, _tmp & ~z); |
514 | } | | 520 | } |
515 | | | 521 | |
516 | /* | | 522 | /* |
517 | * Initialize RealTek PHY per the datasheet. The DSP in the PHYs of existing | | 523 | * Initialize RealTek PHY per the datasheet. The DSP in the PHYs of existing |
518 | * revisions of the 8169S/8110S chips need to be tuned in order to reliably | | 524 | * revisions of the 8169S/8110S chips need to be tuned in order to reliably |
519 | * negotiate a 1000Mbps link. This is only needed for rev 0 and rev 1 of the | | 525 | * negotiate a 1000Mbps link. This is only needed for rev 0 and rev 1 of the |
520 | * PHY. Later versions work without any fixups. | | 526 | * PHY. Later versions work without any fixups. |
521 | */ | | 527 | */ |
522 | static void | | 528 | static void |
523 | rgephy_load_dspcode(struct mii_softc *sc) | | 529 | rgephy_load_dspcode(struct mii_softc *sc) |
524 | { | | 530 | { |
525 | uint16_t val; | | 531 | uint16_t val; |
526 | | | 532 | |
527 | if (sc->mii_mpd_model == MII_MODEL_REALTEK_RTL8251 || | | 533 | if (sc->mii_mpd_model == MII_MODEL_REALTEK_RTL8251 || |
528 | sc->mii_mpd_rev >= RGEPHY_8211B) | | 534 | sc->mii_mpd_rev >= RGEPHY_8211B) |
529 | return; | | 535 | return; |
530 | | | 536 | |
531 | #if 1 | | 537 | #if 1 |
532 | PHY_WRITE(sc, 31, 0x0001); | | 538 | PHY_WRITE(sc, 31, 0x0001); |
533 | PHY_WRITE(sc, 21, 0x1000); | | 539 | PHY_WRITE(sc, 21, 0x1000); |
534 | PHY_WRITE(sc, 24, 0x65C7); | | 540 | PHY_WRITE(sc, 24, 0x65C7); |
535 | PHY_CLRBIT(sc, 4, 0x0800); | | 541 | PHY_CLRBIT(sc, 4, 0x0800); |
536 | PHY_READ(sc, 4, &val); | | 542 | PHY_READ(sc, 4, &val); |
537 | val &= 0xFFF; | | 543 | val &= 0xFFF; |
538 | PHY_WRITE(sc, 4, val); | | 544 | PHY_WRITE(sc, 4, val); |
539 | PHY_WRITE(sc, 3, 0x00A1); | | 545 | PHY_WRITE(sc, 3, 0x00A1); |
540 | PHY_WRITE(sc, 2, 0x0008); | | 546 | PHY_WRITE(sc, 2, 0x0008); |
541 | PHY_WRITE(sc, 1, 0x1020); | | 547 | PHY_WRITE(sc, 1, 0x1020); |
542 | PHY_WRITE(sc, 0, 0x1000); | | 548 | PHY_WRITE(sc, 0, 0x1000); |
543 | PHY_SETBIT(sc, 4, 0x0800); | | 549 | PHY_SETBIT(sc, 4, 0x0800); |
544 | PHY_CLRBIT(sc, 4, 0x0800); | | 550 | PHY_CLRBIT(sc, 4, 0x0800); |
545 | PHY_READ(sc, 4, &val); | | 551 | PHY_READ(sc, 4, &val); |
546 | val = (val & 0xFFF) | 0x7000; | | 552 | val = (val & 0xFFF) | 0x7000; |
547 | PHY_WRITE(sc, 4, val); | | 553 | PHY_WRITE(sc, 4, val); |
548 | PHY_WRITE(sc, 3, 0xFF41); | | 554 | PHY_WRITE(sc, 3, 0xFF41); |
549 | PHY_WRITE(sc, 2, 0xDE60); | | 555 | PHY_WRITE(sc, 2, 0xDE60); |
550 | PHY_WRITE(sc, 1, 0x0140); | | 556 | PHY_WRITE(sc, 1, 0x0140); |
551 | PHY_WRITE(sc, 0, 0x0077); | | 557 | PHY_WRITE(sc, 0, 0x0077); |
552 | PHY_READ(sc, 4, &val); | | 558 | PHY_READ(sc, 4, &val); |
553 | val = (val & 0xFFF) | 0xA000; | | 559 | val = (val & 0xFFF) | 0xA000; |
554 | PHY_WRITE(sc, 4, val); | | 560 | PHY_WRITE(sc, 4, val); |
555 | PHY_WRITE(sc, 3, 0xDF01); | | 561 | PHY_WRITE(sc, 3, 0xDF01); |
556 | PHY_WRITE(sc, 2, 0xDF20); | | 562 | PHY_WRITE(sc, 2, 0xDF20); |
557 | PHY_WRITE(sc, 1, 0xFF95); | | 563 | PHY_WRITE(sc, 1, 0xFF95); |
558 | PHY_WRITE(sc, 0, 0xFA00); | | 564 | PHY_WRITE(sc, 0, 0xFA00); |
559 | PHY_READ(sc, 4, &val); | | 565 | PHY_READ(sc, 4, &val); |
560 | val = (val & 0xFFF) | 0xB000; | | 566 | val = (val & 0xFFF) | 0xB000; |
561 | PHY_WRITE(sc, 4, val); | | 567 | PHY_WRITE(sc, 4, val); |
562 | PHY_WRITE(sc, 3, 0xFF41); | | 568 | PHY_WRITE(sc, 3, 0xFF41); |
563 | PHY_WRITE(sc, 2, 0xDE20); | | 569 | PHY_WRITE(sc, 2, 0xDE20); |
564 | PHY_WRITE(sc, 1, 0x0140); | | 570 | PHY_WRITE(sc, 1, 0x0140); |
565 | PHY_WRITE(sc, 0, 0x00BB); | | 571 | PHY_WRITE(sc, 0, 0x00BB); |
566 | PHY_READ(sc, 4, &val); | | 572 | PHY_READ(sc, 4, &val); |
567 | val = (val & 0xFFF) | 0xF000; | | 573 | val = (val & 0xFFF) | 0xF000; |
568 | PHY_WRITE(sc, 4, val); | | 574 | PHY_WRITE(sc, 4, val); |
569 | PHY_WRITE(sc, 3, 0xDF01); | | 575 | PHY_WRITE(sc, 3, 0xDF01); |
570 | PHY_WRITE(sc, 2, 0xDF20); | | 576 | PHY_WRITE(sc, 2, 0xDF20); |
571 | PHY_WRITE(sc, 1, 0xFF95); | | 577 | PHY_WRITE(sc, 1, 0xFF95); |
572 | PHY_WRITE(sc, 0, 0xBF00); | | 578 | PHY_WRITE(sc, 0, 0xBF00); |
573 | PHY_SETBIT(sc, 4, 0x0800); | | 579 | PHY_SETBIT(sc, 4, 0x0800); |
574 | PHY_CLRBIT(sc, 4, 0x0800); | | 580 | PHY_CLRBIT(sc, 4, 0x0800); |
575 | PHY_WRITE(sc, 31, 0x0000); | | 581 | PHY_WRITE(sc, 31, 0x0000); |
576 | #else | | 582 | #else |
577 | (void)val; | | 583 | (void)val; |
578 | PHY_WRITE(sc, 0x1f, 0x0001); | | 584 | PHY_WRITE(sc, 0x1f, 0x0001); |
579 | PHY_WRITE(sc, 0x15, 0x1000); | | 585 | PHY_WRITE(sc, 0x15, 0x1000); |
580 | PHY_WRITE(sc, 0x18, 0x65c7); | | 586 | PHY_WRITE(sc, 0x18, 0x65c7); |
581 | PHY_WRITE(sc, 0x04, 0x0000); | | 587 | PHY_WRITE(sc, 0x04, 0x0000); |
582 | PHY_WRITE(sc, 0x03, 0x00a1); | | 588 | PHY_WRITE(sc, 0x03, 0x00a1); |
583 | PHY_WRITE(sc, 0x02, 0x0008); | | 589 | PHY_WRITE(sc, 0x02, 0x0008); |
584 | PHY_WRITE(sc, 0x01, 0x1020); | | 590 | PHY_WRITE(sc, 0x01, 0x1020); |
585 | PHY_WRITE(sc, 0x00, 0x1000); | | 591 | PHY_WRITE(sc, 0x00, 0x1000); |
586 | PHY_WRITE(sc, 0x04, 0x0800); | | 592 | PHY_WRITE(sc, 0x04, 0x0800); |
587 | PHY_WRITE(sc, 0x04, 0x0000); | | 593 | PHY_WRITE(sc, 0x04, 0x0000); |
588 | PHY_WRITE(sc, 0x04, 0x7000); | | 594 | PHY_WRITE(sc, 0x04, 0x7000); |
589 | PHY_WRITE(sc, 0x03, 0xff41); | | 595 | PHY_WRITE(sc, 0x03, 0xff41); |
590 | PHY_WRITE(sc, 0x02, 0xde60); | | 596 | PHY_WRITE(sc, 0x02, 0xde60); |
591 | PHY_WRITE(sc, 0x01, 0x0140); | | 597 | PHY_WRITE(sc, 0x01, 0x0140); |
592 | PHY_WRITE(sc, 0x00, 0x0077); | | 598 | PHY_WRITE(sc, 0x00, 0x0077); |
593 | PHY_WRITE(sc, 0x04, 0x7800); | | 599 | PHY_WRITE(sc, 0x04, 0x7800); |
594 | PHY_WRITE(sc, 0x04, 0x7000); | | 600 | PHY_WRITE(sc, 0x04, 0x7000); |
595 | PHY_WRITE(sc, 0x04, 0xa000); | | 601 | PHY_WRITE(sc, 0x04, 0xa000); |
596 | PHY_WRITE(sc, 0x03, 0xdf01); | | 602 | PHY_WRITE(sc, 0x03, 0xdf01); |
597 | PHY_WRITE(sc, 0x02, 0xdf20); | | 603 | PHY_WRITE(sc, 0x02, 0xdf20); |
598 | PHY_WRITE(sc, 0x01, 0xff95); | | 604 | PHY_WRITE(sc, 0x01, 0xff95); |
599 | PHY_WRITE(sc, 0x00, 0xfa00); | | 605 | PHY_WRITE(sc, 0x00, 0xfa00); |
600 | PHY_WRITE(sc, 0x04, 0xa800); | | 606 | PHY_WRITE(sc, 0x04, 0xa800); |
601 | PHY_WRITE(sc, 0x04, 0xa000); | | 607 | PHY_WRITE(sc, 0x04, 0xa000); |
602 | PHY_WRITE(sc, 0x04, 0xb000); | | 608 | PHY_WRITE(sc, 0x04, 0xb000); |
603 | PHY_WRITE(sc, 0x0e, 0xff41); | | 609 | PHY_WRITE(sc, 0x0e, 0xff41); |
604 | PHY_WRITE(sc, 0x02, 0xde20); | | 610 | PHY_WRITE(sc, 0x02, 0xde20); |
605 | PHY_WRITE(sc, 0x01, 0x0140); | | 611 | PHY_WRITE(sc, 0x01, 0x0140); |
606 | PHY_WRITE(sc, 0x00, 0x00bb); | | 612 | PHY_WRITE(sc, 0x00, 0x00bb); |
607 | PHY_WRITE(sc, 0x04, 0xb800); | | 613 | PHY_WRITE(sc, 0x04, 0xb800); |
608 | PHY_WRITE(sc, 0x04, 0xb000); | | 614 | PHY_WRITE(sc, 0x04, 0xb000); |
609 | PHY_WRITE(sc, 0x04, 0xf000); | | 615 | PHY_WRITE(sc, 0x04, 0xf000); |
610 | PHY_WRITE(sc, 0x03, 0xdf01); | | 616 | PHY_WRITE(sc, 0x03, 0xdf01); |
611 | PHY_WRITE(sc, 0x02, 0xdf20); | | 617 | PHY_WRITE(sc, 0x02, 0xdf20); |
612 | PHY_WRITE(sc, 0x01, 0xff95); | | 618 | PHY_WRITE(sc, 0x01, 0xff95); |
613 | PHY_WRITE(sc, 0x00, 0xbf00); | | 619 | PHY_WRITE(sc, 0x00, 0xbf00); |
614 | PHY_WRITE(sc, 0x04, 0xf800); | | 620 | PHY_WRITE(sc, 0x04, 0xf800); |
615 | PHY_WRITE(sc, 0x04, 0xf000); | | 621 | PHY_WRITE(sc, 0x04, 0xf000); |
616 | PHY_WRITE(sc, 0x04, 0x0000); | | 622 | PHY_WRITE(sc, 0x04, 0x0000); |
617 | PHY_WRITE(sc, 0x1f, 0x0000); | | 623 | PHY_WRITE(sc, 0x1f, 0x0000); |
618 | PHY_WRITE(sc, 0x0b, 0x0000); | | 624 | PHY_WRITE(sc, 0x0b, 0x0000); |
619 | | | 625 | |
620 | #endif | | 626 | #endif |
621 | | | 627 | |
622 | DELAY(40); | | 628 | DELAY(40); |
623 | } | | 629 | } |
624 | | | 630 | |
625 | static void | | 631 | static void |
626 | rgephy_reset(struct mii_softc *sc) | | 632 | rgephy_reset(struct mii_softc *sc) |
627 | { | | 633 | { |
628 | struct rgephy_softc *rsc = (struct rgephy_softc *)sc; | | 634 | struct rgephy_softc *rsc = (struct rgephy_softc *)sc; |
629 | uint16_t ssr, phycr1; | | 635 | uint16_t ssr, phycr1; |
630 | | | 636 | |
631 | mii_phy_reset(sc); | | 637 | mii_phy_reset(sc); |
632 | DELAY(1000); | | 638 | DELAY(1000); |
633 | | | 639 | |
634 | if (sc->mii_mpd_model != MII_MODEL_REALTEK_RTL8251 && | | 640 | if (sc->mii_mpd_model != MII_MODEL_REALTEK_RTL8251 && |
635 | sc->mii_mpd_rev < RGEPHY_8211B) { | | 641 | sc->mii_mpd_rev < RGEPHY_8211B) { |
636 | rgephy_load_dspcode(sc); | | 642 | rgephy_load_dspcode(sc); |
637 | } else if (sc->mii_mpd_rev == RGEPHY_8211C) { | | 643 | } else if (sc->mii_mpd_rev == RGEPHY_8211C) { |
638 | /* RTL8211C(L) */ | | 644 | /* RTL8211C(L) */ |
639 | PHY_READ(sc, RGEPHY_MII_SSR, &ssr); | | 645 | PHY_READ(sc, RGEPHY_MII_SSR, &ssr); |
640 | if ((ssr & RGEPHY_SSR_ALDPS) != 0) { | | 646 | if ((ssr & RGEPHY_SSR_ALDPS) != 0) { |
641 | ssr &= ~RGEPHY_SSR_ALDPS; | | 647 | ssr &= ~RGEPHY_SSR_ALDPS; |
642 | PHY_WRITE(sc, RGEPHY_MII_SSR, ssr); | | 648 | PHY_WRITE(sc, RGEPHY_MII_SSR, ssr); |
643 | } | | 649 | } |
644 | } else if (sc->mii_mpd_rev == RGEPHY_8211E) { | | 650 | } else if (sc->mii_mpd_rev == RGEPHY_8211E) { |
645 | /* RTL8211E */ | | 651 | /* RTL8211E */ |
646 | if (rsc->mii_no_rx_delay) { | | 652 | if (rsc->mii_no_rx_delay) { |
647 | /* Disable RX internal delay (undocumented) */ | | 653 | /* Disable RX internal delay (undocumented) */ |
648 | PHY_WRITE(sc, 0x1f, 0x0007); | | 654 | PHY_WRITE(sc, 0x1f, 0x0007); |
649 | PHY_WRITE(sc, 0x1e, 0x00a4); | | 655 | PHY_WRITE(sc, 0x1e, 0x00a4); |
650 | PHY_WRITE(sc, 0x1c, 0xb591); | | 656 | PHY_WRITE(sc, 0x1c, 0xb591); |
651 | PHY_WRITE(sc, 0x1f, 0x0000); | | 657 | PHY_WRITE(sc, 0x1f, 0x0000); |
652 | } | | 658 | } |
653 | } else if (sc->mii_mpd_rev == RGEPHY_8211F) { | | 659 | } else if (sc->mii_mpd_rev == RGEPHY_8211F) { |
654 | /* RTL8211F */ | | 660 | /* RTL8211F */ |
655 | PHY_READ(sc, RGEPHY_MII_PHYCR1, &phycr1); | | 661 | PHY_READ(sc, RGEPHY_MII_PHYCR1, &phycr1); |
656 | phycr1 &= ~RGEPHY_PHYCR1_MDI_MMCE; | | 662 | phycr1 &= ~RGEPHY_PHYCR1_MDI_MMCE; |
657 | phycr1 &= ~RGEPHY_PHYCR1_ALDPS_EN; | | 663 | phycr1 &= ~RGEPHY_PHYCR1_ALDPS_EN; |
658 | PHY_WRITE(sc, RGEPHY_MII_PHYCR1, phycr1); | | 664 | PHY_WRITE(sc, RGEPHY_MII_PHYCR1, phycr1); |
659 | } else { | | 665 | } else { |
660 | PHY_WRITE(sc, 0x1F, 0x0000); | | 666 | PHY_WRITE(sc, 0x1F, 0x0000); |
661 | PHY_WRITE(sc, 0x0e, 0x0000); | | 667 | PHY_WRITE(sc, 0x0e, 0x0000); |
662 | } | | 668 | } |
663 | | | 669 | |
664 | /* Reset capabilities */ | | 670 | /* Reset capabilities */ |
665 | /* Step1: write our capability */ | | 671 | /* Step1: write our capability */ |
666 | /* 10/100 capability */ | | 672 | /* 10/100 capability */ |
667 | PHY_WRITE(sc, MII_ANAR, | | 673 | PHY_WRITE(sc, MII_ANAR, |
668 | ANAR_TX_FD | ANAR_TX | ANAR_10_FD | ANAR_10 | ANAR_CSMA); | | 674 | ANAR_TX_FD | ANAR_TX | ANAR_10_FD | ANAR_10 | ANAR_CSMA); |
669 | /* 1000 capability */ | | 675 | /* 1000 capability */ |
670 | PHY_WRITE(sc, MII_100T2CR, GTCR_ADV_1000TFDX | GTCR_ADV_1000THDX); | | 676 | PHY_WRITE(sc, MII_100T2CR, GTCR_ADV_1000TFDX | GTCR_ADV_1000THDX); |
671 | | | 677 | |
672 | /* Step2: Restart NWay */ | | 678 | /* Step2: Restart NWay */ |
673 | /* NWay enable and Restart NWay */ | | 679 | /* NWay enable and Restart NWay */ |
674 | PHY_WRITE(sc, MII_BMCR, BMCR_RESET | BMCR_AUTOEN | BMCR_STARTNEG); | | 680 | PHY_WRITE(sc, MII_BMCR, BMCR_RESET | BMCR_AUTOEN | BMCR_STARTNEG); |
675 | | | 681 | |
676 | if (sc->mii_mpd_rev >= RGEPHY_8211D) { | | 682 | if (sc->mii_mpd_rev >= RGEPHY_8211D) { |
677 | /* RTL8211F */ | | 683 | /* RTL8211F */ |
678 | delay(10000); | | 684 | delay(10000); |
679 | /* disable EEE */ | | 685 | /* disable EEE */ |
680 | MMD_INDIRECT_WRITE(sc, MDIO_MMD_AN | MMDACR_FN_DATA, | | 686 | MMD_INDIRECT_WRITE(sc, MDIO_MMD_AN | MMDACR_FN_DATA, |
681 | MDIO_AN_EEEADVERT, 0x0000); | | 687 | MDIO_AN_EEEADVERT, 0x0000); |
682 | } | | 688 | } |
683 | } | | 689 | } |