summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorkettenis <kettenis@openbsd.org>2018-05-27 16:19:25 +0000
committerkettenis <kettenis@openbsd.org>2018-05-27 16:19:25 +0000
commit112c3f0225bf1b6b37664bb82d3c6fe8c9729224 (patch)
tree887f950ec029c09edd6a6b5777caa77658e21d8f
parentOn Allwinner R40, export a regmap covering the GMAC_CLK_REG. (diff)
downloadwireguard-openbsd-112c3f0225bf1b6b37664bb82d3c6fe8c9729224.tar.xz
wireguard-openbsd-112c3f0225bf1b6b37664bb82d3c6fe8c9729224.zip
Add support for the GMAC on Allwinner R40/V40 SoCs.
ok patrick@
-rw-r--r--sys/dev/fdt/if_dwxe.c62
1 files changed, 55 insertions, 7 deletions
diff --git a/sys/dev/fdt/if_dwxe.c b/sys/dev/fdt/if_dwxe.c
index 020de824664..e8a70487de0 100644
--- a/sys/dev/fdt/if_dwxe.c
+++ b/sys/dev/fdt/if_dwxe.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: if_dwxe.c,v 1.7 2018/03/28 09:03:48 kettenis Exp $ */
+/* $OpenBSD: if_dwxe.c,v 1.8 2018/05/27 16:19:25 kettenis Exp $ */
/*
* Copyright (c) 2008 Mark Kettenis
* Copyright (c) 2017 Patrick Wildt <patrick@blueri.se>
@@ -220,7 +220,7 @@ struct dwxe_desc {
#define DWXE_RX_INT_CTL (1 << 31)
/* EMAC syscon bits */
-#define SYSCON 0x30
+#define SYSCON_EMAC 0x30
#define SYSCON_ETCS_MASK (0x3 << 0)
#define SYSCON_ETCS_MII (0 << 0)
#define SYSCON_ETCS_EXT_GMII (1 << 0)
@@ -238,6 +238,16 @@ struct dwxe_desc {
#define SYSCON_H3_EPHY_ADDR_MASK (0x1f << 20)
#define SYSCON_H3_EPHY_ADDR_SHIFT 20
+/* GMAC syscon bits (Allwinner R40) */
+#define SYSCON_GMAC 0x00
+#define SYSCON_GTCS_MASK SYSCON_ETCS_MASK
+#define SYSCON_GTCS_MII SYSCON_ETCS_MII
+#define SYSCON_GTCS_EXT_GMII SYSCON_ETCS_EXT_GMII
+#define SYSCON_GTCS_INT_GMII SYSCON_ETCS_INT_GMII
+#define SYSCON_GPIT SYSCON_EPIT
+#define SYSCON_GRXDC_MASK (0x7 << 5)
+#define SYSCON_GRXDC_SHIFT 5
+
struct dwxe_buf {
bus_dmamap_t tb_map;
struct mbuf *tb_m;
@@ -296,7 +306,8 @@ struct dwxe_softc {
int dwxe_match(struct device *, void *, void *);
void dwxe_attach(struct device *, struct device *, void *);
-void dwxe_phy_setup(struct dwxe_softc *);
+void dwxe_phy_setup_emac(struct dwxe_softc *);
+void dwxe_phy_setup_gmac(struct dwxe_softc *);
struct cfattach dwxe_ca = {
sizeof(struct dwxe_softc), dwxe_match, dwxe_attach
@@ -349,6 +360,7 @@ dwxe_match(struct device *parent, void *cfdata, void *aux)
struct fdt_attach_args *faa = aux;
return OF_is_compatible(faa->fa_node, "allwinner,sun8i-h3-emac") ||
+ OF_is_compatible(faa->fa_node, "allwinner,sun8i-r40-gmac") ||
OF_is_compatible(faa->fa_node, "allwinner,sun50i-a64-emac");
}
@@ -403,7 +415,10 @@ dwxe_attach(struct device *parent, struct device *self, void *aux)
printf(": address %s\n", ether_sprintf(sc->sc_lladdr));
/* Do hardware specific initializations. */
- dwxe_phy_setup(sc);
+ if (OF_is_compatible(faa->fa_node, "allwinner,sun8i-r40-gmac"))
+ dwxe_phy_setup_gmac(sc);
+ else
+ dwxe_phy_setup_emac(sc);
timeout_set(&sc->sc_tick, dwxe_tick, sc);
@@ -444,7 +459,7 @@ dwxe_attach(struct device *parent, struct device *self, void *aux)
}
void
-dwxe_phy_setup(struct dwxe_softc *sc)
+dwxe_phy_setup_emac(struct dwxe_softc *sc)
{
struct regmap *rm;
uint32_t syscon;
@@ -456,7 +471,7 @@ dwxe_phy_setup(struct dwxe_softc *sc)
if (rm == NULL)
return;
- syscon = regmap_read_4(rm, SYSCON);
+ syscon = regmap_read_4(rm, SYSCON_EMAC);
syscon &= ~(SYSCON_ETCS_MASK|SYSCON_EPIT|SYSCON_RMII_EN);
syscon &= ~(SYSCON_ETXDC_MASK | SYSCON_ERXDC_MASK);
syscon &= ~SYSCON_H3_EPHY_SELECT;
@@ -487,7 +502,40 @@ dwxe_phy_setup(struct dwxe_softc *sc)
syscon |= ((tx_delay / 100) << SYSCON_ETXDC_SHIFT) & SYSCON_ETXDC_MASK;
syscon |= ((rx_delay / 100) << SYSCON_ERXDC_SHIFT) & SYSCON_ERXDC_MASK;
- regmap_write_4(rm, SYSCON, syscon);
+ regmap_write_4(rm, SYSCON_EMAC, syscon);
+ dwxe_reset(sc);
+}
+
+void
+dwxe_phy_setup_gmac(struct dwxe_softc *sc)
+{
+ struct regmap *rm;
+ uint32_t syscon;
+ uint32_t rx_delay;
+ char *phy_mode;
+ int len;
+
+ rm = regmap_byphandle(OF_getpropint(sc->sc_node, "syscon", 0));
+ if (rm == NULL)
+ return;
+
+ syscon = regmap_read_4(rm, SYSCON_GMAC);
+ syscon &= ~(SYSCON_GTCS_MASK|SYSCON_GPIT|SYSCON_ERXDC_MASK);
+
+ if ((len = OF_getproplen(sc->sc_node, "phy-mode")) <= 0)
+ return;
+ phy_mode = malloc(len, M_TEMP, M_WAITOK);
+ OF_getprop(sc->sc_node, "phy-mode", phy_mode, len);
+ if (!strncmp(phy_mode, "rgmii", strlen("rgmii")))
+ syscon |= SYSCON_GPIT | SYSCON_GTCS_INT_GMII;
+ else if (!strncmp(phy_mode, "rmii", strlen("rmii")))
+ syscon |= SYSCON_GPIT | SYSCON_GTCS_EXT_GMII;
+ free(phy_mode, M_TEMP, len);
+
+ rx_delay = OF_getpropint(sc->sc_node, "allwinner,rx-delay-ps", 0);
+ syscon |= ((rx_delay / 100) << SYSCON_ERXDC_SHIFT) & SYSCON_ERXDC_MASK;
+
+ regmap_write_4(rm, SYSCON_GMAC, syscon);
dwxe_reset(sc);
}