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>
This commit is contained in:
Bernie Thompson 2011-08-21 13:34:11 -07:00 committed by Florian Tobias Schandinat
parent 3c470f33e6
commit 58e7c3b001
2 changed files with 74 additions and 24 deletions

View File

@ -94,17 +94,39 @@ static char *dlfb_vidreg_unlock(char *buf)
} }
/* /*
* On/Off for driving the DisplayLink framebuffer to the display * Map FB_BLANK_* to DisplayLink register
* 0x00 H and V sync on * DLReg FB_BLANK_*
* 0x01 H and V sync off (screen blank but powered) * ----- -----------------------------
* 0x07 DPMS powerdown (requires modeset to come back) * 0x00 FB_BLANK_UNBLANK (0)
* 0x01 FB_BLANK (1)
* 0x03 FB_BLANK_VSYNC_SUSPEND (2)
* 0x05 FB_BLANK_HSYNC_SUSPEND (3)
* 0x07 FB_BLANK_POWERDOWN (4) Note: requires modeset to come back
*/ */
static char *dlfb_enable_hvsync(char *buf, bool enable) static char *dlfb_blanking(char *buf, int fb_blank)
{ {
if (enable) u8 reg;
return dlfb_set_register(buf, 0x1F, 0x00);
else switch (fb_blank) {
return dlfb_set_register(buf, 0x1F, 0x07); case FB_BLANK_POWERDOWN:
reg = 0x07;
break;
case FB_BLANK_HSYNC_SUSPEND:
reg = 0x05;
break;
case FB_BLANK_VSYNC_SUSPEND:
reg = 0x03;
break;
case FB_BLANK_NORMAL:
reg = 0x01;
break;
default:
reg = 0x00;
}
buf = dlfb_set_register(buf, 0x1F, reg);
return buf;
} }
static char *dlfb_set_color_depth(char *buf, u8 selection) static char *dlfb_set_color_depth(char *buf, u8 selection)
@ -272,13 +294,15 @@ static int dlfb_set_video_mode(struct dlfb_data *dev,
wrptr = dlfb_set_base8bpp(wrptr, dev->info->fix.smem_len); wrptr = dlfb_set_base8bpp(wrptr, dev->info->fix.smem_len);
wrptr = dlfb_set_vid_cmds(wrptr, var); wrptr = dlfb_set_vid_cmds(wrptr, var);
wrptr = dlfb_enable_hvsync(wrptr, true); wrptr = dlfb_blanking(wrptr, FB_BLANK_UNBLANK);
wrptr = dlfb_vidreg_unlock(wrptr); wrptr = dlfb_vidreg_unlock(wrptr);
writesize = wrptr - buf; writesize = wrptr - buf;
retval = dlfb_submit_urb(dev, urb, writesize); retval = dlfb_submit_urb(dev, urb, writesize);
dev->blank_mode = FB_BLANK_UNBLANK;
return retval; return retval;
} }
@ -1039,32 +1063,57 @@ static int dlfb_ops_set_par(struct fb_info *info)
return result; return result;
} }
/* To fonzi the jukebox (e.g. make blanking changes take effect) */
static char *dlfb_dummy_render(char *buf)
{
*buf++ = 0xAF;
*buf++ = 0x6A; /* copy */
*buf++ = 0x00; /* from address*/
*buf++ = 0x00;
*buf++ = 0x00;
*buf++ = 0x01; /* one pixel */
*buf++ = 0x00; /* to address */
*buf++ = 0x00;
*buf++ = 0x00;
return buf;
}
/* /*
* In order to come back from full DPMS off, we need to set the mode again * In order to come back from full DPMS off, we need to set the mode again
*/ */
static int dlfb_ops_blank(int blank_mode, struct fb_info *info) static int dlfb_ops_blank(int blank_mode, struct fb_info *info)
{ {
struct dlfb_data *dev = info->par; struct dlfb_data *dev = info->par;
char *bufptr;
struct urb *urb;
if (blank_mode != FB_BLANK_UNBLANK) { pr_info("/dev/fb%d FB_BLANK mode %d --> %d\n",
char *bufptr; info->node, dev->blank_mode, blank_mode);
struct urb *urb;
urb = dlfb_get_urb(dev); if ((dev->blank_mode == FB_BLANK_POWERDOWN) &&
if (!urb) (blank_mode != FB_BLANK_POWERDOWN)) {
return 0;
bufptr = (char *) urb->transfer_buffer; /* returning from powerdown requires a fresh modeset */
bufptr = dlfb_vidreg_lock(bufptr);
bufptr = dlfb_enable_hvsync(bufptr, false);
bufptr = dlfb_vidreg_unlock(bufptr);
dlfb_submit_urb(dev, urb, bufptr -
(char *) urb->transfer_buffer);
} else {
dlfb_set_video_mode(dev, &info->var); dlfb_set_video_mode(dev, &info->var);
} }
urb = dlfb_get_urb(dev);
if (!urb)
return 0;
bufptr = (char *) urb->transfer_buffer;
bufptr = dlfb_vidreg_lock(bufptr);
bufptr = dlfb_blanking(bufptr, blank_mode);
bufptr = dlfb_vidreg_unlock(bufptr);
/* seems like a render op is needed to have blank change take effect */
bufptr = dlfb_dummy_render(bufptr);
dlfb_submit_urb(dev, urb, bufptr -
(char *) urb->transfer_buffer);
dev->blank_mode = blank_mode;
return 0; return 0;
} }

View File

@ -50,6 +50,7 @@ struct dlfb_data {
int base16; int base16;
int base8; int base8;
u32 pseudo_palette[256]; u32 pseudo_palette[256];
int blank_mode; /*one of FB_BLANK_ */
/* blit-only rendering path metrics, exposed through sysfs */ /* blit-only rendering path metrics, exposed through sysfs */
atomic_t bytes_rendered; /* raw pixel-bytes driver asked to render */ atomic_t bytes_rendered; /* raw pixel-bytes driver asked to render */
atomic_t bytes_identical; /* saved effort with backbuffer comparison */ atomic_t bytes_identical; /* saved effort with backbuffer comparison */