Preserve U-Boot splash on Colibri-iMX6DL

I have a Colibri iMX6DL running a custom version of Toradex BSP 7.2
I have U-Boot configured to show a splash screen and Linux configured to drive a parallel display, both working fine individually.
However between U-Boot jumping to the kernel and my user-space application running the display goes blank.
I would like to preserve the U-Boot splash screen until my application runs.

I have done this before on the iMX8X, my strategy was to prevent U-Boot from disabling the driver, reserve the U-Boot framebuffer memory in the Linux device tree and then have the mxsfb driver re-use that framebuffer.

Trying the same strategy on the iMX6DL I am able to prevent U-Boot from disabling the driver, and to reserve the U-Boot framebuffer.
However I can’t find a way to have the imx-drm driver re-use the framebuffer, it always creates its own buffer(s).

Has anyone else worked on this problem? Is there a method to pass an existing buffer to a DRM driver? Is this even the right way to tackle this problem?

Hi, I’m the Toradex AI Assistant.

I might make mistakes or occasionally get you wrong. Our support team will step in if needed.


i.MX6 DRM Driver Behavior and Framebuffer Reuse

Based on the available documentation, the challenge you’re experiencing with the imx-drm driver on Colibri iMX6DL is well-documented. The imx-drm driver has specific limitations regarding framebuffer reuse that differ from other platforms.

Key Limitations with i.MX6 DRM

The i.MX6 DRM implementation creates its own framebuffer buffers and doesn’t provide a straightforward mechanism to reuse existing U-Boot framebuffers (1). This is a known limitation of the current imx-drm driver architecture.

Alternative Approaches for i.MX6

For i.MX6-based modules, the documentation suggests working with the framebuffer configuration through kernel command line parameters (1):

"video=mxcfb<number>:dev=<Output>,<Mode Specifier>,if=<Output Format>,[bpp=<Framebuffer Depth>]"

For parallel RGB displays, you would use:

video=mxcfb0:dev=lcd,EDT-WVGA,if=RGB24

Device Tree Memory Reservation

You can reserve memory regions in the device tree as you’ve done before (2). The /reserved-memory node can be defined at SoC or SoM level:

/reserved-memory

However, the imx-drm driver’s behavior of creating its own buffers means this reserved memory approach may not work as expected with the DRM subsystem.

Framebuffer vs DRM Considerations

The documentation notes an important limitation: “The Vivante X driver can only make use of the first framebuffer /dev/fb0 while the others can be used through the fbdev framebuffer interface” (1). This suggests that applications using DRM may face different constraints than those using the traditional framebuffer interface.

Community Discussion

There has been discussion in the community about similar challenges with i.MX6 DRM drivers, particularly regarding color depth and framebuffer management (3). The consensus indicates that the imx-drm driver has architectural limitations that make framebuffer reuse difficult.

Recommended Approach

Given the documented limitations of the imx-drm driver on i.MX6, you might need to consider:

  1. Using the traditional mxcfb framebuffer interface instead of DRM if your application allows it
  2. Implementing a custom solution that works with the DRM driver’s buffer allocation behavior
  3. Exploring kernel-level modifications to the imx-drm driver (though this would require significant development effort)

The approach that worked on i.MX8X unfortunately doesn’t translate directly to i.MX6DL due to the different driver architectures and capabilities.

**


Did you like my answer? :+1: :-1:

If I answered your question, please tick the “Solution” checkbox.

For follow-up questions to me, please use @ToradexAI in your post.

I am indeed using a reserved-memory node to preserve the U-Boot framebuffer.
I am only attempting to use /dev/fb0 (and indeed, CAN use /dev/fb0) so I don’t think that reference is relevant, at any rate it comes from an older BSP.

I’m not sure what the AI is suggesting with the command line parameters. My parallel display is already working and those parameters don’t provide any additional information.

Likewise the community post referenced seems to be about getting the parallel display working in the first place, not about framebuffer reuse.

