diff options
author | Mark Kettenis <kettenis@cvs.openbsd.org> | 2017-05-07 12:09:47 +0000 |
---|---|---|
committer | Mark Kettenis <kettenis@cvs.openbsd.org> | 2017-05-07 12:09:47 +0000 |
commit | fcff1b912e56d39c541a16080ce22a8a3a070b9f (patch) | |
tree | 34205dfe3cb7ea209690430de0dec9484329ec99 /sys/dev | |
parent | c6b7802a6936d6594657ba8aa2c5784a60a9b1aa (diff) |
Refactor this code to support the GMAC found on the Rockchip RK3399 alongside
the GMAC found on the Allwinner A20/A31.
With this diff I can receive packets on the Firefly-RK3399. Unfortunately
sending packets doesn't seem to work yet.
Diffstat (limited to 'sys/dev')
-rw-r--r-- | sys/dev/fdt/if_dwge_fdt.c | 155 |
1 files changed, 133 insertions, 22 deletions
diff --git a/sys/dev/fdt/if_dwge_fdt.c b/sys/dev/fdt/if_dwge_fdt.c index fc6eda1c14e..7bea944e050 100644 --- a/sys/dev/fdt/if_dwge_fdt.c +++ b/sys/dev/fdt/if_dwge_fdt.c @@ -1,4 +1,4 @@ -/* $OpenBSD: if_dwge_fdt.c,v 1.1 2017/05/05 20:13:54 kettenis Exp $ */ +/* $OpenBSD: if_dwge_fdt.c,v 1.2 2017/05/07 12:09:46 kettenis Exp $ */ /* * Copyright (c) 2016 Patrick Wildt <patrick@blueri.se> * Copyright (c) 2016 Mark Kettenis <kettenis@openbsd.org> @@ -46,29 +46,36 @@ #include <dev/ofw/openfirm.h> #include <dev/ofw/ofw_clock.h> #include <dev/ofw/ofw_gpio.h> +#include <dev/ofw/ofw_misc.h> #include <dev/ofw/ofw_pinctrl.h> #include <dev/ofw/ofw_regulator.h> #include <dev/ofw/fdt.h> int dwge_fdt_match(struct device *, void *, void *); void dwge_fdt_attach(struct device *, struct device *, void *); -int dwge_fdt_intr(void *); struct dwge_fdt_softc { struct dwc_gmac_softc sc_core; void *sc_ih; + int sc_node; }; struct cfattach dwge_fdt_ca = { sizeof(struct dwge_fdt_softc), dwge_fdt_match, dwge_fdt_attach, }; +void dwge_fdt_reset_phy(struct dwge_fdt_softc *); +int dwge_fdt_intr(void *); +void dwge_fdt_attach_allwinner(struct dwge_fdt_softc *); +void dwge_fdt_attach_rockchip(struct dwge_fdt_softc *); + int dwge_fdt_match(struct device *parent, void *match, void *aux) { struct fdt_attach_args *faa = aux; - return OF_is_compatible(faa->fa_node, "allwinner,sun7i-a20-gmac"); + return (OF_is_compatible(faa->fa_node, "allwinner,sun7i-a20-gmac") || + OF_is_compatible(faa->fa_node, "rockchip,rk3399-gmac")); } void @@ -77,50 +84,55 @@ dwge_fdt_attach(struct device *parent, struct device *self, void *aux) struct dwge_fdt_softc *fsc = (struct dwge_fdt_softc *)self; struct dwc_gmac_softc *sc = &fsc->sc_core; struct fdt_attach_args *faa = aux; - char phy_mode[8]; int phyloc = MII_PHY_ANY; uint32_t phy_supply; uint32_t phy; - uint32_t freq; int node; - if (faa->fa_nreg < 1) + if (faa->fa_nreg < 1) { + printf(": no registers\n"); return; + } - pinctrl_byname(faa->fa_node, "default"); - + fsc->sc_node = faa->fa_node; sc->sc_bst = faa->fa_iot; sc->sc_dmat = faa->fa_dmat; - printf("\n"); - if (bus_space_map(sc->sc_bst, faa->fa_reg[0].addr, - faa->fa_reg[0].size, 0, &sc->sc_bsh)) - panic("%s: bus_space_map failed!", __func__); + faa->fa_reg[0].size, 0, &sc->sc_bsh)) { + printf(": can't map registers\n"); + return; + } - /* default to RGMII */ - OF_getprop(faa->fa_node, "phy-mode", phy_mode, sizeof(phy_mode)); - if (strcmp(phy_mode, "mii") == 0) - freq = 25000000; - else - freq = 125000000; - clock_set_frequency(faa->fa_node, "allwinner_gmac_tx", freq); + printf("\n"); - /* lookup PHY */ + /* Lookup PHY. */ phy = OF_getpropint(faa->fa_node, "phy", 0); node = OF_getnodebyphandle(phy); if (node) phyloc = OF_getpropint(node, "reg", phyloc); - /* enable clock */ + pinctrl_byname(faa->fa_node, "default"); + + /* Do hardware specific initializations. */ + if (OF_is_compatible(faa->fa_node, "allwinner,sun7i-a20-gmac")) + dwge_fdt_attach_allwinner(fsc); + else if (OF_is_compatible(faa->fa_node, "rockchip,rk3399-gmac")) + dwge_fdt_attach_rockchip(fsc); + + /* Enable clock. */ clock_enable(faa->fa_node, "stmmaceth"); + reset_deassert(faa->fa_node, "stmmaceth"); delay(5000); - /* power up phy */ + /* Power up PHY. */ phy_supply = OF_getpropint(faa->fa_node, "phy-supply", 0); if (phy_supply) regulator_enable(phy_supply); + /* Reset PHY */ + dwge_fdt_reset_phy(fsc); + fsc->sc_ih = arm_intr_establish_fdt(faa->fa_node, IPL_NET, dwge_fdt_intr, sc, sc->sc_dev.dv_xname); if (fsc->sc_ih == NULL) { @@ -131,6 +143,7 @@ dwge_fdt_attach(struct device *parent, struct device *self, void *aux) dwc_gmac_attach(sc, GMAC_MII_CLK_150_250M_DIV102, phyloc); return; + clrpwr: if (phy_supply) regulator_disable(phy_supply); @@ -138,6 +151,40 @@ clrpwr: bus_space_unmap(sc->sc_bst, sc->sc_bsh, faa->fa_reg[0].size); } +void +dwge_fdt_reset_phy(struct dwge_fdt_softc *sc) +{ + uint32_t *gpio; + uint32_t delays[3]; + int active = 1; + int len; + + len = OF_getproplen(sc->sc_node, "snps,reset-gpio"); + if (len <= 0) + return; + + gpio = malloc(len, M_TEMP, M_WAITOK); + + /* Gather information. */ + OF_getpropintarray(sc->sc_node, "snps,reset-gpio", gpio, len); + if (OF_getproplen(sc->sc_node, "snps-reset-active-low") == 0) + active = 0; + delays[0] = delays[1] = delays[2] = 0; + OF_getpropintarray(sc->sc_node, "snps,reset-delay-us", delays, + sizeof(delays)); + + /* Perform reset sequence. */ + gpio_controller_config_pin(gpio, GPIO_CONFIG_OUTPUT); + gpio_controller_set_pin(gpio, !active); + delay(delays[0]); + gpio_controller_set_pin(gpio, active); + delay(delays[1]); + gpio_controller_set_pin(gpio, !active); + delay(delays[2]); + + free(gpio, M_TEMP, len); +} + int dwge_fdt_intr(void *arg) { @@ -145,3 +192,67 @@ dwge_fdt_intr(void *arg) return dwc_gmac_intr(&sc->sc_core); } + +/* + * Allwinner A20/A31. + */ + +void +dwge_fdt_attach_allwinner(struct dwge_fdt_softc *sc) +{ + char phy_mode[8]; + uint32_t freq; + + /* default to RGMII */ + OF_getprop(sc->sc_node, "phy-mode", phy_mode, sizeof(phy_mode)); + if (strcmp(phy_mode, "mii") == 0) + freq = 25000000; + else + freq = 125000000; + clock_set_frequency(sc->sc_node, "allwinner_gmac_tx", freq); +} + +/* + * Rockchip RK3399 + */ + +/* Registers */ +#define RK3399_GRF_SOC_CON5 0xc214 +#define RK3399_GMAC_PHY_INTF_SEL_RGMII ((0x7 << 9) << 16 | (0x1 << 9)) +#define RK3399_GMAC_PHY_INTF_SEL_RMII ((0x7 << 9) << 16 | (0x4 << 9)) +#define RK3399_RMII_MODE_RMII ((1 << 6) << 16 | (1 << 6)) +#define RK3399_RMII_MODE_MII ((1 << 6) << 16 | (0 << 6)) +#define RK3399_GRF_SOC_CON6 0xc218 +#define RK3399_GMAC_RXCLK_DLY_ENA ((1 << 15) << 16 | (1 << 15)) +#define RK3399_GMAC_CLK_RX_DL_CFG(val) ((0x7f << 8) << 16 | ((val) << 8)) +#define RK3399_GMAC_TXCLK_DLY_ENA ((1 << 7) << 16 | (1 << 7)) +#define RK3399_GMAC_CLK_TX_DL_CFG(val) ((0x7f << 0) << 16 | ((val) << 0)) + +void +dwge_fdt_attach_rockchip(struct dwge_fdt_softc *sc) +{ + struct regmap *rm; + uint32_t grf; + int tx_delay, rx_delay; + + grf = OF_getpropint(sc->sc_node, "rockchip,grf", 0); + rm = regmap_byphandle(grf); + if (rm == NULL) + return; + + clock_enable(sc->sc_node, "mac_clk_rx"); + clock_enable(sc->sc_node, "mac_clk_tx"); + clock_enable(sc->sc_node, "aclk_mac"); + clock_enable(sc->sc_node, "pclk_mac"); + + /* Use RGMII interface. */ + regmap_write_4(rm, RK3399_GRF_SOC_CON5, + RK3399_GMAC_PHY_INTF_SEL_RGMII | RK3399_RMII_MODE_MII); + + /* Program clock delay lines. */ + tx_delay = OF_getpropint(sc->sc_node, "tx_delay", 0x30); + rx_delay = OF_getpropint(sc->sc_node, "rx_delay", 0x10); + regmap_write_4(rm, RK3399_GRF_SOC_CON6, + RK3399_GMAC_TXCLK_DLY_ENA | RK3399_GMAC_CLK_TX_DL_CFG(tx_delay) | + RK3399_GMAC_RXCLK_DLY_ENA | RK3399_GMAC_CLK_RX_DL_CFG(rx_delay)); +} |