tsec.c 41.1 KB
Newer Older
1
/*
2
 * Freescale Three Speed Ethernet Controller driver
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.
 *
Andy Fleming's avatar
Andy Fleming committed
8
 * Copyright 2004, 2007 Freescale Semiconductor, Inc.
9
10
11
12
13
14
15
16
17
18
19
20
21
 * (C) Copyright 2003, Motorola, Inc.
 * author Andy Fleming
 *
 */

#include <config.h>
#include <common.h>
#include <malloc.h>
#include <net.h>
#include <command.h>

#if defined(CONFIG_TSEC_ENET)
#include "tsec.h"
22
#include "miiphy.h"
23

24
25
DECLARE_GLOBAL_DATA_PTR;

26
#define TX_BUF_CNT		2
27

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

typedef volatile struct rtxbd {
	txbd8_t txbd[TX_BUF_CNT];
	rxbd8_t rxbd[PKTBUFSRX];
34
} RTXBD;
35

36
37
struct tsec_info_struct {
	unsigned int phyaddr;
38
	u32 flags;
39
40
41
42
43
	unsigned int phyregidx;
};

/* The tsec_info structure contains 3 values which the
 * driver uses to determine how to operate a given ethernet
44
 * device. The information needed is:
45
 *  phyaddr - The address of the PHY which is attached to
46
 *	the given device.
47
 *
48
49
50
 *  flags - This variable indicates whether the device
 *	supports gigabit speed ethernet, and whether it should be
 *	in reduced mode.
51
52
 *
 *  phyregidx - This variable specifies which ethernet device
53
 *	controls the MII Management registers which are connected
54
 *	to the PHY.  For now, only TSEC1 (index 0) has
55
 *	access to the PHYs, so all of the entries have "0".
56
57
58
59
 *
 * The values specified in the table are taken from the board's
 * config file in include/configs/.  When implementing a new
 * board with ethernet capability, it is necessary to define:
60
61
 *   TSECn_PHY_ADDR
 *   TSECn_PHYIDX
62
 *
63
 * for n = 1,2,3, etc.  And for FEC:
64
65
66
67
 *   FEC_PHY_ADDR
 *   FEC_PHYIDX
 */
static struct tsec_info_struct tsec_info[] = {
68
69
#ifdef CONFIG_TSEC1
	{TSEC1_PHY_ADDR, TSEC1_FLAGS, TSEC1_PHYIDX},
Zach Sadecki's avatar
Zach Sadecki committed
70
#else
71
	{0, 0, 0},
72
#endif
73
74
#ifdef CONFIG_TSEC2
	{TSEC2_PHY_ADDR, TSEC2_FLAGS, TSEC2_PHYIDX},
Zach Sadecki's avatar
Zach Sadecki committed
75
#else
76
	{0, 0, 0},
77
78
#endif
#ifdef CONFIG_MPC85XX_FEC
79
	{FEC_PHY_ADDR, FEC_FLAGS, FEC_PHYIDX},
80
#else
81
82
#ifdef CONFIG_TSEC3
	{TSEC3_PHY_ADDR, TSEC3_FLAGS, TSEC3_PHYIDX},
83
#else
84
	{0, 0, 0},
85
#endif
86
87
#ifdef CONFIG_TSEC4
	{TSEC4_PHY_ADDR, TSEC4_FLAGS, TSEC4_PHYIDX},
88
#else
89
	{0, 0, 0},
90
91
#endif	/* CONFIG_TSEC4 */
#endif	/* CONFIG_MPC85XX_FEC */
92
93
};

94
#define MAXCONTROLLERS	(4)
95
96
97
98
99

static int relocated = 0;

static struct tsec_private *privlist[MAXCONTROLLERS];

100
101
102
103
104
105
#ifdef __GNUC__
static RTXBD rtx __attribute__ ((aligned(8)));
#else
#error "rtx must be 64-bit aligned"
#endif