I have not explored using the mxcfb driver on the iMX6, since the BSP already provides a device tree configured to use imx-drm, but I suppose that would be possible.

I am currently looking at modifications to the imx-drm driver, but I’m not very familiar with the drm subsystem.

Any input on where to make changes, or a general approach, would be helpful.

Based on the available documentation and your specific requirements for preserving the U-Boot framebuffer with the imx-drm driver on Colibri iMX6DL, you’re facing a well-documented architectural challenge.

DRM Driver Buffer Allocation Behavior

The community discussion confirms that the imx-drm driver on i.MX6 “always creates its own buffer(s)” and doesn’t provide a straightforward mechanism for reusing existing framebuffers (1). This is indeed a driver limitation rather than a hardware restriction (1).

Potential DRM Subsystem Modification Approach

Since you’re exploring modifications to the imx-drm driver, the key areas to investigate would be:

  1. Buffer allocation during DRM initialization - The driver typically allocates its own framebuffer memory during the modeset process
  2. Memory mapping in the DRM framework - Look for where the driver maps physical memory to the DRM framebuffer objects
  3. Integration with reserved memory - You’ll need to modify how the driver handles memory allocation to use your reserved region instead

Alternative: mxcfb Driver Consideration

For BSP 7.x on i.MX6, the documentation shows that the traditional mxcfb framebuffer interface was available in earlier kernel versions (2). The mxcfb driver supported direct framebuffer access through /dev/fb0 and had more straightforward memory management that might be more compatible with your framebuffer preservation approach (2).

However, transitioning from imx-drm back to mxcfb would require significant device tree modifications and potentially kernel configuration changes.

Framebuffer Console Considerations

The documentation provides some insights on framebuffer console management that might be relevant (3). You could explore disabling the framebuffer console entirely during the transition period to prevent conflicts:

# systemctl disable getty@tty1.service

(3)

Or use kernel parameters to redirect console output away from your display framebuffer (3).

Summary

Unfortunately, the available documentation confirms that achieving framebuffer reuse with imx-drm on i.MX6DL requires kernel driver modifications, as there’s no documented standard mechanism for this functionality (1). The driver architecture differences between i.MX6 and i.MX8X explain why your previous approach doesn’t translate directly.

Your current path of exploring imx-drm driver modifications is likely the most viable approach, though it requires deep DRM subsystem knowledge.

Best regards, Toradex AI Assistant.


Did you like my answer? :+1: :-1:

If I answered your question, please tick the “Solution” checkbox.

For follow-up questions to me, please use @ToradexAI in your post.

Hi @SamM,

I’m working on this topic at the moment. I will also need to a look a bit deeper into the imx-drm driver and also check if there are any upstream implementations already. I will update you soon.

Hi Rudhi,

I’ll definitely be interested to hear what you find.
I’ve realised my original strategy was bad. I don’t need the imx-drm driver to use the same framebuffer as U-Boot. It is enough to avoid committing to the new framebuffer until there is something to display.

I’ve been able to determine where imx-drm creates the framebuffer (drm_fbdev_dma.c), and at that point I can copy my splash out of the original framebuffer and into the drm framebuffer and it appears on the screen. That reduces the time my screen is blank, but is too hacky for me to consider it a solution.

I’m now getting my head around the hardware registers, with the aim of just keeping the U-Boot framebuffer active until imx-drm is ready to take over.

I now have something working, though its still very hacky. The changes I made are:

  1. Prevent U-Boot from disabling the IPU on jump to the kernel, by commenting the call to ipuv3_fb_shutdown
  2. Reserve the U-Boot framebuffer with a reserved-memory node in the kernel device tree.
  3. Pass clk_ignore_unused as a boot argument to prevent gating of CCGR3
  4. Skip early clock initialisation in imx6q_clocks_init (specifically IMX6QDL_CLK_IPU1_SEL, IMX6QDL_CLK_IPU1_DI0_PRE_SEL and IMX6QDL_CLK_IPU1_DI0_SEL)
  5. Skip various reset calls in ipu_probe(as U-Boot has already set things up)
    1. device_reset
    2. ipu_memory_reset
    3. A write to IPU_DISP_GEN
    4. Writes to IPU_DC_WR_CH_CONF and IPU_DC_MAP in ipu_dc_init
    5. A write to IPU_DI_BS_CLKGEN0 in ipu_di_init
  6. Copy the splash from reserved framebuffer memory to the CMA-backed IPU framebuffer in drm_fbdev_dma_helper_fb_probe

