lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Date:	Thu, 15 May 2014 09:53:49 -0700
From:	Mike Turquette <mturquette@...aro.org>
To:	Heikki Krogerus <heikki.krogerus@...ux.intel.com>,
	"Rafael J. Wysocki" <rjw@...ysocki.net>
Cc:	"Mika Westerberg" <mika.westerberg@...ux.intel.com>,
	"Jin Yao" <yao.jin@...ux.intel.com>,
	"Li Aubrey" <aubrey.li@...ux.intel.com>,
	"Andy Shevchenko" <andriy.shevchenko@...ux.intel.com>,
	linux-acpi@...r.kernel.org, linux-kernel@...r.kernel.org
Subject: Re: [PATCHv2 3/4] clk: new basic clk type for fractional divider

Quoting Heikki Krogerus (2014-05-15 06:40:25)
> Fractional divider clocks are fairly common. This adds basic
> type for them.
> 
> Signed-off-by: Heikki Krogerus <heikki.krogerus@...ux.intel.com>

Taken into clk-next.

Just FYI, there was some talk at Embedded Linux Conference on providing
a better abstraction layer for some of these "basic" clock types. This
abstraction would allow the basic clock types to implement the
machine-agnostic logic (e.g. an incoming rate is divided by a value) and
then platforms and drivers could plug in the machine-specific parts
(e.g. divider is made up of m/n, or divider is power-of-two, or divider
is a simple integer with min == 1 and max == 5).

All of that is to say that in time this fractional divider could go away
once the abstraction layer allows us to fold the m/n divider stuff into
a core divider implementation.

Nothing wrong with the patch for now, so I've taken it for 3.16.

Regards,
Mike

