Re: [PATCH v3 3/4] clk: rockchip: add support for half divider
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
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
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
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
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
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
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
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