Commit 1faa7cb2 authored by Stephen Boyd's avatar Stephen Boyd
Browse files

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
parents 7110569a e81b917a
Loading
Loading
Loading
Loading
+2 −2
Original line number Diff line number Diff line
@@ -436,8 +436,8 @@ static int register_device_clock(struct acpi_device *adev,
		if (!clk_name)
			return -ENOMEM;
		clk = clk_register_fractional_divider(NULL, clk_name, parent,
						      0, prv_base,
						      1, 15, 16, 15, 0, NULL);
						      CLK_FRAC_DIVIDER_POWER_OF_TWO_PS,
						      prv_base, 1, 15, 16, 15, 0, NULL);
		parent = clk_name;

		clk_name = kasprintf(GFP_KERNEL, "%s-update", devname);
+47 −9
Original line number Diff line number Diff line
@@ -3,8 +3,39 @@
 * Copyright (C) 2014 Intel Corporation
 *
 * Adjustable fractional divider clock implementation.
 * Output rate = (m / n) * parent_rate.
 * 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>
@@ -14,6 +45,8 @@
#include <linux/slab.h>
#include <linux/rational.h>

#include "clk-fractional-divider.h"

static inline u32 clk_fd_readl(struct clk_fractional_divider *fd)
{
	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;
}

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 rate,
						  unsigned long *parent_rate,
						  unsigned long *m, unsigned long *n)
{
	struct clk_fractional_divider *fd = to_clk_fd(hw);
	unsigned long scale;

	/*
	 * 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.
	 *
	 * 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) {
		unsigned long 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),
@@ -102,7 +140,7 @@ static long clk_fd_round_rate(struct clk_hw *hw, unsigned long rate,
	if (fd->approximation)
		fd->approximation(hw, rate, parent_rate, &m, &n);
	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;
	do_div(ret, n);
+15 −0
Original line number Diff line number Diff line
/* 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
+1 −0
Original line number Diff line number Diff line
@@ -10,6 +10,7 @@
#include <linux/err.h>
#include <linux/slab.h>

#include "../clk-fractional-divider.h"
#include "clk.h"

#define PCG_PCS_SHIFT	24
+3 −14
Original line number Diff line number Diff line
@@ -22,6 +22,8 @@
#include <linux/regmap.h>
#include <linux/reboot.h>
#include <linux/rational.h>

#include "../clk-fractional-divider.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 *m, unsigned long *n)
{
	struct clk_fractional_divider *fd = to_clk_fd(hw);
	unsigned long p_rate, p_parent_rate;
	struct clk_hw *p_parent;
	unsigned long scale;

	p_rate = clk_hw_get_rate(clk_hw_get_parent(hw));
	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;
	}

	/*
	 * 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);
	clk_fractional_divider_general_approximation(hw, rate, parent_rate, m, n);
}

static struct clk *rockchip_clk_register_frac_branch(
Loading