diff options
Diffstat (limited to 'drivers/video/omap2/omapfb/omapfb-main.c')
| -rw-r--r-- | drivers/video/omap2/omapfb/omapfb-main.c | 166 | 
1 files changed, 133 insertions, 33 deletions
| diff --git a/drivers/video/omap2/omapfb/omapfb-main.c b/drivers/video/omap2/omapfb/omapfb-main.c index 505bc12a3031..602b71a92d3c 100644 --- a/drivers/video/omap2/omapfb/omapfb-main.c +++ b/drivers/video/omap2/omapfb/omapfb-main.c @@ -46,6 +46,10 @@ static char *def_vram;  static int def_vrfb;  static int def_rotate;  static int def_mirror; +static bool auto_update; +static unsigned int auto_update_freq; +module_param(auto_update, bool, 0); +module_param(auto_update_freq, uint, 0644);  #ifdef DEBUG  unsigned int omapfb_debug; @@ -1242,6 +1246,7 @@ static int omapfb_blank(int blank, struct fb_info *fbi)  	struct omapfb_info *ofbi = FB2OFB(fbi);  	struct omapfb2_device *fbdev = ofbi->fbdev;  	struct omap_dss_device *display = fb2display(fbi); +	struct omapfb_display_data *d;  	int r = 0;  	if (!display) @@ -1249,6 +1254,8 @@ static int omapfb_blank(int blank, struct fb_info *fbi)  	omapfb_lock(fbdev); +	d = get_display_data(fbdev, display); +  	switch (blank) {  	case FB_BLANK_UNBLANK:  		if (display->state != OMAP_DSS_DISPLAY_SUSPENDED) @@ -1257,6 +1264,11 @@ static int omapfb_blank(int blank, struct fb_info *fbi)  		if (display->driver->resume)  			r = display->driver->resume(display); +		if ((display->caps & OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE) && +				d->update_mode == OMAPFB_AUTO_UPDATE && +				!d->auto_update_work_enabled) +			omapfb_start_auto_update(fbdev, display); +  		break;  	case FB_BLANK_NORMAL: @@ -1268,6 +1280,9 @@ static int omapfb_blank(int blank, struct fb_info *fbi)  		if (display->state != OMAP_DSS_DISPLAY_ACTIVE)  			goto exit; +		if (d->auto_update_work_enabled) +			omapfb_stop_auto_update(fbdev, display); +  		if (display->driver->suspend)  			r = display->driver->suspend(display); @@ -1724,6 +1739,78 @@ err:  	return r;  } +static void omapfb_auto_update_work(struct work_struct *work) +{ +	struct omap_dss_device *dssdev; +	struct omap_dss_driver *dssdrv; +	struct omapfb_display_data *d; +	u16 w, h; +	unsigned int freq; +	struct omapfb2_device *fbdev; + +	d = container_of(work, struct omapfb_display_data, +			auto_update_work.work); + +	dssdev = d->dssdev; +	dssdrv = dssdev->driver; +	fbdev = d->fbdev; + +	if (!dssdrv || !dssdrv->update) +		return; + +	if (dssdrv->sync) +		dssdrv->sync(dssdev); + +	dssdrv->get_resolution(dssdev, &w, &h); +	dssdrv->update(dssdev, 0, 0, w, h); + +	freq = auto_update_freq; +	if (freq == 0) +		freq = 20; +	queue_delayed_work(fbdev->auto_update_wq, +			&d->auto_update_work, HZ / freq); +} + +void omapfb_start_auto_update(struct omapfb2_device *fbdev, +		struct omap_dss_device *display) +{ +	struct omapfb_display_data *d; + +	if (fbdev->auto_update_wq == NULL) { +		struct workqueue_struct *wq; + +		wq = create_singlethread_workqueue("omapfb_auto_update"); + +		if (wq == NULL) { +			dev_err(fbdev->dev, "Failed to create workqueue for " +					"auto-update\n"); +			return; +		} + +		fbdev->auto_update_wq = wq; +	} + +	d = get_display_data(fbdev, display); + +	INIT_DELAYED_WORK(&d->auto_update_work, omapfb_auto_update_work); + +	d->auto_update_work_enabled = true; + +	omapfb_auto_update_work(&d->auto_update_work.work); +} + +void omapfb_stop_auto_update(struct omapfb2_device *fbdev, +		struct omap_dss_device *display) +{ +	struct omapfb_display_data *d; + +	d = get_display_data(fbdev, display); + +	cancel_delayed_work_sync(&d->auto_update_work); + +	d->auto_update_work_enabled = false; +} +  /* initialize fb_info, var, fix to something sane based on the display */  static int omapfb_fb_init(struct omapfb2_device *fbdev, struct fb_info *fbi)  { @@ -1858,10 +1945,21 @@ static void omapfb_free_resources(struct omapfb2_device *fbdev)  	}  	for (i = 0; i < fbdev->num_displays; i++) { -		if (fbdev->displays[i]->state != OMAP_DSS_DISPLAY_DISABLED) -			fbdev->displays[i]->driver->disable(fbdev->displays[i]); +		struct omap_dss_device *dssdev = fbdev->displays[i].dssdev; + +		if (fbdev->displays[i].auto_update_work_enabled) +			omapfb_stop_auto_update(fbdev, dssdev); + +		if (dssdev->state != OMAP_DSS_DISPLAY_DISABLED) +			dssdev->driver->disable(dssdev); + +		omap_dss_put_device(dssdev); +	} -		omap_dss_put_device(fbdev->displays[i]); +	if (fbdev->auto_update_wq != NULL) { +		flush_workqueue(fbdev->auto_update_wq); +		destroy_workqueue(fbdev->auto_update_wq); +		fbdev->auto_update_wq = NULL;  	}  	dev_set_drvdata(fbdev->dev, NULL); @@ -2084,14 +2182,14 @@ static int omapfb_set_def_mode(struct omapfb2_device *fbdev,  	int r;  	u8 bpp;  	struct omap_video_timings timings, temp_timings; +	struct omapfb_display_data *d;  	r = omapfb_mode_to_timings(mode_str, &timings, &bpp);  	if (r)  		return r; -	fbdev->bpp_overrides[fbdev->num_bpp_overrides].dssdev = display; -	fbdev->bpp_overrides[fbdev->num_bpp_overrides].bpp = bpp; -	++fbdev->num_bpp_overrides; +	d = get_display_data(fbdev, display); +	d->bpp_override = bpp;  	if (display->driver->check_timings) {  		r = display->driver->check_timings(display, &timings); @@ -2117,14 +2215,14 @@ static int omapfb_set_def_mode(struct omapfb2_device *fbdev,  static int omapfb_get_recommended_bpp(struct omapfb2_device *fbdev,  		struct omap_dss_device *dssdev)  { -	int i; +	struct omapfb_display_data *d;  	BUG_ON(dssdev->driver->get_recommended_bpp == NULL); -	for (i = 0; i < fbdev->num_bpp_overrides; ++i) { -		if (dssdev == fbdev->bpp_overrides[i].dssdev) -			return fbdev->bpp_overrides[i].bpp; -	} +	d = get_display_data(fbdev, dssdev); + +	if (d->bpp_override != 0) +		return d->bpp_override;  	return dssdev->driver->get_recommended_bpp(dssdev);  } @@ -2156,9 +2254,9 @@ static int omapfb_parse_def_modes(struct omapfb2_device *fbdev)  		display = NULL;  		for (i = 0; i < fbdev->num_displays; ++i) { -			if (strcmp(fbdev->displays[i]->name, +			if (strcmp(fbdev->displays[i].dssdev->name,  						display_str) == 0) { -				display = fbdev->displays[i]; +				display = fbdev->displays[i].dssdev;  				break;  			}  		} @@ -2182,6 +2280,7 @@ static int omapfb_init_display(struct omapfb2_device *fbdev,  		struct omap_dss_device *dssdev)  {  	struct omap_dss_driver *dssdrv = dssdev->driver; +	struct omapfb_display_data *d;  	int r;  	r = dssdrv->enable(dssdev); @@ -2191,8 +2290,20 @@ static int omapfb_init_display(struct omapfb2_device *fbdev,  		return r;  	} +	d = get_display_data(fbdev, dssdev); + +	d->fbdev = fbdev; +  	if (dssdev->caps & OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE) {  		u16 w, h; + +		if (auto_update) { +			omapfb_start_auto_update(fbdev, dssdev); +			d->update_mode = OMAPFB_AUTO_UPDATE; +		} else { +			d->update_mode = OMAPFB_MANUAL_UPDATE; +		} +  		if (dssdrv->enable_te) {  			r = dssdrv->enable_te(dssdev, 1);  			if (r) { @@ -2201,16 +2312,6 @@ static int omapfb_init_display(struct omapfb2_device *fbdev,  			}  		} -		if (dssdrv->set_update_mode) { -			r = dssdrv->set_update_mode(dssdev, -					OMAP_DSS_UPDATE_MANUAL); -			if (r) { -				dev_err(fbdev->dev, -						"Failed to set update mode\n"); -				return r; -			} -		} -  		dssdrv->get_resolution(dssdev, &w, &h);  		r = dssdrv->update(dssdev, 0, 0, w, h);  		if (r) { @@ -2219,15 +2320,7 @@ static int omapfb_init_display(struct omapfb2_device *fbdev,  			return r;  		}  	} else { -		if (dssdrv->set_update_mode) { -			r = dssdrv->set_update_mode(dssdev, -					OMAP_DSS_UPDATE_AUTO); -			if (r) { -				dev_err(fbdev->dev, -						"Failed to set update mode\n"); -				return r; -			} -		} +		d->update_mode = OMAPFB_AUTO_UPDATE;  	}  	return 0; @@ -2275,6 +2368,8 @@ static int omapfb_probe(struct platform_device *pdev)  	fbdev->num_displays = 0;  	dssdev = NULL;  	for_each_dss_dev(dssdev) { +		struct omapfb_display_data *d; +  		omap_dss_get_device(dssdev);  		if (!dssdev->driver) { @@ -2282,7 +2377,12 @@ static int omapfb_probe(struct platform_device *pdev)  			r = -ENODEV;  		} -		fbdev->displays[fbdev->num_displays++] = dssdev; +		d = &fbdev->displays[fbdev->num_displays++]; +		d->dssdev = dssdev; +		if (dssdev->caps & OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE) +			d->update_mode = OMAPFB_MANUAL_UPDATE; +		else +			d->update_mode = OMAPFB_AUTO_UPDATE;  	}  	if (r) | 
