From: Sean Anderson <seanga2@gmail.com>
To: u-boot@lists.denx.de
Subject: [PATCH v2 01/11] clk: Always use the supplied struct clk
Date: Thu, 30 Jan 2020 00:47:42 -0500 [thread overview]
Message-ID: <263ed00a-c396-bad6-9223-4579d9d2b0fa@gmail.com> (raw)
In-Reply-To: <20200130012913.62624ec0@jawa>
Hi Lukasz,
On 1/29/20 7:29 PM, Lukasz Majewski wrote:
>> Yes, but then clk_get_parent throws a fit, which gets called by
>
> Could you explain what "throw a fit" means here? I'm a bit confused.
Ok, so imagine I have a clk_divider in a composite clock. When
clk_get_rate gets called on the composite clock, the composite clock
then calls clk_divider_get_rate on the divider clock. The first thing
that function does is call clk_get_parent_rate, which in turn calls
clk_get_parent. This last call fails because the divider clock has a
NULL ->dev. The end behaviour is that the parent rate looks like 0,
which causes the divider to in turn return 0 as its rate. So while it
doesn't throw a fit, we still end up with a bad result.
>> - struct clk as used by CCF clocks. Here the structure
>> contains specific information configuring each clock. Each struct clk
>> refers to a different logical clock. clk->dev->priv
>> contains a struct clk (though this may not be the same struct clk).
>
> The struct clk pointer is now stored in the struct's udevice
> uclass_priv pointer.
>
> For CCF it looks like below:
>
> struct clk_gate2 -> struct clk -> struct udevice *dev -> struct udevice
> /|\ |
> | |
> -------------uclass_priv<------------
>
Right, so at best doing dev_get_clk_ptr(clk->dev) in something like
clk_divider_set_rate is a no-op, and at worst it breaks something.
>> These clocks cannot appear in a device tree
>
> I think they could, but I've followed the approach of Linux CCF in e.g.
> i.MX6Q SoC.
They could, but none of them have compatible strings at the moment.
>> , and hence cannot be
>> acquired by clk_get_by_* (except for clk_get_by_id which
>> doesn't use the device tree). These clocks are not created
>> by xlate and request.
>
> Correct. Those clocks are instantiated in SoC specific file. For
> example in ./drivers/clk/imx/clk-imx6q.c
>
>
>> With this in mind, I'm not sure why one would ever need to call
>> dev_get_clk_ptr. In the first case, clk->dev->priv could be anything,
>> and probably not a clock. In the second case, one already has the
>> "canonical" struct clk.
>
> The problem is that clocks are linked together with struct udevice
> (_NOT_ struct clk). All clocks are linked together and have the same
> uclass - UCLASS_CLK.
>
> To access clock - one needs to search this doubly linked list and you
> get struct udevice from it.
> (for example in ./cmd/clk.c)
>
> And then you need a "back pointer" to struct clk to use clock
> ops/functions. And this back pointer is stored in struct udevice's
> uclass_priv pointer (accessed via dev_get_clk_ptr).
Right, but clock implementations will never need to do this. Whatever
clock they get passed is going to be the clock they should use. This is
why I think the calls which I removed were unnecessary.
In fact, through this discussion I think the patch as-submitted is
probably the least-disruptive way to make composite clocks work in a
useful way. The only thing it does is that sometimes clk->dev->priv !=
clk, but I don't think that anyone was relying on this being the case.
>>> - The struct clk has flags field (clk->flags). New flags:
>>> -- CCF_CLK_COMPOSITE_REGISTERED (visible with dm
>>> tree) -- CCF_CLK_COMPOSITE_HIDDEN (used internally to
>>> gate, mux, etc. the composite clock)
>>>
>>>
>>> -- clk->dev->flags with CCF_CLK_COMPOSITE_REGISTERED
>>> set puts all "servant" clocks to its child_head list
>>> (clk->dev->child_head).
>>>
>>> __OR__
>>>
>>> -- we extend the ccf core to use struct uc_clk_priv
>>> (as described:
>>> https://gitlab.denx.de/u-boot/u-boot/blob/master/doc/imx/clk/ccf.txt#L40)
>>> which would have
>>>
>>> struct uc_clk_priv {
>>> struct clk *c; /* back pointer to clk */
>>>
>>> struct clk_composite *cc;
>>> };
>>>
>>> struct clk_composite {
>>> struct clk *mux;
>>> struct clk *gate;
>>> ...
>>> (no ops here - they shall be in struct
>>> udevice) };
>>>
>>> The overhead is to have extra 4 bytes (or use union
>>> and check CCF_CLK_COMPOSITE flags).
>>>
>>>
>>> For me the more natural seems the approach with using
>>> clk->dev->child_head (maybe with some extra new flags defined).
>>> U-Boot handles lists pretty well and maybe OF_PLATDATA could be
>>> used as well.
>>
>> I like the private data approach, but couldn't we use the existing
>> clk->data field? E.g. instead of having
>>
>> struct clk_foo {
>> struct clk clk;
>
> This is the approach took from the Linux kernel. This is somewhat
> similar to having the struct clk_hw:
> https://elixir.bootlin.com/linux/latest/source/drivers/clk/imx/clk-gate2.c#L27
>> /* ... */
>> };
>>
>> clk_register_foo(...)
>> {
>> struct clk_foo *foo;
>> struct clk *clk;
>>
>> foo = kzalloc(sizeof(*foo));
>> /* ... */
>>
>> clk = foo->clk;
>> clk_register(...);
>> }
>>
>> int clk_foo_get_rate(struct clk *clk)
>> {
>> struct clk_foo *foo = to_clk_foo(clk);
>> /* ... */
>> }
>>
>> we do
>>
>> struct clk_foo {
>> /* ... */
>> };
>>
>> clk_register_foo(...)
>> {
>> struct clk_foo *foo;
>> struct clk *clk;
>>
>> foo = kzalloc(sizeof(*foo));
>> clk = kzalloc(sizeof(*clk));
>> /* ... */
>>
>> clk->data = foo;
>
> According to the description of struct clk definition (@
> ./include/clk.h) the data field has other purposes.
>
> Maybe we shall add a new member of struct clk?
Well, the CCF doesn't use xlate or register, so this field is unused at
the moment.
>
>> clk_register(...);
>> }
>>
>> int clk_foo_get_rate(struct clk *clk)
>> {
>> struct clk_foo *foo = (struct clk_foo *)clk->data;
>> /* ... */
>> }
>>
>> Of course, now that I have written this all out, it really feels like
>> the container_of approach all over again...
>
> Indeed. Even the access cost is the same as the struct clk is always
> placed as the first element of e.g. struct clk_gate2
>
>>
>> I think the best way of approaching this may be to simply introduce a
>> get_parent op. CCF already does something like this with
>> clk_mux_get_parent. This would also allow for some clocks to have a
>> NULL ->dev.
>
> I've thought about this some time ago and wondered if struct clk
> shouldn't be extended a bit.
>
> Maybe adding there a pointer to "get_parent" would simplify the overall
> design of CCF?
>
> Then one could set this callback pointer in e.g. clk_register_gate2 (or
> clk_register_composite) and set clk->dev to NULL to indicate
> "composite" clock?
>
> So we would have:
>
> static inline bool is_composite_clk(struct clk *clk)
> {
> return !clk->dev && clk->flags == CCF_CLK_COMPOSITE;
> }
What would use that predicate?
> I'm just wondering if "normal" clocks shall set this clk->get_parent
> pointer or continue to use clk->dev->parent?
Hm, well after thinking it over, I think with the current system having
a method for this would not do anything useful, since you still need to
get the ops from the udevice (and then you could just use the default
behaviour).
If I could make big sweeping changes clock uclass, I would
do something like:
- Split off of_xlate, request, and free into a new
clk_device_ops struct, with an optional pointer to clk_ops
- Create a new struct clk_handle containing id, data, a pointer to
struct udevice, and a pointer to struct clk
- Add get_parent to clk_ops and change all ops to work on struct
clk_handle
- Add a pointer to clk_ops in struct clk, and remove dev, id,
and data.
So for users, the api would look like
struct clk_handle clk = clk_get_by_index(dev, 0, &clk);
clk_enable(&clk);
ulong rate = clk_get_rate(&clk);
Method calls would roughly look like
ulong clk_get_rate(struct clk_handle *h)
{
struct clk_ops *ops;
if (h->clk)
ops = h->clk->ops;
else
ops = clk_dev_ops(h->dev)->ops;
return ops->get_rate(h);
}
Getting the parent would use h->clk->ops->get_parent if it exists, and
otherwise use h->dev to figure it out.
For non-CCF drivers, the implementation could look something like
ulong foo_get_rate(struct clk_handle *h)
{
/* Do something with h->id and h->dev */
}
struct foo_clk_ops = {
.get_rate = foo_get_rate,
};
struct foo_clk_driver_ops = {
.ops = &foo_clk_ops,
};
For drivers using the CCF, the implementation could look like
struct clk_gate *foo_gate;
int foo_probe(struct udevice *dev)
{
foo_gate = /* ... */;
}
int foo_request(struct clk_handle *h)
{
h->clk = foo_gate->clk;
}
struct foo_clk_driver_ops = {
.request = foo_request,
};
So why these changes?
- Clear separation between the different duties which are both
currently handled by struct clk
- Simplification for drivers using the CCF
- Minimal changes for existing users
- Clock consumers have almost the same api
- Every clock driver will need to be changed, but most
drivers which don't use CCF never use any fields in
clk other than ->dev and ->id
- No need to get the "canonical" clock, since it is pointed at
by clk_handle->clk
- Reduction in memory/driver usage since CCF clocks no longer
need a udevice for each clock
- Less function calls since each driver using CCF no longer
needs to be a proxy for clock ops
Now these are big changes, and definitely would be the subject of their
own patch series. As-is, I think the patch as it exists now is the best
way to get the most functionality from clk_composite with the least
changes to other code.
--Sean
next prev parent reply other threads:[~2020-01-30 5:47 UTC|newest]
Thread overview: 45+ messages / expand[flat|nested] mbox.gz Atom feed top
2020-01-15 22:45 [PATCH v2 00/11] riscv: Add Sipeed Maix support Sean Anderson
2020-01-15 22:47 ` [PATCH v2 01/11] clk: Always use the supplied struct clk Sean Anderson
[not found] ` <752D002CFF5D0F4FA35C0100F1D73F3FA46C88BE@ATCPCS16.andestech.com>
2020-01-21 1:54 ` Rick Chen
2020-01-21 2:02 ` Sean Anderson
2020-01-21 2:23 ` Rick Chen
2020-01-21 3:18 ` Sean Anderson
2020-01-23 5:53 ` Sean Anderson
2020-01-24 14:27 ` Lukasz Majewski
2020-01-24 23:22 ` Sean Anderson
2020-01-25 20:18 ` Lukasz Majewski
2020-01-26 21:20 ` Lukasz Majewski
2020-01-26 22:07 ` Sean Anderson
2020-01-27 23:40 ` Lukasz Majewski
2020-01-28 16:11 ` Sean Anderson
2020-01-30 0:29 ` Lukasz Majewski
2020-01-30 5:47 ` Sean Anderson [this message]
2020-01-31 9:18 ` Lukasz Majewski
2020-01-15 22:49 ` [PATCH v2 02/11] clk: Check that ops of composite clock components, exist before calling Sean Anderson
2020-01-26 21:25 ` Lukasz Majewski
2020-01-15 22:50 ` [PATCH v2 03/11] riscv: Add headers for asm/global_data.h Sean Anderson
[not found] ` <752D002CFF5D0F4FA35C0100F1D73F3FA46C88DF@ATCPCS16.andestech.com>
2020-01-21 2:07 ` Rick Chen
2020-01-21 2:17 ` Sean Anderson
2020-01-26 22:04 ` Lukas Auer
2020-01-26 22:12 ` Sean Anderson
2020-01-26 22:23 ` Lukas Auer
2020-01-15 22:51 ` [PATCH v2 04/11] riscv: Add an option to default to RV64I Sean Anderson
[not found] ` <752D002CFF5D0F4FA35C0100F1D73F3FA46C88FE@ATCPCS16.andestech.com>
2020-01-21 2:16 ` Rick Chen
2020-01-15 22:53 ` [PATCH v2 05/11] riscv: Add option to disable writes to mcounteren Sean Anderson
2020-01-26 22:09 ` Lukas Auer
2020-01-26 22:24 ` Sean Anderson
2020-01-30 22:13 ` Lukas Auer
2020-01-15 22:55 ` [PATCH v2 06/11] riscv: Fix incorrect cpu frequency on RV64 Sean Anderson
2020-01-26 22:04 ` Lukas Auer
2020-01-15 23:04 ` [PATCH v2 07/11] riscv: Add initial Sipeed Maix support Sean Anderson
2020-01-26 22:17 ` Lukas Auer
2020-01-27 1:09 ` Sean Anderson
2020-01-30 22:21 ` Lukas Auer
2020-02-02 6:06 ` Sean Anderson
2020-01-15 23:16 ` [PATCH v2 00/11] riscv: Add " Sean Anderson
2020-01-15 23:18 ` [PATCH v2 08/11] riscv: Add device tree for K210 Sean Anderson
[not found] ` <752D002CFF5D0F4FA35C0100F1D73F3FA46C8947@ATCPCS16.andestech.com>
2020-01-21 2:54 ` Rick Chen
2020-01-15 23:20 ` [PATCH v2 09/11] riscv: Add K210 sysctl support Sean Anderson
2020-01-15 23:24 ` [PATCH v2 10/11] riscv: Add K210 pll support Sean Anderson
2020-01-15 23:26 ` [PATCH v2 11/11] riscv: Add K210 clock support Sean Anderson
2020-01-21 3:46 ` [PATCH v2 08/11] riscv: Add device tree for K210 Sean Anderson
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=263ed00a-c396-bad6-9223-4579d9d2b0fa@gmail.com \
--to=seanga2@gmail.com \
--cc=u-boot@lists.denx.de \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox