--- linux-2.4.30/drivers/net/b44.c	2004-08-08 01:26:05.000000000 +0200
+++ openwrt/build_mipsel/linux-2.4.30/drivers/net/b44.c	2005-05-01 20:10:19.193354917 +0200
@@ -1,7 +1,8 @@
 /* b44.c: Broadcom 4400 device driver.
  *
  * Copyright (C) 2002 David S. Miller (davem@redhat.com)
- * Fixed by Pekka Pietikainen (pp@ee.oulu.fi)
+ * Copyright (C) 2004 Pekka Pietikainen (pp@ee.oulu.fi)
+ * Copyright (C) 2004 Florian Schirmer (jolt@tuxbox.org)
  *
  * Distribute under GPL.
  */
@@ -25,6 +26,16 @@
 
 #include "b44.h"
 
+#include <typedefs.h>
+#include <bcmdevs.h>
+#include <bcmutils.h>
+#include <osl.h>
+#include <bcmutils.h>
+#include <bcmnvram.h>
+#include <sbconfig.h>
+#include <sbchipc.h>
+#include <sflash.h>
+
 #define DRV_MODULE_NAME		"b44"
 #define PFX DRV_MODULE_NAME	": "
 #define DRV_MODULE_VERSION	"0.93"
@@ -75,7 +86,7 @@
 	DRV_MODULE_NAME ".c:v" DRV_MODULE_VERSION " (" DRV_MODULE_RELDATE ")\n";
 
 MODULE_AUTHOR("David S. Miller (davem@redhat.com)");
-MODULE_DESCRIPTION("Broadcom 4400 10/100 PCI ethernet driver");
+MODULE_DESCRIPTION("Broadcom 4400/47xx 10/100 PCI ethernet driver");
 MODULE_LICENSE("GPL");
 MODULE_PARM(b44_debug, "i");
 MODULE_PARM_DESC(b44_debug, "B44 bitmapped debugging message enable value");
@@ -89,6 +100,8 @@
 	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
 	{ PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_BCM4401B1,
 	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
+	{ PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_BCM4713,
+	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
 	{ }	/* terminate list with empty entry */
 };
 
@@ -236,6 +249,8 @@
 	udelay(1);
 }
 
+static int b44_4713_instance;
+
 static int ssb_core_unit(struct b44 *bp)
 {
 #if 0
@@ -258,6 +273,9 @@
 		break;
 	};
 #endif
+	if (bp->pdev->device == PCI_DEVICE_ID_BCM4713)
+		return b44_4713_instance++;
+	else
 	return 0;
 }
 
@@ -267,6 +285,28 @@
 		== SBTMSLOW_CLOCK);
 }
 
