Feasibility of Hardware Screen Mirroring on MediaTek DRM (DSI + HDMI)

Hello MediaTek Community,

I am working on a MediaTek Genio–based platform (G510) running Linux with the MediaTek DRM/KMS driver, and I would like to understand the feasibility of hardware screen mirroring (clone mode) between:

  • Primary display: DSI (portrait panel, 1200×1920)

  • Secondary display: HDMI (external monitor)

The goal is to mirror the same UI content on both displays using DRM/Weston (hardware scanout), not application-level duplication.

After extensive testing, it appears that hardware mirroring may not be supported by the current MediaTek DRM driver, but I would like confirmation from MediaTek experts and guidance on whether any support exists (current or planned).


System Details

  • SoC / Platform: MediaTek Genio series

  • Kernel: Linux 6.6.37-mtk+

  • DRM driver: mediatek

  • Compositor: Weston 13.0.1

  • GPU: Mali-G57 (Valhall)

  • Backend: drm-backend.so


What We Tried

1. Weston Output Mirroring (same-as / clone-of)

Weston configuration example:

[core]
backend=drm-backend.so

[output]
name=DSI-1
mode=1920x1200

[output]
name=HDMI-A-1
same-as=DSI-1

Result:

  • One display works

  • The other becomes black or Weston fails to start

  • Extended mode works, mirror mode does not


2. Direct DRM Test Using modetest

Attempted to force the same CRTC for both connectors:

modetest -M mediatek -s 32@47:1200x1920 -s 34@47:1200x1920

Output:

failed to find mode "1200x1920" for connector 34
setting mode 1200x1920-60.00Hz on connectors 32, crtc 47
failed to set mode: Permission denied

This suggests the DRM driver does not allow a single CRTC to drive both connectors.


3. DRM Topology Inspection (modetest -pc)

Key observations:

  • Two CRTCs exist:

    • CRTC 47 → DSI

    • CRTC 56 → HDMI

  • Multiple planes exist, but plane capabilities are restricted:

Example:

Plane 35 → possible crtcs: 0x1  (DSI only)
Plane 48 → possible crtcs: 0x2  (HDMI only)

Important finding:

  • No plane has possible crtcs: 0x3

  • This means no plane can be shared between both CRTCs

So even though multiple planes and CRTCs exist, a single framebuffer cannot be scanned out to both displays.


4. Weston DRM Debug Logs

Weston was started with DRM debugging enabled.
No indication was found that a shared plane or clone path exists.
Weston falls back or fails when mirroring is requested, indicating a driver-level limitation rather than a compositor misconfiguration.


Our Understanding So Far

Based on the above:

  • Hardware mirroring requires:

    • A single framebuffer to be scanned out by multiple CRTCs, OR

    • A shared primary plane with possible_crtcs = 0x3, OR

    • A dedicated hardware clone/duplication path

  • The current MediaTek DRM driver appears to:

    • Provide separate display pipelines

    • Bind primary planes strictly to individual CRTCs

    • Not support framebuffer fan-out / shared scanout

This makes hardware mirroring impossible with the current driver design, while extended mode works as expected.


Questions for MediaTek Community

  1. Is hardware screen mirroring (clone mode) officially supported on MediaTek DRM?

  2. If not supported today:

    • Is this a hardware limitation or a driver limitation?
  3. Are there:

    • Any kernel patches

    • Any MediaTek-specific extensions

    • Any future roadmap plans
      that would allow shared framebuffer scanout or clone mode?

  4. Is software mirroring at application/compositor level the only supported solution on MediaTek platforms?


We want to ensure that our conclusion is correct before moving further.
Any confirmation, guidance, or references from MediaTek engineers would be greatly appreciated.

Thank you for your time and support.

Best regards,
Murali


Follow-up: Additional DRM-Level Testing Results for DSI + HDMI Mirroring

Hello,

I would like to provide additional results from low-level DRM testing (with Weston fully stopped) to clarify the feasibility of hardware mirroring between DSI and HDMI on the Genio 510.


1 Simultaneous Mode Setting Works

After stopping Weston and weston.socket:

systemctl stop weston
systemctl stop weston.socket

I successfully set independent modes on both CRTCs:

