patch-2.4.0-test2 linux/drivers/video/atyfb.c
Next file: linux/drivers/video/chipsfb.c
Previous file: linux/drivers/video/aty128fb.c
Back to the patch index
Back to the overall index
- Lines: 527
- Date:
Tue Jun 20 14:14:51 2000
- Orig file:
v2.4.0-test1/linux/drivers/video/atyfb.c
- Orig date:
Tue Apr 11 15:09:21 2000
diff -u --recursive --new-file v2.4.0-test1/linux/drivers/video/atyfb.c linux/drivers/video/atyfb.c
@@ -1,4 +1,4 @@
-/* $Id: atyfb.c,v 1.141 2000/03/12 03:53:16 davem Exp $
+/* $Id: atyfb.c,v 1.142 2000/04/12 01:39:41 davem Exp $
* linux/drivers/video/atyfb.c -- Frame buffer device for ATI Mach64
*
* Copyright (C) 1997-1998 Geert Uytterhoeven
@@ -475,14 +475,20 @@
static int currcon = 0;
static struct fb_ops atyfb_ops = {
- atyfb_open, atyfb_release, atyfb_get_fix, atyfb_get_var, atyfb_set_var,
- atyfb_get_cmap, atyfb_set_cmap, atyfb_pan_display, atyfb_ioctl,
+ owner: THIS_MODULE,
+ fb_open: atyfb_open,
+ fb_release: atyfb_release,
+ fb_get_fix: atyfb_get_fix,
+ fb_get_var: atyfb_get_var,
+ fb_set_var: atyfb_set_var,
+ fb_get_cmap: atyfb_get_cmap,
+ fb_set_cmap: atyfb_set_cmap,
+ fb_pan_display: atyfb_pan_display,
+ fb_ioctl: atyfb_ioctl,
#ifdef __sparc__
- atyfb_mmap,
-#else
- NULL,
+ fb_mmap: atyfb_mmap,
#endif
- atyfb_rasterimg
+ fb_rasterimg: atyfb_rasterimg,
};
static char atyfb_name[16] = "ATY Mach64";
@@ -536,7 +542,7 @@
/* mach64CT family / mach64GT (3D RAGE) class */
{ 0x4c42, 0x4c42, "3D RAGE LT PRO (AGP)" },
{ 0x4c44, 0x4c44, "3D RAGE LT PRO" },
- { 0x4c47, 0x4c47, "3D RAGE LT PRO" },
+ { 0x4c47, 0x4c47, "3D RAGE LT-G" },
{ 0x4c49, 0x4c49, "3D RAGE LT PRO" },
{ 0x4c50, 0x4c50, "3D RAGE LT PRO" },
{ 0x4c54, 0x4c54, "3D RAGE LT" },
@@ -606,6 +612,27 @@
writeb (val, info->ati_regbase + regindex);
}
+static void aty_st_lcd(int index, u32 val, const struct fb_info_aty *info)
+{
+ unsigned long temp;
+
+ /* write addr byte */
+ temp = aty_ld_le32(LCD_INDEX, info);
+ aty_st_le32(LCD_INDEX, (temp & ~LCD_INDEX_MASK) | index, info);
+ /* write the register value */
+ aty_st_le32(LCD_DATA, val, info);
+}
+
+static u32 aty_ld_lcd(int index, const struct fb_info_aty *info)
+{
+ unsigned long temp;
+
+ /* write addr byte */
+ temp = aty_ld_le32(LCD_INDEX, info);
+ aty_st_le32(LCD_INDEX, (temp & ~LCD_INDEX_MASK) | index, info);
+ /* read the register value */
+ return aty_ld_le32(LCD_DATA, info);
+}
/*
* Generic Mach64 routines
@@ -1031,7 +1058,7 @@
static struct fb_info_aty *fb_list = NULL;
-static struct aty_cursor * __init
+static struct aty_cursor * __init
aty_init_cursor(struct fb_info_aty *fb)
{
struct aty_cursor *cursor;
@@ -1267,7 +1294,7 @@
gModeReg = 0;
devSetupRegA = 0;
-
+
switch (bpp) {
case 8:
gModeReg = 0x83;
@@ -1583,7 +1610,7 @@
/* Calculate the programming word */
MHz100 = 100000000 / period_in_ps;
-
+
program_bits = -1;
post_divider = 1;
@@ -1691,7 +1718,7 @@
udelay(50000); /* delay for 50 (15) ms */
aty_st_8(CLOCK_CNTL + info->clk_wr_offset,
((pll->locationAddr & 0x0F) | CLOCK_STROBE), info);
-
+
return;
}
@@ -1711,7 +1738,7 @@
mach64MinFreq = MIN_FREQ_2595;
mach64MaxFreq = MAX_FREQ_2595;
mach64RefFreq = REF_FREQ_2595; /* 14.32 MHz */
-
+
/* Calculate program word */
if (mhz100 == 0)
program_bits = 0xFF;
@@ -1843,7 +1870,7 @@
mach64MinFreq = MIN_FREQ_2595;
mach64MaxFreq = MAX_FREQ_2595;
mach64RefFreq = REF_FREQ_2595; /* 14.32 MHz */
-
+
/* Calculate program word */
if (mhz100 == 0)
program_bits = 0xE0;
@@ -1945,7 +1972,7 @@
mach64MinFreq = MIN_FREQ_2595;
mach64MaxFreq = MAX_FREQ_2595;
mach64RefFreq = REF_FREQ_2595; /* 14.32 MHz */
-
+
save_m = 0;
save_n = 0;
@@ -2359,7 +2386,7 @@
int accelmode;
int muxmode;
u8 tmp;
-
+
accelmode = par->accel_flags; /* hack */
info->current_par = *par;
@@ -2441,7 +2468,7 @@
break;
}
aty_st_le32(MEM_CNTL, i, info);
-
+
} else {
aty_set_pll_ct(info, &par->pll.ct);
i = aty_ld_le32(MEM_CNTL, info) & 0xf00fffff;
@@ -2618,7 +2645,6 @@
fb->consolecnt++;
}
#endif
- MOD_INC_USE_COUNT;
return(0);
}
@@ -2674,7 +2700,6 @@
fb->consolecnt--;
}
#endif
- MOD_DEC_USE_COUNT;
return(0);
}
@@ -2967,7 +2992,7 @@
#ifdef __sparc__
struct fbtype fbtyp;
struct display *disp;
-
+
if (con >= 0)
disp = &fb_display[con];
else
@@ -3080,7 +3105,7 @@
{
unsigned long j, align;
int max = -1;
-
+
map_offset = off + size;
for (i = 0; fb->mmap_map[i].size; i++) {
if (fb->mmap_map[i].voff < off)
@@ -3118,7 +3143,7 @@
}
}
}
-#endif
+#endif
/* Each page, see which map applies */
for (page = 0; page < size; ) {
@@ -3452,8 +3477,8 @@
if (default_mclk)
mclk = default_mclk;
- printk("%d%c %s, %s MHz XTAL, %d MHz PLL, %d Mhz MCLK\n",
- info->total_vram == 0x80000 ? 512 : (info->total_vram >> 20),
+ printk("%d%c %s, %s MHz XTAL, %d MHz PLL, %d Mhz MCLK\n",
+ info->total_vram == 0x80000 ? 512 : (info->total_vram >> 20),
info->total_vram == 0x80000 ? 'K' : 'M', ramname, xtal, pll, mclk);
if (mclk < 44)
@@ -3517,6 +3542,14 @@
info->fb_info.blank = &atyfbcon_blank;
info->fb_info.flags = FBINFO_FLAG_DEFAULT;
+#ifdef CONFIG_PPC
+ if (Gx == LI_CHIP_ID && machine_is_compatible("PowerBook1,1")) {
+ /* these bits let the 101 powerbook wake up from sleep -- paulus */
+ aty_st_lcd(LCD_POWER_MANAGEMENT, aty_ld_lcd(LCD_POWER_MANAGEMENT, info)
+ | (USE_F32KHZ | TRISTATE_MEM_EN), info);
+ }
+#endif /* CONFIG_PPC */
+
#ifdef MODULE
var = default_var;
#else /* !MODULE */
@@ -3539,13 +3572,16 @@
}
#endif
if (default_vmode == VMODE_CHOOSE) {
- if (Gx == LG_CHIP_ID)
+ if (Gx == LG_CHIP_ID || Gx == LI_CHIP_ID)
/* G3 PowerBook with 1024x768 LCD */
default_vmode = VMODE_1024_768_60;
- else {
- sense = read_aty_sense(info);
- default_vmode = mac_map_monitor_sense(sense);
- }
+ else if (machine_is_compatible("iMac"))
+ default_vmode = VMODE_1024_768_75;
+ else
+ default_vmode = VMODE_640_480_67;
+ sense = read_aty_sense(info);
+ printk(KERN_INFO "atyfb: monitor sense=%x, mode %d\n",
+ sense, mac_map_monitor_sense(sense));
}
if (default_vmode <= 0 || default_vmode > VMODE_MAX)
default_vmode = VMODE_640_480_60;
@@ -3608,7 +3644,7 @@
info->dispsw.set_font = atyfb_set_font;
}
}
-
+
atyfb_set_var(&var, -1, &info->fb_info);
if (register_framebuffer(&info->fb_info) < 0)
@@ -3653,7 +3689,7 @@
break;
if (i < 0)
continue;
-
+
info = kmalloc(sizeof(struct fb_info_aty), GFP_ATOMIC);
if (!info) {
printk("atyfb_init: can't alloc fb_info_aty\n");
@@ -3714,7 +3750,7 @@
io = (rp->flags & IORESOURCE_IO);
size = rp->end - base + 1;
-
+
pci_read_config_dword(pdev, breg, &pbase);
if (io)
@@ -4253,7 +4289,7 @@
if (Gx == GT_CHIP_ID || Gx == GU_CHIP_ID || Gx == GV_CHIP_ID ||
Gx == GW_CHIP_ID || Gx == GZ_CHIP_ID || Gx == LG_CHIP_ID ||
Gx == GB_CHIP_ID || Gx == GD_CHIP_ID || Gx == GI_CHIP_ID ||
- Gx == GP_CHIP_ID || Gx == GQ_CHIP_ID)
+ Gx == GP_CHIP_ID || Gx == GQ_CHIP_ID || Gx == LI_CHIP_ID)
i |= 0x2; /*DAC_CNTL|0x2 turns off the extra brightness for gt*/
aty_st_8(DAC_CNTL, i, info);
aty_st_8(DAC_MASK, 0xff, info);
@@ -4702,6 +4738,124 @@
#endif
#ifdef CONFIG_PMAC_PBOOK
+
+/* Power management routines. Those are used for PowerBook sleep.
+ *
+ * It appears that Rage LT and Rage LT Pro have different power
+ * management registers. There's is some confusion about which
+ * chipID is a Rage LT or LT pro :(
+ */
+static int
+aty_power_mgmt_LT(int sleep, struct fb_info_aty *info)
+{
+ unsigned int pm;
+ int timeout;
+
+ pm = aty_ld_le32(POWER_MANAGEMENT_LG, info);
+ pm = (pm & ~PWR_MGT_MODE_MASK) | PWR_MGT_MODE_REG;
+ aty_st_le32(POWER_MANAGEMENT_LG, pm, info);
+ pm = aty_ld_le32(POWER_MANAGEMENT_LG, info);
+
+ timeout = 200000;
+ if (sleep) {
+ /* Sleep */
+ pm &= ~PWR_MGT_ON;
+ aty_st_le32(POWER_MANAGEMENT_LG, pm, info);
+ pm = aty_ld_le32(POWER_MANAGEMENT_LG, info);
+ udelay(10);
+ pm &= ~(PWR_BLON | AUTO_PWR_UP);
+ pm |= SUSPEND_NOW;
+ aty_st_le32(POWER_MANAGEMENT_LG, pm, info);
+ pm = aty_ld_le32(POWER_MANAGEMENT_LG, info);
+ udelay(10);
+ pm |= PWR_MGT_ON;
+ aty_st_le32(POWER_MANAGEMENT_LG, pm, info);
+ do {
+ pm = aty_ld_le32(POWER_MANAGEMENT_LG, info);
+ udelay(10);
+ if ((--timeout) == 0)
+ break;
+ } while ((pm & PWR_MGT_STATUS_MASK) != PWR_MGT_STATUS_SUSPEND);
+ } else {
+ /* Wakeup */
+ pm &= ~PWR_MGT_ON;
+ aty_st_le32(POWER_MANAGEMENT_LG, pm, info);
+ pm = aty_ld_le32(POWER_MANAGEMENT_LG, info);
+ udelay(10);
+ pm |= (PWR_BLON | AUTO_PWR_UP);
+ pm &= ~SUSPEND_NOW;
+ aty_st_le32(POWER_MANAGEMENT_LG, pm, info);
+ pm = aty_ld_le32(POWER_MANAGEMENT_LG, info);
+ udelay(10);
+ pm |= PWR_MGT_ON;
+ aty_st_le32(POWER_MANAGEMENT_LG, pm, info);
+ do {
+ pm = aty_ld_le32(POWER_MANAGEMENT_LG, info);
+ udelay(10);
+ if ((--timeout) == 0)
+ break;
+ } while ((pm & PWR_MGT_STATUS_MASK) != 0);
+ }
+ mdelay(500);
+
+ return timeout ? PBOOK_SLEEP_OK : PBOOK_SLEEP_REFUSE;
+}
+
+static int
+aty_power_mgmt_LTPro(int sleep, struct fb_info_aty *info)
+{
+ unsigned int pm;
+ int timeout;
+
+ pm = aty_ld_lcd(LCD_POWER_MANAGEMENT, info);
+ pm = (pm & ~PWR_MGT_MODE_MASK) | PWR_MGT_MODE_REG;
+ aty_st_lcd(LCD_POWER_MANAGEMENT, pm, info);
+ pm = aty_ld_lcd(LCD_POWER_MANAGEMENT, info);
+
+ timeout = 200;
+ if (sleep) {
+ /* Sleep */
+ pm &= ~PWR_MGT_ON;
+ aty_st_lcd(LCD_POWER_MANAGEMENT, pm, info);
+ pm = aty_ld_lcd(LCD_POWER_MANAGEMENT, info);
+ udelay(10);
+ pm &= ~(PWR_BLON | AUTO_PWR_UP);
+ pm |= SUSPEND_NOW;
+ aty_st_lcd(LCD_POWER_MANAGEMENT, pm, info);
+ pm = aty_ld_lcd(LCD_POWER_MANAGEMENT, info);
+ udelay(10);
+ pm |= PWR_MGT_ON;
+ aty_st_lcd(LCD_POWER_MANAGEMENT, pm, info);
+ do {
+ pm = aty_ld_lcd(LCD_POWER_MANAGEMENT, info);
+ udelay(1000);
+ if ((--timeout) == 0)
+ break;
+ } while ((pm & PWR_MGT_STATUS_MASK) != PWR_MGT_STATUS_SUSPEND);
+ } else {
+ /* Wakeup */
+ pm &= ~PWR_MGT_ON;
+ aty_st_lcd(LCD_POWER_MANAGEMENT, pm, info);
+ pm = aty_ld_lcd(LCD_POWER_MANAGEMENT, info);
+ udelay(10);
+ pm &= ~SUSPEND_NOW;
+ pm |= (PWR_BLON | AUTO_PWR_UP);
+ aty_st_lcd(LCD_POWER_MANAGEMENT, pm, info);
+ pm = aty_ld_lcd(LCD_POWER_MANAGEMENT, info);
+ udelay(10);
+ pm |= PWR_MGT_ON;
+ aty_st_lcd(LCD_POWER_MANAGEMENT, pm, info);
+ do {
+ pm = aty_ld_lcd(LCD_POWER_MANAGEMENT, info);
+ udelay(1000);
+ if ((--timeout) == 0)
+ break;
+ } while ((pm & PWR_MGT_STATUS_MASK) != 0);
+ }
+
+ return timeout ? PBOOK_SLEEP_OK : PBOOK_SLEEP_REFUSE;
+}
+
/*
* Save the contents of the frame buffer when we go to sleep,
* and restore it when we wake up again.
@@ -4710,86 +4864,71 @@
aty_sleep_notify(struct pmu_sleep_notifier *self, int when)
{
struct fb_info_aty *info;
- unsigned int pm;
-
+ int result;
+
+ result = PBOOK_SLEEP_OK;
+
for (info = first_display; info != NULL; info = info->next) {
struct fb_fix_screeninfo fix;
int nb;
-
+
atyfb_get_fix(&fix, fg_console, (struct fb_info *)info);
nb = fb_display[fg_console].var.yres * fix.line_length;
switch (when) {
+ case PBOOK_SLEEP_REQUEST:
+ info->save_framebuffer = vmalloc(nb);
+ if (info->save_framebuffer == NULL)
+ return PBOOK_SLEEP_REFUSE;
+ break;
+ case PBOOK_SLEEP_REJECT:
+ if (info->save_framebuffer) {
+ vfree(info->save_framebuffer);
+ info->save_framebuffer = 0;
+ }
+ break;
case PBOOK_SLEEP_NOW:
+ if (info->blitter_may_be_busy)
+ wait_for_idle(info);
/* Stop accel engine (stop bus mastering) */
if (info->current_par.accel_flags & FB_ACCELF_TEXT)
reset_engine(info);
-#if 1
+
/* Backup fb content */
- info->save_framebuffer = vmalloc(nb);
if (info->save_framebuffer)
- memcpy(info->save_framebuffer,
+ memcpy_fromio(info->save_framebuffer,
(void *)info->frame_buffer, nb);
-#endif
- /* Blank display and LCD */
- atyfbcon_blank(VESA_POWERDOWN+1, (struct fb_info *)info);
-
- /* Set chip to "suspend" mode. Note: There's an HW bug in the
- chip which prevents proper resync on wakeup with automatic
- power management, we handle suspend manually using the
- following (weird) sequence described by ATI. Note2:
- We could enable this for all Rage LT Pro chip ids */
- if ((Gx == LG_CHIP_ID) || (Gx == LT_CHIP_ID) || (Gx == LP_CHIP_ID)) {
- pm = aty_ld_le32(POWER_MANAGEMENT, info);
- pm &= ~PWR_MGT_ON;
- aty_st_le32(POWER_MANAGEMENT, pm, info);
- pm = aty_ld_le32(POWER_MANAGEMENT, info);
- pm &= ~(PWR_BLON | AUTO_PWR_UP);
- pm |= SUSPEND_NOW;
- aty_st_le32(POWER_MANAGEMENT, pm, info);
- pm = aty_ld_le32(POWER_MANAGEMENT, info);
- pm |= PWR_MGT_ON;
- aty_st_le32(POWER_MANAGEMENT, pm, info);
- do {
- pm = aty_ld_le32(POWER_MANAGEMENT, info);
- } while ((pm & PWR_MGT_STATUS_MASK) != PWR_MGT_STATUS_SUSPEND);
- mdelay(500);
- }
+
+ /* Blank display and LCD */
+ atyfbcon_blank(VESA_POWERDOWN+1, (struct fb_info *)info);
+
+ /* Set chip to "suspend" mode */
+ if (Gx == LG_CHIP_ID)
+ result = aty_power_mgmt_LT(1, info);
+ else
+ result = aty_power_mgmt_LTPro(1, info);
break;
case PBOOK_WAKE:
/* Wakeup chip */
- if ((Gx == LG_CHIP_ID) || (Gx == LT_CHIP_ID) || (Gx == LP_CHIP_ID)) {
- pm = aty_ld_le32(POWER_MANAGEMENT, info);
- pm &= ~PWR_MGT_ON;
- aty_st_le32(POWER_MANAGEMENT, pm, info);
- pm = aty_ld_le32(POWER_MANAGEMENT, info);
- pm |= (PWR_BLON | AUTO_PWR_UP);
- pm &= ~SUSPEND_NOW;
- aty_st_le32(POWER_MANAGEMENT, pm, info);
- pm = aty_ld_le32(POWER_MANAGEMENT, info);
- pm |= PWR_MGT_ON;
- aty_st_le32(POWER_MANAGEMENT, pm, info);
- do {
- pm = aty_ld_le32(POWER_MANAGEMENT, info);
- } while ((pm & PWR_MGT_STATUS_MASK) != 0);
- mdelay(500);
- }
-#if 1
+ if (Gx == LG_CHIP_ID)
+ result = aty_power_mgmt_LT(0, info);
+ else
+ result = aty_power_mgmt_LTPro(0, info);
+
/* Restore fb content */
if (info->save_framebuffer) {
- memcpy((void *)info->frame_buffer,
+ memcpy_toio((void *)info->frame_buffer,
info->save_framebuffer, nb);
vfree(info->save_framebuffer);
info->save_framebuffer = 0;
}
-#endif
- /* Restore display */
+ /* Restore display */
atyfb_set_par(&info->current_par, info);
atyfbcon_blank(0, (struct fb_info *)info);
break;
}
}
- return PBOOK_SLEEP_OK;
+ return result;
}
#endif /* CONFIG_PMAC_PBOOK */
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)