aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/video
diff options
context:
space:
mode:
authorDave Airlie <airlied@redhat.com>2013-02-07 21:34:44 -0500
committerDave Airlie <airlied@redhat.com>2013-02-07 21:34:44 -0500
commited914f69f8f979ea2b664abc4f1437235cf3db35 (patch)
tree43d839d79d02f4a9415199a2db7a4b6cfeb281eb /drivers/video
parentbb0f78dd7ded88082b2430c43c65bc821c4ea360 (diff)
parentedb37a95c58147f89713e6c5cd220fa8fdfb4833 (diff)
Merge tag 'of_videomode_helper' of git://git.pengutronix.de/git/str/linux into drm-next
videomode helpers for of + devicetree stuff, required for new kms drivers (not the fbdev maintainer). * tag 'of_videomode_helper' of git://git.pengutronix.de/git/str/linux: drm_modes: add of_videomode helpers drm_modes: add videomode helpers fbmon: add of_videomode helpers fbmon: add videomode helpers video: add of helper for display timings/videomode video: add display_timing and videomode viafb: rename display_timing to via_display_timing
Diffstat (limited to 'drivers/video')
-rw-r--r--drivers/video/Kconfig21
-rw-r--r--drivers/video/Makefile4
-rw-r--r--drivers/video/display_timing.c24
-rw-r--r--drivers/video/fbmon.c94
-rw-r--r--drivers/video/of_display_timing.c239
-rw-r--r--drivers/video/of_videomode.c54
-rw-r--r--drivers/video/via/hw.c6
-rw-r--r--drivers/video/via/hw.h2
-rw-r--r--drivers/video/via/lcd.c2
-rw-r--r--drivers/video/via/share.h2
-rw-r--r--drivers/video/via/via_modesetting.c8
-rw-r--r--drivers/video/via/via_modesetting.h6
-rw-r--r--drivers/video/videomode.c39
13 files changed, 488 insertions, 13 deletions
diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig
index e7068c508800..807c7fa689fa 100644
--- a/drivers/video/Kconfig
+++ b/drivers/video/Kconfig
@@ -33,6 +33,27 @@ config VIDEO_OUTPUT_CONTROL
33 This framework adds support for low-level control of the video 33 This framework adds support for low-level control of the video
34 output switch. 34 output switch.
35 35
36config DISPLAY_TIMING
37 bool
38
39config VIDEOMODE
40 bool
41
42config OF_DISPLAY_TIMING
43 bool "Enable device tree display timing support"
44 depends on OF
45 select DISPLAY_TIMING
46 help
47 helper to parse display timings from the devicetree
48
49config OF_VIDEOMODE
50 bool "Enable device tree videomode support"
51 depends on OF
52 select VIDEOMODE
53 select OF_DISPLAY_TIMING
54 help
55 helper to get videomodes from the devicetree
56
36menuconfig FB 57menuconfig FB
37 tristate "Support for frame buffer devices" 58 tristate "Support for frame buffer devices"
38 ---help--- 59 ---help---
diff --git a/drivers/video/Makefile b/drivers/video/Makefile
index 768a137a1bac..f592f3b32ec7 100644
--- a/drivers/video/Makefile
+++ b/drivers/video/Makefile
@@ -168,3 +168,7 @@ obj-$(CONFIG_FB_VIRTUAL) += vfb.o
168 168
169#video output switch sysfs driver 169#video output switch sysfs driver
170obj-$(CONFIG_VIDEO_OUTPUT_CONTROL) += output.o 170obj-$(CONFIG_VIDEO_OUTPUT_CONTROL) += output.o
171obj-$(CONFIG_DISPLAY_TIMING) += display_timing.o
172obj-$(CONFIG_OF_DISPLAY_TIMING) += of_display_timing.o
173obj-$(CONFIG_VIDEOMODE) += videomode.o
174obj-$(CONFIG_OF_VIDEOMODE) += of_videomode.o
diff --git a/drivers/video/display_timing.c b/drivers/video/display_timing.c
new file mode 100644
index 000000000000..5e1822cef571
--- /dev/null
+++ b/drivers/video/display_timing.c
@@ -0,0 +1,24 @@
1/*
2 * generic display timing functions
3 *
4 * Copyright (c) 2012 Steffen Trumtrar <s.trumtrar@pengutronix.de>, Pengutronix
5 *
6 * This file is released under the GPLv2
7 */
8
9#include <linux/export.h>
10#include <linux/slab.h>
11#include <video/display_timing.h>
12
13void display_timings_release(struct display_timings *disp)
14{
15 if (disp->timings) {
16 unsigned int i;
17
18 for (i = 0; i < disp->num_timings; i++)
19 kfree(disp->timings[i]);
20 kfree(disp->timings);
21 }
22 kfree(disp);
23}
24EXPORT_SYMBOL_GPL(display_timings_release);
diff --git a/drivers/video/fbmon.c b/drivers/video/fbmon.c
index cef65574db6c..94ad0f71383c 100644
--- a/drivers/video/fbmon.c
+++ b/drivers/video/fbmon.c
@@ -31,6 +31,8 @@
31#include <linux/pci.h> 31#include <linux/pci.h>
32#include <linux/slab.h> 32#include <linux/slab.h>
33#include <video/edid.h> 33#include <video/edid.h>
34#include <video/of_videomode.h>
35#include <video/videomode.h>
34#ifdef CONFIG_PPC_OF 36#ifdef CONFIG_PPC_OF
35#include <asm/prom.h> 37#include <asm/prom.h>
36#include <asm/pci-bridge.h> 38#include <asm/pci-bridge.h>
@@ -1373,6 +1375,98 @@ int fb_get_mode(int flags, u32 val, struct fb_var_screeninfo *var, struct fb_inf
1373 kfree(timings); 1375 kfree(timings);
1374 return err; 1376 return err;
1375} 1377}
1378
1379#if IS_ENABLED(CONFIG_VIDEOMODE)
1380int fb_videomode_from_videomode(const struct videomode *vm,
1381 struct fb_videomode *fbmode)
1382{
1383 unsigned int htotal, vtotal;
1384
1385 fbmode->xres = vm->hactive;
1386 fbmode->left_margin = vm->hback_porch;
1387 fbmode->right_margin = vm->hfront_porch;
1388 fbmode->hsync_len = vm->hsync_len;
1389
1390 fbmode->yres = vm->vactive;
1391 fbmode->upper_margin = vm->vback_porch;
1392 fbmode->lower_margin = vm->vfront_porch;
1393 fbmode->vsync_len = vm->vsync_len;
1394
1395 /* prevent division by zero in KHZ2PICOS macro */
1396 fbmode->pixclock = vm->pixelclock ?
1397 KHZ2PICOS(vm->pixelclock / 1000) : 0;
1398
1399 fbmode->sync = 0;
1400 fbmode->vmode = 0;
1401 if (vm->dmt_flags & VESA_DMT_HSYNC_HIGH)
1402 fbmode->sync |= FB_SYNC_HOR_HIGH_ACT;
1403 if (vm->dmt_flags & VESA_DMT_HSYNC_HIGH)
1404 fbmode->sync |= FB_SYNC_VERT_HIGH_ACT;
1405 if (vm->data_flags & DISPLAY_FLAGS_INTERLACED)
1406 fbmode->vmode |= FB_VMODE_INTERLACED;
1407 if (vm->data_flags & DISPLAY_FLAGS_DOUBLESCAN)
1408 fbmode->vmode |= FB_VMODE_DOUBLE;
1409 fbmode->flag = 0;
1410
1411 htotal = vm->hactive + vm->hfront_porch + vm->hback_porch +
1412 vm->hsync_len;
1413 vtotal = vm->vactive + vm->vfront_porch + vm->vback_porch +
1414 vm->vsync_len;
1415 /* prevent division by zero */
1416 if (htotal && vtotal) {
1417 fbmode->refresh = vm->pixelclock / (htotal * vtotal);
1418 /* a mode must have htotal and vtotal != 0 or it is invalid */
1419 } else {
1420 fbmode->refresh = 0;
1421 return -EINVAL;
1422 }
1423
1424 return 0;
1425}
1426EXPORT_SYMBOL_GPL(fb_videomode_from_videomode);
1427#endif
1428
1429#if IS_ENABLED(CONFIG_OF_VIDEOMODE)
1430static inline void dump_fb_videomode(const struct fb_videomode *m)
1431{
1432 pr_debug("fb_videomode = %ux%u@%uHz (%ukHz) %u %u %u %u %u %u %u %u %u\n",
1433 m->xres, m->yres, m->refresh, m->pixclock, m->left_margin,
1434 m->right_margin, m->upper_margin, m->lower_margin,
1435 m->hsync_len, m->vsync_len, m->sync, m->vmode, m->flag);
1436}
1437
1438/**
1439 * of_get_fb_videomode - get a fb_videomode from devicetree
1440 * @np: device_node with the timing specification
1441 * @fb: will be set to the return value
1442 * @index: index into the list of display timings in devicetree
1443 *
1444 * DESCRIPTION:
1445 * This function is expensive and should only be used, if only one mode is to be
1446 * read from DT. To get multiple modes start with of_get_display_timings ond
1447 * work with that instead.
1448 */
1449int of_get_fb_videomode(struct device_node *np, struct fb_videomode *fb,
1450 int index)
1451{
1452 struct videomode vm;
1453 int ret;
1454
1455 ret = of_get_videomode(np, &vm, index);
1456 if (ret)
1457 return ret;
1458
1459 fb_videomode_from_videomode(&vm, fb);
1460
1461 pr_debug("%s: got %dx%d display mode from %s\n",
1462 of_node_full_name(np), vm.hactive, vm.vactive, np->name);
1463 dump_fb_videomode(fb);
1464
1465 return 0;
1466}
1467EXPORT_SYMBOL_GPL(of_get_fb_videomode);
1468#endif
1469
1376#else 1470#else
1377int fb_parse_edid(unsigned char *edid, struct fb_var_screeninfo *var) 1471int fb_parse_edid(unsigned char *edid, struct fb_var_screeninfo *var)
1378{ 1472{
diff --git a/drivers/video/of_display_timing.c b/drivers/video/of_display_timing.c
new file mode 100644
index 000000000000..13ecd9897010
--- /dev/null
+++ b/drivers/video/of_display_timing.c
@@ -0,0 +1,239 @@
1/*
2 * OF helpers for parsing display timings
3 *
4 * Copyright (c) 2012 Steffen Trumtrar <s.trumtrar@pengutronix.de>, Pengutronix
5 *
6 * based on of_videomode.c by Sascha Hauer <s.hauer@pengutronix.de>
7 *
8 * This file is released under the GPLv2
9 */
10#include <linux/export.h>
11#include <linux/of.h>
12#include <linux/slab.h>
13#include <video/display_timing.h>
14#include <video/of_display_timing.h>
15
16/**
17 * parse_timing_property - parse timing_entry from device_node
18 * @np: device_node with the property
19 * @name: name of the property
20 * @result: will be set to the return value
21 *
22 * DESCRIPTION:
23 * Every display_timing can be specified with either just the typical value or
24 * a range consisting of min/typ/max. This function helps handling this
25 **/
26static int parse_timing_property(struct device_node *np, const char *name,
27 struct timing_entry *result)
28{
29 struct property *prop;
30 int length, cells, ret;
31
32 prop = of_find_property(np, name, &length);
33 if (!prop) {
34 pr_err("%s: could not find property %s\n",
35 of_node_full_name(np), name);
36 return -EINVAL;
37 }
38
39 cells = length / sizeof(u32);
40 if (cells == 1) {
41 ret = of_property_read_u32(np, name, &result->typ);
42 result->min = result->typ;
43 result->max = result->typ;
44 } else if (cells == 3) {
45 ret = of_property_read_u32_array(np, name, &result->min, cells);
46 } else {
47 pr_err("%s: illegal timing specification in %s\n",
48 of_node_full_name(np), name);
49 return -EINVAL;
50 }
51
52 return ret;
53}
54
55/**
56 * of_get_display_timing - parse display_timing entry from device_node
57 * @np: device_node with the properties
58 **/
59static struct display_timing *of_get_display_timing(struct device_node *np)
60{
61 struct display_timing *dt;
62 u32 val = 0;
63 int ret = 0;
64
65 dt = kzalloc(sizeof(*dt), GFP_KERNEL);
66 if (!dt) {
67 pr_err("%s: could not allocate display_timing struct\n",
68 of_node_full_name(np));
69 return NULL;
70 }
71
72 ret |= parse_timing_property(np, "hback-porch", &dt->hback_porch);
73 ret |= parse_timing_property(np, "hfront-porch", &dt->hfront_porch);
74 ret |= parse_timing_property(np, "hactive", &dt->hactive);
75 ret |= parse_timing_property(np, "hsync-len", &dt->hsync_len);
76 ret |= parse_timing_property(np, "vback-porch", &dt->vback_porch);
77 ret |= parse_timing_property(np, "vfront-porch", &dt->vfront_porch);
78 ret |= parse_timing_property(np, "vactive", &dt->vactive);
79 ret |= parse_timing_property(np, "vsync-len", &dt->vsync_len);
80 ret |= parse_timing_property(np, "clock-frequency", &dt->pixelclock);
81
82 dt->dmt_flags = 0;
83 dt->data_flags = 0;
84 if (!of_property_read_u32(np, "vsync-active", &val))
85 dt->dmt_flags |= val ? VESA_DMT_VSYNC_HIGH :
86 VESA_DMT_VSYNC_LOW;
87 if (!of_property_read_u32(np, "hsync-active", &val))
88 dt->dmt_flags |= val ? VESA_DMT_HSYNC_HIGH :
89 VESA_DMT_HSYNC_LOW;
90 if (!of_property_read_u32(np, "de-active", &val))
91 dt->data_flags |= val ? DISPLAY_FLAGS_DE_HIGH :
92 DISPLAY_FLAGS_DE_LOW;
93 if (!of_property_read_u32(np, "pixelclk-active", &val))
94 dt->data_flags |= val ? DISPLAY_FLAGS_PIXDATA_POSEDGE :
95 DISPLAY_FLAGS_PIXDATA_NEGEDGE;
96
97 if (of_property_read_bool(np, "interlaced"))
98 dt->data_flags |= DISPLAY_FLAGS_INTERLACED;
99 if (of_property_read_bool(np, "doublescan"))
100 dt->data_flags |= DISPLAY_FLAGS_DOUBLESCAN;
101
102 if (ret) {
103 pr_err("%s: error reading timing properties\n",
104 of_node_full_name(np));
105 kfree(dt);
106 return NULL;
107 }
108
109 return dt;
110}
111
112/**
113 * of_get_display_timings - parse all display_timing entries from a device_node
114 * @np: device_node with the subnodes
115 **/
116struct display_timings *of_get_display_timings(struct device_node *np)
117{
118 struct device_node *timings_np;
119 struct device_node *entry;
120 struct device_node *native_mode;
121 struct display_timings *disp;
122
123 if (!np) {
124 pr_err("%s: no devicenode given\n", of_node_full_name(np));
125 return NULL;
126 }
127
128 timings_np = of_find_node_by_name(np, "display-timings");
129 if (!timings_np) {
130 pr_err("%s: could not find display-timings node\n",
131 of_node_full_name(np));
132 return NULL;
133 }
134
135 disp = kzalloc(sizeof(*disp), GFP_KERNEL);
136 if (!disp) {
137 pr_err("%s: could not allocate struct disp'\n",
138 of_node_full_name(np));
139 goto dispfail;
140 }
141
142 entry = of_parse_phandle(timings_np, "native-mode", 0);
143 /* assume first child as native mode if none provided */
144 if (!entry)
145 entry = of_get_next_child(np, NULL);
146 /* if there is no child, it is useless to go on */
147 if (!entry) {
148 pr_err("%s: no timing specifications given\n",
149 of_node_full_name(np));
150 goto entryfail;
151 }
152
153 pr_debug("%s: using %s as default timing\n",
154 of_node_full_name(np), entry->name);
155
156 native_mode = entry;
157
158 disp->num_timings = of_get_child_count(timings_np);
159 if (disp->num_timings == 0) {
160 /* should never happen, as entry was already found above */
161 pr_err("%s: no timings specified\n", of_node_full_name(np));
162 goto entryfail;
163 }
164
165 disp->timings = kzalloc(sizeof(struct display_timing *) *
166 disp->num_timings, GFP_KERNEL);
167 if (!disp->timings) {
168 pr_err("%s: could not allocate timings array\n",
169 of_node_full_name(np));
170 goto entryfail;
171 }
172
173 disp->num_timings = 0;
174 disp->native_mode = 0;
175
176 for_each_child_of_node(timings_np, entry) {
177 struct display_timing *dt;
178
179 dt = of_get_display_timing(entry);
180 if (!dt) {
181 /*
182 * to not encourage wrong devicetrees, fail in case of
183 * an error
184 */
185 pr_err("%s: error in timing %d\n",
186 of_node_full_name(np), disp->num_timings + 1);
187 goto timingfail;
188 }
189
190 if (native_mode == entry)
191 disp->native_mode = disp->num_timings;
192
193 disp->timings[disp->num_timings] = dt;
194 disp->num_timings++;
195 }
196 of_node_put(timings_np);
197 /*
198 * native_mode points to the device_node returned by of_parse_phandle
199 * therefore call of_node_put on it
200 */
201 of_node_put(native_mode);
202
203 pr_debug("%s: got %d timings. Using timing #%d as default\n",
204 of_node_full_name(np), disp->num_timings,
205 disp->native_mode + 1);
206
207 return disp;
208
209timingfail:
210 if (native_mode)
211 of_node_put(native_mode);
212 display_timings_release(disp);
213entryfail:
214 kfree(disp);
215dispfail:
216 of_node_put(timings_np);
217 return NULL;
218}
219EXPORT_SYMBOL_GPL(of_get_display_timings);
220
221/**
222 * of_display_timings_exist - check if a display-timings node is provided
223 * @np: device_node with the timing
224 **/
225int of_display_timings_exist(struct device_node *np)
226{
227 struct device_node *timings_np;
228
229 if (!np)
230 return -EINVAL;
231
232 timings_np = of_parse_phandle(np, "display-timings", 0);
233 if (!timings_np)
234 return -EINVAL;
235
236 of_node_put(timings_np);
237 return 1;
238}
239EXPORT_SYMBOL_GPL(of_display_timings_exist);
diff --git a/drivers/video/of_videomode.c b/drivers/video/of_videomode.c
new file mode 100644
index 000000000000..5b8066cd397f
--- /dev/null
+++ b/drivers/video/of_videomode.c
@@ -0,0 +1,54 @@
1/*
2 * generic videomode helper
3 *
4 * Copyright (c) 2012 Steffen Trumtrar <s.trumtrar@pengutronix.de>, Pengutronix
5 *
6 * This file is released under the GPLv2
7 */
8#include <linux/errno.h>
9#include <linux/export.h>
10#include <linux/of.h>
11#include <video/display_timing.h>
12#include <video/of_display_timing.h>
13#include <video/of_videomode.h>
14#include <video/videomode.h>
15
16/**
17 * of_get_videomode - get the videomode #<index> from devicetree
18 * @np - devicenode with the display_timings
19 * @vm - set to return value
20 * @index - index into list of display_timings
21 * (Set this to OF_USE_NATIVE_MODE to use whatever mode is
22 * specified as native mode in the DT.)
23 *
24 * DESCRIPTION:
25 * Get a list of all display timings and put the one
26 * specified by index into *vm. This function should only be used, if
27 * only one videomode is to be retrieved. A driver that needs to work
28 * with multiple/all videomodes should work with
29 * of_get_display_timings instead.
30 **/
31int of_get_videomode(struct device_node *np, struct videomode *vm,
32 int index)
33{
34 struct display_timings *disp;
35 int ret;
36
37 disp = of_get_display_timings(np);
38 if (!disp) {
39 pr_err("%s: no timings specified\n", of_node_full_name(np));
40 return -EINVAL;
41 }
42
43 if (index == OF_USE_NATIVE_MODE)
44 index = disp->native_mode;
45
46 ret = videomode_from_timing(disp, vm, index);
47 if (ret)
48 return ret;
49
50 display_timings_release(disp);
51
52 return 0;
53}
54EXPORT_SYMBOL_GPL(of_get_videomode);
diff --git a/drivers/video/via/hw.c b/drivers/video/via/hw.c
index 80233dae358a..22450908306c 100644
--- a/drivers/video/via/hw.c
+++ b/drivers/video/via/hw.c
@@ -1467,10 +1467,10 @@ void viafb_set_vclock(u32 clk, int set_iga)
1467 via_write_misc_reg_mask(0x0C, 0x0C); /* select external clock */ 1467 via_write_misc_reg_mask(0x0C, 0x0C); /* select external clock */
1468} 1468}
1469 1469
1470struct display_timing var_to_timing(const struct fb_var_screeninfo *var, 1470struct via_display_timing var_to_timing(const struct fb_var_screeninfo *var,
1471 u16 cxres, u16 cyres) 1471 u16 cxres, u16 cyres)
1472{ 1472{
1473 struct display_timing timing; 1473 struct via_display_timing timing;
1474 u16 dx = (var->xres - cxres) / 2, dy = (var->yres - cyres) / 2; 1474 u16 dx = (var->xres - cxres) / 2, dy = (var->yres - cyres) / 2;
1475 1475
1476 timing.hor_addr = cxres; 1476 timing.hor_addr = cxres;
@@ -1491,7 +1491,7 @@ struct display_timing var_to_timing(const struct fb_var_screeninfo *var,
1491void viafb_fill_crtc_timing(const struct fb_var_screeninfo *var, 1491void viafb_fill_crtc_timing(const struct fb_var_screeninfo *var,
1492 u16 cxres, u16 cyres, int iga) 1492 u16 cxres, u16 cyres, int iga)
1493{ 1493{
1494 struct display_timing crt_reg = var_to_timing(var, 1494 struct via_display_timing crt_reg = var_to_timing(var,
1495 cxres ? cxres : var->xres, cyres ? cyres : var->yres); 1495 cxres ? cxres : var->xres, cyres ? cyres : var->yres);
1496 1496
1497 if (iga == IGA1) 1497 if (iga == IGA1)
diff --git a/drivers/video/via/hw.h b/drivers/video/via/hw.h
index a8205754c736..3be073c58b03 100644
--- a/drivers/video/via/hw.h
+++ b/drivers/video/via/hw.h
@@ -637,7 +637,7 @@ extern int viafb_LCD_ON;
637extern int viafb_DVI_ON; 637extern int viafb_DVI_ON;
638extern int viafb_hotplug; 638extern int viafb_hotplug;
639 639
640struct display_timing var_to_timing(const struct fb_var_screeninfo *var, 640struct via_display_timing var_to_timing(const struct fb_var_screeninfo *var,
641 u16 cxres, u16 cyres); 641 u16 cxres, u16 cyres);
642void viafb_fill_crtc_timing(const struct fb_var_screeninfo *var, 642void viafb_fill_crtc_timing(const struct fb_var_screeninfo *var,
643 u16 cxres, u16 cyres, int iga); 643 u16 cxres, u16 cyres, int iga);
diff --git a/drivers/video/via/lcd.c b/drivers/video/via/lcd.c
index 980ee1b1dcf3..5d21ff436ec8 100644
--- a/drivers/video/via/lcd.c
+++ b/drivers/video/via/lcd.c
@@ -549,7 +549,7 @@ void viafb_lcd_set_mode(const struct fb_var_screeninfo *var, u16 cxres,
549 int panel_hres = plvds_setting_info->lcd_panel_hres; 549 int panel_hres = plvds_setting_info->lcd_panel_hres;
550 int panel_vres = plvds_setting_info->lcd_panel_vres; 550 int panel_vres = plvds_setting_info->lcd_panel_vres;
551 u32 clock; 551 u32 clock;
552 struct display_timing timing; 552 struct via_display_timing timing;
553 struct fb_var_screeninfo panel_var; 553 struct fb_var_screeninfo panel_var;
554 const struct fb_videomode *mode_crt_table, *panel_crt_table; 554 const struct fb_videomode *mode_crt_table, *panel_crt_table;
555 555
diff --git a/drivers/video/via/share.h b/drivers/video/via/share.h
index 3158dfc90bed..65c65c611e0a 100644
--- a/drivers/video/via/share.h
+++ b/drivers/video/via/share.h
@@ -319,7 +319,7 @@ struct crt_mode_table {
319 int refresh_rate; 319 int refresh_rate;
320 int h_sync_polarity; 320 int h_sync_polarity;
321 int v_sync_polarity; 321 int v_sync_polarity;
322 struct display_timing crtc; 322 struct via_display_timing crtc;
323}; 323};
324 324
325struct io_reg { 325struct io_reg {
diff --git a/drivers/video/via/via_modesetting.c b/drivers/video/via/via_modesetting.c
index 0e431aee17bb..0b414b09b9b4 100644
--- a/drivers/video/via/via_modesetting.c
+++ b/drivers/video/via/via_modesetting.c
@@ -30,9 +30,9 @@
30#include "debug.h" 30#include "debug.h"
31 31
32 32
33void via_set_primary_timing(const struct display_timing *timing) 33void via_set_primary_timing(const struct via_display_timing *timing)
34{ 34{
35 struct display_timing raw; 35 struct via_display_timing raw;
36 36
37 raw.hor_total = timing->hor_total / 8 - 5; 37 raw.hor_total = timing->hor_total / 8 - 5;
38 raw.hor_addr = timing->hor_addr / 8 - 1; 38 raw.hor_addr = timing->hor_addr / 8 - 1;
@@ -88,9 +88,9 @@ void via_set_primary_timing(const struct display_timing *timing)
88 via_write_reg_mask(VIACR, 0x17, 0x80, 0x80); 88 via_write_reg_mask(VIACR, 0x17, 0x80, 0x80);
89} 89}
90 90
91void via_set_secondary_timing(const struct display_timing *timing) 91void via_set_secondary_timing(const struct via_display_timing *timing)
92{ 92{
93 struct display_timing raw; 93 struct via_display_timing raw;
94 94
95 raw.hor_total = timing->hor_total - 1; 95 raw.hor_total = timing->hor_total - 1;
96 raw.hor_addr = timing->hor_addr - 1; 96 raw.hor_addr = timing->hor_addr - 1;
diff --git a/drivers/video/via/via_modesetting.h b/drivers/video/via/via_modesetting.h
index 06e09fe351ae..f6a6503da3b3 100644
--- a/drivers/video/via/via_modesetting.h
+++ b/drivers/video/via/via_modesetting.h
@@ -33,7 +33,7 @@
33#define VIA_PITCH_MAX 0x3FF8 33#define VIA_PITCH_MAX 0x3FF8
34 34
35 35
36struct display_timing { 36struct via_display_timing {
37 u16 hor_total; 37 u16 hor_total;
38 u16 hor_addr; 38 u16 hor_addr;
39 u16 hor_blank_start; 39 u16 hor_blank_start;
@@ -49,8 +49,8 @@ struct display_timing {
49}; 49};
50 50
51 51
52void via_set_primary_timing(const struct display_timing *timing); 52void via_set_primary_timing(const struct via_display_timing *timing);
53void via_set_secondary_timing(const struct display_timing *timing); 53void via_set_secondary_timing(const struct via_display_timing *timing);
54void via_set_primary_address(u32 addr); 54void via_set_primary_address(u32 addr);
55void via_set_secondary_address(u32 addr); 55void via_set_secondary_address(u32 addr);
56void via_set_primary_pitch(u32 pitch); 56void via_set_primary_pitch(u32 pitch);
diff --git a/drivers/video/videomode.c b/drivers/video/videomode.c
new file mode 100644
index 000000000000..21c47a202afa
--- /dev/null
+++ b/drivers/video/videomode.c
@@ -0,0 +1,39 @@
1/*
2 * generic display timing functions
3 *
4 * Copyright (c) 2012 Steffen Trumtrar <s.trumtrar@pengutronix.de>, Pengutronix
5 *
6 * This file is released under the GPLv2
7 */
8
9#include <linux/errno.h>
10#include <linux/export.h>
11#include <video/display_timing.h>
12#include <video/videomode.h>
13
14int videomode_from_timing(const struct display_timings *disp,
15 struct videomode *vm, unsigned int index)
16{
17 struct display_timing *dt;
18
19 dt = display_timings_get(disp, index);
20 if (!dt)
21 return -EINVAL;
22
23 vm->pixelclock = display_timing_get_value(&dt->pixelclock, TE_TYP);
24 vm->hactive = display_timing_get_value(&dt->hactive, TE_TYP);
25 vm->hfront_porch = display_timing_get_value(&dt->hfront_porch, TE_TYP);
26 vm->hback_porch = display_timing_get_value(&dt->hback_porch, TE_TYP);
27 vm->hsync_len = display_timing_get_value(&dt->hsync_len, TE_TYP);
28
29 vm->vactive = display_timing_get_value(&dt->vactive, TE_TYP);
30 vm->vfront_porch = display_timing_get_value(&dt->vfront_porch, TE_TYP);
31 vm->vback_porch = display_timing_get_value(&dt->vback_porch, TE_TYP);
32 vm->vsync_len = display_timing_get_value(&dt->vsync_len, TE_TYP);
33
34 vm->dmt_flags = dt->dmt_flags;
35 vm->data_flags = dt->data_flags;
36
37 return 0;
38}
39EXPORT_SYMBOL_GPL(videomode_from_timing);