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