aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/video/omap2
diff options
context:
space:
mode:
authorTomi Valkeinen <tomi.valkeinen@ti.com>2011-04-30 09:55:12 -0400
committerTomi Valkeinen <tomi.valkeinen@ti.com>2011-07-01 05:01:14 -0400
commit27cc213ea7dde929692df46a64c8d8ef74663e48 (patch)
treee500ad95bb76864878966aeaafa29ed5ef330ef1 /drivers/video/omap2
parent065a40bd461d3709a2c36adf0ec383581cc692a7 (diff)
OMAP: DSS2: OMAPFB: Implement auto-update mode
Implement auto-update mode for manual-update displays. omapfb driver uses a delayed work to update the display with a constant rate. The update mode can be changed via OMAPFB_SET_UPDATE_MODE ioctl, which previously called omapdss but is now handled inside omapfb, and a new sysfs file, "update_mode". The update interval is by default 20 times per second, but can be changed via "auto_update_freq" module parameter. There is also a new module parameter "auto_update", which will make omapfb start manual update displays in auto-update mode. This auto-update mode can be used for testing if the userspace does not support manual update displays properly. However, it is a very inefficient solution, and should be considered more as a hack for testing than something that could be used as a long term solution. Signed-off-by: Tomi Valkeinen <tomi.valkeinen@ti.com>
Diffstat (limited to 'drivers/video/omap2')
-rw-r--r--drivers/video/omap2/omapfb/omapfb-ioctl.c72
-rw-r--r--drivers/video/omap2/omapfb/omapfb-main.c139
-rw-r--r--drivers/video/omap2/omapfb/omapfb-sysfs.c34
-rw-r--r--drivers/video/omap2/omapfb/omapfb.h13
4 files changed, 202 insertions, 56 deletions
diff --git a/drivers/video/omap2/omapfb/omapfb-ioctl.c b/drivers/video/omap2/omapfb/omapfb-ioctl.c
index cff450392b79..6b1ac23dbbd3 100644
--- a/drivers/video/omap2/omapfb/omapfb-ioctl.c
+++ b/drivers/video/omap2/omapfb/omapfb-ioctl.c
@@ -316,67 +316,67 @@ int omapfb_update_window(struct fb_info *fbi,
316} 316}
317EXPORT_SYMBOL(omapfb_update_window); 317EXPORT_SYMBOL(omapfb_update_window);
318 318
319static int omapfb_set_update_mode(struct fb_info *fbi, 319int omapfb_set_update_mode(struct fb_info *fbi,
320 enum omapfb_update_mode mode) 320 enum omapfb_update_mode mode)
321{ 321{
322 struct omap_dss_device *display = fb2display(fbi); 322 struct omap_dss_device *display = fb2display(fbi);
323 enum omap_dss_update_mode um; 323 struct omapfb_info *ofbi = FB2OFB(fbi);
324 struct omapfb2_device *fbdev = ofbi->fbdev;
325 struct omapfb_display_data *d;
324 int r; 326 int r;
325 327
326 if (!display || !display->driver->set_update_mode) 328 if (!display)
327 return -EINVAL; 329 return -EINVAL;
328 330
329 switch (mode) { 331 if (mode != OMAPFB_AUTO_UPDATE && mode != OMAPFB_MANUAL_UPDATE)
330 case OMAPFB_UPDATE_DISABLED: 332 return -EINVAL;
331 um = OMAP_DSS_UPDATE_DISABLED;
332 break;
333 333
334 case OMAPFB_AUTO_UPDATE: 334 omapfb_lock(fbdev);
335 um = OMAP_DSS_UPDATE_AUTO;
336 break;
337 335
338 case OMAPFB_MANUAL_UPDATE: 336 d = get_display_data(fbdev, display);
339 um = OMAP_DSS_UPDATE_MANUAL;
340 break;
341 337
342 default: 338 if (d->update_mode == mode) {
343 return -EINVAL; 339 omapfb_unlock(fbdev);
340 return 0;
344 } 341 }
345 342
346 r = display->driver->set_update_mode(display, um); 343 r = 0;
344
345 if (display->caps & OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE) {
346 if (mode == OMAPFB_AUTO_UPDATE)
347 omapfb_start_auto_update(fbdev, display);
348 else /* MANUAL_UPDATE */
349 omapfb_stop_auto_update(fbdev, display);
350
351 d->update_mode = mode;
352 } else { /* AUTO_UPDATE */
353 if (mode == OMAPFB_MANUAL_UPDATE)
354 r = -EINVAL;
355 }
356
357 omapfb_unlock(fbdev);
347 358
348 return r; 359 return r;
349} 360}
350 361
351static int omapfb_get_update_mode(struct fb_info *fbi, 362int omapfb_get_update_mode(struct fb_info *fbi,
352 enum omapfb_update_mode *mode) 363 enum omapfb_update_mode *mode)
353{ 364{
354 struct omap_dss_device *display = fb2display(fbi); 365 struct omap_dss_device *display = fb2display(fbi);
355 enum omap_dss_update_mode m; 366 struct omapfb_info *ofbi = FB2OFB(fbi);
367 struct omapfb2_device *fbdev = ofbi->fbdev;
368 struct omapfb_display_data *d;
356 369
357 if (!display) 370 if (!display)
358 return -EINVAL; 371 return -EINVAL;
359 372
360 if (!display->driver->get_update_mode) { 373 omapfb_lock(fbdev);
361 *mode = OMAPFB_AUTO_UPDATE;
362 return 0;
363 }
364 374
365 m = display->driver->get_update_mode(display); 375 d = get_display_data(fbdev, display);
366 376
367 switch (m) { 377 *mode = d->update_mode;
368 case OMAP_DSS_UPDATE_DISABLED: 378
369 *mode = OMAPFB_UPDATE_DISABLED; 379 omapfb_unlock(fbdev);
370 break;
371 case OMAP_DSS_UPDATE_AUTO:
372 *mode = OMAPFB_AUTO_UPDATE;
373 break;
374 case OMAP_DSS_UPDATE_MANUAL:
375 *mode = OMAPFB_MANUAL_UPDATE;
376 break;
377 default:
378 BUG();
379 }
380 380
381 return 0; 381 return 0;
382} 382}
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;
46static int def_vrfb; 46static int def_vrfb;
47static int def_rotate; 47static int def_rotate;
48static int def_mirror; 48static int def_mirror;
49static bool auto_update;
50static unsigned int auto_update_freq;
51module_param(auto_update, bool, 0);
52module_param(auto_update_freq, uint, 0644);
49 53
50#ifdef DEBUG 54#ifdef DEBUG
51unsigned int omapfb_debug; 55unsigned 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
1742static 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
1774void 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
1802void 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 */
1728static int omapfb_fb_init(struct omapfb2_device *fbdev, struct fb_info *fbi) 1815static 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)
diff --git a/drivers/video/omap2/omapfb/omapfb-sysfs.c b/drivers/video/omap2/omapfb/omapfb-sysfs.c
index 2f5e817b2a9a..153bf1aceebc 100644
--- a/drivers/video/omap2/omapfb/omapfb-sysfs.c
+++ b/drivers/video/omap2/omapfb/omapfb-sysfs.c
@@ -518,6 +518,39 @@ static ssize_t show_virt(struct device *dev,
518 return snprintf(buf, PAGE_SIZE, "%p\n", ofbi->region->vaddr); 518 return snprintf(buf, PAGE_SIZE, "%p\n", ofbi->region->vaddr);
519} 519}
520 520
521static ssize_t show_upd_mode(struct device *dev,
522 struct device_attribute *attr, char *buf)
523{
524 struct fb_info *fbi = dev_get_drvdata(dev);
525 enum omapfb_update_mode mode;
526 int r;
527
528 r = omapfb_get_update_mode(fbi, &mode);
529
530 if (r)
531 return r;
532
533 return snprintf(buf, PAGE_SIZE, "%u\n", (unsigned)mode);
534}
535
536static ssize_t store_upd_mode(struct device *dev, struct device_attribute *attr,
537 const char *buf, size_t count)
538{
539 struct fb_info *fbi = dev_get_drvdata(dev);
540 unsigned mode;
541 int r;
542
543 r = kstrtouint(buf, 0, &mode);
544 if (r)
545 return r;
546
547 r = omapfb_set_update_mode(fbi, mode);
548 if (r)
549 return r;
550
551 return count;
552}
553
521static struct device_attribute omapfb_attrs[] = { 554static struct device_attribute omapfb_attrs[] = {
522 __ATTR(rotate_type, S_IRUGO | S_IWUSR, show_rotate_type, 555 __ATTR(rotate_type, S_IRUGO | S_IWUSR, show_rotate_type,
523 store_rotate_type), 556 store_rotate_type),
@@ -528,6 +561,7 @@ static struct device_attribute omapfb_attrs[] = {
528 store_overlays_rotate), 561 store_overlays_rotate),
529 __ATTR(phys_addr, S_IRUGO, show_phys, NULL), 562 __ATTR(phys_addr, S_IRUGO, show_phys, NULL),
530 __ATTR(virt_addr, S_IRUGO, show_virt, NULL), 563 __ATTR(virt_addr, S_IRUGO, show_virt, NULL),
564 __ATTR(update_mode, S_IRUGO | S_IWUSR, show_upd_mode, store_upd_mode),
531}; 565};
532 566
533int omapfb_create_sysfs(struct omapfb2_device *fbdev) 567int omapfb_create_sysfs(struct omapfb2_device *fbdev)
diff --git a/drivers/video/omap2/omapfb/omapfb.h b/drivers/video/omap2/omapfb/omapfb.h
index f07dbbb08db1..fdf0edeccf4e 100644
--- a/drivers/video/omap2/omapfb/omapfb.h
+++ b/drivers/video/omap2/omapfb/omapfb.h
@@ -74,8 +74,12 @@ struct omapfb_info {
74}; 74};
75 75
76struct omapfb_display_data { 76struct omapfb_display_data {
77 struct omapfb2_device *fbdev;
77 struct omap_dss_device *dssdev; 78 struct omap_dss_device *dssdev;
78 u8 bpp_override; 79 u8 bpp_override;
80 enum omapfb_update_mode update_mode;
81 bool auto_update_work_enabled;
82 struct delayed_work auto_update_work;
79}; 83};
80 84
81struct omapfb2_device { 85struct omapfb2_device {
@@ -96,6 +100,8 @@ struct omapfb2_device {
96 struct omap_overlay *overlays[10]; 100 struct omap_overlay *overlays[10];
97 unsigned num_managers; 101 unsigned num_managers;
98 struct omap_overlay_manager *managers[10]; 102 struct omap_overlay_manager *managers[10];
103
104 struct workqueue_struct *auto_update_wq;
99}; 105};
100 106
101struct omapfb_colormode { 107struct omapfb_colormode {
@@ -127,6 +133,13 @@ int dss_mode_to_fb_mode(enum omap_color_mode dssmode,
127int omapfb_setup_overlay(struct fb_info *fbi, struct omap_overlay *ovl, 133int omapfb_setup_overlay(struct fb_info *fbi, struct omap_overlay *ovl,
128 u16 posx, u16 posy, u16 outw, u16 outh); 134 u16 posx, u16 posy, u16 outw, u16 outh);
129 135
136void omapfb_start_auto_update(struct omapfb2_device *fbdev,
137 struct omap_dss_device *display);
138void omapfb_stop_auto_update(struct omapfb2_device *fbdev,
139 struct omap_dss_device *display);
140int omapfb_get_update_mode(struct fb_info *fbi, enum omapfb_update_mode *mode);
141int omapfb_set_update_mode(struct fb_info *fbi, enum omapfb_update_mode mode);
142
130/* find the display connected to this fb, if any */ 143/* find the display connected to this fb, if any */
131static inline struct omap_dss_device *fb2display(struct fb_info *fbi) 144static inline struct omap_dss_device *fb2display(struct fb_info *fbi)
132{ 145{