xref: /netbsd/sys/arch/playstation2/dev/emac3.c (revision f61a121e)
1 /*	$NetBSD: emac3.c,v 1.15 2022/02/11 23:49:19 riastradh 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.15 2022/02/11 23:49:19 riastradh 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
_emac3_reg_read_4(int ofs)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
_emac3_reg_write_4(int ofs,u_int32_t v)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
emac3_init(struct emac3_softc * sc)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", device_xname(sc->dev));
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
emac3_exit(struct emac3_softc * sc)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", device_xname(sc->dev));
136 }
137 
138 int
emac3_reset(struct emac3_softc * sc)139 emac3_reset(struct emac3_softc *sc)
140 {
141 
142 	if (emac3_soft_reset() != 0) {
143 		printf("%s: reset failed.\n", device_xname(sc->dev));
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
emac3_enable(void)156 emac3_enable(void)
157 {
158 
159 	_emac3_reg_write_4(EMAC3_MR0, MR0_TXE | MR0_RXE);
160 }
161 
162 void
emac3_disable(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
emac3_intr_enable(void)180 emac3_intr_enable(void)
181 {
182 
183 	_emac3_reg_write_4(EMAC3_ISER, ~0);
184 }
185 
186 void
emac3_intr_disable(void)187 emac3_intr_disable(void)
188 {
189 
190 	_emac3_reg_write_4(EMAC3_ISER, 0);
191 }
192 
193 void
emac3_intr_clear(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
emac3_intr(void * arg)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
emac3_tx_kick(void)212 emac3_tx_kick(void)
213 {
214 
215 	_emac3_reg_write_4(EMAC3_TMR0, TMR0_GNP0);
216 }
217 
218 int
emac3_tx_done(void)219 emac3_tx_done(void)
220 {
221 
222 	return (_emac3_reg_read_4(EMAC3_TMR0) & TMR0_GNP0);
223 }
224 
225 void
emac3_setmulti(struct emac3_softc * sc,struct ethercom * ec)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_LOCK(ec);
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 			ETHER_UNLOCK(ec);
251 			goto allmulti;
252 		}
253 
254 		ETHER_NEXT_MULTI(step, enm);
255 	}
256 	ETHER_UNLOCK(ec);
257 
258 	/* XXX always multicast promiscuous mode. XXX use hash table.. */
259 	ifp->if_flags |= IFF_ALLMULTI;
260 	r |= RMR_PMME;
261 	_emac3_reg_write_4(EMAC3_RMR, r);
262 }
263 
264 int
emac3_soft_reset(void)265 emac3_soft_reset(void)
266 {
267 	int retry = 10000;
268 
269 	_emac3_reg_write_4(EMAC3_MR0, MR0_SRST);
270 
271 	while ((_emac3_reg_read_4(EMAC3_MR0) & MR0_SRST) == MR0_SRST &&
272 	    --retry > 0)
273 		;
274 
275 	return (retry == 0);
276 }
277 
278 void
emac3_config(const u_int8_t * eaddr)279 emac3_config(const u_int8_t *eaddr)
280 {
281 
282 	/* set ethernet address */
283 	_emac3_reg_write_4(EMAC3_IAHR, (eaddr[0] << 8) | eaddr[1]);
284 	_emac3_reg_write_4(EMAC3_IALR, (eaddr[2] << 24) | (eaddr[3] << 16) |
285 	    (eaddr[4] << 8) | eaddr[5]);
286 
287 	/* inter-frame GAP */
288 	_emac3_reg_write_4(EMAC3_IPGVR, 4);
289 
290 	/* RX mode */
291 	_emac3_reg_write_4(EMAC3_RMR,
292 	    RMR_SP |	/* strip padding */
293 	    RMR_SFCS |	/* strip FCS */
294 	    RMR_IAE |	/* individual address enable */
295 	    RMR_BAE);	/* boradcast address enable */
296 
297 	/* TX mode */
298 	_emac3_reg_write_4(EMAC3_TMR1,
299 	    ((7 << TMR1_TLR_SHIFT) & TMR1_TLR_MASK) | /* 16 word burst */
300 	    ((15 << TMR1_TUR_SHIFT) & TMR1_TUR_MASK));
301 
302 	/* TX threshold */
303 	_emac3_reg_write_4(EMAC3_TRTR,
304 	    (12 << TRTR_SHIFT) & TRTR_MASK); /* 832 bytes */
305 
306 	/* RX watermark */
307 	_emac3_reg_write_4(EMAC3_RWMR,
308 	    ((16 << RWMR_RLWM_SHIFT) & RWMR_RLWM_MASK) |
309 	    ((128 << RWMR_RHWM_SHIFT) & RWMR_RHWM_MASK));
310 }
311 
312 /*
313  * PHY/MII
314  */
315 int
emac3_phy_writereg(device_t self,int phy,int reg,uint16_t val)316 emac3_phy_writereg(device_t self, int phy, int reg, uint16_t val)
317 {
318 	int rv;
319 
320 	if ((rv = emac3_phy_ready()) != 0)
321 		return rv;
322 
323 	_emac3_reg_write_4(EMAC3_STACR, STACR_WRITE |
324 	    ((phy << STACR_PCDASHIFT) & STACR_PCDA)  | /* command dest addr*/
325 	    ((reg << STACR_PRASHIFT) & STACR_PRA) |   /* register addr */
326 	    ((val << STACR_PHYDSHIFT) & STACR_PHYD)); /* data */
327 
328 	return emac3_phy_ready();
329 }
330 
331 int
emac3_phy_readreg(device_t self,int phy,int reg,uint16_t * val)332 emac3_phy_readreg(device_t self, int phy, int reg, uint16_t *val)
333 {
334 	int rv;
335 
336 	if ((rv = emac3_phy_ready()) != 0)
337 		return rv;
338 
339 	_emac3_reg_write_4(EMAC3_STACR, STACR_READ |
340 	    ((phy << STACR_PCDASHIFT) & STACR_PCDA)  | /* command dest addr*/
341 	    ((reg << STACR_PRASHIFT) & STACR_PRA));   /* register addr */
342 
343 	if ((rv = emac3_phy_ready()) != 0)
344 		return rv;
345 
346 	*val =(_emac3_reg_read_4(EMAC3_STACR) >> STACR_PHYDSHIFT) & 0xffff;
347 	return 0;
348 }
349 
350 void
emac3_phy_statchg(struct ifnet * ifp)351 emac3_phy_statchg(struct ifnet *ifp)
352 {
353 #define EMAC3_FDX	(MR1_FDE | MR1_EIFC | MR1_APP)
354 	struct emac3_softc *sc = ifp->if_softc;
355 	int media;
356 	u_int32_t r;
357 
358 	media = sc->mii.mii_media_active;
359 
360 	r = _emac3_reg_read_4(EMAC3_MR1);
361 
362 	r &= ~(MR1_MF_MASK | MR1_IST | EMAC3_FDX);
363 
364 	switch (media & 0x1f) {
365 	default:
366 		printf("unknown media type. %08x", media);
367 		/* FALLTHROUGH */
368 	case IFM_100_TX:
369 		r |= (MR1_MF_100MBS | MR1_IST);
370 		if (media & IFM_FDX)
371 			r |= EMAC3_FDX;
372 
373 		break;
374 	case IFM_10_T:
375 		r |= MR1_MF_10MBS;
376 		if (media & IFM_FDX)
377 			r |= (EMAC3_FDX | MR1_IST);
378 		break;
379 	}
380 
381 	_emac3_reg_write_4(EMAC3_MR1, r);
382 
383 	/* store current state for re-initialize */
384 	sc->mode1_reg = _emac3_reg_read_4(EMAC3_MR1);
385 #undef EMAC3_FDX
386 }
387 
388 int
emac3_phy_ready(void)389 emac3_phy_ready(void)
390 {
391 	int retry = 10000;
392 
393 	while ((_emac3_reg_read_4(EMAC3_STACR) & STACR_OC) == 0 &&
394 	    --retry > 0)
395 		;
396 	if (retry == 0) {
397 		printf("emac3: phy busy.\n");
398 		return ETIMEDOUT;
399 	}
400 
401 	return (0);
402 }
403 
404