svn commit: r365388 - in stable/12/sys: arm64/rockchip dev/dwc

Oleksandr Tymoshenko gonzo at FreeBSD.org
Sun Sep 6 19:03:21 UTC 2020


Author: gonzo
Date: Sun Sep  6 19:03:19 2020
New Revision: 365388
URL: https://svnweb.freebsd.org/changeset/base/365388

Log:
  MFC r362736, r364088
  
  r362736:
  Configure rx_delay/tx_delay values for RK3399/RK3328 GMAC
  
  For 1000Mb mode to work reliably TX/RX delays need to be configured
  between the TX/RX clock and the respective signals on the PHY
  to compensate for differing trace lengths on the PCB.
  
  Reviewed by:	manu
  
  r364088:
  Improve Rockchip's integration of if_dwc
  
  - Do not rely on U-Boot for clocks configuration, enable and set frequencies
      in the driver's attach method.
  - Adjust MAC settings according to detected linespeed on RK3399 and RK3328.
  - Add support for RMII PHY mode on RK3328.
  
  Reviewed by:	manu
  Differential Revision:	https://reviews.freebsd.org/D26006

Modified:
  stable/12/sys/arm64/rockchip/if_dwc_rk.c
  stable/12/sys/dev/dwc/if_dwc.c
  stable/12/sys/dev/dwc/if_dwc.h
  stable/12/sys/dev/dwc/if_dwc_if.m
  stable/12/sys/dev/dwc/if_dwcvar.h
Directory Properties:
  stable/12/   (props changed)

Modified: stable/12/sys/arm64/rockchip/if_dwc_rk.c
==============================================================================
--- stable/12/sys/arm64/rockchip/if_dwc_rk.c	Sun Sep  6 18:48:50 2020	(r365387)
+++ stable/12/sys/arm64/rockchip/if_dwc_rk.c	Sun Sep  6 19:03:19 2020	(r365388)
@@ -24,7 +24,7 @@
  * 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.
- */
+*/
 
 #include <sys/cdefs.h>
 __FBSDID("$FreeBSD$");
@@ -34,91 +34,350 @@ __FBSDID("$FreeBSD$");
 #include <sys/bus.h>
 #include <sys/kernel.h>
 #include <sys/module.h>
+#include <sys/socket.h>
 
 #include <machine/bus.h>
 
+#include <net/if.h>
+#include <net/if_media.h>
+
 #include <dev/dwc/if_dwc.h>
 #include <dev/dwc/if_dwcvar.h>
 #include <dev/ofw/ofw_bus.h>
 #include <dev/ofw/ofw_bus_subr.h>
 
 #include <dev/extres/clk/clk.h>
+#include <dev/extres/hwreset/hwreset.h>
 #include <dev/extres/regulator/regulator.h>
-
 #include <dev/extres/syscon/syscon.h>
 
+#include "if_dwc_if.h"
 #include "syscon_if.h"
 
-#include "if_dwc_if.h"
-
 #define	RK3328_GRF_MAC_CON0		0x0900
-#define	 RK3328_GRF_MAC_CON0_TX_MASK	0x7F
-#define	 RK3328_GRF_MAC_CON0_TX_SHIFT	0
-#define	 RK3328_GRF_MAC_CON0_RX_MASK	0x7F
-#define	 RK3328_GRF_MAC_CON0_RX_SHIFT	7
+#define	 MAC_CON0_GMAC2IO_TX_DL_CFG_MASK	0x7F
+#define	 MAC_CON0_GMAC2IO_TX_DL_CFG_SHIFT	0
+#define	 MAC_CON0_GMAC2IO_RX_DL_CFG_MASK	0x7F
+#define	 MAC_CON0_GMAC2IO_RX_DL_CFG_SHIFT	7
 
 #define	RK3328_GRF_MAC_CON1		0x0904
+#define	 MAC_CON1_GMAC2IO_GMAC_TXCLK_DLY_ENA	(1 << 0)
+#define	 MAC_CON1_GMAC2IO_GMAC_RXCLK_DLY_ENA	(1 << 1)
+#define	 MAC_CON1_GMAC2IO_GMII_CLK_SEL_MASK	(3 << 11)
+#define	 MAC_CON1_GMAC2IO_GMII_CLK_SEL_125	(0 << 11)
+#define	 MAC_CON1_GMAC2IO_GMII_CLK_SEL_25	(3 << 11)
+#define	 MAC_CON1_GMAC2IO_GMII_CLK_SEL_2_5	(2 << 11)
+#define	 MAC_CON1_GMAC2IO_RMII_MODE_MASK	(1 << 9)
+#define	 MAC_CON1_GMAC2IO_RMII_MODE		(1 << 9)
+#define	 MAC_CON1_GMAC2IO_INTF_SEL_MASK		(7 << 4)
+#define	 MAC_CON1_GMAC2IO_INTF_RMII		(4 << 4)
+#define	 MAC_CON1_GMAC2IO_INTF_RGMII		(1 << 4)
+#define	 MAC_CON1_GMAC2IO_RMII_CLK_SEL_MASK	(1 << 7)
+#define	 MAC_CON1_GMAC2IO_RMII_CLK_SEL_25	(1 << 7)
+#define	 MAC_CON1_GMAC2IO_RMII_CLK_SEL_2_5	(0 << 7)
+#define	 MAC_CON1_GMAC2IO_MAC_SPEED_MASK	(1 << 2)
+#define	 MAC_CON1_GMAC2IO_MAC_SPEED_100		(1 << 2)
+#define	 MAC_CON1_GMAC2IO_MAC_SPEED_10		(0 << 2)
 #define	RK3328_GRF_MAC_CON2		0x0908
 #define	RK3328_GRF_MACPHY_CON0		0x0B00
