brintos

brintos / linux-shallow public Read only

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