tsec.c 48.7 KB
Newer Older
W
wdenk 已提交
1
/*
2
 * Freescale Three Speed Ethernet Controller driver
W
wdenk 已提交
3 4 5 6 7
 *
 * This software may be used and distributed according to the
 * terms of the GNU Public License, Version 2, incorporated
 * herein by reference.
 *
8
 * Copyright 2004-2009 Freescale Semiconductor, Inc.
W
wdenk 已提交
9 10 11 12 13 14 15 16 17 18
 * (C) Copyright 2003, Motorola, Inc.
 * author Andy Fleming
 *
 */

#include <config.h>
#include <common.h>
#include <malloc.h>
#include <net.h>
#include <command.h>
A
Andy Fleming 已提交
19
#include <tsec.h>
20
#include <asm/errno.h>
W
wdenk 已提交
21

M
Marian Balakowicz 已提交
22
#include "miiphy.h"
W
wdenk 已提交
23

24 25
DECLARE_GLOBAL_DATA_PTR;

M
Marian Balakowicz 已提交
26
#define TX_BUF_CNT		2
W
wdenk 已提交
27

28 29
static uint rxIdx;		/* index of the current RX buffer */
static uint txIdx;		/* index of the current TX buffer */
W
wdenk 已提交
30 31 32 33

typedef volatile struct rtxbd {
	txbd8_t txbd[TX_BUF_CNT];
	rxbd8_t rxbd[PKTBUFSRX];
34
} RTXBD;
W
wdenk 已提交
35

36
#define MAXCONTROLLERS	(8)
37 38

static struct tsec_private *privlist[MAXCONTROLLERS];
39
static int num_tsecs = 0;
40

W
wdenk 已提交
41 42 43 44 45 46
#ifdef __GNUC__
static RTXBD rtx __attribute__ ((aligned(8)));
#else
#error "rtx must be 64-bit aligned"
#endif

47 48 49 50
static int tsec_send(struct eth_device *dev,
		     volatile void *packet, int length);
static int tsec_recv(struct eth_device *dev);
static int tsec_init(struct eth_device *dev, bd_t * bd);
51
static int tsec_initialize(bd_t * bis, struct tsec_info_struct *tsec_info);
52 53
static void tsec_halt(struct eth_device *dev);
static void init_registers(volatile tsec_t * regs);
54 55 56 57
static void startup_tsec(struct eth_device *dev);
static int init_phy(struct eth_device *dev);
void write_phy_reg(struct tsec_private *priv, uint regnum, uint value);
uint read_phy_reg(struct tsec_private *priv, uint regnum);
58 59
static struct phy_info *get_phy_info(struct eth_device *dev);
static void phy_run_commands(struct tsec_private *priv, struct phy_cmd *cmd);
60
static void adjust_link(struct eth_device *dev);
61 62
#if defined(CONFIG_MII) || defined(CONFIG_CMD_MII) \
	&& !defined(BITBANGMII)
M
Marian Balakowicz 已提交
63
static int tsec_miiphy_write(char *devname, unsigned char addr,
64
			     unsigned char reg, unsigned short value);
M
Marian Balakowicz 已提交
65
static int tsec_miiphy_read(char *devname, unsigned char addr,
66
			    unsigned char reg, unsigned short *value);
67
#endif
D
David Updegraff 已提交
68 69 70
#ifdef CONFIG_MCAST_TFTP
static int tsec_mcast_addr (struct eth_device *dev, u8 mcast_mac, u8 set);
#endif
71

72 73 74 75 76 77 78 79 80 81 82 83
/* Default initializations for TSEC controllers. */

static struct tsec_info_struct tsec_info[] = {
#ifdef CONFIG_TSEC1
	STD_TSEC_INFO(1),	/* TSEC1 */
#endif
#ifdef CONFIG_TSEC2
	STD_TSEC_INFO(2),	/* TSEC2 */
#endif
#ifdef CONFIG_MPC85XX_FEC
	{
		.regs = (tsec_t *)(TSEC_BASE_ADDR + 0x2000),
84
		.miiregs = (tsec_mdio_t *)(MDIO_BASE_ADDR),
85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112
		.devname = CONFIG_MPC85XX_FEC_NAME,
		.phyaddr = FEC_PHY_ADDR,
		.flags = FEC_FLAGS
	},			/* FEC */
#endif
#ifdef CONFIG_TSEC3
	STD_TSEC_INFO(3),	/* TSEC3 */
#endif
#ifdef CONFIG_TSEC4
	STD_TSEC_INFO(4),	/* TSEC4 */
#endif
};

int tsec_eth_init(bd_t *bis, struct tsec_info_struct *tsecs, int num)
{
	int i;

	for (i = 0; i < num; i++)
		tsec_initialize(bis, &tsecs[i]);

	return 0;
}

int tsec_standard_init(bd_t *bis)
{
	return tsec_eth_init(bis, tsec_info, ARRAY_SIZE(tsec_info));
}

113 114 115
/* Initialize device structure. Returns success if PHY
 * initialization succeeded (i.e. if it recognizes the PHY)
 */
116
static int tsec_initialize(bd_t * bis, struct tsec_info_struct *tsec_info)
W
wdenk 已提交
117
{
118
	struct eth_device *dev;
W
wdenk 已提交
119
	int i;
120
	struct tsec_private *priv;
W
wdenk 已提交
121

122
	dev = (struct eth_device *)malloc(sizeof *dev);
W
wdenk 已提交
123

124
	if (NULL == dev)
W
wdenk 已提交
125 126 127 128
		return 0;

	memset(dev, 0, sizeof *dev);

129
	priv = (struct tsec_private *)malloc(sizeof(*priv));
130

131
	if (NULL == priv)
132 133
		return 0;

134 135 136
	privlist[num_tsecs++] = priv;
	priv->regs = tsec_info->regs;
	priv->phyregs = tsec_info->miiregs;
137
	priv->phyregs_sgmii = tsec_info->miiregs_sgmii;
138

139 140
	priv->phyaddr = tsec_info->phyaddr;
	priv->flags = tsec_info->flags;
141

142
	sprintf(dev->name, tsec_info->devname);
W
wdenk 已提交
143
	dev->iobase = 0;
144 145 146 147 148
	dev->priv = priv;
	dev->init = tsec_init;
	dev->halt = tsec_halt;
	dev->send = tsec_send;
	dev->recv = tsec_recv;
D
David Updegraff 已提交
149 150 151
#ifdef CONFIG_MCAST_TFTP
	dev->mcast = tsec_mcast_addr;
#endif
W
wdenk 已提交
152 153

	/* Tell u-boot to get the addr from the env */
154
	for (i = 0; i < 6; i++)
W
wdenk 已提交
155 156 157 158
		dev->enetaddr[i] = 0;

	eth_register(dev);

159 160
	/* Reset the MAC */
	priv->regs->maccfg1 |= MACCFG1_SOFT_RESET;
A
Andy Fleming 已提交
161
	udelay(2);  /* Soft Reset must be asserted for 3 TX clocks */
162
	priv->regs->maccfg1 &= ~(MACCFG1_SOFT_RESET);
W
wdenk 已提交
163

164
#if defined(CONFIG_MII) || defined(CONFIG_CMD_MII) \
M
Marian Balakowicz 已提交
165 166 167 168
	&& !defined(BITBANGMII)
	miiphy_register(dev->name, tsec_miiphy_read, tsec_miiphy_write);
#endif

169 170
	/* Try to initialize PHY here, and return */
	return init_phy(dev);
W
wdenk 已提交
171 172 173
}

/* Initializes data structures and registers for the controller,
W
wdenk 已提交
174
 * and brings the interface up.	 Returns the link status, meaning
175
 * that it returns success if the link is up, failure otherwise.
176 177
 * This allows u-boot to find the first active controller.
 */
178
static int tsec_init(struct eth_device *dev, bd_t * bd)
W
wdenk 已提交
179 180 181 182
{
	uint tempval;
	char tmpbuf[MAC_ADDR_LEN];
	int i;
183 184
	struct tsec_private *priv = (struct tsec_private *)dev->priv;
	volatile tsec_t *regs = priv->regs;
W
wdenk 已提交
185 186 187 188

	/* Make sure the controller is stopped */
	tsec_halt(dev);

189
	/* Init MACCFG2.  Defaults to GMII */
W
wdenk 已提交
190 191 192 193 194 195 196
	regs->maccfg2 = MACCFG2_INIT_SETTINGS;

	/* Init ECNTRL */
	regs->ecntrl = ECNTRL_INIT_SETTINGS;

	/* Copy the station address into the address registers.
	 * Backwards, because little endian MACS are dumb */
197
	for (i = 0; i < MAC_ADDR_LEN; i++) {
198
		tmpbuf[MAC_ADDR_LEN - 1 - i] = dev->enetaddr[i];
W
wdenk 已提交
199
	}
200 201 202 203
	tempval = (tmpbuf[0] << 24) | (tmpbuf[1] << 16) | (tmpbuf[2] << 8) |
		  tmpbuf[3];

	regs->macstnaddr1 = tempval;
W
wdenk 已提交
204

205
	tempval = *((uint *) (tmpbuf + 4));
W
wdenk 已提交
206

W
Wolfgang Denk 已提交
207
	regs->macstnaddr2 = tempval;
W
wdenk 已提交
208 209 210 211 212 213 214 215 216

	/* reset the indices to zero */
	rxIdx = 0;
	txIdx = 0;

	/* Clear out (for the most part) the other registers */
	init_registers(regs);

	/* Ready the device for tx/rx */
217
	startup_tsec(dev);
W
wdenk 已提交
218

219
	/* If there's no link, fail */
B
Ben Warren 已提交
220
	return (priv->link ? 0 : -1);
W
wdenk 已提交
221 222
}

A
Andy Fleming 已提交
223
/* Writes the given phy's reg with value, using the specified MDIO regs */
224
static void tsec_local_mdio_write(volatile tsec_mdio_t *phyregs, uint addr,
A
Andy Fleming 已提交
225
		uint reg, uint value)
226
{
227
	int timeout = 1000000;
228

A
Andy Fleming 已提交
229 230
	phyregs->miimadd = (addr << 8) | reg;
	phyregs->miimcon = value;
E
Eran Liberty 已提交
231
	asm("sync");
232

233
	timeout = 1000000;
A
Andy Fleming 已提交
234
	while ((phyregs->miimind & MIIMIND_BUSY) && timeout--) ;
235 236
}

A
Andy Fleming 已提交
237 238

/* Provide the default behavior of writing the PHY of this ethernet device */
P
Peter Tyser 已提交
239 240
#define write_phy_reg(priv, regnum, value) \
	tsec_local_mdio_write(priv->phyregs,priv->phyaddr,regnum,value)
241

