Module Name:    src
Committed By:   phx
Date:           Sun Mar  6 13:55:12 UTC 2011

Modified Files:
        src/sys/arch/sandpoint/stand/altboot: Makefile brdsetup.c dsk.c
            globals.h main.c nif.c pciide.c siisata.c
Added Files:
        src/sys/arch/sandpoint/stand/altboot: stg.c

Log Message:
New experimental driver for SundanceIT ST1023 / IP1000+ NICs.
PHY initialization, media select and MAC address are working, but I found no
way to make the chip transmit any frame yet (although it clears the DONE flag).

Moved DSK_DECL to globals.h, where NIF_DECL already was.


To generate a diff of this commit:
cvs rdiff -u -r1.8 -r1.9 src/sys/arch/sandpoint/stand/altboot/Makefile
cvs rdiff -u -r1.5 -r1.6 src/sys/arch/sandpoint/stand/altboot/brdsetup.c
cvs rdiff -u -r1.4 -r1.5 src/sys/arch/sandpoint/stand/altboot/dsk.c
cvs rdiff -u -r1.6 -r1.7 src/sys/arch/sandpoint/stand/altboot/globals.h
cvs rdiff -u -r1.7 -r1.8 src/sys/arch/sandpoint/stand/altboot/main.c
cvs rdiff -u -r1.2 -r1.3 src/sys/arch/sandpoint/stand/altboot/nif.c \
    src/sys/arch/sandpoint/stand/altboot/pciide.c \
    src/sys/arch/sandpoint/stand/altboot/siisata.c
cvs rdiff -u -r0 -r1.1 src/sys/arch/sandpoint/stand/altboot/stg.c

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/sys/arch/sandpoint/stand/altboot/Makefile
diff -u src/sys/arch/sandpoint/stand/altboot/Makefile:1.8 src/sys/arch/sandpoint/stand/altboot/Makefile:1.9
--- src/sys/arch/sandpoint/stand/altboot/Makefile:1.8	Sat Feb 26 20:11:24 2011
+++ src/sys/arch/sandpoint/stand/altboot/Makefile	Sun Mar  6 13:55:12 2011
@@ -1,4 +1,4 @@
-#	$NetBSD: Makefile,v 1.8 2011/02/26 20:11:24 phx Exp $
+#	$NetBSD: Makefile,v 1.9 2011/03/06 13:55:12 phx Exp $
 
 S=		${.CURDIR}/../../../..
 
@@ -6,8 +6,8 @@
 FILES+=		${PROG}.bin ${PROG}.img
 NOMAN=		# defined
 SRCS=		entry.S main.c brdsetup.c pci.c devopen.c dev_net.c nif.c
-SRCS+=		fxp.c tlp.c rge.c skg.c dsk.c pciide.c siisata.c printf.c
-SRCS+=		vers.c
+SRCS+=		fxp.c tlp.c rge.c skg.c stg.c dsk.c pciide.c siisata.c
+SRCS+=		printf.c vers.c
 CLEANFILES+=	vers.c ${PROG} ${PROG}.bin ${PROG}.img
 CFLAGS+=	-Wall -Wno-main -ffreestanding -msoft-float -mmultiple
 CFLAGS+=	-Wmissing-prototypes -Wstrict-prototypes -Wpointer-arith

