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