+#define	 MACPHY_CON0_CLK_50M_MASK		(1 << 14)
+#define	 MACPHY_CON0_CLK_50M			(1 << 14)
+#define	 MACPHY_CON0_RMII_MODE_MASK		(3 << 6)
+#define	 MACPHY_CON0_RMII_MODE			(1 << 6)
 #define	RK3328_GRF_MACPHY_CON1		0x0B04
+#define	 MACPHY_CON1_RMII_MODE_MASK		(1 << 9)
+#define	 MACPHY_CON1_RMII_MODE			(1 << 9)
 #define	RK3328_GRF_MACPHY_CON2		0x0B08
 #define	RK3328_GRF_MACPHY_CON3		0x0B0C
 #define	RK3328_GRF_MACPHY_STATUS	0x0B10
 
+#define	RK3399_GRF_SOC_CON5		0xc214
+#define	 SOC_CON5_GMAC_CLK_SEL_MASK		(3 << 4)
+#define	 SOC_CON5_GMAC_CLK_SEL_125		(0 << 4)
+#define	 SOC_CON5_GMAC_CLK_SEL_25		(3 << 4)
+#define	 SOC_CON5_GMAC_CLK_SEL_2_5		(2 << 4)
+#define	RK3399_GRF_SOC_CON6		0xc218
+#define	 SOC_CON6_GMAC_TXCLK_DLY_ENA		(1 << 7)
+#define	 SOC_CON6_TX_DL_CFG_MASK		0x7F
+#define	 SOC_CON6_TX_DL_CFG_SHIFT		0
+#define	 SOC_CON6_RX_DL_CFG_MASK		0x7F
+#define	 SOC_CON6_GMAC_RXCLK_DLY_ENA		(1 << 15)
+#define	 SOC_CON6_RX_DL_CFG_SHIFT		8
+
+struct if_dwc_rk_softc;
+
+typedef void (*if_dwc_rk_set_delaysfn_t)(struct if_dwc_rk_softc *);
+typedef int (*if_dwc_rk_set_speedfn_t)(struct if_dwc_rk_softc *, int);
+typedef void (*if_dwc_rk_set_phy_modefn_t)(struct if_dwc_rk_softc *);
+typedef void (*if_dwc_rk_phy_powerupfn_t)(struct if_dwc_rk_softc *);
+
+struct if_dwc_rk_ops {
+	if_dwc_rk_set_delaysfn_t	set_delays;
+	if_dwc_rk_set_speedfn_t		set_speed;
+	if_dwc_rk_set_phy_modefn_t	set_phy_mode;
+	if_dwc_rk_phy_powerupfn_t	phy_powerup;
+};
+
+struct if_dwc_rk_softc {
+	struct dwc_softc	base;
+	uint32_t		tx_delay;
+	uint32_t		rx_delay;
+	bool			integrated_phy;
+	bool			clock_in;
+	phandle_t		phy_node;
+	struct syscon		*grf;
+	struct if_dwc_rk_ops	*ops;
+	/* Common clocks */
+	clk_t			mac_clk_rx;
+	clk_t			mac_clk_tx;
+	clk_t			aclk_mac;
+	clk_t			pclk_mac;
+	clk_t			clk_stmmaceth;
+	/* RMII clocks */
+	clk_t			clk_mac_ref;
+	clk_t			clk_mac_refout;
+	/* PHY clock */
+	clk_t			clk_phy;
+};
+
+static void rk3328_set_delays(struct if_dwc_rk_softc *sc);
+static int rk3328_set_speed(struct if_dwc_rk_softc *sc, int speed);
+static void rk3328_set_phy_mode(struct if_dwc_rk_softc *sc);
+static void rk3328_phy_powerup(struct if_dwc_rk_softc *sc);
+
+static void rk3399_set_delays(struct if_dwc_rk_softc *sc);
+static int rk3399_set_speed(struct if_dwc_rk_softc *sc, int speed);
+
+static struct if_dwc_rk_ops rk3288_ops = {
+};
+
+static struct if_dwc_rk_ops rk3328_ops = {
+	.set_delays = rk3328_set_delays,
+	.set_speed = rk3328_set_speed,
+	.set_phy_mode = rk3328_set_phy_mode,
+	.phy_powerup = rk3328_phy_powerup,
+};
+
+static struct if_dwc_rk_ops rk3399_ops = {
+	.set_delays = rk3399_set_delays,
+	.set_speed = rk3399_set_speed,
+};
+
 static struct ofw_compat_data compat_data[] = {
-	{"rockchip,rk3288-gmac", 1},
-	{"rockchip,rk3328-gmac", 1},
-	{"rockchip,rk3399-gmac", 1},
+	{"rockchip,rk3288-gmac", (uintptr_t)&rk3288_ops},
+	{"rockchip,rk3328-gmac", (uintptr_t)&rk3328_ops},
+	{"rockchip,rk3399-gmac", (uintptr_t)&rk3399_ops},
 	{NULL,			 0}
 };
 
