diff mbox series

[v6,12/17] phy: sun4i-usb: Introduce port2 SIDDQ quirk

Message ID 20210519104152.21119-13-andre.przywara@arm.com
State New
Headers show
Series None | expand

Commit Message

Andre Przywara May 19, 2021, 10:41 a.m. UTC
At least the Allwinner H616 SoC requires a weird quirk to make most
USB PHYs work: Only port2 works out of the box, but all other ports
need some help from this port2 to work correctly: The CLK_BUS_PHY2 and
RST_USB_PHY2 clock and reset need to be enabled, and the SIDDQ bit in
the PMU PHY control register needs to be cleared. For this register to
be accessible, CLK_BUS_ECHI2 needs to be ungated. Don't ask ....

Instead of disguising this as some generic feature, do exactly that
in our PHY init:
If the quirk bit is set, and we initialise a PHY other than PHY2, ungate
this one special clock, and clear the SIDDQ bit. We can pull in the
other required clocks via the DT.

Signed-off-by: Andre Przywara <andre.przywara@arm.com>
---
 drivers/phy/allwinner/phy-sun4i-usb.c | 29 +++++++++++++++++++++++++++
 1 file changed, 29 insertions(+)

Comments

Maxime Ripard May 24, 2021, 11:59 a.m. UTC | #1
Hi

On Wed, May 19, 2021 at 11:41:47AM +0100, Andre Przywara wrote:
> At least the Allwinner H616 SoC requires a weird quirk to make most

> USB PHYs work: Only port2 works out of the box, but all other ports

> need some help from this port2 to work correctly: The CLK_BUS_PHY2 and

> RST_USB_PHY2 clock and reset need to be enabled, and the SIDDQ bit in

> the PMU PHY control register needs to be cleared. For this register to

> be accessible, CLK_BUS_ECHI2 needs to be ungated. Don't ask ....

> 

> Instead of disguising this as some generic feature, do exactly that

> in our PHY init:

> If the quirk bit is set, and we initialise a PHY other than PHY2, ungate

> this one special clock, and clear the SIDDQ bit. We can pull in the

> other required clocks via the DT.

> 

> Signed-off-by: Andre Przywara <andre.przywara@arm.com>


What is this SIDDQ bit doing exactly?

I guess we could also expose this using a power-domain if it's relevant?

Maxime
Jernej Škrabec May 24, 2021, 12:51 p.m. UTC | #2
Dne ponedeljek, 24. maj 2021 ob 13:59:46 CEST je Maxime Ripard napisal(a):
> Hi

> 

> On Wed, May 19, 2021 at 11:41:47AM +0100, Andre Przywara wrote:

> > At least the Allwinner H616 SoC requires a weird quirk to make most

> > USB PHYs work: Only port2 works out of the box, but all other ports

> > need some help from this port2 to work correctly: The CLK_BUS_PHY2 and

> > RST_USB_PHY2 clock and reset need to be enabled, and the SIDDQ bit in

> > the PMU PHY control register needs to be cleared. For this register to

> > be accessible, CLK_BUS_ECHI2 needs to be ungated. Don't ask ....

> > 

> > Instead of disguising this as some generic feature, do exactly that

> > in our PHY init:

> > If the quirk bit is set, and we initialise a PHY other than PHY2, ungate

> > this one special clock, and clear the SIDDQ bit. We can pull in the

> > other required clocks via the DT.

> > 

> > Signed-off-by: Andre Przywara <andre.przywara@arm.com>

> 

> What is this SIDDQ bit doing exactly?


If this is similar to Rockchip USB PHY, then this bit takes care for powering 
up/down analog parts of USB PHY:
https://elixir.bootlin.com/linux/latest/source/drivers/phy/rockchip/phy-rockchip-usb.c#L83

Best regards,
Jernej

> 

> I guess we could also expose this using a power-domain if it's relevant?

> 

> Maxime
Andre Przywara May 25, 2021, 11:29 a.m. UTC | #3
On Mon, 24 May 2021 13:59:46 +0200
Maxime Ripard <maxime@cerno.tech> wrote:

Hi Maxime,

> On Wed, May 19, 2021 at 11:41:47AM +0100, Andre Przywara wrote:

> > At least the Allwinner H616 SoC requires a weird quirk to make most

> > USB PHYs work: Only port2 works out of the box, but all other ports

> > need some help from this port2 to work correctly: The CLK_BUS_PHY2 and

> > RST_USB_PHY2 clock and reset need to be enabled, and the SIDDQ bit in

> > the PMU PHY control register needs to be cleared. For this register to

> > be accessible, CLK_BUS_ECHI2 needs to be ungated. Don't ask ....

> > 

> > Instead of disguising this as some generic feature, do exactly that

> > in our PHY init:

> > If the quirk bit is set, and we initialise a PHY other than PHY2, ungate

> > this one special clock, and clear the SIDDQ bit. We can pull in the

> > other required clocks via the DT.

> > 

> > Signed-off-by: Andre Przywara <andre.przywara@arm.com>  

> 

> What is this SIDDQ bit doing exactly?


I probably know as much as you do, but as Jernej pointed out, in some
Rockchip code it's indeed documented as some analogue PHY supply switch:
($ git grep -i siddq drivers/phy/rockchip)

In fact we had this pin/bit for ages, it was just hidden as BIT(1) in
our infamous PMU_UNK1 register. Patch 10/17 drags that into the light.

> I guess we could also expose this using a power-domain if it's relevant?


Mmmh, interesting idea. So are you thinking about registering a genpd
provider in sun4i_usb_phy_probe(), then having a power-domains property
in the ehci/ohci nodes, pointing to the PHY node? And if yes, should
the provider be a subnode of the USB PHY node, with a separate
compatible? That sounds a bit more involved, but would have the
advantage of allowing us to specify the resets and clocks from PHY2
there, and would look a bit cleaner than hacking them into the
other EHCI/OHCI nodes.

I would not touch the existing SoCs (even though it seems to apply to
them as well, just not in the exact same way), but I can give it a
try for the H616. It seems like the other SIDDQ bits (in the other
PHYs) are still needed for operation, but the PD provide could actually
take care of this as well.

Does that make sense or is this a bit over the top for just clearing an
extra bit?

Cheers,
Andre
Maxime Ripard June 7, 2021, 1:22 p.m. UTC | #4
Hi,

On Tue, May 25, 2021 at 12:29:01PM +0100, Andre Przywara wrote:
> On Mon, 24 May 2021 13:59:46 +0200

> Maxime Ripard <maxime@cerno.tech> wrote:

> 

> Hi Maxime,

> 

> > On Wed, May 19, 2021 at 11:41:47AM +0100, Andre Przywara wrote:

> > > At least the Allwinner H616 SoC requires a weird quirk to make most

> > > USB PHYs work: Only port2 works out of the box, but all other ports

> > > need some help from this port2 to work correctly: The CLK_BUS_PHY2 and

> > > RST_USB_PHY2 clock and reset need to be enabled, and the SIDDQ bit in

> > > the PMU PHY control register needs to be cleared. For this register to

> > > be accessible, CLK_BUS_ECHI2 needs to be ungated. Don't ask ....

> > > 

> > > Instead of disguising this as some generic feature, do exactly that

> > > in our PHY init:

> > > If the quirk bit is set, and we initialise a PHY other than PHY2, ungate

> > > this one special clock, and clear the SIDDQ bit. We can pull in the

> > > other required clocks via the DT.

> > > 

> > > Signed-off-by: Andre Przywara <andre.przywara@arm.com>  

> > 

> > What is this SIDDQ bit doing exactly?

> 

> I probably know as much as you do, but as Jernej pointed out, in some

> Rockchip code it's indeed documented as some analogue PHY supply switch:

> ($ git grep -i siddq drivers/phy/rockchip)

> 

> In fact we had this pin/bit for ages, it was just hidden as BIT(1) in

> our infamous PMU_UNK1 register. Patch 10/17 drags that into the light.


Ok

> > I guess we could also expose this using a power-domain if it's relevant?

> 

> Mmmh, interesting idea. So are you thinking about registering a genpd

> provider in sun4i_usb_phy_probe(), then having a power-domains property

