summaryrefslogtreecommitdiffstats
path: root/drivers/video/aty
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/video/aty')
-rw-r--r--drivers/video/aty/Makefile1
-rw-r--r--drivers/video/aty/aty128fb.c359
-rw-r--r--drivers/video/aty/atyfb.h2
-rw-r--r--drivers/video/aty/atyfb_base.c230
-rw-r--r--drivers/video/aty/mach64_accel.c10
-rw-r--r--drivers/video/aty/mach64_cursor.c33
-rw-r--r--drivers/video/aty/radeon_backlight.c247
-rw-r--r--drivers/video/aty/radeon_base.c143
-rw-r--r--drivers/video/aty/radeon_i2c.c1
-rw-r--r--drivers/video/aty/radeonfb.h12
10 files changed, 704 insertions, 334 deletions
diff --git a/drivers/video/aty/Makefile b/drivers/video/aty/Makefile
index 18521397a6e3..a6cc0e9ec790 100644
--- a/drivers/video/aty/Makefile
+++ b/drivers/video/aty/Makefile
@@ -10,5 +10,6 @@ atyfb-objs := $(atyfb-y)
radeonfb-y := radeon_base.o radeon_pm.o radeon_monitor.o radeon_accel.o
radeonfb-$(CONFIG_FB_RADEON_I2C) += radeon_i2c.o
+radeonfb-$(CONFIG_FB_RADEON_BACKLIGHT) += radeon_backlight.o
radeonfb-objs := $(radeonfb-y)
diff --git a/drivers/video/aty/aty128fb.c b/drivers/video/aty/aty128fb.c
index f7bbff4ddc6a..72c589109471 100644
--- a/drivers/video/aty/aty128fb.c
+++ b/drivers/video/aty/aty128fb.c
@@ -46,7 +46,6 @@
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/kernel.h>
@@ -64,6 +63,7 @@
#include <linux/pci.h>
#include <linux/ioport.h>
#include <linux/console.h>
+#include <linux/backlight.h>
#include <asm/io.h>
#ifdef CONFIG_PPC_PMAC
@@ -99,7 +99,7 @@
#ifndef CONFIG_PPC_PMAC
/* default mode */
-static struct fb_var_screeninfo default_var __initdata = {
+static struct fb_var_screeninfo default_var __devinitdata = {
/* 640x480, 60 Hz, Non-Interlaced (25.175 MHz dotclock) */
640, 480, 640, 480, 0, 0, 8, 0,
{0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
@@ -122,7 +122,7 @@ static struct fb_var_screeninfo default_var = {
/* default modedb mode */
/* 640x480, 60 Hz, Non-Interlaced (25.172 MHz dotclock) */
-static struct fb_videomode defaultmode __initdata = {
+static struct fb_videomode defaultmode __devinitdata = {
.refresh = 60,
.xres = 640,
.yres = 480,
@@ -334,7 +334,7 @@ static const struct aty128_meminfo sdr_sgram =
static const struct aty128_meminfo ddr_sgram =
{ 4, 4, 3, 3, 2, 3, 1, 16, 31, 16, "64-bit DDR SGRAM" };
-static struct fb_fix_screeninfo aty128fb_fix __initdata = {
+static struct fb_fix_screeninfo aty128fb_fix __devinitdata = {
.id = "ATY Rage128",
.type = FB_TYPE_PACKED_PIXELS,
.visual = FB_VISUAL_PSEUDOCOLOR,
@@ -344,15 +344,15 @@ static struct fb_fix_screeninfo aty128fb_fix __initdata = {
.accel = FB_ACCEL_ATI_RAGE128,
};
-static char *mode_option __initdata = NULL;
+static char *mode_option __devinitdata = NULL;
#ifdef CONFIG_PPC_PMAC
-static int default_vmode __initdata = VMODE_1024_768_60;
-static int default_cmode __initdata = CMODE_8;
+static int default_vmode __devinitdata = VMODE_1024_768_60;
+static int default_cmode __devinitdata = CMODE_8;
#endif
-static int default_crt_on __initdata = 0;
-static int default_lcd_on __initdata = 1;
+static int default_crt_on __devinitdata = 0;
+static int default_lcd_on __devinitdata = 1;
#ifdef CONFIG_MTRR
static int mtrr = 1;
@@ -444,9 +444,9 @@ static int aty128_encode_var(struct fb_var_screeninfo *var,
static int aty128_decode_var(struct fb_var_screeninfo *var,
struct aty128fb_par *par);
#if 0
-static void __init aty128_get_pllinfo(struct aty128fb_par *par,
+static void __devinit aty128_get_pllinfo(struct aty128fb_par *par,
void __iomem *bios);
-static void __init __iomem *aty128_map_ROM(struct pci_dev *pdev, const struct aty128fb_par *par);
+static void __devinit __iomem *aty128_map_ROM(struct pci_dev *pdev, const struct aty128fb_par *par);
#endif
static void aty128_timings(struct aty128fb_par *par);
static void aty128_init_engine(struct aty128fb_par *par);
@@ -480,16 +480,6 @@ static struct fb_ops aty128fb_ops = {
.fb_imageblit = cfb_imageblit,
};
-#ifdef CONFIG_PMAC_BACKLIGHT
-static int aty128_set_backlight_enable(int on, int level, void* data);
-static int aty128_set_backlight_level(int level, void* data);
-
-static struct backlight_controller aty128_backlight_controller = {
- aty128_set_backlight_enable,
- aty128_set_backlight_level
-};
-#endif /* CONFIG_PMAC_BACKLIGHT */
-
/*
* Functions to read from/write to the mmio registers
* - endian conversions may possibly be avoided by
@@ -582,7 +572,7 @@ static void aty_pll_writeupdate(const struct aty128fb_par *par)
/* write to the scratch register to test r/w functionality */
-static int __init register_test(const struct aty128fb_par *par)
+static int __devinit register_test(const struct aty128fb_par *par)
{
u32 val;
int flag = 0;
@@ -781,7 +771,7 @@ static u32 depth_to_dst(u32 depth)
#ifndef __sparc__
-static void __iomem * __init aty128_map_ROM(const struct aty128fb_par *par, struct pci_dev *dev)
+static void __iomem * __devinit aty128_map_ROM(const struct aty128fb_par *par, struct pci_dev *dev)
{
u16 dptr;
u8 rom_type;
@@ -865,7 +855,7 @@ static void __iomem * __init aty128_map_ROM(const struct aty128fb_par *par, stru
return NULL;
}
-static void __init aty128_get_pllinfo(struct aty128fb_par *par, unsigned char __iomem *bios)
+static void __devinit aty128_get_pllinfo(struct aty128fb_par *par, unsigned char __iomem *bios)
{
unsigned int bios_hdr;
unsigned int bios_pll;
@@ -912,7 +902,7 @@ static void __iomem * __devinit aty128_find_mem_vbios(struct aty128fb_par *par)
#endif /* ndef(__sparc__) */
/* fill in known card constants if pll_block is not available */
-static void __init aty128_timings(struct aty128fb_par *par)
+static void __devinit aty128_timings(struct aty128fb_par *par)
{
#ifdef CONFIG_PPC_OF
/* instead of a table lookup, assume OF has properly
@@ -1258,19 +1248,35 @@ static void aty128_set_crt_enable(struct aty128fb_par *par, int on)
static void aty128_set_lcd_enable(struct aty128fb_par *par, int on)
{
u32 reg;
+#ifdef CONFIG_FB_ATY128_BACKLIGHT
+ struct fb_info *info = pci_get_drvdata(par->pdev);
+#endif
if (on) {
reg = aty_ld_le32(LVDS_GEN_CNTL);
reg |= LVDS_ON | LVDS_EN | LVDS_BLON | LVDS_DIGION;
reg &= ~LVDS_DISPLAY_DIS;
aty_st_le32(LVDS_GEN_CNTL, reg);
-#ifdef CONFIG_PMAC_BACKLIGHT
- aty128_set_backlight_enable(get_backlight_enable(),
- get_backlight_level(), par);
+#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);
#endif
} else {
-#ifdef CONFIG_PMAC_BACKLIGHT
- aty128_set_backlight_enable(0, 0, par);
+#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);
#endif
reg = aty_ld_le32(LVDS_GEN_CNTL);
reg |= LVDS_DISPLAY_DIS;
@@ -1638,7 +1644,7 @@ static int aty128fb_sync(struct fb_info *info)
}
#ifndef MODULE
-static int __init aty128fb_setup(char *options)
+static int __devinit aty128fb_setup(char *options)
{
char *this_opt;
@@ -1691,6 +1697,184 @@ static int __init aty128fb_setup(char *options)
}
#endif /* MODULE */
+/* Backlight */
+#ifdef CONFIG_FB_ATY128_BACKLIGHT
+#define MAX_LEVEL 0xFF
+
+static struct backlight_properties aty128_bl_data;
+
+static int aty128_bl_get_level_brightness(struct aty128fb_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 = MAX_LEVEL -
+ (info->bl_curve[level] * FB_BACKLIGHT_MAX / MAX_LEVEL);
+ mutex_unlock(&info->bl_mutex);
+
+ if (atylevel < 0)
+ atylevel = 0;
+ else if (atylevel > MAX_LEVEL)
+ atylevel = MAX_LEVEL;
+
+ return atylevel;
+}
+
+/* We turn off the LCD completely instead of just dimming the backlight.
+ * This provides greater power saving and the display is useless without
+ * backlight anyway
+ */
+#define BACKLIGHT_LVDS_OFF
+/* That one prevents proper CRT output with LCD off */
+#undef BACKLIGHT_DAC_OFF
+
+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);
+ int level;
+
+ if (bd->props->power != FB_BLANK_UNBLANK ||
+ bd->props->fb_blank != FB_BLANK_UNBLANK ||
+ !par->lcd_on)
+ level = 0;
+ else
+ level = bd->props->brightness;
+
+ reg |= LVDS_BL_MOD_EN | LVDS_BLON;
+ if (level > 0) {
+ reg |= LVDS_DIGION;
+ if (!(reg & LVDS_ON)) {
+ reg &= ~LVDS_BLON;
+ aty_st_le32(LVDS_GEN_CNTL, reg);
+ aty_ld_le32(LVDS_GEN_CNTL);
+ mdelay(10);
+ reg |= LVDS_BLON;
+ aty_st_le32(LVDS_GEN_CNTL, reg);
+ }
+ reg &= ~LVDS_BL_MOD_LEVEL_MASK;
+ reg |= (aty128_bl_get_level_brightness(par, level) << LVDS_BL_MOD_LEVEL_SHIFT);
+#ifdef BACKLIGHT_LVDS_OFF
+ reg |= LVDS_ON | LVDS_EN;
+ reg &= ~LVDS_DISPLAY_DIS;
+#endif
+ aty_st_le32(LVDS_GEN_CNTL, reg);
+#ifdef BACKLIGHT_DAC_OFF
+ aty_st_le32(DAC_CNTL, aty_ld_le32(DAC_CNTL) & (~DAC_PDWN));
+#endif
+ } else {
+ reg &= ~LVDS_BL_MOD_LEVEL_MASK;
+ reg |= (aty128_bl_get_level_brightness(par, 0) << LVDS_BL_MOD_LEVEL_SHIFT);
+#ifdef BACKLIGHT_LVDS_OFF
+ reg |= LVDS_DISPLAY_DIS;
+ aty_st_le32(LVDS_GEN_CNTL, reg);
+ aty_ld_le32(LVDS_GEN_CNTL);
+ udelay(10);
+ reg &= ~(LVDS_ON | LVDS_EN | LVDS_BLON | LVDS_DIGION);
+#endif
+ aty_st_le32(LVDS_GEN_CNTL, reg);
+#ifdef BACKLIGHT_DAC_OFF
+ aty_st_le32(DAC_CNTL, aty_ld_le32(DAC_CNTL) | DAC_PDWN);
+#endif
+ }
+
+ return 0;
+}
+
+static int aty128_bl_get_brightness(struct backlight_device *bd)
+{
+ return bd->props->brightness;
+}
+
+static struct backlight_properties aty128_bl_data = {
+ .owner = THIS_MODULE,
+ .get_brightness = aty128_bl_get_brightness,
+ .update_status = aty128_bl_update_status,
+ .max_brightness = (FB_BACKLIGHT_LEVELS - 1),
+};
+
+static void aty128_bl_init(struct aty128fb_par *par)
+{
+ struct fb_info *info = pci_get_drvdata(par->pdev);
+ struct backlight_device *bd;
+ char name[12];
+
+ /* Could be extended to Rage128Pro LVDS output too */
+ if (par->chip_gen != rage_M3)
+ return;
+
+#ifdef CONFIG_PMAC_BACKLIGHT
+ if (!pmac_has_backlight_type("ati"))
+ return;
+#endif
+
+ snprintf(name, sizeof(name), "aty128bl%d", info->node);
+
+ bd = backlight_device_register(name, par, &aty128_bl_data);
+ if (IS_ERR(bd)) {
+ info->bl_dev = NULL;
+ printk("aty128: Backlight registration failed\n");
+ goto error;
+ }
+
+ mutex_lock(&info->bl_mutex);
+ info->bl_dev = bd;
+ fb_bl_default_curve(info, 0,
+ 63 * FB_BACKLIGHT_MAX / MAX_LEVEL,
+ 219 * FB_BACKLIGHT_MAX / MAX_LEVEL);
+ mutex_unlock(&info->bl_mutex);
+
+ up(&bd->sem);
+ bd->props->brightness = aty128_bl_data.max_brightness;
+ bd->props->power = FB_BLANK_UNBLANK;
+ bd->props->update_status(bd);
+ down(&bd->sem);
+
+#ifdef CONFIG_PMAC_BACKLIGHT
+ mutex_lock(&pmac_backlight_mutex);
+ if (!pmac_backlight)
+ pmac_backlight = bd;
+ mutex_unlock(&pmac_backlight_mutex);
+#endif
+
+ printk("aty128: Backlight initialized (%s)\n", name);
+
+ return;
+
+error:
+ return;
+}
+
+static void aty128_bl_exit(struct aty128fb_par *par)
+{
+ struct fb_info *info = pci_get_drvdata(par->pdev);
+
+#ifdef CONFIG_PMAC_BACKLIGHT
+ mutex_lock(&pmac_backlight_mutex);
+#endif
+
+ mutex_lock(&info->bl_mutex);
+ if (info->bl_dev) {
+#ifdef CONFIG_PMAC_BACKLIGHT
+ if (pmac_backlight == info->bl_dev)
+ pmac_backlight = NULL;
+#endif
+
+ backlight_device_unregister(info->bl_dev);
+ info->bl_dev = NULL;
+
+ printk("aty128: Backlight unloaded\n");
+ }
+ mutex_unlock(&info->bl_mutex);
+
+#ifdef CONFIG_PMAC_BACKLIGHT
+ mutex_unlock(&pmac_backlight_mutex);
+#endif
+}
+#endif /* CONFIG_FB_ATY128_BACKLIGHT */
/*
* Initialisation
@@ -1708,7 +1892,7 @@ static void aty128_early_resume(void *data)
}
#endif /* CONFIG_PPC_PMAC */
-static int __init aty128_init(struct pci_dev *pdev, const struct pci_device_id *ent)
+static int __devinit aty128_init(struct pci_dev *pdev, const struct pci_device_id *ent)
{
struct fb_info *info = pci_get_drvdata(pdev);
struct aty128fb_par *par = info->par;
@@ -1835,17 +2019,15 @@ static int __init aty128_init(struct pci_dev *pdev, const struct pci_device_id *
if (register_framebuffer(info) < 0)
return 0;
-#ifdef CONFIG_PMAC_BACKLIGHT
- /* Could be extended to Rage128Pro LVDS output too */
- if (par->chip_gen == rage_M3)
- register_backlight_controller(&aty128_backlight_controller, par, "ati");
-#endif /* CONFIG_PMAC_BACKLIGHT */
-
par->pm_reg = pci_find_capability(pdev, PCI_CAP_ID_PM);
par->pdev = pdev;
par->asleep = 0;
par->lock_blank = 0;
-
+
+#ifdef CONFIG_FB_ATY128_BACKLIGHT
+ aty128_bl_init(par);
+#endif
+
printk(KERN_INFO "fb%d: %s frame buffer device on %s\n",
info->node, info->fix.id, video_card);
@@ -1854,7 +2036,7 @@ static int __init aty128_init(struct pci_dev *pdev, const struct pci_device_id *
#ifdef CONFIG_PCI
/* register a card ++ajoshi */
-static int __init aty128_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
+static int __devinit aty128_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
{
unsigned long fb_addr, reg_addr;
struct aty128fb_par *par;
@@ -1981,6 +2163,10 @@ static void __devexit aty128_remove(struct pci_dev *pdev)
par = info->par;
+#ifdef CONFIG_FB_ATY128_BACKLIGHT
+ aty128_bl_exit(par);
+#endif
+
unregister_framebuffer(info);
#ifdef CONFIG_MTRR
if (par->mtrr.vram_valid)
@@ -2011,10 +2197,14 @@ static int aty128fb_blank(int blank, struct fb_info *fb)
if (par->lock_blank || par->asleep)
return 0;
-#ifdef CONFIG_PMAC_BACKLIGHT
- if (machine_is(powermac) && blank)
- set_backlight_enable(0);
-#endif /* CONFIG_PMAC_BACKLIGHT */
+#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);
+ }
+#endif
if (blank & FB_BLANK_VSYNC_SUSPEND)
state |= 2;
@@ -2029,10 +2219,14 @@ 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_PMAC_BACKLIGHT
- if (machine_is(powermac) && !blank)
- set_backlight_enable(1);
-#endif /* CONFIG_PMAC_BACKLIGHT */
+#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);
+ }
+#endif
return 0;
}
@@ -2138,73 +2332,6 @@ static int aty128fb_ioctl(struct fb_info *info, u_int cmd, u_long arg)
return -EINVAL;
}
-#ifdef CONFIG_PMAC_BACKLIGHT
-static int backlight_conv[] = {
- 0xff, 0xc0, 0xb5, 0xaa, 0x9f, 0x94, 0x89, 0x7e,
- 0x73, 0x68, 0x5d, 0x52, 0x47, 0x3c, 0x31, 0x24
-};
-
-/* We turn off the LCD completely instead of just dimming the backlight.
- * This provides greater power saving and the display is useless without
- * backlight anyway
- */
-#define BACKLIGHT_LVDS_OFF
-/* That one prevents proper CRT output with LCD off */
-#undef BACKLIGHT_DAC_OFF
-
-static int aty128_set_backlight_enable(int on, int level, void *data)
-{
- struct aty128fb_par *par = data;
- unsigned int reg = aty_ld_le32(LVDS_GEN_CNTL);
-
- if (!par->lcd_on)
- on = 0;
- reg |= LVDS_BL_MOD_EN | LVDS_BLON;
- if (on && level > BACKLIGHT_OFF) {
- reg |= LVDS_DIGION;
- if (!(reg & LVDS_ON)) {
- reg &= ~LVDS_BLON;
- aty_st_le32(LVDS_GEN_CNTL, reg);
- (void)aty_ld_le32(LVDS_GEN_CNTL);
- mdelay(10);
- reg |= LVDS_BLON;
- aty_st_le32(LVDS_GEN_CNTL, reg);
- }
- reg &= ~LVDS_BL_MOD_LEVEL_MASK;
- reg |= (backlight_conv[level] << LVDS_BL_MOD_LEVEL_SHIFT);
-#ifdef BACKLIGHT_LVDS_OFF
- reg |= LVDS_ON | LVDS_EN;
- reg &= ~LVDS_DISPLAY_DIS;
-#endif
- aty_st_le32(LVDS_GEN_CNTL, reg);
-#ifdef BACKLIGHT_DAC_OFF
- aty_st_le32(DAC_CNTL, aty_ld_le32(DAC_CNTL) & (~DAC_PDWN));
-#endif
- } else {
- reg &= ~LVDS_BL_MOD_LEVEL_MASK;
- reg |= (backlight_conv[0] << LVDS_BL_MOD_LEVEL_SHIFT);
-#ifdef BACKLIGHT_LVDS_OFF
- reg |= LVDS_DISPLAY_DIS;
- aty_st_le32(LVDS_GEN_CNTL, reg);
- (void)aty_ld_le32(LVDS_GEN_CNTL);
- udelay(10);
- reg &= ~(LVDS_ON | LVDS_EN | LVDS_BLON | LVDS_DIGION);
-#endif
- aty_st_le32(LVDS_GEN_CNTL, reg);
-#ifdef BACKLIGHT_DAC_OFF
- aty_st_le32(DAC_CNTL, aty_ld_le32(DAC_CNTL) | DAC_PDWN);
-#endif
- }
-
- return 0;
-}
-
-static int aty128_set_backlight_level(int level, void* data)
-{
- return aty128_set_backlight_enable(1, level, data);
-}
-#endif /* CONFIG_PMAC_BACKLIGHT */
-
#if 0
/*
* Accelerated functions
@@ -2428,7 +2555,7 @@ static int aty128_pci_resume(struct pci_dev *pdev)
}
-static int __init aty128fb_init(void)
+static int __devinit aty128fb_init(void)
{
#ifndef MODULE
char *option = NULL;
diff --git a/drivers/video/aty/atyfb.h b/drivers/video/aty/atyfb.h
index e9b7a64c1ac4..55fb8b04489b 100644
--- a/drivers/video/aty/atyfb.h
+++ b/drivers/video/aty/atyfb.h
@@ -2,7 +2,6 @@
* ATI Frame Buffer Device Driver Core Definitions
*/
-#include <linux/config.h>
#include <linux/spinlock.h>
#include <linux/wait.h>
/*
@@ -151,6 +150,7 @@ struct atyfb_par {
int lock_blank;
unsigned long res_start;
unsigned long res_size;
+ struct pci_dev *pdev;
#ifdef __sparc__
struct pci_mmap_map *mmap_map;
u8 mmaped;
diff --git a/drivers/video/aty/atyfb_base.c b/drivers/video/aty/atyfb_base.c
index d9d7d3c4cae2..0c9706746d79 100644
--- a/drivers/video/aty/atyfb_base.c
+++ b/drivers/video/aty/atyfb_base.c
@@ -49,7 +49,6 @@
******************************************************************************/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/kernel.h>
@@ -66,6 +65,7 @@
#include <linux/interrupt.h>
#include <linux/spinlock.h>
#include <linux/wait.h>
+#include <linux/backlight.h>
#include <asm/io.h>
#include <asm/uaccess.h>
@@ -315,12 +315,12 @@ static int vram;
static int pll;
static int mclk;
static int xclk;
-static int comp_sync __initdata = -1;
+static int comp_sync __devinitdata = -1;
static char *mode;
#ifdef CONFIG_PPC
-static int default_vmode __initdata = VMODE_CHOOSE;
-static int default_cmode __initdata = CMODE_CHOOSE;
+static int default_vmode __devinitdata = VMODE_CHOOSE;
+static int default_cmode __devinitdata = CMODE_CHOOSE;
module_param_named(vmode, default_vmode, int, 0);
MODULE_PARM_DESC(vmode, "int: video mode for mac");
@@ -329,10 +329,10 @@ MODULE_PARM_DESC(cmode, "int: color mode for mac");
#endif
#ifdef CONFIG_ATARI
-static unsigned int mach64_count __initdata = 0;
-static unsigned long phys_vmembase[FB_MAX] __initdata = { 0, };
-static unsigned long phys_size[FB_MAX] __initdata = { 0, };
-static unsigned long phys_guiregbase[FB_MAX] __initdata = { 0, };
+static unsigned int mach64_count __devinitdata = 0;
+static unsigned long phys_vmembase[FB_MAX] __devinitdata = { 0, };
+static unsigned long phys_size[FB_MAX] __devinitdata = { 0, };
+static unsigned long phys_guiregbase[FB_MAX] __devinitdata = { 0, };
#endif
/* top -> down is an evolution of mach64 chipset, any corrections? */
@@ -582,7 +582,7 @@ static u32 atyfb_get_pixclock(struct fb_var_screeninfo *var, struct atyfb_par *p
* Apple monitor sense
*/
-static int __init read_aty_sense(const struct atyfb_par *par)
+static int __devinit read_aty_sense(const struct atyfb_par *par)
{
int sense, i;
@@ -1280,6 +1280,14 @@ static int atyfb_set_par(struct fb_info *info)
par->accel_flags = var->accel_flags; /* hack */
+ if (var->accel_flags) {
+ info->fbops->fb_sync = atyfb_sync;
+ info->flags &= ~FBINFO_HWACCEL_DISABLED;
+ } else {
+ info->fbops->fb_sync = NULL;
+ info->flags |= FBINFO_HWACCEL_DISABLED;
+ }
+
if (par->blitter_may_be_busy)
wait_for_idle(par);
@@ -1559,7 +1567,7 @@ static int aty_enable_irq(struct atyfb_par *par, int reenable)
u32 int_cntl;
if (!test_and_set_bit(0, &par->irq_flags)) {
- if (request_irq(par->irq, aty_irq, SA_SHIRQ, "atyfb", par)) {
+ if (request_irq(par->irq, aty_irq, IRQF_SHARED, "atyfb", par)) {
clear_bit(0, &par->irq_flags);
return -EINVAL;
}
@@ -2115,47 +2123,144 @@ static int atyfb_pci_resume(struct pci_dev *pdev)
#endif /* defined(CONFIG_PM) && defined(CONFIG_PCI) */
-#ifdef CONFIG_PMAC_BACKLIGHT
+/* Backlight */
+#ifdef CONFIG_FB_ATY_BACKLIGHT
+#define MAX_LEVEL 0xFF
- /*
- * LCD backlight control
- */
+static struct backlight_properties aty_bl_data;
-static int backlight_conv[] = {
- 0x00, 0x3f, 0x4c, 0x59, 0x66, 0x73, 0x80, 0x8d,
- 0x9a, 0xa7, 0xb4, 0xc1, 0xcf, 0xdc, 0xe9, 0xff
-};
+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);
-static int aty_set_backlight_enable(int on, int level, void *data)
+ if (atylevel < 0)
+ atylevel = 0;
+ else if (atylevel > MAX_LEVEL)
+ atylevel = MAX_LEVEL;
+
+ return atylevel;
+}
+
+static int aty_bl_update_status(struct backlight_device *bd)
{
- struct fb_info *info = (struct fb_info *) data;
- struct atyfb_par *par = (struct atyfb_par *) info->par;
+ struct atyfb_par *par = class_get_devdata(&bd->class_dev);
unsigned int reg = aty_ld_lcd(LCD_MISC_CNTL, par);
+ int level;
+
+ if (bd->props->power != FB_BLANK_UNBLANK ||
+ bd->props->fb_blank != FB_BLANK_UNBLANK)
+ level = 0;
+ else
+ level = bd->props->brightness;
reg |= (BLMOD_EN | BIASMOD_EN);
- if (on && level > BACKLIGHT_OFF) {
+ if (level > 0) {
reg &= ~BIAS_MOD_LEVEL_MASK;
- reg |= (backlight_conv[level] << BIAS_MOD_LEVEL_SHIFT);
+ reg |= (aty_bl_get_level_brightness(par, level) << BIAS_MOD_LEVEL_SHIFT);
} else {
reg &= ~BIAS_MOD_LEVEL_MASK;
- reg |= (backlight_conv[0] << BIAS_MOD_LEVEL_SHIFT);
+ reg |= (aty_bl_get_level_brightness(par, 0) << BIAS_MOD_LEVEL_SHIFT);
}
aty_st_lcd(LCD_MISC_CNTL, reg, par);
+
return 0;
}
-static int aty_set_backlight_level(int level, void *data)
+static int aty_bl_get_brightness(struct backlight_device *bd)
{
- return aty_set_backlight_enable(1, level, data);
+ return bd->props->brightness;
}
-static struct backlight_controller aty_backlight_controller = {
- aty_set_backlight_enable,
- aty_set_backlight_level
+static struct backlight_properties aty_bl_data = {
+ .owner = THIS_MODULE,
+ .get_brightness = aty_bl_get_brightness,
+ .update_status = aty_bl_update_status,
+ .max_brightness = (FB_BACKLIGHT_LEVELS - 1),
};
-#endif /* CONFIG_PMAC_BACKLIGHT */
-static void __init aty_calc_mem_refresh(struct atyfb_par *par, int xclk)
+static void aty_bl_init(struct atyfb_par *par)
+{
+ struct fb_info *info = pci_get_drvdata(par->pdev);
+ struct backlight_device *bd;
+ char name[12];
+
+#ifdef CONFIG_PMAC_BACKLIGHT
+ if (!pmac_has_backlight_type("ati"))
+ return;
+#endif
+
+ snprintf(name, sizeof(name), "atybl%d", info->node);
+
+ bd = backlight_device_register(name, par, &aty_bl_data);
+ if (IS_ERR(bd)) {
+ info->bl_dev = NULL;
+ printk("aty: Backlight registration failed\n");
+ goto error;
+ }
+
+ mutex_lock(&info->bl_mutex);
+ info->bl_dev = bd;
+ fb_bl_default_curve(info, 0,
+ 0x3F * FB_BACKLIGHT_MAX / MAX_LEVEL,
+ 0xFF * FB_BACKLIGHT_MAX / MAX_LEVEL);
+ mutex_unlock(&info->bl_mutex);
+
+ up(&bd->sem);
+ bd->props->brightness = aty_bl_data.max_brightness;
+ bd->props->power = FB_BLANK_UNBLANK;
+ bd->props->update_status(bd);
+ down(&bd->sem);
+
+#ifdef CONFIG_PMAC_BACKLIGHT
+ mutex_lock(&pmac_backlight_mutex);
+ if (!pmac_backlight)
+ pmac_backlight = bd;
+ mutex_unlock(&pmac_backlight_mutex);
+#endif
+
+ printk("aty: Backlight initialized (%s)\n", name);
+
+ return;
+
+error:
+ return;
+}
+
+static void aty_bl_exit(struct atyfb_par *par)
+{
+ struct fb_info *info = pci_get_drvdata(par->pdev);
+
+#ifdef CONFIG_PMAC_BACKLIGHT
+ mutex_lock(&pmac_backlight_mutex);
+#endif
+
+ mutex_lock(&info->bl_mutex);
+ if (info->bl_dev) {
+#ifdef CONFIG_PMAC_BACKLIGHT
+ if (pmac_backlight == info->bl_dev)
+ pmac_backlight = NULL;
+#endif
+
+ backlight_device_unregister(info->bl_dev);
+
+ printk("aty: Backlight unloaded\n");
+ }
+ mutex_unlock(&info->bl_mutex);
+
+#ifdef CONFIG_PMAC_BACKLIGHT
+ mutex_unlock(&pmac_backlight_mutex);
+#endif
+}
+
+#endif /* CONFIG_FB_ATY_BACKLIGHT */
+
+static void __devinit aty_calc_mem_refresh(struct atyfb_par *par, int xclk)
{
const int ragepro_tbl[] = {
44, 50, 55, 66, 75, 80, 100
@@ -2215,7 +2320,7 @@ static int __devinit atyfb_get_timings_from_lcd(struct atyfb_par *par,
}
#endif /* defined(__i386__) && defined(CONFIG_FB_ATY_GENERIC_LCD) */
-static int __init aty_init(struct fb_info *info, const char *name)
+static int __devinit aty_init(struct fb_info *info, const char *name)
{
struct atyfb_par *par = (struct atyfb_par *) info->par;
const char *ramname = NULL, *xtal;
@@ -2296,12 +2401,15 @@ static int __init aty_init(struct fb_info *info, const char *name)
break;
}
switch (clk_type) {
+#ifdef CONFIG_ATARI
case CLK_ATI18818_1:
par->pll_ops = &aty_pll_ati18818_1;
break;
+#else
case CLK_IBMRGB514:
par->pll_ops = &aty_pll_ibm514;
break;
+#endif
#if 0 /* dead code */
case CLK_STG1703:
par->pll_ops = &aty_pll_stg1703;
@@ -2506,16 +2614,24 @@ static int __init aty_init(struct fb_info *info, const char *name)
info->fbops = &atyfb_ops;
info->pseudo_palette = pseudo_palette;
- info->flags = FBINFO_FLAG_DEFAULT;
+ info->flags = FBINFO_DEFAULT |
+ FBINFO_HWACCEL_IMAGEBLIT |
+ FBINFO_HWACCEL_FILLRECT |
+ FBINFO_HWACCEL_COPYAREA |
+ FBINFO_HWACCEL_YPAN;
#ifdef CONFIG_PMAC_BACKLIGHT
if (M64_HAS(G3_PB_1_1) && machine_is_compatible("PowerBook1,1")) {
/* these bits let the 101 powerbook wake up from sleep -- paulus */
aty_st_lcd(POWER_MANAGEMENT, aty_ld_lcd(POWER_MANAGEMENT, par)
| (USE_F32KHZ | TRISTATE_MEM_EN), par);
- } else if (M64_HAS(MOBIL_BUS))
- register_backlight_controller(&aty_backlight_controller, info, "ati");
-#endif /* CONFIG_PMAC_BACKLIGHT */
+ } else
+#endif
+ if (M64_HAS(MOBIL_BUS)) {
+#ifdef CONFIG_FB_ATY_BACKLIGHT
+ aty_bl_init (par);
+#endif
+ }
memset(&var, 0, sizeof(var));
#ifdef CONFIG_PPC
@@ -2631,7 +2747,7 @@ aty_init_exit:
}
#ifdef CONFIG_ATARI
-static int __init store_video_par(char *video_str, unsigned char m64_num)
+static int __devinit store_video_par(char *video_str, unsigned char m64_num)
{
char *p;
unsigned long vmembase, size, guiregbase;
@@ -2674,8 +2790,16 @@ static int atyfb_blank(int blank, struct fb_info *info)
return 0;
#ifdef CONFIG_PMAC_BACKLIGHT
- if (machine_is(powermac) && blank > FB_BLANK_NORMAL)
- set_backlight_enable(0);
+ 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);
+ }
#elif defined(CONFIG_FB_ATY_GENERIC_LCD)
if (par->lcd_table && blank > FB_BLANK_NORMAL &&
(aty_ld_lcd(LCD_GEN_CNTL, par) & LCD_ON)) {
@@ -2706,8 +2830,16 @@ 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)
- set_backlight_enable(1);
+ 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);
+ }
#elif defined(CONFIG_FB_ATY_GENERIC_LCD)
if (par->lcd_table && blank <= FB_BLANK_NORMAL &&
(aty_ld_lcd(LCD_GEN_CNTL, par) & LCD_ON)) {
@@ -2966,7 +3098,7 @@ static int __devinit atyfb_setup_sparc(struct pci_dev *pdev,
}
pcp = pdev->sysdata;
- if (node == pcp->prom_node) {
+ if (node == pcp->prom_node->node) {
struct fb_var_screeninfo *var = &default_var;
unsigned int N, P, Q, M, T, R;
u32 v_total, h_total;
@@ -3440,6 +3572,7 @@ static int __devinit atyfb_pci_probe(struct pci_dev *pdev, const struct pci_devi
par->res_start = res_start;
par->res_size = res_size;
par->irq = pdev->irq;
+ par->pdev = pdev;
/* Setup "info" structure */
#ifdef __sparc__
@@ -3571,6 +3704,11 @@ static void __devexit atyfb_remove(struct fb_info *info)
aty_set_crtc(par, &saved_crtc);
par->pll_ops->set_pll(info, &saved_pll);
+#ifdef CONFIG_FB_ATY_BACKLIGHT
+ if (M64_HAS(MOBIL_BUS))
+ aty_bl_exit(par);
+#endif
+
unregister_framebuffer(info);
#ifdef CONFIG_MTRR
@@ -3640,7 +3778,7 @@ static struct pci_driver atyfb_driver = {
#endif /* CONFIG_PCI */
#ifndef MODULE
-static int __init atyfb_setup(char *options)
+static int __devinit atyfb_setup(char *options)
{
char *this_opt;
@@ -3712,7 +3850,7 @@ static int __init atyfb_setup(char *options)
}
#endif /* MODULE */
-static int __init atyfb_init(void)
+static int __devinit atyfb_init(void)
{
#ifndef MODULE
char *option = NULL;
@@ -3722,7 +3860,9 @@ static int __init atyfb_init(void)
atyfb_setup(option);
#endif
+#ifdef CONFIG_PCI
pci_register_driver(&atyfb_driver);
+#endif
#ifdef CONFIG_ATARI
atyfb_atari_probe();
#endif
@@ -3731,7 +3871,9 @@ static int __init atyfb_init(void)
static void __exit atyfb_exit(void)
{
+#ifdef CONFIG_PCI
pci_unregister_driver(&atyfb_driver);
+#endif
}
module_init(atyfb_init);
diff --git a/drivers/video/aty/mach64_accel.c b/drivers/video/aty/mach64_accel.c
index c98f4a442134..1490e5e1c232 100644
--- a/drivers/video/aty/mach64_accel.c
+++ b/drivers/video/aty/mach64_accel.c
@@ -200,8 +200,6 @@ void atyfb_copyarea(struct fb_info *info, const struct fb_copyarea *area)
if (!area->width || !area->height)
return;
if (!par->accel_flags) {
- if (par->blitter_may_be_busy)
- wait_for_idle(par);
cfb_copyarea(info, area);
return;
}
@@ -248,8 +246,6 @@ void atyfb_fillrect(struct fb_info *info, const struct fb_fillrect *rect)
if (!rect->width || !rect->height)
return;
if (!par->accel_flags) {
- if (par->blitter_may_be_busy)
- wait_for_idle(par);
cfb_fillrect(info, rect);
return;
}
@@ -288,14 +284,10 @@ void atyfb_imageblit(struct fb_info *info, const struct fb_image *image)
return;
if (!par->accel_flags ||
(image->depth != 1 && info->var.bits_per_pixel != image->depth)) {
- if (par->blitter_may_be_busy)
- wait_for_idle(par);
-
cfb_imageblit(info, image);
return;
}
- wait_for_idle(par);
pix_width = pix_width_save = aty_ld_le32(DP_PIX_WIDTH, par);
host_cntl = aty_ld_le32(HOST_CNTL, par) | HOST_BYTE_ALIGN;
@@ -425,8 +417,6 @@ void atyfb_imageblit(struct fb_info *info, const struct fb_image *image)
}
}
- wait_for_idle(par);
-
/* restore pix_width */
wait_for_fifo(1, par);
aty_st_le32(DP_PIX_WIDTH, pix_width_save, par);
diff --git a/drivers/video/aty/mach64_cursor.c b/drivers/video/aty/mach64_cursor.c
index ad8b7496f853..2a7f381c330f 100644
--- a/drivers/video/aty/mach64_cursor.c
+++ b/drivers/video/aty/mach64_cursor.c
@@ -66,11 +66,6 @@ static const u8 cursor_bits_lookup[16] = {
0x01, 0x41, 0x11, 0x51, 0x05, 0x45, 0x15, 0x55
};
-static const u8 cursor_mask_lookup[16] = {
- 0xaa, 0x2a, 0x8a, 0x0a, 0xa2, 0x22, 0x82, 0x02,
- 0xa8, 0x28, 0x88, 0x08, 0xa0, 0x20, 0x80, 0x00
-};
-
static int atyfb_cursor(struct fb_info *info, struct fb_cursor *cursor)
{
struct atyfb_par *par = (struct atyfb_par *) info->par;
@@ -130,13 +125,13 @@ static int atyfb_cursor(struct fb_info *info, struct fb_cursor *cursor)
fg_idx = cursor->image.fg_color;
bg_idx = cursor->image.bg_color;
- fg = (info->cmap.red[fg_idx] << 24) |
- (info->cmap.green[fg_idx] << 16) |
- (info->cmap.blue[fg_idx] << 8) | 15;
+ fg = ((info->cmap.red[fg_idx] & 0xff) << 24) |
+ ((info->cmap.green[fg_idx] & 0xff) << 16) |
+ ((info->cmap.blue[fg_idx] & 0xff) << 8) | 0xff;
- bg = (info->cmap.red[bg_idx] << 24) |
- (info->cmap.green[bg_idx] << 16) |
- (info->cmap.blue[bg_idx] << 8);
+ bg = ((info->cmap.red[bg_idx] & 0xff) << 24) |
+ ((info->cmap.green[bg_idx] & 0xff) << 16) |
+ ((info->cmap.blue[bg_idx] & 0xff) << 8);
wait_for_fifo(2, par);
aty_st_le32(CUR_CLR0, bg, par);
@@ -166,19 +161,17 @@ static int atyfb_cursor(struct fb_info *info, struct fb_cursor *cursor)
switch (cursor->rop) {
case ROP_XOR:
// Upper 4 bits of mask data
- fb_writeb(cursor_mask_lookup[m >> 4 ] |
- cursor_bits_lookup[(b ^ m) >> 4], dst++);
+ fb_writeb(cursor_bits_lookup[(b ^ m) >> 4], dst++);
// Lower 4 bits of mask
- fb_writeb(cursor_mask_lookup[m & 0x0f ] |
- cursor_bits_lookup[(b ^ m) & 0x0f], dst++);
+ fb_writeb(cursor_bits_lookup[(b ^ m) & 0x0f],
+ dst++);
break;
case ROP_COPY:
// Upper 4 bits of mask data
- fb_writeb(cursor_mask_lookup[m >> 4 ] |
- cursor_bits_lookup[(b & m) >> 4], dst++);
+ fb_writeb(cursor_bits_lookup[(b & m) >> 4], dst++);
// Lower 4 bits of mask
- fb_writeb(cursor_mask_lookup[m & 0x0f ] |
- cursor_bits_lookup[(b & m) & 0x0f], dst++);
+ fb_writeb(cursor_bits_lookup[(b & m) & 0x0f],
+ dst++);
break;
}
}
@@ -194,7 +187,7 @@ static int atyfb_cursor(struct fb_info *info, struct fb_cursor *cursor)
return 0;
}
-int __init aty_init_cursor(struct fb_info *info)
+int __devinit aty_init_cursor(struct fb_info *info)
{
unsigned long addr;
diff --git a/drivers/video/aty/radeon_backlight.c b/drivers/video/aty/radeon_backlight.c
new file mode 100644
index 000000000000..1755dddf1899
--- /dev/null
+++ b/drivers/video/aty/radeon_backlight.c
@@ -0,0 +1,247 @@
+/*
+ * Backlight code for ATI Radeon based graphic cards
+ *
+ * Copyright (c) 2000 Ani Joshi <ajoshi@kernel.crashing.org>
+ * Copyright (c) 2003 Benjamin Herrenschmidt <benh@kernel.crashing.org>
+ * Copyright (c) 2006 Michael Hanselmann <linux-kernel@hansmi.ch>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include "radeonfb.h"
+#include <linux/backlight.h>
+
+#ifdef CONFIG_PMAC_BACKLIGHT
+#include <asm/backlight.h>
+#endif
+
+#define MAX_RADEON_LEVEL 0xFF
+
+static struct backlight_properties radeon_bl_data;
+
+struct radeon_bl_privdata {
+ struct radeonfb_info *rinfo;
+ uint8_t negative;
+};
+
+static int radeon_bl_get_level_brightness(struct radeon_bl_privdata *pdata,
+ int level)
+{
+ struct fb_info *info = pdata->rinfo->info;
+ int rlevel;
+
+ mutex_lock(&info->bl_mutex);
+
+ /* Get and convert the value */
+ rlevel = pdata->rinfo->info->bl_curve[level] *
+ FB_BACKLIGHT_MAX / MAX_RADEON_LEVEL;
+
+ mutex_unlock(&info->bl_mutex);
+
+ if (rlevel < 0)
+ rlevel = 0;
+ else if (rlevel > MAX_RADEON_LEVEL)
+ rlevel = MAX_RADEON_LEVEL;
+
+ if (pdata->negative)
+ rlevel = MAX_RADEON_LEVEL - rlevel;
+
+ return rlevel;
+}
+
+static int radeon_bl_update_status(struct backlight_device *bd)
+{
+ struct radeon_bl_privdata *pdata = class_get_devdata(&bd->class_dev);
+ struct radeonfb_info *rinfo = pdata->rinfo;
+ u32 lvds_gen_cntl, tmpPixclksCntl;
+ int level;
+
+ if (rinfo->mon1_type != MT_LCD)
+ return 0;
+
+ /* We turn off the LCD completely instead of just dimming the
+ * backlight. This provides some greater power saving and the display
+ * is useless without backlight anyway.
+ */
+ if (bd->props->power != FB_BLANK_UNBLANK ||
+ bd->props->fb_blank != FB_BLANK_UNBLANK)
+ level = 0;
+ else
+ level = bd->props->brightness;
+
+ del_timer_sync(&rinfo->lvds_timer);
+ radeon_engine_idle();
+
+ lvds_gen_cntl = INREG(LVDS_GEN_CNTL);
+ if (level > 0) {
+ lvds_gen_cntl &= ~LVDS_DISPLAY_DIS;
+ if (!(lvds_gen_cntl & LVDS_BLON) || !(lvds_gen_cntl & LVDS_ON)) {
+ lvds_gen_cntl |= (rinfo->init_state.lvds_gen_cntl & LVDS_DIGON);
+ lvds_gen_cntl |= LVDS_BLON | LVDS_EN;
+ OUTREG(LVDS_GEN_CNTL, lvds_gen_cntl);
+ lvds_gen_cntl &= ~LVDS_BL_MOD_LEVEL_MASK;
+ lvds_gen_cntl |=
+ (radeon_bl_get_level_brightness(pdata, level) <<
+ LVDS_BL_MOD_LEVEL_SHIFT);
+ lvds_gen_cntl |= LVDS_ON;
+ lvds_gen_cntl |= (rinfo->init_state.lvds_gen_cntl & LVDS_BL_MOD_EN);
+ rinfo->pending_lvds_gen_cntl = lvds_gen_cntl;
+ mod_timer(&rinfo->lvds_timer,
+ jiffies + msecs_to_jiffies(rinfo->panel_info.pwr_delay));
+ } else {
+ lvds_gen_cntl &= ~LVDS_BL_MOD_LEVEL_MASK;
+ lvds_gen_cntl |=
+ (radeon_bl_get_level_brightness(pdata, level) <<
+ LVDS_BL_MOD_LEVEL_SHIFT);
+ OUTREG(LVDS_GEN_CNTL, lvds_gen_cntl);
+ }
+ rinfo->init_state.lvds_gen_cntl &= ~LVDS_STATE_MASK;
+ rinfo->init_state.lvds_gen_cntl |= rinfo->pending_lvds_gen_cntl
+ & LVDS_STATE_MASK;
+ } else {
+ /* Asic bug, when turning off LVDS_ON, we have to make sure
+ RADEON_PIXCLK_LVDS_ALWAYS_ON bit is off
+ */
+ tmpPixclksCntl = INPLL(PIXCLKS_CNTL);
+ if (rinfo->is_mobility || rinfo->is_IGP)
+ OUTPLLP(PIXCLKS_CNTL, 0, ~PIXCLK_LVDS_ALWAYS_ONb);
+ lvds_gen_cntl &= ~(LVDS_BL_MOD_LEVEL_MASK | LVDS_BL_MOD_EN);
+ lvds_gen_cntl |= (radeon_bl_get_level_brightness(pdata, 0) <<
+ LVDS_BL_MOD_LEVEL_SHIFT);
+ lvds_gen_cntl |= LVDS_DISPLAY_DIS;
+ OUTREG(LVDS_GEN_CNTL, lvds_gen_cntl);
+ udelay(100);
+ lvds_gen_cntl &= ~(LVDS_ON | LVDS_EN);
+ OUTREG(LVDS_GEN_CNTL, lvds_gen_cntl);
+ lvds_gen_cntl &= ~(LVDS_DIGON);
+ rinfo->pending_lvds_gen_cntl = lvds_gen_cntl;
+ mod_timer(&rinfo->lvds_timer,
+ jiffies + msecs_to_jiffies(rinfo->panel_info.pwr_delay));
+ if (rinfo->is_mobility || rinfo->is_IGP)
+ OUTPLL(PIXCLKS_CNTL, tmpPixclksCntl);
+ }
+ rinfo->init_state.lvds_gen_cntl &= ~LVDS_STATE_MASK;
+ rinfo->init_state.lvds_gen_cntl |= (lvds_gen_cntl & LVDS_STATE_MASK);
+
+ return 0;
+}
+
+static int radeon_bl_get_brightness(struct backlight_device *bd)
+{
+ return bd->props->brightness;
+}
+
+static struct backlight_properties radeon_bl_data = {
+ .owner = THIS_MODULE,
+ .get_brightness = radeon_bl_get_brightness,
+ .update_status = radeon_bl_update_status,
+ .max_brightness = (FB_BACKLIGHT_LEVELS - 1),
+};
+
+void radeonfb_bl_init(struct radeonfb_info *rinfo)
+{
+ struct backlight_device *bd;
+ struct radeon_bl_privdata *pdata;
+ char name[12];
+
+ if (rinfo->mon1_type != MT_LCD)
+ return;
+
+#ifdef CONFIG_PMAC_BACKLIGHT
+ if (!pmac_has_backlight_type("ati") &&
+ !pmac_has_backlight_type("mnca"))
+ return;
+#endif
+
+ pdata = kmalloc(sizeof(struct radeon_bl_privdata), GFP_KERNEL);
+ if (!pdata) {
+ printk("radeonfb: Memory allocation failed\n");
+ goto error;
+ }
+
+ snprintf(name, sizeof(name), "radeonbl%d", rinfo->info->node);
+
+ bd = backlight_device_register(name, pdata, &radeon_bl_data);
+ if (IS_ERR(bd)) {
+ rinfo->info->bl_dev = NULL;
+ printk("radeonfb: Backlight registration failed\n");
+ goto error;
+ }
+
+ pdata->rinfo = rinfo;
+
+ /* Pardon me for that hack... maybe some day we can figure out in what
+ * direction backlight should work on a given panel?
+ */
+ pdata->negative =
+ (rinfo->family != CHIP_FAMILY_RV200 &&
+ rinfo->family != CHIP_FAMILY_RV250 &&
+ rinfo->family != CHIP_FAMILY_RV280 &&
+ rinfo->family != CHIP_FAMILY_RV350);
+
+#ifdef CONFIG_PMAC_BACKLIGHT
+ pdata->negative = pdata->negative ||
+ machine_is_compatible("PowerBook4,3") ||
+ machine_is_compatible("PowerBook6,3") ||
+ machine_is_compatible("PowerBook6,5");
+#endif
+
+ mutex_lock(&rinfo->info->bl_mutex);
+ rinfo->info->bl_dev = bd;
+ fb_bl_default_curve(rinfo->info, 0,
+ 63 * FB_BACKLIGHT_MAX / MAX_RADEON_LEVEL,
+ 217 * FB_BACKLIGHT_MAX / MAX_RADEON_LEVEL);
+ mutex_unlock(&rinfo->info->bl_mutex);
+
+ up(&bd->sem);
+ bd->props->brightness = radeon_bl_data.max_brightness;
+ bd->props->power = FB_BLANK_UNBLANK;
+ bd->props->update_status(bd);
+ down(&bd->sem);
+
+#ifdef CONFIG_PMAC_BACKLIGHT
+ mutex_lock(&pmac_backlight_mutex);
+ if (!pmac_backlight)
+ pmac_backlight = bd;
+ mutex_unlock(&pmac_backlight_mutex);
+#endif
+
+ printk("radeonfb: Backlight initialized (%s)\n", name);
+
+ return;
+
+error:
+ kfree(pdata);
+ return;
+}
+
+void radeonfb_bl_exit(struct radeonfb_info *rinfo)
+{
+#ifdef CONFIG_PMAC_BACKLIGHT
+ mutex_lock(&pmac_backlight_mutex);
+#endif
+
+ mutex_lock(&rinfo->info->bl_mutex);
+ if (rinfo->info->bl_dev) {
+ struct radeon_bl_privdata *pdata;
+
+#ifdef CONFIG_PMAC_BACKLIGHT
+ if (pmac_backlight == rinfo->info->bl_dev)
+ pmac_backlight = NULL;
+#endif
+
+ pdata = class_get_devdata(&rinfo->info->bl_dev->class_dev);
+ backlight_device_unregister(rinfo->info->bl_dev);
+ kfree(pdata);
+ rinfo->info->bl_dev = NULL;
+
+ printk("radeonfb: Backlight unloaded\n");
+ }
+ mutex_unlock(&rinfo->info->bl_mutex);
+
+#ifdef CONFIG_PMAC_BACKLIGHT
+ mutex_unlock(&pmac_backlight_mutex);
+#endif
+}
diff --git a/drivers/video/aty/radeon_base.c b/drivers/video/aty/radeon_base.c
index 387a18a47ac2..51b78f8de949 100644
--- a/drivers/video/aty/radeon_base.c
+++ b/drivers/video/aty/radeon_base.c
@@ -52,7 +52,6 @@
#define RADEON_VERSION "0.2.0"
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/kernel.h>
@@ -78,10 +77,6 @@
#include <asm/pci-bridge.h>
#include "../macmodes.h"
-#ifdef CONFIG_PMAC_BACKLIGHT
-#include <asm/backlight.h>
-#endif
-
#ifdef CONFIG_BOOTX_TEXT
#include <asm/btext.h>
#endif
@@ -277,20 +272,6 @@ static int nomtrr = 0;
* prototypes
*/
-
-#ifdef CONFIG_PPC_OF
-
-#ifdef CONFIG_PMAC_BACKLIGHT
-static int radeon_set_backlight_enable(int on, int level, void *data);
-static int radeon_set_backlight_level(int level, void *data);
-static struct backlight_controller radeon_backlight_controller = {
- radeon_set_backlight_enable,
- radeon_set_backlight_level
-};
-#endif /* CONFIG_PMAC_BACKLIGHT */
-
-#endif /* CONFIG_PPC_OF */
-
static void radeon_unmap_ROM(struct radeonfb_info *rinfo, struct pci_dev *dev)
{
if (!rinfo->bios_seg)
@@ -1913,116 +1894,6 @@ static int __devinit radeon_set_fbinfo (struct radeonfb_info *rinfo)
return 0;
}
-
-#ifdef CONFIG_PMAC_BACKLIGHT
-
-/* TODO: Dbl check these tables, we don't go up to full ON backlight
- * in these, possibly because we noticed MacOS doesn't, but I'd prefer
- * having some more official numbers from ATI
- */
-static int backlight_conv_m6[] = {
- 0xff, 0xc0, 0xb5, 0xaa, 0x9f, 0x94, 0x89, 0x7e,
- 0x73, 0x68, 0x5d, 0x52, 0x47, 0x3c, 0x31, 0x24
-};
-static int backlight_conv_m7[] = {
- 0x00, 0x3f, 0x4a, 0x55, 0x60, 0x6b, 0x76, 0x81,
- 0x8c, 0x97, 0xa2, 0xad, 0xb8, 0xc3, 0xce, 0xd9
-};
-
-#define BACKLIGHT_LVDS_OFF
-#undef BACKLIGHT_DAC_OFF
-
-/* We turn off the LCD completely instead of just dimming the backlight.
- * This provides some greater power saving and the display is useless
- * without backlight anyway.
- */
-static int radeon_set_backlight_enable(int on, int level, void *data)
-{
- struct radeonfb_info *rinfo = (struct radeonfb_info *)data;
- u32 lvds_gen_cntl, tmpPixclksCntl;
- int* conv_table;
-
- if (rinfo->mon1_type != MT_LCD)
- return 0;
-
- /* Pardon me for that hack... maybe some day we can figure
- * out in what direction backlight should work on a given
- * panel ?
- */
- if ((rinfo->family == CHIP_FAMILY_RV200 ||
- rinfo->family == CHIP_FAMILY_RV250 ||
- rinfo->family == CHIP_FAMILY_RV280 ||
- rinfo->family == CHIP_FAMILY_RV350) &&
- !machine_is_compatible("PowerBook4,3") &&
- !machine_is_compatible("PowerBook6,3") &&
- !machine_is_compatible("PowerBook6,5"))
- conv_table = backlight_conv_m7;
- else
- conv_table = backlight_conv_m6;
-
- del_timer_sync(&rinfo->lvds_timer);
- radeon_engine_idle();
-
- lvds_gen_cntl = INREG(LVDS_GEN_CNTL);
- if (on && (level > BACKLIGHT_OFF)) {
- lvds_gen_cntl &= ~LVDS_DISPLAY_DIS;
- if (!(lvds_gen_cntl & LVDS_BLON) || !(lvds_gen_cntl & LVDS_ON)) {
- lvds_gen_cntl |= (rinfo->init_state.lvds_gen_cntl & LVDS_DIGON);
- lvds_gen_cntl |= LVDS_BLON | LVDS_EN;
- OUTREG(LVDS_GEN_CNTL, lvds_gen_cntl);
- lvds_gen_cntl &= ~LVDS_BL_MOD_LEVEL_MASK;
- lvds_gen_cntl |= (conv_table[level] <<
- LVDS_BL_MOD_LEVEL_SHIFT);
- lvds_gen_cntl |= LVDS_ON;
- lvds_gen_cntl |= (rinfo->init_state.lvds_gen_cntl & LVDS_BL_MOD_EN);
- rinfo->pending_lvds_gen_cntl = lvds_gen_cntl;
- mod_timer(&rinfo->lvds_timer,
- jiffies + msecs_to_jiffies(rinfo->panel_info.pwr_delay));
- } else {
- lvds_gen_cntl &= ~LVDS_BL_MOD_LEVEL_MASK;
- lvds_gen_cntl |= (conv_table[level] <<
- LVDS_BL_MOD_LEVEL_SHIFT);
- OUTREG(LVDS_GEN_CNTL, lvds_gen_cntl);
- }
- rinfo->init_state.lvds_gen_cntl &= ~LVDS_STATE_MASK;
- rinfo->init_state.lvds_gen_cntl |= rinfo->pending_lvds_gen_cntl
- & LVDS_STATE_MASK;
- } else {
- /* Asic bug, when turning off LVDS_ON, we have to make sure
- RADEON_PIXCLK_LVDS_ALWAYS_ON bit is off
- */
- tmpPixclksCntl = INPLL(PIXCLKS_CNTL);
- if (rinfo->is_mobility || rinfo->is_IGP)
- OUTPLLP(PIXCLKS_CNTL, 0, ~PIXCLK_LVDS_ALWAYS_ONb);
- lvds_gen_cntl &= ~(LVDS_BL_MOD_LEVEL_MASK | LVDS_BL_MOD_EN);
- lvds_gen_cntl |= (conv_table[0] <<
- LVDS_BL_MOD_LEVEL_SHIFT);
- lvds_gen_cntl |= LVDS_DISPLAY_DIS;
- OUTREG(LVDS_GEN_CNTL, lvds_gen_cntl);
- udelay(100);
- lvds_gen_cntl &= ~(LVDS_ON | LVDS_EN);
- OUTREG(LVDS_GEN_CNTL, lvds_gen_cntl);
- lvds_gen_cntl &= ~(LVDS_DIGON);
- rinfo->pending_lvds_gen_cntl = lvds_gen_cntl;
- mod_timer(&rinfo->lvds_timer,
- jiffies + msecs_to_jiffies(rinfo->panel_info.pwr_delay));
- if (rinfo->is_mobility || rinfo->is_IGP)
- OUTPLL(PIXCLKS_CNTL, tmpPixclksCntl);
- }
- rinfo->init_state.lvds_gen_cntl &= ~LVDS_STATE_MASK;
- rinfo->init_state.lvds_gen_cntl |= (lvds_gen_cntl & LVDS_STATE_MASK);
-
- return 0;
-}
-
-
-static int radeon_set_backlight_level(int level, void *data)
-{
- return radeon_set_backlight_enable(1, level, data);
-}
-#endif /* CONFIG_PMAC_BACKLIGHT */
-
-
/*
* This reconfigure the card's internal memory map. In theory, we'd like
* to setup the card's memory at the same address as it's PCI bus address,
@@ -2477,14 +2348,7 @@ static int __devinit radeonfb_pci_register (struct pci_dev *pdev,
MTRR_TYPE_WRCOMB, 1);
#endif
-#ifdef CONFIG_PMAC_BACKLIGHT
- if (rinfo->mon1_type == MT_LCD) {
- register_backlight_controller(&radeon_backlight_controller,
- rinfo, "ati");
- register_backlight_controller(&radeon_backlight_controller,
- rinfo, "mnca");
- }
-#endif
+ radeonfb_bl_init(rinfo);
printk ("radeonfb (%s): %s\n", pci_name(rinfo->pdev), rinfo->name);
@@ -2514,7 +2378,6 @@ err_release_pci0:
err_release_fb:
framebuffer_release(info);
err_disable:
- pci_disable_device(pdev);
err_out:
return ret;
}
@@ -2528,7 +2391,8 @@ static void __devexit radeonfb_pci_unregister (struct pci_dev *pdev)
if (!rinfo)
return;
-
+
+ radeonfb_bl_exit(rinfo);
radeonfb_pm_exit(rinfo);
if (rinfo->mon1_EDID)
@@ -2570,7 +2434,6 @@ static void __devexit radeonfb_pci_unregister (struct pci_dev *pdev)
#endif
fb_dealloc_cmap(&info->cmap);
framebuffer_release(info);
- pci_disable_device(pdev);
}
diff --git a/drivers/video/aty/radeon_i2c.c b/drivers/video/aty/radeon_i2c.c
index a9d0414e4655..9aaca58c074a 100644
--- a/drivers/video/aty/radeon_i2c.c
+++ b/drivers/video/aty/radeon_i2c.c
@@ -1,4 +1,3 @@
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/sched.h>
diff --git a/drivers/video/aty/radeonfb.h b/drivers/video/aty/radeonfb.h
index 217e00ab4a2d..38657b2d10eb 100644
--- a/drivers/video/aty/radeonfb.h
+++ b/drivers/video/aty/radeonfb.h
@@ -1,7 +1,6 @@
#ifndef __RADEONFB_H__
#define __RADEONFB_H__
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/sched.h>
@@ -382,7 +381,7 @@ struct radeonfb_info {
/* Note about this function: we have some rare cases where we must not schedule,
* this typically happen with our special "wake up early" hook which allows us to
* wake up the graphic chip (and thus get the console back) before everything else
- * on some machines that support that mecanism. At this point, interrupts are off
+ * on some machines that support that mechanism. At this point, interrupts are off
* and scheduling is not permitted
*/
static inline void _radeon_msleep(struct radeonfb_info *rinfo, unsigned long ms)
@@ -625,4 +624,13 @@ extern int radeon_screen_blank(struct radeonfb_info *rinfo, int blank, int mode_
extern void radeon_write_mode (struct radeonfb_info *rinfo, struct radeon_regs *mode,
int reg_only);
+/* Backlight functions */
+#ifdef CONFIG_FB_RADEON_BACKLIGHT
+extern void radeonfb_bl_init(struct radeonfb_info *rinfo);
+extern void radeonfb_bl_exit(struct radeonfb_info *rinfo);
+#else
+static inline void radeonfb_bl_init(struct radeonfb_info *rinfo) {}
+static inline void radeonfb_bl_exit(struct radeonfb_info *rinfo) {}
+#endif
+
#endif /* __RADEONFB_H__ */