11da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
23396c7823efb3a5b8630388c464e1034ea031cedPaul Gortmaker	drivers/net/ethernet/dec/tulip/media.c
31da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
41da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	Copyright 2000,2001  The Linux Kernel Team
51da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	Written/copyright 1994-2001 by Donald Becker.
61da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
71da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	This software may be used and distributed according to the terms
81da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	of the GNU General Public License, incorporated herein by reference.
91da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1078a655181409d9d0f2b730ccb897c18794826495Grant Grundler	Please submit bugs to http://bugzilla.kernel.org/ .
111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds*/
121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/kernel.h>
141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/mii.h>
151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/init.h>
161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/delay.h>
171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/pci.h>
181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include "tulip.h"
191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* The maximum data clock rate is 2.5 Mhz.  The minimum timing is usually
221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   met by back-to-back PCI I/O cycles, but we insert a delay to avoid
231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   "overclocking" issues or future 66Mhz PCI. */
241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define mdio_delay() ioread32(mdio_addr)
251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Read and write the MII registers using software-generated serial
271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   MDIO protocol.  It is just different enough from the EEPROM protocol
281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   to not share code.  The maxium data clock rate is 2.5 Mhz. */
291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define MDIO_SHIFT_CLK		0x10000
301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define MDIO_DATA_WRITE0	0x00000
311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define MDIO_DATA_WRITE1	0x20000
321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define MDIO_ENB		0x00000 /* Ignore the 0x02000 databook setting. */
331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define MDIO_ENB_IN		0x40000
341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define MDIO_DATA_READ		0x80000
351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic const unsigned char comet_miireg2offset[32] = {
371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	0xB4, 0xB8, 0xBC, 0xC0,  0xC4, 0xC8, 0xCC, 0,  0,0,0,0,  0,0,0,0,
381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	0,0xD0,0,0,  0,0,0,0,  0,0,0,0, 0, 0xD4, 0xD8, 0xDC, };
391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* MII transceiver control section.
421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   Read and write the MII registers using software-generated serial
43b3bff39a2b3574542f5007e19038393dfdd64c85Valerie Henson   MDIO protocol.
44b3bff39a2b3574542f5007e19038393dfdd64c85Valerie Henson   See IEEE 802.3-2002.pdf (Section 2, Chapter "22.2.4 Management functions")
45b3bff39a2b3574542f5007e19038393dfdd64c85Valerie Henson   or DP83840A data sheet for more details.
46b3bff39a2b3574542f5007e19038393dfdd64c85Valerie Henson   */
471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint tulip_mdio_read(struct net_device *dev, int phy_id, int location)
491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct tulip_private *tp = netdev_priv(dev);
511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int i;
521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int read_cmd = (0xf6 << 10) | ((phy_id & 0x1f) << 5) | location;
531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int retval = 0;
541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	void __iomem *ioaddr = tp->base_addr;
551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	void __iomem *mdio_addr = ioaddr + CSR9;
561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long flags;
571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (location & ~0x1f)
591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return 0xffff;
601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (tp->chip_id == COMET  &&  phy_id == 30) {
621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (comet_miireg2offset[location])
631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return ioread32(ioaddr + comet_miireg2offset[location]);
641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return 0xffff;
651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_lock_irqsave(&tp->mii_lock, flags);
681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (tp->chip_id == LC82C168) {
691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		iowrite32(0x60020000 + (phy_id<<23) + (location<<18), ioaddr + 0xA0);
701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ioread32(ioaddr + 0xA0);
711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ioread32(ioaddr + 0xA0);
72de2f19daac017301b0bfd73bdecff89e7ea30eb7Hannes Eder		for (i = 1000; i >= 0; --i) {
731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			barrier();
741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if ( ! ((retval = ioread32(ioaddr + 0xA0)) & 0x80000000))
751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				break;
761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		spin_unlock_irqrestore(&tp->mii_lock, flags);
781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return retval & 0xffff;
791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Establish sync by sending at least 32 logic ones. */
821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (i = 32; i >= 0; i--) {
831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		iowrite32(MDIO_ENB | MDIO_DATA_WRITE1, mdio_addr);
841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		mdio_delay();
851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		iowrite32(MDIO_ENB | MDIO_DATA_WRITE1 | MDIO_SHIFT_CLK, mdio_addr);
861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		mdio_delay();
871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Shift the read command bits out. */
891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (i = 15; i >= 0; i--) {
901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		int dataval = (read_cmd & (1 << i)) ? MDIO_DATA_WRITE1 : 0;
911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		iowrite32(MDIO_ENB | dataval, mdio_addr);
931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		mdio_delay();
941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		iowrite32(MDIO_ENB | dataval | MDIO_SHIFT_CLK, mdio_addr);
951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		mdio_delay();
961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Read the two transition, 16 data, and wire-idle bits. */
981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (i = 19; i > 0; i--) {
991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		iowrite32(MDIO_ENB_IN, mdio_addr);
1001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		mdio_delay();
1011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		retval = (retval << 1) | ((ioread32(mdio_addr) & MDIO_DATA_READ) ? 1 : 0);
1021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		iowrite32(MDIO_ENB_IN | MDIO_SHIFT_CLK, mdio_addr);
1031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		mdio_delay();
1041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_unlock_irqrestore(&tp->mii_lock, flags);
1071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return (retval>>1) & 0xffff;
1081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid tulip_mdio_write(struct net_device *dev, int phy_id, int location, int val)
1111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct tulip_private *tp = netdev_priv(dev);
1131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int i;
1141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int cmd = (0x5002 << 16) | ((phy_id & 0x1f) << 23) | (location<<18) | (val & 0xffff);
1151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	void __iomem *ioaddr = tp->base_addr;
1161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	void __iomem *mdio_addr = ioaddr + CSR9;
1171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long flags;
1181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (location & ~0x1f)
1201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return;
1211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (tp->chip_id == COMET && phy_id == 30) {
1231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (comet_miireg2offset[location])
1241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			iowrite32(val, ioaddr + comet_miireg2offset[location]);
1251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return;
1261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_lock_irqsave(&tp->mii_lock, flags);
1291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (tp->chip_id == LC82C168) {
1301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		iowrite32(cmd, ioaddr + 0xA0);
131de2f19daac017301b0bfd73bdecff89e7ea30eb7Hannes Eder		for (i = 1000; i >= 0; --i) {
1321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			barrier();
1331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if ( ! (ioread32(ioaddr + 0xA0) & 0x80000000))
1341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				break;
135de2f19daac017301b0bfd73bdecff89e7ea30eb7Hannes Eder		}
1361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		spin_unlock_irqrestore(&tp->mii_lock, flags);
1371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return;
1381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
139f3b197ac26ed0e57989856494c495818dcc7f9acJeff Garzik
1401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Establish sync by sending 32 logic ones. */
1411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (i = 32; i >= 0; i--) {
1421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		iowrite32(MDIO_ENB | MDIO_DATA_WRITE1, mdio_addr);
1431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		mdio_delay();
1441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		iowrite32(MDIO_ENB | MDIO_DATA_WRITE1 | MDIO_SHIFT_CLK, mdio_addr);
1451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		mdio_delay();
1461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Shift the command bits out. */
1481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (i = 31; i >= 0; i--) {
1491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		int dataval = (cmd & (1 << i)) ? MDIO_DATA_WRITE1 : 0;
1501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		iowrite32(MDIO_ENB | dataval, mdio_addr);
1511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		mdio_delay();
1521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		iowrite32(MDIO_ENB | dataval | MDIO_SHIFT_CLK, mdio_addr);
1531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		mdio_delay();
1541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Clear out extra bits. */
1561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (i = 2; i > 0; i--) {
1571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		iowrite32(MDIO_ENB_IN, mdio_addr);
1581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		mdio_delay();
1591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		iowrite32(MDIO_ENB_IN | MDIO_SHIFT_CLK, mdio_addr);
1601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		mdio_delay();
1611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_unlock_irqrestore(&tp->mii_lock, flags);
1641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Set up the transceiver control registers for the selected media type. */
1681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid tulip_select_media(struct net_device *dev, int startup)
1691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct tulip_private *tp = netdev_priv(dev);
1711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	void __iomem *ioaddr = tp->base_addr;
1721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct mediatable *mtable = tp->mtable;
1731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u32 new_csr6;
1741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int i;
1751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (mtable) {
1771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		struct medialeaf *mleaf = &mtable->mleaf[tp->cur_index];
1781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		unsigned char *p = mleaf->leafdata;
1791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		switch (mleaf->type) {
1801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case 0:					/* 21140 non-MII xcvr. */
1811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (tulip_debug > 1)
182726b65ad444dd142e34d0087fcbba03d16b34ca6Joe Perches				netdev_dbg(dev, "Using a 21140 non-MII transceiver with control setting %02x\n",
183726b65ad444dd142e34d0087fcbba03d16b34ca6Joe Perches					   p[1]);
1841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			dev->if_port = p[0];
1851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (startup)
1861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				iowrite32(mtable->csr12dir | 0x100, ioaddr + CSR12);
1871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			iowrite32(p[1], ioaddr + CSR12);
1881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			new_csr6 = 0x02000000 | ((p[2] & 0x71) << 18);
1891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
1901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case 2: case 4: {
1911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			u16 setup[5];
1921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			u32 csr13val, csr14val, csr15dir, csr15val;
1931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			for (i = 0; i < 5; i++)
1941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				setup[i] = get_u16(&p[i*2 + 1]);
1951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			dev->if_port = p[0] & MEDIA_MASK;
1971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (tulip_media_cap[dev->if_port] & MediaAlwaysFD)
1981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				tp->full_duplex = 1;
1991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (startup && mtable->has_reset) {
2011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				struct medialeaf *rleaf = &mtable->mleaf[mtable->has_reset];
2021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				unsigned char *rst = rleaf->leafdata;
2031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				if (tulip_debug > 1)
204726b65ad444dd142e34d0087fcbba03d16b34ca6Joe Perches					netdev_dbg(dev, "Resetting the transceiver\n");
2051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				for (i = 0; i < rst[0]; i++)
2061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					iowrite32(get_u16(rst + 1 + (i<<1)) << 16, ioaddr + CSR15);
2071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
2081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (tulip_debug > 1)
209726b65ad444dd142e34d0087fcbba03d16b34ca6Joe Perches				netdev_dbg(dev, "21143 non-MII %s transceiver control %04x/%04x\n",
210726b65ad444dd142e34d0087fcbba03d16b34ca6Joe Perches					   medianame[dev->if_port],
211726b65ad444dd142e34d0087fcbba03d16b34ca6Joe Perches					   setup[0], setup[1]);
2121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (p[0] & 0x40) {	/* SIA (CSR13-15) setup values are provided. */
2131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				csr13val = setup[0];
2141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				csr14val = setup[1];
2151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				csr15dir = (setup[3]<<16) | setup[2];
2161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				csr15val = (setup[4]<<16) | setup[2];
2171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				iowrite32(0, ioaddr + CSR13);
2181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				iowrite32(csr14val, ioaddr + CSR14);
2191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				iowrite32(csr15dir, ioaddr + CSR15);	/* Direction */
2201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				iowrite32(csr15val, ioaddr + CSR15);	/* Data */
2211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				iowrite32(csr13val, ioaddr + CSR13);
2221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			} else {
2231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				csr13val = 1;
2241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				csr14val = 0;
2251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				csr15dir = (setup[0]<<16) | 0x0008;
2261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				csr15val = (setup[1]<<16) | 0x0008;
2271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				if (dev->if_port <= 4)
2281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					csr14val = t21142_csr14[dev->if_port];
2291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				if (startup) {
2301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					iowrite32(0, ioaddr + CSR13);
2311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					iowrite32(csr14val, ioaddr + CSR14);
2321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				}
2331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				iowrite32(csr15dir, ioaddr + CSR15);	/* Direction */
2341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				iowrite32(csr15val, ioaddr + CSR15);	/* Data */
2351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				if (startup) iowrite32(csr13val, ioaddr + CSR13);
2361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
2371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (tulip_debug > 1)
238726b65ad444dd142e34d0087fcbba03d16b34ca6Joe Perches				netdev_dbg(dev, "Setting CSR15 to %08x/%08x\n",
239726b65ad444dd142e34d0087fcbba03d16b34ca6Joe Perches					   csr15dir, csr15val);
2401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (mleaf->type == 4)
2411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				new_csr6 = 0x82020000 | ((setup[2] & 0x71) << 18);
2421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			else
2431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				new_csr6 = 0x82420000;
2441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
2451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
2461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case 1: case 3: {
2471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			int phy_num = p[0];
2481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			int init_length = p[1];
2491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			u16 *misc_info, tmp_info;
2501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			dev->if_port = 11;
2521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			new_csr6 = 0x020E0000;
2531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (mleaf->type == 3) {	/* 21142 */
2541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				u16 *init_sequence = (u16*)(p+2);
2551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				u16 *reset_sequence = &((u16*)(p+3))[init_length];
2561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				int reset_length = p[2 + init_length*2];
2571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				misc_info = reset_sequence + reset_length;
258eb117b1786804f2e128b871879ffe8f6a2701378Thibaut VARENE				if (startup) {
259eb117b1786804f2e128b871879ffe8f6a2701378Thibaut VARENE					int timeout = 10;	/* max 1 ms */
2601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					for (i = 0; i < reset_length; i++)
2611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						iowrite32(get_u16(&reset_sequence[i]) << 16, ioaddr + CSR15);
262eb117b1786804f2e128b871879ffe8f6a2701378Thibaut VARENE
263eb117b1786804f2e128b871879ffe8f6a2701378Thibaut VARENE					/* flush posted writes */
264eb117b1786804f2e128b871879ffe8f6a2701378Thibaut VARENE					ioread32(ioaddr + CSR15);
265eb117b1786804f2e128b871879ffe8f6a2701378Thibaut VARENE
266eb117b1786804f2e128b871879ffe8f6a2701378Thibaut VARENE					/* Sect 3.10.3 in DP83840A.pdf (p39) */
267eb117b1786804f2e128b871879ffe8f6a2701378Thibaut VARENE					udelay(500);
268eb117b1786804f2e128b871879ffe8f6a2701378Thibaut VARENE
269eb117b1786804f2e128b871879ffe8f6a2701378Thibaut VARENE					/* Section 4.2 in DP83840A.pdf (p43) */
270eb117b1786804f2e128b871879ffe8f6a2701378Thibaut VARENE					/* and IEEE 802.3 "22.2.4.1.1 Reset" */
271eb117b1786804f2e128b871879ffe8f6a2701378Thibaut VARENE					while (timeout-- &&
272eb117b1786804f2e128b871879ffe8f6a2701378Thibaut VARENE						(tulip_mdio_read (dev, phy_num, MII_BMCR) & BMCR_RESET))
273eb117b1786804f2e128b871879ffe8f6a2701378Thibaut VARENE						udelay(100);
274eb117b1786804f2e128b871879ffe8f6a2701378Thibaut VARENE				}
2751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				for (i = 0; i < init_length; i++)
2761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					iowrite32(get_u16(&init_sequence[i]) << 16, ioaddr + CSR15);
277eb117b1786804f2e128b871879ffe8f6a2701378Thibaut VARENE
278eb117b1786804f2e128b871879ffe8f6a2701378Thibaut VARENE				ioread32(ioaddr + CSR15);	/* flush posted writes */
2791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			} else {
2801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				u8 *init_sequence = p + 2;
2811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				u8 *reset_sequence = p + 3 + init_length;
2821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				int reset_length = p[2 + init_length];
2831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				misc_info = (u16*)(reset_sequence + reset_length);
2841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				if (startup) {
285b3bff39a2b3574542f5007e19038393dfdd64c85Valerie Henson					int timeout = 10;	/* max 1 ms */
2861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					iowrite32(mtable->csr12dir | 0x100, ioaddr + CSR12);
2871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					for (i = 0; i < reset_length; i++)
2881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						iowrite32(reset_sequence[i], ioaddr + CSR12);
289b3bff39a2b3574542f5007e19038393dfdd64c85Valerie Henson
290b3bff39a2b3574542f5007e19038393dfdd64c85Valerie Henson					/* flush posted writes */
291b3bff39a2b3574542f5007e19038393dfdd64c85Valerie Henson					ioread32(ioaddr + CSR12);
292b3bff39a2b3574542f5007e19038393dfdd64c85Valerie Henson
293b3bff39a2b3574542f5007e19038393dfdd64c85Valerie Henson					/* Sect 3.10.3 in DP83840A.pdf (p39) */
294b3bff39a2b3574542f5007e19038393dfdd64c85Valerie Henson					udelay(500);
295b3bff39a2b3574542f5007e19038393dfdd64c85Valerie Henson
296b3bff39a2b3574542f5007e19038393dfdd64c85Valerie Henson					/* Section 4.2 in DP83840A.pdf (p43) */
297b3bff39a2b3574542f5007e19038393dfdd64c85Valerie Henson					/* and IEEE 802.3 "22.2.4.1.1 Reset" */
298b3bff39a2b3574542f5007e19038393dfdd64c85Valerie Henson					while (timeout-- &&
299b3bff39a2b3574542f5007e19038393dfdd64c85Valerie Henson						(tulip_mdio_read (dev, phy_num, MII_BMCR) & BMCR_RESET))
300b3bff39a2b3574542f5007e19038393dfdd64c85Valerie Henson						udelay(100);
3011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				}
3021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				for (i = 0; i < init_length; i++)
3031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					iowrite32(init_sequence[i], ioaddr + CSR12);
304b3bff39a2b3574542f5007e19038393dfdd64c85Valerie Henson
305b3bff39a2b3574542f5007e19038393dfdd64c85Valerie Henson				ioread32(ioaddr + CSR12);	/* flush posted writes */
3061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
307b3bff39a2b3574542f5007e19038393dfdd64c85Valerie Henson
3081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			tmp_info = get_u16(&misc_info[1]);
3091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (tmp_info)
3101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				tp->advertising[phy_num] = tmp_info | 1;
3111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (tmp_info && startup < 2) {
3121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				if (tp->mii_advertise == 0)
3131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					tp->mii_advertise = tp->advertising[phy_num];
3141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				if (tulip_debug > 1)
315726b65ad444dd142e34d0087fcbba03d16b34ca6Joe Perches					netdev_dbg(dev, " Advertising %04x on MII %d\n",
316726b65ad444dd142e34d0087fcbba03d16b34ca6Joe Perches						   tp->mii_advertise,
317726b65ad444dd142e34d0087fcbba03d16b34ca6Joe Perches						   tp->phys[phy_num]);
3181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				tulip_mdio_write(dev, tp->phys[phy_num], 4, tp->mii_advertise);
3191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
3201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
3211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
3221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case 5: case 6: {
3231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			u16 setup[5];
3241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			new_csr6 = 0; /* FIXME */
3261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			for (i = 0; i < 5; i++)
3281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				setup[i] = get_u16(&p[i*2 + 1]);
3291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (startup && mtable->has_reset) {
3311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				struct medialeaf *rleaf = &mtable->mleaf[mtable->has_reset];
3321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				unsigned char *rst = rleaf->leafdata;
3331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				if (tulip_debug > 1)
334726b65ad444dd142e34d0087fcbba03d16b34ca6Joe Perches					netdev_dbg(dev, "Resetting the transceiver\n");
3351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				for (i = 0; i < rst[0]; i++)
3361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					iowrite32(get_u16(rst + 1 + (i<<1)) << 16, ioaddr + CSR15);
3371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
3381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
3401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
3411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		default:
342726b65ad444dd142e34d0087fcbba03d16b34ca6Joe Perches			netdev_dbg(dev, " Invalid media table selection %d\n",
343726b65ad444dd142e34d0087fcbba03d16b34ca6Joe Perches				   mleaf->type);
3441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			new_csr6 = 0x020E0000;
3451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
3461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (tulip_debug > 1)
347726b65ad444dd142e34d0087fcbba03d16b34ca6Joe Perches			netdev_dbg(dev, "Using media type %s, CSR12 is %02x\n",
348726b65ad444dd142e34d0087fcbba03d16b34ca6Joe Perches				   medianame[dev->if_port],
3491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				   ioread32(ioaddr + CSR12) & 0xff);
3501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else if (tp->chip_id == LC82C168) {
3511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (startup && ! tp->medialock)
3521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			dev->if_port = tp->mii_cnt ? 11 : 0;
3531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (tulip_debug > 1)
354726b65ad444dd142e34d0087fcbba03d16b34ca6Joe Perches			netdev_dbg(dev, "PNIC PHY status is %3.3x, media %s\n",
355726b65ad444dd142e34d0087fcbba03d16b34ca6Joe Perches				   ioread32(ioaddr + 0xB8),
356726b65ad444dd142e34d0087fcbba03d16b34ca6Joe Perches				   medianame[dev->if_port]);
3571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (tp->mii_cnt) {
3581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			new_csr6 = 0x810C0000;
3591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			iowrite32(0x0001, ioaddr + CSR15);
3601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			iowrite32(0x0201B07A, ioaddr + 0xB8);
3611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		} else if (startup) {
3621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* Start with 10mbps to do autonegotiation. */
3631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			iowrite32(0x32, ioaddr + CSR12);
3641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			new_csr6 = 0x00420000;
3651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			iowrite32(0x0001B078, ioaddr + 0xB8);
3661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			iowrite32(0x0201B078, ioaddr + 0xB8);
3671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		} else if (dev->if_port == 3  ||  dev->if_port == 5) {
3681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			iowrite32(0x33, ioaddr + CSR12);
3691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			new_csr6 = 0x01860000;
3701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* Trigger autonegotiation. */
3711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			iowrite32(startup ? 0x0201F868 : 0x0001F868, ioaddr + 0xB8);
3721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		} else {
3731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			iowrite32(0x32, ioaddr + CSR12);
3741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			new_csr6 = 0x00420000;
3751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			iowrite32(0x1F078, ioaddr + 0xB8);
3761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
3771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else {					/* Unknown chip type with no media table. */
3781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (tp->default_port == 0)
3791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			dev->if_port = tp->mii_cnt ? 11 : 3;
3801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (tulip_media_cap[dev->if_port] & MediaIsMII) {
3811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			new_csr6 = 0x020E0000;
3821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		} else if (tulip_media_cap[dev->if_port] & MediaIsFx) {
3831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			new_csr6 = 0x02860000;
3841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		} else
3851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			new_csr6 = 0x03860000;
3861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (tulip_debug > 1)
387726b65ad444dd142e34d0087fcbba03d16b34ca6Joe Perches			netdev_dbg(dev, "No media description table, assuming %s transceiver, CSR12 %02x\n",
388726b65ad444dd142e34d0087fcbba03d16b34ca6Joe Perches				   medianame[dev->if_port],
389726b65ad444dd142e34d0087fcbba03d16b34ca6Joe Perches				   ioread32(ioaddr + CSR12));
3901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
3911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	tp->csr6 = new_csr6 | (tp->csr6 & 0xfdff) | (tp->full_duplex ? 0x0200 : 0);
39312755c16a9e4fa2fd5b0ca1963e83d671a6251daRalf Baechle
39412755c16a9e4fa2fd5b0ca1963e83d671a6251daRalf Baechle	mdelay(1);
3951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
3961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
3981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds  Check the MII negotiated duplex and change the CSR6 setting if
3991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds  required.
4001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds  Return 0 if everything is OK.
4011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds  Return < 0 if the transceiver is missing or has no link beat.
4021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds  */
4031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint tulip_check_duplex(struct net_device *dev)
4041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
4051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct tulip_private *tp = netdev_priv(dev);
4061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned int bmsr, lpa, negotiated, new_csr6;
4071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	bmsr = tulip_mdio_read(dev, tp->phys[0], MII_BMSR);
4091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	lpa = tulip_mdio_read(dev, tp->phys[0], MII_LPA);
4101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (tulip_debug > 1)
411fa0b9a4c41490d550ebd3bd418f4551c989fec5dJoe Perches		dev_info(&dev->dev, "MII status %04x, Link partner report %04x\n",
412fa0b9a4c41490d550ebd3bd418f4551c989fec5dJoe Perches			 bmsr, lpa);
4131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (bmsr == 0xffff)
4141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -2;
4151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if ((bmsr & BMSR_LSTATUS) == 0) {
4161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		int new_bmsr = tulip_mdio_read(dev, tp->phys[0], MII_BMSR);
4171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if ((new_bmsr & BMSR_LSTATUS) == 0) {
4181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (tulip_debug  > 1)
419fa0b9a4c41490d550ebd3bd418f4551c989fec5dJoe Perches				dev_info(&dev->dev,
420fa0b9a4c41490d550ebd3bd418f4551c989fec5dJoe Perches					 "No link beat on the MII interface, status %04x\n",
421fa0b9a4c41490d550ebd3bd418f4551c989fec5dJoe Perches					 new_bmsr);
4221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return -1;
4231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
4241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
4251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	negotiated = lpa & tp->advertising[0];
4261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	tp->full_duplex = mii_duplex(tp->full_duplex_lock, negotiated);
4271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	new_csr6 = tp->csr6;
4291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (negotiated & LPA_100) new_csr6 &= ~TxThreshold;
4311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	else			  new_csr6 |= TxThreshold;
4321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (tp->full_duplex) new_csr6 |= FullDuplex;
4331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	else		     new_csr6 &= ~FullDuplex;
4341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (new_csr6 != tp->csr6) {
4361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		tp->csr6 = new_csr6;
4371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		tulip_restart_rxtx(tp);
4381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (tulip_debug > 0)
440fa0b9a4c41490d550ebd3bd418f4551c989fec5dJoe Perches			dev_info(&dev->dev,
441fa0b9a4c41490d550ebd3bd418f4551c989fec5dJoe Perches				 "Setting %s-duplex based on MII#%d link partner capability of %04x\n",
442fa0b9a4c41490d550ebd3bd418f4551c989fec5dJoe Perches				 tp->full_duplex ? "full" : "half",
443fa0b9a4c41490d550ebd3bd418f4551c989fec5dJoe Perches				 tp->phys[0], lpa);
4441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return 1;
4451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
4461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
4481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
4491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid __devinit tulip_find_mii (struct net_device *dev, int board_idx)
4511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
4521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct tulip_private *tp = netdev_priv(dev);
4531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int phyn, phy_idx = 0;
4541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int mii_reg0;
4551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int mii_advert;
4561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned int to_advert, new_bmcr, ane_switch;
4571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Find the connected MII xcvrs.
4591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	   Doing this in open() would allow detecting external xcvrs later,
4601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	   but takes much time. */
4611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (phyn = 1; phyn <= 32 && phy_idx < sizeof (tp->phys); phyn++) {
4621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		int phy = phyn & 0x1f;
4631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		int mii_status = tulip_mdio_read (dev, phy, MII_BMSR);
4641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if ((mii_status & 0x8301) == 0x8001 ||
4658e95a2026f3b43f7c3d676adaccd2de9532e8dccJoe Perches		    ((mii_status & BMSR_100BASE4) == 0 &&
4668e95a2026f3b43f7c3d676adaccd2de9532e8dccJoe Perches		     (mii_status & 0x7800) != 0)) {
4671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* preserve Becker logic, gain indentation level */
4681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		} else {
4691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			continue;
4701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
4711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		mii_reg0 = tulip_mdio_read (dev, phy, MII_BMCR);
4731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		mii_advert = tulip_mdio_read (dev, phy, MII_ADVERTISE);
4741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ane_switch = 0;
4751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* if not advertising at all, gen an
4771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * advertising value from the capability
4781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * bits in BMSR
4791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 */
4801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if ((mii_advert & ADVERTISE_ALL) == 0) {
4811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			unsigned int tmpadv = tulip_mdio_read (dev, phy, MII_BMSR);
4821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			mii_advert = ((tmpadv >> 6) & 0x3e0) | 1;
4831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
4841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (tp->mii_advertise) {
4861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			tp->advertising[phy_idx] =
4871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			to_advert = tp->mii_advertise;
4881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		} else if (tp->advertising[phy_idx]) {
4891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			to_advert = tp->advertising[phy_idx];
4901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		} else {
4911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			tp->advertising[phy_idx] =
4921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			tp->mii_advertise =
4931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			to_advert = mii_advert;
4941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
4951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		tp->phys[phy_idx++] = phy;
4971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
498fa0b9a4c41490d550ebd3bd418f4551c989fec5dJoe Perches		pr_info("tulip%d:  MII transceiver #%d config %04x status %04x advertising %04x\n",
4991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			board_idx, phy, mii_reg0, mii_status, mii_advert);
5001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* Fixup for DLink with miswired PHY. */
5021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (mii_advert != to_advert) {
503726b65ad444dd142e34d0087fcbba03d16b34ca6Joe Perches			pr_debug("tulip%d:  Advertising %04x on PHY %d, previously advertising %04x\n",
504726b65ad444dd142e34d0087fcbba03d16b34ca6Joe Perches				 board_idx, to_advert, phy, mii_advert);
5051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			tulip_mdio_write (dev, phy, 4, to_advert);
5061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
5071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* Enable autonegotiation: some boards default to off. */
5091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (tp->default_port == 0) {
5101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			new_bmcr = mii_reg0 | BMCR_ANENABLE;
5111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (new_bmcr != mii_reg0) {
5121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				new_bmcr |= BMCR_ANRESTART;
5131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				ane_switch = 1;
5141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
5151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
5161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* ...or disable nway, if forcing media */
5171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		else {
5181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			new_bmcr = mii_reg0 & ~BMCR_ANENABLE;
5191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (new_bmcr != mii_reg0)
5201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				ane_switch = 1;
5211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
5221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* clear out bits we never want at this point */
5241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		new_bmcr &= ~(BMCR_CTST | BMCR_FULLDPLX | BMCR_ISOLATE |
5251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      BMCR_PDOWN | BMCR_SPEED100 | BMCR_LOOPBACK |
5261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      BMCR_RESET);
5271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (tp->full_duplex)
5291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			new_bmcr |= BMCR_FULLDPLX;
5301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (tulip_media_cap[tp->default_port] & MediaIs100)
5311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			new_bmcr |= BMCR_SPEED100;
5321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (new_bmcr != mii_reg0) {
5341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* some phys need the ANE switch to
5351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 * happen before forced media settings
5361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 * will "take."  However, we write the
5371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 * same value twice in order not to
5381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 * confuse the sane phys.
5391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 */
5401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (ane_switch) {
5411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				tulip_mdio_write (dev, phy, MII_BMCR, new_bmcr);
5421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				udelay (10);
5431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
5441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			tulip_mdio_write (dev, phy, MII_BMCR, new_bmcr);
5451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
5461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
5471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	tp->mii_cnt = phy_idx;
5481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (tp->mtable && tp->mtable->has_mii && phy_idx == 0) {
549fa0b9a4c41490d550ebd3bd418f4551c989fec5dJoe Perches		pr_info("tulip%d: ***WARNING***: No MII transceiver found!\n",
5501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			board_idx);
5511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		tp->phys[0] = 1;
5521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
5531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
554