diff options
Diffstat (limited to 'drivers/video/omap2/omapfb/omapfb-main.c')
-rw-r--r-- | drivers/video/omap2/omapfb/omapfb-main.c | 139 |
1 files changed, 119 insertions, 20 deletions
diff --git a/drivers/video/omap2/omapfb/omapfb-main.c b/drivers/video/omap2/omapfb/omapfb-main.c index 44eb666536cc..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; | |||
46 | static int def_vrfb; | 46 | static int def_vrfb; |
47 | static int def_rotate; | 47 | static int def_rotate; |
48 | static int def_mirror; | 48 | static int def_mirror; |
49 | static bool auto_update; | ||
50 | static unsigned int auto_update_freq; | ||
51 | module_param(auto_update, bool, 0); | ||
52 | module_param(auto_update_freq, uint, 0644); | ||
49 | 53 | ||
50 | #ifdef DEBUG | 54 | #ifdef DEBUG |
51 | unsigned int omapfb_debug; | 55 | unsigned int omapfb_debug; |
@@ -1242,6 +1246,7 @@ static int omapfb_blank(int blank, struct fb_info *fbi) | |||
1242 | struct omapfb_info *ofbi = FB2OFB(fbi); | 1246 | struct omapfb_info *ofbi = FB2OFB(fbi); |
1243 | struct omapfb2_device *fbdev = ofbi->fbdev; | 1247 | struct omapfb2_device *fbdev = ofbi->fbdev; |
1244 | struct omap_dss_device *display = fb2display(fbi); | 1248 | struct omap_dss_device *display = fb2display(fbi); |
1249 | struct omapfb_display_data *d; | ||
1245 | int r = 0; | 1250 | int r = 0; |
1246 | 1251 | ||
1247 | if (!display) | 1252 | if (!display) |
@@ -1249,6 +1254,8 @@ static int omapfb_blank(int blank, struct fb_info *fbi) | |||
1249 | 1254 | ||
1250 | omapfb_lock(fbdev); | 1255 | omapfb_lock(fbdev); |
1251 | 1256 | ||
1257 | d = get_display_data(fbdev, display); | ||
1258 | |||
1252 | switch (blank) { | 1259 | switch (blank) { |
1253 | case FB_BLANK_UNBLANK: | 1260 | case FB_BLANK_UNBLANK: |
1254 | if (display->state != OMAP_DSS_DISPLAY_SUSPENDED) | 1261 | if (display->state != OMAP_DSS_DISPLAY_SUSPENDED) |
@@ -1257,6 +1264,11 @@ static int omapfb_blank(int blank, struct fb_info *fbi) | |||
1257 | if (display->driver->resume) | 1264 | if (display->driver->resume) |
1258 | r = display->driver->resume(display); | 1265 | r = display->driver->resume(display); |
1259 | 1266 | ||
1267 | if ((display->caps & OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE) && | ||
1268 | d->update_mode == OMAPFB_AUTO_UPDATE && | ||
1269 | !d->auto_update_work_enabled) | ||
1270 | omapfb_start_auto_update(fbdev, display); | ||
1271 | |||
1260 | break; | 1272 | break; |
1261 | 1273 | ||
1262 | case FB_BLANK_NORMAL: | 1274 | case FB_BLANK_NORMAL: |
@@ -1268,6 +1280,9 @@ static int omapfb_blank(int blank, struct fb_info *fbi) | |||
1268 | if (display->state != OMAP_DSS_DISPLAY_ACTIVE) | 1280 | if (display->state != OMAP_DSS_DISPLAY_ACTIVE) |
1269 | goto exit; | 1281 | goto exit; |
1270 | 1282 | ||
1283 | if (d->auto_update_work_enabled) | ||
1284 | omapfb_stop_auto_update(fbdev, display); | ||
1285 | |||
1271 | if (display->driver->suspend) | 1286 | if (display->driver->suspend) |
1272 | r = display->driver->suspend(display); | 1287 | r = display->driver->suspend(display); |
1273 | 1288 | ||
@@ -1724,6 +1739,78 @@ err: | |||
1724 | return r; | 1739 | return r; |
1725 | } | 1740 | } |
1726 | 1741 | ||
1742 | static void omapfb_auto_update_work(struct work_struct *work) | ||
1743 | { | ||
1744 | struct omap_dss_device *dssdev; | ||
1745 | struct omap_dss_driver *dssdrv; | ||
1746 | struct omapfb_display_data *d; | ||
1747 | u16 w, h; | ||
1748 | unsigned int freq; | ||
1749 | struct omapfb2_device *fbdev; | ||
1750 | |||
1751 | d = container_of(work, struct omapfb_display_data, | ||
1752 | auto_update_work.work); | ||
1753 | |||
1754 | dssdev = d->dssdev; | ||
1755 | dssdrv = dssdev->driver; | ||
1756 | fbdev = d->fbdev; | ||
1757 | |||
1758 | if (!dssdrv || !dssdrv->update) | ||
1759 | return; | ||
1760 | |||
1761 | if (dssdrv->sync) | ||
1762 | dssdrv->sync(dssdev); | ||
1763 | |||
1764 | dssdrv->get_resolution(dssdev, &w, &h); | ||
1765 | dssdrv->update(dssdev, 0, 0, w, h); | ||
1766 | |||
1767 | freq = auto_update_freq; | ||
1768 | if (freq == 0) | ||
1769 | freq = 20; | ||
1770 | queue_delayed_work(fbdev->auto_update_wq, | ||
1771 | &d->auto_update_work, HZ / freq); | ||
1772 | } | ||
1773 | |||
1774 | void omapfb_start_auto_update(struct omapfb2_device *fbdev, | ||
1775 | struct omap_dss_device *display) | ||
1776 | { | ||
1777 | struct omapfb_display_data *d; | ||
1778 | |||
1779 | if (fbdev->auto_update_wq == NULL) { | ||
1780 | struct workqueue_struct *wq; | ||
1781 | |||
1782 | wq = create_singlethread_workqueue("omapfb_auto_update"); | ||
1783 | |||
1784 | if (wq == NULL) { | ||
1785 | dev_err(fbdev->dev, "Failed to create workqueue for " | ||
1786 | "auto-update\n"); | ||
1787 | return; | ||
1788 | } | ||
1789 | |||
1790 | fbdev->auto_update_wq = wq; | ||
1791 | } | ||
1792 | |||
1793 | d = get_display_data(fbdev, display); | ||
1794 | |||
1795 | INIT_DELAYED_WORK(&d->auto_update_work, omapfb_auto_update_work); | ||
1796 | |||
1797 | d->auto_update_work_enabled = true; | ||
1798 | |||
1799 | omapfb_auto_update_work(&d->auto_update_work.work); | ||
1800 | } | ||
1801 | |||
1802 | void omapfb_stop_auto_update(struct omapfb2_device *fbdev, | ||
1803 | struct omap_dss_device *display) | ||
1804 | { | ||
1805 | struct omapfb_display_data *d; | ||
1806 | |||
1807 | d = get_display_data(fbdev, display); | ||
1808 | |||
1809 | cancel_delayed_work_sync(&d->auto_update_work); | ||
1810 | |||
1811 | d->auto_update_work_enabled = false; | ||
1812 | } | ||
1813 | |||
1727 | /* initialize fb_info, var, fix to something sane based on the display */ | 1814 | /* initialize fb_info, var, fix to something sane based on the display */ |
1728 | static int omapfb_fb_init(struct omapfb2_device *fbdev, struct fb_info *fbi) | 1815 | static int omapfb_fb_init(struct omapfb2_device *fbdev, struct fb_info *fbi) |
1729 | { | 1816 | { |
@@ -1859,12 +1946,22 @@ static void omapfb_free_resources(struct omapfb2_device *fbdev) | |||
1859 | 1946 | ||
1860 | for (i = 0; i < fbdev->num_displays; i++) { | 1947 | for (i = 0; i < fbdev->num_displays; i++) { |
1861 | struct omap_dss_device *dssdev = fbdev->displays[i].dssdev; | 1948 | struct omap_dss_device *dssdev = fbdev->displays[i].dssdev; |
1949 | |||
1950 | if (fbdev->displays[i].auto_update_work_enabled) | ||
1951 | omapfb_stop_auto_update(fbdev, dssdev); | ||
1952 | |||
1862 | if (dssdev->state != OMAP_DSS_DISPLAY_DISABLED) | 1953 | if (dssdev->state != OMAP_DSS_DISPLAY_DISABLED) |
1863 | dssdev->driver->disable(dssdev); | 1954 | dssdev->driver->disable(dssdev); |
1864 | 1955 | ||
1865 | omap_dss_put_device(dssdev); | 1956 | omap_dss_put_device(dssdev); |
1866 | } | 1957 | } |
1867 | 1958 | ||
1959 | if (fbdev->auto_update_wq != NULL) { | ||
1960 | flush_workqueue(fbdev->auto_update_wq); | ||
1961 | destroy_workqueue(fbdev->auto_update_wq); | ||
1962 | fbdev->auto_update_wq = NULL; | ||
1963 | } | ||
1964 | |||
1868 | dev_set_drvdata(fbdev->dev, NULL); | 1965 | dev_set_drvdata(fbdev->dev, NULL); |
1869 | kfree(fbdev); | 1966 | kfree(fbdev); |
1870 | } | 1967 | } |
@@ -2183,6 +2280,7 @@ static int omapfb_init_display(struct omapfb2_device *fbdev, | |||
2183 | struct omap_dss_device *dssdev) | 2280 | struct omap_dss_device *dssdev) |
2184 | { | 2281 | { |
2185 | struct omap_dss_driver *dssdrv = dssdev->driver; | 2282 | struct omap_dss_driver *dssdrv = dssdev->driver; |
2283 | struct omapfb_display_data *d; | ||
2186 | int r; | 2284 | int r; |
2187 | 2285 | ||
2188 | r = dssdrv->enable(dssdev); | 2286 | r = dssdrv->enable(dssdev); |
@@ -2192,8 +2290,20 @@ static int omapfb_init_display(struct omapfb2_device *fbdev, | |||
2192 | return r; | 2290 | return r; |
2193 | } | 2291 | } |
2194 | 2292 | ||
2293 | d = get_display_data(fbdev, dssdev); | ||
2294 | |||
2295 | d->fbdev = fbdev; | ||
2296 | |||
2195 | if (dssdev->caps & OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE) { | 2297 | if (dssdev->caps & OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE) { |
2196 | u16 w, h; | 2298 | u16 w, h; |
2299 | |||
2300 | if (auto_update) { | ||
2301 | omapfb_start_auto_update(fbdev, dssdev); | ||
2302 | d->update_mode = OMAPFB_AUTO_UPDATE; | ||
2303 | } else { | ||
2304 | d->update_mode = OMAPFB_MANUAL_UPDATE; | ||
2305 | } | ||
2306 | |||
2197 | if (dssdrv->enable_te) { | 2307 | if (dssdrv->enable_te) { |
2198 | r = dssdrv->enable_te(dssdev, 1); | 2308 | r = dssdrv->enable_te(dssdev, 1); |
2199 | if (r) { | 2309 | if (r) { |
@@ -2202,16 +2312,6 @@ static int omapfb_init_display(struct omapfb2_device *fbdev, | |||
2202 | } | 2312 | } |
2203 | } | 2313 | } |
2204 | 2314 | ||
2205 | if (dssdrv->set_update_mode) { | ||
2206 | r = dssdrv->set_update_mode(dssdev, | ||
2207 | OMAP_DSS_UPDATE_MANUAL); | ||
2208 | if (r) { | ||
2209 | dev_err(fbdev->dev, | ||
2210 | "Failed to set update mode\n"); | ||
2211 | return r; | ||
2212 | } | ||
2213 | } | ||
2214 | |||
2215 | dssdrv->get_resolution(dssdev, &w, &h); | 2315 | dssdrv->get_resolution(dssdev, &w, &h); |
2216 | r = dssdrv->update(dssdev, 0, 0, w, h); | 2316 | r = dssdrv->update(dssdev, 0, 0, w, h); |
2217 | if (r) { | 2317 | if (r) { |
@@ -2220,15 +2320,7 @@ static int omapfb_init_display(struct omapfb2_device *fbdev, | |||
2220 | return r; | 2320 | return r; |
2221 | } | 2321 | } |
2222 | } else { | 2322 | } else { |
2223 | if (dssdrv->set_update_mode) { | 2323 | d->update_mode = OMAPFB_AUTO_UPDATE; |
2224 | r = dssdrv->set_update_mode(dssdev, | ||
2225 | OMAP_DSS_UPDATE_AUTO); | ||
2226 | if (r) { | ||
2227 | dev_err(fbdev->dev, | ||
2228 | "Failed to set update mode\n"); | ||
2229 | return r; | ||
2230 | } | ||
2231 | } | ||
2232 | } | 2324 | } |
2233 | 2325 | ||
2234 | return 0; | 2326 | return 0; |
@@ -2276,6 +2368,8 @@ static int omapfb_probe(struct platform_device *pdev) | |||
2276 | fbdev->num_displays = 0; | 2368 | fbdev->num_displays = 0; |
2277 | dssdev = NULL; | 2369 | dssdev = NULL; |
2278 | for_each_dss_dev(dssdev) { | 2370 | for_each_dss_dev(dssdev) { |
2371 | struct omapfb_display_data *d; | ||
2372 | |||
2279 | omap_dss_get_device(dssdev); | 2373 | omap_dss_get_device(dssdev); |
2280 | 2374 | ||
2281 | if (!dssdev->driver) { | 2375 | if (!dssdev->driver) { |
@@ -2283,7 +2377,12 @@ static int omapfb_probe(struct platform_device *pdev) | |||
2283 | r = -ENODEV; | 2377 | r = -ENODEV; |
2284 | } | 2378 | } |
2285 | 2379 | ||
2286 | fbdev->displays[fbdev->num_displays++].dssdev = dssdev; | 2380 | d = &fbdev->displays[fbdev->num_displays++]; |
2381 | d->dssdev = dssdev; | ||
2382 | if (dssdev->caps & OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE) | ||
2383 | d->update_mode = OMAPFB_MANUAL_UPDATE; | ||
2384 | else | ||
2385 | d->update_mode = OMAPFB_AUTO_UPDATE; | ||
2287 | } | 2386 | } |
2288 | 2387 | ||
2289 | if (r) | 2388 | if (r) |