diff mbox series

[v1,1/2] clk: socfpga: Read the clock parent's register base in probe function

Message ID 1583742120-6661-2-git-send-email-chee.hong.ang@intel.com
State Accepted
Commit 32d630fc1d2eb935027f4a760e4830dc3f15040c
Headers show
Series Fix A10 clock driver crash after changes in DM core | expand

Commit Message

Ang, Chee Hong March 9, 2020, 8:21 a.m. UTC
From: Chee Hong Ang <chee.hong.ang at intel.com>

This commit (82de42fa14682d408da935adfb0f935354c5008f) calls child's
ofdata_to_platdata() method before the parent is probed in dm core.
This has caused the driver no longer able to get the correct parent
clock's register base in the ofdata_to_platdata() method because the
parent clocks will only be probed after the child's ofdata_to_platdata().
To resolve this, the clock parent's register base will only be retrieved
by the child in probe() method instead of ofdata_to_platdata().

Signed-off-by: Chee Hong Ang <chee.hong.ang at intel.com>
---
 drivers/clk/altera/clk-arria10.c | 40 ++++++++++++++++++----------------------
 1 file changed, 18 insertions(+), 22 deletions(-)

Comments

Tan, Ley Foon March 9, 2020, 9:05 a.m. UTC | #1
> -----Original Message-----
> From: Ang, Chee Hong <chee.hong.ang at intel.com>
> Sent: Monday, March 9, 2020 4:22 PM
> To: u-boot at lists.denx.de
> Cc: Marek Vasut <marex at denx.de>; Simon Goldschmidt
> <simon.k.r.goldschmidt at gmail.com>; See, Chin Liang
> <chin.liang.see at intel.com>; Tan, Ley Foon <ley.foon.tan at intel.com>;
> Westergreen, Dalon <dalon.westergreen at intel.com>; Ang, Chee Hong
> <chee.hong.ang at intel.com>
> Subject: [PATCH v1 1/2] clk: socfpga: Read the clock parent's register base in
> probe function
> 
> From: Chee Hong Ang <chee.hong.ang at intel.com>
> 
> This commit (82de42fa14682d408da935adfb0f935354c5008f) calls child's
> ofdata_to_platdata() method before the parent is probed in dm core.
> This has caused the driver no longer able to get the correct parent clock's
> register base in the ofdata_to_platdata() method because the parent clocks
> will only be probed after the child's ofdata_to_platdata().
> To resolve this, the clock parent's register base will only be retrieved by the
> child in probe() method instead of ofdata_to_platdata().
> 
> Signed-off-by: Chee Hong Ang <chee.hong.ang at intel.com>

Reviewed-by: Ley Foon Tan <ley.foon.tan at intel.com>
Marek Vasut March 9, 2020, 12:28 p.m. UTC | #2
On 3/9/20 9:21 AM, chee.hong.ang at intel.com wrote:
> From: Chee Hong Ang <chee.hong.ang at intel.com>
> 
> This commit (82de42fa14682d408da935adfb0f935354c5008f) calls child's
> ofdata_to_platdata() method before the parent is probed in dm core.
> This has caused the driver no longer able to get the correct parent
> clock's register base in the ofdata_to_platdata() method because the
> parent clocks will only be probed after the child's ofdata_to_platdata().
> To resolve this, the clock parent's register base will only be retrieved
> by the child in probe() method instead of ofdata_to_platdata().

You should be able to bind the drivers and resolve their register
offsets without probing them, so this look more like a bug in the driver
core ?

