diff options
author | Bernie Thompson <bernie@plugable.com> | 2011-08-21 16:34:11 -0400 |
---|---|---|
committer | Florian Tobias Schandinat <FlorianSchandinat@gmx.de> | 2011-08-24 06:07:59 -0400 |
commit | 58e7c3b00114c48e0879e9fbafd37e0e0c2402cb (patch) | |
tree | 372fa4a8702694cc50ba609c6a650c65d8812a18 | |
parent | 3c470f33e6a1df1398143c1f3dd619f675602472 (diff) |
udlfb: add more comprehensive support for DPMS FB_BLANK_* modes
Fixes earlier problems where monitor would not return from blank
Test with any DisplayLink-based USB 2.0 graphics adapter
sudo nano /sys/class/graphics/fb?/blank
and write out single digit FB_BLANK_* code from include/linux/fb.h
Supports on (0), blank (1), suspend (2,3), powerdown (4)
Signed-off-by: Bernie Thompson <bernie@plugable.com>
Signed-off-by: Florian Tobias Schandinat <FlorianSchandinat@gmx.de>
-rw-r--r-- | drivers/video/udlfb.c | 97 | ||||
-rw-r--r-- | include/video/udlfb.h | 1 |
2 files changed, 74 insertions, 24 deletions
diff --git a/drivers/video/udlfb.c b/drivers/video/udlfb.c index 087fc9960bb..fecd2d3543b 100644 --- a/drivers/video/udlfb.c +++ b/drivers/video/udlfb.c | |||
@@ -94,17 +94,39 @@ static char *dlfb_vidreg_unlock(char *buf) | |||
94 | } | 94 | } |
95 | 95 | ||
96 | /* | 96 | /* |
97 | * On/Off for driving the DisplayLink framebuffer to the display | 97 | * Map FB_BLANK_* to DisplayLink register |
98 | * 0x00 H and V sync on | 98 | * DLReg FB_BLANK_* |
99 | * 0x01 H and V sync off (screen blank but powered) | 99 | * ----- ----------------------------- |
100 | * 0x07 DPMS powerdown (requires modeset to come back) | 100 | * 0x00 FB_BLANK_UNBLANK (0) |
101 | * 0x01 FB_BLANK (1) | ||
102 | * 0x03 FB_BLANK_VSYNC_SUSPEND (2) | ||
103 | * 0x05 FB_BLANK_HSYNC_SUSPEND (3) | ||
104 | * 0x07 FB_BLANK_POWERDOWN (4) Note: requires modeset to come back | ||
101 | */ | 105 | */ |
102 | static char *dlfb_enable_hvsync(char *buf, bool enable) | 106 | static char *dlfb_blanking(char *buf, int fb_blank) |
103 | { | 107 | { |
104 | if (enable) | 108 | u8 reg; |
105 | return dlfb_set_register(buf, 0x1F, 0x00); | 109 | |
106 | else | 110 | switch (fb_blank) { |
107 | return dlfb_set_register(buf, 0x1F, 0x07); | 111 | case FB_BLANK_POWERDOWN: |
112 | reg = 0x07; | ||
113 | break; | ||
114 | case FB_BLANK_HSYNC_SUSPEND: | ||
115 | reg = 0x05; | ||
116 | break; | ||
117 | case FB_BLANK_VSYNC_SUSPEND: | ||
118 | reg = 0x03; | ||
119 | break; | ||
120 | case FB_BLANK_NORMAL: | ||
121 | reg = 0x01; | ||
122 | break; | ||
123 | default: | ||
124 | reg = 0x00; | ||
125 | } | ||
126 | |||
127 | buf = dlfb_set_register(buf, 0x1F, reg); | ||
128 | |||
129 | return buf; | ||
108 | } | 130 | } |
109 | 131 | ||
110 | static char *dlfb_set_color_depth(char *buf, u8 selection) | 132 | static char *dlfb_set_color_depth(char *buf, u8 selection) |
@@ -272,13 +294,15 @@ static int dlfb_set_video_mode(struct dlfb_data *dev, | |||
272 | wrptr = dlfb_set_base8bpp(wrptr, dev->info->fix.smem_len); | 294 | wrptr = dlfb_set_base8bpp(wrptr, dev->info->fix.smem_len); |
273 | 295 | ||
274 | wrptr = dlfb_set_vid_cmds(wrptr, var); | 296 | wrptr = dlfb_set_vid_cmds(wrptr, var); |
275 | wrptr = dlfb_enable_hvsync(wrptr, true); | 297 | wrptr = dlfb_blanking(wrptr, FB_BLANK_UNBLANK); |
276 | wrptr = dlfb_vidreg_unlock(wrptr); | 298 | wrptr = dlfb_vidreg_unlock(wrptr); |
277 | 299 | ||
278 | writesize = wrptr - buf; | 300 | writesize = wrptr - buf; |
279 | 301 | ||
280 | retval = dlfb_submit_urb(dev, urb, writesize); | 302 | retval = dlfb_submit_urb(dev, urb, writesize); |
281 | 303 | ||
304 | dev->blank_mode = FB_BLANK_UNBLANK; | ||
305 | |||
282 | return retval; | 306 | return retval; |
283 | } | 307 | } |
284 | 308 | ||
@@ -1039,32 +1063,57 @@ static int dlfb_ops_set_par(struct fb_info *info) | |||
1039 | return result; | 1063 | return result; |
1040 | } | 1064 | } |
1041 | 1065 | ||
1066 | /* To fonzi the jukebox (e.g. make blanking changes take effect) */ | ||
1067 | static char *dlfb_dummy_render(char *buf) | ||
1068 | { | ||
1069 | *buf++ = 0xAF; | ||
1070 | *buf++ = 0x6A; /* copy */ | ||
1071 | *buf++ = 0x00; /* from address*/ | ||
1072 | *buf++ = 0x00; | ||
1073 | *buf++ = 0x00; | ||
1074 | *buf++ = 0x01; /* one pixel */ | ||
1075 | *buf++ = 0x00; /* to address */ | ||
1076 | *buf++ = 0x00; | ||
1077 | *buf++ = 0x00; | ||
1078 | return buf; | ||
1079 | } | ||
1080 | |||
1042 | /* | 1081 | /* |
1043 | * In order to come back from full DPMS off, we need to set the mode again | 1082 | * In order to come back from full DPMS off, we need to set the mode again |
1044 | */ | 1083 | */ |
1045 | static int dlfb_ops_blank(int blank_mode, struct fb_info *info) | 1084 | static int dlfb_ops_blank(int blank_mode, struct fb_info *info) |
1046 | { | 1085 | { |
1047 | struct dlfb_data *dev = info->par; | 1086 | struct dlfb_data *dev = info->par; |
1087 | char *bufptr; | ||
1088 | struct urb *urb; | ||
1048 | 1089 | ||
1049 | if (blank_mode != FB_BLANK_UNBLANK) { | 1090 | pr_info("/dev/fb%d FB_BLANK mode %d --> %d\n", |
1050 | char *bufptr; | 1091 | info->node, dev->blank_mode, blank_mode); |
1051 | struct urb *urb; | ||
1052 | |||
1053 | urb = dlfb_get_urb(dev); | ||
1054 | if (!urb) | ||
1055 | return 0; | ||
1056 | 1092 | ||
1057 | bufptr = (char *) urb->transfer_buffer; | 1093 | if ((dev->blank_mode == FB_BLANK_POWERDOWN) && |
1058 | bufptr = dlfb_vidreg_lock(bufptr); | 1094 | (blank_mode != FB_BLANK_POWERDOWN)) { |
1059 | bufptr = dlfb_enable_hvsync(bufptr, false); | ||
1060 | bufptr = dlfb_vidreg_unlock(bufptr); | ||
1061 | 1095 | ||
1062 | dlfb_submit_urb(dev, urb, bufptr - | 1096 | /* returning from powerdown requires a fresh modeset */ |
1063 | (char *) urb->transfer_buffer); | ||
1064 | } else { | ||
1065 | dlfb_set_video_mode(dev, &info->var); | 1097 | dlfb_set_video_mode(dev, &info->var); |
1066 | } | 1098 | } |
1067 | 1099 | ||
1100 | urb = dlfb_get_urb(dev); | ||
1101 | if (!urb) | ||
1102 | return 0; | ||
1103 | |||
1104 | bufptr = (char *) urb->transfer_buffer; | ||
1105 | bufptr = dlfb_vidreg_lock(bufptr); | ||
1106 | bufptr = dlfb_blanking(bufptr, blank_mode); | ||
1107 | bufptr = dlfb_vidreg_unlock(bufptr); | ||
1108 | |||
1109 | /* seems like a render op is needed to have blank change take effect */ | ||
1110 | bufptr = dlfb_dummy_render(bufptr); | ||
1111 | |||
1112 | dlfb_submit_urb(dev, urb, bufptr - | ||
1113 | (char *) urb->transfer_buffer); | ||
1114 | |||
1115 | dev->blank_mode = blank_mode; | ||
1116 | |||
1068 | return 0; | 1117 | return 0; |
1069 | } | 1118 | } |
1070 | 1119 | ||
diff --git a/include/video/udlfb.h b/include/video/udlfb.h index 69d485a4a02..c41f308c963 100644 --- a/include/video/udlfb.h +++ b/include/video/udlfb.h | |||
@@ -50,6 +50,7 @@ struct dlfb_data { | |||
50 | int base16; | 50 | int base16; |
51 | int base8; | 51 | int base8; |
52 | u32 pseudo_palette[256]; | 52 | u32 pseudo_palette[256]; |
53 | int blank_mode; /*one of FB_BLANK_ */ | ||
53 | /* blit-only rendering path metrics, exposed through sysfs */ | 54 | /* blit-only rendering path metrics, exposed through sysfs */ |
54 | atomic_t bytes_rendered; /* raw pixel-bytes driver asked to render */ | 55 | atomic_t bytes_rendered; /* raw pixel-bytes driver asked to render */ |
55 | atomic_t bytes_identical; /* saved effort with backbuffer comparison */ | 56 | atomic_t bytes_identical; /* saved effort with backbuffer comparison */ |