Module Name: src Committed By: jmcneill Date: Sat Jul 8 11:12:24 UTC 2017
Modified Files: src/sys/arch/arm/sunxi: files.sunxi sunxi_gpio.c src/sys/arch/evbarm/conf: SUNXI Added Files: src/sys/arch/arm/sunxi: sunxi_gates.c sunxi_resets.c Log Message: Add misc. gates and resets driver, and explicitly enable PIO clocks at attach. To generate a diff of this commit: cvs rdiff -u -r1.10 -r1.11 src/sys/arch/arm/sunxi/files.sunxi cvs rdiff -u -r0 -r1.1 src/sys/arch/arm/sunxi/sunxi_gates.c \ src/sys/arch/arm/sunxi/sunxi_resets.c cvs rdiff -u -r1.7 -r1.8 src/sys/arch/arm/sunxi/sunxi_gpio.c cvs rdiff -u -r1.13 -r1.14 src/sys/arch/evbarm/conf/SUNXI Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.
Modified files: Index: src/sys/arch/arm/sunxi/files.sunxi diff -u src/sys/arch/arm/sunxi/files.sunxi:1.10 src/sys/arch/arm/sunxi/files.sunxi:1.11 --- src/sys/arch/arm/sunxi/files.sunxi:1.10 Fri Jul 7 13:11:31 2017 +++ src/sys/arch/arm/sunxi/files.sunxi Sat Jul 8 11:12:24 2017 @@ -1,4 +1,4 @@ -# $NetBSD: files.sunxi,v 1.10 2017/07/07 13:11:31 jmcneill Exp $ +# $NetBSD: files.sunxi,v 1.11 2017/07/08 11:12:24 jmcneill Exp $ # # Configuration info for Allwinner sunxi family SoCs # @@ -41,6 +41,16 @@ device sun8ih3ccu: sunxi_ccu attach sun8ih3ccu at fdt with sunxi_h3_ccu file arch/arm/sunxi/sun8i_h3_ccu.c sunxi_h3_ccu +# Misc. clock resets +device sunxiresets +attach sunxiresets at fdt with sunxi_resets +file arch/arm/sunxi/sunxi_resets.c sunxi_resets + +# Misc. clock gates +device sunxigates +attach sunxigates at fdt with sunxi_gates +file arch/arm/sunxi/sunxi_gates.c sunxi_gates + # GPIO device sunxigpio: gpiobus attach sunxigpio at fdt with sunxi_gpio Index: src/sys/arch/arm/sunxi/sunxi_gpio.c diff -u src/sys/arch/arm/sunxi/sunxi_gpio.c:1.7 src/sys/arch/arm/sunxi/sunxi_gpio.c:1.8 --- src/sys/arch/arm/sunxi/sunxi_gpio.c:1.7 Sat Jul 8 00:26:19 2017 +++ src/sys/arch/arm/sunxi/sunxi_gpio.c Sat Jul 8 11:12:24 2017 @@ -1,4 +1,4 @@ -/* $NetBSD: sunxi_gpio.c,v 1.7 2017/07/08 00:26:19 jmcneill Exp $ */ +/* $NetBSD: sunxi_gpio.c,v 1.8 2017/07/08 11:12:24 jmcneill Exp $ */ /*- * Copyright (c) 2017 Jared McNeill <jmcne...@invisible.ca> @@ -29,7 +29,7 @@ #include "opt_soc.h" #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: sunxi_gpio.c,v 1.7 2017/07/08 00:26:19 jmcneill Exp $"); +__KERNEL_RCSID(0, "$NetBSD: sunxi_gpio.c,v 1.8 2017/07/08 11:12:24 jmcneill Exp $"); #include <sys/param.h> #include <sys/bus.h> @@ -507,6 +507,8 @@ sunxi_gpio_attach(device_t parent, devic struct sunxi_gpio_softc * const sc = device_private(self); struct fdt_attach_args * const faa = aux; const int phandle = faa->faa_phandle; + struct fdtbus_reset *rst; + struct clk *clk; bus_addr_t addr; bus_size_t size; int child; @@ -516,6 +518,18 @@ sunxi_gpio_attach(device_t parent, devic return; } + if ((clk = fdtbus_clock_get_index(phandle, 0)) != NULL) + if (clk_enable(clk) != 0) { + aprint_error(": couldn't enable clock\n"); + return; + } + + if ((rst = fdtbus_reset_get_index(phandle, 0)) != NULL) + if (fdtbus_reset_deassert(rst) != 0) { + aprint_error(": couldn't de-assert reset\n"); + return; + } + sc->sc_dev = self; sc->sc_bst = faa->faa_bst; if (bus_space_map(sc->sc_bst, addr, size, 0, &sc->sc_bsh) != 0) { Index: src/sys/arch/evbarm/conf/SUNXI diff -u src/sys/arch/evbarm/conf/SUNXI:1.13 src/sys/arch/evbarm/conf/SUNXI:1.14 --- src/sys/arch/evbarm/conf/SUNXI:1.13 Sat Jul 8 00:55:21 2017 +++ src/sys/arch/evbarm/conf/SUNXI Sat Jul 8 11:12:24 2017 @@ -1,5 +1,5 @@ # -# $NetBSD: SUNXI,v 1.13 2017/07/08 00:55:21 jmcneill Exp $ +# $NetBSD: SUNXI,v 1.14 2017/07/08 11:12:24 jmcneill Exp $ # # Allwinner sunxi family # @@ -64,6 +64,8 @@ psci* at fdt? sun6ia31ccu* at fdt? pass 4 # A31 CCU sun8ia83tccu* at fdt? pass 4 # A83T CCU sun8ih3ccu* at fdt? pass 4 # H3 CCU +sunxiresets* at fdt? pass 1 # Misc. clock resets +sunxigates* at fdt? pass 1 # Misc. clock gates fclock* at fdt? pass 3 fregulator* at fdt? pass 4 Added files: Index: src/sys/arch/arm/sunxi/sunxi_gates.c diff -u /dev/null src/sys/arch/arm/sunxi/sunxi_gates.c:1.1 --- /dev/null Sat Jul 8 11:12:24 2017 +++ src/sys/arch/arm/sunxi/sunxi_gates.c Sat Jul 8 11:12:24 2017 @@ -0,0 +1,277 @@ +/* $NetBSD: sunxi_gates.c,v 1.1 2017/07/08 11:12:24 jmcneill Exp $ */ + +/*- + * Copyright (c) 2017 Jared McNeill <jmcne...@invisible.ca> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 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> +__KERNEL_RCSID(0, "$NetBSD: sunxi_gates.c,v 1.1 2017/07/08 11:12:24 jmcneill Exp $"); + +#include <sys/param.h> +#include <sys/bus.h> +#include <sys/cpu.h> +#include <sys/device.h> +#include <sys/kmem.h> + +#include <dev/fdt/fdtvar.h> + +#include <dev/clk/clk_backend.h> + +#define GATE_REG(index) (((index) / 32) * 4) +#define GATE_MASK(index) __BIT((index) % 32) + +static const char * compatible[] = { + "allwinner,sun4i-a10-gates-clk", + NULL +}; + +struct sunxi_gate { + struct clk base; + u_int index; + + TAILQ_ENTRY(sunxi_gate) gates; +}; + +struct sunxi_gates_softc { + device_t sc_dev; + bus_space_tag_t sc_bst; + bus_space_handle_t sc_bsh; + int sc_phandle; + + struct clk_domain sc_clkdom; + TAILQ_HEAD(, sunxi_gate) sc_gates; +}; + +#define GATE_READ(sc, reg) \ + bus_space_read_4((sc)->sc_bst, (sc)->sc_bsh, (reg)) +#define GATE_WRITE(sc, reg, val) \ + bus_space_write_4((sc)->sc_bst, (sc)->sc_bsh, (reg), (val)) + +static struct clk * +sunxi_gates_clock_decode(device_t dev, const void *data, size_t len) +{ + struct sunxi_gates_softc * const sc = device_private(dev); + struct sunxi_gate *gate; + + if (len != 4) + return NULL; + + const u_int index = be32dec(data); + + TAILQ_FOREACH(gate, &sc->sc_gates, gates) + if (gate->index == index) + return &gate->base; + + return NULL; +} + +static const struct fdtbus_clock_controller_func sunxi_gates_fdtclock_funcs = { + .decode = sunxi_gates_clock_decode, +}; + +static struct clk * +sunxi_gates_clock_get(void *priv, const char *name) +{ + struct sunxi_gates_softc * const sc = priv; + struct sunxi_gate *gate; + + TAILQ_FOREACH(gate, &sc->sc_gates, gates) + if (strcmp(gate->base.name, name) == 0) + return &gate->base; + + return NULL; +} + +static void +sunxi_gates_clock_put(void *priv, struct clk *clk) +{ +} + +static u_int +sunxi_gates_clock_get_rate(void *priv, struct clk *clkp) +{ + struct sunxi_gates_softc * const sc = priv; + struct sunxi_gate *gate = (struct sunxi_gate *)clkp; + struct clk *clkp_parent; + + clkp_parent = clk_get_parent(clkp); + if (clkp_parent == NULL) + return 0; + + const bus_size_t gate_reg = GATE_REG(gate->index); + const uint32_t gate_mask = GATE_MASK(gate->index); + + if ((GATE_READ(sc, gate_reg) & gate_mask) == 0) + return 0; + + return clk_get_rate(clkp_parent); +} + +static int +sunxi_gates_clock_enable(void *priv, struct clk *clkp) +{ + struct sunxi_gates_softc * const sc = priv; + struct sunxi_gate *gate = (struct sunxi_gate *)clkp; + uint32_t val; + + const bus_size_t gate_reg = GATE_REG(gate->index); + const uint32_t gate_mask = GATE_MASK(gate->index); + + val = GATE_READ(sc, gate_reg); + val |= gate_mask; + GATE_WRITE(sc, gate_reg, val); + + return 0; +} + +static int +sunxi_gates_clock_disable(void *priv, struct clk *clkp) +{ + struct sunxi_gates_softc * const sc = priv; + struct sunxi_gate *gate = (struct sunxi_gate *)clkp; + uint32_t val; + + const bus_size_t gate_reg = GATE_REG(gate->index); + const uint32_t gate_mask = GATE_MASK(gate->index); + + val = GATE_READ(sc, gate_reg); + val &= ~gate_mask; + GATE_WRITE(sc, gate_reg, val); + + return 0; +} + +static struct clk * +sunxi_gates_clock_get_parent(void *priv, struct clk *clkp) +{ + struct sunxi_gates_softc * const sc = priv; + + return fdtbus_clock_get_index(sc->sc_phandle, 0); +} + +static const struct clk_funcs sunxi_gates_clock_funcs = { + .get = sunxi_gates_clock_get, + .put = sunxi_gates_clock_put, + .get_rate = sunxi_gates_clock_get_rate, + .enable = sunxi_gates_clock_enable, + .disable = sunxi_gates_clock_disable, + .get_parent = sunxi_gates_clock_get_parent, +}; + +static void +sunxi_gates_print(struct sunxi_gates_softc *sc) +{ + struct sunxi_gate *gate; + struct clk *clkp_parent; + + TAILQ_FOREACH(gate, &sc->sc_gates, gates) { + clkp_parent = clk_get_parent(&gate->base); + + aprint_debug_dev(sc->sc_dev, + "%3d %-12s %2s %-12s %-7s ", + gate->index, + gate->base.name, + clkp_parent ? "<-" : "", + clkp_parent ? clkp_parent->name : "", + "gate"); + aprint_debug("%10d Hz\n", clk_get_rate(&gate->base)); + } +} + +static int +sunxi_gates_match(device_t parent, cfdata_t cf, void *aux) +{ + struct fdt_attach_args * const faa = aux; + + return of_match_compatible(faa->faa_phandle, compatible); +} + +static void +sunxi_gates_attach(device_t parent, device_t self, void *aux) +{ + struct sunxi_gates_softc * const sc = device_private(self); + struct fdt_attach_args * const faa = aux; + const int phandle = faa->faa_phandle; + struct sunxi_gate *gate; + const u_int *indices; + bus_addr_t addr; + bus_size_t size; + int len, i; + + if (fdtbus_get_reg(phandle, 0, &addr, &size) != 0) { + aprint_error(": couldn't get registers\n"); + return; + } + + sc->sc_dev = self; + sc->sc_phandle = phandle; + sc->sc_bst = faa->faa_bst; + if (bus_space_map(sc->sc_bst, addr, size, 0, &sc->sc_bsh) != 0) { + aprint_error(": couldn't map registers\n"); + return; + } + TAILQ_INIT(&sc->sc_gates); + + aprint_naive("\n"); + aprint_normal("\n"); + + sc->sc_clkdom.funcs = &sunxi_gates_clock_funcs; + sc->sc_clkdom.priv = sc; + + indices = fdtbus_get_prop(phandle, "clock-indices", &len); + if (indices == NULL) { + aprint_error_dev(self, "no clock-indices property\n"); + return; + } + + for (i = 0; + len >= sizeof(u_int); + len -= sizeof(u_int), i++, indices++) { + const u_int index = be32dec(indices); + const char *name = fdtbus_get_string_index(phandle, + "clock-output-names", i); + + if (name == NULL) { + aprint_error_dev(self, "no name for clk index %d\n", + index); + continue; + } + + gate = kmem_zalloc(sizeof(*gate), KM_SLEEP); + gate->base.domain = &sc->sc_clkdom; + gate->base.name = name; + gate->index = index; + + TAILQ_INSERT_TAIL(&sc->sc_gates, gate, gates); + } + + fdtbus_register_clock_controller(sc->sc_dev, phandle, + &sunxi_gates_fdtclock_funcs); + + sunxi_gates_print(sc); +} + +CFATTACH_DECL_NEW(sunxi_gates, sizeof(struct sunxi_gates_softc), + sunxi_gates_match, sunxi_gates_attach, NULL, NULL); Index: src/sys/arch/arm/sunxi/sunxi_resets.c diff -u /dev/null src/sys/arch/arm/sunxi/sunxi_resets.c:1.1 --- /dev/null Sat Jul 8 11:12:24 2017 +++ src/sys/arch/arm/sunxi/sunxi_resets.c Sat Jul 8 11:12:24 2017 @@ -0,0 +1,149 @@ +/* $NetBSD: sunxi_resets.c,v 1.1 2017/07/08 11:12:24 jmcneill Exp $ */ + +/*- + * Copyright (c) 2017 Jared McNeill <jmcne...@invisible.ca> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 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> +__KERNEL_RCSID(0, "$NetBSD: sunxi_resets.c,v 1.1 2017/07/08 11:12:24 jmcneill Exp $"); + +#include <sys/param.h> +#include <sys/bus.h> +#include <sys/cpu.h> +#include <sys/device.h> + +#include <dev/fdt/fdtvar.h> + +#include <dev/clk/clk_backend.h> + +#define RESET_REG(index) (((index) / 32) * 4) +#define RESET_MASK(index) __BIT((index) % 32) + +static const char * compatible[] = { + "allwinner,sun6i-a31-clock-reset", + NULL +}; + +struct sunxi_resets_softc { + device_t sc_dev; + bus_space_tag_t sc_bst; + bus_space_handle_t sc_bsh; +}; + +#define RESET_READ(sc, reg) \ + bus_space_read_4((sc)->sc_bst, (sc)->sc_bsh, (reg)) +#define RESET_WRITE(sc, reg, val) \ + bus_space_write_4((sc)->sc_bst, (sc)->sc_bsh, (reg), (val)) + +static void * +sunxi_resets_acquire(device_t dev, const void *data, size_t len) +{ + if (len != 4) + return NULL; + + /* Specifier is an index. Just return it. */ + return (void *)(uintptr_t)be32dec(data); +} + +static void +sunxi_resets_release(device_t dev, void *priv) +{ +} + +static int +sunxi_resets_assert(device_t dev, void *priv) +{ + struct sunxi_resets_softc * const sc = device_private(dev); + const uintptr_t index = (uintptr_t)priv; + + const bus_size_t reset_reg = RESET_REG(index); + const uint32_t reset_mask = RESET_MASK(index); + + const uint32_t val = RESET_READ(sc, reset_reg); + RESET_WRITE(sc, reset_reg, val & ~reset_mask); + + return 0; +} + +static int +sunxi_resets_deassert(device_t dev, void *priv) +{ + struct sunxi_resets_softc * const sc = device_private(dev); + const uintptr_t index = (uintptr_t)priv; + + const bus_size_t reset_reg = RESET_REG(index); + const uint32_t reset_mask = RESET_MASK(index); + + const uint32_t val = RESET_READ(sc, reset_reg); + RESET_WRITE(sc, reset_reg, val | reset_mask); + + return 0; +} + +static const struct fdtbus_reset_controller_func sunxi_fdtreset_funcs = { + .acquire = sunxi_resets_acquire, + .release = sunxi_resets_release, + .reset_assert = sunxi_resets_assert, + .reset_deassert = sunxi_resets_deassert, +}; + +static int +sunxi_resets_match(device_t parent, cfdata_t cf, void *aux) +{ + struct fdt_attach_args * const faa = aux; + + return of_match_compatible(faa->faa_phandle, compatible); +} + +static void +sunxi_resets_attach(device_t parent, device_t self, void *aux) +{ + struct sunxi_resets_softc * const sc = device_private(self); + struct fdt_attach_args * const faa = aux; + const int phandle = faa->faa_phandle; + bus_addr_t addr; + bus_size_t size; + + if (fdtbus_get_reg(phandle, 0, &addr, &size) != 0) { + aprint_error(": couldn't get registers\n"); + return; + } + + sc->sc_dev = self; + sc->sc_bst = faa->faa_bst; + if (bus_space_map(sc->sc_bst, addr, size, 0, &sc->sc_bsh) != 0) { + aprint_error(": couldn't map registers\n"); + return; + } + + aprint_naive("\n"); + aprint_normal("\n"); + + fdtbus_register_reset_controller(sc->sc_dev, phandle, + &sunxi_fdtreset_funcs); +} + +CFATTACH_DECL_NEW(sunxi_resets, sizeof(struct sunxi_resets_softc), + sunxi_resets_match, sunxi_resets_attach, NULL, NULL);