diff mbox

[BUG] hdlcd gets confused about base address

Message ID 20161118233733.GP1041@n2100.armlinux.org.uk (mailing list archive)
State New, archived
Headers show

Commit Message

Russell King (Oracle) Nov. 18, 2016, 11:37 p.m. UTC
Hi,

While testing HDMI with Xorg on the Juno board, I find that when Xorg
starts up or shuts down, the display is shifted significantly to the
right and wrapped in the active region.  (No sync bars are visible.)
The timings are correct, it behaves as if the start address has been
shifted many pixels _into_ the framebuffer.

This occurs whenever the display mode size is changed - using xrandr
in Xorg shows that changing the resolution triggers the problem
almost every time, but changing the refresh rate does not.

Using devmem2 to disable and re-enable the HDLCD resolves the issue,
and repeated disable/enable cycles do not make the issue re-appear.

So, I patched the HDLCD to do this, and testing it with Xorg after
several repetitions seems to work.

Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
---
What I think is going on is that the FIFO or address generator for
reading data from the AXI bus is not properly reset when changing the
resolution, and the enable-disable-enable cycle causes the HDLCD
hardware to sort itself out.  It's (eg) significantly out - for example,
to properly align the display, I have to program an address of
0xf4ff0200 into the hardware rather than 0xf5000000 - that's 896 pixels
before the real start of the frame buffer.

With this patch, a patch to TDA998x to avoid the i2c-designware issue,
and xf86-video-armada, I have LXDE running on the Juno.

Something I also noticed is this:

        scanout_start = gem->paddr + plane->state->fb->offsets[0] +
                plane->state->crtc_y * plane->state->fb->pitches[0] +
                plane->state->crtc_x * bpp / 8;

Surely this should be using src_[xy] (which are the position in the
source - iow, memory, and not crtc_[xy] which is the position on the
CRTC displayed window.  To put it another way, the src_* define the
region of the source material that is mapped onto a rectangular area
on the display defined by crtc_*.

Another note is that since the CRTC can't place the plane in arbitary
positions and sizes within the active area, should the atomic_check
ensure that crtc_x = crtc_y = 0, and the crtc width/height are the
size of the active area?

 drivers/gpu/drm/arm/hdlcd_crtc.c |    2 ++
 1 file changed, 2 insertions(+)

Comments

Daniel Vetter Nov. 21, 2016, 9:44 a.m. UTC | #1
On Fri, Nov 18, 2016 at 11:37:33PM +0000, Russell King - ARM Linux wrote:
> Hi,
> 
> While testing HDMI with Xorg on the Juno board, I find that when Xorg
> starts up or shuts down, the display is shifted significantly to the
> right and wrapped in the active region.  (No sync bars are visible.)
> The timings are correct, it behaves as if the start address has been
> shifted many pixels _into_ the framebuffer.
> 
> This occurs whenever the display mode size is changed - using xrandr
> in Xorg shows that changing the resolution triggers the problem
> almost every time, but changing the refresh rate does not.
> 
> Using devmem2 to disable and re-enable the HDLCD resolves the issue,
> and repeated disable/enable cycles do not make the issue re-appear.
> 
> So, I patched the HDLCD to do this, and testing it with Xorg after
> several repetitions seems to work.
> 
> Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
> ---
> What I think is going on is that the FIFO or address generator for
> reading data from the AXI bus is not properly reset when changing the
> resolution, and the enable-disable-enable cycle causes the HDLCD
> hardware to sort itself out.  It's (eg) significantly out - for example,
> to properly align the display, I have to program an address of
> 0xf4ff0200 into the hardware rather than 0xf5000000 - that's 896 pixels
> before the real start of the frame buffer.
> 
> With this patch, a patch to TDA998x to avoid the i2c-designware issue,
> and xf86-video-armada, I have LXDE running on the Juno.
> 
> Something I also noticed is this:
> 
>         scanout_start = gem->paddr + plane->state->fb->offsets[0] +
>                 plane->state->crtc_y * plane->state->fb->pitches[0] +
>                 plane->state->crtc_x * bpp / 8;
> 
> Surely this should be using src_[xy] (which are the position in the
> source - iow, memory, and not crtc_[xy] which is the position on the
> CRTC displayed window.  To put it another way, the src_* define the
> region of the source material that is mapped onto a rectangular area
> on the display defined by crtc_*.
> 
> Another note is that since the CRTC can't place the plane in arbitary
> positions and sizes within the active area, should the atomic_check
> ensure that crtc_x = crtc_y = 0, and the crtc width/height are the
> size of the active area?

Yup, it should. See drm_plane_helper_check_state() and its caller for a
helper to make this easier. Long-term computing this stuff by default and
having a bunch of igts to regression-test it would be good I think, but
that needs CRC support. And lots of work, since we have lots of drivers.
-Daniel

> 
>  drivers/gpu/drm/arm/hdlcd_crtc.c |    2 ++
>  1 file changed, 2 insertions(+)
> 
> diff --git a/drivers/gpu/drm/arm/hdlcd_crtc.c b/drivers/gpu/drm/arm/hdlcd_crtc.c
> index 48019ae22ddb..3e97acf6e2a7 100644
> --- a/drivers/gpu/drm/arm/hdlcd_crtc.c
> +++ b/drivers/gpu/drm/arm/hdlcd_crtc.c
> @@ -150,6 +150,8 @@ static void hdlcd_crtc_enable(struct drm_crtc *crtc)
>  	clk_prepare_enable(hdlcd->clk);
>  	hdlcd_crtc_mode_set_nofb(crtc);
>  	hdlcd_write(hdlcd, HDLCD_REG_COMMAND, 1);
> +	hdlcd_write(hdlcd, HDLCD_REG_COMMAND, 0);
> +	hdlcd_write(hdlcd, HDLCD_REG_COMMAND, 1);
>  }
>  
>  static void hdlcd_crtc_disable(struct drm_crtc *crtc)
> 
> 
> -- 
> RMK's Patch system: http://www.armlinux.org.uk/developer/patches/
> FTTC broadband for 0.8mile line: currently at 9.6Mbps down 400kbps up
> according to speedtest.net.
> _______________________________________________
> dri-devel mailing list
> dri-devel@lists.freedesktop.org
> https://lists.freedesktop.org/mailman/listinfo/dri-devel
Liviu Dudau Nov. 21, 2016, 11:06 a.m. UTC | #2
On Fri, Nov 18, 2016 at 11:37:33PM +0000, Russell King - ARM Linux wrote:
> Hi,

Hi Russell,

> 
> While testing HDMI with Xorg on the Juno board, I find that when Xorg
> starts up or shuts down, the display is shifted significantly to the
> right and wrapped in the active region.  (No sync bars are visible.)
> The timings are correct, it behaves as if the start address has been
> shifted many pixels _into_ the framebuffer.
> 
> This occurs whenever the display mode size is changed - using xrandr
> in Xorg shows that changing the resolution triggers the problem
> almost every time, but changing the refresh rate does not.

Thanks for reporting this. To double check your issue, you are booting
with HDLCD using the native monitor resolution as detected via EDID
and then using xrandr to change the display mode. When you do that you
are seeing the image being shifted to the right. Is that a correct
description? (I'm trying to reproduce it here and want to make sure 
I've got the details right).

> 
> Using devmem2 to disable and re-enable the HDLCD resolves the issue,
> and repeated disable/enable cycles do not make the issue re-appear.

Do you resize the display mode as well afer re-enabling HDLCD?

> 
> So, I patched the HDLCD to do this, and testing it with Xorg after
> several repetitions seems to work.
> 
> Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
> ---
> What I think is going on is that the FIFO or address generator for
> reading data from the AXI bus is not properly reset when changing the
> resolution, and the enable-disable-enable cycle causes the HDLCD
> hardware to sort itself out.

That is likely what is happening. According to the datasheet, changing
the resolution should be done while the HDLCD command mode is disabled,
which is what writing 0 into HDLCD_REG_COMMAND does.


> It's (eg) significantly out - for example,
> to properly align the display, I have to program an address of
> 0xf4ff0200 into the hardware rather than 0xf5000000 - that's 896 pixels
> before the real start of the frame buffer.

What is the resolution you are using?

> 
> With this patch, a patch to TDA998x to avoid the i2c-designware issue,
> and xf86-video-armada, I have LXDE running on the Juno.

Can you tell me more about the TDA998x and i2c-designware issue?
Also, I don't think you need to use xf86-video-armada, the mode-setting
driver built into Xorg should be working fine (that is what I've used
in my testing).

> 
> Something I also noticed is this:
> 
>         scanout_start = gem->paddr + plane->state->fb->offsets[0] +
>                 plane->state->crtc_y * plane->state->fb->pitches[0] +
>                 plane->state->crtc_x * bpp / 8;
> 
> Surely this should be using src_[xy] (which are the position in the
> source - iow, memory, and not crtc_[xy] which is the position on the
> CRTC displayed window.  To put it another way, the src_* define the
> region of the source material that is mapped onto a rectangular area
> on the display defined by crtc_*.

Yes, that is a bug and most likely the source of the issue that you are
seeing if my understanding of your testing is correct.

> 
> Another note is that since the CRTC can't place the plane in arbitary
> positions and sizes within the active area, should the atomic_check
> ensure that crtc_x = crtc_y = 0, and the crtc width/height are the
> size of the active area?

That should be the case, indeed. I'm going prepare a patch to do that.

> 
>  drivers/gpu/drm/arm/hdlcd_crtc.c |    2 ++
>  1 file changed, 2 insertions(+)
> 
> diff --git a/drivers/gpu/drm/arm/hdlcd_crtc.c b/drivers/gpu/drm/arm/hdlcd_crtc.c
> index 48019ae22ddb..3e97acf6e2a7 100644
> --- a/drivers/gpu/drm/arm/hdlcd_crtc.c
> +++ b/drivers/gpu/drm/arm/hdlcd_crtc.c
> @@ -150,6 +150,8 @@ static void hdlcd_crtc_enable(struct drm_crtc *crtc)
>  	clk_prepare_enable(hdlcd->clk);
>  	hdlcd_crtc_mode_set_nofb(crtc);
>  	hdlcd_write(hdlcd, HDLCD_REG_COMMAND, 1);
> +	hdlcd_write(hdlcd, HDLCD_REG_COMMAND, 0);
> +	hdlcd_write(hdlcd, HDLCD_REG_COMMAND, 1);

I am not convinced that this is the right fix. If anything, I would put a
hdlcd_write(hdlcd, HDLCD_REG_COMMAND, 0); line before hdlcd_crtc_mode_set_nofs(crtc);
line to make sure the command mode is disabled before setting the mode, but
again, I need to understand your use case to make sure that this indeed fixes it.

Best regards,
Liviu

>  }
>  
>  static void hdlcd_crtc_disable(struct drm_crtc *crtc)
> 
> 
> -- 
> RMK's Patch system: http://www.armlinux.org.uk/developer/patches/
> FTTC broadband for 0.8mile line: currently at 9.6Mbps down 400kbps up
> according to speedtest.net.
Russell King (Oracle) Nov. 21, 2016, 11:20 a.m. UTC | #3
On Mon, Nov 21, 2016 at 11:06:04AM +0000, Liviu Dudau wrote:
> On Fri, Nov 18, 2016 at 11:37:33PM +0000, Russell King - ARM Linux wrote:
> > Hi,
> 
> Hi Russell,
> 
> > 
> > While testing HDMI with Xorg on the Juno board, I find that when Xorg
> > starts up or shuts down, the display is shifted significantly to the
> > right and wrapped in the active region.  (No sync bars are visible.)
> > The timings are correct, it behaves as if the start address has been
> > shifted many pixels _into_ the framebuffer.
> > 
> > This occurs whenever the display mode size is changed - using xrandr
> > in Xorg shows that changing the resolution triggers the problem
> > almost every time, but changing the refresh rate does not.
> 
> Thanks for reporting this. To double check your issue, you are booting
> with HDLCD using the native monitor resolution as detected via EDID
> and then using xrandr to change the display mode. When you do that you
> are seeing the image being shifted to the right. Is that a correct
> description? (I'm trying to reproduce it here and want to make sure 
> I've got the details right).

I first noticed it when booting with the buggy I2C EDID reading, so
DRM wasn't seeing a valid EDID.  Then when Xorg started up and shut
down, I noticed that the framebuffer console was shifted.  It's actually
shifted to the left because framebuffer pixel 0,0 is not displayed.

> > Using devmem2 to disable and re-enable the HDLCD resolves the issue,
> > and repeated disable/enable cycles do not make the issue re-appear.
> 
> Do you resize the display mode as well afer re-enabling HDLCD?

I quite literally just did:

./devmem2 0x7ff60230 w 0; ./devmem2 0x7ff60230 w 1

(with a devmem2 fixed for ARM64) which immediately fixed the issue.

> > What I think is going on is that the FIFO or address generator for
> > reading data from the AXI bus is not properly reset when changing the
> > resolution, and the enable-disable-enable cycle causes the HDLCD
> > hardware to sort itself out.
> 
> That is likely what is happening. According to the datasheet, changing
> the resolution should be done while the HDLCD command mode is disabled,
> which is what writing 0 into HDLCD_REG_COMMAND does.

That does not appear to be sufficient.

> > It's (eg) significantly out - for example,
> > to properly align the display, I have to program an address of
> > 0xf4ff0200 into the hardware rather than 0xf5000000 - that's 896 pixels
> > before the real start of the frame buffer.
> 
> What is the resolution you are using?

In the case I detailed here, 1920x1080.

> > With this patch, a patch to TDA998x to avoid the i2c-designware issue,
> > and xf86-video-armada, I have LXDE running on the Juno.
> 
> Can you tell me more about the TDA998x and i2c-designware issue?
> Also, I don't think you need to use xf86-video-armada, the mode-setting
> driver built into Xorg should be working fine (that is what I've used
> in my testing).

See the i2c-designware thread on lakml.  It's a spontaneous high
interrupt latency causing the Tx FIFO not to be loaded before it
empties, and the i2c-designware crap decides at that point to
immediately generate an I2C stop.  The I2C controller in Juno can
only work reliably in a system which has guaranteed low interrupt
latencies.

> > Something I also noticed is this:
> > 
> >         scanout_start = gem->paddr + plane->state->fb->offsets[0] +
> >                 plane->state->crtc_y * plane->state->fb->pitches[0] +
> >                 plane->state->crtc_x * bpp / 8;
> > 
> > Surely this should be using src_[xy] (which are the position in the
> > source - iow, memory, and not crtc_[xy] which is the position on the
> > CRTC displayed window.  To put it another way, the src_* define the
> > region of the source material that is mapped onto a rectangular area
> > on the display defined by crtc_*.
> 
> Yes, that is a bug and most likely the source of the issue that you are
> seeing if my understanding of your testing is correct.

It isn't the source of this issue at all.  gem->paddr is 0xf5000000, and
the value programmed originally into the register is the same.  So, from
those two pieces of information, we can reasonably assume that crtc_y
and crtc_x were both zero here.

> > Another note is that since the CRTC can't place the plane in arbitary
> > positions and sizes within the active area, should the atomic_check
> > ensure that crtc_x = crtc_y = 0, and the crtc width/height are the
> > size of the active area?
> 
> That should be the case, indeed. I'm going prepare a patch to do that.

I've already a patch along the lines of Daniel Vetter's response to this
point which I'm just testing.

> > diff --git a/drivers/gpu/drm/arm/hdlcd_crtc.c b/drivers/gpu/drm/arm/hdlcd_crtc.c
> > index 48019ae22ddb..3e97acf6e2a7 100644
> > --- a/drivers/gpu/drm/arm/hdlcd_crtc.c
> > +++ b/drivers/gpu/drm/arm/hdlcd_crtc.c
> > @@ -150,6 +150,8 @@ static void hdlcd_crtc_enable(struct drm_crtc *crtc)
> >  	clk_prepare_enable(hdlcd->clk);
> >  	hdlcd_crtc_mode_set_nofb(crtc);
> >  	hdlcd_write(hdlcd, HDLCD_REG_COMMAND, 1);
> > +	hdlcd_write(hdlcd, HDLCD_REG_COMMAND, 0);
> > +	hdlcd_write(hdlcd, HDLCD_REG_COMMAND, 1);
> 
> I am not convinced that this is the right fix. If anything, I would put a
> hdlcd_write(hdlcd, HDLCD_REG_COMMAND, 0); line before hdlcd_crtc_mode_set_nofs(crtc);
> line to make sure the command mode is disabled before setting the mode, but
> again, I need to understand your use case to make sure that this indeed fixes it.

Maybe hdlcd shouldn't be implementing the ->enable callback but instead
the ->commit callback then?

I'll give it a try.
Liviu Dudau Nov. 21, 2016, 11:32 a.m. UTC | #4
On Mon, Nov 21, 2016 at 11:20:30AM +0000, Russell King - ARM Linux wrote:
> On Mon, Nov 21, 2016 at 11:06:04AM +0000, Liviu Dudau wrote:
> > On Fri, Nov 18, 2016 at 11:37:33PM +0000, Russell King - ARM Linux wrote:
> > > Hi,
> > 
> > Hi Russell,
> > 
> > > 
> > > While testing HDMI with Xorg on the Juno board, I find that when Xorg
> > > starts up or shuts down, the display is shifted significantly to the
> > > right and wrapped in the active region.  (No sync bars are visible.)
> > > The timings are correct, it behaves as if the start address has been
> > > shifted many pixels _into_ the framebuffer.
> > > 
> > > This occurs whenever the display mode size is changed - using xrandr
> > > in Xorg shows that changing the resolution triggers the problem
> > > almost every time, but changing the refresh rate does not.
> > 
> > Thanks for reporting this. To double check your issue, you are booting
> > with HDLCD using the native monitor resolution as detected via EDID
> > and then using xrandr to change the display mode. When you do that you
> > are seeing the image being shifted to the right. Is that a correct
> > description? (I'm trying to reproduce it here and want to make sure 
> > I've got the details right).
> 
> I first noticed it when booting with the buggy I2C EDID reading, so
> DRM wasn't seeing a valid EDID.  Then when Xorg started up and shut
> down, I noticed that the framebuffer console was shifted.  It's actually
> shifted to the left because framebuffer pixel 0,0 is not displayed.

I see. So the reason why I did not notice this was the EDID transfers
mostly working for me.

> 
> > > Using devmem2 to disable and re-enable the HDLCD resolves the issue,
> > > and repeated disable/enable cycles do not make the issue re-appear.
> > 
> > Do you resize the display mode as well afer re-enabling HDLCD?
> 
> I quite literally just did:
> 
> ./devmem2 0x7ff60230 w 0; ./devmem2 0x7ff60230 w 1

Sorry, was not very clear. Under my assumption that you were resizing the
display with xrandr, I was wondering if the issue you were seeing disappeared
when using devmem2 plus the resizing.

> 
> (with a devmem2 fixed for ARM64) which immediately fixed the issue.
> 
> > > What I think is going on is that the FIFO or address generator for
> > > reading data from the AXI bus is not properly reset when changing the
> > > resolution, and the enable-disable-enable cycle causes the HDLCD
> > > hardware to sort itself out.
> > 
> > That is likely what is happening. According to the datasheet, changing
> > the resolution should be done while the HDLCD command mode is disabled,
> > which is what writing 0 into HDLCD_REG_COMMAND does.
> 
> That does not appear to be sufficient.
> 
> > > It's (eg) significantly out - for example,
> > > to properly align the display, I have to program an address of
> > > 0xf4ff0200 into the hardware rather than 0xf5000000 - that's 896 pixels
> > > before the real start of the frame buffer.
> > 
> > What is the resolution you are using?
> 
> In the case I detailed here, 1920x1080.
> 
> > > With this patch, a patch to TDA998x to avoid the i2c-designware issue,
> > > and xf86-video-armada, I have LXDE running on the Juno.
> > 
> > Can you tell me more about the TDA998x and i2c-designware issue?
> > Also, I don't think you need to use xf86-video-armada, the mode-setting
> > driver built into Xorg should be working fine (that is what I've used
> > in my testing).
> 
> See the i2c-designware thread on lakml.  It's a spontaneous high
> interrupt latency causing the Tx FIFO not to be loaded before it
> empties, and the i2c-designware crap decides at that point to
> immediately generate an I2C stop.  The I2C controller in Juno can
> only work reliably in a system which has guaranteed low interrupt
> latencies.

Sorry, my email setup had a hickup and it was slow fetching all my emails.
I've seen the thread after replying in this thread.

> 
> > > Something I also noticed is this:
> > > 
> > >         scanout_start = gem->paddr + plane->state->fb->offsets[0] +
> > >                 plane->state->crtc_y * plane->state->fb->pitches[0] +
> > >                 plane->state->crtc_x * bpp / 8;
> > > 
> > > Surely this should be using src_[xy] (which are the position in the
> > > source - iow, memory, and not crtc_[xy] which is the position on the
> > > CRTC displayed window.  To put it another way, the src_* define the
> > > region of the source material that is mapped onto a rectangular area
> > > on the display defined by crtc_*.
> > 
> > Yes, that is a bug and most likely the source of the issue that you are
> > seeing if my understanding of your testing is correct.
> 
> It isn't the source of this issue at all.  gem->paddr is 0xf5000000, and
> the value programmed originally into the register is the same.  So, from
> those two pieces of information, we can reasonably assume that crtc_y
> and crtc_x were both zero here.

Yes, they should be zero all the time, as we don't support plane positioning
with HDLCD.

> 
> > > Another note is that since the CRTC can't place the plane in arbitary
> > > positions and sizes within the active area, should the atomic_check
> > > ensure that crtc_x = crtc_y = 0, and the crtc width/height are the
> > > size of the active area?
> > 
> > That should be the case, indeed. I'm going prepare a patch to do that.
> 
> I've already a patch along the lines of Daniel Vetter's response to this
> point which I'm just testing.

OK, let me know how it goes and please Cc me on it.


> 
> > > diff --git a/drivers/gpu/drm/arm/hdlcd_crtc.c b/drivers/gpu/drm/arm/hdlcd_crtc.c
> > > index 48019ae22ddb..3e97acf6e2a7 100644
> > > --- a/drivers/gpu/drm/arm/hdlcd_crtc.c
> > > +++ b/drivers/gpu/drm/arm/hdlcd_crtc.c
> > > @@ -150,6 +150,8 @@ static void hdlcd_crtc_enable(struct drm_crtc *crtc)
> > >  	clk_prepare_enable(hdlcd->clk);
> > >  	hdlcd_crtc_mode_set_nofb(crtc);
> > >  	hdlcd_write(hdlcd, HDLCD_REG_COMMAND, 1);
> > > +	hdlcd_write(hdlcd, HDLCD_REG_COMMAND, 0);
> > > +	hdlcd_write(hdlcd, HDLCD_REG_COMMAND, 1);
> > 
> > I am not convinced that this is the right fix. If anything, I would put a
> > hdlcd_write(hdlcd, HDLCD_REG_COMMAND, 0); line before hdlcd_crtc_mode_set_nofs(crtc);
> > line to make sure the command mode is disabled before setting the mode, but
> > again, I need to understand your use case to make sure that this indeed fixes it.
> 
> Maybe hdlcd shouldn't be implementing the ->enable callback but instead
> the ->commit callback then?

I believe we need ->enable for the initial setup (cold boot or module reloading).

Best regards,
Liviu

> 
> I'll give it a try.
> 
> -- 
> RMK's Patch system: http://www.armlinux.org.uk/developer/patches/
> FTTC broadband for 0.8mile line: currently at 9.6Mbps down 400kbps up
> according to speedtest.net.
Russell King (Oracle) Nov. 21, 2016, 12:25 p.m. UTC | #5
On Mon, Nov 21, 2016 at 11:32:12AM +0000, Liviu Dudau wrote:
> On Mon, Nov 21, 2016 at 11:20:30AM +0000, Russell King - ARM Linux wrote:
> > I first noticed it when booting with the buggy I2C EDID reading, so
> > DRM wasn't seeing a valid EDID.  Then when Xorg started up and shut
> > down, I noticed that the framebuffer console was shifted.  It's actually
> > shifted to the left because framebuffer pixel 0,0 is not displayed.
> 
> I see. So the reason why I did not notice this was the EDID transfers
> mostly working for me.

It also happens when EDID transfers work too!

> > > > Using devmem2 to disable and re-enable the HDLCD resolves the issue,
> > > > and repeated disable/enable cycles do not make the issue re-appear.
> > > 
> > > Do you resize the display mode as well afer re-enabling HDLCD?
> > 
> > I quite literally just did:
> > 
> > ./devmem2 0x7ff60230 w 0; ./devmem2 0x7ff60230 w 1
> 
> Sorry, was not very clear. Under my assumption that you were resizing the
> display with xrandr, I was wondering if the issue you were seeing disappeared
> when using devmem2 plus the resizing.

I think the problems are much deeper.  I've added this:

static void hdlcd_crtc_enable(struct drm_crtc *crtc)
{
        struct hdlcd_drm_private *hdlcd = crtc_to_hdlcd_priv(crtc);
printk("%s: active %d cmd %08x\n", __func__, crtc->state->active, hdlcd_read(hdlcd, HDLCD_REG_COMMAND));
        clk_prepare_enable(hdlcd->clk);

...
static void hdlcd_crtc_disable(struct drm_crtc *crtc)
{
        struct hdlcd_drm_private *hdlcd = crtc_to_hdlcd_priv(crtc);
printk("%s: active %d\n", __func__, crtc->state->active);
        if (!crtc->state->active)
                return;

What I see in the kernel log each time I change the resolution is:

[  221.409577] hdlcd_crtc_disable: active 0
[  221.430206] hdlcd_crtc_enable: active 1 cmd 00000001
[  239.264672] hdlcd_crtc_disable: active 0
[  239.285180] hdlcd_crtc_enable: active 1 cmd 00000001
[  278.712792] hdlcd_crtc_disable: active 0
[  278.730361] hdlcd_crtc_enable: active 1 cmd 00000001
[  281.633841] hdlcd_crtc_disable: active 0
[  281.668578] hdlcd_crtc_enable: active 1 cmd 00000001

So, when ->disable is called, active is always zero.  This
leads to...

$ head -n3 /sys/kernel/debug/clk/clk_summary
   clock                         enable_cnt  prepare_cnt        rate   accuracy
  phase
----------------------------------------------------------------------------------------
 pxlclk                                   6            6   148500000          0 0

the enable and prepare counts for this clock incrementing by one each
time I change the resolution.

> > Maybe hdlcd shouldn't be implementing the ->enable callback but instead
> > the ->commit callback then?
> 
> I believe we need ->enable for the initial setup (cold boot or module
> reloading).

Yes, I found a comment in DRM saying that ->commit is for legacy drivers
only.

I think the problem is that hdlcd is not really knowing what the true
state of the CRTC is, as illustrated by the clock counts increasing
and the state of crtc->state->active.

I'm wondering if this is a core DRM bug though... the comments and
code do not align:

/**
 * drm_atomic_helper_commit_tail - commit atomic update to hardware
 * @state: new modeset state to be committed

void drm_atomic_helper_commit_tail(struct drm_atomic_state *state)
{
        struct drm_device *dev = state->dev;

        drm_atomic_helper_commit_modeset_disables(dev, state);

/**
 * drm_atomic_helper_commit_modeset_disables - modeset commit to disable outputs * @dev: DRM device
 * @old_state: atomic state object with old state structures
void drm_atomic_helper_commit_modeset_disables(struct drm_device *dev,
                                               struct drm_atomic_state *old_state)

So, is "state" in drm_atomic_helper_commit_tail the old state or the
new state?  Should this state be passed to
drm_atomic_helper_commit_modeset_disables(), which seems to expect
the old state?

It looks _really_ screwed up here - in any case, it really doesn't
help when you're not experienced with atomic mode set to work out
what the hell this code is doing... it seems to be a horrible mess.
Maybe someone who understands this code ought to read through it
from the point of view of someone who doesn't understand it and fix
the comments, or get rid of the down-right misleading comments.

Comments are worse than useless if they mislead.  Better to have no
comments than misleading comments.

Daniel?
Liviu Dudau Nov. 21, 2016, 12:56 p.m. UTC | #6
On Mon, Nov 21, 2016 at 12:25:56PM +0000, Russell King - ARM Linux wrote:
> On Mon, Nov 21, 2016 at 11:32:12AM +0000, Liviu Dudau wrote:
> > On Mon, Nov 21, 2016 at 11:20:30AM +0000, Russell King - ARM Linux wrote:
> > > I first noticed it when booting with the buggy I2C EDID reading, so
> > > DRM wasn't seeing a valid EDID.  Then when Xorg started up and shut
> > > down, I noticed that the framebuffer console was shifted.  It's actually
> > > shifted to the left because framebuffer pixel 0,0 is not displayed.
> > 
> > I see. So the reason why I did not notice this was the EDID transfers
> > mostly working for me.
> 
> It also happens when EDID transfers work too!
> 
> > > > > Using devmem2 to disable and re-enable the HDLCD resolves the issue,
> > > > > and repeated disable/enable cycles do not make the issue re-appear.
> > > > 
> > > > Do you resize the display mode as well afer re-enabling HDLCD?
> > > 
> > > I quite literally just did:
> > > 
> > > ./devmem2 0x7ff60230 w 0; ./devmem2 0x7ff60230 w 1
> > 
> > Sorry, was not very clear. Under my assumption that you were resizing the
> > display with xrandr, I was wondering if the issue you were seeing disappeared
> > when using devmem2 plus the resizing.
> 
> I think the problems are much deeper.  I've added this:
> 
> static void hdlcd_crtc_enable(struct drm_crtc *crtc)
> {
>         struct hdlcd_drm_private *hdlcd = crtc_to_hdlcd_priv(crtc);
> printk("%s: active %d cmd %08x\n", __func__, crtc->state->active, hdlcd_read(hdlcd, HDLCD_REG_COMMAND));
>         clk_prepare_enable(hdlcd->clk);
> 
> ...
> static void hdlcd_crtc_disable(struct drm_crtc *crtc)
> {
>         struct hdlcd_drm_private *hdlcd = crtc_to_hdlcd_priv(crtc);
> printk("%s: active %d\n", __func__, crtc->state->active);
>         if (!crtc->state->active)
>                 return;
> 
> What I see in the kernel log each time I change the resolution is:
> 
> [  221.409577] hdlcd_crtc_disable: active 0
> [  221.430206] hdlcd_crtc_enable: active 1 cmd 00000001
> [  239.264672] hdlcd_crtc_disable: active 0
> [  239.285180] hdlcd_crtc_enable: active 1 cmd 00000001
> [  278.712792] hdlcd_crtc_disable: active 0
> [  278.730361] hdlcd_crtc_enable: active 1 cmd 00000001
> [  281.633841] hdlcd_crtc_disable: active 0
> [  281.668578] hdlcd_crtc_enable: active 1 cmd 00000001
> 
> So, when ->disable is called, active is always zero.  

That is expected, the DRM framework will determine that the crtc is no longer active and
call ->disable hook on the CRTC helper struct.

> This leads to...
> 
> $ head -n3 /sys/kernel/debug/clk/clk_summary
>    clock                         enable_cnt  prepare_cnt        rate   accuracy
>   phase
> ----------------------------------------------------------------------------------------
>  pxlclk                                   6            6   148500000          0 0
> 
> the enable and prepare counts for this clock incrementing by one each
> time I change the resolution.

That is mostly due to the check in hdlcd_crtc_disable() which I should remove,
I've added it because I was getting a ->disable() hook call before any ->enable()
was called at startup time. I need to revisit this as I remember Daniel was commenting
that this was not needed.

> 
> > > Maybe hdlcd shouldn't be implementing the ->enable callback but instead
> > > the ->commit callback then?
> > 
> > I believe we need ->enable for the initial setup (cold boot or module
> > reloading).
> 
> Yes, I found a comment in DRM saying that ->commit is for legacy drivers
> only.
> 
> I think the problem is that hdlcd is not really knowing what the true
> state of the CRTC is, as illustrated by the clock counts increasing
> and the state of crtc->state->active.

I think crtc->state->active is correct, we are just not acting as we should
in HDLCD.

> 
> I'm wondering if this is a core DRM bug though... the comments and
> code do not align:
> 
> /**
>  * drm_atomic_helper_commit_tail - commit atomic update to hardware
>  * @state: new modeset state to be committed
> 
> void drm_atomic_helper_commit_tail(struct drm_atomic_state *state)
> {
>         struct drm_device *dev = state->dev;
> 
>         drm_atomic_helper_commit_modeset_disables(dev, state);
> 
> /**
>  * drm_atomic_helper_commit_modeset_disables - modeset commit to disable outputs * @dev: DRM device
>  * @old_state: atomic state object with old state structures
> void drm_atomic_helper_commit_modeset_disables(struct drm_device *dev,
>                                                struct drm_atomic_state *old_state)
> 
> So, is "state" in drm_atomic_helper_commit_tail the old state or the
> new state?  Should this state be passed to
> drm_atomic_helper_commit_modeset_disables(), which seems to expect
> the old state?

Yes, you have reached one (of the many?) DRM quirks. When drm_atomic_helper_commit_tail()
gets called the *state pointer contains the old state that was swapped
out by drm_atomic_helper_commit() function before calling commit_tail().
The comment on drm_atomic_helper_commit_tail function (and maybe parameter name)
should be updated.


> 
> It looks _really_ screwed up here - in any case, it really doesn't
> help when you're not experienced with atomic mode set to work out
> what the hell this code is doing... it seems to be a horrible mess.
> Maybe someone who understands this code ought to read through it
> from the point of view of someone who doesn't understand it and fix
> the comments, or get rid of the down-right misleading comments.
> 
> Comments are worse than useless if they mislead.  Better to have no
> comments than misleading comments.

Sometimes code gets shuffled around and functions that made sense in
one workflow are kept in the new workflow except their order gets changed.
I believe that was the case for the function above.

Best regards,
Liviu

> 
> Daniel?
> 
> -- 
> RMK's Patch system: http://www.armlinux.org.uk/developer/patches/
> FTTC broadband for 0.8mile line: currently at 9.6Mbps down 400kbps up
> according to speedtest.net.
Russell King (Oracle) Nov. 21, 2016, 1:24 p.m. UTC | #7
On Mon, Nov 21, 2016 at 12:56:53PM +0000, Liviu Dudau wrote:
> That is mostly due to the check in hdlcd_crtc_disable() which I should
> remove, I've added it because I was getting a ->disable() hook call
> before any ->enable() was called at startup time. I need to revisit
> this as I remember Daniel was commenting that this was not needed.

Removing that test results in:

[drm:drm_atomic_helper_commit_cleanup_done] *ERROR* [CRTC:24:crtc-0] flip_done timed out

and the kernel hanging, seemingly in an IRQs-off region.
Liviu Dudau Nov. 21, 2016, 1:50 p.m. UTC | #8
On Mon, Nov 21, 2016 at 01:24:19PM +0000, Russell King - ARM Linux wrote:
> On Mon, Nov 21, 2016 at 12:56:53PM +0000, Liviu Dudau wrote:
> > That is mostly due to the check in hdlcd_crtc_disable() which I should
> > remove, I've added it because I was getting a ->disable() hook call
> > before any ->enable() was called at startup time. I need to revisit
> > this as I remember Daniel was commenting that this was not needed.
> 
> Removing that test results in:
> 
> [drm:drm_atomic_helper_commit_cleanup_done] *ERROR* [CRTC:24:crtc-0] flip_done timed out
> 
> and the kernel hanging, seemingly in an IRQs-off region.

Right, I need to sort this one out. Are you doing these tests out of
some tagged branch that I can get in sync with?

Best regards,
Liviu

> 
> -- 
> RMK's Patch system: http://www.armlinux.org.uk/developer/patches/
> FTTC broadband for 0.8mile line: currently at 9.6Mbps down 400kbps up
> according to speedtest.net.
Russell King (Oracle) Nov. 21, 2016, 2:03 p.m. UTC | #9
On Mon, Nov 21, 2016 at 01:50:31PM +0000, Liviu Dudau wrote:
> On Mon, Nov 21, 2016 at 01:24:19PM +0000, Russell King - ARM Linux wrote:
> > On Mon, Nov 21, 2016 at 12:56:53PM +0000, Liviu Dudau wrote:
> > > That is mostly due to the check in hdlcd_crtc_disable() which I should
> > > remove, I've added it because I was getting a ->disable() hook call
> > > before any ->enable() was called at startup time. I need to revisit
> > > this as I remember Daniel was commenting that this was not needed.
> > 
> > Removing that test results in:
> > 
> > [drm:drm_atomic_helper_commit_cleanup_done] *ERROR* [CRTC:24:crtc-0] flip_done timed out
> > 
> > and the kernel hanging, seemingly in an IRQs-off region.
> 
> Right, I need to sort this one out. Are you doing these tests out of
> some tagged branch that I can get in sync with?

No, not yet, and some of the changes I have are rather hacky.

I do always build my full tree of patches (which is currently running at
around 320 patches at the moment) but I never share that entire patch
set.  However, none of those touch i2c (apart from the ones I've recently
posted) and the only patches touching hdlcd are those I've posted so far.

Most of the problems I'm finding are through trying basic stuff - I'm not
doing anything special or unusual to find them, at the moment quite
literally just starting Xorg up and shutting it down.  For example, the
above was caused by logging in on serial, running:

	Xorg -terminate -verbose

and then hitting ^C.  (I have lxdm disabled so systemd boots to VT login
prompts on both the "framebuffer" and serial - I don't want Xorg coming
up when the machine is booting for its nightly KVM boot tests.)

I'm afraid that when I try someone elses code, I have a tendency to find
loads of seemingly trivial bugs when I try putting it through some basic
tests.
Russell King (Oracle) Nov. 21, 2016, 2:30 p.m. UTC | #10
On Mon, Nov 21, 2016 at 01:24:19PM +0000, Russell King - ARM Linux wrote:
> On Mon, Nov 21, 2016 at 12:56:53PM +0000, Liviu Dudau wrote:
> > That is mostly due to the check in hdlcd_crtc_disable() which I should
> > remove, I've added it because I was getting a ->disable() hook call
> > before any ->enable() was called at startup time. I need to revisit
> > this as I remember Daniel was commenting that this was not needed.
> 
> Removing that test results in:
> 
> [drm:drm_atomic_helper_commit_cleanup_done] *ERROR* [CRTC:24:crtc-0] flip_done timed out
> 
> and the kernel hanging, seemingly in an IRQs-off region.

Annoyingly, enabling DRM debug prevents the kernel hanging...
Russell King (Oracle) Nov. 21, 2016, 2:55 p.m. UTC | #11
On Mon, Nov 21, 2016 at 02:30:53PM +0000, Russell King - ARM Linux wrote:
> On Mon, Nov 21, 2016 at 01:24:19PM +0000, Russell King - ARM Linux wrote:
> > On Mon, Nov 21, 2016 at 12:56:53PM +0000, Liviu Dudau wrote:
> > > That is mostly due to the check in hdlcd_crtc_disable() which I should
> > > remove, I've added it because I was getting a ->disable() hook call
> > > before any ->enable() was called at startup time. I need to revisit
> > > this as I remember Daniel was commenting that this was not needed.
> > 
> > Removing that test results in:
> > 
> > [drm:drm_atomic_helper_commit_cleanup_done] *ERROR* [CRTC:24:crtc-0] flip_done timed out
> > 
> > and the kernel hanging, seemingly in an IRQs-off region.
> 
> Annoyingly, enabling DRM debug prevents the kernel hanging...

I've been trying to trace through what's happening with this flip_done
stuff, but I'm finding it _extremely_ difficult to follow the atomic
code.

(Sorry, I'm going to go over my usual 72 column limit for this due to
the damn long DRM function names.)

I can see that drm_atomic_helper_commit() calls drm_atomic_helper_setup_commit()
which sets up commit->flip_done for each CRTC, and sets up an event for
each.

drm_atomic_helper_commit() continues on to eventually call drm_atomic_helper_swap_state()
which then swaps the state for the CRTCs, but then ends up dropping
the event reference:

	state->crtcs[i].commit->event = NULL;

What I can't see is why this isn't a leaked pointer - I don't see
anything inbetween taking charge of that structure.  The _commit_
hasn't been swapped from what I can see, it's just state->crtcs[i].state
that have been swapped.

So I can't see who's responsible for generating this event, or how the
backend DRM drivers get to know about this event, and that they should
complete the flip.

What I also don't get is why DRM is wanting to wait for a flip event
when we're disabling the CRTC.  None of this makes sense to me, like
much of the atomic modeset code...

(I'm probably never going to convert Armada DRM to atomic modeset, I
just don't seem to be capable of understanding atomic modeset.  Maybe
I'm too old?)

[drm:drm_ioctl] pid=2178, dev=0xe200, auth=1, DRM_IOCTL_MODE_RMFB
[drm:drm_mode_object_unreference] OBJ ID: 38 (4)
[drm:drm_atomic_state_init] Allocated atomic state ffffffc974c7c300
[drm:drm_mode_object_reference] OBJ ID: 43 (1)
[drm:drm_atomic_get_crtc_state] Added [CRTC:24:crtc-0] ffffffc975e59400 state to ffffffc974c7c300
[drm:drm_mode_object_reference] OBJ ID: 38 (3)
[drm:drm_atomic_get_plane_state] Added [PLANE:23:plane-0] ffffffc974c7c100 state to ffffffc974c7c300
[drm:drm_mode_object_unreference] OBJ ID: 43 (2)
[drm:drm_atomic_set_mode_for_crtc] Set [NOMODE] for CRTC state ffffffc975e59400
[drm:drm_atomic_set_crtc_for_plane] Link plane state ffffffc974c7c100 to [NOCRTC]
[drm:drm_mode_object_unreference] OBJ ID: 38 (4)
[drm:drm_atomic_set_fb_for_plane] Set [NOFB] for plane state ffffffc974c7c100
[drm:drm_atomic_add_affected_connectors] Adding all current connectors for [CRTC:24:crtc-0] to ffffffc974c7c300
[drm:drm_mode_object_reference] OBJ ID: 26 (4)
[drm:drm_mode_object_reference] OBJ ID: 26 (5)
[drm:drm_atomic_get_connector_state] Added [CONNECTOR:26] ffffffc974c7c000 state to ffffffc974c7c300
[drm:drm_mode_object_unreference] OBJ ID: 26 (6)
[drm:drm_atomic_set_crtc_for_connector] Link connector state ffffffc974c7c000 to [NOCRTC]
[drm:drm_atomic_check_only] checking ffffffc974c7c300
[drm:drm_atomic_helper_check_modeset] [CRTC:24:crtc-0] mode changed
[drm:drm_atomic_helper_check_modeset] [CRTC:24:crtc-0] enable changed
[drm:drm_atomic_helper_check_modeset] Updating routing for [CONNECTOR:26:HDMI-A-1]
[drm:drm_atomic_helper_check_modeset] Disabling [CONNECTOR:26:HDMI-A-1]
[drm:drm_atomic_helper_check_modeset] [CRTC:24:crtc-0] active changed
[drm:drm_atomic_helper_check_modeset] [CRTC:24:crtc-0] needs all connectors, enable: n, active: n
[drm:drm_atomic_add_affected_connectors] Adding all current connectors for [CRTC:24:crtc-0] to ffffffc974c7c300
[drm:drm_atomic_commit] commiting ffffffc974c7c300
[drm:drm_atomic_helper_commit_modeset_disables] disabling [ENCODER:25:TMDS-25]
[drm:drm_atomic_helper_commit_modeset_disables] disabling [CRTC:24:crtc-0]
hdlcd_crtc_disable: active 0
[drm:drm_atomic_helper_commit_cleanup_done] *ERROR* [CRTC:24:crtc-0] flip_done timed out
[drm:drm_atomic_state_default_clear] Clearing atomic state ffffffc974c7c300
[drm:drm_mode_object_unreference] OBJ ID: 26 (5)
[drm:drm_mode_object_unreference] OBJ ID: 26 (4)
[drm:drm_mode_object_unreference] OBJ ID: 43 (1)
[drm:drm_mode_object_unreference] OBJ ID: 38 (3)
[drm:drm_atomic_state_free] Freeing atomic state ffffffc974c7c300
[drm:drm_mode_object_unreference] OBJ ID: 38 (2)
[drm:drm_mode_object_unreference] OBJ ID: 38 (1)
Daniel Vetter Nov. 22, 2016, 7:02 a.m. UTC | #12
On Mon, Nov 21, 2016 at 02:55:28PM +0000, Russell King - ARM Linux wrote:
> On Mon, Nov 21, 2016 at 02:30:53PM +0000, Russell King - ARM Linux wrote:
> > On Mon, Nov 21, 2016 at 01:24:19PM +0000, Russell King - ARM Linux wrote:
> > > On Mon, Nov 21, 2016 at 12:56:53PM +0000, Liviu Dudau wrote:
> > > > That is mostly due to the check in hdlcd_crtc_disable() which I should
> > > > remove, I've added it because I was getting a ->disable() hook call
> > > > before any ->enable() was called at startup time. I need to revisit
> > > > this as I remember Daniel was commenting that this was not needed.
> > > 
> > > Removing that test results in:
> > > 
> > > [drm:drm_atomic_helper_commit_cleanup_done] *ERROR* [CRTC:24:crtc-0] flip_done timed out
> > > 
> > > and the kernel hanging, seemingly in an IRQs-off region.
> > 
> > Annoyingly, enabling DRM debug prevents the kernel hanging...
> 
> I've been trying to trace through what's happening with this flip_done
> stuff, but I'm finding it _extremely_ difficult to follow the atomic
> code.
> 
> (Sorry, I'm going to go over my usual 72 column limit for this due to
> the damn long DRM function names.)
> 
> I can see that drm_atomic_helper_commit() calls drm_atomic_helper_setup_commit()
> which sets up commit->flip_done for each CRTC, and sets up an event for
> each.
> 
> drm_atomic_helper_commit() continues on to eventually call drm_atomic_helper_swap_state()
> which then swaps the state for the CRTCs, but then ends up dropping
> the event reference:
> 
> 	state->crtcs[i].commit->event = NULL;
> 
> What I can't see is why this isn't a leaked pointer - I don't see
> anything inbetween taking charge of that structure.  The _commit_
> hasn't been swapped from what I can see, it's just state->crtcs[i].state
> that have been swapped.

The event is also stored in crtc_state->event, which after swap_states
land in drm_crtc->state->event, which is the place drivers are supposed to
pick it up from for delivery.

> So I can't see who's responsible for generating this event, or how the
> backend DRM drivers get to know about this event, and that they should
> complete the flip.
> 
> What I also don't get is why DRM is wanting to wait for a flip event
> when we're disabling the CRTC.  None of this makes sense to me, like
> much of the atomic modeset code...

The DRM event has two uses:
- high-precision timestamp for when the new frame starts displaying.
- confirmation that the old buffers are no longer being used by the hw.
  This is used on Android's drm_hwcomposer in the new hwc2 mode.

Note that the crtc_state->event has 3 uses in total, all hidden behind the
abstraction:
- flip_done, for the atomic helpers
- drm event, for current userspace (also needed to emulate legacy flips)
- and out-fences, needed by android.

The trouble with ->event delivery was that many drivers didn't bother to
implement this at all, since driver submitters never even tested
pageflippping. And for those maintainers that did test pageflipping, they
only ever tested the legacy page_flip paths, which e.g. doesn't ever ask
for an event when disabling the CRTC (since you can't do that). But atomic
allows all this, and review wasn't enough to fight the influx of bad
drivers. Hence I opted to make the nonblocking support in the atomic
helpers enforce this part of the abi contract, even for blocking modesets.
If you're stuck on a flip_done, then your driver doesn't send out events
when disabling the CRTC.

All the waits have a 10s timeout, and none of them are in atomic contexts,
so no idea why this takes down your box. I suspect it's something
unrelated.
-Daniel
Russell King (Oracle) Feb. 20, 2017, 12:16 p.m. UTC | #13
On Fri, Nov 18, 2016 at 11:37:33PM +0000, Russell King - ARM Linux wrote:
> Something I also noticed is this:
> 
>         scanout_start = gem->paddr + plane->state->fb->offsets[0] +
>                 plane->state->crtc_y * plane->state->fb->pitches[0] +
>                 plane->state->crtc_x * bpp / 8;
> 
> Surely this should be using src_[xy] (which are the position in the
> source - iow, memory, and not crtc_[xy] which is the position on the
> CRTC displayed window.  To put it another way, the src_* define the
> region of the source material that is mapped onto a rectangular area
> on the display defined by crtc_*.

This problem still exists...
diff mbox

Patch

diff --git a/drivers/gpu/drm/arm/hdlcd_crtc.c b/drivers/gpu/drm/arm/hdlcd_crtc.c
index 48019ae22ddb..3e97acf6e2a7 100644
--- a/drivers/gpu/drm/arm/hdlcd_crtc.c
+++ b/drivers/gpu/drm/arm/hdlcd_crtc.c
@@ -150,6 +150,8 @@  static void hdlcd_crtc_enable(struct drm_crtc *crtc)
 	clk_prepare_enable(hdlcd->clk);
 	hdlcd_crtc_mode_set_nofb(crtc);
 	hdlcd_write(hdlcd, HDLCD_REG_COMMAND, 1);
+	hdlcd_write(hdlcd, HDLCD_REG_COMMAND, 0);
+	hdlcd_write(hdlcd, HDLCD_REG_COMMAND, 1);
 }
 
 static void hdlcd_crtc_disable(struct drm_crtc *crtc)