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