emac3.c revision 1.2 1 /* $NetBSD: emac3.c,v 1.2 2003/07/15 02:54:36 lukem Exp $ */
2
3 /*-
4 * Copyright (c) 2001 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by UCHIYAMA Yasushi.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 * 3. All advertising materials mentioning features or use of this software
19 * must display the following acknowledgement:
20 * This product includes software developed by the NetBSD
21 * Foundation, Inc. and its contributors.
22 * 4. Neither the name of The NetBSD Foundation nor the names of its
23 * contributors may be used to endorse or promote products derived
24 * from this software without specific prior written permission.
25 *
26 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
27 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
28 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
29 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
30 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
31 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
32 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
33 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
34 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
35 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
36 * POSSIBILITY OF SUCH DAMAGE.
37 */
38
39 /*
40 * EMAC3 (Ethernet Media Access Controller)
41 */
42
43 #include <sys/cdefs.h>
44 __KERNEL_RCSID(0, "$NetBSD: emac3.c,v 1.2 2003/07/15 02:54:36 lukem Exp $");
45
46 #include "debug_playstation2.h"
47
48 #include <sys/param.h>
49 #include <sys/systm.h>
50
51 #include <sys/socket.h>
52
53 #include <net/if.h>
54 #include <net/if_ether.h>
55 #include <net/if_media.h>
56
57 #include <dev/mii/mii.h>
58 #include <dev/mii/miivar.h>
59
60 #include <playstation2/ee/eevar.h>
61 #include <playstation2/dev/emac3reg.h>
62 #include <playstation2/dev/emac3var.h>
63
64 #ifdef EMAC3_DEBUG
65 #define STATIC
66 int emac3_debug = 0;
67 #define DPRINTF(fmt, args...) \
68 if (emac3_debug) \
69 printf("%s: " fmt, __FUNCTION__ , ##args)
70 #define DPRINTFN(n, arg) \
71 if (emac3_debug > (n)) \
72 n printf("%s: " fmt, __FUNCTION__ , ##args)
73 #else
74 #define STATIC static
75 #define DPRINTF(arg...) ((void)0)
76 #define DPRINTFN(n, arg...) ((void)0)
77 #endif
78
79 /* SMAP specific EMAC3 define */
80 #define EMAC3_BASE MIPS_PHYS_TO_KSEG1(0x14002000)
81 static __inline__ u_int32_t
82 _emac3_reg_read_4(int ofs)
83 {
84 bus_addr_t a_ = EMAC3_BASE + ofs;
85
86 return (_reg_read_2(a_) << 16) | _reg_read_2(a_ + 2);
87 }
88
89 static __inline__ void
90 _emac3_reg_write_4(int ofs, u_int32_t v)
91 {
92 bus_addr_t a_ = EMAC3_BASE + ofs;
93
94 _reg_write_2(a_, (v >> 16) & 0xffff);
95 _reg_write_2(a_ + 2, v & 0xffff);
96 }
97
98 STATIC int emac3_phy_ready(void);
99 STATIC int emac3_soft_reset(void);
100 STATIC void emac3_config(const u_int8_t *);
101
102 int
103 emac3_init(struct emac3_softc *sc)
104 {
105 u_int32_t r;
106
107 /* save current mode before reset */
108 r = _emac3_reg_read_4(EMAC3_MR1);
109
110 if (emac3_soft_reset() != 0) {
111 printf("%s: reset failed.\n", sc->dev.dv_xname);
112 return (1);
113 }
114
115 /* set operation mode */
116 r |= MR1_RFS_2KB | MR1_TFS_1KB | MR1_TR0_SINGLE | MR1_TR1_SINGLE;
117 _emac3_reg_write_4(EMAC3_MR1, r);
118
119 sc->mode1_reg = _emac3_reg_read_4(EMAC3_MR1);
120
121 emac3_intr_clear();
122 emac3_intr_disable();
123
124 emac3_config(sc->eaddr);
125
126 return (0);
127 }
128
129 void
130 emac3_exit(struct emac3_softc *sc)
131 {
132 int retry = 10000;
133
134 /* wait for kicked transmission */
135 while (((_emac3_reg_read_4(EMAC3_TMR0) & TMR0_GNP0) != 0) &&
136 --retry > 0)
137 ;
138
139 if (retry == 0)
140 printf("%s: still running.\n", sc->dev.dv_xname);
141 }
142
143 int
144 emac3_reset(struct emac3_softc *sc)
145 {
146
147 if (emac3_soft_reset() != 0) {
148 printf("%s: reset failed.\n", sc->dev.dv_xname);
149 return (1);
150 }
151
152 /* restore previous mode */
153 _emac3_reg_write_4(EMAC3_MR1, sc->mode1_reg);
154
155 emac3_config(sc->eaddr);
156
157 return (0);
158 }
159
160 void
161 emac3_enable()
162 {
163
164 _emac3_reg_write_4(EMAC3_MR0, MR0_TXE | MR0_RXE);
165 }
166
167 void
168 emac3_disable()
169 {
170 int retry = 10000;
171
172 _emac3_reg_write_4(EMAC3_MR0,
173 _emac3_reg_read_4(EMAC3_MR0) & ~(MR0_TXE | MR0_RXE));
174
175 /* wait for idling state */
176 while (((_emac3_reg_read_4(EMAC3_MR0) & (MR0_RXI | MR0_TXI)) !=
177 (MR0_RXI | MR0_TXI)) && --retry > 0)
178 ;
179
180 if (retry == 0)
181 printf("emac3 running.\n");
182 }
183
184 void
185 emac3_intr_enable()
186 {
187
188 _emac3_reg_write_4(EMAC3_ISER, ~0);
189 }
190
191 void
192 emac3_intr_disable()
193 {
194
195 _emac3_reg_write_4(EMAC3_ISER, 0);
196 }
197
198 void
199 emac3_intr_clear()
200 {
201
202 _emac3_reg_write_4(EMAC3_ISR, _emac3_reg_read_4(EMAC3_ISR));
203 }
204
205 int
206 emac3_intr(void *arg)
207 {
208 u_int32_t r = _emac3_reg_read_4(EMAC3_ISR);
209
210 DPRINTF("%08x\n", r);
211 _emac3_reg_write_4(EMAC3_ISR, r);
212
213 return (1);
214 }
215
216 void
217 emac3_tx_kick()
218 {
219
220 _emac3_reg_write_4(EMAC3_TMR0, TMR0_GNP0);
221 }
222
223 int
224 emac3_tx_done()
225 {
226
227 return (_emac3_reg_read_4(EMAC3_TMR0) & TMR0_GNP0);
228 }
229
230 void
231 emac3_setmulti(struct emac3_softc *sc, struct ethercom *ec)
232 {
233 struct ether_multi *enm;
234 struct ether_multistep step;
235 struct ifnet *ifp = &ec->ec_if;
236 u_int32_t r;
237
238 r = _emac3_reg_read_4(EMAC3_RMR);
239 r &= ~(RMR_PME | RMR_PMME | RMR_MIAE);
240
241 if (ifp->if_flags & IFF_PROMISC) {
242 allmulti:
243 ifp->if_flags |= IFF_ALLMULTI;
244 r |= RMR_PME;
245 _emac3_reg_write_4(EMAC3_RMR, r);
246
247 return;
248 }
249
250 ETHER_FIRST_MULTI(step, ec, enm);
251 while (enm != NULL) {
252 if (memcmp(enm->enm_addrlo, enm->enm_addrhi,
253 ETHER_ADDR_LEN) != 0)
254 goto allmulti;
255
256 ETHER_NEXT_MULTI(step, enm)
257 }
258
259 /* XXX always multicast promiscuous mode. XXX use hash table.. */
260 ifp->if_flags |= IFF_ALLMULTI;
261 r |= RMR_PMME;
262 _emac3_reg_write_4(EMAC3_RMR, r);
263 }
264
265 int
266 emac3_soft_reset()
267 {
268 int retry = 10000;
269
270 _emac3_reg_write_4(EMAC3_MR0, MR0_SRST);
271
272 while ((_emac3_reg_read_4(EMAC3_MR0) & MR0_SRST) == MR0_SRST &&
273 --retry > 0)
274 ;
275
276 return (retry == 0);
277 }
278
279 void
280 emac3_config(const u_int8_t *eaddr)
281 {
282
283 /* set ethernet address */
284 _emac3_reg_write_4(EMAC3_IAHR, (eaddr[0] << 8) | eaddr[1]);
285 _emac3_reg_write_4(EMAC3_IALR, (eaddr[2] << 24) | (eaddr[3] << 16) |
286 (eaddr[4] << 8) | eaddr[5]);
287
288 /* inter-frame GAP */
289 _emac3_reg_write_4(EMAC3_IPGVR, 4);
290
291 /* RX mode */
292 _emac3_reg_write_4(EMAC3_RMR,
293 RMR_SP | /* strip padding */
294 RMR_SFCS | /* strip FCS */
295 RMR_IAE | /* individual address enable */
296 RMR_BAE); /* boradcast address enable */
297
298 /* TX mode */
299 _emac3_reg_write_4(EMAC3_TMR1,
300 ((7 << TMR1_TLR_SHIFT) & TMR1_TLR_MASK) | /* 16 word burst */
301 ((15 << TMR1_TUR_SHIFT) & TMR1_TUR_MASK));
302
303 /* TX threshold */
304 _emac3_reg_write_4(EMAC3_TRTR,
305 (12 << TRTR_SHIFT) & TRTR_MASK); /* 832 bytes */
306
307 /* RX watermark */
308 _emac3_reg_write_4(EMAC3_RWMR,
309 ((16 << RWMR_RLWM_SHIFT) & RWMR_RLWM_MASK) |
310 ((128 << RWMR_RHWM_SHIFT) & RWMR_RHWM_MASK));
311 }
312
313 /*
314 * PHY/MII
315 */
316 int
317 emac3_ifmedia_upd(struct ifnet *ifp)
318 {
319 struct emac3_softc *sc;
320
321 sc = ifp->if_softc;
322
323 return (mii_mediachg(&sc->mii));
324 }
325
326 void
327 emac3_ifmedia_sts(struct ifnet *ifp, struct ifmediareq *ifmr)
328 {
329 struct emac3_softc *sc;
330
331 sc = ifp->if_softc;
332
333 mii_pollstat(&sc->mii);
334 ifmr->ifm_status = sc->mii.mii_media_status;
335 ifmr->ifm_active = sc->mii.mii_media_active;
336 }
337
338 void
339 emac3_phy_writereg(struct device *self, int phy, int reg, int data)
340 {
341
342 if (emac3_phy_ready() != 0)
343 return;
344
345 _emac3_reg_write_4(EMAC3_STACR, STACR_WRITE |
346 ((phy << STACR_PCDASHIFT) & STACR_PCDA) | /* command dest addr*/
347 ((reg << STACR_PRASHIFT) & STACR_PRA) | /* register addr */
348 ((data << STACR_PHYDSHIFT) & STACR_PHYD)); /* data */
349
350 if (emac3_phy_ready() != 0)
351 return;
352 }
353
354 int
355 emac3_phy_readreg(struct device *self, int phy, int reg)
356 {
357
358 if (emac3_phy_ready() != 0)
359 return (0);
360
361 _emac3_reg_write_4(EMAC3_STACR, STACR_READ |
362 ((phy << STACR_PCDASHIFT) & STACR_PCDA) | /* command dest addr*/
363 ((reg << STACR_PRASHIFT) & STACR_PRA)); /* register addr */
364
365 if (emac3_phy_ready() != 0)
366 return (0);
367
368 return ((_emac3_reg_read_4(EMAC3_STACR) >> STACR_PHYDSHIFT) & 0xffff);
369 }
370
371 void
372 emac3_phy_statchg(struct device *dev)
373 {
374 #define EMAC3_FDX (MR1_FDE | MR1_EIFC | MR1_APP)
375 struct emac3_softc *sc = (void *)dev;
376 int media;
377 u_int32_t r;
378
379 media = sc->mii.mii_media_active;
380
381 r = _emac3_reg_read_4(EMAC3_MR1);
382
383 r &= ~(MR1_MF_MASK | MR1_IST | EMAC3_FDX);
384
385 switch (media & 0x1f) {
386 default:
387 printf("unknown media type. %08x", media);
388 /* FALLTHROUGH */
389 case IFM_100_TX:
390 r |= (MR1_MF_100MBS | MR1_IST);
391 if (media & IFM_FDX)
392 r |= EMAC3_FDX;
393
394 break;
395 case IFM_10_T:
396 r |= MR1_MF_10MBS;
397 if (media & IFM_FDX)
398 r |= (EMAC3_FDX | MR1_IST);
399 break;
400 }
401
402 _emac3_reg_write_4(EMAC3_MR1, r);
403
404 /* store current state for re-initialize */
405 sc->mode1_reg = _emac3_reg_read_4(EMAC3_MR1);
406 #undef EMAC3_FDX
407 }
408
409 int
410 emac3_phy_ready()
411 {
412 int retry = 10000;
413
414 while ((_emac3_reg_read_4(EMAC3_STACR) & STACR_OC) == 0 &&
415 --retry > 0)
416 ;
417 if (retry == 0) {
418 printf("emac3: phy busy.\n");
419 return (1);
420 }
421
422 return (0);
423 }
424
425