diff options
Diffstat (limited to 'drivers/video/omap2/dss/dispc-compat.c')
| -rw-r--r-- | drivers/video/omap2/dss/dispc-compat.c | 666 | 
1 files changed, 0 insertions, 666 deletions
diff --git a/drivers/video/omap2/dss/dispc-compat.c b/drivers/video/omap2/dss/dispc-compat.c deleted file mode 100644 index 83779c2b292..00000000000 --- a/drivers/video/omap2/dss/dispc-compat.c +++ /dev/null @@ -1,666 +0,0 @@ -/* - * Copyright (C) 2012 Texas Instruments - * Author: Tomi Valkeinen <tomi.valkeinen@ti.com> - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program.  If not, see <http://www.gnu.org/licenses/>. - */ - -#define DSS_SUBSYS_NAME "APPLY" - -#include <linux/kernel.h> -#include <linux/module.h> -#include <linux/slab.h> -#include <linux/spinlock.h> -#include <linux/jiffies.h> -#include <linux/delay.h> -#include <linux/interrupt.h> -#include <linux/seq_file.h> - -#include <video/omapdss.h> - -#include "dss.h" -#include "dss_features.h" -#include "dispc-compat.h" - -#define DISPC_IRQ_MASK_ERROR            (DISPC_IRQ_GFX_FIFO_UNDERFLOW | \ -					 DISPC_IRQ_OCP_ERR | \ -					 DISPC_IRQ_VID1_FIFO_UNDERFLOW | \ -					 DISPC_IRQ_VID2_FIFO_UNDERFLOW | \ -					 DISPC_IRQ_SYNC_LOST | \ -					 DISPC_IRQ_SYNC_LOST_DIGIT) - -#define DISPC_MAX_NR_ISRS		8 - -struct omap_dispc_isr_data { -	omap_dispc_isr_t	isr; -	void			*arg; -	u32			mask; -}; - -struct dispc_irq_stats { -	unsigned long last_reset; -	unsigned irq_count; -	unsigned irqs[32]; -}; - -static struct { -	spinlock_t irq_lock; -	u32 irq_error_mask; -	struct omap_dispc_isr_data registered_isr[DISPC_MAX_NR_ISRS]; -	u32 error_irqs; -	struct work_struct error_work; - -#ifdef CONFIG_OMAP2_DSS_COLLECT_IRQ_STATS -	spinlock_t irq_stats_lock; -	struct dispc_irq_stats irq_stats; -#endif -} dispc_compat; - - -#ifdef CONFIG_OMAP2_DSS_COLLECT_IRQ_STATS -static void dispc_dump_irqs(struct seq_file *s) -{ -	unsigned long flags; -	struct dispc_irq_stats stats; - -	spin_lock_irqsave(&dispc_compat.irq_stats_lock, flags); - -	stats = dispc_compat.irq_stats; -	memset(&dispc_compat.irq_stats, 0, sizeof(dispc_compat.irq_stats)); -	dispc_compat.irq_stats.last_reset = jiffies; - -	spin_unlock_irqrestore(&dispc_compat.irq_stats_lock, flags); - -	seq_printf(s, "period %u ms\n", -			jiffies_to_msecs(jiffies - stats.last_reset)); - -	seq_printf(s, "irqs %d\n", stats.irq_count); -#define PIS(x) \ -	seq_printf(s, "%-20s %10d\n", #x, stats.irqs[ffs(DISPC_IRQ_##x)-1]); - -	PIS(FRAMEDONE); -	PIS(VSYNC); -	PIS(EVSYNC_EVEN); -	PIS(EVSYNC_ODD); -	PIS(ACBIAS_COUNT_STAT); -	PIS(PROG_LINE_NUM); -	PIS(GFX_FIFO_UNDERFLOW); -	PIS(GFX_END_WIN); -	PIS(PAL_GAMMA_MASK); -	PIS(OCP_ERR); -	PIS(VID1_FIFO_UNDERFLOW); -	PIS(VID1_END_WIN); -	PIS(VID2_FIFO_UNDERFLOW); -	PIS(VID2_END_WIN); -	if (dss_feat_get_num_ovls() > 3) { -		PIS(VID3_FIFO_UNDERFLOW); -		PIS(VID3_END_WIN); -	} -	PIS(SYNC_LOST); -	PIS(SYNC_LOST_DIGIT); -	PIS(WAKEUP); -	if (dss_has_feature(FEAT_MGR_LCD2)) { -		PIS(FRAMEDONE2); -		PIS(VSYNC2); -		PIS(ACBIAS_COUNT_STAT2); -		PIS(SYNC_LOST2); -	} -	if (dss_has_feature(FEAT_MGR_LCD3)) { -		PIS(FRAMEDONE3); -		PIS(VSYNC3); -		PIS(ACBIAS_COUNT_STAT3); -		PIS(SYNC_LOST3); -	} -#undef PIS -} -#endif - -/* dispc.irq_lock has to be locked by the caller */ -static void _omap_dispc_set_irqs(void) -{ -	u32 mask; -	int i; -	struct omap_dispc_isr_data *isr_data; - -	mask = dispc_compat.irq_error_mask; - -	for (i = 0; i < DISPC_MAX_NR_ISRS; i++) { -		isr_data = &dispc_compat.registered_isr[i]; - -		if (isr_data->isr == NULL) -			continue; - -		mask |= isr_data->mask; -	} - -	dispc_write_irqenable(mask); -} - -int omap_dispc_register_isr(omap_dispc_isr_t isr, void *arg, u32 mask) -{ -	int i; -	int ret; -	unsigned long flags; -	struct omap_dispc_isr_data *isr_data; - -	if (isr == NULL) -		return -EINVAL; - -	spin_lock_irqsave(&dispc_compat.irq_lock, flags); - -	/* check for duplicate entry */ -	for (i = 0; i < DISPC_MAX_NR_ISRS; i++) { -		isr_data = &dispc_compat.registered_isr[i]; -		if (isr_data->isr == isr && isr_data->arg == arg && -				isr_data->mask == mask) { -			ret = -EINVAL; -			goto err; -		} -	} - -	isr_data = NULL; -	ret = -EBUSY; - -	for (i = 0; i < DISPC_MAX_NR_ISRS; i++) { -		isr_data = &dispc_compat.registered_isr[i]; - -		if (isr_data->isr != NULL) -			continue; - -		isr_data->isr = isr; -		isr_data->arg = arg; -		isr_data->mask = mask; -		ret = 0; - -		break; -	} - -	if (ret) -		goto err; - -	_omap_dispc_set_irqs(); - -	spin_unlock_irqrestore(&dispc_compat.irq_lock, flags); - -	return 0; -err: -	spin_unlock_irqrestore(&dispc_compat.irq_lock, flags); - -	return ret; -} -EXPORT_SYMBOL(omap_dispc_register_isr); - -int omap_dispc_unregister_isr(omap_dispc_isr_t isr, void *arg, u32 mask) -{ -	int i; -	unsigned long flags; -	int ret = -EINVAL; -	struct omap_dispc_isr_data *isr_data; - -	spin_lock_irqsave(&dispc_compat.irq_lock, flags); - -	for (i = 0; i < DISPC_MAX_NR_ISRS; i++) { -		isr_data = &dispc_compat.registered_isr[i]; -		if (isr_data->isr != isr || isr_data->arg != arg || -				isr_data->mask != mask) -			continue; - -		/* found the correct isr */ - -		isr_data->isr = NULL; -		isr_data->arg = NULL; -		isr_data->mask = 0; - -		ret = 0; -		break; -	} - -	if (ret == 0) -		_omap_dispc_set_irqs(); - -	spin_unlock_irqrestore(&dispc_compat.irq_lock, flags); - -	return ret; -} -EXPORT_SYMBOL(omap_dispc_unregister_isr); - -static void print_irq_status(u32 status) -{ -	if ((status & dispc_compat.irq_error_mask) == 0) -		return; - -#define PIS(x) (status & DISPC_IRQ_##x) ? (#x " ") : "" - -	pr_debug("DISPC IRQ: 0x%x: %s%s%s%s%s%s%s%s%s\n", -		status, -		PIS(OCP_ERR), -		PIS(GFX_FIFO_UNDERFLOW), -		PIS(VID1_FIFO_UNDERFLOW), -		PIS(VID2_FIFO_UNDERFLOW), -		dss_feat_get_num_ovls() > 3 ? PIS(VID3_FIFO_UNDERFLOW) : "", -		PIS(SYNC_LOST), -		PIS(SYNC_LOST_DIGIT), -		dss_has_feature(FEAT_MGR_LCD2) ? PIS(SYNC_LOST2) : "", -		dss_has_feature(FEAT_MGR_LCD3) ? PIS(SYNC_LOST3) : ""); -#undef PIS -} - -/* Called from dss.c. Note that we don't touch clocks here, - * but we presume they are on because we got an IRQ. However, - * an irq handler may turn the clocks off, so we may not have - * clock later in the function. */ -static irqreturn_t omap_dispc_irq_handler(int irq, void *arg) -{ -	int i; -	u32 irqstatus, irqenable; -	u32 handledirqs = 0; -	u32 unhandled_errors; -	struct omap_dispc_isr_data *isr_data; -	struct omap_dispc_isr_data registered_isr[DISPC_MAX_NR_ISRS]; - -	spin_lock(&dispc_compat.irq_lock); - -	irqstatus = dispc_read_irqstatus(); -	irqenable = dispc_read_irqenable(); - -	/* IRQ is not for us */ -	if (!(irqstatus & irqenable)) { -		spin_unlock(&dispc_compat.irq_lock); -		return IRQ_NONE; -	} - -#ifdef CONFIG_OMAP2_DSS_COLLECT_IRQ_STATS -	spin_lock(&dispc_compat.irq_stats_lock); -	dispc_compat.irq_stats.irq_count++; -	dss_collect_irq_stats(irqstatus, dispc_compat.irq_stats.irqs); -	spin_unlock(&dispc_compat.irq_stats_lock); -#endif - -	print_irq_status(irqstatus); - -	/* Ack the interrupt. Do it here before clocks are possibly turned -	 * off */ -	dispc_clear_irqstatus(irqstatus); -	/* flush posted write */ -	dispc_read_irqstatus(); - -	/* make a copy and unlock, so that isrs can unregister -	 * themselves */ -	memcpy(registered_isr, dispc_compat.registered_isr, -			sizeof(registered_isr)); - -	spin_unlock(&dispc_compat.irq_lock); - -	for (i = 0; i < DISPC_MAX_NR_ISRS; i++) { -		isr_data = ®istered_isr[i]; - -		if (!isr_data->isr) -			continue; - -		if (isr_data->mask & irqstatus) { -			isr_data->isr(isr_data->arg, irqstatus); -			handledirqs |= isr_data->mask; -		} -	} - -	spin_lock(&dispc_compat.irq_lock); - -	unhandled_errors = irqstatus & ~handledirqs & dispc_compat.irq_error_mask; - -	if (unhandled_errors) { -		dispc_compat.error_irqs |= unhandled_errors; - -		dispc_compat.irq_error_mask &= ~unhandled_errors; -		_omap_dispc_set_irqs(); - -		schedule_work(&dispc_compat.error_work); -	} - -	spin_unlock(&dispc_compat.irq_lock); - -	return IRQ_HANDLED; -} - -static void dispc_error_worker(struct work_struct *work) -{ -	int i; -	u32 errors; -	unsigned long flags; -	static const unsigned fifo_underflow_bits[] = { -		DISPC_IRQ_GFX_FIFO_UNDERFLOW, -		DISPC_IRQ_VID1_FIFO_UNDERFLOW, -		DISPC_IRQ_VID2_FIFO_UNDERFLOW, -		DISPC_IRQ_VID3_FIFO_UNDERFLOW, -	}; - -	spin_lock_irqsave(&dispc_compat.irq_lock, flags); -	errors = dispc_compat.error_irqs; -	dispc_compat.error_irqs = 0; -	spin_unlock_irqrestore(&dispc_compat.irq_lock, flags); - -	dispc_runtime_get(); - -	for (i = 0; i < omap_dss_get_num_overlays(); ++i) { -		struct omap_overlay *ovl; -		unsigned bit; - -		ovl = omap_dss_get_overlay(i); -		bit = fifo_underflow_bits[i]; - -		if (bit & errors) { -			DSSERR("FIFO UNDERFLOW on %s, disabling the overlay\n", -					ovl->name); -			ovl->disable(ovl); -			msleep(50); -		} -	} - -	for (i = 0; i < omap_dss_get_num_overlay_managers(); ++i) { -		struct omap_overlay_manager *mgr; -		unsigned bit; - -		mgr = omap_dss_get_overlay_manager(i); -		bit = dispc_mgr_get_sync_lost_irq(i); - -		if (bit & errors) { -			int j; - -			DSSERR("SYNC_LOST on channel %s, restarting the output " -					"with video overlays disabled\n", -					mgr->name); - -			dss_mgr_disable(mgr); - -			for (j = 0; j < omap_dss_get_num_overlays(); ++j) { -				struct omap_overlay *ovl; -				ovl = omap_dss_get_overlay(j); - -				if (ovl->id != OMAP_DSS_GFX && -						ovl->manager == mgr) -					ovl->disable(ovl); -			} - -			dss_mgr_enable(mgr); -		} -	} - -	if (errors & DISPC_IRQ_OCP_ERR) { -		DSSERR("OCP_ERR\n"); -		for (i = 0; i < omap_dss_get_num_overlay_managers(); ++i) { -			struct omap_overlay_manager *mgr; - -			mgr = omap_dss_get_overlay_manager(i); -			dss_mgr_disable(mgr); -		} -	} - -	spin_lock_irqsave(&dispc_compat.irq_lock, flags); -	dispc_compat.irq_error_mask |= errors; -	_omap_dispc_set_irqs(); -	spin_unlock_irqrestore(&dispc_compat.irq_lock, flags); - -	dispc_runtime_put(); -} - -int dss_dispc_initialize_irq(void) -{ -	int r; - -#ifdef CONFIG_OMAP2_DSS_COLLECT_IRQ_STATS -	spin_lock_init(&dispc_compat.irq_stats_lock); -	dispc_compat.irq_stats.last_reset = jiffies; -	dss_debugfs_create_file("dispc_irq", dispc_dump_irqs); -#endif - -	spin_lock_init(&dispc_compat.irq_lock); - -	memset(dispc_compat.registered_isr, 0, -			sizeof(dispc_compat.registered_isr)); - -	dispc_compat.irq_error_mask = DISPC_IRQ_MASK_ERROR; -	if (dss_has_feature(FEAT_MGR_LCD2)) -		dispc_compat.irq_error_mask |= DISPC_IRQ_SYNC_LOST2; -	if (dss_has_feature(FEAT_MGR_LCD3)) -		dispc_compat.irq_error_mask |= DISPC_IRQ_SYNC_LOST3; -	if (dss_feat_get_num_ovls() > 3) -		dispc_compat.irq_error_mask |= DISPC_IRQ_VID3_FIFO_UNDERFLOW; - -	/* -	 * there's SYNC_LOST_DIGIT waiting after enabling the DSS, -	 * so clear it -	 */ -	dispc_clear_irqstatus(dispc_read_irqstatus()); - -	INIT_WORK(&dispc_compat.error_work, dispc_error_worker); - -	_omap_dispc_set_irqs(); - -	r = dispc_request_irq(omap_dispc_irq_handler, &dispc_compat); -	if (r) { -		DSSERR("dispc_request_irq failed\n"); -		return r; -	} - -	return 0; -} - -void dss_dispc_uninitialize_irq(void) -{ -	dispc_free_irq(&dispc_compat); -} - -static void dispc_mgr_disable_isr(void *data, u32 mask) -{ -	struct completion *compl = data; -	complete(compl); -} - -static void dispc_mgr_enable_lcd_out(enum omap_channel channel) -{ -	dispc_mgr_enable(channel, true); -} - -static void dispc_mgr_disable_lcd_out(enum omap_channel channel) -{ -	DECLARE_COMPLETION_ONSTACK(framedone_compl); -	int r; -	u32 irq; - -	if (dispc_mgr_is_enabled(channel) == false) -		return; - -	/* -	 * When we disable LCD output, we need to wait for FRAMEDONE to know -	 * that DISPC has finished with the LCD output. -	 */ - -	irq = dispc_mgr_get_framedone_irq(channel); - -	r = omap_dispc_register_isr(dispc_mgr_disable_isr, &framedone_compl, -			irq); -	if (r) -		DSSERR("failed to register FRAMEDONE isr\n"); - -	dispc_mgr_enable(channel, false); - -	/* if we couldn't register for framedone, just sleep and exit */ -	if (r) { -		msleep(100); -		return; -	} - -	if (!wait_for_completion_timeout(&framedone_compl, -				msecs_to_jiffies(100))) -		DSSERR("timeout waiting for FRAME DONE\n"); - -	r = omap_dispc_unregister_isr(dispc_mgr_disable_isr, &framedone_compl, -			irq); -	if (r) -		DSSERR("failed to unregister FRAMEDONE isr\n"); -} - -static void dispc_digit_out_enable_isr(void *data, u32 mask) -{ -	struct completion *compl = data; - -	/* ignore any sync lost interrupts */ -	if (mask & (DISPC_IRQ_EVSYNC_EVEN | DISPC_IRQ_EVSYNC_ODD)) -		complete(compl); -} - -static void dispc_mgr_enable_digit_out(void) -{ -	DECLARE_COMPLETION_ONSTACK(vsync_compl); -	int r; -	u32 irq_mask; - -	if (dispc_mgr_is_enabled(OMAP_DSS_CHANNEL_DIGIT) == true) -		return; - -	/* -	 * Digit output produces some sync lost interrupts during the first -	 * frame when enabling. Those need to be ignored, so we register for the -	 * sync lost irq to prevent the error handler from triggering. -	 */ - -	irq_mask = dispc_mgr_get_vsync_irq(OMAP_DSS_CHANNEL_DIGIT) | -		dispc_mgr_get_sync_lost_irq(OMAP_DSS_CHANNEL_DIGIT); - -	r = omap_dispc_register_isr(dispc_digit_out_enable_isr, &vsync_compl, -			irq_mask); -	if (r) { -		DSSERR("failed to register %x isr\n", irq_mask); -		return; -	} - -	dispc_mgr_enable(OMAP_DSS_CHANNEL_DIGIT, true); - -	/* wait for the first evsync */ -	if (!wait_for_completion_timeout(&vsync_compl, msecs_to_jiffies(100))) -		DSSERR("timeout waiting for digit out to start\n"); - -	r = omap_dispc_unregister_isr(dispc_digit_out_enable_isr, &vsync_compl, -			irq_mask); -	if (r) -		DSSERR("failed to unregister %x isr\n", irq_mask); -} - -static void dispc_mgr_disable_digit_out(void) -{ -	DECLARE_COMPLETION_ONSTACK(framedone_compl); -	int r, i; -	u32 irq_mask; -	int num_irqs; - -	if (dispc_mgr_is_enabled(OMAP_DSS_CHANNEL_DIGIT) == false) -		return; - -	/* -	 * When we disable the digit output, we need to wait for FRAMEDONE to -	 * know that DISPC has finished with the output. -	 */ - -	irq_mask = dispc_mgr_get_framedone_irq(OMAP_DSS_CHANNEL_DIGIT); -	num_irqs = 1; - -	if (!irq_mask) { -		/* -		 * omap 2/3 don't have framedone irq for TV, so we need to use -		 * vsyncs for this. -		 */ - -		irq_mask = dispc_mgr_get_vsync_irq(OMAP_DSS_CHANNEL_DIGIT); -		/* -		 * We need to wait for both even and odd vsyncs. Note that this -		 * is not totally reliable, as we could get a vsync interrupt -		 * before we disable the output, which leads to timeout in the -		 * wait_for_completion. -		 */ -		num_irqs = 2; -	} - -	r = omap_dispc_register_isr(dispc_mgr_disable_isr, &framedone_compl, -			irq_mask); -	if (r) -		DSSERR("failed to register %x isr\n", irq_mask); - -	dispc_mgr_enable(OMAP_DSS_CHANNEL_DIGIT, false); - -	/* if we couldn't register the irq, just sleep and exit */ -	if (r) { -		msleep(100); -		return; -	} - -	for (i = 0; i < num_irqs; ++i) { -		if (!wait_for_completion_timeout(&framedone_compl, -					msecs_to_jiffies(100))) -			DSSERR("timeout waiting for digit out to stop\n"); -	} - -	r = omap_dispc_unregister_isr(dispc_mgr_disable_isr, &framedone_compl, -			irq_mask); -	if (r) -		DSSERR("failed to unregister %x isr\n", irq_mask); -} - -void dispc_mgr_enable_sync(enum omap_channel channel) -{ -	if (dss_mgr_is_lcd(channel)) -		dispc_mgr_enable_lcd_out(channel); -	else if (channel == OMAP_DSS_CHANNEL_DIGIT) -		dispc_mgr_enable_digit_out(); -	else -		WARN_ON(1); -} - -void dispc_mgr_disable_sync(enum omap_channel channel) -{ -	if (dss_mgr_is_lcd(channel)) -		dispc_mgr_disable_lcd_out(channel); -	else if (channel == OMAP_DSS_CHANNEL_DIGIT) -		dispc_mgr_disable_digit_out(); -	else -		WARN_ON(1); -} - -int omap_dispc_wait_for_irq_interruptible_timeout(u32 irqmask, -		unsigned long timeout) -{ -	void dispc_irq_wait_handler(void *data, u32 mask) -	{ -		complete((struct completion *)data); -	} - -	int r; -	DECLARE_COMPLETION_ONSTACK(completion); - -	r = omap_dispc_register_isr(dispc_irq_wait_handler, &completion, -			irqmask); - -	if (r) -		return r; - -	timeout = wait_for_completion_interruptible_timeout(&completion, -			timeout); - -	omap_dispc_unregister_isr(dispc_irq_wait_handler, &completion, irqmask); - -	if (timeout == 0) -		return -ETIMEDOUT; - -	if (timeout == -ERESTARTSYS) -		return -ERESTARTSYS; - -	return 0; -}  | 
