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