[RFC PATCH RESEND 1/2] clk: add clk accuracy retrieval support
boris brezillon
b.brezillon at overkiz.com
Fri Nov 8 03:54:45 EST 2013
Hello Mike,
On 08/11/2013 01:51, Mike Turquette wrote:
> Quoting Boris BREZILLON (2013-10-13 10:17:10)
>> The clock accuracy is expressed in ppb (parts per billion) and represents
>> the possible clock drift.
>> Say you have a clock (e.g. an oscillator) which provides a fixed clock of
>> 20MHz with an accuracy of +- 20Hz. This accuracy expressed in ppb is
>> 20Hz/20MHz = 1000 ppb (or 1 ppm).
>>
>> Clock users may need the clock accuracy information in order to choose
>> the best clock (the one with the best accuracy) across several available
>> clocks.
>>
>> This patch adds clk accuracy retrieval support for common clk framework by
>> means of a new function called clk_get_accuracy.
>> This function returns the given clock accuracy expressed in ppb.
>>
>> In order to get the clock accuracy, this implementation adds one callback
>> called recalc_accuracy to the clk_ops structure.
>> This callback is given the parent clock accuracy (if the clock is not a
>> root clock) and should recalculate the given clock accuracy.
>>
>> This callback is optional and may be implemented if the clock is not
>> a perfect clock (accuracy != 0 ppb).
>>
>> Signed-off-by: Boris BREZILLON <b.brezillon at overkiz.com>
>> ---
>> Documentation/clk.txt | 4 ++
>> drivers/clk/Kconfig | 4 ++
>> drivers/clk/clk.c | 92 ++++++++++++++++++++++++++++++++++++++++--
>> include/linux/clk-private.h | 1 +
>> include/linux/clk-provider.h | 11 +++++
>> include/linux/clk.h | 17 ++++++++
>> 6 files changed, 125 insertions(+), 4 deletions(-)
>>
>> diff --git a/Documentation/clk.txt b/Documentation/clk.txt
>> index 3aeb5c4..dc52da1 100644
>> --- a/Documentation/clk.txt
>> +++ b/Documentation/clk.txt
>> @@ -77,6 +77,8 @@ the operations defined in clk.h:
>> int (*set_parent)(struct clk_hw *hw, u8 index);
>> u8 (*get_parent)(struct clk_hw *hw);
>> int (*set_rate)(struct clk_hw *hw, unsigned long);
>> + unsigned long (*recalc_accuracy)(struct clk_hw *hw,
>> + unsigned long parent_accuracy);
>> void (*init)(struct clk_hw *hw);
>> };
>>
>> @@ -202,6 +204,8 @@ optional or must be evaluated on a case-by-case basis.
>> .set_parent | | | n | y | n |
>> .get_parent | | | n | y | n |
>> | | | | | |
>> +.recalc_rate | | | | | |
> s/recalc_rate/recalc_accuracy/
Oops. I'll fix it :).
>
>> + | | | | | |
>> .init | | | | | |
>> -----------------------------------------------------------
>> [1] either one of round_rate or determine_rate is required.
>> diff --git a/drivers/clk/Kconfig b/drivers/clk/Kconfig
>> index 279407a..4d12ae7 100644
>> --- a/drivers/clk/Kconfig
>> +++ b/drivers/clk/Kconfig
>> @@ -6,12 +6,16 @@ config CLKDEV_LOOKUP
>> config HAVE_CLK_PREPARE
>> bool
>>
>> +config HAVE_CLK_GET_ACCURACY
>> + bool
>> +
> This sort of thing gets messy. For platforms converted to common struct
> clk we select HAVE_CLK_PREPARE and we let legacy platforms select it on
> a case-by-case basis.
>
> For something like HAVE_CLK_GET_ACCURACY I am inclined to only add it
> for platforms converted to the common struct clk and not even expose it
> to legacy clock framework implementations. In those cases the call to
> clk_get_accuracy would return -EINVAL or -EPERM or something.
Okay.
If Russell agrees, I'll define a static inline function returning an
error (-ENOTSUPP ?) in case CONFIG_COMMON_CLK is not defined.
>
> Russell, any thoughts on that approach?
>
>> config HAVE_MACH_CLKDEV
>> bool
>>
>> config COMMON_CLK
>> bool
>> select HAVE_CLK_PREPARE
>> + select HAVE_CLK_GET_ACCURACY
>> select CLKDEV_LOOKUP
>> ---help---
>> The common clock framework is a single definition of struct
>> diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c
>> index a004769..6a8f3ef 100644
>> --- a/drivers/clk/clk.c
>> +++ b/drivers/clk/clk.c
>> @@ -104,10 +104,11 @@ static void clk_summary_show_one(struct seq_file *s, struct clk *c, int level)
>> if (!c)
>> return;
>>
>> - seq_printf(s, "%*s%-*s %-11d %-12d %-10lu",
>> + seq_printf(s, "%*s%-*s %-11d %-12d %-10lu %-11lu",
>> level * 3 + 1, "",
>> 30 - level * 3, c->name,
>> - c->enable_count, c->prepare_count, clk_get_rate(c));
>> + c->enable_count, c->prepare_count, clk_get_rate(c),
>> + clk_get_accuracy(c));
>> seq_printf(s, "\n");
>> }
>>
>> @@ -129,8 +130,8 @@ static int clk_summary_show(struct seq_file *s, void *data)
>> {
>> struct clk *c;
>>
>> - seq_printf(s, " clock enable_cnt prepare_cnt rate\n");
>> - seq_printf(s, "---------------------------------------------------------------------\n");
>> + seq_printf(s, " clock enable_cnt prepare_cnt rate accuracy\n");
>> + seq_printf(s, "---------------------------------------------------------------------------------\n");
>>
>> clk_prepare_lock();
>>
>> @@ -167,6 +168,7 @@ static void clk_dump_one(struct seq_file *s, struct clk *c, int level)
>> seq_printf(s, "\"enable_count\": %d,", c->enable_count);
>> seq_printf(s, "\"prepare_count\": %d,", c->prepare_count);
>> seq_printf(s, "\"rate\": %lu", clk_get_rate(c));
>> + seq_printf(s, "\"accuracy\": %lu", clk_get_accuracy(c));
>> }
>>
>> static void clk_dump_subtree(struct seq_file *s, struct clk *c, int level)
>> @@ -248,6 +250,11 @@ static int clk_debug_create_one(struct clk *clk, struct dentry *pdentry)
>> if (!d)
>> goto err_out;
>>
>> + d = debugfs_create_u32("clk_accuracy", S_IRUGO, clk->dentry,
>> + (u32 *)&clk->accuracy);
>> + if (!d)
>> + goto err_out;
>> +
>> d = debugfs_create_x32("clk_flags", S_IRUGO, clk->dentry,
>> (u32 *)&clk->flags);
>> if (!d)
>> @@ -602,6 +609,11 @@ out:
>> return ret;
>> }
>>
>> +unsigned long __clk_get_accuracy(struct clk *clk)
>> +{
>> + return !clk ? 0 : clk->accuracy;
>> +}
>> +
>> unsigned long __clk_get_flags(struct clk *clk)
>> {
>> return !clk ? 0 : clk->flags;
>> @@ -1016,6 +1028,59 @@ static int __clk_notify(struct clk *clk, unsigned long msg,
>> }
>>
>> /**
>> + * __clk_recalc_accuracies
>> + * @clk: first clk in the subtree
>> + * @msg: notification type (see include/linux/clk.h)
>> + *
>> + * Walks the subtree of clks starting with clk and recalculates accuracies as
>> + * it goes. Note that if a clk does not implement the .recalc_rate callback
>> + * then it is assumed that the clock will take on the rate of it's parent.
>> + *
>> + * Caller must hold prepare_lock.
>> + */
>> +static void __clk_recalc_accuracies(struct clk *clk)
>> +{
>> + unsigned long parent_accuracy = 0;
>> + struct clk *child;
>> +
>> + if (clk->parent)
>> + parent_accuracy = clk->parent->accuracy;
>> +
>> + if (clk->ops->recalc_accuracy)
>> + clk->accuracy = clk->ops->recalc_accuracy(clk->hw,
>> + parent_accuracy);
>> + else
>> + clk->accuracy = parent_accuracy;
>> +
>> + hlist_for_each_entry(child, &clk->children, child_node)
>> + __clk_recalc_accuracies(child);
>> +}
>> +
>> +/**
>> + * clk_get_accuracy - return the accuracy of clk
>> + * @clk: the clk whose accuracy is being returned
>> + *
>> + * Simply returns the cached accuracy of the clk, unless
>> + * CLK_GET_ACCURACY_NOCACHE flag is set, which means a recalc_rate will be
>> + * issued.
>> + * If clk is NULL then returns 0.
>> + */
>> +unsigned long clk_get_accuracy(struct clk *clk)
>> +{
>> + unsigned long accuracy;
>> + clk_prepare_lock();
>> +
>> + if (clk && (clk->flags & CLK_GET_ACCURACY_NOCACHE))
>> + __clk_recalc_accuracies(clk);
> I think that there is some overlap between recalculating the accuracy
> here and simply getting it. You only provide clk_get_accuracy and it
> serves both purposes. It would be better if clk_recalc_accuracy walked
> the subtree of children and if clk_get_accuracy simply returned a cached
> value.
I'm not sure I get your point.
I used exactly the same model as for clk rate retrieval.
Actually there's one flag (CLK_GET_ACCURACY_NOCACHE) which is
checked to decide wether the accuracy should be recalculated each
time the get_accuracy is called or not.
This means most of the time the clk_get_accuracy will return the cached
value unless the clk provider explicitely ask for accuracy recalculation
(e.g. a clk with dynamic accuracy according to temperature range ?).
Are you suggesting to expose 2 functions to clk users (clk_get_accuracy
and clk_recalc_accuracy) ?
Or is clk_recalc_accuracy an internal/private function used by the CCF ?
>
>> +
>> + accuracy = __clk_get_accuracy(clk);
>> + clk_prepare_unlock();
>> +
>> + return accuracy;
>> +}
>> +EXPORT_SYMBOL_GPL(clk_get_accuracy);
>> +
>> +/**
>> * __clk_recalc_rates
>> * @clk: first clk in the subtree
>> * @msg: notification type (see include/linux/clk.h)
>> @@ -1545,6 +1610,7 @@ void __clk_reparent(struct clk *clk, struct clk *new_parent)
>> {
>> clk_reparent(clk, new_parent);
>> clk_debug_reparent(clk, new_parent);
>> + __clk_recalc_accuracies(clk);
> Similar to the above statement. Why do this here? We do this for rates
> since calls to clk_get_rate will return the cached rate (unless the
> NOCACHE flag is set). But since a call to clk_get_accuracy will always
> recalculate it then there is no benefit to doing that here.
This is the same for clk_get_accuracies (it returns the cached
accuracy unless CLK_GET_ACCURACY_NOCACHE is defined).
And changing parent of a clk will indirectly change the clk
accuracy (clk accuracies are cumulative).
>
>> __clk_recalc_rates(clk, POST_RATE_CHANGE);
>> }
>>
>> @@ -1615,6 +1681,9 @@ int clk_set_parent(struct clk *clk, struct clk *parent)
>> /* do the re-parent */
>> ret = __clk_set_parent(clk, parent, p_index);
>>
>> + /* propagate accuracy recalculation */
>> + __clk_recalc_accuracies(clk);
> Ditto.
Ditto. :)
Please tell me if I misunderstood your requests.
Best Regards,
Boris
>
> Regards,
> Mike
>
>> +
>> /* propagate rate recalculation accordingly */
>> if (ret)
>> __clk_recalc_rates(clk, ABORT_RATE_CHANGE);
>> @@ -1724,6 +1793,21 @@ int __clk_init(struct device *dev, struct clk *clk)
>> hlist_add_head(&clk->child_node, &clk_orphan_list);
>>
>> /*
>> + * Set clk's accuracy. The preferred method is to use
>> + * .recalc_accuracy. For simple clocks and lazy developers the default
>> + * fallback is to use the parent's accuracy. If a clock doesn't have a
>> + * parent (or is orphaned) then accuracy is set to zero (perfect
>> + * clock).
>> + */
>> + if (clk->ops->recalc_accuracy)
>> + clk->accuracy = clk->ops->recalc_accuracy(clk->hw,
>> + __clk_get_accuracy(clk->parent));
>> + else if (clk->parent)
>> + clk->accuracy = clk->parent->accuracy;
>> + else
>> + clk->accuracy = 0;
>> +
>> + /*
>> * Set clk's rate. The preferred method is to use .recalc_rate. For
>> * simple clocks and lazy developers the default fallback is to use the
>> * parent's rate. If a clock doesn't have a parent (or is orphaned)
>> diff --git a/include/linux/clk-private.h b/include/linux/clk-private.h
>> index 8138c94..accb517 100644
>> --- a/include/linux/clk-private.h
>> +++ b/include/linux/clk-private.h
>> @@ -41,6 +41,7 @@ struct clk {
>> unsigned long flags;
>> unsigned int enable_count;
>> unsigned int prepare_count;
>> + unsigned long accuracy;
>> struct hlist_head children;
>> struct hlist_node child_node;
>> unsigned int notifier_count;
>> diff --git a/include/linux/clk-provider.h b/include/linux/clk-provider.h
>> index 73bdb69..942811d 100644
>> --- a/include/linux/clk-provider.h
>> +++ b/include/linux/clk-provider.h
>> @@ -29,6 +29,7 @@
>> #define CLK_IS_BASIC BIT(5) /* Basic clk, can't do a to_clk_foo() */
>> #define CLK_GET_RATE_NOCACHE BIT(6) /* do not use the cached clk rate */
>> #define CLK_SET_RATE_NO_REPARENT BIT(7) /* don't re-parent on rate change */
>> +#define CLK_GET_ACCURACY_NOCACHE BIT(8) /* do not use the cached clk accuracy */
>>
>> struct clk_hw;
>>
>> @@ -108,6 +109,13 @@ struct clk_hw;
>> * which is likely helpful for most .set_rate implementation.
>> * Returns 0 on success, -EERROR otherwise.
>> *
>> + * @recalc_accuracy: Recalculate the accuracy of this clock. The clock accuracy
>> + * is expressed in ppb (parts per billion). The parent accuracy is
>> + * an input parameter.
>> + * Returns the calculated accuracy. Optional - if this op is not
>> + * set then clock accuracy will be initialized to parent accuracy
>> + * or 0 (perfect clock) if clock has no parent.
>> + *
>> * The clk_enable/clk_disable and clk_prepare/clk_unprepare pairs allow
>> * implementations to split any work between atomic (enable) and sleepable
>> * (prepare) contexts. If enabling a clock requires code that might sleep,
>> @@ -139,6 +147,8 @@ struct clk_ops {
>> u8 (*get_parent)(struct clk_hw *hw);
>> int (*set_rate)(struct clk_hw *hw, unsigned long,
>> unsigned long);
>> + unsigned long (*recalc_accuracy)(struct clk_hw *hw,
>> + unsigned long parent_accuracy);
>> void (*init)(struct clk_hw *hw);
>> };
>>
>> @@ -194,6 +204,7 @@ struct clk_hw {
>> struct clk_fixed_rate {
>> struct clk_hw hw;
>> unsigned long fixed_rate;
>> + unsigned long fixed_accuracy;
>> u8 flags;
>> };
>>
>> diff --git a/include/linux/clk.h b/include/linux/clk.h
>> index 9a6d045..2fe3b54 100644
>> --- a/include/linux/clk.h
>> +++ b/include/linux/clk.h
>> @@ -85,6 +85,23 @@ int clk_notifier_unregister(struct clk *clk, struct notifier_block *nb);
>> #endif
>>
>> /**
>> + * clk_get_accuracy - obtain the clock accuracy in ppb (parts per billion)
>> + * for a clock source.
>> + * @clk: clock source
>> + *
>> + * This gets the clock source accuracy expressed in ppb.
>> + * A perfect clock returns 0.
>> + */
>> +#ifdef CONFIG_HAVE_CLK_GET_ACCURACY
>> +unsigned long clk_get_accuracy(struct clk *clk);
>> +#else
>> +static inline unsigned long clk_get_accuracy(struct clk *clk)
>> +{
>> + return 0;
>> +}
>> +#endif
>> +
>> +/**
>> * clk_prepare - prepare a clock source
>> * @clk: clock source
>> *
>> --
>> 1.7.9.5
>>
>>
>> _______________________________________________
>> linux-arm-kernel mailing list
>> linux-arm-kernel at lists.infradead.org
>> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
More information about the linux-arm-kernel
mailing list