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-head mailing list