xref: /linux/drivers/gpu/drm/panel/panel-himax-hx83121a.c (revision 51d24842acb9b8d643046c71314cc3d7a846a3cf)
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