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 <m...@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
_______________________________________________
svn-src-all@freebsd.org mailing list
https://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "svn-src-all-unsubscr...@freebsd.org"

Reply via email to