Re: [PATCH v3 1/4] drm: panel: Add LG LH609QH1 Panel with SW49410 controller

Neil Armstrong <[email protected]>
Newsgroups org.kernel.vger.phone-devel,org.freedesktop.lists.dri-devel,org.kernel.vger.linux-devicetree,org.kernel.vger.linux-kernel
Organization Linaro
Message-ID <[email protected]>
On 6/15/26 02:07, Paul Sajna wrote:
> From: Amir Dahan <[email protected]>
> 
> Add panel driver used by LG G7 ThinQ (judyln)
> 
> Signed-off-by: Amir Dahan <[email protected]>
> Co-developed-by: Paul Sajna <[email protected]>
> Signed-off-by: Paul Sajna <[email protected]>
> ---
>   drivers/gpu/drm/panel/Kconfig            |  15 +
>   drivers/gpu/drm/panel/Makefile           |   1 +
>   drivers/gpu/drm/panel/panel-lg-sw49410.c | 528 +++++++++++++++++++++++++++++++
>   3 files changed, 544 insertions(+)
> 
> diff --git a/drivers/gpu/drm/panel/Kconfig b/drivers/gpu/drm/panel/Kconfig
> index 7450b27622a2..ecf6a45224d3 100644
> --- a/drivers/gpu/drm/panel/Kconfig
> +++ b/drivers/gpu/drm/panel/Kconfig
> @@ -498,6 +498,21 @@ config DRM_PANEL_LG_SW43408
>   	  pixel. It provides a MIPI DSI interface to the host and has a
>   	  built-in LED backlight.
>   
> +config DRM_PANEL_LG_SW49410
> +	tristate "LG SW49410 panel"
> +	depends on OF
> +	depends on DRM_MIPI_DSI
> +	depends on BACKLIGHT_CLASS_DEVICE
> +	select DRM_DISPLAY_DSC_HELPER
> +	select DRM_DISPLAY_HELPER
> +	help
> +	  Say Y here if you want to enable support for LG/SiliconWorks SW49410 controller
> +	  (found in LG G7 ThinQ).
> +	  The LH609QH1 panel has a 1440x3120@60Hz resolution and uses 24 bit RGB per
> +	  pixel. It provides a MIPI DSI interface to the host and has a
> +	  built-in LED backlight.
> +	  To compile this driver as a module, choose M here.
> +
>   config DRM_PANEL_LXD_M9189A
>   	tristate "LXD M9189A MIPI-DSI LCD panel"
>   	depends on OF
> diff --git a/drivers/gpu/drm/panel/Makefile b/drivers/gpu/drm/panel/Makefile
> index c2c5cf817116..153970480269 100644
> --- a/drivers/gpu/drm/panel/Makefile
> +++ b/drivers/gpu/drm/panel/Makefile
> @@ -49,6 +49,7 @@ obj-$(CONFIG_DRM_PANEL_LG_LB035Q02) += panel-lg-lb035q02.o
>   obj-$(CONFIG_DRM_PANEL_LG_LD070WX3) += panel-lg-ld070wx3.o
>   obj-$(CONFIG_DRM_PANEL_LG_LG4573) += panel-lg-lg4573.o
>   obj-$(CONFIG_DRM_PANEL_LG_SW43408) += panel-lg-sw43408.o
> +obj-$(CONFIG_DRM_PANEL_LG_SW49410) += panel-lg-sw49410.o
>   obj-$(CONFIG_DRM_PANEL_LXD_M9189A) += panel-lxd-m9189a.o
>   obj-$(CONFIG_DRM_PANEL_MAGNACHIP_D53E6EA8966) += panel-magnachip-d53e6ea8966.o
>   obj-$(CONFIG_DRM_PANEL_MOTOROLA_MOT) += panel-motorola-mot.o
> diff --git a/drivers/gpu/drm/panel/panel-lg-sw49410.c b/drivers/gpu/drm/panel/panel-lg-sw49410.c
> new file mode 100644
> index 000000000000..02d1b85c3aff
> --- /dev/null
> +++ b/drivers/gpu/drm/panel/panel-lg-sw49410.c
> @@ -0,0 +1,528 @@
> +// SPDX-License-Identifier: GPL-2.0+
> +// Generated with linux-mdss-dsi-panel-driver-generator from vendor device tree:
> +// Copyright (c) 2025, The Linux Foundation. All rights reserved.
> +
> +#include <linux/backlight.h>
> +#include <linux/delay.h>
> +#include <linux/gpio/consumer.h>
> +#include <linux/module.h>
> +#include <linux/of.h>
> +#include <linux/regulator/consumer.h>
> +
> +#include <video/mipi_display.h>
> +
> +#include <drm/drm_mipi_dsi.h>
> +#include <drm/drm_panel.h>
> +#include <drm/drm_probe_helper.h>
> +#include <drm/display/drm_dsc.h>
> +#include <drm/display/drm_dsc_helper.h>
> +
> +static const struct regulator_bulk_data sw49410_supplies[] = {
> +	{ .supply = "vsp"},
> +	{ .supply = "vsn"},
> +};
> +
> +
Spurious empty line

