Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at v3.5-rc4 701 lines 16 kB view raw
1/* 2 * linux/drivers/video/omap2/dss/manager.c 3 * 4 * Copyright (C) 2009 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#define DSS_SUBSYS_NAME "MANAGER" 24 25#include <linux/kernel.h> 26#include <linux/slab.h> 27#include <linux/module.h> 28#include <linux/platform_device.h> 29#include <linux/jiffies.h> 30 31#include <video/omapdss.h> 32 33#include "dss.h" 34#include "dss_features.h" 35 36static int num_managers; 37static struct omap_overlay_manager *managers; 38 39static ssize_t manager_name_show(struct omap_overlay_manager *mgr, char *buf) 40{ 41 return snprintf(buf, PAGE_SIZE, "%s\n", mgr->name); 42} 43 44static ssize_t manager_display_show(struct omap_overlay_manager *mgr, char *buf) 45{ 46 return snprintf(buf, PAGE_SIZE, "%s\n", 47 mgr->device ? mgr->device->name : "<none>"); 48} 49 50static ssize_t manager_display_store(struct omap_overlay_manager *mgr, 51 const char *buf, size_t size) 52{ 53 int r = 0; 54 size_t len = size; 55 struct omap_dss_device *dssdev = NULL; 56 57 int match(struct omap_dss_device *dssdev, void *data) 58 { 59 const char *str = data; 60 return sysfs_streq(dssdev->name, str); 61 } 62 63 if (buf[size-1] == '\n') 64 --len; 65 66 if (len > 0) 67 dssdev = omap_dss_find_device((void *)buf, match); 68 69 if (len > 0 && dssdev == NULL) 70 return -EINVAL; 71 72 if (dssdev) 73 DSSDBG("display %s found\n", dssdev->name); 74 75 if (mgr->device) { 76 r = mgr->unset_device(mgr); 77 if (r) { 78 DSSERR("failed to unset display\n"); 79 goto put_device; 80 } 81 } 82 83 if (dssdev) { 84 r = mgr->set_device(mgr, dssdev); 85 if (r) { 86 DSSERR("failed to set manager\n"); 87 goto put_device; 88 } 89 90 r = mgr->apply(mgr); 91 if (r) { 92 DSSERR("failed to apply dispc config\n"); 93 goto put_device; 94 } 95 } 96 97put_device: 98 if (dssdev) 99 omap_dss_put_device(dssdev); 100 101 return r ? r : size; 102} 103 104static ssize_t manager_default_color_show(struct omap_overlay_manager *mgr, 105 char *buf) 106{ 107 struct omap_overlay_manager_info info; 108 109 mgr->get_manager_info(mgr, &info); 110 111 return snprintf(buf, PAGE_SIZE, "%#x\n", info.default_color); 112} 113 114static ssize_t manager_default_color_store(struct omap_overlay_manager *mgr, 115 const char *buf, size_t size) 116{ 117 struct omap_overlay_manager_info info; 118 u32 color; 119 int r; 120 121 r = kstrtouint(buf, 0, &color); 122 if (r) 123 return r; 124 125 mgr->get_manager_info(mgr, &info); 126 127 info.default_color = color; 128 129 r = mgr->set_manager_info(mgr, &info); 130 if (r) 131 return r; 132 133 r = mgr->apply(mgr); 134 if (r) 135 return r; 136 137 return size; 138} 139 140static const char *trans_key_type_str[] = { 141 "gfx-destination", 142 "video-source", 143}; 144 145static ssize_t manager_trans_key_type_show(struct omap_overlay_manager *mgr, 146 char *buf) 147{ 148 enum omap_dss_trans_key_type key_type; 149 struct omap_overlay_manager_info info; 150 151 mgr->get_manager_info(mgr, &info); 152 153 key_type = info.trans_key_type; 154 BUG_ON(key_type >= ARRAY_SIZE(trans_key_type_str)); 155 156 return snprintf(buf, PAGE_SIZE, "%s\n", trans_key_type_str[key_type]); 157} 158 159static ssize_t manager_trans_key_type_store(struct omap_overlay_manager *mgr, 160 const char *buf, size_t size) 161{ 162 enum omap_dss_trans_key_type key_type; 163 struct omap_overlay_manager_info info; 164 int r; 165 166 for (key_type = OMAP_DSS_COLOR_KEY_GFX_DST; 167 key_type < ARRAY_SIZE(trans_key_type_str); key_type++) { 168 if (sysfs_streq(buf, trans_key_type_str[key_type])) 169 break; 170 } 171 172 if (key_type == ARRAY_SIZE(trans_key_type_str)) 173 return -EINVAL; 174 175 mgr->get_manager_info(mgr, &info); 176 177 info.trans_key_type = key_type; 178 179 r = mgr->set_manager_info(mgr, &info); 180 if (r) 181 return r; 182 183 r = mgr->apply(mgr); 184 if (r) 185 return r; 186 187 return size; 188} 189 190static ssize_t manager_trans_key_value_show(struct omap_overlay_manager *mgr, 191 char *buf) 192{ 193 struct omap_overlay_manager_info info; 194 195 mgr->get_manager_info(mgr, &info); 196 197 return snprintf(buf, PAGE_SIZE, "%#x\n", info.trans_key); 198} 199 200static ssize_t manager_trans_key_value_store(struct omap_overlay_manager *mgr, 201 const char *buf, size_t size) 202{ 203 struct omap_overlay_manager_info info; 204 u32 key_value; 205 int r; 206 207 r = kstrtouint(buf, 0, &key_value); 208 if (r) 209 return r; 210 211 mgr->get_manager_info(mgr, &info); 212 213 info.trans_key = key_value; 214 215 r = mgr->set_manager_info(mgr, &info); 216 if (r) 217 return r; 218 219 r = mgr->apply(mgr); 220 if (r) 221 return r; 222 223 return size; 224} 225 226static ssize_t manager_trans_key_enabled_show(struct omap_overlay_manager *mgr, 227 char *buf) 228{ 229 struct omap_overlay_manager_info info; 230 231 mgr->get_manager_info(mgr, &info); 232 233 return snprintf(buf, PAGE_SIZE, "%d\n", info.trans_enabled); 234} 235 236static ssize_t manager_trans_key_enabled_store(struct omap_overlay_manager *mgr, 237 const char *buf, size_t size) 238{ 239 struct omap_overlay_manager_info info; 240 bool enable; 241 int r; 242 243 r = strtobool(buf, &enable); 244 if (r) 245 return r; 246 247 mgr->get_manager_info(mgr, &info); 248 249 info.trans_enabled = enable; 250 251 r = mgr->set_manager_info(mgr, &info); 252 if (r) 253 return r; 254 255 r = mgr->apply(mgr); 256 if (r) 257 return r; 258 259 return size; 260} 261 262static ssize_t manager_alpha_blending_enabled_show( 263 struct omap_overlay_manager *mgr, char *buf) 264{ 265 struct omap_overlay_manager_info info; 266 267 mgr->get_manager_info(mgr, &info); 268 269 WARN_ON(!dss_has_feature(FEAT_ALPHA_FIXED_ZORDER)); 270 271 return snprintf(buf, PAGE_SIZE, "%d\n", 272 info.partial_alpha_enabled); 273} 274 275static ssize_t manager_alpha_blending_enabled_store( 276 struct omap_overlay_manager *mgr, 277 const char *buf, size_t size) 278{ 279 struct omap_overlay_manager_info info; 280 bool enable; 281 int r; 282 283 WARN_ON(!dss_has_feature(FEAT_ALPHA_FIXED_ZORDER)); 284 285 r = strtobool(buf, &enable); 286 if (r) 287 return r; 288 289 mgr->get_manager_info(mgr, &info); 290 291 info.partial_alpha_enabled = enable; 292 293 r = mgr->set_manager_info(mgr, &info); 294 if (r) 295 return r; 296 297 r = mgr->apply(mgr); 298 if (r) 299 return r; 300 301 return size; 302} 303 304static ssize_t manager_cpr_enable_show(struct omap_overlay_manager *mgr, 305 char *buf) 306{ 307 struct omap_overlay_manager_info info; 308 309 mgr->get_manager_info(mgr, &info); 310 311 return snprintf(buf, PAGE_SIZE, "%d\n", info.cpr_enable); 312} 313 314static ssize_t manager_cpr_enable_store(struct omap_overlay_manager *mgr, 315 const char *buf, size_t size) 316{ 317 struct omap_overlay_manager_info info; 318 int r; 319 bool enable; 320 321 if (!dss_has_feature(FEAT_CPR)) 322 return -ENODEV; 323 324 r = strtobool(buf, &enable); 325 if (r) 326 return r; 327 328 mgr->get_manager_info(mgr, &info); 329 330 if (info.cpr_enable == enable) 331 return size; 332 333 info.cpr_enable = enable; 334 335 r = mgr->set_manager_info(mgr, &info); 336 if (r) 337 return r; 338 339 r = mgr->apply(mgr); 340 if (r) 341 return r; 342 343 return size; 344} 345 346static ssize_t manager_cpr_coef_show(struct omap_overlay_manager *mgr, 347 char *buf) 348{ 349 struct omap_overlay_manager_info info; 350 351 mgr->get_manager_info(mgr, &info); 352 353 return snprintf(buf, PAGE_SIZE, 354 "%d %d %d %d %d %d %d %d %d\n", 355 info.cpr_coefs.rr, 356 info.cpr_coefs.rg, 357 info.cpr_coefs.rb, 358 info.cpr_coefs.gr, 359 info.cpr_coefs.gg, 360 info.cpr_coefs.gb, 361 info.cpr_coefs.br, 362 info.cpr_coefs.bg, 363 info.cpr_coefs.bb); 364} 365 366static ssize_t manager_cpr_coef_store(struct omap_overlay_manager *mgr, 367 const char *buf, size_t size) 368{ 369 struct omap_overlay_manager_info info; 370 struct omap_dss_cpr_coefs coefs; 371 int r, i; 372 s16 *arr; 373 374 if (!dss_has_feature(FEAT_CPR)) 375 return -ENODEV; 376 377 if (sscanf(buf, "%hd %hd %hd %hd %hd %hd %hd %hd %hd", 378 &coefs.rr, &coefs.rg, &coefs.rb, 379 &coefs.gr, &coefs.gg, &coefs.gb, 380 &coefs.br, &coefs.bg, &coefs.bb) != 9) 381 return -EINVAL; 382 383 arr = (s16[]){ coefs.rr, coefs.rg, coefs.rb, 384 coefs.gr, coefs.gg, coefs.gb, 385 coefs.br, coefs.bg, coefs.bb }; 386 387 for (i = 0; i < 9; ++i) { 388 if (arr[i] < -512 || arr[i] > 511) 389 return -EINVAL; 390 } 391 392 mgr->get_manager_info(mgr, &info); 393 394 info.cpr_coefs = coefs; 395 396 r = mgr->set_manager_info(mgr, &info); 397 if (r) 398 return r; 399 400 r = mgr->apply(mgr); 401 if (r) 402 return r; 403 404 return size; 405} 406 407struct manager_attribute { 408 struct attribute attr; 409 ssize_t (*show)(struct omap_overlay_manager *, char *); 410 ssize_t (*store)(struct omap_overlay_manager *, const char *, size_t); 411}; 412 413#define MANAGER_ATTR(_name, _mode, _show, _store) \ 414 struct manager_attribute manager_attr_##_name = \ 415 __ATTR(_name, _mode, _show, _store) 416 417static MANAGER_ATTR(name, S_IRUGO, manager_name_show, NULL); 418static MANAGER_ATTR(display, S_IRUGO|S_IWUSR, 419 manager_display_show, manager_display_store); 420static MANAGER_ATTR(default_color, S_IRUGO|S_IWUSR, 421 manager_default_color_show, manager_default_color_store); 422static MANAGER_ATTR(trans_key_type, S_IRUGO|S_IWUSR, 423 manager_trans_key_type_show, manager_trans_key_type_store); 424static MANAGER_ATTR(trans_key_value, S_IRUGO|S_IWUSR, 425 manager_trans_key_value_show, manager_trans_key_value_store); 426static MANAGER_ATTR(trans_key_enabled, S_IRUGO|S_IWUSR, 427 manager_trans_key_enabled_show, 428 manager_trans_key_enabled_store); 429static MANAGER_ATTR(alpha_blending_enabled, S_IRUGO|S_IWUSR, 430 manager_alpha_blending_enabled_show, 431 manager_alpha_blending_enabled_store); 432static MANAGER_ATTR(cpr_enable, S_IRUGO|S_IWUSR, 433 manager_cpr_enable_show, 434 manager_cpr_enable_store); 435static MANAGER_ATTR(cpr_coef, S_IRUGO|S_IWUSR, 436 manager_cpr_coef_show, 437 manager_cpr_coef_store); 438 439 440static struct attribute *manager_sysfs_attrs[] = { 441 &manager_attr_name.attr, 442 &manager_attr_display.attr, 443 &manager_attr_default_color.attr, 444 &manager_attr_trans_key_type.attr, 445 &manager_attr_trans_key_value.attr, 446 &manager_attr_trans_key_enabled.attr, 447 &manager_attr_alpha_blending_enabled.attr, 448 &manager_attr_cpr_enable.attr, 449 &manager_attr_cpr_coef.attr, 450 NULL 451}; 452 453static ssize_t manager_attr_show(struct kobject *kobj, struct attribute *attr, 454 char *buf) 455{ 456 struct omap_overlay_manager *manager; 457 struct manager_attribute *manager_attr; 458 459 manager = container_of(kobj, struct omap_overlay_manager, kobj); 460 manager_attr = container_of(attr, struct manager_attribute, attr); 461 462 if (!manager_attr->show) 463 return -ENOENT; 464 465 return manager_attr->show(manager, buf); 466} 467 468static ssize_t manager_attr_store(struct kobject *kobj, struct attribute *attr, 469 const char *buf, size_t size) 470{ 471 struct omap_overlay_manager *manager; 472 struct manager_attribute *manager_attr; 473 474 manager = container_of(kobj, struct omap_overlay_manager, kobj); 475 manager_attr = container_of(attr, struct manager_attribute, attr); 476 477 if (!manager_attr->store) 478 return -ENOENT; 479 480 return manager_attr->store(manager, buf, size); 481} 482 483static const struct sysfs_ops manager_sysfs_ops = { 484 .show = manager_attr_show, 485 .store = manager_attr_store, 486}; 487 488static struct kobj_type manager_ktype = { 489 .sysfs_ops = &manager_sysfs_ops, 490 .default_attrs = manager_sysfs_attrs, 491}; 492 493static int dss_mgr_wait_for_vsync(struct omap_overlay_manager *mgr) 494{ 495 unsigned long timeout = msecs_to_jiffies(500); 496 u32 irq; 497 int r; 498 499 r = dispc_runtime_get(); 500 if (r) 501 return r; 502 503 if (mgr->device->type == OMAP_DISPLAY_TYPE_VENC) { 504 irq = DISPC_IRQ_EVSYNC_ODD; 505 } else if (mgr->device->type == OMAP_DISPLAY_TYPE_HDMI) { 506 irq = DISPC_IRQ_EVSYNC_EVEN; 507 } else { 508 if (mgr->id == OMAP_DSS_CHANNEL_LCD) 509 irq = DISPC_IRQ_VSYNC; 510 else 511 irq = DISPC_IRQ_VSYNC2; 512 } 513 514 r = omap_dispc_wait_for_irq_interruptible_timeout(irq, timeout); 515 516 dispc_runtime_put(); 517 518 return r; 519} 520 521int dss_init_overlay_managers(struct platform_device *pdev) 522{ 523 int i, r; 524 525 num_managers = dss_feat_get_num_mgrs(); 526 527 managers = kzalloc(sizeof(struct omap_overlay_manager) * num_managers, 528 GFP_KERNEL); 529 530 BUG_ON(managers == NULL); 531 532 for (i = 0; i < num_managers; ++i) { 533 struct omap_overlay_manager *mgr = &managers[i]; 534 535 switch (i) { 536 case 0: 537 mgr->name = "lcd"; 538 mgr->id = OMAP_DSS_CHANNEL_LCD; 539 break; 540 case 1: 541 mgr->name = "tv"; 542 mgr->id = OMAP_DSS_CHANNEL_DIGIT; 543 break; 544 case 2: 545 mgr->name = "lcd2"; 546 mgr->id = OMAP_DSS_CHANNEL_LCD2; 547 break; 548 } 549 550 mgr->set_device = &dss_mgr_set_device; 551 mgr->unset_device = &dss_mgr_unset_device; 552 mgr->apply = &omap_dss_mgr_apply; 553 mgr->set_manager_info = &dss_mgr_set_info; 554 mgr->get_manager_info = &dss_mgr_get_info; 555 mgr->wait_for_go = &dss_mgr_wait_for_go; 556 mgr->wait_for_vsync = &dss_mgr_wait_for_vsync; 557 558 mgr->caps = 0; 559 mgr->supported_displays = 560 dss_feat_get_supported_displays(mgr->id); 561 562 INIT_LIST_HEAD(&mgr->overlays); 563 564 r = kobject_init_and_add(&mgr->kobj, &manager_ktype, 565 &pdev->dev.kobj, "manager%d", i); 566 567 if (r) 568 DSSERR("failed to create sysfs file\n"); 569 } 570 571 return 0; 572} 573 574void dss_uninit_overlay_managers(struct platform_device *pdev) 575{ 576 int i; 577 578 for (i = 0; i < num_managers; ++i) { 579 struct omap_overlay_manager *mgr = &managers[i]; 580 581 kobject_del(&mgr->kobj); 582 kobject_put(&mgr->kobj); 583 } 584 585 kfree(managers); 586 managers = NULL; 587 num_managers = 0; 588} 589 590int omap_dss_get_num_overlay_managers(void) 591{ 592 return num_managers; 593} 594EXPORT_SYMBOL(omap_dss_get_num_overlay_managers); 595 596struct omap_overlay_manager *omap_dss_get_overlay_manager(int num) 597{ 598 if (num >= num_managers) 599 return NULL; 600 601 return &managers[num]; 602} 603EXPORT_SYMBOL(omap_dss_get_overlay_manager); 604 605int dss_mgr_simple_check(struct omap_overlay_manager *mgr, 606 const struct omap_overlay_manager_info *info) 607{ 608 if (dss_has_feature(FEAT_ALPHA_FIXED_ZORDER)) { 609 /* 610 * OMAP3 supports only graphics source transparency color key 611 * and alpha blending simultaneously. See TRM 15.4.2.4.2.2 612 * Alpha Mode. 613 */ 614 if (info->partial_alpha_enabled && info->trans_enabled 615 && info->trans_key_type != OMAP_DSS_COLOR_KEY_GFX_DST) { 616 DSSERR("check_manager: illegal transparency key\n"); 617 return -EINVAL; 618 } 619 } 620 621 return 0; 622} 623 624static int dss_mgr_check_zorder(struct omap_overlay_manager *mgr, 625 struct omap_overlay_info **overlay_infos) 626{ 627 struct omap_overlay *ovl1, *ovl2; 628 struct omap_overlay_info *info1, *info2; 629 630 list_for_each_entry(ovl1, &mgr->overlays, list) { 631 info1 = overlay_infos[ovl1->id]; 632 633 if (info1 == NULL) 634 continue; 635 636 list_for_each_entry(ovl2, &mgr->overlays, list) { 637 if (ovl1 == ovl2) 638 continue; 639 640 info2 = overlay_infos[ovl2->id]; 641 642 if (info2 == NULL) 643 continue; 644 645 if (info1->zorder == info2->zorder) { 646 DSSERR("overlays %d and %d have the same " 647 "zorder %d\n", 648 ovl1->id, ovl2->id, info1->zorder); 649 return -EINVAL; 650 } 651 } 652 } 653 654 return 0; 655} 656 657int dss_mgr_check_timings(struct omap_overlay_manager *mgr, 658 const struct omap_video_timings *timings) 659{ 660 if (!dispc_mgr_timings_ok(mgr->id, timings)) { 661 DSSERR("check_manager: invalid timings\n"); 662 return -EINVAL; 663 } 664 665 return 0; 666} 667 668int dss_mgr_check(struct omap_overlay_manager *mgr, 669 struct omap_overlay_manager_info *info, 670 const struct omap_video_timings *mgr_timings, 671 struct omap_overlay_info **overlay_infos) 672{ 673 struct omap_overlay *ovl; 674 int r; 675 676 if (dss_has_feature(FEAT_ALPHA_FREE_ZORDER)) { 677 r = dss_mgr_check_zorder(mgr, overlay_infos); 678 if (r) 679 return r; 680 } 681 682 r = dss_mgr_check_timings(mgr, mgr_timings); 683 if (r) 684 return r; 685 686 list_for_each_entry(ovl, &mgr->overlays, list) { 687 struct omap_overlay_info *oi; 688 int r; 689 690 oi = overlay_infos[ovl->id]; 691 692 if (oi == NULL) 693 continue; 694 695 r = dss_ovl_check(ovl, oi, mgr_timings); 696 if (r) 697 return r; 698 } 699 700 return 0; 701}