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