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