aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/video
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2013-02-25 19:46:44 -0500
committerLinus Torvalds <torvalds@linux-foundation.org>2013-02-25 19:46:44 -0500
commitfffddfd6c8e0c10c42c6e2cc54ba880fcc36ebbb (patch)
tree71bc5e597124dbaf7550f1e089d675718b3ed5c0 /drivers/video
parent69086a78bdc973ec0b722be790b146e84ba8a8c4 (diff)
parentbe88298b0a3f771a4802f20c5e66af74bfd1dff1 (diff)
Merge branch 'drm-next' of git://people.freedesktop.org/~airlied/linux
Pull drm merge from Dave Airlie: "Highlights: - TI LCD controller KMS driver - TI OMAP KMS driver merged from staging - drop gma500 stub driver - the fbcon locking fixes - the vgacon dirty like zebra fix. - open firmware videomode and hdmi common code helpers - major locking rework for kms object handling - pageflip/cursor won't block on polling anymore! - fbcon helper and prime helper cleanups - i915: all over the map, haswell power well enhancements, valleyview macro horrors cleaned up, killing lots of legacy GTT code, - radeon: CS ioctl unification, deprecated UMS support, gpu reset rework, VM fixes - nouveau: reworked thermal code, external dp/tmds encoder support (anx9805), fences sleep instead of polling, - exynos: all over the driver fixes." Lovely conflict in radeon/evergreen_cs.c between commit de0babd60d8d ("drm/radeon: enforce use of radeon_get_ib_value when reading user cmd") and the new changes that modified that evergreen_dma_cs_parse() function. * 'drm-next' of git://people.freedesktop.org/~airlied/linux: (508 commits) drm/tilcdc: only build on arm drm/i915: Revert hdmi HDP pin checks drm/tegra: Add list of framebuffers to debugfs drm/tegra: Fix color expansion drm/tegra: Split DC_CMD_STATE_CONTROL register write drm/tegra: Implement page-flipping support drm/tegra: Implement VBLANK support drm/tegra: Implement .mode_set_base() drm/tegra: Add plane support drm/tegra: Remove bogus tegra_framebuffer structure drm: Add consistency check for page-flipping drm/radeon: Use generic HDMI infoframe helpers drm/tegra: Use generic HDMI infoframe helpers drm: Add EDID helper documentation drm: Add HDMI infoframe helpers video: Add generic HDMI infoframe helpers drm: Add some missing forward declarations drm: Move mode tables to drm_edid.c drm: Remove duplicate drm_mode_cea_vic() gma500: Fix n, m1 and m2 clock limits for sdvo and lvds ...
Diffstat (limited to 'drivers/video')
-rw-r--r--drivers/video/Kconfig26
-rw-r--r--drivers/video/Makefile5
-rw-r--r--drivers/video/console/fbcon.c58
-rw-r--r--drivers/video/console/vgacon.c22
-rw-r--r--drivers/video/display_timing.c24
-rw-r--r--drivers/video/fbmem.c11
-rw-r--r--drivers/video/fbmon.c94
-rw-r--r--drivers/video/fbsysfs.c3
-rw-r--r--drivers/video/hdmi.c308
-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
18 files changed, 874 insertions, 35 deletions
diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig
index 80cbd21b483f..4c1546f71d56 100644
--- a/drivers/video/Kconfig
+++ b/drivers/video/Kconfig
@@ -21,8 +21,6 @@ source "drivers/gpu/vga/Kconfig"
21 21
22source "drivers/gpu/drm/Kconfig" 22source "drivers/gpu/drm/Kconfig"
23 23
24source "drivers/gpu/stub/Kconfig"
25
26config VGASTATE 24config VGASTATE
27 tristate 25 tristate
28 default n 26 default n
@@ -33,6 +31,30 @@ config VIDEO_OUTPUT_CONTROL
33 This framework adds support for low-level control of the video 31 This framework adds support for low-level control of the video
34 output switch. 32 output switch.
35 33
34config DISPLAY_TIMING
35 bool
36
37config VIDEOMODE
38 bool
39
40config OF_DISPLAY_TIMING
41 bool "Enable device tree display timing support"
42 depends on OF
43 select DISPLAY_TIMING
44 help
45 helper to parse display timings from the devicetree
46
47config OF_VIDEOMODE
48 bool "Enable device tree videomode support"
49 depends on OF
50 select VIDEOMODE
51 select OF_DISPLAY_TIMING
52 help
53 helper to get videomodes from the devicetree
54
55config HDMI
56 bool
57
36menuconfig FB 58menuconfig FB
37 tristate "Support for frame buffer devices" 59 tristate "Support for frame buffer devices"
38 ---help--- 60 ---help---
diff --git a/drivers/video/Makefile b/drivers/video/Makefile
index 0577f834fdcd..9df387334cb7 100644
--- a/drivers/video/Makefile
+++ b/drivers/video/Makefile
@@ -5,6 +5,7 @@
5# Each configuration option enables a list of files. 5# Each configuration option enables a list of files.
6 6
7obj-$(CONFIG_VGASTATE) += vgastate.o 7obj-$(CONFIG_VGASTATE) += vgastate.o
8obj-$(CONFIG_HDMI) += hdmi.o
8obj-y += fb_notify.o 9obj-y += fb_notify.o
9obj-$(CONFIG_FB) += fb.o 10obj-$(CONFIG_FB) += fb.o
10fb-y := fbmem.o fbmon.o fbcmap.o fbsysfs.o \ 11fb-y := fbmem.o fbmon.o fbcmap.o fbsysfs.o \
@@ -170,3 +171,7 @@ obj-$(CONFIG_FB_VIRTUAL) += vfb.o
170 171
171#video output switch sysfs driver 172#video output switch sysfs driver
172obj-$(CONFIG_VIDEO_OUTPUT_CONTROL) += output.o 173obj-$(CONFIG_VIDEO_OUTPUT_CONTROL) += output.o
174obj-$(CONFIG_DISPLAY_TIMING) += display_timing.o
175obj-$(CONFIG_OF_DISPLAY_TIMING) += of_display_timing.o
176obj-$(CONFIG_VIDEOMODE) += videomode.o
177obj-$(CONFIG_OF_VIDEOMODE) += of_videomode.o
diff --git a/drivers/video/console/fbcon.c b/drivers/video/console/fbcon.c
index f8a61e210d2e..3cd675927826 100644
--- a/drivers/video/console/fbcon.c
+++ b/drivers/video/console/fbcon.c
@@ -529,6 +529,33 @@ static int search_for_mapped_con(void)
529 return retval; 529 return retval;
530} 530}
531 531
532static int do_fbcon_takeover(int show_logo)
533{
534 int err, i;
535
536 if (!num_registered_fb)
537 return -ENODEV;
538
539 if (!show_logo)
540 logo_shown = FBCON_LOGO_DONTSHOW;
541
542 for (i = first_fb_vc; i <= last_fb_vc; i++)
543 con2fb_map[i] = info_idx;
544
545 err = do_take_over_console(&fb_con, first_fb_vc, last_fb_vc,
546 fbcon_is_default);
547
548 if (err) {
549 for (i = first_fb_vc; i <= last_fb_vc; i++)
550 con2fb_map[i] = -1;
551 info_idx = -1;
552 } else {
553 fbcon_has_console_bind = 1;
554 }
555
556 return err;
557}
558
532static int fbcon_takeover(int show_logo) 559static int fbcon_takeover(int show_logo)
533{ 560{
534 int err, i; 561 int err, i;
@@ -815,6 +842,8 @@ static void con2fb_init_display(struct vc_data *vc, struct fb_info *info,
815 * 842 *
816 * Maps a virtual console @unit to a frame buffer device 843 * Maps a virtual console @unit to a frame buffer device
817 * @newidx. 844 * @newidx.
845 *
846 * This should be called with the console lock held.
818 */ 847 */
819static int set_con2fb_map(int unit, int newidx, int user) 848static int set_con2fb_map(int unit, int newidx, int user)
820{ 849{
@@ -832,7 +861,7 @@ static int set_con2fb_map(int unit, int newidx, int user)
832 861
833 if (!search_for_mapped_con() || !con_is_bound(&fb_con)) { 862 if (!search_for_mapped_con() || !con_is_bound(&fb_con)) {
834 info_idx = newidx; 863 info_idx = newidx;
835 return fbcon_takeover(0); 864 return do_fbcon_takeover(0);
836 } 865 }
837 866
838 if (oldidx != -1) 867 if (oldidx != -1)
@@ -840,7 +869,6 @@ static int set_con2fb_map(int unit, int newidx, int user)
840 869
841 found = search_fb_in_map(newidx); 870 found = search_fb_in_map(newidx);
842 871
843 console_lock();
844 con2fb_map[unit] = newidx; 872 con2fb_map[unit] = newidx;
845 if (!err && !found) 873 if (!err && !found)
846 err = con2fb_acquire_newinfo(vc, info, unit, oldidx); 874 err = con2fb_acquire_newinfo(vc, info, unit, oldidx);
@@ -867,7 +895,6 @@ static int set_con2fb_map(int unit, int newidx, int user)
867 if (!search_fb_in_map(info_idx)) 895 if (!search_fb_in_map(info_idx))
868 info_idx = newidx; 896 info_idx = newidx;
869 897
870 console_unlock();
871 return err; 898 return err;
872} 899}
873 900
@@ -990,7 +1017,7 @@ static const char *fbcon_startup(void)
990 } 1017 }
991 1018
992 /* Setup default font */ 1019 /* Setup default font */
993 if (!p->fontdata) { 1020 if (!p->fontdata && !vc->vc_font.data) {
994 if (!fontname[0] || !(font = find_font(fontname))) 1021 if (!fontname[0] || !(font = find_font(fontname)))
995 font = get_default_font(info->var.xres, 1022 font = get_default_font(info->var.xres,
996 info->var.yres, 1023 info->var.yres,
@@ -1000,6 +1027,8 @@ static const char *fbcon_startup(void)
1000 vc->vc_font.height = font->height; 1027 vc->vc_font.height = font->height;
1001 vc->vc_font.data = (void *)(p->fontdata = font->data); 1028 vc->vc_font.data = (void *)(p->fontdata = font->data);
1002 vc->vc_font.charcount = 256; /* FIXME Need to support more fonts */ 1029 vc->vc_font.charcount = 256; /* FIXME Need to support more fonts */
1030 } else {
1031 p->fontdata = vc->vc_font.data;
1003 } 1032 }
1004 1033
1005 cols = FBCON_SWAP(ops->rotate, info->var.xres, info->var.yres); 1034 cols = FBCON_SWAP(ops->rotate, info->var.xres, info->var.yres);
@@ -1159,9 +1188,9 @@ static void fbcon_init(struct vc_data *vc, int init)
1159 ops->p = &fb_display[fg_console]; 1188 ops->p = &fb_display[fg_console];
1160} 1189}
1161 1190
1162static void fbcon_free_font(struct display *p) 1191static void fbcon_free_font(struct display *p, bool freefont)
1163{ 1192{
1164 if (p->userfont && p->fontdata && (--REFCOUNT(p->fontdata) == 0)) 1193 if (freefont && p->userfont && p->fontdata && (--REFCOUNT(p->fontdata) == 0))
1165 kfree(p->fontdata - FONT_EXTRA_WORDS * sizeof(int)); 1194 kfree(p->fontdata - FONT_EXTRA_WORDS * sizeof(int));
1166 p->fontdata = NULL; 1195 p->fontdata = NULL;
1167 p->userfont = 0; 1196 p->userfont = 0;
@@ -1173,8 +1202,8 @@ static void fbcon_deinit(struct vc_data *vc)
1173 struct fb_info *info; 1202 struct fb_info *info;
1174 struct fbcon_ops *ops; 1203 struct fbcon_ops *ops;
1175 int idx; 1204 int idx;
1205 bool free_font = true;
1176 1206
1177 fbcon_free_font(p);
1178 idx = con2fb_map[vc->vc_num]; 1207 idx = con2fb_map[vc->vc_num];
1179 1208
1180 if (idx == -1) 1209 if (idx == -1)
@@ -1185,6 +1214,8 @@ static void fbcon_deinit(struct vc_data *vc)
1185 if (!info) 1214 if (!info)
1186 goto finished; 1215 goto finished;
1187 1216
1217 if (info->flags & FBINFO_MISC_FIRMWARE)
1218 free_font = false;
1188 ops = info->fbcon_par; 1219 ops = info->fbcon_par;
1189 1220
1190 if (!ops) 1221 if (!ops)
@@ -1196,6 +1227,8 @@ static void fbcon_deinit(struct vc_data *vc)
1196 ops->flags &= ~FBCON_FLAGS_INIT; 1227 ops->flags &= ~FBCON_FLAGS_INIT;
1197finished: 1228finished:
1198 1229
1230 fbcon_free_font(p, free_font);
1231
1199 if (!con_is_bound(&fb_con)) 1232 if (!con_is_bound(&fb_con))
1200 fbcon_exit(); 1233 fbcon_exit();
1201 1234
@@ -2985,7 +3018,7 @@ static int fbcon_unbind(void)
2985{ 3018{
2986 int ret; 3019 int ret;
2987 3020
2988 ret = unbind_con_driver(&fb_con, first_fb_vc, last_fb_vc, 3021 ret = do_unbind_con_driver(&fb_con, first_fb_vc, last_fb_vc,
2989 fbcon_is_default); 3022 fbcon_is_default);
2990 3023
2991 if (!ret) 3024 if (!ret)
@@ -3000,6 +3033,7 @@ static inline int fbcon_unbind(void)
3000} 3033}
3001#endif /* CONFIG_VT_HW_CONSOLE_BINDING */ 3034#endif /* CONFIG_VT_HW_CONSOLE_BINDING */
3002 3035
3036/* called with console_lock held */
3003static int fbcon_fb_unbind(int idx) 3037static int fbcon_fb_unbind(int idx)
3004{ 3038{
3005 int i, new_idx = -1, ret = 0; 3039 int i, new_idx = -1, ret = 0;
@@ -3026,6 +3060,7 @@ static int fbcon_fb_unbind(int idx)
3026 return ret; 3060 return ret;
3027} 3061}
3028 3062
3063/* called with console_lock held */
3029static int fbcon_fb_unregistered(struct fb_info *info) 3064static int fbcon_fb_unregistered(struct fb_info *info)
3030{ 3065{
3031 int i, idx; 3066 int i, idx;
@@ -3058,11 +3093,12 @@ static int fbcon_fb_unregistered(struct fb_info *info)
3058 primary_device = -1; 3093 primary_device = -1;
3059 3094
3060 if (!num_registered_fb) 3095 if (!num_registered_fb)
3061 unregister_con_driver(&fb_con); 3096 do_unregister_con_driver(&fb_con);
3062 3097
3063 return 0; 3098 return 0;
3064} 3099}
3065 3100
3101/* called with console_lock held */
3066static void fbcon_remap_all(int idx) 3102static void fbcon_remap_all(int idx)
3067{ 3103{
3068 int i; 3104 int i;
@@ -3107,6 +3143,7 @@ static inline void fbcon_select_primary(struct fb_info *info)
3107} 3143}
3108#endif /* CONFIG_FRAMEBUFFER_DETECT_PRIMARY */ 3144#endif /* CONFIG_FRAMEBUFFER_DETECT_PRIMARY */
3109 3145
3146/* called with console_lock held */
3110static int fbcon_fb_registered(struct fb_info *info) 3147static int fbcon_fb_registered(struct fb_info *info)
3111{ 3148{
3112 int ret = 0, i, idx; 3149 int ret = 0, i, idx;
@@ -3123,7 +3160,7 @@ static int fbcon_fb_registered(struct fb_info *info)
3123 } 3160 }
3124 3161
3125 if (info_idx != -1) 3162 if (info_idx != -1)
3126 ret = fbcon_takeover(1); 3163 ret = do_fbcon_takeover(1);
3127 } else { 3164 } else {
3128 for (i = first_fb_vc; i <= last_fb_vc; i++) { 3165 for (i = first_fb_vc; i <= last_fb_vc; i++) {
3129 if (con2fb_map_boot[i] == idx) 3166 if (con2fb_map_boot[i] == idx)
@@ -3259,6 +3296,7 @@ static int fbcon_event_notify(struct notifier_block *self,
3259 ret = fbcon_fb_unregistered(info); 3296 ret = fbcon_fb_unregistered(info);
3260 break; 3297 break;
3261 case FB_EVENT_SET_CONSOLE_MAP: 3298 case FB_EVENT_SET_CONSOLE_MAP:
3299 /* called with console lock held */
3262 con2fb = event->data; 3300 con2fb = event->data;
3263 ret = set_con2fb_map(con2fb->console - 1, 3301 ret = set_con2fb_map(con2fb->console - 1,
3264 con2fb->framebuffer, 1); 3302 con2fb->framebuffer, 1);
diff --git a/drivers/video/console/vgacon.c b/drivers/video/console/vgacon.c
index d449a74d4a31..5855d17d19ac 100644
--- a/drivers/video/console/vgacon.c
+++ b/drivers/video/console/vgacon.c
@@ -1064,7 +1064,7 @@ static int vgacon_do_font_op(struct vgastate *state,char *arg,int set,int ch512)
1064 unsigned short video_port_status = vga_video_port_reg + 6; 1064 unsigned short video_port_status = vga_video_port_reg + 6;
1065 int font_select = 0x00, beg, i; 1065 int font_select = 0x00, beg, i;
1066 char *charmap; 1066 char *charmap;
1067 1067 bool clear_attribs = false;
1068 if (vga_video_type != VIDEO_TYPE_EGAM) { 1068 if (vga_video_type != VIDEO_TYPE_EGAM) {
1069 charmap = (char *) VGA_MAP_MEM(colourmap, 0); 1069 charmap = (char *) VGA_MAP_MEM(colourmap, 0);
1070 beg = 0x0e; 1070 beg = 0x0e;
@@ -1169,12 +1169,6 @@ static int vgacon_do_font_op(struct vgastate *state,char *arg,int set,int ch512)
1169 1169
1170 /* if 512 char mode is already enabled don't re-enable it. */ 1170 /* if 512 char mode is already enabled don't re-enable it. */
1171 if ((set) && (ch512 != vga_512_chars)) { 1171 if ((set) && (ch512 != vga_512_chars)) {
1172 /* attribute controller */
1173 for (i = 0; i < MAX_NR_CONSOLES; i++) {
1174 struct vc_data *c = vc_cons[i].d;
1175 if (c && c->vc_sw == &vga_con)
1176 c->vc_hi_font_mask = ch512 ? 0x0800 : 0;
1177 }
1178 vga_512_chars = ch512; 1172 vga_512_chars = ch512;
1179 /* 256-char: enable intensity bit 1173 /* 256-char: enable intensity bit
1180 512-char: disable intensity bit */ 1174 512-char: disable intensity bit */
@@ -1185,8 +1179,22 @@ static int vgacon_do_font_op(struct vgastate *state,char *arg,int set,int ch512)
1185 it means, but it works, and it appears necessary */ 1179 it means, but it works, and it appears necessary */
1186 inb_p(video_port_status); 1180 inb_p(video_port_status);
1187 vga_wattr(state->vgabase, VGA_AR_ENABLE_DISPLAY, 0); 1181 vga_wattr(state->vgabase, VGA_AR_ENABLE_DISPLAY, 0);
1182 clear_attribs = true;
1188 } 1183 }
1189 raw_spin_unlock_irq(&vga_lock); 1184 raw_spin_unlock_irq(&vga_lock);
1185
1186 if (clear_attribs) {
1187 for (i = 0; i < MAX_NR_CONSOLES; i++) {
1188 struct vc_data *c = vc_cons[i].d;
1189 if (c && c->vc_sw == &vga_con) {
1190 /* force hi font mask to 0, so we always clear
1191 the bit on either transition */
1192 c->vc_hi_font_mask = 0x00;
1193 clear_buffer_attributes(c);
1194 c->vc_hi_font_mask = ch512 ? 0x0800 : 0;
1195 }
1196 }
1197 }
1190 return 0; 1198 return 0;
1191} 1199}
1192 1200
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/fbmem.c b/drivers/video/fbmem.c
index 3ff0105a496a..dc61c12ecf8c 100644
--- a/drivers/video/fbmem.c
+++ b/drivers/video/fbmem.c
@@ -1177,8 +1177,10 @@ static long do_fb_ioctl(struct fb_info *info, unsigned int cmd,
1177 event.data = &con2fb; 1177 event.data = &con2fb;
1178 if (!lock_fb_info(info)) 1178 if (!lock_fb_info(info))
1179 return -ENODEV; 1179 return -ENODEV;
1180 console_lock();
1180 event.info = info; 1181 event.info = info;
1181 ret = fb_notifier_call_chain(FB_EVENT_SET_CONSOLE_MAP, &event); 1182 ret = fb_notifier_call_chain(FB_EVENT_SET_CONSOLE_MAP, &event);
1183 console_unlock();
1182 unlock_fb_info(info); 1184 unlock_fb_info(info);
1183 break; 1185 break;
1184 case FBIOBLANK: 1186 case FBIOBLANK:
@@ -1650,7 +1652,9 @@ static int do_register_framebuffer(struct fb_info *fb_info)
1650 event.info = fb_info; 1652 event.info = fb_info;
1651 if (!lock_fb_info(fb_info)) 1653 if (!lock_fb_info(fb_info))
1652 return -ENODEV; 1654 return -ENODEV;
1655 console_lock();
1653 fb_notifier_call_chain(FB_EVENT_FB_REGISTERED, &event); 1656 fb_notifier_call_chain(FB_EVENT_FB_REGISTERED, &event);
1657 console_unlock();
1654 unlock_fb_info(fb_info); 1658 unlock_fb_info(fb_info);
1655 return 0; 1659 return 0;
1656} 1660}
@@ -1666,8 +1670,10 @@ static int do_unregister_framebuffer(struct fb_info *fb_info)
1666 1670
1667 if (!lock_fb_info(fb_info)) 1671 if (!lock_fb_info(fb_info))
1668 return -ENODEV; 1672 return -ENODEV;
1673 console_lock();
1669 event.info = fb_info; 1674 event.info = fb_info;
1670 ret = fb_notifier_call_chain(FB_EVENT_FB_UNBIND, &event); 1675 ret = fb_notifier_call_chain(FB_EVENT_FB_UNBIND, &event);
1676 console_unlock();
1671 unlock_fb_info(fb_info); 1677 unlock_fb_info(fb_info);
1672 1678
1673 if (ret) 1679 if (ret)
@@ -1682,7 +1688,9 @@ static int do_unregister_framebuffer(struct fb_info *fb_info)
1682 num_registered_fb--; 1688 num_registered_fb--;
1683 fb_cleanup_device(fb_info); 1689 fb_cleanup_device(fb_info);
1684 event.info = fb_info; 1690 event.info = fb_info;
1691 console_lock();
1685 fb_notifier_call_chain(FB_EVENT_FB_UNREGISTERED, &event); 1692 fb_notifier_call_chain(FB_EVENT_FB_UNREGISTERED, &event);
1693 console_unlock();
1686 1694
1687 /* this may free fb info */ 1695 /* this may free fb info */
1688 put_fb_info(fb_info); 1696 put_fb_info(fb_info);
@@ -1853,11 +1861,8 @@ int fb_new_modelist(struct fb_info *info)
1853 err = 1; 1861 err = 1;
1854 1862
1855 if (!list_empty(&info->modelist)) { 1863 if (!list_empty(&info->modelist)) {
1856 if (!lock_fb_info(info))
1857 return -ENODEV;
1858 event.info = info; 1864 event.info = info;
1859 err = fb_notifier_call_chain(FB_EVENT_NEW_MODELIST, &event); 1865 err = fb_notifier_call_chain(FB_EVENT_NEW_MODELIST, &event);
1860 unlock_fb_info(info);
1861 } 1866 }
1862 1867
1863 return err; 1868 return err;
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/fbsysfs.c b/drivers/video/fbsysfs.c
index a55e3669d135..ef476b02fbe5 100644
--- a/drivers/video/fbsysfs.c
+++ b/drivers/video/fbsysfs.c
@@ -177,6 +177,8 @@ static ssize_t store_modes(struct device *device,
177 if (i * sizeof(struct fb_videomode) != count) 177 if (i * sizeof(struct fb_videomode) != count)
178 return -EINVAL; 178 return -EINVAL;
179 179
180 if (!lock_fb_info(fb_info))
181 return -ENODEV;
180 console_lock(); 182 console_lock();
181 list_splice(&fb_info->modelist, &old_list); 183 list_splice(&fb_info->modelist, &old_list);
182 fb_videomode_to_modelist((const struct fb_videomode *)buf, i, 184 fb_videomode_to_modelist((const struct fb_videomode *)buf, i,
@@ -188,6 +190,7 @@ static ssize_t store_modes(struct device *device,
188 fb_destroy_modelist(&old_list); 190 fb_destroy_modelist(&old_list);
189 191
190 console_unlock(); 192 console_unlock();
193 unlock_fb_info(fb_info);
191 194
192 return 0; 195 return 0;
193} 196}
diff --git a/drivers/video/hdmi.c b/drivers/video/hdmi.c
new file mode 100644
index 000000000000..ab23c9b79143
--- /dev/null
+++ b/drivers/video/hdmi.c
@@ -0,0 +1,308 @@
1/*
2 * Copyright (C) 2012 Avionic Design GmbH
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
7 */
8
9#include <linux/bitops.h>
10#include <linux/errno.h>
11#include <linux/export.h>
12#include <linux/hdmi.h>
13#include <linux/string.h>
14
15static void hdmi_infoframe_checksum(void *buffer, size_t size)
16{
17 u8 *ptr = buffer;
18 u8 csum = 0;
19 size_t i;
20
21 /* compute checksum */
22 for (i = 0; i < size; i++)
23 csum += ptr[i];
24
25 ptr[3] = 256 - csum;
26}
27
28/**
29 * hdmi_avi_infoframe_init() - initialize an HDMI AVI infoframe
30 * @frame: HDMI AVI infoframe
31 *
32 * Returns 0 on success or a negative error code on failure.
33 */
34int hdmi_avi_infoframe_init(struct hdmi_avi_infoframe *frame)
35{
36 memset(frame, 0, sizeof(*frame));
37
38 frame->type = HDMI_INFOFRAME_TYPE_AVI;
39 frame->version = 2;
40 frame->length = 13;
41
42 return 0;
43}
44EXPORT_SYMBOL(hdmi_avi_infoframe_init);
45
46/**
47 * hdmi_avi_infoframe_pack() - write HDMI AVI infoframe to binary buffer
48 * @frame: HDMI AVI infoframe
49 * @buffer: destination buffer
50 * @size: size of buffer
51 *
52 * Packs the information contained in the @frame structure into a binary
53 * representation that can be written into the corresponding controller
54 * registers. Also computes the checksum as required by section 5.3.5 of
55 * the HDMI 1.4 specification.
56 *
57 * Returns the number of bytes packed into the binary buffer or a negative
58 * error code on failure.
59 */
60ssize_t hdmi_avi_infoframe_pack(struct hdmi_avi_infoframe *frame, void *buffer,
61 size_t size)
62{
63 u8 *ptr = buffer;
64 size_t length;
65
66 length = HDMI_INFOFRAME_HEADER_SIZE + frame->length;
67
68 if (size < length)
69 return -ENOSPC;
70
71 memset(buffer, 0, length);
72
73 ptr[0] = frame->type;
74 ptr[1] = frame->version;
75 ptr[2] = frame->length;
76 ptr[3] = 0; /* checksum */
77
78 /* start infoframe payload */
79 ptr += HDMI_INFOFRAME_HEADER_SIZE;
80
81 ptr[0] = ((frame->colorspace & 0x3) << 5) | (frame->scan_mode & 0x3);
82
83 if (frame->active_info_valid)
84 ptr[0] |= BIT(4);
85
86 if (frame->horizontal_bar_valid)
87 ptr[0] |= BIT(3);
88
89 if (frame->vertical_bar_valid)
90 ptr[0] |= BIT(2);
91
92 ptr[1] = ((frame->colorimetry & 0x3) << 6) |
93 ((frame->picture_aspect & 0x3) << 4) |
94 (frame->active_aspect & 0xf);
95
96 ptr[2] = ((frame->extended_colorimetry & 0x7) << 4) |
97 ((frame->quantization_range & 0x3) << 2) |
98 (frame->nups & 0x3);
99
100 if (frame->itc)
101 ptr[2] |= BIT(7);
102
103 ptr[3] = frame->video_code & 0x7f;
104
105 ptr[4] = ((frame->ycc_quantization_range & 0x3) << 6) |
106 ((frame->content_type & 0x3) << 4) |
107 (frame->pixel_repeat & 0xf);
108
109 ptr[5] = frame->top_bar & 0xff;
110 ptr[6] = (frame->top_bar >> 8) & 0xff;
111 ptr[7] = frame->bottom_bar & 0xff;
112 ptr[8] = (frame->bottom_bar >> 8) & 0xff;
113 ptr[9] = frame->left_bar & 0xff;
114 ptr[10] = (frame->left_bar >> 8) & 0xff;
115 ptr[11] = frame->right_bar & 0xff;
116 ptr[12] = (frame->right_bar >> 8) & 0xff;
117
118 hdmi_infoframe_checksum(buffer, length);
119
120 return length;
121}
122EXPORT_SYMBOL(hdmi_avi_infoframe_pack);
123
124/**
125 * hdmi_spd_infoframe_init() - initialize an HDMI SPD infoframe
126 * @frame: HDMI SPD infoframe
127 * @vendor: vendor string
128 * @product: product string
129 *
130 * Returns 0 on success or a negative error code on failure.
131 */
132int hdmi_spd_infoframe_init(struct hdmi_spd_infoframe *frame,
133 const char *vendor, const char *product)
134{
135 memset(frame, 0, sizeof(*frame));
136
137 frame->type = HDMI_INFOFRAME_TYPE_SPD;
138 frame->version = 1;
139 frame->length = 25;
140
141 strncpy(frame->vendor, vendor, sizeof(frame->vendor));
142 strncpy(frame->product, product, sizeof(frame->product));
143
144 return 0;
145}
146EXPORT_SYMBOL(hdmi_spd_infoframe_init);
147
148/**
149 * hdmi_spd_infoframe_pack() - write HDMI SPD infoframe to binary buffer
150 * @frame: HDMI SPD infoframe
151 * @buffer: destination buffer
152 * @size: size of buffer
153 *
154 * Packs the information contained in the @frame structure into a binary
155 * representation that can be written into the corresponding controller
156 * registers. Also computes the checksum as required by section 5.3.5 of
157 * the HDMI 1.4 specification.
158 *
159 * Returns the number of bytes packed into the binary buffer or a negative
160 * error code on failure.
161 */
162ssize_t hdmi_spd_infoframe_pack(struct hdmi_spd_infoframe *frame, void *buffer,
163 size_t size)
164{
165 u8 *ptr = buffer;
166 size_t length;
167
168 length = HDMI_INFOFRAME_HEADER_SIZE + frame->length;
169
170 if (size < length)
171 return -ENOSPC;
172
173 memset(buffer, 0, length);
174
175 ptr[0] = frame->type;
176 ptr[1] = frame->version;
177 ptr[2] = frame->length;
178 ptr[3] = 0; /* checksum */
179
180 /* start infoframe payload */
181 ptr += HDMI_INFOFRAME_HEADER_SIZE;
182
183 memcpy(ptr, frame->vendor, sizeof(frame->vendor));
184 memcpy(ptr + 8, frame->product, sizeof(frame->product));
185
186 ptr[24] = frame->sdi;
187
188 hdmi_infoframe_checksum(buffer, length);
189
190 return length;
191}
192EXPORT_SYMBOL(hdmi_spd_infoframe_pack);
193
194/**
195 * hdmi_audio_infoframe_init() - initialize an HDMI audio infoframe
196 * @frame: HDMI audio infoframe
197 *
198 * Returns 0 on success or a negative error code on failure.
199 */
200int hdmi_audio_infoframe_init(struct hdmi_audio_infoframe *frame)
201{
202 memset(frame, 0, sizeof(*frame));
203
204 frame->type = HDMI_INFOFRAME_TYPE_AUDIO;
205 frame->version = 1;
206 frame->length = 10;
207
208 return 0;
209}
210EXPORT_SYMBOL(hdmi_audio_infoframe_init);
211
212/**
213 * hdmi_audio_infoframe_pack() - write HDMI audio infoframe to binary buffer
214 * @frame: HDMI audio infoframe
215 * @buffer: destination buffer
216 * @size: size of buffer
217 *
218 * Packs the information contained in the @frame structure into a binary
219 * representation that can be written into the corresponding controller
220 * registers. Also computes the checksum as required by section 5.3.5 of
221 * the HDMI 1.4 specification.
222 *
223 * Returns the number of bytes packed into the binary buffer or a negative
224 * error code on failure.
225 */
226ssize_t hdmi_audio_infoframe_pack(struct hdmi_audio_infoframe *frame,
227 void *buffer, size_t size)
228{
229 unsigned char channels;
230 u8 *ptr = buffer;
231 size_t length;
232
233 length = HDMI_INFOFRAME_HEADER_SIZE + frame->length;
234
235 if (size < length)
236 return -ENOSPC;
237
238 memset(buffer, 0, length);
239
240 if (frame->channels >= 2)
241 channels = frame->channels - 1;
242 else
243 channels = 0;
244
245 ptr[0] = frame->type;
246 ptr[1] = frame->version;
247 ptr[2] = frame->length;
248 ptr[3] = 0; /* checksum */
249
250 /* start infoframe payload */
251 ptr += HDMI_INFOFRAME_HEADER_SIZE;
252
253 ptr[0] = ((frame->coding_type & 0xf) << 4) | (channels & 0x7);
254 ptr[1] = ((frame->sample_frequency & 0x7) << 2) |
255 (frame->sample_size & 0x3);
256 ptr[2] = frame->coding_type_ext & 0x1f;
257 ptr[3] = frame->channel_allocation;
258 ptr[4] = (frame->level_shift_value & 0xf) << 3;
259
260 if (frame->downmix_inhibit)
261 ptr[4] |= BIT(7);
262
263 hdmi_infoframe_checksum(buffer, length);
264
265 return length;
266}
267EXPORT_SYMBOL(hdmi_audio_infoframe_pack);
268
269/**
270 * hdmi_vendor_infoframe_pack() - write a HDMI vendor infoframe to binary
271 * buffer
272 * @frame: HDMI vendor infoframe
273 * @buffer: destination buffer
274 * @size: size of buffer
275 *
276 * Packs the information contained in the @frame structure into a binary
277 * representation that can be written into the corresponding controller
278 * registers. Also computes the checksum as required by section 5.3.5 of
279 * the HDMI 1.4 specification.
280 *
281 * Returns the number of bytes packed into the binary buffer or a negative
282 * error code on failure.
283 */
284ssize_t hdmi_vendor_infoframe_pack(struct hdmi_vendor_infoframe *frame,
285 void *buffer, size_t size)
286{
287 u8 *ptr = buffer;
288 size_t length;
289
290 length = HDMI_INFOFRAME_HEADER_SIZE + frame->length;
291
292 if (size < length)
293 return -ENOSPC;
294
295 memset(buffer, 0, length);
296
297 ptr[0] = frame->type;
298 ptr[1] = frame->version;
299 ptr[2] = frame->length;
300 ptr[3] = 0; /* checksum */
301
302 memcpy(&ptr[HDMI_INFOFRAME_HEADER_SIZE], frame->data, frame->length);
303
304 hdmi_infoframe_checksum(buffer, length);
305
306 return length;
307}
308EXPORT_SYMBOL(hdmi_vendor_infoframe_pack);
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);