Home | History | Annotate | Line # | Download | only in dev
      1 /*	$NetBSD: emac3.c,v 1.16 2024/05/24 20:09:09 andvar 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.16 2024/05/24 20:09:09 andvar 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", 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
    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
    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
    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_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
    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
    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);	/* broadcast 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
    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
    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
    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
    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