diff mbox

[v2,1/3] imx-drm: Add mx6 hdmi transmitter support

Message ID 20131016180735.GI25034@n2100.arm.linux.org.uk (mailing list archive)
State New, archived
Headers show

Commit Message

Russell King - ARM Linux Oct. 16, 2013, 6:07 p.m. UTC
On Wed, Oct 16, 2013 at 06:03:42PM +0100, Russell King - ARM Linux wrote:
> On Tue, Oct 15, 2013 at 10:17:07AM -0300, Fabio Estevam wrote:
> > On Tue, Oct 15, 2013 at 10:10 AM, Russell King - ARM Linux
> > <linux@arm.linux.org.uk> wrote:
> > > Another point on patch 1.  Sorry, I don't have patch 1 to reply to, it
> > > seems it was deleted from linux-arm-kernel's moderation queue.
> > >
> > > drm_mode_connector_attach_encoder() is called too early, before the
> > > base.id field in the encoder has been initialised.  This causes the
> > > connectors encoder array to be empty, and userspace KMS to fail.
> > >
> > > There's also bugs in the CSC setting too - it runs off the end of the
> > > array and gcc warns about this.  The code was clearly wrong.
> > >
> > > You may wish to combine this patch with patch 1 to sort all that out.
> > > For the patch below:
> > >
> > > Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
> > > Tested-by: Russell King <rmk+kernel@arm.linux.org.uk>
> > 
> > Thanks, Russell.
> > 
> > Will submit v3 when I am back to the office.
> 
> Okay, I still have a problem with HDMI: I have a magenta vertical line
> down the left hand side of the frame, the displayed frame is shifted
> right by the width of that line and the right hand side is missing some
> pixels.
> 
> First off, the hsync position programmed into the HDMI registers appears
> to be wrong.
> 
> I'm at a loss why imx-hdmi is obfuscated with a conversion from a
> drm_display_mode structure to a fb_videomode.  This adds additional
> confusion and additional opportunities for bugs; this is probably
> exactly why the hsync position is wrong.
> 
> In CEA-861-B for 720p @60Hz:
> 
> DE: ^^^^__________^^^^^^^
> HS: _______^^^___________
>          ^  ^  ^
>          |  |  220 clocks
>          |  40 clocks
>          110 clocks
> 
> The IMX6 manual says HSYINCINDELAY0 is "Hsync active edge delay.  Integer
> number of pixel clock cycles from de non-active edge".  So, this should be
> 110.  Yet it ends up being programmed as 220, leading to a magenta vertical
> bar down the left hand side of the display.
> 
> Now, if you look at Documentation/fb/framebuffer.txt, in this case, the
> right margin should be 110 clocks, hsync len should be 40 and the left
> margin should be 220 clocks.
> 
> However, this is not what your conversion to a fb_videomode does.  It
> reverses the left and right margin.  A similar confusion also exists
> in the conversion of the upper/lower margins too.
> 
> The DRM model is this (for 720p @60Hz):
> 
> 0                             1280         1390 1430      1650
> |===============================|------------|---|----------|
> ^                               ^            ^   ^          ^
> start                       hdisplay hsync_start hsync_end htotal
> 
> The fb model is the same as the above but rotated:
> 
> left margin            displayed            right margin hsync_len
> |----------|===============================|------------|---|
> 
> So, the left margin is the bit between hsync_end and htotal, and the
> right margin is the bit between hdisplay and hsync_start.  Exactly
> the same analysis applies to the upper/lower margins.
> 
> What I suggest is that the use of fb_videomode is entirely killed off
> in this driver to remove this layer of confusion and instead the DRM
> model is stuck to within this DRM driver.
> 
> Now on to the next problem.  HSYNC/VSYNC polarity.
> 
> So, this is the mode which is set:
> 
>   1280x720 (0x41)   74.2MHz +HSync +VSync *current +preferred
>         h: width  1280 start 1390 end 1430 total 1650 skew    0 clock   45.0KHz
>         v: height  720 start  725 end  730 total  750           clock   60.0Hz
> 
> Note the positive HSync and VSync polarity - this is correct, backed
> up by CEA-861-B.
> 
> The IPU DI0 is configured thusly in its general control register:
> 0x2640000 = 0x200006, which is what is set when the requested mode
> has DRM_MODE_FLAG_PHSYNC and DRM_MODE_FLAG_PVSYNC flags set.
> 
> However, if we look at the HDMI config: 0x121000 = 0x18.  Active low
> hsync/vsync.  This is quite obvious when you look at the code -
> convert_to_video_timing() does *nothing* at all when converting the
> sync polarities, which means hdmi_av_composer() doesn't program them
> appropriately.  And yes, poking 0x78 into this register finally fixes
> the problem.
> 
> Yet another reason why this silly conversion from one structure form
> to another is a Very Bad Idea.  Until I found this, I was merely going
> to send a patch to sort out convert_to_video_timing(), but quite frankly
> I'm going to kill this thing off right now.
> 
> Another thing:
> 
> static int imx_hdmi_setup(struct imx_hdmi *hdmi, struct drm_display_mode *mode)
> {
>         int ret;
>         convert_to_video_timing(&hdmi->fb_mode, mode);
> 
>         hdmi_disable_overflow_interrupts(hdmi);
>         
>         hdmi->vic = 6;
> 
> It's quite wrong to force every video mode set to be CEA mode 6.  IIRC,
> There is a function in DRM which will tell you the CEA mode number.
> Again, I'll fix this in my patch rewriting this bit of the driver to
> be correct.
> 
> I'm also suspicious of the "HDMI Initialization Step" comments, because
> they make no sense:
> 
> /* HDMI Initialization Step B.4 */
> static void imx_hdmi_enable_video_path(struct imx_hdmi *hdmi)
> {
> 
> yet:
> 
>         /* HDMI Initialization Step B.3 */
>         imx_hdmi_enable_video_path(hdmi);
> 
> One's left wondering whether Step B.3 really is to just call a function
> with a particular name, but B.4 is to actually do something with the
> hardware.  I'm quite sure that if this is a documented procedure, that
> it doesn't say that and these comments are wrong (and probably the code
> too.)
> 
> Even after all this, I still haven't got rid of that magenta line - in
> as far as I can tell, nothing has changed as a result of any of these
> (although reading back the register values, they're now much better.)
> What I do find is if I poke 0x78 back into the INVIDCONF register
> (which already contains 0x78) the magenta line disappears.
> 
> I'm beginning to suspect that there's some ordering dependency that
> isn't being satisfied - but as the i.MX6Solo/DualLite manual doesn't
> seem to contain any of these details, I'm running out of ideas.

More issues: 720x576p @50Hz doesn't work very well, there's speckles
over the display, with the odd random line of corruption, and the
display occasionally blanks.  1280x720p at 50Hz or 60Hz is fine (apart
from the magenta line).  However, the magenta line disappears after
playing around setting various modes.

Sorry, but I don't think imx-drm is driving the hardware correctly, and
I know that Greg wants it moved out of drivers/staging, but frankly it
seems to be far from ready for that.  Certainly the HDMI parts seems to
be especially problematical.

In any case, here's my patch so far, which applies on top of the previous
I sent for the array overflow/encoder attachment:

 drivers/staging/imx-drm/imx-hdmi.c |   86 ++++++++++++------------------------
 1 files changed, 28 insertions(+), 58 deletions(-)

Comments

Greg Kroah-Hartman Oct. 16, 2013, 6:31 p.m. UTC | #1
On Wed, Oct 16, 2013 at 07:07:35PM +0100, Russell King - ARM Linux wrote:
> Sorry, but I don't think imx-drm is driving the hardware correctly, and
> I know that Greg wants it moved out of drivers/staging, but frankly it
> seems to be far from ready for that.  Certainly the HDMI parts seems to
> be especially problematical.

I want it out of staging if it's working properly.  Yours is the first
report of it not working properly, and in fact, probably one of the
first users of the driver, as I haven't gotten any reports of it working
or not at all over the years.

thanks,

greg k-h
Russell King - ARM Linux Oct. 16, 2013, 7:02 p.m. UTC | #2
On Wed, Oct 16, 2013 at 11:31:07AM -0700, Greg Kroah-Hartman wrote:
> On Wed, Oct 16, 2013 at 07:07:35PM +0100, Russell King - ARM Linux wrote:
> > Sorry, but I don't think imx-drm is driving the hardware correctly, and
> > I know that Greg wants it moved out of drivers/staging, but frankly it
> > seems to be far from ready for that.  Certainly the HDMI parts seems to
> > be especially problematical.
> 
> I want it out of staging if it's working properly.  Yours is the first
> report of it not working properly, and in fact, probably one of the
> first users of the driver, as I haven't gotten any reports of it working
> or not at all over the years.

Well, part of that is because I have this other thing called Armada DRM,
which is a similar thing to imx-drm, except for the Marvell Dove SoCs,
so it's been really quite easy to get a full Ubuntu 12.04 up and running
on the IMX SoC I have here.

As part of that effort, I'm now using my Armada DRM Xorg driver with
imx-drm to test this stuff out.  (Bearing in mind that IMX and Dove use
the same Vivante GPU, there's some sense in getting my Xorg Armada DRM
driver working on both.)

I'm not aware of there being any X drivers for imx-drm (google turns
up nothing), which might be a reason why it hasn't been well tested
and has also languished in drivers/staging for soo long.  Alternatively,
maybe my google searching sucks, or it is out there somewhere but
hidden from googlebot?

To be fair, so far most of the problems I'm finding are with the HDMI
addition to imx-drm rather than imx-drm itself: there's been the lockdep
problem and the clock polarity problem which the HDMI stuff discovered.

Looking at the todo list for moving it out of staging, we have:

- get DRM Maintainer review for this code
- Wait for common display framework to hit mainline and update the IPU
  driver to use it. This will most probably make changes to the devicetree
  bindings necessary.
- Factor out more code to common helper functions
- decide where to put the base driver. It is not specific to a subsystem
  and would be used by DRM/KMS and media/V4L2

(1) is quite a difficult task: I'm waiting for a review of the Armada DRM
stuff, which I'm hoping will make the next merge window.  Rob Clark is
looking at that but has been distracted recently from completing it.

(2) CDF... has been around in RFC according to LWN.net but doesn't seem to
make much in the way of progress from what I can see, despite there
allegedly being "many developers show[ing] interest in the first RFC".
CDF is over a year old now - first RFC 17 Aug 2012, second 22 Nov 2012,
third 9 Aug 2013.

(3) is an on-going effort and really isn't a reason for it to stay in
staging.

(4) is probably the biggest issue.  The problem there is that the IMX
display subsystem is very flexible: it's basically a set of DMA engines
on the front, and behind that a fair number of modules implementing
facilities like image rotation, display driving and image capture.
Display driving alone involves setting up waveforms and writing some
microcode to tell the thing what to do on certain events (like end
of frame etc.)  Hence it doesn't fit well into any particular "Linux"
subsystem.  In this regard, it's a victim of its own flexibility.

I think the biggest problem though is its complexity.  It doesn't fit
into the "single device for a card" model which DRM has.  It's made
up from several separate devices, which is all very well, but it leads
to it having its own private "framework" to glue all the different
devices together - which adds a layer of indirection and makes the code
harder to understand.  As for trying to work out how any of this stuff
works - even though I have the manual which describes all the registers,
I'm struggling with it because there seems to be bits which just aren't
documented and its not always obvious that the code can be relied upon
either.

That all said, I don't think throwing this out of the kernel will do
it any good what so ever - that will just mean that there's even less
potential eyes looking at it.  Yes, some of that is my own selfishness
here - I don't want to have to carry this hunk of code around in my
tree and then be lumbered with trying to get it into mainline myself!
Sascha Hauer Oct. 16, 2013, 9:20 p.m. UTC | #3
On Wed, Oct 16, 2013 at 08:02:11PM +0100, Russell King - ARM Linux wrote:
> On Wed, Oct 16, 2013 at 11:31:07AM -0700, Greg Kroah-Hartman wrote:
> > On Wed, Oct 16, 2013 at 07:07:35PM +0100, Russell King - ARM Linux wrote:
> > > Sorry, but I don't think imx-drm is driving the hardware correctly, and
> > > I know that Greg wants it moved out of drivers/staging, but frankly it
> > > seems to be far from ready for that.  Certainly the HDMI parts seems to
> > > be especially problematical.
> > 
> > I want it out of staging if it's working properly.  Yours is the first
> > report of it not working properly, and in fact, probably one of the
> > first users of the driver, as I haven't gotten any reports of it working
> > or not at all over the years.
> 
> Well, part of that is because I have this other thing called Armada DRM,
> which is a similar thing to imx-drm, except for the Marvell Dove SoCs,
> so it's been really quite easy to get a full Ubuntu 12.04 up and running
> on the IMX SoC I have here.
> 
> As part of that effort, I'm now using my Armada DRM Xorg driver with
> imx-drm to test this stuff out.  (Bearing in mind that IMX and Dove use
> the same Vivante GPU, there's some sense in getting my Xorg Armada DRM
> driver working on both.)
> 
> I'm not aware of there being any X drivers for imx-drm (google turns
> up nothing), which might be a reason why it hasn't been well tested
> and has also languished in drivers/staging for soo long.  Alternatively,
> maybe my google searching sucks, or it is out there somewhere but
> hidden from googlebot?

