<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>A Star Computers Blog</title><link>https://www.astarcomputers.co.uk/blog/</link><description>Recent content on A Star Computers Blog</description><generator>Hugo</generator><language>en-gb</language><lastBuildDate>Mon, 28 Sep 2026 00:00:00 +0000</lastBuildDate><atom:link href="https://www.astarcomputers.co.uk/blog/index.xml" rel="self" type="application/rss+xml"/><item><title>Comet Lake graphics on a 500-series board</title><link>https://www.astarcomputers.co.uk/blog/posts/cmltgpfix/</link><pubDate>Mon, 28 Sep 2026 00:00:00 +0000</pubDate><guid>https://www.astarcomputers.co.uk/blog/posts/cmltgpfix/</guid><description>&lt;div class="layout"&gt;&#13;&#10; &lt;nav class="toc" aria-label="Contents"&gt;&#13;&#10; &lt;p&gt;Contents&lt;/p&gt;&#13;&#10; &lt;ol&gt;&#13;&#10; &lt;li&gt;&lt;a href="#symptoms"&gt;Symptoms&lt;/a&gt;&lt;/li&gt;&#13;&#10; &lt;li&gt;&lt;a href="#cause"&gt;Why it happens&lt;/a&gt;&lt;/li&gt;&#13;&#10; &lt;li&gt;&lt;a href="#fix"&gt;What the plugin does&lt;/a&gt;&lt;/li&gt;&#13;&#10; &lt;li&gt;&lt;a href="#config"&gt;OpenCore config&lt;/a&gt;&lt;/li&gt;&#13;&#10; &lt;li&gt;&lt;a href="#build"&gt;Building it&lt;/a&gt;&lt;/li&gt;&#13;&#10; &lt;li&gt;&lt;a href="#verify"&gt;Checking it works&lt;/a&gt;&lt;/li&gt;&#13;&#10; &lt;li&gt;&lt;a href="#limits"&gt;Limitations&lt;/a&gt;&lt;/li&gt;&#13;&#10; &lt;li&gt;&lt;a href="#gotchas"&gt;Other Tahoe gotchas&lt;/a&gt;&lt;/li&gt;&#13;&#10; &lt;li&gt;&lt;a href="#source"&gt;Source code&lt;/a&gt;&lt;/li&gt;&#13;&#10; &lt;li&gt;&lt;a href="#credits"&gt;Credits&lt;/a&gt;&lt;/li&gt;&#13;&#10; &lt;/ol&gt;&#13;&#10; &lt;/nav&gt;&#13;&#10;&#13;&#10; &lt;article&gt;&#13;&#10; &lt;section id="symptoms"&gt;&#13;&#10; &lt;h2&gt;Symptoms&lt;/h2&gt;&#13;&#10; &lt;p&gt;This applies if you have a &lt;strong&gt;Comet Lake&lt;/strong&gt; desktop CPU (Core i3/i5/i7/i9 10xxx with UHD 630) on a &lt;strong&gt;500-series&lt;/strong&gt; board (H510, B560, H570, Z590, Q570, W580). That pairing is common in OEM machines such as the Dell OptiPlex 7090, which shipped with either 10th or 11th gen CPUs.&lt;/p&gt;&#13;&#10; &lt;ul&gt;&#13;&#10; &lt;li&gt;The iGPU loads (&lt;code&gt;AppleIntelCFLGraphicsFramebuffer&lt;/code&gt;), System Information shows &lt;strong&gt;Metal 3&lt;/strong&gt;, but no display is ever listed and the monitor shows no signal after the Apple logo.&lt;/li&gt;&#13;&#10; &lt;li&gt;&lt;code&gt;sudo dmesg | grep IGFB&lt;/code&gt; shows &lt;code&gt;HPD is low&lt;/code&gt; for every framebuffer, even with a monitor plugged in.&lt;/li&gt;&#13;&#10; &lt;li&gt;Bus-ID hunting, connector type changes, &lt;code&gt;igfxonln=1&lt;/code&gt; and faking the IMEI device-id all change nothing.&lt;/li&gt;&#13;&#10; &lt;li&gt;&lt;code&gt;-igfxvesa&lt;/code&gt; gives a picture, but unaccelerated and very slow.&lt;/li&gt;&#13;&#10; &lt;/ul&gt;&#13;&#10; &lt;p&gt;Forum threads on B560/H510 with Comet Lake reach the same conclusion: the iGPU works headless, nobody gets display output from it, use a dGPU. This page shows why, and how to get the display working.&lt;/p&gt;&#13;&#10; &lt;/section&gt;&#13;&#10;&#13;&#10; &lt;section id="cause"&gt;&#13;&#10; &lt;h2&gt;Why it happens&lt;/h2&gt;&#13;&#10; &lt;p&gt;Hot-plug detection (HPD) for the display ports is wired through the PCH (the chipset), not the CPU. Apple's Coffee Lake framebuffer only knows the 300/400-series PCH layout (Cannon Point / Comet Lake PCH). On a 500-series Tiger Point PCH, the same registers exist at the same addresses but the bits are arranged differently.&lt;/p&gt;&#13;&#10; &lt;p&gt;Linux's i915 driver supports exactly this pairing (Gen9 display + TGP PCH, see &lt;code&gt;skl_hpd_pin()&lt;/code&gt; → &lt;code&gt;icl_hpd_pin()&lt;/code&gt; in &lt;code&gt;intel_ddi.c&lt;/code&gt;). That gives the real mapping.&lt;/p&gt;&#13;&#10;&#13;&#10; &lt;h3&gt;Live hot-plug state, SDEISR (0xC4000)&lt;/h3&gt;&#13;&#10; &lt;div class="table-wrap"&gt;&#13;&#10; &lt;table class="bits"&gt;&#13;&#10; &lt;thead&gt;&lt;tr&gt;&lt;th&gt;Bit&lt;/th&gt;&lt;th&gt;16&lt;/th&gt;&lt;th&gt;17&lt;/th&gt;&lt;th&gt;18&lt;/th&gt;&lt;th&gt;19&lt;/th&gt;&lt;th&gt;20&lt;/th&gt;&lt;th&gt;21&lt;/th&gt;&lt;th&gt;22&lt;/th&gt;&lt;th&gt;23&lt;/th&gt;&lt;th&gt;24&lt;/th&gt;&lt;th&gt;25&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&#13;&#10; &lt;tbody&gt;&#13;&#10; &lt;tr&gt;&lt;td&gt;Apple reads (CNP layout)&lt;/td&gt;&lt;td&gt;&lt;/td&gt;&lt;td&gt;&lt;/td&gt;&lt;td&gt;&lt;/td&gt;&lt;td&gt;&lt;/td&gt;&lt;td&gt;&lt;/td&gt;&lt;td class="hit-cnp"&gt;B&lt;/td&gt;&lt;td class="hit-cnp"&gt;C&lt;/td&gt;&lt;td class="hit-cnp"&gt;D&lt;/td&gt;&lt;td class="hit-cnp"&gt;A&lt;/td&gt;&lt;td&gt;&lt;/td&gt;&lt;/tr&gt;&#13;&#10; &lt;tr&gt;&lt;td&gt;Hardware reports (TGP)&lt;/td&gt;&lt;td class="hit-tgp"&gt;A&lt;/td&gt;&lt;td class="hit-tgp"&gt;B&lt;/td&gt;&lt;td&gt;&lt;/td&gt;&lt;td&gt;&lt;/td&gt;&lt;td&gt;&lt;/td&gt;&lt;td&gt;&lt;/td&gt;&lt;td&gt;&lt;/td&gt;&lt;td&gt;&lt;/td&gt;&lt;td class="hit-tgp"&gt;C&lt;/td&gt;&lt;td class="hit-tgp"&gt;D&lt;/td&gt;&lt;/tr&gt;&#13;&#10; &lt;/tbody&gt;&#13;&#10; &lt;/table&gt;&#13;&#10; &lt;/div&gt;&#13;&#10; &lt;p class="legend"&gt;Letters are the DDI ports. DDI C and D come in through the Type-C hot-plug pins (TC1, TC2) on this pairing.&lt;/p&gt;&#13;&#10; &lt;p&gt;So with a monitor on DDI B, bit 17 goes high while Apple checks bit 21, and the driver concludes nothing is connected. That is the &lt;code&gt;HPD is low&lt;/code&gt; message.&lt;/p&gt;&#13;&#10;&#13;&#10; &lt;h3&gt;The rest of the mismatch&lt;/h3&gt;&#13;&#10; &lt;div class="table-wrap"&gt;&#13;&#10; &lt;table&gt;&#13;&#10; &lt;thead&gt;&lt;tr&gt;&lt;th&gt;What&lt;/th&gt;&lt;th&gt;Apple expects (CNP)&lt;/th&gt;&lt;th&gt;Tiger Point (TGP)&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&#13;&#10; &lt;tbody&gt;&#13;&#10; &lt;tr&gt;&lt;td&gt;Hot-plug interrupt bits in SDEIIR&lt;/td&gt;&lt;td class="mono"&gt;21 / 22 / 23 (B / C / D)&lt;/td&gt;&lt;td class="mono"&gt;17 / 24 / 25&lt;/td&gt;&lt;/tr&gt;&#13;&#10; &lt;tr&gt;&lt;td&gt;Hot-plug status and enables&lt;/td&gt;&lt;td class="mono"&gt;0xC4030 only&lt;/td&gt;&lt;td class="mono"&gt;0xC4030 for DDI B, 0xC4034 (TC) for C and D&lt;/td&gt;&lt;/tr&gt;&#13;&#10; &lt;tr&gt;&lt;td&gt;HPD enable bits&lt;/td&gt;&lt;td class="mono"&gt;0xC4030 bits 4/12/20/28&lt;/td&gt;&lt;td class="mono"&gt;0xC4030 bit 7 (B), 0xC4034 bits 3/7 (C/D)&lt;/td&gt;&lt;/tr&gt;&#13;&#10; &lt;tr&gt;&lt;td&gt;GMBUS (DDC) pin, which is Apple's &lt;code&gt;busid&lt;/code&gt;&lt;/td&gt;&lt;td class="mono"&gt;5 / 4 / 6&lt;/td&gt;&lt;td class="mono"&gt;2 / 9 / 10&lt;/td&gt;&lt;/tr&gt;&#13;&#10; &lt;/tbody&gt;&#13;&#10; &lt;/table&gt;&#13;&#10; &lt;/div&gt;&#13;&#10; &lt;p&gt;The last row matters for HDMI monitors and passive DisplayPort-to-HDMI adapters, because the EDID is read over DDC. It is a config fix, not code: set the connector's bus ID to the TGP pin.&lt;/p&gt;&#13;&#10; &lt;/section&gt;&#13;&#10;&#13;&#10; &lt;section id="fix"&gt;&#13;&#10; &lt;h2&gt;What the plugin does&lt;/h2&gt;&#13;&#10; &lt;p&gt;CMLTGPFix is a Lilu plugin that patches &lt;code&gt;AppleIntelCFLGraphicsFramebuffer&lt;/code&gt; as it loads. OpenCore's own kernel patches cannot be used for this: on Tahoe the graphics kexts live in &lt;code&gt;SystemKernelExtensions.kc&lt;/code&gt;, which OpenCore never sees. WhateverGreen's &lt;code&gt;framebuffer-patchN-find/replace&lt;/code&gt; doesn't reach it either, because it only searches the platform table, not code.&lt;/p&gt;&#13;&#10;&#13;&#10; &lt;h3&gt;1. Live state&lt;/h3&gt;&#13;&#10; &lt;p&gt;&lt;code&gt;AppleIntelFramebufferController::DigPortHDPState&lt;/code&gt; reads SDEISR and picks the bit through a small jump table (&lt;code&gt;mov eax, imm32; jmp short&lt;/code&gt; per port). The plugin swaps the three masks for DDI B, C and D to 17, 24 and 25. This alone makes the monitor detectable at boot.&lt;/p&gt;&#13;&#10;&#13;&#10; &lt;h3&gt;2. Plug and unplug interrupts&lt;/h3&gt;&#13;&#10; &lt;p&gt;After Apple's &lt;code&gt;hwEnableInterrupts&lt;/code&gt;, the plugin enables and unmasks SDEIIR bits 17, 24 and 25. A wrapper around &lt;code&gt;ProcessInterrupt&lt;/code&gt;, which runs in the hardware interrupt filter, then does the following when one of those bits fires:&lt;/p&gt;&#13;&#10; &lt;ol class="flow"&gt;&#13;&#10; &lt;li&gt;&lt;span&gt;Read the TGP status fields (0xC4030 bits 5:4 for DDI B, 0xC4034 for TC1/TC2) and clear them, the way i915 does (write-1-to-clear).&lt;/span&gt;&lt;/li&gt;&#13;&#10; &lt;li&gt;&lt;span&gt;Turn each one into the event bit Apple's own dispatcher already understands: bits 15–18 for a long pulse (plug or unplug) on port 0–3, bits 19–22 for a short pulse.&lt;/span&gt;&lt;/li&gt;&#13;&#10; &lt;li&gt;&lt;span&gt;OR those bits into the controller's pending-events field and report the interrupt as handled, so &lt;code&gt;SWInterruptHandler&lt;/code&gt; runs &lt;code&gt;invokeHotplugHandler(port)&lt;/code&gt; as it would on a real Mac.&lt;/span&gt;&lt;/li&gt;&#13;&#10; &lt;/ol&gt;&#13;&#10;&#13;&#10; &lt;h3&gt;3. Display sleep&lt;/h3&gt;&#13;&#10; &lt;p&gt;The TGP HPD enable bits are set by firmware at boot but lost when the display power domain switches off. Apple re-arms hot-plug using the CNP bit positions, which on TGP are status bits. After display sleep SDEISR stays low, and the monitor looks unplugged on wake. The plugin restores the TGP enables after &lt;code&gt;hwEnableInterrupts&lt;/code&gt; and before every HPD check, without touching pending status bits.&lt;/p&gt;&#13;&#10;&#13;&#10; &lt;h3&gt;4. HDMI and passive DP++ adapters on wake&lt;/h3&gt;&#13;&#10; &lt;p&gt;On wake, &lt;code&gt;getDisplayStatus&lt;/code&gt; checks HPD, then tries to power the sink up over DP AUX. A passive DP-to-HDMI adapter never answers AUX, so it returns 0. Apple's own log calls this the &lt;em&gt;likely HDMI/TMDS case&lt;/em&gt;, yet the wake path still drops the display. The plugin reports the port as connected when that check fails but the port's TGP HPD line is high. An unplugged monitor still reads as disconnected.&lt;/p&gt;&#13;&#10;&#13;&#10; &lt;div class="callout"&gt;&#13;&#10; &lt;p&gt;&lt;strong&gt;Safety check.&lt;/strong&gt; The wrappers depend on a few private structure offsets. Before routing anything, the plugin confirms the target functions still use exactly those offsets. If a macOS update changes them, it skips the wrappers and applies only the byte patches, which are harmless when they don't match. Worst case after an update is no display, not a kernel panic.&lt;/p&gt;&#13;&#10; &lt;/div&gt;&#13;&#10; &lt;/section&gt;&#13;&#10;&#13;&#10; &lt;section id="config"&gt;&#13;&#10; &lt;h2&gt;OpenCore config&lt;/h2&gt;&#13;&#10; &lt;p&gt;This is the iGPU part of &lt;code&gt;DeviceProperties → Add → PciRoot(0x0)/Pci(0x2,0x0)&lt;/code&gt; used on the test machine, with the monitor on a passive DP-to-HDMI adapter in the lower rear DisplayPort (DDI B).&lt;/p&gt;&#13;&#10; &lt;figure class="code"&gt;&#13;&#10; &lt;figcaption&gt;&lt;span&gt;DeviceProperties · PciRoot(0x0)/Pci(0x2,0x0)&lt;/span&gt;&lt;button class="copy" type="button"&gt;Copy&lt;/button&gt;&lt;/figcaption&gt;&#13;&#10; &lt;pre&gt;&lt;code&gt;AAPL,ig-platform-id Data 07009B3E&#13;&#10;device-id Data C89B0000&#13;&#10;framebuffer-patch-enable Data 01000000&#13;&#10;framebuffer-stolenmem Data 00003001&#13;&#10;framebuffer-fbmem Data 00009000&#13;&#10;framebuffer-con0-enable Data 01000000&#13;&#10;framebuffer-con0-busid Data 02000000 &amp;lt;- TGP GMBUS pin for DDI B (Apple default 05)&#13;&#10;framebuffer-con0-type Data 00080000 &amp;lt;- HDMI, for the passive DP-to-HDMI adapter&lt;/code&gt;&lt;/pre&gt;&#13;&#10; &lt;/figure&gt;&#13;&#10; &lt;ul&gt;&#13;&#10; &lt;li&gt;&lt;code&gt;device-id C89B0000&lt;/code&gt; is the usual Comet Lake spoof (the i7-10700 is 0x9BC5). Use the SMBIOS &lt;code&gt;iMac20,1&lt;/code&gt;.&lt;/li&gt;&#13;&#10; &lt;li&gt;&lt;code&gt;framebuffer-con0-type 00080000&lt;/code&gt; (HDMI) is for HDMI through a passive adapter. With a native DisplayPort monitor you would keep &lt;code&gt;00040000&lt;/code&gt; (DP). That combination has &lt;strong&gt;not&lt;/strong&gt; been tested.&lt;/li&gt;&#13;&#10; &lt;li&gt;To find which DDI your monitor is on, boot with the plugin and read &lt;code&gt;SDEISR&lt;/code&gt; from its status (see &lt;a href="#verify"&gt;checking it works&lt;/a&gt;): bit 17 set = DDI B, bit 24 = DDI C, bit 25 = DDI D.&lt;/li&gt;&#13;&#10; &lt;li&gt;Add &lt;code&gt;CMLTGPFix.kext&lt;/code&gt; to &lt;code&gt;Kernel → Add&lt;/code&gt; after Lilu and WhateverGreen. Boot argument &lt;code&gt;-cmltgpoff&lt;/code&gt; disables it.&lt;/li&gt;&#13;&#10; &lt;/ul&gt;&#13;&#10; &lt;p&gt;Other kexts on the test machine: Lilu, VirtualSMC (+SMCProcessor, SMCSuperIO), WhateverGreen, RestrictEvents, IntelMausi, NVMeFix, USBToolBox with a port map, and &lt;code&gt;-wegnoegpu&lt;/code&gt; because an unsupported RX 550 was also installed.&lt;/p&gt;&#13;&#10; &lt;/section&gt;&#13;&#10;&#13;&#10; &lt;section id="build"&gt;&#13;&#10; &lt;h2&gt;Building it&lt;/h2&gt;&#13;&#10; &lt;p&gt;No Xcode is needed. The Command Line Tools are enough, and they install without a GUI session:&lt;/p&gt;&#13;&#10; &lt;figure class="code"&gt;&#13;&#10; &lt;figcaption&gt;&lt;span&gt;Terminal · Command Line Tools, headless&lt;/span&gt;&lt;button class="copy" type="button"&gt;Copy&lt;/button&gt;&lt;/figcaption&gt;&#13;&#10; &lt;pre&gt;&lt;code&gt;touch /tmp/.com.apple.dt.CommandLineTools.installondemand.in-progress&#13;&#10;softwareupdate -l | grep "Label: Command Line Tools"&#13;&#10;sudo softwareupdate -i "Command Line Tools for Xcode 26.6-26.6" # use the label listed above&lt;/code&gt;&lt;/pre&gt;&#13;&#10; &lt;/figure&gt;&#13;&#10; &lt;p&gt;Then fetch the Lilu headers and MacKernelSDK, save the three files from the &lt;a href="#source"&gt;source section&lt;/a&gt; into &lt;code&gt;CMLTGPFix/&lt;/code&gt;, and build:&lt;/p&gt;&#13;&#10; &lt;figure class="code"&gt;&#13;&#10; &lt;figcaption&gt;&lt;span&gt;Terminal · build&lt;/span&gt;&lt;button class="copy" type="button"&gt;Copy&lt;/button&gt;&lt;/figcaption&gt;&#13;&#10; &lt;pre&gt;&lt;code&gt;mkdir -p ~/cmltgp &amp;amp;&amp;amp; cd ~/cmltgp&#13;&#10;curl -sL https://codeload.github.com/acidanthera/Lilu/tar.gz/refs/tags/1.7.2 | tar -xz&#13;&#10;curl -sL https://codeload.github.com/acidanthera/MacKernelSDK/tar.gz/refs/heads/master | tar -xz&#13;&#10;mkdir -p CMLTGPFix # put kern_start.cpp, Info.plist and build.sh here&#13;&#10;bash CMLTGPFix/build.sh&#13;&#10;# result: ~/cmltgp/CMLTGPFix/build/CMLTGPFix.kext -&gt; copy to EFI/OC/Kexts&lt;/code&gt;&lt;/pre&gt;&#13;&#10; &lt;/figure&gt;&#13;&#10; &lt;div class="callout warn"&gt;&#13;&#10; &lt;p&gt;&lt;strong&gt;Check the build before you reboot.&lt;/strong&gt; Make sure &lt;code&gt;CMLTGPFix.kext/Contents/MacOS/CMLTGPFix&lt;/code&gt; and &lt;code&gt;Contents/Info.plist&lt;/code&gt; both exist and aren't empty. An empty kext bundle listed in your config can stop the machine booting. Keep a rescue USB stick with a plain &lt;code&gt;-igfxvesa&lt;/code&gt; config and without this plugin.&lt;/p&gt;&#13;&#10; &lt;/div&gt;&#13;&#10; &lt;/section&gt;&#13;&#10;&#13;&#10; &lt;section id="verify"&gt;&#13;&#10; &lt;h2&gt;Checking it works&lt;/h2&gt;&#13;&#10; &lt;p&gt;The plugin publishes its state once a minute. The first report comes 10 seconds after it starts, which can be before the framebuffer has loaded, so give it a minute after boot.&lt;/p&gt;&#13;&#10; &lt;figure class="code"&gt;&#13;&#10; &lt;figcaption&gt;&lt;span&gt;Terminal&lt;/span&gt;&lt;button class="copy" type="button"&gt;Copy&lt;/button&gt;&lt;/figcaption&gt;&#13;&#10; &lt;pre&gt;&lt;code&gt;ioreg -r -c CMLTGPFix -w0&#13;&#10;sudo dmesg | grep IGFB | grep -E "HPD|HDMI connect|Display status"&#13;&#10;system_profiler SPDisplaysDataType&lt;/code&gt;&lt;/pre&gt;&#13;&#10; &lt;/figure&gt;&#13;&#10; &lt;dl class="status"&gt;&#13;&#10; &lt;dt&gt;patch-DDI-B/C/D = 0&lt;/dt&gt;&lt;dd&gt;The three HPD mask patches applied. &lt;code&gt;-1&lt;/code&gt; means not attempted yet.&lt;/dd&gt;&#13;&#10; &lt;dt&gt;layout-status = 0&lt;/dt&gt;&lt;dd&gt;Framebuffer offsets verified, wrappers installed. &lt;code&gt;1&lt;/code&gt; means the driver changed and only the byte patches were applied.&lt;/dd&gt;&#13;&#10; &lt;dt&gt;route-status = 0&lt;/dt&gt;&lt;dd&gt;All four wrappers routed.&lt;/dd&gt;&#13;&#10; &lt;dt&gt;SDEISR&lt;/dt&gt;&lt;dd&gt;Live hot-plug state: &lt;code&gt;131072&lt;/code&gt; (bit 17) means a monitor is on DDI B.&lt;/dd&gt;&#13;&#10; &lt;dt&gt;tgp-irq-count&lt;/dt&gt;&lt;dd&gt;Increments on every plug or unplug.&lt;/dd&gt;&#13;&#10; &lt;dt&gt;hpd-rearm-count&lt;/dt&gt;&lt;dd&gt;Times the HPD enables had to be restored, usually after display sleep.&lt;/dd&gt;&#13;&#10; &lt;dt&gt;status-override-count&lt;/dt&gt;&lt;dd&gt;Times a failed DP check was corrected for an HDMI sink.&lt;/dd&gt;&#13;&#10; &lt;/dl&gt;&#13;&#10; &lt;p&gt;On the test machine this gave &lt;code&gt;HDMI connect found&lt;/code&gt;, 1366 × 768 online with Metal 3 at boot, a picture after unplugging and replugging the cable, and a working wake from display sleep (&lt;code&gt;Resuming external display&lt;/code&gt; in the log).&lt;/p&gt;&#13;&#10; &lt;/section&gt;&#13;&#10;&#13;&#10; &lt;section id="limits"&gt;&#13;&#10; &lt;h2&gt;Limitations&lt;/h2&gt;&#13;&#10; &lt;ul&gt;&#13;&#10; &lt;li&gt;Tested on &lt;strong&gt;one machine, one port&lt;/strong&gt;: DDI B with a passive HDMI adapter. The C and D mappings come straight from i915 but are untested, and it isn't known whether Apple's GMBUS code accepts bus IDs 9 and 10.&lt;/li&gt;&#13;&#10; &lt;li&gt;Built against &lt;code&gt;AppleIntelCFLGraphicsFramebuffer&lt;/code&gt; 24.5.9 in macOS 26.7. The &lt;a href="#fix"&gt;safety check&lt;/a&gt; guards against changed offsets, but a future update may need the offsets re-derived.&lt;/li&gt;&#13;&#10; &lt;li&gt;Display sleep and full system sleep are both tested: the display comes back on wake.&lt;/li&gt;&#13;&#10; &lt;li&gt;This fixes display detection only. Everything else about the iGPU (acceleration, VideoToolbox) already worked.&lt;/li&gt;&#13;&#10; &lt;/ul&gt;&#13;&#10; &lt;/section&gt;&#13;&#10;&#13;&#10; &lt;section id="gotchas"&gt;&#13;&#10; &lt;h2&gt;Other Tahoe gotchas on this machine&lt;/h2&gt;&#13;&#10; &lt;p&gt;These cost time on the way. They aren't specific to this plugin but are likely on similar Dell builds.&lt;/p&gt;&#13;&#10; &lt;div class="table-wrap"&gt;&#13;&#10; &lt;table&gt;&#13;&#10; &lt;thead&gt;&lt;tr&gt;&lt;th&gt;Problem&lt;/th&gt;&lt;th&gt;Fix&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&#13;&#10; &lt;tbody&gt;&#13;&#10; &lt;tr&gt;&lt;td&gt;Installer boots then loops at the &lt;em&gt;macOS Installer&lt;/em&gt; stage: &lt;code&gt;MSU 1130 … firmware_execute failed&lt;/code&gt;, &lt;code&gt;boot_to_original_os&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;SecureBootModel&lt;/code&gt; = &lt;code&gt;Disabled&lt;/code&gt;, reset NVRAM, erase the disk and reinstall.&lt;/td&gt;&lt;/tr&gt;&#13;&#10; &lt;tr&gt;&lt;td&gt;No working USB at all in the installer&lt;/td&gt;&lt;td&gt;&lt;code&gt;USBToolBox.kext&lt;/code&gt; + &lt;code&gt;UTBDefault.kext&lt;/code&gt;, then a proper map with 15 ports or fewer. The 500-series controller exposes USB 3 on ports 17–24.&lt;/td&gt;&lt;/tr&gt;&#13;&#10; &lt;tr&gt;&lt;td&gt;OpenCore picker shows only Windows&lt;/td&gt;&lt;td&gt;The recovery &lt;code&gt;.dmg&lt;/code&gt; counts as auxiliary. Set &lt;code&gt;HideAuxiliary&lt;/code&gt; false or press Space.&lt;/td&gt;&lt;/tr&gt;&#13;&#10; &lt;tr&gt;&lt;td&gt;No audio: Tahoe removed &lt;code&gt;AppleHDA&lt;/code&gt;, so AppleALC has nothing to patch&lt;/td&gt;&lt;td&gt;VoodooHDA in &lt;code&gt;/Library/Extensions&lt;/code&gt; (Auxiliary KC, since OpenCore can't inject it) with &lt;code&gt;csr-active-config 03000000&lt;/code&gt;, then approve it in Privacy &amp;amp; Security. Remove AppleALC.&lt;/td&gt;&lt;/tr&gt;&#13;&#10; &lt;tr&gt;&lt;td&gt;&lt;code&gt;csr-active-config&lt;/code&gt; changes seem to be ignored&lt;/td&gt;&lt;td&gt;Add it to &lt;code&gt;NVRAM → Delete&lt;/code&gt;. Otherwise the value stored on first boot wins.&lt;/td&gt;&lt;/tr&gt;&#13;&#10; &lt;tr&gt;&lt;td&gt;RX 550 "Lexa" (0x699F) spoofed to 0x67FF&lt;/td&gt;&lt;td&gt;Crashes and drops signal. Not viable. Disable it with &lt;code&gt;-wegnoegpu&lt;/code&gt;.&lt;/td&gt;&lt;/tr&gt;&#13;&#10; &lt;tr&gt;&lt;td&gt;macOS updates&lt;/td&gt;&lt;td&gt;RestrictEvents + &lt;code&gt;revpatch=sbvmm&lt;/code&gt;. Updates drop the Auxiliary KC, so re-approve VoodooHDA afterwards.&lt;/td&gt;&lt;/tr&gt;&#13;&#10; &lt;/tbody&gt;&#13;&#10; &lt;/table&gt;&#13;&#10; &lt;/div&gt;&#13;&#10; &lt;/section&gt;&#13;&#10;&#13;&#10; &lt;section id="source"&gt;&#13;&#10; &lt;h2&gt;Source code&lt;/h2&gt;&#13;&#10; &lt;p&gt;Three files to build from, plus the licence. Save them into a folder called &lt;code&gt;CMLTGPFix&lt;/code&gt; next to the unpacked &lt;code&gt;Lilu-1.7.2&lt;/code&gt; and &lt;code&gt;MacKernelSDK-master&lt;/code&gt;. The code is released under the BSD 3-Clause licence, the same as Lilu and WhateverGreen: build it, change it and share it, keeping the copyright notice.&lt;/p&gt;&#13;&#10; &lt;figure class="code tall"&gt;&#13;&#10; &lt;figcaption&gt;&lt;span&gt;CMLTGPFix/kern_start.cpp&lt;/span&gt;&lt;button class="copy" type="button"&gt;Copy&lt;/button&gt;&lt;/figcaption&gt;&#13;&#10; &lt;pre&gt;&lt;code&gt;//&#13;&#10;// kern_start.cpp&#13;&#10;// CMLTGPFix&#13;&#10;//&#13;&#10;// Copyright (c) 2026, A Star Computers&#13;&#10;// SPDX-License-Identifier: BSD-3-Clause (see LICENSE)&#13;&#10;//&#13;&#10;// Comet Lake (Gen9.5) iGPU on a 500-series (Tiger Point, TGP) PCH, e.g. Dell OptiPlex 7090.&#13;&#10;// Apple never shipped this pairing: AppleIntelCFLGraphicsFramebuffer handles the PCH hot-plug&#13;&#10;// registers with the Cannon/Sunrise Point layout, so every port reads "HPD is low", no display&#13;&#10;// is ever detected, and plug/unplug interrupts are never decoded.&#13;&#10;//&#13;&#10;// Linux i915 (skl_hpd_pin -&amp;gt; icl_hpd_pin for Gen9 BC + TGP) maps the DDIs to TGP HPD pins:&#13;&#10;// DDI B -&amp;gt; HPD_PORT_B -&amp;gt; SDE bit 17, status SHOTPLUG_CTL_DDI[5:4] (Apple: bit 21, 0xC4030[1:0])&#13;&#10;// DDI C -&amp;gt; HPD_PORT_TC1 -&amp;gt; SDE bit 24, status SHOTPLUG_CTL_TC[1:0] (Apple: bit 22, 0xC4030[9:8])&#13;&#10;// DDI D -&amp;gt; HPD_PORT_TC2 -&amp;gt; SDE bit 25, status SHOTPLUG_CTL_TC[5:4] (Apple: bit 23, 0xC4030[17:16])&#13;&#10;//&#13;&#10;// 1. Live state: patch the SDEISR masks in AppleIntelFramebufferController::DigPortHDPState.&#13;&#10;// 2. Interrupts: enable the TGP hot-plug interrupts after hwEnableInterrupts, and translate them&#13;&#10;// in ProcessInterrupt into the CNP event bits Apple's SWInterruptHandler already dispatches.&#13;&#10;// 3. Display sleep: restore the TGP HPD detection enables whenever Apple re-arms hot-plug and&#13;&#10;// before each live-state check (they are lost when the display power domain goes down).&#13;&#10;// 4. Wake with HDMI / passive DP++: treat a failed DP status check as connected while HPD is high.&#13;&#10;//&#13;&#10;// DDC for HDMI / passive DP++ adapters is config only: Apple's busid is the GMBUS pin, and for&#13;&#10;// Gen9 BC + TGP i915 uses DDI B -&amp;gt; pin 2, DDI C -&amp;gt; pin 9, DDI D -&amp;gt; pin 10 (CNP: 5 / 4 / 6).&#13;&#10;//&#13;&#10;&#13;&#10;#include &amp;lt;Headers/plugin_start.hpp&amp;gt;&#13;&#10;#include &amp;lt;Headers/kern_api.hpp&amp;gt;&#13;&#10;#include &amp;lt;Headers/kern_patcher.hpp&amp;gt;&#13;&#10;#include &amp;lt;IOKit/IOService.h&amp;gt;&#13;&#10;#include &amp;lt;kern/thread_call.h&amp;gt;&#13;&#10;#include &amp;lt;kern/clock.h&amp;gt;&#13;&#10;#include &amp;lt;libkern/OSAtomic.h&amp;gt;&#13;&#10;&#13;&#10;static const char *pathCFL[] {&#13;&#10;&#9;"/System/Library/Extensions/AppleIntelCFLGraphicsFramebuffer.kext/Contents/MacOS/AppleIntelCFLGraphicsFramebuffer"&#13;&#10;};&#13;&#10;&#13;&#10;static KernelPatcher::KextInfo kextCFL {&#13;&#10;&#9;"com.apple.driver.AppleIntelCFLGraphicsFramebuffer", pathCFL, arrsize(pathCFL), {true}, {}, KernelPatcher::KextInfo::Unloaded&#13;&#10;};&#13;&#10;&#13;&#10;// ---------------------------------------------------------------------------------------------&#13;&#10;// 1. Live hot-plug state. DigPortHDPState reads SDEISR (0xC4000) and picks the mask through a&#13;&#10;// jump table indexed by displayPath+0x450 (0..3 = DDI A..D): `mov eax, imm32; jmp short`.&#13;&#10;// The jmp displacement makes each pattern unique in the binary.&#13;&#10;// ---------------------------------------------------------------------------------------------&#13;&#10;static const uint8_t findB[] { 0xB8, 0x00, 0x00, 0x20, 0x00, 0xEB, 0x02 }; // DDI B: bit 21&#13;&#10;static const uint8_t replaceB[] { 0xB8, 0x00, 0x00, 0x02, 0x00, 0xEB, 0x02 }; // bit 17&#13;&#10;static const uint8_t findC[] { 0xB8, 0x00, 0x00, 0x40, 0x00, 0xEB, 0x1E }; // DDI C: bit 22&#13;&#10;static const uint8_t replaceC[] { 0xB8, 0x00, 0x00, 0x00, 0x01, 0xEB, 0x1E }; // bit 24&#13;&#10;static const uint8_t findD[] { 0xB8, 0x00, 0x00, 0x80, 0x00, 0xEB, 0x10 }; // DDI D: bit 23&#13;&#10;static const uint8_t replaceD[] { 0xB8, 0x00, 0x00, 0x00, 0x02, 0xEB, 0x10 }; // bit 25&#13;&#10;&#13;&#10;// ---------------------------------------------------------------------------------------------&#13;&#10;// 2. Hot-plug interrupts. Apple's ProcessInterrupt (called from the HW interrupt filter) ORs&#13;&#10;// decoded events into controller+0x2C70; SWInterruptHandler then dispatches bits 15..18 (long&#13;&#10;// pulse = plug/unplug on port index 0..3) to invokeHotplugHandler(idx) and bits 19..22 (short&#13;&#10;// pulse) to invokeShortPulseHandler(idx). TGP status bits are write-1-to-clear.&#13;&#10;// ---------------------------------------------------------------------------------------------&#13;&#10;static constexpr uint32_t SDEIMR = 0xC4004, SDEIIR = 0xC4008, SDEIER = 0xC400C;&#13;&#10;static constexpr uint32_t SHOTPLUG_CTL_DDI = 0xC4030, SHOTPLUG_CTL_TC = 0xC4034;&#13;&#10;static constexpr uint32_t TgpHotplugIrqs = (1U &amp;lt;&amp;lt; 17) | (1U &amp;lt;&amp;lt; 24) | (1U &amp;lt;&amp;lt; 25);&#13;&#10;static constexpr size_t ControllerMmio = 0x1A08, ControllerPendingEvents = 0x2C70;&#13;&#10;&#13;&#10;static inline uint8_t *controllerMmio(void *controller) {&#13;&#10;&#9;return *reinterpret_cast&amp;lt;uint8_t **&amp;gt;(reinterpret_cast&amp;lt;uint8_t *&amp;gt;(controller) + ControllerMmio);&#13;&#10;}&#13;&#10;&#13;&#10;static inline volatile uint32_t &amp;amp;mmioReg(uint8_t *mmio, uint32_t reg) {&#13;&#10;&#9;return *reinterpret_cast&amp;lt;volatile uint32_t *&amp;gt;(mmio + reg);&#13;&#10;}&#13;&#10;&#13;&#10;// HPD detection enables. Firmware sets these at boot, but they are lost when the display power&#13;&#10;// domain goes down (display sleep), and Apple re-arms hot-plug with the CNP layout (0xC4030 bits&#13;&#10;// 4/12/20/28), which on TGP are status bits. With the enables off SDEISR reads low, so after a&#13;&#10;// display sleep the monitor looked unplugged. Restore them without writing back any status bits&#13;&#10;// (write-1-to-clear), as i915's icp_ddi_hpd_detection_setup / icp_tc_hpd_detection_setup do.&#13;&#10;static constexpr uint32_t DdiHpdEnables = 0x80; // SHOTPLUG_CTL_DDI_HPD_ENABLE(HPD_PORT_B)&#13;&#10;static constexpr uint32_t TcHpdEnables = 0x88; // ICP_TC_HPD_ENABLE(TC1) | ICP_TC_HPD_ENABLE(TC2)&#13;&#10;static constexpr uint32_t HpdStatusBits = 0x33333333; // 2-bit status field of every pin nibble&#13;&#10;static uint8_t *lastMmio;&#13;&#10;static uint32_t hpdRearmCount;&#13;&#10;&#13;&#10;static bool restoreHpdEnables(uint8_t *mmio) {&#13;&#10;&#9;lastMmio = mmio;&#13;&#10;&#9;uint32_t ddi = mmioReg(mmio, SHOTPLUG_CTL_DDI);&#13;&#10;&#9;uint32_t tc = mmioReg(mmio, SHOTPLUG_CTL_TC);&#13;&#10;&#9;if ((ddi &amp;amp; DdiHpdEnables) == DdiHpdEnables &amp;amp;&amp;amp; (tc &amp;amp; TcHpdEnables) == TcHpdEnables)&#13;&#10;&#9;&#9;return false;&#13;&#10;&#9;mmioReg(mmio, SHOTPLUG_CTL_DDI) = (ddi &amp;amp; ~HpdStatusBits) | DdiHpdEnables;&#13;&#10;&#9;mmioReg(mmio, SHOTPLUG_CTL_TC) = (tc &amp;amp; ~HpdStatusBits) | TcHpdEnables;&#13;&#10;&#9;hpdRearmCount++;&#13;&#10;&#9;return true;&#13;&#10;}&#13;&#10;&#13;&#10;using t_hwEnableInterrupts = uint64_t (*)(void *);&#13;&#10;static t_hwEnableInterrupts orgHwEnableInterrupts;&#13;&#10;static uint32_t irqEnableCount;&#13;&#10;&#13;&#10;static uint64_t wrapHwEnableInterrupts(void *controller) {&#13;&#10;&#9;auto ret = orgHwEnableInterrupts(controller);&#13;&#10;&#9;if (auto mmio = controllerMmio(controller)) {&#13;&#10;&#9;&#9;restoreHpdEnables(mmio);&#13;&#10;&#9;&#9;mmioReg(mmio, SDEIER) |= TgpHotplugIrqs;&#13;&#10;&#9;&#9;mmioReg(mmio, SDEIMR) &amp;amp;= ~TgpHotplugIrqs;&#13;&#10;&#9;&#9;irqEnableCount++;&#13;&#10;&#9;}&#13;&#10;&#9;return ret;&#13;&#10;}&#13;&#10;&#13;&#10;// DigPortHDPState(controller, framebuffer, displayPath): make sure detection is enabled before&#13;&#10;// the live state is sampled; after re-enabling, give the HPD filter time to settle.&#13;&#10;using t_digPortHDPState = uint8_t (*)(void *, void *, void *);&#13;&#10;static t_digPortHDPState orgDigPortHDPState;&#13;&#10;&#13;&#10;static uint8_t wrapDigPortHDPState(void *controller, void *framebuffer, void *path) {&#13;&#10;&#9;if (auto mmio = controllerMmio(controller))&#13;&#10;&#9;&#9;if (restoreHpdEnables(mmio))&#13;&#10;&#9;&#9;&#9;IODelay(5000);&#13;&#10;&#9;return orgDigPortHDPState(controller, framebuffer, path);&#13;&#10;}&#13;&#10;&#13;&#10;// status: the 2-bit SHOTPLUG_CTL field, bit 0 = short pulse, bit 1 = long pulse&#13;&#10;static uint32_t cnpEvents(uint32_t status, uint32_t portIndex) {&#13;&#10;&#9;uint32_t events = 0;&#13;&#10;&#9;if (status &amp;amp; 2) events |= 1U &amp;lt;&amp;lt; (15 + portIndex);&#13;&#10;&#9;if (status &amp;amp; 1) events |= 1U &amp;lt;&amp;lt; (19 + portIndex);&#13;&#10;&#9;return events ? events : 1U &amp;lt;&amp;lt; (15 + portIndex); // interrupt without status: treat as plug/unplug&#13;&#10;}&#13;&#10;&#13;&#10;using t_processInterrupt = bool (*)(void *);&#13;&#10;static t_processInterrupt orgProcessInterrupt;&#13;&#10;static uint32_t tgpIrqCount, tgpLastEvents;&#13;&#10;&#13;&#10;static bool wrapProcessInterrupt(void *controller) {&#13;&#10;&#9;uint32_t events = 0;&#13;&#10;&#9;if (auto mmio = controllerMmio(controller)) {&#13;&#10;&#9;&#9;uint32_t iir = mmioReg(mmio, SDEIIR) &amp;amp; TgpHotplugIrqs;&#13;&#10;&#9;&#9;if (iir) {&#13;&#10;&#9;&#9;&#9;uint32_t ddi = mmioReg(mmio, SHOTPLUG_CTL_DDI);&#13;&#10;&#9;&#9;&#9;uint32_t tc = mmioReg(mmio, SHOTPLUG_CTL_TC);&#13;&#10;&#9;&#9;&#9;mmioReg(mmio, SHOTPLUG_CTL_DDI) = ddi;&#13;&#10;&#9;&#9;&#9;mmioReg(mmio, SHOTPLUG_CTL_TC) = tc;&#13;&#10;&#9;&#9;&#9;mmioReg(mmio, SDEIIR) = iir;&#13;&#10;&#9;&#9;&#9;if (iir &amp;amp; (1U &amp;lt;&amp;lt; 17)) events |= cnpEvents((ddi &amp;gt;&amp;gt; 4) &amp;amp; 3, 1); // DDI B&#13;&#10;&#9;&#9;&#9;if (iir &amp;amp; (1U &amp;lt;&amp;lt; 24)) events |= cnpEvents(tc &amp;amp; 3, 2); // DDI C (TC1)&#13;&#10;&#9;&#9;&#9;if (iir &amp;amp; (1U &amp;lt;&amp;lt; 25)) events |= cnpEvents((tc &amp;gt;&amp;gt; 4) &amp;amp; 3, 3); // DDI D (TC2)&#13;&#10;&#9;&#9;&#9;tgpIrqCount++;&#13;&#10;&#9;&#9;}&#13;&#10;&#9;}&#13;&#10;&#13;&#10;&#9;bool ret = orgProcessInterrupt(controller);&#13;&#10;&#9;if (events) {&#13;&#10;&#9;&#9;OSBitOrAtomic(events, reinterpret_cast&amp;lt;volatile UInt32 *&amp;gt;(reinterpret_cast&amp;lt;uint8_t *&amp;gt;(controller) + ControllerPendingEvents));&#13;&#10;&#9;&#9;tgpLastEvents = events;&#13;&#10;&#9;&#9;ret = true; // make HWInterruptHandler schedule SWInterruptHandler&#13;&#10;&#9;}&#13;&#10;&#9;return ret;&#13;&#10;}&#13;&#10;&#13;&#10;// ---------------------------------------------------------------------------------------------&#13;&#10;// 4. HDMI / passive DP++ on wake. AppleIntelFramebuffer::getDisplayStatus(path) checks HPD, then&#13;&#10;// powers the sink up over DP AUX; with a passive DP-to-HDMI adapter AUX never answers, so it&#13;&#10;// returns 0 ("Setting DP power failed ... likely HDMI/TMDS case"). At boot the HDMI path still&#13;&#10;// finds the monitor, but Transition_wake trusts this status and drops the display ("display&#13;&#10;// removed in lower powerstate"). If the status is 0 while the port's TGP HPD line is high,&#13;&#10;// report it connected; an unplugged monitor (HPD low) still reads as disconnected.&#13;&#10;// ---------------------------------------------------------------------------------------------&#13;&#10;static constexpr size_t FramebufferController = 0x1D0, DisplayPathPortIndex = 0x450;&#13;&#10;static constexpr uint32_t TgpHpdLiveBit[4] { 1U &amp;lt;&amp;lt; 16, 1U &amp;lt;&amp;lt; 17, 1U &amp;lt;&amp;lt; 24, 1U &amp;lt;&amp;lt; 25 }; // DDI A..D&#13;&#10;&#13;&#10;using t_getDisplayStatus = uint32_t (*)(void *, void *);&#13;&#10;static t_getDisplayStatus orgGetDisplayStatus;&#13;&#10;static uint32_t statusOverrideCount;&#13;&#10;&#13;&#10;static uint32_t wrapGetDisplayStatus(void *framebuffer, void *path) {&#13;&#10;&#9;uint32_t status = orgGetDisplayStatus(framebuffer, path);&#13;&#10;&#9;if (status == 0 &amp;amp;&amp;amp; path) {&#13;&#10;&#9;&#9;auto controller = *reinterpret_cast&amp;lt;void **&amp;gt;(reinterpret_cast&amp;lt;uint8_t *&amp;gt;(framebuffer) + FramebufferController);&#13;&#10;&#9;&#9;uint8_t idx = *(reinterpret_cast&amp;lt;uint8_t *&amp;gt;(path) + DisplayPathPortIndex);&#13;&#10;&#9;&#9;if (controller &amp;amp;&amp;amp; idx &amp;lt; 4)&#13;&#10;&#9;&#9;&#9;if (auto mmio = controllerMmio(controller))&#13;&#10;&#9;&#9;&#9;&#9;if (mmioReg(mmio, 0xC4000) &amp;amp; TgpHpdLiveBit[idx]) {&#13;&#10;&#9;&#9;&#9;&#9;&#9;status = 1;&#13;&#10;&#9;&#9;&#9;&#9;&#9;statusOverrideCount++;&#13;&#10;&#9;&#9;&#9;&#9;}&#13;&#10;&#9;}&#13;&#10;&#9;return status;&#13;&#10;}&#13;&#10;&#13;&#10;// ---------------------------------------------------------------------------------------------&#13;&#10;// Status, published once a minute on our IOService (ioreg -r -c CMLTGPFix): patch and route&#13;&#10;// results (0 = ok, otherwise KernelPatcher::Error, -1 = not attempted) and interrupt counters.&#13;&#10;// ---------------------------------------------------------------------------------------------&#13;&#10;static int patchStatus[3] { -1, -1, -1 };&#13;&#10;static int routeStatus = -1;&#13;&#10;static int layoutStatus = -1; // 0 = offsets verified, 1 = mismatch (wrappers skipped)&#13;&#10;static thread_call_t statusCall;&#13;&#10;&#13;&#10;static void scheduleStatus(uint32_t seconds) {&#13;&#10;&#9;uint64_t deadline;&#13;&#10;&#9;clock_interval_to_deadline(seconds, kSecondScale, &amp;amp;deadline);&#13;&#10;&#9;thread_call_enter_delayed(statusCall, deadline);&#13;&#10;}&#13;&#10;&#13;&#10;static void publishStatus(thread_call_param_t, thread_call_param_t) {&#13;&#10;&#9;if (auto self = ADDPR(selfInstance)) {&#13;&#10;&#9;&#9;self-&amp;gt;setProperty("patch-DDI-B", static_cast&amp;lt;unsigned long long&amp;gt;(patchStatus[0]), 32);&#13;&#10;&#9;&#9;self-&amp;gt;setProperty("patch-DDI-C", static_cast&amp;lt;unsigned long long&amp;gt;(patchStatus[1]), 32);&#13;&#10;&#9;&#9;self-&amp;gt;setProperty("patch-DDI-D", static_cast&amp;lt;unsigned long long&amp;gt;(patchStatus[2]), 32);&#13;&#10;&#9;&#9;self-&amp;gt;setProperty("route-status", static_cast&amp;lt;unsigned long long&amp;gt;(routeStatus), 32);&#13;&#10;&#9;&#9;self-&amp;gt;setProperty("layout-status", static_cast&amp;lt;unsigned long long&amp;gt;(layoutStatus), 32);&#13;&#10;&#9;&#9;self-&amp;gt;setProperty("irq-enable-count", irqEnableCount, 32);&#13;&#10;&#9;&#9;self-&amp;gt;setProperty("tgp-irq-count", tgpIrqCount, 32);&#13;&#10;&#9;&#9;self-&amp;gt;setProperty("tgp-last-events", tgpLastEvents, 32);&#13;&#10;&#9;&#9;self-&amp;gt;setProperty("hpd-rearm-count", hpdRearmCount, 32);&#13;&#10;&#9;&#9;self-&amp;gt;setProperty("status-override-count", statusOverrideCount, 32);&#13;&#10;&#9;&#9;if (lastMmio) {&#13;&#10;&#9;&#9;&#9;self-&amp;gt;setProperty("SDEISR", mmioReg(lastMmio, 0xC4000), 32);&#13;&#10;&#9;&#9;&#9;self-&amp;gt;setProperty("SHOTPLUG_CTL_DDI", mmioReg(lastMmio, SHOTPLUG_CTL_DDI), 32);&#13;&#10;&#9;&#9;&#9;self-&amp;gt;setProperty("SHOTPLUG_CTL_TC", mmioReg(lastMmio, SHOTPLUG_CTL_TC), 32);&#13;&#10;&#9;&#9;}&#13;&#10;&#9;}&#13;&#10;&#9;scheduleStatus(60);&#13;&#10;}&#13;&#10;&#13;&#10;// The wrappers rely on private structure offsets (controller+0x1A08 MMIO, +0x2C70 pending events,&#13;&#10;// framebuffer+0x1D0 controller, displayPath+0x450 port index). A macOS update can change them, so&#13;&#10;// before routing we check that the functions still use exactly these displacements; otherwise we&#13;&#10;// skip the wrappers (worst case: no display) rather than risk a panic.&#13;&#10;static bool codeUsesDisplacement(mach_vm_address_t function, size_t length, uint32_t displacement) {&#13;&#10;&#9;if (!function)&#13;&#10;&#9;&#9;return false;&#13;&#10;&#9;auto code = reinterpret_cast&amp;lt;const uint8_t *&amp;gt;(function);&#13;&#10;&#9;for (size_t i = 0; i + sizeof(displacement) &amp;lt;= length; i++)&#13;&#10;&#9;&#9;if (code[i] == (displacement &amp;amp; 0xFF) &amp;amp;&amp;amp; code[i + 1] == ((displacement &amp;gt;&amp;gt; 8) &amp;amp; 0xFF) &amp;amp;&amp;amp;&#13;&#10;&#9;&#9;&#9;code[i + 2] == ((displacement &amp;gt;&amp;gt; 16) &amp;amp; 0xFF) &amp;amp;&amp;amp; code[i + 3] == ((displacement &amp;gt;&amp;gt; 24) &amp;amp; 0xFF))&#13;&#10;&#9;&#9;&#9;return true;&#13;&#10;&#9;return false;&#13;&#10;}&#13;&#10;&#13;&#10;&#13;&#10;static bool layoutMatches(KernelPatcher &amp;amp;patcher, size_t index, mach_vm_address_t address, size_t size) {&#13;&#10;&#9;auto dig = patcher.solveSymbol(index, "__ZN31AppleIntelFramebufferController15DigPortHDPStateEP21AppleIntelFramebufferP21AppleIntelDisplayPath", address, size);&#13;&#10;&#9;auto proc = patcher.solveSymbol(index, "__ZN31AppleIntelFramebufferController16ProcessInterruptEv", address, size);&#13;&#10;&#9;auto gds = patcher.solveSymbol(index, "__ZN21AppleIntelFramebuffer16getDisplayStatusEP21AppleIntelDisplayPath", address, size);&#13;&#10;&#9;patcher.clearError();&#13;&#10;&#9;return codeUsesDisplacement(dig, 0x100, ControllerMmio) &amp;amp;&amp;amp;&#13;&#10;&#9;&#9;codeUsesDisplacement(dig, 0x100, DisplayPathPortIndex) &amp;amp;&amp;amp;&#13;&#10;&#9;&#9;codeUsesDisplacement(proc, 0x1800, ControllerPendingEvents) &amp;amp;&amp;amp;&#13;&#10;&#9;&#9;codeUsesDisplacement(gds, 0x200, FramebufferController);&#13;&#10;}&#13;&#10;&#13;&#10;static void processKext(void *, KernelPatcher &amp;amp;patcher, size_t index, mach_vm_address_t address, size_t size) {&#13;&#10;&#9;if (index != kextCFL.loadIndex)&#13;&#10;&#9;&#9;return;&#13;&#10;&#13;&#10;&#9;layoutStatus = layoutMatches(patcher, index, address, size) ? 0 : 1;&#13;&#10;&#9;if (layoutStatus != 0) {&#13;&#10;&#9;&#9;SYSLOG("cmltgp", "framebuffer layout differs from the version this was built for, skipping wrappers");&#13;&#10;&#9;&#9;goto patchMasks;&#13;&#10;&#9;}&#13;&#10;&#13;&#10;&#9;{&#13;&#10;&#9;KernelPatcher::RouteRequest requests[] {&#13;&#10;&#9;&#9;{ "__ZN31AppleIntelFramebufferController15DigPortHDPStateEP21AppleIntelFramebufferP21AppleIntelDisplayPath",&#13;&#10;&#9;&#9; wrapDigPortHDPState, orgDigPortHDPState },&#13;&#10;&#9;&#9;{ "__ZN31AppleIntelFramebufferController18hwEnableInterruptsEv", wrapHwEnableInterrupts, orgHwEnableInterrupts },&#13;&#10;&#9;&#9;{ "__ZN31AppleIntelFramebufferController16ProcessInterruptEv", wrapProcessInterrupt, orgProcessInterrupt },&#13;&#10;&#9;&#9;{ "__ZN21AppleIntelFramebuffer16getDisplayStatusEP21AppleIntelDisplayPath", wrapGetDisplayStatus, orgGetDisplayStatus },&#13;&#10;&#9;};&#13;&#10;&#9;patcher.routeMultiple(index, requests, arrsize(requests), address, size);&#13;&#10;&#9;routeStatus = static_cast&amp;lt;int&amp;gt;(patcher.getError());&#13;&#10;&#9;if (patcher.getError() != KernelPatcher::Error::NoError)&#13;&#10;&#9;&#9;SYSLOG("cmltgp", "interrupt routing FAILED (%d)", patcher.getError());&#13;&#10;&#9;patcher.clearError();&#13;&#10;&#9;}&#13;&#10;&#13;&#10;patchMasks:&#13;&#10;&#9;// The mask patches are safe on any version: a pattern that no longer matches is simply not applied.&#13;&#10;&#9;const KernelPatcher::LookupPatch patches[] {&#13;&#10;&#9;&#9;{ &amp;amp;kextCFL, findB, replaceB, sizeof(findB), 1 },&#13;&#10;&#9;&#9;{ &amp;amp;kextCFL, findC, replaceC, sizeof(findC), 1 },&#13;&#10;&#9;&#9;{ &amp;amp;kextCFL, findD, replaceD, sizeof(findD), 1 },&#13;&#10;&#9;};&#13;&#10;&#9;const char *names[] { "DDI B", "DDI C", "DDI D" };&#13;&#10;&#13;&#10;&#9;for (size_t i = 0; i &amp;lt; arrsize(patches); i++) {&#13;&#10;&#9;&#9;patcher.applyLookupPatch(&amp;amp;patches[i]);&#13;&#10;&#9;&#9;patchStatus[i] = static_cast&amp;lt;int&amp;gt;(patcher.getError());&#13;&#10;&#9;&#9;if (patcher.getError() != KernelPatcher::Error::NoError)&#13;&#10;&#9;&#9;&#9;SYSLOG("cmltgp", "HPD mask patch %s FAILED (%d)", names[i], patcher.getError());&#13;&#10;&#9;&#9;patcher.clearError();&#13;&#10;&#9;}&#13;&#10;}&#13;&#10;&#13;&#10;static void pluginStart() {&#13;&#10;&#9;lilu.onKextLoadForce(&amp;amp;kextCFL, 1, processKext);&#13;&#10;&#9;statusCall = thread_call_allocate(publishStatus, nullptr);&#13;&#10;&#9;if (statusCall)&#13;&#10;&#9;&#9;scheduleStatus(10);&#13;&#10;}&#13;&#10;&#13;&#10;static const char *bootargOff[] { "-cmltgpoff" };&#13;&#10;static const char *bootargDebug[] { "-cmltgpdbg" };&#13;&#10;static const char *bootargBeta[] { "-cmltgpbeta" };&#13;&#10;&#13;&#10;PluginConfiguration ADDPR(config) {&#13;&#10;&#9;xStringify(PRODUCT_NAME),&#13;&#10;&#9;parseModuleVersion(xStringify(MODULE_VERSION)),&#13;&#10;&#9;LiluAPI::AllowNormal | LiluAPI::AllowInstallerRecovery | LiluAPI::AllowSafeMode,&#13;&#10;&#9;bootargOff, arrsize(bootargOff),&#13;&#10;&#9;bootargDebug, arrsize(bootargDebug),&#13;&#10;&#9;bootargBeta, arrsize(bootargBeta),&#13;&#10;&#9;KernelVersion::BigSur,&#13;&#10;&#9;KernelVersion::Tahoe,&#13;&#10;&#9;pluginStart&#13;&#10;};&lt;/code&gt;&lt;/pre&gt;&#13;&#10; &lt;/figure&gt;&#13;&#10; &lt;figure class="code tall"&gt;&#13;&#10; &lt;figcaption&gt;&lt;span&gt;CMLTGPFix/build.sh&lt;/span&gt;&lt;button class="copy" type="button"&gt;Copy&lt;/button&gt;&lt;/figcaption&gt;&#13;&#10; &lt;pre&gt;&lt;code&gt;#!/bin/bash&#13;&#10;# Copyright (c) 2026, A Star Computers. SPDX-License-Identifier: BSD-3-Clause (see LICENSE)&#13;&#10;# Builds CMLTGPFix.kext without Xcode (Command Line Tools only). Run on the Mac from this folder,&#13;&#10;# with Lilu-1.7.2/ and MacKernelSDK-master/ unpacked one level up.&#13;&#10;set -e&#13;&#10;cd "$(dirname "$0")"&#13;&#10;SDK=../MacKernelSDK-master&#13;&#10;LILU=../Lilu-1.7.2/Lilu&#13;&#10;OUT=build/CMLTGPFix.kext&#13;&#10;rm -rf build &amp;amp;&amp;amp; mkdir -p "$OUT/Contents/MacOS"&#13;&#10;&#13;&#10;cat &amp;gt; build/kmod_info.c &amp;lt;&amp;lt;'EOF'&#13;&#10;#include &amp;lt;mach/mach_types.h&amp;gt;&#13;&#10;extern kern_return_t _start(kmod_info_t *ki, void *data);&#13;&#10;extern kern_return_t _stop(kmod_info_t *ki, void *data);&#13;&#10;__attribute__((visibility("default"))) KMOD_EXPLICIT_DECL(org.cmltgpfix.CMLTGPFix, "1.3.1", _start, _stop)&#13;&#10;extern kern_return_t CMLTGPFix_kern_start(kmod_info_t *, void *);&#13;&#10;extern kern_return_t CMLTGPFix_kern_stop(kmod_info_t *, void *);&#13;&#10;__private_extern__ kmod_start_func_t *_realmain = CMLTGPFix_kern_start;&#13;&#10;__private_extern__ kmod_stop_func_t *_antimain = CMLTGPFix_kern_stop;&#13;&#10;__private_extern__ int _kext_apple_cc = __APPLE_CC__;&#13;&#10;EOF&#13;&#10;&#13;&#10;COMMON="-arch x86_64 -mmacosx-version-min=11.0 -mkernel -nostdinc -fno-builtin -fno-common -fno-stack-protector&#13;&#10; -D KERNEL -D KERNEL_PRIVATE -D DRIVER_PRIVATE -D APPLE -D NeXT&#13;&#10; -D PRODUCT_NAME=CMLTGPFix -D MODULE_VERSION=1.3.1&#13;&#10; -I $SDK/Headers -I $LILU -O2 -Wno-deprecated-declarations"&#13;&#10;CXXFLAGS="$COMMON -x c++ -std=c++17 -fapple-kext -fno-exceptions -fno-rtti"&#13;&#10;&#13;&#10;clang $COMMON -x c -c build/kmod_info.c -o build/kmod_info.o&#13;&#10;clang $CXXFLAGS -c kern_start.cpp -o build/kern_start.o&#13;&#10;clang $CXXFLAGS -c $LILU/Library/plugin_start.cpp -o build/plugin_start.o&#13;&#10;&#13;&#10;CCKEXT=$(ls /Library/Developer/CommandLineTools/usr/lib/clang/*/lib/darwin/libclang_rt.cc_kext.a 2&amp;gt;/dev/null | head -1)&#13;&#10;clang -arch x86_64 -mmacosx-version-min=11.0 -nostdlib -Xlinker -kext -Xlinker -no_data_const \&#13;&#10; build/kmod_info.o build/kern_start.o build/plugin_start.o \&#13;&#10; -L$SDK/Library/x86_64 -lkmod ${CCKEXT:+$CCKEXT} -o "$OUT/Contents/MacOS/CMLTGPFix"&#13;&#10;&#13;&#10;cp Info.plist "$OUT/Contents/Info.plist"&#13;&#10;echo "built $OUT"&#13;&#10;nm -u "$OUT/Contents/MacOS/CMLTGPFix" | head -30&lt;/code&gt;&lt;/pre&gt;&#13;&#10; &lt;/figure&gt;&#13;&#10; &lt;figure class="code tall"&gt;&#13;&#10; &lt;figcaption&gt;&lt;span&gt;CMLTGPFix/Info.plist&lt;/span&gt;&lt;button class="copy" type="button"&gt;Copy&lt;/button&gt;&lt;/figcaption&gt;&#13;&#10; &lt;pre&gt;&lt;code&gt;&amp;lt;?xml version="1.0" encoding="UTF-8"?&amp;gt;&#13;&#10;&amp;lt;!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"&amp;gt;&#13;&#10;&amp;lt;plist version="1.0"&amp;gt;&#13;&#10;&amp;lt;dict&amp;gt;&#13;&#10;&#9;&amp;lt;key&amp;gt;CFBundleDevelopmentRegion&amp;lt;/key&amp;gt;&#13;&#10;&#9;&amp;lt;string&amp;gt;en&amp;lt;/string&amp;gt;&#13;&#10;&#9;&amp;lt;key&amp;gt;CFBundleExecutable&amp;lt;/key&amp;gt;&#13;&#10;&#9;&amp;lt;string&amp;gt;CMLTGPFix&amp;lt;/string&amp;gt;&#13;&#10;&#9;&amp;lt;key&amp;gt;CFBundleIdentifier&amp;lt;/key&amp;gt;&#13;&#10;&#9;&amp;lt;string&amp;gt;org.cmltgpfix.CMLTGPFix&amp;lt;/string&amp;gt;&#13;&#10;&#9;&amp;lt;key&amp;gt;CFBundleInfoDictionaryVersion&amp;lt;/key&amp;gt;&#13;&#10;&#9;&amp;lt;string&amp;gt;6.0&amp;lt;/string&amp;gt;&#13;&#10;&#9;&amp;lt;key&amp;gt;CFBundleName&amp;lt;/key&amp;gt;&#13;&#10;&#9;&amp;lt;string&amp;gt;CMLTGPFix&amp;lt;/string&amp;gt;&#13;&#10;&#9;&amp;lt;key&amp;gt;CFBundlePackageType&amp;lt;/key&amp;gt;&#13;&#10;&#9;&amp;lt;string&amp;gt;KEXT&amp;lt;/string&amp;gt;&#13;&#10;&#9;&amp;lt;key&amp;gt;CFBundleShortVersionString&amp;lt;/key&amp;gt;&#13;&#10;&#9;&amp;lt;string&amp;gt;1.3.1&amp;lt;/string&amp;gt;&#13;&#10;&#9;&amp;lt;key&amp;gt;CFBundleSignature&amp;lt;/key&amp;gt;&#13;&#10;&#9;&amp;lt;string&amp;gt;????&amp;lt;/string&amp;gt;&#13;&#10;&#9;&amp;lt;key&amp;gt;CFBundleVersion&amp;lt;/key&amp;gt;&#13;&#10;&#9;&amp;lt;string&amp;gt;1.3.1&amp;lt;/string&amp;gt;&#13;&#10;&#9;&amp;lt;key&amp;gt;IOKitPersonalities&amp;lt;/key&amp;gt;&#13;&#10;&#9;&amp;lt;dict&amp;gt;&#13;&#10;&#9;&#9;&amp;lt;key&amp;gt;org.cmltgpfix.CMLTGPFix&amp;lt;/key&amp;gt;&#13;&#10;&#9;&#9;&amp;lt;dict&amp;gt;&#13;&#10;&#9;&#9;&#9;&amp;lt;key&amp;gt;CFBundleIdentifier&amp;lt;/key&amp;gt;&#13;&#10;&#9;&#9;&#9;&amp;lt;string&amp;gt;org.cmltgpfix.CMLTGPFix&amp;lt;/string&amp;gt;&#13;&#10;&#9;&#9;&#9;&amp;lt;key&amp;gt;IOClass&amp;lt;/key&amp;gt;&#13;&#10;&#9;&#9;&#9;&amp;lt;string&amp;gt;CMLTGPFix&amp;lt;/string&amp;gt;&#13;&#10;&#9;&#9;&#9;&amp;lt;key&amp;gt;IOMatchCategory&amp;lt;/key&amp;gt;&#13;&#10;&#9;&#9;&#9;&amp;lt;string&amp;gt;CMLTGPFix&amp;lt;/string&amp;gt;&#13;&#10;&#9;&#9;&#9;&amp;lt;key&amp;gt;IOProviderClass&amp;lt;/key&amp;gt;&#13;&#10;&#9;&#9;&#9;&amp;lt;string&amp;gt;IOResources&amp;lt;/string&amp;gt;&#13;&#10;&#9;&#9;&#9;&amp;lt;key&amp;gt;IOResourceMatch&amp;lt;/key&amp;gt;&#13;&#10;&#9;&#9;&#9;&amp;lt;string&amp;gt;IOKit&amp;lt;/string&amp;gt;&#13;&#10;&#9;&#9;&amp;lt;/dict&amp;gt;&#13;&#10;&#9;&amp;lt;/dict&amp;gt;&#13;&#10;&#9;&amp;lt;key&amp;gt;NSHumanReadableCopyright&amp;lt;/key&amp;gt;&#13;&#10;&#9;&amp;lt;string&amp;gt;Copyright © 2026 A Star Computers. BSD-3-Clause.&amp;lt;/string&amp;gt;&#13;&#10;&#9;&amp;lt;key&amp;gt;OSBundleCompatibleVersion&amp;lt;/key&amp;gt;&#13;&#10;&#9;&amp;lt;string&amp;gt;1.0&amp;lt;/string&amp;gt;&#13;&#10;&#9;&amp;lt;key&amp;gt;OSBundleLibraries&amp;lt;/key&amp;gt;&#13;&#10;&#9;&amp;lt;dict&amp;gt;&#13;&#10;&#9;&#9;&amp;lt;key&amp;gt;as.vit9696.Lilu&amp;lt;/key&amp;gt;&#13;&#10;&#9;&#9;&amp;lt;string&amp;gt;1.3.1&amp;lt;/string&amp;gt;&#13;&#10;&#9;&#9;&amp;lt;key&amp;gt;com.apple.kpi.bsd&amp;lt;/key&amp;gt;&#13;&#10;&#9;&#9;&amp;lt;string&amp;gt;12.0.0&amp;lt;/string&amp;gt;&#13;&#10;&#9;&#9;&amp;lt;key&amp;gt;com.apple.kpi.dsep&amp;lt;/key&amp;gt;&#13;&#10;&#9;&#9;&amp;lt;string&amp;gt;12.0.0&amp;lt;/string&amp;gt;&#13;&#10;&#9;&#9;&amp;lt;key&amp;gt;com.apple.kpi.iokit&amp;lt;/key&amp;gt;&#13;&#10;&#9;&#9;&amp;lt;string&amp;gt;12.0.0&amp;lt;/string&amp;gt;&#13;&#10;&#9;&#9;&amp;lt;key&amp;gt;com.apple.kpi.libkern&amp;lt;/key&amp;gt;&#13;&#10;&#9;&#9;&amp;lt;string&amp;gt;12.0.0&amp;lt;/string&amp;gt;&#13;&#10;&#9;&#9;&amp;lt;key&amp;gt;com.apple.kpi.mach&amp;lt;/key&amp;gt;&#13;&#10;&#9;&#9;&amp;lt;string&amp;gt;12.0.0&amp;lt;/string&amp;gt;&#13;&#10;&#9;&#9;&amp;lt;key&amp;gt;com.apple.kpi.unsupported&amp;lt;/key&amp;gt;&#13;&#10;&#9;&#9;&amp;lt;string&amp;gt;12.0.0&amp;lt;/string&amp;gt;&#13;&#10;&#9;&amp;lt;/dict&amp;gt;&#13;&#10;&#9;&amp;lt;key&amp;gt;OSBundleRequired&amp;lt;/key&amp;gt;&#13;&#10;&#9;&amp;lt;string&amp;gt;Root&amp;lt;/string&amp;gt;&#13;&#10;&amp;lt;/dict&amp;gt;&#13;&#10;&amp;lt;/plist&amp;gt;&lt;/code&gt;&lt;/pre&gt;&#13;&#10; &lt;/figure&gt;&#13;&#10; &lt;figure class="code tall" id="license"&gt;&#13;&#10; &lt;figcaption&gt;&lt;span&gt;CMLTGPFix/LICENSE&lt;/span&gt;&lt;button class="copy" type="button"&gt;Copy&lt;/button&gt;&lt;/figcaption&gt;&#13;&#10; &lt;pre&gt;&lt;code&gt;BSD 3-Clause License&#13;&#10;&#13;&#10;Copyright (c) 2026, A Star Computers&#13;&#10;&#13;&#10;Redistribution and use in source and binary forms, with or without&#13;&#10;modification, are permitted provided that the following conditions are met:&#13;&#10;&#13;&#10;1. Redistributions of source code must retain the above copyright notice, this&#13;&#10; list of conditions and the following disclaimer.&#13;&#10;&#13;&#10;2. Redistributions in binary form must reproduce the above copyright notice,&#13;&#10; this list of conditions and the following disclaimer in the documentation&#13;&#10; and/or other materials provided with the distribution.&#13;&#10;&#13;&#10;3. Neither the name of the copyright holder nor the names of its&#13;&#10; contributors may be used to endorse or promote products derived from&#13;&#10; this software without specific prior written permission.&#13;&#10;&#13;&#10;THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"&#13;&#10;AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE&#13;&#10;IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE&#13;&#10;DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE&#13;&#10;FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL&#13;&#10;DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR&#13;&#10;SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER&#13;&#10;CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,&#13;&#10;OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE&#13;&#10;OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.&lt;/code&gt;&lt;/pre&gt;&#13;&#10; &lt;/figure&gt;&#13;&#10; &lt;/section&gt;&#13;&#10;&#13;&#10; &lt;section id="credits"&gt;&#13;&#10; &lt;h2&gt;Credits&lt;/h2&gt;&#13;&#10; &lt;ul&gt;&#13;&#10; &lt;li&gt;The Linux &lt;strong&gt;i915&lt;/strong&gt; developers, whose Gen9 + TGP support (&lt;code&gt;intel_ddi.c&lt;/code&gt;, &lt;code&gt;intel_hotplug_irq.c&lt;/code&gt;, &lt;code&gt;intel_bios.c&lt;/code&gt;, &lt;code&gt;intel_display_regs.h&lt;/code&gt;) documents every register used here.&lt;/li&gt;&#13;&#10; &lt;li&gt;&lt;a href="https://github.com/acidanthera"&gt;acidanthera&lt;/a&gt; for OpenCore, Lilu, WhateverGreen, RestrictEvents and MacKernelSDK.&lt;/li&gt;&#13;&#10; &lt;li&gt;&lt;a href="https://github.com/USBToolBox"&gt;USBToolBox&lt;/a&gt;, &lt;a href="https://dortania.github.io/OpenCore-Install-Guide/"&gt;Dortania's guides&lt;/a&gt; and &lt;a href="https://github.com/CloverHackyColor/VoodooHDA"&gt;VoodooHDA&lt;/a&gt;.&lt;/li&gt;&#13;&#10; &lt;li&gt;&lt;a href="https://github.com/vladII19/latitude-7390-tahoe-audio"&gt;vladII19's Latitude 7390 Tahoe audio write-up&lt;/a&gt;, which documents the VoodooHDA route.&lt;/li&gt;&#13;&#10; &lt;/ul&gt;&#13;&#10; &lt;/section&gt;&#13;&#10; &lt;/article&gt;&#13;&#10;&lt;/div&gt;</description></item></channel></rss>