This diff will properly initialize cpsw if uboot hasn't done so already. It 
also adds support for 1000BaseT (RGMII) PHY found on some boards. Based heavily 
on a netbsd diff. My BBB is out of comission so please test this and provide 
feedback. Thanks.


diff -r 4d62a2f27093 -r 961793eb2b24 src/sys/arch/armv7/omap/if_cpsw.c
--- a/src/sys/arch/armv7/omap/if_cpsw.c Fri Apr 11 16:35:16 2014 -0400
+++ b/src/sys/arch/armv7/omap/if_cpsw.c Sat Apr 12 06:23:19 2014 -0400
@@ -127,7 +127,7 @@
 
        struct arpcom            sc_ac;
        struct mii_data          sc_mii;
-
+       bool sc_phy_has_1000t;
        struct cpsw_ring_data   *sc_rdp;
        volatile u_int           sc_txnext;
        volatile u_int           sc_txhead;
@@ -174,6 +174,10 @@
 int    cpsw_txintr(void *);
 int    cpsw_miscintr(void *);
 
+#define        CPSW_MAX_ALE_ENTRIES    1024
+
+static int cpsw_ale_update_addresses(struct cpsw_softc *, int purge);
+
 void   cpsw_get_mac_addr(struct cpsw_softc *);
 
 struct cfattach cpsw_ca = {
@@ -298,6 +302,18 @@
        }
 }
 
