162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Copyright (C) 2011 Texas Instruments
462306a36Sopenharmony_ci * Author: Tomi Valkeinen <tomi.valkeinen@ti.com>
562306a36Sopenharmony_ci */
662306a36Sopenharmony_ci
762306a36Sopenharmony_ci#define DSS_SUBSYS_NAME "APPLY"
862306a36Sopenharmony_ci
962306a36Sopenharmony_ci#include <linux/kernel.h>
1062306a36Sopenharmony_ci#include <linux/module.h>
1162306a36Sopenharmony_ci#include <linux/slab.h>
1262306a36Sopenharmony_ci#include <linux/spinlock.h>
1362306a36Sopenharmony_ci#include <linux/jiffies.h>
1462306a36Sopenharmony_ci
1562306a36Sopenharmony_ci#include <video/omapfb_dss.h>
1662306a36Sopenharmony_ci
1762306a36Sopenharmony_ci#include "dss.h"
1862306a36Sopenharmony_ci#include "dss_features.h"
1962306a36Sopenharmony_ci#include "dispc-compat.h"
2062306a36Sopenharmony_ci
2162306a36Sopenharmony_ci/*
2262306a36Sopenharmony_ci * We have 4 levels of cache for the dispc settings. First two are in SW and
2362306a36Sopenharmony_ci * the latter two in HW.
2462306a36Sopenharmony_ci *
2562306a36Sopenharmony_ci *       set_info()
2662306a36Sopenharmony_ci *          v
2762306a36Sopenharmony_ci * +--------------------+
2862306a36Sopenharmony_ci * |     user_info      |
2962306a36Sopenharmony_ci * +--------------------+
3062306a36Sopenharmony_ci *          v
3162306a36Sopenharmony_ci *        apply()
3262306a36Sopenharmony_ci *          v
3362306a36Sopenharmony_ci * +--------------------+
3462306a36Sopenharmony_ci * |       info         |
3562306a36Sopenharmony_ci * +--------------------+
3662306a36Sopenharmony_ci *          v
3762306a36Sopenharmony_ci *      write_regs()
3862306a36Sopenharmony_ci *          v
3962306a36Sopenharmony_ci * +--------------------+
4062306a36Sopenharmony_ci * |  shadow registers  |
4162306a36Sopenharmony_ci * +--------------------+
4262306a36Sopenharmony_ci *          v
4362306a36Sopenharmony_ci * VFP or lcd/digit_enable
4462306a36Sopenharmony_ci *          v
4562306a36Sopenharmony_ci * +--------------------+
4662306a36Sopenharmony_ci * |      registers     |
4762306a36Sopenharmony_ci * +--------------------+
4862306a36Sopenharmony_ci */
4962306a36Sopenharmony_ci
5062306a36Sopenharmony_cistruct ovl_priv_data {
5162306a36Sopenharmony_ci
5262306a36Sopenharmony_ci	bool user_info_dirty;
5362306a36Sopenharmony_ci	struct omap_overlay_info user_info;
5462306a36Sopenharmony_ci
5562306a36Sopenharmony_ci	bool info_dirty;
5662306a36Sopenharmony_ci	struct omap_overlay_info info;
5762306a36Sopenharmony_ci
5862306a36Sopenharmony_ci	bool shadow_info_dirty;
5962306a36Sopenharmony_ci
6062306a36Sopenharmony_ci	bool extra_info_dirty;
6162306a36Sopenharmony_ci	bool shadow_extra_info_dirty;
6262306a36Sopenharmony_ci
6362306a36Sopenharmony_ci	bool enabled;
6462306a36Sopenharmony_ci	u32 fifo_low, fifo_high;
6562306a36Sopenharmony_ci
6662306a36Sopenharmony_ci	/*
6762306a36Sopenharmony_ci	 * True if overlay is to be enabled. Used to check and calculate configs
6862306a36Sopenharmony_ci	 * for the overlay before it is enabled in the HW.
6962306a36Sopenharmony_ci	 */
7062306a36Sopenharmony_ci	bool enabling;
7162306a36Sopenharmony_ci};
7262306a36Sopenharmony_ci
7362306a36Sopenharmony_cistruct mgr_priv_data {
7462306a36Sopenharmony_ci
7562306a36Sopenharmony_ci	bool user_info_dirty;
7662306a36Sopenharmony_ci	struct omap_overlay_manager_info user_info;
7762306a36Sopenharmony_ci
7862306a36Sopenharmony_ci	bool info_dirty;
7962306a36Sopenharmony_ci	struct omap_overlay_manager_info info;
8062306a36Sopenharmony_ci
8162306a36Sopenharmony_ci	bool shadow_info_dirty;
8262306a36Sopenharmony_ci
8362306a36Sopenharmony_ci	/* If true, GO bit is up and shadow registers cannot be written.
8462306a36Sopenharmony_ci	 * Never true for manual update displays */
8562306a36Sopenharmony_ci	bool busy;
8662306a36Sopenharmony_ci
8762306a36Sopenharmony_ci	/* If true, dispc output is enabled */
8862306a36Sopenharmony_ci	bool updating;
8962306a36Sopenharmony_ci
9062306a36Sopenharmony_ci	/* If true, a display is enabled using this manager */
9162306a36Sopenharmony_ci	bool enabled;
9262306a36Sopenharmony_ci
9362306a36Sopenharmony_ci	bool extra_info_dirty;
9462306a36Sopenharmony_ci	bool shadow_extra_info_dirty;
9562306a36Sopenharmony_ci
9662306a36Sopenharmony_ci	struct omap_video_timings timings;
9762306a36Sopenharmony_ci	struct dss_lcd_mgr_config lcd_config;
9862306a36Sopenharmony_ci
9962306a36Sopenharmony_ci	void (*framedone_handler)(void *);
10062306a36Sopenharmony_ci	void *framedone_handler_data;
10162306a36Sopenharmony_ci};
10262306a36Sopenharmony_ci
10362306a36Sopenharmony_cistatic struct {
10462306a36Sopenharmony_ci	struct ovl_priv_data ovl_priv_data_array[MAX_DSS_OVERLAYS];
10562306a36Sopenharmony_ci	struct mgr_priv_data mgr_priv_data_array[MAX_DSS_MANAGERS];
10662306a36Sopenharmony_ci
10762306a36Sopenharmony_ci	bool irq_enabled;
10862306a36Sopenharmony_ci} dss_data;
10962306a36Sopenharmony_ci
11062306a36Sopenharmony_ci/* protects dss_data */
11162306a36Sopenharmony_cistatic DEFINE_SPINLOCK(data_lock);
11262306a36Sopenharmony_ci/* lock for blocking functions */
11362306a36Sopenharmony_cistatic DEFINE_MUTEX(apply_lock);
11462306a36Sopenharmony_cistatic DECLARE_COMPLETION(extra_updated_completion);
11562306a36Sopenharmony_ci
11662306a36Sopenharmony_cistatic void dss_register_vsync_isr(void);
11762306a36Sopenharmony_ci
11862306a36Sopenharmony_cistatic struct ovl_priv_data *get_ovl_priv(struct omap_overlay *ovl)
11962306a36Sopenharmony_ci{
12062306a36Sopenharmony_ci	return &dss_data.ovl_priv_data_array[ovl->id];
12162306a36Sopenharmony_ci}
12262306a36Sopenharmony_ci
12362306a36Sopenharmony_cistatic struct mgr_priv_data *get_mgr_priv(struct omap_overlay_manager *mgr)
12462306a36Sopenharmony_ci{
12562306a36Sopenharmony_ci	return &dss_data.mgr_priv_data_array[mgr->id];
12662306a36Sopenharmony_ci}
12762306a36Sopenharmony_ci
12862306a36Sopenharmony_cistatic void apply_init_priv(void)
12962306a36Sopenharmony_ci{
13062306a36Sopenharmony_ci	const int num_ovls = dss_feat_get_num_ovls();
13162306a36Sopenharmony_ci	struct mgr_priv_data *mp;
13262306a36Sopenharmony_ci	int i;
13362306a36Sopenharmony_ci
13462306a36Sopenharmony_ci	for (i = 0; i < num_ovls; ++i) {
13562306a36Sopenharmony_ci		struct ovl_priv_data *op;
13662306a36Sopenharmony_ci
13762306a36Sopenharmony_ci		op = &dss_data.ovl_priv_data_array[i];
13862306a36Sopenharmony_ci
13962306a36Sopenharmony_ci		op->info.color_mode = OMAP_DSS_COLOR_RGB16;
14062306a36Sopenharmony_ci		op->info.rotation_type = OMAP_DSS_ROT_DMA;
14162306a36Sopenharmony_ci
14262306a36Sopenharmony_ci		op->info.global_alpha = 255;
14362306a36Sopenharmony_ci
14462306a36Sopenharmony_ci		switch (i) {
14562306a36Sopenharmony_ci		case 0:
14662306a36Sopenharmony_ci			op->info.zorder = 0;
14762306a36Sopenharmony_ci			break;
14862306a36Sopenharmony_ci		case 1:
14962306a36Sopenharmony_ci			op->info.zorder =
15062306a36Sopenharmony_ci				dss_has_feature(FEAT_ALPHA_FREE_ZORDER) ? 3 : 0;
15162306a36Sopenharmony_ci			break;
15262306a36Sopenharmony_ci		case 2:
15362306a36Sopenharmony_ci			op->info.zorder =
15462306a36Sopenharmony_ci				dss_has_feature(FEAT_ALPHA_FREE_ZORDER) ? 2 : 0;
15562306a36Sopenharmony_ci			break;
15662306a36Sopenharmony_ci		case 3:
15762306a36Sopenharmony_ci			op->info.zorder =
15862306a36Sopenharmony_ci				dss_has_feature(FEAT_ALPHA_FREE_ZORDER) ? 1 : 0;
15962306a36Sopenharmony_ci			break;
16062306a36Sopenharmony_ci		}
16162306a36Sopenharmony_ci
16262306a36Sopenharmony_ci		op->user_info = op->info;
16362306a36Sopenharmony_ci	}
16462306a36Sopenharmony_ci
16562306a36Sopenharmony_ci	/*
16662306a36Sopenharmony_ci	 * Initialize some of the lcd_config fields for TV manager, this lets
16762306a36Sopenharmony_ci	 * us prevent checking if the manager is LCD or TV at some places
16862306a36Sopenharmony_ci	 */
16962306a36Sopenharmony_ci	mp = &dss_data.mgr_priv_data_array[OMAP_DSS_CHANNEL_DIGIT];
17062306a36Sopenharmony_ci
17162306a36Sopenharmony_ci	mp->lcd_config.video_port_width = 24;
17262306a36Sopenharmony_ci	mp->lcd_config.clock_info.lck_div = 1;
17362306a36Sopenharmony_ci	mp->lcd_config.clock_info.pck_div = 1;
17462306a36Sopenharmony_ci}
17562306a36Sopenharmony_ci
17662306a36Sopenharmony_ci/*
17762306a36Sopenharmony_ci * A LCD manager's stallmode decides whether it is in manual or auto update. TV
17862306a36Sopenharmony_ci * manager is always auto update, stallmode field for TV manager is false by
17962306a36Sopenharmony_ci * default
18062306a36Sopenharmony_ci */
18162306a36Sopenharmony_cistatic bool ovl_manual_update(struct omap_overlay *ovl)
18262306a36Sopenharmony_ci{
18362306a36Sopenharmony_ci	struct mgr_priv_data *mp = get_mgr_priv(ovl->manager);
18462306a36Sopenharmony_ci
18562306a36Sopenharmony_ci	return mp->lcd_config.stallmode;
18662306a36Sopenharmony_ci}
18762306a36Sopenharmony_ci
18862306a36Sopenharmony_cistatic bool mgr_manual_update(struct omap_overlay_manager *mgr)
18962306a36Sopenharmony_ci{
19062306a36Sopenharmony_ci	struct mgr_priv_data *mp = get_mgr_priv(mgr);
19162306a36Sopenharmony_ci
19262306a36Sopenharmony_ci	return mp->lcd_config.stallmode;
19362306a36Sopenharmony_ci}
19462306a36Sopenharmony_ci
19562306a36Sopenharmony_cistatic int dss_check_settings_low(struct omap_overlay_manager *mgr,
19662306a36Sopenharmony_ci		bool applying)
19762306a36Sopenharmony_ci{
19862306a36Sopenharmony_ci	struct omap_overlay_info *oi;
19962306a36Sopenharmony_ci	struct omap_overlay_manager_info *mi;
20062306a36Sopenharmony_ci	struct omap_overlay *ovl;
20162306a36Sopenharmony_ci	struct omap_overlay_info *ois[MAX_DSS_OVERLAYS];
20262306a36Sopenharmony_ci	struct ovl_priv_data *op;
20362306a36Sopenharmony_ci	struct mgr_priv_data *mp;
20462306a36Sopenharmony_ci
20562306a36Sopenharmony_ci	mp = get_mgr_priv(mgr);
20662306a36Sopenharmony_ci
20762306a36Sopenharmony_ci	if (!mp->enabled)
20862306a36Sopenharmony_ci		return 0;
20962306a36Sopenharmony_ci
21062306a36Sopenharmony_ci	if (applying && mp->user_info_dirty)
21162306a36Sopenharmony_ci		mi = &mp->user_info;
21262306a36Sopenharmony_ci	else
21362306a36Sopenharmony_ci		mi = &mp->info;
21462306a36Sopenharmony_ci
21562306a36Sopenharmony_ci	/* collect the infos to be tested into the array */
21662306a36Sopenharmony_ci	list_for_each_entry(ovl, &mgr->overlays, list) {
21762306a36Sopenharmony_ci		op = get_ovl_priv(ovl);
21862306a36Sopenharmony_ci
21962306a36Sopenharmony_ci		if (!op->enabled && !op->enabling)
22062306a36Sopenharmony_ci			oi = NULL;
22162306a36Sopenharmony_ci		else if (applying && op->user_info_dirty)
22262306a36Sopenharmony_ci			oi = &op->user_info;
22362306a36Sopenharmony_ci		else
22462306a36Sopenharmony_ci			oi = &op->info;
22562306a36Sopenharmony_ci
22662306a36Sopenharmony_ci		ois[ovl->id] = oi;
22762306a36Sopenharmony_ci	}
22862306a36Sopenharmony_ci
22962306a36Sopenharmony_ci	return dss_mgr_check(mgr, mi, &mp->timings, &mp->lcd_config, ois);
23062306a36Sopenharmony_ci}
23162306a36Sopenharmony_ci
23262306a36Sopenharmony_ci/*
23362306a36Sopenharmony_ci * check manager and overlay settings using overlay_info from data->info
23462306a36Sopenharmony_ci */
23562306a36Sopenharmony_cistatic int dss_check_settings(struct omap_overlay_manager *mgr)
23662306a36Sopenharmony_ci{
23762306a36Sopenharmony_ci	return dss_check_settings_low(mgr, false);
23862306a36Sopenharmony_ci}
23962306a36Sopenharmony_ci
24062306a36Sopenharmony_ci/*
24162306a36Sopenharmony_ci * check manager and overlay settings using overlay_info from ovl->info if
24262306a36Sopenharmony_ci * dirty and from data->info otherwise
24362306a36Sopenharmony_ci */
24462306a36Sopenharmony_cistatic int dss_check_settings_apply(struct omap_overlay_manager *mgr)
24562306a36Sopenharmony_ci{
24662306a36Sopenharmony_ci	return dss_check_settings_low(mgr, true);
24762306a36Sopenharmony_ci}
24862306a36Sopenharmony_ci
24962306a36Sopenharmony_cistatic bool need_isr(void)
25062306a36Sopenharmony_ci{
25162306a36Sopenharmony_ci	const int num_mgrs = dss_feat_get_num_mgrs();
25262306a36Sopenharmony_ci	int i;
25362306a36Sopenharmony_ci
25462306a36Sopenharmony_ci	for (i = 0; i < num_mgrs; ++i) {
25562306a36Sopenharmony_ci		struct omap_overlay_manager *mgr;
25662306a36Sopenharmony_ci		struct mgr_priv_data *mp;
25762306a36Sopenharmony_ci		struct omap_overlay *ovl;
25862306a36Sopenharmony_ci
25962306a36Sopenharmony_ci		mgr = omap_dss_get_overlay_manager(i);
26062306a36Sopenharmony_ci		mp = get_mgr_priv(mgr);
26162306a36Sopenharmony_ci
26262306a36Sopenharmony_ci		if (!mp->enabled)
26362306a36Sopenharmony_ci			continue;
26462306a36Sopenharmony_ci
26562306a36Sopenharmony_ci		if (mgr_manual_update(mgr)) {
26662306a36Sopenharmony_ci			/* to catch FRAMEDONE */
26762306a36Sopenharmony_ci			if (mp->updating)
26862306a36Sopenharmony_ci				return true;
26962306a36Sopenharmony_ci		} else {
27062306a36Sopenharmony_ci			/* to catch GO bit going down */
27162306a36Sopenharmony_ci			if (mp->busy)
27262306a36Sopenharmony_ci				return true;
27362306a36Sopenharmony_ci
27462306a36Sopenharmony_ci			/* to write new values to registers */
27562306a36Sopenharmony_ci			if (mp->info_dirty)
27662306a36Sopenharmony_ci				return true;
27762306a36Sopenharmony_ci
27862306a36Sopenharmony_ci			/* to set GO bit */
27962306a36Sopenharmony_ci			if (mp->shadow_info_dirty)
28062306a36Sopenharmony_ci				return true;
28162306a36Sopenharmony_ci
28262306a36Sopenharmony_ci			/*
28362306a36Sopenharmony_ci			 * NOTE: we don't check extra_info flags for disabled
28462306a36Sopenharmony_ci			 * managers, once the manager is enabled, the extra_info
28562306a36Sopenharmony_ci			 * related manager changes will be taken in by HW.
28662306a36Sopenharmony_ci			 */
28762306a36Sopenharmony_ci
28862306a36Sopenharmony_ci			/* to write new values to registers */
28962306a36Sopenharmony_ci			if (mp->extra_info_dirty)
29062306a36Sopenharmony_ci				return true;
29162306a36Sopenharmony_ci
29262306a36Sopenharmony_ci			/* to set GO bit */
29362306a36Sopenharmony_ci			if (mp->shadow_extra_info_dirty)
29462306a36Sopenharmony_ci				return true;
29562306a36Sopenharmony_ci
29662306a36Sopenharmony_ci			list_for_each_entry(ovl, &mgr->overlays, list) {
29762306a36Sopenharmony_ci				struct ovl_priv_data *op;
29862306a36Sopenharmony_ci
29962306a36Sopenharmony_ci				op = get_ovl_priv(ovl);
30062306a36Sopenharmony_ci
30162306a36Sopenharmony_ci				/*
30262306a36Sopenharmony_ci				 * NOTE: we check extra_info flags even for
30362306a36Sopenharmony_ci				 * disabled overlays, as extra_infos need to be
30462306a36Sopenharmony_ci				 * always written.
30562306a36Sopenharmony_ci				 */
30662306a36Sopenharmony_ci
30762306a36Sopenharmony_ci				/* to write new values to registers */
30862306a36Sopenharmony_ci				if (op->extra_info_dirty)
30962306a36Sopenharmony_ci					return true;
31062306a36Sopenharmony_ci
31162306a36Sopenharmony_ci				/* to set GO bit */
31262306a36Sopenharmony_ci				if (op->shadow_extra_info_dirty)
31362306a36Sopenharmony_ci					return true;
31462306a36Sopenharmony_ci
31562306a36Sopenharmony_ci				if (!op->enabled)
31662306a36Sopenharmony_ci					continue;
31762306a36Sopenharmony_ci
31862306a36Sopenharmony_ci				/* to write new values to registers */
31962306a36Sopenharmony_ci				if (op->info_dirty)
32062306a36Sopenharmony_ci					return true;
32162306a36Sopenharmony_ci
32262306a36Sopenharmony_ci				/* to set GO bit */
32362306a36Sopenharmony_ci				if (op->shadow_info_dirty)
32462306a36Sopenharmony_ci					return true;
32562306a36Sopenharmony_ci			}
32662306a36Sopenharmony_ci		}
32762306a36Sopenharmony_ci	}
32862306a36Sopenharmony_ci
32962306a36Sopenharmony_ci	return false;
33062306a36Sopenharmony_ci}
33162306a36Sopenharmony_ci
33262306a36Sopenharmony_cistatic bool need_go(struct omap_overlay_manager *mgr)
33362306a36Sopenharmony_ci{
33462306a36Sopenharmony_ci	struct omap_overlay *ovl;
33562306a36Sopenharmony_ci	struct mgr_priv_data *mp;
33662306a36Sopenharmony_ci	struct ovl_priv_data *op;
33762306a36Sopenharmony_ci
33862306a36Sopenharmony_ci	mp = get_mgr_priv(mgr);
33962306a36Sopenharmony_ci
34062306a36Sopenharmony_ci	if (mp->shadow_info_dirty || mp->shadow_extra_info_dirty)
34162306a36Sopenharmony_ci		return true;
34262306a36Sopenharmony_ci
34362306a36Sopenharmony_ci	list_for_each_entry(ovl, &mgr->overlays, list) {
34462306a36Sopenharmony_ci		op = get_ovl_priv(ovl);
34562306a36Sopenharmony_ci		if (op->shadow_info_dirty || op->shadow_extra_info_dirty)
34662306a36Sopenharmony_ci			return true;
34762306a36Sopenharmony_ci	}
34862306a36Sopenharmony_ci
34962306a36Sopenharmony_ci	return false;
35062306a36Sopenharmony_ci}
35162306a36Sopenharmony_ci
35262306a36Sopenharmony_ci/* returns true if an extra_info field is currently being updated */
35362306a36Sopenharmony_cistatic bool extra_info_update_ongoing(void)
35462306a36Sopenharmony_ci{
35562306a36Sopenharmony_ci	const int num_mgrs = dss_feat_get_num_mgrs();
35662306a36Sopenharmony_ci	int i;
35762306a36Sopenharmony_ci
35862306a36Sopenharmony_ci	for (i = 0; i < num_mgrs; ++i) {
35962306a36Sopenharmony_ci		struct omap_overlay_manager *mgr;
36062306a36Sopenharmony_ci		struct omap_overlay *ovl;
36162306a36Sopenharmony_ci		struct mgr_priv_data *mp;
36262306a36Sopenharmony_ci
36362306a36Sopenharmony_ci		mgr = omap_dss_get_overlay_manager(i);
36462306a36Sopenharmony_ci		mp = get_mgr_priv(mgr);
36562306a36Sopenharmony_ci
36662306a36Sopenharmony_ci		if (!mp->enabled)
36762306a36Sopenharmony_ci			continue;
36862306a36Sopenharmony_ci
36962306a36Sopenharmony_ci		if (!mp->updating)
37062306a36Sopenharmony_ci			continue;
37162306a36Sopenharmony_ci
37262306a36Sopenharmony_ci		if (mp->extra_info_dirty || mp->shadow_extra_info_dirty)
37362306a36Sopenharmony_ci			return true;
37462306a36Sopenharmony_ci
37562306a36Sopenharmony_ci		list_for_each_entry(ovl, &mgr->overlays, list) {
37662306a36Sopenharmony_ci			struct ovl_priv_data *op = get_ovl_priv(ovl);
37762306a36Sopenharmony_ci
37862306a36Sopenharmony_ci			if (op->extra_info_dirty || op->shadow_extra_info_dirty)
37962306a36Sopenharmony_ci				return true;
38062306a36Sopenharmony_ci		}
38162306a36Sopenharmony_ci	}
38262306a36Sopenharmony_ci
38362306a36Sopenharmony_ci	return false;
38462306a36Sopenharmony_ci}
38562306a36Sopenharmony_ci
38662306a36Sopenharmony_ci/* wait until no extra_info updates are pending */
38762306a36Sopenharmony_cistatic void wait_pending_extra_info_updates(void)
38862306a36Sopenharmony_ci{
38962306a36Sopenharmony_ci	bool updating;
39062306a36Sopenharmony_ci	unsigned long flags;
39162306a36Sopenharmony_ci	unsigned long t;
39262306a36Sopenharmony_ci	int r;
39362306a36Sopenharmony_ci
39462306a36Sopenharmony_ci	spin_lock_irqsave(&data_lock, flags);
39562306a36Sopenharmony_ci
39662306a36Sopenharmony_ci	updating = extra_info_update_ongoing();
39762306a36Sopenharmony_ci
39862306a36Sopenharmony_ci	if (!updating) {
39962306a36Sopenharmony_ci		spin_unlock_irqrestore(&data_lock, flags);
40062306a36Sopenharmony_ci		return;
40162306a36Sopenharmony_ci	}
40262306a36Sopenharmony_ci
40362306a36Sopenharmony_ci	init_completion(&extra_updated_completion);
40462306a36Sopenharmony_ci
40562306a36Sopenharmony_ci	spin_unlock_irqrestore(&data_lock, flags);
40662306a36Sopenharmony_ci
40762306a36Sopenharmony_ci	t = msecs_to_jiffies(500);
40862306a36Sopenharmony_ci	r = wait_for_completion_timeout(&extra_updated_completion, t);
40962306a36Sopenharmony_ci	if (r == 0)
41062306a36Sopenharmony_ci		DSSWARN("timeout in wait_pending_extra_info_updates\n");
41162306a36Sopenharmony_ci}
41262306a36Sopenharmony_ci
41362306a36Sopenharmony_cistatic struct omap_dss_device *dss_mgr_get_device(struct omap_overlay_manager *mgr)
41462306a36Sopenharmony_ci{
41562306a36Sopenharmony_ci	struct omap_dss_device *dssdev;
41662306a36Sopenharmony_ci
41762306a36Sopenharmony_ci	dssdev = mgr->output;
41862306a36Sopenharmony_ci	if (dssdev == NULL)
41962306a36Sopenharmony_ci		return NULL;
42062306a36Sopenharmony_ci
42162306a36Sopenharmony_ci	while (dssdev->dst)
42262306a36Sopenharmony_ci		dssdev = dssdev->dst;
42362306a36Sopenharmony_ci
42462306a36Sopenharmony_ci	if (dssdev->driver)
42562306a36Sopenharmony_ci		return dssdev;
42662306a36Sopenharmony_ci	else
42762306a36Sopenharmony_ci		return NULL;
42862306a36Sopenharmony_ci}
42962306a36Sopenharmony_ci
43062306a36Sopenharmony_cistatic struct omap_dss_device *dss_ovl_get_device(struct omap_overlay *ovl)
43162306a36Sopenharmony_ci{
43262306a36Sopenharmony_ci	return ovl->manager ? dss_mgr_get_device(ovl->manager) : NULL;
43362306a36Sopenharmony_ci}
43462306a36Sopenharmony_ci
43562306a36Sopenharmony_cistatic int dss_mgr_wait_for_vsync(struct omap_overlay_manager *mgr)
43662306a36Sopenharmony_ci{
43762306a36Sopenharmony_ci	unsigned long timeout = msecs_to_jiffies(500);
43862306a36Sopenharmony_ci	u32 irq;
43962306a36Sopenharmony_ci	int r;
44062306a36Sopenharmony_ci
44162306a36Sopenharmony_ci	if (mgr->output == NULL)
44262306a36Sopenharmony_ci		return -ENODEV;
44362306a36Sopenharmony_ci
44462306a36Sopenharmony_ci	r = dispc_runtime_get();
44562306a36Sopenharmony_ci	if (r)
44662306a36Sopenharmony_ci		return r;
44762306a36Sopenharmony_ci
44862306a36Sopenharmony_ci	switch (mgr->output->id) {
44962306a36Sopenharmony_ci	case OMAP_DSS_OUTPUT_VENC:
45062306a36Sopenharmony_ci		irq = DISPC_IRQ_EVSYNC_ODD;
45162306a36Sopenharmony_ci		break;
45262306a36Sopenharmony_ci	case OMAP_DSS_OUTPUT_HDMI:
45362306a36Sopenharmony_ci		irq = DISPC_IRQ_EVSYNC_EVEN;
45462306a36Sopenharmony_ci		break;
45562306a36Sopenharmony_ci	default:
45662306a36Sopenharmony_ci		irq = dispc_mgr_get_vsync_irq(mgr->id);
45762306a36Sopenharmony_ci		break;
45862306a36Sopenharmony_ci	}
45962306a36Sopenharmony_ci
46062306a36Sopenharmony_ci	r = omap_dispc_wait_for_irq_interruptible_timeout(irq, timeout);
46162306a36Sopenharmony_ci
46262306a36Sopenharmony_ci	dispc_runtime_put();
46362306a36Sopenharmony_ci
46462306a36Sopenharmony_ci	return r;
46562306a36Sopenharmony_ci}
46662306a36Sopenharmony_ci
46762306a36Sopenharmony_cistatic int dss_mgr_wait_for_go(struct omap_overlay_manager *mgr)
46862306a36Sopenharmony_ci{
46962306a36Sopenharmony_ci	unsigned long timeout = msecs_to_jiffies(500);
47062306a36Sopenharmony_ci	struct mgr_priv_data *mp = get_mgr_priv(mgr);
47162306a36Sopenharmony_ci	u32 irq;
47262306a36Sopenharmony_ci	unsigned long flags;
47362306a36Sopenharmony_ci	int r;
47462306a36Sopenharmony_ci	int i;
47562306a36Sopenharmony_ci
47662306a36Sopenharmony_ci	spin_lock_irqsave(&data_lock, flags);
47762306a36Sopenharmony_ci
47862306a36Sopenharmony_ci	if (mgr_manual_update(mgr)) {
47962306a36Sopenharmony_ci		spin_unlock_irqrestore(&data_lock, flags);
48062306a36Sopenharmony_ci		return 0;
48162306a36Sopenharmony_ci	}
48262306a36Sopenharmony_ci
48362306a36Sopenharmony_ci	if (!mp->enabled) {
48462306a36Sopenharmony_ci		spin_unlock_irqrestore(&data_lock, flags);
48562306a36Sopenharmony_ci		return 0;
48662306a36Sopenharmony_ci	}
48762306a36Sopenharmony_ci
48862306a36Sopenharmony_ci	spin_unlock_irqrestore(&data_lock, flags);
48962306a36Sopenharmony_ci
49062306a36Sopenharmony_ci	r = dispc_runtime_get();
49162306a36Sopenharmony_ci	if (r)
49262306a36Sopenharmony_ci		return r;
49362306a36Sopenharmony_ci
49462306a36Sopenharmony_ci	irq = dispc_mgr_get_vsync_irq(mgr->id);
49562306a36Sopenharmony_ci
49662306a36Sopenharmony_ci	i = 0;
49762306a36Sopenharmony_ci	while (1) {
49862306a36Sopenharmony_ci		bool shadow_dirty, dirty;
49962306a36Sopenharmony_ci
50062306a36Sopenharmony_ci		spin_lock_irqsave(&data_lock, flags);
50162306a36Sopenharmony_ci		dirty = mp->info_dirty;
50262306a36Sopenharmony_ci		shadow_dirty = mp->shadow_info_dirty;
50362306a36Sopenharmony_ci		spin_unlock_irqrestore(&data_lock, flags);
50462306a36Sopenharmony_ci
50562306a36Sopenharmony_ci		if (!dirty && !shadow_dirty) {
50662306a36Sopenharmony_ci			r = 0;
50762306a36Sopenharmony_ci			break;
50862306a36Sopenharmony_ci		}
50962306a36Sopenharmony_ci
51062306a36Sopenharmony_ci		/* 4 iterations is the worst case:
51162306a36Sopenharmony_ci		 * 1 - initial iteration, dirty = true (between VFP and VSYNC)
51262306a36Sopenharmony_ci		 * 2 - first VSYNC, dirty = true
51362306a36Sopenharmony_ci		 * 3 - dirty = false, shadow_dirty = true
51462306a36Sopenharmony_ci		 * 4 - shadow_dirty = false */
51562306a36Sopenharmony_ci		if (i++ == 3) {
51662306a36Sopenharmony_ci			DSSERR("mgr(%d)->wait_for_go() not finishing\n",
51762306a36Sopenharmony_ci					mgr->id);
51862306a36Sopenharmony_ci			r = 0;
51962306a36Sopenharmony_ci			break;
52062306a36Sopenharmony_ci		}
52162306a36Sopenharmony_ci
52262306a36Sopenharmony_ci		r = omap_dispc_wait_for_irq_interruptible_timeout(irq, timeout);
52362306a36Sopenharmony_ci		if (r == -ERESTARTSYS)
52462306a36Sopenharmony_ci			break;
52562306a36Sopenharmony_ci
52662306a36Sopenharmony_ci		if (r) {
52762306a36Sopenharmony_ci			DSSERR("mgr(%d)->wait_for_go() timeout\n", mgr->id);
52862306a36Sopenharmony_ci			break;
52962306a36Sopenharmony_ci		}
53062306a36Sopenharmony_ci	}
53162306a36Sopenharmony_ci
53262306a36Sopenharmony_ci	dispc_runtime_put();
53362306a36Sopenharmony_ci
53462306a36Sopenharmony_ci	return r;
53562306a36Sopenharmony_ci}
53662306a36Sopenharmony_ci
53762306a36Sopenharmony_cistatic int dss_mgr_wait_for_go_ovl(struct omap_overlay *ovl)
53862306a36Sopenharmony_ci{
53962306a36Sopenharmony_ci	unsigned long timeout = msecs_to_jiffies(500);
54062306a36Sopenharmony_ci	struct ovl_priv_data *op;
54162306a36Sopenharmony_ci	struct mgr_priv_data *mp;
54262306a36Sopenharmony_ci	u32 irq;
54362306a36Sopenharmony_ci	unsigned long flags;
54462306a36Sopenharmony_ci	int r;
54562306a36Sopenharmony_ci	int i;
54662306a36Sopenharmony_ci
54762306a36Sopenharmony_ci	if (!ovl->manager)
54862306a36Sopenharmony_ci		return 0;
54962306a36Sopenharmony_ci
55062306a36Sopenharmony_ci	mp = get_mgr_priv(ovl->manager);
55162306a36Sopenharmony_ci
55262306a36Sopenharmony_ci	spin_lock_irqsave(&data_lock, flags);
55362306a36Sopenharmony_ci
55462306a36Sopenharmony_ci	if (ovl_manual_update(ovl)) {
55562306a36Sopenharmony_ci		spin_unlock_irqrestore(&data_lock, flags);
55662306a36Sopenharmony_ci		return 0;
55762306a36Sopenharmony_ci	}
55862306a36Sopenharmony_ci
55962306a36Sopenharmony_ci	if (!mp->enabled) {
56062306a36Sopenharmony_ci		spin_unlock_irqrestore(&data_lock, flags);
56162306a36Sopenharmony_ci		return 0;
56262306a36Sopenharmony_ci	}
56362306a36Sopenharmony_ci
56462306a36Sopenharmony_ci	spin_unlock_irqrestore(&data_lock, flags);
56562306a36Sopenharmony_ci
56662306a36Sopenharmony_ci	r = dispc_runtime_get();
56762306a36Sopenharmony_ci	if (r)
56862306a36Sopenharmony_ci		return r;
56962306a36Sopenharmony_ci
57062306a36Sopenharmony_ci	irq = dispc_mgr_get_vsync_irq(ovl->manager->id);
57162306a36Sopenharmony_ci
57262306a36Sopenharmony_ci	op = get_ovl_priv(ovl);
57362306a36Sopenharmony_ci	i = 0;
57462306a36Sopenharmony_ci	while (1) {
57562306a36Sopenharmony_ci		bool shadow_dirty, dirty;
57662306a36Sopenharmony_ci
57762306a36Sopenharmony_ci		spin_lock_irqsave(&data_lock, flags);
57862306a36Sopenharmony_ci		dirty = op->info_dirty;
57962306a36Sopenharmony_ci		shadow_dirty = op->shadow_info_dirty;
58062306a36Sopenharmony_ci		spin_unlock_irqrestore(&data_lock, flags);
58162306a36Sopenharmony_ci
58262306a36Sopenharmony_ci		if (!dirty && !shadow_dirty) {
58362306a36Sopenharmony_ci			r = 0;
58462306a36Sopenharmony_ci			break;
58562306a36Sopenharmony_ci		}
58662306a36Sopenharmony_ci
58762306a36Sopenharmony_ci		/* 4 iterations is the worst case:
58862306a36Sopenharmony_ci		 * 1 - initial iteration, dirty = true (between VFP and VSYNC)
58962306a36Sopenharmony_ci		 * 2 - first VSYNC, dirty = true
59062306a36Sopenharmony_ci		 * 3 - dirty = false, shadow_dirty = true
59162306a36Sopenharmony_ci		 * 4 - shadow_dirty = false */
59262306a36Sopenharmony_ci		if (i++ == 3) {
59362306a36Sopenharmony_ci			DSSERR("ovl(%d)->wait_for_go() not finishing\n",
59462306a36Sopenharmony_ci					ovl->id);
59562306a36Sopenharmony_ci			r = 0;
59662306a36Sopenharmony_ci			break;
59762306a36Sopenharmony_ci		}
59862306a36Sopenharmony_ci
59962306a36Sopenharmony_ci		r = omap_dispc_wait_for_irq_interruptible_timeout(irq, timeout);
60062306a36Sopenharmony_ci		if (r == -ERESTARTSYS)
60162306a36Sopenharmony_ci			break;
60262306a36Sopenharmony_ci
60362306a36Sopenharmony_ci		if (r) {
60462306a36Sopenharmony_ci			DSSERR("ovl(%d)->wait_for_go() timeout\n", ovl->id);
60562306a36Sopenharmony_ci			break;
60662306a36Sopenharmony_ci		}
60762306a36Sopenharmony_ci	}
60862306a36Sopenharmony_ci
60962306a36Sopenharmony_ci	dispc_runtime_put();
61062306a36Sopenharmony_ci
61162306a36Sopenharmony_ci	return r;
61262306a36Sopenharmony_ci}
61362306a36Sopenharmony_ci
61462306a36Sopenharmony_cistatic void dss_ovl_write_regs(struct omap_overlay *ovl)
61562306a36Sopenharmony_ci{
61662306a36Sopenharmony_ci	struct ovl_priv_data *op = get_ovl_priv(ovl);
61762306a36Sopenharmony_ci	struct omap_overlay_info *oi;
61862306a36Sopenharmony_ci	bool replication;
61962306a36Sopenharmony_ci	struct mgr_priv_data *mp;
62062306a36Sopenharmony_ci	int r;
62162306a36Sopenharmony_ci
62262306a36Sopenharmony_ci	DSSDBG("writing ovl %d regs\n", ovl->id);
62362306a36Sopenharmony_ci
62462306a36Sopenharmony_ci	if (!op->enabled || !op->info_dirty)
62562306a36Sopenharmony_ci		return;
62662306a36Sopenharmony_ci
62762306a36Sopenharmony_ci	oi = &op->info;
62862306a36Sopenharmony_ci
62962306a36Sopenharmony_ci	mp = get_mgr_priv(ovl->manager);
63062306a36Sopenharmony_ci
63162306a36Sopenharmony_ci	replication = dss_ovl_use_replication(mp->lcd_config, oi->color_mode);
63262306a36Sopenharmony_ci
63362306a36Sopenharmony_ci	r = dispc_ovl_setup(ovl->id, oi, replication, &mp->timings, false);
63462306a36Sopenharmony_ci	if (r) {
63562306a36Sopenharmony_ci		/*
63662306a36Sopenharmony_ci		 * We can't do much here, as this function can be called from
63762306a36Sopenharmony_ci		 * vsync interrupt.
63862306a36Sopenharmony_ci		 */
63962306a36Sopenharmony_ci		DSSERR("dispc_ovl_setup failed for ovl %d\n", ovl->id);
64062306a36Sopenharmony_ci
64162306a36Sopenharmony_ci		/* This will leave fifo configurations in a nonoptimal state */
64262306a36Sopenharmony_ci		op->enabled = false;
64362306a36Sopenharmony_ci		dispc_ovl_enable(ovl->id, false);
64462306a36Sopenharmony_ci		return;
64562306a36Sopenharmony_ci	}
64662306a36Sopenharmony_ci
64762306a36Sopenharmony_ci	op->info_dirty = false;
64862306a36Sopenharmony_ci	if (mp->updating)
64962306a36Sopenharmony_ci		op->shadow_info_dirty = true;
65062306a36Sopenharmony_ci}
65162306a36Sopenharmony_ci
65262306a36Sopenharmony_cistatic void dss_ovl_write_regs_extra(struct omap_overlay *ovl)
65362306a36Sopenharmony_ci{
65462306a36Sopenharmony_ci	struct ovl_priv_data *op = get_ovl_priv(ovl);
65562306a36Sopenharmony_ci	struct mgr_priv_data *mp;
65662306a36Sopenharmony_ci
65762306a36Sopenharmony_ci	DSSDBG("writing ovl %d regs extra\n", ovl->id);
65862306a36Sopenharmony_ci
65962306a36Sopenharmony_ci	if (!op->extra_info_dirty)
66062306a36Sopenharmony_ci		return;
66162306a36Sopenharmony_ci
66262306a36Sopenharmony_ci	/* note: write also when op->enabled == false, so that the ovl gets
66362306a36Sopenharmony_ci	 * disabled */
66462306a36Sopenharmony_ci
66562306a36Sopenharmony_ci	dispc_ovl_enable(ovl->id, op->enabled);
66662306a36Sopenharmony_ci	dispc_ovl_set_fifo_threshold(ovl->id, op->fifo_low, op->fifo_high);
66762306a36Sopenharmony_ci
66862306a36Sopenharmony_ci	mp = get_mgr_priv(ovl->manager);
66962306a36Sopenharmony_ci
67062306a36Sopenharmony_ci	op->extra_info_dirty = false;
67162306a36Sopenharmony_ci	if (mp->updating)
67262306a36Sopenharmony_ci		op->shadow_extra_info_dirty = true;
67362306a36Sopenharmony_ci}
67462306a36Sopenharmony_ci
67562306a36Sopenharmony_cistatic void dss_mgr_write_regs(struct omap_overlay_manager *mgr)
67662306a36Sopenharmony_ci{
67762306a36Sopenharmony_ci	struct mgr_priv_data *mp = get_mgr_priv(mgr);
67862306a36Sopenharmony_ci	struct omap_overlay *ovl;
67962306a36Sopenharmony_ci
68062306a36Sopenharmony_ci	DSSDBG("writing mgr %d regs\n", mgr->id);
68162306a36Sopenharmony_ci
68262306a36Sopenharmony_ci	if (!mp->enabled)
68362306a36Sopenharmony_ci		return;
68462306a36Sopenharmony_ci
68562306a36Sopenharmony_ci	WARN_ON(mp->busy);
68662306a36Sopenharmony_ci
68762306a36Sopenharmony_ci	/* Commit overlay settings */
68862306a36Sopenharmony_ci	list_for_each_entry(ovl, &mgr->overlays, list) {
68962306a36Sopenharmony_ci		dss_ovl_write_regs(ovl);
69062306a36Sopenharmony_ci		dss_ovl_write_regs_extra(ovl);
69162306a36Sopenharmony_ci	}
69262306a36Sopenharmony_ci
69362306a36Sopenharmony_ci	if (mp->info_dirty) {
69462306a36Sopenharmony_ci		dispc_mgr_setup(mgr->id, &mp->info);
69562306a36Sopenharmony_ci
69662306a36Sopenharmony_ci		mp->info_dirty = false;
69762306a36Sopenharmony_ci		if (mp->updating)
69862306a36Sopenharmony_ci			mp->shadow_info_dirty = true;
69962306a36Sopenharmony_ci	}
70062306a36Sopenharmony_ci}
70162306a36Sopenharmony_ci
70262306a36Sopenharmony_cistatic void dss_mgr_write_regs_extra(struct omap_overlay_manager *mgr)
70362306a36Sopenharmony_ci{
70462306a36Sopenharmony_ci	struct mgr_priv_data *mp = get_mgr_priv(mgr);
70562306a36Sopenharmony_ci
70662306a36Sopenharmony_ci	DSSDBG("writing mgr %d regs extra\n", mgr->id);
70762306a36Sopenharmony_ci
70862306a36Sopenharmony_ci	if (!mp->extra_info_dirty)
70962306a36Sopenharmony_ci		return;
71062306a36Sopenharmony_ci
71162306a36Sopenharmony_ci	dispc_mgr_set_timings(mgr->id, &mp->timings);
71262306a36Sopenharmony_ci
71362306a36Sopenharmony_ci	/* lcd_config parameters */
71462306a36Sopenharmony_ci	if (dss_mgr_is_lcd(mgr->id))
71562306a36Sopenharmony_ci		dispc_mgr_set_lcd_config(mgr->id, &mp->lcd_config);
71662306a36Sopenharmony_ci
71762306a36Sopenharmony_ci	mp->extra_info_dirty = false;
71862306a36Sopenharmony_ci	if (mp->updating)
71962306a36Sopenharmony_ci		mp->shadow_extra_info_dirty = true;
72062306a36Sopenharmony_ci}
72162306a36Sopenharmony_ci
72262306a36Sopenharmony_cistatic void dss_write_regs(void)
72362306a36Sopenharmony_ci{
72462306a36Sopenharmony_ci	const int num_mgrs = omap_dss_get_num_overlay_managers();
72562306a36Sopenharmony_ci	int i;
72662306a36Sopenharmony_ci
72762306a36Sopenharmony_ci	for (i = 0; i < num_mgrs; ++i) {
72862306a36Sopenharmony_ci		struct omap_overlay_manager *mgr;
72962306a36Sopenharmony_ci		struct mgr_priv_data *mp;
73062306a36Sopenharmony_ci		int r;
73162306a36Sopenharmony_ci
73262306a36Sopenharmony_ci		mgr = omap_dss_get_overlay_manager(i);
73362306a36Sopenharmony_ci		mp = get_mgr_priv(mgr);
73462306a36Sopenharmony_ci
73562306a36Sopenharmony_ci		if (!mp->enabled || mgr_manual_update(mgr) || mp->busy)
73662306a36Sopenharmony_ci			continue;
73762306a36Sopenharmony_ci
73862306a36Sopenharmony_ci		r = dss_check_settings(mgr);
73962306a36Sopenharmony_ci		if (r) {
74062306a36Sopenharmony_ci			DSSERR("cannot write registers for manager %s: "
74162306a36Sopenharmony_ci					"illegal configuration\n", mgr->name);
74262306a36Sopenharmony_ci			continue;
74362306a36Sopenharmony_ci		}
74462306a36Sopenharmony_ci
74562306a36Sopenharmony_ci		dss_mgr_write_regs(mgr);
74662306a36Sopenharmony_ci		dss_mgr_write_regs_extra(mgr);
74762306a36Sopenharmony_ci	}
74862306a36Sopenharmony_ci}
74962306a36Sopenharmony_ci
75062306a36Sopenharmony_cistatic void dss_set_go_bits(void)
75162306a36Sopenharmony_ci{
75262306a36Sopenharmony_ci	const int num_mgrs = omap_dss_get_num_overlay_managers();
75362306a36Sopenharmony_ci	int i;
75462306a36Sopenharmony_ci
75562306a36Sopenharmony_ci	for (i = 0; i < num_mgrs; ++i) {
75662306a36Sopenharmony_ci		struct omap_overlay_manager *mgr;
75762306a36Sopenharmony_ci		struct mgr_priv_data *mp;
75862306a36Sopenharmony_ci
75962306a36Sopenharmony_ci		mgr = omap_dss_get_overlay_manager(i);
76062306a36Sopenharmony_ci		mp = get_mgr_priv(mgr);
76162306a36Sopenharmony_ci
76262306a36Sopenharmony_ci		if (!mp->enabled || mgr_manual_update(mgr) || mp->busy)
76362306a36Sopenharmony_ci			continue;
76462306a36Sopenharmony_ci
76562306a36Sopenharmony_ci		if (!need_go(mgr))
76662306a36Sopenharmony_ci			continue;
76762306a36Sopenharmony_ci
76862306a36Sopenharmony_ci		mp->busy = true;
76962306a36Sopenharmony_ci
77062306a36Sopenharmony_ci		if (!dss_data.irq_enabled && need_isr())
77162306a36Sopenharmony_ci			dss_register_vsync_isr();
77262306a36Sopenharmony_ci
77362306a36Sopenharmony_ci		dispc_mgr_go(mgr->id);
77462306a36Sopenharmony_ci	}
77562306a36Sopenharmony_ci
77662306a36Sopenharmony_ci}
77762306a36Sopenharmony_ci
77862306a36Sopenharmony_cistatic void mgr_clear_shadow_dirty(struct omap_overlay_manager *mgr)
77962306a36Sopenharmony_ci{
78062306a36Sopenharmony_ci	struct omap_overlay *ovl;
78162306a36Sopenharmony_ci	struct mgr_priv_data *mp;
78262306a36Sopenharmony_ci	struct ovl_priv_data *op;
78362306a36Sopenharmony_ci
78462306a36Sopenharmony_ci	mp = get_mgr_priv(mgr);
78562306a36Sopenharmony_ci	mp->shadow_info_dirty = false;
78662306a36Sopenharmony_ci	mp->shadow_extra_info_dirty = false;
78762306a36Sopenharmony_ci
78862306a36Sopenharmony_ci	list_for_each_entry(ovl, &mgr->overlays, list) {
78962306a36Sopenharmony_ci		op = get_ovl_priv(ovl);
79062306a36Sopenharmony_ci		op->shadow_info_dirty = false;
79162306a36Sopenharmony_ci		op->shadow_extra_info_dirty = false;
79262306a36Sopenharmony_ci	}
79362306a36Sopenharmony_ci}
79462306a36Sopenharmony_ci
79562306a36Sopenharmony_cistatic int dss_mgr_connect_compat(struct omap_overlay_manager *mgr,
79662306a36Sopenharmony_ci		struct omap_dss_device *dst)
79762306a36Sopenharmony_ci{
79862306a36Sopenharmony_ci	return mgr->set_output(mgr, dst);
79962306a36Sopenharmony_ci}
80062306a36Sopenharmony_ci
80162306a36Sopenharmony_cistatic void dss_mgr_disconnect_compat(struct omap_overlay_manager *mgr,
80262306a36Sopenharmony_ci		struct omap_dss_device *dst)
80362306a36Sopenharmony_ci{
80462306a36Sopenharmony_ci	mgr->unset_output(mgr);
80562306a36Sopenharmony_ci}
80662306a36Sopenharmony_ci
80762306a36Sopenharmony_cistatic void dss_mgr_start_update_compat(struct omap_overlay_manager *mgr)
80862306a36Sopenharmony_ci{
80962306a36Sopenharmony_ci	struct mgr_priv_data *mp = get_mgr_priv(mgr);
81062306a36Sopenharmony_ci	unsigned long flags;
81162306a36Sopenharmony_ci	int r;
81262306a36Sopenharmony_ci
81362306a36Sopenharmony_ci	spin_lock_irqsave(&data_lock, flags);
81462306a36Sopenharmony_ci
81562306a36Sopenharmony_ci	WARN_ON(mp->updating);
81662306a36Sopenharmony_ci
81762306a36Sopenharmony_ci	r = dss_check_settings(mgr);
81862306a36Sopenharmony_ci	if (r) {
81962306a36Sopenharmony_ci		DSSERR("cannot start manual update: illegal configuration\n");
82062306a36Sopenharmony_ci		spin_unlock_irqrestore(&data_lock, flags);
82162306a36Sopenharmony_ci		return;
82262306a36Sopenharmony_ci	}
82362306a36Sopenharmony_ci
82462306a36Sopenharmony_ci	dss_mgr_write_regs(mgr);
82562306a36Sopenharmony_ci	dss_mgr_write_regs_extra(mgr);
82662306a36Sopenharmony_ci
82762306a36Sopenharmony_ci	mp->updating = true;
82862306a36Sopenharmony_ci
82962306a36Sopenharmony_ci	if (!dss_data.irq_enabled && need_isr())
83062306a36Sopenharmony_ci		dss_register_vsync_isr();
83162306a36Sopenharmony_ci
83262306a36Sopenharmony_ci	dispc_mgr_enable_sync(mgr->id);
83362306a36Sopenharmony_ci
83462306a36Sopenharmony_ci	spin_unlock_irqrestore(&data_lock, flags);
83562306a36Sopenharmony_ci}
83662306a36Sopenharmony_ci
83762306a36Sopenharmony_cistatic void dss_apply_irq_handler(void *data, u32 mask);
83862306a36Sopenharmony_ci
83962306a36Sopenharmony_cistatic void dss_register_vsync_isr(void)
84062306a36Sopenharmony_ci{
84162306a36Sopenharmony_ci	const int num_mgrs = dss_feat_get_num_mgrs();
84262306a36Sopenharmony_ci	u32 mask;
84362306a36Sopenharmony_ci	int r, i;
84462306a36Sopenharmony_ci
84562306a36Sopenharmony_ci	mask = 0;
84662306a36Sopenharmony_ci	for (i = 0; i < num_mgrs; ++i)
84762306a36Sopenharmony_ci		mask |= dispc_mgr_get_vsync_irq(i);
84862306a36Sopenharmony_ci
84962306a36Sopenharmony_ci	for (i = 0; i < num_mgrs; ++i)
85062306a36Sopenharmony_ci		mask |= dispc_mgr_get_framedone_irq(i);
85162306a36Sopenharmony_ci
85262306a36Sopenharmony_ci	r = omap_dispc_register_isr(dss_apply_irq_handler, NULL, mask);
85362306a36Sopenharmony_ci	WARN_ON(r);
85462306a36Sopenharmony_ci
85562306a36Sopenharmony_ci	dss_data.irq_enabled = true;
85662306a36Sopenharmony_ci}
85762306a36Sopenharmony_ci
85862306a36Sopenharmony_cistatic void dss_unregister_vsync_isr(void)
85962306a36Sopenharmony_ci{
86062306a36Sopenharmony_ci	const int num_mgrs = dss_feat_get_num_mgrs();
86162306a36Sopenharmony_ci	u32 mask;
86262306a36Sopenharmony_ci	int r, i;
86362306a36Sopenharmony_ci
86462306a36Sopenharmony_ci	mask = 0;
86562306a36Sopenharmony_ci	for (i = 0; i < num_mgrs; ++i)
86662306a36Sopenharmony_ci		mask |= dispc_mgr_get_vsync_irq(i);
86762306a36Sopenharmony_ci
86862306a36Sopenharmony_ci	for (i = 0; i < num_mgrs; ++i)
86962306a36Sopenharmony_ci		mask |= dispc_mgr_get_framedone_irq(i);
87062306a36Sopenharmony_ci
87162306a36Sopenharmony_ci	r = omap_dispc_unregister_isr(dss_apply_irq_handler, NULL, mask);
87262306a36Sopenharmony_ci	WARN_ON(r);
87362306a36Sopenharmony_ci
87462306a36Sopenharmony_ci	dss_data.irq_enabled = false;
87562306a36Sopenharmony_ci}
87662306a36Sopenharmony_ci
87762306a36Sopenharmony_cistatic void dss_apply_irq_handler(void *data, u32 mask)
87862306a36Sopenharmony_ci{
87962306a36Sopenharmony_ci	const int num_mgrs = dss_feat_get_num_mgrs();
88062306a36Sopenharmony_ci	int i;
88162306a36Sopenharmony_ci	bool extra_updating;
88262306a36Sopenharmony_ci
88362306a36Sopenharmony_ci	spin_lock(&data_lock);
88462306a36Sopenharmony_ci
88562306a36Sopenharmony_ci	/* clear busy, updating flags, shadow_dirty flags */
88662306a36Sopenharmony_ci	for (i = 0; i < num_mgrs; i++) {
88762306a36Sopenharmony_ci		struct omap_overlay_manager *mgr;
88862306a36Sopenharmony_ci		struct mgr_priv_data *mp;
88962306a36Sopenharmony_ci
89062306a36Sopenharmony_ci		mgr = omap_dss_get_overlay_manager(i);
89162306a36Sopenharmony_ci		mp = get_mgr_priv(mgr);
89262306a36Sopenharmony_ci
89362306a36Sopenharmony_ci		if (!mp->enabled)
89462306a36Sopenharmony_ci			continue;
89562306a36Sopenharmony_ci
89662306a36Sopenharmony_ci		mp->updating = dispc_mgr_is_enabled(i);
89762306a36Sopenharmony_ci
89862306a36Sopenharmony_ci		if (!mgr_manual_update(mgr)) {
89962306a36Sopenharmony_ci			bool was_busy = mp->busy;
90062306a36Sopenharmony_ci			mp->busy = dispc_mgr_go_busy(i);
90162306a36Sopenharmony_ci
90262306a36Sopenharmony_ci			if (was_busy && !mp->busy)
90362306a36Sopenharmony_ci				mgr_clear_shadow_dirty(mgr);
90462306a36Sopenharmony_ci		}
90562306a36Sopenharmony_ci	}
90662306a36Sopenharmony_ci
90762306a36Sopenharmony_ci	dss_write_regs();
90862306a36Sopenharmony_ci	dss_set_go_bits();
90962306a36Sopenharmony_ci
91062306a36Sopenharmony_ci	extra_updating = extra_info_update_ongoing();
91162306a36Sopenharmony_ci	if (!extra_updating)
91262306a36Sopenharmony_ci		complete_all(&extra_updated_completion);
91362306a36Sopenharmony_ci
91462306a36Sopenharmony_ci	/* call framedone handlers for manual update displays */
91562306a36Sopenharmony_ci	for (i = 0; i < num_mgrs; i++) {
91662306a36Sopenharmony_ci		struct omap_overlay_manager *mgr;
91762306a36Sopenharmony_ci		struct mgr_priv_data *mp;
91862306a36Sopenharmony_ci
91962306a36Sopenharmony_ci		mgr = omap_dss_get_overlay_manager(i);
92062306a36Sopenharmony_ci		mp = get_mgr_priv(mgr);
92162306a36Sopenharmony_ci
92262306a36Sopenharmony_ci		if (!mgr_manual_update(mgr) || !mp->framedone_handler)
92362306a36Sopenharmony_ci			continue;
92462306a36Sopenharmony_ci
92562306a36Sopenharmony_ci		if (mask & dispc_mgr_get_framedone_irq(i))
92662306a36Sopenharmony_ci			mp->framedone_handler(mp->framedone_handler_data);
92762306a36Sopenharmony_ci	}
92862306a36Sopenharmony_ci
92962306a36Sopenharmony_ci	if (!need_isr())
93062306a36Sopenharmony_ci		dss_unregister_vsync_isr();
93162306a36Sopenharmony_ci
93262306a36Sopenharmony_ci	spin_unlock(&data_lock);
93362306a36Sopenharmony_ci}
93462306a36Sopenharmony_ci
93562306a36Sopenharmony_cistatic void omap_dss_mgr_apply_ovl(struct omap_overlay *ovl)
93662306a36Sopenharmony_ci{
93762306a36Sopenharmony_ci	struct ovl_priv_data *op;
93862306a36Sopenharmony_ci
93962306a36Sopenharmony_ci	op = get_ovl_priv(ovl);
94062306a36Sopenharmony_ci
94162306a36Sopenharmony_ci	if (!op->user_info_dirty)
94262306a36Sopenharmony_ci		return;
94362306a36Sopenharmony_ci
94462306a36Sopenharmony_ci	op->user_info_dirty = false;
94562306a36Sopenharmony_ci	op->info_dirty = true;
94662306a36Sopenharmony_ci	op->info = op->user_info;
94762306a36Sopenharmony_ci}
94862306a36Sopenharmony_ci
94962306a36Sopenharmony_cistatic void omap_dss_mgr_apply_mgr(struct omap_overlay_manager *mgr)
95062306a36Sopenharmony_ci{
95162306a36Sopenharmony_ci	struct mgr_priv_data *mp;
95262306a36Sopenharmony_ci
95362306a36Sopenharmony_ci	mp = get_mgr_priv(mgr);
95462306a36Sopenharmony_ci
95562306a36Sopenharmony_ci	if (!mp->user_info_dirty)
95662306a36Sopenharmony_ci		return;
95762306a36Sopenharmony_ci
95862306a36Sopenharmony_ci	mp->user_info_dirty = false;
95962306a36Sopenharmony_ci	mp->info_dirty = true;
96062306a36Sopenharmony_ci	mp->info = mp->user_info;
96162306a36Sopenharmony_ci}
96262306a36Sopenharmony_ci
96362306a36Sopenharmony_cistatic int omap_dss_mgr_apply(struct omap_overlay_manager *mgr)
96462306a36Sopenharmony_ci{
96562306a36Sopenharmony_ci	unsigned long flags;
96662306a36Sopenharmony_ci	struct omap_overlay *ovl;
96762306a36Sopenharmony_ci	int r;
96862306a36Sopenharmony_ci
96962306a36Sopenharmony_ci	DSSDBG("omap_dss_mgr_apply(%s)\n", mgr->name);
97062306a36Sopenharmony_ci
97162306a36Sopenharmony_ci	spin_lock_irqsave(&data_lock, flags);
97262306a36Sopenharmony_ci
97362306a36Sopenharmony_ci	r = dss_check_settings_apply(mgr);
97462306a36Sopenharmony_ci	if (r) {
97562306a36Sopenharmony_ci		spin_unlock_irqrestore(&data_lock, flags);
97662306a36Sopenharmony_ci		DSSERR("failed to apply settings: illegal configuration.\n");
97762306a36Sopenharmony_ci		return r;
97862306a36Sopenharmony_ci	}
97962306a36Sopenharmony_ci
98062306a36Sopenharmony_ci	/* Configure overlays */
98162306a36Sopenharmony_ci	list_for_each_entry(ovl, &mgr->overlays, list)
98262306a36Sopenharmony_ci		omap_dss_mgr_apply_ovl(ovl);
98362306a36Sopenharmony_ci
98462306a36Sopenharmony_ci	/* Configure manager */
98562306a36Sopenharmony_ci	omap_dss_mgr_apply_mgr(mgr);
98662306a36Sopenharmony_ci
98762306a36Sopenharmony_ci	dss_write_regs();
98862306a36Sopenharmony_ci	dss_set_go_bits();
98962306a36Sopenharmony_ci
99062306a36Sopenharmony_ci	spin_unlock_irqrestore(&data_lock, flags);
99162306a36Sopenharmony_ci
99262306a36Sopenharmony_ci	return 0;
99362306a36Sopenharmony_ci}
99462306a36Sopenharmony_ci
99562306a36Sopenharmony_cistatic void dss_apply_ovl_enable(struct omap_overlay *ovl, bool enable)
99662306a36Sopenharmony_ci{
99762306a36Sopenharmony_ci	struct ovl_priv_data *op;
99862306a36Sopenharmony_ci
99962306a36Sopenharmony_ci	op = get_ovl_priv(ovl);
100062306a36Sopenharmony_ci
100162306a36Sopenharmony_ci	if (op->enabled == enable)
100262306a36Sopenharmony_ci		return;
100362306a36Sopenharmony_ci
100462306a36Sopenharmony_ci	op->enabled = enable;
100562306a36Sopenharmony_ci	op->extra_info_dirty = true;
100662306a36Sopenharmony_ci}
100762306a36Sopenharmony_ci
100862306a36Sopenharmony_cistatic void dss_apply_ovl_fifo_thresholds(struct omap_overlay *ovl,
100962306a36Sopenharmony_ci		u32 fifo_low, u32 fifo_high)
101062306a36Sopenharmony_ci{
101162306a36Sopenharmony_ci	struct ovl_priv_data *op = get_ovl_priv(ovl);
101262306a36Sopenharmony_ci
101362306a36Sopenharmony_ci	if (op->fifo_low == fifo_low && op->fifo_high == fifo_high)
101462306a36Sopenharmony_ci		return;
101562306a36Sopenharmony_ci
101662306a36Sopenharmony_ci	op->fifo_low = fifo_low;
101762306a36Sopenharmony_ci	op->fifo_high = fifo_high;
101862306a36Sopenharmony_ci	op->extra_info_dirty = true;
101962306a36Sopenharmony_ci}
102062306a36Sopenharmony_ci
102162306a36Sopenharmony_cistatic void dss_ovl_setup_fifo(struct omap_overlay *ovl)
102262306a36Sopenharmony_ci{
102362306a36Sopenharmony_ci	struct ovl_priv_data *op = get_ovl_priv(ovl);
102462306a36Sopenharmony_ci	u32 fifo_low, fifo_high;
102562306a36Sopenharmony_ci	bool use_fifo_merge = false;
102662306a36Sopenharmony_ci
102762306a36Sopenharmony_ci	if (!op->enabled && !op->enabling)
102862306a36Sopenharmony_ci		return;
102962306a36Sopenharmony_ci
103062306a36Sopenharmony_ci	dispc_ovl_compute_fifo_thresholds(ovl->id, &fifo_low, &fifo_high,
103162306a36Sopenharmony_ci			use_fifo_merge, ovl_manual_update(ovl));
103262306a36Sopenharmony_ci
103362306a36Sopenharmony_ci	dss_apply_ovl_fifo_thresholds(ovl, fifo_low, fifo_high);
103462306a36Sopenharmony_ci}
103562306a36Sopenharmony_ci
103662306a36Sopenharmony_cistatic void dss_mgr_setup_fifos(struct omap_overlay_manager *mgr)
103762306a36Sopenharmony_ci{
103862306a36Sopenharmony_ci	struct omap_overlay *ovl;
103962306a36Sopenharmony_ci	struct mgr_priv_data *mp;
104062306a36Sopenharmony_ci
104162306a36Sopenharmony_ci	mp = get_mgr_priv(mgr);
104262306a36Sopenharmony_ci
104362306a36Sopenharmony_ci	if (!mp->enabled)
104462306a36Sopenharmony_ci		return;
104562306a36Sopenharmony_ci
104662306a36Sopenharmony_ci	list_for_each_entry(ovl, &mgr->overlays, list)
104762306a36Sopenharmony_ci		dss_ovl_setup_fifo(ovl);
104862306a36Sopenharmony_ci}
104962306a36Sopenharmony_ci
105062306a36Sopenharmony_cistatic void dss_setup_fifos(void)
105162306a36Sopenharmony_ci{
105262306a36Sopenharmony_ci	const int num_mgrs = omap_dss_get_num_overlay_managers();
105362306a36Sopenharmony_ci	struct omap_overlay_manager *mgr;
105462306a36Sopenharmony_ci	int i;
105562306a36Sopenharmony_ci
105662306a36Sopenharmony_ci	for (i = 0; i < num_mgrs; ++i) {
105762306a36Sopenharmony_ci		mgr = omap_dss_get_overlay_manager(i);
105862306a36Sopenharmony_ci		dss_mgr_setup_fifos(mgr);
105962306a36Sopenharmony_ci	}
106062306a36Sopenharmony_ci}
106162306a36Sopenharmony_ci
106262306a36Sopenharmony_cistatic int dss_mgr_enable_compat(struct omap_overlay_manager *mgr)
106362306a36Sopenharmony_ci{
106462306a36Sopenharmony_ci	struct mgr_priv_data *mp = get_mgr_priv(mgr);
106562306a36Sopenharmony_ci	unsigned long flags;
106662306a36Sopenharmony_ci	int r;
106762306a36Sopenharmony_ci
106862306a36Sopenharmony_ci	mutex_lock(&apply_lock);
106962306a36Sopenharmony_ci
107062306a36Sopenharmony_ci	if (mp->enabled)
107162306a36Sopenharmony_ci		goto out;
107262306a36Sopenharmony_ci
107362306a36Sopenharmony_ci	spin_lock_irqsave(&data_lock, flags);
107462306a36Sopenharmony_ci
107562306a36Sopenharmony_ci	mp->enabled = true;
107662306a36Sopenharmony_ci
107762306a36Sopenharmony_ci	r = dss_check_settings(mgr);
107862306a36Sopenharmony_ci	if (r) {
107962306a36Sopenharmony_ci		DSSERR("failed to enable manager %d: check_settings failed\n",
108062306a36Sopenharmony_ci				mgr->id);
108162306a36Sopenharmony_ci		goto err;
108262306a36Sopenharmony_ci	}
108362306a36Sopenharmony_ci
108462306a36Sopenharmony_ci	dss_setup_fifos();
108562306a36Sopenharmony_ci
108662306a36Sopenharmony_ci	dss_write_regs();
108762306a36Sopenharmony_ci	dss_set_go_bits();
108862306a36Sopenharmony_ci
108962306a36Sopenharmony_ci	if (!mgr_manual_update(mgr))
109062306a36Sopenharmony_ci		mp->updating = true;
109162306a36Sopenharmony_ci
109262306a36Sopenharmony_ci	if (!dss_data.irq_enabled && need_isr())
109362306a36Sopenharmony_ci		dss_register_vsync_isr();
109462306a36Sopenharmony_ci
109562306a36Sopenharmony_ci	spin_unlock_irqrestore(&data_lock, flags);
109662306a36Sopenharmony_ci
109762306a36Sopenharmony_ci	if (!mgr_manual_update(mgr))
109862306a36Sopenharmony_ci		dispc_mgr_enable_sync(mgr->id);
109962306a36Sopenharmony_ci
110062306a36Sopenharmony_ciout:
110162306a36Sopenharmony_ci	mutex_unlock(&apply_lock);
110262306a36Sopenharmony_ci
110362306a36Sopenharmony_ci	return 0;
110462306a36Sopenharmony_ci
110562306a36Sopenharmony_cierr:
110662306a36Sopenharmony_ci	mp->enabled = false;
110762306a36Sopenharmony_ci	spin_unlock_irqrestore(&data_lock, flags);
110862306a36Sopenharmony_ci	mutex_unlock(&apply_lock);
110962306a36Sopenharmony_ci	return r;
111062306a36Sopenharmony_ci}
111162306a36Sopenharmony_ci
111262306a36Sopenharmony_cistatic void dss_mgr_disable_compat(struct omap_overlay_manager *mgr)
111362306a36Sopenharmony_ci{
111462306a36Sopenharmony_ci	struct mgr_priv_data *mp = get_mgr_priv(mgr);
111562306a36Sopenharmony_ci	unsigned long flags;
111662306a36Sopenharmony_ci
111762306a36Sopenharmony_ci	mutex_lock(&apply_lock);
111862306a36Sopenharmony_ci
111962306a36Sopenharmony_ci	if (!mp->enabled)
112062306a36Sopenharmony_ci		goto out;
112162306a36Sopenharmony_ci
112262306a36Sopenharmony_ci	wait_pending_extra_info_updates();
112362306a36Sopenharmony_ci
112462306a36Sopenharmony_ci	if (!mgr_manual_update(mgr))
112562306a36Sopenharmony_ci		dispc_mgr_disable_sync(mgr->id);
112662306a36Sopenharmony_ci
112762306a36Sopenharmony_ci	spin_lock_irqsave(&data_lock, flags);
112862306a36Sopenharmony_ci
112962306a36Sopenharmony_ci	mp->updating = false;
113062306a36Sopenharmony_ci	mp->enabled = false;
113162306a36Sopenharmony_ci
113262306a36Sopenharmony_ci	spin_unlock_irqrestore(&data_lock, flags);
113362306a36Sopenharmony_ci
113462306a36Sopenharmony_ciout:
113562306a36Sopenharmony_ci	mutex_unlock(&apply_lock);
113662306a36Sopenharmony_ci}
113762306a36Sopenharmony_ci
113862306a36Sopenharmony_cistatic int dss_mgr_set_info(struct omap_overlay_manager *mgr,
113962306a36Sopenharmony_ci		struct omap_overlay_manager_info *info)
114062306a36Sopenharmony_ci{
114162306a36Sopenharmony_ci	struct mgr_priv_data *mp = get_mgr_priv(mgr);
114262306a36Sopenharmony_ci	unsigned long flags;
114362306a36Sopenharmony_ci	int r;
114462306a36Sopenharmony_ci
114562306a36Sopenharmony_ci	r = dss_mgr_simple_check(mgr, info);
114662306a36Sopenharmony_ci	if (r)
114762306a36Sopenharmony_ci		return r;
114862306a36Sopenharmony_ci
114962306a36Sopenharmony_ci	spin_lock_irqsave(&data_lock, flags);
115062306a36Sopenharmony_ci
115162306a36Sopenharmony_ci	mp->user_info = *info;
115262306a36Sopenharmony_ci	mp->user_info_dirty = true;
115362306a36Sopenharmony_ci
115462306a36Sopenharmony_ci	spin_unlock_irqrestore(&data_lock, flags);
115562306a36Sopenharmony_ci
115662306a36Sopenharmony_ci	return 0;
115762306a36Sopenharmony_ci}
115862306a36Sopenharmony_ci
115962306a36Sopenharmony_cistatic void dss_mgr_get_info(struct omap_overlay_manager *mgr,
116062306a36Sopenharmony_ci		struct omap_overlay_manager_info *info)
116162306a36Sopenharmony_ci{
116262306a36Sopenharmony_ci	struct mgr_priv_data *mp = get_mgr_priv(mgr);
116362306a36Sopenharmony_ci	unsigned long flags;
116462306a36Sopenharmony_ci
116562306a36Sopenharmony_ci	spin_lock_irqsave(&data_lock, flags);
116662306a36Sopenharmony_ci
116762306a36Sopenharmony_ci	*info = mp->user_info;
116862306a36Sopenharmony_ci
116962306a36Sopenharmony_ci	spin_unlock_irqrestore(&data_lock, flags);
117062306a36Sopenharmony_ci}
117162306a36Sopenharmony_ci
117262306a36Sopenharmony_cistatic int dss_mgr_set_output(struct omap_overlay_manager *mgr,
117362306a36Sopenharmony_ci		struct omap_dss_device *output)
117462306a36Sopenharmony_ci{
117562306a36Sopenharmony_ci	int r;
117662306a36Sopenharmony_ci
117762306a36Sopenharmony_ci	mutex_lock(&apply_lock);
117862306a36Sopenharmony_ci
117962306a36Sopenharmony_ci	if (mgr->output) {
118062306a36Sopenharmony_ci		DSSERR("manager %s is already connected to an output\n",
118162306a36Sopenharmony_ci			mgr->name);
118262306a36Sopenharmony_ci		r = -EINVAL;
118362306a36Sopenharmony_ci		goto err;
118462306a36Sopenharmony_ci	}
118562306a36Sopenharmony_ci
118662306a36Sopenharmony_ci	if ((mgr->supported_outputs & output->id) == 0) {
118762306a36Sopenharmony_ci		DSSERR("output does not support manager %s\n",
118862306a36Sopenharmony_ci			mgr->name);
118962306a36Sopenharmony_ci		r = -EINVAL;
119062306a36Sopenharmony_ci		goto err;
119162306a36Sopenharmony_ci	}
119262306a36Sopenharmony_ci
119362306a36Sopenharmony_ci	output->manager = mgr;
119462306a36Sopenharmony_ci	mgr->output = output;
119562306a36Sopenharmony_ci
119662306a36Sopenharmony_ci	mutex_unlock(&apply_lock);
119762306a36Sopenharmony_ci
119862306a36Sopenharmony_ci	return 0;
119962306a36Sopenharmony_cierr:
120062306a36Sopenharmony_ci	mutex_unlock(&apply_lock);
120162306a36Sopenharmony_ci	return r;
120262306a36Sopenharmony_ci}
120362306a36Sopenharmony_ci
120462306a36Sopenharmony_cistatic int dss_mgr_unset_output(struct omap_overlay_manager *mgr)
120562306a36Sopenharmony_ci{
120662306a36Sopenharmony_ci	int r;
120762306a36Sopenharmony_ci	struct mgr_priv_data *mp = get_mgr_priv(mgr);
120862306a36Sopenharmony_ci	unsigned long flags;
120962306a36Sopenharmony_ci
121062306a36Sopenharmony_ci	mutex_lock(&apply_lock);
121162306a36Sopenharmony_ci
121262306a36Sopenharmony_ci	if (!mgr->output) {
121362306a36Sopenharmony_ci		DSSERR("failed to unset output, output not set\n");
121462306a36Sopenharmony_ci		r = -EINVAL;
121562306a36Sopenharmony_ci		goto err;
121662306a36Sopenharmony_ci	}
121762306a36Sopenharmony_ci
121862306a36Sopenharmony_ci	spin_lock_irqsave(&data_lock, flags);
121962306a36Sopenharmony_ci
122062306a36Sopenharmony_ci	if (mp->enabled) {
122162306a36Sopenharmony_ci		DSSERR("output can't be unset when manager is enabled\n");
122262306a36Sopenharmony_ci		r = -EINVAL;
122362306a36Sopenharmony_ci		goto err1;
122462306a36Sopenharmony_ci	}
122562306a36Sopenharmony_ci
122662306a36Sopenharmony_ci	spin_unlock_irqrestore(&data_lock, flags);
122762306a36Sopenharmony_ci
122862306a36Sopenharmony_ci	mgr->output->manager = NULL;
122962306a36Sopenharmony_ci	mgr->output = NULL;
123062306a36Sopenharmony_ci
123162306a36Sopenharmony_ci	mutex_unlock(&apply_lock);
123262306a36Sopenharmony_ci
123362306a36Sopenharmony_ci	return 0;
123462306a36Sopenharmony_cierr1:
123562306a36Sopenharmony_ci	spin_unlock_irqrestore(&data_lock, flags);
123662306a36Sopenharmony_cierr:
123762306a36Sopenharmony_ci	mutex_unlock(&apply_lock);
123862306a36Sopenharmony_ci
123962306a36Sopenharmony_ci	return r;
124062306a36Sopenharmony_ci}
124162306a36Sopenharmony_ci
124262306a36Sopenharmony_cistatic void dss_apply_mgr_timings(struct omap_overlay_manager *mgr,
124362306a36Sopenharmony_ci		const struct omap_video_timings *timings)
124462306a36Sopenharmony_ci{
124562306a36Sopenharmony_ci	struct mgr_priv_data *mp = get_mgr_priv(mgr);
124662306a36Sopenharmony_ci
124762306a36Sopenharmony_ci	mp->timings = *timings;
124862306a36Sopenharmony_ci	mp->extra_info_dirty = true;
124962306a36Sopenharmony_ci}
125062306a36Sopenharmony_ci
125162306a36Sopenharmony_cistatic void dss_mgr_set_timings_compat(struct omap_overlay_manager *mgr,
125262306a36Sopenharmony_ci		const struct omap_video_timings *timings)
125362306a36Sopenharmony_ci{
125462306a36Sopenharmony_ci	unsigned long flags;
125562306a36Sopenharmony_ci	struct mgr_priv_data *mp = get_mgr_priv(mgr);
125662306a36Sopenharmony_ci
125762306a36Sopenharmony_ci	spin_lock_irqsave(&data_lock, flags);
125862306a36Sopenharmony_ci
125962306a36Sopenharmony_ci	if (mp->updating) {
126062306a36Sopenharmony_ci		DSSERR("cannot set timings for %s: manager needs to be disabled\n",
126162306a36Sopenharmony_ci			mgr->name);
126262306a36Sopenharmony_ci		goto out;
126362306a36Sopenharmony_ci	}
126462306a36Sopenharmony_ci
126562306a36Sopenharmony_ci	dss_apply_mgr_timings(mgr, timings);
126662306a36Sopenharmony_ciout:
126762306a36Sopenharmony_ci	spin_unlock_irqrestore(&data_lock, flags);
126862306a36Sopenharmony_ci}
126962306a36Sopenharmony_ci
127062306a36Sopenharmony_cistatic void dss_apply_mgr_lcd_config(struct omap_overlay_manager *mgr,
127162306a36Sopenharmony_ci		const struct dss_lcd_mgr_config *config)
127262306a36Sopenharmony_ci{
127362306a36Sopenharmony_ci	struct mgr_priv_data *mp = get_mgr_priv(mgr);
127462306a36Sopenharmony_ci
127562306a36Sopenharmony_ci	mp->lcd_config = *config;
127662306a36Sopenharmony_ci	mp->extra_info_dirty = true;
127762306a36Sopenharmony_ci}
127862306a36Sopenharmony_ci
127962306a36Sopenharmony_cistatic void dss_mgr_set_lcd_config_compat(struct omap_overlay_manager *mgr,
128062306a36Sopenharmony_ci		const struct dss_lcd_mgr_config *config)
128162306a36Sopenharmony_ci{
128262306a36Sopenharmony_ci	unsigned long flags;
128362306a36Sopenharmony_ci	struct mgr_priv_data *mp = get_mgr_priv(mgr);
128462306a36Sopenharmony_ci
128562306a36Sopenharmony_ci	spin_lock_irqsave(&data_lock, flags);
128662306a36Sopenharmony_ci
128762306a36Sopenharmony_ci	if (mp->enabled) {
128862306a36Sopenharmony_ci		DSSERR("cannot apply lcd config for %s: manager needs to be disabled\n",
128962306a36Sopenharmony_ci			mgr->name);
129062306a36Sopenharmony_ci		goto out;
129162306a36Sopenharmony_ci	}
129262306a36Sopenharmony_ci
129362306a36Sopenharmony_ci	dss_apply_mgr_lcd_config(mgr, config);
129462306a36Sopenharmony_ciout:
129562306a36Sopenharmony_ci	spin_unlock_irqrestore(&data_lock, flags);
129662306a36Sopenharmony_ci}
129762306a36Sopenharmony_ci
129862306a36Sopenharmony_cistatic int dss_ovl_set_info(struct omap_overlay *ovl,
129962306a36Sopenharmony_ci		struct omap_overlay_info *info)
130062306a36Sopenharmony_ci{
130162306a36Sopenharmony_ci	struct ovl_priv_data *op = get_ovl_priv(ovl);
130262306a36Sopenharmony_ci	unsigned long flags;
130362306a36Sopenharmony_ci	int r;
130462306a36Sopenharmony_ci
130562306a36Sopenharmony_ci	r = dss_ovl_simple_check(ovl, info);
130662306a36Sopenharmony_ci	if (r)
130762306a36Sopenharmony_ci		return r;
130862306a36Sopenharmony_ci
130962306a36Sopenharmony_ci	spin_lock_irqsave(&data_lock, flags);
131062306a36Sopenharmony_ci
131162306a36Sopenharmony_ci	op->user_info = *info;
131262306a36Sopenharmony_ci	op->user_info_dirty = true;
131362306a36Sopenharmony_ci
131462306a36Sopenharmony_ci	spin_unlock_irqrestore(&data_lock, flags);
131562306a36Sopenharmony_ci
131662306a36Sopenharmony_ci	return 0;
131762306a36Sopenharmony_ci}
131862306a36Sopenharmony_ci
131962306a36Sopenharmony_cistatic void dss_ovl_get_info(struct omap_overlay *ovl,
132062306a36Sopenharmony_ci		struct omap_overlay_info *info)
132162306a36Sopenharmony_ci{
132262306a36Sopenharmony_ci	struct ovl_priv_data *op = get_ovl_priv(ovl);
132362306a36Sopenharmony_ci	unsigned long flags;
132462306a36Sopenharmony_ci
132562306a36Sopenharmony_ci	spin_lock_irqsave(&data_lock, flags);
132662306a36Sopenharmony_ci
132762306a36Sopenharmony_ci	*info = op->user_info;
132862306a36Sopenharmony_ci
132962306a36Sopenharmony_ci	spin_unlock_irqrestore(&data_lock, flags);
133062306a36Sopenharmony_ci}
133162306a36Sopenharmony_ci
133262306a36Sopenharmony_cistatic int dss_ovl_set_manager(struct omap_overlay *ovl,
133362306a36Sopenharmony_ci		struct omap_overlay_manager *mgr)
133462306a36Sopenharmony_ci{
133562306a36Sopenharmony_ci	struct ovl_priv_data *op = get_ovl_priv(ovl);
133662306a36Sopenharmony_ci	unsigned long flags;
133762306a36Sopenharmony_ci	int r;
133862306a36Sopenharmony_ci
133962306a36Sopenharmony_ci	if (!mgr)
134062306a36Sopenharmony_ci		return -EINVAL;
134162306a36Sopenharmony_ci
134262306a36Sopenharmony_ci	mutex_lock(&apply_lock);
134362306a36Sopenharmony_ci
134462306a36Sopenharmony_ci	if (ovl->manager) {
134562306a36Sopenharmony_ci		DSSERR("overlay '%s' already has a manager '%s'\n",
134662306a36Sopenharmony_ci				ovl->name, ovl->manager->name);
134762306a36Sopenharmony_ci		r = -EINVAL;
134862306a36Sopenharmony_ci		goto err;
134962306a36Sopenharmony_ci	}
135062306a36Sopenharmony_ci
135162306a36Sopenharmony_ci	r = dispc_runtime_get();
135262306a36Sopenharmony_ci	if (r)
135362306a36Sopenharmony_ci		goto err;
135462306a36Sopenharmony_ci
135562306a36Sopenharmony_ci	spin_lock_irqsave(&data_lock, flags);
135662306a36Sopenharmony_ci
135762306a36Sopenharmony_ci	if (op->enabled) {
135862306a36Sopenharmony_ci		spin_unlock_irqrestore(&data_lock, flags);
135962306a36Sopenharmony_ci		DSSERR("overlay has to be disabled to change the manager\n");
136062306a36Sopenharmony_ci		r = -EINVAL;
136162306a36Sopenharmony_ci		goto err1;
136262306a36Sopenharmony_ci	}
136362306a36Sopenharmony_ci
136462306a36Sopenharmony_ci	dispc_ovl_set_channel_out(ovl->id, mgr->id);
136562306a36Sopenharmony_ci
136662306a36Sopenharmony_ci	ovl->manager = mgr;
136762306a36Sopenharmony_ci	list_add_tail(&ovl->list, &mgr->overlays);
136862306a36Sopenharmony_ci
136962306a36Sopenharmony_ci	spin_unlock_irqrestore(&data_lock, flags);
137062306a36Sopenharmony_ci
137162306a36Sopenharmony_ci	dispc_runtime_put();
137262306a36Sopenharmony_ci
137362306a36Sopenharmony_ci	mutex_unlock(&apply_lock);
137462306a36Sopenharmony_ci
137562306a36Sopenharmony_ci	return 0;
137662306a36Sopenharmony_ci
137762306a36Sopenharmony_cierr1:
137862306a36Sopenharmony_ci	dispc_runtime_put();
137962306a36Sopenharmony_cierr:
138062306a36Sopenharmony_ci	mutex_unlock(&apply_lock);
138162306a36Sopenharmony_ci	return r;
138262306a36Sopenharmony_ci}
138362306a36Sopenharmony_ci
138462306a36Sopenharmony_cistatic int dss_ovl_unset_manager(struct omap_overlay *ovl)
138562306a36Sopenharmony_ci{
138662306a36Sopenharmony_ci	struct ovl_priv_data *op = get_ovl_priv(ovl);
138762306a36Sopenharmony_ci	unsigned long flags;
138862306a36Sopenharmony_ci	int r;
138962306a36Sopenharmony_ci
139062306a36Sopenharmony_ci	mutex_lock(&apply_lock);
139162306a36Sopenharmony_ci
139262306a36Sopenharmony_ci	if (!ovl->manager) {
139362306a36Sopenharmony_ci		DSSERR("failed to detach overlay: manager not set\n");
139462306a36Sopenharmony_ci		r = -EINVAL;
139562306a36Sopenharmony_ci		goto err;
139662306a36Sopenharmony_ci	}
139762306a36Sopenharmony_ci
139862306a36Sopenharmony_ci	spin_lock_irqsave(&data_lock, flags);
139962306a36Sopenharmony_ci
140062306a36Sopenharmony_ci	if (op->enabled) {
140162306a36Sopenharmony_ci		spin_unlock_irqrestore(&data_lock, flags);
140262306a36Sopenharmony_ci		DSSERR("overlay has to be disabled to unset the manager\n");
140362306a36Sopenharmony_ci		r = -EINVAL;
140462306a36Sopenharmony_ci		goto err;
140562306a36Sopenharmony_ci	}
140662306a36Sopenharmony_ci
140762306a36Sopenharmony_ci	spin_unlock_irqrestore(&data_lock, flags);
140862306a36Sopenharmony_ci
140962306a36Sopenharmony_ci	/* wait for pending extra_info updates to ensure the ovl is disabled */
141062306a36Sopenharmony_ci	wait_pending_extra_info_updates();
141162306a36Sopenharmony_ci
141262306a36Sopenharmony_ci	/*
141362306a36Sopenharmony_ci	 * For a manual update display, there is no guarantee that the overlay
141462306a36Sopenharmony_ci	 * is really disabled in HW, we may need an extra update from this
141562306a36Sopenharmony_ci	 * manager before the configurations can go in. Return an error if the
141662306a36Sopenharmony_ci	 * overlay needed an update from the manager.
141762306a36Sopenharmony_ci	 *
141862306a36Sopenharmony_ci	 * TODO: Instead of returning an error, try to do a dummy manager update
141962306a36Sopenharmony_ci	 * here to disable the overlay in hardware. Use the *GATED fields in
142062306a36Sopenharmony_ci	 * the DISPC_CONFIG registers to do a dummy update.
142162306a36Sopenharmony_ci	 */
142262306a36Sopenharmony_ci	spin_lock_irqsave(&data_lock, flags);
142362306a36Sopenharmony_ci
142462306a36Sopenharmony_ci	if (ovl_manual_update(ovl) && op->extra_info_dirty) {
142562306a36Sopenharmony_ci		spin_unlock_irqrestore(&data_lock, flags);
142662306a36Sopenharmony_ci		DSSERR("need an update to change the manager\n");
142762306a36Sopenharmony_ci		r = -EINVAL;
142862306a36Sopenharmony_ci		goto err;
142962306a36Sopenharmony_ci	}
143062306a36Sopenharmony_ci
143162306a36Sopenharmony_ci	ovl->manager = NULL;
143262306a36Sopenharmony_ci	list_del(&ovl->list);
143362306a36Sopenharmony_ci
143462306a36Sopenharmony_ci	spin_unlock_irqrestore(&data_lock, flags);
143562306a36Sopenharmony_ci
143662306a36Sopenharmony_ci	mutex_unlock(&apply_lock);
143762306a36Sopenharmony_ci
143862306a36Sopenharmony_ci	return 0;
143962306a36Sopenharmony_cierr:
144062306a36Sopenharmony_ci	mutex_unlock(&apply_lock);
144162306a36Sopenharmony_ci	return r;
144262306a36Sopenharmony_ci}
144362306a36Sopenharmony_ci
144462306a36Sopenharmony_cistatic bool dss_ovl_is_enabled(struct omap_overlay *ovl)
144562306a36Sopenharmony_ci{
144662306a36Sopenharmony_ci	struct ovl_priv_data *op = get_ovl_priv(ovl);
144762306a36Sopenharmony_ci	unsigned long flags;
144862306a36Sopenharmony_ci	bool e;
144962306a36Sopenharmony_ci
145062306a36Sopenharmony_ci	spin_lock_irqsave(&data_lock, flags);
145162306a36Sopenharmony_ci
145262306a36Sopenharmony_ci	e = op->enabled;
145362306a36Sopenharmony_ci
145462306a36Sopenharmony_ci	spin_unlock_irqrestore(&data_lock, flags);
145562306a36Sopenharmony_ci
145662306a36Sopenharmony_ci	return e;
145762306a36Sopenharmony_ci}
145862306a36Sopenharmony_ci
145962306a36Sopenharmony_cistatic int dss_ovl_enable(struct omap_overlay *ovl)
146062306a36Sopenharmony_ci{
146162306a36Sopenharmony_ci	struct ovl_priv_data *op = get_ovl_priv(ovl);
146262306a36Sopenharmony_ci	unsigned long flags;
146362306a36Sopenharmony_ci	int r;
146462306a36Sopenharmony_ci
146562306a36Sopenharmony_ci	mutex_lock(&apply_lock);
146662306a36Sopenharmony_ci
146762306a36Sopenharmony_ci	if (op->enabled) {
146862306a36Sopenharmony_ci		r = 0;
146962306a36Sopenharmony_ci		goto err1;
147062306a36Sopenharmony_ci	}
147162306a36Sopenharmony_ci
147262306a36Sopenharmony_ci	if (ovl->manager == NULL || ovl->manager->output == NULL) {
147362306a36Sopenharmony_ci		r = -EINVAL;
147462306a36Sopenharmony_ci		goto err1;
147562306a36Sopenharmony_ci	}
147662306a36Sopenharmony_ci
147762306a36Sopenharmony_ci	spin_lock_irqsave(&data_lock, flags);
147862306a36Sopenharmony_ci
147962306a36Sopenharmony_ci	op->enabling = true;
148062306a36Sopenharmony_ci
148162306a36Sopenharmony_ci	r = dss_check_settings(ovl->manager);
148262306a36Sopenharmony_ci	if (r) {
148362306a36Sopenharmony_ci		DSSERR("failed to enable overlay %d: check_settings failed\n",
148462306a36Sopenharmony_ci				ovl->id);
148562306a36Sopenharmony_ci		goto err2;
148662306a36Sopenharmony_ci	}
148762306a36Sopenharmony_ci
148862306a36Sopenharmony_ci	dss_setup_fifos();
148962306a36Sopenharmony_ci
149062306a36Sopenharmony_ci	op->enabling = false;
149162306a36Sopenharmony_ci	dss_apply_ovl_enable(ovl, true);
149262306a36Sopenharmony_ci
149362306a36Sopenharmony_ci	dss_write_regs();
149462306a36Sopenharmony_ci	dss_set_go_bits();
149562306a36Sopenharmony_ci
149662306a36Sopenharmony_ci	spin_unlock_irqrestore(&data_lock, flags);
149762306a36Sopenharmony_ci
149862306a36Sopenharmony_ci	mutex_unlock(&apply_lock);
149962306a36Sopenharmony_ci
150062306a36Sopenharmony_ci	return 0;
150162306a36Sopenharmony_cierr2:
150262306a36Sopenharmony_ci	op->enabling = false;
150362306a36Sopenharmony_ci	spin_unlock_irqrestore(&data_lock, flags);
150462306a36Sopenharmony_cierr1:
150562306a36Sopenharmony_ci	mutex_unlock(&apply_lock);
150662306a36Sopenharmony_ci	return r;
150762306a36Sopenharmony_ci}
150862306a36Sopenharmony_ci
150962306a36Sopenharmony_cistatic int dss_ovl_disable(struct omap_overlay *ovl)
151062306a36Sopenharmony_ci{
151162306a36Sopenharmony_ci	struct ovl_priv_data *op = get_ovl_priv(ovl);
151262306a36Sopenharmony_ci	unsigned long flags;
151362306a36Sopenharmony_ci	int r;
151462306a36Sopenharmony_ci
151562306a36Sopenharmony_ci	mutex_lock(&apply_lock);
151662306a36Sopenharmony_ci
151762306a36Sopenharmony_ci	if (!op->enabled) {
151862306a36Sopenharmony_ci		r = 0;
151962306a36Sopenharmony_ci		goto err;
152062306a36Sopenharmony_ci	}
152162306a36Sopenharmony_ci
152262306a36Sopenharmony_ci	if (ovl->manager == NULL || ovl->manager->output == NULL) {
152362306a36Sopenharmony_ci		r = -EINVAL;
152462306a36Sopenharmony_ci		goto err;
152562306a36Sopenharmony_ci	}
152662306a36Sopenharmony_ci
152762306a36Sopenharmony_ci	spin_lock_irqsave(&data_lock, flags);
152862306a36Sopenharmony_ci
152962306a36Sopenharmony_ci	dss_apply_ovl_enable(ovl, false);
153062306a36Sopenharmony_ci	dss_write_regs();
153162306a36Sopenharmony_ci	dss_set_go_bits();
153262306a36Sopenharmony_ci
153362306a36Sopenharmony_ci	spin_unlock_irqrestore(&data_lock, flags);
153462306a36Sopenharmony_ci
153562306a36Sopenharmony_ci	mutex_unlock(&apply_lock);
153662306a36Sopenharmony_ci
153762306a36Sopenharmony_ci	return 0;
153862306a36Sopenharmony_ci
153962306a36Sopenharmony_cierr:
154062306a36Sopenharmony_ci	mutex_unlock(&apply_lock);
154162306a36Sopenharmony_ci	return r;
154262306a36Sopenharmony_ci}
154362306a36Sopenharmony_ci
154462306a36Sopenharmony_cistatic int dss_mgr_register_framedone_handler_compat(struct omap_overlay_manager *mgr,
154562306a36Sopenharmony_ci		void (*handler)(void *), void *data)
154662306a36Sopenharmony_ci{
154762306a36Sopenharmony_ci	struct mgr_priv_data *mp = get_mgr_priv(mgr);
154862306a36Sopenharmony_ci
154962306a36Sopenharmony_ci	if (mp->framedone_handler)
155062306a36Sopenharmony_ci		return -EBUSY;
155162306a36Sopenharmony_ci
155262306a36Sopenharmony_ci	mp->framedone_handler = handler;
155362306a36Sopenharmony_ci	mp->framedone_handler_data = data;
155462306a36Sopenharmony_ci
155562306a36Sopenharmony_ci	return 0;
155662306a36Sopenharmony_ci}
155762306a36Sopenharmony_ci
155862306a36Sopenharmony_cistatic void dss_mgr_unregister_framedone_handler_compat(struct omap_overlay_manager *mgr,
155962306a36Sopenharmony_ci		void (*handler)(void *), void *data)
156062306a36Sopenharmony_ci{
156162306a36Sopenharmony_ci	struct mgr_priv_data *mp = get_mgr_priv(mgr);
156262306a36Sopenharmony_ci
156362306a36Sopenharmony_ci	WARN_ON(mp->framedone_handler != handler ||
156462306a36Sopenharmony_ci			mp->framedone_handler_data != data);
156562306a36Sopenharmony_ci
156662306a36Sopenharmony_ci	mp->framedone_handler = NULL;
156762306a36Sopenharmony_ci	mp->framedone_handler_data = NULL;
156862306a36Sopenharmony_ci}
156962306a36Sopenharmony_ci
157062306a36Sopenharmony_cistatic const struct dss_mgr_ops apply_mgr_ops = {
157162306a36Sopenharmony_ci	.connect = dss_mgr_connect_compat,
157262306a36Sopenharmony_ci	.disconnect = dss_mgr_disconnect_compat,
157362306a36Sopenharmony_ci	.start_update = dss_mgr_start_update_compat,
157462306a36Sopenharmony_ci	.enable = dss_mgr_enable_compat,
157562306a36Sopenharmony_ci	.disable = dss_mgr_disable_compat,
157662306a36Sopenharmony_ci	.set_timings = dss_mgr_set_timings_compat,
157762306a36Sopenharmony_ci	.set_lcd_config = dss_mgr_set_lcd_config_compat,
157862306a36Sopenharmony_ci	.register_framedone_handler = dss_mgr_register_framedone_handler_compat,
157962306a36Sopenharmony_ci	.unregister_framedone_handler = dss_mgr_unregister_framedone_handler_compat,
158062306a36Sopenharmony_ci};
158162306a36Sopenharmony_ci
158262306a36Sopenharmony_cistatic int compat_refcnt;
158362306a36Sopenharmony_cistatic DEFINE_MUTEX(compat_init_lock);
158462306a36Sopenharmony_ci
158562306a36Sopenharmony_ciint omapdss_compat_init(void)
158662306a36Sopenharmony_ci{
158762306a36Sopenharmony_ci	struct platform_device *pdev = dss_get_core_pdev();
158862306a36Sopenharmony_ci	int i, r;
158962306a36Sopenharmony_ci
159062306a36Sopenharmony_ci	mutex_lock(&compat_init_lock);
159162306a36Sopenharmony_ci
159262306a36Sopenharmony_ci	if (compat_refcnt++ > 0)
159362306a36Sopenharmony_ci		goto out;
159462306a36Sopenharmony_ci
159562306a36Sopenharmony_ci	apply_init_priv();
159662306a36Sopenharmony_ci
159762306a36Sopenharmony_ci	dss_init_overlay_managers_sysfs(pdev);
159862306a36Sopenharmony_ci	dss_init_overlays(pdev);
159962306a36Sopenharmony_ci
160062306a36Sopenharmony_ci	for (i = 0; i < omap_dss_get_num_overlay_managers(); i++) {
160162306a36Sopenharmony_ci		struct omap_overlay_manager *mgr;
160262306a36Sopenharmony_ci
160362306a36Sopenharmony_ci		mgr = omap_dss_get_overlay_manager(i);
160462306a36Sopenharmony_ci
160562306a36Sopenharmony_ci		mgr->set_output = &dss_mgr_set_output;
160662306a36Sopenharmony_ci		mgr->unset_output = &dss_mgr_unset_output;
160762306a36Sopenharmony_ci		mgr->apply = &omap_dss_mgr_apply;
160862306a36Sopenharmony_ci		mgr->set_manager_info = &dss_mgr_set_info;
160962306a36Sopenharmony_ci		mgr->get_manager_info = &dss_mgr_get_info;
161062306a36Sopenharmony_ci		mgr->wait_for_go = &dss_mgr_wait_for_go;
161162306a36Sopenharmony_ci		mgr->wait_for_vsync = &dss_mgr_wait_for_vsync;
161262306a36Sopenharmony_ci		mgr->get_device = &dss_mgr_get_device;
161362306a36Sopenharmony_ci	}
161462306a36Sopenharmony_ci
161562306a36Sopenharmony_ci	for (i = 0; i < omap_dss_get_num_overlays(); i++) {
161662306a36Sopenharmony_ci		struct omap_overlay *ovl = omap_dss_get_overlay(i);
161762306a36Sopenharmony_ci
161862306a36Sopenharmony_ci		ovl->is_enabled = &dss_ovl_is_enabled;
161962306a36Sopenharmony_ci		ovl->enable = &dss_ovl_enable;
162062306a36Sopenharmony_ci		ovl->disable = &dss_ovl_disable;
162162306a36Sopenharmony_ci		ovl->set_manager = &dss_ovl_set_manager;
162262306a36Sopenharmony_ci		ovl->unset_manager = &dss_ovl_unset_manager;
162362306a36Sopenharmony_ci		ovl->set_overlay_info = &dss_ovl_set_info;
162462306a36Sopenharmony_ci		ovl->get_overlay_info = &dss_ovl_get_info;
162562306a36Sopenharmony_ci		ovl->wait_for_go = &dss_mgr_wait_for_go_ovl;
162662306a36Sopenharmony_ci		ovl->get_device = &dss_ovl_get_device;
162762306a36Sopenharmony_ci	}
162862306a36Sopenharmony_ci
162962306a36Sopenharmony_ci	r = dss_install_mgr_ops(&apply_mgr_ops);
163062306a36Sopenharmony_ci	if (r)
163162306a36Sopenharmony_ci		goto err_mgr_ops;
163262306a36Sopenharmony_ci
163362306a36Sopenharmony_ci	r = display_init_sysfs(pdev);
163462306a36Sopenharmony_ci	if (r)
163562306a36Sopenharmony_ci		goto err_disp_sysfs;
163662306a36Sopenharmony_ci
163762306a36Sopenharmony_ci	dispc_runtime_get();
163862306a36Sopenharmony_ci
163962306a36Sopenharmony_ci	r = dss_dispc_initialize_irq();
164062306a36Sopenharmony_ci	if (r)
164162306a36Sopenharmony_ci		goto err_init_irq;
164262306a36Sopenharmony_ci
164362306a36Sopenharmony_ci	dispc_runtime_put();
164462306a36Sopenharmony_ci
164562306a36Sopenharmony_ciout:
164662306a36Sopenharmony_ci	mutex_unlock(&compat_init_lock);
164762306a36Sopenharmony_ci
164862306a36Sopenharmony_ci	return 0;
164962306a36Sopenharmony_ci
165062306a36Sopenharmony_cierr_init_irq:
165162306a36Sopenharmony_ci	dispc_runtime_put();
165262306a36Sopenharmony_ci	display_uninit_sysfs(pdev);
165362306a36Sopenharmony_ci
165462306a36Sopenharmony_cierr_disp_sysfs:
165562306a36Sopenharmony_ci	dss_uninstall_mgr_ops();
165662306a36Sopenharmony_ci
165762306a36Sopenharmony_cierr_mgr_ops:
165862306a36Sopenharmony_ci	dss_uninit_overlay_managers_sysfs(pdev);
165962306a36Sopenharmony_ci	dss_uninit_overlays(pdev);
166062306a36Sopenharmony_ci
166162306a36Sopenharmony_ci	compat_refcnt--;
166262306a36Sopenharmony_ci
166362306a36Sopenharmony_ci	mutex_unlock(&compat_init_lock);
166462306a36Sopenharmony_ci
166562306a36Sopenharmony_ci	return r;
166662306a36Sopenharmony_ci}
166762306a36Sopenharmony_ciEXPORT_SYMBOL(omapdss_compat_init);
166862306a36Sopenharmony_ci
166962306a36Sopenharmony_civoid omapdss_compat_uninit(void)
167062306a36Sopenharmony_ci{
167162306a36Sopenharmony_ci	struct platform_device *pdev = dss_get_core_pdev();
167262306a36Sopenharmony_ci
167362306a36Sopenharmony_ci	mutex_lock(&compat_init_lock);
167462306a36Sopenharmony_ci
167562306a36Sopenharmony_ci	if (--compat_refcnt > 0)
167662306a36Sopenharmony_ci		goto out;
167762306a36Sopenharmony_ci
167862306a36Sopenharmony_ci	dss_dispc_uninitialize_irq();
167962306a36Sopenharmony_ci
168062306a36Sopenharmony_ci	display_uninit_sysfs(pdev);
168162306a36Sopenharmony_ci
168262306a36Sopenharmony_ci	dss_uninstall_mgr_ops();
168362306a36Sopenharmony_ci
168462306a36Sopenharmony_ci	dss_uninit_overlay_managers_sysfs(pdev);
168562306a36Sopenharmony_ci	dss_uninit_overlays(pdev);
168662306a36Sopenharmony_ciout:
168762306a36Sopenharmony_ci	mutex_unlock(&compat_init_lock);
168862306a36Sopenharmony_ci}
168962306a36Sopenharmony_ciEXPORT_SYMBOL(omapdss_compat_uninit);
1690