There is no X driver for imx-drm. I once tested it with the
xf86-modesetting driver which worked with a few patches back then. These
patches are now part of the modesetting driver.

We have a wrapper tool here which we use to configure the KMS part and
pass the framebuffers to QT.

> 
> To be fair, so far most of the problems I'm finding are with the HDMI
> addition to imx-drm rather than imx-drm itself: there's been the lockdep
> problem and the clock polarity problem which the HDMI stuff discovered.
> 
> Looking at the todo list for moving it out of staging, we have:
> 
> - get DRM Maintainer review for this code
> - Wait for common display framework to hit mainline and update the IPU
>   driver to use it. This will most probably make changes to the devicetree
>   bindings necessary.
> - Factor out more code to common helper functions
> - decide where to put the base driver. It is not specific to a subsystem
>   and would be used by DRM/KMS and media/V4L2
> 
> (1) is quite a difficult task: I'm waiting for a review of the Armada DRM
> stuff, which I'm hoping will make the next merge window.  Rob Clark is
> looking at that but has been distracted recently from completing it.

We have waited for quite a long time aswell before we decided to push
the imx-drm driver to staging to at least get more exposure for the
driver. The situation is, well... unsatisfying.

> 
> (2) CDF... has been around in RFC according to LWN.net but doesn't seem to
> make much in the way of progress from what I can see, despite there
> allegedly being "many developers show[ing] interest in the first RFC".
> CDF is over a year old now - first RFC 17 Aug 2012, second 22 Nov 2012,
> third 9 Aug 2013.

From what I heard Laurent is still committed to mainline CDF.

> 
> (3) is an on-going effort and really isn't a reason for it to stay in
> staging.
> 
> (4) is probably the biggest issue.  The problem there is that the IMX
> display subsystem is very flexible: it's basically a set of DMA engines
> on the front, and behind that a fair number of modules implementing
> facilities like image rotation, display driving and image capture.
> Display driving alone involves setting up waveforms and writing some
> microcode to tell the thing what to do on certain events (like end
> of frame etc.)  Hence it doesn't fit well into any particular "Linux"
> subsystem.  In this regard, it's a victim of its own flexibility.
> 
> I think the biggest problem though is its complexity.  It doesn't fit
> into the "single device for a card" model which DRM has.  It's made
> up from several separate devices, which is all very well, but it leads
> to it having its own private "framework" to glue all the different
> devices together - which adds a layer of indirection and makes the code
> harder to understand.

I tried adding generic stuff to DRM to support this and failed badly due
to resistance of the maintainers. I didn't get much input what I should
do better or different (besides a general "make it a helper library").
Also nobody seemed to understand the problems I had with the multi device
nature of the i.MX IPU.

I think we made ourselves comfortable with being in the kernel, even if
it's only in staging. We should move forward instead and see how we get
the driver into the kernel.

Sascha
Lucas Stach Oct. 17, 2013, 8:27 a.m. UTC | #4
Hi Russell,

Am Mittwoch, den 16.10.2013, 20:02 +0100 schrieb Russell King - ARM
Linux:
> On Wed, Oct 16, 2013 at 11:31:07AM -0700, Greg Kroah-Hartman wrote:
> > On Wed, Oct 16, 2013 at 07:07:35PM +0100, Russell King - ARM Linux wrote:
> > > Sorry, but I don't think imx-drm is driving the hardware correctly, and
> > > I know that Greg wants it moved out of drivers/staging, but frankly it
> > > seems to be far from ready for that.  Certainly the HDMI parts seems to
> > > be especially problematical.
> > 
> > I want it out of staging if it's working properly.  Yours is the first
> > report of it not working properly, and in fact, probably one of the
> > first users of the driver, as I haven't gotten any reports of it working
> > or not at all over the years.
> 
> Well, part of that is because I have this other thing called Armada DRM,
> which is a similar thing to imx-drm, except for the Marvell Dove SoCs,
> so it's been really quite easy to get a full Ubuntu 12.04 up and running
> on the IMX SoC I have here.
> 
> As part of that effort, I'm now using my Armada DRM Xorg driver with
> imx-drm to test this stuff out.  (Bearing in mind that IMX and Dove use
> the same Vivante GPU, there's some sense in getting my Xorg Armada DRM
> driver working on both.)
> 
> I'm not aware of there being any X drivers for imx-drm (google turns
> up nothing), which might be a reason why it hasn't been well tested
> and has also languished in drivers/staging for soo long.  Alternatively,
> maybe my google searching sucks, or it is out there somewhere but
> hidden from googlebot?
> 

X.Org isn't the center of the world anymore. For some general purpose
distros this might still hold true for some time, but certainly not for
the use-cases we test this driver with.

For most of our embedded use-cases we currently use the FBdev emulation
(phasing this out at the moment) or the apps are sitting right on top of
the raw KMS APIs, rather than on top of a display server.
We also did some experiments with Wayland (Weston) on top of imx-drm,
which worked quite well.

There might be dragons hiding in some corners for the more general
purpose use-cases and we are happy to have you test the driver and
provide valuable reports.

> To be fair, so far most of the problems I'm finding are with the HDMI
> addition to imx-drm rather than imx-drm itself: there's been the lockdep
> problem and the clock polarity problem which the HDMI stuff discovered.
> 
> Looking at the todo list for moving it out of staging, we have:
> 
> - get DRM Maintainer review for this code
> - Wait for common display framework to hit mainline and update the IPU
>   driver to use it. This will most probably make changes to the devicetree
>   bindings necessary.
> - Factor out more code to common helper functions
> - decide where to put the base driver. It is not specific to a subsystem
>   and would be used by DRM/KMS and media/V4L2
> 
> (1) is quite a difficult task: I'm waiting for a review of the Armada DRM
> stuff, which I'm hoping will make the next merge window.  Rob Clark is
> looking at that but has been distracted recently from completing it.
> 
> (2) CDF... has been around in RFC according to LWN.net but doesn't seem to
> make much in the way of progress from what I can see, despite there
> allegedly being "many developers show[ing] interest in the first RFC".
> CDF is over a year old now - first RFC 17 Aug 2012, second 22 Nov 2012,
> third 9 Aug 2013.
> 