-#ifdef notyet
 static void
-rk3328_set_delays(struct syscon *grf, phandle_t node)
+rk3328_set_delays(struct if_dwc_rk_softc *sc)
 {
+	uint32_t reg;
 	uint32_t tx, rx;
 
-	if (OF_getencprop(node, "tx_delay", &tx, sizeof(tx)) <= 0)
-		tx = 0x30;
-	if (OF_getencprop(node, "rx_delay", &rx, sizeof(rx)) <= 0)
-		rx = 0x10;
+	if (sc->base.phy_mode != PHY_MODE_RGMII)
+		return;
 
-	tx = ((tx & RK3328_GRF_MAC_CON0_TX_MASK) <<
-	    RK3328_GRF_MAC_CON0_TX_SHIFT);
-	rx = ((rx & RK3328_GRF_MAC_CON0_TX_MASK) <<
-	    RK3328_GRF_MAC_CON0_RX_SHIFT);
+	reg = SYSCON_READ_4(sc->grf, RK3328_GRF_MAC_CON0);
+	tx = ((reg >> MAC_CON0_GMAC2IO_TX_DL_CFG_SHIFT) & MAC_CON0_GMAC2IO_TX_DL_CFG_MASK);
+	rx = ((reg >> MAC_CON0_GMAC2IO_RX_DL_CFG_SHIFT) & MAC_CON0_GMAC2IO_RX_DL_CFG_MASK);
 
-	SYSCON_WRITE_4(grf, RK3328_GRF_MAC_CON0, tx | rx | 0xFFFF0000);
+	reg = SYSCON_READ_4(sc->grf, RK3328_GRF_MAC_CON1);
+	if (bootverbose) {
+		device_printf(sc->base.dev, "current delays settings: tx=%u(%s) rx=%u(%s)\n",
+		    tx, ((reg & MAC_CON1_GMAC2IO_GMAC_TXCLK_DLY_ENA) ? "enabled" : "disabled"),
+		    rx, ((reg & MAC_CON1_GMAC2IO_GMAC_RXCLK_DLY_ENA) ? "enabled" : "disabled"));
+
+		device_printf(sc->base.dev, "setting new RK3328 RX/TX delays:  %d/%d\n",
+			sc->tx_delay, sc->rx_delay);
+	}
+
+	reg = (MAC_CON1_GMAC2IO_GMAC_TXCLK_DLY_ENA | MAC_CON1_GMAC2IO_GMAC_RXCLK_DLY_ENA) << 16;
+	reg |= (MAC_CON1_GMAC2IO_GMAC_TXCLK_DLY_ENA | MAC_CON1_GMAC2IO_GMAC_RXCLK_DLY_ENA);
+	SYSCON_WRITE_4(sc->grf, RK3328_GRF_MAC_CON1, reg);
+
+	reg = 0xffff << 16;
+	reg |= ((sc->tx_delay & MAC_CON0_GMAC2IO_TX_DL_CFG_MASK) <<
+	    MAC_CON0_GMAC2IO_TX_DL_CFG_SHIFT);
+	reg |= ((sc->rx_delay & MAC_CON0_GMAC2IO_TX_DL_CFG_MASK) <<
+	    MAC_CON0_GMAC2IO_RX_DL_CFG_SHIFT);
+	SYSCON_WRITE_4(sc->grf, RK3328_GRF_MAC_CON0, reg);
 }
-#endif
 
