[CE OpenEmbedded] How to change display resolution?

Hi Everyone,

I’m testing on Yocto RPB 16.06 image, and want to change HDMI display resolution for test.

I use ‘fbset’ command in run-time, but the screen resolution keeps identical, only the active area is changed.
Should I modify device tree and rebuild DT & boot images for this requirement?
Do you have any ways to change display resolution efficiently?

Thanks,
Daniel

The video driver you are running is based on DRM/KMS. As a result the kernel determines the best video mode at boot. This can be interfered with by altering the kernel command line arguments. The arch linux wiki has a good review of the different ways this can be accomplished.

Take note of the warning in the middle of the text. If you use video= then only the text console is affected. If you want X11 and the text console to use the same mode then you must use the drm_kms_helper.edid_firmware= method instead. Also note that all the EDIDs provided by the kernel are DVI-D EDIDs rather than HDMI EDIDs (so I think the driver will end up running in DVI-D mode and there will be no audio).

@danielt Thanks! I verify the two methods and both of them are workable!

But I’m curious about the way to modify kernel command line arguments. Currently, I add the argument in <BSP>/meta-qcom/recipes-kernel/linux/linux-qcom-bootimg.inc, and bitbake linux-linaro-qcomlt again to generate boot.img. However, is that a normal way to update kernel command line arguments? Do you have alternative method in run-time?

Thanks,
Daniel

Glad to hear this worked for you.

Yes. This is the normal way, at least for the Dragonboard 410c. This board uses LittleKernel as a bootloader and it loads the kernel, FDT and command line arguments from a raw (no filesystem) boot partition. This is a very common approach on Android systems which is where these tools derive from. Are you using ssh+dd to burn the image after you created it? If not, that is a good trick to avoid having to mess about getting into fastboot mode.

It is possible to modify the command line arguments by parsing the raw partition to find the arguments and amending them. However I am not aware of anyone having written a tool to automate this.

Alternatively you could run skales (which is used to generate boot.img) on the target. You have to copy the kernel and FDT to the target and then you are able to generate an image, with a new command line, and burn it all from one script. However I’ve only tried this on debian; you might find that you have to add a lot of extra packages to OE to get that to work.

@danielt Thanks for detailed explanations. Yes, I’m using fastboot to flash images. It’s easier and safer.

I have also tried Android or Linux on other platforms (not Dragonboard 410c). Some of they are using U-Boot (Universal Boot Loader) and it can be configured as waiting user’s interaction when booting. So, users can add/modify kernel command line arguments in bootloader stage, and then jump into kernel.

I’m also curious if lk supports this feature?

Thanks,
Daniel

Sorry LK doesn’t support this feature. By default it supports extremely minimal user interaction (vol up, vol down or no button).

Note that 96Boards are not required to use an particular bootloader (hikey uses UEFI+grub2, bubblegum-96 uses u-boot) and, in any case, other bootloaders may be ported to them by the community (hikey has a uboot port for example).

@danielt Got it! Maybe I can consider to use u-boot on Dragonboard 410c. Thank you!

I was just chatting to @ndec on #96boards (IRC) and two things came up…

Firstly there is a u-boot port as well! It works by getting LK to boot u-boot (effectively inserting u-boot into the boot flow between LK and the kernel). It will slow down the boot but gain you all the flexibility u-boot can offer.

Secondly there is actually a tool that can update the command line on the target! The abootimg tool that is used to prepare the boot image has an update option. I’ve just tested it and the update option can be applied to a raw partition.

I tried the following (on debian):

abootimg -i /dev/disk/by-partlabel/boot
abootimg -u /dev/disk/by-partlabel/boot -c &quot;cmdline=root=/dev/disk/by-partlabel/rootfs rw rootwait console=tty0 console=ttyMSM0,115200n8 quiet&quot;

To get abootimg onto OE you’ll need to include the meta-android layer…

@danielt @ndec Both of you are fantastic! I tried on OE and it work as well!

abootimg -i /dev/disk/by-partlabel/boot
abootimg -u /dev/disk/by-partlabel/boot -c &quot;cmdline=root=/dev/mmcblk0p10 rw rootwait console=ttyMSM0,115200n8 drm_kms_helper.edid_firmware=HDMI-A-1:edid/1920x1080.bin&quot;

