diff mbox

[RFC,06/15] drm/armada: move variant initialisation to CRTC init

Message ID E1X3NMM-0000A5-N5@rmk-PC.arm.linux.org.uk (mailing list archive)
State New, archived
Headers show

Commit Message

Russell King July 5, 2014, 10:38 a.m. UTC
Move the variant initialisation entirely to the CRTC init function -
the variant support is really about the CRTC properties than the whole
system, and we want to treat each CRTC individually when we support DT.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 drivers/gpu/drm/armada/armada_510.c  | 19 ++++++++-----------
 drivers/gpu/drm/armada/armada_crtc.c |  2 +-
 drivers/gpu/drm/armada/armada_crtc.h |  1 +
 drivers/gpu/drm/armada/armada_drm.h  |  6 ++----
 drivers/gpu/drm/armada/armada_drv.c  |  4 ----
 5 files changed, 12 insertions(+), 20 deletions(-)

Comments

Sebastian Hesselbarth July 5, 2014, 11:58 a.m. UTC | #1
On 07/05/2014 12:38 PM, Russell King wrote:
> Move the variant initialisation entirely to the CRTC init function -
> the variant support is really about the CRTC properties than the whole
> system, and we want to treat each CRTC individually when we support DT.
> 
> Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
> ---
[...]
> diff --git a/drivers/gpu/drm/armada/armada_crtc.h b/drivers/gpu/drm/armada/armada_crtc.h
> index 531a9b0bdcfb..3f0e70bb2e9c 100644
> --- a/drivers/gpu/drm/armada/armada_crtc.h
> +++ b/drivers/gpu/drm/armada/armada_crtc.h
> @@ -38,6 +38,7 @@ struct armada_crtc {
>  	unsigned		num;
>  	void __iomem		*base;
>  	struct clk		*clk;
> +	struct clk		*extclk[2];

Russell,

I wonder, if we should rename above array srcclk instead of extclk
while moving it anyway. That way we can use it for the other variant
specific clocks, too.

FWIW, I totally agree the it was the right thing to wait for you
to sort out the dependencies. Good work, great patience.

Sebastian
Russell King - ARM Linux July 5, 2014, 12:21 p.m. UTC | #2
On Sat, Jul 05, 2014 at 01:58:37PM +0200, Sebastian Hesselbarth wrote:
> On 07/05/2014 12:38 PM, Russell King wrote:
> > Move the variant initialisation entirely to the CRTC init function -
> > the variant support is really about the CRTC properties than the whole
> > system, and we want to treat each CRTC individually when we support DT.
> > 
> > Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
> > ---
> [...]
> > diff --git a/drivers/gpu/drm/armada/armada_crtc.h b/drivers/gpu/drm/armada/armada_crtc.h
> > index 531a9b0bdcfb..3f0e70bb2e9c 100644
> > --- a/drivers/gpu/drm/armada/armada_crtc.h
> > +++ b/drivers/gpu/drm/armada/armada_crtc.h
> > @@ -38,6 +38,7 @@ struct armada_crtc {
> >  	unsigned		num;
> >  	void __iomem		*base;
> >  	struct clk		*clk;
> > +	struct clk		*extclk[2];
> 
> Russell,
> 
> I wonder, if we should rename above array srcclk instead of extclk
> while moving it anyway. That way we can use it for the other variant
> specific clocks, too.

pixelclk may be a better name for it.  I would like to think about the
clock handling further though - the issues surrounding clock selection
are not limited to just Armada - imx-drm has the exact same problem.

The issue with clocking of CRTCs is that it seems to be common that:

1. you have multiple clocks to choose from, some of which may be more
   suitable than others depending on the type of output.

2. clocks end up being shared between multiple CRTCs, and one CRTC
   can (at the moment) interfere with the clock rate delivered to
   another CRTC.

This happens on imx-drm today, where the two DIs (CRTCs) are in use -
one for HDMI, the other for LVDS.  We end up with HDMI set first to
148.5MHz, and then LVDS sets it's clock to 65MHz, which results in
HDMI receiving a clock at over 500MHz!  At the moment, there are hacks
to solve this by adjusting the muxes in the clock paths to ensure that
they both derive from different PLLs - moving the LVDS onto the USB OTG
PLL rather than the video PLL.  That works fine until USB OTG wants
to change the OTG PLL.

There's also the issue whether the output can cope with fractional
clock-skipping dividers - entirely synchronous display systems can
(such as synchronously clocked LCD panels), but asynchronous display
systems (such as HDMI, TV out, etc) can't.  That said, the other
parameter that needs to be taken account of here is that even with the
fractional divider, the minimum output clock period isn't the average
frequency, but the maximum frequency, which may violate a panel's minimum
clock period specification.

I think there's lots to do on the clocking side, and as it's a fairly
complex problem which is common to multiple implementations, I think
that any solution should not be specific.

However, this topic isn't one which I want to work on until I have
reduced down my patch sets to something more manageable - something
which I'm desperate to do.  (I've been trying to avoid adding any
further patches to any tree for some time now.)  This is why (eg) I'm
not going to fix the kernel oops-able bugs I found in the SGTL5000
codec - someone else can do that.
Sebastian Hesselbarth July 6, 2014, 9:46 a.m. UTC | #3
On 07/05/2014 02:21 PM, Russell King - ARM Linux wrote:
> On Sat, Jul 05, 2014 at 01:58:37PM +0200, Sebastian Hesselbarth wrote:
>> On 07/05/2014 12:38 PM, Russell King wrote:
>>> Move the variant initialisation entirely to the CRTC init function -
>>> the variant support is really about the CRTC properties than the whole
>>> system, and we want to treat each CRTC individually when we support DT.
>>>
>>> Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
>>> ---
>> [...]
>>> diff --git a/drivers/gpu/drm/armada/armada_crtc.h b/drivers/gpu/drm/armada/armada_crtc.h
>>> index 531a9b0bdcfb..3f0e70bb2e9c 100644
>>> --- a/drivers/gpu/drm/armada/armada_crtc.h
>>> +++ b/drivers/gpu/drm/armada/armada_crtc.h
>>> @@ -38,6 +38,7 @@ struct armada_crtc {
>>>  	unsigned		num;
>>>  	void __iomem		*base;
>>>  	struct clk		*clk;
>>> +	struct clk		*extclk[2];
>>
>> I wonder, if we should rename above array srcclk instead of extclk
>> while moving it anyway. That way we can use it for the other variant
>> specific clocks, too.
> 
> pixelclk may be a better name for it.  I would like to think about the

The name was derived from the "SCLK_SOURCE_SELECT" bits in Dove FS, but
any other name not limited to external clocks is fine, too.

> clock handling further though - the issues surrounding clock selection
> are not limited to just Armada - imx-drm has the exact same problem.
> 
> The issue with clocking of CRTCs is that it seems to be common that:
> 
> 1. you have multiple clocks to choose from, some of which may be more
>    suitable than others depending on the type of output.

Given the limited capabilities of the internal clock dividers, on Dove
the heuristic seems to be fairly simple: always prefer the external
clock. This is true for all actively supported Dove boards (Cubox and
{d2,d3}plug) as all have an external PLL connected.

I'd even say to make the external clock mandatory. Hitting a standard
pixclk frequency with one of the internal clocks is pure coincidence.

As long as there is no board using anything else than HDMI transmitter
on dumb RGB, we shouldn't try to foresee any suitable heuristic.

> 2. clocks end up being shared between multiple CRTCs, and one CRTC
>    can (at the moment) interfere with the clock rate delivered to
>    another CRTC.
> 
> This happens on imx-drm today, where the two DIs (CRTCs) are in use -
> one for HDMI, the other for LVDS.  We end up with HDMI set first to
> 148.5MHz, and then LVDS sets it's clock to 65MHz, which results in
> HDMI receiving a clock at over 500MHz!  At the moment, there are hacks
> to solve this by adjusting the muxes in the clock paths to ensure that
> they both derive from different PLLs - moving the LVDS onto the USB OTG
> PLL rather than the video PLL.  That works fine until USB OTG wants
> to change the OTG PLL.

Again, luckily on Cubox we have 2 VCOs for the two external clocks
(audio and video) so we won't have to deal with it. For the {d2,d3}plug
I'll have to check the IDT datasheet again.

In particular, for imx maybe it is possible to identify some clock tree
configurations for specific use-cases. I don't think there is any non-
manual way to tell the best clock tree config.

> There's also the issue whether the output can cope with fractional
> clock-skipping dividers - entirely synchronous display systems can
> (such as synchronously clocked LCD panels), but asynchronous display
> systems (such as HDMI, TV out, etc) can't.  That said, the other
> parameter that needs to be taken account of here is that even with the
> fractional divider, the minimum output clock period isn't the average
> frequency, but the maximum frequency, which may violate a panel's minimum
> clock period specification.

Yeah, the fractional divider isn't made for external HDMI transmitters
for sure. I have seen from your branch that there is some Armada 610
stub for OLPC, do they have a dumb panel directly connected?

I also saw that they do have an external PLL, so maybe we should stick
to the external clock inputs as long as no other configurations pops-up
(which may never happen).

Sebastian

> I think there's lots to do on the clocking side, and as it's a fairly
> complex problem which is common to multiple implementations, I think
> that any solution should not be specific.
> 
> However, this topic isn't one which I want to work on until I have
> reduced down my patch sets to something more manageable - something
> which I'm desperate to do.  (I've been trying to avoid adding any
> further patches to any tree for some time now.)  This is why (eg) I'm
> not going to fix the kernel oops-able bugs I found in the SGTL5000
> codec - someone else can do that.
Russell King - ARM Linux July 9, 2014, 9:38 a.m. UTC | #4
On Sun, Jul 06, 2014 at 11:46:56AM +0200, Sebastian Hesselbarth wrote:
> On 07/05/2014 02:21 PM, Russell King - ARM Linux wrote:
> > There's also the issue whether the output can cope with fractional
> > clock-skipping dividers - entirely synchronous display systems can
> > (such as synchronously clocked LCD panels), but asynchronous display
> > systems (such as HDMI, TV out, etc) can't.  That said, the other
> > parameter that needs to be taken account of here is that even with the
> > fractional divider, the minimum output clock period isn't the average
> > frequency, but the maximum frequency, which may violate a panel's minimum
> > clock period specification.
> 
> Yeah, the fractional divider isn't made for external HDMI transmitters
> for sure. I have seen from your branch that there is some Armada 610
> stub for OLPC, do they have a dumb panel directly connected?

I believe they do have a dumb panel connected directly.  I've asked
Jon what the status of OLPC is with mainline kernels, and how difficult
it would be to get to the stage where the 610 stuff could be finished
off.
Russell King - ARM Linux July 11, 2014, 2:37 p.m. UTC | #5
On Sat, Jul 05, 2014 at 01:58:37PM +0200, Sebastian Hesselbarth wrote:
> On 07/05/2014 12:38 PM, Russell King wrote:
> > Move the variant initialisation entirely to the CRTC init function -
> > the variant support is really about the CRTC properties than the whole
> > system, and we want to treat each CRTC individually when we support DT.
> > 
> > Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
> > ---
> [...]
> > diff --git a/drivers/gpu/drm/armada/armada_crtc.h b/drivers/gpu/drm/armada/armada_crtc.h
> > index 531a9b0bdcfb..3f0e70bb2e9c 100644
> > --- a/drivers/gpu/drm/armada/armada_crtc.h
> > +++ b/drivers/gpu/drm/armada/armada_crtc.h
> > @@ -38,6 +38,7 @@ struct armada_crtc {
> >  	unsigned		num;
> >  	void __iomem		*base;
> >  	struct clk		*clk;
> > +	struct clk		*extclk[2];
> 
> Russell,
> 
> I wonder, if we should rename above array srcclk instead of extclk
> while moving it anyway. That way we can use it for the other variant
> specific clocks, too.

As the patches are prepared with this change, I'd prefer to submit them
as-is, and then we can update that as and when the support for things
like the MMP/610 is finished off.  I think they're good to go, so I'll
send them off later today to David.

This leaves the TDA998x componentisation patches which I need to kick
out, and the initial DT changes.  Once those are in place, we should
have almost all ducks lined up for working DRM support - it'll certainly
be advanced enough to describe the LCD controllers and the TDA998x as
three separate DT entities using the of graph helpers.

What's left is the display-subsystem { } entity to describe the makeup
of the subsystem.  That's not included as we currently need to pass
a block of memory, and the DT support for reserving chunks of memory
appeared (last time I looked) to only be botch-merged (only half of it
seems to have been merged making the whole reserved memory thing
totally useless - why people only half-merge features I've no idea.)
Sebastian Hesselbarth July 11, 2014, 3:18 p.m. UTC | #6
On 07/11/2014 04:37 PM, Russell King - ARM Linux wrote:
> On Sat, Jul 05, 2014 at 01:58:37PM +0200, Sebastian Hesselbarth wrote:
>> On 07/05/2014 12:38 PM, Russell King wrote:
>>> Move the variant initialisation entirely to the CRTC init function -
>>> the variant support is really about the CRTC properties than the whole
>>> system, and we want to treat each CRTC individually when we support DT.
>>>
>>> Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
>>> ---
>> [...]
>>> diff --git a/drivers/gpu/drm/armada/armada_crtc.h b/drivers/gpu/drm/armada/armada_crtc.h
>>> index 531a9b0bdcfb..3f0e70bb2e9c 100644
>>> --- a/drivers/gpu/drm/armada/armada_crtc.h
>>> +++ b/drivers/gpu/drm/armada/armada_crtc.h
>>> @@ -38,6 +38,7 @@ struct armada_crtc {
>>>   	unsigned		num;
>>>   	void __iomem		*base;
>>>   	struct clk		*clk;
>>> +	struct clk		*extclk[2];
>>
>> Russell,
>>
>> I wonder, if we should rename above array srcclk instead of extclk
>> while moving it anyway. That way we can use it for the other variant
>> specific clocks, too.
>
> As the patches are prepared with this change, I'd prefer to submit them
> as-is, and then we can update that as and when the support for things
> like the MMP/610 is finished off.  I think they're good to go, so I'll
> send them off later today to David.

Ok, sounds fine to me.

> This leaves the TDA998x componentisation patches which I need to kick
> out, and the initial DT changes.  Once those are in place, we should
> have almost all ducks lined up for working DRM support - it'll certainly
> be advanced enough to describe the LCD controllers and the TDA998x as
> three separate DT entities using the of graph helpers.

Ok.

> What's left is the display-subsystem { } entity to describe the makeup
> of the subsystem.  That's not included as we currently need to pass
> a block of memory, and the DT support for reserving chunks of memory
> appeared (last time I looked) to only be botch-merged (only half of it
> seems to have been merged making the whole reserved memory thing
> totally useless - why people only half-merge features I've no idea.)

There was a follow-up patch set for this some days ago
http://comments.gmane.org/gmane.linux.ports.arm.kernel/337686

Sebastian
Russell King - ARM Linux July 11, 2014, 3:24 p.m. UTC | #7
On Fri, Jul 11, 2014 at 05:18:50PM +0200, Sebastian Hesselbarth wrote:
> On 07/11/2014 04:37 PM, Russell King - ARM Linux wrote:
>> What's left is the display-subsystem { } entity to describe the makeup
>> of the subsystem.  That's not included as we currently need to pass
>> a block of memory, and the DT support for reserving chunks of memory
>> appeared (last time I looked) to only be botch-merged (only half of it
>> seems to have been merged making the whole reserved memory thing
>> totally useless - why people only half-merge features I've no idea.)
>
> There was a follow-up patch set for this some days ago
> http://comments.gmane.org/gmane.linux.ports.arm.kernel/337686

Yes, I did a bit of digging a while back and found the outstanding
stuff, but it wasn't clear what's happening with it.  As it isn't
part of mainline, and I don't want to pick up further patches to
add dependencies, I decided it was better to stick with old proven
ways of a manually declared platform device for the time being.
diff mbox

Patch

diff --git a/drivers/gpu/drm/armada/armada_510.c b/drivers/gpu/drm/armada/armada_510.c
index 59948eff6095..a9dabcaef92e 100644
--- a/drivers/gpu/drm/armada/armada_510.c
+++ b/drivers/gpu/drm/armada/armada_510.c
@@ -15,20 +15,19 @@ 
 #include "armada_drm.h"
 #include "armada_hw.h"
 
-static int armada510_init(struct armada_private *priv, struct device *dev)
+static int armada510_crtc_init(struct armada_crtc *dcrtc, struct device *dev)
 {
-	priv->extclk[0] = devm_clk_get(dev, "ext_ref_clk_1");
+	struct clk *clk;
 
-	if (IS_ERR(priv->extclk[0]) && PTR_ERR(priv->extclk[0]) == -ENOENT)
-		priv->extclk[0] = ERR_PTR(-EPROBE_DEFER);
+	clk = devm_clk_get(dev, "ext_ref_clk_1");
+	if (IS_ERR(clk))
+		return PTR_ERR(clk) == -ENOENT ? -EPROBE_DEFER : PTR_ERR(clk);
 
-	return PTR_RET(priv->extclk[0]);
-}
+	dcrtc->extclk[0] = clk;
 
-static int armada510_crtc_init(struct armada_crtc *dcrtc)
-{
 	/* Lower the watermark so to eliminate jitter at higher bandwidths */
 	armada_updatel(0x20, (1 << 11) | 0xff, dcrtc->base + LCD_CFG_RDREG4F);
+
 	return 0;
 }
 
@@ -45,8 +44,7 @@  static int armada510_crtc_init(struct armada_crtc *dcrtc)
 static int armada510_crtc_compute_clock(struct armada_crtc *dcrtc,
 	const struct drm_display_mode *mode, uint32_t *sclk)
 {
-	struct armada_private *priv = dcrtc->crtc.dev->dev_private;
-	struct clk *clk = priv->extclk[0];
+	struct clk *clk = dcrtc->extclk[0];
 	int ret;
 
 	if (dcrtc->num == 1)
@@ -81,7 +79,6 @@  static int armada510_crtc_compute_clock(struct armada_crtc *dcrtc,
 const struct armada_variant armada510_ops = {
 	.has_spu_adv_reg = true,
 	.spu_adv_reg = ADV_HWC32ENABLE | ADV_HWC32ARGB | ADV_HWC32BLEND,
-	.init = armada510_init,
 	.crtc_init = armada510_crtc_init,
 	.crtc_compute_clock = armada510_crtc_compute_clock,
 };
diff --git a/drivers/gpu/drm/armada/armada_crtc.c b/drivers/gpu/drm/armada/armada_crtc.c
index 4336dfd3585d..3adddabc3626 100644
--- a/drivers/gpu/drm/armada/armada_crtc.c
+++ b/drivers/gpu/drm/armada/armada_crtc.c
@@ -1108,7 +1108,7 @@  int armada_drm_crtc_create(struct drm_device *dev, struct resource *res,
 	}
 
 	if (priv->variant->crtc_init) {
-		ret = priv->variant->crtc_init(dcrtc);
+		ret = priv->variant->crtc_init(dcrtc, dev->dev);
 		if (ret) {
 			kfree(dcrtc);
 			return ret;
diff --git a/drivers/gpu/drm/armada/armada_crtc.h b/drivers/gpu/drm/armada/armada_crtc.h
index 531a9b0bdcfb..3f0e70bb2e9c 100644
--- a/drivers/gpu/drm/armada/armada_crtc.h
+++ b/drivers/gpu/drm/armada/armada_crtc.h
@@ -38,6 +38,7 @@  struct armada_crtc {
 	unsigned		num;
 	void __iomem		*base;
 	struct clk		*clk;
+	struct clk		*extclk[2];
 	struct {
 		uint32_t	spu_v_h_total;
 		uint32_t	spu_v_porch;
diff --git a/drivers/gpu/drm/armada/armada_drm.h b/drivers/gpu/drm/armada/armada_drm.h
index a72cae03b99b..a5452ae883d1 100644
--- a/drivers/gpu/drm/armada/armada_drm.h
+++ b/drivers/gpu/drm/armada/armada_drm.h
@@ -59,10 +59,9 @@  void armada_drm_vbl_event_remove_unlocked(struct armada_crtc *,
 struct armada_private;
 
 struct armada_variant {
-	bool	has_spu_adv_reg;
+	bool has_spu_adv_reg;
 	uint32_t spu_adv_reg;
-	int (*init)(struct armada_private *, struct device *);
-	int (*crtc_init)(struct armada_crtc *);
+	int (*crtc_init)(struct armada_crtc *, struct device *);
 	int (*crtc_compute_clock)(struct armada_crtc *,
 				  const struct drm_display_mode *,
 				  uint32_t *);
@@ -78,7 +77,6 @@  struct armada_private {
 	struct drm_fb_helper	*fbdev;
 	struct armada_crtc	*dcrtc[2];
 	struct drm_mm		linear;
-	struct clk		*extclk[2];
 	struct drm_property	*csc_yuv_prop;
 	struct drm_property	*csc_rgb_prop;
 	struct drm_property	*colorkey_prop;
diff --git a/drivers/gpu/drm/armada/armada_drv.c b/drivers/gpu/drm/armada/armada_drv.c
index add8b101fa9e..4939a86a2afc 100644
--- a/drivers/gpu/drm/armada/armada_drv.c
+++ b/drivers/gpu/drm/armada/armada_drv.c
@@ -130,10 +130,6 @@  static int armada_drm_load(struct drm_device *dev, unsigned long flags)
 
 	priv->variant = (struct armada_variant *)id->driver_data;
 
-	ret = priv->variant->init(priv, dev->dev);
-	if (ret)
-		return ret;
-
 	INIT_WORK(&priv->fb_unref_work, armada_drm_unref_work);
 	INIT_KFIFO(priv->fb_unref);