Merge branch 'clk-frac-divider' into clk-next
- Add power of two flag to fractional divider clk type * clk-frac-divider: clk: fractional-divider: Document the arithmetics used behind the code clk: fractional-divider: Introduce POWER_OF_TWO_PS flag clk: fractional-divider: Hide clk_fractional_divider_ops from wide audience clk: fractional-divider: Export approximation algorithm to the CCF users
This commit is contained in:
commit
1faa7cb2b0
@ -436,8 +436,8 @@ static int register_device_clock(struct acpi_device *adev,
|
|||||||
if (!clk_name)
|
if (!clk_name)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
clk = clk_register_fractional_divider(NULL, clk_name, parent,
|
clk = clk_register_fractional_divider(NULL, clk_name, parent,
|
||||||
0, prv_base,
|
CLK_FRAC_DIVIDER_POWER_OF_TWO_PS,
|
||||||
1, 15, 16, 15, 0, NULL);
|
prv_base, 1, 15, 16, 15, 0, NULL);
|
||||||
parent = clk_name;
|
parent = clk_name;
|
||||||
|
|
||||||
clk_name = kasprintf(GFP_KERNEL, "%s-update", devname);
|
clk_name = kasprintf(GFP_KERNEL, "%s-update", devname);
|
||||||
|
@ -3,8 +3,39 @@
|
|||||||
* Copyright (C) 2014 Intel Corporation
|
* Copyright (C) 2014 Intel Corporation
|
||||||
*
|
*
|
||||||
* Adjustable fractional divider clock implementation.
|
* Adjustable fractional divider clock implementation.
|
||||||
* Output rate = (m / n) * parent_rate.
|
|
||||||
* Uses rational best approximation algorithm.
|
* Uses rational best approximation algorithm.
|
||||||
|
*
|
||||||
|
* Output is calculated as
|
||||||
|
*
|
||||||
|
* rate = (m / n) * parent_rate (1)
|
||||||
|
*
|
||||||
|
* This is useful when we have a prescaler block which asks for
|
||||||
|
* m (numerator) and n (denominator) values to be provided to satisfy
|
||||||
|
* the (1) as much as possible.
|
||||||
|
*
|
||||||
|
* Since m and n have the limitation by a range, e.g.
|
||||||
|
*
|
||||||
|
* n >= 1, n < N_width, where N_width = 2^nwidth (2)
|
||||||
|
*
|
||||||
|
* for some cases the output may be saturated. Hence, from (1) and (2),
|
||||||
|
* assuming the worst case when m = 1, the inequality
|
||||||
|
*
|
||||||
|
* floor(log2(parent_rate / rate)) <= nwidth (3)
|
||||||
|
*
|
||||||
|
* may be derived. Thus, in cases when
|
||||||
|
*
|
||||||
|
* (parent_rate / rate) >> N_width (4)
|
||||||
|
*
|
||||||
|
* we might scale up the rate by 2^scale (see the description of
|
||||||
|
* CLK_FRAC_DIVIDER_POWER_OF_TWO_PS for additional information), where
|
||||||
|
*
|
||||||
|
* scale = floor(log2(parent_rate / rate)) - nwidth (5)
|
||||||
|
*
|
||||||
|
* and assume that the IP, that needs m and n, has also its own
|
||||||
|
* prescaler, which is capable to divide by 2^scale. In this way
|
||||||
|
* we get the denominator to satisfy the desired range (2) and
|
||||||
|
* at the same time much much better result of m and n than simple
|
||||||
|
* saturated values.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <linux/clk-provider.h>
|
#include <linux/clk-provider.h>
|
||||||
@ -14,6 +45,8 @@
|
|||||||
#include <linux/slab.h>
|
#include <linux/slab.h>
|
||||||
#include <linux/rational.h>
|
#include <linux/rational.h>
|
||||||
|
|
||||||
|
#include "clk-fractional-divider.h"
|
||||||
|
|
||||||
static inline u32 clk_fd_readl(struct clk_fractional_divider *fd)
|
static inline u32 clk_fd_readl(struct clk_fractional_divider *fd)
|
||||||
{
|
{
|
||||||
if (fd->flags & CLK_FRAC_DIVIDER_BIG_ENDIAN)
|
if (fd->flags & CLK_FRAC_DIVIDER_BIG_ENDIAN)
|
||||||
@ -68,21 +101,26 @@ static unsigned long clk_fd_recalc_rate(struct clk_hw *hw,
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void clk_fd_general_approximation(struct clk_hw *hw, unsigned long rate,
|
void clk_fractional_divider_general_approximation(struct clk_hw *hw,
|
||||||
unsigned long *parent_rate,
|
unsigned long rate,
|
||||||
unsigned long *m, unsigned long *n)
|
unsigned long *parent_rate,
|
||||||
|
unsigned long *m, unsigned long *n)
|
||||||
{
|
{
|
||||||
struct clk_fractional_divider *fd = to_clk_fd(hw);
|
struct clk_fractional_divider *fd = to_clk_fd(hw);
|
||||||
unsigned long scale;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Get rate closer to *parent_rate to guarantee there is no overflow
|
* Get rate closer to *parent_rate to guarantee there is no overflow
|
||||||
* for m and n. In the result it will be the nearest rate left shifted
|
* for m and n. In the result it will be the nearest rate left shifted
|
||||||
* by (scale - fd->nwidth) bits.
|
* by (scale - fd->nwidth) bits.
|
||||||
|
*
|
||||||
|
* For the detailed explanation see the top comment in this file.
|
||||||
*/
|
*/
|
||||||
scale = fls_long(*parent_rate / rate - 1);
|
if (fd->flags & CLK_FRAC_DIVIDER_POWER_OF_TWO_PS) {
|
||||||
if (scale > fd->nwidth)
|
unsigned long scale = fls_long(*parent_rate / rate - 1);
|
||||||
rate <<= scale - fd->nwidth;
|
|
||||||
|
if (scale > fd->nwidth)
|
||||||
|
rate <<= scale - fd->nwidth;
|
||||||
|
}
|
||||||
|
|
||||||
rational_best_approximation(rate, *parent_rate,
|
rational_best_approximation(rate, *parent_rate,
|
||||||
GENMASK(fd->mwidth - 1, 0), GENMASK(fd->nwidth - 1, 0),
|
GENMASK(fd->mwidth - 1, 0), GENMASK(fd->nwidth - 1, 0),
|
||||||
@ -102,7 +140,7 @@ static long clk_fd_round_rate(struct clk_hw *hw, unsigned long rate,
|
|||||||
if (fd->approximation)
|
if (fd->approximation)
|
||||||
fd->approximation(hw, rate, parent_rate, &m, &n);
|
fd->approximation(hw, rate, parent_rate, &m, &n);
|
||||||
else
|
else
|
||||||
clk_fd_general_approximation(hw, rate, parent_rate, &m, &n);
|
clk_fractional_divider_general_approximation(hw, rate, parent_rate, &m, &n);
|
||||||
|
|
||||||
ret = (u64)*parent_rate * m;
|
ret = (u64)*parent_rate * m;
|
||||||
do_div(ret, n);
|
do_div(ret, n);
|
||||||
|
15
drivers/clk/clk-fractional-divider.h
Normal file
15
drivers/clk/clk-fractional-divider.h
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
/* SPDX-License-Identifier: GPL-2.0 */
|
||||||
|
#ifndef _CLK_FRACTIONAL_DIV_H
|
||||||
|
#define _CLK_FRACTIONAL_DIV_H
|
||||||
|
|
||||||
|
struct clk_hw;
|
||||||
|
|
||||||
|
extern const struct clk_ops clk_fractional_divider_ops;
|
||||||
|
|
||||||
|
void clk_fractional_divider_general_approximation(struct clk_hw *hw,
|
||||||
|
unsigned long rate,
|
||||||
|
unsigned long *parent_rate,
|
||||||
|
unsigned long *m,
|
||||||
|
unsigned long *n);
|
||||||
|
|
||||||
|
#endif
|
@ -10,6 +10,7 @@
|
|||||||
#include <linux/err.h>
|
#include <linux/err.h>
|
||||||
#include <linux/slab.h>
|
#include <linux/slab.h>
|
||||||
|
|
||||||
|
#include "../clk-fractional-divider.h"
|
||||||
#include "clk.h"
|
#include "clk.h"
|
||||||
|
|
||||||
#define PCG_PCS_SHIFT 24
|
#define PCG_PCS_SHIFT 24
|
||||||
|
@ -22,6 +22,8 @@
|
|||||||
#include <linux/regmap.h>
|
#include <linux/regmap.h>
|
||||||
#include <linux/reboot.h>
|
#include <linux/reboot.h>
|
||||||
#include <linux/rational.h>
|
#include <linux/rational.h>
|
||||||
|
|
||||||
|
#include "../clk-fractional-divider.h"
|
||||||
#include "clk.h"
|
#include "clk.h"
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -178,10 +180,8 @@ static void rockchip_fractional_approximation(struct clk_hw *hw,
|
|||||||
unsigned long rate, unsigned long *parent_rate,
|
unsigned long rate, unsigned long *parent_rate,
|
||||||
unsigned long *m, unsigned long *n)
|
unsigned long *m, unsigned long *n)
|
||||||
{
|
{
|
||||||
struct clk_fractional_divider *fd = to_clk_fd(hw);
|
|
||||||
unsigned long p_rate, p_parent_rate;
|
unsigned long p_rate, p_parent_rate;
|
||||||
struct clk_hw *p_parent;
|
struct clk_hw *p_parent;
|
||||||
unsigned long scale;
|
|
||||||
|
|
||||||
p_rate = clk_hw_get_rate(clk_hw_get_parent(hw));
|
p_rate = clk_hw_get_rate(clk_hw_get_parent(hw));
|
||||||
if ((rate * 20 > p_rate) && (p_rate % rate != 0)) {
|
if ((rate * 20 > p_rate) && (p_rate % rate != 0)) {
|
||||||
@ -190,18 +190,7 @@ static void rockchip_fractional_approximation(struct clk_hw *hw,
|
|||||||
*parent_rate = p_parent_rate;
|
*parent_rate = p_parent_rate;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
clk_fractional_divider_general_approximation(hw, rate, parent_rate, m, n);
|
||||||
* Get rate closer to *parent_rate to guarantee there is no overflow
|
|
||||||
* for m and n. In the result it will be the nearest rate left shifted
|
|
||||||
* by (scale - fd->nwidth) bits.
|
|
||||||
*/
|
|
||||||
scale = fls_long(*parent_rate / rate - 1);
|
|
||||||
if (scale > fd->nwidth)
|
|
||||||
rate <<= scale - fd->nwidth;
|
|
||||||
|
|
||||||
rational_best_approximation(rate, *parent_rate,
|
|
||||||
GENMASK(fd->mwidth - 1, 0), GENMASK(fd->nwidth - 1, 0),
|
|
||||||
m, n);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct clk *rockchip_clk_register_frac_branch(
|
static struct clk *rockchip_clk_register_frac_branch(
|
||||||
|
@ -301,7 +301,8 @@ static int intel_lpss_register_clock_divider(struct intel_lpss *lpss,
|
|||||||
|
|
||||||
snprintf(name, sizeof(name), "%s-div", devname);
|
snprintf(name, sizeof(name), "%s-div", devname);
|
||||||
tmp = clk_register_fractional_divider(NULL, name, __clk_get_name(tmp),
|
tmp = clk_register_fractional_divider(NULL, name, __clk_get_name(tmp),
|
||||||
0, lpss->priv, 1, 15, 16, 15, 0,
|
CLK_FRAC_DIVIDER_POWER_OF_TWO_PS,
|
||||||
|
lpss->priv, 1, 15, 16, 15, 0,
|
||||||
NULL);
|
NULL);
|
||||||
if (IS_ERR(tmp))
|
if (IS_ERR(tmp))
|
||||||
return PTR_ERR(tmp);
|
return PTR_ERR(tmp);
|
||||||
|
@ -1001,6 +1001,12 @@ struct clk_hw *devm_clk_hw_register_fixed_factor(struct device *dev,
|
|||||||
* CLK_FRAC_DIVIDER_BIG_ENDIAN - By default little endian register accesses are
|
* CLK_FRAC_DIVIDER_BIG_ENDIAN - By default little endian register accesses are
|
||||||
* used for the divider register. Setting this flag makes the register
|
* used for the divider register. Setting this flag makes the register
|
||||||
* accesses big endian.
|
* accesses big endian.
|
||||||
|
* CLK_FRAC_DIVIDER_POWER_OF_TWO_PS - By default the resulting fraction might
|
||||||
|
* be saturated and the caller will get quite far from the good enough
|
||||||
|
* approximation. Instead the caller may require, by setting this flag,
|
||||||
|
* to shift left by a few bits in case, when the asked one is quite small
|
||||||
|
* to satisfy the desired range of denominator. It assumes that on the
|
||||||
|
* caller's side the power-of-two capable prescaler exists.
|
||||||
*/
|
*/
|
||||||
struct clk_fractional_divider {
|
struct clk_fractional_divider {
|
||||||
struct clk_hw hw;
|
struct clk_hw hw;
|
||||||
@ -1020,10 +1026,10 @@ struct clk_fractional_divider {
|
|||||||
|
|
||||||
#define to_clk_fd(_hw) container_of(_hw, struct clk_fractional_divider, hw)
|
#define to_clk_fd(_hw) container_of(_hw, struct clk_fractional_divider, hw)
|
||||||
|
|
||||||
#define CLK_FRAC_DIVIDER_ZERO_BASED BIT(0)
|
#define CLK_FRAC_DIVIDER_ZERO_BASED BIT(0)
|
||||||
#define CLK_FRAC_DIVIDER_BIG_ENDIAN BIT(1)
|
#define CLK_FRAC_DIVIDER_BIG_ENDIAN BIT(1)
|
||||||
|
#define CLK_FRAC_DIVIDER_POWER_OF_TWO_PS BIT(2)
|
||||||
|
|
||||||
extern const struct clk_ops clk_fractional_divider_ops;
|
|
||||||
struct clk *clk_register_fractional_divider(struct device *dev,
|
struct clk *clk_register_fractional_divider(struct device *dev,
|
||||||
const char *name, const char *parent_name, unsigned long flags,
|
const char *name, const char *parent_name, unsigned long flags,
|
||||||
void __iomem *reg, u8 mshift, u8 mwidth, u8 nshift, u8 nwidth,
|
void __iomem *reg, u8 mshift, u8 mwidth, u8 nshift, u8 nwidth,
|
||||||
|
Loading…
x
Reference in New Issue
Block a user