modetest -M mediatek -s 32@47:1200x1920 -s 34@56:1920x1080

Both modes were applied successfully, confirming:

  • CRTC 47 → DSI (1200x1920)

  • CRTC 56 → HDMI (1920x1080)

  • Dual pipeline operation works correctly.


2 Mode Compatibility Limitation

From modetest -pc:

  • DSI panel exposes only 1200x1920

  • HDMI does not support 1200x1920

  • HDMI supports 1920x1080, 1280x720, etc.

Attempting:

modetest -M mediatek -s 34@56:1200x1920

failed to find mode "1200x1920" for connector 34
failed to create dumb buffer: Invalid argument

Fails because the HDMI EDID does not advertise that mode.

Therefore, there is no common resolution between DSI and HDMI.


3 Plane Capabilities

From modetest -p:

modetest -p
trying to open device 'i915'...failed
trying to open device 'amdgpu'...failed
trying to open device 'radeon'...failed
trying to open device 'nouveau'...failed
trying to open device 'vmwgfx'...failed
trying to open device 'omapdrm'...failed
trying to open device 'exynos'...failed
trying to open device 'tilcdc'...failed
trying to open device 'msm'...failed
trying to open device 'sti'...failed
trying to open device 'tegra'...failed
trying to open device 'imx-drm'...failed
trying to open device 'rockchip'...failed
trying to open device 'atmel-hlcdc'...failed
trying to open device 'fsl-dcu-drm'...failed
trying to open device 'vc4'...failed
trying to open device 'virtio_gpu'...failed
trying to open device 'mediatek'...done
CRTCs:
id	fb	pos	size
47	57	(0,0)	(1200x1920)
  #0 1200x1920 60.00 1200 1250 1260 1330 1920 1945 1949 1969 157126 flags: ; type: preferred, driver
  props:
	24 VRR_ENABLED:
		flags: range
		values: 0 1
		value: 0
	27 CTM:
		flags: blob
		blobs:

		value:
	28 GAMMA_LUT:
		flags: blob
		blobs:

		value:
	29 GAMMA_LUT_SIZE:
		flags: immutable range
		values: 0 4294967295
		value: 512
56	57	(0,0)	(800x480)
  #0 800x480 60.00 800 844 932 1056 480 483 489 535 33900 flags: phsync, pvsync; type: preferred, driver
  props:
	24 VRR_ENABLED:
		flags: range
		values: 0 1
		value: 0

Planes:
id	crtc	fb	CRTC x,y	x,y	gamma size	possible crtcs
35	47	57	0,0		0,0	0       	0x00000001
  formats: XR24 AR24 BX24 BA24 AB24 XB24 RG24 BG24 RG16 UYVY YUYV
  props:
	8 type:
		flags: immutable enum
		enums: Overlay=0 Primary=1 Cursor=2
		value: 1
	30 IN_FORMATS:
		flags: immutable blob
		blobs:

		value:
			01000000000000000b00000018000000
			02000000480000005852323441523234
			42583234424132344142323458423234
			52473234424732345247313655595659
			5955595600000000ff07000000000000
			00000000000000000000000000000000
			ff000000000000000000000000000000
			6200000000000008
		in_formats blob decoded:
			 XR24:  LINEAR(0x0) ARM_BLOCK_SIZE=32x8,MODE=SPLIT|SPARSE(0x800000000000062)
			 AR24:  LINEAR(0x0) ARM_BLOCK_SIZE=32x8,MODE=SPLIT|SPARSE(0x800000000000062)
			 BX24:  LINEAR(0x0) ARM_BLOCK_SIZE=32x8,MODE=SPLIT|SPARSE(0x800000000000062)
			 BA24:  LINEAR(0x0) ARM_BLOCK_SIZE=32x8,MODE=SPLIT|SPARSE(0x800000000000062)
			 AB24:  LINEAR(0x0) ARM_BLOCK_SIZE=32x8,MODE=SPLIT|SPARSE(0x800000000000062)
			 XB24:  LINEAR(0x0) ARM_BLOCK_SIZE=32x8,MODE=SPLIT|SPARSE(0x800000000000062)
			 RG24:  LINEAR(0x0) ARM_BLOCK_SIZE=32x8,MODE=SPLIT|SPARSE(0x800000000000062)
			 BG24:  LINEAR(0x0) ARM_BLOCK_SIZE=32x8,MODE=SPLIT|SPARSE(0x800000000000062)
			 RG16:  LINEAR(0x0)
			 UYVY:  LINEAR(0x0)
			 YUYV:  LINEAR(0x0)
	37 rotation:
		flags: bitmask
		values: rotate-0=0x1 rotate-180=0x4 reflect-x=0x10 reflect-y=0x20
		value: 0
