From 2defb358ea1107e41fd12efd0db0283f47178473 Mon Sep 17 00:00:00 2001 From: Kyle Evans Date: Thu, 4 Jan 2018 22:37:15 +0000 Subject: [PATCH] if_awg: Use syscon prop if it exists The emac bindings that are landing in Linux 4.15 specify a syscon property on the emac node that point to /soc/syscon. Use this property if it's specified, but maintain backwards compatibility with the old method. The older method is still used for boards that we get .dtb from u-boot, such as pine64, that did not yet have stable emac bindings. Tested on: Banana Pi-M3 (a83t) Tested on: Pine64 (a64) Reviewed by: manu Differential Revision: https://reviews.freebsd.org/D13296 --- sys/arm/allwinner/files.allwinner | 2 +- sys/arm/allwinner/if_awg.c | 63 ++++++++++++++++++++++++++++--- sys/arm/conf/GENERIC | 1 + sys/arm64/conf/GENERIC | 1 + sys/conf/files.arm64 | 2 +- 5 files changed, 62 insertions(+), 7 deletions(-) diff --git a/sys/arm/allwinner/files.allwinner b/sys/arm/allwinner/files.allwinner index e62db3cedd22..eadd1686fb79 100644 --- a/sys/arm/allwinner/files.allwinner +++ b/sys/arm/allwinner/files.allwinner @@ -20,7 +20,7 @@ arm/allwinner/aw_usbphy.c optional ehci | ohci arm/allwinner/aw_wdog.c standard arm/allwinner/axp209.c optional axp209 arm/allwinner/axp81x.c optional axp81x -arm/allwinner/if_awg.c optional awg +arm/allwinner/if_awg.c optional awg ext_resources syscon arm/allwinner/if_emac.c optional emac arm/allwinner/sunxi_dma_if.m standard dev/iicbus/twsi/a10_twsi.c optional twsi diff --git a/sys/arm/allwinner/if_awg.c b/sys/arm/allwinner/if_awg.c index 9b233956f24f..b106b2698993 100644 --- a/sys/arm/allwinner/if_awg.c +++ b/sys/arm/allwinner/if_awg.c @@ -69,7 +69,9 @@ __FBSDID("$FreeBSD$"); #include #include #include +#include +#include "syscon_if.h" #include "miibus_if.h" #include "gpio_if.h" @@ -105,6 +107,7 @@ __FBSDID("$FreeBSD$"); #define RX_BATCH_DEFAULT 64 /* syscon EMAC clock register */ +#define EMAC_CLK_REG 0x30 #define EMAC_CLK_EPHY_ADDR (0x1f << 20) /* H3 */ #define EMAC_CLK_EPHY_ADDR_SHIFT 20 #define EMAC_CLK_EPHY_LED_POL (1 << 17) /* H3 */ @@ -203,6 +206,7 @@ struct awg_softc { int link; int if_flags; enum awg_type type; + struct syscon *syscon; struct awg_txring tx; struct awg_rxring rx; @@ -217,6 +221,9 @@ static struct resource_spec awg_spec[] = { static void awg_txeof(struct awg_softc *sc); +static uint32_t syscon_read_emac_clk_reg(device_t dev); +static void syscon_write_emac_clk_reg(device_t dev, uint32_t val); + static int awg_miibus_readreg(device_t dev, int phy, int reg) { @@ -1153,6 +1160,32 @@ awg_ioctl(if_t ifp, u_long cmd, caddr_t data) return (error); } +static uint32_t +syscon_read_emac_clk_reg(device_t dev) +{ + struct awg_softc *sc; + + sc = device_get_softc(dev); + if (sc->syscon != NULL) + return (SYSCON_READ_4(sc->syscon, EMAC_CLK_REG)); + else if (sc->res[_RES_SYSCON] != NULL) + return (bus_read_4(sc->res[_RES_SYSCON], 0)); + + return (0); +} + +static void +syscon_write_emac_clk_reg(device_t dev, uint32_t val) +{ + struct awg_softc *sc; + + sc = device_get_softc(dev); + if (sc->syscon != NULL) + SYSCON_WRITE_4(sc->syscon, EMAC_CLK_REG, val); + else if (sc->res[_RES_SYSCON] != NULL) + bus_write_4(sc->res[_RES_SYSCON], 0, val); +} + static int awg_setup_phy(device_t dev) { @@ -1163,19 +1196,31 @@ awg_setup_phy(device_t dev) phandle_t node; uint32_t reg, tx_delay, rx_delay; int error; + bool use_syscon; sc = device_get_softc(dev); node = ofw_bus_get_node(dev); + use_syscon = false; if (OF_getprop_alloc(node, "phy-mode", 1, (void **)&phy_type) == 0) return (0); + if (sc->syscon != NULL || sc->res[_RES_SYSCON] != NULL) + use_syscon = true; + if (bootverbose) device_printf(dev, "PHY type: %s, conf mode: %s\n", phy_type, - sc->res[_RES_SYSCON] != NULL ? "reg" : "clk"); + use_syscon ? "reg" : "clk"); - if (sc->res[_RES_SYSCON] != NULL) { - reg = bus_read_4(sc->res[_RES_SYSCON], 0); + if (use_syscon) { + /* + * Abstract away writing to syscon for devices like the pine64. + * For the pine64, we get dtb from U-Boot and it still uses the + * legacy setup of specifying syscon register in emac node + * rather than as its own node and using an xref in emac. + * These abstractions can go away once U-Boot dts is up-to-date. + */ + reg = syscon_read_emac_clk_reg(dev); reg &= ~(EMAC_CLK_PIT | EMAC_CLK_SRC | EMAC_CLK_RMII_EN); if (strncmp(phy_type, "rgmii", 5) == 0) reg |= EMAC_CLK_PIT_RGMII | EMAC_CLK_SRC_RGMII; @@ -1215,7 +1260,7 @@ awg_setup_phy(device_t dev) if (bootverbose) device_printf(dev, "EMAC clock: 0x%08x\n", reg); - bus_write_4(sc->res[_RES_SYSCON], 0, reg); + syscon_write_emac_clk_reg(dev, reg); } else { if (strncmp(phy_type, "rgmii", 5) == 0) tx_parent_name = "emac_int_tx"; @@ -1263,6 +1308,7 @@ static int awg_setup_extres(device_t dev) { struct awg_softc *sc; + phandle_t node; hwreset_t rst_ahb, rst_ephy; clk_t clk_ahb, clk_ephy; regulator_t reg; @@ -1273,6 +1319,7 @@ awg_setup_extres(device_t dev) rst_ahb = rst_ephy = NULL; clk_ahb = clk_ephy = NULL; reg = NULL; + node = ofw_bus_get_node(dev); /* Get AHB clock and reset resources */ error = hwreset_get_by_ofw_name(dev, 0, "ahb", &rst_ahb); @@ -1289,7 +1336,13 @@ awg_setup_extres(device_t dev) } if (clk_get_by_ofw_name(dev, 0, "ephy", &clk_ephy) != 0) clk_ephy = NULL; - + + if (OF_hasprop(node, "syscon") && syscon_get_by_ofw_property(dev, node, + "syscon", &sc->syscon) != 0) { + device_printf(dev, "cannot get syscon driver handle\n"); + goto fail; + } + /* Configure PHY for MII or RGMII mode */ if (awg_setup_phy(dev) != 0) goto fail; diff --git a/sys/arm/conf/GENERIC b/sys/arm/conf/GENERIC index cb84f781766a..116ea87cd6ca 100644 --- a/sys/arm/conf/GENERIC +++ b/sys/arm/conf/GENERIC @@ -69,6 +69,7 @@ device clk device phy device hwreset device regulator +device syscon # CPU frequency control device cpufreq diff --git a/sys/arm64/conf/GENERIC b/sys/arm64/conf/GENERIC index 1a039add3c5d..5187ca008c78 100644 --- a/sys/arm64/conf/GENERIC +++ b/sys/arm64/conf/GENERIC @@ -235,6 +235,7 @@ device clk device phy device hwreset device regulator +device syscon # The `bpf' device enables the Berkeley Packet Filter. # Be aware of the administrative consequences of enabling this! diff --git a/sys/conf/files.arm64 b/sys/conf/files.arm64 index 3e35a8ccb447..48c0c7499d58 100644 --- a/sys/conf/files.arm64 +++ b/sys/conf/files.arm64 @@ -59,7 +59,7 @@ arm/allwinner/clkng/ccu_a64.c optional aw_ccu fdt arm/allwinner/clkng/ccu_h3.c optional aw_ccu fdt arm/allwinner/clkng/ccu_sun8i_r.c optional aw_ccu fdt -arm/allwinner/if_awg.c optional awg fdt +arm/allwinner/if_awg.c optional awg ext_resources syscon fdt arm/annapurna/alpine/alpine_ccu.c optional al_ccu fdt arm/annapurna/alpine/alpine_nb_service.c optional al_nb_service fdt arm/annapurna/alpine/alpine_pci.c optional al_pci fdt