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