I created it because I wanted my Nvidia GPUs to be compute only, and needed a cheap and small display GPU to run X11. I bought this GPU on AliExpress, after learning it had Linux support. It does, but kernel 5.x series and the sm750 driver in modern Linux only supports the older VGA/DVI variants.
Rather than send it back or throw it away, I decided to vibe code a new driver with new features, to make it usable for day to day desktop use. I've a little bit of a background in low level graphics so also added a cool little magic ordered dither (a pretty good one I think!) I devised myself, called "bbdither", and a few hacks to get 2560x1080 at 75hz on a device only officially documented as capable of up to 1920x1200 at 60hz, and PCI-E 1x speed.
Screenshots here: https://github.com/KodeMunkie/sm750hdmifb#screenshots
If you try it out, be careful - read the project disclaimer :)
*Vibe coded, as mentioned in Hackernews comments here https://news.ycombinator.com/item?id=49415282
tldr; had Qwen orchestrate, do admin and assist with investigations, builds and debugging when codex was unavailable. Codex had a dedicated test physical machine, and I promoted the driver it created to the actual target (production) machine when it was stable enough. Used syncthing to keep the code synced between the different environments, with Qwen sending me progress updates on Telegram and querying Codex periodically.
Long answer:
1) Ran the concept and investigation past Qwen 3.6, I wanted a card that would fit my spare PCIe 3 X1 socket (faster cards in other sockets). Identified the sm750, and read up on its capabilities.
2) Due to speed and Qwen 3.6's capability, I handed Codex (on high) a whole physical scrap machine / fresh Mint install, with root access and the GPU directly connected and asked it what was needed. Syncthing copied the work folder to my machine desktop for visibility to my main orchestrating Qwen AI. Qwen could also ssh to the Codex owned machine to check progress and send me Telegram messages when any milestones were passed, as well as issues that might need me there.
3) I Identified all the chips on the sm750, whilst it was trying the official older sm750 drivers (attempting to get a HDMI signal) and gave them to it.
4) Used /plan mode to set the first iteration expectations, no DRM/integration into the control panel, modifying a checked out fbdev low level FB to test my magic dither algorithm (this can only be used for test, the integration needs to go elsewhere in the stack typically).
5) Left it a few hours, came back to see colour bars (success!)
6) Asked it to do the basic plumbing for X11, wondered how far I could push the frequencies past the VESA standards, fried the HDMI TV attempting high frequency modes (only realised next day I'd done this after the TV refused to activate that connector)
7) Plugged the card directly into the machine it would be used in, and the actual ultrawide monitor. Resumed the codex session on that machine, when daily limits were hit used Qwen 3.6/3.8 to package up builds, look for solutions to issues I was hitting. At this point the hardware is my "production" system, so effectively I've promoted test to staging.
8) From here I manually iterated with Codex by having it create scripts that would build the module for the current kernel to restart X11 with 1-3 ideas / fixes at a time.
9) In parallel, used Qwen to prep the GitHub project, Codex and Qwen to do research for ideas on how to overclock the chips, feasibility of hacks I wanted investigating
10) Asked Codex and Qwen to identify bugs Vs specs, it found a few in event sequencing, resuming events, wrong bits in packets etc.
11) Switched Codex to Max after the the bugs were fixed because the driver performance was laggy, and recommendations from Qwen and Codex Medium/High for optimisations either caused degradations in some way (e.g. DMA was slower) and asked it to audit and optimise the code. I did this over 3 nights due to credit limits getting hit, again 1 to 3 changes at a time.
12) After I was happy with the quality ran the licencing checks again past Qwen and Codex and set up the project on GitHub, held private until I got workflows working.
^ / 1024^2[bytes/MB] = 23.73[MB]
That one is VGA so I think the original upstream driver should support it.
I have like 4 drivers to upstream myself, plus a couple of patches here and there. Quality is good and they're tested, and while I understand the code and how things work low level, I wouldn't be able to write them myself.
VGA displays are something of a dying breed, and HDMI is the single likeliest interface you might find on a random newish display, so there is a market for absolute cheapest, most basic HDMI output device you can make. If you're going to build that interface, 1080p is the resolution you need to target. My point was simply that 16MB is just barely enough to build that interface, and barely enough is still enough.
For dual-monitor versions?
One avenue I looked at for a real 2560px width was that the second controller was physically independent and could have different hardware limits of the first controller by virtue of supporting DVI directly (but not being physically connected to another port).
Unfortunately other controller is logical so that was a bust.
The dev on this driver used a combination of local Qwen 3.6 and 3.8 27B for admin and basic work, and extensive Codex 5.6 Sol Max to catch the issues I found and do last stage optimisations / isolate the bugs.
I'll freely admit I relied heavily on AI, my expertise and day job is in other software stacks.
I stand on the back of giants :)
Push this card to real 2048-wide output or a software-scaled 2560x1080 ultrawide desktop, with bandwidth-saving colour conversion and update optimisations for smoother performance.
Linux display driver for the single-HDMI SE-DP750A-HDMI PCIe card.
Experimental: this driver is for one specific SM750 board. Optional modes can exceed published GPU or monitor clock limits and may produce no signal, distortion, or an unstable display. Keep SSH or another recovery route available when trying non-EDID modes.
The tested board is sold or marked as SE-DP750A-HDMI and has all of these:
SM750G10-AC, revision A1126f:0750SiI9024ACNU HDMI transmitterThe PCI ID alone is not enough. Other SM750 cards may use VGA, a different transmitter, or different GPIO wiring and are not currently supported.
Ubuntu 24.04 and Linux Mint 22 users can build a DKMS package locally:
sudo apt update
sudo apt install build-essential dkms linux-headers-$(uname -r) libdrm-dev git
git clone https://github.com/KodeMunkie/sm750hdmifb.git
cd sm750hdmifb
make check
./build-package.sh
sudo apt install ./dist/sm750hdmifb_0.5.5_all.deb
sudo reboot
The reboot matters: it lets the package blacklist Linux's old sm750fb driver
before it can claim the card. The package is named sm750hdmifb; the kernel
module is sm750hdmidrm.ko so it cannot be confused with sm750fb.ko.
The driver is intended for Linux 6.17 and newer. DKMS deliberately refuses older kernels because the required DRM interfaces are not supported by this project. The source has compatibility paths for Linux 6.17 through the 6.x series and for Linux 7.0 onward. It currently builds and passes the full test suite against 6.17 and 7.0 Ubuntu kernels; the manual CI workflow also builds against Ubuntu 24.04's 6.17 kernel headers.
There is no fixed upper version cap, but future kernels can change internal DRM
APIs. Because this is an out-of-tree driver, a new kernel version may require a
source update even though it falls within the intended 6.17+ range.
Prebuilt packages, when available, are published under GitHub Releases. Building locally is recommended because DKMS compiles against the installed kernel headers.
By default the driver:
Applications still render in 32-bit colour. Immediately before upload, the driver converts changed screen regions to RGB565 and applies KodeMunkie's ordered dither with a 94% green-channel correction. This is the default because the SM750 framebuffer is reached over a PCIe 1.1 x1 link. At the higher resolutions that link cannot provide responsive full-screen 32-bit updates: XRGB8888 sends four bytes per output pixel, while RGB565 sends two. Dithered RGB565 therefore halves device-bound pixel traffic while preserving much of the apparent colour detail.
Common kernel or GRUB options are:
The table omits the common sm750hdmidrm. prefix to keep it readable. For
example, enter enable_dma=0 as sm750hdmidrm.enable_dma=0 in GRUB.
| Option and default | When to specify it | Effect and tradeoff |
|---|---|---|
scanout_format=rgb565-bbditherDefault: rgb565-bbdither |
No need; this is the recommended default | Dithered 16-bit scanout with green correction |
scanout_format=xrgb8888Default: rgb565-bbdither |
Only for 32-bit scanout | Disables RGB565, dither and green correction; doubles upload traffic and can lag at high resolutions |
scanout_format=rgb565Default: rgb565-bbdither |
Only for plain RGB565 | Disables the dither and green correction, reducing colour quality |
dither_green_gain=94Default: 94 |
No need; correction is on by default | Enables the tuned green correction while dithering |
dither_green_gain=100Default: 94 |
To turn green correction off | Keeps the dither but may produce a greener colour balance |
enable_dma=1Default: 1 |
No need; DMA is on by default | Verified eight-row DMA uploads with automatic CPU fallback |
enable_dma=0Default: 1 |
To disable DMA | Forces CPU uploads, usually with lower update performance |
disable_hardware_cursor=1Default: 0 |
For the software cursor fallback | Disables the hardware cursor and may reduce cursor responsiveness |
edid_only=0Default: 1 |
Required for the driver catalogue and ultrawide modes | DANGEROUS: STOPS EDID RESTRICTING MODES AND CLOCKS THE MONITOR MAY NOT SUPPORT |
softscale_wide=1Default: 0 |
Required for 2464x1080 and 2560x1080; also set edid_only=0 |
DANGEROUS / EXPERIMENTAL: ENABLES WIDE COMPRESSION AND REQUIRES MONITOR STRETCHING |
sharpen=1Default: 0 |
Recommended with ultrawide modes | Adds fixed 8% contrast sharpening after compression |
double_shadow=1Default: 0 |
Recommended to avoid redundant uploads | Adds source and output comparison snapshots; skips unchanged pixels but uses more system memory. This is not front/back page flipping |
async_updates=1Default: 1 |
No need; enabled by default | Keeps only the latest pending update instead of queuing stale frames |
Add options to the existing GRUB_CMDLINE_LINUX_DEFAULT value in
/etc/default/grub, then apply them with:
sudo update-grub
sudo reboot
Every option and its default is listed in Module parameters.
The device is normally described as supporting up to 1920 pixels horizontally.
With edid_only=0, the driver also exposes these real 2048-wide hardware
modes:
| Desktop and HDMI mode | Refresh rates | Output and risk |
|---|---|---|
2048x864 |
59.94, 60, 70, 72, 75 Hz | Native or monitor-scaled. EXPERIMENTAL: NOT RESTRICTED BY EDID |
2048x1024 |
59.94, 60, 70, 72 Hz | Native or monitor-scaled. EXPERIMENTAL: NOT RESTRICTED BY EDID |
2048x1080 |
50, 59.94, 60, 70, 72, 75 Hz | Native or monitor-scaled. EXPERIMENTAL: HIGH REFRESH MAY EXCEED SPECIFICATION |
2048x1152 |
59.94, 60 Hz | Native or monitor-scaled. EXPERIMENTAL: NOT RESTRICTED BY EDID |
softscale_wide=1 adds two wider logical desktops. Both require a physical
2560x1080 ultrawide monitor with FULL WIDESCREEN STRETCH ENABLED in its
on-screen menu:
| Logical desktop | Physical monitor | Width ratio | HDMI and monitor path |
|---|---|---|---|
2464x1080 |
2560x1080 |
77:6416.9% compression |
2048x1080 -> 2560x1080 stretch |
2560x1080 |
2560x1080 |
5:420% compression |
2048x1080 -> 2560x1080 stretch |
| Mode | Refresh rates | Guidance |
|---|---|---|
2464x1080 |
50, 59.94, 60, 70, 72, 75 Hz | RECOMMENDED: more detail and better responsiveness; enable sharpen=1 |
2560x1080 |
50, 59.94, 60, 70, 72, 75 Hz | Less detail and lower performance because more width is compressed; see the reasoning |
For both modes, the HDMI signal is stretched from 2048x1080 to the physical
2560x1080 pixels of a 2K ultrawide monitor.
2048 pixels is the highest real width this card can produce in hardware. The SM750 primary graphics plane has an 11-bit right-edge field, so its physical scanout width cannot exceed 2048 pixels. This is a hardware constraint; reducing the height does not release more horizontal bits. The 2464 and 2560 modes create wider workspaces in software, but the card still outputs only a 2048-pixel-wide signal.
An ultrawide monitor with its full-width or full-widescreen stretch option enabled is required for the intended result. The complete path is:
logical desktop -> driver compression -> 2048x1080 HDMI -> monitor stretch to 2560x1080 physical pixels
The monitor's stretch setting spatially expands the compressed 2048-pixel HDMI image across all 2560 physical panel pixels. It is not recovering lost source data, but it restores the intended ultrawide screen coverage and approximately restores the intended aspect ratio. What looks "correct" is subjective because the 2464 mode deliberately retains a small aspect difference.
For 2560x1080, the driver performs an optimized 5:4 reduction from 2560 to
2048 pixels, a 20% horizontal compression. A 2560-wide monitor then expands the
2048-pixel signal by 25% back across its panel. This provides a true
2560x1080-sized workspace, but some fine horizontal detail is necessarily
combined during the first step and more source pixels must be rendered and
processed.
For a physical 2560x1080 monitor, 2464x1080 is the recommended,
higher-performance and often sharper mode. It starts with
3.75% fewer desktop pixels and compresses width by only 16.9% before sending the
same 2048x1080 signal. The monitor still expands that signal across 2560 panel
pixels, so less source detail was discarded by the driver, but the final image
is about 3.9% wider than its logical geometry. This slight aspect distortion is
generally difficult to notice and is the tradeoff for improved responsiveness
and perceived sharpness. Enabling sm750hdmidrm.sharpen=1 is recommended.
Both wide modes can apply a small fixed 8% contrast sharpen after compression. It restores some edge definition lost to filtering; it does not recreate discarded pixels. The dither and green correction are applied during the final RGB565 conversion before the 2048-wide scanout is uploaded.
This tested profile enables the driver mode catalogue and wide scaling:
DANGER: THIS PROFILE DISABLES EDID MODE RESTRICTIONS AND EXPOSES EXPERIMENTAL OR ABOVE-SPECIFICATION CLOCKS. A LISTED MODE MAY BLANK OR DESTABILIZE THE DISPLAY OR EXCEED A GPU, TRANSMITTER OR MONITOR LIMIT.
sm750hdmidrm.edid_only=0 sm750hdmidrm.softscale_wide=1 sm750hdmidrm.sharpen=1 sm750hdmidrm.scanout_format=rgb565-bbdither sm750hdmidrm.double_shadow=1 sm750hdmidrm.enable_dma=1
Some catalogue refresh rates run the SM750 DVO path or the monitor outside published limits. A mode being listed does not guarantee that every monitor, cable, KVM, or adapter will accept it. See Modes and clock risks before experimenting.
rgb565-bbdither uses an 8x8 ordered dither conceived and tuned by KodeMunkie
specifically for desktop use on this card. It includes an adjustable
green-channel correction and anchors the pattern to screen coordinates, so
small updates do not make the pattern crawl or leave mismatched patches.
The three images below visualise the complete ultrawide conversion process.
Click any preview to open the original image. The logical desktop and physical
photo are shown at 50% page width. The compressed preview is shown at 41.56%,
preserving the 2048 / 2464 width reduction instead of stretching both digital
stages to the same preview width.
The driver receives this original 2464x1080 logical desktop.
The image above deliberately looks horizontally squashed. It reproduces the
2048x1080 HDMI scanout generated by compressing the 2464x1080 logical
desktop to the SM750's hardware-width limit.
The photographed result fills the monitor's 2560x1080 physical pixels at
75 Hz, using the driver's 16-bit rgb565-bbdither dithered scanout.
The monitor's FULL WIDESCREEN STRETCH option expands that signal across its
physical 2560x1080 panel. The complete path is therefore:
Logical desktop -> SM750 hardware scanout -> physical panel, stretched by the monitor.
Check binding and recent driver messages:
lspci -nnk -d 126f:0750
journalctl -k -b | grep -iE 'sm750|sii902'
If an experimental mode gives no signal, boot an older kernel entry or remove
the added sm750hdmidrm.* GRUB options from recovery access. Testing and live
reload guidance is in Testing and recovery.
The official SM750 specification is known to be wrong for at least one hardware-observed partial-update boundary. Empirically verified workarounds are documented in the source and must not be removed solely because an ideal model or specification says they are unnecessary.
The project is GPL-2.0-only. DDK-derived files came from Linux's GPL-2.0
staging sm750fb driver. No proprietary Silicon Motion driver, binary object,
firmware blob, or closed library is included or linked. See the
provenance audit for details.
This project was created through extensive AI-assisted or "vibe coding". I have specified and physically tested the behaviour and designed the custom dither, but do not claim enough Linux DRM, KMS, DKMS, or kernel-framework expertise to independently guarantee every implementation detail. The source is published for review and improvement, not as a claim of upstream kernel quality. Expert review is welcome.
YOU USE THIS EXPERIMENTAL DRIVER AND EVERY NON-EDID OR ABOVE-SPECIFICATION MODE ENTIRELY AT YOUR OWN RISK. YOU ARE RESPONSIBLE FOR RECOVERY ACCESS, BACKUPS, MODE SELECTION AND HARDWARE COMPATIBILITY. THE AUTHORS AND CONTRIBUTORS ARE NOT RESPONSIBLE FOR LOSS OF DISPLAY, DATA, TIME, HARDWARE, INCOME OR ANY OTHER DIRECT OR INDIRECT LOSS.
The software is provided without warranty. See LICENSE.