38	0	0	0,0		0,0	0       	0x00000001
  formats: XR24 AR24 BX24 BA24 AB24 XB24 RG24 BG24 RG16 UYVY YUYV
  props:
	8 type:
		flags: immutable enum
		enums: Overlay=0 Primary=1 Cursor=2
		value: 0
	30 IN_FORMATS:
		flags: immutable blob
		blobs:

		value:
			01000000000000000b00000018000000
			02000000480000005852323441523234
			42583234424132344142323458423234
			52473234424732345247313655595659
			5955595600000000ff07000000000000
			00000000000000000000000000000000
			ff000000000000000000000000000000
			6200000000000008
		in_formats blob decoded:
			 XR24:  LINEAR(0x0) ARM_BLOCK_SIZE=32x8,MODE=SPLIT|SPARSE(0x800000000000062)
			 AR24:  LINEAR(0x0) ARM_BLOCK_SIZE=32x8,MODE=SPLIT|SPARSE(0x800000000000062)
			 BX24:  LINEAR(0x0) ARM_BLOCK_SIZE=32x8,MODE=SPLIT|SPARSE(0x800000000000062)
			 BA24:  LINEAR(0x0) ARM_BLOCK_SIZE=32x8,MODE=SPLIT|SPARSE(0x800000000000062)
			 AB24:  LINEAR(0x0) ARM_BLOCK_SIZE=32x8,MODE=SPLIT|SPARSE(0x800000000000062)
			 XB24:  LINEAR(0x0) ARM_BLOCK_SIZE=32x8,MODE=SPLIT|SPARSE(0x800000000000062)
			 RG24:  LINEAR(0x0) ARM_BLOCK_SIZE=32x8,MODE=SPLIT|SPARSE(0x800000000000062)
			 BG24:  LINEAR(0x0) ARM_BLOCK_SIZE=32x8,MODE=SPLIT|SPARSE(0x800000000000062)
			 RG16:  LINEAR(0x0)
			 UYVY:  LINEAR(0x0)
			 YUYV:  LINEAR(0x0)
	40 rotation:
		flags: bitmask
		values: rotate-0=0x1 rotate-180=0x4 reflect-x=0x10 reflect-y=0x20
		value: 1
41	0	0	0,0		0,0	0       	0x00000001
  formats: XR24 AR24 BX24 BA24 AB24 XB24 RG24 BG24 RG16 UYVY YUYV
  props:
	8 type:
		flags: immutable enum
		enums: Overlay=0 Primary=1 Cursor=2
		value: 0
	30 IN_FORMATS:
		flags: immutable blob
		blobs:

		value:
			01000000000000000b00000018000000
			02000000480000005852323441523234
			42583234424132344142323458423234
			52473234424732345247313655595659
			5955595600000000ff07000000000000
			00000000000000000000000000000000
			ff000000000000000000000000000000
			6200000000000008
		in_formats blob decoded:
			 XR24:  LINEAR(0x0) ARM_BLOCK_SIZE=32x8,MODE=SPLIT|SPARSE(0x800000000000062)
			 AR24:  LINEAR(0x0) ARM_BLOCK_SIZE=32x8,MODE=SPLIT|SPARSE(0x800000000000062)
			 BX24:  LINEAR(0x0) ARM_BLOCK_SIZE=32x8,MODE=SPLIT|SPARSE(0x800000000000062)
			 BA24:  LINEAR(0x0) ARM_BLOCK_SIZE=32x8,MODE=SPLIT|SPARSE(0x800000000000062)
			 AB24:  LINEAR(0x0) ARM_BLOCK_SIZE=32x8,MODE=SPLIT|SPARSE(0x800000000000062)
			 XB24:  LINEAR(0x0) ARM_BLOCK_SIZE=32x8,MODE=SPLIT|SPARSE(0x800000000000062)
			 RG24:  LINEAR(0x0) ARM_BLOCK_SIZE=32x8,MODE=SPLIT|SPARSE(0x800000000000062)
			 BG24:  LINEAR(0x0) ARM_BLOCK_SIZE=32x8,MODE=SPLIT|SPARSE(0x800000000000062)
			 RG16:  LINEAR(0x0)
			 UYVY:  LINEAR(0x0)
			 YUYV:  LINEAR(0x0)
	43 rotation:
		flags: bitmask
		values: rotate-0=0x1 rotate-180=0x4 reflect-x=0x10 reflect-y=0x20
		value: 1
44	0	0	0,0		0,0	0       	0x00000001
  formats: XR24 AR24 BX24 BA24 AB24 XB24 RG24 BG24 RG16 UYVY YUYV
  props:
	8 type:
		flags: immutable enum
		enums: Overlay=0 Primary=1 Cursor=2
		value: 2
	30 IN_FORMATS:
		flags: immutable blob
		blobs:

		value:
			01000000000000000b00000018000000
			02000000480000005852323441523234
			42583234424132344142323458423234
			52473234424732345247313655595659
			5955595600000000ff07000000000000
			00000000000000000000000000000000
			ff000000000000000000000000000000
			6200000000000008
		in_formats blob decoded:
			 XR24:  LINEAR(0x0) ARM_BLOCK_SIZE=32x8,MODE=SPLIT|SPARSE(0x800000000000062)
			 AR24:  LINEAR(0x0) ARM_BLOCK_SIZE=32x8,MODE=SPLIT|SPARSE(0x800000000000062)
			 BX24:  LINEAR(0x0) ARM_BLOCK_SIZE=32x8,MODE=SPLIT|SPARSE(0x800000000000062)
			 BA24:  LINEAR(0x0) ARM_BLOCK_SIZE=32x8,MODE=SPLIT|SPARSE(0x800000000000062)
			 AB24:  LINEAR(0x0) ARM_BLOCK_SIZE=32x8,MODE=SPLIT|SPARSE(0x800000000000062)
			 XB24:  LINEAR(0x0) ARM_BLOCK_SIZE=32x8,MODE=SPLIT|SPARSE(0x800000000000062)
			 RG24:  LINEAR(0x0) ARM_BLOCK_SIZE=32x8,MODE=SPLIT|SPARSE(0x800000000000062)
			 BG24:  LINEAR(0x0) ARM_BLOCK_SIZE=32x8,MODE=SPLIT|SPARSE(0x800000000000062)
			 RG16:  LINEAR(0x0)
			 UYVY:  LINEAR(0x0)
			 YUYV:  LINEAR(0x0)
	46 rotation:
		flags: bitmask
		values: rotate-0=0x1 rotate-180=0x4 reflect-x=0x10 reflect-y=0x20
		value: 1
48	56	57	0,0		0,0	0       	0x00000002
  formats: XR24 AR24 BX24 BA24 AB24 XB24 RG24 BG24 RG16 UYVY YUYV
  props:
	8 type:
		flags: immutable enum
		enums: Overlay=0 Primary=1 Cursor=2
		value: 1
	30 IN_FORMATS:
		flags: immutable blob
		blobs:

		value:
			01000000000000000b00000018000000
			02000000480000005852323441523234
			42583234424132344142323458423234
			52473234424732345247313655595659
			5955595600000000ff07000000000000
			00000000000000000000000000000000
			ff000000000000000000000000000000
			6200000000000008
		in_formats blob decoded:
			 XR24:  LINEAR(0x0) ARM_BLOCK_SIZE=32x8,MODE=SPLIT|SPARSE(0x800000000000062)
			 AR24:  LINEAR(0x0) ARM_BLOCK_SIZE=32x8,MODE=SPLIT|SPARSE(0x800000000000062)
			 BX24:  LINEAR(0x0) ARM_BLOCK_SIZE=32x8,MODE=SPLIT|SPARSE(0x800000000000062)
			 BA24:  LINEAR(0x0) ARM_BLOCK_SIZE=32x8,MODE=SPLIT|SPARSE(0x800000000000062)
			 AB24:  LINEAR(0x0) ARM_BLOCK_SIZE=32x8,MODE=SPLIT|SPARSE(0x800000000000062)
			 XB24:  LINEAR(0x0) ARM_BLOCK_SIZE=32x8,MODE=SPLIT|SPARSE(0x800000000000062)
			 RG24:  LINEAR(0x0) ARM_BLOCK_SIZE=32x8,MODE=SPLIT|SPARSE(0x800000000000062)
			 BG24:  LINEAR(0x0) ARM_BLOCK_SIZE=32x8,MODE=SPLIT|SPARSE(0x800000000000062)
			 RG16:  LINEAR(0x0)
			 UYVY:  LINEAR(0x0)
			 YUYV:  LINEAR(0x0)