> Signed-off-by: Chee Hong Ang <chee.hong.ang at intel.com>
> ---
>  drivers/clk/altera/clk-arria10.c | 40 ++++++++++++++++++----------------------
>  1 file changed, 18 insertions(+), 22 deletions(-)
> 
> diff --git a/drivers/clk/altera/clk-arria10.c b/drivers/clk/altera/clk-arria10.c
> index affeb31..b7eed94 100644
> --- a/drivers/clk/altera/clk-arria10.c
> +++ b/drivers/clk/altera/clk-arria10.c
> @@ -274,6 +274,8 @@ static int socfpga_a10_clk_bind(struct udevice *dev)
>  static int socfpga_a10_clk_probe(struct udevice *dev)
>  {
>  	struct socfpga_a10_clk_platdata *plat = dev_get_platdata(dev);
> +	struct socfpga_a10_clk_platdata *pplat;
> +	struct udevice *pdev;
>  	const void *fdt = gd->fdt_blob;
>  	int offset = dev_of_offset(dev);
>  
> @@ -281,6 +283,21 @@ static int socfpga_a10_clk_probe(struct udevice *dev)
>  
>  	socfpga_a10_handoff_workaround(dev);
>  
> +	if (!fdt_node_check_compatible(fdt, offset, "altr,clk-mgr")) {
> +		plat->regs = devfdt_get_addr(dev);
> +	} else {
> +		pdev = dev_get_parent(dev);
> +		if (!pdev)
> +			return -ENODEV;
> +
> +		pplat = dev_get_platdata(pdev);
> +		if (!pplat)
> +			return -EINVAL;
> +
> +		plat->ctl_reg = dev_read_u32_default(dev, "reg", 0x0);
> +		plat->regs = pplat->regs;
> +	}
> +
>  	if (!fdt_node_check_compatible(fdt, offset,
>  				       "altr,socfpga-a10-pll-clock")) {
>  		/* Main PLL has 3 upstream clock */
> @@ -304,29 +321,8 @@ static int socfpga_a10_clk_probe(struct udevice *dev)
>  static int socfpga_a10_ofdata_to_platdata(struct udevice *dev)
>  {
>  	struct socfpga_a10_clk_platdata *plat = dev_get_platdata(dev);
> -	struct socfpga_a10_clk_platdata *pplat;
> -	struct udevice *pdev;
> -	const void *fdt = gd->fdt_blob;
>  	unsigned int divreg[3], gatereg[2];
> -	int ret, offset = dev_of_offset(dev);
> -	u32 regs;
> -
> -	regs = dev_read_u32_default(dev, "reg", 0x0);
> -
> -	if (!fdt_node_check_compatible(fdt, offset, "altr,clk-mgr")) {
> -		plat->regs = devfdt_get_addr(dev);
> -	} else {
> -		pdev = dev_get_parent(dev);
> -		if (!pdev)
> -			return -ENODEV;
> -
> -		pplat = dev_get_platdata(pdev);
> -		if (!pplat)
> -			return -EINVAL;
> -
> -		plat->ctl_reg = regs;
> -		plat->regs = pplat->regs;
> -	}
> +	int ret;
>  
>  	plat->type = SOCFPGA_A10_CLK_UNKNOWN_CLK;
>  
>
Ang, Chee Hong March 9, 2020, 12:52 p.m. UTC | #3
> On 3/9/20 9:21 AM, chee.hong.ang at intel.com wrote:
> > From: Chee Hong Ang <chee.hong.ang at intel.com>
> >
> > This commit (82de42fa14682d408da935adfb0f935354c5008f) calls child's
> > ofdata_to_platdata() method before the parent is probed in dm core.
> > This has caused the driver no longer able to get the correct parent
> > clock's register base in the ofdata_to_platdata() method because the
> > parent clocks will only be probed after the child's ofdata_to_platdata().
> > To resolve this, the clock parent's register base will only be
> > retrieved by the child in probe() method instead of ofdata_to_platdata().
> 
> You should be able to bind the drivers and resolve their register offsets without
> probing them, so this look more like a bug in the driver core ?
The problem is the children clock driver need to resolve/derive their register base
from their clock parents. With this new change, clock parents are still not yet
being initialized when the children clock drivers need to resolve their register base
from their parent.
A10 is not booting in mainline due to this issue.
I can't think of a better way to fix this. Should we fix the clock driver itself or the
DM core ?
> 
> > Signed-off-by: Chee Hong Ang <chee.hong.ang at intel.com>
> > ---
> >  drivers/clk/altera/clk-arria10.c | 40
> > ++++++++++++++++++----------------------
> >  1 file changed, 18 insertions(+), 22 deletions(-)
> >
> > diff --git a/drivers/clk/altera/clk-arria10.c
> > b/drivers/clk/altera/clk-arria10.c
> > index affeb31..b7eed94 100644
> > --- a/drivers/clk/altera/clk-arria10.c
> > +++ b/drivers/clk/altera/clk-arria10.c
> > @@ -274,6 +274,8 @@ static int socfpga_a10_clk_bind(struct udevice
> > *dev)  static int socfpga_a10_clk_probe(struct udevice *dev)  {
> >  	struct socfpga_a10_clk_platdata *plat = dev_get_platdata(dev);
> > +	struct socfpga_a10_clk_platdata *pplat;
> > +	struct udevice *pdev;
> >  	const void *fdt = gd->fdt_blob;
> >  	int offset = dev_of_offset(dev);
> >
> > @@ -281,6 +283,21 @@ static int socfpga_a10_clk_probe(struct udevice
> > *dev)
> >
> >  	socfpga_a10_handoff_workaround(dev);
> >
> > +	if (!fdt_node_check_compatible(fdt, offset, "altr,clk-mgr")) {
> > +		plat->regs = devfdt_get_addr(dev);
> > +	} else {
> > +		pdev = dev_get_parent(dev);
> > +		if (!pdev)
> > +			return -ENODEV;
> > +
> > +		pplat = dev_get_platdata(pdev);
> > +		if (!pplat)
> > +			return -EINVAL;
> > +
> > +		plat->ctl_reg = dev_read_u32_default(dev, "reg", 0x0);
> > +		plat->regs = pplat->regs;
> > +	}
> > +
> >  	if (!fdt_node_check_compatible(fdt, offset,
> >  				       "altr,socfpga-a10-pll-clock")) {
> >  		/* Main PLL has 3 upstream clock */ @@ -304,29 +321,8 @@
> static int
> > socfpga_a10_clk_probe(struct udevice *dev)  static int
> > socfpga_a10_ofdata_to_platdata(struct udevice *dev)  {
> >  	struct socfpga_a10_clk_platdata *plat = dev_get_platdata(dev);
> > -	struct socfpga_a10_clk_platdata *pplat;
> > -	struct udevice *pdev;
> > -	const void *fdt = gd->fdt_blob;
> >  	unsigned int divreg[3], gatereg[2];
> > -	int ret, offset = dev_of_offset(dev);
> > -	u32 regs;
> > -
> > -	regs = dev_read_u32_default(dev, "reg", 0x0);
> > -
> > -	if (!fdt_node_check_compatible(fdt, offset, "altr,clk-mgr")) {
> > -		plat->regs = devfdt_get_addr(dev);
> > -	} else {
> > -		pdev = dev_get_parent(dev);
> > -		if (!pdev)
> > -			return -ENODEV;
> > -
> > -		pplat = dev_get_platdata(pdev);
> > -		if (!pplat)
> > -			return -EINVAL;
> > -
> > -		plat->ctl_reg = regs;
> > -		plat->regs = pplat->regs;
> > -	}
> > +	int ret;
> >
> >  	plat->type = SOCFPGA_A10_CLK_UNKNOWN_CLK;
> >
> >
> 
> 
> --
> Best regards,
> Marek Vasut
Marek Vasut March 9, 2020, 12:53 p.m. UTC | #4
On 3/9/20 1:52 PM, Ang, Chee Hong wrote:
>> On 3/9/20 9:21 AM, chee.hong.ang at intel.com wrote:
>>> From: Chee Hong Ang <chee.hong.ang at intel.com>
>>>
>>> This commit (82de42fa14682d408da935adfb0f935354c5008f) calls child's
>>> ofdata_to_platdata() method before the parent is probed in dm core.
>>> This has caused the driver no longer able to get the correct parent
>>> clock's register base in the ofdata_to_platdata() method because the
>>> parent clocks will only be probed after the child's ofdata_to_platdata().
>>> To resolve this, the clock parent's register base will only be
>>> retrieved by the child in probe() method instead of ofdata_to_platdata().
>>
>> You should be able to bind the drivers and resolve their register offsets without
>> probing them, so this look more like a bug in the driver core ?
> The problem is the children clock driver need to resolve/derive their register base
> from their clock parents. With this new change, clock parents are still not yet
> being initialized when the children clock drivers need to resolve their register base
> from their parent.
> A10 is not booting in mainline due to this issue.
> I can't think of a better way to fix this. Should we fix the clock driver itself or the
> DM core ?

It seems more like a bug in the later, since the register offsets are in
the DT and reading out the DT information should be possible before
.probe() is called for any of the clock.
Simon Glass March 11, 2020, 11:50 a.m. UTC | #5
Hi,

On Mon, 9 Mar 2020 at 02:22, <chee.hong.ang at intel.com> wrote:
>
> From: Chee Hong Ang <chee.hong.ang at intel.com>
>
> This commit (82de42fa14682d408da935adfb0f935354c5008f) calls child's
> ofdata_to_platdata() method before the parent is probed in dm core.
> This has caused the driver no longer able to get the correct parent
> clock's register base in the ofdata_to_platdata() method because the
> parent clocks will only be probed after the child's ofdata_to_platdata().
> To resolve this, the clock parent's register base will only be retrieved
> by the child in probe() method instead of ofdata_to_platdata().

I think one thing that is going on here is that DM allows ofdata to be
read for a device before its parent devices have been read, but it
requires that parent devices be probed before their children.

The idea is that it should be possible to read the ofdata for a node
without needing to have done so for parents. But perhaps this
assumption is too brave?

I suspect we could change this, so that device_ofdata_to_platdata()
first calls itself on its parent.

I can think of various reasons why this change might be desirable.

>
> Signed-off-by: Chee Hong Ang <chee.hong.ang at intel.com>
> ---
>  drivers/clk/altera/clk-arria10.c | 40 ++++++++++++++++++----------------------
>  1 file changed, 18 insertions(+), 22 deletions(-)
>
> diff --git a/drivers/clk/altera/clk-arria10.c b/drivers/clk/altera/clk-arria10.c
> index affeb31..b7eed94 100644
> --- a/drivers/clk/altera/clk-arria10.c
> +++ b/drivers/clk/altera/clk-arria10.c
> @@ -274,6 +274,8 @@ static int socfpga_a10_clk_bind(struct udevice *dev)
>  static int socfpga_a10_clk_probe(struct udevice *dev)
>  {
>         struct socfpga_a10_clk_platdata *plat = dev_get_platdata(dev);
> +       struct socfpga_a10_clk_platdata *pplat;
> +       struct udevice *pdev;
>         const void *fdt = gd->fdt_blob;
>         int offset = dev_of_offset(dev);
>
> @@ -281,6 +283,21 @@ static int socfpga_a10_clk_probe(struct udevice *dev)
>
>         socfpga_a10_handoff_workaround(dev);
>
> +       if (!fdt_node_check_compatible(fdt, offset, "altr,clk-mgr")) {

This is strange to me. I think the idea here is to detect whether this
is the root clk node or one of the ones created in the bind() function
above. Is that right?

If so, it should be enough to say:

   if (dev_ofvalid(dev))

If you actually need to distinguish between different compatible
strings, you can use the .data member in your udevice_id table, with
dev_get_driver_data().

> +               plat->regs = devfdt_get_addr(dev);
> +       } else {
> +               pdev = dev_get_parent(dev);
> +               if (!pdev)
> +                       return -ENODEV;
> +
> +               pplat = dev_get_platdata(pdev);
> +               if (!pplat)
> +                       return -EINVAL;
> +
> +               plat->ctl_reg = dev_read_u32_default(dev, "reg", 0x0);
> +               plat->regs = pplat->regs;
> +       }
> +
>         if (!fdt_node_check_compatible(fdt, offset,
>                                        "altr,socfpga-a10-pll-clock")) {
>                 /* Main PLL has 3 upstream clock */
> @@ -304,29 +321,8 @@ static int socfpga_a10_clk_probe(struct udevice *dev)
>  static int socfpga_a10_ofdata_to_platdata(struct udevice *dev)
>  {
>         struct socfpga_a10_clk_platdata *plat = dev_get_platdata(dev);
> -       struct socfpga_a10_clk_platdata *pplat;
> -       struct udevice *pdev;
> -       const void *fdt = gd->fdt_blob;
>         unsigned int divreg[3], gatereg[2];
> -       int ret, offset = dev_of_offset(dev);
> -       u32 regs;
> -
> -       regs = dev_read_u32_default(dev, "reg", 0x0);
> -
> -       if (!fdt_node_check_compatible(fdt, offset, "altr,clk-mgr")) {
> -               plat->regs = devfdt_get_addr(dev);
> -       } else {
> -               pdev = dev_get_parent(dev);
> -               if (!pdev)
> -                       return -ENODEV;
> -
> -               pplat = dev_get_platdata(pdev);
> -               if (!pplat)
> -                       return -EINVAL;
> -
> -               plat->ctl_reg = regs;
> -               plat->regs = pplat->regs;
> -       }
> +       int ret;
>
>         plat->type = SOCFPGA_A10_CLK_UNKNOWN_CLK;
>
> --
> 2.7.4
>

Regards,
Simon
Marek Vasut March 11, 2020, 11:54 a.m. UTC | #6
On 3/11/20 12:50 PM, Simon Glass wrote:
> Hi,

Hi,

> On Mon, 9 Mar 2020 at 02:22, <chee.hong.ang at intel.com> wrote:
>>
>> From: Chee Hong Ang <chee.hong.ang at intel.com>
>>
>> This commit (82de42fa14682d408da935adfb0f935354c5008f) calls child's
>> ofdata_to_platdata() method before the parent is probed in dm core.
>> This has caused the driver no longer able to get the correct parent
>> clock's register base in the ofdata_to_platdata() method because the
>> parent clocks will only be probed after the child's ofdata_to_platdata().
>> To resolve this, the clock parent's register base will only be retrieved
>> by the child in probe() method instead of ofdata_to_platdata().
> 
> I think one thing that is going on here is that DM allows ofdata to be
> read for a device before its parent devices have been read, but it
> requires that parent devices be probed before their children.

This seems wrong. The clock driver should be able to instantiate devices
and read their ofdata without probing them. That is one of the core
design principles of the DM.

> The idea is that it should be possible to read the ofdata for a node
> without needing to have done so for parents. But perhaps this
> assumption is too brave?

Why is it brave ? That's how it always was, the DT is already there, so
why wouldn't you be able to read it.

> I suspect we could change this, so that device_ofdata_to_platdata()
> first calls itself on its parent.
> 
> I can think of various reasons why this change might be desirable.

I think this is how it worked before already.
Simon Glass March 11, 2020, 12:27 p.m. UTC | #7
Hi Marek,

On Wed, 11 Mar 2020 at 05:55, Marek Vasut <marex at denx.de> wrote:
>
> On 3/11/20 12:50 PM, Simon Glass wrote:
> > Hi,
>
> Hi,
>
> > On Mon, 9 Mar 2020 at 02:22, <chee.hong.ang at intel.com> wrote:
> >>
> >> From: Chee Hong Ang <chee.hong.ang at intel.com>
> >>
> >> This commit (82de42fa14682d408da935adfb0f935354c5008f) calls child's
> >> ofdata_to_platdata() method before the parent is probed in dm core.
> >> This has caused the driver no longer able to get the correct parent
> >> clock's register base in the ofdata_to_platdata() method because the
> >> parent clocks will only be probed after the child's ofdata_to_platdata().
> >> To resolve this, the clock parent's register base will only be retrieved
> >> by the child in probe() method instead of ofdata_to_platdata().
> >
> > I think one thing that is going on here is that DM allows ofdata to be
> > read for a device before its parent devices have been read, but it
> > requires that parent devices be probed before their children.
>
> This seems wrong. The clock driver should be able to instantiate devices
> and read their ofdata without probing them. That is one of the core
> design principles of the DM.

That's a different question. Yes you can read ofdata without probing a
device. That's why we have two methods.

The point I am making is that at present there is no requirement that
a parent's ofdata be read before a child's ofdata is read. But there
is a requirement that a parent be probed before a child is probed.

>
> > The idea is that it should be possible to read the ofdata for a node
> > without needing to have done so for parents. But perhaps this
> > assumption is too brave?
>
> Why is it brave ? That's how it always was, the DT is already there, so
> why wouldn't you be able to read it.

That was my thinking too. But we are finding in a few situations that
the child's ofdata depends on the parent's. For example, the parent
may have a base address, or a range mapping, or something else that is
needed for the child to correctly get its base address, etc.

>
> > I suspect we could change this, so that device_ofdata_to_platdata()
> > first calls itself on its parent.
> >
> > I can think of various reasons why this change might be desirable.
>
> I think this is how it worked before already.

Well effectively, yes, because ofdata and probe were joined together.

Regards,
Simon
diff mbox series

Patch

diff --git a/drivers/clk/altera/clk-arria10.c b/drivers/clk/altera/clk-arria10.c
index affeb31..b7eed94 100644
--- a/drivers/clk/altera/clk-arria10.c
+++ b/drivers/clk/altera/clk-arria10.c
@@ -274,6 +274,8 @@  static int socfpga_a10_clk_bind(struct udevice *dev)
 static int socfpga_a10_clk_probe(struct udevice *dev)
 {
 	struct socfpga_a10_clk_platdata *plat = dev_get_platdata(dev);
+	struct socfpga_a10_clk_platdata *pplat;
+	struct udevice *pdev;
 	const void *fdt = gd->fdt_blob;
 	int offset = dev_of_offset(dev);
 
@@ -281,6 +283,21 @@  static int socfpga_a10_clk_probe(struct udevice *dev)
 
 	socfpga_a10_handoff_workaround(dev);
 
+	if (!fdt_node_check_compatible(fdt, offset, "altr,clk-mgr")) {
+		plat->regs = devfdt_get_addr(dev);
+	} else {
+		pdev = dev_get_parent(dev);
+		if (!pdev)
+			return -ENODEV;
+
+		pplat = dev_get_platdata(pdev);
+		if (!pplat)
+			return -EINVAL;
+
+		plat->ctl_reg = dev_read_u32_default(dev, "reg", 0x0);
+		plat->regs = pplat->regs;
+	}
+
 	if (!fdt_node_check_compatible(fdt, offset,
 				       "altr,socfpga-a10-pll-clock")) {
 		/* Main PLL has 3 upstream clock */
@@ -304,29 +321,8 @@  static int socfpga_a10_clk_probe(struct udevice *dev)
 static int socfpga_a10_ofdata_to_platdata(struct udevice *dev)
 {
 	struct socfpga_a10_clk_platdata *plat = dev_get_platdata(dev);
-	struct socfpga_a10_clk_platdata *pplat;
-	struct udevice *pdev;
-	const void *fdt = gd->fdt_blob;
 	unsigned int divreg[3], gatereg[2];
-	int ret, offset = dev_of_offset(dev);
-	u32 regs;
-
-	regs = dev_read_u32_default(dev, "reg", 0x0);
-
-	if (!fdt_node_check_compatible(fdt, offset, "altr,clk-mgr")) {
-		plat->regs = devfdt_get_addr(dev);
-	} else {
-		pdev = dev_get_parent(dev);
-		if (!pdev)
-			return -ENODEV;
-
-		pplat = dev_get_platdata(pdev);
-		if (!pplat)
-			return -EINVAL;
-
-		plat->ctl_reg = regs;
-		plat->regs = pplat->regs;
-	}
+	int ret;
 
 	plat->type = SOCFPGA_A10_CLK_UNKNOWN_CLK;