> ---
>  drivers/clk/Makefile                 |   1 +
>  drivers/clk/clk-fractional-divider.c | 135 +++++++++++++++++++++++++++++++++++
>  include/linux/clk-provider.h         |  31 ++++++++
>  3 files changed, 167 insertions(+)
>  create mode 100644 drivers/clk/clk-fractional-divider.c
> 
> diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile
> index f651b2a..33bc79e 100644
> --- a/drivers/clk/Makefile
> +++ b/drivers/clk/Makefile
> @@ -8,6 +8,7 @@ obj-$(CONFIG_COMMON_CLK)        += clk-fixed-rate.o
>  obj-$(CONFIG_COMMON_CLK)       += clk-gate.o
>  obj-$(CONFIG_COMMON_CLK)       += clk-mux.o
>  obj-$(CONFIG_COMMON_CLK)       += clk-composite.o
> +obj-$(CONFIG_COMMON_CLK)       += clk-fractional-divider.o
>  
>  # hardware specific clock types
>  # please keep this section sorted lexicographically by file/directory path name
> diff --git a/drivers/clk/clk-fractional-divider.c b/drivers/clk/clk-fractional-divider.c
> new file mode 100644
> index 0000000..ede685c
> --- /dev/null
> +++ b/drivers/clk/clk-fractional-divider.c
> @@ -0,0 +1,135 @@
> +/*
> + * Copyright (C) 2014 Intel Corporation
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.
> + *
> + * Adjustable fractional divider clock implementation.
> + * Output rate = (m / n) * parent_rate.
> + */
> +
> +#include <linux/clk-provider.h>
> +#include <linux/module.h>
> +#include <linux/device.h>
> +#include <linux/slab.h>
> +#include <linux/gcd.h>
> +
> +#define to_clk_fd(_hw) container_of(_hw, struct clk_fractional_divider, hw)
> +
> +static unsigned long clk_fd_recalc_rate(struct clk_hw *hw,
> +                                       unsigned long parent_rate)
> +{
> +       struct clk_fractional_divider *fd = to_clk_fd(hw);
> +       unsigned long flags = 0;
> +       u32 val, m, n;
> +       u64 ret;
> +
> +       if (fd->lock)
> +               spin_lock_irqsave(fd->lock, flags);
> +
> +       val = clk_readl(fd->reg);
> +
> +       if (fd->lock)
> +               spin_unlock_irqrestore(fd->lock, flags);
> +
> +       m = (val & fd->mmask) >> fd->mshift;
> +       n = (val & fd->nmask) >> fd->nshift;
> +
> +       ret = parent_rate * m;
> +       do_div(ret, n);
> +
> +       return ret;
> +}
> +
> +static long clk_fd_round_rate(struct clk_hw *hw, unsigned long rate,
> +                             unsigned long *prate)
> +{
> +       struct clk_fractional_divider *fd = to_clk_fd(hw);
> +       unsigned maxn = (fd->nmask >> fd->nshift) + 1;
> +       unsigned div;
> +
> +       if (!rate || rate >= *prate)
> +               return *prate;
> +
> +       div = gcd(*prate, rate);
> +
> +       while ((*prate / div) > maxn) {
> +               div <<= 1;
> +               rate <<= 1;
> +       }
> +
> +       return rate;
> +}
> +
> +static int clk_fd_set_rate(struct clk_hw *hw, unsigned long rate,
> +                          unsigned long parent_rate)
> +{
> +       struct clk_fractional_divider *fd = to_clk_fd(hw);
> +       unsigned long flags = 0;
> +       unsigned long div;
> +       unsigned n, m;
> +       u32 val;
> +
> +       div = gcd(parent_rate, rate);
> +       m = rate / div;
> +       n = parent_rate / div;
> +
> +       if (fd->lock)
> +               spin_lock_irqsave(fd->lock, flags);
> +
> +       val = clk_readl(fd->reg);
> +       val &= ~(fd->mmask | fd->nmask);
> +       val |= (m << fd->mshift) | (n << fd->nshift);
> +       clk_writel(val, fd->reg);
> +
> +       if (fd->lock)
> +               spin_unlock_irqrestore(fd->lock, flags);
> +
> +       return 0;
> +}
> +
> +const struct clk_ops clk_fractional_divider_ops = {
> +       .recalc_rate = clk_fd_recalc_rate,
> +       .round_rate = clk_fd_round_rate,
> +       .set_rate = clk_fd_set_rate,
> +};
> +EXPORT_SYMBOL_GPL(clk_fractional_divider_ops);
> +
> +struct clk *clk_register_fractional_divider(struct device *dev,
> +               const char *name, const char *parent_name, unsigned long flags,
> +               void __iomem *reg, u8 mshift, u8 mwidth, u8 nshift, u8 nwidth,
> +               u8 clk_divider_flags, spinlock_t *lock)
> +{
> +       struct clk_fractional_divider *fd;
> +       struct clk_init_data init;
> +       struct clk *clk;
> +
> +       fd = kzalloc(sizeof(*fd), GFP_KERNEL);
> +       if (!fd) {
> +               dev_err(dev, "could not allocate fractional divider clk\n");
> +               return ERR_PTR(-ENOMEM);
> +       }
> +
> +       init.name = name;
> +       init.ops = &clk_fractional_divider_ops;
> +       init.flags = flags | CLK_IS_BASIC;
> +       init.parent_names = parent_name ? &parent_name : NULL;
> +       init.num_parents = parent_name ? 1 : 0;
> +
> +       fd->reg = reg;
> +       fd->mshift = mshift;
> +       fd->mmask = (BIT(mwidth) - 1) << mshift;
> +       fd->nshift = nshift;
> +       fd->nmask = (BIT(nwidth) - 1) << nshift;
> +       fd->flags = clk_divider_flags;
> +       fd->lock = lock;
> +       fd->hw.init = &init;
> +
> +       clk = clk_register(dev, &fd->hw);
> +       if (IS_ERR(clk))
> +               kfree(fd);
> +
> +       return clk;
> +}
> +EXPORT_SYMBOL_GPL(clk_register_fractional_divider);
> diff --git a/include/linux/clk-provider.h b/include/linux/clk-provider.h
> index 4080943..d76188a 100644
> --- a/include/linux/clk-provider.h
> +++ b/include/linux/clk-provider.h
> @@ -422,6 +422,37 @@ struct clk *clk_register_fixed_factor(struct device *dev, const char *name,
>                 const char *parent_name, unsigned long flags,
>                 unsigned int mult, unsigned int div);
>  
> +/**
> + * struct clk_fractional_divider - adjustable fractional divider clock
> + *
> + * @hw:                handle between common and hardware-specific interfaces
> + * @reg:       register containing the divider
> + * @mshift:    shift to the numerator bit field
> + * @mwidth:    width of the numerator bit field
> + * @nshift:    shift to the denominator bit field
> + * @nwidth:    width of the denominator bit field
> + * @lock:      register lock
> + *
> + * Clock with adjustable fractional divider affecting its output frequency.
> + */
> +
> +struct clk_fractional_divider {
> +       struct clk_hw   hw;
> +       void __iomem    *reg;
> +       u8              mshift;
> +       u32             mmask;
> +       u8              nshift;
> +       u32             nmask;
> +       u8              flags;
> +       spinlock_t      *lock;
> +};
> +
> +extern const struct clk_ops clk_fractional_divider_ops;
> +struct clk *clk_register_fractional_divider(struct device *dev,
> +               const char *name, const char *parent_name, unsigned long flags,
> +               void __iomem *reg, u8 mshift, u8 mwidth, u8 nshift, u8 nwidth,
> +               u8 clk_divider_flags, spinlock_t *lock);
> +
>  /***
>   * struct clk_composite - aggregate clock of mux, divider and gate clocks
>   *
> -- 
> 2.0.0.rc2
> 
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@...r.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