+static void __b44_cam_read(struct b44 *bp, unsigned char *data, int index)
+{
+	u32 val;
+
+	bw32(B44_CAM_CTRL, (CAM_CTRL_READ |
+			    (index << CAM_CTRL_INDEX_SHIFT)));
+
+	b44_wait_bit(bp, B44_CAM_CTRL, CAM_CTRL_BUSY, 100, 1);
+
+	val = br32(B44_CAM_DATA_LO);
+
+	data[2] = (val >> 24) & 0xFF;
+	data[3] = (val >> 16) & 0xFF;
+	data[4] = (val >> 8) & 0xFF;
+	data[5] = (val >> 0) & 0xFF;
+
+	val = br32(B44_CAM_DATA_HI);
+
+	data[0] = (val >> 8) & 0xFF;
+	data[1] = (val >> 0) & 0xFF;
+}
+
 static void __b44_cam_write(struct b44 *bp, unsigned char *data, int index)
 {
 	u32 val;
@@ -307,6 +347,9 @@
 {
 	int err;
 
+	if (bp->phy_addr == B44_PHY_ADDR_NO_PHY)
+		return 0;
+
 	bw32(B44_EMAC_ISTAT, EMAC_INT_MII);
 	bw32(B44_MDIO_DATA, (MDIO_DATA_SB_START |
 			     (MDIO_OP_READ << MDIO_DATA_OP_SHIFT) |
@@ -321,6 +364,9 @@
 
 static int b44_writephy(struct b44 *bp, int reg, u32 val)
 {
+	if (bp->phy_addr == B44_PHY_ADDR_NO_PHY)
+		return 0;
+
 	bw32(B44_EMAC_ISTAT, EMAC_INT_MII);
 	bw32(B44_MDIO_DATA, (MDIO_DATA_SB_START |
 			     (MDIO_OP_WRITE << MDIO_DATA_OP_SHIFT) |
@@ -336,6 +382,9 @@
 	u32 val;
 	int err;
 
+	if (bp->phy_addr == B44_PHY_ADDR_NO_PHY)
+		return 0;
+
 	err = b44_writephy(bp, MII_BMCR, BMCR_RESET);
 	if (err)
 		return err;
@@ -406,6 +455,9 @@
 	u32 val;
 	int err;
 
+	if (bp->phy_addr == B44_PHY_ADDR_NO_PHY)
+		return 0;
+
 	if ((err = b44_readphy(bp, B44_MII_ALEDCTRL, &val)) != 0)
 		goto out;
 	if ((err = b44_writephy(bp, B44_MII_ALEDCTRL,
@@ -498,6 +550,19 @@
 {
 	u32 bmsr, aux;
 
+	if (bp->phy_addr == B44_PHY_ADDR_NO_PHY) {
+		bp->flags |= B44_FLAG_100_BASE_T;
+		bp->flags |= B44_FLAG_FULL_DUPLEX;
+		if (!netif_carrier_ok(bp->dev)) {
+			u32 val = br32(B44_TX_CTRL);
+			val |= TX_CTRL_DUPLEX;
+			bw32(B44_TX_CTRL, val);
+			netif_carrier_on(bp->dev);
+			b44_link_report(bp);
+		}
+		return;
+	}
+
 	if (!b44_readphy(bp, MII_BMSR, &bmsr) &&
 	    !b44_readphy(bp, B44_MII_AUXCTRL, &aux) &&
 	    (bmsr != 0xffff)) {
@@ -1092,6 +1157,8 @@
 /* bp->lock is held. */
 static void b44_chip_reset(struct b44 *bp)
 {
+	unsigned int sb_clock;
+
 	if (ssb_is_core_up(bp)) {
 		bw32(B44_RCV_LAZY, 0);
 		bw32(B44_ENET_CTRL, ENET_CTRL_DISABLE);
@@ -1105,9 +1172,10 @@
 		bw32(B44_DMARX_CTRL, 0);
 		bp->rx_prod = bp->rx_cons = 0;
 	} else {
-		ssb_pci_setup(bp, (bp->core_unit == 0 ?
-				   SBINTVEC_ENET0 :
-				   SBINTVEC_ENET1));
+		/*if (bp->pdev->device != PCI_DEVICE_ID_BCM4713)*/
+			ssb_pci_setup(bp, (bp->core_unit == 0 ?
+				   	SBINTVEC_ENET0 :
+				   	SBINTVEC_ENET1));
 	}
 
 	ssb_core_reset(bp);
@@ -1115,6 +1183,11 @@
 	b44_clear_stats(bp);
 
 	/* Make PHY accessible. */
+	if (bp->pdev->device == PCI_DEVICE_ID_BCM4713)
+		sb_clock = 100000000; /* 100 MHz */
+	else
+		sb_clock = 62500000; /* 62.5 MHz */
+
 	bw32(B44_MDIO_CTRL, (MDIO_CTRL_PREAMBLE |
 			     (0x0d & MDIO_CTRL_MAXF_MASK)));
 	br32(B44_MDIO_CTRL);
@@ -1669,20 +1742,42 @@
 {
 	u8 eeprom[128];
 	int err;
+	unsigned long flags;
 
-	err = b44_read_eeprom(bp, &eeprom[0]);
-	if (err)
-		goto out;
-
-	bp->dev->dev_addr[0] = eeprom[79];
-	bp->dev->dev_addr[1] = eeprom[78];
-	bp->dev->dev_addr[2] = eeprom[81];
-	bp->dev->dev_addr[3] = eeprom[80];
-	bp->dev->dev_addr[4] = eeprom[83];
-	bp->dev->dev_addr[5] = eeprom[82];
-
-	bp->phy_addr = eeprom[90] & 0x1f;
-	bp->mdc_port = (eeprom[90] >> 14) & 0x1;
+	if (bp->pdev->device == PCI_DEVICE_ID_BCM4713) {
+		/*
+		 * BCM47xx boards don't have a EEPROM. The MAC is stored in
+		 * a NVRAM area somewhere in the flash memory. As we don't
+		 * know the location and/or the format of the NVRAM area
+		 * here, we simply rely on the bootloader to write the
+		 * MAC into the CAM.
+		 */
+		spin_lock_irqsave(&bp->lock, flags);
+		__b44_cam_read(bp, bp->dev->dev_addr, 0);
+		spin_unlock_irqrestore(&bp->lock, flags);
+
+		/*
+		 * BCM47xx boards don't have a PHY. Usually there is a switch
+		 * chip with multiple PHYs connected to the PHY port.
+		 */
+		bp->phy_addr = B44_PHY_ADDR_NO_PHY;
+		bp->dma_offset = 0;
+	} else {
+		err = b44_read_eeprom(bp, &eeprom[0]);
+		if (err)
+			return err;
+
+		bp->dev->dev_addr[0] = eeprom[79];
+		bp->dev->dev_addr[1] = eeprom[78];
+		bp->dev->dev_addr[2] = eeprom[81];
+		bp->dev->dev_addr[3] = eeprom[80];
+		bp->dev->dev_addr[4] = eeprom[83];
+		bp->dev->dev_addr[5] = eeprom[82];
+
+		bp->phy_addr = eeprom[90] & 0x1f;
+		bp->dma_offset = SB_PCI_DMA;
+		bp->mdc_port = (eeprom[90] >> 14) & 0x1;
+	}
 
 	/* With this, plus the rx_header prepended to the data by the
 	 * hardware, we'll land the ethernet header on a 2-byte boundary.
@@ -1692,13 +1787,12 @@
 	bp->imask = IMASK_DEF;
 
 	bp->core_unit = ssb_core_unit(bp);
-	bp->dma_offset = ssb_get_addr(bp, SBID_PCI_DMA, 0);
 
 	/* XXX - really required? 
 	   bp->flags |= B44_FLAG_BUGGY_TXPTR;
          */
-out:
-	return err;
+
+	return 0;
 }
 
 static int __devinit b44_init_one(struct pci_dev *pdev,
@@ -1819,7 +1913,8 @@
 
 	pci_save_state(bp->pdev, bp->pci_cfg_state);
 
-	printk(KERN_INFO "%s: Broadcom 4400 10/100BaseT Ethernet ", dev->name);
+	printk(KERN_INFO "%s: Broadcom %s 10/100BaseT Ethernet ", dev->name,
+		(pdev->device == PCI_DEVICE_ID_BCM4713) ? "47xx" : "4400");
 	for (i = 0; i < 6; i++)
 		printk("%2.2x%c", dev->dev_addr[i],
 		       i == 5 ? '\n' : ':');