106
107
108
109
110
111
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);
static void tsec_halt(struct eth_device *dev);
static void init_registers(volatile tsec_t * regs);
112
113
114
115
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);
116
struct phy_info *get_phy_info(struct eth_device *dev);
117
118
119
void phy_run_commands(struct tsec_private *priv, struct phy_cmd *cmd);
static void adjust_link(struct eth_device *dev);
static void relocate_cmds(void);
120
121
#if defined(CONFIG_MII) || defined(CONFIG_CMD_MII) \
	&& !defined(BITBANGMII)
122
static int tsec_miiphy_write(char *devname, unsigned char addr,
123
			     unsigned char reg, unsigned short value);
124
static int tsec_miiphy_read(char *devname, unsigned char addr,
125
			    unsigned char reg, unsigned short *value);
126
#endif
David Updegraff's avatar
David Updegraff committed
127
128
129
#ifdef CONFIG_MCAST_TFTP
static int tsec_mcast_addr (struct eth_device *dev, u8 mcast_mac, u8 set);
#endif
130
131
132
133

/* Initialize device structure. Returns success if PHY
 * initialization succeeded (i.e. if it recognizes the PHY)
 */
134
int tsec_initialize(bd_t * bis, int index, char *devname)
135
{
136
	struct eth_device *dev;
137
	int i;
138
	struct tsec_private *priv;
139

140
	dev = (struct eth_device *)malloc(sizeof *dev);
141

142
	if (NULL == dev)
143
144
145
146
		return 0;

	memset(dev, 0, sizeof *dev);

147
	priv = (struct tsec_private *)malloc(sizeof(*priv));
148

149
	if (NULL == priv)
150
151
152
		return 0;

	privlist[index] = priv;
153
	priv->regs = (volatile tsec_t *)(TSEC_BASE_ADDR + index * TSEC_SIZE);
154
	priv->phyregs = (volatile tsec_t *)(TSEC_BASE_ADDR +
155
156
					    tsec_info[index].phyregidx *
					    TSEC_SIZE);
157
158

	priv->phyaddr = tsec_info[index].phyaddr;
159
	priv->flags = tsec_info[index].flags;
160

161
	sprintf(dev->name, devname);
162
	dev->iobase = 0;
163
164
165
166
167
	dev->priv = priv;
	dev->init = tsec_init;
	dev->halt = tsec_halt;
	dev->send = tsec_send;
	dev->recv = tsec_recv;
David Updegraff's avatar
David Updegraff committed
168
169
170
#ifdef CONFIG_MCAST_TFTP
	dev->mcast = tsec_mcast_addr;
#endif
171
172

	/* Tell u-boot to get the addr from the env */
173
	for (i = 0; i < 6; i++)
174
175
176
177
		dev->enetaddr[i] = 0;

	eth_register(dev);

178
179
180
	/* Reset the MAC */
	priv->regs->maccfg1 |= MACCFG1_SOFT_RESET;
	priv->regs->maccfg1 &= ~(MACCFG1_SOFT_RESET);
wdenk's avatar
wdenk committed
181

182
#if defined(CONFIG_MII) || defined(CONFIG_CMD_MII) \
183
184
185
186
	&& !defined(BITBANGMII)
	miiphy_register(dev->name, tsec_miiphy_read, tsec_miiphy_write);
#endif

187
188
	/* Try to initialize PHY here, and return */
	return init_phy(dev);
189
190
191
}

/* Initializes data structures and registers for the controller,
192
 * and brings the interface up.	 Returns the link status, meaning
193
 * that it returns success if the link is up, failure otherwise.
194
195
196
 * This allows u-boot to find the first active controller.
 */
