Skip to content

linux-6.18: optional i915 patch enabling interlaced modes on Intel gen9 - #17

Merged
D0023R merged 2 commits into
D0023R:masterfrom
amxcs:i915-gen9-interlace
Sep 20, 2026
Merged

D0023R merged 2 commits into
D0023R:masterfrom
amxcs:i915-gen9-interlace

Conversation

@amxcs

@amxcs amxcs commented Aug 9, 2026

Copy link
Copy Markdown
Contributor

This adds the missing Intel piece: interlaced (480i) modes on gen9 integrated
graphics, which currently cannot work at all.

The problem

Interlace support is not missing. intel_dp.c already sets interlace_allowed
for DISPLAY_VER < 12. What fails is the framebuffer modifier.

The display engine rejects Y/Yf tiled scanout while a pipe runs in IF-ID
interlace mode — see the "Y/Yf tiling not supported in IF-ID mode" check in
skl_plane_check(). Userspace picks the modifier when it allocates the
buffer, long before any mode is set, and Mesa/glamor prefers Y tiling on gen9.
So every interlaced modeset fails the atomic check with -EINVAL, surfacing as
the unhelpful:

xrandr: Configure crtc 0 failed
(EE) modeset(0): failed to set mode: No such file or directory

The patch

Because the modifier is chosen before the driver can know whether the buffer
will ever be scanned out interlaced, this cannot be decided per-mode. The only
thing the driver can do is not offer the modifiers that interlace cannot use.

Doing that unconditionally would cost every gen9 machine Y tiling and render
compression to serve a feature almost none of them want, so it is behind a
module parameter, off by default:

i915.no_ytiled_scanout=1

With it set, gen9 advertises only LINEAR and X_TILED for scanout. X tiling is a
first class scanout format here, so glamor acceleration keeps working — unlike
Option "AccelMethod" "none", which produces linear buffers but has no swrast
fallback on builds without swrast_dri.so.

No effect on any other display generation, and none at all unless the parameter
is set.

Testing

This patch as submitted: i915.ko built from vanilla 6.18.16 + patch 09 and
nothing else, loaded into Batocera 43.1's 6.18.16 kernel, which carries this
folder's 15 kHz patches. HP ProDesk 400 G2 Mini, HD Graphics 530 (Skylake,
DISPLAY_VER 9), VGA flex port into SCART on a Sony Trinitron. Without the
parameter, every interlaced modeset is rejected with Y/Yf tiling not supported in IF-ID mode; with i915.no_ytiled_scanout=1, real 640x454 and 720x480
interlaced at 15.734 kHz, confirmed from debugfs and on the set. Details in the
comment below.

Earlier, unconditional revision of the same change: also HP ProDesk 400 G5
Mini with UHD Graphics 630 (Coffee Lake), where Switchres generated and set
interlaced modes normally, e.g. SR-1_1280x480@59.94i at 15.67 kHz.

Only tested against 6.18, so I have only added it to linux-6.18. It also
applies cleanly to 6.18.45 and 7.2.5, but I have not tested those.

Written up in more detail, with the measurements, at
https://github.com/amxcs/batocera-crt-15khz-intel

Y/Yf tiled scanout is rejected by the display engine in IF-ID interlace
mode on gen9, and userspace picks the modifier when it allocates the
buffer, long before a mode is set. Every interlaced modeset therefore
fails the atomic check with -EINVAL.

Advertising only LINEAR/X_TILED on DISPLAY_VER 9 makes the scanout
buffer interlace capable from the start. Behind a module parameter,
off by default, since it costs tiling and render compression for
everything else on the platform.
@D0023R

D0023R commented Aug 9, 2026

Copy link
Copy Markdown
Owner

Amazing job on the patch. This looks like a great fix for the interlaced output issue with Intel graphics.
I’m away from my test rig at the moment, so I can’t review it just yet. As soon as I’m back, I’ll tproceed with the review.
Thanks for the great work.

@Redemp

Redemp commented Aug 9, 2026

Copy link
Copy Markdown
Contributor

Hi @amxcs,

Rion here from the Batocera CRT Script project.

We have already been discussing your Intel work over in your Batocera Reddit thread:

https://www.reddit.com/r/batocera/comments/1viedru/real_interlaced_480i_on_intel_integrated_graphics/

First of all, thanks for following up on that discussion and submitting the Intel work here. I'm really glad to see the actual driver fix being separated from the original Batocera-specific setup and moved into the existing Linux 15kHz kernel patch project.

I've now gone through the PR itself in more detail.

I think making the current workaround opt-in with:

i915.no_ytiled_scanout=1

is a sensible safety measure for the patch as it exists today, because the patch itself documents that enabling it removes Y/Yf/CCS scanout on Gen9 and therefore gives up Y tiling and render compression for everything else on that platform.

