1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * Copyright (c) 2017, Fuzhou Rockchip Electronics Co., Ltd
4  */
5 
6 #include <linux/delay.h>
7 #include <linux/gpio/consumer.h>
8 #include <linux/module.h>
9 #include <linux/of.h>
10 #include <linux/regulator/consumer.h>
11 
12 #include <video/mipi_display.h>
13 
14 #include <drm/drm_crtc.h>
15 #include <drm/drm_device.h>
16 #include <drm/drm_mipi_dsi.h>
17 #include <drm/drm_modes.h>
18 #include <drm/drm_panel.h>
19 #include <drm/drm_print.h>
20 
21 struct kingdisplay_panel {
22 	struct drm_panel base;
23 	struct mipi_dsi_device *link;
24 
25 	struct regulator *supply;
26 	struct gpio_desc *enable_gpio;
27 
28 	bool prepared;
29 	bool enabled;
30 };
31 
32 struct kingdisplay_panel_cmd {
33 	char cmd;
34 	char data;
35 };
36 
37 /*
38  * According to the discussion on
39  * https://review.coreboot.org/#/c/coreboot/+/22472/
40  * the panel init array is not part of the panels datasheet but instead
41  * just came in this form from the panel vendor.
42  */
43 static const struct kingdisplay_panel_cmd init_code[] = {
44 	/* voltage setting */
45 	{ 0xB0, 0x00 },
46 	{ 0xB2, 0x02 },
47 	{ 0xB3, 0x11 },
48 	{ 0xB4, 0x00 },
49 	{ 0xB6, 0x80 },
50 	/* VCOM disable */
51 	{ 0xB7, 0x02 },
52 	{ 0xB8, 0x80 },
53 	{ 0xBA, 0x43 },
54 	/* VCOM setting */
55 	{ 0xBB, 0x53 },
56 	/* VSP setting */
57 	{ 0xBC, 0x0A },
58 	/* VSN setting */
59 	{ 0xBD, 0x4A },
60 	/* VGH setting */
61 	{ 0xBE, 0x2F },
62 	/* VGL setting */
63 	{ 0xBF, 0x1A },
64 	{ 0xF0, 0x39 },
65 	{ 0xF1, 0x22 },
66 	/* Gamma setting */
67 	{ 0xB0, 0x02 },
68 	{ 0xC0, 0x00 },
69 	{ 0xC1, 0x01 },
70 	{ 0xC2, 0x0B },
71 	{ 0xC3, 0x15 },
72 	{ 0xC4, 0x22 },
73 	{ 0xC5, 0x11 },
74 	{ 0xC6, 0x15 },
75 	{ 0xC7, 0x19 },
76 	{ 0xC8, 0x1A },
77 	{ 0xC9, 0x16 },
78 	{ 0xCA, 0x18 },
79 	{ 0xCB, 0x13 },
80 	{ 0xCC, 0x18 },
81 	{ 0xCD, 0x13 },
82 	{ 0xCE, 0x1C },
83 	{ 0xCF, 0x19 },
84 	{ 0xD0, 0x21 },
85 	{ 0xD1, 0x2C },
86 	{ 0xD2, 0x2F },
87 	{ 0xD3, 0x30 },
88 	{ 0xD4, 0x19 },
89 	{ 0xD5, 0x1F },
90 	{ 0xD6, 0x00 },
91 	{ 0xD7, 0x01 },
92 	{ 0xD8, 0x0B },
93 	{ 0xD9, 0x15 },
94 	{ 0xDA, 0x22 },
95 	{ 0xDB, 0x11 },
96 	{ 0xDC, 0x15 },
97 	{ 0xDD, 0x19 },
98 	{ 0xDE, 0x1A },
99 	{ 0xDF, 0x16 },
100 	{ 0xE0, 0x18 },
101 	{ 0xE1, 0x13 },
102 	{ 0xE2, 0x18 },
103 	{ 0xE3, 0x13 },
104 	{ 0xE4, 0x1C },
105 	{ 0xE5, 0x19 },
106 	{ 0xE6, 0x21 },
107 	{ 0xE7, 0x2C },
108 	{ 0xE8, 0x2F },
109 	{ 0xE9, 0x30 },
110 	{ 0xEA, 0x19 },
111 	{ 0xEB, 0x1F },
112 	/* GOA MUX setting */
113 	{ 0xB0, 0x01 },
114 	{ 0xC0, 0x10 },
115 	{ 0xC1, 0x0F },
116 	{ 0xC2, 0x0E },
117 	{ 0xC3, 0x0D },
118 	{ 0xC4, 0x0C },
119 	{ 0xC5, 0x0B },
120 	{ 0xC6, 0x0A },
121 	{ 0xC7, 0x09 },
122 	{ 0xC8, 0x08 },
123 	{ 0xC9, 0x07 },
124 	{ 0xCA, 0x06 },
125 	{ 0xCB, 0x05 },
126 	{ 0xCC, 0x00 },
127 	{ 0xCD, 0x01 },
128 	{ 0xCE, 0x02 },
129 	{ 0xCF, 0x03 },
130 	{ 0xD0, 0x04 },
131 	{ 0xD6, 0x10 },
132 	{ 0xD7, 0x0F },
133 	{ 0xD8, 0x0E },
134 	{ 0xD9, 0x0D },
135 	{ 0xDA, 0x0C },
136 	{ 0xDB, 0x0B },
137 	{ 0xDC, 0x0A },
138 	{ 0xDD, 0x09 },
139 	{ 0xDE, 0x08 },
140 	{ 0xDF, 0x07 },
141 	{ 0xE0, 0x06 },
142 	{ 0xE1, 0x05 },
143 	{ 0xE2, 0x00 },
144 	{ 0xE3, 0x01 },
145 	{ 0xE4, 0x02 },
146 	{ 0xE5, 0x03 },
147 	{ 0xE6, 0x04 },
148 	{ 0xE7, 0x00 },
149 	{ 0xEC, 0xC0 },
150 	/* GOA timing setting */
151 	{ 0xB0, 0x03 },
152 	{ 0xC0, 0x01 },
153 	{ 0xC2, 0x6F },
154 	{ 0xC3, 0x6F },
155 	{ 0xC5, 0x36 },
156 	{ 0xC8, 0x08 },
157 	{ 0xC9, 0x04 },
158 	{ 0xCA, 0x41 },
159 	{ 0xCC, 0x43 },
160 	{ 0xCF, 0x60 },
161 	{ 0xD2, 0x04 },
162 	{ 0xD3, 0x04 },
163 	{ 0xD4, 0x03 },
164 	{ 0xD5, 0x02 },
165 	{ 0xD6, 0x01 },
166 	{ 0xD7, 0x00 },
167 	{ 0xDB, 0x01 },
168 	{ 0xDE, 0x36 },
169 	{ 0xE6, 0x6F },
170 	{ 0xE7, 0x6F },
171 	/* GOE setting */
172 	{ 0xB0, 0x06 },
173 	{ 0xB8, 0xA5 },
174 	{ 0xC0, 0xA5 },
175 	{ 0xD5, 0x3F },
176 };
177 
178 static inline
179 struct kingdisplay_panel *to_kingdisplay_panel(struct drm_panel *panel)
180 {
181 	return container_of(panel, struct kingdisplay_panel, base);
182 }
183 
184 static int kingdisplay_panel_disable(struct drm_panel *panel)
185 {
186 	struct kingdisplay_panel *kingdisplay = to_kingdisplay_panel(panel);
187 	int err;
188 
189 	if (!kingdisplay->enabled)
190 		return 0;
191 
192 	err = mipi_dsi_dcs_set_display_off(kingdisplay->link);
193 	if (err < 0)
194 		DRM_DEV_ERROR(panel->dev, "failed to set display off: %d\n",
195 			      err);
196 
197 	kingdisplay->enabled = false;
198 
199 	return 0;
200 }
201 
202 static int kingdisplay_panel_unprepare(struct drm_panel *panel)
203 {
204 	struct kingdisplay_panel *kingdisplay = to_kingdisplay_panel(panel);
205 	int err;
206 
207 	if (!kingdisplay->prepared)
208 		return 0;
209 
210 	err = mipi_dsi_dcs_enter_sleep_mode(kingdisplay->link);
211 	if (err < 0) {
212 		DRM_DEV_ERROR(panel->dev, "failed to enter sleep mode: %d\n",
213 			      err);
214 		return err;
215 	}
216 
217 	/* T15: 120ms */
218 	msleep(120);
219 
220 	gpiod_set_value_cansleep(kingdisplay->enable_gpio, 0);
221 
222 	err = regulator_disable(kingdisplay->supply);
223 	if (err < 0)
224 		return err;
225 
226 	kingdisplay->prepared = false;
227 
228 	return 0;
229 }
230 
231 static int kingdisplay_panel_prepare(struct drm_panel *panel)
232 {
233 	struct kingdisplay_panel *kingdisplay = to_kingdisplay_panel(panel);
234 	int err, regulator_err;
235 	unsigned int i;
236 
237 	if (kingdisplay->prepared)
238 		return 0;
239 
240 	gpiod_set_value_cansleep(kingdisplay->enable_gpio, 0);
241 
242 	err = regulator_enable(kingdisplay->supply);
243 	if (err < 0)
244 		return err;
245 
246 	/* T2: 15ms */
247 	usleep_range(15000, 16000);
248 
249 	gpiod_set_value_cansleep(kingdisplay->enable_gpio, 1);
250 
251 	/* T4: 15ms */
252 	usleep_range(15000, 16000);
253 
254 	for (i = 0; i < ARRAY_SIZE(init_code); i++) {
255 		err = mipi_dsi_generic_write(kingdisplay->link, &init_code[i],
256 					sizeof(struct kingdisplay_panel_cmd));
257 		if (err < 0) {
258 			DRM_DEV_ERROR(panel->dev, "failed write init cmds: %d\n",
259 				      err);
260 			goto poweroff;
261 		}
262 	}
263 
264 	err = mipi_dsi_dcs_exit_sleep_mode(kingdisplay->link);
265 	if (err < 0) {
266 		DRM_DEV_ERROR(panel->dev, "failed to exit sleep mode: %d\n",
267 			      err);
268 		goto poweroff;
269 	}
270 
271 	/* T6: 120ms */
272 	msleep(120);
273 
274 	err = mipi_dsi_dcs_set_display_on(kingdisplay->link);
275 	if (err < 0) {
276 		DRM_DEV_ERROR(panel->dev, "failed to set display on: %d\n",
277 			      err);
278 		goto poweroff;
279 	}
280 
281 	/* T7: 10ms */
282 	usleep_range(10000, 11000);
283 
284 	kingdisplay->prepared = true;
285 
286 	return 0;
287 
288 poweroff:
289 	gpiod_set_value_cansleep(kingdisplay->enable_gpio, 0);
290 
291 	regulator_err = regulator_disable(kingdisplay->supply);
292 	if (regulator_err)
293 		DRM_DEV_ERROR(panel->dev, "failed to disable regulator: %d\n",
294 			      regulator_err);
295 
296 	return err;
297 }
298 
299 static int kingdisplay_panel_enable(struct drm_panel *panel)
300 {
301 	struct kingdisplay_panel *kingdisplay = to_kingdisplay_panel(panel);
302 
303 	if (kingdisplay->enabled)
304 		return 0;
305 
306 	kingdisplay->enabled = true;
307 
308 	return 0;
309 }
310 
311 static const struct drm_display_mode default_mode = {
312 	.clock = 229000,
313 	.hdisplay = 1536,
314 	.hsync_start = 1536 + 100,
315 	.hsync_end = 1536 + 100 + 24,
316 	.htotal = 1536 + 100 + 24 + 100,
317 	.vdisplay = 2048,
318 	.vsync_start = 2048 + 95,
319 	.vsync_end = 2048 + 95 + 2,
320 	.vtotal = 2048 + 95 + 2 + 23,
321 };
322 
323 static int kingdisplay_panel_get_modes(struct drm_panel *panel,
324 				       struct drm_connector *connector)
325 {
326 	struct drm_display_mode *mode;
327 
328 	mode = drm_mode_duplicate(connector->dev, &default_mode);
329 	if (!mode) {
330 		DRM_DEV_ERROR(panel->dev, "failed to add mode %ux%ux@%u\n",
331 			      default_mode.hdisplay, default_mode.vdisplay,
332 			      drm_mode_vrefresh(&default_mode));
333 		return -ENOMEM;
334 	}
335 
336 	drm_mode_set_name(mode);
337 
338 	drm_mode_probed_add(connector, mode);
339 
340 	connector->display_info.width_mm = 147;
341 	connector->display_info.height_mm = 196;
342 	connector->display_info.bpc = 8;
343 
344 	return 1;
345 }
346 
347 static const struct drm_panel_funcs kingdisplay_panel_funcs = {
348 	.disable = kingdisplay_panel_disable,
349 	.unprepare = kingdisplay_panel_unprepare,
350 	.prepare = kingdisplay_panel_prepare,
351 	.enable = kingdisplay_panel_enable,
352 	.get_modes = kingdisplay_panel_get_modes,
353 };
354 
355 static const struct of_device_id kingdisplay_of_match[] = {
356 	{ .compatible = "kingdisplay,kd097d04", },
357 	{ }
358 };
359 MODULE_DEVICE_TABLE(of, kingdisplay_of_match);
360 
361 static int kingdisplay_panel_add(struct kingdisplay_panel *kingdisplay)
362 {
363 	struct device *dev = &kingdisplay->link->dev;
364 	int err;
365 
366 	kingdisplay->supply = devm_regulator_get(dev, "power");
367 	if (IS_ERR(kingdisplay->supply))
368 		return PTR_ERR(kingdisplay->supply);
369 
370 	kingdisplay->enable_gpio = devm_gpiod_get_optional(dev, "enable",
371 							   GPIOD_OUT_HIGH);
372 	if (IS_ERR(kingdisplay->enable_gpio)) {
373 		err = PTR_ERR(kingdisplay->enable_gpio);
374 		dev_dbg(dev, "failed to get enable gpio: %d\n", err);
375 		kingdisplay->enable_gpio = NULL;
376 	}
377 
378 	drm_panel_init(&kingdisplay->base, &kingdisplay->link->dev,
379 		       &kingdisplay_panel_funcs, DRM_MODE_CONNECTOR_DSI);
380 
381 	err = drm_panel_of_backlight(&kingdisplay->base);
382 	if (err)
383 		return err;
384 
385 	return drm_panel_add(&kingdisplay->base);
386 }
387 
388 static void kingdisplay_panel_del(struct kingdisplay_panel *kingdisplay)
389 {
390 	drm_panel_remove(&kingdisplay->base);
391 }
392 
393 static int kingdisplay_panel_probe(struct mipi_dsi_device *dsi)
394 {
395 	struct kingdisplay_panel *kingdisplay;
396 	int err;
397 
398 	dsi->lanes = 4;
399 	dsi->format = MIPI_DSI_FMT_RGB888;
400 	dsi->mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_BURST |
401 			  MIPI_DSI_MODE_LPM;
402 
403 	kingdisplay = devm_kzalloc(&dsi->dev, sizeof(*kingdisplay), GFP_KERNEL);
404 	if (!kingdisplay)
405 		return -ENOMEM;
406 
407 	mipi_dsi_set_drvdata(dsi, kingdisplay);
408 	kingdisplay->link = dsi;
409 
410 	err = kingdisplay_panel_add(kingdisplay);
411 	if (err < 0)
412 		return err;
413 
414 	return mipi_dsi_attach(dsi);
415 }
416 
417 static int kingdisplay_panel_remove(struct mipi_dsi_device *dsi)
418 {
419 	struct kingdisplay_panel *kingdisplay = mipi_dsi_get_drvdata(dsi);
420 	int err;
421 
422 	err = drm_panel_unprepare(&kingdisplay->base);
423 	if (err < 0)
424 		DRM_DEV_ERROR(&dsi->dev, "failed to unprepare panel: %d\n",
425 			      err);
426 
427 	err = drm_panel_disable(&kingdisplay->base);
428 	if (err < 0)
429 		DRM_DEV_ERROR(&dsi->dev, "failed to disable panel: %d\n", err);
430 
431 	err = mipi_dsi_detach(dsi);
432 	if (err < 0)
433 		DRM_DEV_ERROR(&dsi->dev, "failed to detach from DSI host: %d\n",
434 			      err);
435 
436 	kingdisplay_panel_del(kingdisplay);
437 
438 	return 0;
439 }
440 
441 static void kingdisplay_panel_shutdown(struct mipi_dsi_device *dsi)
442 {
443 	struct kingdisplay_panel *kingdisplay = mipi_dsi_get_drvdata(dsi);
444 
445 	drm_panel_unprepare(&kingdisplay->base);
446 	drm_panel_disable(&kingdisplay->base);
447 }
448 
449 static struct mipi_dsi_driver kingdisplay_panel_driver = {
450 	.driver = {
451 		.name = "panel-kingdisplay-kd097d04",
452 		.of_match_table = kingdisplay_of_match,
453 	},
454 	.probe = kingdisplay_panel_probe,
455 	.remove = kingdisplay_panel_remove,
456 	.shutdown = kingdisplay_panel_shutdown,
457 };
458 module_mipi_dsi_driver(kingdisplay_panel_driver);
459 
460 MODULE_AUTHOR("Chris Zhong <zyw@rock-chips.com>");
461 MODULE_AUTHOR("Nickey Yang <nickey.yang@rock-chips.com>");
462 MODULE_DESCRIPTION("kingdisplay KD097D04 panel driver");
463 MODULE_LICENSE("GPL v2");
464