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.3-rc5 676 lines 15 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 498 if (mgr->device->type == OMAP_DISPLAY_TYPE_VENC) { 499 irq = DISPC_IRQ_EVSYNC_ODD; 500 } else if (mgr->device->type == OMAP_DISPLAY_TYPE_HDMI) { 501 irq = DISPC_IRQ_EVSYNC_EVEN; 502 } else { 503 if (mgr->id == OMAP_DSS_CHANNEL_LCD) 504 irq = DISPC_IRQ_VSYNC; 505 else 506 irq = DISPC_IRQ_VSYNC2; 507 } 508 return omap_dispc_wait_for_irq_interruptible_timeout(irq, timeout); 509} 510 511int dss_init_overlay_managers(struct platform_device *pdev) 512{ 513 int i, r; 514 515 num_managers = dss_feat_get_num_mgrs(); 516 517 managers = kzalloc(sizeof(struct omap_overlay_manager) * num_managers, 518 GFP_KERNEL); 519 520 BUG_ON(managers == NULL); 521 522 for (i = 0; i < num_managers; ++i) { 523 struct omap_overlay_manager *mgr = &managers[i]; 524 525 switch (i) { 526 case 0: 527 mgr->name = "lcd"; 528 mgr->id = OMAP_DSS_CHANNEL_LCD; 529 break; 530 case 1: 531 mgr->name = "tv"; 532 mgr->id = OMAP_DSS_CHANNEL_DIGIT; 533 break; 534 case 2: 535 mgr->name = "lcd2"; 536 mgr->id = OMAP_DSS_CHANNEL_LCD2; 537 break; 538 } 539 540 mgr->set_device = &dss_mgr_set_device; 541 mgr->unset_device = &dss_mgr_unset_device; 542 mgr->apply = &omap_dss_mgr_apply; 543 mgr->set_manager_info = &dss_mgr_set_info; 544 mgr->get_manager_info = &dss_mgr_get_info; 545 mgr->wait_for_go = &dss_mgr_wait_for_go; 546 mgr->wait_for_vsync = &dss_mgr_wait_for_vsync; 547 548 mgr->caps = 0; 549 mgr->supported_displays = 550 dss_feat_get_supported_displays(mgr->id); 551 552 INIT_LIST_HEAD(&mgr->overlays); 553 554 r = kobject_init_and_add(&mgr->kobj, &manager_ktype, 555 &pdev->dev.kobj, "manager%d", i); 556 557 if (r) 558 DSSERR("failed to create sysfs file\n"); 559 } 560 561 return 0; 562} 563 564void dss_uninit_overlay_managers(struct platform_device *pdev) 565{ 566 int i; 567 568 for (i = 0; i < num_managers; ++i) { 569 struct omap_overlay_manager *mgr = &managers[i]; 570 571 kobject_del(&mgr->kobj); 572 kobject_put(&mgr->kobj); 573 } 574 575 kfree(managers); 576 managers = NULL; 577 num_managers = 0; 578} 579 580int omap_dss_get_num_overlay_managers(void) 581{ 582 return num_managers; 583} 584EXPORT_SYMBOL(omap_dss_get_num_overlay_managers); 585 586struct omap_overlay_manager *omap_dss_get_overlay_manager(int num) 587{ 588 if (num >= num_managers) 589 return NULL; 590 591 return &managers[num]; 592} 593EXPORT_SYMBOL(omap_dss_get_overlay_manager); 594 595int dss_mgr_simple_check(struct omap_overlay_manager *mgr, 596 const struct omap_overlay_manager_info *info) 597{ 598 if (dss_has_feature(FEAT_ALPHA_FIXED_ZORDER)) { 599 /* 600 * OMAP3 supports only graphics source transparency color key 601 * and alpha blending simultaneously. See TRM 15.4.2.4.2.2 602 * Alpha Mode. 603 */ 604 if (info->partial_alpha_enabled && info->trans_enabled 605 && info->trans_key_type != OMAP_DSS_COLOR_KEY_GFX_DST) { 606 DSSERR("check_manager: illegal transparency key\n"); 607 return -EINVAL; 608 } 609 } 610 611 return 0; 612} 613 614static int dss_mgr_check_zorder(struct omap_overlay_manager *mgr, 615 struct omap_overlay_info **overlay_infos) 616{ 617 struct omap_overlay *ovl1, *ovl2; 618 struct omap_overlay_info *info1, *info2; 619 620 list_for_each_entry(ovl1, &mgr->overlays, list) { 621 info1 = overlay_infos[ovl1->id]; 622 623 if (info1 == NULL) 624 continue; 625 626 list_for_each_entry(ovl2, &mgr->overlays, list) { 627 if (ovl1 == ovl2) 628 continue; 629 630 info2 = overlay_infos[ovl2->id]; 631 632 if (info2 == NULL) 633 continue; 634 635 if (info1->zorder == info2->zorder) { 636 DSSERR("overlays %d and %d have the same " 637 "zorder %d\n", 638 ovl1->id, ovl2->id, info1->zorder); 639 return -EINVAL; 640 } 641 } 642 } 643 644 return 0; 645} 646 647int dss_mgr_check(struct omap_overlay_manager *mgr, 648 struct omap_dss_device *dssdev, 649 struct omap_overlay_manager_info *info, 650 struct omap_overlay_info **overlay_infos) 651{ 652 struct omap_overlay *ovl; 653 int r; 654 655 if (dss_has_feature(FEAT_ALPHA_FREE_ZORDER)) { 656 r = dss_mgr_check_zorder(mgr, overlay_infos); 657 if (r) 658 return r; 659 } 660 661 list_for_each_entry(ovl, &mgr->overlays, list) { 662 struct omap_overlay_info *oi; 663 int r; 664 665 oi = overlay_infos[ovl->id]; 666 667 if (oi == NULL) 668 continue; 669 670 r = dss_ovl_check(ovl, oi, dssdev); 671 if (r) 672 return r; 673 } 674 675 return 0; 676}