int tsec_init(struct eth_device *dev, bd_t * bd)
197
198
199
200
{
	uint tempval;
	char tmpbuf[MAC_ADDR_LEN];
	int i;
201
202
	struct tsec_private *priv = (struct tsec_private *)dev->priv;
	volatile tsec_t *regs = priv->regs;
203
204
205
206

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

207
	/* Init MACCFG2.  Defaults to GMII */
208
209
210
211
212
213
214
	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 */
215
	for (i = 0; i < MAC_ADDR_LEN; i++) {
216
		tmpbuf[MAC_ADDR_LEN - 1 - i] = dev->enetaddr[i];
217
	}
218
	regs->macstnaddr1 = *((uint *) (tmpbuf));
219

220
	tempval = *((uint *) (tmpbuf + 4));
221

Wolfgang Denk's avatar
Wolfgang Denk committed
222
	regs->macstnaddr2 = tempval;
223
224
225
226
227
228
229
230
231

	/* 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 */
232
	startup_tsec(dev);
233

234
	/* If there's no link, fail */
Ben Warren's avatar
Ben Warren committed
235
	return (priv->link ? 0 : -1);
236
237
238

}

239
240
241
242
243
/* Write value to the device's PHY through the registers
 * specified in priv, modifying the register specified in regnum.
 * It will wait for the write to be done (or for a timeout to
 * expire) before exiting
 */
244
void write_any_phy_reg(struct tsec_private *priv, uint phyid, uint regnum, uint value)
245
246
{
	volatile tsec_t *regbase = priv->phyregs;
247
	int timeout = 1000000;
248
249
250

	regbase->miimadd = (phyid << 8) | regnum;
	regbase->miimcon = value;
Eran Liberty's avatar
Eran Liberty committed
251
	asm("sync");
252

253
254
	timeout = 1000000;
	while ((regbase->miimind & MIIMIND_BUSY) && timeout--) ;
255
256
}

257
258
259
/* #define to provide old write_phy_reg functionality without duplicating code */
#define write_phy_reg(priv, regnum, value) write_any_phy_reg(priv,priv->phyaddr,regnum,value)

260
/* Reads register regnum on the device's PHY through the
261
 * registers specified in priv.	 It lowers and raises the read
262
263
264
265
 * 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
 */
266
uint read_any_phy_reg(struct tsec_private *priv, uint phyid, uint regnum)
267
268
{
	uint value;
269
	volatile tsec_t *regbase = priv->phyregs;
270

271
272
273
	/* Put the address of the phy, and the register
	 * number into MIIMADD */
	regbase->miimadd = (phyid << 8) | regnum;
274
275
276

	/* Clear the command register, and wait */
	regbase->miimcom = 0;
Eran Liberty's avatar
Eran Liberty committed
277
	asm("sync");
278
279
280

	/* Initiate a read command, and wait */
	regbase->miimcom = MIIM_READ_COMMAND;
Eran Liberty's avatar
Eran Liberty committed
281
	asm("sync");
282
283

	/* Wait for the the indication that the read is done */
284
	while ((regbase->miimind & (MIIMIND_NOTVALID | MIIMIND_BUSY))) ;
285
286
287
288
289
290
291

	/* Grab the value read from the PHY */
	value = regbase->miimstat;

	return value;
}

292
293
294
/* #define to provide old read_phy_reg functionality without duplicating code */
#define read_phy_reg(priv,regnum) read_any_phy_reg(priv,priv->phyaddr,regnum)

295
296
297
298
299
/* 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)
300
{
301
302
	struct tsec_private *priv = (struct tsec_private *)dev->priv;
	struct phy_info *curphy;
303
	volatile tsec_t *regs = (volatile tsec_t *)(TSEC_BASE_ADDR);
304
305

	/* Assign a Physical address to the TBI */
306
	regs->tbipa = CFG_TBIPA_VALUE;
307
	regs = (volatile tsec_t *)(TSEC_BASE_ADDR + TSEC_SIZE);
308
	regs->tbipa = CFG_TBIPA_VALUE;
309
	asm("sync");
wdenk's avatar
wdenk committed
310
311
312

	/* Reset MII (due to new addresses) */
	priv->phyregs->miimcfg = MIIMCFG_RESET;
Eran Liberty's avatar
Eran Liberty committed
313
	asm("sync");