-#define	RK3399_GRF_SOC_CON6		0xc218
-#define	 RK3399_GRF_SOC_CON6_TX_MASK	0x7F
-#define	 RK3399_GRF_SOC_CON6_TX_SHIFT	0
-#define	 RK3399_GRF_SOC_CON6_RX_MASK	0x7F
-#define	 RK3399_GRF_SOC_CON6_RX_SHIFT	8
+static int
+rk3328_set_speed(struct if_dwc_rk_softc *sc, int speed)
+{
+	uint32_t reg;
 
-#ifdef notyet
+	switch (sc->base.phy_mode) {
+	case PHY_MODE_RGMII:
+		switch (speed) {
+		case IFM_1000_T:
+		case IFM_1000_SX:
+			reg = MAC_CON1_GMAC2IO_GMII_CLK_SEL_125;
+			break;
+		case IFM_100_TX:
+			reg = MAC_CON1_GMAC2IO_GMII_CLK_SEL_25;
+			break;
+		case IFM_10_T:
+			reg = MAC_CON1_GMAC2IO_GMII_CLK_SEL_2_5;
+			break;
+		default:
+			device_printf(sc->base.dev, "unsupported RGMII media %u\n", speed);
+			return (-1);
+		}
+
+		SYSCON_WRITE_4(sc->grf, RK3328_GRF_MAC_CON1,
+		    ((MAC_CON1_GMAC2IO_GMII_CLK_SEL_MASK << 16) | reg));
+		break;
+	case PHY_MODE_RMII:
+		switch (speed) {
+		case IFM_100_TX:
+			reg = MAC_CON1_GMAC2IO_RMII_CLK_SEL_25 |
+			    MAC_CON1_GMAC2IO_MAC_SPEED_100;
+			break;
+		case IFM_10_T:
+			reg = MAC_CON1_GMAC2IO_RMII_CLK_SEL_2_5 |
+			    MAC_CON1_GMAC2IO_MAC_SPEED_10;
+			break;
+		default:
+			device_printf(sc->base.dev, "unsupported RMII media %u\n", speed);
+			return (-1);
+		}
+
+		SYSCON_WRITE_4(sc->grf,
+		    sc->integrated_phy ? RK3328_GRF_MAC_CON2 : RK3328_GRF_MAC_CON1,
+		    reg |
+		    ((MAC_CON1_GMAC2IO_RMII_CLK_SEL_MASK | MAC_CON1_GMAC2IO_MAC_SPEED_MASK) << 16));
+		break;
+	}
+
+	return (0);
+}
+
 static void
-rk3399_set_delays(struct syscon *grf, phandle_t node)
+rk3328_set_phy_mode(struct if_dwc_rk_softc *sc)
 {
-	uint32_t tx, rx;
 
-	if (OF_getencprop(node, "tx_delay", &tx, sizeof(tx)) <= 0)
-		tx = 0x30;
-	if (OF_getencprop(node, "rx_delay", &rx, sizeof(rx)) <= 0)
-		rx = 0x10;
+	switch (sc->base.phy_mode) {
+	case PHY_MODE_RGMII:
+		SYSCON_WRITE_4(sc->grf, RK3328_GRF_MAC_CON1,
+		    ((MAC_CON1_GMAC2IO_INTF_SEL_MASK | MAC_CON1_GMAC2IO_RMII_MODE_MASK) << 16) |
+		    MAC_CON1_GMAC2IO_INTF_RGMII);
+		break;
+	case PHY_MODE_RMII:
+		SYSCON_WRITE_4(sc->grf, sc->integrated_phy ? RK3328_GRF_MAC_CON2 : RK3328_GRF_MAC_CON1,
+		    ((MAC_CON1_GMAC2IO_INTF_SEL_MASK | MAC_CON1_GMAC2IO_RMII_MODE_MASK) << 16) |
+		    MAC_CON1_GMAC2IO_INTF_RMII | MAC_CON1_GMAC2IO_RMII_MODE);
+		break;
+	}
+}
 
-	tx = ((tx & RK3399_GRF_SOC_CON6_TX_MASK) <<
-	    RK3399_GRF_SOC_CON6_TX_SHIFT);
-	rx = ((rx & RK3399_GRF_SOC_CON6_TX_MASK) <<
-	    RK3399_GRF_SOC_CON6_RX_SHIFT);
+static void
+rk3328_phy_powerup(struct if_dwc_rk_softc *sc)
+{
+	SYSCON_WRITE_4(sc->grf, RK3328_GRF_MACPHY_CON1,
+	    (MACPHY_CON1_RMII_MODE_MASK << 16) |
+	    MACPHY_CON1_RMII_MODE);
+}
 