Note that this does change the clocks ultimately used by the IPU driver.
U-Boot derives its IPU clocks from PLL3 while the kernel wants to use PLL5. That clock change was one of the causes of the LCD blank.
I intend to go through both U-Boot and the kernel to see if I can have them configure the same clocks, then revert some of the above changes.

I think copying the U-Boot framebuffer into the ipu-drm framebuffer shortly after allocation is slightly neater than my original plan of preventing early commits, and probably avoided some flickering issues that I ran into with the iMX8.

HI @SamM,

Thanks for sharing your solution here. I’m sure it will help others. Although, hacky as you said, this looks like probably the best workaround. I could also learn something from this.

Anyway, I was discussing your solution with a colleague of mine who is more experienced than me on such topics. He also thinks that if you need a smooth transition, this is the best way to do it. However, instead of disabling the clock setup maybe you can just adapt the device tree, so that the kernel and U-Boot use the same IPU clocks?
It would look something like this:

&ipu1 {	
    assigned-clocks = <&clks IMX6QDL_CLK_IPU1_SEL>;
	assigned-clock-parents = <&clks IMX6QDL_CLK_PLL3_120M>;
}

However, we are not sure if this is the correct clock because PLL5 is not even available for the IPU on the i.MX6. You can find the clock configuration in /sys/kernel/debug/clk/clk_summary. Then you can compare the clocks normally with your hacks applied. Then you can try to change the device tree based on the differences between when the hack is applied and not.

Hi @rudhi.tx

I’ve been working on this a bit more this afternoon.
I think I have managed to switch U-Boot to use PLL5, but I’m getting a flicker on the kernel transition. It looks like the PLL frequency is changing, but I’m not sure why at the moment.
Some of the IPU registers also don’t look right to me at the moment.

Are you sure about this?
If I’m reading the IMX6SDL reference manual correctly, setting CCM_CHSCCDR[8:6] to 0b010 and CCM_CHSCCDR[2:0] to 0b000 results in IPU1_DI0 clocks derived from PLL5

EDIT: But the ipu1_hsp_clk cannot use PLL5, as you say

I hadn’t come across the assigned-clocks property, I’ll take a look at that.

1 Like

Hi @SamM,

Have you made any progress on this topic?

Hi @rudhi.tx

Perhaps even more hacky at this point, but I have been able to get U-Boot to derive the IPU1_DI0_CLK from PLL5 and preserve those clocks through to the kernel.

On the kernel side the change is minimal, imx6q_clocks_init contains a call to disable_anatop_clockswhich explicitly gates PLL5. I just prevent that.
In theory this is OK because no re-parenting is taking place now.

The U-Boot changes are more significant, as I think the U-Boot_2024_07 driver is hard-coded to use LDB. My patch looks like this:
0007-pll.patch (7.6 KB)

I expose the (pre-existing) enable_pll_videofunction so that I can call it from the board file.
In the board file I call that with the same parameters used by Linux and adjust the hard-coded configuration to set up IPU clock sources rather than LDB clock sources.
I also disable the backlight because mine is driven independently.
This all seems reasonable.

The part that is a bit more hacky is in the imx ipu drivers.
I added a clk struct with the rate chosen to match my pixel clock/16 (the driver always multiplies up by 16 because ??), set g_di_clk[0] to use that and adjusted a few clk_set_parent calls so that the parent of g_pixel_clk[0] is g_di_clk[0]

Ideally most (all?) of that would be loaded from the device tree. I’m not sure if I’m up for the challenge of getting that working.