> in the ehci/ohci nodes, pointing to the PHY node? And if yes, should

> the provider be a subnode of the USB PHY node, with a separate

> compatible? That sounds a bit more involved, but would have the

> advantage of allowing us to specify the resets and clocks from PHY2

> there, and would look a bit cleaner than hacking them into the

> other EHCI/OHCI nodes.


I'm not sure we need a separate device node, we could just register the
phy driver as a genpd provider, and then with an arg (so with
of_genpd_add_provider_onecell?) the index of the USB controller we want
to power up.

> I would not touch the existing SoCs (even though it seems to apply to

> them as well, just not in the exact same way), but I can give it a

> try for the H616. It seems like the other SIDDQ bits (in the other

> PHYs) are still needed for operation, but the PD provide could actually

> take care of this as well.

> 

> Does that make sense or is this a bit over the top for just clearing an

> extra bit?


Using what I described above should be fairly simple, so if we can fit
in an available and relevant abstraction, yeah, I guess :)

Maxime
Andre Przywara June 7, 2021, 2:17 p.m. UTC | #5
On Mon, 7 Jun 2021 15:22:55 +0200
Maxime Ripard <maxime@cerno.tech> wrote:

Hi Maxime,

> On Tue, May 25, 2021 at 12:29:01PM +0100, Andre Przywara wrote:

> > On Mon, 24 May 2021 13:59:46 +0200

> > Maxime Ripard <maxime@cerno.tech> wrote:

> > 

> > Hi Maxime,

> >   

> > > On Wed, May 19, 2021 at 11:41:47AM +0100, Andre Przywara wrote:  

> > > > At least the Allwinner H616 SoC requires a weird quirk to make most

> > > > USB PHYs work: Only port2 works out of the box, but all other ports

> > > > need some help from this port2 to work correctly: The CLK_BUS_PHY2 and

> > > > RST_USB_PHY2 clock and reset need to be enabled, and the SIDDQ bit in

> > > > the PMU PHY control register needs to be cleared. For this register to

> > > > be accessible, CLK_BUS_ECHI2 needs to be ungated. Don't ask ....

> > > > 

> > > > Instead of disguising this as some generic feature, do exactly that

> > > > in our PHY init:

> > > > If the quirk bit is set, and we initialise a PHY other than PHY2, ungate

> > > > this one special clock, and clear the SIDDQ bit. We can pull in the

> > > > other required clocks via the DT.

> > > > 

> > > > Signed-off-by: Andre Przywara <andre.przywara@arm.com>    

> > > 

> > > What is this SIDDQ bit doing exactly?  

> > 

> > I probably know as much as you do, but as Jernej pointed out, in some

> > Rockchip code it's indeed documented as some analogue PHY supply switch:

> > ($ git grep -i siddq drivers/phy/rockchip)

> > 

> > In fact we had this pin/bit for ages, it was just hidden as BIT(1) in

> > our infamous PMU_UNK1 register. Patch 10/17 drags that into the light.  

> 

> Ok

> 

> > > I guess we could also expose this using a power-domain if it's relevant?  

> > 

> > Mmmh, interesting idea. So are you thinking about registering a genpd

> > provider in sun4i_usb_phy_probe(), then having a power-domains property

> > in the ehci/ohci nodes, pointing to the PHY node? And if yes, should

> > the provider be a subnode of the USB PHY node, with a separate

> > compatible? That sounds a bit more involved, but would have the

> > advantage of allowing us to specify the resets and clocks from PHY2

> > there, and would look a bit cleaner than hacking them into the

> > other EHCI/OHCI nodes.  

> 

> I'm not sure we need a separate device node, we could just register the

> phy driver as a genpd provider, and then with an arg (so with

> of_genpd_add_provider_onecell?) the index of the USB controller we want

> to power up.


Yeah, I figured that myself meanwhile ;-) I now have a fairly nice
implementation, which does away with the extra clocks and resets from
the EHCI/OHCI nodes, and just adds one extra clock to the PHY node. The
rest is power domains properties.

> > I would not touch the existing SoCs (even though it seems to apply to

> > them as well, just not in the exact same way), but I can give it a

