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;
_______________________________________________
svn-src-all@freebsd.org mailing list
https://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "svn-src-all-unsubscr...@freebsd.org"

Reply via email to