OMAPDSS: Add methods for skipping display initialization
[android-sdk/kernel-video.git] / drivers / video / fbdev / omap2 / omapfb / omapfb-sysfs.c
1 /*
2  * linux/drivers/video/omap2/omapfb-sysfs.c
3  *
4  * Copyright (C) 2008 Nokia Corporation
5  * Author: Tomi Valkeinen <tomi.valkeinen@nokia.com>
6  *
7  * Some code and ideas taken from drivers/video/omap/ driver
8  * by Imre Deak.
9  *
10  * This program is free software; you can redistribute it and/or modify it
11  * under the terms of the GNU General Public License version 2 as published by
12  * the Free Software Foundation.
13  *
14  * This program is distributed in the hope that it will be useful, but WITHOUT
15  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
16  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
17  * more details.
18  *
19  * You should have received a copy of the GNU General Public License along with
20  * this program.  If not, see <http://www.gnu.org/licenses/>.
21  */
23 #include <linux/fb.h>
24 #include <linux/sysfs.h>
25 #include <linux/device.h>
26 #include <linux/uaccess.h>
27 #include <linux/platform_device.h>
28 #include <linux/kernel.h>
29 #include <linux/mm.h>
30 #include <linux/omapfb.h>
32 #include <video/omapdss.h>
33 #include <video/omapvrfb.h>
35 #include "omapfb.h"
37 static ssize_t show_rotate_type(struct device *dev,
38                 struct device_attribute *attr, char *buf)
39 {
40         struct fb_info *fbi = dev_get_drvdata(dev);
41         struct omapfb_info *ofbi = FB2OFB(fbi);
43         return snprintf(buf, PAGE_SIZE, "%d\n", ofbi->rotation_type);
44 }
46 static ssize_t store_rotate_type(struct device *dev,
47                 struct device_attribute *attr,
48                 const char *buf, size_t count)
49 {
50         struct fb_info *fbi = dev_get_drvdata(dev);
51         struct omapfb_info *ofbi = FB2OFB(fbi);
52         struct omapfb2_mem_region *rg;
53         int rot_type;
54         int r;
56         r = kstrtoint(buf, 0, &rot_type);
57         if (r)
58                 return r;
60         if (rot_type != OMAP_DSS_ROT_DMA && rot_type != OMAP_DSS_ROT_VRFB)
61                 return -EINVAL;
63         if (!lock_fb_info(fbi))
64                 return -ENODEV;
66         r = 0;
67         if (rot_type == ofbi->rotation_type)
68                 goto out;
70         rg = omapfb_get_mem_region(ofbi->region);
72         if (rg->size) {
73                 r = -EBUSY;
74                 goto put_region;
75         }
77         ofbi->rotation_type = rot_type;
79         /*
80          * Since the VRAM for this FB is not allocated at the moment we don't
81          * need to do any further parameter checking at this point.
82          */
83 put_region:
84         omapfb_put_mem_region(rg);
85 out:
86         unlock_fb_info(fbi);
88         return r ? r : count;
89 }
92 static ssize_t show_mirror(struct device *dev,
93                 struct device_attribute *attr, char *buf)
94 {
95         struct fb_info *fbi = dev_get_drvdata(dev);
96         struct omapfb_info *ofbi = FB2OFB(fbi);
98         return snprintf(buf, PAGE_SIZE, "%d\n", ofbi->mirror);
99 }
101 static ssize_t store_mirror(struct device *dev,
102                 struct device_attribute *attr,
103                 const char *buf, size_t count)
105         struct fb_info *fbi = dev_get_drvdata(dev);
106         struct omapfb_info *ofbi = FB2OFB(fbi);
107         bool mirror;
108         int r;
109         struct fb_var_screeninfo new_var;
111         r = strtobool(buf, &mirror);
112         if (r)
113                 return r;
115         if (!lock_fb_info(fbi))
116                 return -ENODEV;
118         ofbi->mirror = mirror;
120         omapfb_get_mem_region(ofbi->region);
122         memcpy(&new_var, &fbi->var, sizeof(new_var));
123         r = check_fb_var(fbi, &new_var);
124         if (r)
125                 goto out;
126         memcpy(&fbi->var, &new_var, sizeof(fbi->var));
128         set_fb_fix(fbi);
130         r = omapfb_apply_changes(fbi, 0);
131         if (r)
132                 goto out;
134         r = count;
135 out:
136         omapfb_put_mem_region(ofbi->region);
138         unlock_fb_info(fbi);
140         return r;
143 static ssize_t show_overlays(struct device *dev,
144                 struct device_attribute *attr, char *buf)
146         struct fb_info *fbi = dev_get_drvdata(dev);
147         struct omapfb_info *ofbi = FB2OFB(fbi);
148         struct omapfb2_device *fbdev = ofbi->fbdev;
149         ssize_t l = 0;
150         int t;
152         if (!lock_fb_info(fbi))
153                 return -ENODEV;
154         omapfb_lock(fbdev);
156         for (t = 0; t < ofbi->num_overlays; t++) {
157                 struct omap_overlay *ovl = ofbi->overlays[t];
158                 int ovlnum;
160                 for (ovlnum = 0; ovlnum < fbdev->num_overlays; ++ovlnum)
161                         if (ovl == fbdev->overlays[ovlnum])
162                                 break;
164                 l += snprintf(buf + l, PAGE_SIZE - l, "%s%d",
165                                 t == 0 ? "" : ",", ovlnum);
166         }
168         l += snprintf(buf + l, PAGE_SIZE - l, "\n");
170         omapfb_unlock(fbdev);
171         unlock_fb_info(fbi);
173         return l;
176 static struct omapfb_info *get_overlay_fb(struct omapfb2_device *fbdev,
177                 struct omap_overlay *ovl)
179         int i, t;
181         for (i = 0; i < fbdev->num_fbs; i++) {
182                 struct omapfb_info *ofbi = FB2OFB(fbdev->fbs[i]);
184                 for (t = 0; t < ofbi->num_overlays; t++) {
185                         if (ofbi->overlays[t] == ovl)
186                                 return ofbi;
187                 }
188         }
190         return NULL;
193 static ssize_t store_overlays(struct device *dev, struct device_attribute *attr,
194                 const char *buf, size_t count)
196         struct fb_info *fbi = dev_get_drvdata(dev);
197         struct omapfb_info *ofbi = FB2OFB(fbi);
198         struct omapfb2_device *fbdev = ofbi->fbdev;
199         struct omap_overlay *ovls[OMAPFB_MAX_OVL_PER_FB];
200         struct omap_overlay *ovl;
201         int num_ovls, r, i;
202         int len;
203         bool added = false;
205         num_ovls = 0;
207         len = strlen(buf);
208         if (buf[len - 1] == '\n')
209                 len = len - 1;
211         if (!lock_fb_info(fbi))
212                 return -ENODEV;
213         omapfb_lock(fbdev);
215         if (len > 0) {
216                 char *p = (char *)buf;
217                 int ovlnum;
219                 while (p < buf + len) {
220                         int found;
221                         if (num_ovls == OMAPFB_MAX_OVL_PER_FB) {
222                                 r = -EINVAL;
223                                 goto out;
224                         }
226                         ovlnum = simple_strtoul(p, &p, 0);
227                         if (ovlnum > fbdev->num_overlays) {
228                                 r = -EINVAL;
229                                 goto out;
230                         }
232                         found = 0;
233                         for (i = 0; i < num_ovls; ++i) {
234                                 if (ovls[i] == fbdev->overlays[ovlnum]) {
235                                         found = 1;
236                                         break;
237                                 }
238                         }
240                         if (!found)
241                                 ovls[num_ovls++] = fbdev->overlays[ovlnum];
243                         p++;
244                 }
245         }
247         for (i = 0; i < num_ovls; ++i) {
248                 struct omapfb_info *ofbi2 = get_overlay_fb(fbdev, ovls[i]);
249                 if (ofbi2 && ofbi2 != ofbi) {
250                         dev_err(fbdev->dev, "overlay already in use\n");
251                         r = -EINVAL;
252                         goto out;
253                 }
254         }
256         /* detach unused overlays */
257         for (i = 0; i < ofbi->num_overlays; ++i) {
258                 int t, found;
260                 ovl = ofbi->overlays[i];
262                 found = 0;
264                 for (t = 0; t < num_ovls; ++t) {
265                         if (ovl == ovls[t]) {
266                                 found = 1;
267                                 break;
268                         }
269                 }
271                 if (found)
272                         continue;
274                 DBG("detaching %d\n", ofbi->overlays[i]->id);
276                 omapfb_get_mem_region(ofbi->region);
278                 omapfb_overlay_enable(ovl, 0);
280                 if (ovl->manager)
281                         ovl->manager->apply(ovl->manager);
283                 omapfb_put_mem_region(ofbi->region);
285                 for (t = i + 1; t < ofbi->num_overlays; t++) {
286                         ofbi->rotation[t-1] = ofbi->rotation[t];
287                         ofbi->overlays[t-1] = ofbi->overlays[t];
288                 }
290                 ofbi->num_overlays--;
291                 i--;
292         }
294         for (i = 0; i < num_ovls; ++i) {
295                 int t, found;
297                 ovl = ovls[i];
299                 found = 0;
301                 for (t = 0; t < ofbi->num_overlays; ++t) {
302                         if (ovl == ofbi->overlays[t]) {
303                                 found = 1;
304                                 break;
305                         }
306                 }
308                 if (found)
309                         continue;
310                 ofbi->rotation[ofbi->num_overlays] = 0;
311                 ofbi->overlays[ofbi->num_overlays++] = ovl;
313                 added = true;
314         }
316         if (added) {
317                 omapfb_get_mem_region(ofbi->region);
319                 r = omapfb_apply_changes(fbi, 0);
321                 omapfb_put_mem_region(ofbi->region);
323                 if (r)
324                         goto out;
325         }
327         r = count;
328 out:
329         omapfb_unlock(fbdev);
330         unlock_fb_info(fbi);
332         return r;
335 static ssize_t show_overlays_rotate(struct device *dev,
336                 struct device_attribute *attr, char *buf)
338         struct fb_info *fbi = dev_get_drvdata(dev);
339         struct omapfb_info *ofbi = FB2OFB(fbi);
340         ssize_t l = 0;
341         int t;
343         if (!lock_fb_info(fbi))
344                 return -ENODEV;
346         for (t = 0; t < ofbi->num_overlays; t++) {
347                 l += snprintf(buf + l, PAGE_SIZE - l, "%s%d",
348                                 t == 0 ? "" : ",", ofbi->rotation[t]);
349         }
351         l += snprintf(buf + l, PAGE_SIZE - l, "\n");
353         unlock_fb_info(fbi);
355         return l;
358 static ssize_t store_overlays_rotate(struct device *dev,
359                 struct device_attribute *attr, const char *buf, size_t count)
361         struct fb_info *fbi = dev_get_drvdata(dev);
362         struct omapfb_info *ofbi = FB2OFB(fbi);
363         int num_ovls = 0, r, i;
364         int len;
365         bool changed = false;
366         u8 rotation[OMAPFB_MAX_OVL_PER_FB];
368         len = strlen(buf);
369         if (buf[len - 1] == '\n')
370                 len = len - 1;
372         if (!lock_fb_info(fbi))
373                 return -ENODEV;
375         if (len > 0) {
376                 char *p = (char *)buf;
378                 while (p < buf + len) {
379                         int rot;
381                         if (num_ovls == ofbi->num_overlays) {
382                                 r = -EINVAL;
383                                 goto out;
384                         }
386                         rot = simple_strtoul(p, &p, 0);
387                         if (rot < 0 || rot > 3) {
388                                 r = -EINVAL;
389                                 goto out;
390                         }
392                         if (ofbi->rotation[num_ovls] != rot)
393                                 changed = true;
395                         rotation[num_ovls++] = rot;
397                         p++;
398                 }
399         }
401         if (num_ovls != ofbi->num_overlays) {
402                 r = -EINVAL;
403                 goto out;
404         }
406         if (changed) {
407                 for (i = 0; i < num_ovls; ++i)
408                         ofbi->rotation[i] = rotation[i];
410                 omapfb_get_mem_region(ofbi->region);
412                 r = omapfb_apply_changes(fbi, 0);
414                 omapfb_put_mem_region(ofbi->region);
416                 if (r)
417                         goto out;
419                 /* FIXME error handling? */
420         }
422         r = count;
423 out:
424         unlock_fb_info(fbi);
426         return r;
429 static ssize_t show_size(struct device *dev,
430                 struct device_attribute *attr, char *buf)
432         struct fb_info *fbi = dev_get_drvdata(dev);
433         struct omapfb_info *ofbi = FB2OFB(fbi);
435         return snprintf(buf, PAGE_SIZE, "%lu\n", ofbi->region->size);
438 static ssize_t store_size(struct device *dev, struct device_attribute *attr,
439                 const char *buf, size_t count)
441         struct fb_info *fbi = dev_get_drvdata(dev);
442         struct omapfb_info *ofbi = FB2OFB(fbi);
443         struct omapfb2_device *fbdev = ofbi->fbdev;
444         struct omap_dss_device *display = fb2display(fbi);
445         struct omapfb2_mem_region *rg;
446         unsigned long size;
447         int r;
448         int i;
450         r = kstrtoul(buf, 0, &size);
451         if (r)
452                 return r;
454         size = PAGE_ALIGN(size);
456         if (!lock_fb_info(fbi))
457                 return -ENODEV;
459         if (display && display->driver->sync)
460                 display->driver->sync(display);
462         rg = ofbi->region;
464         down_write_nested(&rg->lock, rg->id);
465         atomic_inc(&rg->lock_count);
467         if (atomic_read(&rg->map_count)) {
468                 r = -EBUSY;
469                 goto out;
470         }
472         for (i = 0; i < fbdev->num_fbs; i++) {
473                 struct omapfb_info *ofbi2 = FB2OFB(fbdev->fbs[i]);
474                 int j;
476                 if (ofbi2->region != rg)
477                         continue;
479                 for (j = 0; j < ofbi2->num_overlays; j++) {
480                         struct omap_overlay *ovl;
481                         ovl = ofbi2->overlays[j];
482                         if (ovl->is_enabled(ovl)) {
483                                 r = -EBUSY;
484                                 goto out;
485                         }
486                 }
487         }
489         if (size != ofbi->region->size) {
490                 r = omapfb_realloc_fbmem(fbi, size, ofbi->region->type);
491                 if (r) {
492                         dev_err(dev, "realloc fbmem failed\n");
493                         goto out;
494                 }
495         }
497         r = count;
498 out:
499         atomic_dec(&rg->lock_count);
500         up_write(&rg->lock);
502         unlock_fb_info(fbi);
504         return r;
507 static ssize_t show_phys(struct device *dev,
508                 struct device_attribute *attr, char *buf)
510         struct fb_info *fbi = dev_get_drvdata(dev);
511         struct omapfb_info *ofbi = FB2OFB(fbi);
513         return snprintf(buf, PAGE_SIZE, "%0x\n", ofbi->region->paddr);
516 static ssize_t show_virt(struct device *dev,
517                 struct device_attribute *attr, char *buf)
519         struct fb_info *fbi = dev_get_drvdata(dev);
520         struct omapfb_info *ofbi = FB2OFB(fbi);
522         return snprintf(buf, PAGE_SIZE, "%p\n", ofbi->region->vaddr);
525 static ssize_t show_upd_mode(struct device *dev,
526                 struct device_attribute *attr, char *buf)
528         struct fb_info *fbi = dev_get_drvdata(dev);
529         enum omapfb_update_mode mode;
530         int r;
532         r = omapfb_get_update_mode(fbi, &mode);
534         if (r)
535                 return r;
537         return snprintf(buf, PAGE_SIZE, "%u\n", (unsigned)mode);
540 static ssize_t store_upd_mode(struct device *dev, struct device_attribute *attr,
541                 const char *buf, size_t count)
543         struct fb_info *fbi = dev_get_drvdata(dev);
544         unsigned mode;
545         int r;
547         r = kstrtouint(buf, 0, &mode);
548         if (r)
549                 return r;
551         r = omapfb_set_update_mode(fbi, mode);
552         if (r)
553                 return r;
555         return count;
558 static struct device_attribute omapfb_attrs[] = {
559         __ATTR(rotate_type, S_IRUGO | S_IWUSR, show_rotate_type,
560                         store_rotate_type),
561         __ATTR(mirror, S_IRUGO | S_IWUSR, show_mirror, store_mirror),
562         __ATTR(size, S_IRUGO | S_IWUSR, show_size, store_size),
563         __ATTR(overlays, S_IRUGO | S_IWUSR, show_overlays, store_overlays),
564         __ATTR(overlays_rotate, S_IRUGO | S_IWUSR, show_overlays_rotate,
565                         store_overlays_rotate),
566         __ATTR(phys_addr, S_IRUGO, show_phys, NULL),
567         __ATTR(virt_addr, S_IRUGO, show_virt, NULL),
568         __ATTR(update_mode, S_IRUGO | S_IWUSR, show_upd_mode, store_upd_mode),
569 };
571 int omapfb_create_sysfs(struct omapfb2_device *fbdev)
573         int i;
574         int r;
576         DBG("create sysfs for fbs\n");
577         for (i = 0; i < fbdev->num_fbs; i++) {
578                 int t;
579                 for (t = 0; t < ARRAY_SIZE(omapfb_attrs); t++) {
580                         r = device_create_file(fbdev->fbs[i]->dev,
581                                         &omapfb_attrs[t]);
583                         if (r) {
584                                 dev_err(fbdev->dev, "failed to create sysfs "
585                                                 "file\n");
586                                 return r;
587                         }
588                 }
589         }
591         return 0;
594 void omapfb_remove_sysfs(struct omapfb2_device *fbdev)
596         int i, t;
598         DBG("remove sysfs for fbs\n");
599         for (i = 0; i < fbdev->num_fbs; i++) {
600                 for (t = 0; t < ARRAY_SIZE(omapfb_attrs); t++)
601                         device_remove_file(fbdev->fbs[i]->dev,
602                                         &omapfb_attrs[t]);
603         }