50	0	0	0,0		0,0	0       	0x00000002
  formats: XR24 AR24 BX24 BA24 AB24 XB24 RG24 BG24 RG16 UYVY YUYV
  props:
	8 type:
		flags: immutable enum
		enums: Overlay=0 Primary=1 Cursor=2
		value: 0
	30 IN_FORMATS:
		flags: immutable blob
		blobs:

		value:
			01000000000000000b00000018000000
			02000000480000005852323441523234
			42583234424132344142323458423234
			52473234424732345247313655595659
			5955595600000000ff07000000000000
			00000000000000000000000000000000
			ff000000000000000000000000000000
			6200000000000008
		in_formats blob decoded:
			 XR24:  LINEAR(0x0) ARM_BLOCK_SIZE=32x8,MODE=SPLIT|SPARSE(0x800000000000062)
			 AR24:  LINEAR(0x0) ARM_BLOCK_SIZE=32x8,MODE=SPLIT|SPARSE(0x800000000000062)
			 BX24:  LINEAR(0x0) ARM_BLOCK_SIZE=32x8,MODE=SPLIT|SPARSE(0x800000000000062)
			 BA24:  LINEAR(0x0) ARM_BLOCK_SIZE=32x8,MODE=SPLIT|SPARSE(0x800000000000062)
			 AB24:  LINEAR(0x0) ARM_BLOCK_SIZE=32x8,MODE=SPLIT|SPARSE(0x800000000000062)
			 XB24:  LINEAR(0x0) ARM_BLOCK_SIZE=32x8,MODE=SPLIT|SPARSE(0x800000000000062)
			 RG24:  LINEAR(0x0) ARM_BLOCK_SIZE=32x8,MODE=SPLIT|SPARSE(0x800000000000062)
			 BG24:  LINEAR(0x0) ARM_BLOCK_SIZE=32x8,MODE=SPLIT|SPARSE(0x800000000000062)
			 RG16:  LINEAR(0x0)
			 UYVY:  LINEAR(0x0)
			 YUYV:  LINEAR(0x0)
52	0	0	0,0		0,0	0       	0x00000002
  formats: XR24 AR24 BX24 BA24 AB24 XB24 RG24 BG24 RG16 UYVY YUYV
  props:
	8 type:
		flags: immutable enum
		enums: Overlay=0 Primary=1 Cursor=2
		value: 0
	30 IN_FORMATS:
		flags: immutable blob
		blobs:

		value:
			01000000000000000b00000018000000
			02000000480000005852323441523234
			42583234424132344142323458423234
			52473234424732345247313655595659
			5955595600000000ff07000000000000
			00000000000000000000000000000000
			ff000000000000000000000000000000
			6200000000000008
		in_formats blob decoded:
			 XR24:  LINEAR(0x0) ARM_BLOCK_SIZE=32x8,MODE=SPLIT|SPARSE(0x800000000000062)
			 AR24:  LINEAR(0x0) ARM_BLOCK_SIZE=32x8,MODE=SPLIT|SPARSE(0x800000000000062)
			 BX24:  LINEAR(0x0) ARM_BLOCK_SIZE=32x8,MODE=SPLIT|SPARSE(0x800000000000062)
			 BA24:  LINEAR(0x0) ARM_BLOCK_SIZE=32x8,MODE=SPLIT|SPARSE(0x800000000000062)
			 AB24:  LINEAR(0x0) ARM_BLOCK_SIZE=32x8,MODE=SPLIT|SPARSE(0x800000000000062)
			 XB24:  LINEAR(0x0) ARM_BLOCK_SIZE=32x8,MODE=SPLIT|SPARSE(0x800000000000062)
			 RG24:  LINEAR(0x0) ARM_BLOCK_SIZE=32x8,MODE=SPLIT|SPARSE(0x800000000000062)
			 BG24:  LINEAR(0x0) ARM_BLOCK_SIZE=32x8,MODE=SPLIT|SPARSE(0x800000000000062)
			 RG16:  LINEAR(0x0)
			 UYVY:  LINEAR(0x0)
			 YUYV:  LINEAR(0x0)