> +struct sw49410_panel {
> +	struct drm_panel panel;
> +	struct mipi_dsi_device *dsi;
> +	struct drm_dsc_config dsc;
> +
> +	struct regulator_bulk_data *supplies;
> +
> +	struct gpio_desc *reset_gpio;
> +};
> +
> +static inline
> +struct sw49410_panel *to_sw49410_panel(struct drm_panel *panel)
> +{
> +	return container_of(panel, struct sw49410_panel, panel);
> +}
> +
> +static void sw49410_panel_reset(struct sw49410_panel *ctx)
> +{
> +	gpiod_set_value(ctx->reset_gpio, 0);
> +	usleep_range(9000, 10000);
> +	gpiod_set_value(ctx->reset_gpio, 1);
> +	usleep_range(1000, 2000);
> +	gpiod_set_value(ctx->reset_gpio, 0);
> +	usleep_range(9000, 10000);
> +}
> +
> +static int sw49410_panel_program(struct sw49410_panel *ctx)
> +{
> +	struct mipi_dsi_multi_context dsi_ctx = { .dsi = ctx->dsi };
> +	struct drm_dsc_picture_parameter_set pps;
> +
> +

Spurious empty line

> +	mipi_dsi_dcs_set_tear_on_multi(&dsi_ctx, MIPI_DSI_DCS_TEAR_MODE_VBLANK);
> +	mipi_dsi_dcs_set_page_address_multi(&dsi_ctx, 0x0000, 0x0c2f);
> +	mipi_dsi_dcs_set_display_brightness_multi(&dsi_ctx, 0x00ff);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, MIPI_DCS_WRITE_CONTROL_DISPLAY,
> +				     0x2c);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, MIPI_DCS_SET_CABC_MIN_BRIGHTNESS,
> +				     0x00);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, MIPI_DCS_WRITE_POWER_SAVE, 0x81);
> +
> +	/* Manufacturer protection */
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xb0, 0xac);
> +
> +	/* Source Control */
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xb3,
> +				     0x04, 0x04, 0x28, 0x08, 0x5a, 0x12, 0x23,
> +				     0x02);
> +
> +	/* Gate & Mux Control */
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xb4,
> +				     0x11, 0x04, 0x02, 0x02, 0x02, 0x02, 0x02,
> +				     0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0xd0,
> +				     0xe4, 0xe4, 0xe4, 0x93, 0x4e, 0x39, 0x0a,
> +				     0x10, 0x18, 0x25, 0x24, 0x00, 0x00, 0x00,
> +				     0x00, 0x00, 0x00);
> +
> +	/* Sync Setup */
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xb5,
> +				     0x2e, 0x0f, 0x10, 0xc0, 0x00, 0x10, 0xc0,
> +				     0x00);
> +
> +	/* Panel Setting */
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xb6,
> +				     0x03, 0x05, 0x0b, 0xb3, 0x30);
> +
> +	/* Touch Timing Control */
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xb8,
> +				     0x57, 0x02, 0x90, 0x40, 0x5d, 0xd0, 0x05,
> +				     0x00, 0x00, 0x18, 0x22, 0x04, 0x01, 0x02,
> +				     0x90, 0x40, 0x4c, 0xc0, 0x04, 0x00, 0x00,
> +				     0x18, 0x22, 0x04, 0x01, 0x08, 0x00, 0x3a,
> +				     0x86, 0x83, 0x00);
> +
> +	/* Touch Source Setting */
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xb9,
> +				     0x64, 0x64, 0x2a, 0x3f, 0xee);
> +
> +	/* DSC Configuration */
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xba,
> +				     0x3d, 0x1f, 0x01, 0xff, 0x01, 0x3c, 0x1f,
> +				     0x01, 0xff, 0x01, 0x00);
> +
> +	/* Low Rate Refresh Setting */
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xbc, 0x00, 0x00, 0x00, 0x90);
> +
> +	/* Black Frame Setting */
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xbd, 0x00, 0x00);
> +
> +	/* U2 Corner Down */
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xbf, 0x4f, 0x02);
> +
> +	/* Internal Oscillator Setting */
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xc0,
> +				     0x00, 0x04, 0x18, 0x07, 0x11, 0x11, 0x3c,
> +				     0x00, 0x0a, 0x0a);
> +
> +	/* Power Control1 */
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xc1,
> +				     0x01, 0x00, 0xf0, 0xc2, 0xcf, 0x0c);
> +
> +	/* Power Control2 */
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xc2,
> +				     0xcc, 0x44, 0x44, 0x20, 0x22, 0x26, 0x21,
> +				     0x00);
> +
> +	/* Power Control3 */
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xc3,
> +				     0x92, 0x11, 0x09, 0x09, 0x11, 0xcc, 0x02,
> +				     0x02, 0xa4, 0xa4, 0x02, 0xa2, 0x38, 0x28,
> +				     0x14, 0x40, 0x38, 0xc0);
> +
> +	/* Vcom Setting */
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xc4, 0x26, 0x00);
> +
> +	/* Power Sequence Option Configuration */
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xc9,
> +				     0x05, 0x5d, 0x03, 0x04, 0x00);
> +
> +	/* Abrupt Power Off Control */
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xca, 0x9b, 0x10);
> +
> +	/* LFD Control */
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xcb,
> +				     0xf3, 0x90, 0x3d, 0x30, 0xcc);
> +
> +	/* Tail TFT Setting */
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xcc,
> +				     0x00, 0x40, 0x50, 0x90, 0x41);
> +
> +	/* U2 Option */
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xce, 0x00, 0x00);
> +
> +	/* Gamma */
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xd0,
> +				     0x12, 0x05, 0x20, 0x1b, 0x2c, 0x28, 0x3f,
> +				     0x3d, 0x4f, 0x4f, 0x66, 0x66, 0x6e, 0x6e,
> +				     0x76, 0x76, 0x80, 0x80, 0x88, 0x88, 0x95,
> +				     0x95, 0x3f, 0x3f, 0xa2, 0xa2, 0x94, 0x94,
> +				     0x8b, 0x8b, 0x81, 0x81, 0x75, 0x75, 0x66,
> +				     0x66, 0x47, 0x47, 0x2d, 0x2d, 0x00, 0x01,
> +				     0x12, 0x05, 0x20, 0x1b, 0x2c, 0x28, 0x3f,
> +				     0x3d, 0x4f, 0x4f, 0x66, 0x66, 0x6e, 0x6e,
> +				     0x76, 0x76, 0x80, 0x80, 0x88, 0x88, 0x95,
> +				     0x95, 0x3f, 0x3f, 0xa2, 0xa2, 0x94, 0x94,
> +				     0x8b, 0x8b, 0x81, 0x81, 0x75, 0x75, 0x66,
> +				     0x66, 0x47, 0x47, 0x2d, 0x2d, 0x00, 0x01,
> +				     0x12, 0x05, 0x20, 0x1b, 0x2c, 0x28, 0x3f,
> +				     0x3d, 0x4f, 0x4f, 0x66, 0x66, 0x6e, 0x6e,
> +				     0x76, 0x76, 0x80, 0x80, 0x88, 0x88, 0x95,
> +				     0x95, 0x3f, 0x3f, 0xa2, 0xa2, 0x94, 0x94,
> +				     0x8b, 0x8b, 0x81, 0x81, 0x75, 0x75, 0x66,
> +				     0x66, 0x47, 0x47, 0x2d, 0x2d, 0x00, 0x01,
> +				     0x12, 0x05, 0x20, 0x1b, 0x2c, 0x28, 0x3f,
> +				     0x3d, 0x4f, 0x4f, 0x66, 0x66, 0x6e, 0x6e,
> +				     0x76, 0x76, 0x80, 0x80, 0x88, 0x88, 0x94,
> +				     0x94, 0x3f, 0x3f, 0xa4, 0xa4, 0x95, 0x95,
> +				     0x8b, 0x8b, 0x81, 0x81, 0x75, 0x75, 0x66,
> +				     0x66, 0x47, 0x47, 0x2d, 0x2d, 0x00, 0x01);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xd1,
> +				     0x12, 0x05, 0x20, 0x1b, 0x2e, 0x29, 0x41,
> +				     0x3f, 0x52, 0x52, 0x6a, 0x6a, 0x72, 0x72,
> +				     0x7a, 0x7a, 0x84, 0x84, 0x8c, 0x8c, 0x9a,
> +				     0x9a, 0x3f, 0x3f, 0x9b, 0x9b, 0x8d, 0x8d,
> +				     0x84, 0x84, 0x7a, 0x7a, 0x6e, 0x6e, 0x5f,
> +				     0x5f, 0x41, 0x41, 0x2a, 0x2a, 0x00, 0x01,
> +				     0x12, 0x05, 0x20, 0x1b, 0x2e, 0x29, 0x41,
> +				     0x3f, 0x52, 0x52, 0x6a, 0x6a, 0x72, 0x72,
> +				     0x7a, 0x7a, 0x84, 0x84, 0x8c, 0x8c, 0x9a,
> +				     0x9a, 0x3f, 0x3f, 0x9b, 0x9b, 0x8d, 0x8d,
> +				     0x84, 0x84, 0x7a, 0x7a, 0x6e, 0x6e, 0x5f,
> +				     0x5f, 0x41, 0x41, 0x2a, 0x2a, 0x00, 0x01,
> +				     0x12, 0x05, 0x20, 0x1b, 0x2e, 0x29, 0x41,
> +				     0x3f, 0x52, 0x52, 0x6a, 0x6a, 0x72, 0x72,
> +				     0x7a, 0x7a, 0x84, 0x84, 0x8c, 0x8c, 0x9a,
> +				     0x9a, 0x3f, 0x3f, 0x9b, 0x9b, 0x8d, 0x8d,
> +				     0x84, 0x84, 0x7a, 0x7a, 0x6e, 0x6e, 0x5f,
> +				     0x5f, 0x41, 0x41, 0x2a, 0x2a, 0x00, 0x01,
> +				     0x12, 0x05, 0x20, 0x1b, 0x2e, 0x29, 0x41,
> +				     0x3f, 0x52, 0x52, 0x6a, 0x6a, 0x72, 0x72,
> +				     0x7a, 0x7a, 0x84, 0x84, 0x8c, 0x8c, 0x9a,
> +				     0x9a, 0x3f, 0x3f, 0x9b, 0x9b, 0x8d, 0x8d,
> +				     0x84, 0x84, 0x7a, 0x7a, 0x6e, 0x6e, 0x5f,
> +				     0x5f, 0x41, 0x41, 0x2a, 0x2a, 0x00, 0x01);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xd2,
> +				     0x12, 0x05, 0x20, 0x1b, 0x2f, 0x2a, 0x43,
> +				     0x41, 0x55, 0x55, 0x6e, 0x6e, 0x76, 0x76,
> +				     0x7e, 0x7e, 0x88, 0x88, 0x90, 0x90, 0x9f,
> +				     0x9f, 0x3f, 0x3f, 0x95, 0x95, 0x86, 0x86,
> +				     0x7d, 0x7d, 0x74, 0x74, 0x68, 0x68, 0x59,
> +				     0x59, 0x3c, 0x3c, 0x26, 0x26, 0x00, 0x01,
> +				     0x12, 0x05, 0x20, 0x1b, 0x2f, 0x2a, 0x43,
> +				     0x41, 0x55, 0x55, 0x6e, 0x6e, 0x76, 0x76,
> +				     0x7e, 0x7e, 0x88, 0x88, 0x90, 0x90, 0x9f,
> +				     0x9f, 0x3f, 0x3f, 0x95, 0x95, 0x86, 0x86,
> +				     0x7d, 0x7d, 0x74, 0x74, 0x68, 0x68, 0x59,
> +				     0x59, 0x3c, 0x3c, 0x26, 0x26, 0x00, 0x01,
> +				     0x12, 0x05, 0x20, 0x1b, 0x2f, 0x2a, 0x43,
> +				     0x41, 0x55, 0x55, 0x6e, 0x6e, 0x76, 0x76,
> +				     0x7e, 0x7e, 0x88, 0x88, 0x90, 0x90, 0x9f,
> +				     0x9f, 0x3f, 0x3f, 0x95, 0x95, 0x86, 0x86,
> +				     0x7d, 0x7d, 0x74, 0x74, 0x68, 0x68, 0x59,
> +				     0x59, 0x3c, 0x3c, 0x26, 0x26, 0x00, 0x01,
> +				     0x12, 0x05, 0x20, 0x1b, 0x2f, 0x2a, 0x43,
> +				     0x41, 0x55, 0x55, 0x6e, 0x6e, 0x76, 0x76,
> +				     0x7e, 0x7e, 0x88, 0x88, 0x90, 0x90, 0x9f,
> +				     0x9f, 0x3f, 0x3f, 0x95, 0x95, 0x86, 0x86,
> +				     0x7d, 0x7d, 0x74, 0x74, 0x68, 0x68, 0x59,
> +				     0x59, 0x3c, 0x3c, 0x26, 0x26, 0x00, 0x01);
> +
> +	/* MPLUS Control */
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xd3, 0x12, 0x01, 0x00, 0x00);
> +
> +	/* MPLUS Setting */
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xd4,
> +				     0xdc, 0x5f, 0x9c, 0xbe, 0x39, 0x39, 0x39,
> +				     0x47, 0x48, 0x48, 0x48, 0x3a, 0x00, 0x03,
> +				     0x6d, 0x80, 0x00, 0x00, 0x8c, 0x66, 0x00,
> +				     0x00, 0x8c, 0x66, 0x00, 0x00, 0x8c, 0x66,
> +				     0x00, 0x0a, 0x48, 0x80, 0x00, 0x0a, 0x48,
> +				     0x80, 0x00, 0x0a, 0x48, 0x80, 0x00, 0x0a,
> +				     0x48, 0x80, 0x20, 0x0a, 0x14, 0x0a, 0x18,
> +				     0x00, 0x1c, 0xcc, 0x23, 0x9e, 0x23, 0x9e,
> +				     0x01, 0x01, 0x01, 0x01, 0x04, 0x04, 0x04,
> +				     0x04, 0x01, 0x00, 0x02, 0x80, 0x00, 0x10,
> +				     0x00, 0x10, 0x00, 0x10, 0x13, 0x9e, 0x13,
> +				     0x9e, 0x13, 0x9e, 0x13, 0x9e, 0x05, 0x05,
> +				     0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x23,
> +				     0x9e, 0xff, 0xff, 0x13, 0x33, 0x18, 0x00,
> +				     0x16, 0x66, 0x10, 0x00, 0xff, 0x01, 0x00,
> +				     0x02, 0x00, 0x03, 0x00, 0x04, 0x00, 0x05,
> +				     0x00, 0x06, 0x00, 0x07, 0x00, 0x08, 0x00,
> +				     0x09, 0x00, 0x0a, 0x00, 0x0b, 0x00, 0x0c,
> +				     0x00, 0x0d, 0x00, 0x0e, 0x00, 0x0f, 0x00,
> +				     0x1b, 0x25, 0xdc, 0x18, 0x00, 0x20, 0x00,
> +				     0x1c, 0xe1, 0x00, 0xff, 0xe0, 0xc8, 0xc8,
> +				     0x41, 0x8f);
> +
> +	/* Notch Up Gradation */
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xad,
> +				     0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x06,
> +				     0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06,
> +				     0x06, 0x06, 0x20, 0x40, 0x60, 0x90, 0xc0,
> +				     0xf0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
> +				     0xff, 0xff, 0xff, 0xff);
> +
> +	/* Notch Down Gradation */
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xae,
> +				     0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x06,
> +				     0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06,
> +				     0x06, 0x06, 0x20, 0x40, 0x60, 0x90, 0xc0,
> +				     0xf0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
> +				     0xff, 0xff, 0xff, 0xff);
> +
> +	/* GIP Setting */
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xe5,
> +				     0x0b, 0x0a, 0x0c, 0x00, 0x02, 0x04, 0x06,
> +				     0x08, 0x0f, 0x1b, 0x02, 0x1a, 0x1a, 0x0b,
> +				     0x0a, 0x0c, 0x01, 0x03, 0x05, 0x07, 0x09,
> +				     0x10, 0x1b, 0x03, 0x1a, 0x1a);
> +
> +	/* Mux Setting */
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xe6,
> +				     0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
> +				     0x18, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16,
> +				     0x17, 0x18);
> +
> +	/* Test1 */
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xed,
> +				     0x21, 0x49, 0x00, 0x00, 0x00, 0x00);
> +
> +	/* BLU Control */
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, MIPI_DCS_WRITE_POWER_SAVE, 0x81);
> +
> +	/* Sharpness */
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xf3,
> +				     0x00, 0x01, 0x00, 0x0d, 0x00);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xf4,
> +				     0x00, 0x00, 0x40, 0x83, 0xc5, 0x00, 0x01,
> +				     0x00, 0x00, 0x00, 0x00, 0x00, 0x00);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xfb,
> +				     0x20, 0x40, 0x60, 0x80, 0xa0, 0xc0, 0xe0,
> +				     0x13, 0x18, 0x18, 0x18, 0x16, 0x0d, 0x0d,
> +				     0x00, 0xc7, 0xcf, 0xd8, 0xe1, 0xea, 0xf3,
> +				     0xf9, 0xff);
> +
> +	/* Gamma Correction */
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xf5, 0x00);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xf6,
> +				     0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
> +				     0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
> +				     0x00, 0x00);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xf7,
> +				     0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
> +				     0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
> +				     0x00, 0x00);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xf8,
> +				     0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
> +				     0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
> +				     0x00, 0x00);
> +
> +	/* BLU PWM Control */
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xfc,
> +				     0x13, 0x70, 0xd0, 0x26, 0x30, 0x7c, 0x02,
> +				     0xff, 0x12, 0x22, 0x22, 0x10, 0x00);
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, MIPI_DCS_ENTER_NORMAL_MODE);
> +	mipi_dsi_dcs_exit_sleep_mode_multi(&dsi_ctx);
> +	mipi_dsi_msleep(&dsi_ctx, 135);
> +
> +	/* Black frame setting */
> +	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xbd, 0x01, 0x05);
> +
> +	mipi_dsi_dcs_set_display_on_multi(&dsi_ctx);
> +	mipi_dsi_msleep(&dsi_ctx, 50);
> +
> +	ctx->dsi->mode_flags &= ~MIPI_DSI_MODE_LPM;
> +
> +	drm_dsc_pps_payload_pack(&pps, &ctx->dsc);
> +
> +	ctx->dsi->mode_flags |= MIPI_DSI_MODE_LPM;
> +
> +	mipi_dsi_picture_parameter_set_multi(&dsi_ctx, &pps);
> +
> +	mipi_dsi_compression_mode_ext_multi(&dsi_ctx, true, MIPI_DSI_COMPRESSION_DSC, 1);
> +
> +	return dsi_ctx.accum_err;
> +}
> +
> +static int sw49410_panel_disable(struct drm_panel *panel)
> +{
> +	struct sw49410_panel *ctx = to_sw49410_panel(panel);
> +	struct mipi_dsi_multi_context dsi_ctx = { .dsi = ctx->dsi };
> +
> +	ctx->dsi->mode_flags &= ~MIPI_DSI_MODE_LPM;
> +
> +	mipi_dsi_dcs_set_display_off_multi(&dsi_ctx);
> +	mipi_dsi_dcs_enter_sleep_mode_multi(&dsi_ctx);
> +	mipi_dsi_msleep(&dsi_ctx, 128);
> +
> +	return dsi_ctx.accum_err;
> +}
> +
> +static int sw49410_panel_prepare(struct drm_panel *panel)
> +{
> +	struct sw49410_panel *ctx = to_sw49410_panel(panel);
> +	int ret;
> +
> +	ret = regulator_bulk_enable(ARRAY_SIZE(sw49410_supplies), ctx->supplies);
> +	if (ret < 0)
> +		return ret;
> +
> +	usleep_range(5000, 6000);
> +
> +	sw49410_panel_reset(ctx);
> +
> +	ret = sw49410_panel_program(ctx);
> +	if (ret)
> +		goto poweroff;
> +
> +	return 0;
> +
> +poweroff:
> +	gpiod_set_value(ctx->reset_gpio, 1);
> +	regulator_bulk_disable(ARRAY_SIZE(sw49410_supplies), ctx->supplies);
> +	return ret;
> +}
> +
> +static int sw49410_panel_unprepare(struct drm_panel *panel)
> +{
> +	struct sw49410_panel *ctx = to_sw49410_panel(panel);
> +
> +	gpiod_set_value(ctx->reset_gpio, 1);
> +	struct mipi_dsi_multi_context dsi_ctx = { .dsi = ctx->dsi };
> +
> +	mipi_dsi_dcs_set_display_off_multi(&dsi_ctx);
> +	mipi_dsi_dcs_enter_sleep_mode_multi(&dsi_ctx);
> +	mipi_dsi_msleep(&dsi_ctx, 100);
> +
> +	gpiod_set_value(ctx->reset_gpio, 1);
> +
> +	regulator_bulk_disable(ARRAY_SIZE(sw49410_supplies), ctx->supplies);
> +
> +	return dsi_ctx.accum_err;
> +}
> +
> +static const struct drm_display_mode sw49410_panel_mode = {
> +	.clock = (1440 + 168 + 4 + 84) * (3120 + 2 + 18 + 18) * 60 / 1000,
> +	.hdisplay = 1440,
> +	.hsync_start = 1440 + 168,
> +	.hsync_end = 1440 + 168 + 4,
> +	.htotal = 1440 + 168 + 4 + 84,
> +	.vdisplay = 3120,
> +	.vsync_start = 3120 + 2,
> +	.vsync_end = 3120 + 2 + 18,
> +	.vtotal = 3120 + 2 + 18 + 18,
> +	.width_mm = 65,
> +	.height_mm = 140,
> +	.type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED,
> +};
> +
> +static int sw49410_panel_get_modes(struct drm_panel *panel, struct drm_connector *connector)
> +{
> +	return drm_connector_helper_get_modes_fixed(connector, &sw49410_panel_mode);
> +}
> +
> +static const struct drm_panel_funcs sw49410_panel_funcs = {
> +	.disable = sw49410_panel_disable,
> +	.prepare = sw49410_panel_prepare,
> +	.unprepare = sw49410_panel_unprepare,
> +	.get_modes = sw49410_panel_get_modes,
> +};
> +
> +static int sw49410_panel_probe(struct mipi_dsi_device *dsi)
> +{
> +	struct device *dev = &dsi->dev;
> +	struct sw49410_panel *ctx;
> +	int ret;
> +
> +	ctx = devm_drm_panel_alloc(&dsi->dev, __typeof(*ctx), panel,
> +				   &sw49410_panel_funcs, DRM_MODE_CONNECTOR_DSI);
> +

Spurious empty line

> +	if (IS_ERR(ctx))
> +		return PTR_ERR(ctx);
> +
> +	ret = devm_regulator_bulk_get_const(dev, ARRAY_SIZE(sw49410_supplies),
> +		sw49410_supplies,
> +		&ctx->supplies
> +	);

Alignment is wrong, it should be:

ret = devm_regulator_bulk_get_const(dev, ARRAY_SIZE(sw49410_supplies),
				    sw49410_supplies, &ctx->supplies);

> +

Spurious empty line

> +	if (ret < 0)
> +		return dev_err_probe(dev, ret, "Failed to get regulators\n");
> +
> +	ctx->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_HIGH);
> +	if (IS_ERR(ctx->reset_gpio))
> +		return dev_err_probe(dev, PTR_ERR(ctx->reset_gpio),
> +				     "Failed to get reset-gpios\n");
> +
> +	ctx->dsi = dsi;
> +	mipi_dsi_set_drvdata(dsi, ctx);
> +
> +	dsi->lanes = 4;
> +	dsi->format = MIPI_DSI_FMT_RGB888;
> +	dsi->mode_flags = MIPI_DSI_MODE_VIDEO_BURST |
> +			  MIPI_DSI_CLOCK_NON_CONTINUOUS;
> +
> +	ctx->panel.prepare_prev_first = true;
> +
> +	ret = drm_panel_of_backlight(&ctx->panel);
> +	if (ret)
> +		return dev_err_probe(dev, ret, "Failed to get backlight\n");
> +
> +	drm_panel_add(&ctx->panel);

