1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  * linux/drivers/video/omap2/omapfb-sysfs.c
4  *
5  * Copyright (C) 2008 Nokia Corporation
6  * Author: Tomi Valkeinen <tomi.valkeinen@nokia.com>
7  *
8  * Some code and ideas taken from drivers/video/omap/ driver
9  * by Imre Deak.
10  */
11 
12 #include <linux/fb.h>
13 #include <linux/sysfs.h>
14 #include <linux/device.h>
15 #include <linux/uaccess.h>
16 #include <linux/platform_device.h>
17 #include <linux/kernel.h>
18 #include <linux/mm.h>
19 #include <linux/omapfb.h>
20 
21 #include <video/omapfb_dss.h>
22 #include <video/omapvrfb.h>
23 
24 #include "omapfb.h"
25 
26 static ssize_t show_rotate_type(struct device *dev,
27 		struct device_attribute *attr, char *buf)
28 {
29 	struct fb_info *fbi = dev_get_drvdata(dev);
30 	struct omapfb_info *ofbi = FB2OFB(fbi);
31 
32 	return snprintf(buf, PAGE_SIZE, "%d\n", ofbi->rotation_type);
33 }
34 
35 static ssize_t store_rotate_type(struct device *dev,
36 		struct device_attribute *attr,
37 		const char *buf, size_t count)
38 {
39 	struct fb_info *fbi = dev_get_drvdata(dev);
40 	struct omapfb_info *ofbi = FB2OFB(fbi);
41 	struct omapfb2_mem_region *rg;
42 	int rot_type;
43 	int r;
44 
45 	r = kstrtoint(buf, 0, &rot_type);
46 	if (r)
47 		return r;
48 
49 	if (rot_type != OMAP_DSS_ROT_DMA && rot_type != OMAP_DSS_ROT_VRFB)
50 		return -EINVAL;
51 
52 	lock_fb_info(fbi);
53 
54 	r = 0;
55 	if (rot_type == ofbi->rotation_type)
56 		goto out;
57 
58 	rg = omapfb_get_mem_region(ofbi->region);
59 
60 	if (rg->size) {
61 		r = -EBUSY;
62 		goto put_region;
63 	}
64 
65 	ofbi->rotation_type = rot_type;
66 
67 	/*
68 	 * Since the VRAM for this FB is not allocated at the moment we don't
69 	 * need to do any further parameter checking at this point.
70 	 */
71 put_region:
72 	omapfb_put_mem_region(rg);
73 out:
74 	unlock_fb_info(fbi);
75 
76 	return r ? r : count;
77 }
78 
79 
80 static ssize_t show_mirror(struct device *dev,
81 		struct device_attribute *attr, char *buf)
82 {
83 	struct fb_info *fbi = dev_get_drvdata(dev);
84 	struct omapfb_info *ofbi = FB2OFB(fbi);
85 
86 	return snprintf(buf, PAGE_SIZE, "%d\n", ofbi->mirror);
87 }
88 
89 static ssize_t store_mirror(struct device *dev,
90 		struct device_attribute *attr,
91 		const char *buf, size_t count)
92 {
93 	struct fb_info *fbi = dev_get_drvdata(dev);
94 	struct omapfb_info *ofbi = FB2OFB(fbi);
95 	bool mirror;
96 	int r;
97 	struct fb_var_screeninfo new_var;
98 
99 	r = strtobool(buf, &mirror);
100 	if (r)
101 		return r;
102 
103 	lock_fb_info(fbi);
104 
105 	ofbi->mirror = mirror;
106 
107 	omapfb_get_mem_region(ofbi->region);
108 
109 	memcpy(&new_var, &fbi->var, sizeof(new_var));
110 	r = check_fb_var(fbi, &new_var);
111 	if (r)
112 		goto out;
113 	memcpy(&fbi->var, &new_var, sizeof(fbi->var));
114 
115 	set_fb_fix(fbi);
116 
117 	r = omapfb_apply_changes(fbi, 0);
118 	if (r)
119 		goto out;
120 
121 	r = count;
122 out:
123 	omapfb_put_mem_region(ofbi->region);
124 
125 	unlock_fb_info(fbi);
126 
127 	return r;
128 }
129 
130 static ssize_t show_overlays(struct device *dev,
131 		struct device_attribute *attr, char *buf)
132 {
133 	struct fb_info *fbi = dev_get_drvdata(dev);
134 	struct omapfb_info *ofbi = FB2OFB(fbi);
135 	struct omapfb2_device *fbdev = ofbi->fbdev;
136 	ssize_t l = 0;
137 	int t;
138 
139 	lock_fb_info(fbi);
140 	omapfb_lock(fbdev);
141 
142 	for (t = 0; t < ofbi->num_overlays; t++) {
143 		struct omap_overlay *ovl = ofbi->overlays[t];
144 		int ovlnum;
145 
146 		for (ovlnum = 0; ovlnum < fbdev->num_overlays; ++ovlnum)
147 			if (ovl == fbdev->overlays[ovlnum])
148 				break;
149 
150 		l += snprintf(buf + l, PAGE_SIZE - l, "%s%d",
151 				t == 0 ? "" : ",", ovlnum);
152 	}
153 
154 	l += snprintf(buf + l, PAGE_SIZE - l, "\n");
155 
156 	omapfb_unlock(fbdev);
157 	unlock_fb_info(fbi);
158 
159 	return l;
160 }
161 
162 static struct omapfb_info *get_overlay_fb(struct omapfb2_device *fbdev,
163 		struct omap_overlay *ovl)
164 {
165 	int i, t;
166 
167 	for (i = 0; i < fbdev->num_fbs; i++) {
168 		struct omapfb_info *ofbi = FB2OFB(fbdev->fbs[i]);
169 
170 		for (t = 0; t < ofbi->num_overlays; t++) {
171 			if (ofbi->overlays[t] == ovl)
172 				return ofbi;
173 		}
174 	}
175 
176 	return NULL;
177 }
178 
179 static ssize_t store_overlays(struct device *dev, struct device_attribute *attr,
180 		const char *buf, size_t count)
181 {
182 	struct fb_info *fbi = dev_get_drvdata(dev);
183 	struct omapfb_info *ofbi = FB2OFB(fbi);
184 	struct omapfb2_device *fbdev = ofbi->fbdev;
185 	struct omap_overlay *ovls[OMAPFB_MAX_OVL_PER_FB];
186 	struct omap_overlay *ovl;
187 	int num_ovls, r, i;
188 	int len;
189 	bool added = false;
190 
191 	num_ovls = 0;
192 
193 	len = strlen(buf);
194 	if (buf[len - 1] == '\n')
195 		len = len - 1;
196 
197 	lock_fb_info(fbi);
198 	omapfb_lock(fbdev);
199 
200 	if (len > 0) {
201 		char *p = (char *)buf;
202 		int ovlnum;
203 
204 		while (p < buf + len) {
205 			int found;
206 			if (num_ovls == OMAPFB_MAX_OVL_PER_FB) {
207 				r = -EINVAL;
208 				goto out;
209 			}
210 
211 			ovlnum = simple_strtoul(p, &p, 0);
212 			if (ovlnum > fbdev->num_overlays) {
213 				r = -EINVAL;
214 				goto out;
215 			}
216 
217 			found = 0;
218 			for (i = 0; i < num_ovls; ++i) {
219 				if (ovls[i] == fbdev->overlays[ovlnum]) {
220 					found = 1;
221 					break;
222 				}
223 			}
224 
225 			if (!found)
226 				ovls[num_ovls++] = fbdev->overlays[ovlnum];
227 
228 			p++;
229 		}
230 	}
231 
232 	for (i = 0; i < num_ovls; ++i) {
233 		struct omapfb_info *ofbi2 = get_overlay_fb(fbdev, ovls[i]);
234 		if (ofbi2 && ofbi2 != ofbi) {
235 			dev_err(fbdev->dev, "overlay already in use\n");
236 			r = -EINVAL;
237 			goto out;
238 		}
239 	}
240 
241 	/* detach unused overlays */
242 	for (i = 0; i < ofbi->num_overlays; ++i) {
243 		int t, found;
244 
245 		ovl = ofbi->overlays[i];
246 
247 		found = 0;
248 
249 		for (t = 0; t < num_ovls; ++t) {
250 			if (ovl == ovls[t]) {
251 				found = 1;
252 				break;
253 			}
254 		}
255 
256 		if (found)
257 			continue;
258 
259 		DBG("detaching %d\n", ofbi->overlays[i]->id);
260 
261 		omapfb_get_mem_region(ofbi->region);
262 
263 		omapfb_overlay_enable(ovl, 0);
264 
265 		if (ovl->manager)
266 			ovl->manager->apply(ovl->manager);
267 
268 		omapfb_put_mem_region(ofbi->region);
269 
270 		for (t = i + 1; t < ofbi->num_overlays; t++) {
271 			ofbi->rotation[t-1] = ofbi->rotation[t];
272 			ofbi->overlays[t-1] = ofbi->overlays[t];
273 		}
274 
275 		ofbi->num_overlays--;
276 		i--;
277 	}
278 
279 	for (i = 0; i < num_ovls; ++i) {
280 		int t, found;
281 
282 		ovl = ovls[i];
283 
284 		found = 0;
285 
286 		for (t = 0; t < ofbi->num_overlays; ++t) {
287 			if (ovl == ofbi->overlays[t]) {
288 				found = 1;
289 				break;
290 			}
291 		}
292 
293 		if (found)
294 			continue;
295 		ofbi->rotation[ofbi->num_overlays] = 0;
296 		ofbi->overlays[ofbi->num_overlays++] = ovl;
297 
298 		added = true;
299 	}
300 
301 	if (added) {
302 		omapfb_get_mem_region(ofbi->region);
303 
304 		r = omapfb_apply_changes(fbi, 0);
305 
306 		omapfb_put_mem_region(ofbi->region);
307 
308 		if (r)
309 			goto out;
310 	}
311 
312 	r = count;
313 out:
314 	omapfb_unlock(fbdev);
315 	unlock_fb_info(fbi);
316 
317 	return r;
318 }
319 
320 static ssize_t show_overlays_rotate(struct device *dev,
321 		struct device_attribute *attr, char *buf)
322 {
323 	struct fb_info *fbi = dev_get_drvdata(dev);
324 	struct omapfb_info *ofbi = FB2OFB(fbi);
325 	ssize_t l = 0;
326 	int t;
327 
328 	lock_fb_info(fbi);
329 
330 	for (t = 0; t < ofbi->num_overlays; t++) {
331 		l += snprintf(buf + l, PAGE_SIZE - l, "%s%d",
332 				t == 0 ? "" : ",", ofbi->rotation[t]);
333 	}
334 
335 	l += snprintf(buf + l, PAGE_SIZE - l, "\n");
336 
337 	unlock_fb_info(fbi);
338 
339 	return l;
340 }
341 
342 static ssize_t store_overlays_rotate(struct device *dev,
343 		struct device_attribute *attr, const char *buf, size_t count)
344 {
345 	struct fb_info *fbi = dev_get_drvdata(dev);
346 	struct omapfb_info *ofbi = FB2OFB(fbi);
347 	int num_ovls = 0, r, i;
348 	int len;
349 	bool changed = false;
350 	u8 rotation[OMAPFB_MAX_OVL_PER_FB];
351 
352 	len = strlen(buf);
353 	if (buf[len - 1] == '\n')
354 		len = len - 1;
355 
356 	lock_fb_info(fbi);
357 
358 	if (len > 0) {
359 		char *p = (char *)buf;
360 
361 		while (p < buf + len) {
362 			int rot;
363 
364 			if (num_ovls == ofbi->num_overlays) {
365 				r = -EINVAL;
366 				goto out;
367 			}
368 
369 			rot = simple_strtoul(p, &p, 0);
370 			if (rot < 0 || rot > 3) {
371 				r = -EINVAL;
372 				goto out;
373 			}
374 
375 			if (ofbi->rotation[num_ovls] != rot)
376 				changed = true;
377 
378 			rotation[num_ovls++] = rot;
379 
380 			p++;
381 		}
382 	}
383 
384 	if (num_ovls != ofbi->num_overlays) {
385 		r = -EINVAL;
386 		goto out;
387 	}
388 
389 	if (changed) {
390 		for (i = 0; i < num_ovls; ++i)
391 			ofbi->rotation[i] = rotation[i];
392 
393 		omapfb_get_mem_region(ofbi->region);
394 
395 		r = omapfb_apply_changes(fbi, 0);
396 
397 		omapfb_put_mem_region(ofbi->region);
398 
399 		if (r)
400 			goto out;
401 
402 		/* FIXME error handling? */
403 	}
404 
405 	r = count;
406 out:
407 	unlock_fb_info(fbi);
408 
409 	return r;
410 }
411 
412 static ssize_t show_size(struct device *dev,
413 		struct device_attribute *attr, char *buf)
414 {
415 	struct fb_info *fbi = dev_get_drvdata(dev);
416 	struct omapfb_info *ofbi = FB2OFB(fbi);
417 
418 	return snprintf(buf, PAGE_SIZE, "%lu\n", ofbi->region->size);
419 }
420 
421 static ssize_t store_size(struct device *dev, struct device_attribute *attr,
422 		const char *buf, size_t count)
423 {
424 	struct fb_info *fbi = dev_get_drvdata(dev);
425 	struct omapfb_info *ofbi = FB2OFB(fbi);
426 	struct omapfb2_device *fbdev = ofbi->fbdev;
427 	struct omap_dss_device *display = fb2display(fbi);
428 	struct omapfb2_mem_region *rg;
429 	unsigned long size;
430 	int r;
431 	int i;
432 
433 	r = kstrtoul(buf, 0, &size);
434 	if (r)
435 		return r;
436 
437 	size = PAGE_ALIGN(size);
438 
439 	lock_fb_info(fbi);
440 
441 	if (display && display->driver->sync)
442 		display->driver->sync(display);
443 
444 	rg = ofbi->region;
445 
446 	down_write_nested(&rg->lock, rg->id);
447 	atomic_inc(&rg->lock_count);
448 
449 	if (atomic_read(&rg->map_count)) {
450 		r = -EBUSY;
451 		goto out;
452 	}
453 
454 	for (i = 0; i < fbdev->num_fbs; i++) {
455 		struct omapfb_info *ofbi2 = FB2OFB(fbdev->fbs[i]);
456 		int j;
457 
458 		if (ofbi2->region != rg)
459 			continue;
460 
461 		for (j = 0; j < ofbi2->num_overlays; j++) {
462 			struct omap_overlay *ovl;
463 			ovl = ofbi2->overlays[j];
464 			if (ovl->is_enabled(ovl)) {
465 				r = -EBUSY;
466 				goto out;
467 			}
468 		}
469 	}
470 
471 	if (size != ofbi->region->size) {
472 		r = omapfb_realloc_fbmem(fbi, size, ofbi->region->type);
473 		if (r) {
474 			dev_err(dev, "realloc fbmem failed\n");
475 			goto out;
476 		}
477 	}
478 
479 	r = count;
480 out:
481 	atomic_dec(&rg->lock_count);
482 	up_write(&rg->lock);
483 
484 	unlock_fb_info(fbi);
485 
486 	return r;
487 }
488 
489 static ssize_t show_phys(struct device *dev,
490 		struct device_attribute *attr, char *buf)
491 {
492 	struct fb_info *fbi = dev_get_drvdata(dev);
493 	struct omapfb_info *ofbi = FB2OFB(fbi);
494 
495 	return snprintf(buf, PAGE_SIZE, "%0x\n", ofbi->region->paddr);
496 }
497 
498 static ssize_t show_virt(struct device *dev,
499 		struct device_attribute *attr, char *buf)
500 {
501 	struct fb_info *fbi = dev_get_drvdata(dev);
502 	struct omapfb_info *ofbi = FB2OFB(fbi);
503 
504 	return snprintf(buf, PAGE_SIZE, "%p\n", ofbi->region->vaddr);
505 }
506 
507 static ssize_t show_upd_mode(struct device *dev,
508 		struct device_attribute *attr, char *buf)
509 {
510 	struct fb_info *fbi = dev_get_drvdata(dev);
511 	enum omapfb_update_mode mode;
512 	int r;
513 
514 	r = omapfb_get_update_mode(fbi, &mode);
515 
516 	if (r)
517 		return r;
518 
519 	return snprintf(buf, PAGE_SIZE, "%u\n", (unsigned)mode);
520 }
521 
522 static ssize_t store_upd_mode(struct device *dev, struct device_attribute *attr,
523 		const char *buf, size_t count)
524 {
525 	struct fb_info *fbi = dev_get_drvdata(dev);
526 	unsigned mode;
527 	int r;
528 
529 	r = kstrtouint(buf, 0, &mode);
530 	if (r)
531 		return r;
532 
533 	r = omapfb_set_update_mode(fbi, mode);
534 	if (r)
535 		return r;
536 
537 	return count;
538 }
539 
540 static struct device_attribute omapfb_attrs[] = {
541 	__ATTR(rotate_type, S_IRUGO | S_IWUSR, show_rotate_type,
542 			store_rotate_type),
543 	__ATTR(mirror, S_IRUGO | S_IWUSR, show_mirror, store_mirror),
544 	__ATTR(size, S_IRUGO | S_IWUSR, show_size, store_size),
545 	__ATTR(overlays, S_IRUGO | S_IWUSR, show_overlays, store_overlays),
546 	__ATTR(overlays_rotate, S_IRUGO | S_IWUSR, show_overlays_rotate,
547 			store_overlays_rotate),
548 	__ATTR(phys_addr, S_IRUGO, show_phys, NULL),
549 	__ATTR(virt_addr, S_IRUGO, show_virt, NULL),
550 	__ATTR(update_mode, S_IRUGO | S_IWUSR, show_upd_mode, store_upd_mode),
551 };
552 
553 int omapfb_create_sysfs(struct omapfb2_device *fbdev)
554 {
555 	int i;
556 	int r;
557 
558 	DBG("create sysfs for fbs\n");
559 	for (i = 0; i < fbdev->num_fbs; i++) {
560 		int t;
561 		for (t = 0; t < ARRAY_SIZE(omapfb_attrs); t++) {
562 			r = device_create_file(fbdev->fbs[i]->dev,
563 					&omapfb_attrs[t]);
564 
565 			if (r) {
566 				dev_err(fbdev->dev, "failed to create sysfs "
567 						"file\n");
568 				return r;
569 			}
570 		}
571 	}
572 
573 	return 0;
574 }
575 
576 void omapfb_remove_sysfs(struct omapfb2_device *fbdev)
577 {
578 	int i, t;
579 
580 	DBG("remove sysfs for fbs\n");
581 	for (i = 0; i < fbdev->num_fbs; i++) {
582 		for (t = 0; t < ARRAY_SIZE(omapfb_attrs); t++)
583 			device_remove_file(fbdev->fbs[i]->dev,
584 					&omapfb_attrs[t]);
585 	}
586 }
587 
588