wdenk's avatar
wdenk committed
314
	priv->phyregs->miimcfg = MIIMCFG_INIT_VALUE;
Eran Liberty's avatar
Eran Liberty committed
315
	asm("sync");
316
	while (priv->phyregs->miimind & MIIMIND_BUSY) ;
317

318
	if (0 == relocated)
319
		relocate_cmds();
320

321
322
323
	/* Get the cmd structure corresponding to the attached
	 * PHY */
	curphy = get_phy_info(dev);
324

325
326
	if (curphy == NULL) {
		priv->phyinfo = NULL;
327
		printf("%s: No PHY found\n", dev->name);
328

329
330
		return 0;
	}
331

332
	priv->phyinfo = curphy;
333

334
	phy_run_commands(priv, priv->phyinfo->config);
335

336
337
	return 1;
}
338

339
340
341
342
343
/*
 * Returns which value to write to the control register.
 * For 10/100, the value is slightly different
 */
uint mii_cr_init(uint mii_reg, struct tsec_private * priv)
344
{
345
	if (priv->flags & TSEC_GIGABIT)
346
		return MIIM_CONTROL_INIT;
347
	else
348
349
		return MIIM_CR_INIT;
}
350

351
/* Parse the status register for link, and then do
352
353
354
 * auto-negotiation
 */
uint mii_parse_sr(uint mii_reg, struct tsec_private * priv)
355
{
356
	/*
357
358
	 * Wait if the link is up, and autonegotiation is in progress
	 * (ie - we're capable and it's not done)
359
360
	 */
	mii_reg = read_phy_reg(priv, MIIM_STATUS);
361
	if ((mii_reg & MIIM_STATUS_LINK) && (mii_reg & PHY_BMSR_AUTN_ABLE)
362
	    && !(mii_reg & PHY_BMSR_AUTN_COMP)) {
363
364
		int i = 0;

365
		puts("Waiting for PHY auto negotiation to complete");
366
		while (!(mii_reg & PHY_BMSR_AUTN_COMP)) {
367
368
369
370
			/*
			 * Timeout reached ?
			 */
			if (i > PHY_AUTONEGOTIATE_TIMEOUT) {
371
				puts(" TIMEOUT !\n");
372
				priv->link = 0;
373
				return 0;
374
			}
375

376
			if ((i++ % 1000) == 0) {
377
				putc('.');
378
			}
379
			udelay(1000);	/* 1 ms */
380
			mii_reg = read_phy_reg(priv, MIIM_STATUS);
381
		}
382
		puts(" done\n");
383
		priv->link = 1;
384
		udelay(500000);	/* another 500 ms (results in faster booting) */
385
	} else {
386
387
388
389
		if (mii_reg & MIIM_STATUS_LINK)
			priv->link = 1;
		else
			priv->link = 0;
390
391
	}

392
393
	return 0;
}
394

395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
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
/* 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
 */