Philipp has a prototype of CDF on imx-drm working internally and I
suspect he will be able to post patches shortly after ELCE.

> (3) is an on-going effort and really isn't a reason for it to stay in
> staging.
> 
> (4) is probably the biggest issue.  The problem there is that the IMX
> display subsystem is very flexible: it's basically a set of DMA engines
> on the front, and behind that a fair number of modules implementing
> facilities like image rotation, display driving and image capture.
> Display driving alone involves setting up waveforms and writing some
> microcode to tell the thing what to do on certain events (like end
> of frame etc.)  Hence it doesn't fit well into any particular "Linux"
> subsystem.  In this regard, it's a victim of its own flexibility.

We are aiming to do the same thing as the Tegra host1x driver: move the
IPU core to drivers/gpu and export API for other drivers to use. This
may mean we still have to keep the DRM part in staging (at least until
the CDF thing is sorted, as this prevents us from setting the devicetree
bindings in stone), but at least should be a step in the right
direction.

Regards,
Lucas
Russell King - ARM Linux Oct. 20, 2013, 12:04 a.m. UTC | #5
On Wed, Oct 16, 2013 at 11:31:07AM -0700, Greg Kroah-Hartman wrote:
> On Wed, Oct 16, 2013 at 07:07:35PM +0100, Russell King - ARM Linux wrote:
> > Sorry, but I don't think imx-drm is driving the hardware correctly, and
> > I know that Greg wants it moved out of drivers/staging, but frankly it
> > seems to be far from ready for that.  Certainly the HDMI parts seems to
> > be especially problematical.
> 
> I want it out of staging if it's working properly.  Yours is the first
> report of it not working properly, and in fact, probably one of the
> first users of the driver, as I haven't gotten any reports of it working
> or not at all over the years.

Next problem... unbinding, rebinding, and then unbinding the imx-drm
device produces the nice oops below.  I've not debugged this yet.

