aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTomi Valkeinen <tomi.valkeinen@ti.com>2012-10-10 08:55:19 -0400
committerTomi Valkeinen <tomi.valkeinen@ti.com>2012-12-07 10:05:57 -0500
commit96e2e6374385d2219b9011f6bfd0de7221a591d4 (patch)
tree4354979f96740cb79fafe33b91e0c16cafcafc44
parent549acbe7a3380dd3bd2ac71698549148ecc0d17e (diff)
OMAPDSS: move irq handling to dispc-compat
The whole dispc irq handling system we currently have is only needed for compat layer, and thus can be moved from dispc.c to the compat layer. This is quite straigtforward, but we need to add new dispc functions to request and free the actual hardware irq: dispc_request_irq() and dispc_free_irq(). Signed-off-by: Tomi Valkeinen <tomi.valkeinen@ti.com>
-rw-r--r--drivers/video/omap2/dss/apply.c14
-rw-r--r--drivers/video/omap2/dss/dispc-compat.c430
-rw-r--r--drivers/video/omap2/dss/dispc-compat.h3
-rw-r--r--drivers/video/omap2/dss/dispc.c437
-rw-r--r--drivers/video/omap2/dss/dss.h5
5 files changed, 463 insertions, 426 deletions
diff --git a/drivers/video/omap2/dss/apply.c b/drivers/video/omap2/dss/apply.c
index 0de0d3cf1764..29e11434b7df 100644
--- a/drivers/video/omap2/dss/apply.c
+++ b/drivers/video/omap2/dss/apply.c
@@ -1607,11 +1607,23 @@ int omapdss_compat_init(void)
1607 if (r) 1607 if (r)
1608 goto err_mgr_ops; 1608 goto err_mgr_ops;
1609 1609
1610 dispc_runtime_get();
1611
1612 r = dss_dispc_initialize_irq();
1613 if (r)
1614 goto err_init_irq;
1615
1616 dispc_runtime_put();
1617
1610out: 1618out:
1611 mutex_unlock(&compat_init_lock); 1619 mutex_unlock(&compat_init_lock);
1612 1620
1613 return 0; 1621 return 0;
1614 1622
1623err_init_irq:
1624 dispc_runtime_put();
1625 dss_uninstall_mgr_ops();
1626
1615err_mgr_ops: 1627err_mgr_ops:
1616 dss_uninit_overlay_managers(pdev); 1628 dss_uninit_overlay_managers(pdev);
1617 dss_uninit_overlays(pdev); 1629 dss_uninit_overlays(pdev);
@@ -1633,6 +1645,8 @@ void omapdss_compat_uninit(void)
1633 if (--compat_refcnt > 0) 1645 if (--compat_refcnt > 0)
1634 goto out; 1646 goto out;
1635 1647
1648 dss_dispc_uninitialize_irq();
1649
1636 dss_uninstall_mgr_ops(); 1650 dss_uninstall_mgr_ops();
1637 1651
1638 dss_uninit_overlay_managers(pdev); 1652 dss_uninit_overlay_managers(pdev);
diff --git a/drivers/video/omap2/dss/dispc-compat.c b/drivers/video/omap2/dss/dispc-compat.c
index 24e1d5e974eb..928884c9a0a9 100644
--- a/drivers/video/omap2/dss/dispc-compat.c
+++ b/drivers/video/omap2/dss/dispc-compat.c
@@ -23,6 +23,8 @@
23#include <linux/spinlock.h> 23#include <linux/spinlock.h>
24#include <linux/jiffies.h> 24#include <linux/jiffies.h>
25#include <linux/delay.h> 25#include <linux/delay.h>
26#include <linux/interrupt.h>
27#include <linux/seq_file.h>
26 28
27#include <video/omapdss.h> 29#include <video/omapdss.h>
28 30
@@ -30,6 +32,434 @@
30#include "dss_features.h" 32#include "dss_features.h"
31#include "dispc-compat.h" 33#include "dispc-compat.h"
32 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
44struct omap_dispc_isr_data {
45 omap_dispc_isr_t isr;
46 void *arg;
47 u32 mask;
48};
49
50struct dispc_irq_stats {
51 unsigned long last_reset;
52 unsigned irq_count;
53 unsigned irqs[32];
54};
55
56static 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_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_OMAP2_DSS_COLLECT_IRQ_STATS
71static 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 */
129static 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
149int 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;
196err:
197 spin_unlock_irqrestore(&dispc_compat.irq_lock, flags);
198
199 return ret;
200}
201EXPORT_SYMBOL(omap_dispc_register_isr);
202
203int 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}
235EXPORT_SYMBOL(omap_dispc_unregister_isr);
236
237static 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. */
262static 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_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 = &registered_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
334static 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 dispc_ovl_enable(ovl->id, false);
364 dispc_mgr_go(ovl->manager->id);
365 msleep(50);
366 }
367 }
368
369 for (i = 0; i < omap_dss_get_num_overlay_managers(); ++i) {
370 struct omap_overlay_manager *mgr;
371 unsigned bit;
372
373 mgr = omap_dss_get_overlay_manager(i);
374 bit = dispc_mgr_get_sync_lost_irq(i);
375
376 if (bit & errors) {
377 int j;
378
379 DSSERR("SYNC_LOST on channel %s, restarting the output "
380 "with video overlays disabled\n",
381 mgr->name);
382
383 dss_mgr_disable(mgr);
384
385 for (j = 0; j < omap_dss_get_num_overlays(); ++j) {
386 struct omap_overlay *ovl;
387 ovl = omap_dss_get_overlay(j);
388
389 if (ovl->id != OMAP_DSS_GFX &&
390 ovl->manager == mgr)
391 ovl->disable(ovl);
392 }
393
394 dss_mgr_enable(mgr);
395 }
396 }
397
398 if (errors & DISPC_IRQ_OCP_ERR) {
399 DSSERR("OCP_ERR\n");
400 for (i = 0; i < omap_dss_get_num_overlay_managers(); ++i) {
401 struct omap_overlay_manager *mgr;
402
403 mgr = omap_dss_get_overlay_manager(i);
404 dss_mgr_disable(mgr);
405 }
406 }
407
408 spin_lock_irqsave(&dispc_compat.irq_lock, flags);
409 dispc_compat.irq_error_mask |= errors;
410 _omap_dispc_set_irqs();
411 spin_unlock_irqrestore(&dispc_compat.irq_lock, flags);
412
413 dispc_runtime_put();
414}
415
416int dss_dispc_initialize_irq(void)
417{
418 int r;
419
420#ifdef CONFIG_OMAP2_DSS_COLLECT_IRQ_STATS
421 spin_lock_init(&dispc_compat.irq_stats_lock);
422 dispc_compat.irq_stats.last_reset = jiffies;
423 dss_debugfs_create_file("dispc_irq", dispc_dump_irqs);
424#endif
425
426 spin_lock_init(&dispc_compat.irq_lock);
427
428 memset(dispc_compat.registered_isr, 0,
429 sizeof(dispc_compat.registered_isr));
430
431 dispc_compat.irq_error_mask = DISPC_IRQ_MASK_ERROR;
432 if (dss_has_feature(FEAT_MGR_LCD2))
433 dispc_compat.irq_error_mask |= DISPC_IRQ_SYNC_LOST2;
434 if (dss_has_feature(FEAT_MGR_LCD3))
435 dispc_compat.irq_error_mask |= DISPC_IRQ_SYNC_LOST3;
436 if (dss_feat_get_num_ovls() > 3)
437 dispc_compat.irq_error_mask |= DISPC_IRQ_VID3_FIFO_UNDERFLOW;
438
439 /*
440 * there's SYNC_LOST_DIGIT waiting after enabling the DSS,
441 * so clear it
442 */
443 dispc_clear_irqstatus(dispc_read_irqstatus());
444
445 INIT_WORK(&dispc_compat.error_work, dispc_error_worker);
446
447 _omap_dispc_set_irqs();
448
449 r = dispc_request_irq(omap_dispc_irq_handler, &dispc_compat);
450 if (r) {
451 DSSERR("dispc_request_irq failed\n");
452 return r;
453 }
454
455 return 0;
456}
457
458void dss_dispc_uninitialize_irq(void)
459{
460 dispc_free_irq(&dispc_compat);
461}
462
33static void dispc_mgr_disable_isr(void *data, u32 mask) 463static void dispc_mgr_disable_isr(void *data, u32 mask)
34{ 464{
35 struct completion *compl = data; 465 struct completion *compl = data;
diff --git a/drivers/video/omap2/dss/dispc-compat.h b/drivers/video/omap2/dss/dispc-compat.h
index 8322d43d28c3..14a69b3d4fb0 100644
--- a/drivers/video/omap2/dss/dispc-compat.h
+++ b/drivers/video/omap2/dss/dispc-compat.h
@@ -24,4 +24,7 @@ void dispc_mgr_disable_sync(enum omap_channel channel);
24int omap_dispc_wait_for_irq_interruptible_timeout(u32 irqmask, 24int omap_dispc_wait_for_irq_interruptible_timeout(u32 irqmask,
25 unsigned long timeout); 25 unsigned long timeout);
26 26
27int dss_dispc_initialize_irq(void);
28void dss_dispc_uninitialize_irq(void);
29
27#endif 30#endif
diff --git a/drivers/video/omap2/dss/dispc.c b/drivers/video/omap2/dss/dispc.c
index f7c734214022..80314bd3427d 100644
--- a/drivers/video/omap2/dss/dispc.c
+++ b/drivers/video/omap2/dss/dispc.c
@@ -33,7 +33,6 @@
33#include <linux/delay.h> 33#include <linux/delay.h>
34#include <linux/workqueue.h> 34#include <linux/workqueue.h>
35#include <linux/hardirq.h> 35#include <linux/hardirq.h>
36#include <linux/interrupt.h>
37#include <linux/platform_device.h> 36#include <linux/platform_device.h>
38#include <linux/pm_runtime.h> 37#include <linux/pm_runtime.h>
39#include <linux/sizes.h> 38#include <linux/sizes.h>
@@ -47,21 +46,6 @@
47/* DISPC */ 46/* DISPC */
48#define DISPC_SZ_REGS SZ_4K 47#define DISPC_SZ_REGS SZ_4K
49 48
50#define DISPC_IRQ_MASK_ERROR (DISPC_IRQ_GFX_FIFO_UNDERFLOW | \
51 DISPC_IRQ_OCP_ERR | \
52 DISPC_IRQ_VID1_FIFO_UNDERFLOW | \
53 DISPC_IRQ_VID2_FIFO_UNDERFLOW | \
54 DISPC_IRQ_SYNC_LOST | \
55 DISPC_IRQ_SYNC_LOST_DIGIT)
56
57#define DISPC_MAX_NR_ISRS 8
58
59struct omap_dispc_isr_data {
60 omap_dispc_isr_t isr;
61 void *arg;
62 u32 mask;
63};
64
65enum omap_burst_size { 49enum omap_burst_size {
66 BURST_SIZE_X2 = 0, 50 BURST_SIZE_X2 = 0,
67 BURST_SIZE_X4 = 1, 51 BURST_SIZE_X4 = 1,
@@ -74,12 +58,6 @@ enum omap_burst_size {
74#define REG_FLD_MOD(idx, val, start, end) \ 58#define REG_FLD_MOD(idx, val, start, end) \
75 dispc_write_reg(idx, FLD_MOD(dispc_read_reg(idx), val, start, end)) 59 dispc_write_reg(idx, FLD_MOD(dispc_read_reg(idx), val, start, end))
76 60
77struct dispc_irq_stats {
78 unsigned long last_reset;
79 unsigned irq_count;
80 unsigned irqs[32];
81};
82
83struct dispc_features { 61struct dispc_features {
84 u8 sw_start; 62 u8 sw_start;
85 u8 fp_start; 63 u8 fp_start;
@@ -124,21 +102,10 @@ static struct {
124 /* maps which plane is using a fifo. fifo-id -> plane-id */ 102 /* maps which plane is using a fifo. fifo-id -> plane-id */
125 int fifo_assignment[DISPC_MAX_NR_FIFOS]; 103 int fifo_assignment[DISPC_MAX_NR_FIFOS];
126 104
127 spinlock_t irq_lock;
128 u32 irq_error_mask;
129 struct omap_dispc_isr_data registered_isr[DISPC_MAX_NR_ISRS];
130 u32 error_irqs;
131 struct work_struct error_work;
132
133 bool ctx_valid; 105 bool ctx_valid;
134 u32 ctx[DISPC_SZ_REGS / sizeof(u32)]; 106 u32 ctx[DISPC_SZ_REGS / sizeof(u32)];
135 107
136 const struct dispc_features *feat; 108 const struct dispc_features *feat;
137
138#ifdef CONFIG_OMAP2_DSS_COLLECT_IRQ_STATS
139 spinlock_t irq_stats_lock;
140 struct dispc_irq_stats irq_stats;
141#endif
142} dispc; 109} dispc;
143 110
144enum omap_color_component { 111enum omap_color_component {
@@ -249,7 +216,6 @@ struct color_conv_coef {
249 int full_range; 216 int full_range;
250}; 217};
251 218
252static void _omap_dispc_set_irqs(void);
253static unsigned long dispc_plane_pclk_rate(enum omap_plane plane); 219static unsigned long dispc_plane_pclk_rate(enum omap_plane plane);
254static unsigned long dispc_plane_lclk_rate(enum omap_plane plane); 220static unsigned long dispc_plane_lclk_rate(enum omap_plane plane);
255 221
@@ -3126,64 +3092,6 @@ void dispc_dump_clocks(struct seq_file *s)
3126 dispc_runtime_put(); 3092 dispc_runtime_put();
3127} 3093}
3128 3094
3129#ifdef CONFIG_OMAP2_DSS_COLLECT_IRQ_STATS
3130static void dispc_dump_irqs(struct seq_file *s)
3131{
3132 unsigned long flags;
3133 struct dispc_irq_stats stats;
3134
3135 spin_lock_irqsave(&dispc.irq_stats_lock, flags);
3136
3137 stats = dispc.irq_stats;
3138 memset(&dispc.irq_stats, 0, sizeof(dispc.irq_stats));
3139 dispc.irq_stats.last_reset = jiffies;
3140
3141 spin_unlock_irqrestore(&dispc.irq_stats_lock, flags);
3142
3143 seq_printf(s, "period %u ms\n",
3144 jiffies_to_msecs(jiffies - stats.last_reset));
3145
3146 seq_printf(s, "irqs %d\n", stats.irq_count);
3147#define PIS(x) \
3148 seq_printf(s, "%-20s %10d\n", #x, stats.irqs[ffs(DISPC_IRQ_##x)-1]);
3149
3150 PIS(FRAMEDONE);
3151 PIS(VSYNC);
3152 PIS(EVSYNC_EVEN);
3153 PIS(EVSYNC_ODD);
3154 PIS(ACBIAS_COUNT_STAT);
3155 PIS(PROG_LINE_NUM);
3156 PIS(GFX_FIFO_UNDERFLOW);
3157 PIS(GFX_END_WIN);
3158 PIS(PAL_GAMMA_MASK);
3159 PIS(OCP_ERR);
3160 PIS(VID1_FIFO_UNDERFLOW);
3161 PIS(VID1_END_WIN);
3162 PIS(VID2_FIFO_UNDERFLOW);
3163 PIS(VID2_END_WIN);
3164 if (dss_feat_get_num_ovls() > 3) {
3165 PIS(VID3_FIFO_UNDERFLOW);
3166 PIS(VID3_END_WIN);
3167 }
3168 PIS(SYNC_LOST);
3169 PIS(SYNC_LOST_DIGIT);
3170 PIS(WAKEUP);
3171 if (dss_has_feature(FEAT_MGR_LCD2)) {
3172 PIS(FRAMEDONE2);
3173 PIS(VSYNC2);
3174 PIS(ACBIAS_COUNT_STAT2);
3175 PIS(SYNC_LOST2);
3176 }
3177 if (dss_has_feature(FEAT_MGR_LCD3)) {
3178 PIS(FRAMEDONE3);
3179 PIS(VSYNC3);
3180 PIS(ACBIAS_COUNT_STAT3);
3181 PIS(SYNC_LOST3);
3182 }
3183#undef PIS
3184}
3185#endif
3186
3187static void dispc_dump_regs(struct seq_file *s) 3095static void dispc_dump_regs(struct seq_file *s)
3188{ 3096{
3189 int i, j; 3097 int i, j;
@@ -3462,319 +3370,6 @@ void dispc_write_irqenable(u32 mask)
3462 dispc_write_reg(DISPC_IRQENABLE, mask); 3370 dispc_write_reg(DISPC_IRQENABLE, mask);
3463} 3371}
3464 3372
3465/* dispc.irq_lock has to be locked by the caller */
3466static void _omap_dispc_set_irqs(void)
3467{
3468 u32 mask;
3469 int i;
3470 struct omap_dispc_isr_data *isr_data;
3471
3472 mask = dispc.irq_error_mask;
3473
3474 for (i = 0; i < DISPC_MAX_NR_ISRS; i++) {
3475 isr_data = &dispc.registered_isr[i];
3476
3477 if (isr_data->isr == NULL)
3478 continue;
3479
3480 mask |= isr_data->mask;
3481 }
3482
3483 dispc_write_irqenable(mask);
3484}
3485
3486int omap_dispc_register_isr(omap_dispc_isr_t isr, void *arg, u32 mask)
3487{
3488 int i;
3489 int ret;
3490 unsigned long flags;
3491 struct omap_dispc_isr_data *isr_data;
3492
3493 if (isr == NULL)
3494 return -EINVAL;
3495
3496 spin_lock_irqsave(&dispc.irq_lock, flags);
3497
3498 /* check for duplicate entry */
3499 for (i = 0; i < DISPC_MAX_NR_ISRS; i++) {
3500 isr_data = &dispc.registered_isr[i];
3501 if (isr_data->isr == isr && isr_data->arg == arg &&
3502 isr_data->mask == mask) {
3503 ret = -EINVAL;
3504 goto err;
3505 }
3506 }
3507
3508 isr_data = NULL;
3509 ret = -EBUSY;
3510
3511 for (i = 0; i < DISPC_MAX_NR_ISRS; i++) {
3512 isr_data = &dispc.registered_isr[i];
3513
3514 if (isr_data->isr != NULL)
3515 continue;
3516
3517 isr_data->isr = isr;
3518 isr_data->arg = arg;
3519 isr_data->mask = mask;
3520 ret = 0;
3521
3522 break;
3523 }
3524
3525 if (ret)
3526 goto err;
3527
3528 _omap_dispc_set_irqs();
3529
3530 spin_unlock_irqrestore(&dispc.irq_lock, flags);
3531
3532 return 0;
3533err:
3534 spin_unlock_irqrestore(&dispc.irq_lock, flags);
3535
3536 return ret;
3537}
3538EXPORT_SYMBOL(omap_dispc_register_isr);
3539
3540int omap_dispc_unregister_isr(omap_dispc_isr_t isr, void *arg, u32 mask)
3541{
3542 int i;
3543 unsigned long flags;
3544 int ret = -EINVAL;
3545 struct omap_dispc_isr_data *isr_data;
3546
3547 spin_lock_irqsave(&dispc.irq_lock, flags);
3548
3549 for (i = 0; i < DISPC_MAX_NR_ISRS; i++) {
3550 isr_data = &dispc.registered_isr[i];
3551 if (isr_data->isr != isr || isr_data->arg != arg ||
3552 isr_data->mask != mask)
3553 continue;
3554
3555 /* found the correct isr */
3556
3557 isr_data->isr = NULL;
3558 isr_data->arg = NULL;
3559 isr_data->mask = 0;
3560
3561 ret = 0;
3562 break;
3563 }
3564
3565 if (ret == 0)
3566 _omap_dispc_set_irqs();
3567
3568 spin_unlock_irqrestore(&dispc.irq_lock, flags);
3569
3570 return ret;
3571}
3572EXPORT_SYMBOL(omap_dispc_unregister_isr);
3573
3574static void print_irq_status(u32 status)
3575{
3576 if ((status & dispc.irq_error_mask) == 0)
3577 return;
3578
3579#define PIS(x) (status & DISPC_IRQ_##x) ? (#x " ") : ""
3580
3581 pr_debug("DISPC IRQ: 0x%x: %s%s%s%s%s%s%s%s%s\n",
3582 status,
3583 PIS(OCP_ERR),
3584 PIS(GFX_FIFO_UNDERFLOW),
3585 PIS(VID1_FIFO_UNDERFLOW),
3586 PIS(VID2_FIFO_UNDERFLOW),
3587 dss_feat_get_num_ovls() > 3 ? PIS(VID3_FIFO_UNDERFLOW) : "",
3588 PIS(SYNC_LOST),
3589 PIS(SYNC_LOST_DIGIT),
3590 dss_has_feature(FEAT_MGR_LCD2) ? PIS(SYNC_LOST2) : "",
3591 dss_has_feature(FEAT_MGR_LCD3) ? PIS(SYNC_LOST3) : "");
3592#undef PIS
3593}
3594
3595/* Called from dss.c. Note that we don't touch clocks here,
3596 * but we presume they are on because we got an IRQ. However,
3597 * an irq handler may turn the clocks off, so we may not have
3598 * clock later in the function. */
3599static irqreturn_t omap_dispc_irq_handler(int irq, void *arg)
3600{
3601 int i;
3602 u32 irqstatus, irqenable;
3603 u32 handledirqs = 0;
3604 u32 unhandled_errors;
3605 struct omap_dispc_isr_data *isr_data;
3606 struct omap_dispc_isr_data registered_isr[DISPC_MAX_NR_ISRS];
3607
3608 spin_lock(&dispc.irq_lock);
3609
3610 irqstatus = dispc_read_irqstatus();
3611 irqenable = dispc_read_irqenable();
3612
3613 /* IRQ is not for us */
3614 if (!(irqstatus & irqenable)) {
3615 spin_unlock(&dispc.irq_lock);
3616 return IRQ_NONE;
3617 }
3618
3619#ifdef CONFIG_OMAP2_DSS_COLLECT_IRQ_STATS
3620 spin_lock(&dispc.irq_stats_lock);
3621 dispc.irq_stats.irq_count++;
3622 dss_collect_irq_stats(irqstatus, dispc.irq_stats.irqs);
3623 spin_unlock(&dispc.irq_stats_lock);
3624#endif
3625
3626 print_irq_status(irqstatus);
3627
3628 /* Ack the interrupt. Do it here before clocks are possibly turned
3629 * off */
3630 dispc_clear_irqstatus(irqstatus);
3631 /* flush posted write */
3632 dispc_read_irqstatus();
3633
3634 /* make a copy and unlock, so that isrs can unregister
3635 * themselves */
3636 memcpy(registered_isr, dispc.registered_isr,
3637 sizeof(registered_isr));
3638
3639 spin_unlock(&dispc.irq_lock);
3640
3641 for (i = 0; i < DISPC_MAX_NR_ISRS; i++) {
3642 isr_data = &registered_isr[i];
3643
3644 if (!isr_data->isr)
3645 continue;
3646
3647 if (isr_data->mask & irqstatus) {
3648 isr_data->isr(isr_data->arg, irqstatus);
3649 handledirqs |= isr_data->mask;
3650 }
3651 }
3652
3653 spin_lock(&dispc.irq_lock);
3654
3655 unhandled_errors = irqstatus & ~handledirqs & dispc.irq_error_mask;
3656
3657 if (unhandled_errors) {
3658 dispc.error_irqs |= unhandled_errors;
3659
3660 dispc.irq_error_mask &= ~unhandled_errors;
3661 _omap_dispc_set_irqs();
3662
3663 schedule_work(&dispc.error_work);
3664 }
3665
3666 spin_unlock(&dispc.irq_lock);
3667
3668 return IRQ_HANDLED;
3669}
3670
3671static void dispc_error_worker(struct work_struct *work)
3672{
3673 int i;
3674 u32 errors;
3675 unsigned long flags;
3676 static const unsigned fifo_underflow_bits[] = {
3677 DISPC_IRQ_GFX_FIFO_UNDERFLOW,
3678 DISPC_IRQ_VID1_FIFO_UNDERFLOW,
3679 DISPC_IRQ_VID2_FIFO_UNDERFLOW,
3680 DISPC_IRQ_VID3_FIFO_UNDERFLOW,
3681 };
3682
3683 spin_lock_irqsave(&dispc.irq_lock, flags);
3684 errors = dispc.error_irqs;
3685 dispc.error_irqs = 0;
3686 spin_unlock_irqrestore(&dispc.irq_lock, flags);
3687
3688 dispc_runtime_get();
3689
3690 for (i = 0; i < omap_dss_get_num_overlays(); ++i) {
3691 struct omap_overlay *ovl;
3692 unsigned bit;
3693
3694 ovl = omap_dss_get_overlay(i);
3695 bit = fifo_underflow_bits[i];
3696
3697 if (bit & errors) {
3698 DSSERR("FIFO UNDERFLOW on %s, disabling the overlay\n",
3699 ovl->name);
3700 dispc_ovl_enable(ovl->id, false);
3701 dispc_mgr_go(ovl->manager->id);
3702 msleep(50);
3703 }
3704 }
3705
3706 for (i = 0; i < omap_dss_get_num_overlay_managers(); ++i) {
3707 struct omap_overlay_manager *mgr;
3708 unsigned bit;
3709
3710 mgr = omap_dss_get_overlay_manager(i);
3711 bit = mgr_desc[i].sync_lost_irq;
3712
3713 if (bit & errors) {
3714 int j;
3715
3716 DSSERR("SYNC_LOST on channel %s, restarting the output "
3717 "with video overlays disabled\n",
3718 mgr->name);
3719
3720 dss_mgr_disable(mgr);
3721
3722 for (j = 0; j < omap_dss_get_num_overlays(); ++j) {
3723 struct omap_overlay *ovl;
3724 ovl = omap_dss_get_overlay(j);
3725
3726 if (ovl->id != OMAP_DSS_GFX &&
3727 ovl->manager == mgr)
3728 ovl->disable(ovl);
3729 }
3730
3731 dss_mgr_enable(mgr);
3732 }
3733 }
3734
3735 if (errors & DISPC_IRQ_OCP_ERR) {
3736 DSSERR("OCP_ERR\n");
3737 for (i = 0; i < omap_dss_get_num_overlay_managers(); ++i) {
3738 struct omap_overlay_manager *mgr;
3739
3740 mgr = omap_dss_get_overlay_manager(i);
3741 dss_mgr_disable(mgr);
3742 }
3743 }
3744
3745 spin_lock_irqsave(&dispc.irq_lock, flags);
3746 dispc.irq_error_mask |= errors;
3747 _omap_dispc_set_irqs();
3748 spin_unlock_irqrestore(&dispc.irq_lock, flags);
3749
3750 dispc_runtime_put();
3751}
3752
3753static void _omap_dispc_initialize_irq(void)
3754{
3755 unsigned long flags;
3756
3757 spin_lock_irqsave(&dispc.irq_lock, flags);
3758
3759 memset(dispc.registered_isr, 0, sizeof(dispc.registered_isr));
3760
3761 dispc.irq_error_mask = DISPC_IRQ_MASK_ERROR;
3762 if (dss_has_feature(FEAT_MGR_LCD2))
3763 dispc.irq_error_mask |= DISPC_IRQ_SYNC_LOST2;
3764 if (dss_has_feature(FEAT_MGR_LCD3))
3765 dispc.irq_error_mask |= DISPC_IRQ_SYNC_LOST3;
3766 if (dss_feat_get_num_ovls() > 3)
3767 dispc.irq_error_mask |= DISPC_IRQ_VID3_FIFO_UNDERFLOW;
3768
3769 /* there's SYNC_LOST_DIGIT waiting after enabling the DSS,
3770 * so clear it */
3771 dispc_clear_irqstatus(dispc_read_irqstatus());
3772
3773 _omap_dispc_set_irqs();
3774
3775 spin_unlock_irqrestore(&dispc.irq_lock, flags);
3776}
3777
3778void dispc_enable_sidle(void) 3373void dispc_enable_sidle(void)
3779{ 3374{
3780 REG_FLD_MOD(DISPC_SYSCONFIG, 2, 4, 3); /* SIDLEMODE: smart idle */ 3375 REG_FLD_MOD(DISPC_SYSCONFIG, 2, 4, 3); /* SIDLEMODE: smart idle */
@@ -3944,6 +3539,17 @@ static int __init dispc_init_features(struct platform_device *pdev)
3944 return 0; 3539 return 0;
3945} 3540}
3946 3541
3542int dispc_request_irq(irq_handler_t handler, void *dev_id)
3543{
3544 return devm_request_irq(&dispc.pdev->dev, dispc.irq, handler,
3545 IRQF_SHARED, "OMAP DISPC", dev_id);
3546}
3547
3548void dispc_free_irq(void *dev_id)
3549{
3550 devm_free_irq(&dispc.pdev->dev, dispc.irq, dev_id);
3551}
3552
3947/* DISPC HW IP initialisation */ 3553/* DISPC HW IP initialisation */
3948static int __init omap_dispchw_probe(struct platform_device *pdev) 3554static int __init omap_dispchw_probe(struct platform_device *pdev)
3949{ 3555{
@@ -3958,15 +3564,6 @@ static int __init omap_dispchw_probe(struct platform_device *pdev)
3958 if (r) 3564 if (r)
3959 return r; 3565 return r;
3960 3566
3961 spin_lock_init(&dispc.irq_lock);
3962
3963#ifdef CONFIG_OMAP2_DSS_COLLECT_IRQ_STATS
3964 spin_lock_init(&dispc.irq_stats_lock);
3965 dispc.irq_stats.last_reset = jiffies;
3966#endif
3967
3968 INIT_WORK(&dispc.error_work, dispc_error_worker);
3969
3970 dispc_mem = platform_get_resource(dispc.pdev, IORESOURCE_MEM, 0); 3567 dispc_mem = platform_get_resource(dispc.pdev, IORESOURCE_MEM, 0);
3971 if (!dispc_mem) { 3568 if (!dispc_mem) {
3972 DSSERR("can't get IORESOURCE_MEM DISPC\n"); 3569 DSSERR("can't get IORESOURCE_MEM DISPC\n");
@@ -3986,13 +3583,6 @@ static int __init omap_dispchw_probe(struct platform_device *pdev)
3986 return -ENODEV; 3583 return -ENODEV;
3987 } 3584 }
3988 3585
3989 r = devm_request_irq(&pdev->dev, dispc.irq, omap_dispc_irq_handler,
3990 IRQF_SHARED, "OMAP DISPC", dispc.pdev);
3991 if (r < 0) {
3992 DSSERR("request_irq failed\n");
3993 return r;
3994 }
3995
3996 clk = clk_get(&pdev->dev, "fck"); 3586 clk = clk_get(&pdev->dev, "fck");
3997 if (IS_ERR(clk)) { 3587 if (IS_ERR(clk)) {
3998 DSSERR("can't get fck\n"); 3588 DSSERR("can't get fck\n");
@@ -4010,8 +3600,6 @@ static int __init omap_dispchw_probe(struct platform_device *pdev)
4010 3600
4011 _omap_dispc_initial_config(); 3601 _omap_dispc_initial_config();
4012 3602
4013 _omap_dispc_initialize_irq();
4014
4015 rev = dispc_read_reg(DISPC_REVISION); 3603 rev = dispc_read_reg(DISPC_REVISION);
4016 dev_dbg(&pdev->dev, "OMAP DISPC rev %d.%d\n", 3604 dev_dbg(&pdev->dev, "OMAP DISPC rev %d.%d\n",
4017 FLD_GET(rev, 7, 4), FLD_GET(rev, 3, 0)); 3605 FLD_GET(rev, 7, 4), FLD_GET(rev, 3, 0));
@@ -4020,9 +3608,6 @@ static int __init omap_dispchw_probe(struct platform_device *pdev)
4020 3608
4021 dss_debugfs_create_file("dispc", dispc_dump_regs); 3609 dss_debugfs_create_file("dispc", dispc_dump_regs);
4022 3610
4023#ifdef CONFIG_OMAP2_DSS_COLLECT_IRQ_STATS
4024 dss_debugfs_create_file("dispc_irq", dispc_dump_irqs);
4025#endif
4026 return 0; 3611 return 0;
4027 3612
4028err_runtime_get: 3613err_runtime_get:
diff --git a/drivers/video/omap2/dss/dss.h b/drivers/video/omap2/dss/dss.h
index 9faaa63d3089..2754bcb231d6 100644
--- a/drivers/video/omap2/dss/dss.h
+++ b/drivers/video/omap2/dss/dss.h
@@ -23,6 +23,8 @@
23#ifndef __OMAP2_DSS_H 23#ifndef __OMAP2_DSS_H
24#define __OMAP2_DSS_H 24#define __OMAP2_DSS_H
25 25
26#include <linux/interrupt.h>
27
26#ifdef pr_fmt 28#ifdef pr_fmt
27#undef pr_fmt 29#undef pr_fmt
28#endif 30#endif
@@ -386,6 +388,9 @@ void dispc_clear_irqstatus(u32 mask);
386u32 dispc_read_irqenable(void); 388u32 dispc_read_irqenable(void);
387void dispc_write_irqenable(u32 mask); 389void dispc_write_irqenable(u32 mask);
388 390
391int dispc_request_irq(irq_handler_t handler, void *dev_id);
392void dispc_free_irq(void *dev_id);
393
389int dispc_runtime_get(void); 394int dispc_runtime_get(void);
390void dispc_runtime_put(void); 395void dispc_runtime_put(void);
391 396