diff options
author | Dave Airlie <airlied@redhat.com> | 2013-02-07 21:34:44 -0500 |
---|---|---|
committer | Dave Airlie <airlied@redhat.com> | 2013-02-07 21:34:44 -0500 |
commit | ed914f69f8f979ea2b664abc4f1437235cf3db35 (patch) | |
tree | 43d839d79d02f4a9415199a2db7a4b6cfeb281eb /drivers/video | |
parent | bb0f78dd7ded88082b2430c43c65bc821c4ea360 (diff) | |
parent | edb37a95c58147f89713e6c5cd220fa8fdfb4833 (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/Kconfig | 21 | ||||
-rw-r--r-- | drivers/video/Makefile | 4 | ||||
-rw-r--r-- | drivers/video/display_timing.c | 24 | ||||
-rw-r--r-- | drivers/video/fbmon.c | 94 | ||||
-rw-r--r-- | drivers/video/of_display_timing.c | 239 | ||||
-rw-r--r-- | drivers/video/of_videomode.c | 54 | ||||
-rw-r--r-- | drivers/video/via/hw.c | 6 | ||||
-rw-r--r-- | drivers/video/via/hw.h | 2 | ||||
-rw-r--r-- | drivers/video/via/lcd.c | 2 | ||||
-rw-r--r-- | drivers/video/via/share.h | 2 | ||||
-rw-r--r-- | drivers/video/via/via_modesetting.c | 8 | ||||
-rw-r--r-- | drivers/video/via/via_modesetting.h | 6 | ||||
-rw-r--r-- | drivers/video/videomode.c | 39 |
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 | ||
36 | config DISPLAY_TIMING | ||
37 | bool | ||
38 | |||
39 | config VIDEOMODE | ||
40 | bool | ||
41 | |||
42 | config 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 | |||
49 | config 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 | |||
36 | menuconfig FB | 57 | menuconfig 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 |
170 | obj-$(CONFIG_VIDEO_OUTPUT_CONTROL) += output.o | 170 | obj-$(CONFIG_VIDEO_OUTPUT_CONTROL) += output.o |
171 | obj-$(CONFIG_DISPLAY_TIMING) += display_timing.o | ||
172 | obj-$(CONFIG_OF_DISPLAY_TIMING) += of_display_timing.o | ||
173 | obj-$(CONFIG_VIDEOMODE) += videomode.o | ||
174 | obj-$(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 | |||
13 | void 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 | } | ||
24 | EXPORT_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) | ||
1380 | int 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 | } | ||
1426 | EXPORT_SYMBOL_GPL(fb_videomode_from_videomode); | ||
1427 | #endif | ||
1428 | |||
1429 | #if IS_ENABLED(CONFIG_OF_VIDEOMODE) | ||
1430 | static 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 | */ | ||
1449 | int 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 | } | ||
1467 | EXPORT_SYMBOL_GPL(of_get_fb_videomode); | ||
1468 | #endif | ||
1469 | |||
1376 | #else | 1470 | #else |
1377 | int fb_parse_edid(unsigned char *edid, struct fb_var_screeninfo *var) | 1471 | int 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 | **/ | ||
26 | static 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 | **/ | ||
59 | static 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 | **/ | ||
116 | struct 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 | |||
209 | timingfail: | ||
210 | if (native_mode) | ||
211 | of_node_put(native_mode); | ||
212 | display_timings_release(disp); | ||
213 | entryfail: | ||
214 | kfree(disp); | ||
215 | dispfail: | ||
216 | of_node_put(timings_np); | ||
217 | return NULL; | ||
218 | } | ||
219 | EXPORT_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 | **/ | ||
225 | int 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 | } | ||
239 | EXPORT_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 | **/ | ||
31 | int 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 | } | ||
54 | EXPORT_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 | ||
1470 | struct display_timing var_to_timing(const struct fb_var_screeninfo *var, | 1470 | struct 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, | |||
1491 | void viafb_fill_crtc_timing(const struct fb_var_screeninfo *var, | 1491 | void 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; | |||
637 | extern int viafb_DVI_ON; | 637 | extern int viafb_DVI_ON; |
638 | extern int viafb_hotplug; | 638 | extern int viafb_hotplug; |
639 | 639 | ||
640 | struct display_timing var_to_timing(const struct fb_var_screeninfo *var, | 640 | struct via_display_timing var_to_timing(const struct fb_var_screeninfo *var, |
641 | u16 cxres, u16 cyres); | 641 | u16 cxres, u16 cyres); |
642 | void viafb_fill_crtc_timing(const struct fb_var_screeninfo *var, | 642 | void 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 | ||
325 | struct io_reg { | 325 | struct 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 | ||
33 | void via_set_primary_timing(const struct display_timing *timing) | 33 | void 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 | ||
91 | void via_set_secondary_timing(const struct display_timing *timing) | 91 | void 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 | ||
36 | struct display_timing { | 36 | struct 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 | ||
52 | void via_set_primary_timing(const struct display_timing *timing); | 52 | void via_set_primary_timing(const struct via_display_timing *timing); |
53 | void via_set_secondary_timing(const struct display_timing *timing); | 53 | void via_set_secondary_timing(const struct via_display_timing *timing); |
54 | void via_set_primary_address(u32 addr); | 54 | void via_set_primary_address(u32 addr); |
55 | void via_set_secondary_address(u32 addr); | 55 | void via_set_secondary_address(u32 addr); |
56 | void via_set_primary_pitch(u32 pitch); | 56 | void 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 | |||
14 | int 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 | } | ||
39 | EXPORT_SYMBOL_GPL(videomode_from_timing); | ||