apply.c revision dbce0160af31d2ea323656c201d8debf5af789bf
1/* 2 * Copyright (C) 2011 Texas Instruments 3 * Author: Tomi Valkeinen <tomi.valkeinen@ti.com> 4 * 5 * This program is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 as published by 7 * the Free Software Foundation. 8 * 9 * This program is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 12 * more details. 13 * 14 * You should have received a copy of the GNU General Public License along with 15 * this program. If not, see <http://www.gnu.org/licenses/>. 16 */ 17 18#define DSS_SUBSYS_NAME "APPLY" 19 20#include <linux/kernel.h> 21#include <linux/slab.h> 22#include <linux/spinlock.h> 23#include <linux/jiffies.h> 24 25#include <video/omapdss.h> 26 27#include "dss.h" 28#include "dss_features.h" 29 30/* 31 * We have 4 levels of cache for the dispc settings. First two are in SW and 32 * the latter two in HW. 33 * 34 * +--------------------+ 35 * |overlay/manager_info| 36 * +--------------------+ 37 * v 38 * apply() 39 * v 40 * +--------------------+ 41 * | dss_cache | 42 * +--------------------+ 43 * v 44 * configure() 45 * v 46 * +--------------------+ 47 * | shadow registers | 48 * +--------------------+ 49 * v 50 * VFP or lcd/digit_enable 51 * v 52 * +--------------------+ 53 * | registers | 54 * +--------------------+ 55 */ 56 57struct overlay_cache_data { 58 /* If true, cache changed, but not written to shadow registers. Set 59 * in apply(), cleared when registers written. */ 60 bool dirty; 61 /* If true, shadow registers contain changed values not yet in real 62 * registers. Set when writing to shadow registers, cleared at 63 * VSYNC/EVSYNC */ 64 bool shadow_dirty; 65 66 bool enabled; 67 68 struct omap_overlay_info info; 69 70 enum omap_channel channel; 71 72 u32 fifo_low; 73 u32 fifo_high; 74}; 75 76struct manager_cache_data { 77 /* If true, cache changed, but not written to shadow registers. Set 78 * in apply(), cleared when registers written. */ 79 bool dirty; 80 /* If true, shadow registers contain changed values not yet in real 81 * registers. Set when writing to shadow registers, cleared at 82 * VSYNC/EVSYNC */ 83 bool shadow_dirty; 84 85 struct omap_overlay_manager_info info; 86 87 bool manual_update; 88 bool do_manual_update; 89}; 90 91static struct { 92 spinlock_t lock; 93 struct overlay_cache_data overlay_cache[MAX_DSS_OVERLAYS]; 94 struct manager_cache_data manager_cache[MAX_DSS_MANAGERS]; 95 96 bool irq_enabled; 97} dss_cache; 98 99void dss_apply_init(void) 100{ 101 spin_lock_init(&dss_cache.lock); 102} 103 104static bool ovl_manual_update(struct omap_overlay *ovl) 105{ 106 return ovl->manager->device->caps & OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE; 107} 108 109static bool mgr_manual_update(struct omap_overlay_manager *mgr) 110{ 111 return mgr->device->caps & OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE; 112} 113 114static int overlay_enabled(struct omap_overlay *ovl) 115{ 116 return ovl->info.enabled && ovl->manager && ovl->manager->device; 117} 118 119int dss_mgr_wait_for_go(struct omap_overlay_manager *mgr) 120{ 121 unsigned long timeout = msecs_to_jiffies(500); 122 struct manager_cache_data *mc; 123 u32 irq; 124 int r; 125 int i; 126 struct omap_dss_device *dssdev = mgr->device; 127 128 if (!dssdev || dssdev->state != OMAP_DSS_DISPLAY_ACTIVE) 129 return 0; 130 131 if (mgr_manual_update(mgr)) 132 return 0; 133 134 if (dssdev->type == OMAP_DISPLAY_TYPE_VENC 135 || dssdev->type == OMAP_DISPLAY_TYPE_HDMI) { 136 irq = DISPC_IRQ_EVSYNC_ODD | DISPC_IRQ_EVSYNC_EVEN; 137 } else { 138 irq = (dssdev->manager->id == OMAP_DSS_CHANNEL_LCD) ? 139 DISPC_IRQ_VSYNC : DISPC_IRQ_VSYNC2; 140 } 141 142 mc = &dss_cache.manager_cache[mgr->id]; 143 i = 0; 144 while (1) { 145 unsigned long flags; 146 bool shadow_dirty, dirty; 147 148 spin_lock_irqsave(&dss_cache.lock, flags); 149 dirty = mc->dirty; 150 shadow_dirty = mc->shadow_dirty; 151 spin_unlock_irqrestore(&dss_cache.lock, flags); 152 153 if (!dirty && !shadow_dirty) { 154 r = 0; 155 break; 156 } 157 158 /* 4 iterations is the worst case: 159 * 1 - initial iteration, dirty = true (between VFP and VSYNC) 160 * 2 - first VSYNC, dirty = true 161 * 3 - dirty = false, shadow_dirty = true 162 * 4 - shadow_dirty = false */ 163 if (i++ == 3) { 164 DSSERR("mgr(%d)->wait_for_go() not finishing\n", 165 mgr->id); 166 r = 0; 167 break; 168 } 169 170 r = omap_dispc_wait_for_irq_interruptible_timeout(irq, timeout); 171 if (r == -ERESTARTSYS) 172 break; 173 174 if (r) { 175 DSSERR("mgr(%d)->wait_for_go() timeout\n", mgr->id); 176 break; 177 } 178 } 179 180 return r; 181} 182 183int dss_mgr_wait_for_go_ovl(struct omap_overlay *ovl) 184{ 185 unsigned long timeout = msecs_to_jiffies(500); 186 struct overlay_cache_data *oc; 187 struct omap_dss_device *dssdev; 188 u32 irq; 189 int r; 190 int i; 191 192 if (!ovl->manager) 193 return 0; 194 195 dssdev = ovl->manager->device; 196 197 if (!dssdev || dssdev->state != OMAP_DSS_DISPLAY_ACTIVE) 198 return 0; 199 200 if (ovl_manual_update(ovl)) 201 return 0; 202 203 if (dssdev->type == OMAP_DISPLAY_TYPE_VENC 204 || dssdev->type == OMAP_DISPLAY_TYPE_HDMI) { 205 irq = DISPC_IRQ_EVSYNC_ODD | DISPC_IRQ_EVSYNC_EVEN; 206 } else { 207 irq = (dssdev->manager->id == OMAP_DSS_CHANNEL_LCD) ? 208 DISPC_IRQ_VSYNC : DISPC_IRQ_VSYNC2; 209 } 210 211 oc = &dss_cache.overlay_cache[ovl->id]; 212 i = 0; 213 while (1) { 214 unsigned long flags; 215 bool shadow_dirty, dirty; 216 217 spin_lock_irqsave(&dss_cache.lock, flags); 218 dirty = oc->dirty; 219 shadow_dirty = oc->shadow_dirty; 220 spin_unlock_irqrestore(&dss_cache.lock, flags); 221 222 if (!dirty && !shadow_dirty) { 223 r = 0; 224 break; 225 } 226 227 /* 4 iterations is the worst case: 228 * 1 - initial iteration, dirty = true (between VFP and VSYNC) 229 * 2 - first VSYNC, dirty = true 230 * 3 - dirty = false, shadow_dirty = true 231 * 4 - shadow_dirty = false */ 232 if (i++ == 3) { 233 DSSERR("ovl(%d)->wait_for_go() not finishing\n", 234 ovl->id); 235 r = 0; 236 break; 237 } 238 239 r = omap_dispc_wait_for_irq_interruptible_timeout(irq, timeout); 240 if (r == -ERESTARTSYS) 241 break; 242 243 if (r) { 244 DSSERR("ovl(%d)->wait_for_go() timeout\n", ovl->id); 245 break; 246 } 247 } 248 249 return r; 250} 251 252static int configure_overlay(enum omap_plane plane) 253{ 254 struct omap_overlay *ovl; 255 struct overlay_cache_data *c; 256 struct omap_overlay_info *oi; 257 bool ilace, replication; 258 int r; 259 260 DSSDBGF("%d", plane); 261 262 c = &dss_cache.overlay_cache[plane]; 263 oi = &c->info; 264 265 if (!c->enabled) { 266 dispc_ovl_enable(plane, 0); 267 return 0; 268 } 269 270 ovl = omap_dss_get_overlay(plane); 271 272 replication = dss_use_replication(ovl->manager->device, oi->color_mode); 273 274 ilace = ovl->manager->device->type == OMAP_DISPLAY_TYPE_VENC; 275 276 dispc_ovl_set_channel_out(plane, c->channel); 277 278 r = dispc_ovl_setup(plane, oi, ilace, replication); 279 if (r) { 280 /* this shouldn't happen */ 281 DSSERR("dispc_ovl_setup failed for ovl %d\n", plane); 282 dispc_ovl_enable(plane, 0); 283 return r; 284 } 285 286 dispc_ovl_set_fifo_threshold(plane, c->fifo_low, c->fifo_high); 287 288 dispc_ovl_enable(plane, 1); 289 290 return 0; 291} 292 293static void configure_manager(enum omap_channel channel) 294{ 295 struct omap_overlay_manager_info *mi; 296 297 DSSDBGF("%d", channel); 298 299 /* picking info from the cache */ 300 mi = &dss_cache.manager_cache[channel].info; 301 302 dispc_mgr_setup(channel, mi); 303} 304 305/* configure_dispc() tries to write values from cache to shadow registers. 306 * It writes only to those managers/overlays that are not busy. 307 * returns 0 if everything could be written to shadow registers. 308 * returns 1 if not everything could be written to shadow registers. */ 309static int configure_dispc(void) 310{ 311 struct overlay_cache_data *oc; 312 struct manager_cache_data *mc; 313 const int num_ovls = dss_feat_get_num_ovls(); 314 const int num_mgrs = dss_feat_get_num_mgrs(); 315 int i; 316 int r; 317 bool mgr_busy[MAX_DSS_MANAGERS]; 318 bool mgr_go[MAX_DSS_MANAGERS]; 319 bool busy; 320 321 r = 0; 322 busy = false; 323 324 for (i = 0; i < num_mgrs; i++) { 325 mgr_busy[i] = dispc_mgr_go_busy(i); 326 mgr_go[i] = false; 327 } 328 329 /* Commit overlay settings */ 330 for (i = 0; i < num_ovls; ++i) { 331 oc = &dss_cache.overlay_cache[i]; 332 mc = &dss_cache.manager_cache[oc->channel]; 333 334 if (!oc->dirty) 335 continue; 336 337 if (mc->manual_update && !mc->do_manual_update) 338 continue; 339 340 if (mgr_busy[oc->channel]) { 341 busy = true; 342 continue; 343 } 344 345 r = configure_overlay(i); 346 if (r) 347 DSSERR("configure_overlay %d failed\n", i); 348 349 oc->dirty = false; 350 oc->shadow_dirty = true; 351 mgr_go[oc->channel] = true; 352 } 353 354 /* Commit manager settings */ 355 for (i = 0; i < num_mgrs; ++i) { 356 mc = &dss_cache.manager_cache[i]; 357 358 if (!mc->dirty) 359 continue; 360 361 if (mc->manual_update && !mc->do_manual_update) 362 continue; 363 364 if (mgr_busy[i]) { 365 busy = true; 366 continue; 367 } 368 369 configure_manager(i); 370 mc->dirty = false; 371 mc->shadow_dirty = true; 372 mgr_go[i] = true; 373 } 374 375 /* set GO */ 376 for (i = 0; i < num_mgrs; ++i) { 377 mc = &dss_cache.manager_cache[i]; 378 379 if (!mgr_go[i]) 380 continue; 381 382 /* We don't need GO with manual update display. LCD iface will 383 * always be turned off after frame, and new settings will be 384 * taken in to use at next update */ 385 if (!mc->manual_update) 386 dispc_mgr_go(i); 387 } 388 389 if (busy) 390 r = 1; 391 else 392 r = 0; 393 394 return r; 395} 396 397void dss_mgr_start_update(struct omap_overlay_manager *mgr) 398{ 399 struct manager_cache_data *mc; 400 struct overlay_cache_data *oc; 401 struct omap_overlay *ovl; 402 403 mc = &dss_cache.manager_cache[mgr->id]; 404 405 mc->do_manual_update = true; 406 configure_dispc(); 407 mc->do_manual_update = false; 408 409 list_for_each_entry(ovl, &mgr->overlays, list) { 410 oc = &dss_cache.overlay_cache[ovl->id]; 411 oc->shadow_dirty = false; 412 } 413 414 mc = &dss_cache.manager_cache[mgr->id]; 415 mc->shadow_dirty = false; 416 417 dispc_mgr_enable(mgr->id, true); 418} 419 420static void dss_apply_irq_handler(void *data, u32 mask); 421 422static void dss_register_vsync_isr(void) 423{ 424 u32 mask; 425 int r; 426 427 mask = DISPC_IRQ_VSYNC | DISPC_IRQ_EVSYNC_ODD | 428 DISPC_IRQ_EVSYNC_EVEN; 429 if (dss_has_feature(FEAT_MGR_LCD2)) 430 mask |= DISPC_IRQ_VSYNC2; 431 432 r = omap_dispc_register_isr(dss_apply_irq_handler, NULL, mask); 433 WARN_ON(r); 434 435 dss_cache.irq_enabled = true; 436} 437 438static void dss_unregister_vsync_isr(void) 439{ 440 u32 mask; 441 int r; 442 443 mask = DISPC_IRQ_VSYNC | DISPC_IRQ_EVSYNC_ODD | 444 DISPC_IRQ_EVSYNC_EVEN; 445 if (dss_has_feature(FEAT_MGR_LCD2)) 446 mask |= DISPC_IRQ_VSYNC2; 447 448 r = omap_dispc_unregister_isr(dss_apply_irq_handler, NULL, mask); 449 WARN_ON(r); 450 451 dss_cache.irq_enabled = false; 452} 453 454static void dss_apply_irq_handler(void *data, u32 mask) 455{ 456 struct manager_cache_data *mc; 457 struct overlay_cache_data *oc; 458 const int num_ovls = dss_feat_get_num_ovls(); 459 const int num_mgrs = dss_feat_get_num_mgrs(); 460 int i, r; 461 bool mgr_busy[MAX_DSS_MANAGERS]; 462 463 for (i = 0; i < num_mgrs; i++) 464 mgr_busy[i] = dispc_mgr_go_busy(i); 465 466 spin_lock(&dss_cache.lock); 467 468 for (i = 0; i < num_ovls; ++i) { 469 oc = &dss_cache.overlay_cache[i]; 470 if (!mgr_busy[oc->channel]) 471 oc->shadow_dirty = false; 472 } 473 474 for (i = 0; i < num_mgrs; ++i) { 475 mc = &dss_cache.manager_cache[i]; 476 if (!mgr_busy[i]) 477 mc->shadow_dirty = false; 478 } 479 480 r = configure_dispc(); 481 if (r == 1) 482 goto end; 483 484 /* re-read busy flags */ 485 for (i = 0; i < num_mgrs; i++) 486 mgr_busy[i] = dispc_mgr_go_busy(i); 487 488 /* keep running as long as there are busy managers, so that 489 * we can collect overlay-applied information */ 490 for (i = 0; i < num_mgrs; ++i) { 491 if (mgr_busy[i]) 492 goto end; 493 } 494 495 dss_unregister_vsync_isr(); 496 497end: 498 spin_unlock(&dss_cache.lock); 499} 500 501static int omap_dss_mgr_apply_ovl(struct omap_overlay *ovl) 502{ 503 struct overlay_cache_data *oc; 504 struct omap_dss_device *dssdev; 505 506 oc = &dss_cache.overlay_cache[ovl->id]; 507 508 if (ovl->manager_changed) { 509 ovl->manager_changed = false; 510 ovl->info_dirty = true; 511 } 512 513 if (!overlay_enabled(ovl)) { 514 if (oc->enabled) { 515 oc->enabled = false; 516 oc->dirty = true; 517 } 518 return 0; 519 } 520 521 if (!ovl->info_dirty) 522 return 0; 523 524 dssdev = ovl->manager->device; 525 526 if (dss_check_overlay(ovl, dssdev)) { 527 if (oc->enabled) { 528 oc->enabled = false; 529 oc->dirty = true; 530 } 531 return -EINVAL; 532 } 533 534 ovl->info_dirty = false; 535 oc->dirty = true; 536 oc->info = ovl->info; 537 538 oc->channel = ovl->manager->id; 539 540 oc->enabled = true; 541 542 return 0; 543} 544 545static void omap_dss_mgr_apply_mgr(struct omap_overlay_manager *mgr) 546{ 547 struct manager_cache_data *mc; 548 549 mc = &dss_cache.manager_cache[mgr->id]; 550 551 if (mgr->device_changed) { 552 mgr->device_changed = false; 553 mgr->info_dirty = true; 554 } 555 556 if (!mgr->info_dirty) 557 return; 558 559 if (!mgr->device) 560 return; 561 562 mgr->info_dirty = false; 563 mc->dirty = true; 564 mc->info = mgr->info; 565 566 mc->manual_update = mgr_manual_update(mgr); 567} 568 569static void omap_dss_mgr_apply_ovl_fifos(struct omap_overlay *ovl) 570{ 571 struct overlay_cache_data *oc; 572 struct omap_dss_device *dssdev; 573 u32 size, burst_size; 574 575 oc = &dss_cache.overlay_cache[ovl->id]; 576 577 if (!oc->enabled) 578 return; 579 580 dssdev = ovl->manager->device; 581 582 size = dispc_ovl_get_fifo_size(ovl->id); 583 584 burst_size = dispc_ovl_get_burst_size(ovl->id); 585 586 switch (dssdev->type) { 587 case OMAP_DISPLAY_TYPE_DPI: 588 case OMAP_DISPLAY_TYPE_DBI: 589 case OMAP_DISPLAY_TYPE_SDI: 590 case OMAP_DISPLAY_TYPE_VENC: 591 case OMAP_DISPLAY_TYPE_HDMI: 592 default_get_overlay_fifo_thresholds(ovl->id, size, 593 burst_size, &oc->fifo_low, 594 &oc->fifo_high); 595 break; 596#ifdef CONFIG_OMAP2_DSS_DSI 597 case OMAP_DISPLAY_TYPE_DSI: 598 dsi_get_overlay_fifo_thresholds(ovl->id, size, 599 burst_size, &oc->fifo_low, 600 &oc->fifo_high); 601 break; 602#endif 603 default: 604 BUG(); 605 } 606} 607 608int omap_dss_mgr_apply(struct omap_overlay_manager *mgr) 609{ 610 int r; 611 unsigned long flags; 612 struct omap_overlay *ovl; 613 614 DSSDBG("omap_dss_mgr_apply(%s)\n", mgr->name); 615 616 r = dispc_runtime_get(); 617 if (r) 618 return r; 619 620 spin_lock_irqsave(&dss_cache.lock, flags); 621 622 /* Configure overlays */ 623 list_for_each_entry(ovl, &mgr->overlays, list) 624 omap_dss_mgr_apply_ovl(ovl); 625 626 /* Configure manager */ 627 omap_dss_mgr_apply_mgr(mgr); 628 629 /* Configure overlay fifos */ 630 list_for_each_entry(ovl, &mgr->overlays, list) 631 omap_dss_mgr_apply_ovl_fifos(ovl); 632 633 r = 0; 634 if (mgr->enabled && !mgr_manual_update(mgr)) { 635 if (!dss_cache.irq_enabled) 636 dss_register_vsync_isr(); 637 638 configure_dispc(); 639 } 640 641 spin_unlock_irqrestore(&dss_cache.lock, flags); 642 643 dispc_runtime_put(); 644 645 return r; 646} 647 648void dss_mgr_enable(struct omap_overlay_manager *mgr) 649{ 650 dispc_mgr_enable(mgr->id, true); 651 mgr->enabled = true; 652} 653 654void dss_mgr_disable(struct omap_overlay_manager *mgr) 655{ 656 dispc_mgr_enable(mgr->id, false); 657 mgr->enabled = false; 658} 659 660