242
/* Reads register regnum on the device's PHY through the
A
Andy Fleming 已提交
243
 * specified registers.	 It lowers and raises the read
244 245 246 247
 * command, and waits for the data to become valid (miimind
 * notvalid bit cleared), and the bus to cease activity (miimind
 * busy bit cleared), and then returns the value
 */
248 249
static uint tsec_local_mdio_read(volatile tsec_mdio_t *phyregs,
				uint phyid, uint regnum)
W
wdenk 已提交
250 251 252
{
	uint value;

253 254
	/* Put the address of the phy, and the register
	 * number into MIIMADD */
A
Andy Fleming 已提交
255
	phyregs->miimadd = (phyid << 8) | regnum;
W
wdenk 已提交
256 257

	/* Clear the command register, and wait */
A
Andy Fleming 已提交
258
	phyregs->miimcom = 0;
E
Eran Liberty 已提交
259
	asm("sync");
W
wdenk 已提交
260 261

	/* Initiate a read command, and wait */
A
Andy Fleming 已提交
262
	phyregs->miimcom = MIIM_READ_COMMAND;
E
Eran Liberty 已提交
263
	asm("sync");
W
wdenk 已提交
264 265

	/* Wait for the the indication that the read is done */
A
Andy Fleming 已提交
266
	while ((phyregs->miimind & (MIIMIND_NOTVALID | MIIMIND_BUSY))) ;
W
wdenk 已提交
267 268

	/* Grab the value read from the PHY */
A
Andy Fleming 已提交
269
	value = phyregs->miimstat;
W
wdenk 已提交
270 271 272 273

	return value;
}

274
/* #define to provide old read_phy_reg functionality without duplicating code */
P
Peter Tyser 已提交
275 276
#define read_phy_reg(priv,regnum) \
	tsec_local_mdio_read(priv->phyregs,priv->phyaddr,regnum)
A
Andy Fleming 已提交
277 278 279 280 281 282 283

#define TBIANA_SETTINGS ( \
		TBIANA_ASYMMETRIC_PAUSE \
		| TBIANA_SYMMETRIC_PAUSE \
		| TBIANA_FULL_DUPLEX \
		)

284
/* Force the TBI PHY into 1000Mbps full duplex when in SGMII mode */
A
Andy Fleming 已提交
285 286 287 288 289
#define TBICR_SETTINGS ( \
		TBICR_PHY_RESET \
		| TBICR_FULL_DUPLEX \
		| TBICR_SPEED1_SET \
		)
290

A
Andy Fleming 已提交
291 292 293
/* Configure the TBI for SGMII operation */
static void tsec_configure_serdes(struct tsec_private *priv)
{
P
Peter Tyser 已提交
294 295
	/* Access TBI PHY registers at given TSEC register offset as opposed
	 * to the register offset used for external PHY accesses */
296
	tsec_local_mdio_write(priv->phyregs_sgmii, priv->regs->tbipa, TBI_ANA,
A
Andy Fleming 已提交
297
			TBIANA_SETTINGS);
298
	tsec_local_mdio_write(priv->phyregs_sgmii, priv->regs->tbipa, TBI_TBICON,
A
Andy Fleming 已提交
299
			TBICON_CLK_SELECT);
300
	tsec_local_mdio_write(priv->phyregs_sgmii, priv->regs->tbipa, TBI_CR,
A
Andy Fleming 已提交
301 302
			TBICR_SETTINGS);
}
303

304 305 306 307 308
/* Discover which PHY is attached to the device, and configure it
 * properly.  If the PHY is not recognized, then return 0
 * (failure).  Otherwise, return 1
 */
static int init_phy(struct eth_device *dev)
W
wdenk 已提交
309
{
310 311
	struct tsec_private *priv = (struct tsec_private *)dev->priv;
	struct phy_info *curphy;
A
Andy Fleming 已提交
312
	volatile tsec_t *regs = priv->regs;
W
wdenk 已提交
313 314

	/* Assign a Physical address to the TBI */
315
	regs->tbipa = CONFIG_SYS_TBIPA_VALUE;
316
	asm("sync");
W
wdenk 已提交
317 318 319

	/* Reset MII (due to new addresses) */
	priv->phyregs->miimcfg = MIIMCFG_RESET;
E
Eran Liberty 已提交
320
	asm("sync");
W
wdenk 已提交
321
	priv->phyregs->miimcfg = MIIMCFG_INIT_VALUE;
E
Eran Liberty 已提交
322
	asm("sync");
323
	while (priv->phyregs->miimind & MIIMIND_BUSY) ;
W
wdenk 已提交
324

325 326 327
	/* Get the cmd structure corresponding to the attached
	 * PHY */
	curphy = get_phy_info(dev);
W
wdenk 已提交
328

329 330
	if (curphy == NULL) {
		priv->phyinfo = NULL;
331
		printf("%s: No PHY found\n", dev->name);
W
wdenk 已提交
332

333 334
		return 0;
	}
W
wdenk 已提交
335

A
Andy Fleming 已提交
336 337 338
	if (regs->ecntrl & ECNTRL_SGMII_MODE)
		tsec_configure_serdes(priv);

339
	priv->phyinfo = curphy;
W
wdenk 已提交
340

341
	phy_run_commands(priv, priv->phyinfo->config);
W
wdenk 已提交
342

343 344
	return 1;
}
W
wdenk 已提交
345

346 347 348 349
/*
 * Returns which value to write to the control register.
 * For 10/100, the value is slightly different
 */
350
static uint mii_cr_init(uint mii_reg, struct tsec_private * priv)
351
{
352
	if (priv->flags & TSEC_GIGABIT)
353
		return MIIM_CONTROL_INIT;
W
wdenk 已提交
354
	else
355 356
		return MIIM_CR_INIT;
}
W
wdenk 已提交
357

358 359
/*
 * Wait for auto-negotiation to complete, then determine link
360
 */
361
static uint mii_parse_sr(uint mii_reg, struct tsec_private * priv)
362
{
363
	/*
A
Andy Fleming 已提交
364 365
	 * Wait if the link is up, and autonegotiation is in progress
	 * (ie - we're capable and it's not done)
366 367
	 */
	mii_reg = read_phy_reg(priv, MIIM_STATUS);
368
	if ((mii_reg & PHY_BMSR_AUTN_ABLE) && !(mii_reg & PHY_BMSR_AUTN_COMP)) {
369 370
		int i = 0;

371
		puts("Waiting for PHY auto negotiation to complete");
A
Andy Fleming 已提交
372
		while (!(mii_reg & PHY_BMSR_AUTN_COMP)) {
373 374 375 376
			/*
			 * Timeout reached ?
			 */
			if (i > PHY_AUTONEGOTIATE_TIMEOUT) {
377
				puts(" TIMEOUT !\n");
378
				priv->link = 0;
379
				return 0;
380
			}
W
wdenk 已提交
381

382 383 384 385 386 387
			if (ctrlc()) {
				puts("user interrupt!\n");
				priv->link = 0;
				return -EINTR;
			}

388
			if ((i++ % 1000) == 0) {
389
				putc('.');
390
			}
391
			udelay(1000);	/* 1 ms */
392
			mii_reg = read_phy_reg(priv, MIIM_STATUS);
393
		}
394
		puts(" done\n");
395 396 397 398

		/* Link status bit is latched low, read it again */
		mii_reg = read_phy_reg(priv, MIIM_STATUS);

399
		udelay(500000);	/* another 500 ms (results in faster booting) */
W
wdenk 已提交
400 401
	}

402 403
	priv->link = mii_reg & MIIM_STATUS_LINK ? 1 : 0;

404 405
	return 0;
}
W
wdenk 已提交
406

407 408 409 410 411 412 413 414
/* Generic function which updates the speed and duplex.  If
 * autonegotiation is enabled, it uses the AND of the link
 * partner's advertised capabilities and our advertised
 * capabilities.  If autonegotiation is disabled, we use the
 * appropriate bits in the control register.
 *
 * Stolen from Linux's mii.c and phy_device.c
 */
415
static uint mii_parse_link(uint mii_reg, struct tsec_private *priv)
416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476
{
	/* We're using autonegotiation */
	if (mii_reg & PHY_BMSR_AUTN_ABLE) {
		uint lpa = 0;
		uint gblpa = 0;

		/* Check for gigabit capability */
		if (mii_reg & PHY_BMSR_EXT) {
			/* We want a list of states supported by
			 * both PHYs in the link
			 */
			gblpa = read_phy_reg(priv, PHY_1000BTSR);
			gblpa &= read_phy_reg(priv, PHY_1000BTCR) << 2;
		}

		/* Set the baseline so we only have to set them
		 * if they're different
		 */
		priv->speed = 10;
		priv->duplexity = 0;

		/* Check the gigabit fields */
		if (gblpa & (PHY_1000BTSR_1000FD | PHY_1000BTSR_1000HD)) {
			priv->speed = 1000;

			if (gblpa & PHY_1000BTSR_1000FD)
				priv->duplexity = 1;

			/* We're done! */
			return 0;
		}

		lpa = read_phy_reg(priv, PHY_ANAR);
		lpa &= read_phy_reg(priv, PHY_ANLPAR);

		if (lpa & (PHY_ANLPAR_TXFD | PHY_ANLPAR_TX)) {
			priv->speed = 100;

			if (lpa & PHY_ANLPAR_TXFD)
				priv->duplexity = 1;

		} else if (lpa & PHY_ANLPAR_10FD)
			priv->duplexity = 1;
	} else {
		uint bmcr = read_phy_reg(priv, PHY_BMCR);

		priv->speed = 10;
		priv->duplexity = 0;

		if (bmcr & PHY_BMCR_DPLX)
			priv->duplexity = 1;

		if (bmcr & PHY_BMCR_1000_MBPS)
			priv->speed = 1000;
		else if (bmcr & PHY_BMCR_100_MBPS)
			priv->speed = 100;
	}

	return 0;
}

Z
Zach LeRoy 已提交
477 478 479 480 481 482 483
/*
 * "Ethernet@Wirespeed" needs to be enabled to achieve link in certain
 * circumstances.  eg a gigabit TSEC connected to a gigabit switch with
 * a 4-wire ethernet cable.  Both ends advertise gigabit, but can't
 * link.  "Ethernet@Wirespeed" reduces advertised speed until link
 * can be achieved.
 */
484
static uint mii_BCM54xx_wirespeed(uint mii_reg, struct tsec_private *priv)
Z
Zach LeRoy 已提交
485 486 487 488
{
	return (read_phy_reg(priv, mii_reg) & 0x8FFF) | 0x8010;
}

489 490 491 492
/*
 * Parse the BCM54xx status register for speed and duplex information.
 * The linux sungem_phy has this information, but in a table format.
 */
