2 * linux/drivers/video/omap2/omapfb-sysfs.c
4 * Copyright (C) 2008 Nokia Corporation
5 * Author: Tomi Valkeinen <tomi.valkeinen@nokia.com>
7 * Some code and ideas taken from drivers/video/omap/ driver
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.
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
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/>.
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>
30 #include <linux/omapfb.h>
32 #include <video/omapdss.h>
33 #include <plat/vrfb.h>
37 static ssize_t
show_rotate_type(struct device
*dev
,
38 struct device_attribute
*attr
, char *buf
)
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
);
46 static ssize_t
store_rotate_type(struct device
*dev
,
47 struct device_attribute
*attr
,
48 const char *buf
, size_t count
)
50 struct fb_info
*fbi
= dev_get_drvdata(dev
);
51 struct omapfb_info
*ofbi
= FB2OFB(fbi
);
52 struct omapfb2_mem_region
*rg
;
56 r
= kstrtoint(buf
, 0, &rot_type
);
60 if (rot_type
!= OMAP_DSS_ROT_DMA
&& rot_type
!= OMAP_DSS_ROT_VRFB
)
63 if (!lock_fb_info(fbi
))
67 if (rot_type
== ofbi
->rotation_type
)
70 rg
= omapfb_get_mem_region(ofbi
->region
);
77 ofbi
->rotation_type
= rot_type
;
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.
84 omapfb_put_mem_region(rg
);
92 static ssize_t
show_mirror(struct device
*dev
,
93 struct device_attribute
*attr
, char *buf
)
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
);
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
);
109 struct fb_var_screeninfo new_var
;
111 r
= strtobool(buf
, &mirror
);
115 if (!lock_fb_info(fbi
))
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
);
126 memcpy(&fbi
->var
, &new_var
, sizeof(fbi
->var
));
130 r
= omapfb_apply_changes(fbi
, 0);
136 omapfb_put_mem_region(ofbi
->region
);
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
;
152 if (!lock_fb_info(fbi
))
156 for (t
= 0; t
< ofbi
->num_overlays
; t
++) {
157 struct omap_overlay
*ovl
= ofbi
->overlays
[t
];
160 for (ovlnum
= 0; ovlnum
< fbdev
->num_overlays
; ++ovlnum
)
161 if (ovl
== fbdev
->overlays
[ovlnum
])
164 l
+= snprintf(buf
+ l
, PAGE_SIZE
- l
, "%s%d",
165 t
== 0 ? "" : ",", ovlnum
);
168 l
+= snprintf(buf
+ l
, PAGE_SIZE
- l
, "\n");
170 omapfb_unlock(fbdev
);
176 static struct omapfb_info
*get_overlay_fb(struct omapfb2_device
*fbdev
,
177 struct omap_overlay
*ovl
)
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
)
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
;
208 if (buf
[len
- 1] == '\n')
211 if (!lock_fb_info(fbi
))
216 char *p
= (char *)buf
;
219 while (p
< buf
+ len
) {
221 if (num_ovls
== OMAPFB_MAX_OVL_PER_FB
) {
226 ovlnum
= simple_strtoul(p
, &p
, 0);
227 if (ovlnum
> fbdev
->num_overlays
) {
233 for (i
= 0; i
< num_ovls
; ++i
) {
234 if (ovls
[i
] == fbdev
->overlays
[ovlnum
]) {
241 ovls
[num_ovls
++] = fbdev
->overlays
[ovlnum
];
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");
256 /* detach unused overlays */
257 for (i
= 0; i
< ofbi
->num_overlays
; ++i
) {
260 ovl
= ofbi
->overlays
[i
];
264 for (t
= 0; t
< num_ovls
; ++t
) {
265 if (ovl
== ovls
[t
]) {
274 DBG("detaching %d\n", ofbi
->overlays
[i
]->id
);
276 omapfb_get_mem_region(ofbi
->region
);
278 omapfb_overlay_enable(ovl
, 0);
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
];
290 ofbi
->num_overlays
--;
294 for (i
= 0; i
< num_ovls
; ++i
) {
301 for (t
= 0; t
< ofbi
->num_overlays
; ++t
) {
302 if (ovl
== ofbi
->overlays
[t
]) {
310 ofbi
->rotation
[ofbi
->num_overlays
] = 0;
311 ofbi
->overlays
[ofbi
->num_overlays
++] = ovl
;
317 omapfb_get_mem_region(ofbi
->region
);
319 r
= omapfb_apply_changes(fbi
, 0);
321 omapfb_put_mem_region(ofbi
->region
);
329 omapfb_unlock(fbdev
);
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
);
343 if (!lock_fb_info(fbi
))
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
]);
351 l
+= snprintf(buf
+ l
, PAGE_SIZE
- l
, "\n");
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
;
365 bool changed
= false;
366 u8 rotation
[OMAPFB_MAX_OVL_PER_FB
];
369 if (buf
[len
- 1] == '\n')
372 if (!lock_fb_info(fbi
))
376 char *p
= (char *)buf
;
378 while (p
< buf
+ len
) {
381 if (num_ovls
== ofbi
->num_overlays
) {
386 rot
= simple_strtoul(p
, &p
, 0);
387 if (rot
< 0 || rot
> 3) {
392 if (ofbi
->rotation
[num_ovls
] != rot
)
395 rotation
[num_ovls
++] = rot
;
401 if (num_ovls
!= ofbi
->num_overlays
) {
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
);
419 /* FIXME error handling? */
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 omapfb2_mem_region
*rg
;
449 r
= kstrtoul(buf
, 0, &size
);
453 size
= PAGE_ALIGN(size
);
455 if (!lock_fb_info(fbi
))
460 down_write_nested(&rg
->lock
, rg
->id
);
461 atomic_inc(&rg
->lock_count
);
463 if (atomic_read(&rg
->map_count
)) {
468 for (i
= 0; i
< fbdev
->num_fbs
; i
++) {
469 struct omapfb_info
*ofbi2
= FB2OFB(fbdev
->fbs
[i
]);
472 if (ofbi2
->region
!= rg
)
475 for (j
= 0; j
< ofbi2
->num_overlays
; j
++) {
476 struct omap_overlay
*ovl
;
477 ovl
= ofbi2
->overlays
[j
];
478 if (ovl
->is_enabled(ovl
)) {
485 if (size
!= ofbi
->region
->size
) {
486 r
= omapfb_realloc_fbmem(fbi
, size
, ofbi
->region
->type
);
488 dev_err(dev
, "realloc fbmem failed\n");
495 atomic_dec(&rg
->lock_count
);
503 static ssize_t
show_phys(struct device
*dev
,
504 struct device_attribute
*attr
, char *buf
)
506 struct fb_info
*fbi
= dev_get_drvdata(dev
);
507 struct omapfb_info
*ofbi
= FB2OFB(fbi
);
509 return snprintf(buf
, PAGE_SIZE
, "%0x\n", ofbi
->region
->paddr
);
512 static ssize_t
show_virt(struct device
*dev
,
513 struct device_attribute
*attr
, char *buf
)
515 struct fb_info
*fbi
= dev_get_drvdata(dev
);
516 struct omapfb_info
*ofbi
= FB2OFB(fbi
);
518 return snprintf(buf
, PAGE_SIZE
, "%p\n", ofbi
->region
->vaddr
);
521 static ssize_t
show_upd_mode(struct device
*dev
,
522 struct device_attribute
*attr
, char *buf
)
524 struct fb_info
*fbi
= dev_get_drvdata(dev
);
525 enum omapfb_update_mode mode
;
528 r
= omapfb_get_update_mode(fbi
, &mode
);
533 return snprintf(buf
, PAGE_SIZE
, "%u\n", (unsigned)mode
);
536 static ssize_t
store_upd_mode(struct device
*dev
, struct device_attribute
*attr
,
537 const char *buf
, size_t count
)
539 struct fb_info
*fbi
= dev_get_drvdata(dev
);
543 r
= kstrtouint(buf
, 0, &mode
);
547 r
= omapfb_set_update_mode(fbi
, mode
);
554 static struct device_attribute omapfb_attrs
[] = {
555 __ATTR(rotate_type
, S_IRUGO
| S_IWUSR
, show_rotate_type
,
557 __ATTR(mirror
, S_IRUGO
| S_IWUSR
, show_mirror
, store_mirror
),
558 __ATTR(size
, S_IRUGO
| S_IWUSR
, show_size
, store_size
),
559 __ATTR(overlays
, S_IRUGO
| S_IWUSR
, show_overlays
, store_overlays
),
560 __ATTR(overlays_rotate
, S_IRUGO
| S_IWUSR
, show_overlays_rotate
,
561 store_overlays_rotate
),
562 __ATTR(phys_addr
, S_IRUGO
, show_phys
, NULL
),
563 __ATTR(virt_addr
, S_IRUGO
, show_virt
, NULL
),
564 __ATTR(update_mode
, S_IRUGO
| S_IWUSR
, show_upd_mode
, store_upd_mode
),
567 int omapfb_create_sysfs(struct omapfb2_device
*fbdev
)
572 DBG("create sysfs for fbs\n");
573 for (i
= 0; i
< fbdev
->num_fbs
; i
++) {
575 for (t
= 0; t
< ARRAY_SIZE(omapfb_attrs
); t
++) {
576 r
= device_create_file(fbdev
->fbs
[i
]->dev
,
580 dev_err(fbdev
->dev
, "failed to create sysfs "
590 void omapfb_remove_sysfs(struct omapfb2_device
*fbdev
)
594 DBG("remove sysfs for fbs\n");
595 for (i
= 0; i
< fbdev
->num_fbs
; i
++) {
596 for (t
= 0; t
< ARRAY_SIZE(omapfb_attrs
); t
++)
597 device_remove_file(fbdev
->fbs
[i
]->dev
,