> > try for the H616. It seems like the other SIDDQ bits (in the other

> > PHYs) are still needed for operation, but the PD provide could actually

> > take care of this as well.

> > 

> > Does that make sense or is this a bit over the top for just clearing an

> > extra bit?  

> 

> Using what I described above should be fairly simple, so if we can fit

> in an available and relevant abstraction, yeah, I guess :)


Thanks!
I will post what I have, just need to find some solution for the RTC
clock bits.

Cheers,
Andre
Chen-Yu Tsai June 7, 2021, 2:26 p.m. UTC | #6
Hi,

On Mon, Jun 7, 2021 at 10:17 PM Andre Przywara <andre.przywara@arm.com> wrote:
>

> On Mon, 7 Jun 2021 15:22:55 +0200

> Maxime Ripard <maxime@cerno.tech> wrote:

>

> Hi Maxime,

>

> > On Tue, May 25, 2021 at 12:29:01PM +0100, Andre Przywara wrote:

> > > On Mon, 24 May 2021 13:59:46 +0200

> > > Maxime Ripard <maxime@cerno.tech> wrote:

> > >

> > > Hi Maxime,

> > >

> > > > On Wed, May 19, 2021 at 11:41:47AM +0100, Andre Przywara wrote:

> > > > > At least the Allwinner H616 SoC requires a weird quirk to make most

> > > > > USB PHYs work: Only port2 works out of the box, but all other ports

> > > > > need some help from this port2 to work correctly: The CLK_BUS_PHY2 and

> > > > > RST_USB_PHY2 clock and reset need to be enabled, and the SIDDQ bit in

> > > > > the PMU PHY control register needs to be cleared. For this register to

> > > > > be accessible, CLK_BUS_ECHI2 needs to be ungated. Don't ask ....

> > > > >

> > > > > Instead of disguising this as some generic feature, do exactly that

> > > > > in our PHY init:

> > > > > If the quirk bit is set, and we initialise a PHY other than PHY2, ungate

> > > > > this one special clock, and clear the SIDDQ bit. We can pull in the

> > > > > other required clocks via the DT.

> > > > >

> > > > > Signed-off-by: Andre Przywara <andre.przywara@arm.com>

> > > >

> > > > What is this SIDDQ bit doing exactly?

> > >

> > > I probably know as much as you do, but as Jernej pointed out, in some

> > > Rockchip code it's indeed documented as some analogue PHY supply switch:

> > > ($ git grep -i siddq drivers/phy/rockchip)

> > >

> > > In fact we had this pin/bit for ages, it was just hidden as BIT(1) in

> > > our infamous PMU_UNK1 register. Patch 10/17 drags that into the light.

> >

> > Ok

> >

> > > > I guess we could also expose this using a power-domain if it's relevant?

> > >

> > > Mmmh, interesting idea. So are you thinking about registering a genpd

> > > provider in sun4i_usb_phy_probe(), then having a power-domains property

> > > in the ehci/ohci nodes, pointing to the PHY node? And if yes, should

> > > the provider be a subnode of the USB PHY node, with a separate

> > > compatible? That sounds a bit more involved, but would have the

> > > advantage of allowing us to specify the resets and clocks from PHY2

> > > there, and would look a bit cleaner than hacking them into the

> > > other EHCI/OHCI nodes.

> >

> > I'm not sure we need a separate device node, we could just register the

> > phy driver as a genpd provider, and then with an arg (so with

> > of_genpd_add_provider_onecell?) the index of the USB controller we want

> > to power up.

>

> Yeah, I figured that myself meanwhile ;-) I now have a fairly nice

> implementation, which does away with the extra clocks and resets from

> the EHCI/OHCI nodes, and just adds one extra clock to the PHY node. The

> rest is power domains properties.


I'm wondering, since SIDDQ refers to the analog power for USB, it shouldn't
really affect the HCIs, only the PHYs. Is there any way to model it like
this and test it?

ChenYu

> > > I would not touch the existing SoCs (even though it seems to apply to

> > > them as well, just not in the exact same way), but I can give it a

> > > try for the H616. It seems like the other SIDDQ bits (in the other

> > > PHYs) are still needed for operation, but the PD provide could actually

