GEODE: decouple sleep/resume from powerdown/powerup
PATCH 1/1 GEODE: decouple sleep/resume from powerdown/powerup
This patch merges the fb_powerup and fb_powerdown hooks in a single operation fb_power with an additional "state" parameter ranging from 0 (running) to 3 (poweroff).
The geodefb uses state 2 as an intermediate low-power mode, where the LX or GX video unit is turned off, but the GPU may still be working. Notably, the GPU register set does not get overwritten when resuming to state 0, so the system can safely keep using the GPU while in state 2. The DCON driver now uses this new suspend state to let the X server draw in the background while the screen frozen.
This fixes the rather amusing OLPC bug #3603 that made the toolbar icons come up tinted in green when "pretty boot" was enabled. Tested on both B2 (GX) and B3 (LX) machines. Both the freeze/unfreeze and suspend/resume codepaths work as expected.
--- drivers/video/fbmem.c | 47 +++++-------------- drivers/video/geode/geodefb.h | 13 +++-- drivers/video/geode/gxfb_core.c | 17 +++---- drivers/video/geode/lxfb.h | 3 +- drivers/video/geode/lxfb_core.c | 12 ++--- drivers/video/geode/lxfb_ops.c | 47 +++++++++++-------- drivers/video/geode/video_gx.c | 97 +++++++++++++++++---------------------- drivers/video/geode/video_gx.h | 3 +- drivers/video/olpc_dcon.c | 8 ++-- include/linux/fb.h | 7 +-- 10 files changed, 112 insertions(+), 142 deletions(-)
drivers/video/fbmem.c +13 -34
@@ -736,49 +736,28 @@ static void try_to_load(int fb)#endif /* CONFIG_KMOD */ int -fb_powerup (struct fb_info *info) +fb_power (struct fb_info *info,int state) {int ret =0 ; -if (!info || info->state ==FBINFO_STATE_RUNNING ) -return 0 ; - -if (info->fbops->fb_powerup) - ret = info->fbops->fb_powerup (info); - -if (!ret) { -acquire_console_sem (); -fb_set_suspend (info,0 ); -release_console_sem (); - } - -return ret; -} - -int -fb_powerdown (struct fb_info *info) -{ -int ret =0 ; - -if (!info || info->state ==FBINFO_STATE_SUSPENDED ) -return 0 ; +if (state <0 || state >3 ) +return -EINVAL ; -/* Tell everybody that the fbdev is going down */ acquire_console_sem (); -fb_set_suspend (info,1 ); -release_console_sem (); +/* Powerdown? */ +if (state ==3 && info->state !=FBINFO_STATE_SUSPENDED ) +/* Tell everybody that the fbdev is going down */ +fb_set_suspend (info,1 ); -if (info->fbops->fb_powerdown) - ret = info->fbops->fb_powerdown (info); +if (info->fbops->fb_power) + ret = info->fbops->fb_power (info, state); -/* If the power down failed, then un-notify */ - -if (ret) { -acquire_console_sem (); +/* Power down failed, or powerup succeeded? */ +if (((state ==3 && ret) || !ret) && (info->state !=FBINFO_STATE_RUNNING )) +/* Tell everybody that the fbdev is back up */ fb_set_suspend (info,0 ); -release_console_sem (); - } +release_console_sem ();return ret; }
drivers/video/geode/geodefb.h +8 -5
@@ -12,12 +12,14 @@ #ifndef __GEODEFB_H__ #define __GEODEFB_H__ -#define FB_POWER_STATE_OFF 0 -#define FB_POWER_STATE_SUSPEND 1 -#define FB_POWER_STATE_ON 2 - struct geodefb_info; +/* For geodefb_par->power_state */ +#define FB_POWER_STATE_OFF 3 +#define FB_POWER_STATE_SUSPEND 2 +#define FB_POWER_STATE_UNUSED 1 /* Reserved */ +#define FB_POWER_STATE_ON 0 + struct geode_dc_ops { void (*set_mode)(struct fb_info *); void (*set_palette_reg)(struct fb_info *, unsigned, unsigned, unsigned, unsigned);
@@ -42,7 +44,8 @@ struct geodefb_par {struct geode_dc_ops *dc_ops;struct geode_vid_ops *vid_ops; - int state; +/* See FB_POWER_STATE_* definitions above */ + int power_state; };#endif /* !__GEODEFB_H__ */
drivers/video/geode/gxfb_core.c +8 -9
@@ -383,8 +383,7 @@ static struct fb_ops gxfb_ops = { .fb_fillrect = cfb_fillrect, .fb_copyarea = cfb_copyarea, .fb_imageblit = cfb_imageblit, - .fb_powerdown = gxfb_powerdown, - .fb_powerup = gxfb_powerup, + .fb_power = gxfb_power, };static struct fb_info *__init gxfb_init_fbinfo (struct device *dev)
@@ -452,13 +451,13 @@ static int gxfb_suspend(struct pci_dev *pdev, pm_message_t state)return 0 ;if (state.event ==PM_EVENT_SUSPEND ) { - +acquire_console_sem (); -gxfb_powerdown (info); +gxfb_power (info,3 ); - par->state =FB_POWER_STATE_OFF ; + par->power_state =FB_POWER_STATE_OFF ;fb_set_suspend (info,1 ); - +release_console_sem (); }
@@ -471,10 +470,10 @@ static int gxfb_resume(struct pci_dev *pdev)struct fb_info *info =pci_get_drvdata (pdev);acquire_console_sem (); - +/* Turn the engine completely on */ -if (gxfb_powerup (info)) +if (gxfb_power (info,0 ))printk (KERN_ERR "gxfb: Powerup failed\n" );fb_set_suspend (info,0 );
@@ -557,7 +556,7 @@ static int __init gxfb_probe(struct pci_dev *pdev,gxfb_set_par (gxfb_info);/* We are powered up */ - par->state =FB_POWER_STATE_ON ; + par->power_state =FB_POWER_STATE_ON ;console_event_register (&gxfb_console_notifier);
drivers/video/geode/lxfb.h +1 -2
@@ -25,8 +25,7 @@ void lx_set_mode(struct fb_info *);void lx_get_gamma (struct fb_info *,unsigned int *,int );void lx_set_gamma (struct fb_info *,unsigned int *,int );unsigned int lx_framebuffer_size (void ); -int lx_shutdown (struct fb_info *); -int lx_powerup (struct fb_info *); +int lx_power (struct fb_info *,int level);int lx_blank_display (struct fb_info *,int );void lx_set_palette_reg (struct fb_info *,unsigned int ,unsigned int ,unsigned int ,unsigned int );
drivers/video/geode/lxfb_core.c +5 -7
@@ -302,8 +302,7 @@ static struct fb_ops lxfb_ops = { .fb_fillrect = cfb_fillrect, .fb_copyarea = cfb_copyarea, .fb_imageblit = cfb_imageblit, - .fb_powerdown = lx_shutdown, - .fb_powerup = lx_powerup, + .fb_power = lx_power, };static struct fb_info *__init lxfb_init_fbinfo (struct device *dev)
@@ -356,8 +355,9 @@ static int lxfb_suspend(struct pci_dev *pdev, pm_message_t state)if (state.event ==PM_EVENT_SUSPEND ) { +/* Turn the engine completely off */ acquire_console_sem (); -lx_shutdown (info); +lx_power (info,3 );fb_set_suspend (info,1 );release_console_sem (); }
@@ -370,11 +370,9 @@ static int lxfb_resume(struct pci_dev *pdev) {struct fb_info *info =pci_get_drvdata (pdev); -acquire_console_sem (); -/* Turn the engine completely on */ - -lx_powerup (info); +acquire_console_sem (); +lx_power (info,0 );fb_set_suspend (info,0 );release_console_sem ();
drivers/video/geode/lxfb_ops.c +28 -19
61 lines not on this page · raw message
drivers/video/geode/video_gx.c +42 -55
131 lines not on this page · raw message
drivers/video/geode/video_gx.h +1 -2
@@ -81,8 +81,7 @@ extern struct geode_vid_ops gx_vid_ops;# define MSR_GLCP_DOTPLL_BYPASS (0x0000000000008000ull)# define MSR_GLCP_DOTPLL_LOCK (0x0000000002000000ull) -int gxfb_powerdown (struct fb_info *info); -int gxfb_powerup (struct fb_info *info); +int gxfb_power (struct fb_info *info,int state);void gx_set_dclk_frequency (struct fb_info *info);unsigned int gx_get_dclk (struct fb_info *info);
drivers/video/olpc_dcon.c +4 -4
@@ -210,13 +210,13 @@ static void dcon_source_switch(struct work_struct *work)/* * Ideally we'd like to disable interrupts here so that the -* fb_powerup and DCON turn on happen at a known time value; +* fb_power() and DCON turn on happen at a known time value; * however, we can't do that right now with fb_set_suspend * messing with semaphores. * * For now, we just hope.. */ -if (fb_powerup (fbinfo)) { +if (fb_power (fbinfo,0 )) {printk (KERN_ERR "olpc-dcon: Failed to enter CPU mode\n" ); dcon_pending =DCON_SOURCE_DCON ;return ;
@@ -250,8 +250,8 @@ static void dcon_source_switch(struct work_struct *work)if (!dcon_switched)printk (KERN_ERR "olpc-dcon: Timeout entering DCON mode; expect a screen glitch.\n" ); -/* Turn off the graphics engine completely */ -fb_powerdown (fbinfo); +/* Turn off the video engine only */ +fb_power (fbinfo,2 );printk (KERN_INFO "olpc-dcon: The DCON has control\n" );break ;
include/linux/fb.h +2 -5
@@ -661,11 +661,8 @@ struct fb_ops {/* restore saved state */ void (*fb_restore_state)(struct fb_info *info); -/* Shut down the graphics engine to save power */ -int (*fb_powerdown)(struct fb_info *info); - -/* Power it back up */ -int (*fb_powerup)(struct fb_info *info); +/* Change the power state of the graphics engine (0 = fully on, 3 = fully off */ +int (*fb_power)(struct fb_info *info,int state);/* get capability given var */ void (*fb_get_caps)(struct fb_info *info, struct fb_blit_caps *caps,
Signature · 1 line
1.5.2.2
Hi!
Quoted 3 lines
This patch merges the
fb_powerupandfb_powerdownhooks in a single operationfb_powerwith an additional "state" parameter ranging from 0 (running) to 3 (poweroff).
No, please don't. Having int with 0/3 being valid specifying what to do is evil.
enum is less evil, but what's wrong about having 3 functions?
Signature · 2 lines
(english) http://www.livejournal.com/~pavelmachek (cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html
Quoted 8 lines · Pavel Machek
Quoted 3 lines
This patch merges the
fb_powerupandfb_powerdownhooks in a single operationfb_powerwith an additional "state" parameter ranging from 0 (running) to 3 (poweroff).No, please don't. Having int with 0/3 being valid specifying what to do is evil.
enum is less evil, but what's wrong about having 3 functions?
Later on, the patch was reworked by Jordan Crouse to use the fb_blank hook instead, which already has enough states.
So the fb_powerup/fb_powerdown hooks, which were not yet upstream anyway, died off in the process.
Signature · 3 lines
\___/ |___| Bernardo Innocenti - http://www.codewiz.org/ \___\ One Laptop Per Child - http://www.laptop.org/