493
static uint mii_parse_BCM54xx_sr(uint mii_reg, struct tsec_private *priv)
494
{
495 496 497
	/* If there is no link, speed and duplex don't matter */
	if (!priv->link)
		return 0;
498

499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529
	switch ((mii_reg & MIIM_BCM54xx_AUXSTATUS_LINKMODE_MASK) >>
		MIIM_BCM54xx_AUXSTATUS_LINKMODE_SHIFT) {
	case 1:
		priv->duplexity = 0;
		priv->speed = 10;
		break;
	case 2:
		priv->duplexity = 1;
		priv->speed = 10;
		break;
	case 3:
		priv->duplexity = 0;
		priv->speed = 100;
		break;
	case 5:
		priv->duplexity = 1;
		priv->speed = 100;
		break;
	case 6:
		priv->duplexity = 0;
		priv->speed = 1000;
		break;
	case 7:
		priv->duplexity = 1;
		priv->speed = 1000;
		break;
	default:
		printf("Auto-neg error, defaulting to 10BT/HD\n");
		priv->duplexity = 0;
		priv->speed = 10;
		break;
530 531 532
	}

	return 0;
533
}
534

535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565
/*
 * Find out if PHY is in copper or serdes mode by looking at Expansion Reg
 * 0x42 - "Operating Mode Status Register"
 */
static int BCM8482_is_serdes(struct tsec_private *priv)
{
	u16 val;
	int serdes = 0;

	write_phy_reg(priv, MIIM_BCM54XX_EXP_SEL, MIIM_BCM54XX_EXP_SEL_ER | 0x42);
	val = read_phy_reg(priv, MIIM_BCM54XX_EXP_DATA);

	switch (val & 0x1f) {
	case 0x0d:	/* RGMII-to-100Base-FX */
	case 0x0e:	/* RGMII-to-SGMII */
	case 0x0f:	/* RGMII-to-SerDes */
	case 0x12:	/* SGMII-to-SerDes */
	case 0x13:	/* SGMII-to-100Base-FX */
	case 0x16:	/* SerDes-to-Serdes */
		serdes = 1;
		break;
	case 0x6:	/* RGMII-to-Copper */
	case 0x14:	/* SGMII-to-Copper */
	case 0x17:	/* SerDes-to-Copper */
		break;
	default:
		printf("ERROR, invalid PHY mode (0x%x\n)", val);
		break;
	}

	return serdes;
566
}
567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619

/*
 * Determine SerDes link speed and duplex from Expansion reg 0x42 "Operating
 * Mode Status Register"
 */
uint mii_parse_BCM5482_serdes_sr(struct tsec_private *priv)
{
	u16 val;
	int i = 0;

	/* Wait 1s for link - Clause 37 autonegotiation happens very fast */
	while (1) {
		write_phy_reg(priv, MIIM_BCM54XX_EXP_SEL,
				MIIM_BCM54XX_EXP_SEL_ER | 0x42);
		val = read_phy_reg(priv, MIIM_BCM54XX_EXP_DATA);

		if (val & 0x8000)
			break;

		if (i++ > 1000) {
			priv->link = 0;
			return 1;
		}

		udelay(1000);	/* 1 ms */
	}

	priv->link = 1;
	switch ((val >> 13) & 0x3) {
	case (0x00):
		priv->speed = 10;
		break;
	case (0x01):
		priv->speed = 100;
		break;
	case (0x02):
		priv->speed = 1000;
		break;
	}

	priv->duplexity = (val & 0x1000) == 0x1000;

	return 0;
}

/*
 * Figure out if BCM5482 is in serdes or copper mode and determine link
 * configuration accordingly
 */
static uint mii_parse_BCM5482_sr(uint mii_reg, struct tsec_private *priv)
{
	if (BCM8482_is_serdes(priv)) {
		mii_parse_BCM5482_serdes_sr(priv);
P
Peter Tyser 已提交
620
		priv->flags |= TSEC_FIBER;
621 622 623 624 625 626 627 628 629 630 631 632
	} else {
		/* Wait for auto-negotiation to complete or fail */
		mii_parse_sr(mii_reg, priv);

		/* Parse BCM54xx copper aux status register */
		mii_reg = read_phy_reg(priv, MIIM_BCM54xx_AUXSTATUS);
		mii_parse_BCM54xx_sr(mii_reg, priv);
	}

	return 0;
}

633
/* Parse the 88E1011's status register for speed and duplex
634 635
 * information
 */
636
static uint mii_parse_88E1011_psr(uint mii_reg, struct tsec_private * priv)
637 638 639
{
	uint speed;

640 641
	mii_reg = read_phy_reg(priv, MIIM_88E1011_PHY_STATUS);

A
Andy Fleming 已提交
642 643
	if ((mii_reg & MIIM_88E1011_PHYSTAT_LINK) &&
		!(mii_reg & MIIM_88E1011_PHYSTAT_SPDDONE)) {
644 645
		int i = 0;

646
		puts("Waiting for PHY realtime link");
A
Andy Fleming 已提交
647 648
		while (!(mii_reg & MIIM_88E1011_PHYSTAT_SPDDONE)) {
			/* Timeout reached ? */
649
			if (i > PHY_AUTONEGOTIATE_TIMEOUT) {
650
				puts(" TIMEOUT !\n");
651 652 653 654 655
				priv->link = 0;
				break;
			}

			if ((i++ % 1000) == 0) {
656
				putc('.');
657
			}
658
			udelay(1000);	/* 1 ms */
659 660
			mii_reg = read_phy_reg(priv, MIIM_88E1011_PHY_STATUS);
		}
661 662
		puts(" done\n");
		udelay(500000);	/* another 500 ms (results in faster booting) */
A
Andy Fleming 已提交
663 664 665 666 667
	} else {
		if (mii_reg & MIIM_88E1011_PHYSTAT_LINK)
			priv->link = 1;
		else
			priv->link = 0;
668 669
	}

670
	if (mii_reg & MIIM_88E1011_PHYSTAT_DUPLEX)
671 672 673 674
		priv->duplexity = 1;
	else
		priv->duplexity = 0;

675
	speed = (mii_reg & MIIM_88E1011_PHYSTAT_SPEED);
676

677 678 679 680 681 682 683 684 685
	switch (speed) {
	case MIIM_88E1011_PHYSTAT_GBIT:
		priv->speed = 1000;
		break;
	case MIIM_88E1011_PHYSTAT_100:
		priv->speed = 100;
		break;
	default:
		priv->speed = 10;
W
wdenk 已提交
686 687
	}

688 689
	return 0;
}
W
wdenk 已提交
690

691 692 693
/* Parse the RTL8211B's status register for speed and duplex
 * information
 */
694
static uint mii_parse_RTL8211B_sr(uint mii_reg, struct tsec_private * priv)
695 696 697 698
{
	uint speed;

	mii_reg = read_phy_reg(priv, MIIM_RTL8211B_PHY_STATUS);
699
	if (!(mii_reg & MIIM_RTL8211B_PHYSTAT_SPDDONE)) {
700 701
		int i = 0;

702 703
		/* in case of timeout ->link is cleared */
		priv->link = 1;
704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748
		puts("Waiting for PHY realtime link");
		while (!(mii_reg & MIIM_RTL8211B_PHYSTAT_SPDDONE)) {
			/* Timeout reached ? */
			if (i > PHY_AUTONEGOTIATE_TIMEOUT) {
				puts(" TIMEOUT !\n");
				priv->link = 0;
				break;
			}

			if ((i++ % 1000) == 0) {
				putc('.');
			}
			udelay(1000);	/* 1 ms */
			mii_reg = read_phy_reg(priv, MIIM_RTL8211B_PHY_STATUS);
		}
		puts(" done\n");
		udelay(500000);	/* another 500 ms (results in faster booting) */
	} else {
		if (mii_reg & MIIM_RTL8211B_PHYSTAT_LINK)
			priv->link = 1;
		else
			priv->link = 0;
	}

	if (mii_reg & MIIM_RTL8211B_PHYSTAT_DUPLEX)
		priv->duplexity = 1;
	else
		priv->duplexity = 0;

	speed = (mii_reg & MIIM_RTL8211B_PHYSTAT_SPEED);

	switch (speed) {
	case MIIM_RTL8211B_PHYSTAT_GBIT:
		priv->speed = 1000;
		break;
	case MIIM_RTL8211B_PHYSTAT_100:
		priv->speed = 100;
		break;
	default:
		priv->speed = 10;
	}

	return 0;
}

749
/* Parse the cis8201's status register for speed and duplex
750 751
 * information
 */
752
static uint mii_parse_cis8201(uint mii_reg, struct tsec_private * priv)
753 754 755
{
	uint speed;

756
	if (mii_reg & MIIM_CIS8201_AUXCONSTAT_DUPLEX)
757 758 759 760 761
		priv->duplexity = 1;
	else
		priv->duplexity = 0;

	speed = mii_reg & MIIM_CIS8201_AUXCONSTAT_SPEED;
762 763 764 765 766 767 768 769 770 771
	switch (speed) {
	case MIIM_CIS8201_AUXCONSTAT_GBIT:
		priv->speed = 1000;
		break;
	case MIIM_CIS8201_AUXCONSTAT_100:
		priv->speed = 100;
		break;
	default:
		priv->speed = 10;
		break;
W
wdenk 已提交
772 773
	}

774 775
	return 0;
}
776

777
/* Parse the vsc8244's status register for speed and duplex
778 779
 * information
 */
780
static uint mii_parse_vsc8244(uint mii_reg, struct tsec_private * priv)
781
{
782
	uint speed;
W
wdenk 已提交
783

784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803
	if (mii_reg & MIIM_VSC8244_AUXCONSTAT_DUPLEX)
		priv->duplexity = 1;
	else
		priv->duplexity = 0;

	speed = mii_reg & MIIM_VSC8244_AUXCONSTAT_SPEED;
	switch (speed) {
	case MIIM_VSC8244_AUXCONSTAT_GBIT:
		priv->speed = 1000;
		break;
	case MIIM_VSC8244_AUXCONSTAT_100:
		priv->speed = 100;
		break;
	default:
		priv->speed = 10;
		break;
	}

	return 0;
}
804 805

/* Parse the DM9161's status register for speed and duplex
806 807
 * information
 */
808
static uint mii_parse_dm9161_scsr(uint mii_reg, struct tsec_private * priv)
809
{
810
	if (mii_reg & (MIIM_DM9161_SCSR_100F | MIIM_DM9161_SCSR_100H))
811 812 813 814
		priv->speed = 100;
	else
		priv->speed = 10;

815
	if (mii_reg & (MIIM_DM9161_SCSR_100F | MIIM_DM9161_SCSR_10F))
816 817 818 819 820 821 822
		priv->duplexity = 1;
	else
		priv->duplexity = 0;

	return 0;
}

823 824 825
/*
 * Hack to write all 4 PHYs with the LED values
 */
