Date: Tue, 15 Mar 2016 15:27:16 +0000 (UTC) From: Michal Meloun <mmel@FreeBSD.org> To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: svn commit: r296904 - in head/sys: conf dev/extres/clk Message-ID: <201603151527.u2FFRGA7071468@repo.freebsd.org>
next in thread | raw e-mail | index | archive | help
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@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
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201603151527.u2FFRGA7071468>