1// SPDX-License-Identifier: GPL-2.0-only
2/*
3 * Generic DSI Command Mode panel driver
4 *
5 * Copyright (C) 2013 Texas Instruments Incorporated - https://www.ti.com/
6 * Author: Tomi Valkeinen <tomi.valkeinen@ti.com>
7 */
8
9#include <linux/backlight.h>
10#include <linux/delay.h>
11#include <linux/gpio/consumer.h>
12#include <linux/jiffies.h>
13#include <linux/module.h>
14#include <linux/of.h>
15#include <linux/regulator/consumer.h>
16
17#include <drm/drm_connector.h>
18#include <drm/drm_mipi_dsi.h>
19#include <drm/drm_modes.h>
20#include <drm/drm_panel.h>
21
22#include <video/mipi_display.h>
23
24#define DCS_GET_ID1 0xda
25#define DCS_GET_ID2 0xdb
26#define DCS_GET_ID3 0xdc
27
28#define DCS_REGULATOR_SUPPLY_NUM 2
29
30static const struct of_device_id dsicm_of_match[];
31
32struct dsic_panel_data {
33 u32 xres;
34 u32 yres;
35 u32 refresh;
36 u32 width_mm;
37 u32 height_mm;
38 u32 max_hs_rate;
39 u32 max_lp_rate;
40 bool te_support;
41};
42
43struct panel_drv_data {
44 struct mipi_dsi_device *dsi;
45 struct drm_panel panel;
46 struct drm_display_mode mode;
47
48 struct mutex lock;
49
50 struct backlight_device *bldev;
51 struct backlight_device *extbldev;
52
53 unsigned long hw_guard_end; /* next value of jiffies when we can
54 * issue the next sleep in/out command
55 */
56 unsigned long hw_guard_wait; /* max guard time in jiffies */
57
58 const struct dsic_panel_data *panel_data;
59
60 struct gpio_desc *reset_gpio;
61
62 struct regulator_bulk_data supplies[DCS_REGULATOR_SUPPLY_NUM];
63
64 bool use_dsi_backlight;
65
66 /* runtime variables */
67 bool enabled;
68
69 bool intro_printed;
70};
71
72static inline struct panel_drv_data *panel_to_ddata(struct drm_panel *panel)
73{
74 return container_of(panel, struct panel_drv_data, panel);
75}
76
77static void dsicm_bl_power(struct panel_drv_data *ddata, bool enable)
78{
79 struct backlight_device *backlight;
80
81 if (ddata->bldev)
82 backlight = ddata->bldev;
83 else if (ddata->extbldev)
84 backlight = ddata->extbldev;
85 else
86 return;
87
88 if (enable)
89 backlight_enable(bd: backlight);
90 else
91 backlight_disable(bd: backlight);
92}
93
94static void hw_guard_start(struct panel_drv_data *ddata, int guard_msec)
95{
96 ddata->hw_guard_wait = msecs_to_jiffies(m: guard_msec);
97 ddata->hw_guard_end = jiffies + ddata->hw_guard_wait;
98}
99
100static void hw_guard_wait(struct panel_drv_data *ddata)
101{
102 unsigned long wait = ddata->hw_guard_end - jiffies;
103
104 if ((long)wait > 0 && wait <= ddata->hw_guard_wait) {
105 set_current_state(TASK_UNINTERRUPTIBLE);
106 schedule_timeout(timeout: wait);
107 }
108}
109
110static int dsicm_dcs_read_1(struct panel_drv_data *ddata, u8 dcs_cmd, u8 *data)
111{
112 return mipi_dsi_dcs_read(dsi: ddata->dsi, cmd: dcs_cmd, data, len: 1);
113}
114
115static int dsicm_dcs_write_1(struct panel_drv_data *ddata, u8 dcs_cmd, u8 param)
116{
117 return mipi_dsi_dcs_write(dsi: ddata->dsi, cmd: dcs_cmd, data: &param, len: 1);
118}
119
120static int dsicm_sleep_in(struct panel_drv_data *ddata)
121
122{
123 int r;
124
125 hw_guard_wait(ddata);
126
127 r = mipi_dsi_dcs_enter_sleep_mode(dsi: ddata->dsi);
128 if (r)
129 return r;
130
131 hw_guard_start(ddata, guard_msec: 120);
132
133 usleep_range(min: 5000, max: 10000);
134
135 return 0;
136}
137
138static int dsicm_sleep_out(struct panel_drv_data *ddata)
139{
140 int r;
141
142 hw_guard_wait(ddata);
143
144 r = mipi_dsi_dcs_exit_sleep_mode(dsi: ddata->dsi);
145 if (r)
146 return r;
147
148 hw_guard_start(ddata, guard_msec: 120);
149
150 usleep_range(min: 5000, max: 10000);
151
152 return 0;
153}
154
155static int dsicm_get_id(struct panel_drv_data *ddata, u8 *id1, u8 *id2, u8 *id3)
156{
157 int r;
158
159 r = dsicm_dcs_read_1(ddata, DCS_GET_ID1, data: id1);
160 if (r)
161 return r;
162 r = dsicm_dcs_read_1(ddata, DCS_GET_ID2, data: id2);
163 if (r)
164 return r;
165 r = dsicm_dcs_read_1(ddata, DCS_GET_ID3, data: id3);
166 if (r)
167 return r;
168
169 return 0;
170}
171
172static int dsicm_set_update_window(struct panel_drv_data *ddata)
173{
174 struct mipi_dsi_device *dsi = ddata->dsi;
175 int r;
176
177 r = mipi_dsi_dcs_set_column_address(dsi, start: 0, end: ddata->mode.hdisplay - 1);
178 if (r < 0)
179 return r;
180
181 r = mipi_dsi_dcs_set_page_address(dsi, start: 0, end: ddata->mode.vdisplay - 1);
182 if (r < 0)
183 return r;
184
185 return 0;
186}
187
188static int dsicm_bl_update_status(struct backlight_device *dev)
189{
190 struct panel_drv_data *ddata = dev_get_drvdata(dev: &dev->dev);
191 int r = 0;
192 int level = backlight_get_brightness(bd: dev);
193
194 dev_dbg(&ddata->dsi->dev, "update brightness to %d\n", level);
195
196 mutex_lock(&ddata->lock);
197
198 if (ddata->enabled)
199 r = dsicm_dcs_write_1(ddata, dcs_cmd: MIPI_DCS_SET_DISPLAY_BRIGHTNESS,
200 param: level);
201
202 mutex_unlock(lock: &ddata->lock);
203
204 return r;
205}
206
207static int dsicm_bl_get_intensity(struct backlight_device *dev)
208{
209 return backlight_get_brightness(bd: dev);
210}
211
212static const struct backlight_ops dsicm_bl_ops = {
213 .get_brightness = dsicm_bl_get_intensity,
214 .update_status = dsicm_bl_update_status,
215};
216
217static ssize_t num_dsi_errors_show(struct device *dev,
218 struct device_attribute *attr, char *buf)
219{
220 struct panel_drv_data *ddata = dev_get_drvdata(dev);
221 u8 errors = 0;
222 int r = -ENODEV;
223
224 mutex_lock(&ddata->lock);
225
226 if (ddata->enabled)
227 r = dsicm_dcs_read_1(ddata, dcs_cmd: MIPI_DCS_GET_ERROR_COUNT_ON_DSI, data: &errors);
228
229 mutex_unlock(lock: &ddata->lock);
230
231 if (r)
232 return r;
233
234 return sysfs_emit(buf, fmt: "%d\n", errors);
235}
236
237static ssize_t hw_revision_show(struct device *dev,
238 struct device_attribute *attr, char *buf)
239{
240 struct panel_drv_data *ddata = dev_get_drvdata(dev);
241 u8 id1, id2, id3;
242 int r = -ENODEV;
243
244 mutex_lock(&ddata->lock);
245
246 if (ddata->enabled)
247 r = dsicm_get_id(ddata, id1: &id1, id2: &id2, id3: &id3);
248
249 mutex_unlock(lock: &ddata->lock);
250
251 if (r)
252 return r;
253
254 return sysfs_emit(buf, fmt: "%02x.%02x.%02x\n", id1, id2, id3);
255}
256
257static DEVICE_ATTR_RO(num_dsi_errors);
258static DEVICE_ATTR_RO(hw_revision);
259
260static struct attribute *dsicm_attrs[] = {
261 &dev_attr_num_dsi_errors.attr,
262 &dev_attr_hw_revision.attr,
263 NULL,
264};
265
266static const struct attribute_group dsicm_attr_group = {
267 .attrs = dsicm_attrs,
268};
269
270static void dsicm_hw_reset(struct panel_drv_data *ddata)
271{
272 gpiod_set_value(desc: ddata->reset_gpio, value: 1);
273 udelay(10);
274 /* reset the panel */
275 gpiod_set_value(desc: ddata->reset_gpio, value: 0);
276 /* assert reset */
277 udelay(10);
278 gpiod_set_value(desc: ddata->reset_gpio, value: 1);
279 /* wait after releasing reset */
280 usleep_range(min: 5000, max: 10000);
281}
282
283static int dsicm_power_on(struct panel_drv_data *ddata)
284{
285 u8 id1, id2, id3;
286 int r;
287
288 dsicm_hw_reset(ddata);
289
290 ddata->dsi->mode_flags |= MIPI_DSI_MODE_LPM;
291
292 r = dsicm_sleep_out(ddata);
293 if (r)
294 goto err;
295
296 r = dsicm_get_id(ddata, id1: &id1, id2: &id2, id3: &id3);
297 if (r)
298 goto err;
299
300 r = dsicm_dcs_write_1(ddata, dcs_cmd: MIPI_DCS_SET_DISPLAY_BRIGHTNESS, param: 0xff);
301 if (r)
302 goto err;
303
304 r = dsicm_dcs_write_1(ddata, dcs_cmd: MIPI_DCS_WRITE_CONTROL_DISPLAY,
305 param: (1<<2) | (1<<5)); /* BL | BCTRL */
306 if (r)
307 goto err;
308
309 r = mipi_dsi_dcs_set_pixel_format(dsi: ddata->dsi, MIPI_DCS_PIXEL_FMT_24BIT);
310 if (r)
311 goto err;
312
313 r = dsicm_set_update_window(ddata);
314 if (r)
315 goto err;
316
317 r = mipi_dsi_dcs_set_display_on(dsi: ddata->dsi);
318 if (r)
319 goto err;
320
321 if (ddata->panel_data->te_support) {
322 r = mipi_dsi_dcs_set_tear_on(dsi: ddata->dsi, mode: MIPI_DSI_DCS_TEAR_MODE_VBLANK);
323 if (r)
324 goto err;
325 }
326
327 /* possible panel bug */
328 msleep(msecs: 100);
329
330 ddata->enabled = true;
331
332 if (!ddata->intro_printed) {
333 dev_info(&ddata->dsi->dev, "panel revision %02x.%02x.%02x\n",
334 id1, id2, id3);
335 ddata->intro_printed = true;
336 }
337
338 ddata->dsi->mode_flags &= ~MIPI_DSI_MODE_LPM;
339
340 return 0;
341err:
342 dev_err(&ddata->dsi->dev, "error while enabling panel, issuing HW reset\n");
343
344 dsicm_hw_reset(ddata);
345
346 return r;
347}
348
349static int dsicm_power_off(struct panel_drv_data *ddata)
350{
351 int r;
352
353 ddata->enabled = false;
354
355 r = mipi_dsi_dcs_set_display_off(dsi: ddata->dsi);
356 if (!r)
357 r = dsicm_sleep_in(ddata);
358
359 if (r) {
360 dev_err(&ddata->dsi->dev,
361 "error disabling panel, issuing HW reset\n");
362 dsicm_hw_reset(ddata);
363 }
364
365 return r;
366}
367
368static int dsicm_prepare(struct drm_panel *panel)
369{
370 struct panel_drv_data *ddata = panel_to_ddata(panel);
371 int r;
372
373 r = regulator_bulk_enable(ARRAY_SIZE(ddata->supplies), consumers: ddata->supplies);
374 if (r)
375 dev_err(&ddata->dsi->dev, "failed to enable supplies: %d\n", r);
376
377 return r;
378}
379
380static int dsicm_enable(struct drm_panel *panel)
381{
382 struct panel_drv_data *ddata = panel_to_ddata(panel);
383 int r;
384
385 mutex_lock(&ddata->lock);
386
387 r = dsicm_power_on(ddata);
388 if (r)
389 goto err;
390
391 mutex_unlock(lock: &ddata->lock);
392
393 dsicm_bl_power(ddata, enable: true);
394
395 return 0;
396err:
397 dev_err(&ddata->dsi->dev, "enable failed (%d)\n", r);
398 mutex_unlock(lock: &ddata->lock);
399 return r;
400}
401
402static int dsicm_unprepare(struct drm_panel *panel)
403{
404 struct panel_drv_data *ddata = panel_to_ddata(panel);
405 int r;
406
407 r = regulator_bulk_disable(ARRAY_SIZE(ddata->supplies), consumers: ddata->supplies);
408 if (r)
409 dev_err(&ddata->dsi->dev, "failed to disable supplies: %d\n", r);
410
411 return r;
412}
413
414static int dsicm_disable(struct drm_panel *panel)
415{
416 struct panel_drv_data *ddata = panel_to_ddata(panel);
417 int r;
418
419 dsicm_bl_power(ddata, enable: false);
420
421 mutex_lock(&ddata->lock);
422
423 r = dsicm_power_off(ddata);
424
425 mutex_unlock(lock: &ddata->lock);
426
427 return r;
428}
429
430static int dsicm_get_modes(struct drm_panel *panel,
431 struct drm_connector *connector)
432{
433 struct panel_drv_data *ddata = panel_to_ddata(panel);
434 struct drm_display_mode *mode;
435
436 mode = drm_mode_duplicate(dev: connector->dev, mode: &ddata->mode);
437 if (!mode) {
438 dev_err(&ddata->dsi->dev, "failed to add mode %ux%ux@%u kHz\n",
439 ddata->mode.hdisplay, ddata->mode.vdisplay,
440 ddata->mode.clock);
441 return -ENOMEM;
442 }
443
444 connector->display_info.width_mm = ddata->panel_data->width_mm;
445 connector->display_info.height_mm = ddata->panel_data->height_mm;
446
447 drm_mode_probed_add(connector, mode);
448
449 return 1;
450}
451
452static const struct drm_panel_funcs dsicm_panel_funcs = {
453 .unprepare = dsicm_unprepare,
454 .disable = dsicm_disable,
455 .prepare = dsicm_prepare,
456 .enable = dsicm_enable,
457 .get_modes = dsicm_get_modes,
458};
459
460static int dsicm_probe_of(struct mipi_dsi_device *dsi)
461{
462 struct backlight_device *backlight;
463 struct panel_drv_data *ddata = mipi_dsi_get_drvdata(dsi);
464 int err;
465 struct drm_display_mode *mode = &ddata->mode;
466
467 ddata->reset_gpio = devm_gpiod_get(dev: &dsi->dev, con_id: "reset", flags: GPIOD_OUT_LOW);
468 if (IS_ERR(ptr: ddata->reset_gpio)) {
469 err = PTR_ERR(ptr: ddata->reset_gpio);
470 dev_err(&dsi->dev, "reset gpio request failed: %d", err);
471 return err;
472 }
473
474 mode->hdisplay = mode->hsync_start = mode->hsync_end = mode->htotal =
475 ddata->panel_data->xres;
476 mode->vdisplay = mode->vsync_start = mode->vsync_end = mode->vtotal =
477 ddata->panel_data->yres;
478 mode->clock = ddata->panel_data->xres * ddata->panel_data->yres *
479 ddata->panel_data->refresh / 1000;
480 mode->width_mm = ddata->panel_data->width_mm;
481 mode->height_mm = ddata->panel_data->height_mm;
482 mode->type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED;
483 drm_mode_set_name(mode);
484
485 ddata->supplies[0].supply = "vpnl";
486 ddata->supplies[1].supply = "vddi";
487 err = devm_regulator_bulk_get(dev: &dsi->dev, ARRAY_SIZE(ddata->supplies),
488 consumers: ddata->supplies);
489 if (err)
490 return err;
491
492 backlight = devm_of_find_backlight(dev: &dsi->dev);
493 if (IS_ERR(ptr: backlight))
494 return PTR_ERR(ptr: backlight);
495
496 /* If no backlight device is found assume native backlight support */
497 if (backlight)
498 ddata->extbldev = backlight;
499 else
500 ddata->use_dsi_backlight = true;
501
502 return 0;
503}
504
505static int dsicm_probe(struct mipi_dsi_device *dsi)
506{
507 struct panel_drv_data *ddata;
508 struct backlight_device *bldev = NULL;
509 struct device *dev = &dsi->dev;
510 int r;
511
512 dev_dbg(dev, "probe\n");
513
514 ddata = devm_kzalloc(dev, size: sizeof(*ddata), GFP_KERNEL);
515 if (!ddata)
516 return -ENOMEM;
517
518 mipi_dsi_set_drvdata(dsi, data: ddata);
519 ddata->dsi = dsi;
520
521 ddata->panel_data = of_device_get_match_data(dev);
522 if (!ddata->panel_data)
523 return -ENODEV;
524
525 r = dsicm_probe_of(dsi);
526 if (r)
527 return r;
528
529 mutex_init(&ddata->lock);
530
531 dsicm_hw_reset(ddata);
532
533 drm_panel_init(panel: &ddata->panel, dev, funcs: &dsicm_panel_funcs,
534 DRM_MODE_CONNECTOR_DSI);
535
536 if (ddata->use_dsi_backlight) {
537 struct backlight_properties props = { 0 };
538 props.max_brightness = 255;
539 props.type = BACKLIGHT_RAW;
540
541 bldev = devm_backlight_device_register(dev, name: dev_name(dev),
542 parent: dev, devdata: ddata, ops: &dsicm_bl_ops, props: &props);
543 if (IS_ERR(ptr: bldev)) {
544 r = PTR_ERR(ptr: bldev);
545 goto err_bl;
546 }
547
548 ddata->bldev = bldev;
549 }
550
551 r = sysfs_create_group(kobj: &dev->kobj, grp: &dsicm_attr_group);
552 if (r) {
553 dev_err(dev, "failed to create sysfs files\n");
554 goto err_bl;
555 }
556
557 dsi->lanes = 2;
558 dsi->format = MIPI_DSI_FMT_RGB888;
559 dsi->mode_flags = MIPI_DSI_CLOCK_NON_CONTINUOUS |
560 MIPI_DSI_MODE_NO_EOT_PACKET;
561 dsi->hs_rate = ddata->panel_data->max_hs_rate;
562 dsi->lp_rate = ddata->panel_data->max_lp_rate;
563
564 drm_panel_add(panel: &ddata->panel);
565
566 r = mipi_dsi_attach(dsi);
567 if (r < 0)
568 goto err_dsi_attach;
569
570 return 0;
571
572err_dsi_attach:
573 drm_panel_remove(panel: &ddata->panel);
574 sysfs_remove_group(kobj: &dsi->dev.kobj, grp: &dsicm_attr_group);
575err_bl:
576 if (ddata->extbldev)
577 put_device(dev: &ddata->extbldev->dev);
578
579 return r;
580}
581
582static void dsicm_remove(struct mipi_dsi_device *dsi)
583{
584 struct panel_drv_data *ddata = mipi_dsi_get_drvdata(dsi);
585
586 dev_dbg(&dsi->dev, "remove\n");
587
588 mipi_dsi_detach(dsi);
589
590 drm_panel_remove(panel: &ddata->panel);
591
592 sysfs_remove_group(kobj: &dsi->dev.kobj, grp: &dsicm_attr_group);
593
594 if (ddata->extbldev)
595 put_device(dev: &ddata->extbldev->dev);
596}
597
598static const struct dsic_panel_data taal_data = {
599 .xres = 864,
600 .yres = 480,
601 .refresh = 60,
602 .width_mm = 0,
603 .height_mm = 0,
604 .max_hs_rate = 300000000,
605 .max_lp_rate = 10000000,
606 .te_support = true,
607};
608
609static const struct dsic_panel_data himalaya_data = {
610 .xres = 480,
611 .yres = 864,
612 .refresh = 60,
613 .width_mm = 49,
614 .height_mm = 88,
615 .max_hs_rate = 300000000,
616 .max_lp_rate = 10000000,
617 .te_support = false,
618};
619
620static const struct dsic_panel_data droid4_data = {
621 .xres = 540,
622 .yres = 960,
623 .refresh = 60,
624 .width_mm = 50,
625 .height_mm = 89,
626 .max_hs_rate = 300000000,
627 .max_lp_rate = 10000000,
628 .te_support = false,
629};
630
631static const struct of_device_id dsicm_of_match[] = {
632 { .compatible = "tpo,taal", .data = &taal_data },
633 { .compatible = "nokia,himalaya", &himalaya_data },
634 { .compatible = "motorola,droid4-panel", &droid4_data },
635 {},
636};
637
638MODULE_DEVICE_TABLE(of, dsicm_of_match);
639
640static struct mipi_dsi_driver dsicm_driver = {
641 .probe = dsicm_probe,
642 .remove = dsicm_remove,
643 .driver = {
644 .name = "panel-dsi-cm",
645 .of_match_table = dsicm_of_match,
646 },
647};
648module_mipi_dsi_driver(dsicm_driver);
649
650MODULE_AUTHOR("Tomi Valkeinen <tomi.valkeinen@ti.com>");
651MODULE_DESCRIPTION("Generic DSI Command Mode Panel Driver");
652MODULE_LICENSE("GPL");
653

source code of linux/drivers/gpu/drm/panel/panel-dsi-cm.c