Index: src/sys/arch/sandpoint/stand/altboot/brdsetup.c
diff -u src/sys/arch/sandpoint/stand/altboot/brdsetup.c:1.5 src/sys/arch/sandpoint/stand/altboot/brdsetup.c:1.6
--- src/sys/arch/sandpoint/stand/altboot/brdsetup.c:1.5	Mon Feb 14 06:21:29 2011
+++ src/sys/arch/sandpoint/stand/altboot/brdsetup.c	Sun Mar  6 13:55:12 2011
@@ -1,4 +1,4 @@
-/* $NetBSD: brdsetup.c,v 1.5 2011/02/14 06:21:29 nisimura Exp $ */
+/* $NetBSD: brdsetup.c,v 1.6 2011/03/06 13:55:12 phx Exp $ */
 
 /*-
  * Copyright (c) 2008 The NetBSD Foundation, Inc.
@@ -959,6 +959,22 @@
 	return NULL;
 }
 
+static uint8_t hex2nibble(char c)
+{
+	if (c >= 'a')
+		c &= ~0x20;
+	return c > '9' ? c - 'A' + 10 : c - '0';
+}
+
+static void
+read_mac_string(uint8_t *mac, char *p)
+{
+	int i;
+
+	for (i = 0; i < 6; i++, p += 3)
+		*mac++ = (hex2nibble(p[0]) << 4) | hex2nibble(p[1]);
+}
+
 /*
  * For cost saving reasons some NAS boxes are missing the ROM for the
  * NIC's ethernet address and keep it in their Flash memory.
@@ -974,7 +990,11 @@
 			memcpy(mac, p, 6);
 			return;
 		}
-	} else
+	} else if (brdtype == BRD_DLINKDSM) {
+		read_mac_string(mac, (char *)0xfff0ff80);
+		return;
+	}
+	else
 		printf("Warning: This board has no known method defined "
 		    "to determine its MAC address!\n");
 

Index: src/sys/arch/sandpoint/stand/altboot/dsk.c
diff -u src/sys/arch/sandpoint/stand/altboot/dsk.c:1.4 src/sys/arch/sandpoint/stand/altboot/dsk.c:1.5
--- src/sys/arch/sandpoint/stand/altboot/dsk.c:1.4	Thu Feb 10 13:38:08 2011
+++ src/sys/arch/sandpoint/stand/altboot/dsk.c	Sun Mar  6 13:55:12 2011
@@ -1,4 +1,4 @@
-/* $NetBSD: dsk.c,v 1.4 2011/02/10 13:38:08 nisimura Exp $ */
+/* $NetBSD: dsk.c,v 1.5 2011/03/06 13:55:12 phx Exp $ */
 
 /*-
  * Copyright (c) 2010 The NetBSD Foundation, Inc.
@@ -57,13 +57,6 @@
 #define CSR_READ_1(r)		*(volatile uint8_t *)(r)
 #define CSR_WRITE_1(r,v)	*(volatile uint8_t *)(r)=(v)
 
-#define DSK_DECL(xxx) \
-    int xxx ## _match(unsigned, void *); \
-    void * xxx ## _init(unsigned, void *)
-
-DSK_DECL(pciide);
-DSK_DECL(siisata);
-
 struct dskdv {
 	char *name;
 	int (*match)(unsigned, void *);

Index: src/sys/arch/sandpoint/stand/altboot/globals.h
diff -u src/sys/arch/sandpoint/stand/altboot/globals.h:1.6 src/sys/arch/sandpoint/stand/altboot/globals.h:1.7
--- src/sys/arch/sandpoint/stand/altboot/globals.h:1.6	Mon Feb 14 06:21:29 2011
+++ src/sys/arch/sandpoint/stand/altboot/globals.h	Sun Mar  6 13:55:12 2011
@@ -1,4 +1,4 @@
-/* $NetBSD: globals.h,v 1.6 2011/02/14 06:21:29 nisimura Exp $ */
+/* $NetBSD: globals.h,v 1.7 2011/03/06 13:55:12 phx Exp $ */
 
 #ifdef DEBUG
 #define	DPRINTF(x)	printf x
@@ -88,6 +88,7 @@
 #define PCI_CLASS_REG			0x08
 #define  PCI_CLASS_PPB			0x0604
 #define  PCI_CLASS_ETH			0x0200
+#define  PCI_CLASS_SCSI			0x0100
 #define  PCI_CLASS_IDE			0x0101
 #define  PCI_CLASS_RAID			0x0104
 #define  PCI_CLASS_SATA			0x0106
@@ -138,6 +139,7 @@
 NIF_DECL(tlp);
 NIF_DECL(rge);
 NIF_DECL(skg);
+NIF_DECL(stg);
 
 /* DSK support */
 int dskdv_init(void *);
@@ -147,6 +149,13 @@
 int dsk_strategy(void *, int, daddr_t, size_t, void *, size_t *);
 struct fs_ops *dsk_fsops(struct open_file *);
 
+#define DSK_DECL(xxx) \
+    int xxx ## _match(unsigned, void *); \
+    void * xxx ## _init(unsigned, void *)
+
+DSK_DECL(pciide);
+DSK_DECL(siisata);
+
 /* status */
 #define ATA_STS_BUSY		0x80
 #define ATA_STS_DRDY		0x40