Alignment trap: not handling instruction e1932f9f at [<c00758ec>]
Unhandled fault: alignment exception (0x001) at 0x6e72666f
Internal error: : 1 [#1] SMP ARM
Modules linked in: fuse bnep rfcomm bluetooth
CPU: 0 PID: 1125 Comm: bash Tainted: G        W    3.12.0-rc4+ #123
task: d0d6ec00 ti: d7ff2000 task.ti: d7ff2000
PC is at __lock_acquire+0x1a8/0x1e14
LR is at lock_acquire+0x68/0x7c
pc : [<c00758f0>]    lr : [<c0077aa8>]    psr: 20070093
sp : d7ff3cc8  ip : 00000000  fp : d7ff3d54
r10: db2a6334  r9 : 00000000  r8 : 6e72656b
r7 : c0846208  r6 : c08852cc  r5 : d0d6ec00  r4 : 00000002
r3 : 6e72666f  r2 : db2a6334  r1 : 00000001  r0 : d7ff2000
Flags: nzCv  IRQs off  FIQs on  Mode SVC_32  ISA ARM  Segment user
Control: 10c53c7d  Table: 20df804a  DAC: 00000015
Process bash (pid: 1125, stack limit = 0xd7ff2240)
Stack: (0xd7ff3cc8 to 0xd7ff4000)
3cc0:                   00000006 00000007 c0cd22f0 00000006 d7ff3d1c d7ff3ce8
3ce0: c00782f8 c0075050 00000001 00000000 db801f00 d7ff2000 c0078648 d7ff2000
3d00: 00000001 d7ff3e08 d7ff3e60 d7ff3dd8 d7ff3d3c d7ff3d20 00000000 d7ff3e08
3d20: d7ff3d7c d7ff3d30 c0072a58 00000000 d7ff2000 60070013 d0d6ec00 d7ff2000
3d40: c06679c8 d0d6ec00 d7ff3d8c d7ff3d58 c0077aa8 c0075754 00000002 00000000
3d60: 00000000 c02ff27c 00000000 00000002 db2a62fc c02ff27c c08852cc 00000000
3d80: d7ff3de4 d7ff3d90 c05f80c4 c0077a4c 00000002 00000000 c02ff27c c0072a20
3da0: dad64000 d7ff3e24 d7ff3df8 d7ff3e04 d7ff3e5c d0d6f000 c013f1c8 db322880
3dc0: db2a6440 db2a6000 c0872568 00000008 c06679c8 db286000 d7ff3e04 d7ff3de8
3de0: c02ff27c c05f8074 db280f00 db322880 db2a6000 db29b810 d7ff3e1c d7ff3e08
3e00: c02f13ac c02ff268 d0e55000 c087265c d7ff3e2c d7ff3e20 c0464d7c c02f1398
3e20: d7ff3e54 d7ff3e30 c02f506c c0464d68 d0e55000 c087265c db29b810 c0872568
3e40: 00000008 db286000 d7ff3e74 d7ff3e58 c02fa284 c02f503c c087265c c087265c
3e60: db29b810 00000008 d7ff3e8c d7ff3e78 c02fb900 c02fa258 db29b810 c0872678
3e80: d7ff3e9c d7ff3e90 c0464d54 c02fb8d4 d7ff3eac d7ff3ea0 c0312bfc c0464d44
3ea0: d7ff3ec4 d7ff3eb0 c03113b0 c0312be8 db29b844 db29b810 d7ff3edc d7ff3ec8
3ec0: c0311434 c0311344 c0872678 c085b588 d7ff3efc d7ff3ee0 c03103ac c0311418
3ee0: c941b300 c941b318 d7ff3f70 db28c280 d7ff3f0c d7ff3f00 c030f934 c0310338
3f00: d7ff3f3c d7ff3f10 c013d7d0 c030f918 d7ff3f70 dbb5e600 00000008 003ba408
3f20: d7ff3f70 00000000 00000000 00000008 d7ff3f6c d7ff3f40 c00db77c c013d6d4
3f40: 00000001 c000eb44 dbb5e600 00000000 d7ff3f70 003ba408 00000000 00000008
3f60: d7ff3fa4 d7ff3f70 c00dbb58 c00db6b8 00000000 00000000 d7ff3f94 b6f7fa78
3f80: 00000008 003ba408 00000004 c000eb44 d7ff2000 00000000 00000000 d7ff3fa8
3fa0: c000e980 c00dbb18 b6f7fa78 00000008 00000001 003ba408 00000008 00000000
3fc0: b6f7fa78 00000008 003ba408 00000004 bee5c9ec 000a6094 00000000 003f7f08
3fe0: 00000000 bee5c96c b6eee747 b6f2611c 40070010 00000001 00000138 00000020
Backtrace: 
[<c0075748>] (__lock_acquire+0x0/0x1e14) from [<c0077aa8>] (lock_acquire+0x68/0x7c)
[<c0077a40>] (lock_acquire+0x0/0x7c) from [<c05f80c4>] (mutex_lock_nested+0x5c/0x394)
 r7:00000000 r6:c08852cc r5:c02ff27c r4:db2a62fc
[<c05f8068>] (mutex_lock_nested+0x0/0x394) from [<c02ff27c>] (drm_modeset_lock_all+0x20/0x58)
[<c02ff25c>] (drm_modeset_lock_all+0x0/0x58) from [<c02f13ac>] (drm_fbdev_cma_restore_mode+0x20/0x34)
 r6:db29b810 r5:db2a6000 r4:db322880 r3:db280f00
[<c02f138c>] (drm_fbdev_cma_restore_mode+0x0/0x34) from [<c0464d7c>] (imx_drm_driver_lastclose+0x20/0x24)
 r5:c087265c r4:d0e55000
[<c0464d5c>] (imx_drm_driver_lastclose+0x0/0x24) from [<c02f506c>] (drm_lastclose+0x3c/0x174)
[<c02f5030>] (drm_lastclose+0x0/0x174) from [<c02fa284>] (drm_put_dev+0x38/0x154)
[<c02fa24c>] (drm_put_dev+0x0/0x154) from [<c02fb900>] (drm_platform_exit+0x38/0x5c)
 r7:00000008 r6:db29b810 r5:c087265c r4:c087265c
[<c02fb8c8>] (drm_platform_exit+0x0/0x5c) from [<c0464d54>] (imx_drm_platform_remove+0x1c/0x24)
 r5:c0872678 r4:db29b810
[<c0464d38>] (imx_drm_platform_remove+0x0/0x24) from [<c0312bfc>] (platform_drv_remove+0x20/0x24)
[<c0312bdc>] (platform_drv_remove+0x0/0x24) from [<c03113b0>] (__device_release_driver+0x78/0xd4)
[<c0311338>] (__device_release_driver+0x0/0xd4) from [<c0311434>] (device_release_driver+0x28/0x34)
 r5:db29b810 r4:db29b844
[<c031140c>] (device_release_driver+0x0/0x34) from [<c03103ac>] (unbind_store+0x80/0x98)
 r5:c085b588 r4:c0872678
[<c031032c>] (unbind_store+0x0/0x98) from [<c030f934>] (drv_attr_store+0x28/0x34)
 r7:db28c280 r6:d7ff3f70 r5:c941b318 r4:c941b300
[<c030f90c>] (drv_attr_store+0x0/0x34) from [<c013d7d0>] (sysfs_write_file+0x108/0x188)
[<c013d6c8>] (sysfs_write_file+0x0/0x188) from [<c00db77c>] (vfs_write+0xd0/0x19c)
[<c00db6ac>] (vfs_write+0x0/0x19c) from [<c00dbb58>] (SyS_write+0x4c/0x78)
[<c00dbb0c>] (SyS_write+0x0/0x78) from [<c000e980>] (ret_fast_syscall+0x0/0x48)
Code: 0affffbd e2883f41 f593f000 e1932f9f (e2822001) 
---[ end trace f2924517b64a28f4 ]---
Russell King - ARM Linux Oct. 20, 2013, 9:32 a.m. UTC | #6
Another problem.

After performing several modesets, the IPU seems to lock up and produce
no syncs or output data.

I've seen this many times over the last week while testing out various
aspects of imx-drm, and had put it down to problems with the clocking
arrangement getting its settings wrong.  Now that I've sorted all that
though, and I still have the problem, there's something else going on.

What I see is:
- the HDMI clock is running correctly (right frequency and unmodulated)
- the TMDS data lines show signs of there being some data (probably
  control, guard bands and data islands from the frame composer in the
  HDMI interface).  The data lines are definitely lacking image data though.
- reading the various status registers indicates that all FIFOs within
  the IPU are empty.
- the attached TV says that there is no HDMI signal.

One of my tests has been to cycle through all display resolutions from the
smallest width to the largest, leaving each one set for 30 seconds.  This
will occasionally provoke the problem, but obviously is rather slow to do
so.

I tried this with a less demanding test last night as far as a change in
the settings: switching between 720p at 50 and 60Hz.  The clocks for these
two modes are the same at 74.25MHz, and the vertical timing parameters are
identical.  The only timing difference is with the horizontal parameters:

  1280x720 (0x41)   74.2MHz +HSync +VSync +preferred
        h: width  1280 start 1390 end 1430 total 1650 skew    0 clock   45.0KHz
        v: height  720 start  725 end  730 total  750           clock   60.0Hz
  1280x720 (0x4f)   74.2MHz +HSync +VSync
        h: width  1280 start 1720 end 1760 total 1980 skew    0 clock   37.5KHz
        v: height  720 start  725 end  730 total  750           clock   50.0Hz

This dies within a couple of minutes.  I haven't gathered enough
information to tell whether it always dies when switching from 50 -> 60Hz
or whether it's any switch.

My test for this is basically:

while :; do
  xrandr -s 1280x720 -r 50
  sleep 5
  xrandr -s 1280x720 -r 60
  sleep 5
done
Russell King - ARM Linux Oct. 20, 2013, 1 p.m. UTC | #7
On Sun, Oct 20, 2013 at 01:04:34AM +0100, Russell King - ARM Linux wrote:
> On Wed, Oct 16, 2013 at 11:31:07AM -0700, Greg Kroah-Hartman wrote:
> > On Wed, Oct 16, 2013 at 07:07:35PM +0100, Russell King - ARM Linux wrote:
> > > Sorry, but I don't think imx-drm is driving the hardware correctly, and
> > > I know that Greg wants it moved out of drivers/staging, but frankly it
> > > seems to be far from ready for that.  Certainly the HDMI parts seems to
> > > be especially problematical.
> > 
> > I want it out of staging if it's working properly.  Yours is the first
> > report of it not working properly, and in fact, probably one of the
> > first users of the driver, as I haven't gotten any reports of it working
> > or not at all over the years.
> 
> Next problem... unbinding, rebinding, and then unbinding the imx-drm
> device produces the nice oops below.  I've not debugged this yet.

I've been tweaking the ARM oops format slightly (I hope this isn't going
to end up breaking any tools... it's only a minor change.)  I've been
using this as a way of testing it.  The change here is using %ps instead
of %pS for the first symbolic print in each entry (it's always the start
of the function).  The other change is fixing the saved register set so
saves including r10 get printed - and its better formatted.


As for imx-drm, there was a warning which preceded that oops.  Here's the
full log, below the "---------" marker - this is from unbinding the imx-drm
module, and then trying to reboot.

imx-drm is really very broken in the way it tries to bend DRM to be
used in DT - it doesn't consider the lifetime for anything like the
CRTCs, connectors or encoders.  All these have empty .destroy functions
to them. If we unbind imx-drm, the top level drm_device tries to be
destroyed, but it leaves behind all the CRTCs, connectors and encoders,
causing the first warning because none of the framebuffers got cleaned
up through that destruction (because the functions did nothing.)

The second one is through trying to clean up the framebuffer, which is
still in use.

The third one is caused because there's still allocated memory objects
against the DRM memory manager - again, because nothing has been cleaned
up.

Finally, the oops at the end.  I thought that's a candidate for
enabling kobject debugging and release debugging, but as soon as I do,
it perversely goes away!  Eventually I managed to reproduce it, and
it's the same bug which was investigated recently wrt sysfs lifetimes.
I would test David's fix for this, but it *isn't* generated against an
-rc kernel, it rejects fairly horribly.

Since it happens without kobject debugging enabled, it would be good
to get the fix in for 3.12-rc.  David?

kobject: 'card0' (db2bfc18): kobject_add_internal: parent: 'drm', set: 'devices'
kobject: 'card0' (db2bfc18): kobject_uevent_env
kobject: 'card0' (db2bfc18): fill_kobj_path: path = '/devices/platform/imx-drm/drm/card0'
[drm] Supports vblank timestamp caching Rev 1 (10.10.2010).
[drm] No driver support for vblank timestamp query.
...
kobject: 'card0' (db2bfc18): kobject_uevent_env
kobject: 'card0' (db2bfc18): fill_kobj_path: path = '/devices/platform/imx-drm/drm/card0'
kobject: 'imx-hdmi' (db293840): kobject_uevent_env
kobject: 'imx-hdmi' (db293840): fill_kobj_path: path = '/bus/platform/drivers/imx-hdmi'
...
kobject: 'card0' (db2bfc18): kobject_uevent_env
kobject: 'card0' (db2bfc18): fill_kobj_path: path = '/devices/platform/imx-drm/drm/card0'
kobject: 'card0-HDMI-A-1' (db837020): kobject_uevent_env
kobject: 'card0-HDMI-A-1' (db837020): fill_kobj_path: path = '/devices/platform/imx-drm/drm/card0/card0-HDMI-A-1'
...
kobject: 'card0' (db2bfc18): kobject_uevent_env
kobject: 'card0' (db2bfc18): fill_kobj_path: path = '/devices/platform/imx-drm/drm/card0'
kobject: 'card0-HDMI-A-1' (db837020): kobject_uevent_env
kobject: 'card0-HDMI-A-1' (db837020): fill_kobj_path: path = '/devices/platform/imx-drm/drm/card0/card0-HDMI-A-1'
...
kobject: 'card0' (db2bfc18): kobject_uevent_env
kobject: 'card0' (db2bfc18): fill_kobj_path: path = '/devices/platform/imx-drm/drm/card0'
kobject: 'drm' (db28fb00): kobject_release, parent db2bf418 (delayed)
[drm] Module unloaded
kobject: 'controlD64' (db2bf818): kobject_cleanup, parent   (null)
kobject: 'controlD64' (db2bf818): calling ktype release
kobject: 'controlD64': free name
kobject: 'drm' (db28fb00): kobject_cleanup, parent db2bf418
kobject: 'drm' (db28fb00): auto cleanup kobject_del
kobject: 'drm' (db28fb00): calling ktype release
kobject: 'drm': free name
...
WARNING: CPU: 0 PID: 1027 at /home/rmk/git/linux-rmk/include/linux/kref.h:47 kobject_get+0x60/0x74()
Modules linked in: fuse rfcomm bnep bluetooth
CPU: 0 PID: 1027 Comm: reboot Tainted: G        W    3.12.0-rc4+ #128
Backtrace:
[<c001218c>] (dump_backtrace) from [<c0012328>] (show_stack+0x18/0x1c)
 r6:c0646298 r5:0000002f r4:00000000 r3:00000000
[<c0012310>] (show_stack) from [<c05f6a78>] (dump_stack+0x70/0x90)
[<c05f6a08>] (dump_stack) from [<c00233a0>] (warn_slowpath_common+0x6c/0x8c)
 r4:00000000 r3:db142400
[<c0023334>] (warn_slowpath_common) from [<c00233e4>] (warn_slowpath_null+0x24/0x2c)
 r8:c088361c r7:db837024 r6:c0dc7fa4 r5:c08834f2 r4:db2bfc18
                                                    ^^^^^^^^ kobject address
[<c00233c0>] (warn_slowpath_null) from [<c027fbc8>] (kobject_get+0x60/0x74)
[<c027fb68>] (kobject_get) from [<c030dbfc>] (get_device+0x1c/0x24)
 r5:00000000 r4:db837018
[<c030dbe0>] (get_device) from [<c030fb0c>] (device_shutdown+0x90/0x19c)

-------------------
WARNING: CPU: 0 PID: 997 at /home/rmk/git/linux-rmk/drivers/gpu/drm/drm_crtc.c:4036 drm_mode_config_cleanup+0x250/0x25c()
Modules linked in: fuse bnep rfcomm bluetooth
CPU: 0 PID: 997 Comm: bash Not tainted 3.12.0-rc4+ #127
Backtrace: 
[<c001218c>] (dump_backtrace) from [<c0012328>] (show_stack+0x18/0x1c)
 r6:c065dc74 r5:00000fc4 r4:00000000 r3:00000000
[<c0012310>] (show_stack) from [<c05f5f90>] (dump_stack+0x70/0x90)
[<c05f5f20>] (dump_stack) from [<c00233a0>] (warn_slowpath_common+0x6c/0x8c)
 r4:00000000 r3:d7c75a00
[<c0023334>] (warn_slowpath_common) from [<c00233e4>] (warn_slowpath_null+0x24/0x2c)
 r8:db2a64cc r7:db2a6410 r6:db2a64c0 r5:db2a6000 r4:db2a64c0
[<c00233c0>] (warn_slowpath_null) from [<c03008b0>] (drm_mode_config_cleanup+0x250/0x25c)
[<c0300660>] (drm_mode_config_cleanup) from [<c0465494>] (imx_drm_driver_unload+0x1c/0x2c)
 r10:db286000 r9:c06679c8 r8:00000008 r7:c0872568 r6:db29b810 r5:c087265c
 r4:db280f00 r3:d7c75a00
[<c0465478>] (imx_drm_driver_unload) from [<c02fa29c>] (drm_put_dev+0x50/0x154)
 r4:db2a6000 r3:c0465478
[<c02fa24c>] (drm_put_dev) from [<c02fb900>] (drm_platform_exit+0x38/0x5c)
 r7:00000008 r6:db29b810 r5:c087265c r4:c087265c
[<c02fb8c8>] (drm_platform_exit) from [<c0464d54>] (imx_drm_platform_remove+0x1c/0x24)
 r5:c0872678 r4:db29b810
[<c0464d38>] (imx_drm_platform_remove) from [<c0312bfc>] (platform_drv_remove+0x20/0x24)
[<c0312bdc>] (platform_drv_remove) from [<c03113b0>] (__device_release_driver+0x78/0xd4)
[<c0311338>] (__device_release_driver) from [<c0311434>] (device_release_driver+0x28/0x34)
 r5:db29b810 r4:db29b844
[<c031140c>] (device_release_driver) from [<c03103ac>] (unbind_store+0x80/0x98)
 r5:c085b588 r4:c0872678
[<c031032c>] (unbind_store) from [<c030f934>] (drv_attr_store+0x28/0x34)
 r7:db28c280 r6:d7d9ff70 r5:d7d9a898 r4:d7d9a880
[<c030f90c>] (drv_attr_store) from [<c013d7d0>] (sysfs_write_file+0x108/0x188)
[<c013d6c8>] (sysfs_write_file) from [<c00db77c>] (vfs_write+0xd0/0x19c)
 r10:00000008 r9:00000000 r8:00000000 r7:d7d9ff70 r6:0132f408 r5:00000008
 r4:d7df5d00 r3:d7d9ff70
[<c00db6ac>] (vfs_write) from [<c00dbb58>] (SyS_write+0x4c/0x78)
 r10:00000008 r8:00000000 r7:0132f408 r6:d7d9ff70 r5:00000000 r4:d7df5d00
[<c00dbb0c>] (SyS_write) from [<c000e980>] (ret_fast_syscall+0x0/0x48)
 r10:00000000 r9:d7d9e000 r8:c000eb44 r7:00000004 r6:0132f408 r5:00000008
 r4:b6f72a78
---[ end trace 44f221ca42d7ae54 ]---
------------[ cut here ]------------
WARNING: CPU: 0 PID: 997 at /home/rmk/git/linux-rmk/drivers/gpu/drm/drm_crtc.c:571 drm_framebuffer_remove+0x10c/0x118()
Modules linked in: fuse bnep rfcomm bluetooth
CPU: 0 PID: 997 Comm: bash Tainted: G        W    3.12.0-rc4+ #127
Backtrace: 
[<c001218c>] (dump_backtrace) from [<c0012328>] (show_stack+0x18/0x1c)
 r6:c065dc74 r5:0000023b r4:00000000 r3:00000000
[<c0012310>] (show_stack) from [<c05f5f90>] (dump_stack+0x70/0x90)
[<c05f5f20>] (dump_stack) from [<c00233a0>] (warn_slowpath_common+0x6c/0x8c)
 r4:00000000 r3:d7c75a00
[<c0023334>] (warn_slowpath_common) from [<c00233e4>] (warn_slowpath_null+0x24/0x2c)
 r8:db2a6000 r7:db2a6410 r6:db2a64c0 r5:dae7b280 r4:db32ea00
[<c00233c0>] (warn_slowpath_null) from [<c0300654>] (drm_framebuffer_remove+0x10c/0x118)
[<c0300548>] (drm_framebuffer_remove) from [<c0300800>] (drm_mode_config_cleanup+0x1a0/0x25c)
 r10:00200200 r9:00100100 r8:db2a64cc r7:db2a6410 r6:db2a64c0 r5:db2a6000
 r4:db32ea00
[<c0300660>] (drm_mode_config_cleanup) from [<c0465494>] (imx_drm_driver_unload+0x1c/0x2c)
 r10:db286000 r9:c06679c8 r8:00000008 r7:c0872568 r6:db29b810 r5:c087265c
 r4:db280f00 r3:d7c75a00
[<c0465478>] (imx_drm_driver_unload) from [<c02fa29c>] (drm_put_dev+0x50/0x154)
 r4:db2a6000 r3:c0465478
[<c02fa24c>] (drm_put_dev) from [<c02fb900>] (drm_platform_exit+0x38/0x5c)
 r7:00000008 r6:db29b810 r5:c087265c r4:c087265c
[<c02fb8c8>] (drm_platform_exit) from [<c0464d54>] (imx_drm_platform_remove+0x1c/0x24)
 r5:c0872678 r4:db29b810
[<c0464d38>] (imx_drm_platform_remove) from [<c0312bfc>] (platform_drv_remove+0x20/0x24)
[<c0312bdc>] (platform_drv_remove) from [<c03113b0>] (__device_release_driver+0x78/0xd4)
[<c0311338>] (__device_release_driver) from [<c0311434>] (device_release_driver+0x28/0x34)
 r5:db29b810 r4:db29b844
[<c031140c>] (device_release_driver) from [<c03103ac>] (unbind_store+0x80/0x98)
 r5:c085b588 r4:c0872678
[<c031032c>] (unbind_store) from [<c030f934>] (drv_attr_store+0x28/0x34)
 r7:db28c280 r6:d7d9ff70 r5:d7d9a898 r4:d7d9a880
[<c030f90c>] (drv_attr_store) from [<c013d7d0>] (sysfs_write_file+0x108/0x188)
[<c013d6c8>] (sysfs_write_file) from [<c00db77c>] (vfs_write+0xd0/0x19c)
 r10:00000008 r9:00000000 r8:00000000 r7:d7d9ff70 r6:0132f408 r5:00000008
 r4:d7df5d00 r3:d7d9ff70
[<c00db6ac>] (vfs_write) from [<c00dbb58>] (SyS_write+0x4c/0x78)
 r10:00000008 r8:00000000 r7:0132f408 r6:d7d9ff70 r5:00000000 r4:d7df5d00
[<c00dbb0c>] (SyS_write) from [<c000e980>] (ret_fast_syscall+0x0/0x48)
 r10:00000000 r9:d7d9e000 r8:c000eb44 r7:00000004 r6:0132f408 r5:00000008
 r4:b6f72a78
---[ end trace 44f221ca42d7ae55 ]---
------------[ cut here ]------------
WARNING: CPU: 0 PID: 997 at /home/rmk/git/linux-rmk/drivers/gpu/drm/drm_mm.c:578 drm_mm_takedown+0x2c/0x34()
Memory manager not clean during takedown.
Modules linked in: fuse bnep rfcomm bluetooth
CPU: 0 PID: 997 Comm: bash Tainted: G        W    3.12.0-rc4+ #127
Backtrace: 
[<c001218c>] (dump_backtrace) from [<c0012328>] (show_stack+0x18/0x1c)
 r6:c065dbc8 r5:00000242 r4:00000000 r3:00000000
[<c0012310>] (show_stack) from [<c05f5f90>] (dump_stack+0x70/0x90)
[<c05f5f20>] (dump_stack) from [<c00233a0>] (warn_slowpath_common+0x6c/0x8c)
 r4:d7d9fdf8 r3:d7c75a00
[<c0023334>] (warn_slowpath_common) from [<c0023464>] (warn_slowpath_fmt+0x38/0x40)
 r8:00000008 r7:c0872568 r6:db2a6110 r5:db286080 r4:db286080
[<c0023430>] (warn_slowpath_fmt) from [<c02fd5f0>] (drm_mm_takedown+0x2c/0x34)
 r3:db2860ac r2:c065dbfc
[<c02fd5c4>] (drm_mm_takedown) from [<c030b3d0>] (drm_vma_offset_manager_destroy+0x1c/0x28)
[<c030b3b4>] (drm_vma_offset_manager_destroy) from [<c02f6d94>] (drm_gem_destroy+0x1c/0x30)
 r4:db2a6000 r3:00003000
[<c02f6d78>] (drm_gem_destroy) from [<c02fa384>] (drm_put_dev+0x138/0x154)
 r5:db2a6110 r4:db2a6000
[<c02fa24c>] (drm_put_dev) from [<c02fb900>] (drm_platform_exit+0x38/0x5c)
 r7:00000008 r6:db29b810 r5:c087265c r4:c087265c
[<c02fb8c8>] (drm_platform_exit) from [<c0464d54>] (imx_drm_platform_remove+0x1c/0x24)
 r5:c0872678 r4:db29b810
[<c0464d38>] (imx_drm_platform_remove) from [<c0312bfc>] (platform_drv_remove+0x20/0x24)
[<c0312bdc>] (platform_drv_remove) from [<c03113b0>] (__device_release_driver+0x78/0xd4)
[<c0311338>] (__device_release_driver) from [<c0311434>] (device_release_driver+0x28/0x34)
 r5:db29b810 r4:db29b844
[<c031140c>] (device_release_driver) from [<c03103ac>] (unbind_store+0x80/0x98)
 r5:c085b588 r4:c0872678
[<c031032c>] (unbind_store) from [<c030f934>] (drv_attr_store+0x28/0x34)
 r7:db28c280 r6:d7d9ff70 r5:d7d9a898 r4:d7d9a880
[<c030f90c>] (drv_attr_store) from [<c013d7d0>] (sysfs_write_file+0x108/0x188)
[<c013d6c8>] (sysfs_write_file) from [<c00db77c>] (vfs_write+0xd0/0x19c)
 r10:00000008 r9:00000000 r8:00000000 r7:d7d9ff70 r6:0132f408 r5:00000008
 r4:d7df5d00 r3:d7d9ff70
[<c00db6ac>] (vfs_write) from [<c00dbb58>] (SyS_write+0x4c/0x78)
 r10:00000008 r8:00000000 r7:0132f408 r6:d7d9ff70 r5:00000000 r4:d7df5d00
[<c00dbb0c>] (SyS_write) from [<c000e980>] (ret_fast_syscall+0x0/0x48)
 r10:00000000 r9:d7d9e000 r8:c000eb44 r7:00000004 r6:0132f408 r5:00000008
 r4:b6f72a78
---[ end trace 44f221ca42d7ae56 ]---
[drm] Module unloaded
Alignment trap: not handling instruction e1932f9f at [<c00758ec>]
Unhandled fault: alignment exception (0x001) at 0x63700b11
Internal error: : 1 [#1] SMP ARM
Modules linked in: fuse bnep rfcomm bluetooth
CPU: 0 PID: 1050 Comm: reboot Tainted: G        W    3.12.0-rc4+ #127
task: d7f68000 ti: d7f4a000 task.ti: d7f4a000
PC is at __lock_acquire+0x1a8/0x1e14
LR is at lock_acquire+0x68/0x7c
pc : [<c00758f0>]    lr : [<c0077aa8>]    psr: 200f0093
sp : d7f4bd18  ip : 00000000  fp : d7f4bda4
r10: db2ac07c  r9 : 00000000  r8 : 63700a0d
r7 : c0846208  r6 : c08852cc  r5 : d7f68000  r4 : 00000002
r3 : 63700b11  r2 : db2ac07c  r1 : 00000001  r0 : d7f4a000
Flags: nzCv  IRQs off  FIQs on  Mode SVC_32  ISA ARM  Segment user
Control: 10c53c7d  Table: 27f0404a  DAC: 00000015
Process reboot (pid: 1050, stack limit = 0xd7f4a240)
Stack: (0xd7f4bd18 to 0xd7f4c000)
bd00:                                                       d7f4bdb4 00000002
bd20: d7f68000 c08852cc 00000001 00000074 00000002 db83ac18 d7f4bdd4 00000000
bd40: c0075a50 c0075050 c00782f8 d7f4a000 8c10a086 0000000a 00000000 d7f4a000
bd60: c0cd22f0 d7f683a0 d7f4bdac 00000000 00546074 00000000 c098f118 00000000
bd80: d7f4a000 600f0013 d7f68000 d7f4a000 d7f4a000 d7f68000 d7f4bddc d7f4bda8
bda0: c0077aa8 c0075754 00000002 00000000 00000000 c030f814 00000000 c088131c
bdc0: db2ac044 c030f814 c08852cc 00000000 d7f4be34 d7f4bde0 c05f80c4 c0077a4c
bde0: 00000002 00000000 c030f814 c0dc5b64 db2acc1c db83ac08 db2ac010 c0dc5b64
be00: db2b0024 c088131c db83ac08 db2b0018 db2ac010 c0dc5b64 db2b0024 c088131c
be20: d7f4a000 00000000 d7f4be5c d7f4be38 c030f814 c05f8074 c0883788 00000000
be40: c0844cc8 00000000 00000003 c000eb44 d7f4be6c d7f4be60 c0048988 c030f74c
be60: d7f4be84 d7f4be70 c00489a0 c0048958 01234567 4321fedc d7f4bfa4 d7f4be88
be80: c0048af4 c0048998 000000a8 db3bee50 00076046 00000000 0000000e d7f4a000
bea0: d7f4bea0 db42310c d7f4bea8 00000000 00000000 00000000 db265970 00000001
bec0: d7f4bedc d7f4bed0 c00a9050 00000000 d7f4a000 600f0013 d7f68000 00000007
bee0: c084192c b6f04714 d7f4bfb0 00000000 00000000 b6f52f3c d7f4bfac d7f4bf08
bf00: c00084b0 c0019e60 00000002 db422ff0 db85d088 c0836300 c083c934 db422ff0
bf20: db422ff0 db423040 d7f4bf54 d7f4bf38 c00f47f8 d7f4a000 c000e9a4 d7f4a000
bf40: c000ea10 d7f68000 00000001 00000000 d7f4a000 b6f52f3c d7f4bf84 d7f4bf68
bf60: c00784cc c0078294 00000000 00000000 bebff7b4 00000058 d7f4bf94 d7f4bf88
bf80: c00785a4 c00783e4 00000000 00000000 bebff7b4 00000058 00000000 d7f4bfa8
bfa0: c000e980 c0048a18 00000000 00000000 fee1dead 28121969 01234567 00000003
bfc0: 00000000 00000000 bebff7b4 00000058 00000000 00000000 b6f52f3c 00000000
bfe0: 00000058 bebff624 b6ea0a1d b6e2b276 20000030 fee1dead 00222c40 002d394c
Backtrace: 
[<c0075748>] (__lock_acquire) from [<c0077aa8>] (lock_acquire+0x68/0x7c)
 r10:d7f68000 r9:d7f4a000 r8:d7f4a000 r7:d7f68000 r6:600f0013 r5:d7f4a000
 r4:00000000
[<c0077a40>] (lock_acquire) from [<c05f80c4>] (mutex_lock_nested+0x5c/0x394)
 r7:00000000 r6:c08852cc r5:c030f814 r4:db2ac044
[<c05f8068>] (mutex_lock_nested) from [<c030f814>] (device_shutdown+0xd4/0x19c)
 r10:00000000 r9:d7f4a000 r8:c088131c r7:db2b0024 r6:c0dc5b64 r5:db2ac010
 r4:db2b0018
[<c030f740>] (device_shutdown) from [<c0048988>] (kernel_restart_prepare+0x3c/0x40)
 r8:c000eb44 r7:00000003 r6:00000000 r5:c0844cc8 r4:00000000 r3:c0883788
[<c004894c>] (kernel_restart_prepare) from [<c00489a0>] (kernel_restart+0x14/0x68)
[<c004898c>] (kernel_restart) from [<c0048af4>] (SyS_reboot+0xe8/0x1cc)
 r4:4321fedc r3:01234567
[<c0048a0c>] (SyS_reboot) from [<c000e980>] (ret_fast_syscall+0x0/0x48)
 r7:00000058 r6:bebff7b4 r5:00000000 r4:00000000
Code: 0affffbd e2883f41 f593f000 e1932f9f (e2822001) 
---[ end trace 44f221ca42d7ae57 ]---
Russell King - ARM Linux Oct. 20, 2013, 4:31 p.m. UTC | #8
On Sun, Oct 20, 2013 at 02:00:57PM +0100, Russell King - ARM Linux wrote:
> As for imx-drm, there was a warning which preceded that oops.  Here's the
> full log, below the "---------" marker - this is from unbinding the imx-drm
> module, and then trying to reboot.
> 
> imx-drm is really very broken in the way it tries to bend DRM to be
> used in DT - it doesn't consider the lifetime for anything like the
> CRTCs, connectors or encoders.  All these have empty .destroy functions
> to them. If we unbind imx-drm, the top level drm_device tries to be
> destroyed, but it leaves behind all the CRTCs, connectors and encoders,
> causing the first warning because none of the framebuffers got cleaned
> up through that destruction (because the functions did nothing.)
> 
> The second one is through trying to clean up the framebuffer, which is
> still in use.
> 
> The third one is caused because there's still allocated memory objects
> against the DRM memory manager - again, because nothing has been cleaned
> up.

Right, so how imx-drm "works" as far as DRM initialization is by a wing
and a prayer at the moment.

It works like this - the driver relies heavily upon this sequence:

- imx_drm_init()
  - creates an imx_drm_device structure to contain references to other
    parts.
  - registers the imx-drm platform device and an associated structure.
    - the platform device is immediately probed, causing it to be registered
      with the DRM subsystem.
    - the DRM subsystem creates the drm_device structure, and calls the
      drivers ->load method.
    - the driver initialises some basic data, places a pointer to the
      drm_device into the imx_drm_device and returns
- imx_pd_driver_init()
  - registers the imx_pd_driver platform device driver for DT devices
    with a compatible string of "fsl,imx-parallel-display"
  - such devices will be immediately probed
    - these allocate an imx_parallel_display structure, which contains
      a drm_connector and drm_encoder structure embedded within.
    - these structures are registered into the core of imx_drm, and
      via the imx_drm_device structure, are both attached to the
      drm_device immediately.
- imx_tve_driver_init()
  essentially the same as imx_pd_driver_init()
- imx_ldb_driver_init()
  essentially the same as imx_pd_driver_init()
- imx_ipu_driver_init()
  - registers a platform driver fot DT devices with a compatible string
    of "fsl,imx51-ipu", "fsl,imx53-ipu", or "fsl,imx6q-ipu".
  - initialises such devices, and creates two new platform devices
    called "imx-ipuv3-crtc", one for each display interface.
- ipu_drm_driver_init()
  - registers a platform driver for "imx-ipuv3-crtc" devices.
    - for each device found
      - it allocates a ipu_crtc device structure, which embeds a drm_crtc
        structure.
      - it registers a CRTC via imx_drm_add_crtc().
        - this allocates an imx_drm_crtc structure, and eventually registers
          the drm_crtc structure against the drm_device
- imx_hdmi_driver_init
  similar to imx_pd_driver_init

All that sequence is in init level 6.  The last bit comes in init level 7
(the late_initcall):

- imx_fb_helper_init()
  - this grabs the drm_device, and calls drm_fbdev_cma_init() on it
    hoping that we know the number of CRTCs at this point.  This is
    held indefinitely.
  - the resulting drm_fbdev_cma is saved into the imx_drm_device.

Now, if the imx-drm device is unbound from its driver, all hell breaks
loose - none of these crtc/connector/encoder structures have a meaningful
destroy function - their destruction is all in their individual driver
"remove" functions.  This causes some warnings to be spat out from DRM.

Amongst this is the "last_close" callback which looks at the imx_drm_device,
sees that drm_fbdev_cma is registered against it, and calls
drm_fbdev_cma_restore_mode() on it.  drm_fbdev_cma contains objects which
store a pointer to the drm_device structure that it was registered against,
which exists at this point, so everything is fine.

The unload proceeds, and eventually the drm_device is freed.

Now, if we rebind the imx-drm device, causing the probe actions above to
be repeated.  imx_drm_device still contains a pointer to the drm_fbdev_cma
object that was allocated...  Let's ignore the fact that none of the
sub-modules have re-initialised anything against this new drm_device.

The real fun comes when you try and unbind it again.  This time, the
drm_device which is being torn down isn't the one in drm_fbdev_cma,
but we still call drm_fbdev_cma_restore_mode().  This tries to get a
mutex on the _original_ drm_device->mode_config.mutex, which has been
freed.  The result is a kernel oops.

Now, several things stand out here: piece-meal construction of a
drm_device in this manner is unsafe:
- it relies heavily on all devices already being present at the time that
  the above sequence starts, and it assumes that the drivers will probe
  immediately, as soon as they are registered.
- the late_initcall() is really a "barrier" on the initialisation sequence:
  no CRTCs can be registered after that point.
- it is impossible to tear down and re-create the subsystem when the device
  goes wrong as you can never clear out that CMA fbdev helper, even if you
  unbind every other device in that setup in the right order.
- each of these drivers is itself a separate loadable module, which means
  when built in a modular state and loaded under Ubuntu 12.04, which does
  multi-threaded module loading, there is no guarantee of any initialisation
  order.

Really, this kind of hack needs to be outlawed.  Trying to bend a subsystem
which has a fairly solid model around a single "device" into this kind of
multi-device for the sake of DT is really buggered.

This is not an imx-drm specific problem: this the same problem which the
Armada DRM driver would have with DT: DT is based around describing
individual components of hardware separately rather than describing
something at high level.

I've been looking at what can be done with imx-drm.  One thing that
desperately needs sorting is that drm_fbdev_cma thing, which has to be
registered after all CRTCs.  The problem is that there is _no way_ to
positively know when all CRTCs have been registered, because they're
separate devices entirely.

For other stuff, it would require quite an amount of restructuring, so
that sub-modules don't "probe" themselves until the main drm_device is
known to be in place, and clean themselves up in the ->destroy callbacks.
... maybe.  Sorting out the connectors/encoders might actually be the
easier bit of the task, something which I'm currently looking into at
the moment.
Russell King - ARM Linux Oct. 20, 2013, 9:56 p.m. UTC | #9
On Sun, Oct 20, 2013 at 05:31:56PM +0100, Russell King - ARM Linux wrote:
> On Sun, Oct 20, 2013 at 02:00:57PM +0100, Russell King - ARM Linux wrote:
> > As for imx-drm, there was a warning which preceded that oops.  Here's the
> > full log, below the "---------" marker - this is from unbinding the imx-drm
> > module, and then trying to reboot.
> > 
> > imx-drm is really very broken in the way it tries to bend DRM to be
> > used in DT - it doesn't consider the lifetime for anything like the
> > CRTCs, connectors or encoders.  All these have empty .destroy functions
> > to them. If we unbind imx-drm, the top level drm_device tries to be
> > destroyed, but it leaves behind all the CRTCs, connectors and encoders,
> > causing the first warning because none of the framebuffers got cleaned
> > up through that destruction (because the functions did nothing.)
> > 
> > The second one is through trying to clean up the framebuffer, which is
> > still in use.
> > 
> > The third one is caused because there's still allocated memory objects
> > against the DRM memory manager - again, because nothing has been cleaned
> > up.
> 
> Right, so how imx-drm "works" as far as DRM initialization is by a wing
> and a prayer at the moment.
> 
> It works like this - the driver relies heavily upon this sequence:
> 
> - imx_drm_init()
>   - creates an imx_drm_device structure to contain references to other
>     parts.
>   - registers the imx-drm platform device and an associated structure.
>     - the platform device is immediately probed, causing it to be registered
>       with the DRM subsystem.
>     - the DRM subsystem creates the drm_device structure, and calls the
>       drivers ->load method.
>     - the driver initialises some basic data, places a pointer to the
>       drm_device into the imx_drm_device and returns
> - imx_pd_driver_init()
>   - registers the imx_pd_driver platform device driver for DT devices
>     with a compatible string of "fsl,imx-parallel-display"
>   - such devices will be immediately probed
>     - these allocate an imx_parallel_display structure, which contains
>       a drm_connector and drm_encoder structure embedded within.
>     - these structures are registered into the core of imx_drm, and
>       via the imx_drm_device structure, are both attached to the
>       drm_device immediately.
> - imx_tve_driver_init()
>   essentially the same as imx_pd_driver_init()
> - imx_ldb_driver_init()
>   essentially the same as imx_pd_driver_init()
> - imx_ipu_driver_init()
>   - registers a platform driver fot DT devices with a compatible string
>     of "fsl,imx51-ipu", "fsl,imx53-ipu", or "fsl,imx6q-ipu".
>   - initialises such devices, and creates two new platform devices
>     called "imx-ipuv3-crtc", one for each display interface.
> - ipu_drm_driver_init()
>   - registers a platform driver for "imx-ipuv3-crtc" devices.
>     - for each device found
>       - it allocates a ipu_crtc device structure, which embeds a drm_crtc
>         structure.
>       - it registers a CRTC via imx_drm_add_crtc().
>         - this allocates an imx_drm_crtc structure, and eventually registers
>           the drm_crtc structure against the drm_device
> - imx_hdmi_driver_init
>   similar to imx_pd_driver_init
> 
> All that sequence is in init level 6.  The last bit comes in init level 7
> (the late_initcall):
> 
> - imx_fb_helper_init()
>   - this grabs the drm_device, and calls drm_fbdev_cma_init() on it
>     hoping that we know the number of CRTCs at this point.  This is
>     held indefinitely.
>   - the resulting drm_fbdev_cma is saved into the imx_drm_device.
> 
> Now, if the imx-drm device is unbound from its driver, all hell breaks
> loose - none of these crtc/connector/encoder structures have a meaningful
> destroy function - their destruction is all in their individual driver
> "remove" functions.  This causes some warnings to be spat out from DRM.
> 
> Amongst this is the "last_close" callback which looks at the imx_drm_device,
> sees that drm_fbdev_cma is registered against it, and calls
> drm_fbdev_cma_restore_mode() on it.  drm_fbdev_cma contains objects which
> store a pointer to the drm_device structure that it was registered against,
> which exists at this point, so everything is fine.
> 
> The unload proceeds, and eventually the drm_device is freed.
> 
> Now, if we rebind the imx-drm device, causing the probe actions above to
> be repeated.  imx_drm_device still contains a pointer to the drm_fbdev_cma
> object that was allocated...  Let's ignore the fact that none of the
> sub-modules have re-initialised anything against this new drm_device.
> 
> The real fun comes when you try and unbind it again.  This time, the
> drm_device which is being torn down isn't the one in drm_fbdev_cma,
> but we still call drm_fbdev_cma_restore_mode().  This tries to get a
> mutex on the _original_ drm_device->mode_config.mutex, which has been
> freed.  The result is a kernel oops.
> 
> Now, several things stand out here: piece-meal construction of a
> drm_device in this manner is unsafe:
> - it relies heavily on all devices already being present at the time that
>   the above sequence starts, and it assumes that the drivers will probe
>   immediately, as soon as they are registered.
> - the late_initcall() is really a "barrier" on the initialisation sequence:
>   no CRTCs can be registered after that point.
> - it is impossible to tear down and re-create the subsystem when the device
>   goes wrong as you can never clear out that CMA fbdev helper, even if you
>   unbind every other device in that setup in the right order.
> - each of these drivers is itself a separate loadable module, which means
>   when built in a modular state and loaded under Ubuntu 12.04, which does
>   multi-threaded module loading, there is no guarantee of any initialisation
>   order.
> 
> Really, this kind of hack needs to be outlawed.  Trying to bend a subsystem
> which has a fairly solid model around a single "device" into this kind of
> multi-device for the sake of DT is really buggered.
> 
> This is not an imx-drm specific problem: this the same problem which the
> Armada DRM driver would have with DT: DT is based around describing
> individual components of hardware separately rather than describing
> something at high level.
> 
> I've been looking at what can be done with imx-drm.  One thing that
> desperately needs sorting is that drm_fbdev_cma thing, which has to be
> registered after all CRTCs.  The problem is that there is _no way_ to
> positively know when all CRTCs have been registered, because they're
> separate devices entirely.
> 
> For other stuff, it would require quite an amount of restructuring, so
> that sub-modules don't "probe" themselves until the main drm_device is
> known to be in place, and clean themselves up in the ->destroy callbacks.
> ... maybe.  Sorting out the connectors/encoders might actually be the
> easier bit of the task, something which I'm currently looking into at
> the moment.

Further comments as a result of this: I have a much better solution
in place for encoders and connectors.  I'm now able to remove and
re-add back connectors.  This all sounds good, but it doesn't quite
work.

The reason is that the fb_helper layer caches pointers to the
connectors, and number of connectors.  This doesn't get updated when
we remove and add connectors - which causes another set of problems.

A similar problem exists if we add a connector after the fb helper
has been initialised.
diff mbox

Patch

diff --git a/drivers/staging/imx-drm/imx-hdmi.c b/drivers/staging/imx-drm/imx-hdmi.c
index ca0450b..942dda6 100644
--- a/drivers/staging/imx-drm/imx-hdmi.c
+++ b/drivers/staging/imx-drm/imx-hdmi.c
@@ -133,7 +133,6 @@  struct imx_hdmi {
 	struct i2c_adapter *ddc;
 	void __iomem *regs;
 
-	struct fb_videomode fb_mode;
 	spinlock_t enable_lock;
 	spinlock_t lock;
 	unsigned long pixel_clk_rate;
@@ -1221,20 +1220,18 @@  static void hdmi_config_AVI(struct imx_hdmi *hdmi)
 	hdmi_writeb(hdmi, 0, HDMI_FC_AVISRB1);
 }
 
-static void hdmi_av_composer(struct imx_hdmi *hdmi)
+static void hdmi_av_composer(struct imx_hdmi *hdmi,
+	const struct drm_display_mode *mode)
 {
 	u8 inv_val;
-	struct fb_videomode *fb_mode = &hdmi->fb_mode;
 	struct hdmi_vmode *vmode = &hdmi->hdmi_data.video_mode;
-	int hblank, vblank;
+	int hblank, vblank, h_de_hs, v_de_vs, hsync_len, vsync_len;
 
-	vmode->mhsyncpolarity = ((fb_mode->sync & FB_SYNC_HOR_HIGH_ACT) != 0);
-	vmode->mvsyncpolarity = ((fb_mode->sync & FB_SYNC_VERT_HIGH_ACT) != 0);
-	vmode->minterlaced = ((fb_mode->vmode & FB_VMODE_INTERLACED) != 0);
-	vmode->mpixelclock = (fb_mode->xres + fb_mode->left_margin +
-		fb_mode->right_margin + fb_mode->hsync_len) * (fb_mode->yres +
-		fb_mode->upper_margin + fb_mode->lower_margin +
-		fb_mode->vsync_len) * fb_mode->refresh;
+	vmode->mhsyncpolarity = !!(mode->flags & DRM_MODE_FLAG_PHSYNC);
+	vmode->mvsyncpolarity = !!(mode->flags & DRM_MODE_FLAG_PVSYNC);
+	vmode->minterlaced = !!(mode->flags & DRM_MODE_FLAG_INTERLACE);
+	vmode->mpixelclock = mode->htotal * mode->vtotal *
+		drm_mode_vrefresh(mode);
 
 	dev_dbg(hdmi->dev, "final pixclk = %d\n", vmode->mpixelclock);
 
@@ -1272,38 +1269,40 @@  static void hdmi_av_composer(struct imx_hdmi *hdmi)
 
 	hdmi_writeb(hdmi, inv_val, HDMI_FC_INVIDCONF);
 
-	/* Set up horizontal active pixel region width */
-	hdmi_writeb(hdmi, fb_mode->xres >> 8, HDMI_FC_INHACTV1);
-	hdmi_writeb(hdmi, fb_mode->xres, HDMI_FC_INHACTV0);
+	/* Set up horizontal active pixel width */
+	hdmi_writeb(hdmi, mode->hdisplay >> 8, HDMI_FC_INHACTV1);
+	hdmi_writeb(hdmi, mode->hdisplay, HDMI_FC_INHACTV0);
 
-	/* Set up vertical blanking pixel region width */
-	hdmi_writeb(hdmi, fb_mode->yres >> 8, HDMI_FC_INVACTV1);
-	hdmi_writeb(hdmi, fb_mode->yres, HDMI_FC_INVACTV0);
+	/* Set up vertical active lines */
+	hdmi_writeb(hdmi, mode->vdisplay >> 8, HDMI_FC_INVACTV1);
+	hdmi_writeb(hdmi, mode->vdisplay, HDMI_FC_INVACTV0);
 
 	/* Set up horizontal blanking pixel region width */
-	hblank = fb_mode->left_margin + fb_mode->right_margin +
-		fb_mode->hsync_len;
+	hblank = mode->htotal - mode->hdisplay;
 	hdmi_writeb(hdmi, hblank >> 8, HDMI_FC_INHBLANK1);
 	hdmi_writeb(hdmi, hblank, HDMI_FC_INHBLANK0);
 
 	/* Set up vertical blanking pixel region width */
-	vblank = fb_mode->upper_margin + fb_mode->lower_margin +
-		fb_mode->vsync_len;
+	vblank = mode->vtotal - mode->vdisplay;
 	hdmi_writeb(hdmi, vblank, HDMI_FC_INVBLANK);
 
 	/* Set up HSYNC active edge delay width (in pixel clks) */
-	hdmi_writeb(hdmi, fb_mode->right_margin >> 8, HDMI_FC_HSYNCINDELAY1);
-	hdmi_writeb(hdmi, fb_mode->right_margin, HDMI_FC_HSYNCINDELAY0);
+	h_de_hs = mode->hsync_start - mode->hdisplay;
+	hdmi_writeb(hdmi, h_de_hs >> 8, HDMI_FC_HSYNCINDELAY1);
+	hdmi_writeb(hdmi, h_de_hs, HDMI_FC_HSYNCINDELAY0);
 
 	/* Set up VSYNC active edge delay (in pixel clks) */
-	hdmi_writeb(hdmi, fb_mode->lower_margin, HDMI_FC_VSYNCINDELAY);
+	v_de_vs = mode->vsync_start - mode->vdisplay;
+	hdmi_writeb(hdmi, v_de_vs, HDMI_FC_VSYNCINDELAY);
 
 	/* Set up HSYNC active pulse width (in pixel clks) */
-	hdmi_writeb(hdmi, fb_mode->hsync_len >> 8, HDMI_FC_HSYNCINWIDTH1);
-	hdmi_writeb(hdmi, fb_mode->hsync_len, HDMI_FC_HSYNCINWIDTH0);
+	hsync_len = mode->hsync_end - mode->hsync_start;
+	hdmi_writeb(hdmi, hsync_len >> 8, HDMI_FC_HSYNCINWIDTH1);
+	hdmi_writeb(hdmi, hsync_len, HDMI_FC_HSYNCINWIDTH0);
 
 	/* Set up VSYNC active edge delay (in pixel clks) */
-	hdmi_writeb(hdmi, fb_mode->vsync_len, HDMI_FC_VSYNCINWIDTH);
+	vsync_len = mode->vsync_end - mode->vsync_start;
+	hdmi_writeb(hdmi, vsync_len, HDMI_FC_VSYNCINWIDTH);
 }
 
 static void imx_hdmi_phy_disable(struct imx_hdmi *hdmi)
@@ -1383,42 +1382,13 @@  static void hdmi_disable_overflow_interrupts(struct imx_hdmi *hdmi)
 		    HDMI_IH_MUTE_FC_STAT2);
 }
 
