emac3.c revision 1.1 1 /* $NetBSD: emac3.c,v 1.1 2001/10/16 15:38:33 uch 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 #include "debug_playstation2.h"
43
44 #include <sys/param.h>
45 #include <sys/systm.h>
46
47 #include <sys/socket.h>
48
49 #include <net/if.h>
50 #include <net/if_ether.h>
51 #include <net/if_media.h>
52
53 #include <dev/mii/mii.h>
54 #include <dev/mii/miivar.h>
55
56 #include <playstation2/ee/eevar.h>
57 #include <playstation2/dev/emac3reg.h>
58 #include <playstation2/dev/emac3var.h>
59
60 #ifdef EMAC3_DEBUG
61 #define STATIC
62 int emac3_debug = 0;
63 #define DPRINTF(fmt, args...) \
64 if (emac3_debug) \
65 printf("%s: " fmt, __FUNCTION__ , ##args)
66 #define DPRINTFN(n, arg) \
67 if (emac3_debug > (n)) \
68 n printf("%s: " fmt, __FUNCTION__ , ##args)
69 #else
70 #define STATIC static
71 #define DPRINTF(arg...) ((void)0)
72 #define DPRINTFN(n, arg...) ((void)0)
73 #endif
74
75 /* SMAP specific EMAC3 define */
76 #define EMAC3_BASE MIPS_PHYS_TO_KSEG1(0x14002000)
77 static __inline__ u_int32_t
78 _emac3_reg_read_4(int ofs)
79 {
80 bus_addr_t a_ = EMAC3_BASE + ofs;
81
82 return (_reg_read_2(a_) << 16) | _reg_read_2(a_ + 2);
83 }
84
85 static __inline__ void
86 _emac3_reg_write_4(int ofs, u_int32_t v)
87 {
88 bus_addr_t a_ = EMAC3_BASE + ofs;
89
90 _reg_write_2(a_, (v >> 16) & 0xffff);
91 _reg_write_2(a_ + 2, v & 0xffff);
92 }
93
94 STATIC int emac3_phy_ready(void);
95 STATIC int emac3_soft_reset(void);
96 STATIC void emac3_config(const u_int8_t *);
97
98 int
99 emac3_init(struct emac3_softc *sc)
100 {
101 u_int32_t r;
102
103 /* save current mode before reset */
104 r = _emac3_reg_read_4(EMAC3_MR1);
105
106 if (emac3_soft_reset() != 0) {
107 printf("%s: reset failed.\n", sc->dev.dv_xname);
108 return (1);
109 }
110
111 /* set operation mode */
112 r |= MR1_RFS_2KB | MR1_TFS_1KB | MR1_TR0_SINGLE | MR1_TR1_SINGLE;
113 _emac3_reg_write_4(EMAC3_MR1, r);
114
115 sc->mode1_reg = _emac3_reg_read_4(EMAC3_MR1);
116
117 emac3_intr_clear();
118 emac3_intr_disable();
119
120 emac3_config(sc->eaddr);
121
122 return (0);
123 }
124
125 void
126 emac3_exit(struct emac3_softc *sc)
127 {
128 int retry = 10000;
129
130 /* wait for kicked transmission */
131 while (((_emac3_reg_read_4(EMAC3_TMR0) & TMR0_GNP0) != 0) &&
132 --retry > 0)
133 ;
134
135 if (retry == 0)
136 printf("%s: still running.\n", sc->dev.dv_xname);
137 }
138
139 int
140 emac3_reset(struct emac3_softc *sc)
141 {
142
143 if (emac3_soft_reset() != 0) {
144 printf("%s: reset failed.\n", sc->dev.dv_xname);
145 return (1);
146 }
147
148 /* restore previous mode */
149 _emac3_reg_write_4(EMAC3_MR1, sc->mode1_reg);
150
151 emac3_config(sc->eaddr);
152
153 return (0);
154 }
155
156 void
157 emac3_enable()
158 {
159
160 _emac3_reg_write_4(EMAC3_MR0, MR0_TXE | MR0_RXE);
161 }
162
163 void
164 emac3_disable()
165 {
166 int retry = 10000;
167
168 _emac3_reg_write_4(EMAC3_MR0,
169 _emac3_reg_read_4(EMAC3_MR0) & ~(MR0_TXE | MR0_RXE));
170
171 /* wait for idling state */
172 while (((_emac3_reg_read_4(EMAC3_MR0) & (MR0_RXI | MR0_TXI)) !=
173 (MR0_RXI | MR0_TXI)) && --retry > 0)
174 ;
175
176 if (retry == 0)
177 printf("emac3 running.\n");
178 }
179
180 void
181 emac3_intr_enable()
182 {
183
184 _emac3_reg_write_4(EMAC3_ISER, ~0);
185 }
186
187 void
188 emac3_intr_disable()
189 {
190
191 _emac3_reg_write_4(EMAC3_ISER, 0);
192 }
193
194 void
195 emac3_intr_clear()
196 {
197
198 _emac3_reg_write_4(EMAC3_ISR, _emac3_reg_read_4(EMAC3_ISR));
199 }
200
201 int
202 emac3_intr(void *arg)
203 {
204 u_int32_t r = _emac3_reg_read_4(EMAC3_ISR);
205
206 DPRINTF("%08x\n", r);
207 _emac3_reg_write_4(EMAC3_ISR, r);
208
209 return (1);
210 }
211
212 void
213 emac3_tx_kick()
214 {
215
216 _emac3_reg_write_4(EMAC3_TMR0, TMR0_GNP0);
217 }
218
219 int
220 emac3_tx_done()
221 {
222
223 return (_emac3_reg_read_4(EMAC3_TMR0) & TMR0_GNP0);
224 }
225
226 void
227 emac3_setmulti(struct emac3_softc *sc, struct ethercom *ec)
228 {
229 struct ether_multi *enm;
230 struct ether_multistep step;
231 struct ifnet *ifp = &ec->ec_if;
232 u_int32_t r;
233
234 r = _emac3_reg_read_4(EMAC3_RMR);
235 r &= ~(RMR_PME | RMR_PMME | RMR_MIAE);
236
237 if (ifp->if_flags & IFF_PROMISC) {
238 allmulti:
239 ifp->if_flags |= IFF_ALLMULTI;
240 r |= RMR_PME;
241 _emac3_reg_write_4(EMAC3_RMR, r);
242
243 return;
244 }
245
246 ETHER_FIRST_MULTI(step, ec, enm);
247 while (enm != NULL) {
248 if (memcmp(enm->enm_addrlo, enm->enm_addrhi,
249 ETHER_ADDR_LEN) != 0)
250 goto allmulti;
251
252 ETHER_NEXT_MULTI(step, enm)
253 }
254
255 /* XXX always multicast promiscuous mode. XXX use hash table.. */
256 ifp->if_flags |= IFF_ALLMULTI;
257 r |= RMR_PMME;
258 _emac3_reg_write_4(EMAC3_RMR, r);
259 }
260
261 int
262 emac3_soft_reset()
263 {
264 int retry = 10000;
265
266 _emac3_reg_write_4(EMAC3_MR0, MR0_SRST);
267
268 while ((_emac3_reg_read_4(EMAC3_MR0) & MR0_SRST) == MR0_SRST &&
269 --retry > 0)
270 ;
271
272 return (retry == 0);
273 }
274
275 void
276 emac3_config(const u_int8_t *eaddr)
277 {
278
279 /* set ethernet address */
280 _emac3_reg_write_4(EMAC3_IAHR, (eaddr[0] << 8) | eaddr[1]);
281 _emac3_reg_write_4(EMAC3_IALR, (eaddr[2] << 24) | (eaddr[3] << 16) |
282 (eaddr[4] << 8) | eaddr[5]);
283
284 /* inter-frame GAP */
285 _emac3_reg_write_4(EMAC3_IPGVR, 4);
286
287 /* RX mode */
288 _emac3_reg_write_4(EMAC3_RMR,
289 RMR_SP | /* strip padding */
290 RMR_SFCS | /* strip FCS */
291 RMR_IAE | /* individual address enable */
292 RMR_BAE); /* boradcast address enable */
293
294 /* TX mode */
295 _emac3_reg_write_4(EMAC3_TMR1,
296 ((7 << TMR1_TLR_SHIFT) & TMR1_TLR_MASK) | /* 16 word burst */
297 ((15 << TMR1_TUR_SHIFT) & TMR1_TUR_MASK));
298
299 /* TX threshold */
300 _emac3_reg_write_4(EMAC3_TRTR,
301 (12 << TRTR_SHIFT) & TRTR_MASK); /* 832 bytes */
302
303 /* RX watermark */
304 _emac3_reg_write_4(EMAC3_RWMR,
305 ((16 << RWMR_RLWM_SHIFT) & RWMR_RLWM_MASK) |
306 ((128 << RWMR_RHWM_SHIFT) & RWMR_RHWM_MASK));
307 }
308
309 /*
310 * PHY/MII
311 */
312 int
313 emac3_ifmedia_upd(struct ifnet *ifp)
314 {
315 struct emac3_softc *sc;
316
317 sc = ifp->if_softc;
318
319 return (mii_mediachg(&sc->mii));
320 }
321
322 void
323 emac3_ifmedia_sts(struct ifnet *ifp, struct ifmediareq *ifmr)
324 {
325 struct emac3_softc *sc;
326
327 sc = ifp->if_softc;
328
329 mii_pollstat(&sc->mii);
330 ifmr->ifm_status = sc->mii.mii_media_status;
331 ifmr->ifm_active = sc->mii.mii_media_active;
332 }
333
334 void
335 emac3_phy_writereg(struct device *self, int phy, int reg, int data)
336 {
337
338 if (emac3_phy_ready() != 0)
339 return;
340
341 _emac3_reg_write_4(EMAC3_STACR, STACR_WRITE |
342 ((phy << STACR_PCDASHIFT) & STACR_PCDA) | /* command dest addr*/
343 ((reg << STACR_PRASHIFT) & STACR_PRA) | /* register addr */
344 ((data << STACR_PHYDSHIFT) & STACR_PHYD)); /* data */
345
346 if (emac3_phy_ready() != 0)
347 return;
348 }
349
350 int
351 emac3_phy_readreg(struct device *self, int phy, int reg)
352 {
353
354 if (emac3_phy_ready() != 0)
355 return (0);
356
357 _emac3_reg_write_4(EMAC3_STACR, STACR_READ |
358 ((phy << STACR_PCDASHIFT) & STACR_PCDA) | /* command dest addr*/
359 ((reg << STACR_PRASHIFT) & STACR_PRA)); /* register addr */
360
361 if (emac3_phy_ready() != 0)
362 return (0);
363
364 return ((_emac3_reg_read_4(EMAC3_STACR) >> STACR_PHYDSHIFT) & 0xffff);
365 }
366
367 void
368 emac3_phy_statchg(struct device *dev)
369 {
370 #define EMAC3_FDX (MR1_FDE | MR1_EIFC | MR1_APP)
371 struct emac3_softc *sc = (void *)dev;
372 int media;
373 u_int32_t r;
374
375 media = sc->mii.mii_media_active;
376
377 r = _emac3_reg_read_4(EMAC3_MR1);
378
379 r &= ~(MR1_MF_MASK | MR1_IST | EMAC3_FDX);
380
381 switch (media & 0x1f) {
382 default:
383 printf("unknown media type. %08x", media);
384 /* FALLTHROUGH */
385 case IFM_100_TX:
386 r |= (MR1_MF_100MBS | MR1_IST);
387 if (media & IFM_FDX)
388 r |= EMAC3_FDX;
389
390 break;
391 case IFM_10_T:
392 r |= MR1_MF_10MBS;
393 if (media & IFM_FDX)
394 r |= (EMAC3_FDX | MR1_IST);
395 break;
396 }
397
398 _emac3_reg_write_4(EMAC3_MR1, r);
399
400 /* store current state for re-initialize */
401 sc->mode1_reg = _emac3_reg_read_4(EMAC3_MR1);
402 #undef EMAC3_FDX
403 }
404
405 int
406 emac3_phy_ready()
407 {
408 int retry = 10000;
409
410 while ((_emac3_reg_read_4(EMAC3_STACR) & STACR_OC) == 0 &&
411 --retry > 0)
412 ;
413 if (retry == 0) {
414 printf("emac3: phy busy.\n");
415 return (1);
416 }
417
418 return (0);
419 }
420
421