Index: src/sys/arch/sandpoint/stand/altboot/main.c
diff -u src/sys/arch/sandpoint/stand/altboot/main.c:1.7 src/sys/arch/sandpoint/stand/altboot/main.c:1.8
--- src/sys/arch/sandpoint/stand/altboot/main.c:1.7	Sat Feb 26 20:11:24 2011
+++ src/sys/arch/sandpoint/stand/altboot/main.c	Sun Mar  6 13:55:12 2011
@@ -1,4 +1,4 @@
-/* $NetBSD: main.c,v 1.7 2011/02/26 20:11:24 phx Exp $ */
+/* $NetBSD: main.c,v 1.8 2011/03/06 13:55:12 phx Exp $ */
 
 /*-
  * Copyright (c) 2007 The NetBSD Foundation, Inc.
@@ -125,6 +125,8 @@
 	nata = pcilookup(PCI_CLASS_IDE, lata, 2);
 	if (nata == 0)
 		nata = pcilookup(PCI_CLASS_MISCSTORAGE, lata, 2);
+	if (nata == 0)
+		nata = pcilookup(PCI_CLASS_SCSI, lata, 2);
 	nnif = pcilookup(PCI_CLASS_ETH, lnif, 1);
 	nusb = pcilookup(PCI_CLASS_USB, lusb, 3);
 
@@ -231,8 +233,8 @@
 	bi_add(&bi_path, BTINFO_BOOTPATH, sizeof(bi_path));
 	bi_add(&bi_rdev, BTINFO_ROOTDEVICE, sizeof(bi_rdev));
 	bi_add(&bi_fam, BTINFO_PRODFAMILY, sizeof(bi_fam));
-	if (brdtype == BRD_SYNOLOGY) {
-		/* need to set MAC address for Marvell-SKnet */
+	if (brdtype == BRD_SYNOLOGY || brdtype == BRD_DLINKDSM) {
+		/* need to set this MAC address in kernel driver later */
 		bi_add(&bi_net, BTINFO_NET, sizeof(bi_net));
 	}
 

Index: src/sys/arch/sandpoint/stand/altboot/nif.c
diff -u src/sys/arch/sandpoint/stand/altboot/nif.c:1.2 src/sys/arch/sandpoint/stand/altboot/nif.c:1.3
--- src/sys/arch/sandpoint/stand/altboot/nif.c:1.2	Thu Feb 10 13:38:08 2011
+++ src/sys/arch/sandpoint/stand/altboot/nif.c	Sun Mar  6 13:55:12 2011
@@ -1,4 +1,4 @@
-/* $NetBSD: nif.c,v 1.2 2011/02/10 13:38:08 nisimura Exp $ */
+/* $NetBSD: nif.c,v 1.3 2011/03/06 13:55:12 phx Exp $ */
 
 /*-
  * Copyright (c) 2007 The NetBSD Foundation, Inc.
@@ -58,6 +58,7 @@
 	{ "tlp", tlp_match, tlp_init, tlp_send, tlp_recv },
 	{ "re",  rge_match, rge_init, rge_send, rge_recv },
 	{ "sk",  skg_match, skg_init, skg_send, skg_recv },
+	{ "stg", stg_match, stg_init, stg_send, stg_recv },
 };
 static int nnifdv = sizeof(lnifdv)/sizeof(lnifdv[0]);
 
Index: src/sys/arch/sandpoint/stand/altboot/pciide.c
diff -u src/sys/arch/sandpoint/stand/altboot/pciide.c:1.2 src/sys/arch/sandpoint/stand/altboot/pciide.c:1.3
--- src/sys/arch/sandpoint/stand/altboot/pciide.c:1.2	Tue Feb  8 00:33:05 2011
+++ src/sys/arch/sandpoint/stand/altboot/pciide.c	Sun Mar  6 13:55:12 2011
@@ -1,4 +1,4 @@
-/* $NetBSD: pciide.c,v 1.2 2011/02/08 00:33:05 nisimura Exp $ */
+/* $NetBSD: pciide.c,v 1.3 2011/03/06 13:55:12 phx Exp $ */
 
 /*-
  * Copyright (c) 2008 The NetBSD Foundation, Inc.
@@ -35,19 +35,18 @@
 
 #include "globals.h"
 
+static int cmdidefix(struct dkdev_ata *);
+
 static uint32_t pciiobase = PCI_XIOBASE;
 
 struct myops {
 	int (*chipfix)(struct dkdev_ata *);
 	int (*presense)(struct dkdev_ata *, int);
 };
-static int cmdidefix(struct dkdev_ata *);
+static struct myops defaultops = { NULL, NULL };
 static struct myops cmdideops = { cmdidefix, NULL };
 static struct myops *myops;
 
-int pciide_match(unsigned, void *);
-void *pciide_init(unsigned, void *);
-
 int
 pciide_match(unsigned tag, void *data)
 {
@@ -63,6 +62,7 @@
 	case PCI_DEVICE(0x10ad, 0x0105): /* Symphony Labs 82C105 IDE */
 	case PCI_DEVICE(0x10b8, 0x5229): /* ALi IDE */
 	case PCI_DEVICE(0x1191, 0x0008): /* ACARD ATP865 */
+		myops = &defaultops;
 		return 1;
 	}
 	return 0;
