Merge remote-tracking branch 'origin/develop-3.10' into develop-3.10-next
[firefly-linux-kernel-4.4.55.git] / drivers / video / rockchip / rkfb_sysfs.c
1 /*
2  * linux/drivers/video/rockchip/rkfb-sysfs.c
3  *
4  * Copyright (C) 2012 Rockchip Corporation
5  * Author: yxj<yxj@rock-chips.com>
6  *
7  * Some code and ideas taken from
8  *drivers/video/omap2/omapfb/omapfb-sys.c
9  *driver by Tomi Valkeinen.
10  *
11  *
12  * This program is free software; you can redistribute it and/or modify it
13  * under the terms of the GNU General Public License version 2 as published by
14  * the Free Software Foundation.
15  *
16  * This program is distributed in the hope that it will be useful, but WITHOUT
17  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
18  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
19  * more details.
20  *
21  * You should have received a copy of the GNU General Public License along with
22  * this program.  If not, see <http://www.gnu.org/licenses/>.
23  */
24
25 #include <linux/fb.h>
26 #include <linux/sysfs.h>
27 #include <linux/device.h>
28 #include <linux/uaccess.h>
29 #include <linux/platform_device.h>
30 #include <linux/kernel.h>
31 #include <linux/mm.h>
32 #include <asm/div64.h>
33 #include <linux/rk_screen.h>
34 #include <linux/rk_fb.h>
35
36 static ssize_t show_screen_info(struct device *dev,
37                                 struct device_attribute *attr, char *buf)
38 {
39         struct fb_info *fbi = dev_get_drvdata(dev);
40         struct rk_lcdc_driver *dev_drv = (struct rk_lcdc_driver *)fbi->par;
41         struct rk_screen *screen = dev_drv->screen0;
42         int fps;
43         u32 x = screen->mode.left_margin + screen->mode.right_margin +
44                 screen->mode.xres + screen->mode.hsync_len;
45         u32 y = screen->mode.upper_margin + screen->mode.lower_margin +
46                 screen->mode.yres + screen->mode.vsync_len;
47         u64 ft = (u64)x * y * (dev_drv->pixclock);
48
49         fps = div64_u64(1000000000000llu, ft);
50         return snprintf(buf, PAGE_SIZE, "xres:%d\nyres:%d\nfps:%d\n",
51                         screen->mode.xres, screen->mode.yres, fps);
52 }
53
54 static ssize_t show_disp_info(struct device *dev,
55                               struct device_attribute *attr, char *buf)
56 {
57         struct fb_info *fbi = dev_get_drvdata(dev);
58         struct rk_lcdc_driver *dev_drv = (struct rk_lcdc_driver *)fbi->par;
59         int win_id = dev_drv->ops->fb_get_win_id(dev_drv, fbi->fix.id);
60
61         if (dev_drv->ops->get_disp_info)
62                 return dev_drv->ops->get_disp_info(dev_drv, buf, win_id);
63
64         return 0;
65 }
66
67 static ssize_t show_phys(struct device *dev,
68                          struct device_attribute *attr, char *buf)
69 {
70         struct fb_info *fbi = dev_get_drvdata(dev);
71
72         return snprintf(buf, PAGE_SIZE, "0x%lx-----0x%x\n",
73                         fbi->fix.smem_start, fbi->fix.smem_len);
74 }
75
76 static ssize_t show_virt(struct device *dev,
77                          struct device_attribute *attr, char *buf)
78 {
79         struct fb_info *fbi = dev_get_drvdata(dev);
80
81         return snprintf(buf, PAGE_SIZE, "0x%p-----0x%x\n",
82                         fbi->screen_base, fbi->fix.smem_len);
83 }
84
85 static ssize_t show_fb_state(struct device *dev,
86                              struct device_attribute *attr, char *buf)
87 {
88         struct fb_info *fbi = dev_get_drvdata(dev);
89         struct rk_lcdc_driver *dev_drv =
90             (struct rk_lcdc_driver *)fbi->par;
91         int win_id = dev_drv->ops->fb_get_win_id(dev_drv, fbi->fix.id);
92         int state = dev_drv->ops->get_win_state(dev_drv, win_id);
93
94         return snprintf(buf, PAGE_SIZE, "%s\n", state ? "enabled" : "disabled");
95 }
96
97 static ssize_t show_dual_mode(struct device *dev,
98                               struct device_attribute *attr, char *buf)
99 {
100         struct fb_info *fbi = dev_get_drvdata(dev);
101         struct rk_fb *rk_fb = dev_get_drvdata(fbi->device);
102         int mode = rk_fb->disp_mode;
103
104         return snprintf(buf, PAGE_SIZE, "%d\n", mode);
105 }
106
107 static ssize_t set_fb_state(struct device *dev, struct device_attribute *attr,
108                             const char *buf, size_t count)
109 {
110         struct fb_info *fbi = dev_get_drvdata(dev);
111         struct rk_lcdc_driver *dev_drv =
112             (struct rk_lcdc_driver *)fbi->par;
113         int win_id = dev_drv->ops->fb_get_win_id(dev_drv, fbi->fix.id);
114         int state;
115         int ret;
116
117         ret = kstrtoint(buf, 0, &state);
118         if (ret)
119                 return ret;
120         dev_drv->ops->open(dev_drv, win_id, state);
121         if (state) {
122                 dev_drv->ops->set_par(dev_drv, win_id);
123                 dev_drv->ops->pan_display(dev_drv, win_id);
124                 dev_drv->ops->cfg_done(dev_drv);
125         }
126         return count;
127 }
128
129 static ssize_t show_overlay(struct device *dev,
130                             struct device_attribute *attr, char *buf)
131 {
132         struct fb_info *fbi = dev_get_drvdata(dev);
133         struct rk_lcdc_driver *dev_drv =
134             (struct rk_lcdc_driver *)fbi->par;
135         int ovl;
136         ovl = dev_drv->ops->ovl_mgr(dev_drv, 0, 0);
137
138         if (ovl < 0)
139                 return ovl;
140
141         return snprintf(buf, PAGE_SIZE, "%s\n",
142                         ovl ? "win0 on the top of win1" :
143                         "win1 on the top of win0");
144 }
145
146 static ssize_t set_overlay(struct device *dev, struct device_attribute *attr,
147                            const char *buf, size_t count)
148 {
149         struct fb_info *fbi = dev_get_drvdata(dev);
150         struct rk_lcdc_driver *dev_drv =
151             (struct rk_lcdc_driver *)fbi->par;
152         int ovl;
153         int ret;
154
155         ret = kstrtoint(buf, 0, &ovl);
156         if (ret)
157                 return ret;
158
159         ret = dev_drv->ops->ovl_mgr(dev_drv, ovl, 1);
160         if (ret < 0)
161                 return ret;
162
163         return count;
164 }
165
166 static ssize_t show_fps(struct device *dev,
167                         struct device_attribute *attr, char *buf)
168 {
169         struct fb_info *fbi = dev_get_drvdata(dev);
170         struct rk_lcdc_driver *dev_drv =
171             (struct rk_lcdc_driver *)fbi->par;
172         int fps;
173
174         fps = dev_drv->ops->fps_mgr(dev_drv, 0, 0);
175         if (fps < 0)
176                 return fps;
177
178         return snprintf(buf, PAGE_SIZE, "fps:%d\n", fps);
179 }
180
181 static ssize_t set_fps(struct device *dev, struct device_attribute *attr,
182                        const char *buf, size_t count)
183 {
184         struct fb_info *fbi = dev_get_drvdata(dev);
185         struct rk_lcdc_driver *dev_drv =
186             (struct rk_lcdc_driver *)fbi->par;
187         int fps;
188         int ret;
189
190         ret = kstrtoint(buf, 0, &fps);
191         if (ret)
192                 return ret;
193         ret = dev_drv->ops->fps_mgr(dev_drv, fps, 1);
194         if (ret < 0)
195                 return ret;
196
197         return count;
198 }
199
200 static ssize_t show_fb_win_map(struct device *dev,
201                                struct device_attribute *attr, char *buf)
202 {
203         int ret;
204         struct fb_info *fbi = dev_get_drvdata(dev);
205         struct rk_lcdc_driver *dev_drv =
206             (struct rk_lcdc_driver *)fbi->par;
207
208         mutex_lock(&dev_drv->fb_win_id_mutex);
209         ret =
210             snprintf(buf, PAGE_SIZE, "fb0:win%d\nfb1:win%d\nfb2:win%d\n",
211                      dev_drv->fb0_win_id, dev_drv->fb1_win_id,
212                      dev_drv->fb2_win_id);
213         mutex_unlock(&dev_drv->fb_win_id_mutex);
214
215         return ret;
216 }
217
218 static ssize_t set_fb_win_map(struct device *dev, struct device_attribute *attr,
219                               const char *buf, size_t count)
220 {
221         struct fb_info *fbi = dev_get_drvdata(dev);
222         struct rk_lcdc_driver *dev_drv =
223             (struct rk_lcdc_driver *)fbi->par;
224         int order;
225         int ret;
226
227         ret = kstrtoint(buf, 0, &order);
228         if ((order != FB0_WIN2_FB1_WIN1_FB2_WIN0) &&
229             (order != FB0_WIN1_FB1_WIN2_FB2_WIN0) &&
230             (order != FB0_WIN2_FB1_WIN0_FB2_WIN1) &&
231             (order != FB0_WIN0_FB1_WIN2_FB2_WIN1) &&
232             (order != FB0_WIN0_FB1_WIN1_FB2_WIN2) &&
233             (order != FB0_WIN1_FB1_WIN0_FB2_WIN2)) {
234                 printk(KERN_ERR "un supported map\n"
235                        "you can use the following order:\n" "201:\n"
236                        "fb0-win1\n" "fb1-win0\n" "fb2-win2\n" "210:\n"
237                        "fb0-win0\n" "fb1-win1\n" "fb2-win2\n" "120:\n"
238                        "fb0-win0\n" "fb1-win2\n" "fb2-win1\n" "102:\n"
239                        "fb0-win2\n" "fb1-win0\n" "fb2-win1\n" "021:\n"
240                        "fb0-win1\n" "fb1-win2\n" "fb2-win0\n" "012:\n"
241                        "fb0-win2\n" "fb1-win1\n" "fb2-win0\n");
242                 return count;
243         } else {
244                 dev_drv->ops->fb_win_remap(dev_drv, order);
245         }
246
247         return count;
248 }
249
250 static ssize_t show_dsp_lut(struct device *dev,
251                             struct device_attribute *attr, char *buf)
252 {
253         return 0;
254 }
255
256 static ssize_t set_dsp_lut(struct device *dev, struct device_attribute *attr,
257                            const char *buf, size_t count)
258 {
259         int dsp_lut[256];
260         const char *start = buf;
261         int i = 256, temp;
262         int space_max = 10;
263
264         struct fb_info *fbi = dev_get_drvdata(dev);
265         struct rk_lcdc_driver *dev_drv =
266             (struct rk_lcdc_driver *)fbi->par;
267
268         for (i = 0; i < 256; i++) {
269                 temp = i;
270                 /*init by default value*/
271                 dsp_lut[i] = temp + (temp << 8) + (temp << 16);
272         }
273         /*printk("count:%d\n>>%s\n\n",count,start);*/
274         for (i = 0; i < 256; i++) {
275                 space_max = 10; /*max space number 10*/
276                 temp = simple_strtoul(start, NULL, 10);
277                 dsp_lut[i] = temp;
278                 do {
279                         start++;
280                         space_max--;
281                 } while ((*start != ' ') && space_max);
282
283                 if (!space_max)
284                         break;
285                 else
286                         start++;
287         }
288 #if 0
289         for (i = 0; i < 16; i++) {
290                 for (j = 0; j < 16; j++)
291                         printk("0x%08x ", dsp_lut[i * 16 + j]);
292                 printk("\n");
293         }
294 #endif
295         dev_drv->ops->set_dsp_lut(dev_drv, dsp_lut);
296
297         return count;
298 }
299
300 static ssize_t show_dsp_cabc(struct device *dev,
301                              struct device_attribute *attr, char *buf)
302 {
303         struct fb_info *fbi = dev_get_drvdata(dev);
304         struct rk_lcdc_driver *dev_drv =
305             (struct rk_lcdc_driver *)fbi->par;
306
307         return snprintf(buf, PAGE_SIZE, "cabc mode=%d\n",
308                 dev_drv->cabc_mode);
309         return 0;
310 }
311
312 static ssize_t set_dsp_cabc(struct device *dev, struct device_attribute *attr,
313                             const char *buf, size_t count)
314 {
315         struct fb_info *fbi = dev_get_drvdata(dev);
316         struct rk_lcdc_driver *dev_drv =
317             (struct rk_lcdc_driver *)fbi->par;
318         int ret, mode = 0;
319
320         ret = kstrtoint(buf, 0, &mode);
321         if (ret)
322                 return ret;
323
324         ret = dev_drv->ops->set_dsp_cabc(dev_drv, mode);
325         if (ret < 0)
326                 return ret;
327
328         return count;
329 }
330
331 static ssize_t show_dsp_bcsh(struct device *dev,
332                              struct device_attribute *attr, char *buf)
333 {
334         struct fb_info *fbi = dev_get_drvdata(dev);
335         struct rk_lcdc_driver *dev_drv =
336             (struct rk_lcdc_driver *)fbi->par;
337         int brightness, contrast, sat_con, sin_hue, cos_hue;
338
339         if (dev_drv->ops->get_dsp_bcsh_bcs) {
340                 brightness = dev_drv->ops->get_dsp_bcsh_bcs(dev_drv,
341                                                             BRIGHTNESS);
342                 contrast = dev_drv->ops->get_dsp_bcsh_bcs(dev_drv, CONTRAST);
343                 sat_con = dev_drv->ops->get_dsp_bcsh_bcs(dev_drv, SAT_CON);
344         }
345         if (dev_drv->ops->get_dsp_bcsh_hue) {
346                 sin_hue = dev_drv->ops->get_dsp_bcsh_hue(dev_drv, H_SIN);
347                 cos_hue = dev_drv->ops->get_dsp_bcsh_hue(dev_drv, H_COS);
348         }
349         return snprintf(buf, PAGE_SIZE,
350                         "brightness:%4d,contrast:%4d,sat_con:%4d,"
351                         "sin_hue:%4d,cos_hue:%4d\n",
352                         brightness, contrast, sat_con, sin_hue, cos_hue);
353 }
354
355 static ssize_t set_dsp_bcsh(struct device *dev, struct device_attribute *attr,
356                             const char *buf, size_t count)
357 {
358         struct fb_info *fbi = dev_get_drvdata(dev);
359         struct rk_lcdc_driver *dev_drv =
360             (struct rk_lcdc_driver *)fbi->par;
361         int brightness, contrast, sat_con, ret, sin_hue, cos_hue;
362
363         if (!strncmp(buf, "open", 4)) {
364                 if (dev_drv->ops->open_bcsh)
365                         ret = dev_drv->ops->open_bcsh(dev_drv, 1);
366                 else
367                         ret = -1;
368         } else if (!strncmp(buf, "close", 5)) {
369                 if (dev_drv->ops->open_bcsh)
370                         ret = dev_drv->ops->open_bcsh(dev_drv, 0);
371                 else
372                         ret = -1;
373         } else if (!strncmp(buf, "brightness", 10)) {
374                 sscanf(buf, "brightness %d", &brightness);
375                 if (unlikely(brightness > 255)) {
376                         dev_err(fbi->dev,
377                                 "brightness should be [0:255],now=%d\n\n",
378                                 brightness);
379                         brightness = 255;
380                 }
381                 if (dev_drv->ops->set_dsp_bcsh_bcs)
382                         ret = dev_drv->ops->set_dsp_bcsh_bcs(dev_drv,
383                                                              BRIGHTNESS,
384                                                              brightness);
385                 else
386                         ret = -1;
387         } else if (!strncmp(buf, "contrast", 8)) {
388                 sscanf(buf, "contrast %d", &contrast);
389                 if (unlikely(contrast > 510)) {
390                         dev_err(fbi->dev,
391                                 "contrast should be [0:510],now=%d\n",
392                                 contrast);
393                         contrast = 510;
394                 }
395                 if (dev_drv->ops->set_dsp_bcsh_bcs)
396                         ret = dev_drv->ops->set_dsp_bcsh_bcs(dev_drv,
397                                                              CONTRAST,
398                                                              contrast);
399                 else
400                         ret = -1;
401         } else if (!strncmp(buf, "sat_con", 7)) {
402                 sscanf(buf, "sat_con %d", &sat_con);
403                 if (unlikely(sat_con > 1015)) {
404                         dev_err(fbi->dev,
405                                 "sat_con should be [0:1015],now=%d\n",
406                                 sat_con);
407                         sat_con = 1015;
408                 }
409                 if (dev_drv->ops->set_dsp_bcsh_bcs)
410                         ret = dev_drv->ops->set_dsp_bcsh_bcs(dev_drv,
411                                                              SAT_CON,
412                                                              sat_con);
413                 else
414                         ret = -1;
415         } else if (!strncmp(buf, "hue", 3)) {
416                 sscanf(buf, "hue %d %d", &sin_hue, &cos_hue);
417                 if (unlikely(sin_hue > 511 || cos_hue > 511)) {
418                         dev_err(fbi->dev, "sin_hue=%d,cos_hue=%d\n",
419                                 sin_hue, cos_hue);
420                 }
421                 if (dev_drv->ops->set_dsp_bcsh_hue)
422                         ret = dev_drv->ops->set_dsp_bcsh_hue(dev_drv,
423                                                              sin_hue,
424                                                              cos_hue);
425                 else
426                         ret = -1;
427         } else {
428                 printk("format error\n");
429         }
430
431         if (ret < 0)
432                 return ret;
433
434         return count;
435 }
436
437 static ssize_t show_scale(struct device *dev,
438                           struct device_attribute *attr, char *buf)
439 {
440         struct fb_info *fbi = dev_get_drvdata(dev);
441         struct rk_lcdc_driver *dev_drv =
442             (struct rk_lcdc_driver *)fbi->par;
443         struct rk_screen *screen = dev_drv->cur_screen;
444
445         return snprintf(buf, PAGE_SIZE,
446                 "xscale=%d yscale=%d\nleft=%d top=%d right=%d bottom=%d\n",
447                 (screen->overscan.left + screen->overscan.right)/2,
448                 (screen->overscan.top + screen->overscan.bottom)/2,
449                 screen->overscan.left, screen->overscan.top,
450                 screen->overscan.right, screen->overscan.bottom);
451 }
452
453 static ssize_t set_scale(struct device *dev, struct device_attribute *attr,
454                          const char *buf, size_t count)
455 {
456         struct fb_info *fbi = dev_get_drvdata(dev);
457         struct rk_lcdc_driver *dev_drv =
458             (struct rk_lcdc_driver *)fbi->par;
459         struct rk_screen *screen = dev_drv->cur_screen;
460         u32 left, top, right, bottom;
461
462         if (!strncmp(buf, "overscan", 8)) {
463                 sscanf(buf,
464                        "overscan %d,%d,%d,%d", &left, &top, &right, &bottom);
465                 if (left > 0 && left <= 100)
466                         screen->overscan.left = left;
467                 if (top > 0 && top <= 100)
468                         screen->overscan.top = top;
469                 if (right > 0 && right <= 100)
470                         screen->overscan.right = right;
471                 if (bottom > 0 && bottom <= 100)
472                         screen->overscan.bottom = bottom;
473         } else if (!strncmp(buf, "left", 4)) {
474                 sscanf(buf, "left=%d", &left);
475                 if (left > 0 && left <= 100)
476                         screen->overscan.left = left;
477         } else if (!strncmp(buf, "top", 3)) {
478                 sscanf(buf, "top=%d", &top);
479                 if (top > 0 && top <= 100)
480                         screen->overscan.top = top;
481         } else if (!strncmp(buf, "right", 5)) {
482                 sscanf(buf, "right=%d", &right);
483                 if (right > 0 && right <= 100)
484                         screen->overscan.right = right;
485         } else if (!strncmp(buf, "bottom", 6)) {
486                 sscanf(buf, "bottom=%d", &bottom);
487                 if (bottom > 0 && bottom <= 100)
488                         screen->overscan.bottom = bottom;
489         } else if (!strncmp(buf, "xscale", 6)) {
490                 sscanf(buf, "xscale=%d", &left);
491                 if (left > 0 && left <= 100) {
492                         screen->overscan.left = left;
493                         screen->overscan.right = left;
494                 }
495         } else if (!strncmp(buf, "yscale", 6)) {
496                 sscanf(buf, "yscale=%d", &left);
497                 if (left > 0 && left <= 100) {
498                         screen->overscan.top = left;
499                         screen->overscan.bottom = left;
500                 }
501         } else {
502                 sscanf(buf, "%d", &left);
503                 if (left > 0 && left <= 100) {
504                         screen->overscan.left = left;
505                         screen->overscan.right = left;
506                         screen->overscan.top = left;
507                         screen->overscan.bottom = left;
508                 }
509         }
510
511         if (dev_drv->ops->set_overscan)
512                 dev_drv->ops->set_overscan(dev_drv, &screen->overscan);
513
514         return count;
515 }
516
517 static struct device_attribute rkfb_attrs[] = {
518         __ATTR(phys_addr, S_IRUGO, show_phys, NULL),
519         __ATTR(virt_addr, S_IRUGO, show_virt, NULL),
520         __ATTR(disp_info, S_IRUGO, show_disp_info, NULL),
521         __ATTR(screen_info, S_IRUGO, show_screen_info, NULL),
522         __ATTR(dual_mode, S_IRUGO, show_dual_mode, NULL),
523         __ATTR(enable, S_IRUGO | S_IWUSR, show_fb_state, set_fb_state),
524         __ATTR(overlay, S_IRUGO | S_IWUSR, show_overlay, set_overlay),
525         __ATTR(fps, S_IRUGO | S_IWUSR, show_fps, set_fps),
526         __ATTR(map, S_IRUGO | S_IWUSR, show_fb_win_map, set_fb_win_map),
527         __ATTR(dsp_lut, S_IRUGO | S_IWUSR, show_dsp_lut, set_dsp_lut),
528         __ATTR(cabc, S_IRUGO | S_IWUSR, show_dsp_cabc, set_dsp_cabc),
529         __ATTR(bcsh, S_IRUGO | S_IWUSR, show_dsp_bcsh, set_dsp_bcsh),
530         __ATTR(scale, S_IRUGO | S_IWUSR, show_scale, set_scale),
531 };
532
533 int rkfb_create_sysfs(struct fb_info *fbi)
534 {
535         int r, t;
536
537         for (t = 0; t < ARRAY_SIZE(rkfb_attrs); t++) {
538                 r = device_create_file(fbi->dev, &rkfb_attrs[t]);
539                 if (r) {
540                         dev_err(fbi->dev, "failed to create sysfs " "file\n");
541                         return r;
542                 }
543         }
544
545         return 0;
546 }
547
548 void rkfb_remove_sysfs(struct rk_fb *rk_fb)
549 {
550         int i, t;
551
552         for (i = 0; i < rk_fb->num_fb; i++) {
553                 for (t = 0; t < ARRAY_SIZE(rkfb_attrs); t++)
554                         device_remove_file(rk_fb->fb[i]->dev, &rkfb_attrs[t]);
555         }
556 }