diff options
Diffstat (limited to 'drivers/video/omap2/dss/apply.c')
| -rw-r--r-- | drivers/video/omap2/dss/apply.c | 330 | 
1 files changed, 82 insertions, 248 deletions
diff --git a/drivers/video/omap2/dss/apply.c b/drivers/video/omap2/dss/apply.c index 0fefc68372b..19d66f471b4 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;  |