826
static uint mii_cis8204_fixled(uint mii_reg, struct tsec_private * priv)
827 828
{
	uint phyid;
829
	volatile tsec_mdio_t *regbase = priv->phyregs;
830
	int timeout = 1000000;
831

832
	for (phyid = 0; phyid < 4; phyid++) {
833 834
		regbase->miimadd = (phyid << 8) | mii_reg;
		regbase->miimcon = MIIM_CIS8204_SLEDCON_INIT;
E
Eran Liberty 已提交
835
		asm("sync");
836

837 838
		timeout = 1000000;
		while ((regbase->miimind & MIIMIND_BUSY) && timeout--) ;
W
wdenk 已提交
839 840
	}

841
	return MIIM_CIS8204_SLEDCON_INIT;
W
wdenk 已提交
842 843
}

844
static uint mii_cis8204_setmode(uint mii_reg, struct tsec_private * priv)
845 846 847 848 849 850
{
	if (priv->flags & TSEC_REDUCED)
		return MIIM_CIS8204_EPHYCON_INIT | MIIM_CIS8204_EPHYCON_RGMII;
	else
		return MIIM_CIS8204_EPHYCON_INIT;
}
W
wdenk 已提交
851

852
static uint mii_m88e1111s_setmode(uint mii_reg, struct tsec_private *priv)
853 854 855 856 857 858 859 860
{
	uint mii_data = read_phy_reg(priv, mii_reg);

	if (priv->flags & TSEC_REDUCED)
		mii_data = (mii_data & 0xfff0) | 0x000b;
	return mii_data;
}

861 862
/* Initialized required registers to appropriate values, zeroing
 * those we don't care about (unless zero is bad, in which case,
863 864 865
 * choose a more appropriate value)
 */
static void init_registers(volatile tsec_t * regs)
W
wdenk 已提交
866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906
{
	/* Clear IEVENT */
	regs->ievent = IEVENT_INIT_CLEAR;

	regs->imask = IMASK_INIT_CLEAR;

	regs->hash.iaddr0 = 0;
	regs->hash.iaddr1 = 0;
	regs->hash.iaddr2 = 0;
	regs->hash.iaddr3 = 0;
	regs->hash.iaddr4 = 0;
	regs->hash.iaddr5 = 0;
	regs->hash.iaddr6 = 0;
	regs->hash.iaddr7 = 0;

	regs->hash.gaddr0 = 0;
	regs->hash.gaddr1 = 0;
	regs->hash.gaddr2 = 0;
	regs->hash.gaddr3 = 0;
	regs->hash.gaddr4 = 0;
	regs->hash.gaddr5 = 0;
	regs->hash.gaddr6 = 0;
	regs->hash.gaddr7 = 0;

	regs->rctrl = 0x00000000;

	/* Init RMON mib registers */
	memset((void *)&(regs->rmon), 0, sizeof(rmon_mib_t));

	regs->rmon.cam1 = 0xffffffff;
	regs->rmon.cam2 = 0xffffffff;

	regs->mrblr = MRBLR_INIT_SETTINGS;

	regs->minflr = MINFLR_INIT_SETTINGS;

	regs->attr = ATTR_INIT_SETTINGS;
	regs->attreli = ATTRELI_INIT_SETTINGS;

}

907
/* Configure maccfg2 based on negotiated speed and duplex
908 909
 * reported by PHY handling code
 */
910 911 912 913 914
static void adjust_link(struct eth_device *dev)
{
	struct tsec_private *priv = (struct tsec_private *)dev->priv;
	volatile tsec_t *regs = priv->regs;

915 916
	if (priv->link) {
		if (priv->duplexity != 0)
917 918 919 920
			regs->maccfg2 |= MACCFG2_FULL_DUPLEX;
		else
			regs->maccfg2 &= ~(MACCFG2_FULL_DUPLEX);

921 922 923 924 925 926 927 928 929 930
		switch (priv->speed) {
		case 1000:
			regs->maccfg2 = ((regs->maccfg2 & ~(MACCFG2_IF))
					 | MACCFG2_GMII);
			break;
		case 100:
		case 10:
			regs->maccfg2 = ((regs->maccfg2 & ~(MACCFG2_IF))
					 | MACCFG2_MII);

931 932
			/* Set R100 bit in all modes although
			 * it is only used in RGMII mode
933
			 */
934
			if (priv->speed == 100)
935 936 937 938 939 940 941
				regs->ecntrl |= ECNTRL_R100;
			else
				regs->ecntrl &= ~(ECNTRL_R100);
			break;
		default:
			printf("%s: Speed was bad\n", dev->name);
			break;
942 943
		}

P
Peter Tyser 已提交
944 945 946
		printf("Speed: %d, %s duplex%s\n", priv->speed,
		       (priv->duplexity) ? "full" : "half",
		       (priv->flags & TSEC_FIBER) ? ", fiber mode" : "");
947 948 949 950 951 952 953

	} else {
		printf("%s: No link.\n", dev->name);
	}
}

/* Set up the buffers and their descriptors, and bring up the
954 955
 * interface
 */
956
static void startup_tsec(struct eth_device *dev)
W
wdenk 已提交
957 958
{
	int i;
959 960
	struct tsec_private *priv = (struct tsec_private *)dev->priv;
	volatile tsec_t *regs = priv->regs;
W
wdenk 已提交
961 962 963 964 965 966 967 968 969

	/* Point to the buffer descriptors */
	regs->tbase = (unsigned int)(&rtx.txbd[txIdx]);
	regs->rbase = (unsigned int)(&rtx.rxbd[rxIdx]);

	/* Initialize the Rx Buffer descriptors */
	for (i = 0; i < PKTBUFSRX; i++) {
		rtx.rxbd[i].status = RXBD_EMPTY;
		rtx.rxbd[i].length = 0;
970
		rtx.rxbd[i].bufPtr = (uint) NetRxPackets[i];
W
wdenk 已提交
971
	}
972
	rtx.rxbd[PKTBUFSRX - 1].status |= RXBD_WRAP;
W
wdenk 已提交
973 974

	/* Initialize the TX Buffer Descriptors */
975
	for (i = 0; i < TX_BUF_CNT; i++) {
W
wdenk 已提交
976 977 978 979
		rtx.txbd[i].status = 0;
		rtx.txbd[i].length = 0;
		rtx.txbd[i].bufPtr = 0;
	}
980
	rtx.txbd[TX_BUF_CNT - 1].status |= TXBD_WRAP;
W
wdenk 已提交
981

982
	/* Start up the PHY */
983 984
	if(priv->phyinfo)
		phy_run_commands(priv, priv->phyinfo->startup);
985

986 987
	adjust_link(dev);

W
wdenk 已提交
988 989 990 991 992 993
	/* Enable Transmit and Receive */
	regs->maccfg1 |= (MACCFG1_RX_EN | MACCFG1_TX_EN);

	/* Tell the DMA it is clear to go */
	regs->dmactrl |= DMACTRL_INIT_SETTINGS;
	regs->tstat = TSTAT_CLEAR_THALT;
994
	regs->rstat = RSTAT_CLEAR_RHALT;
W
wdenk 已提交
995 996 997
	regs->dmactrl &= ~(DMACTRL_GRS | DMACTRL_GTS);
}

W
wdenk 已提交
998
/* This returns the status bits of the device.	The return value
W
wdenk 已提交
999
 * is never checked, and this is what the 8260 driver did, so we
W
wdenk 已提交
1000
 * do the same.	 Presumably, this would be zero if there were no
1001 1002 1003
 * errors
 */
static int tsec_send(struct eth_device *dev, volatile void *packet, int length)
W
wdenk 已提交
1004 1005 1006
{
	int i;
	int result = 0;
1007 1008
	struct tsec_private *priv = (struct tsec_private *)dev->priv;
	volatile tsec_t *regs = priv->regs;
W
wdenk 已提交
1009 1010

	/* Find an empty buffer descriptor */
1011
	for (i = 0; rtx.txbd[txIdx].status & TXBD_READY; i++) {
W
wdenk 已提交
1012
		if (i >= TOUT_LOOP) {
1013
			debug("%s: tsec: tx buffers full\n", dev->name);
W
wdenk 已提交
1014 1015 1016 1017
			return result;
		}
	}

1018
	rtx.txbd[txIdx].bufPtr = (uint) packet;
W
wdenk 已提交
1019
	rtx.txbd[txIdx].length = length;
1020 1021
	rtx.txbd[txIdx].status |=
	    (TXBD_READY | TXBD_LAST | TXBD_CRC | TXBD_INTERRUPT);
W
wdenk 已提交
1022 1023 1024 1025 1026

	/* Tell the DMA to go */
	regs->tstat = TSTAT_CLEAR_THALT;

	/* Wait for buffer to be transmitted */
1027
	for (i = 0; rtx.txbd[txIdx].status & TXBD_READY; i++) {
W
wdenk 已提交
1028
		if (i >= TOUT_LOOP) {
1029
			debug("%s: tsec: tx error\n", dev->name);
W
wdenk 已提交
1030 1031 1032 1033 1034 1035 1036 1037 1038 1039
			return result;
		}
	}

	txIdx = (txIdx + 1) % TX_BUF_CNT;
	result = rtx.txbd[txIdx].status & TXBD_STATS;

	return result;
}

1040
static int tsec_recv(struct eth_device *dev)
W
wdenk 已提交
1041 1042
{
	int length;
1043 1044
	struct tsec_private *priv = (struct tsec_private *)dev->priv;
	volatile tsec_t *regs = priv->regs;
W
wdenk 已提交
1045

1046
	while (!(rtx.rxbd[rxIdx].status & RXBD_EMPTY)) {
W
wdenk 已提交
1047 1048 1049 1050 1051 1052

		length = rtx.rxbd[rxIdx].length;

		/* Send the packet up if there were no errors */
		if (!(rtx.rxbd[rxIdx].status & RXBD_STATS)) {
			NetReceive(NetRxPackets[rxIdx], length - 4);
1053 1054
		} else {
			printf("Got error %x\n",
1055
			       (rtx.rxbd[rxIdx].status & RXBD_STATS));
W
wdenk 已提交
1056 1057 1058 1059 1060
		}

		rtx.rxbd[rxIdx].length = 0;

		/* Set the wrap bit if this is the last element in the list */
1061 1062
		rtx.rxbd[rxIdx].status =
		    RXBD_EMPTY | (((rxIdx + 1) == PKTBUFSRX) ? RXBD_WRAP : 0);
W
wdenk 已提交
1063 1064 1065 1066

		rxIdx = (rxIdx + 1) % PKTBUFSRX;
	}

1067
	if (regs->ievent & IEVENT_BSY) {
W
wdenk 已提交
1068 1069 1070 1071 1072 1073 1074 1075
		regs->ievent = IEVENT_BSY;
		regs->rstat = RSTAT_CLEAR_RHALT;
	}

	return -1;

}