uint mii_parse_link(uint mii_reg, struct tsec_private *priv)
{
	/* 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;
}

465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
/*
 * Parse the BCM54xx status register for speed and duplex information.
 * The linux sungem_phy has this information, but in a table format.
 */
uint mii_parse_BCM54xx_sr(uint mii_reg, struct tsec_private *priv)
{

	switch((mii_reg & MIIM_BCM54xx_AUXSTATUS_LINKMODE_MASK) >> MIIM_BCM54xx_AUXSTATUS_LINKMODE_SHIFT){

		case 1:
			printf("Enet starting in 10BT/HD\n");
			priv->duplexity = 0;
			priv->speed = 10;
			break;

		case 2:
			printf("Enet starting in 10BT/FD\n");
			priv->duplexity = 1;
			priv->speed = 10;
			break;

		case 3:
			printf("Enet starting in 100BT/HD\n");
			priv->duplexity = 0;
			priv->speed = 100;
			break;

		case 5:
			printf("Enet starting in 100BT/FD\n");
			priv->duplexity = 1;
			priv->speed = 100;
			break;

		case 6:
			printf("Enet starting in 1000BT/HD\n");
			priv->duplexity = 0;
			priv->speed = 1000;
			break;

		case 7:
			printf("Enet starting in 1000BT/FD\n");
			priv->duplexity = 1;
			priv->speed = 1000;
			break;

		default:
			printf("Auto-neg error, defaulting to 10BT/HD\n");
			priv->duplexity = 0;
			priv->speed = 10;
			break;
	}

	return 0;

}
520
/* Parse the 88E1011's status register for speed and duplex
521
522
523
 * information
 */
uint mii_parse_88E1011_psr(uint mii_reg, struct tsec_private * priv)
524
525
526
{
	uint speed;

527
528
	mii_reg = read_phy_reg(priv, MIIM_88E1011_PHY_STATUS);

529
530
	if ((mii_reg & MIIM_88E1011_PHYSTAT_LINK) &&
		!(mii_reg & MIIM_88E1011_PHYSTAT_SPDDONE)) {
531
532
		int i = 0;

533
		puts("Waiting for PHY realtime link");
534
535
		while (!(mii_reg & MIIM_88E1011_PHYSTAT_SPDDONE)) {
			/* Timeout reached ? */
536
			if (i > PHY_AUTONEGOTIATE_TIMEOUT) {
537
				puts(" TIMEOUT !\n");
538
539
540
541
542
				priv->link = 0;
				break;
			}

			if ((i++ % 1000) == 0) {
543
				putc('.');
544
			}
545
			udelay(1000);	/* 1 ms */
546
547
			mii_reg = read_phy_reg(priv, MIIM_88E1011_PHY_STATUS);
		}
548
549
		puts(" done\n");
		udelay(500000);	/* another 500 ms (results in faster booting) */
550
551
552
553
554
	} else {
		if (mii_reg & MIIM_88E1011_PHYSTAT_LINK)
			priv->link = 1;
		else
			priv->link = 0;
555
556
	}

557
	if (mii_reg & MIIM_88E1011_PHYSTAT_DUPLEX)
558
559
560
561
		priv->duplexity = 1;
	else
		priv->duplexity = 0;

562
	speed = (mii_reg & MIIM_88E1011_PHYSTAT_SPEED);
563

564
565
566
567
568
569
570
571
572
	switch (speed) {
	case MIIM_88E1011_PHYSTAT_GBIT:
		priv->speed = 1000;
		break;
	case MIIM_88E1011_PHYSTAT_100:
		priv->speed = 100;
		break;
	default:
		priv->speed = 10;
573
574
	}

575
576
	return 0;
}
577

578
579
580
581
582
583
584
585
/* Parse the RTL8211B's status register for speed and duplex
 * information
 */
uint mii_parse_RTL8211B_sr(uint mii_reg, struct tsec_private * priv)
{
	uint speed;

	mii_reg = read_phy_reg(priv, MIIM_RTL8211B_PHY_STATUS);
586
	if (!(mii_reg & MIIM_RTL8211B_PHYSTAT_SPDDONE)) {
587
588
		int i = 0;

589
590
		/* in case of timeout ->link is cleared */
		priv->link = 1;
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
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
		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;
}

636
/* Parse the cis8201's status register for speed and duplex
637
638
639
 * information
 */
uint mii_parse_cis8201(uint mii_reg, struct tsec_private * priv)
640
641
642
{
	uint speed;

643
	if (mii_reg & MIIM_CIS8201_AUXCONSTAT_DUPLEX)
644
645
646
647
648
		priv->duplexity = 1;
	else
		priv->duplexity = 0;

	speed = mii_reg & MIIM_CIS8201_AUXCONSTAT_SPEED;
649
650
651
652
653
654
655
656
657
658
	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;
659
660
	}

661
662
	return 0;
}
663

664
/* Parse the vsc8244's status register for speed and duplex
665
666
667
 * information
 */
uint mii_parse_vsc8244(uint mii_reg, struct tsec_private * priv)
668
{
669
	uint speed;
670

671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
	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;
}
691
692

/* Parse the DM9161's status register for speed and duplex
693
694
695
 * information
 */
uint mii_parse_dm9161_scsr(uint mii_reg, struct tsec_private * priv)
696
{
697
	if (mii_reg & (MIIM_DM9161_SCSR_100F | MIIM_DM9161_SCSR_100H))
698
699
700
701
		priv->speed = 100;
	else
		priv->speed = 10;

702
	if (mii_reg & (MIIM_DM9161_SCSR_100F | MIIM_DM9161_SCSR_10F))
703
704
705
706
707
708
709
		priv->duplexity = 1;
	else
		priv->duplexity = 0;

	return 0;
}

710
711
712
713
/*
 * Hack to write all 4 PHYs with the LED values
 */
uint mii_cis8204_fixled(uint mii_reg, struct tsec_private * priv)
714
715
716
{
	uint phyid;
	volatile tsec_t *regbase = priv->phyregs;
717
	int timeout = 1000000;
718

719
	for (phyid = 0; phyid < 4; phyid++) {
720
721
		regbase->miimadd = (phyid << 8) | mii_reg;
		regbase->miimcon = MIIM_CIS8204_SLEDCON_INIT;
Eran Liberty's avatar
Eran Liberty committed
722
		asm("sync");
723

724
725
		timeout = 1000000;
		while ((regbase->miimind & MIIMIND_BUSY) && timeout--) ;
726
727
	}

728
	return MIIM_CIS8204_SLEDCON_INIT;
729
730
}

731
uint mii_cis8204_setmode(uint mii_reg, struct tsec_private * priv)
732
733
734
735
736
737
{
	if (priv->flags & TSEC_REDUCED)
		return MIIM_CIS8204_EPHYCON_INIT | MIIM_CIS8204_EPHYCON_RGMII;
	else
		return MIIM_CIS8204_EPHYCON_INIT;
}
738

739
740
741
742
743
744
745
746
747
uint mii_m88e1111s_setmode(uint mii_reg, struct tsec_private *priv)
{
	uint mii_data = read_phy_reg(priv, mii_reg);

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

748
749
/* Initialized required registers to appropriate values, zeroing
 * those we don't care about (unless zero is bad, in which case,
750
751
752
 * choose a more appropriate value)
 */
static void init_registers(volatile tsec_t * regs)
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
{
	/* 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;

}

794
/* Configure maccfg2 based on negotiated speed and duplex
795
796
 * reported by PHY handling code
 */
797
798
799
800
801
static void adjust_link(struct eth_device *dev)
{
	struct tsec_private *priv = (struct tsec_private *)dev->priv;
	volatile tsec_t *regs = priv->regs;

802
803
	if (priv->link) {
		if (priv->duplexity != 0)
804
805
806
807
			regs->maccfg2 |= MACCFG2_FULL_DUPLEX;
		else
			regs->maccfg2 &= ~(MACCFG2_FULL_DUPLEX);

808
809
810
811
812
813
814
815
816
817
		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);

818
819
			/* Set R100 bit in all modes although
			 * it is only used in RGMII mode
820
			 */
821
			if (priv->speed == 100)
822
823
824
825
826
827
828
				regs->ecntrl |= ECNTRL_R100;
			else
				regs->ecntrl &= ~(ECNTRL_R100);
			break;
		default:
			printf("%s: Speed was bad\n", dev->name);
			break;
829
830
831
		}

		printf("Speed: %d, %s duplex\n", priv->speed,
832
		       (priv->duplexity) ? "full" : "half");
833
834
835
836
837
838
839

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

/* Set up the buffers and their descriptors, and bring up the
840
841
 * interface
 */
842
static void startup_tsec(struct eth_device *dev)
843
844
{
	int i;
845
846
	struct tsec_private *priv = (struct tsec_private *)dev->priv;
	volatile tsec_t *regs = priv->regs;
847
848
849
850
851
852
853
854
855

	/* 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;
856
		rtx.rxbd[i].bufPtr = (uint) NetRxPackets[i];
857
	}
858
	rtx.rxbd[PKTBUFSRX - 1].status |= RXBD_WRAP;
859
860

	/* Initialize the TX Buffer Descriptors */
861
	for (i = 0; i < TX_BUF_CNT; i++) {
862
863
864
865
		rtx.txbd[i].status = 0;
		rtx.txbd[i].length = 0;
		rtx.txbd[i].bufPtr = 0;
	}
866
	rtx.txbd[TX_BUF_CNT - 1].status |= TXBD_WRAP;
867

868
	/* Start up the PHY */
869
870
	if(priv->phyinfo)
		phy_run_commands(priv, priv->phyinfo->startup);
871

872
873
	adjust_link(dev);

874
875
876
877
878
879
	/* 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;
880
	regs->rstat = RSTAT_CLEAR_RHALT;
881
882
883
	regs->dmactrl &= ~(DMACTRL_GRS | DMACTRL_GTS);
}

884
/* This returns the status bits of the device.	The return value
885
 * is never checked, and this is what the 8260 driver did, so we
886
 * do the same.	 Presumably, this would be zero if there were no
887
888
889
 * errors
 */
static int tsec_send(struct eth_device *dev, volatile void *packet, int length)
890
891
892
{
	int i;
	int result = 0;
893
894
	struct tsec_private *priv = (struct tsec_private *)dev->priv;
	volatile tsec_t *regs = priv->regs;
895
896

	/* Find an empty buffer descriptor */
897
	for (i = 0; rtx.txbd[txIdx].status & TXBD_READY; i++) {
898
		if (i >= TOUT_LOOP) {
899
			debug("%s: tsec: tx buffers full\n", dev->name);
900
901
902
903
			return result;
		}
	}

904
	rtx.txbd[txIdx].bufPtr = (uint) packet;
905
	rtx.txbd[txIdx].length = length;
906
907
	rtx.txbd[txIdx].status |=
	    (TXBD_READY | TXBD_LAST | TXBD_CRC | TXBD_INTERRUPT);
908
909
910
911
912

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

	/* Wait for buffer to be transmitted */
913
	for (i = 0; rtx.txbd[txIdx].status & TXBD_READY; i++) {
914
		if (i >= TOUT_LOOP) {
915
			debug("%s: tsec: tx error\n", dev->name);
916
917
918
919
920
921
922
923
924
925
			return result;
		}
	}

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

	return result;
}

926
static int tsec_recv(struct eth_device *dev)
927
928
{
	int length;
929
930
	struct tsec_private *priv = (struct tsec_private *)dev->priv;
	volatile tsec_t *regs = priv->regs;
931

932
	while (!(rtx.rxbd[rxIdx].status & RXBD_EMPTY)) {
933
934
935
936
937
938

		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);
939
940
		} else {
			printf("Got error %x\n",
941
			       (rtx.rxbd[rxIdx].status & RXBD_STATS));
942
943
944
945
946
		}

		rtx.rxbd[rxIdx].length = 0;

		/* Set the wrap bit if this is the last element in the list */
947
948
		rtx.rxbd[rxIdx].status =
		    RXBD_EMPTY | (((rxIdx + 1) == PKTBUFSRX) ? RXBD_WRAP : 0);
949
950
951
952

		rxIdx = (rxIdx + 1) % PKTBUFSRX;
	}

953
	if (regs->ievent & IEVENT_BSY) {
954
955
956
957
958
959
960
961
		regs->ievent = IEVENT_BSY;
		regs->rstat = RSTAT_CLEAR_RHALT;
	}

	return -1;

}

962
/* Stop the interface */
963
static void tsec_halt(struct eth_device *dev)
964
{
965
966
	struct tsec_private *priv = (struct tsec_private *)dev->priv;
	volatile tsec_t *regs = priv->regs;
967
968
969
970

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

971
	while (!(regs->ievent & (IEVENT_GRSC | IEVENT_GTSC))) ;
972
973
974

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

975
	/* Shut down the PHY, as needed */
976
977
	if(priv->phyinfo)
		phy_run_commands(priv, priv->phyinfo->shutdown);
978
979
}

980
struct phy_info phy_info_M88E1149S = {
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
	0x1410ca,
	"Marvell 88E1149S",
	4,
	(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,}
	},
1011
1012
};

1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
/* The 5411 id is 0x206070, the 5421 is 0x2060e0 */
struct phy_info phy_info_BCM5461S = {
	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,}
	},
};

