162306a36Sopenharmony_ci/*
262306a36Sopenharmony_ci	drivers/net/ethernet/dec/tulip/media.c
362306a36Sopenharmony_ci
462306a36Sopenharmony_ci	Copyright 2000,2001  The Linux Kernel Team
562306a36Sopenharmony_ci	Written/copyright 1994-2001 by Donald Becker.
662306a36Sopenharmony_ci
762306a36Sopenharmony_ci	This software may be used and distributed according to the terms
862306a36Sopenharmony_ci	of the GNU General Public License, incorporated herein by reference.
962306a36Sopenharmony_ci
1062306a36Sopenharmony_ci	Please submit bugs to http://bugzilla.kernel.org/ .
1162306a36Sopenharmony_ci*/
1262306a36Sopenharmony_ci
1362306a36Sopenharmony_ci#include <linux/kernel.h>
1462306a36Sopenharmony_ci#include <linux/mii.h>
1562306a36Sopenharmony_ci#include <linux/delay.h>
1662306a36Sopenharmony_ci#include <linux/pci.h>
1762306a36Sopenharmony_ci#include "tulip.h"
1862306a36Sopenharmony_ci
1962306a36Sopenharmony_ci
2062306a36Sopenharmony_ci/* The maximum data clock rate is 2.5 Mhz.  The minimum timing is usually
2162306a36Sopenharmony_ci   met by back-to-back PCI I/O cycles, but we insert a delay to avoid
2262306a36Sopenharmony_ci   "overclocking" issues or future 66Mhz PCI. */
2362306a36Sopenharmony_ci#define mdio_delay() ioread32(mdio_addr)
2462306a36Sopenharmony_ci
2562306a36Sopenharmony_ci/* Read and write the MII registers using software-generated serial
2662306a36Sopenharmony_ci   MDIO protocol.  It is just different enough from the EEPROM protocol
2762306a36Sopenharmony_ci   to not share code.  The maxium data clock rate is 2.5 Mhz. */
2862306a36Sopenharmony_ci#define MDIO_SHIFT_CLK		0x10000
2962306a36Sopenharmony_ci#define MDIO_DATA_WRITE0	0x00000
3062306a36Sopenharmony_ci#define MDIO_DATA_WRITE1	0x20000
3162306a36Sopenharmony_ci#define MDIO_ENB		0x00000 /* Ignore the 0x02000 databook setting. */
3262306a36Sopenharmony_ci#define MDIO_ENB_IN		0x40000
3362306a36Sopenharmony_ci#define MDIO_DATA_READ		0x80000
3462306a36Sopenharmony_ci
3562306a36Sopenharmony_cistatic const unsigned char comet_miireg2offset[32] = {
3662306a36Sopenharmony_ci	0xB4, 0xB8, 0xBC, 0xC0,  0xC4, 0xC8, 0xCC, 0,  0,0,0,0,  0,0,0,0,
3762306a36Sopenharmony_ci	0,0xD0,0,0,  0,0,0,0,  0,0,0,0, 0, 0xD4, 0xD8, 0xDC, };
3862306a36Sopenharmony_ci
3962306a36Sopenharmony_ci
4062306a36Sopenharmony_ci/* MII transceiver control section.
4162306a36Sopenharmony_ci   Read and write the MII registers using software-generated serial
4262306a36Sopenharmony_ci   MDIO protocol.
4362306a36Sopenharmony_ci   See IEEE 802.3-2002.pdf (Section 2, Chapter "22.2.4 Management functions")
4462306a36Sopenharmony_ci   or DP83840A data sheet for more details.
4562306a36Sopenharmony_ci   */
4662306a36Sopenharmony_ci
4762306a36Sopenharmony_ciint tulip_mdio_read(struct net_device *dev, int phy_id, int location)
4862306a36Sopenharmony_ci{
4962306a36Sopenharmony_ci	struct tulip_private *tp = netdev_priv(dev);
5062306a36Sopenharmony_ci	int i;
5162306a36Sopenharmony_ci	int read_cmd = (0xf6 << 10) | ((phy_id & 0x1f) << 5) | location;
5262306a36Sopenharmony_ci	int retval = 0;
5362306a36Sopenharmony_ci	void __iomem *ioaddr = tp->base_addr;
5462306a36Sopenharmony_ci	void __iomem *mdio_addr = ioaddr + CSR9;
5562306a36Sopenharmony_ci	unsigned long flags;
5662306a36Sopenharmony_ci
5762306a36Sopenharmony_ci	if (location & ~0x1f)
5862306a36Sopenharmony_ci		return 0xffff;
5962306a36Sopenharmony_ci
6062306a36Sopenharmony_ci	if (tp->chip_id == COMET  &&  phy_id == 30) {
6162306a36Sopenharmony_ci		if (comet_miireg2offset[location])
6262306a36Sopenharmony_ci			return ioread32(ioaddr + comet_miireg2offset[location]);
6362306a36Sopenharmony_ci		return 0xffff;
6462306a36Sopenharmony_ci	}
6562306a36Sopenharmony_ci
6662306a36Sopenharmony_ci	spin_lock_irqsave(&tp->mii_lock, flags);
6762306a36Sopenharmony_ci	if (tp->chip_id == LC82C168) {
6862306a36Sopenharmony_ci		iowrite32(0x60020000 + (phy_id<<23) + (location<<18), ioaddr + 0xA0);
6962306a36Sopenharmony_ci		ioread32(ioaddr + 0xA0);
7062306a36Sopenharmony_ci		ioread32(ioaddr + 0xA0);
7162306a36Sopenharmony_ci		for (i = 1000; i >= 0; --i) {
7262306a36Sopenharmony_ci			barrier();
7362306a36Sopenharmony_ci			if ( ! ((retval = ioread32(ioaddr + 0xA0)) & 0x80000000))
7462306a36Sopenharmony_ci				break;
7562306a36Sopenharmony_ci		}
7662306a36Sopenharmony_ci		spin_unlock_irqrestore(&tp->mii_lock, flags);
7762306a36Sopenharmony_ci		return retval & 0xffff;
7862306a36Sopenharmony_ci	}
7962306a36Sopenharmony_ci
8062306a36Sopenharmony_ci	/* Establish sync by sending at least 32 logic ones. */
8162306a36Sopenharmony_ci	for (i = 32; i >= 0; i--) {
8262306a36Sopenharmony_ci		iowrite32(MDIO_ENB | MDIO_DATA_WRITE1, mdio_addr);
8362306a36Sopenharmony_ci		mdio_delay();
8462306a36Sopenharmony_ci		iowrite32(MDIO_ENB | MDIO_DATA_WRITE1 | MDIO_SHIFT_CLK, mdio_addr);
8562306a36Sopenharmony_ci		mdio_delay();
8662306a36Sopenharmony_ci	}
8762306a36Sopenharmony_ci	/* Shift the read command bits out. */
8862306a36Sopenharmony_ci	for (i = 15; i >= 0; i--) {
8962306a36Sopenharmony_ci		int dataval = (read_cmd & (1 << i)) ? MDIO_DATA_WRITE1 : 0;
9062306a36Sopenharmony_ci
9162306a36Sopenharmony_ci		iowrite32(MDIO_ENB | dataval, mdio_addr);
9262306a36Sopenharmony_ci		mdio_delay();
9362306a36Sopenharmony_ci		iowrite32(MDIO_ENB | dataval | MDIO_SHIFT_CLK, mdio_addr);
9462306a36Sopenharmony_ci		mdio_delay();
9562306a36Sopenharmony_ci	}
9662306a36Sopenharmony_ci	/* Read the two transition, 16 data, and wire-idle bits. */
9762306a36Sopenharmony_ci	for (i = 19; i > 0; i--) {
9862306a36Sopenharmony_ci		iowrite32(MDIO_ENB_IN, mdio_addr);
9962306a36Sopenharmony_ci		mdio_delay();
10062306a36Sopenharmony_ci		retval = (retval << 1) | ((ioread32(mdio_addr) & MDIO_DATA_READ) ? 1 : 0);
10162306a36Sopenharmony_ci		iowrite32(MDIO_ENB_IN | MDIO_SHIFT_CLK, mdio_addr);
10262306a36Sopenharmony_ci		mdio_delay();
10362306a36Sopenharmony_ci	}
10462306a36Sopenharmony_ci
10562306a36Sopenharmony_ci	spin_unlock_irqrestore(&tp->mii_lock, flags);
10662306a36Sopenharmony_ci	return (retval>>1) & 0xffff;
10762306a36Sopenharmony_ci}
10862306a36Sopenharmony_ci
10962306a36Sopenharmony_civoid tulip_mdio_write(struct net_device *dev, int phy_id, int location, int val)
11062306a36Sopenharmony_ci{
11162306a36Sopenharmony_ci	struct tulip_private *tp = netdev_priv(dev);
11262306a36Sopenharmony_ci	int i;
11362306a36Sopenharmony_ci	int cmd = (0x5002 << 16) | ((phy_id & 0x1f) << 23) | (location<<18) | (val & 0xffff);
11462306a36Sopenharmony_ci	void __iomem *ioaddr = tp->base_addr;
11562306a36Sopenharmony_ci	void __iomem *mdio_addr = ioaddr + CSR9;
11662306a36Sopenharmony_ci	unsigned long flags;
11762306a36Sopenharmony_ci
11862306a36Sopenharmony_ci	if (location & ~0x1f)
11962306a36Sopenharmony_ci		return;
12062306a36Sopenharmony_ci
12162306a36Sopenharmony_ci	if (tp->chip_id == COMET && phy_id == 30) {
12262306a36Sopenharmony_ci		if (comet_miireg2offset[location])
12362306a36Sopenharmony_ci			iowrite32(val, ioaddr + comet_miireg2offset[location]);
12462306a36Sopenharmony_ci		return;
12562306a36Sopenharmony_ci	}
12662306a36Sopenharmony_ci
12762306a36Sopenharmony_ci	spin_lock_irqsave(&tp->mii_lock, flags);
12862306a36Sopenharmony_ci	if (tp->chip_id == LC82C168) {
12962306a36Sopenharmony_ci		iowrite32(cmd, ioaddr + 0xA0);
13062306a36Sopenharmony_ci		for (i = 1000; i >= 0; --i) {
13162306a36Sopenharmony_ci			barrier();
13262306a36Sopenharmony_ci			if ( ! (ioread32(ioaddr + 0xA0) & 0x80000000))
13362306a36Sopenharmony_ci				break;
13462306a36Sopenharmony_ci		}
13562306a36Sopenharmony_ci		spin_unlock_irqrestore(&tp->mii_lock, flags);
13662306a36Sopenharmony_ci		return;
13762306a36Sopenharmony_ci	}
13862306a36Sopenharmony_ci
13962306a36Sopenharmony_ci	/* Establish sync by sending 32 logic ones. */
14062306a36Sopenharmony_ci	for (i = 32; i >= 0; i--) {
14162306a36Sopenharmony_ci		iowrite32(MDIO_ENB | MDIO_DATA_WRITE1, mdio_addr);
14262306a36Sopenharmony_ci		mdio_delay();
14362306a36Sopenharmony_ci		iowrite32(MDIO_ENB | MDIO_DATA_WRITE1 | MDIO_SHIFT_CLK, mdio_addr);
14462306a36Sopenharmony_ci		mdio_delay();
14562306a36Sopenharmony_ci	}
14662306a36Sopenharmony_ci	/* Shift the command bits out. */
14762306a36Sopenharmony_ci	for (i = 31; i >= 0; i--) {
14862306a36Sopenharmony_ci		int dataval = (cmd & (1 << i)) ? MDIO_DATA_WRITE1 : 0;
14962306a36Sopenharmony_ci		iowrite32(MDIO_ENB | dataval, mdio_addr);
15062306a36Sopenharmony_ci		mdio_delay();
15162306a36Sopenharmony_ci		iowrite32(MDIO_ENB | dataval | MDIO_SHIFT_CLK, mdio_addr);
15262306a36Sopenharmony_ci		mdio_delay();
15362306a36Sopenharmony_ci	}
15462306a36Sopenharmony_ci	/* Clear out extra bits. */
15562306a36Sopenharmony_ci	for (i = 2; i > 0; i--) {
15662306a36Sopenharmony_ci		iowrite32(MDIO_ENB_IN, mdio_addr);
15762306a36Sopenharmony_ci		mdio_delay();
15862306a36Sopenharmony_ci		iowrite32(MDIO_ENB_IN | MDIO_SHIFT_CLK, mdio_addr);
15962306a36Sopenharmony_ci		mdio_delay();
16062306a36Sopenharmony_ci	}
16162306a36Sopenharmony_ci
16262306a36Sopenharmony_ci	spin_unlock_irqrestore(&tp->mii_lock, flags);
16362306a36Sopenharmony_ci}
16462306a36Sopenharmony_ci
16562306a36Sopenharmony_ci
16662306a36Sopenharmony_ci/* Set up the transceiver control registers for the selected media type. */
16762306a36Sopenharmony_civoid tulip_select_media(struct net_device *dev, int startup)
16862306a36Sopenharmony_ci{
16962306a36Sopenharmony_ci	struct tulip_private *tp = netdev_priv(dev);
17062306a36Sopenharmony_ci	void __iomem *ioaddr = tp->base_addr;
17162306a36Sopenharmony_ci	struct mediatable *mtable = tp->mtable;
17262306a36Sopenharmony_ci	u32 new_csr6;
17362306a36Sopenharmony_ci	int i;
17462306a36Sopenharmony_ci
17562306a36Sopenharmony_ci	if (mtable) {
17662306a36Sopenharmony_ci		struct medialeaf *mleaf = &mtable->mleaf[tp->cur_index];
17762306a36Sopenharmony_ci		unsigned char *p = mleaf->leafdata;
17862306a36Sopenharmony_ci		switch (mleaf->type) {
17962306a36Sopenharmony_ci		case 0:					/* 21140 non-MII xcvr. */
18062306a36Sopenharmony_ci			if (tulip_debug > 1)
18162306a36Sopenharmony_ci				netdev_dbg(dev, "Using a 21140 non-MII transceiver with control setting %02x\n",
18262306a36Sopenharmony_ci					   p[1]);
18362306a36Sopenharmony_ci			dev->if_port = p[0];
18462306a36Sopenharmony_ci			if (startup)
18562306a36Sopenharmony_ci				iowrite32(mtable->csr12dir | 0x100, ioaddr + CSR12);
18662306a36Sopenharmony_ci			iowrite32(p[1], ioaddr + CSR12);
18762306a36Sopenharmony_ci			new_csr6 = 0x02000000 | ((p[2] & 0x71) << 18);
18862306a36Sopenharmony_ci			break;
18962306a36Sopenharmony_ci		case 2: case 4: {
19062306a36Sopenharmony_ci			u16 setup[5];
19162306a36Sopenharmony_ci			u32 csr13val, csr14val, csr15dir, csr15val;
19262306a36Sopenharmony_ci			for (i = 0; i < 5; i++)
19362306a36Sopenharmony_ci				setup[i] = get_u16(&p[i*2 + 1]);
19462306a36Sopenharmony_ci
19562306a36Sopenharmony_ci			dev->if_port = p[0] & MEDIA_MASK;
19662306a36Sopenharmony_ci			if (tulip_media_cap[dev->if_port] & MediaAlwaysFD)
19762306a36Sopenharmony_ci				tp->full_duplex = 1;
19862306a36Sopenharmony_ci
19962306a36Sopenharmony_ci			if (startup && mtable->has_reset) {
20062306a36Sopenharmony_ci				struct medialeaf *rleaf = &mtable->mleaf[mtable->has_reset];
20162306a36Sopenharmony_ci				unsigned char *rst = rleaf->leafdata;
20262306a36Sopenharmony_ci				if (tulip_debug > 1)
20362306a36Sopenharmony_ci					netdev_dbg(dev, "Resetting the transceiver\n");
20462306a36Sopenharmony_ci				for (i = 0; i < rst[0]; i++)
20562306a36Sopenharmony_ci					iowrite32(get_u16(rst + 1 + (i<<1)) << 16, ioaddr + CSR15);
20662306a36Sopenharmony_ci			}
20762306a36Sopenharmony_ci			if (tulip_debug > 1)
20862306a36Sopenharmony_ci				netdev_dbg(dev, "21143 non-MII %s transceiver control %04x/%04x\n",
20962306a36Sopenharmony_ci					   medianame[dev->if_port],
21062306a36Sopenharmony_ci					   setup[0], setup[1]);
21162306a36Sopenharmony_ci			if (p[0] & 0x40) {	/* SIA (CSR13-15) setup values are provided. */
21262306a36Sopenharmony_ci				csr13val = setup[0];
21362306a36Sopenharmony_ci				csr14val = setup[1];
21462306a36Sopenharmony_ci				csr15dir = (setup[3]<<16) | setup[2];
21562306a36Sopenharmony_ci				csr15val = (setup[4]<<16) | setup[2];
21662306a36Sopenharmony_ci				iowrite32(0, ioaddr + CSR13);
21762306a36Sopenharmony_ci				iowrite32(csr14val, ioaddr + CSR14);
21862306a36Sopenharmony_ci				iowrite32(csr15dir, ioaddr + CSR15);	/* Direction */
21962306a36Sopenharmony_ci				iowrite32(csr15val, ioaddr + CSR15);	/* Data */
22062306a36Sopenharmony_ci				iowrite32(csr13val, ioaddr + CSR13);
22162306a36Sopenharmony_ci			} else {
22262306a36Sopenharmony_ci				csr13val = 1;
22362306a36Sopenharmony_ci				csr14val = 0;
22462306a36Sopenharmony_ci				csr15dir = (setup[0]<<16) | 0x0008;
22562306a36Sopenharmony_ci				csr15val = (setup[1]<<16) | 0x0008;
22662306a36Sopenharmony_ci				if (dev->if_port <= 4)
22762306a36Sopenharmony_ci					csr14val = t21142_csr14[dev->if_port];
22862306a36Sopenharmony_ci				if (startup) {
22962306a36Sopenharmony_ci					iowrite32(0, ioaddr + CSR13);
23062306a36Sopenharmony_ci					iowrite32(csr14val, ioaddr + CSR14);
23162306a36Sopenharmony_ci				}
23262306a36Sopenharmony_ci				iowrite32(csr15dir, ioaddr + CSR15);	/* Direction */
23362306a36Sopenharmony_ci				iowrite32(csr15val, ioaddr + CSR15);	/* Data */
23462306a36Sopenharmony_ci				if (startup) iowrite32(csr13val, ioaddr + CSR13);
23562306a36Sopenharmony_ci			}
23662306a36Sopenharmony_ci			if (tulip_debug > 1)
23762306a36Sopenharmony_ci				netdev_dbg(dev, "Setting CSR15 to %08x/%08x\n",
23862306a36Sopenharmony_ci					   csr15dir, csr15val);
23962306a36Sopenharmony_ci			if (mleaf->type == 4)
24062306a36Sopenharmony_ci				new_csr6 = 0x82020000 | ((setup[2] & 0x71) << 18);
24162306a36Sopenharmony_ci			else
24262306a36Sopenharmony_ci				new_csr6 = 0x82420000;
24362306a36Sopenharmony_ci			break;
24462306a36Sopenharmony_ci		}
24562306a36Sopenharmony_ci		case 1: case 3: {
24662306a36Sopenharmony_ci			int phy_num = p[0];
24762306a36Sopenharmony_ci			int init_length = p[1];
24862306a36Sopenharmony_ci			u16 *misc_info, tmp_info;
24962306a36Sopenharmony_ci
25062306a36Sopenharmony_ci			dev->if_port = 11;
25162306a36Sopenharmony_ci			new_csr6 = 0x020E0000;
25262306a36Sopenharmony_ci			if (mleaf->type == 3) {	/* 21142 */
25362306a36Sopenharmony_ci				u16 *init_sequence = (u16*)(p+2);
25462306a36Sopenharmony_ci				u16 *reset_sequence = &((u16*)(p+3))[init_length];
25562306a36Sopenharmony_ci				int reset_length = p[2 + init_length*2];
25662306a36Sopenharmony_ci				misc_info = reset_sequence + reset_length;
25762306a36Sopenharmony_ci				if (startup) {
25862306a36Sopenharmony_ci					int timeout = 10;	/* max 1 ms */
25962306a36Sopenharmony_ci					for (i = 0; i < reset_length; i++)
26062306a36Sopenharmony_ci						iowrite32(get_u16(&reset_sequence[i]) << 16, ioaddr + CSR15);
26162306a36Sopenharmony_ci
26262306a36Sopenharmony_ci					/* flush posted writes */
26362306a36Sopenharmony_ci					ioread32(ioaddr + CSR15);
26462306a36Sopenharmony_ci
26562306a36Sopenharmony_ci					/* Sect 3.10.3 in DP83840A.pdf (p39) */
26662306a36Sopenharmony_ci					udelay(500);
26762306a36Sopenharmony_ci
26862306a36Sopenharmony_ci					/* Section 4.2 in DP83840A.pdf (p43) */
26962306a36Sopenharmony_ci					/* and IEEE 802.3 "22.2.4.1.1 Reset" */
27062306a36Sopenharmony_ci					while (timeout-- &&
27162306a36Sopenharmony_ci						(tulip_mdio_read (dev, phy_num, MII_BMCR) & BMCR_RESET))
27262306a36Sopenharmony_ci						udelay(100);
27362306a36Sopenharmony_ci				}
27462306a36Sopenharmony_ci				for (i = 0; i < init_length; i++)
27562306a36Sopenharmony_ci					iowrite32(get_u16(&init_sequence[i]) << 16, ioaddr + CSR15);
27662306a36Sopenharmony_ci
27762306a36Sopenharmony_ci				ioread32(ioaddr + CSR15);	/* flush posted writes */
27862306a36Sopenharmony_ci			} else {
27962306a36Sopenharmony_ci				u8 *init_sequence = p + 2;
28062306a36Sopenharmony_ci				u8 *reset_sequence = p + 3 + init_length;
28162306a36Sopenharmony_ci				int reset_length = p[2 + init_length];
28262306a36Sopenharmony_ci				misc_info = (u16*)(reset_sequence + reset_length);
28362306a36Sopenharmony_ci				if (startup) {
28462306a36Sopenharmony_ci					int timeout = 10;	/* max 1 ms */
28562306a36Sopenharmony_ci					iowrite32(mtable->csr12dir | 0x100, ioaddr + CSR12);
28662306a36Sopenharmony_ci					for (i = 0; i < reset_length; i++)
28762306a36Sopenharmony_ci						iowrite32(reset_sequence[i], ioaddr + CSR12);
28862306a36Sopenharmony_ci
28962306a36Sopenharmony_ci					/* flush posted writes */
29062306a36Sopenharmony_ci					ioread32(ioaddr + CSR12);
29162306a36Sopenharmony_ci
29262306a36Sopenharmony_ci					/* Sect 3.10.3 in DP83840A.pdf (p39) */
29362306a36Sopenharmony_ci					udelay(500);
29462306a36Sopenharmony_ci
29562306a36Sopenharmony_ci					/* Section 4.2 in DP83840A.pdf (p43) */
29662306a36Sopenharmony_ci					/* and IEEE 802.3 "22.2.4.1.1 Reset" */
29762306a36Sopenharmony_ci					while (timeout-- &&
29862306a36Sopenharmony_ci						(tulip_mdio_read (dev, phy_num, MII_BMCR) & BMCR_RESET))
29962306a36Sopenharmony_ci						udelay(100);
30062306a36Sopenharmony_ci				}
30162306a36Sopenharmony_ci				for (i = 0; i < init_length; i++)
30262306a36Sopenharmony_ci					iowrite32(init_sequence[i], ioaddr + CSR12);
30362306a36Sopenharmony_ci
30462306a36Sopenharmony_ci				ioread32(ioaddr + CSR12);	/* flush posted writes */
30562306a36Sopenharmony_ci			}
30662306a36Sopenharmony_ci
30762306a36Sopenharmony_ci			tmp_info = get_u16(&misc_info[1]);
30862306a36Sopenharmony_ci			if (tmp_info)
30962306a36Sopenharmony_ci				tp->advertising[phy_num] = tmp_info | 1;
31062306a36Sopenharmony_ci			if (tmp_info && startup < 2) {
31162306a36Sopenharmony_ci				if (tp->mii_advertise == 0)
31262306a36Sopenharmony_ci					tp->mii_advertise = tp->advertising[phy_num];
31362306a36Sopenharmony_ci				if (tulip_debug > 1)
31462306a36Sopenharmony_ci					netdev_dbg(dev, " Advertising %04x on MII %d\n",
31562306a36Sopenharmony_ci						   tp->mii_advertise,
31662306a36Sopenharmony_ci						   tp->phys[phy_num]);
31762306a36Sopenharmony_ci				tulip_mdio_write(dev, tp->phys[phy_num], 4, tp->mii_advertise);
31862306a36Sopenharmony_ci			}
31962306a36Sopenharmony_ci			break;
32062306a36Sopenharmony_ci		}
32162306a36Sopenharmony_ci		case 5: case 6: {
32262306a36Sopenharmony_ci			new_csr6 = 0; /* FIXME */
32362306a36Sopenharmony_ci
32462306a36Sopenharmony_ci			if (startup && mtable->has_reset) {
32562306a36Sopenharmony_ci				struct medialeaf *rleaf = &mtable->mleaf[mtable->has_reset];
32662306a36Sopenharmony_ci				unsigned char *rst = rleaf->leafdata;
32762306a36Sopenharmony_ci				if (tulip_debug > 1)
32862306a36Sopenharmony_ci					netdev_dbg(dev, "Resetting the transceiver\n");
32962306a36Sopenharmony_ci				for (i = 0; i < rst[0]; i++)
33062306a36Sopenharmony_ci					iowrite32(get_u16(rst + 1 + (i<<1)) << 16, ioaddr + CSR15);
33162306a36Sopenharmony_ci			}
33262306a36Sopenharmony_ci
33362306a36Sopenharmony_ci			break;
33462306a36Sopenharmony_ci		}
33562306a36Sopenharmony_ci		default:
33662306a36Sopenharmony_ci			netdev_dbg(dev, " Invalid media table selection %d\n",
33762306a36Sopenharmony_ci				   mleaf->type);
33862306a36Sopenharmony_ci			new_csr6 = 0x020E0000;
33962306a36Sopenharmony_ci		}
34062306a36Sopenharmony_ci		if (tulip_debug > 1)
34162306a36Sopenharmony_ci			netdev_dbg(dev, "Using media type %s, CSR12 is %02x\n",
34262306a36Sopenharmony_ci				   medianame[dev->if_port],
34362306a36Sopenharmony_ci				   ioread32(ioaddr + CSR12) & 0xff);
34462306a36Sopenharmony_ci	} else if (tp->chip_id == LC82C168) {
34562306a36Sopenharmony_ci		if (startup && ! tp->medialock)
34662306a36Sopenharmony_ci			dev->if_port = tp->mii_cnt ? 11 : 0;
34762306a36Sopenharmony_ci		if (tulip_debug > 1)
34862306a36Sopenharmony_ci			netdev_dbg(dev, "PNIC PHY status is %3.3x, media %s\n",
34962306a36Sopenharmony_ci				   ioread32(ioaddr + 0xB8),
35062306a36Sopenharmony_ci				   medianame[dev->if_port]);
35162306a36Sopenharmony_ci		if (tp->mii_cnt) {
35262306a36Sopenharmony_ci			new_csr6 = 0x810C0000;
35362306a36Sopenharmony_ci			iowrite32(0x0001, ioaddr + CSR15);
35462306a36Sopenharmony_ci			iowrite32(0x0201B07A, ioaddr + 0xB8);
35562306a36Sopenharmony_ci		} else if (startup) {
35662306a36Sopenharmony_ci			/* Start with 10mbps to do autonegotiation. */
35762306a36Sopenharmony_ci			iowrite32(0x32, ioaddr + CSR12);
35862306a36Sopenharmony_ci			new_csr6 = 0x00420000;
35962306a36Sopenharmony_ci			iowrite32(0x0001B078, ioaddr + 0xB8);
36062306a36Sopenharmony_ci			iowrite32(0x0201B078, ioaddr + 0xB8);
36162306a36Sopenharmony_ci		} else if (dev->if_port == 3  ||  dev->if_port == 5) {
36262306a36Sopenharmony_ci			iowrite32(0x33, ioaddr + CSR12);
36362306a36Sopenharmony_ci			new_csr6 = 0x01860000;
36462306a36Sopenharmony_ci			/* Trigger autonegotiation. */
36562306a36Sopenharmony_ci			iowrite32(0x0001F868, ioaddr + 0xB8);
36662306a36Sopenharmony_ci		} else {
36762306a36Sopenharmony_ci			iowrite32(0x32, ioaddr + CSR12);
36862306a36Sopenharmony_ci			new_csr6 = 0x00420000;
36962306a36Sopenharmony_ci			iowrite32(0x1F078, ioaddr + 0xB8);
37062306a36Sopenharmony_ci		}
37162306a36Sopenharmony_ci	} else {					/* Unknown chip type with no media table. */
37262306a36Sopenharmony_ci		if (tp->default_port == 0)
37362306a36Sopenharmony_ci			dev->if_port = tp->mii_cnt ? 11 : 3;
37462306a36Sopenharmony_ci		if (tulip_media_cap[dev->if_port] & MediaIsMII) {
37562306a36Sopenharmony_ci			new_csr6 = 0x020E0000;
37662306a36Sopenharmony_ci		} else if (tulip_media_cap[dev->if_port] & MediaIsFx) {
37762306a36Sopenharmony_ci			new_csr6 = 0x02860000;
37862306a36Sopenharmony_ci		} else
37962306a36Sopenharmony_ci			new_csr6 = 0x03860000;
38062306a36Sopenharmony_ci		if (tulip_debug > 1)
38162306a36Sopenharmony_ci			netdev_dbg(dev, "No media description table, assuming %s transceiver, CSR12 %02x\n",
38262306a36Sopenharmony_ci				   medianame[dev->if_port],
38362306a36Sopenharmony_ci				   ioread32(ioaddr + CSR12));
38462306a36Sopenharmony_ci	}
38562306a36Sopenharmony_ci
38662306a36Sopenharmony_ci	tp->csr6 = new_csr6 | (tp->csr6 & 0xfdff) | (tp->full_duplex ? 0x0200 : 0);
38762306a36Sopenharmony_ci
38862306a36Sopenharmony_ci	mdelay(1);
38962306a36Sopenharmony_ci}
39062306a36Sopenharmony_ci
39162306a36Sopenharmony_ci/*
39262306a36Sopenharmony_ci  Check the MII negotiated duplex and change the CSR6 setting if
39362306a36Sopenharmony_ci  required.
39462306a36Sopenharmony_ci  Return 0 if everything is OK.
39562306a36Sopenharmony_ci  Return < 0 if the transceiver is missing or has no link beat.
39662306a36Sopenharmony_ci  */
39762306a36Sopenharmony_ciint tulip_check_duplex(struct net_device *dev)
39862306a36Sopenharmony_ci{
39962306a36Sopenharmony_ci	struct tulip_private *tp = netdev_priv(dev);
40062306a36Sopenharmony_ci	unsigned int bmsr, lpa, negotiated, new_csr6;
40162306a36Sopenharmony_ci
40262306a36Sopenharmony_ci	bmsr = tulip_mdio_read(dev, tp->phys[0], MII_BMSR);
40362306a36Sopenharmony_ci	lpa = tulip_mdio_read(dev, tp->phys[0], MII_LPA);
40462306a36Sopenharmony_ci	if (tulip_debug > 1)
40562306a36Sopenharmony_ci		dev_info(&dev->dev, "MII status %04x, Link partner report %04x\n",
40662306a36Sopenharmony_ci			 bmsr, lpa);
40762306a36Sopenharmony_ci	if (bmsr == 0xffff)
40862306a36Sopenharmony_ci		return -2;
40962306a36Sopenharmony_ci	if ((bmsr & BMSR_LSTATUS) == 0) {
41062306a36Sopenharmony_ci		int new_bmsr = tulip_mdio_read(dev, tp->phys[0], MII_BMSR);
41162306a36Sopenharmony_ci		if ((new_bmsr & BMSR_LSTATUS) == 0) {
41262306a36Sopenharmony_ci			if (tulip_debug  > 1)
41362306a36Sopenharmony_ci				dev_info(&dev->dev,
41462306a36Sopenharmony_ci					 "No link beat on the MII interface, status %04x\n",
41562306a36Sopenharmony_ci					 new_bmsr);
41662306a36Sopenharmony_ci			return -1;
41762306a36Sopenharmony_ci		}
41862306a36Sopenharmony_ci	}
41962306a36Sopenharmony_ci	negotiated = lpa & tp->advertising[0];
42062306a36Sopenharmony_ci	tp->full_duplex = mii_duplex(tp->full_duplex_lock, negotiated);
42162306a36Sopenharmony_ci
42262306a36Sopenharmony_ci	new_csr6 = tp->csr6;
42362306a36Sopenharmony_ci
42462306a36Sopenharmony_ci	if (negotiated & LPA_100) new_csr6 &= ~TxThreshold;
42562306a36Sopenharmony_ci	else			  new_csr6 |= TxThreshold;
42662306a36Sopenharmony_ci	if (tp->full_duplex) new_csr6 |= FullDuplex;
42762306a36Sopenharmony_ci	else		     new_csr6 &= ~FullDuplex;
42862306a36Sopenharmony_ci
42962306a36Sopenharmony_ci	if (new_csr6 != tp->csr6) {
43062306a36Sopenharmony_ci		tp->csr6 = new_csr6;
43162306a36Sopenharmony_ci		tulip_restart_rxtx(tp);
43262306a36Sopenharmony_ci
43362306a36Sopenharmony_ci		if (tulip_debug > 0)
43462306a36Sopenharmony_ci			dev_info(&dev->dev,
43562306a36Sopenharmony_ci				 "Setting %s-duplex based on MII#%d link partner capability of %04x\n",
43662306a36Sopenharmony_ci				 tp->full_duplex ? "full" : "half",
43762306a36Sopenharmony_ci				 tp->phys[0], lpa);
43862306a36Sopenharmony_ci		return 1;
43962306a36Sopenharmony_ci	}
44062306a36Sopenharmony_ci
44162306a36Sopenharmony_ci	return 0;
44262306a36Sopenharmony_ci}
44362306a36Sopenharmony_ci
44462306a36Sopenharmony_civoid tulip_find_mii(struct net_device *dev, int board_idx)
44562306a36Sopenharmony_ci{
44662306a36Sopenharmony_ci	struct tulip_private *tp = netdev_priv(dev);
44762306a36Sopenharmony_ci	int phyn, phy_idx = 0;
44862306a36Sopenharmony_ci	int mii_reg0;
44962306a36Sopenharmony_ci	int mii_advert;
45062306a36Sopenharmony_ci	unsigned int to_advert, new_bmcr, ane_switch;
45162306a36Sopenharmony_ci
45262306a36Sopenharmony_ci	/* Find the connected MII xcvrs.
45362306a36Sopenharmony_ci	   Doing this in open() would allow detecting external xcvrs later,
45462306a36Sopenharmony_ci	   but takes much time. */
45562306a36Sopenharmony_ci	for (phyn = 1; phyn <= 32 && phy_idx < ARRAY_SIZE(tp->phys); phyn++) {
45662306a36Sopenharmony_ci		int phy = phyn & 0x1f;
45762306a36Sopenharmony_ci		int mii_status = tulip_mdio_read (dev, phy, MII_BMSR);
45862306a36Sopenharmony_ci		if ((mii_status & 0x8301) == 0x8001 ||
45962306a36Sopenharmony_ci		    ((mii_status & BMSR_100BASE4) == 0 &&
46062306a36Sopenharmony_ci		     (mii_status & 0x7800) != 0)) {
46162306a36Sopenharmony_ci			/* preserve Becker logic, gain indentation level */
46262306a36Sopenharmony_ci		} else {
46362306a36Sopenharmony_ci			continue;
46462306a36Sopenharmony_ci		}
46562306a36Sopenharmony_ci
46662306a36Sopenharmony_ci		mii_reg0 = tulip_mdio_read (dev, phy, MII_BMCR);
46762306a36Sopenharmony_ci		mii_advert = tulip_mdio_read (dev, phy, MII_ADVERTISE);
46862306a36Sopenharmony_ci		ane_switch = 0;
46962306a36Sopenharmony_ci
47062306a36Sopenharmony_ci		/* if not advertising at all, gen an
47162306a36Sopenharmony_ci		 * advertising value from the capability
47262306a36Sopenharmony_ci		 * bits in BMSR
47362306a36Sopenharmony_ci		 */
47462306a36Sopenharmony_ci		if ((mii_advert & ADVERTISE_ALL) == 0) {
47562306a36Sopenharmony_ci			unsigned int tmpadv = tulip_mdio_read (dev, phy, MII_BMSR);
47662306a36Sopenharmony_ci			mii_advert = ((tmpadv >> 6) & 0x3e0) | 1;
47762306a36Sopenharmony_ci		}
47862306a36Sopenharmony_ci
47962306a36Sopenharmony_ci		if (tp->mii_advertise) {
48062306a36Sopenharmony_ci			tp->advertising[phy_idx] =
48162306a36Sopenharmony_ci			to_advert = tp->mii_advertise;
48262306a36Sopenharmony_ci		} else if (tp->advertising[phy_idx]) {
48362306a36Sopenharmony_ci			to_advert = tp->advertising[phy_idx];
48462306a36Sopenharmony_ci		} else {
48562306a36Sopenharmony_ci			tp->advertising[phy_idx] =
48662306a36Sopenharmony_ci			tp->mii_advertise =
48762306a36Sopenharmony_ci			to_advert = mii_advert;
48862306a36Sopenharmony_ci		}
48962306a36Sopenharmony_ci
49062306a36Sopenharmony_ci		tp->phys[phy_idx++] = phy;
49162306a36Sopenharmony_ci
49262306a36Sopenharmony_ci		pr_info("tulip%d:  MII transceiver #%d config %04x status %04x advertising %04x\n",
49362306a36Sopenharmony_ci			board_idx, phy, mii_reg0, mii_status, mii_advert);
49462306a36Sopenharmony_ci
49562306a36Sopenharmony_ci		/* Fixup for DLink with miswired PHY. */
49662306a36Sopenharmony_ci		if (mii_advert != to_advert) {
49762306a36Sopenharmony_ci			pr_debug("tulip%d:  Advertising %04x on PHY %d, previously advertising %04x\n",
49862306a36Sopenharmony_ci				 board_idx, to_advert, phy, mii_advert);
49962306a36Sopenharmony_ci			tulip_mdio_write (dev, phy, 4, to_advert);
50062306a36Sopenharmony_ci		}
50162306a36Sopenharmony_ci
50262306a36Sopenharmony_ci		/* Enable autonegotiation: some boards default to off. */
50362306a36Sopenharmony_ci		if (tp->default_port == 0) {
50462306a36Sopenharmony_ci			new_bmcr = mii_reg0 | BMCR_ANENABLE;
50562306a36Sopenharmony_ci			if (new_bmcr != mii_reg0) {
50662306a36Sopenharmony_ci				new_bmcr |= BMCR_ANRESTART;
50762306a36Sopenharmony_ci				ane_switch = 1;
50862306a36Sopenharmony_ci			}
50962306a36Sopenharmony_ci		}
51062306a36Sopenharmony_ci		/* ...or disable nway, if forcing media */
51162306a36Sopenharmony_ci		else {
51262306a36Sopenharmony_ci			new_bmcr = mii_reg0 & ~BMCR_ANENABLE;
51362306a36Sopenharmony_ci			if (new_bmcr != mii_reg0)
51462306a36Sopenharmony_ci				ane_switch = 1;
51562306a36Sopenharmony_ci		}
51662306a36Sopenharmony_ci
51762306a36Sopenharmony_ci		/* clear out bits we never want at this point */
51862306a36Sopenharmony_ci		new_bmcr &= ~(BMCR_CTST | BMCR_FULLDPLX | BMCR_ISOLATE |
51962306a36Sopenharmony_ci			      BMCR_PDOWN | BMCR_SPEED100 | BMCR_LOOPBACK |
52062306a36Sopenharmony_ci			      BMCR_RESET);
52162306a36Sopenharmony_ci
52262306a36Sopenharmony_ci		if (tp->full_duplex)
52362306a36Sopenharmony_ci			new_bmcr |= BMCR_FULLDPLX;
52462306a36Sopenharmony_ci		if (tulip_media_cap[tp->default_port] & MediaIs100)
52562306a36Sopenharmony_ci			new_bmcr |= BMCR_SPEED100;
52662306a36Sopenharmony_ci
52762306a36Sopenharmony_ci		if (new_bmcr != mii_reg0) {
52862306a36Sopenharmony_ci			/* some phys need the ANE switch to
52962306a36Sopenharmony_ci			 * happen before forced media settings
53062306a36Sopenharmony_ci			 * will "take."  However, we write the
53162306a36Sopenharmony_ci			 * same value twice in order not to
53262306a36Sopenharmony_ci			 * confuse the sane phys.
53362306a36Sopenharmony_ci			 */
53462306a36Sopenharmony_ci			if (ane_switch) {
53562306a36Sopenharmony_ci				tulip_mdio_write (dev, phy, MII_BMCR, new_bmcr);
53662306a36Sopenharmony_ci				udelay (10);
53762306a36Sopenharmony_ci			}
53862306a36Sopenharmony_ci			tulip_mdio_write (dev, phy, MII_BMCR, new_bmcr);
53962306a36Sopenharmony_ci		}
54062306a36Sopenharmony_ci	}
54162306a36Sopenharmony_ci	tp->mii_cnt = phy_idx;
54262306a36Sopenharmony_ci	if (tp->mtable && tp->mtable->has_mii && phy_idx == 0) {
54362306a36Sopenharmony_ci		pr_info("tulip%d: ***WARNING***: No MII transceiver found!\n",
54462306a36Sopenharmony_ci			board_idx);
54562306a36Sopenharmony_ci		tp->phys[0] = 1;
54662306a36Sopenharmony_ci	}
54762306a36Sopenharmony_ci}
548