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