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
to_himax(struct drm_panel * panel)67 static inline struct himax *to_himax(struct drm_panel *panel)
68 {
69 return container_of(panel, struct himax, panel);
70 }
71
to_primary_dsi(struct himax * ctx)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
himax_reset(struct himax * ctx)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
himax_prepare(struct drm_panel * panel)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
himax_off(struct mipi_dsi_multi_context * dsi_ctx)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
himax_unprepare(struct drm_panel * panel)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
himax_get_modes(struct drm_panel * panel,struct drm_connector * connector)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
himax_bl_update_status(struct backlight_device * bl)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 *
himax_create_backlight(struct mipi_dsi_device * dsi)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
boe_ppc357db1_4_dsc_init_seq(struct mipi_dsi_multi_context * dsi_ctx)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
boe_ppc357db1_4_init_seq(struct mipi_dsi_multi_context * dsi_ctx)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
csot_ppc357db1_4_dsc_init_seq(struct mipi_dsi_multi_context * dsi_ctx)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
csot_ppc357db1_4_init_seq(struct mipi_dsi_multi_context * dsi_ctx)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
himax_probe(struct mipi_dsi_device * dsi)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 (IS_ERR(ctx))
600 return PTR_ERR(ctx);
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
himax_remove(struct mipi_dsi_device * dsi)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");
750