1076
/* Stop the interface */
1077
static void tsec_halt(struct eth_device *dev)
W
wdenk 已提交
1078
{
1079 1080
	struct tsec_private *priv = (struct tsec_private *)dev->priv;
	volatile tsec_t *regs = priv->regs;
W
wdenk 已提交
1081 1082 1083 1084

	regs->dmactrl &= ~(DMACTRL_GRS | DMACTRL_GTS);
	regs->dmactrl |= (DMACTRL_GRS | DMACTRL_GTS);

1085
	while (!(regs->ievent & (IEVENT_GRSC | IEVENT_GTSC))) ;
W
wdenk 已提交
1086 1087 1088

	regs->maccfg1 &= ~(MACCFG1_TX_EN | MACCFG1_RX_EN);

1089
	/* Shut down the PHY, as needed */
1090 1091
	if(priv->phyinfo)
		phy_run_commands(priv, priv->phyinfo->shutdown);
1092 1093
}

1094
static struct phy_info phy_info_M88E1149S = {
1095 1096 1097
	0x1410ca,
	"Marvell 88E1149S",
	4,
P
Peter Tyser 已提交
1098
	(struct phy_cmd[]) {     /* config */
1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111
		/* Reset and configure the PHY */
		{MIIM_CONTROL, MIIM_CONTROL_RESET, NULL},
		{0x1d, 0x1f, NULL},
		{0x1e, 0x200c, NULL},
		{0x1d, 0x5, NULL},
		{0x1e, 0x0, NULL},
		{0x1e, 0x100, NULL},
		{MIIM_GBIT_CONTROL, MIIM_GBIT_CONTROL_INIT, NULL},
		{MIIM_ANAR, MIIM_ANAR_INIT, NULL},
		{MIIM_CONTROL, MIIM_CONTROL_RESET, NULL},
		{MIIM_CONTROL, MIIM_CONTROL_INIT, &mii_cr_init},
		{miim_end,}
	},
P
Peter Tyser 已提交
1112
	(struct phy_cmd[]) {     /* startup */
1113 1114 1115 1116 1117
		/* Status is read once to clear old link state */
		{MIIM_STATUS, miim_read, NULL},
		/* Auto-negotiate */
		{MIIM_STATUS, miim_read, &mii_parse_sr},
		/* Read the status */
P
Peter Tyser 已提交
1118
		{MIIM_88E1011_PHY_STATUS, miim_read, &mii_parse_88E1011_psr},
1119 1120
		{miim_end,}
	},
P
Peter Tyser 已提交
1121
	(struct phy_cmd[]) {     /* shutdown */
1122 1123
		{miim_end,}
	},
1124 1125
};

1126
/* The 5411 id is 0x206070, the 5421 is 0x2060e0 */
1127
static struct phy_info phy_info_BCM5461S = {
1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153
	0x02060c1,	/* 5461 ID */
	"Broadcom BCM5461S",
	0, /* not clear to me what minor revisions we can shift away */
	(struct phy_cmd[]) { /* config */
		/* Reset and configure the PHY */
		{MIIM_CONTROL, MIIM_CONTROL_RESET, NULL},
		{MIIM_GBIT_CONTROL, MIIM_GBIT_CONTROL_INIT, NULL},
		{MIIM_ANAR, MIIM_ANAR_INIT, NULL},
		{MIIM_CONTROL, MIIM_CONTROL_RESET, NULL},
		{MIIM_CONTROL, MIIM_CONTROL_INIT, &mii_cr_init},
		{miim_end,}
	},
	(struct phy_cmd[]) { /* startup */
		/* Status is read once to clear old link state */
		{MIIM_STATUS, miim_read, NULL},
		/* Auto-negotiate */
		{MIIM_STATUS, miim_read, &mii_parse_sr},
		/* Read the status */
		{MIIM_BCM54xx_AUXSTATUS, miim_read, &mii_parse_BCM54xx_sr},
		{miim_end,}
	},
	(struct phy_cmd[]) { /* shutdown */
		{miim_end,}
	},
};

1154
static struct phy_info phy_info_BCM5464S = {
J
Joe Hamman 已提交
1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180
	0x02060b1,	/* 5464 ID */
	"Broadcom BCM5464S",
	0, /* not clear to me what minor revisions we can shift away */
	(struct phy_cmd[]) { /* config */
		/* Reset and configure the PHY */
		{MIIM_CONTROL, MIIM_CONTROL_RESET, NULL},
		{MIIM_GBIT_CONTROL, MIIM_GBIT_CONTROL_INIT, NULL},
		{MIIM_ANAR, MIIM_ANAR_INIT, NULL},
		{MIIM_CONTROL, MIIM_CONTROL_RESET, NULL},
		{MIIM_CONTROL, MIIM_CONTROL_INIT, &mii_cr_init},
		{miim_end,}
	},
	(struct phy_cmd[]) { /* startup */
		/* Status is read once to clear old link state */
		{MIIM_STATUS, miim_read, NULL},
		/* Auto-negotiate */
		{MIIM_STATUS, miim_read, &mii_parse_sr},
		/* Read the status */
		{MIIM_BCM54xx_AUXSTATUS, miim_read, &mii_parse_BCM54xx_sr},
		{miim_end,}
	},
	(struct phy_cmd[]) { /* shutdown */
		{miim_end,}
	},
};

1181
static struct phy_info phy_info_BCM5482S =  {
Z
Zach LeRoy 已提交
1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192
	0x0143bcb,
	"Broadcom BCM5482S",
	4,
	(struct phy_cmd[]) { /* config */
		/* Reset and configure the PHY */
		{MIIM_CONTROL, MIIM_CONTROL_RESET, NULL},
		/* Setup read from auxilary control shadow register 7 */
		{MIIM_BCM54xx_AUXCNTL, MIIM_BCM54xx_AUXCNTL_ENCODE(7), NULL},
		/* Read Misc Control register and or in Ethernet@Wirespeed */
		{MIIM_BCM54xx_AUXCNTL, 0, &mii_BCM54xx_wirespeed},
		{MIIM_CONTROL, MIIM_CONTROL_INIT, &mii_cr_init},
1193 1194 1195 1196 1197 1198 1199
		/* Initial config/enable of secondary SerDes interface */
		{MIIM_BCM54XX_SHD, MIIM_BCM54XX_SHD_WR_ENCODE(0x14, 0xf), NULL},
		/* Write intial value to secondary SerDes Contol */
		{MIIM_BCM54XX_EXP_SEL, MIIM_BCM54XX_EXP_SEL_SSD | 0, NULL},
		{MIIM_BCM54XX_EXP_DATA, MIIM_CONTROL_RESTART, NULL},
		/* Enable copper/fiber auto-detect */
		{MIIM_BCM54XX_SHD, MIIM_BCM54XX_SHD_WR_ENCODE(0x1e, 0x201)},
Z
Zach LeRoy 已提交
1200 1201 1202 1203 1204
		{miim_end,}
	},
	(struct phy_cmd[]) { /* startup */
		/* Status is read once to clear old link state */
		{MIIM_STATUS, miim_read, NULL},
1205 1206
		/* Determine copper/fiber, auto-negotiate, and read the result */
		{MIIM_STATUS, miim_read, &mii_parse_BCM5482_sr},
Z
Zach LeRoy 已提交
1207 1208 1209 1210 1211 1212 1213
		{miim_end,}
	},
	(struct phy_cmd[]) { /* shutdown */
		{miim_end,}
	},
};

1214
static struct phy_info phy_info_M88E1011S = {
1215 1216 1217
	0x01410c6,
	"Marvell 88E1011S",
	4,
P
Peter Tyser 已提交
1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243
	(struct phy_cmd[]) {	/* config */
		/* Reset and configure the PHY */
		{MIIM_CONTROL, MIIM_CONTROL_RESET, NULL},
		{0x1d, 0x1f, NULL},
		{0x1e, 0x200c, NULL},
		{0x1d, 0x5, NULL},
		{0x1e, 0x0, NULL},
		{0x1e, 0x100, NULL},
		{MIIM_GBIT_CONTROL, MIIM_GBIT_CONTROL_INIT, NULL},
		{MIIM_ANAR, MIIM_ANAR_INIT, NULL},
		{MIIM_CONTROL, MIIM_CONTROL_RESET, NULL},
		{MIIM_CONTROL, MIIM_CONTROL_INIT, &mii_cr_init},
		{miim_end,}
	},
	(struct phy_cmd[]) {	/* startup */
		/* Status is read once to clear old link state */
		{MIIM_STATUS, miim_read, NULL},
		/* Auto-negotiate */
		{MIIM_STATUS, miim_read, &mii_parse_sr},
		/* Read the status */
		{MIIM_88E1011_PHY_STATUS, miim_read, &mii_parse_88E1011_psr},
		{miim_end,}
	},
	(struct phy_cmd[]) {	/* shutdown */
		{miim_end,}
	},
1244 1245
};

1246
static struct phy_info phy_info_M88E1111S = {
W
wdenk 已提交
1247 1248 1249
	0x01410cc,
	"Marvell 88E1111S",
	4,
P
Peter Tyser 已提交
1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272
	(struct phy_cmd[]) {	/* config */
		/* Reset and configure the PHY */
		{MIIM_CONTROL, MIIM_CONTROL_RESET, NULL},
		{0x1b, 0x848f, &mii_m88e1111s_setmode},
		{0x14, 0x0cd2, NULL}, /* Delay RGMII TX and RX */
		{MIIM_GBIT_CONTROL, MIIM_GBIT_CONTROL_INIT, NULL},
		{MIIM_ANAR, MIIM_ANAR_INIT, NULL},
		{MIIM_CONTROL, MIIM_CONTROL_RESET, NULL},
		{MIIM_CONTROL, MIIM_CONTROL_INIT, &mii_cr_init},
		{miim_end,}
	},
	(struct phy_cmd[]) {	/* startup */
		/* Status is read once to clear old link state */
		{MIIM_STATUS, miim_read, NULL},
		/* Auto-negotiate */
		{MIIM_STATUS, miim_read, &mii_parse_sr},
		/* Read the status */
		{MIIM_88E1011_PHY_STATUS, miim_read, &mii_parse_88E1011_psr},
		{miim_end,}
	},
	(struct phy_cmd[]) {	/* shutdown */
		{miim_end,}
	},
W
wdenk 已提交
1273 1274
};

1275
static struct phy_info phy_info_M88E1118 = {
1276 1277 1278
	0x01410e1,
	"Marvell 88E1118",
	4,
P
Peter Tyser 已提交
1279
	(struct phy_cmd[]) {	/* config */
1280 1281 1282 1283
		/* Reset and configure the PHY */
		{MIIM_CONTROL, MIIM_CONTROL_RESET, NULL},
		{0x16, 0x0002, NULL}, /* Change Page Number */
		{0x15, 0x1070, NULL}, /* Delay RGMII TX and RX */
R
Ron Madrid 已提交
1284 1285 1286
		{0x16, 0x0003, NULL}, /* Change Page Number */
		{0x10, 0x021e, NULL}, /* Adjust LED control */
		{0x16, 0x0000, NULL}, /* Change Page Number */
1287 1288 1289 1290 1291
		{MIIM_GBIT_CONTROL, MIIM_GBIT_CONTROL_INIT, NULL},
		{MIIM_ANAR, MIIM_ANAR_INIT, NULL},
		{MIIM_CONTROL, MIIM_CONTROL_RESET, NULL},
		{MIIM_CONTROL, MIIM_CONTROL_INIT, &mii_cr_init},
		{miim_end,}
P
Peter Tyser 已提交
1292 1293
	},
	(struct phy_cmd[]) {	/* startup */
1294 1295 1296 1297
		{0x16, 0x0000, NULL}, /* Change Page Number */
		/* Status is read once to clear old link state */
		{MIIM_STATUS, miim_read, NULL},
		/* Auto-negotiate */
R
Ron Madrid 已提交
1298
		{MIIM_STATUS, miim_read, &mii_parse_sr},
1299 1300 1301 1302
		/* Read the status */
		{MIIM_88E1011_PHY_STATUS, miim_read,
		 &mii_parse_88E1011_psr},
		{miim_end,}
P
Peter Tyser 已提交
1303 1304
	},
	(struct phy_cmd[]) {	/* shutdown */
1305
		{miim_end,}
P
Peter Tyser 已提交
1306
	},
1307 1308
};

1309 1310 1311 1312
/*
 *  Since to access LED register we need do switch the page, we
 * do LED configuring in the miim_read-like function as follows
 */
1313
static uint mii_88E1121_set_led (uint mii_reg, struct tsec_private *priv)
1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329
{
	uint pg;

	/* Switch the page to access the led register */
	pg = read_phy_reg(priv, MIIM_88E1121_PHY_PAGE);
	write_phy_reg(priv, MIIM_88E1121_PHY_PAGE, MIIM_88E1121_PHY_LED_PAGE);

	/* Configure leds */
	write_phy_reg(priv, MIIM_88E1121_PHY_LED_CTRL,
		      MIIM_88E1121_PHY_LED_DEF);

	/* Restore the page pointer */
	write_phy_reg(priv, MIIM_88E1121_PHY_PAGE, pg);
	return 0;
}

1330
static struct phy_info phy_info_M88E1121R = {
1331 1332 1333
	0x01410cb,
	"Marvell 88E1121R",
	4,
P
Peter Tyser 已提交
1334 1335 1336 1337 1338 1339 1340 1341 1342 1343 1344 1345 1346 1347 1348 1349 1350 1351 1352 1353 1354 1355 1356
	(struct phy_cmd[]) {	/* config */
		/* Reset and configure the PHY */
		{MIIM_CONTROL, MIIM_CONTROL_RESET, NULL},
		{MIIM_GBIT_CONTROL, MIIM_GBIT_CONTROL_INIT, NULL},
		{MIIM_ANAR, MIIM_ANAR_INIT, NULL},
		/* Configure leds */
		{MIIM_88E1121_PHY_LED_CTRL, miim_read, &mii_88E1121_set_led},
		{MIIM_CONTROL, MIIM_CONTROL_INIT, &mii_cr_init},
		/* Disable IRQs and de-assert interrupt */
		{MIIM_88E1121_PHY_IRQ_EN, 0, NULL},
		{MIIM_88E1121_PHY_IRQ_STATUS, miim_read, NULL},
		{miim_end,}
	},
	(struct phy_cmd[]) {	/* startup */
		/* Status is read once to clear old link state */
		{MIIM_STATUS, miim_read, NULL},
		{MIIM_STATUS, miim_read, &mii_parse_sr},
		{MIIM_STATUS, miim_read, &mii_parse_link},
		{miim_end,}
	},
	(struct phy_cmd[]) {	/* shutdown */
		{miim_end,}
	},
1357 1358
};

1359 1360 1361 1362 1363 1364 1365
static unsigned int m88e1145_setmode(uint mii_reg, struct tsec_private *priv)
{
	uint mii_data = read_phy_reg(priv, mii_reg);

	/* Setting MIIM_88E1145_PHY_EXT_CR */
	if (priv->flags & TSEC_REDUCED)
		return mii_data |
1366
		    MIIM_M88E1145_RGMII_RX_DELAY | MIIM_M88E1145_RGMII_TX_DELAY;
1367 1368 1369 1370 1371 1372 1373 1374
	else
		return mii_data;
}

static struct phy_info phy_info_M88E1145 = {
	0x01410cd,
	"Marvell 88E1145",
	4,
P
Peter Tyser 已提交
1375 1376 1377 1378 1379 1380 1381 1382 1383 1384 1385 1386 1387 1388 1389 1390 1391 1392 1393 1394 1395 1396 1397 1398 1399 1400 1401 1402 1403 1404 1405 1406
	(struct phy_cmd[]) {	/* config */
		/* Reset the PHY */
		{MIIM_CONTROL, MIIM_CONTROL_RESET, NULL},

		/* Errata E0, E1 */
		{29, 0x001b, NULL},
		{30, 0x418f, NULL},
		{29, 0x0016, NULL},
		{30, 0xa2da, NULL},

		/* Configure the PHY */
		{MIIM_GBIT_CONTROL, MIIM_GBIT_CONTROL_INIT, NULL},
		{MIIM_ANAR, MIIM_ANAR_INIT, NULL},
		{MIIM_88E1011_PHY_SCR, MIIM_88E1011_PHY_MDI_X_AUTO, NULL},
		{MIIM_88E1145_PHY_EXT_CR, 0, &m88e1145_setmode},
		{MIIM_CONTROL, MIIM_CONTROL_RESET, NULL},
		{MIIM_CONTROL, MIIM_CONTROL_INIT, NULL},
		{miim_end,}
	},
	(struct phy_cmd[]) {	/* startup */
		/* Status is read once to clear old link state */
		{MIIM_STATUS, miim_read, NULL},
		/* Auto-negotiate */
		{MIIM_STATUS, miim_read, &mii_parse_sr},
		{MIIM_88E1111_PHY_LED_CONTROL, MIIM_88E1111_PHY_LED_DIRECT, NULL},
		/* Read the Status */
		{MIIM_88E1011_PHY_STATUS, miim_read, &mii_parse_88E1011_psr},
		{miim_end,}
	},
	(struct phy_cmd[]) {	/* shutdown */
		{miim_end,}
	},
1407 1408
};

1409
static struct phy_info phy_info_cis8204 = {
1410 1411 1412
	0x3f11,
	"Cicada Cis8204",
	6,
P
Peter Tyser 已提交
1413 1414 1415 1416 1417 1418 1419 1420 1421 1422 1423 1424 1425 1426 1427 1428 1429 1430 1431 1432 1433 1434 1435
	(struct phy_cmd[]) {	/* config */
		/* Override PHY config settings */
		{MIIM_CIS8201_AUX_CONSTAT, MIIM_CIS8201_AUXCONSTAT_INIT, NULL},
		/* Configure some basic stuff */
		{MIIM_CONTROL, MIIM_CONTROL_INIT, &mii_cr_init},
		{MIIM_CIS8204_SLED_CON, MIIM_CIS8204_SLEDCON_INIT,
		 &mii_cis8204_fixled},
		{MIIM_CIS8204_EPHY_CON, MIIM_CIS8204_EPHYCON_INIT,
		 &mii_cis8204_setmode},
		{miim_end,}
	},
	(struct phy_cmd[]) {	/* startup */
		/* Read the Status (2x to make sure link is right) */
		{MIIM_STATUS, miim_read, NULL},
		/* Auto-negotiate */
		{MIIM_STATUS, miim_read, &mii_parse_sr},
		/* Read the status */
		{MIIM_CIS8201_AUX_CONSTAT, miim_read, &mii_parse_cis8201},
		{miim_end,}
	},
	(struct phy_cmd[]) {	/* shutdown */
		{miim_end,}
	},
1436 1437 1438
};

/* Cicada 8201 */
1439
static struct phy_info phy_info_cis8201 = {
1440 1441 1442
	0xfc41,
	"CIS8201",
	4,
P
Peter Tyser 已提交
1443 1444 1445 1446 1447 1448 1449 1450 1451 1452 1453 1454 1455 1456 1457 1458 1459 1460 1461 1462 1463
	(struct phy_cmd[]) {	/* config */
		/* Override PHY config settings */
		{MIIM_CIS8201_AUX_CONSTAT, MIIM_CIS8201_AUXCONSTAT_INIT, NULL},
		/* Set up the interface mode */
		{MIIM_CIS8201_EXT_CON1, MIIM_CIS8201_EXTCON1_INIT, NULL},
		/* Configure some basic stuff */
		{MIIM_CONTROL, MIIM_CONTROL_INIT, &mii_cr_init},
		{miim_end,}
	},
	(struct phy_cmd[]) {	/* startup */
		/* Read the Status (2x to make sure link is right) */
		{MIIM_STATUS, miim_read, NULL},
		/* Auto-negotiate */
		{MIIM_STATUS, miim_read, &mii_parse_sr},
		/* Read the status */
		{MIIM_CIS8201_AUX_CONSTAT, miim_read, &mii_parse_cis8201},
		{miim_end,}
	},
	(struct phy_cmd[]) {	/* shutdown */
		{miim_end,}
	},
1464
};
1465 1466

static struct phy_info phy_info_VSC8211 = {
1467 1468 1469 1470
	0xfc4b,
	"Vitesse VSC8211",
	4,
	(struct phy_cmd[]) { /* config */
P
Peter Tyser 已提交
1471 1472 1473 1474 1475 1476 1477 1478
		/* Override PHY config settings */
		{MIIM_CIS8201_AUX_CONSTAT, MIIM_CIS8201_AUXCONSTAT_INIT, NULL},
		/* Set up the interface mode */
		{MIIM_CIS8201_EXT_CON1, MIIM_CIS8201_EXTCON1_INIT, NULL},
		/* Configure some basic stuff */
		{MIIM_CONTROL, MIIM_CONTROL_INIT, &mii_cr_init},
		{miim_end,}
	},
1479
	(struct phy_cmd[]) { /* startup */
P
Peter Tyser 已提交
1480 1481 1482 1483 1484 1485 1486 1487
		/* Read the Status (2x to make sure link is right) */
		{MIIM_STATUS, miim_read, NULL},
		/* Auto-negotiate */
		{MIIM_STATUS, miim_read, &mii_parse_sr},
		/* Read the status */
		{MIIM_CIS8201_AUX_CONSTAT, miim_read, &mii_parse_cis8201},
		{miim_end,}
	},
1488
	(struct phy_cmd[]) { /* shutdown */
P
Peter Tyser 已提交
1489
		{miim_end,}
1490 1491
	},
};
1492 1493

static struct phy_info phy_info_VSC8244 = {
1494 1495 1496
	0x3f1b,
	"Vitesse VSC8244",
	6,
P
Peter Tyser 已提交
1497 1498 1499 1500 1501 1502 1503 1504 1505 1506 1507 1508 1509 1510 1511 1512 1513 1514
	(struct phy_cmd[]) {	/* config */
		/* Override PHY config settings */
		/* Configure some basic stuff */
		{MIIM_CONTROL, MIIM_CONTROL_INIT, &mii_cr_init},
		{miim_end,}
	},
	(struct phy_cmd[]) {	/* startup */
		/* Read the Status (2x to make sure link is right) */
		{MIIM_STATUS, miim_read, NULL},
		/* Auto-negotiate */
		{MIIM_STATUS, miim_read, &mii_parse_sr},
		/* Read the status */
		{MIIM_VSC8244_AUX_CONSTAT, miim_read, &mii_parse_vsc8244},
		{miim_end,}
	},
	(struct phy_cmd[]) {	/* shutdown */
		{miim_end,}
	},
1515
};
1516

1517
static struct phy_info phy_info_VSC8641 = {
1518 1519 1520
	0x7043,
	"Vitesse VSC8641",
	4,
P
Peter Tyser 已提交
1521 1522 1523 1524 1525 1526 1527 1528 1529 1530 1531 1532 1533 1534 1535 1536 1537
	(struct phy_cmd[]) {	/* config */
		/* Configure some basic stuff */
		{MIIM_CONTROL, MIIM_CONTROL_INIT, &mii_cr_init},
		{miim_end,}
	},
	(struct phy_cmd[]) {	/* startup */
		/* Read the Status (2x to make sure link is right) */
		{MIIM_STATUS, miim_read, NULL},
		/* Auto-negotiate */
		{MIIM_STATUS, miim_read, &mii_parse_sr},
		/* Read the status */
		{MIIM_VSC8244_AUX_CONSTAT, miim_read, &mii_parse_vsc8244},
		{miim_end,}
	},
	(struct phy_cmd[]) {	/* shutdown */
		{miim_end,}
	},
1538 1539
};

1540
static struct phy_info phy_info_VSC8221 = {
1541 1542 1543
	0xfc55,
	"Vitesse VSC8221",
	4,
P
Peter Tyser 已提交
1544 1545 1546 1547 1548 1549 1550 1551 1552 1553 1554 1555 1556 1557 1558 1559 1560
	(struct phy_cmd[]) {	/* config */
		/* Configure some basic stuff */
		{MIIM_CONTROL, MIIM_CONTROL_INIT, &mii_cr_init},
		{miim_end,}
	},
	(struct phy_cmd[]) {	/* startup */
		/* Read the Status (2x to make sure link is right) */
		{MIIM_STATUS, miim_read, NULL},
		/* Auto-negotiate */
		{MIIM_STATUS, miim_read, &mii_parse_sr},
		/* Read the status */
		{MIIM_VSC8244_AUX_CONSTAT, miim_read, &mii_parse_vsc8244},
		{miim_end,}
	},
	(struct phy_cmd[]) {	/* shutdown */
		{miim_end,}
	},
1561 1562
};

1563
static struct phy_info phy_info_VSC8601 = {
P
Peter Tyser 已提交
1564 1565 1566 1567 1568 1569 1570
	0x00007042,
	"Vitesse VSC8601",
	4,
	(struct phy_cmd[]) {     /* config */
		/* Override PHY config settings */
		/* Configure some basic stuff */
		{MIIM_CONTROL, MIIM_CONTROL_INIT, &mii_cr_init},
1571
#ifdef CONFIG_SYS_VSC8601_SKEWFIX
P
Peter Tyser 已提交
1572
		{MIIM_VSC8601_EPHY_CON,MIIM_VSC8601_EPHY_CON_INIT_SKEW,NULL},
1573
#if defined(CONFIG_SYS_VSC8601_SKEW_TX) && defined(CONFIG_SYS_VSC8601_SKEW_RX)
P
Peter Tyser 已提交
1574 1575 1576 1577 1578
		{MIIM_EXT_PAGE_ACCESS,1,NULL},
#define VSC8101_SKEW \
	(CONFIG_SYS_VSC8601_SKEW_TX << 14) | (CONFIG_SYS_VSC8601_SKEW_RX << 12)
		{MIIM_VSC8601_SKEW_CTRL,VSC8101_SKEW,NULL},
		{MIIM_EXT_PAGE_ACCESS,0,NULL},
1579
#endif
1580
#endif
P
Peter Tyser 已提交
1581 1582 1583 1584 1585 1586 1587 1588 1589 1590 1591 1592 1593 1594 1595 1596
		{MIIM_ANAR, MIIM_ANAR_INIT, NULL},
		{MIIM_CONTROL, MIIM_CONTROL_RESTART, &mii_cr_init},
		{miim_end,}
	},
	(struct phy_cmd[]) {     /* startup */
		/* Read the Status (2x to make sure link is right) */
		{MIIM_STATUS, miim_read, NULL},
		/* Auto-negotiate */
		{MIIM_STATUS, miim_read, &mii_parse_sr},
		/* Read the status */
		{MIIM_VSC8244_AUX_CONSTAT, miim_read, &mii_parse_vsc8244},
		{miim_end,}
	},
	(struct phy_cmd[]) {     /* shutdown */
		{miim_end,}
	},
1597 1598
};

1599
static struct phy_info phy_info_dm9161 = {
1600 1601 1602
	0x0181b88,
	"Davicom DM9161E",
	4,
P
Peter Tyser 已提交
1603 1604 1605 1606 1607 1608 1609 1610 1611 1612 1613 1614 1615 1616 1617 1618 1619 1620 1621 1622 1623 1624 1625 1626
	(struct phy_cmd[]) {	/* config */
		{MIIM_CONTROL, MIIM_DM9161_CR_STOP, NULL},
		/* Do not bypass the scrambler/descrambler */
		{MIIM_DM9161_SCR, MIIM_DM9161_SCR_INIT, NULL},
		/* Clear 10BTCSR to default */
		{MIIM_DM9161_10BTCSR, MIIM_DM9161_10BTCSR_INIT, NULL},
		/* Configure some basic stuff */
		{MIIM_CONTROL, MIIM_CR_INIT, NULL},
		/* Restart Auto Negotiation */
		{MIIM_CONTROL, MIIM_DM9161_CR_RSTAN, NULL},
		{miim_end,}
	},
	(struct phy_cmd[]) {	/* startup */
		/* Status is read once to clear old link state */
		{MIIM_STATUS, miim_read, NULL},
		/* Auto-negotiate */
		{MIIM_STATUS, miim_read, &mii_parse_sr},
		/* Read the status */
		{MIIM_DM9161_SCSR, miim_read, &mii_parse_dm9161_scsr},
		{miim_end,}
	},
	(struct phy_cmd[]) {	/* shutdown */
		{miim_end,}
	},
1627
};
P
Peter Tyser 已提交
1628

1629
/* a generic flavor.  */
1630
static struct phy_info phy_info_generic =  {
1631 1632 1633 1634 1635 1636 1637 1638 1639 1640 1641 1642 1643 1644 1645 1646 1647 1648 1649
	0,
	"Unknown/Generic PHY",
	32,
	(struct phy_cmd[]) { /* config */
		{PHY_BMCR, PHY_BMCR_RESET, NULL},
		{PHY_BMCR, PHY_BMCR_AUTON|PHY_BMCR_RST_NEG, NULL},
		{miim_end,}
	},
	(struct phy_cmd[]) { /* startup */
		{PHY_BMSR, miim_read, NULL},
		{PHY_BMSR, miim_read, &mii_parse_sr},
		{PHY_BMSR, miim_read, &mii_parse_link},
		{miim_end,}
	},
	(struct phy_cmd[]) { /* shutdown */
		{miim_end,}
	}
};

1650
static uint mii_parse_lxt971_sr2(uint mii_reg, struct tsec_private *priv)
W
wdenk 已提交
1651
{
W
wdenk 已提交
1652 1653 1654 1655 1656 1657 1658 1659 1660 1661 1662 1663 1664 1665 1666 1667
	unsigned int speed;
	if (priv->link) {
		speed = mii_reg & MIIM_LXT971_SR2_SPEED_MASK;

		switch (speed) {
		case MIIM_LXT971_SR2_10HDX:
			priv->speed = 10;
			priv->duplexity = 0;
			break;
		case MIIM_LXT971_SR2_10FDX:
			priv->speed = 10;
			priv->duplexity = 1;
			break;
		case MIIM_LXT971_SR2_100HDX:
			priv->speed = 100;
			priv->duplexity = 0;
U
urwithsughosh@gmail.com 已提交
1668
			break;
W
wdenk 已提交
1669 1670 1671 1672 1673 1674 1675 1676 1677 1678
		default:
			priv->speed = 100;
			priv->duplexity = 1;
		}
	} else {
		priv->speed = 0;
		priv->duplexity = 0;
	}

	return 0;
W
wdenk 已提交
1679 1680
}

W
wdenk 已提交
1681 1682 1683 1684
static struct phy_info phy_info_lxt971 = {
	0x0001378e,
	"LXT971",
	4,
P
Peter Tyser 已提交
1685 1686 1687 1688 1689 1690 1691 1692 1693 1694 1695 1696 1697 1698
	(struct phy_cmd[]) {	/* config */
		{MIIM_CR, MIIM_CR_INIT, mii_cr_init},	/* autonegotiate */
		{miim_end,}
	},
	(struct phy_cmd[]) {	/* startup - enable interrupts */
		/* { 0x12, 0x00f2, NULL }, */
		{MIIM_STATUS, miim_read, NULL},
		{MIIM_STATUS, miim_read, &mii_parse_sr},
		{MIIM_LXT971_SR2, miim_read, &mii_parse_lxt971_sr2},
		{miim_end,}
	},
	(struct phy_cmd[]) {	/* shutdown - disable interrupts */
		{miim_end,}
	},
W
wdenk 已提交
1699 1700
};

1701
/* Parse the DP83865's link and auto-neg status register for speed and duplex
1702 1703
 * information
 */
1704
static uint mii_parse_dp83865_lanr(uint mii_reg, struct tsec_private *priv)
1705 1706 1707 1708 1709 1710 1711 1712 1713 1714 1715 1716 1717 1718 1719 1720 1721 1722 1723 1724 1725 1726 1727 1728 1729
{
	switch (mii_reg & MIIM_DP83865_SPD_MASK) {

	case MIIM_DP83865_SPD_1000:
		priv->speed = 1000;
		break;

	case MIIM_DP83865_SPD_100:
		priv->speed = 100;
		break;

	default:
		priv->speed = 10;
		break;

	}

	if (mii_reg & MIIM_DP83865_DPX_FULL)
		priv->duplexity = 1;
	else
		priv->duplexity = 0;

	return 0;
}

1730
static struct phy_info phy_info_dp83865 = {
1731 1732 1733
	0x20005c7,
	"NatSemi DP83865",
	4,
P
Peter Tyser 已提交
1734 1735 1736 1737 1738 1739 1740 1741 1742 1743 1744 1745 1746 1747 1748 1749
	(struct phy_cmd[]) {	/* config */
		{MIIM_CONTROL, MIIM_DP83865_CR_INIT, NULL},
		{miim_end,}
	},
	(struct phy_cmd[]) {	/* startup */
		/* Status is read once to clear old link state */
		{MIIM_STATUS, miim_read, NULL},
		/* Auto-negotiate */
		{MIIM_STATUS, miim_read, &mii_parse_sr},
		/* Read the link and auto-neg status */
		{MIIM_DP83865_LANR, miim_read, &mii_parse_dp83865_lanr},
		{miim_end,}
	},
	(struct phy_cmd[]) {	/* shutdown */
		{miim_end,}
	},
1750 1751
};

1752
static struct phy_info phy_info_rtl8211b = {
1753 1754 1755
	0x001cc91,
	"RealTek RTL8211B",
	4,
P
Peter Tyser 已提交
1756
	(struct phy_cmd[]) {	/* config */
1757 1758 1759 1760 1761 1762 1763 1764
		/* Reset and configure the PHY */
		{MIIM_CONTROL, MIIM_CONTROL_RESET, NULL},
		{MIIM_GBIT_CONTROL, MIIM_GBIT_CONTROL_INIT, NULL},
		{MIIM_ANAR, MIIM_ANAR_INIT, NULL},
		{MIIM_CONTROL, MIIM_CONTROL_RESET, NULL},
		{MIIM_CONTROL, MIIM_CONTROL_INIT, &mii_cr_init},
		{miim_end,}
	},
P
Peter Tyser 已提交
1765
	(struct phy_cmd[]) {	/* startup */
1766 1767 1768 1769 1770 1771 1772 1773
		/* Status is read once to clear old link state */
		{MIIM_STATUS, miim_read, NULL},
		/* Auto-negotiate */
		{MIIM_STATUS, miim_read, &mii_parse_sr},
		/* Read the status */
		{MIIM_RTL8211B_PHY_STATUS, miim_read, &mii_parse_RTL8211B_sr},
		{miim_end,}
	},
P
Peter Tyser 已提交
1774
	(struct phy_cmd[]) {	/* shutdown */
1775 1776 1777 1778
		{miim_end,}
	},
};

1779
static struct phy_info *phy_info[] = {
1780
	&phy_info_cis8204,
1781
	&phy_info_cis8201,
1782
	&phy_info_BCM5461S,
J
Joe Hamman 已提交
1783
	&phy_info_BCM5464S,
Z
Zach LeRoy 已提交
1784
	&phy_info_BCM5482S,
1785
	&phy_info_M88E1011S,
W
wdenk 已提交
1786
	&phy_info_M88E1111S,
1787
	&phy_info_M88E1118,
1788
	&phy_info_M88E1121R,
1789
	&phy_info_M88E1145,
1790
	&phy_info_M88E1149S,
1791
	&phy_info_dm9161,
W
wdenk 已提交
1792
	&phy_info_lxt971,
1793
	&phy_info_VSC8211,
1794
	&phy_info_VSC8244,
1795
	&phy_info_VSC8601,
1796 1797
	&phy_info_VSC8641,
	&phy_info_VSC8221,
1798
	&phy_info_dp83865,
1799
	&phy_info_rtl8211b,
1800
	&phy_info_generic,	/* must be last; has ID 0 and 32 bit mask */
1801 1802 1803 1804
	NULL
};

/* Grab the identifier of the device's PHY, and search through
W
wdenk 已提交
1805
 * all of the known PHYs to see if one matches.	 If so, return
1806 1807
 * it, if not, return NULL
 */
1808
static struct phy_info *get_phy_info(struct eth_device *dev)
1809 1810 1811 1812 1813 1814 1815 1816 1817 1818 1819 1820 1821 1822 1823 1824
{
	struct tsec_private *priv = (struct tsec_private *)dev->priv;
	uint phy_reg, phy_ID;
	int i;
	struct phy_info *theInfo = NULL;

	/* Grab the bits from PHYIR1, and put them in the upper half */
	phy_reg = read_phy_reg(priv, MIIM_PHYIR1);
	phy_ID = (phy_reg & 0xffff) << 16;

	/* Grab the bits from PHYIR2, and put them in the lower half */
	phy_reg = read_phy_reg(priv, MIIM_PHYIR2);
	phy_ID |= (phy_reg & 0xffff);

	/* loop through all the known PHY types, and find one that */
	/* matches the ID we read from the PHY. */
1825
	for (i = 0; phy_info[i]; i++) {
1826
		if (phy_info[i]->id == (phy_ID >> phy_info[i]->shift)) {
1827
			theInfo = phy_info[i];
1828 1829
			break;
		}
1830 1831
	}

1832
	if (theInfo == &phy_info_generic) {
P
Peter Tyser 已提交
1833 1834
		printf("%s: No support for PHY id %x; assuming generic\n",
			dev->name, phy_ID);
1835
	} else {
1836
		debug("%s: PHY is %s (%x)\n", dev->name, theInfo->name, phy_ID);
1837 1838 1839
	}

	return theInfo;
W
wdenk 已提交
1840
}
W
wdenk 已提交
1841

1842
/* Execute the given series of commands on the given device's
1843 1844
 * PHY, running functions as necessary
 */
1845
static void phy_run_commands(struct tsec_private *priv, struct phy_cmd *cmd)
1846 1847 1848
{
	int i;
	uint result;
1849
	volatile tsec_mdio_t *phyregs = priv->phyregs;
1850 1851 1852 1853 1854

	phyregs->miimcfg = MIIMCFG_RESET;

	phyregs->miimcfg = MIIMCFG_INIT_VALUE;

1855
	while (phyregs->miimind & MIIMIND_BUSY) ;
1856

1857 1858
	for (i = 0; cmd->mii_reg != miim_end; i++) {
		if (cmd->mii_data == miim_read) {
1859 1860
			result = read_phy_reg(priv, cmd->mii_reg);

1861 1862
			if (cmd->funct != NULL)
				(*(cmd->funct)) (result, priv);
1863 1864

		} else {
1865 1866
			if (cmd->funct != NULL)
				result = (*(cmd->funct)) (cmd->mii_reg, priv);
1867 1868 1869 1870 1871 1872 1873 1874 1875 1876
			else
				result = cmd->mii_data;

			write_phy_reg(priv, cmd->mii_reg, result);

		}
		cmd++;
	}
}

1877
#if defined(CONFIG_MII) || defined(CONFIG_CMD_MII) \
M
Marian Balakowicz 已提交
1878
	&& !defined(BITBANGMII)
1879

W
wdenk 已提交
1880 1881 1882 1883
/*
 * Read a MII PHY register.
 *
 * Returns:
1884
 *  0 on success
W
wdenk 已提交
1885
 */
M
Marian Balakowicz 已提交
1886
static int tsec_miiphy_read(char *devname, unsigned char addr,
1887
			    unsigned char reg, unsigned short *value)
W
wdenk 已提交
1888
{
1889
	unsigned short ret;
1890
	struct tsec_private *priv = privlist[0];
1891

1892
	if (NULL == priv) {
1893 1894 1895
		printf("Can't read PHY at address %d\n", addr);
		return -1;
	}
W
wdenk 已提交
1896

A
Andy Fleming 已提交
1897
	ret = (unsigned short)tsec_local_mdio_read(priv->phyregs, addr, reg);
1898
	*value = ret;
W
wdenk 已提交
1899 1900 1901 1902 1903 1904 1905 1906

	return 0;
}

/*
 * Write a MII PHY register.
 *
 * Returns:
1907
 *  0 on success
W
wdenk 已提交
1908
 */
M
Marian Balakowicz 已提交
1909
static int tsec_miiphy_write(char *devname, unsigned char addr,
1910
			     unsigned char reg, unsigned short value)
W
wdenk 已提交
1911
{
1912
	struct tsec_private *priv = privlist[0];
1913

1914
	if (NULL == priv) {
1915 1916 1917
		printf("Can't write PHY at address %d\n", addr);
		return -1;
	}
W
wdenk 已提交
1918

A
Andy Fleming 已提交
1919
	tsec_local_mdio_write(priv->phyregs, addr, reg, value);
W
wdenk 已提交
1920 1921 1922

	return 0;
}
1923

1924
#endif
1925

D
David Updegraff 已提交
1926 1927 1928 1929 1930 1931 1932 1933 1934 1935 1936 1937 1938 1939 1940 1941 1942 1943 1944 1945 1946
#ifdef CONFIG_MCAST_TFTP

/* CREDITS: linux gianfar driver, slightly adjusted... thanx. */

/* Set the appropriate hash bit for the given addr */

/* The algorithm works like so:
 * 1) Take the Destination Address (ie the multicast address), and
 * do a CRC on it (little endian), and reverse the bits of the
 * result.
 * 2) Use the 8 most significant bits as a hash into a 256-entry
 * table.  The table is controlled through 8 32-bit registers:
 * gaddr0-7.  gaddr0's MSB is entry 0, and gaddr7's LSB is
 * gaddr7.  This means that the 3 most significant bits in the
 * hash index which gaddr register to use, and the 5 other bits
 * indicate which bit (assuming an IBM numbering scheme, which
 * for PowerPC (tm) is usually the case) in the tregister holds
 * the entry. */
static int
tsec_mcast_addr (struct eth_device *dev, u8 mcast_mac, u8 set)
{
P
Peter Tyser 已提交
1947 1948 1949 1950
	struct tsec_private *priv = privlist[1];
	volatile tsec_t *regs = priv->regs;
	volatile u32  *reg_array, value;
	u8 result, whichbit, whichreg;
D
David Updegraff 已提交
1951 1952 1953 1954 1955 1956 1957 1958 1959 1960 1961 1962 1963 1964 1965 1966

	result = (u8)((ether_crc(MAC_ADDR_LEN,mcast_mac) >> 24) & 0xff);
	whichbit = result & 0x1f;	/* the 5 LSB = which bit to set */
	whichreg = result >> 5;		/* the 3 MSB = which reg to set it in */
	value = (1 << (31-whichbit));

	reg_array = &(regs->hash.gaddr0);

	if (set) {
		reg_array[whichreg] |= value;
	} else {
		reg_array[whichreg] &= ~value;
	}
	return 0;
}
#endif /* Multicast TFTP ? */