Index: src/sys/arch/sandpoint/stand/altboot/siisata.c
diff -u src/sys/arch/sandpoint/stand/altboot/siisata.c:1.2 src/sys/arch/sandpoint/stand/altboot/siisata.c:1.3
--- src/sys/arch/sandpoint/stand/altboot/siisata.c:1.2	Thu Jan 27 17:38:04 2011
+++ src/sys/arch/sandpoint/stand/altboot/siisata.c	Sun Mar  6 13:55:12 2011
@@ -1,4 +1,4 @@
-/* $NetBSD: siisata.c,v 1.2 2011/01/27 17:38:04 phx Exp $ */
+/* $NetBSD: siisata.c,v 1.3 2011/03/06 13:55:12 phx Exp $ */
 
 /*-
  * Copyright (c) 2008 The NetBSD Foundation, Inc.
@@ -37,9 +37,6 @@
 
 static uint32_t pciiobase = PCI_XIOBASE;
 
-int siisata_match(unsigned, void *);
-void *siisata_init(unsigned, void *);
-
 int
 siisata_match(unsigned tag, void *data)
 {

Added files:

Index: src/sys/arch/sandpoint/stand/altboot/stg.c
diff -u /dev/null src/sys/arch/sandpoint/stand/altboot/stg.c:1.1
--- /dev/null	Sun Mar  6 13:55:12 2011
+++ src/sys/arch/sandpoint/stand/altboot/stg.c	Sun Mar  6 13:55:12 2011
@@ -0,0 +1,542 @@
+/* $NetBSD: stg.c,v 1.1 2011/03/06 13:55:12 phx Exp $ */
+
+/*-
+ * Copyright (c) 2011 Frank Wille.
+ * All rights reserved.
+ *
+ * Written by Frank Wille for The NetBSD Project.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/param.h>
+
+#include <netinet/in.h>
+#include <netinet/in_systm.h>
+
+#include <lib/libsa/stand.h>
+#include <lib/libsa/net.h>
+
+#include "globals.h"
+
+#define CSR_WRITE_1(l, r, v)	*(volatile uint8_t *)((l)->csr+(r)) = (v)
+#define CSR_READ_1(l, r)	*(volatile uint8_t *)((l)->csr+(r))
+#define CSR_WRITE_2(l, r, v)	out16rb((l)->csr+(r), (v))
+#define CSR_READ_2(l, r)	in16rb((l)->csr+(r))
+#define CSR_WRITE_4(l, r, v)	out32rb((l)->csr+(r), (v))
+#define CSR_READ_4(l, r)	in32rb((l)->csr+(r))
+#define VTOPHYS(va)		(uint32_t)(va)
+#define DEVTOV(pa)		(uint32_t)(pa)
+#define wbinv(adr, siz)		_wbinv(VTOPHYS(adr), (uint32_t)(siz))
+#define inv(adr, siz)		_inv(VTOPHYS(adr), (uint32_t)(siz))
+#define DELAY(n)		delay(n)
+#define ALLOC(T,A)		(T *)allocaligned(sizeof(T),(A))
+
+struct desc {
+	uint64_t xd0, xd1, xd2;
+};
+/* xd1 */
+#define RXLEN(x)		((x) & 0xffff)
+#define RXERRORMASK		0x3f0000LL
+#define TXNOALIGN		(1ULL << 16)
+#define TXFRAGCOUNT(x)		(((uint64_t)((x) & 0xf)) << 48)
+#define DONE			(1ULL << 31)
+/* xd2 */
+#define FRAGADDR(x)		((uint64_t)(x))
+#define FRAGLEN(x)		(((uint64_t)((x) & 0xffff)) << 48)
+
+#define STGE_DMACtrl		0x00
+#define  DMAC_RxDMAComplete	(1U << 3)
+#define  DMAC_RxDMAPollNow	(1U << 4)
+#define  DMAC_TxDMAComplete	(1U << 11)
+#define  DMAC_TxDMAPollNow	(1U << 12)
+#define STGE_TFDListPtrLo	0x10
+#define STGE_TFDListPtrHi	0x14
+#define STGE_RFDListPtrLo	0x1c
+#define STGE_RFDListPtrHi	0x20
+#define STGE_AsicCtrl		0x30
+#define  AC_PhyMedia		(1U << 7)
+#define  AC_GlobalReset		(1U << 16)
+#define  AC_RxReset		(1U << 17)
+#define  AC_TxReset		(1U << 18)
+#define  AC_DMA			(1U << 19) 
+#define  AC_FIFO		(1U << 20)
+#define  AC_Network		(1U << 21)
+#define  AC_Host		(1U << 22)
+#define  AC_AutoInit		(1U << 23)
+#define  AC_RstOut		(1U << 24)
+#define  AC_ResetBusy		(1U << 26)
+#define STGE_EepromData		0x48
+#define STGE_EepromCtrl		0x4a
+#define  EC_EepromAddress(x)	((x) & 0xff)
+#define  EC_EepromOpcode(x)	((x) << 8)
+#define  EC_OP_RR		2
+#define  EC_EepromBusy		(1U << 15)
+#define STGE_IntEnable		0x5c
+#define STGE_MACCtrl		0x6c
+#define  MC_TxEnable		(1U << 24)
+#define  MC_RxEnable		(1U << 27)
+#define STGE_PhyCtrl		0x76
+#define  PC_MgmtClk		(1U << 0)
+#define  PC_MgmtData		(1U << 1)
+#define  PC_MgmtDir		(1U << 2)
+#define  PC_PhyDuplexPolarity	(1U << 3)
+#define  PC_PhyDuplexStatus	(1U << 4)
+#define  PC_PhyLnkPolarity	(1U << 5)
+#define  PC_LinkSpeed(x)	(((x) >> 6) & 3)
+#define  PC_LinkSpeed_Down	0
+#define  PC_LinkSpeed_10	1
+#define  PC_LinkSpeed_100	2
+#define  PC_LinkSpeed_1000	3
+#define STGE_StationAddress0	0x78
+#define STGE_StationAddress1	0x7a
+#define STGE_StationAddress2	0x7c
+
+#define STGE_EEPROM_SA0		0x10
+
+#define MII_PSSR		0x11	/* MAKPHY status register */
+#define  PSSR_DUPLEX		0x2000	/* FDX */
+#define  PSSR_RESOLVED		0x0800	/* speed and duplex resolved */
+#define  PSSR_LINK		0x0400  /* link indication */
+#define  PSSR_SPEED(x)		(((x) >> 14) & 0x3)
+#define  SPEED10		0
+#define  SPEED100		1
+#define  SPEED1000 		2
+
+#define FRAMESIZE	1536
+
+struct local {
+	struct desc txd[2];
+	struct desc rxd[2];
+	uint8_t rxstore[2][FRAMESIZE];
+	unsigned csr, rx, tx, phy;
+	uint16_t bmsr, anlpar;
+	uint8_t phyctrl_saved;
+};
+
+static int mii_read(struct local *, int, int);
+static void mii_write(struct local *, int, int, int);
+static void mii_initphy(struct local *);
+static void mii_dealan(struct local *, unsigned);
+static void mii_bitbang_sync(struct local *);
+static void mii_bitbang_send(struct local *, uint32_t, int);
+static void mii_bitbang_clk(struct local *, uint8_t);
+static int eeprom_wait(struct local *);
+
+int
+stg_match(unsigned tag, void *data)
+{
+	unsigned v;
+
+	v = pcicfgread(tag, PCI_ID_REG);
+	switch (v) {
+	case PCI_DEVICE(0x13f0, 0x1023):	/* ST1023 */
+		return 1;
+	}
+	return 0;
+}
+
+void *
+stg_init(unsigned tag, void *data)
+{
+	struct local *l;
+	struct desc *txd, *rxd;
+	uint8_t *en;
+	unsigned i;
+	uint32_t reg;
+
+	l = ALLOC(struct local, 32);		/* desc alignment */
+	memset(l, 0, sizeof(struct local));
+	l->csr = DEVTOV(pcicfgread(tag, 0x14));	/* first try mem space */
+	if (l->csr == 0)
+		l->csr = DEVTOV(PCI_XIOBASE + (pcicfgread(tag, 0x10) & ~01));
+
+	/* reset the chip */
+	reg = CSR_READ_4(l, STGE_AsicCtrl);
+	CSR_WRITE_4(l, STGE_AsicCtrl, reg | AC_GlobalReset | AC_RxReset |
+	    AC_TxReset | AC_DMA | AC_FIFO | AC_Network | AC_Host |
+	    AC_AutoInit | ((reg & AC_PhyMedia) ? AC_RstOut : 0));
+	DELAY(50000);
+	for (i = 0; i < 1000; i++) {
+		DELAY(5000);
+		if ((CSR_READ_4(l, STGE_AsicCtrl) & AC_ResetBusy) == 0)
+			break;
+	}
+	if (i >= 1000)
+		printf("NIC reset failed to complete!\n");
+	DELAY(1000);
+
+	mii_initphy(l);
+
+	/* read ethernet address */
+	en = data;
+	if (PCI_PRODUCT(pcicfgread(tag, PCI_ID_REG)) != 0x1023) {
+		/* read from station address registers when not ST1023 */
+		en[0] = CSR_READ_2(l, STGE_StationAddress0) & 0xff;
+		en[1] = CSR_READ_2(l, STGE_StationAddress0) >> 8;
+		en[2] = CSR_READ_2(l, STGE_StationAddress1) & 0xff;
+		en[3] = CSR_READ_2(l, STGE_StationAddress1) >> 8;
+		en[4] = CSR_READ_2(l, STGE_StationAddress2) & 0xff;
+		en[5] = CSR_READ_2(l, STGE_StationAddress2) >> 8;
+	} else {
+		/* ST1023: read the address from the serial EEPROM */
+		static uint8_t bad[2][6] = {
+			{ 0x00,0x00,0x00,0x00,0x00,0x00 },
+			{ 0xff,0xff,0xff,0xff,0xff,0xff }
+		};
+		uint16_t addr[3];
+
+		for (i = 0; i < 3; i++) {
+			if (eeprom_wait(l) != 0)
+				printf("NIC: serial EEPROM is not ready!\n");
+			CSR_WRITE_2(l, STGE_EepromCtrl,
+			    EC_EepromAddress(STGE_EEPROM_SA0 + i) |
+			    EC_EepromOpcode(EC_OP_RR));
+			if (eeprom_wait(l) != 0)
+				printf("NIC: serial EEPROM read time out!\n");
+			addr[i] = le16toh(CSR_READ_2(l, STGE_EepromData));
+		}
+		(void)memcpy(en, addr, 6);
+
+		/* try to read MAC from Flash, when EEPROM is empty/missing */
+		if (memcmp(en, bad[0], 6) == 0 || memcmp(en, bad[1], 6) == 0)
+			read_mac_from_flash(en);
+
+		/* set the station address now */
+		for (i = 0; i < 6; i++)
+			CSR_WRITE_1(l, STGE_StationAddress0 + i, en[i]);
+	}
+	printf("MAC address %02x:%02x:%02x:%02x:%02x:%02x\n",
+	    en[0], en[1], en[2], en[3], en[4], en[5]);
+
+	DPRINTF(("PHY %d (%04x.%04x)\n", l->phy,
+	    mii_read(l, l->phy, 2), mii_read(l, l->phy, 3)));
+
+	mii_dealan(l, 5);
+
+	reg = CSR_READ_1(l, STGE_PhyCtrl);
+	switch (PC_LinkSpeed(reg)) {
+	case PC_LinkSpeed_1000:
+		printf("1000Mbps");
+		break;
+	case PC_LinkSpeed_100:
+		printf("100Mbps");
+		break;
+	case PC_LinkSpeed_10:
+		printf("10Mbps");
+		break;
+	}
+	if (reg & PC_PhyDuplexStatus)
+		printf("-FDX");
+	printf("\n");
+
+	/* setup descriptors */
+	txd = &l->txd[0];
+	txd[0].xd0 = htole64(VTOPHYS(&txd[1]));
+	txd[0].xd1 = htole64(DONE);
+	txd[1].xd0 = htole64(VTOPHYS(&txd[0]));
+	txd[1].xd1 = htole64(DONE);
+	rxd = &l->rxd[0];
+	rxd[0].xd0 = htole64(VTOPHYS(&rxd[1]));
+	rxd[0].xd2 = htole64(FRAGADDR(VTOPHYS(l->rxstore[0])) |
+	    FRAGLEN(FRAMESIZE));
+	rxd[1].xd0 = htole64(VTOPHYS(&rxd[0]));
+	rxd[1].xd2 = htole64(FRAGADDR(VTOPHYS(l->rxstore[1])) |
+	    FRAGLEN(FRAMESIZE));
+	wbinv(l, sizeof(struct local));
+
+	CSR_WRITE_2(l, STGE_IntEnable, 0);
+	CSR_WRITE_4(l, STGE_TFDListPtrHi, 0);
+	CSR_WRITE_4(l, STGE_TFDListPtrLo, VTOPHYS(txd));
+	CSR_WRITE_4(l, STGE_RFDListPtrHi, 0);
+	CSR_WRITE_4(l, STGE_RFDListPtrLo, VTOPHYS(rxd));
+	CSR_WRITE_4(l, STGE_MACCtrl, MC_TxEnable | MC_RxEnable);
+#if 0
+	CSR_WRITE_4(l, STGE_DMACtrl, DMAC_RxDMAPollNow | DMAC_TxDMAPollNow);
+#endif
+	return l;
+}
+
+int
+stg_send(void *dev, char *buf, unsigned len)
+{
+	struct local *l = dev;
+	volatile struct desc *txd;
+	unsigned loop;
+
+	wbinv(buf, len);
+	txd = &l->txd[l->tx];
+	txd->xd1 = htole64(DONE);
+	wbinv(txd, sizeof(struct desc));
+	txd->xd2 = htole64(FRAGADDR(VTOPHYS(buf)) | FRAGLEN(len));
+	txd->xd1 = htole64(DONE | TXNOALIGN | 0x400000 | TXFRAGCOUNT(1));
+	txd->xd1 = htole64(TXNOALIGN | 0x400000 | TXFRAGCOUNT(1));
+	wbinv(txd, sizeof(struct desc));
+	CSR_WRITE_4(l, STGE_DMACtrl, DMAC_TxDMAPollNow);	/* XXX ? */
+	loop = 100;
+	do {
+		if ((le64toh(txd->xd1) & DONE) != 0)
+			goto done;
+		DELAY(10);
+		inv(txd, sizeof(struct desc));
+	} while (--loop > 0);
+	printf("xmit failed\n");
+	return -1;
+  done:
+	l->tx ^= 1;
+	return len;
+}
+
+int
+stg_recv(void *dev, char *buf, unsigned maxlen, unsigned timo)
+{
+	struct local *l = dev;
+	volatile struct desc *rxd;
+	uint64_t sts;
+	unsigned bound, len;
+	uint8_t *ptr;
+
+	bound = 1000 * timo;
+  again:
+	rxd = &l->rxd[l->rx];
+	do {
+		inv(rxd, sizeof(struct desc));
+		sts = le64toh(rxd->xd1);
+		if ((sts & DONE) != 0)
+			goto gotone;
+		DELAY(1000);	/* 1 milli second */
+	} while (--bound > 0);
+	errno = 0;
+	return -1;
+  gotone:
+	if ((sts & RXERRORMASK) != 0) {
+		rxd->xd1 = 0;
+		wbinv(rxd, sizeof(struct desc));
+		l->rx ^= 1;
+		goto again;
+	}
+	len = RXLEN(sts);
+	if (len > maxlen)
+		len = maxlen;
+	ptr = l->rxstore[l->rx];
+	inv(ptr, len);
+	memcpy(buf, ptr, len);
+	rxd->xd1 = 0;
+	wbinv(rxd, sizeof(struct desc));
+	l->rx ^= 1;
+	return len;
+}
+
+#define MIICMD_START	1
+#define MIICMD_READ	2
+#define MIICMD_WRITE	1
+#define MIICMD_ACK	2
+
+/* read the MII by bitbanging STGE_PhyCtrl */
+static int
+mii_read(struct local *l, int phy, int reg)
+{
+	int data, i;
+	uint8_t v;
+
+	/* initiate read access */
+	data = 0;
+	mii_bitbang_sync(l);
+	mii_bitbang_send(l, MIICMD_START, 2);
+	mii_bitbang_send(l, MIICMD_READ, 2);
+	mii_bitbang_send(l, phy, 5);
+	mii_bitbang_send(l, reg, 5);
+
+	/* switch direction to PHY->host */
+	v = l->phyctrl_saved;
+	CSR_WRITE_1(l, STGE_PhyCtrl, v);
+	DELAY(1);
+	mii_bitbang_clk(l, v);
+	if (CSR_READ_1(l, STGE_PhyCtrl) & PC_MgmtData)
+		printf("MII: read error\n");
+	mii_bitbang_clk(l, v);
+
+	/* read data */
+	for (i = 0; i < 16; i++) {
+		data <<= 1;
+		if ((CSR_READ_1(l, STGE_PhyCtrl) & PC_MgmtData) != 0)
+			data |= 1;
+		mii_bitbang_clk(l, v);
+	}
+	/* reset direction to host->PHY */
+	CSR_WRITE_1(l, STGE_PhyCtrl, v | PC_MgmtDir);
+	return data;
+}
+
+/* write the MII by bitbanging STGE_PhyCtrl */
+static void
+mii_write(struct local *l, int phy, int reg, int val)
+{
+
+	/* initiate write access */
+	mii_bitbang_sync(l);
+	mii_bitbang_send(l, MIICMD_START, 2);
+	mii_bitbang_send(l, MIICMD_WRITE, 2);
+	mii_bitbang_send(l, phy, 5);
+	mii_bitbang_send(l, reg, 5);
+
+	/* send data */
+	mii_bitbang_send(l, MIICMD_ACK, 2);
+	mii_bitbang_send(l, val, 16);
+
+	CSR_WRITE_1(l, STGE_PhyCtrl, l->phyctrl_saved | PC_MgmtDir);
+}
+
+#define MII_BMCR	0x00	/* Basic mode control register (rw) */
+#define  BMCR_RESET	0x8000	/* reset */
+#define  BMCR_AUTOEN	0x1000	/* autonegotiation enable */
+#define  BMCR_ISO	0x0400	/* isolate */
+#define  BMCR_STARTNEG	0x0200	/* restart autonegotiation */
+#define MII_BMSR	0x01	/* Basic mode status register (ro) */
+#define  BMSR_ACOMP	0x0020	/* Autonegotiation complete */
+#define  BMSR_LINK	0x0004	/* Link status */
+#define MII_ANAR	0x04	/* Autonegotiation advertisement (rw) */
+#define  ANAR_FC	0x0400	/* local device supports PAUSE */
+#define  ANAR_TX_FD	0x0100	/* local device supports 100bTx FD */
+#define  ANAR_TX	0x0080	/* local device supports 100bTx */
+#define  ANAR_10_FD	0x0040	/* local device supports 10bT FD */
+#define  ANAR_10	0x0020	/* local device supports 10bT */
+#define  ANAR_CSMA	0x0001	/* protocol selector CSMA/CD */
+#define MII_ANLPAR	0x05	/* Autonegotiation lnk partner abilities (rw) */
+
+static void
+mii_initphy(struct local *l)
+{
+	int phy, ctl, sts, bound;
+
+	l->phyctrl_saved = CSR_READ_1(l, STGE_PhyCtrl) &
+	    (PC_PhyDuplexPolarity | PC_PhyLnkPolarity);
+
+	for (phy = 0; phy < 32; phy++) {
+		ctl = mii_read(l, phy, MII_BMCR);
+		sts = mii_read(l, phy, MII_BMSR);
+		if (ctl != 0xffff && sts != 0xffff && sts != 0)
+			goto found;
+	}
+	printf("MII: no PHY found\n");
+	return;
+
+  found:
+	ctl = mii_read(l, phy, MII_BMCR);
+	mii_write(l, phy, MII_BMCR, ctl | BMCR_RESET);
+
+	bound = 100;
+	do {
+		DELAY(10);
+		ctl = mii_read(l, phy, MII_BMCR);
+		if (ctl == 0xffff) {
+			printf("MII: PHY %d has died after reset\n", phy);
+			return;
+		}
+	} while (bound-- > 0 && (ctl & BMCR_RESET));
+	if (bound == 0)
+		printf("PHY %d reset failed\n", phy);
+
+	ctl &= ~BMCR_ISO;
+	mii_write(l, phy, MII_BMCR, ctl);
+	sts = mii_read(l, phy, MII_BMSR) |
+	    mii_read(l, phy, MII_BMSR); /* read twice */
+	l->phy = phy;
+	l->bmsr = sts;
+}
+
+static void
+mii_dealan(struct local *l, unsigned timo)
+{
+	unsigned anar, bound;
+
+	anar = ANAR_TX_FD | ANAR_TX | ANAR_10_FD | ANAR_10 | ANAR_CSMA;
+	mii_write(l, l->phy, MII_ANAR, anar);
+	mii_write(l, l->phy, MII_BMCR, BMCR_AUTOEN | BMCR_STARTNEG);
+	l->anlpar = 0;
+	bound = getsecs() + timo;
+	do {
+		l->bmsr = mii_read(l, l->phy, MII_BMSR) |
+		   mii_read(l, l->phy, MII_BMSR); /* read twice */
+		if ((l->bmsr & BMSR_LINK) && (l->bmsr & BMSR_ACOMP)) {
+			l->anlpar = mii_read(l, l->phy, MII_ANLPAR);
+			break;
+		}
+		DELAY(10 * 1000);
+	} while (getsecs() < bound);
+}
+
+static void
+mii_bitbang_sync(struct local *l)
+{
+	int i;
+	uint8_t v;
+
+	v = l->phyctrl_saved | PC_MgmtDir | PC_MgmtData;
+	CSR_WRITE_1(l, STGE_PhyCtrl, v);
+	DELAY(1);
+	for (i = 0; i < 32; i++)
+		mii_bitbang_clk(l, v);
+}
+
+static void
+mii_bitbang_send(struct local *l, uint32_t data, int nbits)
+{
+	uint32_t i;
+	uint8_t v;
+
+	v = l->phyctrl_saved | PC_MgmtDir;
+	CSR_WRITE_1(l, STGE_PhyCtrl, v);
+	DELAY(1);
+	for (i = 1 << (nbits - 1); i != 0; i >>= 1) {
+		if (data & i)
+			v |= PC_MgmtData;
+		else
+			v &= ~PC_MgmtData;
+		CSR_WRITE_1(l, STGE_PhyCtrl, v);
+		DELAY(1);
+		mii_bitbang_clk(l, v);
+	}
+}
+
+static void
+mii_bitbang_clk(struct local *l, uint8_t v)
+{
+
+	CSR_WRITE_1(l, STGE_PhyCtrl, v | PC_MgmtClk);
+	DELAY(1);
+	CSR_WRITE_1(l, STGE_PhyCtrl, v);
+	DELAY(1);
+}
+
+static int
+eeprom_wait(struct local *l)
+{
+	int i;
+
+	for (i = 0; i < 1000; i++) {
+		DELAY(1000);
+		if ((CSR_READ_2(l, STGE_EepromCtrl) & EC_EepromBusy) == 0)
+			return 0;
+	}
+	return 1;
+}

Reply via email to