1

my stack is: raspberrypi, uboot, buildroot and weston. I have two display devices connected to the board. First is the touchscreen for the user interface(HDMI-A-1), second is for the projector (HDMI-A-2). I use a custom kernel boot logo. Is it possible to show the boot splash screen only on HDMI-A-1? I managed to do this by disabling HDMI-A-2 in bootargs as following:

bootargs=console=ttyAMA0,115200 earlycon=ttyAMA0,115200 splash video=HDMI-A-1:1024x600-32 video=HDMI-A-2:d vt.global_cursor_default=0

but later I'm not able to turn on HDMI-A-2 during runtime:

connector[89]: HDMI-A-1
        crtc=crtc-0
        self_refresh_aware=0
connector[153]: HDMI-A-2
        crtc=(null)
        self_refresh_aware=0

Is there any solution?

EDIT:

I discovered that it is partially possible by mapping frame buffers to consoles:

fbcon=map:1

documentation

It will work only in case both displays have separate frame buffers. Unfortunately vc4 issues one shared framebuffer for both monitors so it is not a solution for me.

EDIT2:

Unfortunately according to my knowledge it is not possible without patching the kernel. There is raspberrypi firmware that is able to do this, but it only compiles on 32bit systems. RaspberryPi firmware developers strongly claim that there is no 64bit port and they have no future plans to do this.

link: https://github.com/raspberrypi/firmware/issues/550

Piotr Zych
  • 61
  • 5
  • This [article](https://yingtongli.me/blog/2016/12/21/splash.html) is not recent, but may help with the problem. I don't have a Raspberry Pi to test on. – harrymc Oct 04 '21 at 16:48
  • @harrymc Both displays share same fb. There is no possibility to switch mode from mirror to extended (mirror means two displays output the same buffer). – Piotr Zych Oct 04 '21 at 17:14
  • The "edit2" do you have a link? If the source code here - https://github.com/raspberrypi/firmware contains it; your only option is to create a kernel patch. – tukan Oct 08 '21 at 09:39
  • 1
    @tukan there is one more option, but I'am working on it. It's about creating a dummy frame buffer using `DRM_IOCTL_MODE_CREATE_DUMB`. Then you are able to set resolution and control each display separately. Then put program to triggered by udev after `/dev/dri/video0` startup. When I finish, I will post solution. The effects are quite promising – Piotr Zych Oct 11 '21 at 11:37

1 Answers1

0

As I mentioned in comments, there is possibility to create dummy frame buffer using DRM.

  1. Prepare your logo in proper resolution in *.h file. It may be helpful: https://lvgl.io/tools/imageconverter

  2. We need to write simple C program:

a) include logo from first step:

#include "logo.h"

b) we need this to invoke drm via ioctl:

#include <sys/ioctl.h>
#include <drm/drm.h>
#include <drm/drm_mode.h>

c) open proper device:

int dri_fd0  = open("/dev/dri/card0",O_RDWR | O_CLOEXEC);

d) retrieve info from drm:

struct drm_mode_modeinfo conn_mode_buf[20]={0};
    uint64_t    conn_prop_buf[20]={0},
                conn_propval_buf[20]={0},
                conn_enc_buf[20]={0};

    struct drm_mode_get_connector conn={0};

    conn.connector_id=res_conn_buf[i];

    ioctl(dri_fd, DRM_IOCTL_MODE_GETCONNECTOR, &conn);
    conn.modes_ptr=(uint64_t)conn_mode_buf;
    conn.props_ptr=(uint64_t)conn_prop_buf;
    conn.prop_values_ptr=(uint64_t)conn_propval_buf;
    conn.encoders_ptr=(uint64_t)conn_enc_buf;
    ioctl(dri_fd, DRM_IOCTL_MODE_GETCONNECTOR, &conn);

e) Init dummy buffer: struct drm_mode_create_dumb create_dumb={0}; struct drm_mode_map_dumb map_dumb={0}; struct drm_mode_fb_cmd cmd_dumb={0};

create_dumb.width = width;
create_dumb.height = height;

create_dumb.bpp = 32;
create_dumb.flags = 0;
create_dumb.pitch = 0;
create_dumb.size = 0;
create_dumb.handle = 0;
ioctl(dri_fd, DRM_IOCTL_MODE_CREATE_DUMB, &create_dumb);

cmd_dumb.width=create_dumb.width;
cmd_dumb.height=create_dumb.height;
cmd_dumb.bpp=create_dumb.bpp;
cmd_dumb.pitch=create_dumb.pitch;
cmd_dumb.depth=24;
cmd_dumb.handle=create_dumb.handle;
ioctl(dri_fd,DRM_IOCTL_MODE_ADDFB,&cmd_dumb);

map_dumb.handle=create_dumb.handle;
ioctl(dri_fd,DRM_IOCTL_MODE_MAP_DUMB,&map_dumb);

fb_base[i] = mmap(0, create_dumb.size, PROT_READ | PROT_WRITE, MAP_SHARED, dri_fd, map_dumb.offset);

struct drm_mode_get_encoder enc={0};

enc.encoder_id=conn.encoder_id;
ioctl(dri_fd, DRM_IOCTL_MODE_GETENCODER, &enc); //get encoder

struct drm_mode_crtc crtc={0};

crtc.crtc_id=enc.crtc_id;
ioctl(dri_fd, DRM_IOCTL_MODE_GETCRTC, &crtc);

crtc.fb_id=cmd_dumb.fb_id;
crtc.set_connectors_ptr=(uint64_t)&res_conn_buf[i];
crtc.count_connectors=1;
crtc.mode=conn_mode_buf[0];
crtc.mode_valid=1;
ioctl(dri_fd, DRM_IOCTL_MODE_SETCRTC, &crtc);

f) copy data from c-array with your logo to video card shared buffer:

memcpy(fb_base[0], uint32_data, sizeof(uint32_t) * logo_width * logo_height);

We need to do this in loop because buffer is regularly auto-clearing.

  1. Build application for dedicated platform and copy to /usr/bin/.

  2. Add trigger in udev: a) create new file in /usr/lib/udev/rules.d/11-framebuffer.rules

b) Inside file add trigger to invoke splash screen when video card will be ready: KERNEL=="card0", RUN+="/usr/bin/splash-launch" in

Piotr Zych
  • 61
  • 5