aboutsummaryrefslogtreecommitdiff
path: root/drivers/video/aty
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/video/aty')
-rw-r--r--drivers/video/aty/aty128fb.c31
-rw-r--r--drivers/video/aty/atyfb_base.c22
-rw-r--r--drivers/video/aty/radeon_backlight.c4
-rw-r--r--drivers/video/aty/radeon_base.c18
-rw-r--r--drivers/video/aty/radeon_pm.c146
-rw-r--r--drivers/video/aty/radeonfb.h6
6 files changed, 177 insertions, 50 deletions
diff --git a/drivers/video/aty/aty128fb.c b/drivers/video/aty/aty128fb.c
index c64a717e2d4..276a21530b9 100644
--- a/drivers/video/aty/aty128fb.c
+++ b/drivers/video/aty/aty128fb.c
@@ -455,7 +455,10 @@ 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);
+
+#ifdef CONFIG_FB_ATY128_BACKLIGHT
static void aty128_bl_set_power(struct fb_info *info, int power);
+#endif
#define BIOS_IN8(v) (readb(bios + (v)))
#define BIOS_IN16(v) (readb(bios + (v)) | \
@@ -1798,10 +1801,14 @@ static struct backlight_properties aty128_bl_data = {
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);
+
+ if (info->bl_dev) {
+ down(&info->bl_dev->sem);
+ info->bl_dev->props->power = power;
+ __aty128_bl_update_status(info->bl_dev);
+ up(&info->bl_dev->sem);
+ }
+
mutex_unlock(&info->bl_mutex);
}
@@ -1825,7 +1832,7 @@ static void aty128_bl_init(struct aty128fb_par *par)
bd = backlight_device_register(name, par, &aty128_bl_data);
if (IS_ERR(bd)) {
info->bl_dev = NULL;
- printk("aty128: Backlight registration failed\n");
+ printk(KERN_WARNING "aty128: Backlight registration failed\n");
goto error;
}
@@ -1836,11 +1843,11 @@ static void aty128_bl_init(struct aty128fb_par *par)
219 * FB_BACKLIGHT_MAX / MAX_LEVEL);
mutex_unlock(&info->bl_mutex);
- up(&bd->sem);
+ down(&bd->sem);
bd->props->brightness = aty128_bl_data.max_brightness;
bd->props->power = FB_BLANK_UNBLANK;
bd->props->update_status(bd);
- down(&bd->sem);
+ up(&bd->sem);
#ifdef CONFIG_PMAC_BACKLIGHT
mutex_lock(&pmac_backlight_mutex);
@@ -1910,9 +1917,6 @@ static int __devinit aty128_init(struct pci_dev *pdev, const struct pci_device_i
u8 chip_rev;
u32 dac;
- if (!par->vram_size) /* may have already been probed */
- par->vram_size = aty_ld_le32(CONFIG_MEMSIZE) & 0x03FFFFFF;
-
/* Get the chip revision */
chip_rev = (aty_ld_le32(CONFIG_CNTL) >> 16) & 0x1F;
@@ -2025,9 +2029,6 @@ static int __devinit aty128_init(struct pci_dev *pdev, const struct pci_device_i
aty128_init_engine(par);
- if (register_framebuffer(info) < 0)
- return 0;
-
par->pm_reg = pci_find_capability(pdev, PCI_CAP_ID_PM);
par->pdev = pdev;
par->asleep = 0;
@@ -2037,6 +2038,9 @@ static int __devinit aty128_init(struct pci_dev *pdev, const struct pci_device_i
aty128_bl_init(par);
#endif
+ if (register_framebuffer(info) < 0)
+ return 0;
+
printk(KERN_INFO "fb%d: %s frame buffer device on %s\n",
info->node, info->fix.id, video_card);
@@ -2086,7 +2090,6 @@ static int __devinit aty128_probe(struct pci_dev *pdev, const struct pci_device_
par = info->par;
info->pseudo_palette = par->pseudo_palette;
- info->fix = aty128fb_fix;
/* Virtualize mmio region */
info->fix.mmio_start = reg_addr;
diff --git a/drivers/video/aty/atyfb_base.c b/drivers/video/aty/atyfb_base.c
index 1507d19f481..19a71f04578 100644
--- a/drivers/video/aty/atyfb_base.c
+++ b/drivers/video/aty/atyfb_base.c
@@ -2200,10 +2200,14 @@ static struct backlight_properties aty_bl_data = {
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);
+
+ if (info->bl_dev) {
+ down(&info->bl_dev->sem);
+ info->bl_dev->props->power = power;
+ __aty_bl_update_status(info->bl_dev);
+ up(&info->bl_dev->sem);
+ }
+
mutex_unlock(&info->bl_mutex);
}
@@ -2223,7 +2227,7 @@ static void aty_bl_init(struct atyfb_par *par)
bd = backlight_device_register(name, par, &aty_bl_data);
if (IS_ERR(bd)) {
info->bl_dev = NULL;
- printk("aty: Backlight registration failed\n");
+ printk(KERN_WARNING "aty: Backlight registration failed\n");
goto error;
}
@@ -2234,11 +2238,11 @@ static void aty_bl_init(struct atyfb_par *par)
0xFF * FB_BACKLIGHT_MAX / MAX_LEVEL);
mutex_unlock(&info->bl_mutex);
- up(&bd->sem);
+ down(&bd->sem);
bd->props->brightness = aty_bl_data.max_brightness;
bd->props->power = FB_BLANK_UNBLANK;
bd->props->update_status(bd);
- down(&bd->sem);
+ up(&bd->sem);
#ifdef CONFIG_PMAC_BACKLIGHT
mutex_lock(&pmac_backlight_mutex);
@@ -2812,7 +2816,7 @@ static int atyfb_blank(int blank, struct fb_info *info)
if (par->lock_blank || par->asleep)
return 0;
-#ifdef CONFIG_PMAC_BACKLIGHT
+#ifdef CONFIG_FB_ATY_BACKLIGHT
if (machine_is(powermac) && blank > FB_BLANK_NORMAL)
aty_bl_set_power(info, FB_BLANK_POWERDOWN);
#elif defined(CONFIG_FB_ATY_GENERIC_LCD)
@@ -2844,7 +2848,7 @@ static int atyfb_blank(int blank, struct fb_info *info)
}
aty_st_le32(CRTC_GEN_CNTL, gen_cntl, par);
-#ifdef CONFIG_PMAC_BACKLIGHT
+#ifdef CONFIG_FB_ATY_BACKLIGHT
if (machine_is(powermac) && blank <= FB_BLANK_NORMAL)
aty_bl_set_power(info, FB_BLANK_UNBLANK);
#elif defined(CONFIG_FB_ATY_GENERIC_LCD)
diff --git a/drivers/video/aty/radeon_backlight.c b/drivers/video/aty/radeon_backlight.c
index 1755dddf189..585eb7b9e63 100644
--- a/drivers/video/aty/radeon_backlight.c
+++ b/drivers/video/aty/radeon_backlight.c
@@ -195,11 +195,11 @@ void radeonfb_bl_init(struct radeonfb_info *rinfo)
217 * FB_BACKLIGHT_MAX / MAX_RADEON_LEVEL);
mutex_unlock(&rinfo->info->bl_mutex);
- up(&bd->sem);
+ down(&bd->sem);
bd->props->brightness = radeon_bl_data.max_brightness;
bd->props->power = FB_BLANK_UNBLANK;
bd->props->update_status(bd);
- down(&bd->sem);
+ up(&bd->sem);
#ifdef CONFIG_PMAC_BACKLIGHT
mutex_lock(&pmac_backlight_mutex);
diff --git a/drivers/video/aty/radeon_base.c b/drivers/video/aty/radeon_base.c
index 8d85fc58142..8e3400d5dd2 100644
--- a/drivers/video/aty/radeon_base.c
+++ b/drivers/video/aty/radeon_base.c
@@ -266,6 +266,8 @@ static int force_measure_pll = 0;
#ifdef CONFIG_MTRR
static int nomtrr = 0;
#endif
+static int force_sleep;
+static int ignore_devlist;
/*
* prototypes
@@ -2327,9 +2329,9 @@ static int __devinit radeonfb_pci_register (struct pci_dev *pdev,
/* -2 is special: means ON on mobility chips and do not
* change on others
*/
- radeonfb_pm_init(rinfo, rinfo->is_mobility ? 1 : -1);
+ radeonfb_pm_init(rinfo, rinfo->is_mobility ? 1 : -1, ignore_devlist, force_sleep);
} else
- radeonfb_pm_init(rinfo, default_dynclk);
+ radeonfb_pm_init(rinfo, default_dynclk, ignore_devlist, force_sleep);
pci_set_drvdata(pdev, info);
@@ -2477,6 +2479,12 @@ static int __init radeonfb_setup (char *options)
force_measure_pll = 1;
} else if (!strncmp(this_opt, "ignore_edid", 11)) {
ignore_edid = 1;
+#if defined(CONFIG_PM) && defined(CONFIG_X86)
+ } else if (!strncmp(this_opt, "force_sleep", 11)) {
+ force_sleep = 1;
+ } else if (!strncmp(this_opt, "ignore_devlist", 14)) {
+ ignore_devlist = 1;
+#endif
} else
mode_option = this_opt;
}
@@ -2532,3 +2540,9 @@ module_param(panel_yres, int, 0);
MODULE_PARM_DESC(panel_yres, "int: set panel yres");
module_param(mode_option, charp, 0);
MODULE_PARM_DESC(mode_option, "Specify resolution as \"<xres>x<yres>[-<bpp>][@<refresh>]\" ");
+#if defined(CONFIG_PM) && defined(CONFIG_X86)
+module_param(force_sleep, bool, 0);
+MODULE_PARM_DESC(force_sleep, "bool: force D2 sleep mode on all hardware");
+module_param(ignore_devlist, bool, 0);
+MODULE_PARM_DESC(ignore_devlist, "bool: ignore workarounds for bugs in specific laptops");
+#endif
diff --git a/drivers/video/aty/radeon_pm.c b/drivers/video/aty/radeon_pm.c
index c7091761cef..f31e606a2de 100644
--- a/drivers/video/aty/radeon_pm.c
+++ b/drivers/video/aty/radeon_pm.c
@@ -27,6 +27,99 @@
#include "ati_ids.h"
+static void radeon_reinitialize_M10(struct radeonfb_info *rinfo);
+
+/*
+ * Workarounds for bugs in PC laptops:
+ * - enable D2 sleep in some IBM Thinkpads
+ * - special case for Samsung P35
+ *
+ * Whitelist by subsystem vendor/device because
+ * its the subsystem vendor's fault!
+ */
+
+#if defined(CONFIG_PM) && defined(CONFIG_X86)
+struct radeon_device_id {
+ const char *ident; /* (arbitrary) Name */
+ const unsigned short subsystem_vendor; /* Subsystem Vendor ID */
+ const unsigned short subsystem_device; /* Subsystem Device ID */
+ const enum radeon_pm_mode pm_mode_modifier; /* modify pm_mode */
+ const reinit_function_ptr new_reinit_func; /* changed reinit_func */
+};
+
+#define BUGFIX(model, sv, sd, pm, fn) { \
+ .ident = model, \
+ .subsystem_vendor = sv, \
+ .subsystem_device = sd, \
+ .pm_mode_modifier = pm, \
+ .new_reinit_func = fn \
+}
+
+static struct radeon_device_id radeon_workaround_list[] = {
+ BUGFIX("IBM Thinkpad R32",
+ PCI_VENDOR_ID_IBM, 0x1905,
+ radeon_pm_d2, NULL),
+ BUGFIX("IBM Thinkpad R40",
+ PCI_VENDOR_ID_IBM, 0x0526,
+ radeon_pm_d2, NULL),
+ BUGFIX("IBM Thinkpad R40",
+ PCI_VENDOR_ID_IBM, 0x0527,
+ radeon_pm_d2, NULL),
+ BUGFIX("IBM Thinkpad R50/R51/T40/T41",
+ PCI_VENDOR_ID_IBM, 0x0531,
+ radeon_pm_d2, NULL),
+ BUGFIX("IBM Thinkpad R51/T40/T41/T42",
+ PCI_VENDOR_ID_IBM, 0x0530,
+ radeon_pm_d2, NULL),
+ BUGFIX("IBM Thinkpad T30",
+ PCI_VENDOR_ID_IBM, 0x0517,
+ radeon_pm_d2, NULL),
+ BUGFIX("IBM Thinkpad T40p",
+ PCI_VENDOR_ID_IBM, 0x054d,
+ radeon_pm_d2, NULL),
+ BUGFIX("IBM Thinkpad T42",
+ PCI_VENDOR_ID_IBM, 0x0550,
+ radeon_pm_d2, NULL),
+ BUGFIX("IBM Thinkpad X31/X32",
+ PCI_VENDOR_ID_IBM, 0x052f,
+ radeon_pm_d2, NULL),
+ BUGFIX("Samsung P35",
+ PCI_VENDOR_ID_SAMSUNG, 0xc00c,
+ radeon_pm_off, radeon_reinitialize_M10),
+ { .ident = NULL }
+};
+
+static int radeon_apply_workarounds(struct radeonfb_info *rinfo)
+{
+ struct radeon_device_id *id;
+
+ for (id = radeon_workaround_list; id->ident != NULL; id++ )
+ if ((id->subsystem_vendor == rinfo->pdev->subsystem_vendor ) &&
+ (id->subsystem_device == rinfo->pdev->subsystem_device )) {
+
+ /* we found a device that requires workaround */
+ printk(KERN_DEBUG "radeonfb: %s detected"
+ ", enabling workaround\n", id->ident);
+
+ rinfo->pm_mode |= id->pm_mode_modifier;
+
+ if (id->new_reinit_func != NULL)
+ rinfo->reinit_func = id->new_reinit_func;
+
+ return 1;
+ }
+ return 0; /* not found */
+}
+
+#else /* defined(CONFIG_PM) && defined(CONFIG_X86) */
+static inline int radeon_apply_workarounds(struct radeonfb_info *rinfo)
+{
+ return 0;
+}
+#endif /* defined(CONFIG_PM) && defined(CONFIG_X86) */
+
+
+
static void radeon_pm_disable_dynamic_mode(struct radeonfb_info *rinfo)
{
u32 tmp;
@@ -852,18 +945,26 @@ static void radeon_pm_setup_for_suspend(struct radeonfb_info *rinfo)
/* because both INPLL and OUTPLL take the same lock, that's why. */
tmp = INPLL( pllMCLK_MISC) | MCLK_MISC__EN_MCLK_TRISTATE_IN_SUSPEND;
OUTPLL( pllMCLK_MISC, tmp);
-
- /* AGP PLL control */
- if (rinfo->family <= CHIP_FAMILY_RV280) {
- OUTREG(BUS_CNTL1, INREG(BUS_CNTL1) | BUS_CNTL1__AGPCLK_VALID);
- OUTREG(BUS_CNTL1,
- (INREG(BUS_CNTL1) & ~BUS_CNTL1__MOBILE_PLATFORM_SEL_MASK)
- | (2<<BUS_CNTL1__MOBILE_PLATFORM_SEL__SHIFT)); // 440BX
- } else {
- OUTREG(BUS_CNTL1, INREG(BUS_CNTL1));
- OUTREG(BUS_CNTL1, (INREG(BUS_CNTL1) & ~0x4000) | 0x8000);
+ /* BUS_CNTL1__MOBILE_PLATORM_SEL setting is northbridge chipset
+ * and radeon chip dependent. Thus we only enable it on Mac for
+ * now (until we get more info on how to compute the correct
+ * value for various X86 bridges).
+ */
+#ifdef CONFIG_PPC_PMAC
+ if (machine_is(powermac)) {
+ /* AGP PLL control */
+ if (rinfo->family <= CHIP_FAMILY_RV280) {
+ OUTREG(BUS_CNTL1, INREG(BUS_CNTL1) | BUS_CNTL1__AGPCLK_VALID);
+ OUTREG(BUS_CNTL1,
+ (INREG(BUS_CNTL1) & ~BUS_CNTL1__MOBILE_PLATFORM_SEL_MASK)
+ | (2<<BUS_CNTL1__MOBILE_PLATFORM_SEL__SHIFT)); // 440BX
+ } else {
+ OUTREG(BUS_CNTL1, INREG(BUS_CNTL1));
+ OUTREG(BUS_CNTL1, (INREG(BUS_CNTL1) & ~0x4000) | 0x8000);
+ }
}
+#endif
OUTREG(CRTC_OFFSET_CNTL, (INREG(CRTC_OFFSET_CNTL)
& ~CRTC_OFFSET_CNTL__CRTC_STEREO_SYNC_OUT_EN));
@@ -2713,7 +2814,7 @@ static void radeonfb_early_resume(void *data)
#endif /* CONFIG_PM */
-void radeonfb_pm_init(struct radeonfb_info *rinfo, int dynclk)
+void radeonfb_pm_init(struct radeonfb_info *rinfo, int dynclk, int ignore_devlist, int force_sleep)
{
/* Find PM registers in config space if any*/
rinfo->pm_reg = pci_find_capability(rinfo->pdev, PCI_CAP_ID_PM);
@@ -2729,22 +2830,13 @@ void radeonfb_pm_init(struct radeonfb_info *rinfo, int dynclk)
}
#if defined(CONFIG_PM)
+#if defined(CONFIG_PPC_PMAC)
/* Check if we can power manage on suspend/resume. We can do
* D2 on M6, M7 and M9, and we can resume from D3 cold a few other
* "Mac" cards, but that's all. We need more infos about what the
* BIOS does tho. Right now, all this PM stuff is pmac-only for that
* reason. --BenH
*/
- /* Special case for Samsung P35 laptops
- */
- if ((rinfo->pdev->vendor == PCI_VENDOR_ID_ATI) &&
- (rinfo->pdev->device == PCI_CHIP_RV350_NP) &&
- (rinfo->pdev->subsystem_vendor == PCI_VENDOR_ID_SAMSUNG) &&
- (rinfo->pdev->subsystem_device == 0xc00c)) {
- rinfo->reinit_func = radeon_reinitialize_M10;
- rinfo->pm_mode |= radeon_pm_off;
- }
-#if defined(CONFIG_PPC_PMAC)
if (machine_is(powermac) && rinfo->of_node) {
if (rinfo->is_mobility && rinfo->pm_reg &&
rinfo->family <= CHIP_FAMILY_RV250)
@@ -2790,6 +2882,18 @@ void radeonfb_pm_init(struct radeonfb_info *rinfo, int dynclk)
}
#endif /* defined(CONFIG_PPC_PMAC) */
#endif /* defined(CONFIG_PM) */
+
+ if (ignore_devlist)
+ printk(KERN_DEBUG
+ "radeonfb: skipping test for device workarounds\n");
+ else
+ radeon_apply_workarounds(rinfo);
+
+ if (force_sleep) {
+ printk(KERN_DEBUG
+ "radeonfb: forcefully enabling D2 sleep mode\n");
+ rinfo->pm_mode |= radeon_pm_d2;
+ }
}
void radeonfb_pm_exit(struct radeonfb_info *rinfo)
diff --git a/drivers/video/aty/radeonfb.h b/drivers/video/aty/radeonfb.h
index 38657b2d10e..d5ff224a625 100644
--- a/drivers/video/aty/radeonfb.h
+++ b/drivers/video/aty/radeonfb.h
@@ -273,6 +273,8 @@ enum radeon_pm_mode {
radeon_pm_off = 0x00000002, /* Can resume from D3 cold */
};
+typedef void (*reinit_function_ptr)(struct radeonfb_info *rinfo);
+
struct radeonfb_info {
struct fb_info *info;
@@ -338,7 +340,7 @@ struct radeonfb_info {
int dynclk;
int no_schedule;
enum radeon_pm_mode pm_mode;
- void (*reinit_func)(struct radeonfb_info *rinfo);
+ reinit_function_ptr reinit_func;
/* Lock on register access */
spinlock_t reg_lock;
@@ -600,7 +602,7 @@ extern int radeon_probe_i2c_connector(struct radeonfb_info *rinfo, int conn, u8
/* PM Functions */
extern int radeonfb_pci_suspend(struct pci_dev *pdev, pm_message_t state);
extern int radeonfb_pci_resume(struct pci_dev *pdev);
-extern void radeonfb_pm_init(struct radeonfb_info *rinfo, int dynclk);
+extern void radeonfb_pm_init(struct radeonfb_info *rinfo, int dynclk, int ignore_devlist, int force_sleep);
extern void radeonfb_pm_exit(struct radeonfb_info *rinfo);
/* Monitor probe functions */