чт, 2 лип. 2026 р. о 18:14 Advait Dhamorikar <[email protected]> пише: > > Add support for AMOLED panels based on the ChipWealth CH13726A > MIPI DSI display driver IC. > > The driver configures the MIPI DSI interface for 4 data lanes in RGB888 > video mode, performs the panel reset sequence, sends the vendor-specific > initialization commands required by the controller, and enables the > panel using the standard MIPI DCS Sleep Out and Display On commands. > > This driver is based on an earlier implementation by Pratham Malaviya. > > Signed-off-by: Advait Dhamorikar <[email protected]> > --- > > v1->v2 > - Expand CC list based on get_maintainer.pl output. > > drivers/video/Kconfig | 8 ++ > drivers/video/Makefile | 1 + > drivers/video/chipwealth-ch13726a.c | 193 ++++++++++++++++++++++++++++ > 3 files changed, 202 insertions(+) > create mode 100644 drivers/video/chipwealth-ch13726a.c >
Hey there! Thanks for your contribution, it is pretty solid but there are a few places that can be improved. > diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig > index c2acc13139c..7e82778e294 100644 > --- a/drivers/video/Kconfig > +++ b/drivers/video/Kconfig > @@ -533,6 +533,14 @@ config VIDEO_BCM2835 > that same resolution (or as near as possible) and 32bpp depth, so > that U-Boot can access it with full colour depth. > > +config VIDEO_AMOLED_CHIPWEALTH_CH13726A May you please rename AMOLED > PANEL > + bool "ChipWealth CH13726A AMOLED panel support" > + depends on VIDEO "depends on PANEL && BACKLIGHT" > + select VIDEO_MIPI_DSI > + help > + Say Y here if you want to enable support for AMOLED panels > + based on the ChipWealth CH13726A MIPI DSI display driver IC. > + > config VIDEO_LCD_ENDEAVORU > tristate "Endeavoru 720x1280 DSI video mode panel" > depends on PANEL && BACKLIGHT > diff --git a/drivers/video/Makefile b/drivers/video/Makefile > index 082b8967982..56df5e1860d 100644 > --- a/drivers/video/Makefile > +++ b/drivers/video/Makefile > @@ -55,6 +55,7 @@ obj-$(CONFIG_VIDEO_DW_HDMI) += dw_hdmi.o > obj-$(CONFIG_VIDEO_DW_MIPI_DSI) += dw_mipi_dsi.o > obj-$(CONFIG_VIDEO_EFI) += efi.o > obj-y += imx/ > +obj-$(CONFIG_VIDEO_AMOLED_CHIPWEALTH_CH13726A) += chipwealth-ch13726a.o > obj-$(CONFIG_VIDEO_IVYBRIDGE_IGD) += ivybridge_igd.o > obj-$(CONFIG_VIDEO_LCD_PANEL_EDP_4_LANE_1620M_VIA_ANX9804) += anx9804.o > obj-$(CONFIG_VIDEO_LCD_ENDEAVORU) += endeavoru-panel.o > diff --git a/drivers/video/chipwealth-ch13726a.c > b/drivers/video/chipwealth-ch13726a.c > new file mode 100644 > index 00000000000..e6fef6c8e7f > --- /dev/null > +++ b/drivers/video/chipwealth-ch13726a.c > @@ -0,0 +1,193 @@ > +// SPDX-License-Identifier: GPL-2.0+ > +/* > + * ChipWealth CH13726A DSI panel driver > + * > + * Copyright (C) 2026 Mecha Systems > + * Author(s): > + * Advait Dhamorikar <[email protected]> > + * Pratham Malaviya <[email protected]> > + */ > + > +#include <backlight.h> > +#include <dm.h> > +#include <mipi_dsi.h> > +#include <panel.h> > +#include <asm/gpio.h> > +#include <linux/delay.h> > +#include <log.h> > + > +struct ch13726a_panel_priv { > + struct udevice *reg; > + struct udevice *backlight; > + struct gpio_desc reset; > +}; You are lacking supplies here: vdd1v2, vddio, vdd and avdd U-Boot can handle them so you should include control over them. > + > +static const struct display_timing default_timing = { > + .pixelclock.typ = 59832000, > + .hactive.typ = 1080, > + .hfront_porch.typ = 12, > + .hback_porch.typ = 12, > + .hsync_len.typ = 28, > + .vactive.typ = 1240, > + .vfront_porch.typ = 2, > + .vback_porch.typ = 2, > + .vsync_len.typ = 2, > +}; > + > +static int ch13726a_dcs_write_buf(struct udevice *dev, const void *data, > + size_t len) > +{ > + struct mipi_dsi_panel_plat *plat = dev_get_plat(dev); > + int ret; > + > + ret = mipi_dsi_dcs_write_buffer(plat->device, data, len); > + if (ret < 0) > + log_err("failed to write dcs sequence: %d\n", ret); > + > + return ret; > +} > + > +#define dcs_write_seq(dev, cmd, seq...) \ > +({ \ > + const u8 d[] = { cmd, seq }; \ > + \ > + ch13726a_dcs_write_buf(dev, d, ARRAY_SIZE(d)); \ > +}) > + You can fold this. > +static void ch13726a_reset(struct udevice *dev) > +{ > + struct ch13726a_panel_priv *priv = dev_get_priv(dev); > + > + dm_gpio_set_value(&priv->reset, true); > + mdelay(10); > + dm_gpio_set_value(&priv->reset, false); > + mdelay(10); > + dm_gpio_set_value(&priv->reset, true); > + mdelay(5); > +} > + > +static int ch13726a_set_backlight(struct udevice *dev, int percent) > +{ > + struct mipi_dsi_panel_plat *plat = dev_get_plat(dev); > + struct mipi_dsi_device *device = plat->device; > + u8 brightness; > + > + if (percent < 0) > + percent = 0; > + else if (percent > 100) > + percent = 100; > + > + brightness = (percent * 255) / 100; > + > + return mipi_dsi_dcs_set_display_brightness(device, brightness); > +} > + > +static int ch13726a_panel_enable_backlight(struct udevice *dev) > +{ > + struct mipi_dsi_panel_plat *plat = dev_get_plat(dev); > + struct mipi_dsi_device *device = plat->device; > + int ret; > + > + device->lanes = plat->lanes; > + device->format = plat->format; > + device->mode_flags = plat->mode_flags; > + You don't need this assignment. > + ret = mipi_dsi_attach(device); > + if (ret < 0) > + return ret; > + > + ch13726a_reset(dev); > + > + device->mode_flags |= MIPI_DSI_MODE_LPM; > + LPM flag is removed by mipi_dsi_device_transfer so you don't need it here. > + ret = dcs_write_seq(dev, 0x53, 0x00); > + if (ret < 0) { > + log_debug("%s: Init command failed(%d)\n", > + __func__, ret); > + return ret; > + } > + > + ret = dcs_write_seq(dev, 0x17, 0x00); > + if (ret < 0) { > + log_debug("%s: Init command failed (%d)\n", > + __func__, ret); > + return ret; > + } > + > + ret = dcs_write_seq(dev, 0x41, 0x00); > + if (ret < 0) { > + log_debug("%s: Init command failed (%d)\n", > + __func__, ret); > + return ret; > + } > + > + ret = mipi_dsi_dcs_exit_sleep_mode(device); > + if (ret) > + return ret; > + > + mdelay(120); > + > + ret = mipi_dsi_dcs_set_display_on(device); > + if (ret) > + return ret; > + > + return 0; > +} > + > +static int ch13726a_panel_get_display_timing(struct udevice *dev, > + struct display_timing *timings) > +{ > + memcpy(timings, &default_timing, sizeof(*timings)); > + return 0; > +} > + > +static int ch13726a_panel_of_to_plat(struct udevice *dev) > +{ > + struct ch13726a_panel_priv *priv = dev_get_priv(dev); > + int ret; > + > + ret = gpio_request_by_name(dev, "reset-gpios", 0, > + &priv->reset, > + GPIOD_IS_OUT); > + if (ret) { > + log_err("%s: cannot get reset GPIO (%d)\n", > + __func__, ret); > + return ret; > + } > + > + return 0; > +} > + > +static int ch13726a_panel_probe(struct udevice *dev) > +{ > + struct mipi_dsi_panel_plat *plat = dev_get_plat(dev); > + > + plat->lanes = 4; > + plat->format = MIPI_DSI_FMT_RGB888; > + plat->mode_flags = MIPI_DSI_MODE_VIDEO | > + MIPI_DSI_MODE_VIDEO_BURST; > + > + return 0; > +} > + > +static const struct panel_ops ch13726a_panel_ops = { > + .enable_backlight = ch13726a_panel_enable_backlight, > + .set_backlight = ch13726a_set_backlight, > + .get_display_timing = ch13726a_panel_get_display_timing, > +}; > + > +static const struct udevice_id ch13726a_panel_ids[] = { > + { .compatible = "chipwealth,ch13726a" }, > + { } > +}; > + > +U_BOOT_DRIVER(ch13726a_panel) = { > + .name = "ch13726a_panel", > + .id = UCLASS_PANEL, > + .of_match = ch13726a_panel_ids, > + .ops = &ch13726a_panel_ops, > + .of_to_plat = ch13726a_panel_of_to_plat, > + .probe = ch13726a_panel_probe, > + .plat_auto = sizeof(struct mipi_dsi_panel_plat), > + .priv_auto = sizeof(struct ch13726a_panel_priv), > +}; > -- > 2.43.0 >

