Subject: Broadcom 575x GigE support
To: None <current-users@NetBSD.org>
From: Quentin Garnier <cube@NetBSD.org>
List: current-users
Date: 10/22/2004 17:17:19
This is a multi-part message in MIME format.

--Multipart=_Fri__22_Oct_2004_17_17_19_+0200_anxmFZKyaP/PHT5H
Content-Type: text/plain; charset=US-ASCII
Content-Transfer-Encoding: 7bit

Hi all,

Reading mostly from Linux and a bit from FreeBSD (it all comes from the
Linux driver anyway), I was able to make my Broadcom 5751 chip working.

I tried to reduce the number of magic numbers as much as I could, but
there are still a lot of them.

I'd like people to test the attached patch, since I can't test on 5750
and 5750M chips, and of course I can't test if it introduces a
regression for the rest of the 57xx series.

Unless there is a breakage, I'll commit it sometime next week.

Quentin Garnier.

--Multipart=_Fri__22_Oct_2004_17_17_19_+0200_anxmFZKyaP/PHT5H
Content-Type: text/plain;
 name="bge.diff"
Content-Disposition: attachment;
 filename="bge.diff"
Content-Transfer-Encoding: 7bit

Index: if_bge.c
===================================================================
RCS file: /cvsroot/src/sys/dev/pci/if_bge.c,v
retrieving revision 1.75
diff -u -r1.75 if_bge.c
--- if_bge.c	29 Sep 2004 11:22:03 -0000	1.75
+++ if_bge.c	22 Oct 2004 15:04:37 -0000
@@ -1288,7 +1288,14 @@
 		BGE_MEMWIN_WRITE(pa->pa_pc, pa->pa_tag, i, 0);
 
 	/* Set up the PCI DMA control register. */
-	if (pci_conf_read(pa->pa_pc, pa->pa_tag,BGE_PCI_PCISTATE) &
+	if (sc->bge_pcie) {
+		/* From FreeBSD */
+		DPRINTFN(4, ("(%s: PCI-Express DMA setting)\n",
+		    sc->bge_dev.dv_xname));
+		dma_rw_ctl = (BGE_PCI_READ_CMD | BGE_PCI_WRITE_CMD |
+		    (0xf << BGE_PCIDMARWCTL_RD_WAT_SHIFT) |
+		    (0x2 << BGE_PCIDMARWCTL_WR_WAT_SHIFT));
+	} else if (pci_conf_read(pa->pa_pc, pa->pa_tag,BGE_PCI_PCISTATE) &
 	    BGE_PCISTATE_PCI_BUSMODE) {
 		/* Conventional PCI bus */
 	  	DPRINTFN(4, ("(%s: PCI 2.2 DMA setting)\n", sc->bge_dev.dv_xname));
@@ -1926,6 +1933,14 @@
 	  BGE_QUIRK_ONLY_PHY_1|BGE_QUIRK_5705_CORE,
 	  "BCM5705 A3" },
 
+	{ BGE_CHIPID_BCM5750_A0,
+	  BGE_QUIRK_ONLY_PHY_1|BGE_QUIRK_5705_CORE,
+	  "BCM5750 A1" },
+
+	{ BGE_CHIPID_BCM5750_A1,
+	  BGE_QUIRK_ONLY_PHY_1|BGE_QUIRK_5705_CORE,
+	  "BCM5750 A1" },
+
 	{ 0, 0, NULL }
 };
 
@@ -1954,6 +1969,10 @@
 	  BGE_QUIRK_ONLY_PHY_1|BGE_QUIRK_5705_CORE,
 	  "unknown BCM5705" },
 
+	{ BGE_ASICREV_BCM5750,
+	  BGE_QUIRK_ONLY_PHY_1|BGE_QUIRK_5705_CORE,
+	  "unknown BCM5750" },
+
 	{ 0,
 	  0,
 	  NULL }
@@ -2062,6 +2081,21 @@
 	  "Broadcom BCM5705M Gigabit Ethernet",
 	  },
 
