1 /* 2 * Copyright (C) 2012 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/module.h> 22 #include <linux/slab.h> 23 #include <linux/spinlock.h> 24 #include <linux/jiffies.h> 25 #include <linux/delay.h> 26 #include <linux/interrupt.h> 27 #include <linux/seq_file.h> 28 29 #include <video/omapfb_dss.h> 30 31 #include "dss.h" 32 #include "dss_features.h" 33 #include "dispc-compat.h" 34 35 #define DISPC_IRQ_MASK_ERROR (DISPC_IRQ_GFX_FIFO_UNDERFLOW | \ 36 DISPC_IRQ_OCP_ERR | \ 37 DISPC_IRQ_VID1_FIFO_UNDERFLOW | \ 38 DISPC_IRQ_VID2_FIFO_UNDERFLOW | \ 39 DISPC_IRQ_SYNC_LOST | \ 40 DISPC_IRQ_SYNC_LOST_DIGIT) 41 42 #define DISPC_MAX_NR_ISRS 8 43 44 struct omap_dispc_isr_data { 45 omap_dispc_isr_t isr; 46 void *arg; 47 u32 mask; 48 }; 49 50 struct dispc_irq_stats { 51 unsigned long last_reset; 52 unsigned irq_count; 53 unsigned irqs[32]; 54 }; 55 56 static struct { 57 spinlock_t irq_lock; 58 u32 irq_error_mask; 59 struct omap_dispc_isr_data registered_isr[DISPC_MAX_NR_ISRS]; 60 u32 error_irqs; 61 struct work_struct error_work; 62 63 #ifdef CONFIG_FB_OMAP2_DSS_COLLECT_IRQ_STATS 64 spinlock_t irq_stats_lock; 65 struct dispc_irq_stats irq_stats; 66 #endif 67 } dispc_compat; 68 69 70 #ifdef CONFIG_FB_OMAP2_DSS_COLLECT_IRQ_STATS 71 static void dispc_dump_irqs(struct seq_file *s) 72 { 73 unsigned long flags; 74 struct dispc_irq_stats stats; 75 76 spin_lock_irqsave(&dispc_compat.irq_stats_lock, flags); 77 78 stats = dispc_compat.irq_stats; 79 memset(&dispc_compat.irq_stats, 0, sizeof(dispc_compat.irq_stats)); 80 dispc_compat.irq_stats.last_reset = jiffies; 81 82 spin_unlock_irqrestore(&dispc_compat.irq_stats_lock, flags); 83 84 seq_printf(s, "period %u ms\n", 85 jiffies_to_msecs(jiffies - stats.last_reset)); 86 87 seq_printf(s, "irqs %d\n", stats.irq_count); 88 #define PIS(x) \ 89 seq_printf(s, "%-20s %10d\n", #x, stats.irqs[ffs(DISPC_IRQ_##x)-1]); 90 91 PIS(FRAMEDONE); 92 PIS(VSYNC); 93 PIS(EVSYNC_EVEN); 94 PIS(EVSYNC_ODD); 95 PIS(ACBIAS_COUNT_STAT); 96 PIS(PROG_LINE_NUM); 97 PIS(GFX_FIFO_UNDERFLOW); 98 PIS(GFX_END_WIN); 99 PIS(PAL_GAMMA_MASK); 100 PIS(OCP_ERR); 101 PIS(VID1_FIFO_UNDERFLOW); 102 PIS(VID1_END_WIN); 103 PIS(VID2_FIFO_UNDERFLOW); 104 PIS(VID2_END_WIN); 105 if (dss_feat_get_num_ovls() > 3) { 106 PIS(VID3_FIFO_UNDERFLOW); 107 PIS(VID3_END_WIN); 108 } 109 PIS(SYNC_LOST); 110 PIS(SYNC_LOST_DIGIT); 111 PIS(WAKEUP); 112 if (dss_has_feature(FEAT_MGR_LCD2)) { 113 PIS(FRAMEDONE2); 114 PIS(VSYNC2); 115 PIS(ACBIAS_COUNT_STAT2); 116 PIS(SYNC_LOST2); 117 } 118 if (dss_has_feature(FEAT_MGR_LCD3)) { 119 PIS(FRAMEDONE3); 120 PIS(VSYNC3); 121 PIS(ACBIAS_COUNT_STAT3); 122 PIS(SYNC_LOST3); 123 } 124 #undef PIS 125 } 126 #endif 127 128 /* dispc.irq_lock has to be locked by the caller */ 129 static void _omap_dispc_set_irqs(void) 130 { 131 u32 mask; 132 int i; 133 struct omap_dispc_isr_data *isr_data; 134 135 mask = dispc_compat.irq_error_mask; 136 137 for (i = 0; i < DISPC_MAX_NR_ISRS; i++) { 138 isr_data = &dispc_compat.registered_isr[i]; 139 140 if (isr_data->isr == NULL) 141 continue; 142 143 mask |= isr_data->mask; 144 } 145 146 dispc_write_irqenable(mask); 147 } 148 149 int omap_dispc_register_isr(omap_dispc_isr_t isr, void *arg, u32 mask) 150 { 151 int i; 152 int ret; 153 unsigned long flags; 154 struct omap_dispc_isr_data *isr_data; 155 156 if (isr == NULL) 157 return -EINVAL; 158 159 spin_lock_irqsave(&dispc_compat.irq_lock, flags); 160 161 /* check for duplicate entry */ 162 for (i = 0; i < DISPC_MAX_NR_ISRS; i++) { 163 isr_data = &dispc_compat.registered_isr[i]; 164 if (isr_data->isr == isr && isr_data->arg == arg && 165 isr_data->mask == mask) { 166 ret = -EINVAL; 167 goto err; 168 } 169 } 170 171 isr_data = NULL; 172 ret = -EBUSY; 173 174 for (i = 0; i < DISPC_MAX_NR_ISRS; i++) { 175 isr_data = &dispc_compat.registered_isr[i]; 176 177 if (isr_data->isr != NULL) 178 continue; 179 180 isr_data->isr = isr; 181 isr_data->arg = arg; 182 isr_data->mask = mask; 183 ret = 0; 184 185 break; 186 } 187 188 if (ret) 189 goto err; 190 191 _omap_dispc_set_irqs(); 192 193 spin_unlock_irqrestore(&dispc_compat.irq_lock, flags); 194 195 return 0; 196 err: 197 spin_unlock_irqrestore(&dispc_compat.irq_lock, flags); 198 199 return ret; 200 } 201 EXPORT_SYMBOL(omap_dispc_register_isr); 202 203 int omap_dispc_unregister_isr(omap_dispc_isr_t isr, void *arg, u32 mask) 204 { 205 int i; 206 unsigned long flags; 207 int ret = -EINVAL; 208 struct omap_dispc_isr_data *isr_data; 209 210 spin_lock_irqsave(&dispc_compat.irq_lock, flags); 211 212 for (i = 0; i < DISPC_MAX_NR_ISRS; i++) { 213 isr_data = &dispc_compat.registered_isr[i]; 214 if (isr_data->isr != isr || isr_data->arg != arg || 215 isr_data->mask != mask) 216 continue; 217 218 /* found the correct isr */ 219 220 isr_data->isr = NULL; 221 isr_data->arg = NULL; 222 isr_data->mask = 0; 223 224 ret = 0; 225 break; 226 } 227 228 if (ret == 0) 229 _omap_dispc_set_irqs(); 230 231 spin_unlock_irqrestore(&dispc_compat.irq_lock, flags); 232 233 return ret; 234 } 235 EXPORT_SYMBOL(omap_dispc_unregister_isr); 236 237 static void print_irq_status(u32 status) 238 { 239 if ((status & dispc_compat.irq_error_mask) == 0) 240 return; 241 242 #define PIS(x) (status & DISPC_IRQ_##x) ? (#x " ") : "" 243 244 pr_debug("DISPC IRQ: 0x%x: %s%s%s%s%s%s%s%s%s\n", 245 status, 246 PIS(OCP_ERR), 247 PIS(GFX_FIFO_UNDERFLOW), 248 PIS(VID1_FIFO_UNDERFLOW), 249 PIS(VID2_FIFO_UNDERFLOW), 250 dss_feat_get_num_ovls() > 3 ? PIS(VID3_FIFO_UNDERFLOW) : "", 251 PIS(SYNC_LOST), 252 PIS(SYNC_LOST_DIGIT), 253 dss_has_feature(FEAT_MGR_LCD2) ? PIS(SYNC_LOST2) : "", 254 dss_has_feature(FEAT_MGR_LCD3) ? PIS(SYNC_LOST3) : ""); 255 #undef PIS 256 } 257 258 /* Called from dss.c. Note that we don't touch clocks here, 259 * but we presume they are on because we got an IRQ. However, 260 * an irq handler may turn the clocks off, so we may not have 261 * clock later in the function. */ 262 static irqreturn_t omap_dispc_irq_handler(int irq, void *arg) 263 { 264 int i; 265 u32 irqstatus, irqenable; 266 u32 handledirqs = 0; 267 u32 unhandled_errors; 268 struct omap_dispc_isr_data *isr_data; 269 struct omap_dispc_isr_data registered_isr[DISPC_MAX_NR_ISRS]; 270 271 spin_lock(&dispc_compat.irq_lock); 272 273 irqstatus = dispc_read_irqstatus(); 274 irqenable = dispc_read_irqenable(); 275 276 /* IRQ is not for us */ 277 if (!(irqstatus & irqenable)) { 278 spin_unlock(&dispc_compat.irq_lock); 279 return IRQ_NONE; 280 } 281 282 #ifdef CONFIG_FB_OMAP2_DSS_COLLECT_IRQ_STATS 283 spin_lock(&dispc_compat.irq_stats_lock); 284 dispc_compat.irq_stats.irq_count++; 285 dss_collect_irq_stats(irqstatus, dispc_compat.irq_stats.irqs); 286 spin_unlock(&dispc_compat.irq_stats_lock); 287 #endif 288 289 print_irq_status(irqstatus); 290 291 /* Ack the interrupt. Do it here before clocks are possibly turned 292 * off */ 293 dispc_clear_irqstatus(irqstatus); 294 /* flush posted write */ 295 dispc_read_irqstatus(); 296 297 /* make a copy and unlock, so that isrs can unregister 298 * themselves */ 299 memcpy(registered_isr, dispc_compat.registered_isr, 300 sizeof(registered_isr)); 301 302 spin_unlock(&dispc_compat.irq_lock); 303 304 for (i = 0; i < DISPC_MAX_NR_ISRS; i++) { 305 isr_data = ®istered_isr[i]; 306 307 if (!isr_data->isr) 308 continue; 309 310 if (isr_data->mask & irqstatus) { 311 isr_data->isr(isr_data->arg, irqstatus); 312 handledirqs |= isr_data->mask; 313 } 314 } 315 316 spin_lock(&dispc_compat.irq_lock); 317 318 unhandled_errors = irqstatus & ~handledirqs & dispc_compat.irq_error_mask; 319 320 if (unhandled_errors) { 321 dispc_compat.error_irqs |= unhandled_errors; 322 323 dispc_compat.irq_error_mask &= ~unhandled_errors; 324 _omap_dispc_set_irqs(); 325 326 schedule_work(&dispc_compat.error_work); 327 } 328 329 spin_unlock(&dispc_compat.irq_lock); 330 331 return IRQ_HANDLED; 332 } 333 334 static void dispc_error_worker(struct work_struct *work) 335 { 336 int i; 337 u32 errors; 338 unsigned long flags; 339 static const unsigned fifo_underflow_bits[] = { 340 DISPC_IRQ_GFX_FIFO_UNDERFLOW, 341 DISPC_IRQ_VID1_FIFO_UNDERFLOW, 342 DISPC_IRQ_VID2_FIFO_UNDERFLOW, 343 DISPC_IRQ_VID3_FIFO_UNDERFLOW, 344 }; 345 346 spin_lock_irqsave(&dispc_compat.irq_lock, flags); 347 errors = dispc_compat.error_irqs; 348 dispc_compat.error_irqs = 0; 349 spin_unlock_irqrestore(&dispc_compat.irq_lock, flags); 350 351 dispc_runtime_get(); 352 353 for (i = 0; i < omap_dss_get_num_overlays(); ++i) { 354 struct omap_overlay *ovl; 355 unsigned bit; 356 357 ovl = omap_dss_get_overlay(i); 358 bit = fifo_underflow_bits[i]; 359 360 if (bit & errors) { 361 DSSERR("FIFO UNDERFLOW on %s, disabling the overlay\n", 362 ovl->name); 363 ovl->disable(ovl); 364 msleep(50); 365 } 366 } 367 368 for (i = 0; i < omap_dss_get_num_overlay_managers(); ++i) { 369 struct omap_overlay_manager *mgr; 370 unsigned bit; 371 372 mgr = omap_dss_get_overlay_manager(i); 373 bit = dispc_mgr_get_sync_lost_irq(i); 374 375 if (bit & errors) { 376 int j; 377 378 DSSERR("SYNC_LOST on channel %s, restarting the output " 379 "with video overlays disabled\n", 380 mgr->name); 381 382 dss_mgr_disable(mgr); 383 384 for (j = 0; j < omap_dss_get_num_overlays(); ++j) { 385 struct omap_overlay *ovl; 386 ovl = omap_dss_get_overlay(j); 387 388 if (ovl->id != OMAP_DSS_GFX && 389 ovl->manager == mgr) 390 ovl->disable(ovl); 391 } 392 393 dss_mgr_enable(mgr); 394 } 395 } 396 397 if (errors & DISPC_IRQ_OCP_ERR) { 398 DSSERR("OCP_ERR\n"); 399 for (i = 0; i < omap_dss_get_num_overlay_managers(); ++i) { 400 struct omap_overlay_manager *mgr; 401 402 mgr = omap_dss_get_overlay_manager(i); 403 dss_mgr_disable(mgr); 404 } 405 } 406 407 spin_lock_irqsave(&dispc_compat.irq_lock, flags); 408 dispc_compat.irq_error_mask |= errors; 409 _omap_dispc_set_irqs(); 410 spin_unlock_irqrestore(&dispc_compat.irq_lock, flags); 411 412 dispc_runtime_put(); 413 } 414 415 int dss_dispc_initialize_irq(void) 416 { 417 int r; 418 419 #ifdef CONFIG_FB_OMAP2_DSS_COLLECT_IRQ_STATS 420 spin_lock_init(&dispc_compat.irq_stats_lock); 421 dispc_compat.irq_stats.last_reset = jiffies; 422 dss_debugfs_create_file("dispc_irq", dispc_dump_irqs); 423 #endif 424 425 spin_lock_init(&dispc_compat.irq_lock); 426 427 memset(dispc_compat.registered_isr, 0, 428 sizeof(dispc_compat.registered_isr)); 429 430 dispc_compat.irq_error_mask = DISPC_IRQ_MASK_ERROR; 431 if (dss_has_feature(FEAT_MGR_LCD2)) 432 dispc_compat.irq_error_mask |= DISPC_IRQ_SYNC_LOST2; 433 if (dss_has_feature(FEAT_MGR_LCD3)) 434 dispc_compat.irq_error_mask |= DISPC_IRQ_SYNC_LOST3; 435 if (dss_feat_get_num_ovls() > 3) 436 dispc_compat.irq_error_mask |= DISPC_IRQ_VID3_FIFO_UNDERFLOW; 437 438 /* 439 * there's SYNC_LOST_DIGIT waiting after enabling the DSS, 440 * so clear it 441 */ 442 dispc_clear_irqstatus(dispc_read_irqstatus()); 443 444 INIT_WORK(&dispc_compat.error_work, dispc_error_worker); 445 446 _omap_dispc_set_irqs(); 447 448 r = dispc_request_irq(omap_dispc_irq_handler, &dispc_compat); 449 if (r) { 450 DSSERR("dispc_request_irq failed\n"); 451 return r; 452 } 453 454 return 0; 455 } 456 457 void dss_dispc_uninitialize_irq(void) 458 { 459 dispc_free_irq(&dispc_compat); 460 } 461 462 static void dispc_mgr_disable_isr(void *data, u32 mask) 463 { 464 struct completion *compl = data; 465 complete(compl); 466 } 467 468 static void dispc_mgr_enable_lcd_out(enum omap_channel channel) 469 { 470 dispc_mgr_enable(channel, true); 471 } 472 473 static void dispc_mgr_disable_lcd_out(enum omap_channel channel) 474 { 475 DECLARE_COMPLETION_ONSTACK(framedone_compl); 476 int r; 477 u32 irq; 478 479 if (!dispc_mgr_is_enabled(channel)) 480 return; 481 482 /* 483 * When we disable LCD output, we need to wait for FRAMEDONE to know 484 * that DISPC has finished with the LCD output. 485 */ 486 487 irq = dispc_mgr_get_framedone_irq(channel); 488 489 r = omap_dispc_register_isr(dispc_mgr_disable_isr, &framedone_compl, 490 irq); 491 if (r) 492 DSSERR("failed to register FRAMEDONE isr\n"); 493 494 dispc_mgr_enable(channel, false); 495 496 /* if we couldn't register for framedone, just sleep and exit */ 497 if (r) { 498 msleep(100); 499 return; 500 } 501 502 if (!wait_for_completion_timeout(&framedone_compl, 503 msecs_to_jiffies(100))) 504 DSSERR("timeout waiting for FRAME DONE\n"); 505 506 r = omap_dispc_unregister_isr(dispc_mgr_disable_isr, &framedone_compl, 507 irq); 508 if (r) 509 DSSERR("failed to unregister FRAMEDONE isr\n"); 510 } 511 512 static void dispc_digit_out_enable_isr(void *data, u32 mask) 513 { 514 struct completion *compl = data; 515 516 /* ignore any sync lost interrupts */ 517 if (mask & (DISPC_IRQ_EVSYNC_EVEN | DISPC_IRQ_EVSYNC_ODD)) 518 complete(compl); 519 } 520 521 static void dispc_mgr_enable_digit_out(void) 522 { 523 DECLARE_COMPLETION_ONSTACK(vsync_compl); 524 int r; 525 u32 irq_mask; 526 527 if (dispc_mgr_is_enabled(OMAP_DSS_CHANNEL_DIGIT)) 528 return; 529 530 /* 531 * Digit output produces some sync lost interrupts during the first 532 * frame when enabling. Those need to be ignored, so we register for the 533 * sync lost irq to prevent the error handler from triggering. 534 */ 535 536 irq_mask = dispc_mgr_get_vsync_irq(OMAP_DSS_CHANNEL_DIGIT) | 537 dispc_mgr_get_sync_lost_irq(OMAP_DSS_CHANNEL_DIGIT); 538 539 r = omap_dispc_register_isr(dispc_digit_out_enable_isr, &vsync_compl, 540 irq_mask); 541 if (r) { 542 DSSERR("failed to register %x isr\n", irq_mask); 543 return; 544 } 545 546 dispc_mgr_enable(OMAP_DSS_CHANNEL_DIGIT, true); 547 548 /* wait for the first evsync */ 549 if (!wait_for_completion_timeout(&vsync_compl, msecs_to_jiffies(100))) 550 DSSERR("timeout waiting for digit out to start\n"); 551 552 r = omap_dispc_unregister_isr(dispc_digit_out_enable_isr, &vsync_compl, 553 irq_mask); 554 if (r) 555 DSSERR("failed to unregister %x isr\n", irq_mask); 556 } 557 558 static void dispc_mgr_disable_digit_out(void) 559 { 560 DECLARE_COMPLETION_ONSTACK(framedone_compl); 561 int r, i; 562 u32 irq_mask; 563 int num_irqs; 564 565 if (!dispc_mgr_is_enabled(OMAP_DSS_CHANNEL_DIGIT)) 566 return; 567 568 /* 569 * When we disable the digit output, we need to wait for FRAMEDONE to 570 * know that DISPC has finished with the output. 571 */ 572 573 irq_mask = dispc_mgr_get_framedone_irq(OMAP_DSS_CHANNEL_DIGIT); 574 num_irqs = 1; 575 576 if (!irq_mask) { 577 /* 578 * omap 2/3 don't have framedone irq for TV, so we need to use 579 * vsyncs for this. 580 */ 581 582 irq_mask = dispc_mgr_get_vsync_irq(OMAP_DSS_CHANNEL_DIGIT); 583 /* 584 * We need to wait for both even and odd vsyncs. Note that this 585 * is not totally reliable, as we could get a vsync interrupt 586 * before we disable the output, which leads to timeout in the 587 * wait_for_completion. 588 */ 589 num_irqs = 2; 590 } 591 592 r = omap_dispc_register_isr(dispc_mgr_disable_isr, &framedone_compl, 593 irq_mask); 594 if (r) 595 DSSERR("failed to register %x isr\n", irq_mask); 596 597 dispc_mgr_enable(OMAP_DSS_CHANNEL_DIGIT, false); 598 599 /* if we couldn't register the irq, just sleep and exit */ 600 if (r) { 601 msleep(100); 602 return; 603 } 604 605 for (i = 0; i < num_irqs; ++i) { 606 if (!wait_for_completion_timeout(&framedone_compl, 607 msecs_to_jiffies(100))) 608 DSSERR("timeout waiting for digit out to stop\n"); 609 } 610 611 r = omap_dispc_unregister_isr(dispc_mgr_disable_isr, &framedone_compl, 612 irq_mask); 613 if (r) 614 DSSERR("failed to unregister %x isr\n", irq_mask); 615 } 616 617 void dispc_mgr_enable_sync(enum omap_channel channel) 618 { 619 if (dss_mgr_is_lcd(channel)) 620 dispc_mgr_enable_lcd_out(channel); 621 else if (channel == OMAP_DSS_CHANNEL_DIGIT) 622 dispc_mgr_enable_digit_out(); 623 else 624 WARN_ON(1); 625 } 626 627 void dispc_mgr_disable_sync(enum omap_channel channel) 628 { 629 if (dss_mgr_is_lcd(channel)) 630 dispc_mgr_disable_lcd_out(channel); 631 else if (channel == OMAP_DSS_CHANNEL_DIGIT) 632 dispc_mgr_disable_digit_out(); 633 else 634 WARN_ON(1); 635 } 636 637 static inline void dispc_irq_wait_handler(void *data, u32 mask) 638 { 639 complete((struct completion *)data); 640 } 641 642 int omap_dispc_wait_for_irq_interruptible_timeout(u32 irqmask, 643 unsigned long timeout) 644 { 645 646 int r; 647 long time_left; 648 DECLARE_COMPLETION_ONSTACK(completion); 649 650 r = omap_dispc_register_isr(dispc_irq_wait_handler, &completion, 651 irqmask); 652 653 if (r) 654 return r; 655 656 time_left = wait_for_completion_interruptible_timeout(&completion, 657 timeout); 658 659 omap_dispc_unregister_isr(dispc_irq_wait_handler, &completion, irqmask); 660 661 if (time_left == 0) 662 return -ETIMEDOUT; 663 664 if (time_left == -ERESTARTSYS) 665 return -ERESTARTSYS; 666 667 return 0; 668 } 669