-	SYSCON_WRITE_4(grf, RK3399_GRF_SOC_CON6, tx | rx | 0xFFFF0000);
+static void
+rk3399_set_delays(struct if_dwc_rk_softc *sc)
+{
+	uint32_t reg, tx, rx;
+
+	if (sc->base.phy_mode != PHY_MODE_RGMII)
+		return;
+
+	reg = SYSCON_READ_4(sc->grf, RK3399_GRF_SOC_CON6);
+	tx = ((reg >> SOC_CON6_TX_DL_CFG_SHIFT) & SOC_CON6_TX_DL_CFG_MASK);
+	rx = ((reg >> SOC_CON6_RX_DL_CFG_SHIFT) & SOC_CON6_RX_DL_CFG_MASK);
+
+	if (bootverbose) {
+		device_printf(sc->base.dev, "current delays settings: tx=%u(%s) rx=%u(%s)\n",
+		    tx, ((reg & SOC_CON6_GMAC_TXCLK_DLY_ENA) ? "enabled" : "disabled"),
+		    rx, ((reg & SOC_CON6_GMAC_RXCLK_DLY_ENA) ? "enabled" : "disabled"));
+
+		device_printf(sc->base.dev, "setting new RK3399 RX/TX delays:  %d/%d\n",
+		    sc->rx_delay, sc->tx_delay);
+	}
+
+	reg = 0xFFFF << 16;
+	reg |= ((sc->tx_delay & SOC_CON6_TX_DL_CFG_MASK) <<
+	    SOC_CON6_TX_DL_CFG_SHIFT);
+	reg |= ((sc->rx_delay & SOC_CON6_RX_DL_CFG_MASK) <<
+	    SOC_CON6_RX_DL_CFG_SHIFT);
+	reg |= SOC_CON6_GMAC_TXCLK_DLY_ENA | SOC_CON6_GMAC_RXCLK_DLY_ENA;
+
+	SYSCON_WRITE_4(sc->grf, RK3399_GRF_SOC_CON6, reg);
 }
-#endif
 
 static int
+rk3399_set_speed(struct if_dwc_rk_softc *sc, int speed)
+{
+	uint32_t reg;
+
+	switch (speed) {
+	case IFM_1000_T:
+	case IFM_1000_SX:
+		reg = SOC_CON5_GMAC_CLK_SEL_125;
+		break;
+	case IFM_100_TX:
+		reg = SOC_CON5_GMAC_CLK_SEL_25;
+		break;
+	case IFM_10_T:
+		reg = SOC_CON5_GMAC_CLK_SEL_2_5;
+		break;
+	default:
+		device_printf(sc->base.dev, "unsupported media %u\n", speed);
+		return (-1);
+	}
+
+	SYSCON_WRITE_4(sc->grf, RK3399_GRF_SOC_CON5,
+	    ((SOC_CON5_GMAC_CLK_SEL_MASK << 16) | reg));
+	return (0);
+}
+
+static int
+if_dwc_rk_sysctl_delays(SYSCTL_HANDLER_ARGS)
+{
+	struct if_dwc_rk_softc *sc;
+	int rv;
+	uint32_t rxtx;
+
+	sc = arg1;
+	rxtx = ((sc->rx_delay << 8) | sc->tx_delay);
+
+	rv = sysctl_handle_int(oidp, &rxtx, 0, req);
+	if (rv != 0 || req->newptr == NULL)
+		return (rv);
+	sc->tx_delay = rxtx & 0xff;
+	sc->rx_delay = (rxtx >> 8) & 0xff;
+
+	if (sc->ops->set_delays)
+	    sc->ops->set_delays(sc);
+
+	return (0);
+}
+
+static int
+if_dwc_rk_init_sysctl(struct if_dwc_rk_softc *sc)
+{
+	struct sysctl_oid *child;
+	struct sysctl_ctx_list *ctx_list;
+
+	ctx_list = device_get_sysctl_ctx(sc->base.dev);
+	child = device_get_sysctl_tree(sc->base.dev);
+	SYSCTL_ADD_PROC(ctx_list,
+	    SYSCTL_CHILDREN(child), OID_AUTO, "delays",
+	    CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_RWTUN | CTLFLAG_MPSAFE, sc, 0,
+	    if_dwc_rk_sysctl_delays, "", "RGMII RX/TX delays: ((rx << 8) | tx)");
+
+	return (0);
+}
+
+static int
 if_dwc_rk_probe(device_t dev)
 {
 
@@ -132,28 +391,189 @@ if_dwc_rk_probe(device_t dev)
 }
 
 static int
