Skip to content

Instantly share code, notes, and snippets.

@devsnek
Created May 4, 2026 08:25
Show Gist options
  • Select an option

  • Save devsnek/2184bfe1f1be3d1f4fee0b69edc337c2 to your computer and use it in GitHub Desktop.

Select an option

Save devsnek/2184bfe1f1be3d1f4fee0b69edc337c2 to your computer and use it in GitHub Desktop.
From 399ffde6b7f27efd0b492fadc240bdce41174824 Mon Sep 17 00:00:00 2001
From: snek <the@snek.dev>
Date: Mon, 4 May 2026 09:44:07 +0200
Subject: [PATCH] mipi-dbi
---
.../base-files/lib/firmware/ubnt,utr-lcd.bin | Bin 0 -> 93 bytes
target/linux/ipq40xx/dts/qcom-ipq4018-utr.dts | 32 ++-
target/linux/ipq40xx/image/generic.mk | 2 +-
.../875-fb-st7789v-geometry.patch | 197 ------------------
4 files changed, 23 insertions(+), 208 deletions(-)
create mode 100644 target/linux/ipq40xx/base-files/lib/firmware/ubnt,utr-lcd.bin
delete mode 100644 target/linux/ipq40xx/patches-6.12/875-fb-st7789v-geometry.patch
diff --git a/target/linux/ipq40xx/base-files/lib/firmware/ubnt,utr-lcd.bin b/target/linux/ipq40xx/base-files/lib/firmware/ubnt,utr-lcd.bin
new file mode 100644
index 0000000000000000000000000000000000000000..252ab55287667c9c3d786483757b4bec24240491
GIT binary patch
literal 93
zcmebE4DeKNaq?t<07gLu2F402MpiS%1DjY`Ss9Ftw=<URW>h-F#Q6U(qwo<%g`<oL
n7nqhTe86{sm5Y;uRnNthUtCPv_#uq%?8+}DrfsaqpveFLtq2rB
literal 0
HcmV?d00001
diff --git a/target/linux/ipq40xx/dts/qcom-ipq4018-utr.dts b/target/linux/ipq40xx/dts/qcom-ipq4018-utr.dts
index 9cfb52e8ba..2297ed605e 100644
--- a/target/linux/ipq40xx/dts/qcom-ipq4018-utr.dts
+++ b/target/linux/ipq40xx/dts/qcom-ipq4018-utr.dts
@@ -15,10 +15,12 @@
};
chosen {
- bootargs-append = " ubi.mtd=kernel1 root=/dev/ubiblock0_1 rootfstype=squashfs";
+ stdout-path = "serial0:115200n8";
+ bootargs-append = " ubi.mtd=kernel1 root=/dev/ubiblock0_1 rootfstype=squashfs clk_ignore_unused";
};
aliases {
+ serial0 = &blsp1_uart1;
ethernet0 = &gmac;
};
@@ -234,18 +236,28 @@
};
display@2 {
- compatible = "sitronix,st7789v";
+ compatible = "ubnt,utr-lcd", "panel-mipi-dbi-spi";
reg = <2>;
spi-max-frequency = <24000000>;
- buswidth = <8>;
dc-gpios = <&tlmm 3 GPIO_ACTIVE_HIGH>;
- reset-gpios = <&tlmm 0 GPIO_ACTIVE_LOW>;
- backlight = <&backlight>;
- panel-width = <135>;
- panel-height = <240>;
- x-offset = <52>;
- y-offset = <39>;
- rotate = <180>;
+ reset-gpios = <&tlmm 0 GPIO_ACTIVE_HIGH>;
+ /*backlight = <&backlight>;*/
+ write-only;
+
+ width-mm = <14>;
+ height-mm = <25>;
+
+ panel-timing {
+ hactive = <136>;
+ vactive = <240>;
+ hback-porch = <53>;
+ vback-porch = <40>;
+ clock-frequency = <0>;
+ hfront-porch = <0>;
+ hsync-len = <0>;
+ vfront-porch = <0>;
+ vsync-len = <0>;
+ };
};
};
diff --git a/target/linux/ipq40xx/image/generic.mk b/target/linux/ipq40xx/image/generic.mk
index 9cbeea06bb..8fb049e069 100644
--- a/target/linux/ipq40xx/image/generic.mk
+++ b/target/linux/ipq40xx/image/generic.mk
@@ -1284,7 +1284,7 @@ define Device/ubnt_utr
PAGESIZE := 2048
KERNEL_IN_UBI :=
UBINIZE_PARTS = vol=$(KDIR)/ubnt_utr-uImage.itb
- DEVICE_PACKAGES := kmod-fb-tft-st7789v kmod-bluetooth kmod-btusb
+ DEVICE_PACKAGES := kmod-drm-panel-mipi-dbi kmod-gpio-backlight kmod-bluetooth kmod-btusb
endef
TARGET_DEVICES += ubnt_utr
diff --git a/target/linux/ipq40xx/patches-6.12/875-fb-st7789v-geometry.patch b/target/linux/ipq40xx/patches-6.12/875-fb-st7789v-geometry.patch
deleted file mode 100644
index 870ef04941..0000000000
--- a/target/linux/ipq40xx/patches-6.12/875-fb-st7789v-geometry.patch
+++ /dev/null
@@ -1,197 +0,0 @@
-From: Matt Eaton <linux@divinehawk.com>
-Subject: [PATCH] staging: fbtft: st7789v: add configurable panel geometry and offset
-
-Add device-tree-driven panel geometry and a fixed x/y offset for the
-addr-window. Pad xres_virtual up to a 32-bit boundary so fbcon's
-sys_imageblit slow path doesn't scatter glyph rows when the visible
-width isn't word-aligned at the framebuffer's bpp; trim each row back
-to the visible width before shipping pixels to the panel.
-
-Signed-off-by: Matt Eaton <linux@divinehawk.com>
----
- drivers/staging/fbtft/fb_st7789v.c | 146 ++++++++++++++++++++++
- 1 file changed, 126 insertions(+), 20 deletions(-)
-
---- a/drivers/staging/fbtft/fb_st7789v.c
-+++ b/drivers/staging/fbtft/fb_st7789v.c
-@@ -76,6 +76,102 @@
- static struct completion panel_te; /* completion for panel TE line */
- static int irq_te; /* Linux IRQ for LCD TE line */
-
-+struct st7789v_panel_cfg {
-+ u16 panel_width;
-+ u16 panel_height;
-+ u16 x_offset;
-+ u16 y_offset;
-+};
-+
-+static int st7789v_init_panel_cfg(struct fbtft_par *par)
-+{
-+ struct device *dev = par->info->device;
-+ struct st7789v_panel_cfg *cfg;
-+ u32 val;
-+
-+ cfg = devm_kzalloc(dev, sizeof(*cfg), GFP_KERNEL);
-+ if (!cfg)
-+ return -ENOMEM;
-+
-+ cfg->panel_width = 240;
-+ cfg->panel_height = 320;
-+ cfg->x_offset = 0;
-+ cfg->y_offset = 0;
-+
-+ if (!device_property_read_u32(dev, "panel-width", &val))
-+ cfg->panel_width = val;
-+ if (!device_property_read_u32(dev, "panel-height", &val))
-+ cfg->panel_height = val;
-+ if (!device_property_read_u32(dev, "x-offset", &val))
-+ cfg->x_offset = val;
-+ if (!device_property_read_u32(dev, "y-offset", &val))
-+ cfg->y_offset = val;
-+
-+ par->extra = cfg;
-+ return 0;
-+}
-+
-+static void st7789v_apply_panel_cfg(struct fbtft_par *par)
-+{
-+ struct st7789v_panel_cfg *cfg = par->extra;
-+ unsigned int bpp = par->info->var.bits_per_pixel;
-+ unsigned int xres_v;
-+
-+ /* Pad xres_virtual so line_length is 32-bit aligned: fbcon's
-+ * sys_imageblit slow path writes glyphs as u32 words and
-+ * assumes each row starts at the same alignment, so a
-+ * non-word-aligned stride scatters glyph rows horizontally.
-+ */
-+ xres_v = round_up(cfg->panel_width * bpp, 32) / bpp;
-+
-+ par->info->var.xres = cfg->panel_width;
-+ par->info->var.yres = cfg->panel_height;
-+ par->info->var.xres_virtual = xres_v;
-+ par->info->var.yres_virtual = cfg->panel_height;
-+ par->info->fix.line_length = xres_v * bpp / 8;
-+ par->info->fix.smem_len = par->info->fix.line_length *
-+ cfg->panel_height;
-+}
-+
-+static void set_addr_win(struct fbtft_par *par, int xs, int ys, int xe, int ye)
-+{
-+ struct st7789v_panel_cfg *cfg = par->extra;
-+
-+ /* MADCTL_MX/MY/MV reverse the *write order* within the addr
-+ * window; they don't translate the physical address mapping.
-+ * The window therefore always stays at the panel's natural
-+ * visible region regardless of rotation.
-+ */
-+ xs += cfg->x_offset; xe += cfg->x_offset;
-+ ys += cfg->y_offset; ye += cfg->y_offset;
-+
-+ write_reg(par, MIPI_DCS_SET_COLUMN_ADDRESS,
-+ (xs >> 8) & 0xff, xs & 0xff,
-+ (xe >> 8) & 0xff, xe & 0xff);
-+ write_reg(par, MIPI_DCS_SET_PAGE_ADDRESS,
-+ (ys >> 8) & 0xff, ys & 0xff,
-+ (ye >> 8) & 0xff, ye & 0xff);
-+ write_reg(par, MIPI_DCS_WRITE_MEMORY_START);
-+}
-+
-+static int write_vmem_bus(struct fbtft_par *par, size_t offset, size_t len)
-+{
-+ struct device *dev = par->info->device;
-+
-+ switch (par->pdata->display.buswidth) {
-+ case 8:
-+ return fbtft_write_vmem16_bus8(par, offset, len);
-+ case 9:
-+ return fbtft_write_vmem16_bus9(par, offset, len);
-+ case 16:
-+ return fbtft_write_vmem16_bus16(par, offset, len);
-+ default:
-+ dev_err(dev, "Unsupported buswidth %d\n",
-+ par->pdata->display.buswidth);
-+ return 0;
-+ }
-+}
-+
- static irqreturn_t panel_te_handler(int irq, void *data)
- {
- complete(&panel_te);
-@@ -214,6 +310,13 @@
- if (HSD20_IPS)
- write_reg(par, MIPI_DCS_ENTER_INVERT_MODE);
-
-+ if (!par->extra) {
-+ rc = st7789v_init_panel_cfg(par);
-+ if (rc)
-+ return rc;
-+ }
-+ st7789v_apply_panel_cfg(par);
-+
- return 0;
- }
-
-@@ -228,7 +331,9 @@
- static int write_vmem(struct fbtft_par *par, size_t offset, size_t len)
- {
- struct device *dev = par->info->device;
-- int ret;
-+ struct st7789v_panel_cfg *cfg = par->extra;
-+ size_t row_bytes, stride, sent;
-+ int ret = 0;
-
- if (irq_te) {
- enable_irq(irq_te);
-@@ -241,21 +346,21 @@
- disable_irq(irq_te);
- }
-
-- switch (par->pdata->display.buswidth) {
-- case 8:
-- ret = fbtft_write_vmem16_bus8(par, offset, len);
-- break;
-- case 9:
-- ret = fbtft_write_vmem16_bus9(par, offset, len);
-- break;
-- case 16:
-- ret = fbtft_write_vmem16_bus16(par, offset, len);
-- break;
-- default:
-- dev_err(dev, "Unsupported buswidth %d\n",
-- par->pdata->display.buswidth);
-- ret = 0;
-- break;
-+ stride = par->info->fix.line_length;
-+ row_bytes = cfg ? (size_t)cfg->panel_width *
-+ par->info->var.bits_per_pixel / 8 : stride;
-+
-+ if (row_bytes == stride)
-+ return write_vmem_bus(par, offset, len);
-+
-+ /* line_length is padded so sys_imageblit stays 32-bit aligned
-+ * across rows; ship only the visible portion of each row and
-+ * skip the trailing pad bytes.
-+ */
-+ for (sent = 0; sent < len; sent += stride) {
-+ ret = write_vmem_bus(par, offset + sent, row_bytes);
-+ if (ret < 0)
-+ return ret;
- }
-
- return ret;
-@@ -375,10 +480,11 @@
- .gamma = HSD20_IPS_GAMMA,
- .fbtftops = {
- .init_display = init_display,
-- .write_vmem = write_vmem,
-- .set_var = set_var,
-- .set_gamma = set_gamma,
-- .blank = blank,
-+ .write_vmem = write_vmem,
-+ .set_addr_win = set_addr_win,
-+ .set_var = set_var,
-+ .set_gamma = set_gamma,
-+ .blank = blank,
- },
- };
-
--
2.54.0
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment