display-sys: debug node support to show debug information.
[firefly-linux-kernel-4.4.55.git] / drivers / video / rockchip / display-sys.c
1 #include <linux/module.h>
2 #include <linux/ctype.h>
3 #include <linux/idr.h>
4 #include <linux/err.h>
5 #include <linux/kdev_t.h>
6 #include <linux/display-sys.h>
7
8 static struct list_head main_display_device_list;
9 static struct list_head aux_display_device_list;
10
11 static ssize_t display_show_name(struct device *dev,
12                                  struct device_attribute *attr, char *buf)
13 {
14         struct rk_display_device *dsp = dev_get_drvdata(dev);
15
16         return snprintf(buf, PAGE_SIZE, "%s\n", dsp->name);
17 }
18
19 static ssize_t display_show_type(struct device *dev,
20                                  struct device_attribute *attr, char *buf)
21 {
22         struct rk_display_device *dsp = dev_get_drvdata(dev);
23
24         return snprintf(buf, PAGE_SIZE, "%s\n", dsp->type);
25 }
26
27 static ssize_t display_show_property(struct device *dev,
28                                      struct device_attribute *attr, char *buf)
29 {
30         struct rk_display_device *dsp = dev_get_drvdata(dev);
31
32         return snprintf(buf, PAGE_SIZE, "%d\n", dsp->property);
33 }
34
35 static ssize_t display_show_enable(struct device *dev,
36                                    struct device_attribute *attr, char *buf)
37 {
38         struct rk_display_device *dsp = dev_get_drvdata(dev);
39         int enable;
40
41         if (dsp->ops && dsp->ops->getenable)
42                 enable = dsp->ops->getenable(dsp);
43         else
44                 return 0;
45         return snprintf(buf, PAGE_SIZE, "%d\n", enable);
46 }
47
48 static ssize_t display_store_enable(struct device *dev,
49                                     struct device_attribute *attr,
50                                     const char *buf, size_t size)
51 {
52         struct rk_display_device *dsp = dev_get_drvdata(dev);
53         int enable;
54
55         if (kstrtoint(buf, 0, &enable))
56                 return size;
57         if (dsp->ops && dsp->ops->setenable)
58                 dsp->ops->setenable(dsp, enable);
59         return size;
60 }
61
62 static ssize_t display_show_connect(struct device *dev,
63                                     struct device_attribute *attr, char *buf)
64 {
65         struct rk_display_device *dsp = dev_get_drvdata(dev);
66         int connect;
67
68         if (dsp->ops && dsp->ops->getstatus)
69                 connect = dsp->ops->getstatus(dsp);
70         else
71                 return 0;
72         return snprintf(buf, PAGE_SIZE, "%d\n", connect);
73 }
74
75 static int mode_string(char *buf, unsigned int offset,
76                        const struct fb_videomode *mode)
77 {
78         char v = 'p';
79
80         if (mode->xres == 0 && mode->yres == 0)
81                 return snprintf(&buf[offset], PAGE_SIZE - offset, "auto\n");
82 /*
83         if (mode->flag & FB_MODE_IS_DETAILED)
84                 m = 'D';
85         if (mode->flag & FB_MODE_IS_VESA)
86                 m = 'V';
87         if (mode->flag & FB_MODE_IS_STANDARD)
88                 m = 'S';
89 */
90         if (mode->vmode & FB_VMODE_INTERLACED)
91                 v = 'i';
92         if (mode->vmode & FB_VMODE_DOUBLE)
93                 v = 'd';
94         if (mode->flag)
95                 return snprintf(&buf[offset], PAGE_SIZE - offset,
96                                 "%dx%d%c-%d(YCbCr420)\n",
97                                 mode->xres, mode->yres, v, mode->refresh);
98         else
99                 return snprintf(&buf[offset], PAGE_SIZE - offset,
100                                 "%dx%d%c-%d\n",
101                                 mode->xres, mode->yres, v, mode->refresh);
102 }
103
104 static ssize_t display_show_modes(struct device *dev,
105                                   struct device_attribute *attr, char *buf)
106 {
107         struct rk_display_device *dsp = dev_get_drvdata(dev);
108         struct list_head *modelist, *pos;
109         struct display_modelist *display_modelist;
110         const struct fb_videomode *mode;
111         int i;
112
113         if (dsp->ops && dsp->ops->getmodelist) {
114                 if (dsp->ops->getmodelist(dsp, &modelist))
115                         return -EINVAL;
116         } else {
117                 return 0;
118         }
119         i = 0;
120         if (dsp->priority == DISPLAY_PRIORITY_HDMI)
121                 i += snprintf(buf, PAGE_SIZE, "auto\n");
122
123         list_for_each(pos, modelist) {
124                 display_modelist = list_entry(pos,
125                                               struct display_modelist,
126                                               list);
127                 mode = &display_modelist->mode;
128                 i += mode_string(buf, i, mode);
129         }
130         return i;
131 }
132
133 static ssize_t display_show_mode(struct device *dev,
134                                  struct device_attribute *attr, char *buf)
135 {
136         struct rk_display_device *dsp = dev_get_drvdata(dev);
137         struct fb_videomode mode;
138
139         if (dsp->ops && dsp->ops->getmode)
140                 if (dsp->ops->getmode(dsp, &mode) == 0)
141                         return mode_string(buf, 0, &mode);
142         return 0;
143 }
144
145 static ssize_t display_store_mode(struct device *dev,
146                                   struct device_attribute *attr,
147                                   const char *buf, size_t count)
148 {
149         struct rk_display_device *dsp = dev_get_drvdata(dev);
150         char mstr[100];
151         struct list_head *modelist, *pos;
152         struct display_modelist *display_modelist;
153         struct fb_videomode *mode;
154         size_t i;
155
156         if (!memcmp(buf, "auto", 4)) {
157                 if (dsp->ops && dsp->ops->setmode)
158                         dsp->ops->setmode(dsp, NULL);
159                 return count;
160         }
161
162         if (dsp->ops && dsp->ops->getmodelist) {
163                 if (dsp->ops && dsp->ops->getmodelist) {
164                         if (dsp->ops->getmodelist(dsp, &modelist))
165                                 return -EINVAL;
166                 }
167                 list_for_each(pos, modelist) {
168                         display_modelist = list_entry(pos,
169                                                       struct display_modelist,
170                                                       list);
171                         mode = &display_modelist->mode;
172                         i = mode_string(mstr, 0, mode);
173                         if (strncmp(mstr, buf, max(count, i)) == 0) {
174                                 if (dsp->ops && dsp->ops->setmode)
175                                         dsp->ops->setmode(dsp, mode);
176                                 return count;
177                         }
178                 }
179         }
180         return -EINVAL;
181 }
182
183 static ssize_t display_show_scale(struct device *dev,
184                                   struct device_attribute *attr,
185                                   char *buf)
186 {
187         struct rk_display_device *dsp = dev_get_drvdata(dev);
188         int xscale, yscale;
189
190         if (dsp->ops && dsp->ops->getscale) {
191                 xscale = dsp->ops->getscale(dsp, DISPLAY_SCALE_X);
192                 yscale = dsp->ops->getscale(dsp, DISPLAY_SCALE_Y);
193                 if (xscale && yscale)
194                         return snprintf(buf, PAGE_SIZE,
195                                         "xscale=%d yscale=%d\n",
196                                         xscale, yscale);
197         }
198         return -EINVAL;
199 }
200
201 static ssize_t display_store_scale(struct device *dev,
202                                    struct device_attribute *attr,
203                                    const char *buf, size_t count)
204 {
205         struct rk_display_device *dsp = dev_get_drvdata(dev);
206         int scale = 100;
207
208         if (dsp->ops && dsp->ops->setscale) {
209                 if (!strncmp(buf, "xscale", 6)) {
210                         if (!kstrtoint(buf, 0, &scale))
211                                 dsp->ops->setscale(dsp,
212                                                    DISPLAY_SCALE_X,
213                                                    scale);
214                 } else if (!strncmp(buf, "yscale", 6)) {
215                         if (!kstrtoint(buf, 0, &scale))
216                                 dsp->ops->setscale(dsp,
217                                                    DISPLAY_SCALE_Y,
218                                                    scale);
219                 } else {
220                         if (!kstrtoint(buf, 0, &scale)) {
221                                 dsp->ops->setscale(dsp,
222                                                    DISPLAY_SCALE_X,
223                                                    scale);
224                                 dsp->ops->setscale(dsp,
225                                                    DISPLAY_SCALE_Y,
226                                                    scale);
227                         }
228                 }
229                 return count;
230         }
231         return -EINVAL;
232 }
233
234 static ssize_t display_show_3dmode(struct device *dev,
235                                    struct device_attribute *attr, char *buf)
236 {
237         struct rk_display_device *dsp = dev_get_drvdata(dev);
238         struct list_head *modelist, *pos;
239         struct display_modelist *display_modelist;
240         struct fb_videomode mode;
241         int i = 0, cur_3d_mode = -1;
242         char mode_str[128];
243         int mode_strlen, format_3d;
244
245         if (dsp->ops && dsp->ops->getmodelist) {
246                 if (dsp->ops->getmodelist(dsp, &modelist))
247                         return -EINVAL;
248         } else {
249                 return 0;
250         }
251
252         if (dsp->ops && dsp->ops->getmode) {
253                 if (dsp->ops->getmode(dsp, &mode))
254                         return -EINVAL;
255         } else {
256                 return 0;
257         }
258
259         list_for_each(pos, modelist) {
260                 display_modelist = list_entry(pos,
261                                               struct display_modelist,
262                                               list);
263                 if (fb_mode_is_equal(&mode, &display_modelist->mode))
264                         break;
265                 else
266                         display_modelist = NULL;
267         }
268         if (display_modelist)
269                 i = snprintf(buf, PAGE_SIZE, "3dmodes=%d\n",
270                              display_modelist->format_3d);
271         else
272                 i = snprintf(buf, PAGE_SIZE, "3dmodes=0\n");
273
274         if (dsp->ops && dsp->ops->get3dmode)
275                 cur_3d_mode = dsp->ops->get3dmode(dsp);
276         i += snprintf(buf + i, PAGE_SIZE - i, "cur3dmode=%d\n", cur_3d_mode);
277
278         list_for_each(pos, modelist) {
279                 display_modelist = list_entry(pos,
280                                               struct display_modelist,
281                                               list);
282                 mode_strlen = mode_string(mode_str, 0,
283                                           &(display_modelist->mode));
284                 mode_str[mode_strlen-1] = 0;
285                 format_3d = display_modelist->format_3d;
286                 i += snprintf(buf+i, PAGE_SIZE, "%s,%d\n",
287                               mode_str, format_3d);
288         }
289         return i;
290 }
291
292 static ssize_t display_store_3dmode(struct device *dev,
293                                     struct device_attribute *attr,
294                                     const char *buf, size_t count)
295 {
296         struct rk_display_device *dsp = dev_get_drvdata(dev);
297         int mode;
298
299         if (dsp->ops && dsp->ops->set3dmode) {
300                 if (!kstrtoint(buf, 0, &mode))
301                         dsp->ops->set3dmode(dsp, mode);
302                 return count;
303         }
304         return -EINVAL;
305 }
306
307 static ssize_t display_show_color(struct device *dev,
308                                   struct device_attribute *attr, char *buf)
309 {
310         struct rk_display_device *dsp = dev_get_drvdata(dev);
311
312         if (dsp->ops && dsp->ops->getcolor)
313                 return dsp->ops->getcolor(dsp, buf);
314         else
315                 return 0;
316 }
317
318 static ssize_t display_store_color(struct device *dev,
319                                    struct device_attribute *attr,
320                                    const char *buf, size_t count)
321 {
322         struct rk_display_device *dsp = dev_get_drvdata(dev);
323
324         if (dsp->ops && dsp->ops->setcolor) {
325                 if (!dsp->ops->setcolor(dsp, buf, count))
326                         return count;
327         }
328         return -EINVAL;
329 }
330
331 static ssize_t display_show_sinkaudioinfo(struct device *dev,
332                                           struct device_attribute *attr,
333                                           char *buf)
334 {
335         struct rk_display_device *dsp = dev_get_drvdata(dev);
336         char audioinfo[200];
337         int ret = 0;
338
339         if (dsp->ops && dsp->ops->getedidaudioinfo) {
340                 ret = dsp->ops->getedidaudioinfo(dsp, audioinfo, 200);
341                 if (!ret)
342                         return snprintf(buf, PAGE_SIZE, "%s\n", audioinfo);
343         }
344         return -EINVAL;
345 }
346
347 static ssize_t display_show_monspecs(struct device *dev,
348                                      struct device_attribute *attr, char *buf)
349 {
350         struct rk_display_device *dsp = dev_get_drvdata(dev);
351         struct fb_monspecs monspecs;
352         int ret = 0;
353
354         if (dsp->ops && dsp->ops->getmonspecs) {
355                 ret = dsp->ops->getmonspecs(dsp, &monspecs);
356                 if (!ret) {
357                         memcpy(buf, &monspecs, sizeof(struct fb_monspecs));
358                         return sizeof(struct fb_monspecs);
359                 }
360         }
361         return -EINVAL;
362 }
363
364 static ssize_t display_show_debug(struct device *dev,
365                                   struct device_attribute *attr, char *buf)
366 {
367         struct rk_display_device *dsp = dev_get_drvdata(dev);
368
369         if (dsp->ops && dsp->ops->getdebug)
370                 return dsp->ops->getdebug(dsp, buf);
371         else
372                 return -EINVAL;
373 }
374
375 static ssize_t display_store_debug(struct device *dev,
376                                    struct device_attribute *attr,
377                                    const char *buf, size_t count)
378 {
379         int cmd;
380         struct rk_display_device *dsp = dev_get_drvdata(dev);
381
382         if (dsp->ops && dsp->ops->setdebug) {
383                 if (kstrtoint(buf, 0, &cmd) == 0)
384                         dsp->ops->setdebug(dsp, cmd);
385                 return count;
386         }
387         return -EINVAL;
388 }
389
390 static struct device_attribute display_attrs[] = {
391         __ATTR(name, S_IRUGO, display_show_name, NULL),
392         __ATTR(type, S_IRUGO, display_show_type, NULL),
393         __ATTR(property, S_IRUGO, display_show_property, NULL),
394         __ATTR(enable, 0666, display_show_enable, display_store_enable),
395         __ATTR(connect, S_IRUGO, display_show_connect, NULL),
396         __ATTR(modes, S_IRUGO, display_show_modes, NULL),
397         __ATTR(mode, 0666, display_show_mode, display_store_mode),
398         __ATTR(scale, 0666, display_show_scale, display_store_scale),
399         __ATTR(3dmode, 0666, display_show_3dmode, display_store_3dmode),
400         __ATTR(color, 0666, display_show_color, display_store_color),
401         __ATTR(audioinfo, S_IRUGO, display_show_sinkaudioinfo, NULL),
402         __ATTR(monspecs, S_IRUGO, display_show_monspecs, NULL),
403         __ATTR(debug, 0664, display_show_debug, display_store_debug),
404         __ATTR_NULL
405 };
406
407 static int display_suspend(struct device *dev, pm_message_t state)
408 {
409         struct rk_display_device *dsp = dev_get_drvdata(dev);
410
411         mutex_lock(&dsp->lock);
412         if (likely(dsp->driver->suspend))
413                 dsp->driver->suspend(dsp, state);
414         mutex_unlock(&dsp->lock);
415         return 0;
416 };
417
418 static int display_resume(struct device *dev)
419 {
420         struct rk_display_device *dsp = dev_get_drvdata(dev);
421
422         mutex_lock(&dsp->lock);
423         if (likely(dsp->driver->resume))
424                 dsp->driver->resume(dsp);
425         mutex_unlock(&dsp->lock);
426         return 0;
427 };
428
429 int display_add_videomode(const struct fb_videomode *mode,
430                           struct list_head *head)
431 {
432         struct list_head *pos;
433         struct display_modelist *modelist;
434         struct fb_videomode *m;
435         int found = 0;
436
437         list_for_each(pos, head) {
438                 modelist = list_entry(pos, struct display_modelist, list);
439                 m = &modelist->mode;
440                 if (fb_mode_is_equal(m, mode)) {
441                         found = 1;
442                         break;
443                 }
444         }
445         if (!found) {
446                 modelist = kmalloc(sizeof(*modelist),
447                                    GFP_KERNEL);
448
449                 if (!modelist)
450                         return -ENOMEM;
451                 modelist->mode = *mode;
452                 list_add(&modelist->list, head);
453         }
454         return 0;
455 }
456
457 void rk_display_device_enable(struct rk_display_device *ddev)
458 {
459         struct list_head *pos, *head;
460         struct rk_display_device *dev = NULL, *dev_enabled = NULL;
461         struct rk_display_device *dev_enable = NULL;
462         int enable = 0, connect;
463
464         if (ddev->property == DISPLAY_MAIN)
465                 head = &main_display_device_list;
466         else
467                 head = &aux_display_device_list;
468
469         list_for_each(pos, head) {
470                 dev = list_entry(pos, struct rk_display_device, list);
471                 enable = dev->ops->getenable(dev);
472                 connect = dev->ops->getstatus(dev);
473                 if (connect)
474                         dev_enable = dev;
475                 if (enable == 1)
476                         dev_enabled = dev;
477         }
478         /* If no device is connected, enable highest priority device. */
479         if (dev_enable == NULL) {
480                 dev->ops->setenable(dev, 1);
481                 return;
482         }
483
484         if (dev_enable == dev_enabled) {
485                 if (dev_enable != ddev)
486                         ddev->ops->setenable(ddev, 0);
487         } else {
488                 if (dev_enabled &&
489                     dev_enabled->priority != DISPLAY_PRIORITY_HDMI)
490                         dev_enabled->ops->setenable(dev_enabled, 0);
491                 dev_enable->ops->setenable(dev_enable, 1);
492         }
493 }
494 EXPORT_SYMBOL(rk_display_device_enable);
495
496 void rk_display_device_enable_other(struct rk_display_device *ddev)
497 {
498 #ifndef CONFIG_DISPLAY_AUTO_SWITCH
499         return;
500 #else
501         struct list_head *pos, *head;
502         struct rk_display_device *dev;
503         int connect = 0;
504
505         if (ddev->property == DISPLAY_MAIN)
506                 head = &main_display_device_list;
507         else
508                 head = &aux_display_device_list;
509
510         list_for_each_prev(pos, head) {
511                 dev = list_entry(pos, struct rk_display_device, list);
512                 if (dev != ddev) {
513                         connect = dev->ops->getstatus(dev);
514                         if (connect) {
515                                 dev->ops->setenable(dev, 1);
516                                 return;
517                         }
518                 }
519         }
520 #endif
521 }
522 EXPORT_SYMBOL(rk_display_device_enable_other);
523
524 void rk_display_device_disable_other(struct rk_display_device *ddev)
525 {
526 #ifndef CONFIG_DISPLAY_AUTO_SWITCH
527         return;
528 #else
529         struct list_head *pos, *head;
530         struct rk_display_device *dev;
531         int enable = 0;
532
533         if (ddev->property == DISPLAY_MAIN)
534                 head = &main_display_device_list;
535         else
536                 head = &aux_display_device_list;
537
538         list_for_each(pos, head) {
539                 dev = list_entry(pos, struct rk_display_device, list);
540                 if (dev != ddev) {
541                         enable = dev->ops->getenable(dev);
542                         if (enable)
543                                 dev->ops->setenable(dev, 0);
544                 }
545         }
546         ddev->ops->setenable(ddev, 1);
547 #endif
548 }
549 EXPORT_SYMBOL(rk_display_device_disable_other);
550
551 void rk_display_device_select(int property, int priority)
552 {
553         struct list_head *pos, *head;
554         struct rk_display_device *dev;
555         int enable, found = 0;
556
557         if (property == DISPLAY_MAIN)
558                 head = &main_display_device_list;
559         else
560                 head = &aux_display_device_list;
561
562         list_for_each(pos, head) {
563                 dev = list_entry(pos, struct rk_display_device, list);
564                 if (dev->priority == priority)
565                         found = 1;
566         }
567
568         if (!found) {
569                 pr_err("[%s] select display interface %d not exist\n",
570                        __func__, priority);
571                 return;
572         }
573
574         list_for_each(pos, head) {
575                 dev = list_entry(pos, struct rk_display_device, list);
576                 enable = dev->ops->getenable(dev);
577                 if (dev->priority == priority) {
578                         if (!enable)
579                                 dev->ops->setenable(dev, 1);
580                 } else if (enable) {
581                         dev->ops->setenable(dev, 0);
582                 }
583         }
584 }
585 EXPORT_SYMBOL(rk_display_device_select);
586 static struct mutex allocated_dsp_lock;
587 static DEFINE_IDR(allocated_dsp);
588 static struct class *display_class;
589
590 struct rk_display_device
591         *rk_display_device_register(struct rk_display_driver *driver,
592                                     struct device *parent, void *devdata)
593 {
594         struct rk_display_device *new_dev = NULL;
595         int ret = -EINVAL;
596
597         if (unlikely(!driver))
598                 return ERR_PTR(ret);
599
600         new_dev = kzalloc(sizeof(*new_dev), GFP_KERNEL);
601         if (likely(new_dev) && unlikely(driver->probe(new_dev, devdata))) {
602                 /* Reserve the index for this display */
603                 mutex_lock(&allocated_dsp_lock);
604                 new_dev->idx = idr_alloc(&allocated_dsp, new_dev,
605                                          0, 0, GFP_KERNEL);
606                 mutex_unlock(&allocated_dsp_lock);
607
608                 if (new_dev->idx >= 0) {
609                         if (new_dev->property == DISPLAY_MAIN)
610                                 new_dev->dev =
611                                 device_create(display_class, parent,
612                                               MKDEV(0, 0), new_dev,
613                                               "%s", new_dev->type);
614                         else
615                                 new_dev->dev =
616                                 device_create(display_class, parent,
617                                               MKDEV(0, 0), new_dev,
618                                               "display%d.%s",
619                                               new_dev->property,
620                                               new_dev->type);
621                         if (!IS_ERR(new_dev->dev)) {
622                                 new_dev->parent = parent;
623                                 new_dev->driver = driver;
624                                 if (parent)
625                                         new_dev->dev->driver = parent->driver;
626                                 mutex_init(&new_dev->lock);
627                                 /* Add new device to display device list. */
628                                 {
629                                 struct list_head *pos, *head;
630                                 struct rk_display_device *dev;
631
632                                 if (new_dev->property == DISPLAY_MAIN)
633                                         head = &main_display_device_list;
634                                 else
635                                         head = &aux_display_device_list;
636
637                                 list_for_each(pos, head) {
638                                         dev =
639                                         list_entry(pos,
640                                                    struct rk_display_device,
641                                                    list);
642                                         if (dev->priority > new_dev->priority)
643                                                 break;
644                                 }
645                                 list_add_tail(&new_dev->list, pos);
646                                 return new_dev;
647                                 }
648                         }
649                         mutex_lock(&allocated_dsp_lock);
650                         idr_remove(&allocated_dsp, new_dev->idx);
651                         mutex_unlock(&allocated_dsp_lock);
652                         ret = -EINVAL;
653                 }
654         }
655         kfree(new_dev);
656         return ERR_PTR(ret);
657 }
658 EXPORT_SYMBOL(rk_display_device_register);
659
660 void rk_display_device_unregister(struct rk_display_device *ddev)
661 {
662         if (!ddev)
663                 return;
664         /* Free device */
665         mutex_lock(&ddev->lock);
666         device_unregister(ddev->dev);
667         mutex_unlock(&ddev->lock);
668         /* Mark device index as avaliable */
669         mutex_lock(&allocated_dsp_lock);
670         idr_remove(&allocated_dsp, ddev->idx);
671         mutex_unlock(&allocated_dsp_lock);
672         list_del(&ddev->list);
673         kfree(ddev);
674 }
675 EXPORT_SYMBOL(rk_display_device_unregister);
676
677 static int __init rk_display_class_init(void)
678 {
679         display_class = class_create(THIS_MODULE, "display");
680         if (IS_ERR(display_class)) {
681                 pr_err("Failed to create display class\n");
682                 display_class = NULL;
683                 return -EINVAL;
684         }
685         display_class->dev_attrs = display_attrs;
686         display_class->suspend = display_suspend;
687         display_class->resume = display_resume;
688         mutex_init(&allocated_dsp_lock);
689         INIT_LIST_HEAD(&main_display_device_list);
690         INIT_LIST_HEAD(&aux_display_device_list);
691         return 0;
692 }
693
694 static void __exit rk_display_class_exit(void)
695 {
696         class_destroy(display_class);
697 }
698
699 subsys_initcall(rk_display_class_init);
700 module_exit(rk_display_class_exit);
701
702
703 MODULE_AUTHOR("zhengyang@rock-chips.com");
704 MODULE_DESCRIPTION("Driver for rk display device");
705 MODULE_LICENSE("GPL");