Module Name: src Committed By: jmcneill Date: Tue Dec 22 21:42:11 UTC 2015
Modified Files: src/sys/dev/fdt: fdt_subr.c fdtvar.h files.fdt Added Files: src/sys/dev/fdt: fdt_clock.c fdt_reset.c Log Message: Add support for fdt clock and reset controllers. To generate a diff of this commit: cvs rdiff -u -r0 -r1.1 src/sys/dev/fdt/fdt_clock.c \ src/sys/dev/fdt/fdt_reset.c cvs rdiff -u -r1.4 -r1.5 src/sys/dev/fdt/fdt_subr.c src/sys/dev/fdt/files.fdt cvs rdiff -u -r1.2 -r1.3 src/sys/dev/fdt/fdtvar.h Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.
Modified files: Index: src/sys/dev/fdt/fdt_subr.c diff -u src/sys/dev/fdt/fdt_subr.c:1.4 src/sys/dev/fdt/fdt_subr.c:1.5 --- src/sys/dev/fdt/fdt_subr.c:1.4 Wed Dec 16 19:33:55 2015 +++ src/sys/dev/fdt/fdt_subr.c Tue Dec 22 21:42:11 2015 @@ -1,4 +1,4 @@ -/* $NetBSD: fdt_subr.c,v 1.4 2015/12/16 19:33:55 jmcneill Exp $ */ +/* $NetBSD: fdt_subr.c,v 1.5 2015/12/22 21:42:11 jmcneill Exp $ */ /*- * Copyright (c) 2015 Jared D. McNeill <jmcne...@invisible.ca> @@ -27,7 +27,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: fdt_subr.c,v 1.4 2015/12/16 19:33:55 jmcneill Exp $"); +__KERNEL_RCSID(0, "$NetBSD: fdt_subr.c,v 1.5 2015/12/22 21:42:11 jmcneill Exp $"); #include <sys/param.h> #include <sys/bus.h> @@ -130,11 +130,16 @@ fdtbus_get_phandle(int phandle, const ch phandle_ref = fdt32_to_cpu(buf[0]); kmem_free(buf, len); - const int off = fdt_node_offset_by_phandle(fdt_data, phandle_ref); + return fdtbus_get_phandle_from_native(phandle_ref); +} + +int +fdtbus_get_phandle_from_native(int phandle) +{ + const int off = fdt_node_offset_by_phandle(fdt_data, phandle); if (off < 0) { return -1; } - return fdtbus_offset2phandle(off); } Index: src/sys/dev/fdt/files.fdt diff -u src/sys/dev/fdt/files.fdt:1.4 src/sys/dev/fdt/files.fdt:1.5 --- src/sys/dev/fdt/files.fdt:1.4 Wed Dec 16 12:22:48 2015 +++ src/sys/dev/fdt/files.fdt Tue Dec 22 21:42:11 2015 @@ -1,4 +1,4 @@ -# $NetBSD: files.fdt,v 1.4 2015/12/16 12:22:48 jmcneill Exp $ +# $NetBSD: files.fdt,v 1.5 2015/12/22 21:42:11 jmcneill Exp $ include "external/bsd/libfdt/conf/files.libfdt" @@ -24,7 +24,9 @@ file dev/fdt/gpiokeys.c gpiokeys file dev/fdt/fdt_openfirm.c fdtbus file dev/fdt/fdt_subr.c fdtbus +file dev/fdt/fdt_clock.c fdtbus file dev/fdt/fdt_gpio.c fdtbus file dev/fdt/fdt_i2c.c fdtbus file dev/fdt/fdt_intr.c fdtbus file dev/fdt/fdt_regulator.c fdtbus +file dev/fdt/fdt_reset.c fdtbus Index: src/sys/dev/fdt/fdtvar.h diff -u src/sys/dev/fdt/fdtvar.h:1.2 src/sys/dev/fdt/fdtvar.h:1.3 --- src/sys/dev/fdt/fdtvar.h:1.2 Wed Dec 16 12:17:45 2015 +++ src/sys/dev/fdt/fdtvar.h Tue Dec 22 21:42:11 2015 @@ -1,4 +1,4 @@ -/* $NetBSD: fdtvar.h,v 1.2 2015/12/16 12:17:45 jmcneill Exp $ */ +/* $NetBSD: fdtvar.h,v 1.3 2015/12/22 21:42:11 jmcneill Exp $ */ /*- * Copyright (c) 2015 Jared D. McNeill <jmcne...@invisible.ca> @@ -33,6 +33,7 @@ #include <sys/bus.h> #include <dev/i2c/i2cvar.h> +#include <dev/clk/clk.h> #include <dev/ofw/openfirm.h> @@ -87,6 +88,24 @@ struct fdtbus_regulator_controller_func int (*enable)(device_t, bool); }; +struct fdtbus_clock_controller_func { + struct clk * (*decode)(device_t, const void *, size_t); +}; + +struct fdtbus_reset_controller; + +struct fdtbus_reset { + struct fdtbus_reset_controller *rst_rc; + void *rst_priv; +}; + +struct fdtbus_reset_controller_func { + void * (*acquire)(device_t, const void *, size_t); + void (*release)(device_t, void *); + int (*reset_assert)(device_t, void *); + int (*reset_deassert)(device_t, void *); +}; + int fdtbus_register_interrupt_controller(device_t, int, const struct fdtbus_interrupt_controller_func *); int fdtbus_register_i2c_controller(device_t, int, @@ -95,9 +114,14 @@ int fdtbus_register_gpio_controller(dev const struct fdtbus_gpio_controller_func *); int fdtbus_register_regulator_controller(device_t, int, const struct fdtbus_regulator_controller_func *); +int fdtbus_register_clock_controller(device_t, int, + const struct fdtbus_clock_controller_func *); +int fdtbus_register_reset_controller(device_t, int, + const struct fdtbus_reset_controller_func *); int fdtbus_get_reg(int, u_int, bus_addr_t *, bus_size_t *); int fdtbus_get_phandle(int, const char *); +int fdtbus_get_phandle_from_native(int); i2c_tag_t fdtbus_get_i2c_tag(int); void * fdtbus_intr_establish(int, u_int, int, int, int (*func)(void *), void *arg); @@ -112,6 +136,15 @@ void fdtbus_regulator_release(struct fd int fdtbus_regulator_enable(struct fdtbus_regulator *); int fdtbus_regulator_disable(struct fdtbus_regulator *); +struct clk * fdtbus_clock_get(int, const char *); +struct clk * fdtbus_clock_get_index(int, u_int); + +struct fdtbus_reset *fdtbus_reset_get(int, const char *); +struct fdtbus_reset *fdtbus_reset_get_index(int, u_int); +void fdtbus_reset_put(struct fdtbus_reset *); +int fdtbus_reset_assert(struct fdtbus_reset *); +int fdtbus_reset_deassert(struct fdtbus_reset *); + bool fdtbus_set_data(const void *); const void * fdtbus_get_data(void); int fdtbus_phandle2offset(int); Added files: Index: src/sys/dev/fdt/fdt_clock.c diff -u /dev/null src/sys/dev/fdt/fdt_clock.c:1.1 --- /dev/null Tue Dec 22 21:42:11 2015 +++ src/sys/dev/fdt/fdt_clock.c Tue Dec 22 21:42:11 2015 @@ -0,0 +1,158 @@ +/* $NetBSD: fdt_clock.c,v 1.1 2015/12/22 21:42:11 jmcneill Exp $ */ + +/*- + * Copyright (c) 2015 Jared D. 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: fdt_clock.c,v 1.1 2015/12/22 21:42:11 jmcneill Exp $"); + +#include <sys/param.h> +#include <sys/bus.h> +#include <sys/kmem.h> + +#include <libfdt.h> +#include <dev/fdt/fdtvar.h> + +struct fdtbus_clock_controller { + device_t cc_dev; + int cc_phandle; + const struct fdtbus_clock_controller_func *cc_funcs; + + struct fdtbus_clock_controller *cc_next; +}; + +static struct fdtbus_clock_controller *fdtbus_cc = NULL; + +int +fdtbus_register_clock_controller(device_t dev, int phandle, + const struct fdtbus_clock_controller_func *funcs) +{ + struct fdtbus_clock_controller *cc; + + cc = kmem_alloc(sizeof(*cc), KM_SLEEP); + cc->cc_dev = dev; + cc->cc_phandle = phandle; + cc->cc_funcs = funcs; + + cc->cc_next = fdtbus_cc; + fdtbus_cc = cc; + + return 0; +} + +static struct fdtbus_clock_controller * +fdtbus_get_clock_controller(int phandle) +{ + struct fdtbus_clock_controller *cc; + + for (cc = fdtbus_cc; cc; cc = cc->cc_next) { + if (cc->cc_phandle == phandle) { + return cc; + } + } + + return NULL; +} + +struct clk * +fdtbus_clock_get_index(int phandle, u_int index) +{ + struct fdtbus_clock_controller *cc; + struct clk *clk = NULL; + uint32_t *clocks = NULL; + uint32_t *p; + u_int n, clock_cells; + int len, resid; + + len = OF_getproplen(phandle, "clocks"); + if (len <= 0) + return NULL; + + clocks = kmem_alloc(len, KM_SLEEP); + if (OF_getprop(phandle, "clocks", clocks, len) != len) { + kmem_free(clocks, len); + return NULL; + } + + p = clocks; + for (n = 0, resid = len; resid > 0; n++) { + const int cc_phandle = + fdtbus_get_phandle_from_native(be32toh(p[0])); + if (of_getprop_uint32(cc_phandle, "#clock-cells", &clock_cells)) + break; + if (n == index) { + cc = fdtbus_get_clock_controller(cc_phandle); + if (cc == NULL) + goto done; + clk = cc->cc_funcs->decode(cc->cc_dev, + clock_cells > 0 ? &p[1] : NULL, clock_cells * 4); + break; + } + resid -= (clock_cells + 1) * 4; + p += clock_cells + 1; + } + +done: + if (clocks) + kmem_free(clocks, len); + + return clk; +} + +struct clk * +fdtbus_clock_get(int phandle, const char *clkname) +{ + struct clk *clk = NULL; + char *clock_names = NULL; + const char *p; + u_int index; + int len, resid; + + len = OF_getproplen(phandle, "clock-names"); + if (len <= 0) + return NULL; + + clock_names = kmem_alloc(len, KM_SLEEP); + if (OF_getprop(phandle, "clock-names", clock_names, len) != len) { + kmem_free(clock_names, len); + return NULL; + } + + p = clock_names; + for (index = 0, resid = len; resid > 0; index++) { + if (strcmp(p, clkname) == 0) { + clk = fdtbus_clock_get_index(phandle, index); + break; + } + resid -= strlen(p); + p += strlen(p) + 1; + } + + if (clock_names) + kmem_free(clock_names, len); + + return clk; +} Index: src/sys/dev/fdt/fdt_reset.c diff -u /dev/null src/sys/dev/fdt/fdt_reset.c:1.1 --- /dev/null Tue Dec 22 21:42:11 2015 +++ src/sys/dev/fdt/fdt_reset.c Tue Dec 22 21:42:11 2015 @@ -0,0 +1,189 @@ +/* $NetBSD: fdt_reset.c,v 1.1 2015/12/22 21:42:11 jmcneill Exp $ */ + +/*- + * Copyright (c) 2015 Jared D. 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: fdt_reset.c,v 1.1 2015/12/22 21:42:11 jmcneill Exp $"); + +#include <sys/param.h> +#include <sys/bus.h> +#include <sys/kmem.h> + +#include <libfdt.h> +#include <dev/fdt/fdtvar.h> + +struct fdtbus_reset_controller { + device_t rc_dev; + int rc_phandle; + const struct fdtbus_reset_controller_func *rc_funcs; + + struct fdtbus_reset_controller *rc_next; +}; + +static struct fdtbus_reset_controller *fdtbus_rc = NULL; + +int +fdtbus_register_reset_controller(device_t dev, int phandle, + const struct fdtbus_reset_controller_func *funcs) +{ + struct fdtbus_reset_controller *rc; + + rc = kmem_alloc(sizeof(*rc), KM_SLEEP); + rc->rc_dev = dev; + rc->rc_phandle = phandle; + rc->rc_funcs = funcs; + + rc->rc_next = fdtbus_rc; + fdtbus_rc = rc; + + return 0; +} + +static struct fdtbus_reset_controller * +fdtbus_get_reset_controller(int phandle) +{ + struct fdtbus_reset_controller *rc; + + for (rc = fdtbus_rc; rc; rc = rc->rc_next) { + if (rc->rc_phandle == phandle) { + return rc; + } + } + + return NULL; +} + +struct fdtbus_reset * +fdtbus_reset_get_index(int phandle, u_int index) +{ + struct fdtbus_reset_controller *rc; + struct fdtbus_reset *rst = NULL; + void *rst_priv = NULL; + uint32_t *resets = NULL; + uint32_t *p; + u_int n, reset_cells; + int len, resid; + + len = OF_getproplen(phandle, "resets"); + if (len <= 0) + return NULL; + + resets = kmem_alloc(len, KM_SLEEP); + if (OF_getprop(phandle, "resets", resets, len) != len) { + kmem_free(resets, len); + return NULL; + } + + p = resets; + for (n = 0, resid = len; resid > 0; n++) { + const int rc_phandle = + fdtbus_get_phandle_from_native(be32toh(p[0])); + if (of_getprop_uint32(rc_phandle, "#reset-cells", &reset_cells)) + break; + if (n == index) { + rc = fdtbus_get_reset_controller(rc_phandle); + if (rc == NULL) + goto done; + rst_priv = rc->rc_funcs->acquire(rc->rc_dev, + reset_cells > 0 ? &p[1] : NULL, reset_cells * 4); + if (rst_priv) { + rst = kmem_alloc(sizeof(*rst), KM_SLEEP); + rst->rst_rc = rc; + rst->rst_priv = rst_priv; + } + break; + } + resid -= (reset_cells + 1) * 4; + p += reset_cells + 1; + } + +done: + if (resets) + kmem_free(resets, len); + + return rst; +} + +struct fdtbus_reset * +fdtbus_reset_get(int phandle, const char *rstname) +{ + struct fdtbus_reset *rst = NULL; + char *reset_names = NULL; + const char *p; + u_int index; + int len, resid; + + len = OF_getproplen(phandle, "reset-names"); + if (len <= 0) + return NULL; + + reset_names = kmem_alloc(len, KM_SLEEP); + if (OF_getprop(phandle, "reset-names", reset_names, len) != len) { + kmem_free(reset_names, len); + return NULL; + } + + p = reset_names; + for (index = 0, resid = len; resid > 0; index++) { + if (strcmp(p, rstname) == 0) { + rst = fdtbus_reset_get_index(phandle, index); + break; + } + resid -= strlen(p); + p += strlen(p) + 1; + } + + if (reset_names) + kmem_free(reset_names, len); + + return rst; +} + +void +fdtbus_reset_put(struct fdtbus_reset *rst) +{ + struct fdtbus_reset_controller *rc = rst->rst_rc; + + rc->rc_funcs->release(rc->rc_dev, rst->rst_priv); + kmem_free(rst, sizeof(*rst)); +} + +int +fdtbus_reset_assert(struct fdtbus_reset *rst) +{ + struct fdtbus_reset_controller *rc = rst->rst_rc; + + return rc->rc_funcs->reset_assert(rc->rc_dev, rst->rst_priv); +} + +int +fdtbus_reset_deassert(struct fdtbus_reset *rst) +{ + struct fdtbus_reset_controller *rc = rst->rst_rc; + + return rc->rc_funcs->reset_deassert(rc->rc_dev, rst->rst_priv); +}