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 27 static 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 36 static 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 */ 72 put_region: 73 omapfb_put_mem_region(rg); 74 out: 75 unlock_fb_info(fbi); 76 77 return r ? r : count; 78 } 79 80 81 static 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 90 static 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; 123 out: 124 omapfb_put_mem_region(ofbi->region); 125 126 unlock_fb_info(fbi); 127 128 return r; 129 } 130 131 static 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 163 static 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 180 static 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; 314 out: 315 omapfb_unlock(fbdev); 316 unlock_fb_info(fbi); 317 318 return r; 319 } 320 321 static 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 343 static 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; 407 out: 408 unlock_fb_info(fbi); 409 410 return r; 411 } 412 413 static 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 422 static 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; 481 out: 482 atomic_dec(&rg->lock_count); 483 up_write(&rg->lock); 484 485 unlock_fb_info(fbi); 486 487 return r; 488 } 489 490 static 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 499 static 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 508 static 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 523 static 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 541 static 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 554 int 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 577 void 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