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 if (!lock_fb_info(fbi)) 53 return -ENODEV; 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 snprintf(buf, PAGE_SIZE, "%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 = strtobool(buf, &mirror); 101 if (r) 102 return r; 103 104 if (!lock_fb_info(fbi)) 105 return -ENODEV; 106 107 ofbi->mirror = mirror; 108 109 omapfb_get_mem_region(ofbi->region); 110 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; 124 out: 125 omapfb_put_mem_region(ofbi->region); 126 127 unlock_fb_info(fbi); 128 129 return r; 130 } 131 132 static 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 141 if (!lock_fb_info(fbi)) 142 return -ENODEV; 143 omapfb_lock(fbdev); 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 159 omapfb_unlock(fbdev); 160 unlock_fb_info(fbi); 161 162 return l; 163 } 164 165 static 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 182 static 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 200 if (!lock_fb_info(fbi)) 201 return -ENODEV; 202 omapfb_lock(fbdev); 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 265 omapfb_get_mem_region(ofbi->region); 266 267 omapfb_overlay_enable(ovl, 0); 268 269 if (ovl->manager) 270 ovl->manager->apply(ovl->manager); 271 272 omapfb_put_mem_region(ofbi->region); 273 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) { 306 omapfb_get_mem_region(ofbi->region); 307 308 r = omapfb_apply_changes(fbi, 0); 309 310 omapfb_put_mem_region(ofbi->region); 311 312 if (r) 313 goto out; 314 } 315 316 r = count; 317 out: 318 omapfb_unlock(fbdev); 319 unlock_fb_info(fbi); 320 321 return r; 322 } 323 324 static 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 332 if (!lock_fb_info(fbi)) 333 return -ENODEV; 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 347 static 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 361 if (!lock_fb_info(fbi)) 362 return -ENODEV; 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 399 omapfb_get_mem_region(ofbi->region); 400 401 r = omapfb_apply_changes(fbi, 0); 402 403 omapfb_put_mem_region(ofbi->region); 404 405 if (r) 406 goto out; 407 408 /* FIXME error handling? */ 409 } 410 411 r = count; 412 out: 413 unlock_fb_info(fbi); 414 415 return r; 416 } 417 418 static 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 424 return snprintf(buf, PAGE_SIZE, "%lu\n", ofbi->region->size); 425 } 426 427 static 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); 432 struct omapfb2_device *fbdev = ofbi->fbdev; 433 struct omap_dss_device *display = fb2display(fbi); 434 struct omapfb2_mem_region *rg; 435 unsigned long size; 436 int r; 437 int i; 438 439 r = kstrtoul(buf, 0, &size); 440 if (r) 441 return r; 442 443 size = PAGE_ALIGN(size); 444 445 if (!lock_fb_info(fbi)) 446 return -ENODEV; 447 448 if (display && display->driver->sync) 449 display->driver->sync(display); 450 451 rg = ofbi->region; 452 453 down_write_nested(&rg->lock, rg->id); 454 atomic_inc(&rg->lock_count); 455 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++) { 469 struct omap_overlay *ovl; 470 ovl = ofbi2->overlays[j]; 471 if (ovl->is_enabled(ovl)) { 472 r = -EBUSY; 473 goto out; 474 } 475 } 476 } 477 478 if (size != ofbi->region->size) { 479 r = omapfb_realloc_fbmem(fbi, size, ofbi->region->type); 480 if (r) { 481 dev_err(dev, "realloc fbmem failed\n"); 482 goto out; 483 } 484 } 485 486 r = count; 487 out: 488 atomic_dec(&rg->lock_count); 489 up_write(&rg->lock); 490 491 unlock_fb_info(fbi); 492 493 return r; 494 } 495 496 static 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 502 return snprintf(buf, PAGE_SIZE, "%0x\n", ofbi->region->paddr); 503 } 504 505 static 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 511 return snprintf(buf, PAGE_SIZE, "%p\n", ofbi->region->vaddr); 512 } 513 514 static 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 529 static 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 547 static 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), 557 __ATTR(update_mode, S_IRUGO | S_IWUSR, show_upd_mode, store_upd_mode), 558 }; 559 560 int 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 583 void 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 595