Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

drm/panel: Add Himax HX83121A panel driver

Add a driver for panels using the Himax HX83121A Display Driver IC,
including support for the BOE/CSOT PPC357DB1-4, found in HUAWEI
Matebook E Go series (Gaokun2/3).

Signed-off-by: Pengyu Luo <mitltlatltl@gmail.com>
Reviewed-by: Neil Armstrong <neil.armstrong@linaro.org>
Signed-off-by: Neil Armstrong <neil.armstrong@linaro.org>
Link: https://patch.msgid.link/20260316084040.728106-3-mitltlatltl@gmail.com

authored by

Pengyu Luo and committed by
Neil Armstrong
a7c61963 9f96a50d

+761
+11
drivers/gpu/drm/panel/Kconfig
··· 203 203 Say Y here if you want to enable support for Himax HX83112B-based 204 204 display panels, such as the one found in the Fairphone 3 smartphone. 205 205 206 + config DRM_PANEL_HIMAX_HX83121A 207 + tristate "Himax HX83121A-based DSI panel" 208 + depends on OF 209 + depends on DRM_MIPI_DSI 210 + depends on BACKLIGHT_CLASS_DEVICE 211 + select DRM_KMS_HELPER 212 + help 213 + Say Y here if you want to enable support for Himax HX83121A-based 214 + display panels, such as the one found in the HUAWEI Matebook E Go 215 + series. 216 + 206 217 config DRM_PANEL_HIMAX_HX8394 207 218 tristate "HIMAX HX8394 MIPI-DSI LCD panels" 208 219 depends on OF
+1
drivers/gpu/drm/panel/Makefile
··· 21 21 obj-$(CONFIG_DRM_PANEL_HIMAX_HX83102) += panel-himax-hx83102.o 22 22 obj-$(CONFIG_DRM_PANEL_HIMAX_HX83112A) += panel-himax-hx83112a.o 23 23 obj-$(CONFIG_DRM_PANEL_HIMAX_HX83112B) += panel-himax-hx83112b.o 24 + obj-$(CONFIG_DRM_PANEL_HIMAX_HX83121A) += panel-himax-hx83121a.o 24 25 obj-$(CONFIG_DRM_PANEL_HIMAX_HX8394) += panel-himax-hx8394.o 25 26 obj-$(CONFIG_DRM_PANEL_HYDIS_HV101HD1) += panel-hydis-hv101hd1.o 26 27 obj-$(CONFIG_DRM_PANEL_ILITEK_IL9322) += panel-ilitek-ili9322.o
+749
drivers/gpu/drm/panel/panel-himax-hx83121a.c
··· 1 + // SPDX-License-Identifier: GPL-2.0-only 2 + /* 3 + * Himax HX83121A DriverIC panels driver 4 + * Copyright (c) 2024-2026 Pengyu Luo <mitltlatltl@gmail.com> 5 + * 6 + * Multiple panels handling based on panel-novatek-nt36523.c 7 + */ 8 + 9 + #include <linux/backlight.h> 10 + #include <linux/delay.h> 11 + #include <linux/gpio/consumer.h> 12 + #include <linux/mod_devicetable.h> 13 + #include <linux/module.h> 14 + #include <linux/of.h> 15 + #include <linux/of_graph.h> 16 + #include <linux/regulator/consumer.h> 17 + 18 + #include <drm/display/drm_dsc.h> 19 + #include <drm/display/drm_dsc_helper.h> 20 + #include <drm/drm_mipi_dsi.h> 21 + #include <drm/drm_modes.h> 22 + #include <drm/drm_panel.h> 23 + 24 + #include <video/mipi_display.h> 25 + 26 + static bool enable_dsc; 27 + module_param(enable_dsc, bool, 0); 28 + MODULE_PARM_DESC(enable_dsc, "enable DSC on the panel (default: false)"); 29 + 30 + struct himax { 31 + struct drm_panel panel; 32 + struct mipi_dsi_device *dsi[2]; 33 + const struct panel_desc *desc; 34 + struct drm_dsc_config dsc; 35 + struct gpio_desc *reset_gpio; 36 + struct regulator_bulk_data *supplies; 37 + struct backlight_device *backlight; 38 + }; 39 + 40 + struct panel_desc { 41 + unsigned int width_mm; 42 + unsigned int height_mm; 43 + unsigned int bpc; 44 + unsigned int lanes; 45 + enum mipi_dsi_pixel_format format; 46 + unsigned long mode_flags; 47 + const struct drm_dsc_config *dsc_cfg; 48 + const struct drm_display_mode *dsc_modes; 49 + unsigned int num_dsc_modes; 50 + 51 + const struct drm_display_mode *modes; 52 + unsigned int num_modes; 53 + 54 + int (*init_sequence_dsc)(struct mipi_dsi_multi_context *dsi_ctx); 55 + int (*init_sequence)(struct mipi_dsi_multi_context *dsi_ctx); 56 + 57 + bool is_dual_dsi; 58 + bool has_dcs_backlight; 59 + }; 60 + 61 + static const struct regulator_bulk_data himax_supplies[] = { 62 + { .supply = "vddi" }, 63 + { .supply = "avdd" }, 64 + { .supply = "avee" }, 65 + }; 66 + 67 + static inline struct himax *to_himax(struct drm_panel *panel) 68 + { 69 + return container_of(panel, struct himax, panel); 70 + } 71 + 72 + static inline struct mipi_dsi_device *to_primary_dsi(struct himax *ctx) 73 + { 74 + /* Sync on DSI1 for dual dsi */ 75 + return ctx->desc->is_dual_dsi ? ctx->dsi[1] : ctx->dsi[0]; 76 + } 77 + 78 + static void himax_reset(struct himax *ctx) 79 + { 80 + gpiod_set_value_cansleep(ctx->reset_gpio, 1); 81 + usleep_range(4000, 4100); 82 + gpiod_set_value_cansleep(ctx->reset_gpio, 0); 83 + msleep(20); 84 + } 85 + 86 + static int himax_prepare(struct drm_panel *panel) 87 + { 88 + struct himax *ctx = to_himax(panel); 89 + struct mipi_dsi_device *dsi = to_primary_dsi(ctx); 90 + struct mipi_dsi_multi_context dsi_ctx = { .dsi = dsi }; 91 + struct drm_dsc_picture_parameter_set pps; 92 + int ret; 93 + 94 + ret = regulator_bulk_enable(ARRAY_SIZE(himax_supplies), 95 + ctx->supplies); 96 + if (ret < 0) 97 + return ret; 98 + 99 + himax_reset(ctx); 100 + 101 + if (enable_dsc && ctx->desc->init_sequence_dsc) 102 + ret = ctx->desc->init_sequence_dsc(&dsi_ctx); 103 + else if (ctx->desc->init_sequence) 104 + ret = ctx->desc->init_sequence(&dsi_ctx); 105 + else 106 + ret = -EOPNOTSUPP; 107 + 108 + if (ret < 0) { 109 + gpiod_set_value_cansleep(ctx->reset_gpio, 1); 110 + regulator_bulk_disable(ARRAY_SIZE(himax_supplies), 111 + ctx->supplies); 112 + return ret; 113 + } 114 + 115 + if (enable_dsc) { 116 + drm_dsc_pps_payload_pack(&pps, &ctx->dsc); 117 + mipi_dsi_picture_parameter_set_multi(&dsi_ctx, &pps); 118 + mipi_dsi_compression_mode_multi(&dsi_ctx, true); 119 + } 120 + 121 + return backlight_enable(ctx->backlight); 122 + } 123 + 124 + static int himax_off(struct mipi_dsi_multi_context *dsi_ctx) 125 + { 126 + mipi_dsi_dcs_enter_sleep_mode_multi(dsi_ctx); 127 + mipi_dsi_msleep(dsi_ctx, 120); 128 + 129 + return dsi_ctx->accum_err; 130 + } 131 + 132 + static int himax_unprepare(struct drm_panel *panel) 133 + { 134 + struct himax *ctx = to_himax(panel); 135 + struct mipi_dsi_device *dsi = to_primary_dsi(ctx); 136 + struct mipi_dsi_multi_context dsi_ctx = { .dsi = dsi }; 137 + struct device *dev = &dsi->dev; 138 + int ret; 139 + 140 + ret = himax_off(&dsi_ctx); 141 + if (ret < 0) 142 + dev_err(dev, "panel failed to off: %d\n", ret); 143 + 144 + gpiod_set_value_cansleep(ctx->reset_gpio, 1); 145 + regulator_bulk_disable(ARRAY_SIZE(himax_supplies), ctx->supplies); 146 + 147 + return 0; 148 + } 149 + 150 + static int himax_get_modes(struct drm_panel *panel, 151 + struct drm_connector *connector) 152 + { 153 + struct himax *ctx = to_himax(panel); 154 + const struct panel_desc *desc = ctx->desc; 155 + const struct drm_display_mode *modes; 156 + int num_modes; 157 + int i; 158 + 159 + modes = enable_dsc ? desc->dsc_modes : desc->modes; 160 + num_modes = enable_dsc ? desc->num_dsc_modes : desc->num_modes; 161 + 162 + for (i = 0; i < num_modes; i++) { 163 + const struct drm_display_mode *m = &modes[i]; 164 + struct drm_display_mode *mode; 165 + 166 + mode = drm_mode_duplicate(connector->dev, m); 167 + if (!mode) { 168 + dev_err(panel->dev, "failed to add mode %ux%u@%u\n", 169 + m->hdisplay, m->vdisplay, drm_mode_vrefresh(m)); 170 + return -ENOMEM; 171 + } 172 + 173 + mode->type = DRM_MODE_TYPE_DRIVER; 174 + if (i == 0) 175 + mode->type |= DRM_MODE_TYPE_PREFERRED; 176 + 177 + drm_mode_set_name(mode); 178 + drm_mode_probed_add(connector, mode); 179 + } 180 + 181 + connector->display_info.width_mm = desc->width_mm; 182 + connector->display_info.height_mm = desc->height_mm; 183 + connector->display_info.bpc = desc->bpc; 184 + 185 + return num_modes; 186 + } 187 + 188 + static const struct drm_panel_funcs himax_panel_funcs = { 189 + .prepare = himax_prepare, 190 + .unprepare = himax_unprepare, 191 + .get_modes = himax_get_modes, 192 + }; 193 + 194 + static int himax_bl_update_status(struct backlight_device *bl) 195 + { 196 + struct mipi_dsi_device *dsi = bl_get_data(bl); 197 + u16 brightness = backlight_get_brightness(bl); 198 + /* TODO: brightness to raw map table */ 199 + return mipi_dsi_dcs_set_display_brightness_large(dsi, brightness); 200 + } 201 + 202 + static const struct backlight_ops himax_bl_ops = { 203 + .options = BL_CORE_SUSPENDRESUME, 204 + .update_status = himax_bl_update_status, 205 + }; 206 + 207 + static struct backlight_device * 208 + himax_create_backlight(struct mipi_dsi_device *dsi) 209 + { 210 + struct device *dev = &dsi->dev; 211 + const struct backlight_properties props = { 212 + .type = BACKLIGHT_RAW, 213 + .brightness = 512, 214 + .max_brightness = 4095, 215 + .scale = BACKLIGHT_SCALE_NON_LINEAR, 216 + }; 217 + 218 + return devm_backlight_device_register(dev, dev_name(dev), dev, dsi, 219 + &himax_bl_ops, &props); 220 + } 221 + 222 + static int boe_ppc357db1_4_dsc_init_seq(struct mipi_dsi_multi_context *dsi_ctx) 223 + { 224 + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xb9, 0x83, 0x12, 0x1a, 0x55, 0x00); 225 + mipi_dsi_dcs_write_seq_multi(dsi_ctx, MIPI_DCS_WRITE_CONTROL_DISPLAY, 0x24); 226 + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xe2, 0x00); 227 + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xbd, 0x03); 228 + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xe1, 0x01); 229 + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xbd, 0x00); 230 + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xe9, 0xc7); 231 + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xb2, 0x98); 232 + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xe9, 0x3f); 233 + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xbd, 0x02); 234 + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xe7, 235 + 0x01, 0x07, 0x01, 0x07, 0x01, 0x07, 0x06, 0x06, 236 + 0x06, 0x16, 0x00, 0x16, 0x81, 0x02, 0x40, 0x00, 237 + 0x1a, 0x4a, 0x05, 0x04, 0x03, 0x02, 0x01); 238 + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xbd, 0x01); 239 + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xe9, 0xc6); 240 + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xd2, 0x00, 0x30); 241 + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xe9, 0x3f); 242 + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xe9, 0xc9); 243 + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xd3, 0x04); 244 + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xe9, 0x3f); 245 + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xe9, 0xc6); 246 + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xe2, 0x42); 247 + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xe9, 0x3f); 248 + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xbd, 0x00); 249 + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xe9, 0xd0); 250 + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xb2, 0xf5); 251 + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xe9, 0x3f); 252 + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xcd, 253 + 0x81, 0x00, 0x80, 0x77, 0x00, 0x01, 0x00); 254 + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xbd, 0x01); 255 + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xe4, 256 + 0xe1, 0xe1, 0xe1, 0xe1, 0xe1, 0xe1, 0xe1, 0xe1, 257 + 0xc7, 0xb2, 0xa0, 0x90, 0x81, 0x75, 0x69, 0x5f, 258 + 0x55, 0x4c, 0x44, 0x3d, 0x36, 0x2f, 0x2a, 0x24, 259 + 0x1e, 0x19, 0x14, 0x10, 0x09, 0x08, 0x07, 0x54, 260 + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55); 261 + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xbd, 0x03); 262 + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xe4, 263 + 0xaa, 0xd4, 0xff, 0x2a, 0x55, 0x7f, 0xaa, 0xd4, 264 + 0xff, 0xea, 0xff, 0x03); 265 + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xbd, 0x00); 266 + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xe9, 0xc8); 267 + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xb1, 0x25); 268 + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xe9, 0x3f); 269 + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xbe, 0x01, 0x35, 0x00); 270 + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xd9, 0x5f); 271 + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xb9, 0x00, 0x00, 0x00); 272 + 273 + mipi_dsi_dcs_exit_sleep_mode_multi(dsi_ctx); 274 + mipi_dsi_msleep(dsi_ctx, 140); 275 + mipi_dsi_dcs_set_display_on_multi(dsi_ctx); 276 + 277 + mipi_dsi_dcs_write_seq_multi(dsi_ctx, MIPI_DCS_WRITE_POWER_SAVE, 0x01); 278 + mipi_dsi_dcs_write_seq_multi(dsi_ctx, MIPI_DCS_WRITE_CONTROL_DISPLAY, 0x24); 279 + mipi_dsi_msleep(dsi_ctx, 20); 280 + 281 + return dsi_ctx->accum_err; 282 + } 283 + 284 + static int boe_ppc357db1_4_init_seq(struct mipi_dsi_multi_context *dsi_ctx) 285 + { 286 + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xb9, 0x83, 0x12, 0x1a, 0x55, 0x00); 287 + mipi_dsi_dcs_write_seq_multi(dsi_ctx, MIPI_DCS_WRITE_CONTROL_DISPLAY, 0x24); 288 + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xd1, 0x37, 0x03, 0x0c, 0xfd); 289 + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xe2, 0x20); 290 + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xbd, 0x03); 291 + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xe1, 0x00); 292 + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xbd, 0x00); 293 + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xe9, 0xc7); 294 + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xb2, 0xa6); 295 + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xe9, 0x3f); 296 + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xbd, 0x02); 297 + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xe7, 298 + 0x01, 0x07, 0x01, 0x07, 0x01, 0x07, 0x06, 0x06, 299 + 0x06, 0x16, 0x00, 0x16, 0x81, 0x02, 0x40, 0x00, 300 + 0x1a, 0x4a, 0x05, 0x04, 0x03, 0x02, 0x01); 301 + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xe2, 302 + 0x02, 0x68, 0x02, 0x68, 0x02, 0x68, 0x02, 0x68, 303 + 0x02, 0x6f, 0x03, 0x04, 0x2d, 0x09, 0x09, 0x00, 304 + 0x00, 0x0f, 0x0f, 0x0f, 0x0f, 0x00, 0x00, 0x00, 305 + 0x01, 0x10, 0x10, 0x1c, 0x25, 0x3c, 0x00, 0x23, 306 + 0x5d, 0x02, 0x02, 0x00, 0x00, 0x58, 0x01, 0xac, 307 + 0x0f, 0xa9, 0x10, 0x00, 0x2d, 0x6f, 0x00, 0x70, 308 + 0x00, 0x0a, 0xcb, 0x01); 309 + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xbd, 0x01); 310 + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xe9, 0xc6); 311 + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xd2, 0x09, 0x85); 312 + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xe9, 0x3f); 313 + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xe9, 0xc9); 314 + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xd3, 0x04); 315 + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xe9, 0x3f); 316 + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xbd, 0x00); 317 + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xe9, 0xd0); 318 + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xb2, 0xf5); 319 + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xe9, 0x3f); 320 + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xbd, 0x01); 321 + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xe4, 322 + 0xe1, 0xe1, 0xe1, 0xe1, 0xe1, 0xe1, 0xe1, 0xe1, 323 + 0xc7, 0xb2, 0xa0, 0x90, 0x81, 0x75, 0x69, 0x5f, 324 + 0x55, 0x4c, 0x44, 0x3d, 0x36, 0x2f, 0x2a, 0x24, 325 + 0x1e, 0x19, 0x14, 0x10, 0x09, 0x08, 0x07, 0x54, 326 + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55); 327 + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xbd, 0x03); 328 + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xe4, 329 + 0xaa, 0xd4, 0xff, 0x2a, 0x55, 0x7f, 0xaa, 0xd4, 330 + 0xff, 0xea, 0xff, 0x03); 331 + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xbd, 0x00); 332 + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xe9, 0xc8); 333 + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xb1, 0x25); 334 + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xe9, 0x3f); 335 + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xbe, 0x01, 0x35, 0x00); 336 + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xd9, 0x5f); 337 + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xb9, 0x00, 0x00, 0x00); 338 + 339 + mipi_dsi_dcs_exit_sleep_mode_multi(dsi_ctx); 340 + mipi_dsi_msleep(dsi_ctx, 140); 341 + mipi_dsi_dcs_set_display_on_multi(dsi_ctx); 342 + 343 + mipi_dsi_dcs_write_seq_multi(dsi_ctx, MIPI_DCS_WRITE_POWER_SAVE, 0x01); 344 + mipi_dsi_dcs_write_seq_multi(dsi_ctx, MIPI_DCS_WRITE_CONTROL_DISPLAY, 0x24); 345 + mipi_dsi_msleep(dsi_ctx, 31); 346 + 347 + return dsi_ctx->accum_err; 348 + } 349 + 350 + static int csot_ppc357db1_4_dsc_init_seq(struct mipi_dsi_multi_context *dsi_ctx) 351 + { 352 + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xb9, 0x83, 0x12, 0x1a, 0x55, 0x00); 353 + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xbd, 0x00); 354 + mipi_dsi_dcs_write_seq_multi(dsi_ctx, MIPI_DCS_WRITE_CONTROL_DISPLAY, 0x24); 355 + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xb1, 356 + 0x1c, 0x6b, 0x6b, 0x27, 0xe7, 0x00, 0x1b, 0x25, 357 + 0x21, 0x21, 0x2d, 0x2d, 0x17, 0x33, 0x31, 0x40, 358 + 0xcd, 0xff, 0x1a, 0x05, 0x15, 0x98, 0x00, 0x88, 359 + 0x7f, 0xff, 0xff, 0xcf, 0x1a, 0xcc, 0x02, 0x00); 360 + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xd1, 0x37, 0x03, 0x0c, 0xfd); 361 + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xb2, 362 + 0x00, 0x6a, 0x40, 0x00, 0x00, 0x14, 0x98, 0x60, 363 + 0x3c, 0x02, 0x80, 0x21, 0x21, 0x00, 0x00, 0xf0, 364 + 0x27); 365 + /* 366 + * NOTE: Register 0xE2 configuration (based on downstream reference): 367 + * - 0x00: 120Hz with DSC enabled 368 + * - 0x10: 60Hz with DSC enabled 369 + * - 0x20: 60Hz with DSC disabled 370 + * 371 + * Both 0x00 and 0x10 are compatible with 60Hz/120Hz when DSC is active. 372 + * We use a fixed DSC-on value to remain refresh-rate agnostic. 373 + */ 374 + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xe2, 0x00); 375 + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xc0, 0x23, 0x23, 0xcc, 0x22, 0x99, 0xd8); 376 + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xb4, 377 + 0x46, 0x06, 0x0c, 0xbe, 0x0c, 0xbe, 0x09, 0x46, 378 + 0x0f, 0x57, 0x0f, 0x57, 0x03, 0x4a, 0x00, 0x00, 379 + 0x04, 0x0c, 0x00, 0x18, 0x01, 0x06, 0x08, 0x00, 380 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 381 + 0x00, 0x00, 0xff, 0x00, 0xff, 0x10, 0x00, 0x02, 382 + 0x14, 0x14, 0x14, 0x14); 383 + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xbd, 0x03); 384 + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xe1, 0x01, 0x3f); 385 + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xbd, 0x00); 386 + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xe9, 0xe2); 387 + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xe7, 0x49); 388 + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xe9, 0x3f); 389 + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xd3, 390 + 0x00, 0xc0, 0x08, 0x08, 0x08, 0x04, 0x04, 0x04, 391 + 0x16, 0x02, 0x07, 0x07, 0x07, 0x31, 0x13, 0x19, 392 + 0x12, 0x12, 0x03, 0x03, 0x03, 0x32, 0x10, 0x18, 393 + 0x00, 0x11, 0x32, 0x10, 0x03, 0x00, 0x03, 0x32, 394 + 0x10, 0x03, 0x00, 0x03, 0x00, 0x00, 0xff, 0x00); 395 + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xe1, 396 + 0x11, 0x00, 0x00, 0x89, 0x30, 0x80, 0x0a, 0x00, 397 + 0x03, 0x20, 0x00, 0x14, 0x03, 0x20, 0x03, 0x20, 398 + 0x02, 0x00, 0x02, 0x91, 0x00, 0x20, 0x02, 0x47, 399 + 0x00, 0x0b, 0x00, 0x0c, 0x05, 0x0e, 0x03, 0x68, 400 + 0x18, 0x00, 0x10, 0xe0, 0x03, 0x0c, 0x20, 0x00, 401 + 0x06, 0x0b, 0x0b, 0x33, 0x0e, 0x1c, 0x2a, 0x38, 402 + 0x46, 0x54, 0x62, 0x69, 0x70, 0x77, 0x79, 0x7b, 403 + 0x7d, 0x7e, 0x01, 0x02, 0x01, 0x00, 0x09); 404 + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xe7, 405 + 0x17, 0x08, 0x08, 0x2c, 0x46, 0x1e, 0x02, 0x23, 406 + 0x5d, 0x02, 0xc9, 0x00, 0x00, 0x00, 0x00, 0x12, 407 + 0x05, 0x02, 0x02, 0x07, 0x10, 0x10, 0x00, 0x1d, 408 + 0xb9, 0x23, 0xb9, 0x00, 0x33, 0x02, 0x88); 409 + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xbd, 0x01); 410 + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xe7, 411 + 0x02, 0x00, 0xb2, 0x01, 0x56, 0x07, 0x56, 0x08, 412 + 0x48, 0x14, 0xfd, 0x26); 413 + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xbd, 0x02); 414 + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xe7, 415 + 0x08, 0x08, 0x01, 0x03, 0x01, 0x03, 0x07, 0x02, 416 + 0x02, 0x47, 0x00, 0x47, 0x81, 0x02, 0x40, 0x00, 417 + 0x18, 0x4a, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 418 + 0x00, 0x00, 0x03, 0x02, 0x01, 0x00, 0x00, 0x00, 419 + 0x00, 0x00); 420 + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xbd, 0x00); 421 + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xbf, 422 + 0xfd, 0x00, 0x80, 0x9c, 0x36, 0x00, 0x81, 0x0c); 423 + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xcd, 424 + 0x81, 0x00, 0x80, 0x77, 0x00, 0x01, 0x00); 425 + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xbd, 0x01); 426 + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xe4, 427 + 0xe1, 0xe1, 0xe1, 0xe1, 0xe1, 0xe1, 0xe1, 0xe1, 428 + 0xc7, 0xb2, 0xa0, 0x90, 0x81, 0x75, 0x69, 0x5f, 429 + 0x55, 0x4c, 0x44, 0x3d, 0x36, 0x2f, 0x2a, 0x24, 430 + 0x1e, 0x19, 0x14, 0x10, 0x09, 0x08, 0x07, 0x54, 431 + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55); 432 + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xbd, 0x03); 433 + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xe4, 434 + 0xaa, 0xd4, 0xff, 0x2a, 0x55, 0x7f, 0xaa, 0xd4, 435 + 0xff, 0xea, 0xff, 0x03); 436 + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xbd, 0x00); 437 + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xbe, 0x01, 0x35, 0x00); 438 + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xd9, 0x5f); 439 + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xb9, 0x00, 0x00, 0x00); 440 + 441 + mipi_dsi_dcs_exit_sleep_mode_multi(dsi_ctx); 442 + mipi_dsi_msleep(dsi_ctx, 140); 443 + mipi_dsi_dcs_set_display_on_multi(dsi_ctx); 444 + 445 + mipi_dsi_dcs_write_seq_multi(dsi_ctx, MIPI_DCS_WRITE_POWER_SAVE, 0x01); 446 + mipi_dsi_dcs_write_seq_multi(dsi_ctx, MIPI_DCS_WRITE_CONTROL_DISPLAY, 0x24); 447 + mipi_dsi_msleep(dsi_ctx, 20); 448 + 449 + return dsi_ctx->accum_err; 450 + } 451 + 452 + static int csot_ppc357db1_4_init_seq(struct mipi_dsi_multi_context *dsi_ctx) 453 + { 454 + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xb9, 0x83, 0x12, 0x1a, 0x55, 0x00); 455 + mipi_dsi_dcs_write_seq_multi(dsi_ctx, MIPI_DCS_WRITE_CONTROL_DISPLAY, 0x24); 456 + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xbd, 0x00); 457 + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xb1, 458 + 0x1c, 0x6b, 0x6b, 0x27, 0xe7, 0x00, 0x1b, 0x11, 459 + 0x21, 0x21, 0x2d, 0x2d, 0x17, 0x33, 0x31, 0x40, 460 + 0xcd, 0xff, 0x1a, 0x05, 0x15, 0x98, 0x00, 0x88, 461 + 0x7f, 0xff, 0xff, 0xcf, 0x1a, 0xcc, 0x02, 0x00); 462 + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xd1, 0x37, 0x03, 0x0c, 0xfd); 463 + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xe2, 0x20); 464 + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xb2, 465 + 0x00, 0x6a, 0x40, 0x00, 0x00, 0x14, 0x98, 0x60, 466 + 0x3c, 0x02, 0x80, 0x21, 0x21, 0x00, 0x00, 0x10, 467 + 0x27); 468 + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xbd, 0x03); 469 + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xe1, 0x00, 0x3f); 470 + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xbd, 0x00); 471 + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xe9, 0xe2); 472 + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xe7, 0x49); 473 + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xe9, 0x3f); 474 + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xd3, 475 + 0x00, 0xc0, 0x08, 0x08, 0x08, 0x04, 0x04, 0x04, 476 + 0x16, 0x02, 0x07, 0x07, 0x07, 0x31, 0x13, 0x16, 477 + 0x12, 0x12, 0x03, 0x03, 0x03, 0x32, 0x10, 0x15, 478 + 0x00, 0x11, 0x32, 0x10, 0x03, 0x00, 0x03, 0x32, 479 + 0x10, 0x03, 0x00, 0x03, 0x00, 0x00, 0xff, 0x00); 480 + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xbd, 0x02); 481 + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xe2, 482 + 0x80, 0x05, 0x1c, 0xbe, 0x09, 0x8d, 0x0f, 0x57, 483 + 0x03, 0x87, 0x06, 0x10, 0x32, 0x06, 0x15, 0x00, 484 + 0x00, 0x14, 0x14, 0x14, 0x14, 0x00, 0x00, 0x00, 485 + 0x01, 0x10, 0x10, 0x16, 0x28, 0x3c, 0x03, 0x23, 486 + 0x5d, 0x02, 0x02, 0x00, 0x00, 0x48, 0x01, 0xac, 487 + 0x0f, 0xab, 0x10, 0x00, 0x32, 0x87, 0x00, 0xa1, 488 + 0x00, 0x0a, 0xcb, 0x00); 489 + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xbd, 0x01); 490 + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xe7, 491 + 0x02, 0x00, 0xb2, 0x01, 0x56, 0x07, 0x56, 0x08, 492 + 0x48, 0x14, 0x00, 0x26); 493 + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xbd, 0x02); 494 + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xe7, 495 + 0x05, 0x05, 0x01, 0x05, 0x01, 0x05, 0x04, 0x04, 496 + 0x04, 0x24, 0x00, 0x24, 0x81, 0x02, 0x40, 0x00, 497 + 0x32, 0x87, 0x03, 0x02, 0x01, 0x00, 0x00, 0x00, 498 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 499 + 0x00, 0x00); 500 + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xbd, 0x00); 501 + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xe9, 0xd0); 502 + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xb2, 0xf0); 503 + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xe9, 0x3f); 504 + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xbf, 505 + 0xfd, 0x00, 0x80, 0x9c, 0x10, 0x00, 0x81, 0x0c); 506 + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xbd, 0x01); 507 + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xe4, 508 + 0xe1, 0xe1, 0xe1, 0xe1, 0xe1, 0xe1, 0xe1, 0xe1, 509 + 0xc7, 0xb2, 0xa0, 0x90, 0x81, 0x75, 0x69, 0x5f, 510 + 0x55, 0x4c, 0x44, 0x3d, 0x36, 0x2f, 0x2a, 0x24, 511 + 0x1e, 0x19, 0x14, 0x10, 0x09, 0x08, 0x07, 0x54, 512 + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55); 513 + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xbd, 0x03); 514 + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xe4, 515 + 0xaa, 0xd4, 0xff, 0x2a, 0x55, 0x7f, 0xaa, 0xd4, 516 + 0xff, 0xea, 0xff, 0x03); 517 + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xbd, 0x00); 518 + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xe9, 0xc8); 519 + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xb1, 0x25); 520 + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xe9, 0x3f); 521 + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xbe, 0x01, 0x35, 0x00); 522 + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xd9, 0x5f); 523 + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xb9, 0x00, 0x00, 0x00); 524 + 525 + mipi_dsi_dcs_exit_sleep_mode_multi(dsi_ctx); 526 + mipi_dsi_msleep(dsi_ctx, 140); 527 + mipi_dsi_dcs_set_display_on_multi(dsi_ctx); 528 + 529 + mipi_dsi_dcs_write_seq_multi(dsi_ctx, MIPI_DCS_WRITE_POWER_SAVE, 0x01); 530 + mipi_dsi_dcs_write_seq_multi(dsi_ctx, MIPI_DCS_WRITE_CONTROL_DISPLAY, 0x24); 531 + mipi_dsi_msleep(dsi_ctx, 31); 532 + 533 + return dsi_ctx->accum_err; 534 + } 535 + 536 + static struct drm_dsc_config ppc357db1_4_dsc_cfg = { 537 + .dsc_version_major = 1, 538 + .dsc_version_minor = 1, 539 + .slice_height = 20, 540 + .slice_width = 800, 541 + .slice_count = 1, 542 + .bits_per_component = 8, 543 + .bits_per_pixel = 8 << 4, 544 + .block_pred_enable = true, 545 + }; 546 + 547 + static const struct drm_display_mode ppc357db1_4_dsc_modes[] = { 548 + { 549 + .clock = (800 + 60 + 40 + 40) * 2 * (2560 + 154 + 4 + 18) * 120 / 1000, 550 + .hdisplay = 800 * 2, 551 + .hsync_start = (800 + 60) * 2, 552 + .hsync_end = (800 + 60 + 40) * 2, 553 + .htotal = (800 + 60 + 40 + 40) * 2, 554 + .vdisplay = 2560, 555 + .vsync_start = 2560 + 154, 556 + .vsync_end = 2560 + 154 + 4, 557 + .vtotal = 2560 + 154 + 4 + 18, 558 + }, 559 + { 560 + .clock = (800 + 60 + 40 + 40) * 2 * (2560 + 2890 + 4 + 18) * 60 / 1000, 561 + .hdisplay = 800 * 2, 562 + .hsync_start = (800 + 60) * 2, 563 + .hsync_end = (800 + 60 + 40) * 2, 564 + .htotal = (800 + 60 + 40 + 40) * 2, 565 + .vdisplay = 2560, 566 + .vsync_start = 2560 + 2890, 567 + .vsync_end = 2560 + 2890 + 4, 568 + .vtotal = 2560 + 2890 + 4 + 18, 569 + }, 570 + }; 571 + 572 + static const struct drm_display_mode ppc357db1_4_modes[] = { 573 + { 574 + .clock = (800 + 60 + 20 + 40) * 2 * (2560 + 154 + 4 + 18) * 60 / 1000, 575 + .hdisplay = 800 * 2, 576 + .hsync_start = (800 + 60) * 2, 577 + .hsync_end = (800 + 60 + 20) * 2, 578 + .htotal = (800 + 60 + 20 + 40) * 2, 579 + .vdisplay = 2560, 580 + .vsync_start = 2560 + 168, 581 + .vsync_end = 2560 + 168 + 4, 582 + .vtotal = 2560 + 168 + 4 + 18, 583 + }, 584 + }; 585 + 586 + static int himax_probe(struct mipi_dsi_device *dsi) 587 + { 588 + struct mipi_dsi_device_info dsi_info = {"dsi-secondary", 0, NULL}; 589 + struct mipi_dsi_host *dsi1_host; 590 + struct device *dev = &dsi->dev; 591 + const struct panel_desc *desc; 592 + struct device_node *dsi1; 593 + struct himax *ctx; 594 + int num_dsi = 1; 595 + int ret, i; 596 + 597 + ctx = devm_drm_panel_alloc(dev, struct himax, panel, &himax_panel_funcs, 598 + DRM_MODE_CONNECTOR_DSI); 599 + if (!ctx) 600 + return -ENOMEM; 601 + 602 + ret = devm_regulator_bulk_get_const(&dsi->dev, 603 + ARRAY_SIZE(himax_supplies), 604 + himax_supplies, &ctx->supplies); 605 + if (ret < 0) 606 + return ret; 607 + 608 + ctx->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_HIGH); 609 + if (IS_ERR(ctx->reset_gpio)) 610 + return dev_err_probe(dev, PTR_ERR(ctx->reset_gpio), 611 + "Failed to get reset-gpios\n"); 612 + 613 + desc = of_device_get_match_data(dev); 614 + if (!desc) 615 + return -ENODEV; 616 + ctx->desc = desc; 617 + ctx->dsc = *desc->dsc_cfg; 618 + 619 + if (desc->is_dual_dsi) { 620 + num_dsi = 2; 621 + dsi1 = of_graph_get_remote_node(dsi->dev.of_node, 1, -1); 622 + if (!dsi1) { 623 + dev_err(dev, "cannot get secondary DSI node.\n"); 624 + return -ENODEV; 625 + } 626 + 627 + dsi1_host = of_find_mipi_dsi_host_by_node(dsi1); 628 + of_node_put(dsi1); 629 + if (!dsi1_host) 630 + return dev_err_probe(dev, -EPROBE_DEFER, 631 + "cannot get secondary DSI host\n"); 632 + 633 + ctx->dsi[1] = devm_mipi_dsi_device_register_full(dev, dsi1_host, 634 + &dsi_info); 635 + if (IS_ERR(ctx->dsi[1])) { 636 + dev_err(dev, "cannot get secondary DSI device\n"); 637 + return PTR_ERR(ctx->dsi[1]); 638 + } 639 + 640 + mipi_dsi_set_drvdata(ctx->dsi[1], ctx); 641 + } 642 + 643 + ctx->dsi[0] = dsi; 644 + mipi_dsi_set_drvdata(dsi, ctx); 645 + 646 + ctx->panel.prepare_prev_first = true; 647 + 648 + if (desc->has_dcs_backlight) { 649 + ctx->backlight = himax_create_backlight(to_primary_dsi(ctx)); 650 + if (IS_ERR(ctx->backlight)) 651 + return dev_err_probe(dev, PTR_ERR(ctx->backlight), 652 + "Failed to create backlight\n"); 653 + } else { 654 + ret = drm_panel_of_backlight(&ctx->panel); 655 + if (ret) 656 + return dev_err_probe(dev, ret, "Failed to get backlight\n"); 657 + } 658 + 659 + drm_panel_add(&ctx->panel); 660 + 661 + for (i = 0; i < num_dsi; i++) { 662 + ctx->dsi[i]->lanes = desc->lanes; 663 + ctx->dsi[i]->format = desc->format; 664 + ctx->dsi[i]->mode_flags = desc->mode_flags; 665 + ctx->dsi[i]->dsc = enable_dsc ? &ctx->dsc : NULL; 666 + ret = devm_mipi_dsi_attach(dev, ctx->dsi[i]); 667 + if (ret < 0) { 668 + drm_panel_remove(&ctx->panel); 669 + return dev_err_probe(dev, ret, 670 + "Failed to attach to DSI host\n"); 671 + } 672 + } 673 + 674 + return 0; 675 + } 676 + 677 + static void himax_remove(struct mipi_dsi_device *dsi) 678 + { 679 + struct himax *ctx = mipi_dsi_get_drvdata(dsi); 680 + 681 + drm_panel_remove(&ctx->panel); 682 + } 683 + 684 + /* Model name: BOE PPC357DB1-4 */ 685 + static const struct panel_desc boe_ppc357db1_4_desc = { 686 + .width_mm = 266, 687 + .height_mm = 166, 688 + .lanes = 4, 689 + .format = MIPI_DSI_FMT_RGB888, 690 + .mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_CLOCK_NON_CONTINUOUS | 691 + MIPI_DSI_MODE_LPM, 692 + .dsc_cfg = &ppc357db1_4_dsc_cfg, 693 + .dsc_modes = ppc357db1_4_dsc_modes, 694 + .num_dsc_modes = ARRAY_SIZE(ppc357db1_4_dsc_modes), 695 + .modes = ppc357db1_4_modes, 696 + .num_modes = ARRAY_SIZE(ppc357db1_4_modes), 697 + .init_sequence_dsc = boe_ppc357db1_4_dsc_init_seq, 698 + .init_sequence = boe_ppc357db1_4_init_seq, 699 + .is_dual_dsi = true, 700 + .has_dcs_backlight = true, 701 + }; 702 + 703 + /* Model name: CSOT PPC357DB1-4 */ 704 + static const struct panel_desc csot_ppc357db1_4_desc = { 705 + .width_mm = 266, 706 + .height_mm = 166, 707 + .lanes = 4, 708 + .format = MIPI_DSI_FMT_RGB888, 709 + .mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_CLOCK_NON_CONTINUOUS | 710 + MIPI_DSI_MODE_LPM, 711 + .dsc_cfg = &ppc357db1_4_dsc_cfg, 712 + .dsc_modes = ppc357db1_4_dsc_modes, 713 + .num_dsc_modes = ARRAY_SIZE(ppc357db1_4_dsc_modes), 714 + .modes = ppc357db1_4_modes, 715 + .num_modes = ARRAY_SIZE(ppc357db1_4_modes), 716 + .init_sequence_dsc = csot_ppc357db1_4_dsc_init_seq, 717 + .init_sequence = csot_ppc357db1_4_init_seq, 718 + .is_dual_dsi = true, 719 + .has_dcs_backlight = true, 720 + }; 721 + 722 + /* 723 + * Known panels with HX83121A: 724 + * CSOT PNC357DB1-4: on MI Book S 12.4 725 + * CSOT PPC357DB1-1: on SAMSUNG Galaxy Tab S7 FE 726 + * BOE/CSOT PPC357DB1-4: on HUAWEI Matebook E Go 727 + * CSOT PPC357DB1-5: on MI Pad 5 Pro 12.4 728 + */ 729 + 730 + static const struct of_device_id himax_of_match[] = { 731 + { .compatible = "boe,ppc357db1-4", .data = &boe_ppc357db1_4_desc }, 732 + { .compatible = "csot,ppc357db1-4", .data = &csot_ppc357db1_4_desc }, 733 + { /* sentinel */ } 734 + }; 735 + MODULE_DEVICE_TABLE(of, himax_of_match); 736 + 737 + static struct mipi_dsi_driver himax_driver = { 738 + .probe = himax_probe, 739 + .remove = himax_remove, 740 + .driver = { 741 + .name = "panel-himax-hx83121a", 742 + .of_match_table = himax_of_match, 743 + }, 744 + }; 745 + module_mipi_dsi_driver(himax_driver); 746 + 747 + MODULE_AUTHOR("Pengyu Luo <mitltlatltl0@gmail.com>"); 748 + MODULE_DESCRIPTION("Himax HX83121A DriverIC panels driver"); 749 + MODULE_LICENSE("GPL");