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  */
22 
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>
31 
32 #include <video/omapdss.h>
33 #include <plat/vrfb.h>
34 
35 #include "omapfb.h"
36 
show_rotate_type(struct device * dev,struct device_attribute * attr,char * buf)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);
42 
43 	return snprintf(buf, PAGE_SIZE, "%d\n", ofbi->rotation_type);
44 }
45 
store_rotate_type(struct device * dev,struct device_attribute * attr,const char * buf,size_t count)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;
55 
56 	r = kstrtoint(buf, 0, &rot_type);
57 	if (r)
58 		return r;
59 
60 	if (rot_type != OMAP_DSS_ROT_DMA && rot_type != OMAP_DSS_ROT_VRFB)
61 		return -EINVAL;
62 
63 	if (!lock_fb_info(fbi))
64 		return -ENODEV;
65 
66 	r = 0;
67 	if (rot_type == ofbi->rotation_type)
68 		goto out;
69 
70 	rg = omapfb_get_mem_region(ofbi->region);
71 
72 	if (rg->size) {
73 		r = -EBUSY;
74 		goto put_region;
75 	}
76 
77 	ofbi->rotation_type = rot_type;
78 
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);
87 
88 	return r ? r : count;
89 }
90 
91 
show_mirror(struct device * dev,struct device_attribute * attr,char * buf)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);
97 
98 	return snprintf(buf, PAGE_SIZE, "%d\n", ofbi->mirror);
99 }
100 
store_mirror(struct device * dev,struct device_attribute * attr,const char * buf,size_t count)101 static ssize_t store_mirror(struct device *dev,
102 		struct device_attribute *attr,
103 		const char *buf, size_t count)
104 {
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;
110 
111 	r = strtobool(buf, &mirror);
112 	if (r)
113 		return r;
114 
115 	if (!lock_fb_info(fbi))
116 		return -ENODEV;
117 
118 	ofbi->mirror = mirror;
119 
120 	omapfb_get_mem_region(ofbi->region);
121 
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));
127 
128 	set_fb_fix(fbi);
129 
130 	r = omapfb_apply_changes(fbi, 0);
131 	if (r)
132 		goto out;
133 
134 	r = count;
135 out:
136 	omapfb_put_mem_region(ofbi->region);
137 
138 	unlock_fb_info(fbi);
139 
140 	return r;
141 }
142 
show_overlays(struct device * dev,struct device_attribute * attr,char * buf)143 static ssize_t show_overlays(struct device *dev,
144 		struct device_attribute *attr, char *buf)
145 {
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;
151 
152 	if (!lock_fb_info(fbi))
153 		return -ENODEV;
154 	omapfb_lock(fbdev);
155 
156 	for (t = 0; t < ofbi->num_overlays; t++) {
157 		struct omap_overlay *ovl = ofbi->overlays[t];
158 		int ovlnum;
159 
160 		for (ovlnum = 0; ovlnum < fbdev->num_overlays; ++ovlnum)
161 			if (ovl == fbdev->overlays[ovlnum])
162 				break;
163 
164 		l += snprintf(buf + l, PAGE_SIZE - l, "%s%d",
165 				t == 0 ? "" : ",", ovlnum);
166 	}
167 
168 	l += snprintf(buf + l, PAGE_SIZE - l, "\n");
169 
170 	omapfb_unlock(fbdev);
171 	unlock_fb_info(fbi);
172 
173 	return l;
174 }
175 
get_overlay_fb(struct omapfb2_device * fbdev,struct omap_overlay * ovl)176 static struct omapfb_info *get_overlay_fb(struct omapfb2_device *fbdev,
177 		struct omap_overlay *ovl)
178 {
179 	int i, t;
180 
181 	for (i = 0; i < fbdev->num_fbs; i++) {
182 		struct omapfb_info *ofbi = FB2OFB(fbdev->fbs[i]);
183 
184 		for (t = 0; t < ofbi->num_overlays; t++) {
185 			if (ofbi->overlays[t] == ovl)
186 				return ofbi;
187 		}
188 	}
189 
190 	return NULL;
191 }
192 
store_overlays(struct device * dev,struct device_attribute * attr,const char * buf,size_t count)193 static ssize_t store_overlays(struct device *dev, struct device_attribute *attr,
194 		const char *buf, size_t count)
195 {
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;
204 
205 	num_ovls = 0;
206 
207 	len = strlen(buf);
208 	if (buf[len - 1] == '\n')
209 		len = len - 1;
210 
211 	if (!lock_fb_info(fbi))
212 		return -ENODEV;
213 	omapfb_lock(fbdev);
214 
215 	if (len > 0) {
216 		char *p = (char *)buf;
217 		int ovlnum;
218 
219 		while (p < buf + len) {
220 			int found;
221 			if (num_ovls == OMAPFB_MAX_OVL_PER_FB) {
222 				r = -EINVAL;
223 				goto out;
224 			}
225 
226 			ovlnum = simple_strtoul(p, &p, 0);
227 			if (ovlnum > fbdev->num_overlays) {
228 				r = -EINVAL;
229 				goto out;
230 			}
231 
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 			}
239 
240 			if (!found)
241 				ovls[num_ovls++] = fbdev->overlays[ovlnum];
242 
243 			p++;
244 		}
245 	}
246 
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 	}
255 
256 	/* detach unused overlays */
257 	for (i = 0; i < ofbi->num_overlays; ++i) {
258 		int t, found;
259 
260 		ovl = ofbi->overlays[i];
261 
262 		found = 0;
263 
264 		for (t = 0; t < num_ovls; ++t) {
265 			if (ovl == ovls[t]) {
266 				found = 1;
267 				break;
268 			}
269 		}
270 
271 		if (found)
272 			continue;
273 
274 		DBG("detaching %d\n", ofbi->overlays[i]->id);
275 
276 		omapfb_get_mem_region(ofbi->region);
277 
278 		omapfb_overlay_enable(ovl, 0);
279 
280 		if (ovl->manager)
281 			ovl->manager->apply(ovl->manager);
282 
283 		omapfb_put_mem_region(ofbi->region);
284 
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 		}
289 
290 		ofbi->num_overlays--;
291 		i--;
292 	}
293 
294 	for (i = 0; i < num_ovls; ++i) {
295 		int t, found;
296 
297 		ovl = ovls[i];
298 
299 		found = 0;
300 
301 		for (t = 0; t < ofbi->num_overlays; ++t) {
302 			if (ovl == ofbi->overlays[t]) {
303 				found = 1;
304 				break;
305 			}
306 		}
307 
308 		if (found)
309 			continue;
310 		ofbi->rotation[ofbi->num_overlays] = 0;
311 		ofbi->overlays[ofbi->num_overlays++] = ovl;
312 
313 		added = true;
314 	}
315 
316 	if (added) {
317 		omapfb_get_mem_region(ofbi->region);
318 
319 		r = omapfb_apply_changes(fbi, 0);
320 
321 		omapfb_put_mem_region(ofbi->region);
322 
323 		if (r)
324 			goto out;
325 	}
326 
327 	r = count;
328 out:
329 	omapfb_unlock(fbdev);
330 	unlock_fb_info(fbi);
331 
332 	return r;
333 }
334 
show_overlays_rotate(struct device * dev,struct device_attribute * attr,char * buf)335 static ssize_t show_overlays_rotate(struct device *dev,
336 		struct device_attribute *attr, char *buf)
337 {
338 	struct fb_info *fbi = dev_get_drvdata(dev);
339 	struct omapfb_info *ofbi = FB2OFB(fbi);
340 	ssize_t l = 0;
341 	int t;
342 
343 	if (!lock_fb_info(fbi))
344 		return -ENODEV;
345 
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 	}
350 
351 	l += snprintf(buf + l, PAGE_SIZE - l, "\n");
352 
353 	unlock_fb_info(fbi);
354 
355 	return l;
356 }
357 
store_overlays_rotate(struct device * dev,struct device_attribute * attr,const char * buf,size_t count)358 static ssize_t store_overlays_rotate(struct device *dev,
359 		struct device_attribute *attr, const char *buf, size_t count)
360 {
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];
367 
368 	len = strlen(buf);
369 	if (buf[len - 1] == '\n')
370 		len = len - 1;
371 
372 	if (!lock_fb_info(fbi))
373 		return -ENODEV;
374 
375 	if (len > 0) {
376 		char *p = (char *)buf;
377 
378 		while (p < buf + len) {
379 			int rot;
380 
381 			if (num_ovls == ofbi->num_overlays) {
382 				r = -EINVAL;
383 				goto out;
384 			}
385 
386 			rot = simple_strtoul(p, &p, 0);
387 			if (rot < 0 || rot > 3) {
388 				r = -EINVAL;
389 				goto out;
390 			}
391 
392 			if (ofbi->rotation[num_ovls] != rot)
393 				changed = true;
394 
395 			rotation[num_ovls++] = rot;
396 
397 			p++;
398 		}
399 	}
400 
401 	if (num_ovls != ofbi->num_overlays) {
402 		r = -EINVAL;
403 		goto out;
404 	}
405 
406 	if (changed) {
407 		for (i = 0; i < num_ovls; ++i)
408 			ofbi->rotation[i] = rotation[i];
409 
410 		omapfb_get_mem_region(ofbi->region);
411 
412 		r = omapfb_apply_changes(fbi, 0);
413 
414 		omapfb_put_mem_region(ofbi->region);
415 
416 		if (r)
417 			goto out;
418 
419 		/* FIXME error handling? */
420 	}
421 
422 	r = count;
423 out:
424 	unlock_fb_info(fbi);
425 
426 	return r;
427 }
428 
show_size(struct device * dev,struct device_attribute * attr,char * buf)429 static ssize_t show_size(struct device *dev,
430 		struct device_attribute *attr, char *buf)
431 {
432 	struct fb_info *fbi = dev_get_drvdata(dev);
433 	struct omapfb_info *ofbi = FB2OFB(fbi);
434 
435 	return snprintf(buf, PAGE_SIZE, "%lu\n", ofbi->region->size);
436 }
437 
store_size(struct device * dev,struct device_attribute * attr,const char * buf,size_t count)438 static ssize_t store_size(struct device *dev, struct device_attribute *attr,
439 		const char *buf, size_t count)
440 {
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;
445 	unsigned long size;
446 	int r;
447 	int i;
448 
449 	r = kstrtoul(buf, 0, &size);
450 	if (r)
451 		return r;
452 
453 	size = PAGE_ALIGN(size);
454 
455 	if (!lock_fb_info(fbi))
456 		return -ENODEV;
457 
458 	rg = ofbi->region;
459 
460 	down_write_nested(&rg->lock, rg->id);
461 	atomic_inc(&rg->lock_count);
462 
463 	if (atomic_read(&rg->map_count)) {
464 		r = -EBUSY;
465 		goto out;
466 	}
467 
468 	for (i = 0; i < fbdev->num_fbs; i++) {
469 		struct omapfb_info *ofbi2 = FB2OFB(fbdev->fbs[i]);
470 		int j;
471 
472 		if (ofbi2->region != rg)
473 			continue;
474 
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)) {
479 				r = -EBUSY;
480 				goto out;
481 			}
482 		}
483 	}
484 
485 	if (size != ofbi->region->size) {
486 		r = omapfb_realloc_fbmem(fbi, size, ofbi->region->type);
487 		if (r) {
488 			dev_err(dev, "realloc fbmem failed\n");
489 			goto out;
490 		}
491 	}
492 
493 	r = count;
494 out:
495 	atomic_dec(&rg->lock_count);
496 	up_write(&rg->lock);
497 
498 	unlock_fb_info(fbi);
499 
500 	return r;
501 }
502 
show_phys(struct device * dev,struct device_attribute * attr,char * buf)503 static ssize_t show_phys(struct device *dev,
504 		struct device_attribute *attr, char *buf)
505 {
506 	struct fb_info *fbi = dev_get_drvdata(dev);
507 	struct omapfb_info *ofbi = FB2OFB(fbi);
508 
509 	return snprintf(buf, PAGE_SIZE, "%0x\n", ofbi->region->paddr);
510 }
511 
show_virt(struct device * dev,struct device_attribute * attr,char * buf)512 static ssize_t show_virt(struct device *dev,
513 		struct device_attribute *attr, char *buf)
514 {
515 	struct fb_info *fbi = dev_get_drvdata(dev);
516 	struct omapfb_info *ofbi = FB2OFB(fbi);
517 
518 	return snprintf(buf, PAGE_SIZE, "%p\n", ofbi->region->vaddr);
519 }
520 
show_upd_mode(struct device * dev,struct device_attribute * attr,char * buf)521 static ssize_t show_upd_mode(struct device *dev,
522 		struct device_attribute *attr, char *buf)
523 {
524 	struct fb_info *fbi = dev_get_drvdata(dev);
525 	enum omapfb_update_mode mode;
526 	int r;
527 
528 	r = omapfb_get_update_mode(fbi, &mode);
529 
530 	if (r)
531 		return r;
532 
533 	return snprintf(buf, PAGE_SIZE, "%u\n", (unsigned)mode);
534 }
535 
store_upd_mode(struct device * dev,struct device_attribute * attr,const char * buf,size_t count)536 static ssize_t store_upd_mode(struct device *dev, struct device_attribute *attr,
537 		const char *buf, size_t count)
538 {
539 	struct fb_info *fbi = dev_get_drvdata(dev);
540 	unsigned mode;
541 	int r;
542 
543 	r = kstrtouint(buf, 0, &mode);
544 	if (r)
545 		return r;
546 
547 	r = omapfb_set_update_mode(fbi, mode);
548 	if (r)
549 		return r;
550 
551 	return count;
552 }
553 
554 static struct device_attribute omapfb_attrs[] = {
555 	__ATTR(rotate_type, S_IRUGO | S_IWUSR, show_rotate_type,
556 			store_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),
565 };
566 
omapfb_create_sysfs(struct omapfb2_device * fbdev)567 int omapfb_create_sysfs(struct omapfb2_device *fbdev)
568 {
569 	int i;
570 	int r;
571 
572 	DBG("create sysfs for fbs\n");
573 	for (i = 0; i < fbdev->num_fbs; i++) {
574 		int t;
575 		for (t = 0; t < ARRAY_SIZE(omapfb_attrs); t++) {
576 			r = device_create_file(fbdev->fbs[i]->dev,
577 					&omapfb_attrs[t]);
578 
579 			if (r) {
580 				dev_err(fbdev->dev, "failed to create sysfs "
581 						"file\n");
582 				return r;
583 			}
584 		}
585 	}
586 
587 	return 0;
588 }
589 
omapfb_remove_sysfs(struct omapfb2_device * fbdev)590 void omapfb_remove_sysfs(struct omapfb2_device *fbdev)
591 {
592 	int i, t;
593 
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,
598 					&omapfb_attrs[t]);
599 	}
600 }
601 
602