Merge tag 'for-5.13-rc2-tag' of git://git.kernel.org/pub/scm/linux/kernel/git/kdave...
[linux-2.6-microblaze.git] / drivers / gpu / drm / panel / panel-innolux-p079zca.c
1 // SPDX-License-Identifier: GPL-2.0-or-later
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/of_device.h>
11 #include <linux/regulator/consumer.h>
12
13 #include <video/mipi_display.h>
14
15 #include <drm/drm_crtc.h>
16 #include <drm/drm_device.h>
17 #include <drm/drm_mipi_dsi.h>
18 #include <drm/drm_modes.h>
19 #include <drm/drm_panel.h>
20
21 struct panel_init_cmd {
22         size_t len;
23         const char *data;
24 };
25
26 #define _INIT_CMD(...) { \
27         .len = sizeof((char[]){__VA_ARGS__}), \
28         .data = (char[]){__VA_ARGS__} }
29
30 struct panel_desc {
31         const struct drm_display_mode *mode;
32         unsigned int bpc;
33         struct {
34                 unsigned int width;
35                 unsigned int height;
36         } size;
37
38         unsigned long flags;
39         enum mipi_dsi_pixel_format format;
40         const struct panel_init_cmd *init_cmds;
41         unsigned int lanes;
42         const char * const *supply_names;
43         unsigned int num_supplies;
44         unsigned int sleep_mode_delay;
45         unsigned int power_down_delay;
46 };
47
48 struct innolux_panel {
49         struct drm_panel base;
50         struct mipi_dsi_device *link;
51         const struct panel_desc *desc;
52
53         struct regulator_bulk_data *supplies;
54         struct gpio_desc *enable_gpio;
55
56         bool prepared;
57         bool enabled;
58 };
59
60 static inline struct innolux_panel *to_innolux_panel(struct drm_panel *panel)
61 {
62         return container_of(panel, struct innolux_panel, base);
63 }
64
65 static int innolux_panel_disable(struct drm_panel *panel)
66 {
67         struct innolux_panel *innolux = to_innolux_panel(panel);
68
69         if (!innolux->enabled)
70                 return 0;
71
72         innolux->enabled = false;
73
74         return 0;
75 }
76
77 static int innolux_panel_unprepare(struct drm_panel *panel)
78 {
79         struct innolux_panel *innolux = to_innolux_panel(panel);
80         int err;
81
82         if (!innolux->prepared)
83                 return 0;
84
85         err = mipi_dsi_dcs_set_display_off(innolux->link);
86         if (err < 0)
87                 dev_err(panel->dev, "failed to set display off: %d\n", err);
88
89         err = mipi_dsi_dcs_enter_sleep_mode(innolux->link);
90         if (err < 0) {
91                 dev_err(panel->dev, "failed to enter sleep mode: %d\n", err);
92                 return err;
93         }
94
95         if (innolux->desc->sleep_mode_delay)
96                 msleep(innolux->desc->sleep_mode_delay);
97
98         gpiod_set_value_cansleep(innolux->enable_gpio, 0);
99
100         if (innolux->desc->power_down_delay)
101                 msleep(innolux->desc->power_down_delay);
102
103         err = regulator_bulk_disable(innolux->desc->num_supplies,
104                                      innolux->supplies);
105         if (err < 0)
106                 return err;
107
108         innolux->prepared = false;
109
110         return 0;
111 }
112
113 static int innolux_panel_prepare(struct drm_panel *panel)
114 {
115         struct innolux_panel *innolux = to_innolux_panel(panel);
116         int err;
117
118         if (innolux->prepared)
119                 return 0;
120
121         gpiod_set_value_cansleep(innolux->enable_gpio, 0);
122
123         err = regulator_bulk_enable(innolux->desc->num_supplies,
124                                     innolux->supplies);
125         if (err < 0)
126                 return err;
127
128         /* p079zca: t2 (20ms), p097pfg: t4 (15ms) */
129         usleep_range(20000, 21000);
130
131         gpiod_set_value_cansleep(innolux->enable_gpio, 1);
132
133         /* p079zca: t4, p097pfg: t5 */
134         usleep_range(20000, 21000);
135
136         if (innolux->desc->init_cmds) {
137                 const struct panel_init_cmd *cmds =
138                                         innolux->desc->init_cmds;
139                 unsigned int i;
140
141                 for (i = 0; cmds[i].len != 0; i++) {
142                         const struct panel_init_cmd *cmd = &cmds[i];
143
144                         err = mipi_dsi_generic_write(innolux->link, cmd->data,
145                                                      cmd->len);
146                         if (err < 0) {
147                                 dev_err(panel->dev, "failed to write command %u\n", i);
148                                 goto poweroff;
149                         }
150
151                         /*
152                          * Included by random guessing, because without this
153                          * (or at least, some delay), the panel sometimes
154                          * didn't appear to pick up the command sequence.
155                          */
156                         err = mipi_dsi_dcs_nop(innolux->link);
157                         if (err < 0) {
158                                 dev_err(panel->dev, "failed to send DCS nop: %d\n", err);
159                                 goto poweroff;
160                         }
161                 }
162         }
163
164         err = mipi_dsi_dcs_exit_sleep_mode(innolux->link);
165         if (err < 0) {
166                 dev_err(panel->dev, "failed to exit sleep mode: %d\n", err);
167                 goto poweroff;
168         }
169
170         /* T6: 120ms - 1000ms*/
171         msleep(120);
172
173         err = mipi_dsi_dcs_set_display_on(innolux->link);
174         if (err < 0) {
175                 dev_err(panel->dev, "failed to set display on: %d\n", err);
176                 goto poweroff;
177         }
178
179         /* T7: 5ms */
180         usleep_range(5000, 6000);
181
182         innolux->prepared = true;
183
184         return 0;
185
186 poweroff:
187         gpiod_set_value_cansleep(innolux->enable_gpio, 0);
188         regulator_bulk_disable(innolux->desc->num_supplies, innolux->supplies);
189
190         return err;
191 }
192
193 static int innolux_panel_enable(struct drm_panel *panel)
194 {
195         struct innolux_panel *innolux = to_innolux_panel(panel);
196
197         if (innolux->enabled)
198                 return 0;
199
200         innolux->enabled = true;
201
202         return 0;
203 }
204
205 static const char * const innolux_p079zca_supply_names[] = {
206         "power",
207 };
208
209 static const struct drm_display_mode innolux_p079zca_mode = {
210         .clock = 56900,
211         .hdisplay = 768,
212         .hsync_start = 768 + 40,
213         .hsync_end = 768 + 40 + 40,
214         .htotal = 768 + 40 + 40 + 40,
215         .vdisplay = 1024,
216         .vsync_start = 1024 + 20,
217         .vsync_end = 1024 + 20 + 4,
218         .vtotal = 1024 + 20 + 4 + 20,
219 };
220
221 static const struct panel_desc innolux_p079zca_panel_desc = {
222         .mode = &innolux_p079zca_mode,
223         .bpc = 8,
224         .size = {
225                 .width = 120,
226                 .height = 160,
227         },
228         .flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_SYNC_PULSE |
229                  MIPI_DSI_MODE_LPM,
230         .format = MIPI_DSI_FMT_RGB888,
231         .lanes = 4,
232         .supply_names = innolux_p079zca_supply_names,
233         .num_supplies = ARRAY_SIZE(innolux_p079zca_supply_names),
234         .power_down_delay = 80, /* T8: 80ms - 1000ms */
235 };
236
237 static const char * const innolux_p097pfg_supply_names[] = {
238         "avdd",
239         "avee",
240 };
241
242 static const struct drm_display_mode innolux_p097pfg_mode = {
243         .clock = 229000,
244         .hdisplay = 1536,
245         .hsync_start = 1536 + 100,
246         .hsync_end = 1536 + 100 + 24,
247         .htotal = 1536 + 100 + 24 + 100,
248         .vdisplay = 2048,
249         .vsync_start = 2048 + 100,
250         .vsync_end = 2048 + 100 + 2,
251         .vtotal = 2048 + 100 + 2 + 18,
252 };
253
254 /*
255  * Display manufacturer failed to provide init sequencing according to
256  * https://chromium-review.googlesource.com/c/chromiumos/third_party/coreboot/+/892065/
257  * so the init sequence stems from a register dump of a working panel.
258  */
259 static const struct panel_init_cmd innolux_p097pfg_init_cmds[] = {
260         /* page 0 */
261         _INIT_CMD(0xF0, 0x55, 0xAA, 0x52, 0x08, 0x00),
262         _INIT_CMD(0xB1, 0xE8, 0x11),
263         _INIT_CMD(0xB2, 0x25, 0x02),
264         _INIT_CMD(0xB5, 0x08, 0x00),
265         _INIT_CMD(0xBC, 0x0F, 0x00),
266         _INIT_CMD(0xB8, 0x03, 0x06, 0x00, 0x00),
267         _INIT_CMD(0xBD, 0x01, 0x90, 0x14, 0x14),
268         _INIT_CMD(0x6F, 0x01),
269         _INIT_CMD(0xC0, 0x03),
270         _INIT_CMD(0x6F, 0x02),
271         _INIT_CMD(0xC1, 0x0D),
272         _INIT_CMD(0xD9, 0x01, 0x09, 0x70),
273         _INIT_CMD(0xC5, 0x12, 0x21, 0x00),
274         _INIT_CMD(0xBB, 0x93, 0x93),
275
276         /* page 1 */
277         _INIT_CMD(0xF0, 0x55, 0xAA, 0x52, 0x08, 0x01),
278         _INIT_CMD(0xB3, 0x3C, 0x3C),
279         _INIT_CMD(0xB4, 0x0F, 0x0F),
280         _INIT_CMD(0xB9, 0x45, 0x45),
281         _INIT_CMD(0xBA, 0x14, 0x14),
282         _INIT_CMD(0xCA, 0x02),
283         _INIT_CMD(0xCE, 0x04),
284         _INIT_CMD(0xC3, 0x9B, 0x9B),
285         _INIT_CMD(0xD8, 0xC0, 0x03),
286         _INIT_CMD(0xBC, 0x82, 0x01),
287         _INIT_CMD(0xBD, 0x9E, 0x01),
288
289         /* page 2 */
290         _INIT_CMD(0xF0, 0x55, 0xAA, 0x52, 0x08, 0x02),
291         _INIT_CMD(0xB0, 0x82),
292         _INIT_CMD(0xD1, 0x00, 0x00, 0x00, 0x3E, 0x00, 0x82, 0x00, 0xA5,
293                   0x00, 0xC1, 0x00, 0xEA, 0x01, 0x0D, 0x01, 0x40),
294         _INIT_CMD(0xD2, 0x01, 0x6A, 0x01, 0xA8, 0x01, 0xDC, 0x02, 0x29,
295                   0x02, 0x67, 0x02, 0x68, 0x02, 0xA8, 0x02, 0xF0),
296         _INIT_CMD(0xD3, 0x03, 0x19, 0x03, 0x49, 0x03, 0x67, 0x03, 0x8C,
297                   0x03, 0xA6, 0x03, 0xC7, 0x03, 0xDE, 0x03, 0xEC),
298         _INIT_CMD(0xD4, 0x03, 0xFF, 0x03, 0xFF),
299         _INIT_CMD(0xE0, 0x00, 0x00, 0x00, 0x86, 0x00, 0xC5, 0x00, 0xE5,
300                   0x00, 0xFF, 0x01, 0x26, 0x01, 0x45, 0x01, 0x75),
301         _INIT_CMD(0xE1, 0x01, 0x9C, 0x01, 0xD5, 0x02, 0x05, 0x02, 0x4D,
302                   0x02, 0x86, 0x02, 0x87, 0x02, 0xC3, 0x03, 0x03),
303         _INIT_CMD(0xE2, 0x03, 0x2A, 0x03, 0x56, 0x03, 0x72, 0x03, 0x94,
304                   0x03, 0xAC, 0x03, 0xCB, 0x03, 0xE0, 0x03, 0xED),
305         _INIT_CMD(0xE3, 0x03, 0xFF, 0x03, 0xFF),
306
307         /* page 3 */
308         _INIT_CMD(0xF0, 0x55, 0xAA, 0x52, 0x08, 0x03),
309         _INIT_CMD(0xB0, 0x00, 0x00, 0x00, 0x00),
310         _INIT_CMD(0xB1, 0x00, 0x00, 0x00, 0x00),
311         _INIT_CMD(0xB2, 0x00, 0x00, 0x06, 0x04, 0x01, 0x40, 0x85),
312         _INIT_CMD(0xB3, 0x10, 0x07, 0xFC, 0x04, 0x01, 0x40, 0x80),
313         _INIT_CMD(0xB6, 0xF0, 0x08, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01,
314                   0x40, 0x80),
315         _INIT_CMD(0xBA, 0xC5, 0x07, 0x00, 0x04, 0x11, 0x25, 0x8C),
316         _INIT_CMD(0xBB, 0xC5, 0x07, 0x00, 0x03, 0x11, 0x25, 0x8C),
317         _INIT_CMD(0xC0, 0x00, 0x3C, 0x00, 0x00, 0x00, 0x80, 0x80),
318         _INIT_CMD(0xC1, 0x00, 0x3C, 0x00, 0x00, 0x00, 0x80, 0x80),
319         _INIT_CMD(0xC4, 0x00, 0x00),
320         _INIT_CMD(0xEF, 0x41),
321
322         /* page 4 */
323         _INIT_CMD(0xF0, 0x55, 0xAA, 0x52, 0x08, 0x04),
324         _INIT_CMD(0xEC, 0x4C),
325
326         /* page 5 */
327         _INIT_CMD(0xF0, 0x55, 0xAA, 0x52, 0x08, 0x05),
328         _INIT_CMD(0xB0, 0x13, 0x03, 0x03, 0x01),
329         _INIT_CMD(0xB1, 0x30, 0x00),
330         _INIT_CMD(0xB2, 0x02, 0x02, 0x00),
331         _INIT_CMD(0xB3, 0x82, 0x23, 0x82, 0x9D),
332         _INIT_CMD(0xB4, 0xC5, 0x75, 0x24, 0x57),
333         _INIT_CMD(0xB5, 0x00, 0xD4, 0x72, 0x11, 0x11, 0xAB, 0x0A),
334         _INIT_CMD(0xB6, 0x00, 0x00, 0xD5, 0x72, 0x24, 0x56),
335         _INIT_CMD(0xB7, 0x5C, 0xDC, 0x5C, 0x5C),
336         _INIT_CMD(0xB9, 0x0C, 0x00, 0x00, 0x01, 0x00),
337         _INIT_CMD(0xC0, 0x75, 0x11, 0x11, 0x54, 0x05),
338         _INIT_CMD(0xC6, 0x00, 0x00, 0x00, 0x00),
339         _INIT_CMD(0xD0, 0x00, 0x48, 0x08, 0x00, 0x00),
340         _INIT_CMD(0xD1, 0x00, 0x48, 0x09, 0x00, 0x00),
341
342         /* page 6 */
343         _INIT_CMD(0xF0, 0x55, 0xAA, 0x52, 0x08, 0x06),
344         _INIT_CMD(0xB0, 0x02, 0x32, 0x32, 0x08, 0x2F),
345         _INIT_CMD(0xB1, 0x2E, 0x15, 0x14, 0x13, 0x12),
346         _INIT_CMD(0xB2, 0x11, 0x10, 0x00, 0x3D, 0x3D),
347         _INIT_CMD(0xB3, 0x3D, 0x3D, 0x3D, 0x3D, 0x3D),
348         _INIT_CMD(0xB4, 0x3D, 0x32),
349         _INIT_CMD(0xB5, 0x03, 0x32, 0x32, 0x09, 0x2F),
350         _INIT_CMD(0xB6, 0x2E, 0x1B, 0x1A, 0x19, 0x18),
351         _INIT_CMD(0xB7, 0x17, 0x16, 0x01, 0x3D, 0x3D),
352         _INIT_CMD(0xB8, 0x3D, 0x3D, 0x3D, 0x3D, 0x3D),
353         _INIT_CMD(0xB9, 0x3D, 0x32),
354         _INIT_CMD(0xC0, 0x01, 0x32, 0x32, 0x09, 0x2F),
355         _INIT_CMD(0xC1, 0x2E, 0x1A, 0x1B, 0x16, 0x17),
356         _INIT_CMD(0xC2, 0x18, 0x19, 0x03, 0x3D, 0x3D),
357         _INIT_CMD(0xC3, 0x3D, 0x3D, 0x3D, 0x3D, 0x3D),
358         _INIT_CMD(0xC4, 0x3D, 0x32),
359         _INIT_CMD(0xC5, 0x00, 0x32, 0x32, 0x08, 0x2F),
360         _INIT_CMD(0xC6, 0x2E, 0x14, 0x15, 0x10, 0x11),
361         _INIT_CMD(0xC7, 0x12, 0x13, 0x02, 0x3D, 0x3D),
362         _INIT_CMD(0xC8, 0x3D, 0x3D, 0x3D, 0x3D, 0x3D),
363         _INIT_CMD(0xC9, 0x3D, 0x32),
364
365         {},
366 };
367
368 static const struct panel_desc innolux_p097pfg_panel_desc = {
369         .mode = &innolux_p097pfg_mode,
370         .bpc = 8,
371         .size = {
372                 .width = 147,
373                 .height = 196,
374         },
375         .flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_SYNC_PULSE |
376                  MIPI_DSI_MODE_LPM,
377         .format = MIPI_DSI_FMT_RGB888,
378         .init_cmds = innolux_p097pfg_init_cmds,
379         .lanes = 4,
380         .supply_names = innolux_p097pfg_supply_names,
381         .num_supplies = ARRAY_SIZE(innolux_p097pfg_supply_names),
382         .sleep_mode_delay = 100, /* T15 */
383 };
384
385 static int innolux_panel_get_modes(struct drm_panel *panel,
386                                    struct drm_connector *connector)
387 {
388         struct innolux_panel *innolux = to_innolux_panel(panel);
389         const struct drm_display_mode *m = innolux->desc->mode;
390         struct drm_display_mode *mode;
391
392         mode = drm_mode_duplicate(connector->dev, m);
393         if (!mode) {
394                 dev_err(panel->dev, "failed to add mode %ux%u@%u\n",
395                         m->hdisplay, m->vdisplay, drm_mode_vrefresh(m));
396                 return -ENOMEM;
397         }
398
399         drm_mode_set_name(mode);
400
401         drm_mode_probed_add(connector, mode);
402
403         connector->display_info.width_mm = innolux->desc->size.width;
404         connector->display_info.height_mm = innolux->desc->size.height;
405         connector->display_info.bpc = innolux->desc->bpc;
406
407         return 1;
408 }
409
410 static const struct drm_panel_funcs innolux_panel_funcs = {
411         .disable = innolux_panel_disable,
412         .unprepare = innolux_panel_unprepare,
413         .prepare = innolux_panel_prepare,
414         .enable = innolux_panel_enable,
415         .get_modes = innolux_panel_get_modes,
416 };
417
418 static const struct of_device_id innolux_of_match[] = {
419         { .compatible = "innolux,p079zca",
420           .data = &innolux_p079zca_panel_desc
421         },
422         { .compatible = "innolux,p097pfg",
423           .data = &innolux_p097pfg_panel_desc
424         },
425         { }
426 };
427 MODULE_DEVICE_TABLE(of, innolux_of_match);
428
429 static int innolux_panel_add(struct mipi_dsi_device *dsi,
430                              const struct panel_desc *desc)
431 {
432         struct innolux_panel *innolux;
433         struct device *dev = &dsi->dev;
434         int err, i;
435
436         innolux = devm_kzalloc(dev, sizeof(*innolux), GFP_KERNEL);
437         if (!innolux)
438                 return -ENOMEM;
439
440         innolux->desc = desc;
441
442         innolux->supplies = devm_kcalloc(dev, desc->num_supplies,
443                                          sizeof(*innolux->supplies),
444                                          GFP_KERNEL);
445         if (!innolux->supplies)
446                 return -ENOMEM;
447
448         for (i = 0; i < desc->num_supplies; i++)
449                 innolux->supplies[i].supply = desc->supply_names[i];
450
451         err = devm_regulator_bulk_get(dev, desc->num_supplies,
452                                       innolux->supplies);
453         if (err < 0)
454                 return err;
455
456         innolux->enable_gpio = devm_gpiod_get_optional(dev, "enable",
457                                                        GPIOD_OUT_HIGH);
458         if (IS_ERR(innolux->enable_gpio)) {
459                 err = PTR_ERR(innolux->enable_gpio);
460                 dev_dbg(dev, "failed to get enable gpio: %d\n", err);
461                 innolux->enable_gpio = NULL;
462         }
463
464         drm_panel_init(&innolux->base, dev, &innolux_panel_funcs,
465                        DRM_MODE_CONNECTOR_DSI);
466
467         err = drm_panel_of_backlight(&innolux->base);
468         if (err)
469                 return err;
470
471         drm_panel_add(&innolux->base);
472
473         mipi_dsi_set_drvdata(dsi, innolux);
474         innolux->link = dsi;
475
476         return 0;
477 }
478
479 static void innolux_panel_del(struct innolux_panel *innolux)
480 {
481         drm_panel_remove(&innolux->base);
482 }
483
484 static int innolux_panel_probe(struct mipi_dsi_device *dsi)
485 {
486         const struct panel_desc *desc;
487         int err;
488
489         desc = of_device_get_match_data(&dsi->dev);
490         dsi->mode_flags = desc->flags;
491         dsi->format = desc->format;
492         dsi->lanes = desc->lanes;
493
494         err = innolux_panel_add(dsi, desc);
495         if (err < 0)
496                 return err;
497
498         return mipi_dsi_attach(dsi);
499 }
500
501 static int innolux_panel_remove(struct mipi_dsi_device *dsi)
502 {
503         struct innolux_panel *innolux = mipi_dsi_get_drvdata(dsi);
504         int err;
505
506         err = drm_panel_unprepare(&innolux->base);
507         if (err < 0)
508                 dev_err(&dsi->dev, "failed to unprepare panel: %d\n", err);
509
510         err = drm_panel_disable(&innolux->base);
511         if (err < 0)
512                 dev_err(&dsi->dev, "failed to disable panel: %d\n", err);
513
514         err = mipi_dsi_detach(dsi);
515         if (err < 0)
516                 dev_err(&dsi->dev, "failed to detach from DSI host: %d\n", err);
517
518         innolux_panel_del(innolux);
519
520         return 0;
521 }
522
523 static void innolux_panel_shutdown(struct mipi_dsi_device *dsi)
524 {
525         struct innolux_panel *innolux = mipi_dsi_get_drvdata(dsi);
526
527         drm_panel_unprepare(&innolux->base);
528         drm_panel_disable(&innolux->base);
529 }
530
531 static struct mipi_dsi_driver innolux_panel_driver = {
532         .driver = {
533                 .name = "panel-innolux-p079zca",
534                 .of_match_table = innolux_of_match,
535         },
536         .probe = innolux_panel_probe,
537         .remove = innolux_panel_remove,
538         .shutdown = innolux_panel_shutdown,
539 };
540 module_mipi_dsi_driver(innolux_panel_driver);
541
542 MODULE_AUTHOR("Chris Zhong <zyw@rock-chips.com>");
543 MODULE_AUTHOR("Lin Huang <hl@rock-chips.com>");
544 MODULE_DESCRIPTION("Innolux P079ZCA panel driver");
545 MODULE_LICENSE("GPL v2");