> > > take care of this as well.

> > >

> > > Does that make sense or is this a bit over the top for just clearing an

> > > extra bit?

> >

> > Using what I described above should be fairly simple, so if we can fit

> > in an available and relevant abstraction, yeah, I guess :)

>

> Thanks!

> I will post what I have, just need to find some solution for the RTC

> clock bits.

>

> Cheers,

> Andre

>

> --

> You received this message because you are subscribed to the Google Groups "linux-sunxi" group.

> To unsubscribe from this group and stop receiving emails from it, send an email to linux-sunxi+unsubscribe@googlegroups.com.

> To view this discussion on the web, visit https://groups.google.com/d/msgid/linux-sunxi/20210607151742.2f05ff95%40slackpad.fritz.box.
Andre Przywara June 14, 2021, 12:20 a.m. UTC | #7
On Mon, 7 Jun 2021 22:26:02 +0800
Chen-Yu Tsai <wens@csie.org> wrote:

Hi Chen-Yu,

> On Mon, Jun 7, 2021 at 10:17 PM Andre Przywara <andre.przywara@arm.com> wrote:

> >

> > On Mon, 7 Jun 2021 15:22:55 +0200

> > Maxime Ripard <maxime@cerno.tech> wrote:

> >

> > Hi Maxime,

> >  

> > > On Tue, May 25, 2021 at 12:29:01PM +0100, Andre Przywara wrote:  

> > > > On Mon, 24 May 2021 13:59:46 +0200

> > > > Maxime Ripard <maxime@cerno.tech> wrote:

> > > >

> > > > Hi Maxime,

> > > >  

> > > > > On Wed, May 19, 2021 at 11:41:47AM +0100, Andre Przywara wrote:  

> > > > > > At least the Allwinner H616 SoC requires a weird quirk to make most

> > > > > > USB PHYs work: Only port2 works out of the box, but all other ports

> > > > > > need some help from this port2 to work correctly: The CLK_BUS_PHY2 and

> > > > > > RST_USB_PHY2 clock and reset need to be enabled, and the SIDDQ bit in

> > > > > > the PMU PHY control register needs to be cleared. For this register to

> > > > > > be accessible, CLK_BUS_ECHI2 needs to be ungated. Don't ask ....

> > > > > >

> > > > > > Instead of disguising this as some generic feature, do exactly that

> > > > > > in our PHY init:

> > > > > > If the quirk bit is set, and we initialise a PHY other than PHY2, ungate

> > > > > > this one special clock, and clear the SIDDQ bit. We can pull in the

> > > > > > other required clocks via the DT.

> > > > > >

> > > > > > Signed-off-by: Andre Przywara <andre.przywara@arm.com>  

> > > > >

> > > > > What is this SIDDQ bit doing exactly?  

> > > >

> > > > I probably know as much as you do, but as Jernej pointed out, in some

> > > > Rockchip code it's indeed documented as some analogue PHY supply switch:

> > > > ($ git grep -i siddq drivers/phy/rockchip)

> > > >

> > > > In fact we had this pin/bit for ages, it was just hidden as BIT(1) in

> > > > our infamous PMU_UNK1 register. Patch 10/17 drags that into the light.  

> > >

> > > Ok

> > >  

> > > > > I guess we could also expose this using a power-domain if it's relevant?  

> > > >

> > > > Mmmh, interesting idea. So are you thinking about registering a genpd

> > > > provider in sun4i_usb_phy_probe(), then having a power-domains property

> > > > in the ehci/ohci nodes, pointing to the PHY node? And if yes, should

> > > > the provider be a subnode of the USB PHY node, with a separate

> > > > compatible? That sounds a bit more involved, but would have the

> > > > advantage of allowing us to specify the resets and clocks from PHY2

> > > > there, and would look a bit cleaner than hacking them into the

> > > > other EHCI/OHCI nodes.  

> > >

> > > I'm not sure we need a separate device node, we could just register the

> > > phy driver as a genpd provider, and then with an arg (so with

> > > of_genpd_add_provider_onecell?) the index of the USB controller we want

> > > to power up.  

> >

> > Yeah, I figured that myself meanwhile ;-) I now have a fairly nice