54	0	0	0,0		0,0	0       	0x00000002
  formats: XR24 AR24 BX24 BA24 AB24 XB24 RG24 BG24 RG16 UYVY YUYV
  props:
	8 type:
		flags: immutable enum
		enums: Overlay=0 Primary=1 Cursor=2
		value: 2
	30 IN_FORMATS:
		flags: immutable blob
		blobs:

		value:
			01000000000000000b00000018000000
			02000000480000005852323441523234
			42583234424132344142323458423234
			52473234424732345247313655595659
			5955595600000000ff07000000000000
			00000000000000000000000000000000
			ff000000000000000000000000000000
			6200000000000008
		in_formats blob decoded:
			 XR24:  LINEAR(0x0) ARM_BLOCK_SIZE=32x8,MODE=SPLIT|SPARSE(0x800000000000062)
			 AR24:  LINEAR(0x0) ARM_BLOCK_SIZE=32x8,MODE=SPLIT|SPARSE(0x800000000000062)
			 BX24:  LINEAR(0x0) ARM_BLOCK_SIZE=32x8,MODE=SPLIT|SPARSE(0x800000000000062)
			 BA24:  LINEAR(0x0) ARM_BLOCK_SIZE=32x8,MODE=SPLIT|SPARSE(0x800000000000062)
			 AB24:  LINEAR(0x0) ARM_BLOCK_SIZE=32x8,MODE=SPLIT|SPARSE(0x800000000000062)
			 XB24:  LINEAR(0x0) ARM_BLOCK_SIZE=32x8,MODE=SPLIT|SPARSE(0x800000000000062)
			 RG24:  LINEAR(0x0) ARM_BLOCK_SIZE=32x8,MODE=SPLIT|SPARSE(0x800000000000062)
			 BG24:  LINEAR(0x0) ARM_BLOCK_SIZE=32x8,MODE=SPLIT|SPARSE(0x800000000000062)
			 RG16:  LINEAR(0x0)
			 UYVY:  LINEAR(0x0)
			 YUYV:  LINEAR(0x0)


  • DSI planes → possible_crtcs = 0x1

  • HDMI planes → possible_crtcs = 0x2

  • No plane supports 0x3 (shared across CRTCs)

  • No SRC_W / CRTC_W scaling properties are exposed

Both pipelines support identical pixel formats (including ARM modifiers), but scaling properties are not visible through DRM.


4 Experimental Shared Framebuffer Test

Using modetest -P, I verified that both CRTCs can be active simultaneously and independently drive their respective planes.

However, I observed that each plane receives its own dumb buffer allocation. The two displays showed different random patterns, indicating that separate framebuffers were being scanned out rather than a single shared framebuffer.

Therefore, I could not conclusively verify true cross-CRTC shared framebuffer scanout using modetest alone.

modetest -M mediatek -a   -s 32@47:1200x1920   -s 34@56:1920x1080   -P 35@47:1200x1920   -P 48@56:1200x1920
setting mode 1200x1920-60.00Hz on connectors 32, crtc 47
setting mode 1920x1080-60.00Hz on connectors 34, crtc 56
testing 1200x1920@XR24 on plane 35, crtc 47
testing 1200x1920@XR24 on plane 48, crtc 56


Clarification Requested

Given the above:

  1. Does the MediaTek display engine support hardware clone mode internally?

  2. Is hardware scaling between outputs supported but not exposed via DRM?

  3. Is there any driver configuration or patch required to enable hardware mirroring?

  4. Or is application/compositor-level dual rendering the only supported approach?

Thank you for your guidance.