From e01af0384f54023b4548b7742952da2ffcafd4cd Mon Sep 17 00:00:00 2001 From: Michael Hanselmann Date: Mon, 10 Jul 2006 04:44:45 -0700 Subject: [PATCH] powermac: Combined fixes for backlight code This patch fixes several problems: - pmac_backlight_key() is called under interrupt context, and therefore can't use mutexes or semaphores, so defer the backlight level for later, as it's not critical (original code by Aristeu S. Rozanski F. ). - Add exports for functions that might be called from modules - Fix Kconfig depdencies on PMAC_BACKLIGHT. - Fix locking issues on calls from inside the driver (reported by Aristeu S. Rozanski F., too) - Fix wrong calculation of backlight values in some of the drivers - Replace pmac_backlight_key_up/down by inline functions [akpm@osdl.org: fix function prototypes] Signed-off-by: Michael Hanselmann Acked-by: Aristeu S. Rozanski F. Acked-by: Rene Nussbaumer Cc: Benjamin Herrenschmidt Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/video/aty/aty128fb.c | 66 ++++++++++++++++++++----------------- drivers/video/aty/atyfb_base.c | 53 ++++++++++++++++------------- drivers/video/chipsfb.c | 3 +- drivers/video/nvidia/nv_backlight.c | 32 +++++++++++++++--- drivers/video/nvidia/nv_proto.h | 2 ++ drivers/video/nvidia/nvidia.c | 11 +------ drivers/video/riva/fbdev.c | 44 +++++++++++++++++-------- 7 files changed, 127 insertions(+), 84 deletions(-) (limited to 'drivers/video') diff --git a/drivers/video/aty/aty128fb.c b/drivers/video/aty/aty128fb.c index 1006f125fcc7..c64a717e2d4b 100644 --- a/drivers/video/aty/aty128fb.c +++ b/drivers/video/aty/aty128fb.c @@ -455,6 +455,7 @@ static void do_wait_for_fifo(u16 entries, struct aty128fb_par *par); static void wait_for_fifo(u16 entries, struct aty128fb_par *par); static void wait_for_idle(struct aty128fb_par *par); static u32 depth_to_dst(u32 depth); +static void aty128_bl_set_power(struct fb_info *info, int power); #define BIOS_IN8(v) (readb(bios + (v))) #define BIOS_IN16(v) (readb(bios + (v)) | \ @@ -1257,25 +1258,11 @@ static void aty128_set_lcd_enable(struct aty128fb_par *par, int on) reg &= ~LVDS_DISPLAY_DIS; aty_st_le32(LVDS_GEN_CNTL, reg); #ifdef CONFIG_FB_ATY128_BACKLIGHT - mutex_lock(&info->bl_mutex); - if (info->bl_dev) { - down(&info->bl_dev->sem); - info->bl_dev->props->update_status(info->bl_dev); - up(&info->bl_dev->sem); - } - mutex_unlock(&info->bl_mutex); + aty128_bl_set_power(info, FB_BLANK_UNBLANK); #endif } else { #ifdef CONFIG_FB_ATY128_BACKLIGHT - mutex_lock(&info->bl_mutex); - if (info->bl_dev) { - down(&info->bl_dev->sem); - info->bl_dev->props->brightness = 0; - info->bl_dev->props->power = FB_BLANK_POWERDOWN; - info->bl_dev->props->update_status(info->bl_dev); - up(&info->bl_dev->sem); - } - mutex_unlock(&info->bl_mutex); + aty128_bl_set_power(info, FB_BLANK_POWERDOWN); #endif reg = aty_ld_le32(LVDS_GEN_CNTL); reg |= LVDS_DISPLAY_DIS; @@ -1702,6 +1689,7 @@ static int __devinit aty128fb_setup(char *options) static struct backlight_properties aty128_bl_data; +/* Call with fb_info->bl_mutex held */ static int aty128_bl_get_level_brightness(struct aty128fb_par *par, int level) { @@ -1709,10 +1697,8 @@ static int aty128_bl_get_level_brightness(struct aty128fb_par *par, int atylevel; /* Get and convert the value */ - mutex_lock(&info->bl_mutex); atylevel = MAX_LEVEL - (info->bl_curve[level] * FB_BACKLIGHT_MAX / MAX_LEVEL); - mutex_unlock(&info->bl_mutex); if (atylevel < 0) atylevel = 0; @@ -1730,7 +1716,8 @@ static int aty128_bl_get_level_brightness(struct aty128fb_par *par, /* That one prevents proper CRT output with LCD off */ #undef BACKLIGHT_DAC_OFF -static int aty128_bl_update_status(struct backlight_device *bd) +/* Call with fb_info->bl_mutex held */ +static int __aty128_bl_update_status(struct backlight_device *bd) { struct aty128fb_par *par = class_get_devdata(&bd->class_dev); unsigned int reg = aty_ld_le32(LVDS_GEN_CNTL); @@ -1783,6 +1770,19 @@ static int aty128_bl_update_status(struct backlight_device *bd) return 0; } +static int aty128_bl_update_status(struct backlight_device *bd) +{ + struct aty128fb_par *par = class_get_devdata(&bd->class_dev); + struct fb_info *info = pci_get_drvdata(par->pdev); + int ret; + + mutex_lock(&info->bl_mutex); + ret = __aty128_bl_update_status(bd); + mutex_unlock(&info->bl_mutex); + + return ret; +} + static int aty128_bl_get_brightness(struct backlight_device *bd) { return bd->props->brightness; @@ -1795,6 +1795,16 @@ static struct backlight_properties aty128_bl_data = { .max_brightness = (FB_BACKLIGHT_LEVELS - 1), }; +static void aty128_bl_set_power(struct fb_info *info, int power) +{ + mutex_lock(&info->bl_mutex); + up(&info->bl_dev->sem); + info->bl_dev->props->power = power; + __aty128_bl_update_status(info->bl_dev); + down(&info->bl_dev->sem); + mutex_unlock(&info->bl_mutex); +} + static void aty128_bl_init(struct aty128fb_par *par) { struct fb_info *info = pci_get_drvdata(par->pdev); @@ -2197,12 +2207,8 @@ static int aty128fb_blank(int blank, struct fb_info *fb) return 0; #ifdef CONFIG_FB_ATY128_BACKLIGHT - if (machine_is(powermac) && blank) { - down(&fb->bl_dev->sem); - fb->bl_dev->props->power = FB_BLANK_POWERDOWN; - fb->bl_dev->props->update_status(fb->bl_dev); - up(&fb->bl_dev->sem); - } + if (machine_is(powermac) && blank) + aty128_bl_set_power(fb, FB_BLANK_POWERDOWN); #endif if (blank & FB_BLANK_VSYNC_SUSPEND) @@ -2218,14 +2224,12 @@ static int aty128fb_blank(int blank, struct fb_info *fb) aty128_set_crt_enable(par, par->crt_on && !blank); aty128_set_lcd_enable(par, par->lcd_on && !blank); } + #ifdef CONFIG_FB_ATY128_BACKLIGHT - if (machine_is(powermac) && !blank) { - down(&fb->bl_dev->sem); - fb->bl_dev->props->power = FB_BLANK_UNBLANK; - fb->bl_dev->props->update_status(fb->bl_dev); - up(&fb->bl_dev->sem); - } + if (machine_is(powermac) && !blank) + aty128_bl_set_power(fb, FB_BLANK_UNBLANK); #endif + return 0; } diff --git a/drivers/video/aty/atyfb_base.c b/drivers/video/aty/atyfb_base.c index 0c9706746d79..1507d19f481f 100644 --- a/drivers/video/aty/atyfb_base.c +++ b/drivers/video/aty/atyfb_base.c @@ -2129,15 +2129,14 @@ static int atyfb_pci_resume(struct pci_dev *pdev) static struct backlight_properties aty_bl_data; +/* Call with fb_info->bl_mutex held */ static int aty_bl_get_level_brightness(struct atyfb_par *par, int level) { struct fb_info *info = pci_get_drvdata(par->pdev); int atylevel; /* Get and convert the value */ - mutex_lock(&info->bl_mutex); atylevel = info->bl_curve[level] * FB_BACKLIGHT_MAX / MAX_LEVEL; - mutex_unlock(&info->bl_mutex); if (atylevel < 0) atylevel = 0; @@ -2147,7 +2146,8 @@ static int aty_bl_get_level_brightness(struct atyfb_par *par, int level) return atylevel; } -static int aty_bl_update_status(struct backlight_device *bd) +/* Call with fb_info->bl_mutex held */ +static int __aty_bl_update_status(struct backlight_device *bd) { struct atyfb_par *par = class_get_devdata(&bd->class_dev); unsigned int reg = aty_ld_lcd(LCD_MISC_CNTL, par); @@ -2172,6 +2172,19 @@ static int aty_bl_update_status(struct backlight_device *bd) return 0; } +static int aty_bl_update_status(struct backlight_device *bd) +{ + struct atyfb_par *par = class_get_devdata(&bd->class_dev); + struct fb_info *info = pci_get_drvdata(par->pdev); + int ret; + + mutex_lock(&info->bl_mutex); + ret = __aty_bl_update_status(bd); + mutex_unlock(&info->bl_mutex); + + return ret; +} + static int aty_bl_get_brightness(struct backlight_device *bd) { return bd->props->brightness; @@ -2184,6 +2197,16 @@ static struct backlight_properties aty_bl_data = { .max_brightness = (FB_BACKLIGHT_LEVELS - 1), }; +static void aty_bl_set_power(struct fb_info *info, int power) +{ + mutex_lock(&info->bl_mutex); + up(&info->bl_dev->sem); + info->bl_dev->props->power = power; + __aty_bl_update_status(info->bl_dev); + down(&info->bl_dev->sem); + mutex_unlock(&info->bl_mutex); +} + static void aty_bl_init(struct atyfb_par *par) { struct fb_info *info = pci_get_drvdata(par->pdev); @@ -2790,16 +2813,8 @@ static int atyfb_blank(int blank, struct fb_info *info) return 0; #ifdef CONFIG_PMAC_BACKLIGHT - if (machine_is(powermac) && blank > FB_BLANK_NORMAL) { - mutex_lock(&info->bl_mutex); - if (info->bl_dev) { - down(&info->bl_dev->sem); - info->bl_dev->props->power = FB_BLANK_POWERDOWN; - info->bl_dev->props->update_status(info->bl_dev); - up(&info->bl_dev->sem); - } - mutex_unlock(&info->bl_mutex); - } + if (machine_is(powermac) && blank > FB_BLANK_NORMAL) + aty_bl_set_power(info, FB_BLANK_POWERDOWN); #elif defined(CONFIG_FB_ATY_GENERIC_LCD) if (par->lcd_table && blank > FB_BLANK_NORMAL && (aty_ld_lcd(LCD_GEN_CNTL, par) & LCD_ON)) { @@ -2830,16 +2845,8 @@ static int atyfb_blank(int blank, struct fb_info *info) aty_st_le32(CRTC_GEN_CNTL, gen_cntl, par); #ifdef CONFIG_PMAC_BACKLIGHT - if (machine_is(powermac) && blank <= FB_BLANK_NORMAL) { - mutex_lock(&info->bl_mutex); - if (info->bl_dev) { - down(&info->bl_dev->sem); - info->bl_dev->props->power = FB_BLANK_UNBLANK; - info->bl_dev->props->update_status(info->bl_dev); - up(&info->bl_dev->sem); - } - mutex_unlock(&info->bl_mutex); - } + if (machine_is(powermac) && blank <= FB_BLANK_NORMAL) + aty_bl_set_power(info, FB_BLANK_UNBLANK); #elif defined(CONFIG_FB_ATY_GENERIC_LCD) if (par->lcd_table && blank <= FB_BLANK_NORMAL && (aty_ld_lcd(LCD_GEN_CNTL, par) & LCD_ON)) { diff --git a/drivers/video/chipsfb.c b/drivers/video/chipsfb.c index eba9d93ae360..73cb426bf2d7 100644 --- a/drivers/video/chipsfb.c +++ b/drivers/video/chipsfb.c @@ -149,12 +149,11 @@ static int chipsfb_blank(int blank, struct fb_info *info) mutex_lock(&pmac_backlight_mutex); if (pmac_backlight) { - down(&pmac_backlight->sem); - /* used to disable backlight only for blank > 1, but it seems * useful at blank = 1 too (saves battery, extends backlight * life) */ + down(&pmac_backlight->sem); if (blank) pmac_backlight->props->power = FB_BLANK_POWERDOWN; else diff --git a/drivers/video/nvidia/nv_backlight.c b/drivers/video/nvidia/nv_backlight.c index 1c1c10c699c5..b45f577094ac 100644 --- a/drivers/video/nvidia/nv_backlight.c +++ b/drivers/video/nvidia/nv_backlight.c @@ -26,9 +26,11 @@ */ #define MIN_LEVEL 0x158 #define MAX_LEVEL 0x534 +#define LEVEL_STEP ((MAX_LEVEL - MIN_LEVEL) / FB_BACKLIGHT_MAX) static struct backlight_properties nvidia_bl_data; +/* Call with fb_info->bl_mutex held */ static int nvidia_bl_get_level_brightness(struct nvidia_par *par, int level) { @@ -36,9 +38,7 @@ static int nvidia_bl_get_level_brightness(struct nvidia_par *par, int nlevel; /* Get and convert the value */ - mutex_lock(&info->bl_mutex); - nlevel = info->bl_curve[level] * FB_BACKLIGHT_MAX / MAX_LEVEL; - mutex_unlock(&info->bl_mutex); + nlevel = MIN_LEVEL + info->bl_curve[level] * LEVEL_STEP; if (nlevel < 0) nlevel = 0; @@ -50,7 +50,8 @@ static int nvidia_bl_get_level_brightness(struct nvidia_par *par, return nlevel; } -static int nvidia_bl_update_status(struct backlight_device *bd) +/* Call with fb_info->bl_mutex held */ +static int __nvidia_bl_update_status(struct backlight_device *bd) { struct nvidia_par *par = class_get_devdata(&bd->class_dev); u32 tmp_pcrt, tmp_pmc, fpcontrol; @@ -84,6 +85,19 @@ static int nvidia_bl_update_status(struct backlight_device *bd) return 0; } +static int nvidia_bl_update_status(struct backlight_device *bd) +{ + struct nvidia_par *par = class_get_devdata(&bd->class_dev); + struct fb_info *info = pci_get_drvdata(par->pci_dev); + int ret; + + mutex_lock(&info->bl_mutex); + ret = __nvidia_bl_update_status(bd); + mutex_unlock(&info->bl_mutex); + + return ret; +} + static int nvidia_bl_get_brightness(struct backlight_device *bd) { return bd->props->brightness; @@ -96,6 +110,16 @@ static struct backlight_properties nvidia_bl_data = { .max_brightness = (FB_BACKLIGHT_LEVELS - 1), }; +void nvidia_bl_set_power(struct fb_info *info, int power) +{ + mutex_lock(&info->bl_mutex); + up(&info->bl_dev->sem); + info->bl_dev->props->power = power; + __nvidia_bl_update_status(info->bl_dev); + down(&info->bl_dev->sem); + mutex_unlock(&info->bl_mutex); +} + void nvidia_bl_init(struct nvidia_par *par) { struct fb_info *info = pci_get_drvdata(par->pci_dev); diff --git a/drivers/video/nvidia/nv_proto.h b/drivers/video/nvidia/nv_proto.h index 6fba656cd56b..861271017655 100644 --- a/drivers/video/nvidia/nv_proto.h +++ b/drivers/video/nvidia/nv_proto.h @@ -68,9 +68,11 @@ extern u8 byte_rev[256]; #ifdef CONFIG_FB_NVIDIA_BACKLIGHT extern void nvidia_bl_init(struct nvidia_par *par); extern void nvidia_bl_exit(struct nvidia_par *par); +extern void nvidia_bl_set_power(struct fb_info *info, int power); #else static inline void nvidia_bl_init(struct nvidia_par *par) {} static inline void nvidia_bl_exit(struct nvidia_par *par) {} +static inline void nvidia_bl_set_power(struct fb_info *info, int power) {} #endif #endif /* __NV_PROTO_H__ */ diff --git a/drivers/video/nvidia/nvidia.c b/drivers/video/nvidia/nvidia.c index ef58c3825501..9f2066f0745a 100644 --- a/drivers/video/nvidia/nvidia.c +++ b/drivers/video/nvidia/nvidia.c @@ -932,16 +932,7 @@ static int nvidiafb_blank(int blank, struct fb_info *info) NVWriteSeq(par, 0x01, tmp); NVWriteCrtc(par, 0x1a, vesa); -#ifdef CONFIG_FB_NVIDIA_BACKLIGHT - mutex_lock(&info->bl_mutex); - if (info->bl_dev) { - down(&info->bl_dev->sem); - info->bl_dev->props->power = blank; - info->bl_dev->props->update_status(info->bl_dev); - up(&info->bl_dev->sem); - } - mutex_unlock(&info->bl_mutex); -#endif + nvidia_bl_set_power(info, blank); NVTRACE_LEAVE(); diff --git a/drivers/video/riva/fbdev.c b/drivers/video/riva/fbdev.c index baf494cecc10..33dddbae5420 100644 --- a/drivers/video/riva/fbdev.c +++ b/drivers/video/riva/fbdev.c @@ -277,9 +277,11 @@ static const struct riva_regs reg_template = { */ #define MIN_LEVEL 0x158 #define MAX_LEVEL 0x534 +#define LEVEL_STEP ((MAX_LEVEL - MIN_LEVEL) / FB_BACKLIGHT_MAX) static struct backlight_properties riva_bl_data; +/* Call with fb_info->bl_mutex held */ static int riva_bl_get_level_brightness(struct riva_par *par, int level) { @@ -287,9 +289,7 @@ static int riva_bl_get_level_brightness(struct riva_par *par, int nlevel; /* Get and convert the value */ - mutex_lock(&info->bl_mutex); - nlevel = info->bl_curve[level] * FB_BACKLIGHT_MAX / MAX_LEVEL; - mutex_unlock(&info->bl_mutex); + nlevel = MIN_LEVEL + info->bl_curve[level] * LEVEL_STEP; if (nlevel < 0) nlevel = 0; @@ -301,7 +301,8 @@ static int riva_bl_get_level_brightness(struct riva_par *par, return nlevel; } -static int riva_bl_update_status(struct backlight_device *bd) +/* Call with fb_info->bl_mutex held */ +static int __riva_bl_update_status(struct backlight_device *bd) { struct riva_par *par = class_get_devdata(&bd->class_dev); U032 tmp_pcrt, tmp_pmc; @@ -326,6 +327,19 @@ static int riva_bl_update_status(struct backlight_device *bd) return 0; } +static int riva_bl_update_status(struct backlight_device *bd) +{ + struct riva_par *par = class_get_devdata(&bd->class_dev); + struct fb_info *info = pci_get_drvdata(par->pdev); + int ret; + + mutex_lock(&info->bl_mutex); + ret = __riva_bl_update_status(bd); + mutex_unlock(&info->bl_mutex); + + return ret; +} + static int riva_bl_get_brightness(struct backlight_device *bd) { return bd->props->brightness; @@ -338,6 +352,16 @@ static struct backlight_properties riva_bl_data = { .max_brightness = (FB_BACKLIGHT_LEVELS - 1), }; +static void riva_bl_set_power(struct fb_info *info, int power) +{ + mutex_lock(&info->bl_mutex); + up(&info->bl_dev->sem); + info->bl_dev->props->power = power; + __riva_bl_update_status(info->bl_dev); + down(&info->bl_dev->sem); + mutex_unlock(&info->bl_mutex); +} + static void riva_bl_init(struct riva_par *par) { struct fb_info *info = pci_get_drvdata(par->pdev); @@ -418,6 +442,7 @@ static void riva_bl_exit(struct riva_par *par) #else static inline void riva_bl_init(struct riva_par *par) {} static inline void riva_bl_exit(struct riva_par *par) {} +static inline void riva_bl_set_power(struct fb_info *info, int power) {} #endif /* CONFIG_FB_RIVA_BACKLIGHT */ /* ------------------------------------------------------------------------- * @@ -1336,16 +1361,7 @@ static int rivafb_blank(int blank, struct fb_info *info) SEQout(par, 0x01, tmp); CRTCout(par, 0x1a, vesa); -#ifdef CONFIG_FB_RIVA_BACKLIGHT - mutex_lock(&info->bl_mutex); - if (info->bl_dev) { - down(&info->bl_dev->sem); - info->bl_dev->props->power = blank; - info->bl_dev->props->update_status(info->bl_dev); - up(&info->bl_dev->sem); - } - mutex_unlock(&info->bl_mutex); -#endif + riva_bl_set_power(info, blank); NVTRACE_LEAVE(); -- cgit v1.2.2