+	{ PCI_VENDOR_BROADCOM,
+	  PCI_PRODUCT_BROADCOM_BCM5750,
+	  "Broadcom BCM5750 Gigabit Ethernet",
+	  },
+
+	{ PCI_VENDOR_BROADCOM,
+	  PCI_PRODUCT_BROADCOM_BCM5750M,
+	  "Broadcom BCM5750M Gigabit Ethernet",
+	  },
+
+	{ PCI_VENDOR_BROADCOM,
+	  PCI_PRODUCT_BROADCOM_BCM5751,
+	  "Broadcom BCM5751 Gigabit Ethernet",
+	  },
+
    	{ PCI_VENDOR_BROADCOM,
 	  PCI_PRODUCT_BROADCOM_BCM5782,
 	  "Broadcom BCM5782 Gigabit Ethernet",
@@ -2280,6 +2314,25 @@
 	pci_conf_write(pc, pa->pa_tag, BGE_PCI_PWRMGMT_CMD, pm_ctl);
 	DELAY(1000);	/* 27 usec is allegedly sufficent */
 
+	/*
+	 * Save ASIC rev.  Look up any quirks associated with this
+	 * ASIC.
+	 */
+	sc->bge_chipid =
+	    pci_conf_read(pa->pa_pc, pa->pa_tag, BGE_PCI_MISC_CTL) &
+	    BGE_PCIMISCCTL_ASICREV;
+
+	/*
+	 * Detect PCI-Express devices
+	 * XXX: guessed from Linux/FreeBSD; no documentation
+	 */
+	if (BGE_ASICREV(sc->bge_chipid) == BGE_ASICREV_BCM5750 &&
+	    pci_get_capability(pa->pa_pc, pa->pa_tag, PCI_CAP_PCIEXPRESS,
+	    NULL, NULL) != 0)
+		sc->bge_pcie = 1;
+	else
+		sc->bge_pcie = 0;
+
 	/* Try to reset the chip. */
 	DPRINTFN(5, ("bge_reset\n"));
 	bge_reset(sc);
@@ -2311,15 +2364,7 @@
 		return;
 	}
 
-	/*
-	 * Save ASIC rev.  Look up any quirks associated with this
-	 * ASIC.
-	 */
-	sc->bge_chipid =
-	    pci_conf_read(pa->pa_pc, pa->pa_tag, BGE_PCI_MISC_CTL) &
-	    BGE_PCIMISCCTL_ASICREV;
 	br = bge_lookup_rev(sc->bge_chipid);
-
 	aprint_normal("%s: ", sc->bge_dev.dv_xname);
 
 	if (br == NULL) {
@@ -2544,7 +2589,7 @@
 {
 	struct pci_attach_args *pa = &sc->bge_pa;
 	u_int32_t cachesize, command, pcistate, new_pcistate;
-	int i, val = 0;
+	int i, val;
 
 	/* Save some important PCI state. */
 	cachesize = pci_conf_read(pa->pa_pc, pa->pa_tag, BGE_PCI_CACHESZ);
@@ -2555,12 +2600,42 @@
 	    BGE_PCIMISCCTL_INDIRECT_ACCESS|BGE_PCIMISCCTL_MASK_PCI_INTR|
 	    BGE_HIF_SWAP_OPTIONS|BGE_PCIMISCCTL_PCISTATE_RW);
 
+	val = BGE_MISCCFG_RESET_CORE_CLOCKS | (65<<1);
+	/*
+	 * XXX: from FreeBSD/Linux; no documentation
+	 */
+	if (sc->bge_pcie) {
+		if (CSR_READ_4(sc, BGE_PCIE_CTL1) == 0x60)
+			CSR_WRITE_4(sc, BGE_PCIE_CTL1, 0x20);
+		if (sc->bge_chipid != BGE_CHIPID_BCM5750_A0) {
+			/* No idea what that actually means */
+			CSR_WRITE_4(sc, BGE_MISC_CFG, 1 << 29);
+			val |= (1<<29);
+		}
+	}
+
 	/* Issue global reset */
-	bge_writereg_ind(sc, BGE_MISC_CFG,
-	    BGE_MISCCFG_RESET_CORE_CLOCKS|(65<<1));
+	bge_writereg_ind(sc, BGE_MISC_CFG, val);
 
 	DELAY(1000);
 
+	/*
+	 * XXX: from FreeBSD/Linux; no documentation
+	 */
+	if (sc->bge_pcie) {
+		if (sc->bge_chipid == BGE_CHIPID_BCM5750_A0) {
+			pcireg_t reg;
+
+			DELAY(500000);
+			/* XXX: Magic Numbers */
+			reg = pci_conf_read(pa->pa_pc, pa->pa_tag, BGE_PCI_UNKNOWN0);
+			pci_conf_write(pa->pa_pc, pa->pa_tag, BGE_PCI_UNKNOWN0,
+			    reg | (1 << 15));
+		}
+		/* XXX: Magic Numbers */
+		pci_conf_write(pa->pa_pc, pa->pa_tag, BGE_PCI_UNKNOWN1, 0xf5000);
+	}
+
 	/* Reset some of the PCI state that got zapped by reset */
 	pci_conf_write(pa->pa_pc, pa->pa_tag, BGE_PCI_MISC_CTL,
 	    BGE_PCIMISCCTL_INDIRECT_ACCESS|BGE_PCIMISCCTL_MASK_PCI_INTR|
@@ -2621,6 +2696,10 @@
 		    sc->bge_dev.dv_xname);
 	}
 
