Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F150438408
D26006.id75616.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
21 KB
Referenced Files
None
Subscribers
None
D26006.id75616.diff
View Options
Index: sys/arm64/rockchip/if_dwc_rk.c
===================================================================
--- sys/arm64/rockchip/if_dwc_rk.c
+++ sys/arm64/rockchip/if_dwc_rk.c
@@ -23,7 +23,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$");
@@ -33,97 +33,350 @@
#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 RK3328_GRF_MAC_CON1_RX_ENA (1 << 1)
-#define RK3328_GRF_MAC_CON1_TX_ENA (1 << 0)
+#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}
};
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;
- if (bootverbose)
- printf("setting RK3328 RX/TX delays: %d/%d\n", rx, tx);
- 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);
- SYSCON_WRITE_4(grf, RK3328_GRF_MAC_CON1, RK3328_GRF_MAC_CON1_TX_ENA | RK3328_GRF_MAC_CON1_RX_ENA |
- ((RK3328_GRF_MAC_CON1_TX_ENA | RK3328_GRF_MAC_CON1_RX_ENA) << 16));
+ 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);
}
-#define RK3399_GRF_SOC_CON6 0xc218
-#define RK3399_GRF_SOC_CON6_TX_ENA (1 << 7)
-#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_ENA (1 << 15)
-#define RK3399_GRF_SOC_CON6_RX_SHIFT 8
+static int
+rk3328_set_speed(struct if_dwc_rk_softc *sc, int speed)
+{
+ uint32_t reg;
+ 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;
+ }
+}
- if (bootverbose)
- printf("setting RK3399 RX/TX delays: %d/%d\n", rx, tx);
- tx = ((tx & RK3399_GRF_SOC_CON6_TX_MASK) <<
- RK3399_GRF_SOC_CON6_TX_SHIFT) | RK3399_GRF_SOC_CON6_TX_ENA;
- rx = ((rx & RK3399_GRF_SOC_CON6_TX_MASK) <<
- RK3399_GRF_SOC_CON6_RX_SHIFT) | RK3399_GRF_SOC_CON6_RX_ENA;
+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);
}
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)
{
@@ -137,26 +390,189 @@
}
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);
}
- 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);
+ 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);
}
@@ -175,12 +591,26 @@
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
};
@@ -190,6 +620,6 @@
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);
Index: sys/dev/dwc/if_dwc.h
===================================================================
--- sys/dev/dwc/if_dwc.h
+++ sys/dev/dwc/if_dwc.h
@@ -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 */
Index: sys/dev/dwc/if_dwc.c
===================================================================
--- sys/dev/dwc/if_dwc.c
+++ sys/dev/dwc/if_dwc.c
@@ -1209,15 +1209,23 @@
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 @@
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 @@
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 @@
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[] = {
Index: sys/dev/dwc/if_dwc_if.m
===================================================================
--- sys/dev/dwc/if_dwc_if.m
+++ sys/dev/dwc/if_dwc_if.m
@@ -49,6 +49,12 @@
{
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 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;
Index: sys/dev/dwc/if_dwcvar.h
===================================================================
--- sys/dev/dwc/if_dwcvar.h
+++ sys/dev/dwc/if_dwcvar.h
@@ -71,6 +71,7 @@
boolean_t is_detaching;
int tx_watchdog_count;
int stats_harvest_count;
+ int phy_mode;
/* RX */
bus_dma_tag_t rxdesc_tag;
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Thu, Apr 2, 5:39 AM (13 m, 56 s)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
30708522
Default Alt Text
D26006.id75616.diff (21 KB)
Attached To
Mode
D26006: Improvements for Rockchip's integration of if_dwc
Attached
Detach File
Event Timeline
Log In to Comment