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 <[email protected]>
@@ -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 <[email protected]>
@@ -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 <[email protected]>
+ * 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 <[email protected]>
+ * 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);
+}