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