Joe Hamman's avatar
Joe Hamman committed
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
struct phy_info phy_info_BCM5464S = {
	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,}
	},
};

1068
1069
1070
1071
struct phy_info phy_info_M88E1011S = {
	0x01410c6,
	"Marvell 88E1011S",
	4,
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
	(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,}
			   },
1099
1100
};

1101
1102
1103
1104
struct phy_info phy_info_M88E1111S = {
	0x01410cc,
	"Marvell 88E1111S",
	4,
1105
1106
1107
	(struct phy_cmd[]){	/* config */
			   /* Reset and configure the PHY */
			   {MIIM_CONTROL, MIIM_CONTROL_RESET, NULL},
1108
			   {0x1b, 0x848f, &mii_m88e1111s_setmode},
1109
			   {0x14, 0x0cd2, NULL}, /* Delay RGMII TX and RX */
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
			   {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,}
			   },
1129
1130
};

1131
1132
1133
1134
1135
1136
1137
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 |
1138
		    MIIM_M88E1145_RGMII_RX_DELAY | MIIM_M88E1145_RGMII_TX_DELAY;
1139
1140
1141
1142
1143
1144
1145
1146
	else
		return mii_data;
}

static struct phy_info phy_info_M88E1145 = {
	0x01410cd,
	"Marvell 88E1145",
	4,
1147
	(struct phy_cmd[]){	/* config */
1148
1149
1150
			   /* Reset the PHY */
			   {MIIM_CONTROL, MIIM_CONTROL_RESET, NULL},

1151
1152
1153
1154
1155
1156
			   /* Errata E0, E1 */
			   {29, 0x001b, NULL},
			   {30, 0x418f, NULL},
			   {29, 0x0016, NULL},
			   {30, 0xa2da, NULL},

1157
			   /* Configure the PHY */
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
			   {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,}
			   },
1182
1183
};

1184
1185
1186
1187
struct phy_info phy_info_cis8204 = {
	0x3f11,
	"Cicada Cis8204",
	6,
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
	(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,}
			   },
1213
1214
1215
1216
1217
1218
1219
};

/* Cicada 8201 */
struct phy_info phy_info_cis8201 = {
	0xfc41,
	"CIS8201",
	4,
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 */
			   /* 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,}
			   },
1244
};
1245
struct phy_info phy_info_VSC8244 = {
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
	0x3f1b,
	"Vitesse VSC8244",
	6,
	(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,}
			   },
1268
};
1269
1270
1271
1272
1273

struct phy_info phy_info_dm9161 = {
	0x0181b88,
	"Davicom DM9161E",
	4,
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
	(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,}
			   },
1300
};
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
/* a generic flavor.  */
struct phy_info phy_info_generic =  {
	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,}
	}
};

1322

wdenk's avatar
wdenk committed
1323
1324
uint mii_parse_lxt971_sr2(uint mii_reg, struct tsec_private *priv)
{
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
	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;
urwithsughosh@gmail.com's avatar
urwithsughosh@gmail.com committed
1341
			break;
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
		default:
			priv->speed = 100;
			priv->duplexity = 1;
		}
	} else {
		priv->speed = 0;
		priv->duplexity = 0;
	}

	return 0;
wdenk's avatar
wdenk committed
1352
1353
}

1354
1355
1356
1357
static struct phy_info phy_info_lxt971 = {
	0x0001378e,
	"LXT971",
	4,
1358
1359