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