Skip to content

Instantly share code, notes, and snippets.

@ozaki-r
Last active August 29, 2015 13:56
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ozaki-r/9182826 to your computer and use it in GitHub Desktop.
Save ozaki-r/9182826 to your computer and use it in GitHub Desktop.
Patches for CKB-3352
Index: sys/arch/arm/omap/if_cpsw.c
===================================================================
RCS file: /cvs/cvsroot/src/sys/arch/arm/omap/if_cpsw.c,v
retrieving revision 1.4
diff -u -r1.4 if_cpsw.c
--- sys/arch/arm/omap/if_cpsw.c 18 Dec 2013 12:53:26 -0000 1.4
+++ sys/arch/arm/omap/if_cpsw.c 26 Feb 2014 02:44:33 -0000
@@ -122,6 +122,7 @@
bus_addr_t sc_rxdescs_pa;
struct ethercom sc_ec;
struct mii_data sc_mii;
+ bool sc_phy_has_1000t;
callout_t sc_tick_ch;
void *sc_ih;
struct cpsw_ring_data *sc_rdp;
@@ -163,6 +164,11 @@
static int cpsw_txintr(void *);
static int cpsw_miscintr(void *);
+/* ALE support */
+#define CPSW_MAX_ALE_ENTRIES 1024
+
+static int cpsw_ale_update_addresses(struct cpsw_softc *, int purge);
+
CFATTACH_DECL_NEW(cpsw, sizeof(struct cpsw_softc),
cpsw_match, cpsw_attach, NULL, NULL);
@@ -318,6 +324,18 @@
return 0;
}
+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;
+}
+
static void
cpsw_attach(device_t parent, device_t self, void *aux)
{
@@ -469,13 +487,28 @@
sc->sc_ec.ec_mii = &sc->sc_mii;
ifmedia_init(&sc->sc_mii.mii_media, 0, ether_mediachange,
ether_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, 0, 0);
if (LIST_FIRST(&sc->sc_mii.mii_phys) == NULL) {
aprint_error_dev(self, "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) {
+ aprint_normal_dev(sc->sc_dev, "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);
}
@@ -791,6 +824,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);
@@ -805,9 +840,12 @@
cpsw_write_4(sc, CPSW_PORT_P_SA_LO(i+1),
sc->sc_enaddr[4] | (sc->sc_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));
+ /* 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);
@@ -820,6 +858,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);
@@ -1242,3 +1283,194 @@
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)
+{
+ uint8_t *mac = sc->sc_enaddr;
+ uint32_t ale_entry[3];
+ int i;
+ struct ethercom * const ec = &sc->sc_ec;
+ 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, &ec->ec_multiaddrs, enm_list) {
+ cpsw_ale_mc_entry_set(sc, ALE_PORT_MASK_ALL, ifma->enm_addrlo);
+ }
+
+ return 0;
+}
Index: sys/arch/arm/omap/if_cpswreg.h
===================================================================
RCS file: /cvs/cvsroot/src/sys/arch/arm/omap/if_cpswreg.h,v
retrieving revision 1.1
diff -u -r1.1 if_cpswreg.h
--- sys/arch/arm/omap/if_cpswreg.h 3 Jan 2013 21:13:26 -0000 1.1
+++ sys/arch/arm/omap/if_cpswreg.h 26 Feb 2014 02:44:33 -0000
@@ -34,6 +34,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))
@@ -42,6 +43,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)
@@ -133,4 +136,82 @@
#define CPSW_INTROFF_TX 2
#define CPSW_INTROFF_MISC 3
+/* MDIOCONTROL Register Field */
+#define MDIOCTL_IDLE __BIT32(31)
+#define MDIOCTL_ENABLE __BIT32(30)
+#define MDIOCTL_HIGHEST_USER_CHANNEL(val) ((0xf & (val)) << 24)
+#define MDIOCTL_PREAMBLE __BIT32(20)
+#define MDIOCTL_FAULT __BIT32(19)
+#define MDIOCTL_FAULTENB __BIT32(18)
+#define MDIOCTL_INTTESTENB __BIT32(17)
+#define MDIOCTL_CLKDIV(val) (0xff & (val))
+
+/* ALE Control Register Field */
+#define ALECTL_ENABLE_ALE __BIT32(31)
+#define ALECTL_CLEAR_TABLE __BIT32(30)
+#define ALECTL_AGE_OUT_NOW __BIT32(29)
+#define ALECTL_EN_P0_UNI_FLOOD __BIT32(8)
+#define ALECTL_LEARN_NO_VID __BIT32(7)
+#define ALECTL_EN_VID0_MODE __BIT32(6)
+#define ALECTL_ENABLE_OUI_DENY __BIT32(5)
+#define ALECTL_BYPASS __BIT32(4)
+#define ALECTL_RATE_LIMIT_TX __BIT32(3)
+#define ALECTL_VLAN_AWARE __BIT32(2)
+#define ALECTL_ENABLE_AUTH_MODE __BIT32(1)
+#define ALECTL_ENABLE_RATE_LIMIT __BIT32(0)
+
+/* GMII_SEL Register Field */
+#define GMIISEL_RMII2_IO_CLK_EN __BIT32(7)
+#define GMIISEL_RMII1_IO_CLK_EN __BIT32(6)
+#define GMIISEL_RGMII2_IDMODE __BIT32(5)
+#define GMIISEL_RGMII1_IDMODE __BIT32(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 __BIT32(24)
+#define SLMACCTL_RX_CSF_EN __BIT32(23)
+#define SLMACCTL_RX_CEF_EN __BIT32(22)
+#define SLMACCTL_TX_SHORT_GAP_LIM_EN __BIT32(21)
+#define SLMACCTL_EXT_EN __BIT32(18)
+#define SLMACCTL_GIG_FORCE __BIT32(17)
+#define SLMACCTL_IFCTL_B __BIT32(16)
+#define SLMACCTL_IFCTL_A __BIT32(15)
+#define SLMACCTL_CMD_IDLE __BIT32(11)
+#define SLMACCTL_TX_SHORT_GAP_EN __BIT32(10)
+#define SLMACCTL_GIG __BIT32(7)
+#define SLMACCTL_TX_PACE __BIT32(6)
+#define SLMACCTL_GMII_EN __BIT32(5)
+#define SLMACCTL_TX_FLOW_EN __BIT32(4)
+#define SLMACCTL_RX_FLOW_EN __BIT32(3)
+#define SLMACCTL_MTEST __BIT32(2)
+#define SLMACCTL_LOOPBACK __BIT32(1)
+#define SLMACCTL_FULLDUPLEX __BIT32(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 */
Index: sys/dev/mii/files.mii
===================================================================
RCS file: /cvs/cvsroot/src/sys/dev/mii/files.mii,v
retrieving revision 1.48
diff -u -r1.48 files.mii
--- sys/dev/mii/files.mii 26 Jan 2011 18:48:12 -0000 1.48
+++ sys/dev/mii/files.mii 25 Feb 2014 10:52:05 -0000
@@ -148,3 +148,7 @@
device rdcphy: mii_phy
attach rdcphy at mii
file dev/mii/rdcphy.c rdcphy
+
+device micphy: mii_phy, ukphy_subr
+attach micphy at mii
+file dev/mii/micphy.c micphy
Index: sys/dev/mii/micphy.c
===================================================================
RCS file: sys/dev/mii/micphy.c
diff -N sys/dev/mii/micphy.c
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ sys/dev/mii/micphy.c 25 Feb 2014 10:52:06 -0000
@@ -0,0 +1,251 @@
+/* $NetBSD$ */
+
+/*-
+ * Copyright (c) 1998, 1999, 2000 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility,
+ * NASA Ames Research Center, and by Frank van der Linden.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * Copyright (c) 1997 Manuel Bouyer. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * Driver for Micrel KSZ9021RN PHYs
+ */
+
+#include <sys/cdefs.h>
+__KERNEL_RCSID(0, "$NetBSD$");
+
+#include "opt_mii.h"
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/device.h>
+#include <sys/socket.h>
+#include <sys/errno.h>
+
+#include <net/if.h>
+#include <net/if_media.h>
+
+#include <dev/mii/mii.h>
+#include <dev/mii/miivar.h>
+#include <dev/mii/miidevs.h>
+
+static int micphymatch(device_t, cfdata_t, void *);
+static void micphyattach(device_t, device_t, void *);
+
+CFATTACH_DECL3_NEW(micphy, sizeof(struct mii_softc),
+ micphymatch, micphyattach, mii_phy_detach, mii_phy_activate, NULL, NULL,
+ DVF_DETACH_SHUTDOWN);
+
+static int micphy_service(struct mii_softc *, struct mii_data *, int);
+static void micphy_fixup(struct mii_softc *, int, int, device_t);
+
+static const struct mii_phy_funcs micphy_funcs = {
+ micphy_service, ukphy_status, mii_phy_reset,
+};
+
+static const struct mii_phydesc micphys[] = {
+ { MII_OUI_MICREL, MII_MODEL_MICREL_KSZ9021RNI,
+ MII_STR_MICREL_KSZ9021RNI },
+
+ { 0, 0,
+ NULL },
+};
+
+static int
+micphymatch(device_t parent, cfdata_t match, void *aux)
+{
+ struct mii_attach_args *ma = aux;
+
+ if (mii_phy_match(ma, micphys) != NULL)
+ return 10;
+
+ return 1;
+}
+
+static void
+micphyattach(device_t parent, device_t self, void *aux)
+{
+ struct mii_softc *sc = device_private(self);
+ struct mii_attach_args *ma = aux;
+ struct mii_data *mii = ma->mii_data;
+ int model = MII_MODEL(ma->mii_id2);
+ int rev = MII_REV(ma->mii_id2);
+ const struct mii_phydesc *mpd;
+
+ mpd = mii_phy_match(ma, micphys);
+ aprint_naive(": Media interface\n");
+ aprint_normal(": %s, rev. %d\n", mpd->mpd_name, rev);
+
+ sc->mii_dev = self;
+ sc->mii_inst = mii->mii_instance;
+ sc->mii_phy = ma->mii_phyno;
+ sc->mii_funcs = &micphy_funcs;
+ sc->mii_pdata = mii;
+ sc->mii_flags = ma->mii_flags;
+ sc->mii_anegticks = MII_ANEGTICKS;
+
+ PHY_RESET(sc);
+
+ micphy_fixup(sc, model, rev, parent);
+
+ sc->mii_capabilities =
+ PHY_READ(sc, MII_BMSR) & ma->mii_capmask;
+ if (sc->mii_capabilities & BMSR_EXTSTAT)
+ sc->mii_extcapabilities = PHY_READ(sc, MII_EXTSR);
+ aprint_normal_dev(self, "");
+ if ((sc->mii_capabilities & BMSR_MEDIAMASK) == 0 &&
+ (sc->mii_extcapabilities & EXTSR_MEDIAMASK) == 0)
+ aprint_error("no media present");
+ else
+ mii_phy_add_media(sc);
+ aprint_normal("\n");
+}
+
+static int
+micphy_service(struct mii_softc *sc, struct mii_data *mii, int cmd)
+{
+ struct ifmedia_entry *ife = mii->mii_media.ifm_cur;
+ int reg;
+
+ switch (cmd) {
+ case MII_POLLSTAT:
+ /*
+ * If we're not polling our PHY instance, just return.
+ */
+ if (IFM_INST(ife->ifm_media) != sc->mii_inst)
+ return 0;
+ break;
+
+ case MII_MEDIACHG:
+ /*
+ * If the media indicates a different PHY instance,
+ * isolate ourselves.
+ */
+ if (IFM_INST(ife->ifm_media) != sc->mii_inst) {
+ reg = PHY_READ(sc, MII_BMCR);
+ PHY_WRITE(sc, MII_BMCR, reg | BMCR_ISO);
+ return 0;
+ }
+
+ /*
+ * If the interface is not up, don't do anything.
+ */
+ if ((mii->mii_ifp->if_flags & IFF_UP) == 0)
+ break;
+
+ mii_phy_setmedia(sc);
+ break;
+
+ case MII_TICK:
+ /*
+ * If we're not currently selected, just return.
+ */
+ if (IFM_INST(ife->ifm_media) != sc->mii_inst)
+ return 0;
+
+ if (mii_phy_tick(sc) == EJUSTRETURN)
+ return 0;
+ break;
+
+ case MII_DOWN:
+ mii_phy_down(sc);
+ return 0;
+ }
+
+ /* Update the media status. */
+ mii_phy_status(sc);
+
+ /* Callback if something changed. */
+ mii_phy_update(sc, cmd);
+ return 0;
+}
+
+#define XREG_CONTROL 0x0b
+#define XREG_WRITE 0x0c
+#define XREG_READ 0x0d
+#define XREG_CTL_SEL_READ 0x0000
+#define XREG_CTL_SEL_WRITE 0x8000
+
+#define REG_RGMII_CLOCK_AND_CONTROL 0x104
+#define REG_RGMII_RX_DATA 0x105
+
+static void micphy_writexreg(struct mii_softc *sc, uint32_t reg, uint32_t wval)
+{
+ int rval;
+
+ PHY_WRITE(sc, XREG_CONTROL, XREG_CTL_SEL_WRITE | reg);
+ PHY_WRITE(sc, XREG_WRITE, wval);
+ PHY_WRITE(sc, XREG_CONTROL, XREG_CTL_SEL_READ | reg);
+ rval = PHY_READ(sc, XREG_READ);
+ KDASSERT(wval == rval);
+}
+
+static void
+micphy_fixup(struct mii_softc *sc, int model, int rev, device_t parent)
+{
+ switch (model) {
+ case MII_MODEL_MICREL_KSZ9021RNI:
+ if (!device_is_a(parent, "cpsw"))
+ break;
+
+ aprint_normal_dev(sc->mii_dev, "adjusting RGMII signal timing for cpsw\n");
+
+ // RGMII RX Data Pad Skew
+ micphy_writexreg(sc, REG_RGMII_RX_DATA, 0x0000);
+
+ // RGMII Clock and Control Pad Skew
+ micphy_writexreg(sc, REG_RGMII_CLOCK_AND_CONTROL, 0x9090);
+
+ break;
+ }
+
+ return;
+}
Index: sys/dev/mii/miidevs
===================================================================
RCS file: /cvs/cvsroot/src/sys/dev/mii/miidevs,v
retrieving revision 1.117
diff -u -r1.117 miidevs
--- sys/dev/mii/miidevs 21 Dec 2013 15:16:23 -0000 1.117
+++ sys/dev/mii/miidevs 25 Feb 2014 10:52:06 -0000
@@ -66,6 +66,7 @@
oui JMICRON 0x00d831 JMicron
oui LEVEL1 0x00207b Level 1
oui MARVELL 0x005043 Marvell Semiconductor
+oui MICREL 0x0010a1 Micrel
oui MYSON 0x00c0b4 Myson Technology
oui NATSEMI 0x080017 National Semiconductor
oui PMCSIERRA 0x00e004 PMC-Sierra
@@ -260,6 +261,9 @@
model xxMARVELL E1116R_29 0x0029 Marvell 88E1116R Gigabit PHY
model xxMARVELL E1543 0x002a Marvell 88E1543 Alaska Quad Port Gb PHY
+/* Micrel PHYs */
+model MICREL KSZ9021RNI 0x0021 Micrel KSZ9021RNI 10/100/1000 PHY
+
/* Myson Technology PHYs */
model xxMYSON MTD972 0x0000 MTD972 10/100 media interface
model MYSON MTD803 0x0000 MTD803 3-in-1 media interface
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment