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 	.vrefresh = 60,
322 };
323 
324 static int kingdisplay_panel_get_modes(struct drm_panel *panel,
325 				       struct drm_connector *connector)
326 {
327 	struct drm_display_mode *mode;
328 
329 	mode = drm_mode_duplicate(connector->dev, &default_mode);
330 	if (!mode) {
331 		DRM_DEV_ERROR(panel->dev, "failed to add mode %ux%ux@%u\n",
332 			      default_mode.hdisplay, default_mode.vdisplay,
333 			      default_mode.vrefresh);
334 		return -ENOMEM;
335 	}
336 
337 	drm_mode_set_name(mode);
338 
339 	drm_mode_probed_add(connector, mode);
340 
341 	connector->display_info.width_mm = 147;
342 	connector->display_info.height_mm = 196;
343 	connector->display_info.bpc = 8;
344 
345 	return 1;
346 }
347 
348 static const struct drm_panel_funcs kingdisplay_panel_funcs = {
349 	.disable = kingdisplay_panel_disable,
350 	.unprepare = kingdisplay_panel_unprepare,
351 	.prepare = kingdisplay_panel_prepare,
352 	.enable = kingdisplay_panel_enable,
353 	.get_modes = kingdisplay_panel_get_modes,
354 };
355 
356 static const struct of_device_id kingdisplay_of_match[] = {
357 	{ .compatible = "kingdisplay,kd097d04", },
358 	{ }
359 };
360 MODULE_DEVICE_TABLE(of, kingdisplay_of_match);
361 
362 static int kingdisplay_panel_add(struct kingdisplay_panel *kingdisplay)
363 {
364 	struct device *dev = &kingdisplay->link->dev;
365 	int err;
366 
367 	kingdisplay->supply = devm_regulator_get(dev, "power");
368 	if (IS_ERR(kingdisplay->supply))
369 		return PTR_ERR(kingdisplay->supply);
370 
371 	kingdisplay->enable_gpio = devm_gpiod_get_optional(dev, "enable",
372 							   GPIOD_OUT_HIGH);
373 	if (IS_ERR(kingdisplay->enable_gpio)) {
374 		err = PTR_ERR(kingdisplay->enable_gpio);
375 		dev_dbg(dev, "failed to get enable gpio: %d\n", err);
376 		kingdisplay->enable_gpio = NULL;
377 	}
378 
379 	drm_panel_init(&kingdisplay->base, &kingdisplay->link->dev,
380 		       &kingdisplay_panel_funcs, DRM_MODE_CONNECTOR_DSI);
381 
382 	err = drm_panel_of_backlight(&kingdisplay->base);
383 	if (err)
384 		return err;
385 
386 	return drm_panel_add(&kingdisplay->base);
387 }
388 
389 static void kingdisplay_panel_del(struct kingdisplay_panel *kingdisplay)
390 {
391 	drm_panel_remove(&kingdisplay->base);
392 }
393 
394 static int kingdisplay_panel_probe(struct mipi_dsi_device *dsi)
395 {
396 	struct kingdisplay_panel *kingdisplay;
397 	int err;
398 
399 	dsi->lanes = 4;
400 	dsi->format = MIPI_DSI_FMT_RGB888;
401 	dsi->mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_BURST |
402 			  MIPI_DSI_MODE_LPM;
403 
404 	kingdisplay = devm_kzalloc(&dsi->dev, sizeof(*kingdisplay), GFP_KERNEL);
405 	if (!kingdisplay)
406 		return -ENOMEM;
407 
408 	mipi_dsi_set_drvdata(dsi, kingdisplay);
409 	kingdisplay->link = dsi;
410 
411 	err = kingdisplay_panel_add(kingdisplay);
412 	if (err < 0)
413 		return err;
414 
415 	return mipi_dsi_attach(dsi);
416 }
417 
418 static int kingdisplay_panel_remove(struct mipi_dsi_device *dsi)
419 {
420 	struct kingdisplay_panel *kingdisplay = mipi_dsi_get_drvdata(dsi);
421 	int err;
422 
423 	err = drm_panel_unprepare(&kingdisplay->base);
424 	if (err < 0)
425 		DRM_DEV_ERROR(&dsi->dev, "failed to unprepare panel: %d\n",
426 			      err);
427 
428 	err = drm_panel_disable(&kingdisplay->base);
429 	if (err < 0)
430 		DRM_DEV_ERROR(&dsi->dev, "failed to disable panel: %d\n", err);
431 
432 	err = mipi_dsi_detach(dsi);
433 	if (err < 0)
434 		DRM_DEV_ERROR(&dsi->dev, "failed to detach from DSI host: %d\n",
435 			      err);
436 
437 	kingdisplay_panel_del(kingdisplay);
438 
439 	return 0;
440 }
441 
442 static void kingdisplay_panel_shutdown(struct mipi_dsi_device *dsi)
443 {
444 	struct kingdisplay_panel *kingdisplay = mipi_dsi_get_drvdata(dsi);
445 
446 	drm_panel_unprepare(&kingdisplay->base);
447 	drm_panel_disable(&kingdisplay->base);
448 }
449 
450 static struct mipi_dsi_driver kingdisplay_panel_driver = {
451 	.driver = {
452 		.name = "panel-kingdisplay-kd097d04",
453 		.of_match_table = kingdisplay_of_match,
454 	},
455 	.probe = kingdisplay_panel_probe,
456 	.remove = kingdisplay_panel_remove,
457 	.shutdown = kingdisplay_panel_shutdown,
458 };
459 module_mipi_dsi_driver(kingdisplay_panel_driver);
460 
461 MODULE_AUTHOR("Chris Zhong <zyw@rock-chips.com>");
462 MODULE_AUTHOR("Nickey Yang <nickey.yang@rock-chips.com>");
463 MODULE_DESCRIPTION("kingdisplay KD097D04 panel driver");
464 MODULE_LICENSE("GPL v2");
465