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