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 <patr...@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?

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.

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);
+                       if (!ret)
+                               ret = power_domain_on(&pd);
+               } else {
                        ret = power_domain_off(&pd);
+                       if (!ret)
+                               ret = dev_power_domain_off(pd.dev);
+               }
        }
 
        /*

Reply via email to