瀏覽代碼

init_fix_up

tags/v0.9.3
Udayan Kumar 17 年之前
父節點
當前提交
334abbde83
共有 1 個文件被更改,包括 161 次插入0 次删除
  1. 161
    0
      src/drivers/net/natsemi.c

+ 161
- 0
src/drivers/net/natsemi.c 查看文件

@@ -79,6 +79,7 @@
79 79
 #include <gpxe/spi_bit.h>
80 80
 #include <gpxe/threewire.h>
81 81
 #include <gpxe/nvo.h>
82
+#include <mii.h>
82 83
 
83 84
 #define TX_RING_SIZE 4
84 85
 #define NUM_RX_DESC  4
@@ -122,6 +123,28 @@ struct natsemi_nic {
122 123
 	struct nvo_block nvo;
123 124
 };
124 125
 
126
+
127
+/*
128
+ * Support for fibre connections on Am79C874:
129
+ * This phy needs a special setup when connected to a fibre cable.
130
+ * http://www.amd.com/files/connectivitysolutions/networking/archivednetworking/22235.pdf
131
+ */
132
+#define PHYID_AM79C874	0x0022561b
133
+
134
+enum {
135
+	MII_MCTRL	= 0x15,		/* mode control register */
136
+	MII_FX_SEL	= 0x0001,	/* 100BASE-FX (fiber) */
137
+	MII_EN_SCRM	= 0x0004,	/* enable scrambler (tp) */
138
+};
139
+
140
+
141
+
142
+/* values we might find in the silicon revision register */
143
+#define SRR_DP83815_C	0x0302
144
+#define SRR_DP83815_D	0x0403
145
+#define SRR_DP83816_A4	0x0504
146
+#define SRR_DP83816_A5	0x0505
147
+
125 148
 /* NATSEMI: Offsets to the device registers.
126 149
  * Unlike software-only systems, device drivers interact with complex hardware.
127 150
  * It's not useful to define symbolic names for every register bit in the
@@ -351,6 +374,143 @@ static void nat_reset ( struct natsemi_nic *nat ) {
351 374
 	outl ( SavedClkRun, nat->ioaddr + ClkRun );
352 375
 }
353 376
 
377
+
378
+static int mdio_read(struct net_device *netdev, int reg) {
379
+	struct natsemi_nic *nat = netdev->priv;
380
+
381
+	/* The 83815 series has two ports:
382
+	 * - an internal transceiver
383
+	 * - an external mii bus
384
+	 */
385
+		return inw(nat->ioaddr+BasicControl+(reg<<2));
386
+}
387
+
388
+static void mdio_write(struct net_device *netdev, int reg, u16 data) {
389
+	struct natsemi_nic *nat = netdev->priv;
390
+
391
+	/* The 83815 series has an internal transceiver; handle separately */
392
+		writew(data, nat->ioaddr+BasicControl+(reg<<2));
393
+}
394
+
395
+static void init_phy_fixup(struct net_device *netdev) {
396
+	struct natsemi_nic *nat = netdev->priv;
397
+	int i;
398
+	u32 cfg;
399
+	u16 tmp;
400
+	uint16_t advertising;
401
+	int mii;
402
+
403
+	/* restore stuff lost when power was out */
404
+	tmp = mdio_read(netdev, MII_BMCR);
405
+	advertising= mdio_read(netdev, MII_ADVERTISE);
406
+//	if (np->autoneg == AUTONEG_ENABLE) {
407
+		/* renegotiate if something changed */
408
+		if ((tmp & BMCR_ANENABLE) == 0
409
+		 || advertising != mdio_read(netdev, MII_ADVERTISE))
410
+		{
411
+			/* turn on autonegotiation and force negotiation */
412
+			tmp |= (BMCR_ANENABLE | BMCR_ANRESTART);
413
+			mdio_write(netdev, MII_ADVERTISE, advertising);
414
+		}
415
+//	} else {
416
+		/* turn off auto negotiation, set speed and duplexity */
417
+//		tmp &= ~(BMCR_ANENABLE | BMCR_SPEED100 | BMCR_FULLDPLX);
418
+//		if (np->speed == SPEED_100)
419
+///			tmp |= BMCR_SPEED100;
420
+//		if (np->duplex == DUPLEX_FULL)
421
+//			tmp |= BMCR_FULLDPLX;
422
+		/*
423
+		 * Note: there is no good way to inform the link partner
424
+		 * that our capabilities changed. The user has to unplug
425
+		 * and replug the network cable after some changes, e.g.
426
+		 * after switching from 10HD, autoneg off to 100 HD,
427
+		 * autoneg off.
428
+		 */
429
+//	}
430
+	mdio_write(netdev, MII_BMCR, tmp);
431
+	inl(nat->ioaddr + ChipConfig);
432
+	udelay(1);
433
+
434
+	/* find out what phy this is */
435
+	mii = (mdio_read(netdev, MII_PHYSID1) << 16)
436
+				+ mdio_read(netdev, MII_PHYSID2);
437
+
438
+	/* handle external phys here */
439
+	switch (mii) {
440
+	case PHYID_AM79C874:
441
+		/* phy specific configuration for fibre/tp operation */
442
+		tmp = mdio_read(netdev, MII_MCTRL);
443
+		tmp &= ~(MII_FX_SEL | MII_EN_SCRM);
444
+		//if (dev->if_port == PORT_FIBRE)
445
+		//	tmp |= MII_FX_SEL;
446
+		//else
447
+			tmp |= MII_EN_SCRM;
448
+		mdio_write(netdev, MII_MCTRL, tmp);
449
+		break;
450
+	default:
451
+		break;
452
+	}
453
+	cfg = inl(nat->ioaddr + ChipConfig);
454
+	if (cfg & CfgExtPhy)
455
+		return;
456
+
457
+	/* On page 78 of the spec, they recommend some settings for "optimum
458
+	   performance" to be done in sequence.  These settings optimize some
459
+	   of the 100Mbit autodetection circuitry.  They say we only want to
460
+	   do this for rev C of the chip, but engineers at NSC (Bradley
461
+	   Kennedy) recommends always setting them.  If you don't, you get
462
+	   errors on some autonegotiations that make the device unusable.
463
+
464
+	   It seems that the DSP needs a few usec to reinitialize after
465
+	   the start of the phy. Just retry writing these values until they
466
+	   stick.
467
+	*/
468
+	uint32_t srr = inl(nat->ioaddr + SiliconRev);
469
+	int NATSEMI_HW_TIMEOUT = 400;
470
+	for (i=0;i<NATSEMI_HW_TIMEOUT;i++) {
471
+
472
+		int dspcfg,dspcfg_1;
473
+		outw(1, nat->ioaddr + PGSEL);
474
+		outw(PMDCSR_VAL, nat->ioaddr + PMDCSR);
475
+		outw(TSTDAT_VAL, nat->ioaddr + TSTDAT);
476
+		dspcfg = (srr <= SRR_DP83815_C)?
477
+			DSPCFG_VAL : (DSPCFG_COEF | readw(nat->ioaddr + DSPCFG));
478
+		outw(dspcfg, nat->ioaddr + DSPCFG);
479
+		outw(SDCFG_VAL, nat->ioaddr + SDCFG);
480
+		outw(0, nat->ioaddr + PGSEL);
481
+		inl(nat->ioaddr + ChipConfig);
482
+		udelay(10);
483
+
484
+		outw(1, nat->ioaddr + PGSEL);
485
+		dspcfg_1 = readw(nat->ioaddr + DSPCFG);
486
+		outw(0, nat->ioaddr + PGSEL);
487
+		if (dspcfg == dspcfg_1)
488
+			break;
489
+	}
490
+
491
+		if (i==NATSEMI_HW_TIMEOUT) {
492
+			DBG ( "Natsemi: DSPCFG mismatch after retrying for"
493
+			      " %d usec.\n", i*10);
494
+		} else {
495
+			DBG ( "NATSEMI: DSPCFG accepted after %d usec.\n",
496
+			      i*10);
497
+		}
498
+	/*
499
+	 * Enable PHY Specific event based interrupts.  Link state change
500
+	 * and Auto-Negotiation Completion are among the affected.
501
+	 * Read the intr status to clear it (needed for wake events).
502
+	 */
503
+	inw(nat->ioaddr + MIntrStatus);
504
+	//MICRIntEn = 0x2
505
+	outw(0x2, nat->ioaddr + MIntrCtrl);
506
+}
507
+
508
+
509
+/* 
510
+ * Patch up for fixing CRC errors.
511
+ * adapted from linux natsemi driver
512
+ *
513
+ */
354 514
 static void do_cable_magic ( struct net_device *netdev ) {
355 515
 	struct natsemi_nic *nat = netdev->priv;
356 516
 	uint16_t data;
@@ -478,6 +638,7 @@ static int nat_open ( struct net_device *netdev ) {
478 638
 	 * testing this feature is required or not
479 639
 	 */
480 640
 	do_cable_magic ( netdev ); 
641
+	init_phy_fixup ( netdev );
481 642
 	
482 643
 
483 644
 	/* mask the interrupts. note interrupt is not enabled here

Loading…
取消
儲存