svn commit: r296904 - in head/sys: conf dev/extres/clk
Michal Meloun
mmel at FreeBSD.org
Tue Mar 15 15:27:17 UTC 2016
Author: mmel
Date: Tue Mar 15 15:27:15 2016
New Revision: 296904
URL: https://svnweb.freebsd.org/changeset/base/296904
Log:
CLK: Add enumerator for 'clocks' OFW node. Add bus device bindings
for clk_fixed class.
Added:
head/sys/dev/extres/clk/clk_bus.c (contents, props changed)
Modified:
head/sys/conf/files
head/sys/dev/extres/clk/clk.c
head/sys/dev/extres/clk/clk.h
head/sys/dev/extres/clk/clk_fixed.c
Modified: head/sys/conf/files
==============================================================================
--- head/sys/conf/files Tue Mar 15 15:25:26 2016 (r296903)
+++ head/sys/conf/files Tue Mar 15 15:27:15 2016 (r296904)
@@ -1413,6 +1413,7 @@ dev/exca/exca.c optional cbb
dev/extres/clk/clk.c optional ext_resources clk
dev/extres/clk/clkdev_if.m optional ext_resources clk
dev/extres/clk/clknode_if.m optional ext_resources clk
+dev/extres/clk/clk_bus.c optional ext_resources clk fdt
dev/extres/clk/clk_div.c optional ext_resources clk
dev/extres/clk/clk_fixed.c optional ext_resources clk
dev/extres/clk/clk_gate.c optional ext_resources clk
Modified: head/sys/dev/extres/clk/clk.c
==============================================================================
--- head/sys/dev/extres/clk/clk.c Tue Mar 15 15:25:26 2016 (r296903)
+++ head/sys/dev/extres/clk/clk.c Tue Mar 15 15:27:15 2016 (r296904)
@@ -1258,4 +1258,75 @@ clk_get_by_ofw_name(device_t dev, const
return (rv);
return (clk_get_by_ofw_index(dev, idx, clk));
}
+
+/* --------------------------------------------------------------------------
+ *
+ * Support functions for parsing various clock related OFW things.
+ */
+
+/*
+ * Get "clock-output-names" and (optional) "clock-indices" lists.
+ * Both lists are alocated using M_OFWPROP specifier.
+ *
+ * Returns number of items or 0.
+ */
+int
+clk_parse_ofw_out_names(device_t dev, phandle_t node, const char ***out_names,
+ uint32_t *indices)
+{
+ int name_items, rv;
+
+ *out_names = NULL;
+ indices = NULL;
+ if (!OF_hasprop(node, "clock-output-names"))
+ return (0);
+ rv = ofw_bus_string_list_to_array(node, "clock-output-names",
+ out_names);
+ if (rv <= 0)
+ return (0);
+ name_items = rv;
+
+ if (!OF_hasprop(node, "clock-indices"))
+ return (name_items);
+ rv = OF_getencprop_alloc(node, "clock-indices", sizeof (uint32_t),
+ (void **)indices);
+ if (rv != name_items) {
+ device_printf(dev, " Size of 'clock-output-names' and "
+ "'clock-indices' differs\n");
+ free(*out_names, M_OFWPROP);
+ free(indices, M_OFWPROP);
+ return (0);
+ }
+ return (name_items);
+}
+
+/*
+ * Get output clock name for single output clock node.
+ */
+int
+clk_parse_ofw_clk_name(device_t dev, phandle_t node, const char **name)
+{
+ const char **out_names;
+ const char *tmp_name;
+ int rv;
+
+ *name = NULL;
+ if (!OF_hasprop(node, "clock-output-names")) {
+ tmp_name = ofw_bus_get_name(dev);
+ if (tmp_name == NULL)
+ return (ENXIO);
+ *name = strdup(tmp_name, M_OFWPROP);
+ return (0);
+ }
+ rv = ofw_bus_string_list_to_array(node, "clock-output-names",
+ &out_names);
+ if (rv != 1) {
+ free(out_names, M_OFWPROP);
+ device_printf(dev, "Malformed 'clock-output-names' property\n");
+ return (ENXIO);
+ }
+ *name = strdup(out_names[0], M_OFWPROP);
+ free(out_names, M_OFWPROP);
+ return (0);
+}
#endif
Modified: head/sys/dev/extres/clk/clk.h
==============================================================================
--- head/sys/dev/extres/clk/clk.h Tue Mar 15 15:25:26 2016 (r296903)
+++ head/sys/dev/extres/clk/clk.h Tue Mar 15 15:27:15 2016 (r296904)
@@ -131,6 +131,9 @@ const char *clk_get_name(clk_t clk);
#ifdef FDT
int clk_get_by_ofw_index(device_t dev, int idx, clk_t *clk);
int clk_get_by_ofw_name(device_t dev, const char *name, clk_t *clk);
+int clk_parse_ofw_out_names(device_t dev, phandle_t node,
+ const char ***out_names, uint32_t *indices);
+int clk_parse_ofw_clk_name(device_t dev, phandle_t node, const char **name);
#endif
#endif /* _DEV_EXTRES_CLK_H_ */
Added: head/sys/dev/extres/clk/clk_bus.c
==============================================================================
--- /dev/null 00:00:00 1970 (empty, because file is newly added)
+++ head/sys/dev/extres/clk/clk_bus.c Tue Mar 15 15:27:15 2016 (r296904)
@@ -0,0 +1,93 @@
+/*-
+ * Copyright 2016 Michal Meloun <mmel at FreeBSD.org>
+ * 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 AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/module.h>
+#include <sys/bus.h>
+
+#include <dev/fdt/simplebus.h>
+
+#include <dev/ofw/openfirm.h>
+#include <dev/ofw/ofw_bus_subr.h>
+
+struct ofw_clkbus_softc {
+ struct simplebus_softc simplebus_sc;
+};
+
+static int
+ofw_clkbus_probe(device_t dev)
+{
+ const char *name;
+
+ name = ofw_bus_get_name(dev);
+
+ if (name == NULL || strcmp(name, "clocks") != 0)
+ return (ENXIO);
+
+ device_set_desc(dev, "OFW clocks bus");
+
+ return (0);
+}
+
+static int
+ofw_clkbus_attach(device_t dev)
+{
+ struct ofw_clkbus_softc *sc;
+ phandle_t node, child;
+ device_t cdev;
+
+ sc = device_get_softc(dev);
+ node = ofw_bus_get_node(dev);
+ simplebus_init(dev, node);
+
+ for (child = OF_child(node); child > 0; child = OF_peer(child)) {
+ cdev = simplebus_add_device(dev, child, 0, NULL, -1, NULL);
+ if (cdev != NULL)
+ device_probe_and_attach(cdev);
+ }
+
+ return (bus_generic_attach(dev));
+}
+
+static device_method_t ofw_clkbus_methods[] = {
+ /* Device interface */
+ DEVMETHOD(device_probe, ofw_clkbus_probe),
+ DEVMETHOD(device_attach, ofw_clkbus_attach),
+
+ DEVMETHOD_END
+};
+
+DEFINE_CLASS_1(ofw_clkbus, ofw_clkbus_driver, ofw_clkbus_methods,
+ sizeof(struct ofw_clkbus_softc), simplebus_driver);
+static devclass_t ofw_clkbus_devclass;
+EARLY_DRIVER_MODULE(ofw_clkbus, simplebus, ofw_clkbus_driver,
+ ofw_clkbus_devclass, 0, 0, BUS_PASS_BUS + BUS_PASS_ORDER_MIDDLE);
+MODULE_VERSION(ofw_clkbus, 1);
Modified: head/sys/dev/extres/clk/clk_fixed.c
==============================================================================
--- head/sys/dev/extres/clk/clk_fixed.c Tue Mar 15 15:25:26 2016 (r296903)
+++ head/sys/dev/extres/clk/clk_fixed.c Tue Mar 15 15:27:15 2016 (r296904)
@@ -27,7 +27,6 @@
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
-
#include <sys/param.h>
#include <sys/conf.h>
#include <sys/bus.h>
@@ -35,15 +34,24 @@ __FBSDID("$FreeBSD$");
#include <sys/kobj.h>
#include <sys/malloc.h>
#include <sys/mutex.h>
+#include <sys/module.h>
#include <sys/rman.h>
#include <sys/systm.h>
#include <machine/bus.h>
+#include <dev/ofw/ofw_bus.h>
+#include <dev/ofw/ofw_bus_subr.h>
#include <dev/extres/clk/clk_fixed.h>
+#define CLK_TYPE_FIXED 1
+#define CLK_TYPE_FIXED_FACTOR 2
+
static int clknode_fixed_init(struct clknode *clk, device_t dev);
static int clknode_fixed_recalc(struct clknode *clk, uint64_t *freq);
+static int clknode_fixed_set_freq(struct clknode *clk, uint64_t fin,
+ uint64_t *fout, int flags, int *stop);
+
struct clknode_fixed_sc {
int fixed_flags;
uint64_t freq;
@@ -55,6 +63,7 @@ static clknode_method_t clknode_fixed_me
/* Device interface */
CLKNODEMETHOD(clknode_init, clknode_fixed_init),
CLKNODEMETHOD(clknode_recalc_freq, clknode_fixed_recalc),
+ CLKNODEMETHOD(clknode_set_freq, clknode_fixed_set_freq),
CLKNODEMETHOD_END
};
DEFINE_CLASS_1(clknode_fixed, clknode_fixed_class, clknode_fixed_methods,
@@ -77,12 +86,31 @@ clknode_fixed_recalc(struct clknode *clk
struct clknode_fixed_sc *sc;
sc = clknode_get_softc(clk);
- if (sc->freq != 0)
- *freq = sc->freq;
- else if ((sc->mult != 0) && (sc->div != 0))
+
+ if ((sc->mult != 0) && (sc->div != 0))
*freq = (*freq / sc->div) * sc->mult;
else
- *freq = 0;
+ *freq = sc->freq;
+ return (0);
+}
+
+static int
+clknode_fixed_set_freq(struct clknode *clk, uint64_t fin, uint64_t *fout,
+ int flags, int *stop)
+{
+ struct clknode_fixed_sc *sc;
+
+ sc = clknode_get_softc(clk);
+ if (sc->mult == 0 || sc->div == 0) {
+ /* Fixed frequency clock. */
+ *stop = 1;
+ if (*fout != sc->freq)
+ return (ERANGE);
+ return (0);
+ }
+ /* Fixed factor clock. */
+ *stop = 0;
+ *fout = (*fout / sc->mult) * sc->div;
return (0);
}
@@ -92,8 +120,6 @@ clknode_fixed_register(struct clkdom *cl
struct clknode *clk;
struct clknode_fixed_sc *sc;
- if ((clkdef->freq == 0) && (clkdef->clkdef.parent_cnt == 0))
- panic("fixed clk: Frequency is not defined for clock source");
clk = clknode_create(clkdom, &clknode_fixed_class, &clkdef->clkdef);
if (clk == NULL)
return (1);
@@ -107,3 +133,143 @@ clknode_fixed_register(struct clkdom *cl
clknode_register(clkdom, clk);
return (0);
}
+
+#ifdef FDT
+
+static struct ofw_compat_data compat_data[] = {
+ {"fixed-clock", CLK_TYPE_FIXED},
+ {"fixed-factor-clock", CLK_TYPE_FIXED_FACTOR},
+ {NULL, 0},
+};
+
+struct clk_fixed_softc {
+ device_t dev;
+ struct clkdom *clkdom;
+};
+
+static int
+clk_fixed_probe(device_t dev)
+{
+
+ if (ofw_bus_search_compatible(dev, compat_data)->ocd_data != 0) {
+ device_set_desc(dev, "Fixed clock");
+ return (BUS_PROBE_DEFAULT);
+ }
+ return (ENXIO);
+}
+
+static int
+clk_fixed_init_fixed(struct clk_fixed_softc *sc, phandle_t node,
+ struct clk_fixed_def *def)
+{
+ uint32_t freq;
+ int rv;
+
+ def->clkdef.id = 1;
+ rv = OF_getencprop(node, "clock-frequency", &freq, sizeof(freq));
+ if (rv <= 0)
+ return (ENXIO);
+ def->freq = freq;
+ return (0);
+}
+
+static int
+clk_fixed_init_fixed_factor(struct clk_fixed_softc *sc, phandle_t node,
+ struct clk_fixed_def *def)
+{
+ int rv;
+ clk_t parent;
+
+ def->clkdef.id = 1;
+ rv = OF_getencprop(node, "clock-mult", &def->mult, sizeof(def->mult));
+ if (rv <= 0)
+ return (ENXIO);
+ rv = OF_getencprop(node, "clock-div", &def->mult, sizeof(def->div));
+ if (rv <= 0)
+ return (ENXIO);
+ /* Get name of parent clock */
+ rv = clk_get_by_ofw_name(sc->dev, "clocks", &parent);
+ if (rv != 0)
+ return (ENXIO);
+ def->clkdef.parent_names = malloc(sizeof(char *), M_OFWPROP, M_WAITOK);
+ def->clkdef.parent_names[0] = clk_get_name(parent);
+ def->clkdef.parent_cnt = 1;
+ clk_release(parent);
+ return (0);
+}
+
+static int
+clk_fixed_attach(device_t dev)
+{
+ struct clk_fixed_softc *sc;
+ intptr_t clk_type;
+ phandle_t node;
+ struct clk_fixed_def def;
+ int rv;
+
+ sc = device_get_softc(dev);
+ sc->dev = dev;
+ node = ofw_bus_get_node(dev);
+ clk_type = ofw_bus_search_compatible(dev, compat_data)->ocd_data;
+
+ bzero(&def, sizeof(def));
+ if (clk_type == CLK_TYPE_FIXED)
+ rv = clk_fixed_init_fixed(sc, node, &def);
+ else if (clk_type == CLK_TYPE_FIXED_FACTOR)
+ rv = clk_fixed_init_fixed_factor(sc, node, &def);
+ else
+ rv = ENXIO;
+ if (rv != 0) {
+ device_printf(sc->dev, "Cannot FDT parameters.\n");
+ goto fail;
+ }
+ rv = clk_parse_ofw_clk_name(dev, node, &def.clkdef.name);
+ if (rv != 0) {
+ device_printf(sc->dev, "Cannot parse clock name.\n");
+ goto fail;
+ }
+ sc->clkdom = clkdom_create(dev);
+ KASSERT(sc->clkdom != NULL, ("Clock domain is NULL"));
+
+ rv = clknode_fixed_register(sc->clkdom, &def);
+ if (rv != 0) {
+ device_printf(sc->dev, "Cannot register fixed clock.\n");
+ rv = ENXIO;
+ goto fail;
+ }
+
+ rv = clkdom_finit(sc->clkdom);
+ if (rv != 0) {
+ device_printf(sc->dev, "Clk domain finit fails.\n");
+ rv = ENXIO;
+ goto fail;
+ }
+#ifdef CLK_DEBUG
+ clkdom_dump(sc->clkdom);
+#endif
+ free(__DECONST(char *, def.clkdef.name), M_OFWPROP);
+ free(def.clkdef.parent_names, M_OFWPROP);
+ return (bus_generic_attach(dev));
+
+fail:
+ free(__DECONST(char *, def.clkdef.name), M_OFWPROP);
+ free(def.clkdef.parent_names, M_OFWPROP);
+ return (rv);
+}
+
+static device_method_t clk_fixed_methods[] = {
+ /* Device interface */
+ DEVMETHOD(device_probe, clk_fixed_probe),
+ DEVMETHOD(device_attach, clk_fixed_attach),
+
+ DEVMETHOD_END
+};
+
+DEFINE_CLASS_0(clk_fixed, clk_fixed_driver, clk_fixed_methods,
+ sizeof(struct clk_fixed_softc));
+static devclass_t clk_fixed_devclass;
+EARLY_DRIVER_MODULE(clk_fixed, simplebus, clk_fixed_driver,
+ clk_fixed_devclass, 0, 0, BUS_PASS_BUS + BUS_PASS_ORDER_MIDDLE);
+MODULE_VERSION(clk_fixed, 1);
+
+#endif
More information about the svn-src-all
mailing list