Use the devm variant

> +
> +	/* This panel only supports DSC; unconditionally enable it */
> +	dsi->dsc = &ctx->dsc;
> +
> +	ctx->dsc.dsc_version_major = 1;
> +	ctx->dsc.dsc_version_minor = 1;
> +
> +	ctx->dsc.slice_height = 60;
> +	ctx->dsc.slice_width = 720;
> +
> +	WARN_ON(1440 % ctx->dsc.slice_width);
> +	ctx->dsc.slice_count = 1440 / ctx->dsc.slice_width;
> +	ctx->dsc.bits_per_component = 8;
> +	ctx->dsc.bits_per_pixel = 8 << 4; /* 4 fractional bits */
> +	ctx->dsc.block_pred_enable = true;
> +
> +	return mipi_dsi_attach(dsi);

Use the devm variant

> +}
> +
> +static void sw49410_panel_remove(struct mipi_dsi_device *dsi)
> +{
> +	struct sw49410_panel *ctx = mipi_dsi_get_drvdata(dsi);
> +	int ret;
> +
> +	ret = mipi_dsi_detach(dsi);
> +	if (ret < 0)
> +		dev_err(&dsi->dev, "Failed to detach from DSI host: %d\n", ret);
> +
> +	drm_panel_remove(&ctx->panel);
> +}

Drop the remove after switching to the devm_ variants.

> +
> +static const struct of_device_id sw49410_of_match[] = {
> +	{ .compatible = "lg,sw49410" },
> +	{ .compatible = "lg,sw49410-lh609qh1" },
> +	{ /* sentinel */ }
> +};
> +MODULE_DEVICE_TABLE(of, sw49410_of_match);
> +
> +static struct mipi_dsi_driver sw49410_panel_driver = {
> +	.driver = {
> +		.name = "panel-lg-sw49410",
> +		.of_match_table = sw49410_of_match,
> +	},
> +	.probe = sw49410_panel_probe,
> +	.remove = sw49410_panel_remove,
> +};
> +module_mipi_dsi_driver(sw49410_panel_driver);
> +
> +MODULE_AUTHOR("Amir Dahan <[email protected]>");
> +MODULE_DESCRIPTION("DRM driver for LG DSI Panel with SW49410 controller");
> +MODULE_LICENSE("GPL");
> 


Thanks,
Neil
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.