svn commit: r309894 - head/sys/dev/extres/clk
Emmanuel Vadot
manu at FreeBSD.org
Mon Dec 12 16:43:32 UTC 2016
Author: manu
Date: Mon Dec 12 16:43:31 2016
New Revision: 309894
URL: https://svnweb.freebsd.org/changeset/base/309894
Log:
clk_div: Add a div lookup table
Some clocks on SoC have a diff between the value written in the register
and the real divider.
Add a table that where we can lookup the real value of the divider.
Reviewed by: mmel (earlier revision)
Differential Revision: https://reviews.freebsd.org/D8728
Modified:
head/sys/dev/extres/clk/clk_div.c
head/sys/dev/extres/clk/clk_div.h
Modified: head/sys/dev/extres/clk/clk_div.c
==============================================================================
--- head/sys/dev/extres/clk/clk_div.c Mon Dec 12 15:37:11 2016 (r309893)
+++ head/sys/dev/extres/clk/clk_div.c Mon Dec 12 16:43:31 2016 (r309894)
@@ -68,6 +68,8 @@ struct clknode_div_sc {
uint32_t f_width;
int div_flags;
uint32_t divider; /* in natural form */
+
+ struct clk_div_table *div_table;
};
static clknode_method_t clknode_div_methods[] = {
@@ -80,6 +82,36 @@ static clknode_method_t clknode_div_meth
DEFINE_CLASS_1(clknode_div, clknode_div_class, clknode_div_methods,
sizeof(struct clknode_div_sc), clknode_class);
+static uint32_t
+clknode_div_table_get_divider(struct clknode_div_sc *sc, uint32_t divider)
+{
+ struct clk_div_table *table;
+
+ if (!(sc->div_flags & CLK_DIV_WITH_TABLE))
+ return (divider);
+
+ for (table = sc->div_table; table->divider != 0; table++)
+ if (table->value == sc->divider)
+ return (table->divider);
+
+ return (0);
+}
+
+static uint32_t
+clknode_div_table_get_value(struct clknode_div_sc *sc, uint32_t divider)
+{
+ struct clk_div_table *table;
+
+ if (!(sc->div_flags & CLK_DIV_WITH_TABLE))
+ return (divider);
+
+ for (table = sc->div_table; table->divider != 0; table++)
+ if (table->divider == sc->divider)
+ return (table->value);
+
+ return (0);
+}
+
static int
clknode_div_init(struct clknode *clk, device_t dev)
{
@@ -101,6 +133,11 @@ clknode_div_init(struct clknode *clk, de
i_div++;
f_div = (reg >> sc->f_shift) & sc->f_mask;
sc->divider = i_div << sc->f_width | f_div;
+
+ sc->divider = clknode_div_table_get_divider(sc, sc->divider);
+ if (sc->divider == 0)
+ panic("%s: divider is zero!\n", clknode_get_name(clk));
+
clknode_init_parent_idx(clk, 0);
return(0);
}
@@ -177,6 +214,10 @@ clknode_div_set_freq(struct clknode *clk
(*fout != (_fin / divider)))
return (ERANGE);
+ divider = clknode_div_table_get_value(sc, divider);
+ if (divider == 0)
+ return (ERANGE);
+
DEVICE_LOCK(clk);
rv = MD4(clk, sc->offset,
(sc->i_mask << sc->i_shift) | (sc->f_mask << sc->f_shift),
@@ -214,6 +255,7 @@ clknode_div_register(struct clkdom *clkd
sc->f_width = clkdef->f_width;
sc->f_mask = (1 << clkdef->f_width) - 1;
sc->div_flags = clkdef->div_flags;
+ sc->div_table = clkdef->div_table;
clknode_register(clkdom, clk);
return (0);
Modified: head/sys/dev/extres/clk/clk_div.h
==============================================================================
--- head/sys/dev/extres/clk/clk_div.h Mon Dec 12 15:37:11 2016 (r309893)
+++ head/sys/dev/extres/clk/clk_div.h Mon Dec 12 16:43:31 2016 (r309894)
@@ -32,6 +32,12 @@
#include <dev/extres/clk/clk.h>
#define CLK_DIV_ZERO_BASED 0x0001 /* Zero based divider. */
+#define CLK_DIV_WITH_TABLE 0x0002 /* Table to lookup the real value */
+
+struct clk_div_table {
+ uint32_t value;
+ uint32_t divider;
+};
struct clk_div_def {
struct clknode_init_def clkdef;
@@ -41,6 +47,7 @@ struct clk_div_def {
uint32_t f_shift; /* Fractional divide bits, */
uint32_t f_width; /* set to 0 for int divider */
int div_flags; /* Divider-specific flags */
+ struct clk_div_table *div_table; /* Divider table */
};
int clknode_div_register(struct clkdom *clkdom, struct clk_div_def *clkdef);
More information about the svn-src-all
mailing list