summary refs log tree commit diff
path: root/drivers/video/omap2/dss/apply.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/video/omap2/dss/apply.c')
-rw-r--r--drivers/video/omap2/dss/apply.c330
1 files changed, 82 insertions, 248 deletions
diff --git a/drivers/video/omap2/dss/apply.c b/drivers/video/omap2/dss/apply.c
index 0fefc68372b9..19d66f471b4b 100644
--- a/drivers/video/omap2/dss/apply.c
+++ b/drivers/video/omap2/dss/apply.c
@@ -111,9 +111,6 @@ static struct {
 	struct ovl_priv_data ovl_priv_data_array[MAX_DSS_OVERLAYS];
 	struct mgr_priv_data mgr_priv_data_array[MAX_DSS_MANAGERS];
 
-	bool fifo_merge_dirty;
-	bool fifo_merge;
-
 	bool irq_enabled;
 } dss_data;
 
@@ -424,17 +421,25 @@ static void wait_pending_extra_info_updates(void)
 int dss_mgr_wait_for_go(struct omap_overlay_manager *mgr)
 {
 	unsigned long timeout = msecs_to_jiffies(500);
-	struct mgr_priv_data *mp;
+	struct mgr_priv_data *mp = get_mgr_priv(mgr);
 	u32 irq;
+	unsigned long flags;
 	int r;
 	int i;
-	struct omap_dss_device *dssdev = mgr->device;
 
-	if (!dssdev || dssdev->state != OMAP_DSS_DISPLAY_ACTIVE)
+	spin_lock_irqsave(&data_lock, flags);
+
+	if (mgr_manual_update(mgr)) {
+		spin_unlock_irqrestore(&data_lock, flags);
 		return 0;
+	}
 
-	if (mgr_manual_update(mgr))
+	if (!mp->enabled) {
+		spin_unlock_irqrestore(&data_lock, flags);
 		return 0;
+	}
+
+	spin_unlock_irqrestore(&data_lock, flags);
 
 	r = dispc_runtime_get();
 	if (r)
@@ -442,10 +447,8 @@ int dss_mgr_wait_for_go(struct omap_overlay_manager *mgr)
 
 	irq = dispc_mgr_get_vsync_irq(mgr->id);
 
-	mp = get_mgr_priv(mgr);
 	i = 0;
 	while (1) {
-		unsigned long flags;
 		bool shadow_dirty, dirty;
 
 		spin_lock_irqsave(&data_lock, flags);
@@ -489,21 +492,30 @@ int dss_mgr_wait_for_go_ovl(struct omap_overlay *ovl)
 {
 	unsigned long timeout = msecs_to_jiffies(500);
 	struct ovl_priv_data *op;
-	struct omap_dss_device *dssdev;
+	struct mgr_priv_data *mp;
 	u32 irq;
+	unsigned long flags;
 	int r;
 	int i;
 
 	if (!ovl->manager)
 		return 0;
 
-	dssdev = ovl->manager->device;
+	mp = get_mgr_priv(ovl->manager);
+
+	spin_lock_irqsave(&data_lock, flags);
 
-	if (!dssdev || dssdev->state != OMAP_DSS_DISPLAY_ACTIVE)
+	if (ovl_manual_update(ovl)) {
+		spin_unlock_irqrestore(&data_lock, flags);
 		return 0;
+	}
 
-	if (ovl_manual_update(ovl))
+	if (!mp->enabled) {
+		spin_unlock_irqrestore(&data_lock, flags);
 		return 0;
+	}
+
+	spin_unlock_irqrestore(&data_lock, flags);
 
 	r = dispc_runtime_get();
 	if (r)
@@ -514,7 +526,6 @@ int dss_mgr_wait_for_go_ovl(struct omap_overlay *ovl)
 	op = get_ovl_priv(ovl);
 	i = 0;
 	while (1) {
-		unsigned long flags;
 		bool shadow_dirty, dirty;
 
 		spin_lock_irqsave(&data_lock, flags);
@@ -573,7 +584,7 @@ static void dss_ovl_write_regs(struct omap_overlay *ovl)
 
 	replication = dss_ovl_use_replication(mp->lcd_config, oi->color_mode);
 
-	r = dispc_ovl_setup(ovl->id, oi, replication, &mp->timings);
+	r = dispc_ovl_setup(ovl->id, oi, replication, &mp->timings, false);
 	if (r) {
 		/*
 		 * We can't do much here, as this function can be called from
@@ -677,40 +688,11 @@ static void dss_mgr_write_regs_extra(struct omap_overlay_manager *mgr)
 		mp->shadow_extra_info_dirty = true;
 }
 
-static void dss_write_regs_common(void)
-{
-	const int num_mgrs = omap_dss_get_num_overlay_managers();
-	int i;
-
-	if (!dss_data.fifo_merge_dirty)
-		return;
-
-	for (i = 0; i < num_mgrs; ++i) {
-		struct omap_overlay_manager *mgr;
-		struct mgr_priv_data *mp;
-
-		mgr = omap_dss_get_overlay_manager(i);
-		mp = get_mgr_priv(mgr);
-
-		if (mp->enabled) {
-			if (dss_data.fifo_merge_dirty) {
-				dispc_enable_fifomerge(dss_data.fifo_merge);
-				dss_data.fifo_merge_dirty = false;
-			}
-
-			if (mp->updating)
-				mp->shadow_info_dirty = true;
-		}
-	}
-}
-
 static void dss_write_regs(void)
 {
 	const int num_mgrs = omap_dss_get_num_overlay_managers();
 	int i;
 
-	dss_write_regs_common();
-
 	for (i = 0; i < num_mgrs; ++i) {
 		struct omap_overlay_manager *mgr;
 		struct mgr_priv_data *mp;
@@ -799,8 +781,6 @@ void dss_mgr_start_update(struct omap_overlay_manager *mgr)
 	dss_mgr_write_regs(mgr);
 	dss_mgr_write_regs_extra(mgr);
 
-	dss_write_regs_common();
-
 	mp->updating = true;
 
 	if (!dss_data.irq_enabled && need_isr())
@@ -984,20 +964,11 @@ static void dss_apply_ovl_fifo_thresholds(struct omap_overlay *ovl,
 	op->extra_info_dirty = true;
 }
 
-static void dss_apply_fifo_merge(bool use_fifo_merge)
-{
-	if (dss_data.fifo_merge == use_fifo_merge)
-		return;
-
-	dss_data.fifo_merge = use_fifo_merge;
-	dss_data.fifo_merge_dirty = true;
-}
-
-static void dss_ovl_setup_fifo(struct omap_overlay *ovl,
-		bool use_fifo_merge)
+static void dss_ovl_setup_fifo(struct omap_overlay *ovl)
 {
 	struct ovl_priv_data *op = get_ovl_priv(ovl);
 	u32 fifo_low, fifo_high;
+	bool use_fifo_merge = false;
 
 	if (!op->enabled && !op->enabling)
 		return;
@@ -1008,8 +979,7 @@ static void dss_ovl_setup_fifo(struct omap_overlay *ovl,
 	dss_apply_ovl_fifo_thresholds(ovl, fifo_low, fifo_high);
 }
 
-static void dss_mgr_setup_fifos(struct omap_overlay_manager *mgr,
-		bool use_fifo_merge)
+static void dss_mgr_setup_fifos(struct omap_overlay_manager *mgr)
 {
 	struct omap_overlay *ovl;
 	struct mgr_priv_data *mp;
@@ -1020,94 +990,19 @@ static void dss_mgr_setup_fifos(struct omap_overlay_manager *mgr,
 		return;
 
 	list_for_each_entry(ovl, &mgr->overlays, list)
-		dss_ovl_setup_fifo(ovl, use_fifo_merge);
-}
-
-static void dss_setup_fifos(bool use_fifo_merge)
-{
-	const int num_mgrs = omap_dss_get_num_overlay_managers();
-	struct omap_overlay_manager *mgr;
-	int i;
-
-	for (i = 0; i < num_mgrs; ++i) {
-		mgr = omap_dss_get_overlay_manager(i);
-		dss_mgr_setup_fifos(mgr, use_fifo_merge);
-	}
+		dss_ovl_setup_fifo(ovl);
 }
 
-static int get_num_used_managers(void)
+static void dss_setup_fifos(void)
 {
 	const int num_mgrs = omap_dss_get_num_overlay_managers();
 	struct omap_overlay_manager *mgr;
-	struct mgr_priv_data *mp;
 	int i;
-	int enabled_mgrs;
-
-	enabled_mgrs = 0;
 
 	for (i = 0; i < num_mgrs; ++i) {
 		mgr = omap_dss_get_overlay_manager(i);
-		mp = get_mgr_priv(mgr);
-
-		if (!mp->enabled)
-			continue;
-
-		enabled_mgrs++;
+		dss_mgr_setup_fifos(mgr);
 	}
-
-	return enabled_mgrs;
-}
-
-static int get_num_used_overlays(void)
-{
-	const int num_ovls = omap_dss_get_num_overlays();
-	struct omap_overlay *ovl;
-	struct ovl_priv_data *op;
-	struct mgr_priv_data *mp;
-	int i;
-	int enabled_ovls;
-
-	enabled_ovls = 0;
-
-	for (i = 0; i < num_ovls; ++i) {
-		ovl = omap_dss_get_overlay(i);
-		op = get_ovl_priv(ovl);
-
-		if (!op->enabled && !op->enabling)
-			continue;
-
-		mp = get_mgr_priv(ovl->manager);
-
-		if (!mp->enabled)
-			continue;
-
-		enabled_ovls++;
-	}
-
-	return enabled_ovls;
-}
-
-static bool get_use_fifo_merge(void)
-{
-	int enabled_mgrs = get_num_used_managers();
-	int enabled_ovls = get_num_used_overlays();
-
-	if (!dss_has_feature(FEAT_FIFO_MERGE))
-		return false;
-
-	/*
-	 * In theory the only requirement for fifomerge is enabled_ovls <= 1.
-	 * However, if we have two managers enabled and set/unset the fifomerge,
-	 * we need to set the GO bits in particular sequence for the managers,
-	 * and wait in between.
-	 *
-	 * This is rather difficult as new apply calls can happen at any time,
-	 * so we simplify the problem by requiring also that enabled_mgrs <= 1.
-	 * In practice this shouldn't matter, because when only one overlay is
-	 * enabled, most likely only one output is enabled.
-	 */
-
-	return enabled_mgrs <= 1 && enabled_ovls <= 1;
 }
 
 int dss_mgr_enable(struct omap_overlay_manager *mgr)
@@ -1115,7 +1010,6 @@ int dss_mgr_enable(struct omap_overlay_manager *mgr)
 	struct mgr_priv_data *mp = get_mgr_priv(mgr);
 	unsigned long flags;
 	int r;
-	bool fifo_merge;
 
 	mutex_lock(&apply_lock);
 
@@ -1133,23 +1027,11 @@ int dss_mgr_enable(struct omap_overlay_manager *mgr)
 		goto err;
 	}
 
-	/* step 1: setup fifos/fifomerge before enabling the manager */
-
-	fifo_merge = get_use_fifo_merge();
-	dss_setup_fifos(fifo_merge);
-	dss_apply_fifo_merge(fifo_merge);
+	dss_setup_fifos();
 
 	dss_write_regs();
 	dss_set_go_bits();
 
-	spin_unlock_irqrestore(&data_lock, flags);
-
-	/* wait until fifo config is in */
-	wait_pending_extra_info_updates();
-
-	/* step 2: enable the manager */
-	spin_lock_irqsave(&data_lock, flags);
-
 	if (!mgr_manual_update(mgr))
 		mp->updating = true;
 
@@ -1174,7 +1056,6 @@ void dss_mgr_disable(struct omap_overlay_manager *mgr)
 {
 	struct mgr_priv_data *mp = get_mgr_priv(mgr);
 	unsigned long flags;
-	bool fifo_merge;
 
 	mutex_lock(&apply_lock);
 
@@ -1189,16 +1070,8 @@ void dss_mgr_disable(struct omap_overlay_manager *mgr)
 	mp->updating = false;
 	mp->enabled = false;
 
-	fifo_merge = get_use_fifo_merge();
-	dss_setup_fifos(fifo_merge);
-	dss_apply_fifo_merge(fifo_merge);
-
-	dss_write_regs();
-	dss_set_go_bits();
-
 	spin_unlock_irqrestore(&data_lock, flags);
 
-	wait_pending_extra_info_updates();
 out:
 	mutex_unlock(&apply_lock);
 }
@@ -1237,29 +1110,29 @@ void dss_mgr_get_info(struct omap_overlay_manager *mgr,
 	spin_unlock_irqrestore(&data_lock, flags);
 }
 
-int dss_mgr_set_device(struct omap_overlay_manager *mgr,
-		struct omap_dss_device *dssdev)
+int dss_mgr_set_output(struct omap_overlay_manager *mgr,
+		struct omap_dss_output *output)
 {
 	int r;
 
 	mutex_lock(&apply_lock);
 
-	if (dssdev->manager) {
-		DSSERR("display '%s' already has a manager '%s'\n",
-			       dssdev->name, dssdev->manager->name);
+	if (mgr->output) {
+		DSSERR("manager %s is already connected to an output\n",
+			mgr->name);
 		r = -EINVAL;
 		goto err;
 	}
 
-	if ((mgr->supported_displays & dssdev->type) == 0) {
-		DSSERR("display '%s' does not support manager '%s'\n",
-			       dssdev->name, mgr->name);
+	if ((mgr->supported_outputs & output->id) == 0) {
+		DSSERR("output does not support manager %s\n",
+			mgr->name);
 		r = -EINVAL;
 		goto err;
 	}
 
-	dssdev->manager = mgr;
-	mgr->device = dssdev;
+	output->manager = mgr;
+	mgr->output = output;
 
 	mutex_unlock(&apply_lock);
 
@@ -1269,40 +1142,46 @@ err:
 	return r;
 }
 
-int dss_mgr_unset_device(struct omap_overlay_manager *mgr)
+int dss_mgr_unset_output(struct omap_overlay_manager *mgr)
 {
 	int r;
+	struct mgr_priv_data *mp = get_mgr_priv(mgr);
+	unsigned long flags;
 
 	mutex_lock(&apply_lock);
 
-	if (!mgr->device) {
-		DSSERR("failed to unset display, display not set.\n");
+	if (!mgr->output) {
+		DSSERR("failed to unset output, output not set\n");
 		r = -EINVAL;
 		goto err;
 	}
 
-	/*
-	 * Don't allow currently enabled displays to have the overlay manager
-	 * pulled out from underneath them
-	 */
-	if (mgr->device->state != OMAP_DSS_DISPLAY_DISABLED) {
+	spin_lock_irqsave(&data_lock, flags);
+
+	if (mp->enabled) {
+		DSSERR("output can't be unset when manager is enabled\n");
 		r = -EINVAL;
-		goto err;
+		goto err1;
 	}
 
-	mgr->device->manager = NULL;
-	mgr->device = NULL;
+	spin_unlock_irqrestore(&data_lock, flags);
+
+	mgr->output->manager = NULL;
+	mgr->output = NULL;
 
 	mutex_unlock(&apply_lock);
 
 	return 0;
+err1:
+	spin_unlock_irqrestore(&data_lock, flags);
 err:
 	mutex_unlock(&apply_lock);
+
 	return r;
 }
 
 static void dss_apply_mgr_timings(struct omap_overlay_manager *mgr,
-		struct omap_video_timings *timings)
+		const struct omap_video_timings *timings)
 {
 	struct mgr_priv_data *mp = get_mgr_priv(mgr);
 
@@ -1311,24 +1190,22 @@ static void dss_apply_mgr_timings(struct omap_overlay_manager *mgr,
 }
 
 void dss_mgr_set_timings(struct omap_overlay_manager *mgr,
-		struct omap_video_timings *timings)
+		const struct omap_video_timings *timings)
 {
 	unsigned long flags;
-
-	mutex_lock(&apply_lock);
+	struct mgr_priv_data *mp = get_mgr_priv(mgr);
 
 	spin_lock_irqsave(&data_lock, flags);
 
-	dss_apply_mgr_timings(mgr, timings);
-
-	dss_write_regs();
-	dss_set_go_bits();
+	if (mp->updating) {
+		DSSERR("cannot set timings for %s: manager needs to be disabled\n",
+			mgr->name);
+		goto out;
+	}
 
+	dss_apply_mgr_timings(mgr, timings);
+out:
 	spin_unlock_irqrestore(&data_lock, flags);
-
-	wait_pending_extra_info_updates();
-
-	mutex_unlock(&apply_lock);
 }
 
 static void dss_apply_mgr_lcd_config(struct omap_overlay_manager *mgr,
@@ -1346,7 +1223,7 @@ void dss_mgr_set_lcd_config(struct omap_overlay_manager *mgr,
 	unsigned long flags;
 	struct mgr_priv_data *mp = get_mgr_priv(mgr);
 
-	mutex_lock(&apply_lock);
+	spin_lock_irqsave(&data_lock, flags);
 
 	if (mp->enabled) {
 		DSSERR("cannot apply lcd config for %s: manager needs to be disabled\n",
@@ -1354,19 +1231,9 @@ void dss_mgr_set_lcd_config(struct omap_overlay_manager *mgr,
 		goto out;
 	}
 
-	spin_lock_irqsave(&data_lock, flags);
-
 	dss_apply_mgr_lcd_config(mgr, config);
-
-	dss_write_regs();
-	dss_set_go_bits();
-
-	spin_unlock_irqrestore(&data_lock, flags);
-
-	wait_pending_extra_info_updates();
-
 out:
-	mutex_unlock(&apply_lock);
+	spin_unlock_irqrestore(&data_lock, flags);
 }
 
 int dss_ovl_set_info(struct omap_overlay *ovl,
@@ -1483,6 +1350,13 @@ int dss_ovl_unset_manager(struct omap_overlay *ovl)
 		goto err;
 	}
 
+	spin_unlock_irqrestore(&data_lock, flags);
+
+	/* wait for pending extra_info updates to ensure the ovl is disabled */
+	wait_pending_extra_info_updates();
+
+	spin_lock_irqsave(&data_lock, flags);
+
 	op->channel = -1;
 
 	ovl->manager = NULL;
@@ -1517,7 +1391,6 @@ int dss_ovl_enable(struct omap_overlay *ovl)
 {
 	struct ovl_priv_data *op = get_ovl_priv(ovl);
 	unsigned long flags;
-	bool fifo_merge;
 	int r;
 
 	mutex_lock(&apply_lock);
@@ -1527,7 +1400,7 @@ int dss_ovl_enable(struct omap_overlay *ovl)
 		goto err1;
 	}
 
-	if (ovl->manager == NULL || ovl->manager->device == NULL) {
+	if (ovl->manager == NULL || ovl->manager->output == NULL) {
 		r = -EINVAL;
 		goto err1;
 	}
@@ -1543,22 +1416,7 @@ int dss_ovl_enable(struct omap_overlay *ovl)
 		goto err2;
 	}
 
-	/* step 1: configure fifos/fifomerge for currently enabled ovls */
-
-	fifo_merge = get_use_fifo_merge();
-	dss_setup_fifos(fifo_merge);
-	dss_apply_fifo_merge(fifo_merge);
-
-	dss_write_regs();
-	dss_set_go_bits();
-
-	spin_unlock_irqrestore(&data_lock, flags);
-
-	/* wait for fifo configs to go in */
-	wait_pending_extra_info_updates();
-
-	/* step 2: enable the overlay */
-	spin_lock_irqsave(&data_lock, flags);
+	dss_setup_fifos();
 
 	op->enabling = false;
 	dss_apply_ovl_enable(ovl, true);
@@ -1568,9 +1426,6 @@ int dss_ovl_enable(struct omap_overlay *ovl)
 
 	spin_unlock_irqrestore(&data_lock, flags);
 
-	/* wait for overlay to be enabled */
-	wait_pending_extra_info_updates();
-
 	mutex_unlock(&apply_lock);
 
 	return 0;
@@ -1586,7 +1441,6 @@ int dss_ovl_disable(struct omap_overlay *ovl)
 {
 	struct ovl_priv_data *op = get_ovl_priv(ovl);
 	unsigned long flags;
-	bool fifo_merge;
 	int r;
 
 	mutex_lock(&apply_lock);
@@ -1596,39 +1450,19 @@ int dss_ovl_disable(struct omap_overlay *ovl)
 		goto err;
 	}
 
-	if (ovl->manager == NULL || ovl->manager->device == NULL) {
+	if (ovl->manager == NULL || ovl->manager->output == NULL) {
 		r = -EINVAL;
 		goto err;
 	}
 
-	/* step 1: disable the overlay */
 	spin_lock_irqsave(&data_lock, flags);
 
 	dss_apply_ovl_enable(ovl, false);
-
 	dss_write_regs();
 	dss_set_go_bits();
 
 	spin_unlock_irqrestore(&data_lock, flags);
 
-	/* wait for the overlay to be disabled */
-	wait_pending_extra_info_updates();
-
-	/* step 2: configure fifos/fifomerge */
-	spin_lock_irqsave(&data_lock, flags);
-
-	fifo_merge = get_use_fifo_merge();
-	dss_setup_fifos(fifo_merge);
-	dss_apply_fifo_merge(fifo_merge);
-
-	dss_write_regs();
-	dss_set_go_bits();
-
-	spin_unlock_irqrestore(&data_lock, flags);
-
-	/* wait for fifo config to go in */
-	wait_pending_extra_info_updates();
-
 	mutex_unlock(&apply_lock);
 
 	return 0;