With the parameter defaulting to false and being limited to DISPLAY_VER == 9, simply compiling the patch into a kernel shouldn't change normal Intel behavior.

However, I'm not sure an opt-in switch like this should necessarily be considered the final solution.

Ideally, Intel CRT support should eventually behave more like the existing AMD 15kHz support: the kernel can contain the CRT patches all the time, and the user shouldn't have to globally disable normal scanout capabilities just because they want interlaced CRT output.

The difficulty here is understandable. As you've documented in the patch, userspace chooses the framebuffer modifier when the buffer is allocated, before the driver knows that the framebuffer will later be used for an interlaced modeset. That makes it difficult to simply disable Y tiling only at the moment an interlaced mode is selected.

So for now the module parameter may be the most practical workaround, but I think it would still be worth investigating whether there is a cleaner way to influence framebuffer/modifier selection without globally removing Y/Yf/CCS whenever CRT support is enabled.

I would also like to see i915.no_ytiled_scanout=1 tested thoroughly with normal progressive displays.

These kernel patches are not specific to Batocera. They can be used by GroovyArcade or essentially any other Linux distribution, and users may switch between a CRT and a modern HDMI/DisplayPort display or use both on the same machine.

It would therefore be useful to test normal progressive modes such as 720p, 1080p, 1440p and higher with the option enabled and check for any noticeable performance, acceleration, scanout or framebuffer-related regressions.

The goal should be that adding CRT capabilities does not turn the kernel into a special CRT-only build.

There is also another Intel limitation that is completely separate from the interlace problem: the minimum pixel/dot-clock restriction in i915.

We already have a clear starting point for this one.

In drivers/gpu/drm/i915/display/intel_dp.c, intel_dp_mode_valid() contains an explicit 10 MHz minimum pixel-clock check:

if (mode->clock < 10000)
    return MODE_CLOCK_LOW;

So DisplayPort modes below 10.000 MHz are rejected by i915 before they can proceed through the normal downstream mode validation.

This is particularly relevant for native low-resolution progressive CRT modes. Fixing the Gen9 framebuffer modifier issue gives us working interlace, but it doesn't remove this separate restriction.

Switchres can work around the 10 MHz floor to some extent by using super resolutions, but ideally we shouldn't need to increase the horizontal resolution simply to get around a hard-coded driver check if the Intel display hardware is actually capable of generating the requested lower pixel clock.

So at the moment I see Intel CRT support as two separate driver problems:

  1. Gen9 interlaced scanout: the Y/Yf/CCS framebuffer modifier incompatibility with IF-ID interlace, which this PR addresses.

  2. Low native progressive resolutions: the hard-coded 10 MHz minimum pixel-clock restriction in the Intel DisplayPort mode validation path.

For the second issue, I think the next step would be experimenting with lowering or bypassing that 10 MHz check and allowing the normal downstream i915/DisplayPort validation to determine whether the requested mode is actually possible.

We would then need to establish what the real hardware limit is. The important question is whether there is another genuine DPLL/display hardware limitation below that point, or whether the 10 MHz value is simply a conservative driver restriction that can safely be relaxed.

If the hardware can generate those lower clocks reliably, it would be interesting to find a clean way of relaxing the restriction without affecting normal Intel operation.

It would also be very useful to test DisplayPort through one of the known low-pixel-clock DP-to-VGA DACs we've already tested extensively:

https://gitlab.com/groovyarcade/support/-/wikis/2-Pre-Requisites-and-Installation/2.1-Hardware-Suggestions-General#optional-hardware

This is important because we want to separate three different things:

  • what i915 allows
  • what the Intel display hardware can actually generate
  • what the VGA conversion hardware can accept and output

Using a known external DAC that works with the low pixel clocks required for CRT use gives us a much better reference point than relying entirely on the onboard VGA conversion path.

It may also help investigate the ~5–6 second resolution switching delay you mentioned on Reddit.

Having both the onboard VGA output and a known external DAC available on the same Intel machine would allow us to run identical Switchres mode changes through both paths and see how much of that delay is actually coming from the Intel driver/display path, the VGA conversion hardware, or the CRT resynchronizing.

If we can eventually solve both the interlace and low pixel-clock sides without sacrificing normal progressive operation, then this becomes much more than an Intel 480i workaround.

We could potentially have proper Intel 15kHz support where native low-resolution progressive modes and interlaced modes both work, while the same patched kernel remains perfectly usable with modern displays.

That would make the Intel patches useful not only for Batocera, but also GroovyArcade and any other Linux distribution using the Linux 15kHz kernel patches.

Great work finding the original interlace issue and following through by getting it into the existing Linux 15kHz project. I think this gives us a very good starting point, and now we have a couple of interesting areas where we can hopefully take Intel CRT support further.

//Rion
Batocera CRT Script Dev

@Redemp

Redemp commented Aug 9, 2026

Copy link
Copy Markdown
Contributor

@WeebLabs
You want to join in on the conversation?