+if_dwc_rk_init_clocks(device_t dev)
+{
+	struct if_dwc_rk_softc *sc;
+	int error;
+
+	sc = device_get_softc(dev);
+	error = clk_set_assigned(dev, ofw_bus_get_node(dev));
+	if (error != 0) {
+		device_printf(dev, "clk_set_assigned failed\n");
+		return (error);
+	}
+
+	/* Enable clocks */
+	error = clk_get_by_ofw_name(dev, 0, "stmmaceth", &sc->clk_stmmaceth);
+	if (error != 0) {
+		device_printf(dev, "could not find clock stmmaceth\n");
+		return (error);
+	}
+
+	if (clk_get_by_ofw_name(dev, 0, "mac_clk_rx", &sc->mac_clk_rx) != 0) {
+		device_printf(sc->base.dev, "could not get mac_clk_rx clock\n");
+		sc->mac_clk_rx = NULL;
+	}
+
+	if (clk_get_by_ofw_name(dev, 0, "mac_clk_tx", &sc->mac_clk_tx) != 0) {
+		device_printf(sc->base.dev, "could not get mac_clk_tx clock\n");
+		sc->mac_clk_tx = NULL;
+	}
+
+	if (clk_get_by_ofw_name(dev, 0, "aclk_mac", &sc->aclk_mac) != 0) {
+		device_printf(sc->base.dev, "could not get aclk_mac clock\n");
+		sc->aclk_mac = NULL;
+	}
+
+	if (clk_get_by_ofw_name(dev, 0, "pclk_mac", &sc->pclk_mac) != 0) {
+		device_printf(sc->base.dev, "could not get pclk_mac clock\n");
+		sc->pclk_mac = NULL;
+	}
+
+	if (sc->base.phy_mode == PHY_MODE_RGMII) {
+		if (clk_get_by_ofw_name(dev, 0, "clk_mac_ref", &sc->clk_mac_ref) != 0) {
+			device_printf(sc->base.dev, "could not get clk_mac_ref clock\n");
+			sc->clk_mac_ref = NULL;
+		}
+
+		if (!sc->clock_in) {
+			if (clk_get_by_ofw_name(dev, 0, "clk_mac_refout", &sc->clk_mac_refout) != 0) {
+				device_printf(sc->base.dev, "could not get clk_mac_refout clock\n");
+				sc->clk_mac_refout = NULL;
+			}
+
+			clk_set_freq(sc->clk_stmmaceth, 50000000, 0);
+		}
+	}
+
+	if ((sc->phy_node != 0) && sc->integrated_phy) {
+		if (clk_get_by_ofw_index(dev, sc->phy_node, 0, &sc->clk_phy) != 0) {
+			device_printf(sc->base.dev, "could not get PHY clock\n");
+			sc->clk_phy = NULL;
+		}
+
+		if (sc->clk_phy) {
+			clk_set_freq(sc->clk_phy, 50000000, 0);
+		}
+	}
+
+	if (sc->base.phy_mode == PHY_MODE_RMII) {
+		if (sc->mac_clk_rx)
+			clk_enable(sc->mac_clk_rx);
+		if (sc->clk_mac_ref)
+			clk_enable(sc->clk_mac_ref);
+		if (sc->clk_mac_refout)
+			clk_enable(sc->clk_mac_refout);
+	}
+	if (sc->clk_phy)
+		clk_enable(sc->clk_phy);
+	if (sc->aclk_mac)
+		clk_enable(sc->aclk_mac);
+	if (sc->pclk_mac)
+		clk_enable(sc->pclk_mac);
+	if (sc->mac_clk_tx)
+		clk_enable(sc->mac_clk_tx);
+
+	DELAY(50);
+
+	return (0);
+}
+
+static int
 if_dwc_rk_init(device_t dev)
 {
+	struct if_dwc_rk_softc *sc;
 	phandle_t node;
-	struct syscon *grf = NULL;
+	uint32_t rx, tx;
+	int err;
+	pcell_t phy_handle;
+	char *clock_in_out;
+	hwreset_t phy_reset;
+	regulator_t phy_supply;
 
+	sc = device_get_softc(dev);
 	node = ofw_bus_get_node(dev);
+	sc->ops = (struct if_dwc_rk_ops *)ofw_bus_search_compatible(dev, compat_data)->ocd_data;
 	if (OF_hasprop(node, "rockchip,grf") &&
 	    syscon_get_by_ofw_property(dev, node,
-	    "rockchip,grf", &grf) != 0) {
+	    "rockchip,grf", &sc->grf) != 0) {
 		device_printf(dev, "cannot get grf driver handle\n");
 		return (ENXIO);
 	}
 
-#ifdef notyet
-	if (ofw_bus_is_compatible(dev, "rockchip,rk3399-gmac"))
-	    rk3399_set_delays(grf, node);
-	else if (ofw_bus_is_compatible(dev, "rockchip,rk3328-gmac"))
-	    rk3328_set_delays(grf, node);
-#endif
+	if (OF_getencprop(node, "tx_delay", &tx, sizeof(tx)) <= 0)
+		tx = 0x30;
+	if (OF_getencprop(node, "rx_delay", &rx, sizeof(rx)) <= 0)
+		rx = 0x10;
+	sc->tx_delay = tx;
+	sc->rx_delay = rx;
 