> > implementation, which does away with the extra clocks and resets from

> > the EHCI/OHCI nodes, and just adds one extra clock to the PHY node. The

> > rest is power domains properties.  

> 

> I'm wondering, since SIDDQ refers to the analog power for USB, it shouldn't

> really affect the HCIs, only the PHYs. Is there any way to model it like

> this and test it?


That is actually a good point: it is indeed solely a PHY property. The
HCIs already connect to their PHYs, among other reasons to power them
on, so it should really be an internal PHY affair.
Which is actually what this patch here does.
So I can combine the best of both approaches: we already have the
PHY2 clock and reset references in the PHY node, so can just reach out
and enable them as well, alongside the actually associated PHY clock.
This allows us to get rid of the bogus PHY2 clock references from all
HCIs.
So all of this H616 quirk can be fully contained within the PHY driver,
with no impact on the HCI parts and no extra DT properties
(power-domains, clocks) needed there.

Seems to work on a quick test. I will send a version ASAP.

Thanks!
Andre

> 

> ChenYu

> 

> > > > I would not touch the existing SoCs (even though it seems to apply to

> > > > them as well, just not in the exact same way), but I can give it a

> > > > try for the H616. It seems like the other SIDDQ bits (in the other

> > > > PHYs) are still needed for operation, but the PD provide could actually

> > > > take care of this as well.

> > > >

> > > > Does that make sense or is this a bit over the top for just clearing an

> > > > extra bit?  

> > >

> > > Using what I described above should be fairly simple, so if we can fit

> > > in an available and relevant abstraction, yeah, I guess :)  

> >

> > Thanks!

> > I will post what I have, just need to find some solution for the RTC

> > clock bits.

> >

> > Cheers,

> > Andre

> >
diff mbox series

Patch

diff --git a/drivers/phy/allwinner/phy-sun4i-usb.c b/drivers/phy/allwinner/phy-sun4i-usb.c
index 126ef74d013c..ed7b9cc5a424 100644
--- a/drivers/phy/allwinner/phy-sun4i-usb.c
+++ b/drivers/phy/allwinner/phy-sun4i-usb.c
@@ -120,6 +120,7 @@  struct sun4i_usb_phy_cfg {
 	u8 phyctl_offset;
 	bool dedicated_clocks;
 	bool phy0_dual_route;
+	bool needs_phy2_siddq;
 	int missing_phys;
 };
 
@@ -331,6 +332,27 @@  static int sun4i_usb_phy_init(struct phy *_phy)
 		queue_delayed_work(system_wq, &data->detect, 0);
 	}
 
+	/* Some PHYs on some SoCs need the help of PHY2 to work. */
+	if (data->cfg->needs_phy2_siddq && phy->index != 2) {
+		struct sun4i_usb_phy *phy2 = &data->phys[2];
+
+		/*
+		 * This extra clock is just needed to access the
+		 * REG_HCI_PHY_CTL PMU register for PHY2.
+		 */
+		ret = clk_prepare_enable(phy2->clk2);
+		if (ret)
+			return ret;
+
+		if (phy2->pmu && data->cfg->hci_phy_ctl_clear) {
+			val = readl(phy2->pmu + REG_HCI_PHY_CTL);
+			val &= ~data->cfg->hci_phy_ctl_clear;
+			writel(val, phy2->pmu + REG_HCI_PHY_CTL);
+		}
+
+		clk_disable_unprepare(phy->clk2);
+	}
+
 	return 0;
 }
 
@@ -785,6 +807,13 @@  static int sun4i_usb_phy_probe(struct platform_device *pdev)
 				dev_err(dev, "failed to get clock %s\n", name);
 				return PTR_ERR(phy->clk2);
 			}
+		} else {
+			snprintf(name, sizeof(name), "pmu%d_clk", i);
+			phy->clk2 = devm_clk_get_optional(dev, name);
+			if (IS_ERR(phy->clk2)) {
+				dev_err(dev, "failed to get clock %s\n", name);
+				return PTR_ERR(phy->clk2);
+			}
 		}
 
 		snprintf(name, sizeof(name), "usb%d_reset", i);