0001
0002
0003
0004
0005
0006
0007 #define DSS_SUBSYS_NAME "APPLY"
0008
0009 #include <linux/kernel.h>
0010 #include <linux/module.h>
0011 #include <linux/slab.h>
0012 #include <linux/spinlock.h>
0013 #include <linux/jiffies.h>
0014 #include <linux/delay.h>
0015 #include <linux/interrupt.h>
0016 #include <linux/seq_file.h>
0017
0018 #include <video/omapfb_dss.h>
0019
0020 #include "dss.h"
0021 #include "dss_features.h"
0022 #include "dispc-compat.h"
0023
0024 #define DISPC_IRQ_MASK_ERROR (DISPC_IRQ_GFX_FIFO_UNDERFLOW | \
0025 DISPC_IRQ_OCP_ERR | \
0026 DISPC_IRQ_VID1_FIFO_UNDERFLOW | \
0027 DISPC_IRQ_VID2_FIFO_UNDERFLOW | \
0028 DISPC_IRQ_SYNC_LOST | \
0029 DISPC_IRQ_SYNC_LOST_DIGIT)
0030
0031 #define DISPC_MAX_NR_ISRS 8
0032
0033 struct omap_dispc_isr_data {
0034 omap_dispc_isr_t isr;
0035 void *arg;
0036 u32 mask;
0037 };
0038
0039 struct dispc_irq_stats {
0040 unsigned long last_reset;
0041 unsigned irq_count;
0042 unsigned irqs[32];
0043 };
0044
0045 static struct {
0046 spinlock_t irq_lock;
0047 u32 irq_error_mask;
0048 struct omap_dispc_isr_data registered_isr[DISPC_MAX_NR_ISRS];
0049 u32 error_irqs;
0050 struct work_struct error_work;
0051
0052 #ifdef CONFIG_FB_OMAP2_DSS_COLLECT_IRQ_STATS
0053 spinlock_t irq_stats_lock;
0054 struct dispc_irq_stats irq_stats;
0055 #endif
0056 } dispc_compat;
0057
0058
0059 #ifdef CONFIG_FB_OMAP2_DSS_COLLECT_IRQ_STATS
0060 static void dispc_dump_irqs(struct seq_file *s)
0061 {
0062 unsigned long flags;
0063 struct dispc_irq_stats stats;
0064
0065 spin_lock_irqsave(&dispc_compat.irq_stats_lock, flags);
0066
0067 stats = dispc_compat.irq_stats;
0068 memset(&dispc_compat.irq_stats, 0, sizeof(dispc_compat.irq_stats));
0069 dispc_compat.irq_stats.last_reset = jiffies;
0070
0071 spin_unlock_irqrestore(&dispc_compat.irq_stats_lock, flags);
0072
0073 seq_printf(s, "period %u ms\n",
0074 jiffies_to_msecs(jiffies - stats.last_reset));
0075
0076 seq_printf(s, "irqs %d\n", stats.irq_count);
0077 #define PIS(x) \
0078 seq_printf(s, "%-20s %10d\n", #x, stats.irqs[ffs(DISPC_IRQ_##x)-1])
0079
0080 PIS(FRAMEDONE);
0081 PIS(VSYNC);
0082 PIS(EVSYNC_EVEN);
0083 PIS(EVSYNC_ODD);
0084 PIS(ACBIAS_COUNT_STAT);
0085 PIS(PROG_LINE_NUM);
0086 PIS(GFX_FIFO_UNDERFLOW);
0087 PIS(GFX_END_WIN);
0088 PIS(PAL_GAMMA_MASK);
0089 PIS(OCP_ERR);
0090 PIS(VID1_FIFO_UNDERFLOW);
0091 PIS(VID1_END_WIN);
0092 PIS(VID2_FIFO_UNDERFLOW);
0093 PIS(VID2_END_WIN);
0094 if (dss_feat_get_num_ovls() > 3) {
0095 PIS(VID3_FIFO_UNDERFLOW);
0096 PIS(VID3_END_WIN);
0097 }
0098 PIS(SYNC_LOST);
0099 PIS(SYNC_LOST_DIGIT);
0100 PIS(WAKEUP);
0101 if (dss_has_feature(FEAT_MGR_LCD2)) {
0102 PIS(FRAMEDONE2);
0103 PIS(VSYNC2);
0104 PIS(ACBIAS_COUNT_STAT2);
0105 PIS(SYNC_LOST2);
0106 }
0107 if (dss_has_feature(FEAT_MGR_LCD3)) {
0108 PIS(FRAMEDONE3);
0109 PIS(VSYNC3);
0110 PIS(ACBIAS_COUNT_STAT3);
0111 PIS(SYNC_LOST3);
0112 }
0113 #undef PIS
0114 }
0115 #endif
0116
0117
0118 static void _omap_dispc_set_irqs(void)
0119 {
0120 u32 mask;
0121 int i;
0122 struct omap_dispc_isr_data *isr_data;
0123
0124 mask = dispc_compat.irq_error_mask;
0125
0126 for (i = 0; i < DISPC_MAX_NR_ISRS; i++) {
0127 isr_data = &dispc_compat.registered_isr[i];
0128
0129 if (isr_data->isr == NULL)
0130 continue;
0131
0132 mask |= isr_data->mask;
0133 }
0134
0135 dispc_write_irqenable(mask);
0136 }
0137
0138 int omap_dispc_register_isr(omap_dispc_isr_t isr, void *arg, u32 mask)
0139 {
0140 int i;
0141 int ret;
0142 unsigned long flags;
0143 struct omap_dispc_isr_data *isr_data;
0144
0145 if (isr == NULL)
0146 return -EINVAL;
0147
0148 spin_lock_irqsave(&dispc_compat.irq_lock, flags);
0149
0150
0151 for (i = 0; i < DISPC_MAX_NR_ISRS; i++) {
0152 isr_data = &dispc_compat.registered_isr[i];
0153 if (isr_data->isr == isr && isr_data->arg == arg &&
0154 isr_data->mask == mask) {
0155 ret = -EINVAL;
0156 goto err;
0157 }
0158 }
0159
0160 isr_data = NULL;
0161 ret = -EBUSY;
0162
0163 for (i = 0; i < DISPC_MAX_NR_ISRS; i++) {
0164 isr_data = &dispc_compat.registered_isr[i];
0165
0166 if (isr_data->isr != NULL)
0167 continue;
0168
0169 isr_data->isr = isr;
0170 isr_data->arg = arg;
0171 isr_data->mask = mask;
0172 ret = 0;
0173
0174 break;
0175 }
0176
0177 if (ret)
0178 goto err;
0179
0180 _omap_dispc_set_irqs();
0181
0182 spin_unlock_irqrestore(&dispc_compat.irq_lock, flags);
0183
0184 return 0;
0185 err:
0186 spin_unlock_irqrestore(&dispc_compat.irq_lock, flags);
0187
0188 return ret;
0189 }
0190 EXPORT_SYMBOL(omap_dispc_register_isr);
0191
0192 int omap_dispc_unregister_isr(omap_dispc_isr_t isr, void *arg, u32 mask)
0193 {
0194 int i;
0195 unsigned long flags;
0196 int ret = -EINVAL;
0197 struct omap_dispc_isr_data *isr_data;
0198
0199 spin_lock_irqsave(&dispc_compat.irq_lock, flags);
0200
0201 for (i = 0; i < DISPC_MAX_NR_ISRS; i++) {
0202 isr_data = &dispc_compat.registered_isr[i];
0203 if (isr_data->isr != isr || isr_data->arg != arg ||
0204 isr_data->mask != mask)
0205 continue;
0206
0207
0208
0209 isr_data->isr = NULL;
0210 isr_data->arg = NULL;
0211 isr_data->mask = 0;
0212
0213 ret = 0;
0214 break;
0215 }
0216
0217 if (ret == 0)
0218 _omap_dispc_set_irqs();
0219
0220 spin_unlock_irqrestore(&dispc_compat.irq_lock, flags);
0221
0222 return ret;
0223 }
0224 EXPORT_SYMBOL(omap_dispc_unregister_isr);
0225
0226 static void print_irq_status(u32 status)
0227 {
0228 if ((status & dispc_compat.irq_error_mask) == 0)
0229 return;
0230
0231 #define PIS(x) (status & DISPC_IRQ_##x) ? (#x " ") : ""
0232
0233 pr_debug("DISPC IRQ: 0x%x: %s%s%s%s%s%s%s%s%s\n",
0234 status,
0235 PIS(OCP_ERR),
0236 PIS(GFX_FIFO_UNDERFLOW),
0237 PIS(VID1_FIFO_UNDERFLOW),
0238 PIS(VID2_FIFO_UNDERFLOW),
0239 dss_feat_get_num_ovls() > 3 ? PIS(VID3_FIFO_UNDERFLOW) : "",
0240 PIS(SYNC_LOST),
0241 PIS(SYNC_LOST_DIGIT),
0242 dss_has_feature(FEAT_MGR_LCD2) ? PIS(SYNC_LOST2) : "",
0243 dss_has_feature(FEAT_MGR_LCD3) ? PIS(SYNC_LOST3) : "");
0244 #undef PIS
0245 }
0246
0247
0248
0249
0250
0251 static irqreturn_t omap_dispc_irq_handler(int irq, void *arg)
0252 {
0253 int i;
0254 u32 irqstatus, irqenable;
0255 u32 handledirqs = 0;
0256 u32 unhandled_errors;
0257 struct omap_dispc_isr_data *isr_data;
0258 struct omap_dispc_isr_data registered_isr[DISPC_MAX_NR_ISRS];
0259
0260 spin_lock(&dispc_compat.irq_lock);
0261
0262 irqstatus = dispc_read_irqstatus();
0263 irqenable = dispc_read_irqenable();
0264
0265
0266 if (!(irqstatus & irqenable)) {
0267 spin_unlock(&dispc_compat.irq_lock);
0268 return IRQ_NONE;
0269 }
0270
0271 #ifdef CONFIG_FB_OMAP2_DSS_COLLECT_IRQ_STATS
0272 spin_lock(&dispc_compat.irq_stats_lock);
0273 dispc_compat.irq_stats.irq_count++;
0274 dss_collect_irq_stats(irqstatus, dispc_compat.irq_stats.irqs);
0275 spin_unlock(&dispc_compat.irq_stats_lock);
0276 #endif
0277
0278 print_irq_status(irqstatus);
0279
0280
0281
0282 dispc_clear_irqstatus(irqstatus);
0283
0284 dispc_read_irqstatus();
0285
0286
0287
0288 memcpy(registered_isr, dispc_compat.registered_isr,
0289 sizeof(registered_isr));
0290
0291 spin_unlock(&dispc_compat.irq_lock);
0292
0293 for (i = 0; i < DISPC_MAX_NR_ISRS; i++) {
0294 isr_data = ®istered_isr[i];
0295
0296 if (!isr_data->isr)
0297 continue;
0298
0299 if (isr_data->mask & irqstatus) {
0300 isr_data->isr(isr_data->arg, irqstatus);
0301 handledirqs |= isr_data->mask;
0302 }
0303 }
0304
0305 spin_lock(&dispc_compat.irq_lock);
0306
0307 unhandled_errors = irqstatus & ~handledirqs & dispc_compat.irq_error_mask;
0308
0309 if (unhandled_errors) {
0310 dispc_compat.error_irqs |= unhandled_errors;
0311
0312 dispc_compat.irq_error_mask &= ~unhandled_errors;
0313 _omap_dispc_set_irqs();
0314
0315 schedule_work(&dispc_compat.error_work);
0316 }
0317
0318 spin_unlock(&dispc_compat.irq_lock);
0319
0320 return IRQ_HANDLED;
0321 }
0322
0323 static void dispc_error_worker(struct work_struct *work)
0324 {
0325 int i;
0326 u32 errors;
0327 unsigned long flags;
0328 static const unsigned fifo_underflow_bits[] = {
0329 DISPC_IRQ_GFX_FIFO_UNDERFLOW,
0330 DISPC_IRQ_VID1_FIFO_UNDERFLOW,
0331 DISPC_IRQ_VID2_FIFO_UNDERFLOW,
0332 DISPC_IRQ_VID3_FIFO_UNDERFLOW,
0333 };
0334
0335 spin_lock_irqsave(&dispc_compat.irq_lock, flags);
0336 errors = dispc_compat.error_irqs;
0337 dispc_compat.error_irqs = 0;
0338 spin_unlock_irqrestore(&dispc_compat.irq_lock, flags);
0339
0340 dispc_runtime_get();
0341
0342 for (i = 0; i < omap_dss_get_num_overlays(); ++i) {
0343 struct omap_overlay *ovl;
0344 unsigned bit;
0345
0346 ovl = omap_dss_get_overlay(i);
0347 bit = fifo_underflow_bits[i];
0348
0349 if (bit & errors) {
0350 DSSERR("FIFO UNDERFLOW on %s, disabling the overlay\n",
0351 ovl->name);
0352 ovl->disable(ovl);
0353 msleep(50);
0354 }
0355 }
0356
0357 for (i = 0; i < omap_dss_get_num_overlay_managers(); ++i) {
0358 struct omap_overlay_manager *mgr;
0359 unsigned bit;
0360
0361 mgr = omap_dss_get_overlay_manager(i);
0362 bit = dispc_mgr_get_sync_lost_irq(i);
0363
0364 if (bit & errors) {
0365 int j;
0366
0367 DSSERR("SYNC_LOST on channel %s, restarting the output "
0368 "with video overlays disabled\n",
0369 mgr->name);
0370
0371 dss_mgr_disable(mgr);
0372
0373 for (j = 0; j < omap_dss_get_num_overlays(); ++j) {
0374 struct omap_overlay *ovl;
0375 ovl = omap_dss_get_overlay(j);
0376
0377 if (ovl->id != OMAP_DSS_GFX &&
0378 ovl->manager == mgr)
0379 ovl->disable(ovl);
0380 }
0381
0382 dss_mgr_enable(mgr);
0383 }
0384 }
0385
0386 if (errors & DISPC_IRQ_OCP_ERR) {
0387 DSSERR("OCP_ERR\n");
0388 for (i = 0; i < omap_dss_get_num_overlay_managers(); ++i) {
0389 struct omap_overlay_manager *mgr;
0390
0391 mgr = omap_dss_get_overlay_manager(i);
0392 dss_mgr_disable(mgr);
0393 }
0394 }
0395
0396 spin_lock_irqsave(&dispc_compat.irq_lock, flags);
0397 dispc_compat.irq_error_mask |= errors;
0398 _omap_dispc_set_irqs();
0399 spin_unlock_irqrestore(&dispc_compat.irq_lock, flags);
0400
0401 dispc_runtime_put();
0402 }
0403
0404 int dss_dispc_initialize_irq(void)
0405 {
0406 int r;
0407
0408 #ifdef CONFIG_FB_OMAP2_DSS_COLLECT_IRQ_STATS
0409 spin_lock_init(&dispc_compat.irq_stats_lock);
0410 dispc_compat.irq_stats.last_reset = jiffies;
0411 dss_debugfs_create_file("dispc_irq", dispc_dump_irqs);
0412 #endif
0413
0414 spin_lock_init(&dispc_compat.irq_lock);
0415
0416 memset(dispc_compat.registered_isr, 0,
0417 sizeof(dispc_compat.registered_isr));
0418
0419 dispc_compat.irq_error_mask = DISPC_IRQ_MASK_ERROR;
0420 if (dss_has_feature(FEAT_MGR_LCD2))
0421 dispc_compat.irq_error_mask |= DISPC_IRQ_SYNC_LOST2;
0422 if (dss_has_feature(FEAT_MGR_LCD3))
0423 dispc_compat.irq_error_mask |= DISPC_IRQ_SYNC_LOST3;
0424 if (dss_feat_get_num_ovls() > 3)
0425 dispc_compat.irq_error_mask |= DISPC_IRQ_VID3_FIFO_UNDERFLOW;
0426
0427
0428
0429
0430
0431 dispc_clear_irqstatus(dispc_read_irqstatus());
0432
0433 INIT_WORK(&dispc_compat.error_work, dispc_error_worker);
0434
0435 _omap_dispc_set_irqs();
0436
0437 r = dispc_request_irq(omap_dispc_irq_handler, &dispc_compat);
0438 if (r) {
0439 DSSERR("dispc_request_irq failed\n");
0440 return r;
0441 }
0442
0443 return 0;
0444 }
0445
0446 void dss_dispc_uninitialize_irq(void)
0447 {
0448 dispc_free_irq(&dispc_compat);
0449 }
0450
0451 static void dispc_mgr_disable_isr(void *data, u32 mask)
0452 {
0453 struct completion *compl = data;
0454 complete(compl);
0455 }
0456
0457 static void dispc_mgr_enable_lcd_out(enum omap_channel channel)
0458 {
0459 dispc_mgr_enable(channel, true);
0460 }
0461
0462 static void dispc_mgr_disable_lcd_out(enum omap_channel channel)
0463 {
0464 DECLARE_COMPLETION_ONSTACK(framedone_compl);
0465 int r;
0466 u32 irq;
0467
0468 if (!dispc_mgr_is_enabled(channel))
0469 return;
0470
0471
0472
0473
0474
0475
0476 irq = dispc_mgr_get_framedone_irq(channel);
0477
0478 r = omap_dispc_register_isr(dispc_mgr_disable_isr, &framedone_compl,
0479 irq);
0480 if (r)
0481 DSSERR("failed to register FRAMEDONE isr\n");
0482
0483 dispc_mgr_enable(channel, false);
0484
0485
0486 if (r) {
0487 msleep(100);
0488 return;
0489 }
0490
0491 if (!wait_for_completion_timeout(&framedone_compl,
0492 msecs_to_jiffies(100)))
0493 DSSERR("timeout waiting for FRAME DONE\n");
0494
0495 r = omap_dispc_unregister_isr(dispc_mgr_disable_isr, &framedone_compl,
0496 irq);
0497 if (r)
0498 DSSERR("failed to unregister FRAMEDONE isr\n");
0499 }
0500
0501 static void dispc_digit_out_enable_isr(void *data, u32 mask)
0502 {
0503 struct completion *compl = data;
0504
0505
0506 if (mask & (DISPC_IRQ_EVSYNC_EVEN | DISPC_IRQ_EVSYNC_ODD))
0507 complete(compl);
0508 }
0509
0510 static void dispc_mgr_enable_digit_out(void)
0511 {
0512 DECLARE_COMPLETION_ONSTACK(vsync_compl);
0513 int r;
0514 u32 irq_mask;
0515
0516 if (dispc_mgr_is_enabled(OMAP_DSS_CHANNEL_DIGIT))
0517 return;
0518
0519
0520
0521
0522
0523
0524
0525 irq_mask = dispc_mgr_get_vsync_irq(OMAP_DSS_CHANNEL_DIGIT) |
0526 dispc_mgr_get_sync_lost_irq(OMAP_DSS_CHANNEL_DIGIT);
0527
0528 r = omap_dispc_register_isr(dispc_digit_out_enable_isr, &vsync_compl,
0529 irq_mask);
0530 if (r) {
0531 DSSERR("failed to register %x isr\n", irq_mask);
0532 return;
0533 }
0534
0535 dispc_mgr_enable(OMAP_DSS_CHANNEL_DIGIT, true);
0536
0537
0538 if (!wait_for_completion_timeout(&vsync_compl, msecs_to_jiffies(100)))
0539 DSSERR("timeout waiting for digit out to start\n");
0540
0541 r = omap_dispc_unregister_isr(dispc_digit_out_enable_isr, &vsync_compl,
0542 irq_mask);
0543 if (r)
0544 DSSERR("failed to unregister %x isr\n", irq_mask);
0545 }
0546
0547 static void dispc_mgr_disable_digit_out(void)
0548 {
0549 DECLARE_COMPLETION_ONSTACK(framedone_compl);
0550 int r, i;
0551 u32 irq_mask;
0552 int num_irqs;
0553
0554 if (!dispc_mgr_is_enabled(OMAP_DSS_CHANNEL_DIGIT))
0555 return;
0556
0557
0558
0559
0560
0561
0562 irq_mask = dispc_mgr_get_framedone_irq(OMAP_DSS_CHANNEL_DIGIT);
0563 num_irqs = 1;
0564
0565 if (!irq_mask) {
0566
0567
0568
0569
0570
0571 irq_mask = dispc_mgr_get_vsync_irq(OMAP_DSS_CHANNEL_DIGIT);
0572
0573
0574
0575
0576
0577
0578 num_irqs = 2;
0579 }
0580
0581 r = omap_dispc_register_isr(dispc_mgr_disable_isr, &framedone_compl,
0582 irq_mask);
0583 if (r)
0584 DSSERR("failed to register %x isr\n", irq_mask);
0585
0586 dispc_mgr_enable(OMAP_DSS_CHANNEL_DIGIT, false);
0587
0588
0589 if (r) {
0590 msleep(100);
0591 return;
0592 }
0593
0594 for (i = 0; i < num_irqs; ++i) {
0595 if (!wait_for_completion_timeout(&framedone_compl,
0596 msecs_to_jiffies(100)))
0597 DSSERR("timeout waiting for digit out to stop\n");
0598 }
0599
0600 r = omap_dispc_unregister_isr(dispc_mgr_disable_isr, &framedone_compl,
0601 irq_mask);
0602 if (r)
0603 DSSERR("failed to unregister %x isr\n", irq_mask);
0604 }
0605
0606 void dispc_mgr_enable_sync(enum omap_channel channel)
0607 {
0608 if (dss_mgr_is_lcd(channel))
0609 dispc_mgr_enable_lcd_out(channel);
0610 else if (channel == OMAP_DSS_CHANNEL_DIGIT)
0611 dispc_mgr_enable_digit_out();
0612 else
0613 WARN_ON(1);
0614 }
0615
0616 void dispc_mgr_disable_sync(enum omap_channel channel)
0617 {
0618 if (dss_mgr_is_lcd(channel))
0619 dispc_mgr_disable_lcd_out(channel);
0620 else if (channel == OMAP_DSS_CHANNEL_DIGIT)
0621 dispc_mgr_disable_digit_out();
0622 else
0623 WARN_ON(1);
0624 }
0625
0626 static inline void dispc_irq_wait_handler(void *data, u32 mask)
0627 {
0628 complete((struct completion *)data);
0629 }
0630
0631 int omap_dispc_wait_for_irq_interruptible_timeout(u32 irqmask,
0632 unsigned long timeout)
0633 {
0634
0635 int r;
0636 long time_left;
0637 DECLARE_COMPLETION_ONSTACK(completion);
0638
0639 r = omap_dispc_register_isr(dispc_irq_wait_handler, &completion,
0640 irqmask);
0641
0642 if (r)
0643 return r;
0644
0645 time_left = wait_for_completion_interruptible_timeout(&completion,
0646 timeout);
0647
0648 omap_dispc_unregister_isr(dispc_irq_wait_handler, &completion, irqmask);
0649
0650 if (time_left == 0)
0651 return -ETIMEDOUT;
0652
0653 if (time_left == -ERESTARTSYS)
0654 return -ERESTARTSYS;
0655
0656 return 0;
0657 }