-	/* Mode should be set according to dtb property */
+	sc->clock_in = true;
+	if (OF_getprop_alloc(node, "clock_in_out", (void **)&clock_in_out)) {
+		if (strcmp(clock_in_out, "input") == 0)
+			sc->clock_in = true;
+		else
+			sc->clock_in = false;
+		OF_prop_free(clock_in_out);
+	}
 
+	if (OF_getencprop(node, "phy-handle", (void *)&phy_handle,
+	    sizeof(phy_handle)) > 0)
+		sc->phy_node = OF_node_from_xref(phy_handle);
+
+	if (sc->phy_node)
+		sc->integrated_phy = OF_hasprop(sc->phy_node, "phy-is-integrated");
+
+	if (sc->integrated_phy)
+		device_printf(sc->base.dev, "PHY is integrated\n");
+
+	if_dwc_rk_init_clocks(dev);
+
+	if (sc->ops->set_phy_mode)
+	    sc->ops->set_phy_mode(sc);
+
+	if (sc->ops->set_delays)
+	    sc->ops->set_delays(sc);
+
+	/*
+	 * this also sets delays if tunable is defined
+	 */
+	err = if_dwc_rk_init_sysctl(sc);
+	if (err != 0)
+		return (err);
+
+	if (regulator_get_by_ofw_property(sc->base.dev, 0,
+		            "phy-supply", &phy_supply) == 0) {
+		if (regulator_enable(phy_supply)) {
+			device_printf(sc->base.dev,
+			    "cannot enable 'phy' regulator\n");
+		}
+	}
+	else
+		device_printf(sc->base.dev, "no phy-supply property\n");
+
+	/* Power up */
+	if (sc->integrated_phy) {
+		if (sc->ops->phy_powerup)
+			sc->ops->phy_powerup(sc);
+
+		SYSCON_WRITE_4(sc->grf, RK3328_GRF_MACPHY_CON0,
+		    (MACPHY_CON0_CLK_50M_MASK << 16) |
+		    MACPHY_CON0_CLK_50M);
+		SYSCON_WRITE_4(sc->grf, RK3328_GRF_MACPHY_CON0,
+		    (MACPHY_CON0_RMII_MODE_MASK << 16) |
+		    MACPHY_CON0_RMII_MODE);
+		SYSCON_WRITE_4(sc->grf, RK3328_GRF_MACPHY_CON2, 0xffff1234);
+		SYSCON_WRITE_4(sc->grf, RK3328_GRF_MACPHY_CON3, 0x003f0035);
+
+		if (hwreset_get_by_ofw_idx(dev, sc->phy_node, 0, &phy_reset)  == 0) {
+			hwreset_assert(phy_reset);
+			DELAY(20);
+			hwreset_deassert(phy_reset);
+			DELAY(20);
+		}
+	}
+
 	return (0);
 }
 
@@ -172,12 +592,26 @@ if_dwc_rk_mii_clk(device_t dev)
 	return (GMAC_MII_CLK_150_250M_DIV102);
 }
 
+static int
+if_dwc_rk_set_speed(device_t dev, int speed)
+{
+	struct if_dwc_rk_softc *sc;
+
+	sc = device_get_softc(dev);
+
+	if (sc->ops->set_speed)
+	    return sc->ops->set_speed(sc, speed);
+
+	return (0);
+}
+
 static device_method_t if_dwc_rk_methods[] = {
 	DEVMETHOD(device_probe,		if_dwc_rk_probe),
 
 	DEVMETHOD(if_dwc_init,		if_dwc_rk_init),
 	DEVMETHOD(if_dwc_mac_type,	if_dwc_rk_mac_type),
 	DEVMETHOD(if_dwc_mii_clk,	if_dwc_rk_mii_clk),
+	DEVMETHOD(if_dwc_set_speed,	if_dwc_rk_set_speed),
 
 	DEVMETHOD_END
 };
@@ -187,6 +621,6 @@ static devclass_t dwc_rk_devclass;
 extern driver_t dwc_driver;
 
 DEFINE_CLASS_1(dwc, dwc_rk_driver, if_dwc_rk_methods,
-    sizeof(struct dwc_softc), dwc_driver);
+    sizeof(struct if_dwc_rk_softc), dwc_driver);
 DRIVER_MODULE(dwc_rk, simplebus, dwc_rk_driver, dwc_rk_devclass, 0, 0);
 MODULE_DEPEND(dwc_rk, dwc, 1, 1, 1);

Modified: stable/12/sys/dev/dwc/if_dwc.c
==============================================================================
--- stable/12/sys/dev/dwc/if_dwc.c	Sun Sep  6 18:48:50 2020	(r365387)
+++ stable/12/sys/dev/dwc/if_dwc.c	Sun Sep  6 19:03:19 2020	(r365388)
@@ -1209,15 +1209,23 @@ dwc_clock_init(device_t dev)
 	hwreset_t rst;
 	clk_t clk;
 	int error;
+	int64_t freq;
 
-	/* Enable clock */
+	/* Enable clocks */
 	if (clk_get_by_ofw_name(dev, 0, "stmmaceth", &clk) == 0) {
 		error = clk_enable(clk);
 		if (error != 0) {
 			device_printf(dev, "could not enable main clock\n");
 			return (error);
 		}
+		if (bootverbose) {
+			clk_get_freq(clk, &freq);
+			device_printf(dev, "MAC clock(%s) freq: %ld\n",  clk_get_name(clk), freq);
+		}
 	}
+	else {
+		device_printf(dev, "could not find clock stmmaceth\n");
+	}
 
 	/* De-assert reset */
 	if (hwreset_get_by_ofw_name(dev, 0, "stmmaceth", &rst) == 0) {
@@ -1254,6 +1262,8 @@ dwc_attach(device_t dev)
 	struct ifnet *ifp;
 	int error, i;
 	uint32_t reg;
+	char *phy_mode;
+	phandle_t node;
 
 	sc = device_get_softc(dev);
 	sc->dev = dev;
@@ -1262,6 +1272,15 @@ dwc_attach(device_t dev)
 	sc->mii_clk = IF_DWC_MII_CLK(dev);
 	sc->mactype = IF_DWC_MAC_TYPE(dev);
 
+	node = ofw_bus_get_node(dev);
+	if (OF_getprop_alloc(node, "phy-mode", (void **)&phy_mode)) {
+		if (strcmp(phy_mode, "rgmii") == 0)
+			sc->phy_mode = PHY_MODE_RGMII;
+		if (strcmp(phy_mode, "rmii") == 0)
+			sc->phy_mode = PHY_MODE_RMII;
+		OF_prop_free(phy_mode);
+	}
+
 	if (IF_DWC_INIT(dev) != 0)
 		return (ENXIO);
 
@@ -1475,6 +1494,9 @@ dwc_miibus_statchg(device_t dev)
 	else
 		reg &= ~(CONF_DM);
 	WRITE4(sc, MAC_CONFIGURATION, reg);
+
+	IF_DWC_SET_SPEED(dev, IFM_SUBTYPE(mii->mii_media_active));
+
 }
 
 static device_method_t dwc_methods[] = {

Modified: stable/12/sys/dev/dwc/if_dwc.h
==============================================================================
--- stable/12/sys/dev/dwc/if_dwc.h	Sun Sep  6 18:48:50 2020	(r365387)
+++ stable/12/sys/dev/dwc/if_dwc.h	Sun Sep  6 19:03:19 2020	(r365388)
@@ -37,6 +37,10 @@
 #ifndef __IF_DWC_H__
 #define __IF_DWC_H__
 
+#define	PHY_MODE_UNKNOWN	0x0
+#define	PHY_MODE_RMII		0x1
+#define	PHY_MODE_RGMII		0x2
+
 #define	MAC_CONFIGURATION	0x0
 #define	 CONF_JD		(1 << 22)	/* jabber timer disable */
 #define	 CONF_BE		(1 << 21)	/* Frame Burst Enable */

Modified: stable/12/sys/dev/dwc/if_dwc_if.m
==============================================================================
--- stable/12/sys/dev/dwc/if_dwc_if.m	Sun Sep  6 18:48:50 2020	(r365387)
+++ stable/12/sys/dev/dwc/if_dwc_if.m	Sun Sep  6 19:03:19 2020	(r365388)
@@ -49,6 +49,12 @@ CODE {
 	{
 		return (GMAC_MII_CLK_25_35M_DIV16);
 	}
+
+	static int
+	if_dwc_default_set_speed(device_t dev, int speed)
+	{
+		return (0);
+	}
 };
 
 HEADER {
@@ -74,3 +80,11 @@ METHOD int mac_type {
 METHOD int mii_clk {
 	device_t dev;
 } DEFAULT if_dwc_default_mii_clk;
+
+#
+# Signal media change to a specific hardware
+#
+METHOD int set_speed {
+	device_t dev;
+	int speed;
+} DEFAULT if_dwc_default_set_speed;

Modified: stable/12/sys/dev/dwc/if_dwcvar.h
==============================================================================
--- stable/12/sys/dev/dwc/if_dwcvar.h	Sun Sep  6 18:48:50 2020	(r365387)
+++ stable/12/sys/dev/dwc/if_dwcvar.h	Sun Sep  6 19:03:19 2020	(r365388)
@@ -71,6 +71,7 @@ struct dwc_softc {
 	boolean_t		is_detaching;
 	int			tx_watchdog_count;
 	int			stats_harvest_count;
+	int			phy_mode;
 
 	/* RX */
 	bus_dma_tag_t		rxdesc_tag;


More information about the svn-src-all mailing list