+static bool
+cpsw_phy_has_1000t(struct cpsw_softc * const sc)
+{
+       struct ifmedia_entry *ifm;
+
+       TAILQ_FOREACH(ifm, &sc->sc_mii.mii_media.ifm_list, ifm_list) {
+       if (IFM_SUBTYPE(ifm->ifm_media) == IFM_1000_T)
+               return true;
+       }
+       return false;
+}
+
 void
 cpsw_attach(struct device *parent, struct device *self, void *aux)
 {
@@ -405,14 +421,29 @@
 
        ifmedia_init(&sc->sc_mii.mii_media, 0, cpsw_mediachange,
            cpsw_mediastatus);
+
+       /* Initialize MDIO */
+       cpsw_write_4(sc, MDIOCONTROL, MDIOCTL_ENABLE | MDIOCTL_FAULTENB | 
MDIOCTL_CLKDIV(0xff));
+       /* Clear ALE */
+       cpsw_write_4(sc, CPSW_ALE_CONTROL, ALECTL_CLEAR_TABLE);
+
        mii_attach(self, &sc->sc_mii, 0xffffffff,
            MII_PHY_ANY, MII_OFFSET_ANY, 0);
        if (LIST_FIRST(&sc->sc_mii.mii_phys) == NULL) {
                printf("no PHY found!\n");
+               sc->sc_phy_has_1000t = false;
                ifmedia_add(&sc->sc_mii.mii_media,
                    IFM_ETHER|IFM_MANUAL, 0, NULL);
                ifmedia_set(&sc->sc_mii.mii_media, IFM_ETHER|IFM_MANUAL);
        } else {
+               sc->sc_phy_has_1000t = cpsw_phy_has_1000t(sc);
+               if (sc->sc_phy_has_1000t) {
+                       printf("1000baseT PHY found. setting RGMII Mode\n");
+                       /* Select the Interface RGMII Mode in the Control 
Module */
+                       sitara_cm_reg_write_4(CPSW_GMII_SEL,
+                               GMIISEL_GMII2_SEL(RGMII_MODE) | 
GMIISEL_GMII1_SEL(RGMII_MODE));
+               }
+
                ifmedia_set(&sc->sc_mii.mii_media, IFM_ETHER|IFM_AUTO);
        }
 
@@ -781,6 +812,8 @@
 
        /* Reset and init Sliver port 1 and 2 */
        for (i = 0; i < 2; i++) {
+               uint32_t macctl;
+
                /* Reset */
                cpsw_write_4(sc, CPSW_SL_SOFT_RESET(i), 1);
                while(cpsw_read_4(sc, CPSW_SL_SOFT_RESET(i)) & 1);
@@ -795,10 +828,12 @@
                cpsw_write_4(sc, CPSW_PORT_P_SA_LO(i+1),
                    ac->ac_enaddr[4] | (ac->ac_enaddr[5] << 8));
 
-               /* Set MACCONTROL for ports 0,1: FULLDUPLEX(1), GMII_EN(5),
-                  IFCTL_A(15), IFCTL_B(16) FIXME */
-               cpsw_write_4(sc, CPSW_SL_MACCONTROL(i),
-                   1 | (1<<5) | (1<<15) | (1<<16));
+               /* Set MACCONTROL for ports 0,1 */
+               macctl = SLMACCTL_FULLDUPLEX | SLMACCTL_GMII_EN | 
+                  SLMACCTL_IFCTL_A;
+               if (sc->sc_phy_has_1000t)
+                       macctl |= SLMACCTL_GIG;
+               cpsw_write_4(sc, CPSW_SL_MACCONTROL(i), macctl);
 
                /* Set ALE port to forwarding(3) */
                cpsw_write_4(sc, CPSW_ALE_PORTCTL(i+1), 3);
@@ -811,6 +846,9 @@
        /* Set ALE port to forwarding(3) */
        cpsw_write_4(sc, CPSW_ALE_PORTCTL(0), 3);
 
+       /* Initialize addrs */
+       cpsw_ale_update_addresses(sc, 1);
+
        cpsw_write_4(sc, CPSW_SS_PTYPE, 0);
        cpsw_write_4(sc, CPSW_SS_STAT_PORT_EN, 7);
 
@@ -1220,3 +1258,191 @@
 
        return 1;
 }
+/*
+ * ALE support routines.
+ */
+
+static void
+cpsw_ale_entry_init(uint32_t *ale_entry)
+{
+       ale_entry[0] = ale_entry[1] = ale_entry[2] = 0;
+}
+ 
+static void
+cpsw_ale_entry_set_mac(uint32_t *ale_entry, const uint8_t *mac)
+{
+       ale_entry[0] = mac[2] << 24 | mac[3] << 16 | mac[4] << 8 | mac[5];
+       ale_entry[1] = mac[0] << 8 | mac[1];
+}
+ 
+static void
+cpsw_ale_entry_set_bcast_mac(uint32_t *ale_entry)
+{
+       ale_entry[0] = 0xffffffff;
+       ale_entry[1] = 0x0000ffff;
+}
+ 
+static void
+cpsw_ale_entry_set(uint32_t *ale_entry, ale_entry_filed_t field, uint32_t val)
+{
+       /* Entry type[61:60] is addr entry(1), Mcast fwd state[63:62] is fw(3)*/
+       switch (field) {
+       case ALE_ENTRY_TYPE:
+               /* [61:60] */
+               ale_entry[1] |= (val & 0x3) << 28;
+               break;
+       case ALE_MCAST_FWD_STATE:
+               /* [63:62] */
+               ale_entry[1] |= (val & 0x3) << 30;
+               break;
+       case ALE_PORT_MASK:
+               /* [68:66] */
+               ale_entry[2] |= (val & 0x7) << 2;
+               break;
+       case ALE_PORT_NUMBER:
+               /* [67:66] */
+               ale_entry[2] |= (val & 0x3) << 2;
+               break;
+       default:
+               panic("Invalid ALE entry field: %d\n", field);
+       }
+
+       return;
+}
+ 
+static bool
+cpsw_ale_entry_mac_match(const uint32_t *ale_entry, const uint8_t *mac)
+{
+       return (((ale_entry[1] >> 8) & 0xff) == mac[0]) &&
+            (((ale_entry[1] >> 0) & 0xff) == mac[1]) &&
+            (((ale_entry[0] >>24) & 0xff) == mac[2]) &&
+            (((ale_entry[0] >>16) & 0xff) == mac[3]) &&
+            (((ale_entry[0] >> 8) & 0xff) == mac[4]) &&
+            (((ale_entry[0] >> 0) & 0xff) == mac[5]);
+}
+ 
+static void
+cpsw_ale_set_outgoing_mac(struct cpsw_softc *sc, int port, const uint8_t *mac)
+{
+       cpsw_write_4(sc, CPSW_PORT_P_SA_HI(port),
+            mac[3] << 24 | mac[2] << 16 | mac[1] << 8 | mac[0]);
+       cpsw_write_4(sc, CPSW_PORT_P_SA_LO(port),
+            mac[5] << 8 | mac[4]);
+}
+ 
+static void
+cpsw_ale_read_entry(struct cpsw_softc *sc, uint16_t idx, uint32_t *ale_entry)
+{
+       cpsw_write_4(sc, CPSW_ALE_TBLCTL, idx & 1023);
+       ale_entry[0] = cpsw_read_4(sc, CPSW_ALE_TBLW0);
+       ale_entry[1] = cpsw_read_4(sc, CPSW_ALE_TBLW1);
+       ale_entry[2] = cpsw_read_4(sc, CPSW_ALE_TBLW2);
+}
+ 
+static void
+cpsw_ale_write_entry(struct cpsw_softc *sc, uint16_t idx, uint32_t *ale_entry)
+{
+       cpsw_write_4(sc, CPSW_ALE_TBLW0, ale_entry[0]);
+       cpsw_write_4(sc, CPSW_ALE_TBLW1, ale_entry[1]);
+       cpsw_write_4(sc, CPSW_ALE_TBLW2, ale_entry[2]);
+       cpsw_write_4(sc, CPSW_ALE_TBLCTL, 1 << 31 | (idx & 1023));
+}
+ 
+static int
+cpsw_ale_remove_all_mc_entries(struct cpsw_softc *sc)
+{
+       int i;
+       uint32_t ale_entry[3];
+ 
+       /* First two entries are link address and broadcast. */
+       for (i = 2; i < CPSW_MAX_ALE_ENTRIES; i++) {
+               cpsw_ale_read_entry(sc, i, ale_entry);
+               if (((ale_entry[1] >> 28) & 3) == 1 && /* Address entry */
+                    ((ale_entry[1] >> 8) & 1) == 1) { /* MCast link addr */
+                       ale_entry[0] = ale_entry[1] = ale_entry[2] = 0;
+                       cpsw_ale_write_entry(sc, i, ale_entry);
+               }
+       }
+       return CPSW_MAX_ALE_ENTRIES;
+}
+ 
+static int
+cpsw_ale_mc_entry_set(struct cpsw_softc *sc, uint8_t portmask, uint8_t *mac)
+{
+       int free_index = -1, matching_index = -1, i;
+       uint32_t ale_entry[3];
+ 
+       /* Find a matching entry or a free entry. */
+       for (i = 0; i < CPSW_MAX_ALE_ENTRIES; i++) {
+               cpsw_ale_read_entry(sc, i, ale_entry);
+ 
+               /* Entry Type[61:60] is 0 for free entry */
+               if (free_index < 0 && ((ale_entry[1] >> 28) & 3) == 0) {
+                       free_index = i;
+               }
+ 
+               if (cpsw_ale_entry_mac_match(ale_entry, mac)) {
+                       matching_index = i;
+                       break;
+               }
+       }
+ 
+       if (matching_index < 0) {
+               if (free_index < 0)
+                       return ENOMEM;
+               i = free_index;
+       }
+ 
+       cpsw_ale_entry_init(ale_entry);
+ 
+       cpsw_ale_entry_set_mac(ale_entry, mac);
+       cpsw_ale_entry_set(ale_entry, ALE_ENTRY_TYPE, ALE_TYPE_ADDRESS);
+       cpsw_ale_entry_set(ale_entry, ALE_MCAST_FWD_STATE, ALE_FWSTATE_FWONLY);
+       cpsw_ale_entry_set(ale_entry, ALE_PORT_MASK, portmask);
+ 
+       cpsw_ale_write_entry(sc, i, ale_entry);
+ 
+       return 0;
+}
+ 
+static int
+cpsw_ale_update_addresses(struct cpsw_softc *sc, int purge)
+{
+       struct arpcom *ac = &sc->sc_ac;
+       uint8_t *mac = ac->ac_enaddr;
+       uint32_t ale_entry[3];
+       int i;
+       struct ether_multi *ifma;
+ 
+       cpsw_ale_entry_init(ale_entry);
+       /* Route incoming packets for our MAC address to Port 0 (host). */
+       /* For simplicity, keep this entry at table index 0 in the ALE. */
+       cpsw_ale_entry_set_mac(ale_entry, mac);
+       cpsw_ale_entry_set(ale_entry, ALE_ENTRY_TYPE, ALE_TYPE_ADDRESS);
+       cpsw_ale_entry_set(ale_entry, ALE_PORT_NUMBER, 0);
+       cpsw_ale_write_entry(sc, 0, ale_entry);
+ 
+       /* Set outgoing MAC Address for Ports 1 and 2. */
+       for (i = 1; i < 3; ++i)
+               cpsw_ale_set_outgoing_mac(sc, i, mac);
+ 
+       /* Keep the broadcast address at table entry 1. */
+       cpsw_ale_entry_init(ale_entry);
+       cpsw_ale_entry_set_bcast_mac(ale_entry);
+       cpsw_ale_entry_set(ale_entry, ALE_ENTRY_TYPE, ALE_TYPE_ADDRESS);
+       cpsw_ale_entry_set(ale_entry, ALE_MCAST_FWD_STATE, ALE_FWSTATE_FWONLY);
+       cpsw_ale_entry_set(ale_entry, ALE_PORT_MASK, ALE_PORT_MASK_ALL);
+       cpsw_ale_write_entry(sc, 1, ale_entry);
+ 
+       /* SIOCDELMULTI doesn't specify the particular address
+*                  being removed, so we have to remove all and rebuild. */
+       if (purge)
+               cpsw_ale_remove_all_mc_entries(sc);
+ 
+       /* Set other multicast addrs desired. */
+       LIST_FOREACH(ifma, &ac->ac_multiaddrs, enm_list) {
+               cpsw_ale_mc_entry_set(sc, ALE_PORT_MASK_ALL, ifma->enm_addrlo);
+       }
+ 
+       return 0;
+}
diff -r 4d62a2f27093 -r 961793eb2b24 src/sys/arch/armv7/omap/if_cpswreg.h
--- a/src/sys/arch/armv7/omap/if_cpswreg.h      Fri Apr 11 16:35:16 2014 -0400
+++ b/src/sys/arch/armv7/omap/if_cpswreg.h      Sat Apr 12 06:23:19 2014 -0400
@@ -39,6 +39,7 @@
 #define CPSW_SS_SOFT_RESET             (CPSW_SS_OFFSET + 0x08)
 #define CPSW_SS_STAT_PORT_EN           (CPSW_SS_OFFSET + 0x0C)
 #define CPSW_SS_PTYPE                  (CPSW_SS_OFFSET + 0x10)
+#define CPSW_SS_RGMII_CTL              (CPSW_SS_OFFSET + 0x88)
 
 #define CPSW_PORT_OFFSET               0x0100
 #define CPSW_PORT_P_TX_PRI_MAP(p)      (CPSW_PORT_OFFSET + 0x118 + ((p-1) * 
0x100))
@@ -47,6 +48,8 @@
 #define CPSW_PORT_P_SA_LO(p)           (CPSW_PORT_OFFSET + 0x120 + ((p-1) * 
0x100))
 #define CPSW_PORT_P_SA_HI(p)           (CPSW_PORT_OFFSET + 0x124 + ((p-1) * 
0x100))
 
+#define        CPSW_GMII_SEL                   0x0650
+
 #define CPSW_CPDMA_OFFSET              0x0800
 #define CPSW_CPDMA_TX_CONTROL          (CPSW_CPDMA_OFFSET + 0x04)
 #define CPSW_CPDMA_TX_TEARDOWN         (CPSW_CPDMA_OFFSET + 0x08)
@@ -112,7 +115,7 @@
 #define CPSW_WR_C_RX_STAT(p)           (CPSW_WR_OFFSET + (0x10 * (p)) + 0x44)
 #define CPSW_WR_C_TX_STAT(p)           (CPSW_WR_OFFSET + (0x10 * (p)) + 0x48)
 #define CPSW_WR_C_MISC_STAT(p)         (CPSW_WR_OFFSET + (0x10 * (p)) + 0x4C)
-#define  CPSW_MISC_HOST_PEND                   0x0004
+#define CPSW_MISC_HOST_PEND            0x0004
 
 #define CPSW_CPPI_RAM_OFFSET           0x2000
 
@@ -139,4 +142,82 @@
 #define CPSW_INTROFF_TX                2
 #define CPSW_INTROFF_MISC      3
 