@amxcs

amxcs commented Sep 17, 2026

Copy link
Copy Markdown
Contributor Author

Update: patch 09 verified on a CRT, plus the progressive-display test and the dot-clock question

Sorry for the long gap. Rion's review raised three things; here is where each one stands.

1. This exact patch on a CRT, with and without the parameter

While preparing this update I found that the 480i confirmation in the description had been done with an earlier, unconditional revision of the change — not with the parameterised patch this PR actually proposes. So I rebuilt and re-tested it properly:

  • i915.ko built from vanilla 6.18.16 + this PR's patch 09 and nothing else (checked file by file against a pristine tree), loaded on Batocera 43.1.
  • HP ProDesk 400 G2 Mini, HD Graphics 530 (Skylake, DISPLAY_VER 9), VGA flex port → SCART → Sony Trinitron, with only the CRT connected.
  • The same Xorg modelines on both boots: 640x454, 720x480 and 640x480, all interlaced at 15.734 kHz.
parameter not set i915.no_ytiled_scanout=1
scanout modifiers advertised LINEAR, X, Y, Yf, Y_CCS, Yf_CCS LINEAR, X only
X starting on 640x454i (EE) modeset(0): failed to set mode starts cleanly
what the pipe actually runs stays on the 240p console mode 640x454 interlaced, 15.734 kHz
forced 720x480, then 640x454 xrandr: Configure crtc 0 failed (both) both accepted, interlaced
kernel's reason (drm.debug=0x04) skl_plane_check: [PLANE:33:plane 1A] Y/Yf tiling not supported in IF-ID mode

With the parameter set, the picture on the Trinitron is correct. Without it, the failure is exactly the one this PR describes, down to the kernel's own message. So the parameter does precisely what it says and nothing else is needed for interlace on gen9.

Everything above is read back from debugfs rather than judged from the screen, including the mode the pipe is really running: X reported 640x454 as current in the failing case too, while the kernel had never applied it.

2. Progressive displays with the parameter set

Stock vs patched driver, same machine, an LCD over DisplayPort at 1080p. The patch removes Y/Yf/CCS from IN_FORMATS, and nothing measurable changed: glxgears, hardware video decode through VA-API, 100 modesets between 1080p and 720p, EmulationStation, and dmesg with no underruns or errors. One detail worth knowing: on that setup X was already scanning out X-tiled on the stock driver. I don't have a 1440p panel, so higher resolutions are still untested.

3. The 10 MHz DisplayPort dot-clock floor

Measured — and it turned out not to need a kernel change. The check in intel_dp_mode_valid() is the connector's probe-time filter: it prunes the enumerated mode list, and the atomic modeset path never consults it. A hand-written 6.5 MHz modeline is programmed by a completely stock i915, and the pipe's own CRC frame counter confirms real scanout down to 1 MHz, with no FIFO underruns. So on DisplayPort there is no hardware floor anywhere near 10 MHz, and switchres modelines were never blocked by it. What remains open is the DAC side.

Write-up with all the numbers and a script to reproduce it: https://github.com/amxcs/batocera-crt-15khz-intel/blob/master/docs/dp-dotclock-floor.md

Compatibility

Patch 09 still applies cleanly to 6.18.45 (current in linux-6.18 here) and to 7.2.5 with a one-line offset. I've only tested 6.18, so it stays in linux-6.18 only.

Not tested: the parameterised patch on Coffee Lake (UHD 630 was tested with the earlier revision only), an external low-pixel-clock DP→VGA DAC, and progressive modes above 1080p.

@D0023R

D0023R commented Sep 20, 2026

Copy link
Copy Markdown
Owner

Thanks for the solid implementation and the thorough follow-up testing.

While the patch makes the activation dependent on a module parameter, this is completely fine for now.
As previously discussed, it provides the necessary flexibility to safely opt-in or out of the patch while leaving plenty of room for further testing and investigation into a cleaner, non-global solution.

Since infrastructure for setting custom boot resolutions and passing kernel parameters already exists in these CRT setups, users can easily append this parameter (or an extension of it in the future) to enable Intel Gen9 interlace support. Anyone choosing to configure this will normally keep the setting static for their specific hardware layout.

The earlier selection of Y-tiling by userspace drivers like Mesa is the culprit here, as it forces the allocation choice before the display engine knows the final mode. As soon as a consensus is reached on the activation routine, we can look into an automated way to disable Y-tiling dynamically. Perhaps triggering it automatically when an interlaced boot resolution is detected in conjunction with a generic userspace mode request implying an interlaced mode. The goal is to handle this entirely by patching the Linux kernel, without introducing dependencies on external projects.

I'm happy to merge this into the linux-6.18 branch so we can begin wider testing.

@D0023R D0023R left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Initial merge.

@D0023R
D0023R merged commit 5ec25e5 into D0023R:master Sep 20, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants