Module Name: src Committed By: jmcneill Date: Mon May 27 21:12:54 UTC 2019
Modified Files: src/sys/arch/arm/sunxi: files.sunxi Added Files: src/sys/arch/arm/sunxi: sun8i_a23_apbclk.c sun9i_a80_cpusclk.c Log Message: Add apb0 and cpus clock drivers for A80 To generate a diff of this commit: cvs rdiff -u -r1.62 -r1.63 src/sys/arch/arm/sunxi/files.sunxi cvs rdiff -u -r0 -r1.1 src/sys/arch/arm/sunxi/sun8i_a23_apbclk.c \ src/sys/arch/arm/sunxi/sun9i_a80_cpusclk.c 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.62 src/sys/arch/arm/sunxi/files.sunxi:1.63 --- src/sys/arch/arm/sunxi/files.sunxi:1.62 Wed May 8 13:40:14 2019 +++ src/sys/arch/arm/sunxi/files.sunxi Mon May 27 21:12:54 2019 @@ -1,4 +1,4 @@ -# $NetBSD: files.sunxi,v 1.62 2019/05/08 13:40:14 isaki Exp $ +# $NetBSD: files.sunxi,v 1.63 2019/05/27 21:12:54 jmcneill Exp $ # # Configuration info for Allwinner sunxi family SoCs # @@ -97,6 +97,16 @@ device sun9immcclk attach sun9immcclk at fdt with sunxi_a80_mmcclk file arch/arm/sunxi/sun9i_a80_mmcclk.c sunxi_a80_mmcclk +# CPUS clock driver (A80) +device sun9icpusclk +attach sun9icpusclk at fdt with sunxi_a80_cpusclk +file arch/arm/sunxi/sun9i_a80_cpusclk.c sunxi_a80_cpusclk + +# APB0 clock driver (A80) +device sun8iapbclk +attach sun8iapbclk at fdt with sunxi_a23_apbclk +file arch/arm/sunxi/sun8i_a23_apbclk.c sunxi_a23_apbclk + # Interrupt controller device sunxiintc: pic, pic_splfuncs attach sunxiintc at fdt with sunxi_intc Added files: Index: src/sys/arch/arm/sunxi/sun8i_a23_apbclk.c diff -u /dev/null src/sys/arch/arm/sunxi/sun8i_a23_apbclk.c:1.1 --- /dev/null Mon May 27 21:12:54 2019 +++ src/sys/arch/arm/sunxi/sun8i_a23_apbclk.c Mon May 27 21:12:54 2019 @@ -0,0 +1,182 @@ +/* $NetBSD: sun8i_a23_apbclk.c,v 1.1 2019/05/27 21:12:54 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: sun8i_a23_apbclk.c,v 1.1 2019/05/27 21:12:54 jmcneill Exp $"); + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/device.h> +#include <sys/kmem.h> +#include <sys/bus.h> + +#include <dev/clk/clk_backend.h> + +#include <dev/fdt/fdtvar.h> + +#define APB0_DIV __BITS(1,0) + +static int sun8i_a23_apbclk_match(device_t, cfdata_t, void *); +static void sun8i_a23_apbclk_attach(device_t, device_t, void *); + +static struct clk *sun8i_a23_apbclk_decode(device_t, int, const void *, size_t); + +static const struct fdtbus_clock_controller_func sun8i_a23_apbclk_fdt_funcs = { + .decode = sun8i_a23_apbclk_decode +}; + +static struct clk *sun8i_a23_apbclk_get(void *, const char *); +static void sun8i_a23_apbclk_put(void *, struct clk *); +static int sun8i_a23_apbclk_set_rate(void *, struct clk *, u_int); +static u_int sun8i_a23_apbclk_get_rate(void *, struct clk *); +static struct clk *sun8i_a23_apbclk_get_parent(void *, struct clk *); + +static const struct clk_funcs sun8i_a23_apbclk_clk_funcs = { + .get = sun8i_a23_apbclk_get, + .put = sun8i_a23_apbclk_put, + .set_rate = sun8i_a23_apbclk_set_rate, + .get_rate = sun8i_a23_apbclk_get_rate, + .get_parent = sun8i_a23_apbclk_get_parent, +}; + +struct sun8i_a23_apbclk_softc { + device_t sc_dev; + int sc_phandle; + bus_space_tag_t sc_bst; + bus_space_handle_t sc_bsh; + + struct clk_domain sc_clkdom; + struct clk sc_clk; + struct clk *sc_parent; +}; + +#define RD4(sc, reg) \ + bus_space_read_4((sc)->sc_bst, (sc)->sc_bsh, (reg)) +#define WR4(sc, reg, val) \ + bus_space_write_4((sc)->sc_bst, (sc)->sc_bsh, (reg), (val)) + +CFATTACH_DECL_NEW(sunxi_a23_apbclk, sizeof(struct sun8i_a23_apbclk_softc), + sun8i_a23_apbclk_match, sun8i_a23_apbclk_attach, NULL, NULL); + +static int +sun8i_a23_apbclk_match(device_t parent, cfdata_t cf, void *aux) +{ + const char * const compatible[] = { "allwinner,sun8i-a23-apb0-clk", NULL }; + const struct fdt_attach_args *faa = aux; + + return of_match_compatible(faa->faa_phandle, compatible); +} + +static void +sun8i_a23_apbclk_attach(device_t parent, device_t self, void *aux) +{ + struct sun8i_a23_apbclk_softc * const sc = device_private(self); + const struct fdt_attach_args *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_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; + } + sc->sc_parent = fdtbus_clock_get_index(phandle, 0); + + sc->sc_clkdom.funcs = &sun8i_a23_apbclk_clk_funcs; + sc->sc_clkdom.priv = sc; + + sc->sc_clk.domain = &sc->sc_clkdom; + sc->sc_clk.name = kmem_asprintf("%s", faa->faa_name); + + aprint_naive("\n"); + aprint_normal(": A23 APB0 clock\n"); + + fdtbus_register_clock_controller(self, phandle, &sun8i_a23_apbclk_fdt_funcs); +} + +static struct clk * +sun8i_a23_apbclk_decode(device_t dev, int cc_phandle, const void *data, + size_t len) +{ + struct sun8i_a23_apbclk_softc * const sc = device_private(dev); + + if (len != 0) + return NULL; + + return &sc->sc_clk; +} + +static struct clk * +sun8i_a23_apbclk_get(void *priv, const char *name) +{ + struct sun8i_a23_apbclk_softc * const sc = priv; + + if (strcmp(name, sc->sc_clk.name) != 0) + return NULL; + + return &sc->sc_clk; +} + +static void +sun8i_a23_apbclk_put(void *priv, struct clk *clk) +{ +} + +static int +sun8i_a23_apbclk_set_rate(void *priv, struct clk *clk, u_int rate) +{ + return ENXIO; +} + +static u_int +sun8i_a23_apbclk_get_rate(void *priv, struct clk *clk) +{ + struct sun8i_a23_apbclk_softc * const sc = priv; + struct clk *clk_parent = clk_get_parent(clk); + + const uint32_t val = RD4(sc, 0); + const u_int div = __SHIFTOUT(val, APB0_DIV); + + return clk_get_rate(clk_parent) / (div + 1); +} + +static struct clk * +sun8i_a23_apbclk_get_parent(void *priv, struct clk *clk) +{ + struct sun8i_a23_apbclk_softc * const sc = priv; + + return sc->sc_parent; +} Index: src/sys/arch/arm/sunxi/sun9i_a80_cpusclk.c diff -u /dev/null src/sys/arch/arm/sunxi/sun9i_a80_cpusclk.c:1.1 --- /dev/null Mon May 27 21:12:54 2019 +++ src/sys/arch/arm/sunxi/sun9i_a80_cpusclk.c Mon May 27 21:12:54 2019 @@ -0,0 +1,193 @@ +/* $NetBSD: sun9i_a80_cpusclk.c,v 1.1 2019/05/27 21:12:54 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: sun9i_a80_cpusclk.c,v 1.1 2019/05/27 21:12:54 jmcneill Exp $"); + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/device.h> +#include <sys/kmem.h> +#include <sys/bus.h> + +#include <dev/clk/clk_backend.h> + +#include <dev/fdt/fdtvar.h> + +#define CPUS_CLK_SRC_SEL __BITS(17,16) +#define CPUS_CLK_SRC_SEL_PLL_PERIPH0 2 +#define CPUS_POST_DIV __BITS(12,8) +#define CPUS_CLK_RATIO __BITS(5,4) + +static int sun9i_a80_cpusclk_match(device_t, cfdata_t, void *); +static void sun9i_a80_cpusclk_attach(device_t, device_t, void *); + +static struct clk *sun9i_a80_cpusclk_decode(device_t, int, const void *, size_t); + +static const struct fdtbus_clock_controller_func sun9i_a80_cpusclk_fdt_funcs = { + .decode = sun9i_a80_cpusclk_decode +}; + +static struct clk *sun9i_a80_cpusclk_get(void *, const char *); +static void sun9i_a80_cpusclk_put(void *, struct clk *); +static int sun9i_a80_cpusclk_set_rate(void *, struct clk *, u_int); +static u_int sun9i_a80_cpusclk_get_rate(void *, struct clk *); +static struct clk *sun9i_a80_cpusclk_get_parent(void *, struct clk *); + +static const struct clk_funcs sun9i_a80_cpusclk_clk_funcs = { + .get = sun9i_a80_cpusclk_get, + .put = sun9i_a80_cpusclk_put, + .set_rate = sun9i_a80_cpusclk_set_rate, + .get_rate = sun9i_a80_cpusclk_get_rate, + .get_parent = sun9i_a80_cpusclk_get_parent, +}; + +struct sun9i_a80_cpusclk_softc { + device_t sc_dev; + int sc_phandle; + bus_space_tag_t sc_bst; + bus_space_handle_t sc_bsh; + + struct clk_domain sc_clkdom; + struct clk sc_clk; +}; + +#define RD4(sc, reg) \ + bus_space_read_4((sc)->sc_bst, (sc)->sc_bsh, (reg)) +#define WR4(sc, reg, val) \ + bus_space_write_4((sc)->sc_bst, (sc)->sc_bsh, (reg), (val)) + +CFATTACH_DECL_NEW(sunxi_a80_cpusclk, sizeof(struct sun9i_a80_cpusclk_softc), + sun9i_a80_cpusclk_match, sun9i_a80_cpusclk_attach, NULL, NULL); + +static int +sun9i_a80_cpusclk_match(device_t parent, cfdata_t cf, void *aux) +{ + const char * const compatible[] = { "allwinner,sun9i-a80-cpus-clk", NULL }; + const struct fdt_attach_args *faa = aux; + + return of_match_compatible(faa->faa_phandle, compatible); +} + +static void +sun9i_a80_cpusclk_attach(device_t parent, device_t self, void *aux) +{ + struct sun9i_a80_cpusclk_softc * const sc = device_private(self); + const struct fdt_attach_args *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_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; + } + + sc->sc_clkdom.funcs = &sun9i_a80_cpusclk_clk_funcs; + sc->sc_clkdom.priv = sc; + + sc->sc_clk.domain = &sc->sc_clkdom; + sc->sc_clk.name = kmem_asprintf("%s", faa->faa_name); + + aprint_naive("\n"); + aprint_normal(": A80 CPUS clock\n"); + + fdtbus_register_clock_controller(self, phandle, &sun9i_a80_cpusclk_fdt_funcs); +} + +static struct clk * +sun9i_a80_cpusclk_decode(device_t dev, int cc_phandle, const void *data, + size_t len) +{ + struct sun9i_a80_cpusclk_softc * const sc = device_private(dev); + + if (len != 0) + return NULL; + + return &sc->sc_clk; +} + +static struct clk * +sun9i_a80_cpusclk_get(void *priv, const char *name) +{ + struct sun9i_a80_cpusclk_softc * const sc = priv; + + if (strcmp(name, sc->sc_clk.name) != 0) + return NULL; + + return &sc->sc_clk; +} + +static void +sun9i_a80_cpusclk_put(void *priv, struct clk *clk) +{ +} + +static int +sun9i_a80_cpusclk_set_rate(void *priv, struct clk *clk, u_int rate) +{ + return ENXIO; +} + +static u_int +sun9i_a80_cpusclk_get_rate(void *priv, struct clk *clk) +{ + struct sun9i_a80_cpusclk_softc * const sc = priv; + struct clk *clk_parent = clk_get_parent(clk); + u_int rate; + + const uint32_t val = RD4(sc, 0); + const u_int sel = __SHIFTOUT(val, CPUS_CLK_SRC_SEL); + const u_int post_div = __SHIFTOUT(val, CPUS_POST_DIV); + const u_int clk_ratio = __SHIFTOUT(val, CPUS_CLK_RATIO); + + rate = clk_get_rate(clk_parent) / (clk_ratio + 1); + if (sel == CPUS_CLK_SRC_SEL_PLL_PERIPH0) + rate /= (post_div + 1); + + return rate; +} + +static struct clk * +sun9i_a80_cpusclk_get_parent(void *priv, struct clk *clk) +{ + struct sun9i_a80_cpusclk_softc * const sc = priv; + + const uint32_t val = RD4(sc, 0); + const u_int sel = __SHIFTOUT(val, CPUS_CLK_SRC_SEL); + + return fdtbus_clock_get_index(sc->sc_phandle, sel); +}