+ /* MDIOCONTROL Register Field */
+#define MDIOCTL_IDLE            (1<<31)
+#define MDIOCTL_ENABLE          (1<<30)
+#define MDIOCTL_HIGHEST_USER_CHANNEL(val)       ((0xf & (val)) << 24)
+#define MDIOCTL_PREAMBLE        (1<<20)
+#define MDIOCTL_FAULT           (1<<19)
+#define MDIOCTL_FAULTENB        (1<<18)
+#define MDIOCTL_INTTESTENB      (1<<17)
+#define MDIOCTL_CLKDIV(val)     (0xff & (val))
+ 
+/* ALE Control Register Field */
+#define ALECTL_ENABLE_ALE       (1<<31)
+#define ALECTL_CLEAR_TABLE      (1<<30)
+#define ALECTL_AGE_OUT_NOW      (1<<29)
+#define ALECTL_EN_P0_UNI_FLOOD  (1<<8)
+#define ALECTL_LEARN_NO_VID     (1<<7)
+#define ALECTL_EN_VID0_MODE     (1<<6)
+#define ALECTL_ENABLE_OUI_DENY  (1<<5)
+#define ALECTL_BYPASS           (1<<4)
+#define ALECTL_RATE_LIMIT_TX    (1<<3)
+#define ALECTL_VLAN_AWARE       (1<<2)
+#define ALECTL_ENABLE_AUTH_MODE (1<<1)
+#define ALECTL_ENABLE_RATE_LIMIT        (1<<0)
+
+/* GMII_SEL Register Field */
+#define GMIISEL_RMII2_IO_CLK_EN (1<<7)
+#define GMIISEL_RMII1_IO_CLK_EN (1<<6)
+#define GMIISEL_RGMII2_IDMODE   (1<<5)
+#define GMIISEL_RGMII1_IDMODE   (1<<4)
+#define GMIISEL_GMII2_SEL(val)  ((0x3 & (val)) << 2)
+#define GMIISEL_GMII1_SEL(val)  ((0x3 & (val)) << 0)
+#define GMII_MODE       0
+#define RMII_MODE       1
+#define RGMII_MODE      2
+ 
+/* Sliver MACCONTROL Register Field */
+#define SLMACCTL_RX_CMF_EN      (1<<24)
+#define SLMACCTL_RX_CSF_EN      (1<<23)
+#define SLMACCTL_RX_CEF_EN      (1<<22)
+#define SLMACCTL_TX_SHORT_GAP_LIM_EN    (1<<21)
+#define SLMACCTL_EXT_EN         (1<<18)
+#define SLMACCTL_GIG_FORCE      (1<<17)
+#define SLMACCTL_IFCTL_B        (1<<16)
+#define SLMACCTL_IFCTL_A        (1<<15)
+#define SLMACCTL_CMD_IDLE       (1<<11)
+#define SLMACCTL_TX_SHORT_GAP_EN        (1<<10)
+#define SLMACCTL_GIG            (1<<7)
+#define SLMACCTL_TX_PACE        (1<<6)
+#define SLMACCTL_GMII_EN        (1<<5)
+#define SLMACCTL_TX_FLOW_EN     (1<<4)
+#define SLMACCTL_RX_FLOW_EN     (1<<3)
+#define SLMACCTL_MTEST          (1<<2)
+#define SLMACCTL_LOOPBACK       (1<<1)
+#define SLMACCTL_FULLDUPLEX     (1<<0)
+
+/* ALE Address Table Entry Field */
+typedef enum {
+        ALE_ENTRY_TYPE,
+        ALE_MCAST_FWD_STATE,
+        ALE_PORT_MASK,
+        ALE_PORT_NUMBER,
+} ale_entry_filed_t;
+        
+#define ALE_TYPE_FREE           0
+#define ALE_TYPE_ADDRESS        1
+#define ALE_TYPE_VLAN           2
+#define ALE_TYPE_VLAN_ADDRESS   3
+
+/*
+ * The port state(s) required for the received port on a destination address 
lookup
+ * in order for the multicast packet to be forwarded to the transmit port(s)
+ */
+#define ALE_FWSTATE_ALL         1       /* Blocking/Forwarding/Learning */
+#define ALE_FWSTATE_NOBLOCK     2       /* Forwarding/Learning */
+#define ALE_FWSTATE_FWONLY      3       /* Forwarding */
+
+#define ALE_PORT_MASK_ALL       7
+
 #endif /*_IF_CPSWREG_H */

Reply via email to