+	/* XXX: from FreeBSD/Linux; no documentation */
+	if (sc->bge_pcie && sc->bge_chipid != BGE_CHIPID_BCM5750_A0)
+		CSR_WRITE_4(sc, BGE_PCIE_CTL0, CSR_READ_4(sc, BGE_PCIE_CTL0) | (1<<25));
+
 	/* Enable memory arbiter. */
 	if ((sc->bge_quirks & BGE_QUIRK_5705_CORE) == 0) {
 		CSR_WRITE_4(sc, BGE_MARB_MODE, BGE_MARBMODE_ENABLE);
Index: if_bgereg.h
===================================================================
RCS file: /cvsroot/src/sys/dev/pci/if_bgereg.h,v
retrieving revision 1.21
diff -u -r1.21 if_bgereg.h
--- if_bgereg.h	15 May 2004 22:19:27 -0000	1.21
+++ if_bgereg.h	22 Oct 2004 15:04:37 -0000
@@ -192,6 +192,9 @@
 #define BGE_PCI_UNDI_TX_BD_PRODIDX_LO	0xAC
 #define BGE_PCI_ISR_MBX_HI		0xB0
 #define BGE_PCI_ISR_MBX_LO		0xB4
+/* XXX: used in PCI-Express code for 575x chips */
+#define BGE_PCI_UNKNOWN0		0xC4
+#define BGE_PCI_UNKNOWN1		0xD8
 
 /* PCI Misc. Host control register */
 #define BGE_PCIMISCCTL_CLEAR_INTA	0x00000001
@@ -244,6 +247,8 @@
 #define BGE_CHIPID_BCM5705_A1		0x30010000
 #define BGE_CHIPID_BCM5705_A2		0x30020000
 #define BGE_CHIPID_BCM5705_A3		0x30030000
+#define BGE_CHIPID_BCM5750_A0		0x40000000
+#define BGE_CHIPID_BCM5750_A1		0x40010000
 
 /* shorthand one */
 #define BGE_ASICREV(x)                  ((x) >> 28)
@@ -252,6 +257,7 @@
 #define BGE_ASICREV_BCM5703             0x01
 #define BGE_ASICREV_BCM5704             0x02
 #define BGE_ASICREV_BCM5705             0x03
+#define BGE_ASICREV_BCM5750             0x04
 
 /* chip revisions */
 #define BGE_CHIPREV(x)                  ((x) >> 24)
@@ -1608,6 +1614,12 @@
 #define BGE_EE_CTL			0x6840
 #define BGE_MDI_CTL			0x6844
 #define BGE_EE_DELAY			0x6848
+/*
+ * XXX: Those names are made up as I have no documentation about it;
+ *      I only know it is only used in the PCI-Express case.
+ */
+#define BGE_PCIE_CTL0			0x7c00
+#define BGE_PCIE_CTL1			0x7e2c
 
 /* Mode control register */
 #define BGE_MODECTL_INT_SNDCOAL_ONLY	0x00000001
@@ -2313,6 +2325,7 @@
 	u_int8_t		bge_extram;	/* has external SSRAM */
 	u_int8_t		bge_tbi;
     	u_int8_t		bge_rx_alignment_bug;
+	u_int8_t		bge_pcie;	/* on a PCI Express port */
 	u_int32_t		bge_return_ring_cnt;
 	bus_dma_tag_t		bge_dmatag;
 	u_int32_t		bge_chipid;

--Multipart=_Fri__22_Oct_2004_17_17_19_+0200_anxmFZKyaP/PHT5H--