diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2013-02-25 19:46:44 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2013-02-25 19:46:44 -0500 |
commit | fffddfd6c8e0c10c42c6e2cc54ba880fcc36ebbb (patch) | |
tree | 71bc5e597124dbaf7550f1e089d675718b3ed5c0 /drivers/video | |
parent | 69086a78bdc973ec0b722be790b146e84ba8a8c4 (diff) | |
parent | be88298b0a3f771a4802f20c5e66af74bfd1dff1 (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/Kconfig | 26 | ||||
-rw-r--r-- | drivers/video/Makefile | 5 | ||||
-rw-r--r-- | drivers/video/console/fbcon.c | 58 | ||||
-rw-r--r-- | drivers/video/console/vgacon.c | 22 | ||||
-rw-r--r-- | drivers/video/display_timing.c | 24 | ||||
-rw-r--r-- | drivers/video/fbmem.c | 11 | ||||
-rw-r--r-- | drivers/video/fbmon.c | 94 | ||||
-rw-r--r-- | drivers/video/fbsysfs.c | 3 | ||||
-rw-r--r-- | drivers/video/hdmi.c | 308 | ||||
-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 |
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 | ||
22 | source "drivers/gpu/drm/Kconfig" | 22 | source "drivers/gpu/drm/Kconfig" |
23 | 23 | ||
24 | source "drivers/gpu/stub/Kconfig" | ||
25 | |||
26 | config VGASTATE | 24 | config 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 | ||
34 | config DISPLAY_TIMING | ||
35 | bool | ||
36 | |||
37 | config VIDEOMODE | ||
38 | bool | ||
39 | |||
40 | config 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 | |||
47 | config 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 | |||
55 | config HDMI | ||
56 | bool | ||
57 | |||
36 | menuconfig FB | 58 | menuconfig 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 | ||
7 | obj-$(CONFIG_VGASTATE) += vgastate.o | 7 | obj-$(CONFIG_VGASTATE) += vgastate.o |
8 | obj-$(CONFIG_HDMI) += hdmi.o | ||
8 | obj-y += fb_notify.o | 9 | obj-y += fb_notify.o |
9 | obj-$(CONFIG_FB) += fb.o | 10 | obj-$(CONFIG_FB) += fb.o |
10 | fb-y := fbmem.o fbmon.o fbcmap.o fbsysfs.o \ | 11 | fb-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 |
172 | obj-$(CONFIG_VIDEO_OUTPUT_CONTROL) += output.o | 173 | obj-$(CONFIG_VIDEO_OUTPUT_CONTROL) += output.o |
174 | obj-$(CONFIG_DISPLAY_TIMING) += display_timing.o | ||
175 | obj-$(CONFIG_OF_DISPLAY_TIMING) += of_display_timing.o | ||
176 | obj-$(CONFIG_VIDEOMODE) += videomode.o | ||
177 | obj-$(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 | ||
532 | static 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 | |||
532 | static int fbcon_takeover(int show_logo) | 559 | static 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 | */ |
819 | static int set_con2fb_map(int unit, int newidx, int user) | 848 | static 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 | ||
1162 | static void fbcon_free_font(struct display *p) | 1191 | static 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; |
1197 | finished: | 1228 | finished: |
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 */ | ||
3003 | static int fbcon_fb_unbind(int idx) | 3037 | static 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 */ | ||
3029 | static int fbcon_fb_unregistered(struct fb_info *info) | 3064 | static 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 */ | ||
3066 | static void fbcon_remap_all(int idx) | 3102 | static 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 */ | ||
3110 | static int fbcon_fb_registered(struct fb_info *info) | 3147 | static 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 | |||
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/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) | ||
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/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 | |||
15 | static 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 | */ | ||
34 | int 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 | } | ||
44 | EXPORT_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 | */ | ||
60 | ssize_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 | } | ||
122 | EXPORT_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 | */ | ||
132 | int 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 | } | ||
146 | EXPORT_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 | */ | ||
162 | ssize_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 | } | ||
192 | EXPORT_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 | */ | ||
200 | int 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 | } | ||
210 | EXPORT_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 | */ | ||
226 | ssize_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 | } | ||
267 | EXPORT_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 | */ | ||
284 | ssize_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 | } | ||
308 | EXPORT_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 | **/ | ||
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); | ||