public inbox for linux-kernel@vger.kernel.org
 help / color / mirror / Atom feed
From: Michael Clark <michael@metaparadigm.com>
To: LKML <linux-kernel@vger.kernel.org>
Cc: Benjamin LaHaise <bcrl@redhat.com>
Subject: [PATCH] - 2.4.16 ns83820 optical support (Netgear GA621)
Date: Tue, 04 Dec 2001 23:35:23 +0800	[thread overview]
Message-ID: <3C0CED3B.7030409@metaparadigm.com> (raw)

[-- Attachment #1: Type: text/plain, Size: 587 bytes --]

Hi,

This patch adds Netgear GA621 support to the ns83820 driver
by adding code to configure the optical transceiver on
these boards. People currently using Netgear driver (gam)
may like to test this.

I decided to add support for GA621 to the ns83820 driver after
suffering an oops with the netgear supplied driver whose code
is rather convoluted on not very Linux like (appears to be a
port of a NDIS driver) ie. it won't probably ever make it into
the kernel without a lot of rework.

It would be good if someone could test this on copper
cards to make sure it still works okay.

~mc

[-- Attachment #2: ns83820-optical.patch --]
[-- Type: text/plain, Size: 6431 bytes --]

--- linux/drivers/net/ns83820.c.orig	Tue Dec  4 20:27:10 2001
+++ linux/drivers/net/ns83820.c	Tue Dec  4 23:33:34 2001
@@ -43,10 +43,12 @@
  *			       otherwise fragments get lost
  *			     - fix >> 32 bugs
  *			0.12 - add statistics counters
  *			     - add allmulti/promisc support
  *	20011009	0.13 - hotplug support, other smaller pci api cleanups
+ *	20011204	0.13a - optical transceiver support added
+ *			        by Michael Clark <michael@metaparadigm.com>
  *
  * Driver Overview
  * ===============
  *
  * This driver was originally written for the National Semiconductor
@@ -63,10 +65,11 @@
  *
  *	Cameo		SOHO-GA2000T	SOHO-GA2500T
  *	D-Link		DGE-500T
  *	PureData	PDP8023Z-TG
  *	SMC		SMC9452TX	SMC9462TX
+ *	Netgear		GA621
  *
  * Special thanks to SMC for providing hardware to test this driver on.
  *
  * Reports of success or failure would be greatly appreciated.
  */
@@ -210,10 +213,11 @@
 #define CFG_SPDSTS	0x60000000
 #define CFG_SPDSTS1	0x40000000
 #define CFG_SPDSTS0	0x20000000
 #define CFG_DUPSTS	0x10000000
 #define CFG_TBI_EN	0x01000000
+#define CFG_AUTO_1000	0x00200000
 #define CFG_MODE_1000	0x00400000
 #define CFG_PINT_CTL	0x001c0000
 #define CFG_PINT_DUPSTS	0x00100000
 #define CFG_PINT_LNKSTS	0x00080000
 #define CFG_PINT_SPDSTS	0x00040000
@@ -314,10 +318,44 @@
 #define VRCR		0xbc
 #define VTCR		0xc0
 #define VDR		0xc4
 #define CCSR		0xcc
 
+#define TBICR		0xe0
+#define TBISR		0xe4
+#define TANAR		0xe8
+#define TANLPAR		0xec
+#define TANER		0xf0
+#define TESR		0xf4
+
+/* TBICR bit definitions */
+
+#define MR_AN_ENABLE 		0x00001000
+#define MR_RESTART_AN 		0x00000200
+
+/* TBISR bit definitions */
+
+#define MR_LINK_STATUS 		0x00000020
+#define MR_AN_COMPLETE 		0x00000004
+
+/* TANAR, TANALPAR bit definitions */
+
+#define PS2 			0x00000100
+#define PS1 			0x00000080
+#define HALF_DUP 		0x00000040
+#define FULL_DUP 		0x00000020
+
+/* GPIOR bit definitions */
+
+#define GP5_OE			0x00000200
+#define GP4_OE			0x00000100
+#define GP3_OE			0x00000080
+#define GP2_OE			0x00000040
+#define GP1_OE			0x00000020
+#define GP3_OUT			0x00000004
+#define GP1_OUT			0x00000001
+
 #define __kick_rx(dev)	writel(CR_RXE, dev->base + CR)
 
 #define kick_rx(dev) do { \
 	dprintk("kick_rx: maybe kicking\n"); \
 	if (test_and_clear_bit(0, &dev->rx_info.idle)) { \
@@ -543,28 +581,82 @@
 	build_rx_desc(dev, dev->rx_info.descs + (DESC_SIZE * i), 0, 0, CMDSTS_OWN, 0);
 }
 
 static void phy_intr(struct ns83820 *dev)
 {
-	static char *speeds[] = { "10", "100", "1000", "1000(?)" };
+	static char *speeds[] = { "10", "100", "1000", "1000(?)", "1000F" };
 	u32 cfg, new_cfg;
+	u32 tbisr, tanar, tanlpar;
+	int speed, fullduplex = 0;
 
-	new_cfg = dev->CFG_cache & ~(CFG_SB | CFG_MODE_1000 | CFG_SPDSTS);
 	cfg = readl(dev->base + CFG) ^ SPDSTS_POLARITY;
 
-	if (cfg & CFG_SPDSTS1)
-		new_cfg |= CFG_MODE_1000 | CFG_SB;
-	else
-		new_cfg &= ~CFG_MODE_1000 | CFG_SB;
+	if (dev->CFG_cache & CFG_TBI_EN) {
 
-	if ((cfg & CFG_LNKSTS) && ((new_cfg ^ dev->CFG_cache) & CFG_MODE_1000)) {
-		writel(new_cfg, dev->base + CFG);
-		dev->CFG_cache = new_cfg;
-	}
+		/* we have an optical transceiver */
+		tbisr = readl(dev->base + TBISR);
+		tanar = readl(dev->base + TANAR);
+		tanlpar = readl(dev->base + TANLPAR);
+		dprintk("phy_intr: tbisr=%08x, tanar=%08x, tanlpar=%08x\n",
+			tbisr, tanar, tanlpar);
+
+		if (!tanlpar && !tbisr) {
+			dprintk("%s: waiting for autoneg to complete\n",
+				dev->net_dev.name);
+			return;
+		}
+
+		if ( (fullduplex = (tanlpar & FULL_DUP)
+		      && (tanar & FULL_DUP)) ) {
 
-	dev->CFG_cache &= ~CFG_SPDSTS;
-	dev->CFG_cache |= cfg & CFG_SPDSTS;
+			/* both of us are full duplex */
+			writel(readl(dev->base + TXCFG)
+			       | TXCFG_CSI | TXCFG_HBI | TXCFG_ATP,
+			       dev->base + TXCFG);
+			writel(readl(dev->base + RXCFG) | RXCFG_RX_FD,
+			       dev->base + RXCFG);
+			/* Light up full duplex LED */
+			writel(readl(dev->base + GPIOR) | GP1_OUT,
+			       dev->base + GPIOR);
+
+		} else if(((tanlpar & HALF_DUP) && (tanar & HALF_DUP))
+			|| ((tanlpar & FULL_DUP) && (tanar & HALF_DUP))
+			|| ((tanlpar & HALF_DUP) && (tanar & FULL_DUP))) {
+
+			/* one or both of us are half duplex */
+			writel((readl(dev->base + TXCFG)
+				& ~(TXCFG_CSI | TXCFG_HBI)) | TXCFG_ATP,
+			       dev->base + TXCFG);
+			writel(readl(dev->base + RXCFG) & ~RXCFG_RX_FD,
+			       dev->base + RXCFG);
+			/* Turn off full duplex LED */
+			writel(readl(dev->base + GPIOR) & ~GP1_OUT,
+			       dev->base + GPIOR);
+		}
+
+		speed = 4; /* 1000F */
+
+	} else {
+		/* we have a copper transceiver */
+		new_cfg = dev->CFG_cache & ~(CFG_SB | CFG_MODE_1000 | CFG_SPDSTS);
+
+		if (cfg & CFG_SPDSTS1)
+			new_cfg |= CFG_MODE_1000 | CFG_SB;
+		else
+			new_cfg &= ~CFG_MODE_1000 | CFG_SB;
+
+		if ((cfg & CFG_LNKSTS) && ((new_cfg ^ dev->CFG_cache) & CFG_MODE_1000)) {
+			writel(new_cfg, dev->base + CFG);
+			dev->CFG_cache = new_cfg;
+		}
+
+		dev->CFG_cache &= ~CFG_SPDSTS;
+		dev->CFG_cache |= cfg & CFG_SPDSTS;
+
+		speed = ((cfg / CFG_SPDSTS0) & 3);
+		fullduplex = (cfg & CFG_DUPSTS);
+	}
 
 	if (cfg & CFG_LNKSTS) {
 		netif_start_queue(&dev->net_dev);
 		netif_wake_queue(&dev->net_dev);
 	} else {
@@ -572,12 +664,12 @@
 	}
 
 	if (cfg & CFG_LNKSTS)
 		printk(KERN_INFO "%s: link now %s mbps, %s duplex and up.\n",
 			dev->net_dev.name,
-			speeds[((cfg / CFG_SPDSTS0) & 3)],
-			(cfg & CFG_DUPSTS) ? "full" : "half");
+			speeds[speed],
+			fullduplex ? "full" : "half");
 	else
 		printk(KERN_INFO "%s: link now down.\n", dev->net_dev.name);
 }
 
 static int ns83820_setup_rx(struct ns83820 *dev)
@@ -1341,10 +1433,27 @@
 	dev->CFG_cache |= CFG_BEM;
 #else
 #error This driver only works for big or little endian!!!
 #endif
 
+	/* setup optical transceiver if we have one */
+	if(dev->CFG_cache & CFG_TBI_EN) {
+		printk("%s: enabling optical transceiver\n",
+		       dev->net_dev.name);
+		writel(readl(dev->base + GPIOR) | 0x3e8, dev->base + GPIOR);
+
+		/* setup auto negotiation feature advertisement */
+		writel(readl(dev->base + TANAR) | HALF_DUP | FULL_DUP,
+		       dev->base + TANAR);
+
+		/* start auto negotiation */
+		writel(MR_AN_ENABLE | MR_RESTART_AN, dev->base + TBICR);
+		writel(MR_AN_ENABLE, dev->base + TBICR);
+
+		dev->CFG_cache |= CFG_MODE_1000;
+	}
+
 	writel(dev->CFG_cache, dev->base + CFG);
 	dprintk("CFG: %08x\n", dev->CFG_cache);
 
 	if (readl(dev->base + SRR))
 		writel(readl(dev->base+0x20c) | 0xfe00, dev->base + 0x20c);

             reply	other threads:[~2001-12-04 15:36 UTC|newest]

Thread overview: 9+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2001-12-04 15:35 Michael Clark [this message]
2001-12-04 21:24 ` [PATCH] - 2.4.16 ns83820 optical support (Netgear GA621) Rob Myers
2001-12-04 21:31   ` Jeff Garzik
2001-12-05  1:48   ` Michael Clark
2001-12-05  5:02     ` Michael Clark
2001-12-05 12:55     ` Jeff Garzik
2001-12-05 14:37       ` Michael Clark
2001-12-05 16:56         ` Rob Myers
2001-12-05 22:50     ` Benjamin LaHaise

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=3C0CED3B.7030409@metaparadigm.com \
    --to=michael@metaparadigm.com \
    --cc=bcrl@redhat.com \
    --cc=linux-kernel@vger.kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox