Re: [PATCH v3 3/4] clk: rockchip: add support for half divider

2018-07-06 Thread Stephen Boyd
Quoting Heiko Stuebner (2018-07-06 10:19:11)
> Am Freitag, 6. Juli 2018, 18:50:51 CEST schrieb Stephen Boyd:
> > Quoting Elaine Zhang (2018-06-14 19:16:50)
> > > 
> > > diff --git a/drivers/clk/rockchip/clk-half-divider.c 
> > > b/drivers/clk/rockchip/clk-half-divider.c
> > > new file mode 100644
> > > index ..fb7a6501e0c1
> > > --- /dev/null
> > > +++ b/drivers/clk/rockchip/clk-half-divider.c
> > > @@ -0,0 +1,230 @@
> > > +// SPDX-License-Identifier: GPL-2.0
> > > +/*
> > > + * Copyright (c) 2018 Fuzhou Rockchip Electronics Co., Ltd
> > > + */
> > > +
> > > +#include 
> > > +#include 
> > > +#include 
> > > +#include 
> > 
> > Is this include used?
> 
> nope, and so are bitops and regmap as well.
> I've amended the commit patch accordingly.
> 
> 

Cool. Thanks!


Re: [PATCH v3 3/4] clk: rockchip: add support for half divider

2018-07-06 Thread Stephen Boyd
Quoting Heiko Stuebner (2018-07-06 10:19:11)
> Am Freitag, 6. Juli 2018, 18:50:51 CEST schrieb Stephen Boyd:
> > Quoting Elaine Zhang (2018-06-14 19:16:50)
> > > 
> > > diff --git a/drivers/clk/rockchip/clk-half-divider.c 
> > > b/drivers/clk/rockchip/clk-half-divider.c
> > > new file mode 100644
> > > index ..fb7a6501e0c1
> > > --- /dev/null
> > > +++ b/drivers/clk/rockchip/clk-half-divider.c
> > > @@ -0,0 +1,230 @@
> > > +// SPDX-License-Identifier: GPL-2.0
> > > +/*
> > > + * Copyright (c) 2018 Fuzhou Rockchip Electronics Co., Ltd
> > > + */
> > > +
> > > +#include 
> > > +#include 
> > > +#include 
> > > +#include 
> > 
> > Is this include used?
> 
> nope, and so are bitops and regmap as well.
> I've amended the commit patch accordingly.
> 
> 

Cool. Thanks!


Re: [PATCH v3 3/4] clk: rockchip: add support for half divider

2018-07-06 Thread Heiko Stuebner
Am Freitag, 6. Juli 2018, 18:50:51 CEST schrieb Stephen Boyd:
> Quoting Elaine Zhang (2018-06-14 19:16:50)
> > 
> > diff --git a/drivers/clk/rockchip/clk-half-divider.c 
> > b/drivers/clk/rockchip/clk-half-divider.c
> > new file mode 100644
> > index ..fb7a6501e0c1
> > --- /dev/null
> > +++ b/drivers/clk/rockchip/clk-half-divider.c
> > @@ -0,0 +1,230 @@
> > +// SPDX-License-Identifier: GPL-2.0
> > +/*
> > + * Copyright (c) 2018 Fuzhou Rockchip Electronics Co., Ltd
> > + */
> > +
> > +#include 
> > +#include 
> > +#include 
> > +#include 
> 
> Is this include used?

nope, and so are bitops and regmap as well.
I've amended the commit patch accordingly.


Heiko




Re: [PATCH v3 3/4] clk: rockchip: add support for half divider

2018-07-06 Thread Heiko Stuebner
Am Freitag, 6. Juli 2018, 18:50:51 CEST schrieb Stephen Boyd:
> Quoting Elaine Zhang (2018-06-14 19:16:50)
> > 
> > diff --git a/drivers/clk/rockchip/clk-half-divider.c 
> > b/drivers/clk/rockchip/clk-half-divider.c
> > new file mode 100644
> > index ..fb7a6501e0c1
> > --- /dev/null
> > +++ b/drivers/clk/rockchip/clk-half-divider.c
> > @@ -0,0 +1,230 @@
> > +// SPDX-License-Identifier: GPL-2.0
> > +/*
> > + * Copyright (c) 2018 Fuzhou Rockchip Electronics Co., Ltd
> > + */
> > +
> > +#include 
> > +#include 
> > +#include 
> > +#include 
> 
> Is this include used?

nope, and so are bitops and regmap as well.
I've amended the commit patch accordingly.


Heiko




Re: [PATCH v3 3/4] clk: rockchip: add support for half divider

2018-07-06 Thread Stephen Boyd
Quoting Elaine Zhang (2018-06-14 19:16:50)
> 
> diff --git a/drivers/clk/rockchip/clk-half-divider.c 
> b/drivers/clk/rockchip/clk-half-divider.c
> new file mode 100644
> index ..fb7a6501e0c1
> --- /dev/null
> +++ b/drivers/clk/rockchip/clk-half-divider.c
> @@ -0,0 +1,230 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * Copyright (c) 2018 Fuzhou Rockchip Electronics Co., Ltd
> + */
> +
> +#include 
> +#include 
> +#include 
> +#include 

Is this include used?

> +#include 
> +#include "clk.h"


Re: [PATCH v3 3/4] clk: rockchip: add support for half divider

2018-07-06 Thread Stephen Boyd
Quoting Elaine Zhang (2018-06-14 19:16:50)
> 
> diff --git a/drivers/clk/rockchip/clk-half-divider.c 
> b/drivers/clk/rockchip/clk-half-divider.c
> new file mode 100644
> index ..fb7a6501e0c1
> --- /dev/null
> +++ b/drivers/clk/rockchip/clk-half-divider.c
> @@ -0,0 +1,230 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * Copyright (c) 2018 Fuzhou Rockchip Electronics Co., Ltd
> + */
> +
> +#include 
> +#include 
> +#include 
> +#include 

Is this include used?

> +#include 
> +#include "clk.h"


[PATCH v3 3/4] clk: rockchip: add support for half divider

2018-06-14 Thread Elaine Zhang
The new Rockchip socs have optional half divider:
The formula is shown as:
freq_out = 2*freq_in / (2*div + 3)
Is this the same for all of new SoCs.

So we use "branch_half_divider" + "COMPOSITE_NOMUX_HALFDIV \
DIV_HALF \ COMPOSITE_HALFDIV \ CMPOSITE_NOGATE_HALFDIV"
to hook that special divider clock-type into our clock-tree.

Signed-off-by: Elaine Zhang 
---
 drivers/clk/rockchip/Makefile   |   1 +
 drivers/clk/rockchip/clk-half-divider.c | 230 
 drivers/clk/rockchip/clk.c  |  10 ++
 drivers/clk/rockchip/clk.h  |  85 
 4 files changed, 326 insertions(+)
 create mode 100644 drivers/clk/rockchip/clk-half-divider.c

diff --git a/drivers/clk/rockchip/Makefile b/drivers/clk/rockchip/Makefile
index 59b8d320960a..2b380fafd232 100644
--- a/drivers/clk/rockchip/Makefile
+++ b/drivers/clk/rockchip/Makefile
@@ -7,6 +7,7 @@ obj-y   += clk-rockchip.o
 obj-y  += clk.o
 obj-y  += clk-pll.o
 obj-y  += clk-cpu.o
+obj-y  += clk-half-divider.o
 obj-y  += clk-inverter.o
 obj-y  += clk-mmc-phase.o
 obj-y  += clk-muxgrf.o
