[PATCH] imx: power-domain: enable parent power domain
Marek Vasut
marex at denx.de
Sun Jan 29 17:38:50 CET 2023
On 1/29/23 11:47, Patrick Wildt wrote:
> On Sun, Jan 29, 2023 at 05:00:15AM +0100, Marek Vasut wrote:
>> On 1/29/23 04:28, Patrick Wildt wrote:
>>> Am Sun, Jan 29, 2023 at 02:46:36AM +0100 schrieb Marek Vasut:
>>>> On 1/28/23 23:14, Patrick Wildt wrote:
>>>>> The PCIe power domains are dependant on each other, which is why
>>>>> the device tree makes both PCIe controllers reference the PCIe1
>>>>> power domain, which then depends on the PCIe2 power domain.
>>>>>
>>>>> Enabling the parent power domain used to be part of the driver,
>>>>> but got partially lost in the rewrite. Add the enable call back
>>>>> to be able to power up PCIe2.
>>>>>
>>>>> Signed-off-by: Patrick Wildt <patrick at blueri.se>
>>>>> ---
>>>>> drivers/power/domain/imx8m-power-domain.c | 3 +++
>>>>> 1 file changed, 3 insertions(+)
>>>>>
>>>>> diff --git a/drivers/power/domain/imx8m-power-domain.c b/drivers/power/domain/imx8m-power-domain.c
>>>>> index 145f6ec0cd..d8e9ce3291 100644
>>>>> --- a/drivers/power/domain/imx8m-power-domain.c
>>>>> +++ b/drivers/power/domain/imx8m-power-domain.c
>>>>> @@ -330,6 +330,9 @@ static int imx8m_power_domain_on(struct power_domain *power_domain)
>>>>> u32 pgc;
>>>>> int ret;
>>>>> + if (pdata->has_pd)
>>>>> + power_domain_on(&pdata->pd);
>>>>> +
>>>>> if (pdata->clk.count) {
>>>>> ret = clk_enable_bulk(&pdata->clk);
>>>>> if (ret) {
>>>>
>>>> One problem with this patch is that it does not turn the power domain back
>>>> OFF in imx8m_power_domain_off().
>>>
>>> That's not true. That function already turns the power domain off, it
>>> just never enables them in the first place. The enabling was lost when
>>> the code was rewritten to not use smcc but the disabling is still there:
>>>
>>> static int imx8m_power_domain_off(struct power_domain *power_domain)
>>> {
>>> (...)
>>> if (pdata->has_pd)
>>> power_domain_off(&pdata->pd);
>>>
>>> return 0;
>>> (...)
>>> }
>>
>> Doh, sorry, I did miss that one. Indeed, the imx power domain driver is not
>> symmetrical now.
>>
>>> What might be missing though is error handling to turn the power domain
>>> back off when enabling clocks/power up fails. In case this needs to be
>>> fixed elsewhere, then maybe we need to *remove* the call to power_domain_
>>> off().
>>>
>>>> However, the driver should not have to care about that. It is the uclass job
>>>> to turn on any prerequisite power domains, which I believe happens in:
>>>>
>>>> drivers/power/domain/power-domain-uclass.c
>>>> dev_power_domain_ctrl()
>>>>
>>>> However, I suspect the code fails to recurse through more than one level of
>>>> power domains and therefore doesn't enable the power domains all the way up
>>>> the power domain tree. I also think this would be the fix -- recurse in
>>>> dev_power_domain_ctrl() if there are upstream domains to enable, enable them
>>>> in that recursive call, and then enable the current power domain using
>>>> power_domain_on() .
>>>>
>>>> Can you take a closer look at the uclass and the way it enables (or fail to)
>>>> the upstream domains instead ?
>>>
>>> I guess one issue is that I was calling power_domain_on() directly instead of
>>> dev_power_domain_on() in my PCIe driver.
>>
>> That sounds like a good idea.
>>
>>> And maybe I shouldn't even need to
>>> have the PCIe driver call that one function anyway, maybe uclass is supposed
>>> to turn on my PCIe controllers power domain automatically.
>>
>> device_probe() does call dev_power_domain_on(), so that sounds like a good
>> idea too.
>>
>>> As you mentioned, there's no "parent handling" in dev_power_domain_ctrl().
>>> Something like this could work, but I'm not sure that's better. Also I can't
>>> judge if there are any other side-effects of this. Still feels a bit like a
>>> layer violation
>>
>> How so ?
>>
>>> , but maybe it's the right thing to do.
>>>
>>> for (i = 0; i < count; i++) {
>>> ret = power_domain_get_by_index(dev, &pd, i);
>>> if (ret)
>>> return ret;
>>> if (on) {
>>> ret = dev_power_domain_on(pd.dev);
>>> if (!ret)
>>> ret = power_domain_on(&pd);
>>> } else {
>>> ret = power_domain_off(&pd);
>>> if (!ret)
>>> ret = dev_power_domain_off(pd.dev);
>>> }
>>> }
>>>
>>> I'll give this a go after some sleep.
>>
>> I think this makes sense -- the domain should enable all its upstream
>> domains first, before enabling itself.
>>
>> It might also make sense to remove the aforementioned power_domain_off()
>> from imx8m-power-domain.c once the dev_power_domain_ctrl() is fixed.
>
> Just tested, this diff works for me. Should I send it as a patch to the
> list?
Yes please !
> One thing that worries me is that there's no refcounting to make sure
> that a parent that is used twice doesn't get disabled. That might be
> something to follow-up on.
I agree. Could you try and add that too ? Separate patch is fine.
> diff --git a/drivers/power/domain/power-domain-uclass.c b/drivers/power/domain/power-domain-uclass.c
> index f6286c70c1..3b3caf6164 100644
> --- a/drivers/power/domain/power-domain-uclass.c
> +++ b/drivers/power/domain/power-domain-uclass.c
> @@ -138,10 +138,15 @@ static int dev_power_domain_ctrl(struct udevice *dev, bool on)
> ret = power_domain_get_by_index(dev, &pd, i);
> if (ret)
> return ret;
> - if (on)
> - ret = power_domain_on(&pd);
> - else
> + if (on) {
> + ret = dev_power_domain_on(pd.dev);
You might want to add a fail path here:
if (ret)
goto err_power_on;
...
err_poewr_on:
... un-do the power on ...
> + if (!ret)
> + ret = power_domain_on(&pd);
> + } else {
> ret = power_domain_off(&pd);
> + if (!ret)
> + ret = dev_power_domain_off(pd.dev);
> + }
> }
>
> /*
[...]
More information about the U-Boot
mailing list