-static inline void
-convert_to_video_timing(struct fb_videomode *timing,
-			struct drm_display_mode *mode)
-{
-	memset(timing, 0, sizeof(*timing));
-
-	timing->pixclock = mode->clock * 1000;
-	timing->refresh = drm_mode_vrefresh(mode);
-
-	timing->xres = mode->hdisplay;
-	timing->left_margin = mode->hsync_start - mode->hdisplay;
-	timing->hsync_len = mode->hsync_end - mode->hsync_start;
-	timing->right_margin = mode->htotal - mode->hsync_end;
-
-	timing->yres = mode->vdisplay;
-	timing->upper_margin = mode->vsync_start - mode->vdisplay;
-	timing->vsync_len = mode->vsync_end - mode->vsync_start;
-	timing->lower_margin = mode->vtotal - mode->vsync_end;
-
-	if (mode->flags & DRM_MODE_FLAG_INTERLACE)
-		timing->vmode = FB_VMODE_INTERLACED;
-	else
-		timing->vmode = FB_VMODE_NONINTERLACED;
-
-	if (mode->flags & DRM_MODE_FLAG_DBLSCAN)
-		timing->vmode |= FB_VMODE_DOUBLE;
-}
-
 static int imx_hdmi_setup(struct imx_hdmi *hdmi, struct drm_display_mode *mode)
 {
 	int ret;
-	convert_to_video_timing(&hdmi->fb_mode, mode);
 
 	hdmi_disable_overflow_interrupts(hdmi);
 
-	hdmi->vic = 6;
+	hdmi->vic = drm_match_cea_mode(mode);
 
 	if (!hdmi->vic) {
 		dev_dbg(hdmi->dev, "Non-CEA mode used in HDMI\n");
@@ -1461,7 +1431,7 @@  static int imx_hdmi_setup(struct imx_hdmi *hdmi, struct drm_display_mode *mode)
 	hdmi->hdmi_data.video_mode.mdataenablepolarity = true;
 
 	/* HDMI Initialization Step B.1 */
-	hdmi_av_composer(hdmi);
+	hdmi_av_composer(hdmi, mode);
 
 	/* HDMI Initializateion Step B.2 */
 	ret = imx_hdmi_phy_init(hdmi);