diff --git a/drivers/clk/rockchip/clk-half-divider.c 
b/drivers/clk/rockchip/clk-half-divider.c
new file mode 100644
index ..fb7a6501e0c1
--- /dev/null
+++ b/drivers/clk/rockchip/clk-half-divider.c
@@ -0,0 +1,230 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2018 Fuzhou Rockchip Electronics Co., Ltd
+ */
+
+#include 
+#include 
+#include 
+#include 
+#include 
+#include "clk.h"
+
+#define div_mask(width)((1 << (width)) - 1)
+
+static bool _is_best_half_div(unsigned long rate, unsigned long now,
+ unsigned long best, unsigned long flags)
+{
+   if (flags & CLK_DIVIDER_ROUND_CLOSEST)
+   return abs(rate - now) < abs(rate - best);
+
+   return now <= rate && now > best;
+}
+
+static unsigned long clk_half_divider_recalc_rate(struct clk_hw *hw,
+ unsigned long parent_rate)
+{
+   struct clk_divider *divider = to_clk_divider(hw);
+   unsigned int val;
+
+   val = clk_readl(divider->reg) >> divider->shift;
+   val &= div_mask(divider->width);
+   val = val * 2 + 3;
+
+   return DIV_ROUND_UP_ULL(((u64)parent_rate * 2), val);
+}
+
+static int clk_half_divider_bestdiv(struct clk_hw *hw, unsigned long rate,
+   unsigned long *best_parent_rate, u8 width,
+   unsigned long flags)
+{
+   unsigned int i, bestdiv = 0;
+   unsigned long parent_rate, best = 0, now, maxdiv;
+   unsigned long parent_rate_saved = *best_parent_rate;
+
+   if (!rate)
+   rate = 1;
+
+   maxdiv = div_mask(width);
+
+   if (!(clk_hw_get_flags(hw) & CLK_SET_RATE_PARENT)) {
+   parent_rate = *best_parent_rate;
+   bestdiv = DIV_ROUND_UP_ULL(((u64)parent_rate * 2), rate);
+   if (bestdiv < 3)
+   bestdiv = 0;
+   else
+   bestdiv = (bestdiv - 3) / 2;
+   bestdiv = bestdiv > maxdiv ? maxdiv : bestdiv;
+   return bestdiv;
+   }
+
+   /*
+* The maximum divider we can use without overflowing
+* unsigned long in rate * i below
+*/
+   maxdiv = min(ULONG_MAX / rate, maxdiv);
+
+   for (i = 0; i <= maxdiv; i++) {
+   if (((u64)rate * (i * 2 + 3)) == ((u64)parent_rate_saved * 2)) {
+   /*
+* It's the most ideal case if the requested rate can be
+* divided from parent clock without needing to change
+* parent rate, so return the divider immediately.
+*/
+   *best_parent_rate = parent_rate_saved;
+   return i;
+   }
+   parent_rate = clk_hw_round_rate(clk_hw_get_parent(hw),
+   ((u64)rate * (i * 2 + 3)) / 2);
+   now = DIV_ROUND_UP_ULL(((u64)parent_rate * 2),
+  (i * 2 + 3));
+
+   if (_is_best_half_div(rate, now, best, flags)) {
+   bestdiv = i;
+   best = now;
+   *best_parent_rate = parent_rate;
+   }
+   }
+
+   if (!bestdiv) {
+   bestdiv = div_mask(width);
+   *best_parent_rate = clk_hw_round_rate(clk_hw_get_parent(hw), 1);
+   }
+
+   return bestdiv;
+}
+
+static long clk_half_divider_round_rate(struct clk_hw *hw, unsigned long rate,
+   unsigned long *prate)
+{
+   struct clk_divider *divider = to_clk_divider(hw);
+   int div;
+
+   div = clk_half_divider_bestdiv(hw, rate, prate,
+  divider->width,
+  divider->flags);
+
+   return 

[PATCH v3 3/4] clk: rockchip: add support for half divider

2018-06-14 Thread Elaine Zhang
The new Rockchip socs have optional half divider:
The formula is shown as:
freq_out = 2*freq_in / (2*div + 3)
Is this the same for all of new SoCs.

So we use "branch_half_divider" + "COMPOSITE_NOMUX_HALFDIV \
DIV_HALF \ COMPOSITE_HALFDIV \ CMPOSITE_NOGATE_HALFDIV"
to hook that special divider clock-type into our clock-tree.

Signed-off-by: Elaine Zhang 
---
 drivers/clk/rockchip/Makefile   |   1 +
 drivers/clk/rockchip/clk-half-divider.c | 230 
 drivers/clk/rockchip/clk.c  |  10 ++
 drivers/clk/rockchip/clk.h  |  85 
 4 files changed, 326 insertions(+)
 create mode 100644 drivers/clk/rockchip/clk-half-divider.c

diff --git a/drivers/clk/rockchip/Makefile b/drivers/clk/rockchip/Makefile
index 59b8d320960a..2b380fafd232 100644
--- a/drivers/clk/rockchip/Makefile
+++ b/drivers/clk/rockchip/Makefile
@@ -7,6 +7,7 @@ obj-y   += clk-rockchip.o
 obj-y  += clk.o
 obj-y  += clk-pll.o
 obj-y  += clk-cpu.o
+obj-y  += clk-half-divider.o
 obj-y  += clk-inverter.o
 obj-y  += clk-mmc-phase.o
 obj-y  += clk-muxgrf.o
diff --git a/drivers/clk/rockchip/clk-half-divider.c 
b/drivers/clk/rockchip/clk-half-divider.c
new file mode 100644
index ..fb7a6501e0c1
--- /dev/null
+++ b/drivers/clk/rockchip/clk-half-divider.c
@@ -0,0 +1,230 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2018 Fuzhou Rockchip Electronics Co., Ltd
+ */
+
+#include 
+#include 
+#include 
+#include 
+#include 
+#include "clk.h"
+
+#define div_mask(width)((1 << (width)) - 1)
+
+static bool _is_best_half_div(unsigned long rate, unsigned long now,
+ unsigned long best, unsigned long flags)
+{
+   if (flags & CLK_DIVIDER_ROUND_CLOSEST)
+   return abs(rate - now) < abs(rate - best);
+
+   return now <= rate && now > best;
+}
+
+static unsigned long clk_half_divider_recalc_rate(struct clk_hw *hw,
+ unsigned long parent_rate)
+{
+   struct clk_divider *divider = to_clk_divider(hw);
+   unsigned int val;
+
+   val = clk_readl(divider->reg) >> divider->shift;
+   val &= div_mask(divider->width);
+   val = val * 2 + 3;
+
+   return DIV_ROUND_UP_ULL(((u64)parent_rate * 2), val);
+}
+
+static int clk_half_divider_bestdiv(struct clk_hw *hw, unsigned long rate,
+   unsigned long *best_parent_rate, u8 width,
+   unsigned long flags)
+{
+   unsigned int i, bestdiv = 0;
+   unsigned long parent_rate, best = 0, now, maxdiv;
+   unsigned long parent_rate_saved = *best_parent_rate;
+
+   if (!rate)
+   rate = 1;
+
+   maxdiv = div_mask(width);
+
+   if (!(clk_hw_get_flags(hw) & CLK_SET_RATE_PARENT)) {
+   parent_rate = *best_parent_rate;
+   bestdiv = DIV_ROUND_UP_ULL(((u64)parent_rate * 2), rate);
+   if (bestdiv < 3)
+   bestdiv = 0;
+   else
+   bestdiv = (bestdiv - 3) / 2;
+   bestdiv = bestdiv > maxdiv ? maxdiv : bestdiv;
+   return bestdiv;
+   }
+
+   /*
+* The maximum divider we can use without overflowing
+* unsigned long in rate * i below
+*/
+   maxdiv = min(ULONG_MAX / rate, maxdiv);
+
+   for (i = 0; i <= maxdiv; i++) {
+   if (((u64)rate * (i * 2 + 3)) == ((u64)parent_rate_saved * 2)) {
+   /*
+* It's the most ideal case if the requested rate can be
+* divided from parent clock without needing to change
+* parent rate, so return the divider immediately.
+*/
+   *best_parent_rate = parent_rate_saved;
+   return i;
+   }
+   parent_rate = clk_hw_round_rate(clk_hw_get_parent(hw),
+   ((u64)rate * (i * 2 + 3)) / 2);
+   now = DIV_ROUND_UP_ULL(((u64)parent_rate * 2),
+  (i * 2 + 3));
+
+   if (_is_best_half_div(rate, now, best, flags)) {
+   bestdiv = i;
+   best = now;
+   *best_parent_rate = parent_rate;
+   }
+   }
+
+   if (!bestdiv) {
+   bestdiv = div_mask(width);
+   *best_parent_rate = clk_hw_round_rate(clk_hw_get_parent(hw), 1);
+   }
+
+   return bestdiv;
+}
+
+static long clk_half_divider_round_rate(struct clk_hw *hw, unsigned long rate,
+   unsigned long *prate)
+{
+   struct clk_divider *divider = to_clk_divider(hw);
+   int div;
+
+   div = clk_half_divider_bestdiv(hw, rate, prate,
+  divider->width,
+  divider->flags);
+
+   return