xref: /netbsd/sys/arch/sandpoint/stand/altboot/rge.c (revision b67d9b68)
1*b67d9b68Srin /* $NetBSD: rge.c,v 1.8 2021/03/25 03:44:25 rin Exp $ */
203058dddSnisimura 
303058dddSnisimura /*-
403058dddSnisimura  * Copyright (c) 2007 The NetBSD Foundation, Inc.
503058dddSnisimura  * All rights reserved.
603058dddSnisimura  *
703058dddSnisimura  * This code is derived from software contributed to The NetBSD Foundation
803058dddSnisimura  * by Tohru Nishimura.
903058dddSnisimura  *
1003058dddSnisimura  * Redistribution and use in source and binary forms, with or without
1103058dddSnisimura  * modification, are permitted provided that the following conditions
1203058dddSnisimura  * are met:
1303058dddSnisimura  * 1. Redistributions of source code must retain the above copyright
1403058dddSnisimura  *    notice, this list of conditions and the following disclaimer.
1503058dddSnisimura  * 2. Redistributions in binary form must reproduce the above copyright
1603058dddSnisimura  *    notice, this list of conditions and the following disclaimer in the
1703058dddSnisimura  *    documentation and/or other materials provided with the distribution.
1803058dddSnisimura  *
1903058dddSnisimura  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
2003058dddSnisimura  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
2103058dddSnisimura  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
2203058dddSnisimura  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
2303058dddSnisimura  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
2403058dddSnisimura  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
2503058dddSnisimura  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
2603058dddSnisimura  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
2703058dddSnisimura  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
2803058dddSnisimura  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
2903058dddSnisimura  * POSSIBILITY OF SUCH DAMAGE.
3003058dddSnisimura  */
3103058dddSnisimura 
3203058dddSnisimura #include <sys/param.h>
3303058dddSnisimura 
3403058dddSnisimura #include <netinet/in.h>
3503058dddSnisimura #include <netinet/in_systm.h>
3603058dddSnisimura 
3703058dddSnisimura #include <lib/libsa/stand.h>
3803058dddSnisimura #include <lib/libsa/net.h>
3903058dddSnisimura 
4003058dddSnisimura #include "globals.h"
4103058dddSnisimura 
4203058dddSnisimura /*
4303058dddSnisimura  * - reverse endian access every CSR.
4403058dddSnisimura  * - no vtophys() translation, vaddr_t == paddr_t.
4503058dddSnisimura  * - PIPT writeback cache aware.
4603058dddSnisimura  */
47a3034375Sphx #define CSR_WRITE_1(l, r, v)	out8((l)->csr+(r), (v))
48a3034375Sphx #define CSR_READ_1(l, r)	in8((l)->csr+(r))
4903058dddSnisimura #define CSR_WRITE_2(l, r, v)	out16rb((l)->csr+(r), (v))
5003058dddSnisimura #define CSR_READ_2(l, r)	in16rb((l)->csr+(r))
5103058dddSnisimura #define CSR_WRITE_4(l, r, v)	out32rb((l)->csr+(r), (v))
5203058dddSnisimura #define CSR_READ_4(l, r)	in32rb((l)->csr+(r))
5303058dddSnisimura #define VTOPHYS(va)		(uint32_t)(va)
5403058dddSnisimura #define DEVTOV(pa)		(uint32_t)(pa)
5503058dddSnisimura #define wbinv(adr, siz)		_wbinv(VTOPHYS(adr), (uint32_t)(siz))
5603058dddSnisimura #define inv(adr, siz)		_inv(VTOPHYS(adr), (uint32_t)(siz))
5703058dddSnisimura #define DELAY(n)		delay(n)
5803058dddSnisimura #define ALLOC(T,A)		(T *)allocaligned(sizeof(T),(A))
5903058dddSnisimura 
6003058dddSnisimura struct desc {
6103058dddSnisimura 	uint32_t xd0, xd1, xd2, xd3;
6203058dddSnisimura };
6303058dddSnisimura #define T0_OWN		0x80000000	/* loaded for HW to send */
6403058dddSnisimura #define T0_EOR		0x40000000	/* end of ring */
6503058dddSnisimura #define T0_FS		0x20000000	/* first descriptor */
6603058dddSnisimura #define T0_LS		0x10000000	/* last descriptor */
6703058dddSnisimura #define T0_FRMASK	0x0000ffff
6803058dddSnisimura 
6903058dddSnisimura #define R0_OWN		0x80000000	/* empty for HW to load anew */
7003058dddSnisimura #define R0_EOR		0x40000000	/* end mark to form a ring */
7103058dddSnisimura #define R0_BUFLEN	0x00003ff8	/* max frag. size to receive */
7203058dddSnisimura #define R0_FS		0x20000000	/* start of frame */
7303058dddSnisimura #define R0_LS		0x10000000	/* end of frame */
7403058dddSnisimura #define R0_RES		0x00200000	/* Rx error summary */
7503058dddSnisimura #define R0_RUNT		0x00100000	/* runt frame received */
7603058dddSnisimura #define R0_CRC		0x00080000	/* CRC error found */
7703058dddSnisimura #define R0_FRMASK	0x00003fff	/* 13:0 frame length */
7803058dddSnisimura 
7903058dddSnisimura #define RGE_IDR0	0x00		/* MAC address [0] */
8003058dddSnisimura #define RGE_IDR1	0x01		/* MAC address [1] */
8103058dddSnisimura #define RGE_IDR2	0x02		/* MAC address [2] */
8203058dddSnisimura #define RGE_IDR3	0x03		/* MAC address [3] */
8303058dddSnisimura #define RGE_IDR4	0x04		/* MAC address [4] */
8403058dddSnisimura #define RGE_IDR5	0x05		/* MAC address [5] */
8503058dddSnisimura #define RGE_TNPDS	0x20		/* Tx descriptor base paddr */
8603058dddSnisimura #define RGE_THPDS	0x28		/* high pro. Tx des. base paddr */
8703058dddSnisimura #define RGE_CR		0x37		/* command */
8803058dddSnisimura #define	 CR_RESET	(1U << 4)	/* reset S1C */
8903058dddSnisimura #define	 CR_RXEN	(1U << 3)	/* Rx enable */
9003058dddSnisimura #define	 CR_TXEN	(1U << 2)	/* Tx enable */
9103058dddSnisimura #define RGE_TPPOLL	0x38		/* activate desc polling */
9203058dddSnisimura #define RGE_IMR		0x3c		/* interrupt mask */
9303058dddSnisimura #define RGE_ISR		0x3e		/* interrupt status */
9403058dddSnisimura #define RGE_TCR		0x40		/* Tx control */
9503058dddSnisimura #define	 TCR_MAXDMA	0x0700		/* 10:8 Tx DMA burst size */
9603058dddSnisimura #define RGE_RCR		0x44		/* Rx control */
9703058dddSnisimura #define	 RCR_RXTFH	0xe000		/* 15:13 Rx FIFO threshold */
9803058dddSnisimura #define	 RCR_MAXDMA	0x0700		/* 10:8 Rx DMA burst size */
9903058dddSnisimura #define	 RCR_AE		(1U << 5)	/* accept error frame */
10003058dddSnisimura #define	 RCR_RE		(1U << 4)	/* accept runt frame */
10103058dddSnisimura #define	 RCR_AB		(1U << 3)	/* accept broadcast frame */
10203058dddSnisimura #define	 RCR_AM		(1U << 2)	/* accept multicast frame */
10303058dddSnisimura #define	 RCR_APM	(1U << 1)	/* accept unicast frame */
10403058dddSnisimura #define	 RCR_AAP	(1U << 0)	/* promiscuous */
105984eca8bSphx #define RGE_EECMD	0x50		/* EEPROM command register */
106984eca8bSphx #define  EECMD_LOCK	0x00
107984eca8bSphx #define  EECMD_UNLOCK	0xc0
10803058dddSnisimura #define RGE_PHYAR	0x60		/* PHY access */
10903058dddSnisimura #define RGE_PHYSR	0x6c		/* PHY status */
11003058dddSnisimura #define RGE_RMS		0xda		/* Rx maximum frame size */
11103058dddSnisimura #define RGE_RDSAR	0xe4		/* Rx descriptor base paddr */
11203058dddSnisimura #define RGE_ETTHR	0xec		/* Tx threshold */
11303058dddSnisimura 
11403058dddSnisimura #define FRAMESIZE	1536
11503058dddSnisimura 
11603058dddSnisimura struct local {
11703058dddSnisimura 	struct desc txd[2]; /* 256B align */
11803058dddSnisimura 	  uint8_t _hole0[256 - 2 * sizeof(struct desc)];
11903058dddSnisimura 	struct desc rxd[2]; /* 256B align */
12003058dddSnisimura 	  uint8_t _hole1[256 - 2 * sizeof(struct desc)];
12103058dddSnisimura 	uint8_t rxstore[2][FRAMESIZE];
12203058dddSnisimura 	unsigned csr, tx, rx;
12303058dddSnisimura 	unsigned phy, bmsr, anlpar;
12403058dddSnisimura 	unsigned tcr, rcr;
12503058dddSnisimura };
12603058dddSnisimura 
12703058dddSnisimura static int mii_read(struct local *, int, int);
12803058dddSnisimura static void mii_write(struct local *, int, int, int);
12903058dddSnisimura static void mii_initphy(struct local *);
13003058dddSnisimura static void mii_dealan(struct local *, unsigned);
13103058dddSnisimura 
13203058dddSnisimura int
rge_match(unsigned tag,void * data)13303058dddSnisimura rge_match(unsigned tag, void *data)
13403058dddSnisimura {
13503058dddSnisimura 	unsigned v;
13603058dddSnisimura 
13703058dddSnisimura 	v = pcicfgread(tag, PCI_ID_REG);
13803058dddSnisimura 	switch (v) {
13993f78c00Sphx 	case PCI_DEVICE(0x10ec, 0x8167):
14003058dddSnisimura 	case PCI_DEVICE(0x10ec, 0x8169):
14103058dddSnisimura 		return 1;
14203058dddSnisimura 	}
14303058dddSnisimura 	return 0;
14403058dddSnisimura }
14503058dddSnisimura 
14603058dddSnisimura void *
rge_init(unsigned tag,void * data)14703058dddSnisimura rge_init(unsigned tag, void *data)
14803058dddSnisimura {
14903058dddSnisimura 	unsigned val;
15003058dddSnisimura 	struct local *l;
15103058dddSnisimura 	struct desc *txd, *rxd;
152984eca8bSphx 	uint32_t reg;
153984eca8bSphx 	uint8_t *en;
15403058dddSnisimura 
15503058dddSnisimura 	l = ALLOC(struct local, 256);	/* desc alignment */
15603058dddSnisimura 	memset(l, 0, sizeof(struct local));
15703058dddSnisimura 	l->csr = DEVTOV(pcicfgread(tag, 0x14)); /* use mem space */
15803058dddSnisimura 
15903058dddSnisimura 	CSR_WRITE_1(l, RGE_CR, CR_RESET);
16003058dddSnisimura 	do {
16103058dddSnisimura 		val = CSR_READ_1(l, RGE_CR);
16203058dddSnisimura 	} while (val & CR_RESET);
16303058dddSnisimura 
16403058dddSnisimura 	mii_initphy(l);
16503058dddSnisimura 	en = data;
166984eca8bSphx 
167984eca8bSphx 	if (brdtype == BRD_QNAPTS) {
168984eca8bSphx 		/* read the MAC from flash and write it into the ID-Regs */
169984eca8bSphx 		read_mac_from_flash(en);
170984eca8bSphx 
171984eca8bSphx 		CSR_WRITE_1(l, RGE_EECMD, EECMD_UNLOCK);
172984eca8bSphx 		reg = en[0] | (en[1] << 8) | (en[2] << 16) | (en[3] << 24);
173984eca8bSphx 		CSR_WRITE_4(l, RGE_IDR0, reg);
174984eca8bSphx 		reg = en[4] | (en[5] << 8);
175984eca8bSphx 		CSR_WRITE_4(l, RGE_IDR4, reg);
176984eca8bSphx 		CSR_WRITE_1(l, RGE_EECMD, EECMD_LOCK);
177984eca8bSphx 	} else {
178984eca8bSphx 		/* pretent the ID-Regs have the correct address */
17903058dddSnisimura 		en[0] = CSR_READ_1(l, RGE_IDR0);
18003058dddSnisimura 		en[1] = CSR_READ_1(l, RGE_IDR1);
18103058dddSnisimura 		en[2] = CSR_READ_1(l, RGE_IDR2);
18203058dddSnisimura 		en[3] = CSR_READ_1(l, RGE_IDR3);
18303058dddSnisimura 		en[4] = CSR_READ_1(l, RGE_IDR4);
18403058dddSnisimura 		en[5] = CSR_READ_1(l, RGE_IDR5);
185984eca8bSphx 	}
18603058dddSnisimura 
18703058dddSnisimura 	printf("MAC address %02x:%02x:%02x:%02x:%02x:%02x\n",
18803058dddSnisimura 	    en[0], en[1], en[2], en[3], en[4], en[5]);
1899d74806aSphx 	DPRINTF(("PHY %d (%04x.%04x)\n", l->phy,
1909d74806aSphx 	    mii_read(l, l->phy, 2), mii_read(l, l->phy, 3)));
19103058dddSnisimura 
19203058dddSnisimura 	mii_dealan(l, 5);
19303058dddSnisimura 
19403058dddSnisimura 	/* speed and duplexity can be seen in PHYSR */
19503058dddSnisimura 	val = CSR_READ_1(l, RGE_PHYSR);
19603058dddSnisimura 	if (val & (1U << 4))
19703058dddSnisimura 		printf("1000Mbps");
19803058dddSnisimura 	if (val & (1U << 3))
19903058dddSnisimura 		printf("100Mbps");
20003058dddSnisimura 	if (val & (1U << 2))
20103058dddSnisimura 		printf("10Mbps");
20203058dddSnisimura 	if (val & (1U << 0))
20303058dddSnisimura 		printf("-FDX");
20403058dddSnisimura 	printf("\n");
20503058dddSnisimura 
20603058dddSnisimura 	txd = &l->txd[0];
20703058dddSnisimura 	txd[1].xd0 = htole32(T0_EOR);
20803058dddSnisimura 	rxd = &l->rxd[0];
20903058dddSnisimura 	rxd[0].xd0 = htole32(R0_OWN | FRAMESIZE);
21003058dddSnisimura 	rxd[0].xd2 = htole32(VTOPHYS(l->rxstore[0]));
21103058dddSnisimura 	rxd[1].xd0 = htole32(R0_OWN | R0_EOR | FRAMESIZE);
21203058dddSnisimura 	rxd[1].xd2 = htole32(VTOPHYS(l->rxstore[1]));
21303058dddSnisimura 	wbinv(l, sizeof(struct local));
21403058dddSnisimura 	l->tx = l->rx = 0;
21503058dddSnisimura 
21603058dddSnisimura 	l->tcr = (03 << 24) | (07 << 8);
21703058dddSnisimura 	l->rcr = (07 << 13) | (07 << 8) | RCR_APM;
21803058dddSnisimura 	CSR_WRITE_1(l, RGE_CR, CR_TXEN | CR_RXEN);
21903058dddSnisimura 	CSR_WRITE_1(l, RGE_ETTHR, 0x3f);
22093f78c00Sphx 	CSR_WRITE_2(l, RGE_RMS, FRAMESIZE);
22103058dddSnisimura 	CSR_WRITE_4(l, RGE_TCR, l->tcr);
22203058dddSnisimura 	CSR_WRITE_4(l, RGE_RCR, l->rcr);
22303058dddSnisimura 	CSR_WRITE_4(l, RGE_TNPDS, VTOPHYS(txd));
22403058dddSnisimura 	CSR_WRITE_4(l, RGE_RDSAR, VTOPHYS(rxd));
22503058dddSnisimura 	CSR_WRITE_4(l, RGE_TNPDS + 4, 0);
22603058dddSnisimura 	CSR_WRITE_4(l, RGE_RDSAR + 4, 0);
22703058dddSnisimura 	CSR_WRITE_2(l, RGE_ISR, ~0);
22803058dddSnisimura 	CSR_WRITE_2(l, RGE_IMR, 0);
22903058dddSnisimura 	return l;
23003058dddSnisimura }
23103058dddSnisimura 
23203058dddSnisimura int
rge_send(void * dev,char * buf,unsigned len)23303058dddSnisimura rge_send(void *dev, char *buf, unsigned len)
23403058dddSnisimura {
23503058dddSnisimura 	struct local *l = dev;
23603058dddSnisimura 	volatile struct desc *txd;
2371e856246Sphx 	unsigned loop, ret;
238*b67d9b68Srin 	char tmp[60];
23903058dddSnisimura 
2401e856246Sphx 	ret = len;
241*b67d9b68Srin 	/* RTL does not stretch <60 Tx frame */
242050d1b8bSphx 	if (len < 60) {
243*b67d9b68Srin 		memcpy(tmp, buf, len);
244*b67d9b68Srin 		buf = tmp;
245050d1b8bSphx 		memset(buf + len, 0, 60 - len);
246*b67d9b68Srin 		len = 60;
247050d1b8bSphx 	}
24803058dddSnisimura 	wbinv(buf, len);
24903058dddSnisimura 	txd = &l->txd[l->tx];
25003058dddSnisimura 	txd->xd2 = htole32(VTOPHYS(buf));
25103058dddSnisimura 	txd->xd0 &= htole32(T0_EOR);
25203058dddSnisimura 	txd->xd0 |= htole32(T0_OWN | T0_FS | T0_LS | (len & T0_FRMASK));
25303058dddSnisimura 	wbinv(txd, sizeof(struct desc));
25403058dddSnisimura 	CSR_WRITE_1(l, RGE_TPPOLL, 0x40);
25503058dddSnisimura 	loop = 100;
25603058dddSnisimura 	do {
25703058dddSnisimura 		if ((le32toh(txd->xd0) & T0_OWN) == 0)
25803058dddSnisimura 			goto done;
25903058dddSnisimura 		DELAY(10);
26003058dddSnisimura 		inv(txd, sizeof(struct desc));
26103058dddSnisimura 	} while (--loop > 0);
26203058dddSnisimura 	printf("xmit failed\n");
26303058dddSnisimura 	return -1;
26403058dddSnisimura   done:
26503058dddSnisimura 	l->tx ^= 1;
2661e856246Sphx 	return ret;
26703058dddSnisimura }
26803058dddSnisimura 
26903058dddSnisimura int
rge_recv(void * dev,char * buf,unsigned maxlen,unsigned timo)27003058dddSnisimura rge_recv(void *dev, char *buf, unsigned maxlen, unsigned timo)
27103058dddSnisimura {
27203058dddSnisimura 	struct local *l = dev;
27303058dddSnisimura 	volatile struct desc *rxd;
27403058dddSnisimura 	unsigned bound, rxstat, len;
27503058dddSnisimura 	uint8_t *ptr;
27603058dddSnisimura 
27703058dddSnisimura 	bound = 1000 * timo;
27803058dddSnisimura #if 0
27903058dddSnisimura printf("recving with %u sec. timeout\n", timo);
28003058dddSnisimura #endif
28103058dddSnisimura   again:
28203058dddSnisimura 	rxd = &l->rxd[l->rx];
28303058dddSnisimura 	do {
28403058dddSnisimura 		inv(rxd, sizeof(struct desc));
28503058dddSnisimura 		rxstat = le32toh(rxd->xd0);
28603058dddSnisimura 		if ((rxstat & R0_OWN) == 0)
28703058dddSnisimura 			goto gotone;
28803058dddSnisimura 		DELAY(1000);	/* 1 milli second */
28903058dddSnisimura 	} while (--bound > 0);
29003058dddSnisimura 	errno = 0;
29103058dddSnisimura 	return -1;
29203058dddSnisimura   gotone:
29303058dddSnisimura 	if (rxstat & R0_RES) {
29403058dddSnisimura 		rxd->xd0 &= htole32(R0_EOR);
29503058dddSnisimura 		rxd->xd0 |= htole32(R0_OWN | FRAMESIZE);
29603058dddSnisimura 		wbinv(rxd, sizeof(struct desc));
29703058dddSnisimura 		l->rx ^= 1;
29803058dddSnisimura 		goto again;
29903058dddSnisimura 	}
30003058dddSnisimura 	len = rxstat & R0_FRMASK;
30103058dddSnisimura 	if (len > maxlen)
30203058dddSnisimura 		len = maxlen;
30303058dddSnisimura 	ptr = l->rxstore[l->rx];
30403058dddSnisimura 	inv(ptr, len);
30503058dddSnisimura 	memcpy(buf, ptr, len);
30603058dddSnisimura 	rxd->xd0 &= htole32(R0_EOR);
30703058dddSnisimura 	rxd->xd0 |= htole32(R0_OWN | FRAMESIZE);
30803058dddSnisimura 	wbinv(rxd, sizeof(struct desc));
30903058dddSnisimura 	l->rx ^= 1;
31003058dddSnisimura 	return len;
31103058dddSnisimura }
31203058dddSnisimura 
31303058dddSnisimura static int
mii_read(struct local * l,int phy,int reg)31403058dddSnisimura mii_read(struct local *l, int phy, int reg)
31503058dddSnisimura {
31693f78c00Sphx 	unsigned v;
31703058dddSnisimura 
31803058dddSnisimura 	v = reg << 16;
31903058dddSnisimura 	CSR_WRITE_4(l, RGE_PHYAR, v);
32093f78c00Sphx 	DELAY(1000);
32103058dddSnisimura 	do {
32293f78c00Sphx 		DELAY(100);
32303058dddSnisimura 		v = CSR_READ_4(l, RGE_PHYAR);
32403058dddSnisimura 	} while ((v & (1U << 31)) == 0); /* wait for 0 -> 1 */
32593f78c00Sphx 	return v & 0xffff;
32603058dddSnisimura }
32703058dddSnisimura 
32803058dddSnisimura static void
mii_write(struct local * l,int phy,int reg,int data)32903058dddSnisimura mii_write(struct local *l, int phy, int reg, int data)
33003058dddSnisimura {
33103058dddSnisimura 	unsigned v;
33203058dddSnisimura 
33303058dddSnisimura 	v = (reg << 16) | (data & 0xffff) | (1U << 31);
33403058dddSnisimura 	CSR_WRITE_4(l, RGE_PHYAR, v);
33593f78c00Sphx 	DELAY(1000);
33603058dddSnisimura 	do {
33793f78c00Sphx 		DELAY(100);
33803058dddSnisimura 		v = CSR_READ_4(l, RGE_PHYAR);
33903058dddSnisimura 	} while (v & (1U << 31)); /* wait for 1 -> 0 */
34003058dddSnisimura }
34103058dddSnisimura 
34203058dddSnisimura #define MII_BMCR	0x00	/* Basic mode control register (rw) */
34303058dddSnisimura #define  BMCR_RESET	0x8000	/* reset */
34403058dddSnisimura #define  BMCR_AUTOEN	0x1000	/* autonegotiation enable */
34503058dddSnisimura #define  BMCR_ISO	0x0400	/* isolate */
34603058dddSnisimura #define  BMCR_STARTNEG	0x0200	/* restart autonegotiation */
34703058dddSnisimura #define MII_BMSR	0x01	/* Basic mode status register (ro) */
34803058dddSnisimura #define  BMSR_ACOMP	0x0020	/* Autonegotiation complete */
34903058dddSnisimura #define  BMSR_LINK	0x0004	/* Link status */
35003058dddSnisimura #define MII_ANAR	0x04	/* Autonegotiation advertisement (rw) */
35103058dddSnisimura #define  ANAR_FC	0x0400	/* local device supports PAUSE */
35203058dddSnisimura #define  ANAR_TX_FD	0x0100	/* local device supports 100bTx FD */
35303058dddSnisimura #define  ANAR_TX	0x0080	/* local device supports 100bTx */
35403058dddSnisimura #define  ANAR_10_FD	0x0040	/* local device supports 10bT FD */
35503058dddSnisimura #define  ANAR_10	0x0020	/* local device supports 10bT */
35603058dddSnisimura #define  ANAR_CSMA	0x0001	/* protocol selector CSMA/CD */
35703058dddSnisimura #define MII_ANLPAR	0x05	/* Autonegotiation lnk partner abilities (rw) */
35803058dddSnisimura #define MII_GTCR	0x09	/* 1000baseT control */
35903058dddSnisimura #define  GANA_1000TFDX	0x0200	/* advertise 1000baseT FDX */
36003058dddSnisimura #define  GANA_1000THDX	0x0100	/* advertise 1000baseT HDX */
36103058dddSnisimura #define MII_GTSR	0x0a	/* 1000baseT status */
36203058dddSnisimura #define  GLPA_1000TFDX	0x0800	/* link partner 1000baseT FDX capable */
36303058dddSnisimura #define  GLPA_1000THDX	0x0400	/* link partner 1000baseT HDX capable */
36403058dddSnisimura #define  GLPA_ASM_DIR	0x0200	/* link partner asym. pause dir. capable */
36503058dddSnisimura 
36603058dddSnisimura static void
mii_initphy(struct local * l)36703058dddSnisimura mii_initphy(struct local *l)
36803058dddSnisimura {
36993f78c00Sphx 	int bound, ctl, phy, sts;
37003058dddSnisimura 
37193f78c00Sphx 	phy = 7;	/* internal rgephy, always at 7 */
37203058dddSnisimura 	ctl = mii_read(l, phy, MII_BMCR);
37303058dddSnisimura 	mii_write(l, phy, MII_BMCR, ctl | BMCR_RESET);
37403058dddSnisimura 	bound = 100;
37503058dddSnisimura 	do {
37603058dddSnisimura 		DELAY(10);
37703058dddSnisimura 		ctl = mii_read(l, phy, MII_BMCR);
37803058dddSnisimura 		if (ctl == 0xffff) {
37903058dddSnisimura 			printf("MII: PHY %d has died after reset\n", phy);
38003058dddSnisimura 			return;
38103058dddSnisimura 		}
38203058dddSnisimura 	} while (bound-- > 0 && (ctl & BMCR_RESET));
38303058dddSnisimura 	if (bound == 0) {
38403058dddSnisimura 		printf("PHY %d reset failed\n", phy);
38503058dddSnisimura 	}
38603058dddSnisimura 	ctl &= ~BMCR_ISO;
38703058dddSnisimura 	mii_write(l, phy, MII_BMCR, ctl);
38803058dddSnisimura 	sts = mii_read(l, phy, MII_BMSR) |
38903058dddSnisimura 	    mii_read(l, phy, MII_BMSR); /* read twice */
39003058dddSnisimura 	l->phy = phy;
39103058dddSnisimura 	l->bmsr = sts;
39203058dddSnisimura }
39303058dddSnisimura 
39403058dddSnisimura void
mii_dealan(struct local * l,unsigned timo)39503058dddSnisimura mii_dealan(struct local *l, unsigned timo)
39603058dddSnisimura {
39703058dddSnisimura 	unsigned anar, gtcr, bound;
39803058dddSnisimura 
39903058dddSnisimura 	anar = ANAR_TX_FD | ANAR_TX | ANAR_10_FD | ANAR_10 | ANAR_CSMA;
40003058dddSnisimura 	anar |= ANAR_FC;
40103058dddSnisimura 	gtcr = GANA_1000TFDX | GANA_1000THDX;
40203058dddSnisimura 	mii_write(l, l->phy, MII_ANAR, anar);
40303058dddSnisimura 	mii_write(l, l->phy, MII_GTCR, gtcr);
40403058dddSnisimura 	mii_write(l, l->phy, MII_BMCR, BMCR_AUTOEN | BMCR_STARTNEG);
40503058dddSnisimura 	l->anlpar = 0;
40603058dddSnisimura 	bound = getsecs() + timo;
40703058dddSnisimura 	do {
40803058dddSnisimura 		l->bmsr = mii_read(l, l->phy, MII_BMSR) |
40903058dddSnisimura 		   mii_read(l, l->phy, MII_BMSR); /* read twice */
41003058dddSnisimura 		if ((l->bmsr & BMSR_LINK) && (l->bmsr & BMSR_ACOMP)) {
41103058dddSnisimura 			l->anlpar = mii_read(l, l->phy, MII_ANLPAR);
41203058dddSnisimura 			break;
41303058dddSnisimura 		}
41403058dddSnisimura 		DELAY(10 * 1000);
41503058dddSnisimura 	} while (getsecs() < bound);
41603058dddSnisimura 	return;
41703058dddSnisimura }
418