1/*
2 * Copyright (C) 2011 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
26#include <video/omapdss.h>
27
28#include "dss.h"
29#include "dss_features.h"
30#include "dispc-compat.h"
31
32/*
33 * We have 4 levels of cache for the dispc settings. First two are in SW and
34 * the latter two in HW.
35 *
36 *       set_info()
37 *          v
38 * +--------------------+
39 * |     user_info      |
40 * +--------------------+
41 *          v
42 *        apply()
43 *          v
44 * +--------------------+
45 * |       info         |
46 * +--------------------+
47 *          v
48 *      write_regs()
49 *          v
50 * +--------------------+
51 * |  shadow registers  |
52 * +--------------------+
53 *          v
54 * VFP or lcd/digit_enable
55 *          v
56 * +--------------------+
57 * |      registers     |
58 * +--------------------+
59 */
60
61struct ovl_priv_data {
62
63	bool user_info_dirty;
64	struct omap_overlay_info user_info;
65
66	bool info_dirty;
67	struct omap_overlay_info info;
68
69	bool shadow_info_dirty;
70
71	bool extra_info_dirty;
72	bool shadow_extra_info_dirty;
73
74	bool enabled;
75	u32 fifo_low, fifo_high;
76
77	/*
78	 * True if overlay is to be enabled. Used to check and calculate configs
79	 * for the overlay before it is enabled in the HW.
80	 */
81	bool enabling;
82};
83
84struct mgr_priv_data {
85
86	bool user_info_dirty;
87	struct omap_overlay_manager_info user_info;
88
89	bool info_dirty;
90	struct omap_overlay_manager_info info;
91
92	bool shadow_info_dirty;
93
94	/* If true, GO bit is up and shadow registers cannot be written.
95	 * Never true for manual update displays */
96	bool busy;
97
98	/* If true, dispc output is enabled */
99	bool updating;
100
101	/* If true, a display is enabled using this manager */
102	bool enabled;
103
104	bool extra_info_dirty;
105	bool shadow_extra_info_dirty;
106
107	struct omap_video_timings timings;
108	struct dss_lcd_mgr_config lcd_config;
109
110	void (*framedone_handler)(void *);
111	void *framedone_handler_data;
112};
113
114static struct {
115	struct ovl_priv_data ovl_priv_data_array[MAX_DSS_OVERLAYS];
116	struct mgr_priv_data mgr_priv_data_array[MAX_DSS_MANAGERS];
117
118	bool irq_enabled;
119} dss_data;
120
121/* protects dss_data */
122static spinlock_t data_lock;
123/* lock for blocking functions */
124static DEFINE_MUTEX(apply_lock);
125static DECLARE_COMPLETION(extra_updated_completion);
126
127static void dss_register_vsync_isr(void);
128
129static struct ovl_priv_data *get_ovl_priv(struct omap_overlay *ovl)
130{
131	return &dss_data.ovl_priv_data_array[ovl->id];
132}
133
134static struct mgr_priv_data *get_mgr_priv(struct omap_overlay_manager *mgr)
135{
136	return &dss_data.mgr_priv_data_array[mgr->id];
137}
138
139static void apply_init_priv(void)
140{
141	const int num_ovls = dss_feat_get_num_ovls();
142	struct mgr_priv_data *mp;
143	int i;
144
145	spin_lock_init(&data_lock);
146
147	for (i = 0; i < num_ovls; ++i) {
148		struct ovl_priv_data *op;
149
150		op = &dss_data.ovl_priv_data_array[i];
151
152		op->info.color_mode = OMAP_DSS_COLOR_RGB16;
153		op->info.rotation_type = OMAP_DSS_ROT_DMA;
154
155		op->info.global_alpha = 255;
156
157		switch (i) {
158		case 0:
159			op->info.zorder = 0;
160			break;
161		case 1:
162			op->info.zorder =
163				dss_has_feature(FEAT_ALPHA_FREE_ZORDER) ? 3 : 0;
164			break;
165		case 2:
166			op->info.zorder =
167				dss_has_feature(FEAT_ALPHA_FREE_ZORDER) ? 2 : 0;
168			break;
169		case 3:
170			op->info.zorder =
171				dss_has_feature(FEAT_ALPHA_FREE_ZORDER) ? 1 : 0;
172			break;
173		}
174
175		op->user_info = op->info;
176	}
177
178	/*
179	 * Initialize some of the lcd_config fields for TV manager, this lets
180	 * us prevent checking if the manager is LCD or TV at some places
181	 */
182	mp = &dss_data.mgr_priv_data_array[OMAP_DSS_CHANNEL_DIGIT];
183
184	mp->lcd_config.video_port_width = 24;
185	mp->lcd_config.clock_info.lck_div = 1;
186	mp->lcd_config.clock_info.pck_div = 1;
187}
188
189/*
190 * A LCD manager's stallmode decides whether it is in manual or auto update. TV
191 * manager is always auto update, stallmode field for TV manager is false by
192 * default
193 */
194static bool ovl_manual_update(struct omap_overlay *ovl)
195{
196	struct mgr_priv_data *mp = get_mgr_priv(ovl->manager);
197
198	return mp->lcd_config.stallmode;
199}
200
201static bool mgr_manual_update(struct omap_overlay_manager *mgr)
202{
203	struct mgr_priv_data *mp = get_mgr_priv(mgr);
204
205	return mp->lcd_config.stallmode;
206}
207
208static int dss_check_settings_low(struct omap_overlay_manager *mgr,
209		bool applying)
210{
211	struct omap_overlay_info *oi;
212	struct omap_overlay_manager_info *mi;
213	struct omap_overlay *ovl;
214	struct omap_overlay_info *ois[MAX_DSS_OVERLAYS];
215	struct ovl_priv_data *op;
216	struct mgr_priv_data *mp;
217
218	mp = get_mgr_priv(mgr);
219
220	if (!mp->enabled)
221		return 0;
222
223	if (applying && mp->user_info_dirty)
224		mi = &mp->user_info;
225	else
226		mi = &mp->info;
227
228	/* collect the infos to be tested into the array */
229	list_for_each_entry(ovl, &mgr->overlays, list) {
230		op = get_ovl_priv(ovl);
231
232		if (!op->enabled && !op->enabling)
233			oi = NULL;
234		else if (applying && op->user_info_dirty)
235			oi = &op->user_info;
236		else
237			oi = &op->info;
238
239		ois[ovl->id] = oi;
240	}
241
242	return dss_mgr_check(mgr, mi, &mp->timings, &mp->lcd_config, ois);
243}
244
245/*
246 * check manager and overlay settings using overlay_info from data->info
247 */
248static int dss_check_settings(struct omap_overlay_manager *mgr)
249{
250	return dss_check_settings_low(mgr, false);
251}
252
253/*
254 * check manager and overlay settings using overlay_info from ovl->info if
255 * dirty and from data->info otherwise
256 */
257static int dss_check_settings_apply(struct omap_overlay_manager *mgr)
258{
259	return dss_check_settings_low(mgr, true);
260}
261
262static bool need_isr(void)
263{
264	const int num_mgrs = dss_feat_get_num_mgrs();
265	int i;
266
267	for (i = 0; i < num_mgrs; ++i) {
268		struct omap_overlay_manager *mgr;
269		struct mgr_priv_data *mp;
270		struct omap_overlay *ovl;
271
272		mgr = omap_dss_get_overlay_manager(i);
273		mp = get_mgr_priv(mgr);
274
275		if (!mp->enabled)
276			continue;
277
278		if (mgr_manual_update(mgr)) {
279			/* to catch FRAMEDONE */
280			if (mp->updating)
281				return true;
282		} else {
283			/* to catch GO bit going down */
284			if (mp->busy)
285				return true;
286
287			/* to write new values to registers */
288			if (mp->info_dirty)
289				return true;
290
291			/* to set GO bit */
292			if (mp->shadow_info_dirty)
293				return true;
294
295			/*
296			 * NOTE: we don't check extra_info flags for disabled
297			 * managers, once the manager is enabled, the extra_info
298			 * related manager changes will be taken in by HW.
299			 */
300
301			/* to write new values to registers */
302			if (mp->extra_info_dirty)
303				return true;
304
305			/* to set GO bit */
306			if (mp->shadow_extra_info_dirty)
307				return true;
308
309			list_for_each_entry(ovl, &mgr->overlays, list) {
310				struct ovl_priv_data *op;
311
312				op = get_ovl_priv(ovl);
313
314				/*
315				 * NOTE: we check extra_info flags even for
316				 * disabled overlays, as extra_infos need to be
317				 * always written.
318				 */
319
320				/* to write new values to registers */
321				if (op->extra_info_dirty)
322					return true;
323
324				/* to set GO bit */
325				if (op->shadow_extra_info_dirty)
326					return true;
327
328				if (!op->enabled)
329					continue;
330
331				/* to write new values to registers */
332				if (op->info_dirty)
333					return true;
334
335				/* to set GO bit */
336				if (op->shadow_info_dirty)
337					return true;
338			}
339		}
340	}
341
342	return false;
343}
344
345static bool need_go(struct omap_overlay_manager *mgr)
346{
347	struct omap_overlay *ovl;
348	struct mgr_priv_data *mp;
349	struct ovl_priv_data *op;
350
351	mp = get_mgr_priv(mgr);
352
353	if (mp->shadow_info_dirty || mp->shadow_extra_info_dirty)
354		return true;
355
356	list_for_each_entry(ovl, &mgr->overlays, list) {
357		op = get_ovl_priv(ovl);
358		if (op->shadow_info_dirty || op->shadow_extra_info_dirty)
359			return true;
360	}
361
362	return false;
363}
364
365/* returns true if an extra_info field is currently being updated */
366static bool extra_info_update_ongoing(void)
367{
368	const int num_mgrs = dss_feat_get_num_mgrs();
369	int i;
370
371	for (i = 0; i < num_mgrs; ++i) {
372		struct omap_overlay_manager *mgr;
373		struct omap_overlay *ovl;
374		struct mgr_priv_data *mp;
375
376		mgr = omap_dss_get_overlay_manager(i);
377		mp = get_mgr_priv(mgr);
378
379		if (!mp->enabled)
380			continue;
381
382		if (!mp->updating)
383			continue;
384
385		if (mp->extra_info_dirty || mp->shadow_extra_info_dirty)
386			return true;
387
388		list_for_each_entry(ovl, &mgr->overlays, list) {
389			struct ovl_priv_data *op = get_ovl_priv(ovl);
390
391			if (op->extra_info_dirty || op->shadow_extra_info_dirty)
392				return true;
393		}
394	}
395
396	return false;
397}
398
399/* wait until no extra_info updates are pending */
400static void wait_pending_extra_info_updates(void)
401{
402	bool updating;
403	unsigned long flags;
404	unsigned long t;
405	int r;
406
407	spin_lock_irqsave(&data_lock, flags);
408
409	updating = extra_info_update_ongoing();
410
411	if (!updating) {
412		spin_unlock_irqrestore(&data_lock, flags);
413		return;
414	}
415
416	init_completion(&extra_updated_completion);
417
418	spin_unlock_irqrestore(&data_lock, flags);
419
420	t = msecs_to_jiffies(500);
421	r = wait_for_completion_timeout(&extra_updated_completion, t);
422	if (r == 0)
423		DSSWARN("timeout in wait_pending_extra_info_updates\n");
424}
425
426static struct omap_dss_device *dss_mgr_get_device(struct omap_overlay_manager *mgr)
427{
428	struct omap_dss_device *dssdev;
429
430	dssdev = mgr->output;
431	if (dssdev == NULL)
432		return NULL;
433
434	while (dssdev->dst)
435		dssdev = dssdev->dst;
436
437	if (dssdev->driver)
438		return dssdev;
439	else
440		return NULL;
441}
442
443static struct omap_dss_device *dss_ovl_get_device(struct omap_overlay *ovl)
444{
445	return ovl->manager ? dss_mgr_get_device(ovl->manager) : NULL;
446}
447
448static int dss_mgr_wait_for_vsync(struct omap_overlay_manager *mgr)
449{
450	unsigned long timeout = msecs_to_jiffies(500);
451	u32 irq;
452	int r;
453
454	if (mgr->output == NULL)
455		return -ENODEV;
456
457	r = dispc_runtime_get();
458	if (r)
459		return r;
460
461	switch (mgr->output->id) {
462	case OMAP_DSS_OUTPUT_VENC:
463		irq = DISPC_IRQ_EVSYNC_ODD;
464		break;
465	case OMAP_DSS_OUTPUT_HDMI:
466		irq = DISPC_IRQ_EVSYNC_EVEN;
467		break;
468	default:
469		irq = dispc_mgr_get_vsync_irq(mgr->id);
470		break;
471	}
472
473	r = omap_dispc_wait_for_irq_interruptible_timeout(irq, timeout);
474
475	dispc_runtime_put();
476
477	return r;
478}
479
480static int dss_mgr_wait_for_go(struct omap_overlay_manager *mgr)
481{
482	unsigned long timeout = msecs_to_jiffies(500);
483	struct mgr_priv_data *mp = get_mgr_priv(mgr);
484	u32 irq;
485	unsigned long flags;
486	int r;
487	int i;
488
489	spin_lock_irqsave(&data_lock, flags);
490
491	if (mgr_manual_update(mgr)) {
492		spin_unlock_irqrestore(&data_lock, flags);
493		return 0;
494	}
495
496	if (!mp->enabled) {
497		spin_unlock_irqrestore(&data_lock, flags);
498		return 0;
499	}
500
501	spin_unlock_irqrestore(&data_lock, flags);
502
503	r = dispc_runtime_get();
504	if (r)
505		return r;
506
507	irq = dispc_mgr_get_vsync_irq(mgr->id);
508
509	i = 0;
510	while (1) {
511		bool shadow_dirty, dirty;
512
513		spin_lock_irqsave(&data_lock, flags);
514		dirty = mp->info_dirty;
515		shadow_dirty = mp->shadow_info_dirty;
516		spin_unlock_irqrestore(&data_lock, flags);
517
518		if (!dirty && !shadow_dirty) {
519			r = 0;
520			break;
521		}
522
523		/* 4 iterations is the worst case:
524		 * 1 - initial iteration, dirty = true (between VFP and VSYNC)
525		 * 2 - first VSYNC, dirty = true
526		 * 3 - dirty = false, shadow_dirty = true
527		 * 4 - shadow_dirty = false */
528		if (i++ == 3) {
529			DSSERR("mgr(%d)->wait_for_go() not finishing\n",
530					mgr->id);
531			r = 0;
532			break;
533		}
534
535		r = omap_dispc_wait_for_irq_interruptible_timeout(irq, timeout);
536		if (r == -ERESTARTSYS)
537			break;
538
539		if (r) {
540			DSSERR("mgr(%d)->wait_for_go() timeout\n", mgr->id);
541			break;
542		}
543	}
544
545	dispc_runtime_put();
546
547	return r;
548}
549
550static int dss_mgr_wait_for_go_ovl(struct omap_overlay *ovl)
551{
552	unsigned long timeout = msecs_to_jiffies(500);
553	struct ovl_priv_data *op;
554	struct mgr_priv_data *mp;
555	u32 irq;
556	unsigned long flags;
557	int r;
558	int i;
559
560	if (!ovl->manager)
561		return 0;
562
563	mp = get_mgr_priv(ovl->manager);
564
565	spin_lock_irqsave(&data_lock, flags);
566
567	if (ovl_manual_update(ovl)) {
568		spin_unlock_irqrestore(&data_lock, flags);
569		return 0;
570	}
571
572	if (!mp->enabled) {
573		spin_unlock_irqrestore(&data_lock, flags);
574		return 0;
575	}
576
577	spin_unlock_irqrestore(&data_lock, flags);
578
579	r = dispc_runtime_get();
580	if (r)
581		return r;
582
583	irq = dispc_mgr_get_vsync_irq(ovl->manager->id);
584
585	op = get_ovl_priv(ovl);
586	i = 0;
587	while (1) {
588		bool shadow_dirty, dirty;
589
590		spin_lock_irqsave(&data_lock, flags);
591		dirty = op->info_dirty;
592		shadow_dirty = op->shadow_info_dirty;
593		spin_unlock_irqrestore(&data_lock, flags);
594
595		if (!dirty && !shadow_dirty) {
596			r = 0;
597			break;
598		}
599
600		/* 4 iterations is the worst case:
601		 * 1 - initial iteration, dirty = true (between VFP and VSYNC)
602		 * 2 - first VSYNC, dirty = true
603		 * 3 - dirty = false, shadow_dirty = true
604		 * 4 - shadow_dirty = false */
605		if (i++ == 3) {
606			DSSERR("ovl(%d)->wait_for_go() not finishing\n",
607					ovl->id);
608			r = 0;
609			break;
610		}
611
612		r = omap_dispc_wait_for_irq_interruptible_timeout(irq, timeout);
613		if (r == -ERESTARTSYS)
614			break;
615
616		if (r) {
617			DSSERR("ovl(%d)->wait_for_go() timeout\n", ovl->id);
618			break;
619		}
620	}
621
622	dispc_runtime_put();
623
624	return r;
625}
626
627static void dss_ovl_write_regs(struct omap_overlay *ovl)
628{
629	struct ovl_priv_data *op = get_ovl_priv(ovl);
630	struct omap_overlay_info *oi;
631	bool replication;
632	struct mgr_priv_data *mp;
633	int r;
634
635	DSSDBG("writing ovl %d regs\n", ovl->id);
636
637	if (!op->enabled || !op->info_dirty)
638		return;
639
640	oi = &op->info;
641
642	mp = get_mgr_priv(ovl->manager);
643
644	replication = dss_ovl_use_replication(mp->lcd_config, oi->color_mode);
645
646	r = dispc_ovl_setup(ovl->id, oi, replication, &mp->timings, false);
647	if (r) {
648		/*
649		 * We can't do much here, as this function can be called from
650		 * vsync interrupt.
651		 */
652		DSSERR("dispc_ovl_setup failed for ovl %d\n", ovl->id);
653
654		/* This will leave fifo configurations in a nonoptimal state */
655		op->enabled = false;
656		dispc_ovl_enable(ovl->id, false);
657		return;
658	}
659
660	op->info_dirty = false;
661	if (mp->updating)
662		op->shadow_info_dirty = true;
663}
664
665static void dss_ovl_write_regs_extra(struct omap_overlay *ovl)
666{
667	struct ovl_priv_data *op = get_ovl_priv(ovl);
668	struct mgr_priv_data *mp;
669
670	DSSDBG("writing ovl %d regs extra\n", ovl->id);
671
672	if (!op->extra_info_dirty)
673		return;
674
675	/* note: write also when op->enabled == false, so that the ovl gets
676	 * disabled */
677
678	dispc_ovl_enable(ovl->id, op->enabled);
679	dispc_ovl_set_fifo_threshold(ovl->id, op->fifo_low, op->fifo_high);
680
681	mp = get_mgr_priv(ovl->manager);
682
683	op->extra_info_dirty = false;
684	if (mp->updating)
685		op->shadow_extra_info_dirty = true;
686}
687
688static void dss_mgr_write_regs(struct omap_overlay_manager *mgr)
689{
690	struct mgr_priv_data *mp = get_mgr_priv(mgr);
691	struct omap_overlay *ovl;
692
693	DSSDBG("writing mgr %d regs\n", mgr->id);
694
695	if (!mp->enabled)
696		return;
697
698	WARN_ON(mp->busy);
699
700	/* Commit overlay settings */
701	list_for_each_entry(ovl, &mgr->overlays, list) {
702		dss_ovl_write_regs(ovl);
703		dss_ovl_write_regs_extra(ovl);
704	}
705
706	if (mp->info_dirty) {
707		dispc_mgr_setup(mgr->id, &mp->info);
708
709		mp->info_dirty = false;
710		if (mp->updating)
711			mp->shadow_info_dirty = true;
712	}
713}
714
715static void dss_mgr_write_regs_extra(struct omap_overlay_manager *mgr)
716{
717	struct mgr_priv_data *mp = get_mgr_priv(mgr);
718
719	DSSDBG("writing mgr %d regs extra\n", mgr->id);
720
721	if (!mp->extra_info_dirty)
722		return;
723
724	dispc_mgr_set_timings(mgr->id, &mp->timings);
725
726	/* lcd_config parameters */
727	if (dss_mgr_is_lcd(mgr->id))
728		dispc_mgr_set_lcd_config(mgr->id, &mp->lcd_config);
729
730	mp->extra_info_dirty = false;
731	if (mp->updating)
732		mp->shadow_extra_info_dirty = true;
733}
734
735static void dss_write_regs(void)
736{
737	const int num_mgrs = omap_dss_get_num_overlay_managers();
738	int i;
739
740	for (i = 0; i < num_mgrs; ++i) {
741		struct omap_overlay_manager *mgr;
742		struct mgr_priv_data *mp;
743		int r;
744
745		mgr = omap_dss_get_overlay_manager(i);
746		mp = get_mgr_priv(mgr);
747
748		if (!mp->enabled || mgr_manual_update(mgr) || mp->busy)
749			continue;
750
751		r = dss_check_settings(mgr);
752		if (r) {
753			DSSERR("cannot write registers for manager %s: "
754					"illegal configuration\n", mgr->name);
755			continue;
756		}
757
758		dss_mgr_write_regs(mgr);
759		dss_mgr_write_regs_extra(mgr);
760	}
761}
762
763static void dss_set_go_bits(void)
764{
765	const int num_mgrs = omap_dss_get_num_overlay_managers();
766	int i;
767
768	for (i = 0; i < num_mgrs; ++i) {
769		struct omap_overlay_manager *mgr;
770		struct mgr_priv_data *mp;
771
772		mgr = omap_dss_get_overlay_manager(i);
773		mp = get_mgr_priv(mgr);
774
775		if (!mp->enabled || mgr_manual_update(mgr) || mp->busy)
776			continue;
777
778		if (!need_go(mgr))
779			continue;
780
781		mp->busy = true;
782
783		if (!dss_data.irq_enabled && need_isr())
784			dss_register_vsync_isr();
785
786		dispc_mgr_go(mgr->id);
787	}
788
789}
790
791static void mgr_clear_shadow_dirty(struct omap_overlay_manager *mgr)
792{
793	struct omap_overlay *ovl;
794	struct mgr_priv_data *mp;
795	struct ovl_priv_data *op;
796
797	mp = get_mgr_priv(mgr);
798	mp->shadow_info_dirty = false;
799	mp->shadow_extra_info_dirty = false;
800
801	list_for_each_entry(ovl, &mgr->overlays, list) {
802		op = get_ovl_priv(ovl);
803		op->shadow_info_dirty = false;
804		op->shadow_extra_info_dirty = false;
805	}
806}
807
808static int dss_mgr_connect_compat(struct omap_overlay_manager *mgr,
809		struct omap_dss_device *dst)
810{
811	return mgr->set_output(mgr, dst);
812}
813
814static void dss_mgr_disconnect_compat(struct omap_overlay_manager *mgr,
815		struct omap_dss_device *dst)
816{
817	mgr->unset_output(mgr);
818}
819
820static void dss_mgr_start_update_compat(struct omap_overlay_manager *mgr)
821{
822	struct mgr_priv_data *mp = get_mgr_priv(mgr);
823	unsigned long flags;
824	int r;
825
826	spin_lock_irqsave(&data_lock, flags);
827
828	WARN_ON(mp->updating);
829
830	r = dss_check_settings(mgr);
831	if (r) {
832		DSSERR("cannot start manual update: illegal configuration\n");
833		spin_unlock_irqrestore(&data_lock, flags);
834		return;
835	}
836
837	dss_mgr_write_regs(mgr);
838	dss_mgr_write_regs_extra(mgr);
839
840	mp->updating = true;
841
842	if (!dss_data.irq_enabled && need_isr())
843		dss_register_vsync_isr();
844
845	dispc_mgr_enable_sync(mgr->id);
846
847	spin_unlock_irqrestore(&data_lock, flags);
848}
849
850static void dss_apply_irq_handler(void *data, u32 mask);
851
852static void dss_register_vsync_isr(void)
853{
854	const int num_mgrs = dss_feat_get_num_mgrs();
855	u32 mask;
856	int r, i;
857
858	mask = 0;
859	for (i = 0; i < num_mgrs; ++i)
860		mask |= dispc_mgr_get_vsync_irq(i);
861
862	for (i = 0; i < num_mgrs; ++i)
863		mask |= dispc_mgr_get_framedone_irq(i);
864
865	r = omap_dispc_register_isr(dss_apply_irq_handler, NULL, mask);
866	WARN_ON(r);
867
868	dss_data.irq_enabled = true;
869}
870
871static void dss_unregister_vsync_isr(void)
872{
873	const int num_mgrs = dss_feat_get_num_mgrs();
874	u32 mask;
875	int r, i;
876
877	mask = 0;
878	for (i = 0; i < num_mgrs; ++i)
879		mask |= dispc_mgr_get_vsync_irq(i);
880
881	for (i = 0; i < num_mgrs; ++i)
882		mask |= dispc_mgr_get_framedone_irq(i);
883
884	r = omap_dispc_unregister_isr(dss_apply_irq_handler, NULL, mask);
885	WARN_ON(r);
886
887	dss_data.irq_enabled = false;
888}
889
890static void dss_apply_irq_handler(void *data, u32 mask)
891{
892	const int num_mgrs = dss_feat_get_num_mgrs();
893	int i;
894	bool extra_updating;
895
896	spin_lock(&data_lock);
897
898	/* clear busy, updating flags, shadow_dirty flags */
899	for (i = 0; i < num_mgrs; i++) {
900		struct omap_overlay_manager *mgr;
901		struct mgr_priv_data *mp;
902
903		mgr = omap_dss_get_overlay_manager(i);
904		mp = get_mgr_priv(mgr);
905
906		if (!mp->enabled)
907			continue;
908
909		mp->updating = dispc_mgr_is_enabled(i);
910
911		if (!mgr_manual_update(mgr)) {
912			bool was_busy = mp->busy;
913			mp->busy = dispc_mgr_go_busy(i);
914
915			if (was_busy && !mp->busy)
916				mgr_clear_shadow_dirty(mgr);
917		}
918	}
919
920	dss_write_regs();
921	dss_set_go_bits();
922
923	extra_updating = extra_info_update_ongoing();
924	if (!extra_updating)
925		complete_all(&extra_updated_completion);
926
927	/* call framedone handlers for manual update displays */
928	for (i = 0; i < num_mgrs; i++) {
929		struct omap_overlay_manager *mgr;
930		struct mgr_priv_data *mp;
931
932		mgr = omap_dss_get_overlay_manager(i);
933		mp = get_mgr_priv(mgr);
934
935		if (!mgr_manual_update(mgr) || !mp->framedone_handler)
936			continue;
937
938		if (mask & dispc_mgr_get_framedone_irq(i))
939			mp->framedone_handler(mp->framedone_handler_data);
940	}
941
942	if (!need_isr())
943		dss_unregister_vsync_isr();
944
945	spin_unlock(&data_lock);
946}
947
948static void omap_dss_mgr_apply_ovl(struct omap_overlay *ovl)
949{
950	struct ovl_priv_data *op;
951
952	op = get_ovl_priv(ovl);
953
954	if (!op->user_info_dirty)
955		return;
956
957	op->user_info_dirty = false;
958	op->info_dirty = true;
959	op->info = op->user_info;
960}
961
962static void omap_dss_mgr_apply_mgr(struct omap_overlay_manager *mgr)
963{
964	struct mgr_priv_data *mp;
965
966	mp = get_mgr_priv(mgr);
967
968	if (!mp->user_info_dirty)
969		return;
970
971	mp->user_info_dirty = false;
972	mp->info_dirty = true;
973	mp->info = mp->user_info;
974}
975
976static int omap_dss_mgr_apply(struct omap_overlay_manager *mgr)
977{
978	unsigned long flags;
979	struct omap_overlay *ovl;
980	int r;
981
982	DSSDBG("omap_dss_mgr_apply(%s)\n", mgr->name);
983
984	spin_lock_irqsave(&data_lock, flags);
985
986	r = dss_check_settings_apply(mgr);
987	if (r) {
988		spin_unlock_irqrestore(&data_lock, flags);
989		DSSERR("failed to apply settings: illegal configuration.\n");
990		return r;
991	}
992
993	/* Configure overlays */
994	list_for_each_entry(ovl, &mgr->overlays, list)
995		omap_dss_mgr_apply_ovl(ovl);
996
997	/* Configure manager */
998	omap_dss_mgr_apply_mgr(mgr);
999
1000	dss_write_regs();
1001	dss_set_go_bits();
1002
1003	spin_unlock_irqrestore(&data_lock, flags);
1004
1005	return 0;
1006}
1007
1008static void dss_apply_ovl_enable(struct omap_overlay *ovl, bool enable)
1009{
1010	struct ovl_priv_data *op;
1011
1012	op = get_ovl_priv(ovl);
1013
1014	if (op->enabled == enable)
1015		return;
1016
1017	op->enabled = enable;
1018	op->extra_info_dirty = true;
1019}
1020
1021static void dss_apply_ovl_fifo_thresholds(struct omap_overlay *ovl,
1022		u32 fifo_low, u32 fifo_high)
1023{
1024	struct ovl_priv_data *op = get_ovl_priv(ovl);
1025
1026	if (op->fifo_low == fifo_low && op->fifo_high == fifo_high)
1027		return;
1028
1029	op->fifo_low = fifo_low;
1030	op->fifo_high = fifo_high;
1031	op->extra_info_dirty = true;
1032}
1033
1034static void dss_ovl_setup_fifo(struct omap_overlay *ovl)
1035{
1036	struct ovl_priv_data *op = get_ovl_priv(ovl);
1037	u32 fifo_low, fifo_high;
1038	bool use_fifo_merge = false;
1039
1040	if (!op->enabled && !op->enabling)
1041		return;
1042
1043	dispc_ovl_compute_fifo_thresholds(ovl->id, &fifo_low, &fifo_high,
1044			use_fifo_merge, ovl_manual_update(ovl));
1045
1046	dss_apply_ovl_fifo_thresholds(ovl, fifo_low, fifo_high);
1047}
1048
1049static void dss_mgr_setup_fifos(struct omap_overlay_manager *mgr)
1050{
1051	struct omap_overlay *ovl;
1052	struct mgr_priv_data *mp;
1053
1054	mp = get_mgr_priv(mgr);
1055
1056	if (!mp->enabled)
1057		return;
1058
1059	list_for_each_entry(ovl, &mgr->overlays, list)
1060		dss_ovl_setup_fifo(ovl);
1061}
1062
1063static void dss_setup_fifos(void)
1064{
1065	const int num_mgrs = omap_dss_get_num_overlay_managers();
1066	struct omap_overlay_manager *mgr;
1067	int i;
1068
1069	for (i = 0; i < num_mgrs; ++i) {
1070		mgr = omap_dss_get_overlay_manager(i);
1071		dss_mgr_setup_fifos(mgr);
1072	}
1073}
1074
1075static int dss_mgr_enable_compat(struct omap_overlay_manager *mgr)
1076{
1077	struct mgr_priv_data *mp = get_mgr_priv(mgr);
1078	unsigned long flags;
1079	int r;
1080
1081	mutex_lock(&apply_lock);
1082
1083	if (mp->enabled)
1084		goto out;
1085
1086	spin_lock_irqsave(&data_lock, flags);
1087
1088	mp->enabled = true;
1089
1090	r = dss_check_settings(mgr);
1091	if (r) {
1092		DSSERR("failed to enable manager %d: check_settings failed\n",
1093				mgr->id);
1094		goto err;
1095	}
1096
1097	dss_setup_fifos();
1098
1099	dss_write_regs();
1100	dss_set_go_bits();
1101
1102	if (!mgr_manual_update(mgr))
1103		mp->updating = true;
1104
1105	if (!dss_data.irq_enabled && need_isr())
1106		dss_register_vsync_isr();
1107
1108	spin_unlock_irqrestore(&data_lock, flags);
1109
1110	if (!mgr_manual_update(mgr))
1111		dispc_mgr_enable_sync(mgr->id);
1112
1113out:
1114	mutex_unlock(&apply_lock);
1115
1116	return 0;
1117
1118err:
1119	mp->enabled = false;
1120	spin_unlock_irqrestore(&data_lock, flags);
1121	mutex_unlock(&apply_lock);
1122	return r;
1123}
1124
1125static void dss_mgr_disable_compat(struct omap_overlay_manager *mgr)
1126{
1127	struct mgr_priv_data *mp = get_mgr_priv(mgr);
1128	unsigned long flags;
1129
1130	mutex_lock(&apply_lock);
1131
1132	if (!mp->enabled)
1133		goto out;
1134
1135	wait_pending_extra_info_updates();
1136
1137	if (!mgr_manual_update(mgr))
1138		dispc_mgr_disable_sync(mgr->id);
1139
1140	spin_lock_irqsave(&data_lock, flags);
1141
1142	mp->updating = false;
1143	mp->enabled = false;
1144
1145	spin_unlock_irqrestore(&data_lock, flags);
1146
1147out:
1148	mutex_unlock(&apply_lock);
1149}
1150
1151static int dss_mgr_set_info(struct omap_overlay_manager *mgr,
1152		struct omap_overlay_manager_info *info)
1153{
1154	struct mgr_priv_data *mp = get_mgr_priv(mgr);
1155	unsigned long flags;
1156	int r;
1157
1158	r = dss_mgr_simple_check(mgr, info);
1159	if (r)
1160		return r;
1161
1162	spin_lock_irqsave(&data_lock, flags);
1163
1164	mp->user_info = *info;
1165	mp->user_info_dirty = true;
1166
1167	spin_unlock_irqrestore(&data_lock, flags);
1168
1169	return 0;
1170}
1171
1172static void dss_mgr_get_info(struct omap_overlay_manager *mgr,
1173		struct omap_overlay_manager_info *info)
1174{
1175	struct mgr_priv_data *mp = get_mgr_priv(mgr);
1176	unsigned long flags;
1177
1178	spin_lock_irqsave(&data_lock, flags);
1179
1180	*info = mp->user_info;
1181
1182	spin_unlock_irqrestore(&data_lock, flags);
1183}
1184
1185static int dss_mgr_set_output(struct omap_overlay_manager *mgr,
1186		struct omap_dss_device *output)
1187{
1188	int r;
1189
1190	mutex_lock(&apply_lock);
1191
1192	if (mgr->output) {
1193		DSSERR("manager %s is already connected to an output\n",
1194			mgr->name);
1195		r = -EINVAL;
1196		goto err;
1197	}
1198
1199	if ((mgr->supported_outputs & output->id) == 0) {
1200		DSSERR("output does not support manager %s\n",
1201			mgr->name);
1202		r = -EINVAL;
1203		goto err;
1204	}
1205
1206	output->manager = mgr;
1207	mgr->output = output;
1208
1209	mutex_unlock(&apply_lock);
1210
1211	return 0;
1212err:
1213	mutex_unlock(&apply_lock);
1214	return r;
1215}
1216
1217static int dss_mgr_unset_output(struct omap_overlay_manager *mgr)
1218{
1219	int r;
1220	struct mgr_priv_data *mp = get_mgr_priv(mgr);
1221	unsigned long flags;
1222
1223	mutex_lock(&apply_lock);
1224
1225	if (!mgr->output) {
1226		DSSERR("failed to unset output, output not set\n");
1227		r = -EINVAL;
1228		goto err;
1229	}
1230
1231	spin_lock_irqsave(&data_lock, flags);
1232
1233	if (mp->enabled) {
1234		DSSERR("output can't be unset when manager is enabled\n");
1235		r = -EINVAL;
1236		goto err1;
1237	}
1238
1239	spin_unlock_irqrestore(&data_lock, flags);
1240
1241	mgr->output->manager = NULL;
1242	mgr->output = NULL;
1243
1244	mutex_unlock(&apply_lock);
1245
1246	return 0;
1247err1:
1248	spin_unlock_irqrestore(&data_lock, flags);
1249err:
1250	mutex_unlock(&apply_lock);
1251
1252	return r;
1253}
1254
1255static void dss_apply_mgr_timings(struct omap_overlay_manager *mgr,
1256		const struct omap_video_timings *timings)
1257{
1258	struct mgr_priv_data *mp = get_mgr_priv(mgr);
1259
1260	mp->timings = *timings;
1261	mp->extra_info_dirty = true;
1262}
1263
1264static void dss_mgr_set_timings_compat(struct omap_overlay_manager *mgr,
1265		const struct omap_video_timings *timings)
1266{
1267	unsigned long flags;
1268	struct mgr_priv_data *mp = get_mgr_priv(mgr);
1269
1270	spin_lock_irqsave(&data_lock, flags);
1271
1272	if (mp->updating) {
1273		DSSERR("cannot set timings for %s: manager needs to be disabled\n",
1274			mgr->name);
1275		goto out;
1276	}
1277
1278	dss_apply_mgr_timings(mgr, timings);
1279out:
1280	spin_unlock_irqrestore(&data_lock, flags);
1281}
1282
1283static void dss_apply_mgr_lcd_config(struct omap_overlay_manager *mgr,
1284		const struct dss_lcd_mgr_config *config)
1285{
1286	struct mgr_priv_data *mp = get_mgr_priv(mgr);
1287
1288	mp->lcd_config = *config;
1289	mp->extra_info_dirty = true;
1290}
1291
1292static void dss_mgr_set_lcd_config_compat(struct omap_overlay_manager *mgr,
1293		const struct dss_lcd_mgr_config *config)
1294{
1295	unsigned long flags;
1296	struct mgr_priv_data *mp = get_mgr_priv(mgr);
1297
1298	spin_lock_irqsave(&data_lock, flags);
1299
1300	if (mp->enabled) {
1301		DSSERR("cannot apply lcd config for %s: manager needs to be disabled\n",
1302			mgr->name);
1303		goto out;
1304	}
1305
1306	dss_apply_mgr_lcd_config(mgr, config);
1307out:
1308	spin_unlock_irqrestore(&data_lock, flags);
1309}
1310
1311static int dss_ovl_set_info(struct omap_overlay *ovl,
1312		struct omap_overlay_info *info)
1313{
1314	struct ovl_priv_data *op = get_ovl_priv(ovl);
1315	unsigned long flags;
1316	int r;
1317
1318	r = dss_ovl_simple_check(ovl, info);
1319	if (r)
1320		return r;
1321
1322	spin_lock_irqsave(&data_lock, flags);
1323
1324	op->user_info = *info;
1325	op->user_info_dirty = true;
1326
1327	spin_unlock_irqrestore(&data_lock, flags);
1328
1329	return 0;
1330}
1331
1332static void dss_ovl_get_info(struct omap_overlay *ovl,
1333		struct omap_overlay_info *info)
1334{
1335	struct ovl_priv_data *op = get_ovl_priv(ovl);
1336	unsigned long flags;
1337
1338	spin_lock_irqsave(&data_lock, flags);
1339
1340	*info = op->user_info;
1341
1342	spin_unlock_irqrestore(&data_lock, flags);
1343}
1344
1345static int dss_ovl_set_manager(struct omap_overlay *ovl,
1346		struct omap_overlay_manager *mgr)
1347{
1348	struct ovl_priv_data *op = get_ovl_priv(ovl);
1349	unsigned long flags;
1350	int r;
1351
1352	if (!mgr)
1353		return -EINVAL;
1354
1355	mutex_lock(&apply_lock);
1356
1357	if (ovl->manager) {
1358		DSSERR("overlay '%s' already has a manager '%s'\n",
1359				ovl->name, ovl->manager->name);
1360		r = -EINVAL;
1361		goto err;
1362	}
1363
1364	r = dispc_runtime_get();
1365	if (r)
1366		goto err;
1367
1368	spin_lock_irqsave(&data_lock, flags);
1369
1370	if (op->enabled) {
1371		spin_unlock_irqrestore(&data_lock, flags);
1372		DSSERR("overlay has to be disabled to change the manager\n");
1373		r = -EINVAL;
1374		goto err1;
1375	}
1376
1377	dispc_ovl_set_channel_out(ovl->id, mgr->id);
1378
1379	ovl->manager = mgr;
1380	list_add_tail(&ovl->list, &mgr->overlays);
1381
1382	spin_unlock_irqrestore(&data_lock, flags);
1383
1384	dispc_runtime_put();
1385
1386	mutex_unlock(&apply_lock);
1387
1388	return 0;
1389
1390err1:
1391	dispc_runtime_put();
1392err:
1393	mutex_unlock(&apply_lock);
1394	return r;
1395}
1396
1397static int dss_ovl_unset_manager(struct omap_overlay *ovl)
1398{
1399	struct ovl_priv_data *op = get_ovl_priv(ovl);
1400	unsigned long flags;
1401	int r;
1402
1403	mutex_lock(&apply_lock);
1404
1405	if (!ovl->manager) {
1406		DSSERR("failed to detach overlay: manager not set\n");
1407		r = -EINVAL;
1408		goto err;
1409	}
1410
1411	spin_lock_irqsave(&data_lock, flags);
1412
1413	if (op->enabled) {
1414		spin_unlock_irqrestore(&data_lock, flags);
1415		DSSERR("overlay has to be disabled to unset the manager\n");
1416		r = -EINVAL;
1417		goto err;
1418	}
1419
1420	spin_unlock_irqrestore(&data_lock, flags);
1421
1422	/* wait for pending extra_info updates to ensure the ovl is disabled */
1423	wait_pending_extra_info_updates();
1424
1425	/*
1426	 * For a manual update display, there is no guarantee that the overlay
1427	 * is really disabled in HW, we may need an extra update from this
1428	 * manager before the configurations can go in. Return an error if the
1429	 * overlay needed an update from the manager.
1430	 *
1431	 * TODO: Instead of returning an error, try to do a dummy manager update
1432	 * here to disable the overlay in hardware. Use the *GATED fields in
1433	 * the DISPC_CONFIG registers to do a dummy update.
1434	 */
1435	spin_lock_irqsave(&data_lock, flags);
1436
1437	if (ovl_manual_update(ovl) && op->extra_info_dirty) {
1438		spin_unlock_irqrestore(&data_lock, flags);
1439		DSSERR("need an update to change the manager\n");
1440		r = -EINVAL;
1441		goto err;
1442	}
1443
1444	ovl->manager = NULL;
1445	list_del(&ovl->list);
1446
1447	spin_unlock_irqrestore(&data_lock, flags);
1448
1449	mutex_unlock(&apply_lock);
1450
1451	return 0;
1452err:
1453	mutex_unlock(&apply_lock);
1454	return r;
1455}
1456
1457static bool dss_ovl_is_enabled(struct omap_overlay *ovl)
1458{
1459	struct ovl_priv_data *op = get_ovl_priv(ovl);
1460	unsigned long flags;
1461	bool e;
1462
1463	spin_lock_irqsave(&data_lock, flags);
1464
1465	e = op->enabled;
1466
1467	spin_unlock_irqrestore(&data_lock, flags);
1468
1469	return e;
1470}
1471
1472static int dss_ovl_enable(struct omap_overlay *ovl)
1473{
1474	struct ovl_priv_data *op = get_ovl_priv(ovl);
1475	unsigned long flags;
1476	int r;
1477
1478	mutex_lock(&apply_lock);
1479
1480	if (op->enabled) {
1481		r = 0;
1482		goto err1;
1483	}
1484
1485	if (ovl->manager == NULL || ovl->manager->output == NULL) {
1486		r = -EINVAL;
1487		goto err1;
1488	}
1489
1490	spin_lock_irqsave(&data_lock, flags);
1491
1492	op->enabling = true;
1493
1494	r = dss_check_settings(ovl->manager);
1495	if (r) {
1496		DSSERR("failed to enable overlay %d: check_settings failed\n",
1497				ovl->id);
1498		goto err2;
1499	}
1500
1501	dss_setup_fifos();
1502
1503	op->enabling = false;
1504	dss_apply_ovl_enable(ovl, true);
1505
1506	dss_write_regs();
1507	dss_set_go_bits();
1508
1509	spin_unlock_irqrestore(&data_lock, flags);
1510
1511	mutex_unlock(&apply_lock);
1512
1513	return 0;
1514err2:
1515	op->enabling = false;
1516	spin_unlock_irqrestore(&data_lock, flags);
1517err1:
1518	mutex_unlock(&apply_lock);
1519	return r;
1520}
1521
1522static int dss_ovl_disable(struct omap_overlay *ovl)
1523{
1524	struct ovl_priv_data *op = get_ovl_priv(ovl);
1525	unsigned long flags;
1526	int r;
1527
1528	mutex_lock(&apply_lock);
1529
1530	if (!op->enabled) {
1531		r = 0;
1532		goto err;
1533	}
1534
1535	if (ovl->manager == NULL || ovl->manager->output == NULL) {
1536		r = -EINVAL;
1537		goto err;
1538	}
1539
1540	spin_lock_irqsave(&data_lock, flags);
1541
1542	dss_apply_ovl_enable(ovl, false);
1543	dss_write_regs();
1544	dss_set_go_bits();
1545
1546	spin_unlock_irqrestore(&data_lock, flags);
1547
1548	mutex_unlock(&apply_lock);
1549
1550	return 0;
1551
1552err:
1553	mutex_unlock(&apply_lock);
1554	return r;
1555}
1556
1557static int dss_mgr_register_framedone_handler_compat(struct omap_overlay_manager *mgr,
1558		void (*handler)(void *), void *data)
1559{
1560	struct mgr_priv_data *mp = get_mgr_priv(mgr);
1561
1562	if (mp->framedone_handler)
1563		return -EBUSY;
1564
1565	mp->framedone_handler = handler;
1566	mp->framedone_handler_data = data;
1567
1568	return 0;
1569}
1570
1571static void dss_mgr_unregister_framedone_handler_compat(struct omap_overlay_manager *mgr,
1572		void (*handler)(void *), void *data)
1573{
1574	struct mgr_priv_data *mp = get_mgr_priv(mgr);
1575
1576	WARN_ON(mp->framedone_handler != handler ||
1577			mp->framedone_handler_data != data);
1578
1579	mp->framedone_handler = NULL;
1580	mp->framedone_handler_data = NULL;
1581}
1582
1583static const struct dss_mgr_ops apply_mgr_ops = {
1584	.connect = dss_mgr_connect_compat,
1585	.disconnect = dss_mgr_disconnect_compat,
1586	.start_update = dss_mgr_start_update_compat,
1587	.enable = dss_mgr_enable_compat,
1588	.disable = dss_mgr_disable_compat,
1589	.set_timings = dss_mgr_set_timings_compat,
1590	.set_lcd_config = dss_mgr_set_lcd_config_compat,
1591	.register_framedone_handler = dss_mgr_register_framedone_handler_compat,
1592	.unregister_framedone_handler = dss_mgr_unregister_framedone_handler_compat,
1593};
1594
1595static int compat_refcnt;
1596static DEFINE_MUTEX(compat_init_lock);
1597
1598int omapdss_compat_init(void)
1599{
1600	struct platform_device *pdev = dss_get_core_pdev();
1601	int i, r;
1602
1603	mutex_lock(&compat_init_lock);
1604
1605	if (compat_refcnt++ > 0)
1606		goto out;
1607
1608	apply_init_priv();
1609
1610	dss_init_overlay_managers_sysfs(pdev);
1611	dss_init_overlays(pdev);
1612
1613	for (i = 0; i < omap_dss_get_num_overlay_managers(); i++) {
1614		struct omap_overlay_manager *mgr;
1615
1616		mgr = omap_dss_get_overlay_manager(i);
1617
1618		mgr->set_output = &dss_mgr_set_output;
1619		mgr->unset_output = &dss_mgr_unset_output;
1620		mgr->apply = &omap_dss_mgr_apply;
1621		mgr->set_manager_info = &dss_mgr_set_info;
1622		mgr->get_manager_info = &dss_mgr_get_info;
1623		mgr->wait_for_go = &dss_mgr_wait_for_go;
1624		mgr->wait_for_vsync = &dss_mgr_wait_for_vsync;
1625		mgr->get_device = &dss_mgr_get_device;
1626	}
1627
1628	for (i = 0; i < omap_dss_get_num_overlays(); i++) {
1629		struct omap_overlay *ovl = omap_dss_get_overlay(i);
1630
1631		ovl->is_enabled = &dss_ovl_is_enabled;
1632		ovl->enable = &dss_ovl_enable;
1633		ovl->disable = &dss_ovl_disable;
1634		ovl->set_manager = &dss_ovl_set_manager;
1635		ovl->unset_manager = &dss_ovl_unset_manager;
1636		ovl->set_overlay_info = &dss_ovl_set_info;
1637		ovl->get_overlay_info = &dss_ovl_get_info;
1638		ovl->wait_for_go = &dss_mgr_wait_for_go_ovl;
1639		ovl->get_device = &dss_ovl_get_device;
1640	}
1641
1642	r = dss_install_mgr_ops(&apply_mgr_ops);
1643	if (r)
1644		goto err_mgr_ops;
1645
1646	r = display_init_sysfs(pdev);
1647	if (r)
1648		goto err_disp_sysfs;
1649
1650	dispc_runtime_get();
1651
1652	r = dss_dispc_initialize_irq();
1653	if (r)
1654		goto err_init_irq;
1655
1656	dispc_runtime_put();
1657
1658out:
1659	mutex_unlock(&compat_init_lock);
1660
1661	return 0;
1662
1663err_init_irq:
1664	dispc_runtime_put();
1665	display_uninit_sysfs(pdev);
1666
1667err_disp_sysfs:
1668	dss_uninstall_mgr_ops();
1669
1670err_mgr_ops:
1671	dss_uninit_overlay_managers_sysfs(pdev);
1672	dss_uninit_overlays(pdev);
1673
1674	compat_refcnt--;
1675
1676	mutex_unlock(&compat_init_lock);
1677
1678	return r;
1679}
1680EXPORT_SYMBOL(omapdss_compat_init);
1681
1682void omapdss_compat_uninit(void)
1683{
1684	struct platform_device *pdev = dss_get_core_pdev();
1685
1686	mutex_lock(&compat_init_lock);
1687
1688	if (--compat_refcnt > 0)
1689		goto out;
1690
1691	dss_dispc_uninitialize_irq();
1692
1693	display_uninit_sysfs(pdev);
1694
1695	dss_uninstall_mgr_ops();
1696
1697	dss_uninit_overlay_managers_sysfs(pdev);
1698	dss_uninit_overlays(pdev);
1699out:
1700	mutex_unlock(&compat_init_lock);
1701}
1702EXPORT_SYMBOL(omapdss_compat_uninit);
1703