But I do not migrate entire meta-android layer. I just add abootimg_git.bb into my build. Thank you!

Hi all,

I get another problem about resolution change.
I would like to change to 640x480 which does not support by default in Documentation/EDID.
Then, I follow the steps below and try to generate a new 640x480.bin.
But, it seems not work. Does anyone know which step is wrong? Thanks!

*1. Get modeline setting for 640x480


$ cvt 640 480 60
# 640x480 59.38 Hz (CVT 0.31M3) hsync: 29.69 kHz; pclk: 23.75 MHz
Modeline &quot;640x480_60.00&quot;   23.75  640 664 720 800  480 483 487 500 -hsync +vsync

*2. Change the settings to EDID.S
HowTo


/* EDID */
#define VERSION 1
#define REVISION 3

/* Display */
#define CLOCK 23750 /* kHz */
#define XPIX 640
#define YPIX 480
#define XY_RATIO XY_RATIO_4_3
#define XBLANK 160
#define YBLANK 20
#define XOFFSET 24
#define XPULSE 56
#define YOFFSET (63+3)
#define YPULSE (63+4)
#define DPI 72
#define VFREQ 60 /* Hz */
#define TIMING_NAME &quot;Linux XGA&quot;
#define ESTABLISHED_TIMINGS_BITS 0x20 /* Bit 3 -&gt; 640x480 @60 Hz */
#define HSYNC_POL 0
#define VSYNC_POL 0
#define CRC 0x96

#include &quot;edid.S&quot;

*3. Modify EDID checksum


$ edid-decode 640x480.bin
...
Monitor name: Linux XGA
   Checksum: 0x96 (should be 0xd2)
EDID block does not conform at all!
        Block has broken checksum

//Modify the correct checksum into 640x480.S and build again
$ edid-decode 640x480.bin
...
Monitor name: Linux XGA
   Checksum: 0xd2

*4. Add 640x480.bin to kernel cmdline


$ cp 640x480.bin /usr/lib/firmware/edid
$ abootimg -u /dev/disk/by-partlabel/boot -c &quot;cmdline=root=/dev/mmcblk0p10 rw rootwait console=ttyMSM0,115200n8 drm_kms_helper.edid_firmware=edid/640x480.bin&quot;
$ reboot

1 Like

The only thing I can offer you is that cvt generates timings different to both 800x600.S (which I wrote) and 1024x768.S (nothing to do with me).

When I was working on 800x600.S I just grabbed the timing from the Mr. Internet (checking the timings against 1024x768.S as a basic quality test). http://martin.hinner.info/vga/timing.html looks OK.

@danielt Thanks! I find the root cause now. It’s not about different timing configurations. All the timings are workable, including cvt and the websites you provided.

In short, there are two problems.

  1. Incorrect firmware search PATH
    I put the 640x480.bin in /usr/lib/firmware/edid folder as arch linux wiki mentioned, but this path is invalid.
    According to Linux kernel documentation, I should put the binary into /lib/firmware/ folder.

  2. EDID firmware cannot be loaded, when DRM detects HDMI at bootup.
    If I boot with HDMI cable inserted, I get the following error messages.


[drm:drm_load_edid_firmware] *ERROR* Requesting EDID firmware &quot;edid/640x480.bin&quot; failed (err=-2)

To load EDID binary successfully, I have to unplug & plug in HDMI cable again.
Or, it also works if I insert HDMI cable later after kernel is ready.

I think the default resolutions, e.g. 1024x768, 800x600, etc. works at boot up, because those EDID has already built-in in <kernel>/drivers/gpu/drm/drm_edid_load.c, and they are not loaded via firmware.

Best regards,
Daniel

Great to hear you’ve got it working.

Reflecting on the video timings I think the “best” timings to use would be those from the CEA-861 spec. 640x480p60 mode (CEA-861 mode 1) is the only universally supported HDMI video mode so adopting these timing should result in the greatest monitor compatibility.

Regarding the loading of the “firmware” from the filesystem, I suspect the root filesystem has not yet been mounted. If you do require this to work without a hotplug it might be necessary to compile the DRM drivers as a module…