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