patch-2.4.18 linux/drivers/video/radeonfb.c
Next file: linux/drivers/video/riva/fbdev.c
Previous file: linux/drivers/video/radeon.h
Back to the patch index
Back to the overall index
- Lines: 1404
- Date:
Wed Feb 13 17:38:14 2002
- Orig file:
linux.orig/drivers/video/radeonfb.c
- Orig date:
Mon Feb 18 20:18:40 2002
diff -Naur -X /home/marcelo/lib/dontdiff linux.orig/drivers/video/radeonfb.c linux/drivers/video/radeonfb.c
@@ -15,13 +15,17 @@
* blanking, pan_display, and cmap fixes, 0.1.0
* 2001-10-10 Radeon 7500 and 8500 support, and experimental
* flat panel support, 0.1.1
+ * 2001-11-17 Radeon M6 (ppc) support, Daniel Berlin, 0.1.2
+ * 2001-11-18 DFP fixes, Kevin Hendricks, 0.1.3
+ * 2001-11-29 more cmap, backlight fixes, Benjamin Herrenschmidt
+ * 2002-01-18 DFP panel detection via BIOS, Michael Clark, 0.1.4
*
* Special thanks to ATI DevRel team for their hardware donations.
*
*/
-#define RADEON_VERSION "0.1.1"
+#define RADEON_VERSION "0.1.4"
#include <linux/config.h>
@@ -39,12 +43,33 @@
#include <linux/ioport.h>
#include <linux/init.h>
#include <linux/pci.h>
+#include <linux/vmalloc.h>
#include <asm/io.h>
#if defined(__powerpc__)
#include <asm/prom.h>
+#include <asm/pci-bridge.h>
+#include <video/macmodes.h>
+
+#ifdef CONFIG_NVRAM
+#include <linux/nvram.h>
+#endif
+
+#ifdef CONFIG_PMAC_BACKLIGHT
+#include <asm/backlight.h>
+#endif
+
+#ifdef CONFIG_BOOTX_TEXT
+#include <asm/btext.h>
#endif
+#ifdef CONFIG_ADB_PMU
+#include <linux/adb.h>
+#include <linux/pmu.h>
+#endif
+
+#endif /* __powerpc__ */
+
#include <video/fbcon.h>
#include <video/fbcon-cfb8.h>
#include <video/fbcon-cfb16.h>
@@ -65,17 +90,17 @@
enum radeon_chips {
- RADEON_QD,
- RADEON_QE,
- RADEON_QF,
- RADEON_QG,
- RADEON_QY,
- RADEON_QZ,
- RADEON_QL,
- RADEON_QW,
- RADEON_LW,
- RADEON_LY,
- RADEON_LZ
+ RADEON_QD, /* Radeon R100 */
+ RADEON_QE, /* Radeon R100 */
+ RADEON_QF, /* Radeon R100 */
+ RADEON_QG, /* Radeon R100 */
+ RADEON_QY, /* Radeon RV100 (VE) */
+ RADEON_QZ, /* Radeon RV100 (VE) */
+ RADEON_QL, /* Radeon R200 (8500) */
+ RADEON_QW, /* Radeon RV200 (7500) */
+ RADEON_LW, /* Radeon Mobility M7 */
+ RADEON_LY, /* Radeon Mobility M6 */
+ RADEON_LZ /* Radeon Mobility M6 */
};
@@ -192,7 +217,6 @@
u32 flags;
u32 pix_clock;
int xres, yres;
- int bpp;
/* DDA regs */
u32 dda_config;
@@ -214,6 +238,7 @@
u32 lvds_gen_cntl;
u32 lvds_pll_cntl;
u32 tmds_crc;
+ u32 tmds_transmitter_cntl;
#if defined(__BIG_ENDIAN)
u32 surface_cntl;
@@ -238,6 +263,9 @@
struct pci_dev *pdev;
+ unsigned char *EDID;
+ unsigned char *bios_seg;
+
struct display disp;
int currcon;
struct display *currcon_display;
@@ -250,13 +278,19 @@
int pitch, bpp, depth;
int xres, yres, pixclock;
+ int use_default_var;
+ int got_dfpinfo;
+
int hasCRTC2;
int crtDisp_type;
int dviDisp_type;
int panel_xres, panel_yres;
+ int clock;
int hOver_plus, hSync_width, hblank;
int vOver_plus, vSync_width, vblank;
+ int hAct_high, vAct_high, interlaced;
+ int synct, misc;
u32 dp_gui_master_cntl;
@@ -281,6 +315,13 @@
#endif
} con_cmap;
#endif
+
+#ifdef CONFIG_PMAC_PBOOK
+ unsigned char *save_framebuffer;
+ int pm_reg;
+#endif
+
+ struct radeonfb_info *next;
};
@@ -433,6 +474,14 @@
}
+static inline int var_to_depth(const struct fb_var_screeninfo *var)
+{
+ if (var->bits_per_pixel != 16)
+ return var->bits_per_pixel;
+ return (var->green.length == 6) ? 16 : 15;
+}
+
+
static void _radeon_engine_reset(struct radeonfb_info *rinfo)
{
u32 clock_cntl_index, mclk_cntl, rbbm_soft_reset;
@@ -546,7 +595,9 @@
static char fontname[40] __initdata;
static char *mode_option __initdata;
static char noaccel __initdata = 0;
-static char panel_yres __initdata = 0;
+static int panel_yres __initdata = 0;
+static char force_dfp __initdata = 0;
+static struct radeonfb_info *board_list = NULL;
#ifdef FBCON_HAS_CFB8
static struct display_switch fbcon_radeon8;
@@ -598,11 +649,31 @@
static void radeon_get_pllinfo(struct radeonfb_info *rinfo, char *bios_seg);
static void radeon_get_moninfo (struct radeonfb_info *rinfo);
static int radeon_get_dfpinfo (struct radeonfb_info *rinfo);
-static int radeon_read_OF (struct radeonfb_info *rinfo);
+static int radeon_get_dfpinfo_BIOS(struct radeonfb_info *rinfo);
+static void radeon_get_EDID(struct radeonfb_info *rinfo);
+static int radeon_dfp_parse_EDID(struct radeonfb_info *rinfo);
+static void radeon_update_default_var(struct radeonfb_info *rinfo);
-#if defined(__powerpc__)
+
+#ifdef CONFIG_ALL_PPC
+static int radeon_read_OF (struct radeonfb_info *rinfo);
+static int radeon_get_EDID_OF(struct radeonfb_info *rinfo);
extern struct device_node *pci_device_to_OF_node(struct pci_dev *dev);
-#endif
+
+#ifdef CONFIG_PMAC_PBOOK
+int radeon_sleep_notify(struct pmu_sleep_notifier *self, int when);
+static struct pmu_sleep_notifier radeon_sleep_notifier = {
+ radeon_sleep_notify, SLEEP_LEVEL_VIDEO,
+};
+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_PBOOK */
+
+#endif /* CONFIG_ALL_PPC */
static struct fb_ops radeon_fb_ops = {
fb_get_fix: radeonfb_get_fix,
@@ -656,6 +727,8 @@
memcpy(fontname, this_opt + 5, i);
} else if (!strncmp(this_opt, "noaccel", 7)) {
noaccel = 1;
+ } else if (!strncmp(this_opt, "dfp", 3)) {
+ force_dfp = 1;
} else if (!strncmp(this_opt, "panel_yres:", 11)) {
panel_yres = simple_strtoul((this_opt+11), NULL, 0);
} else
@@ -681,7 +754,6 @@
struct radeonfb_info *rinfo;
u32 tmp;
int i, j;
- char *bios_seg = NULL;
RTRACE("radeonfb_pci_register BEGIN\n");
@@ -840,12 +912,28 @@
break;
}
- bios_seg = radeon_find_rom(rinfo);
- radeon_get_pllinfo(rinfo, bios_seg);
+ rinfo->bios_seg = radeon_find_rom(rinfo);
+ radeon_get_pllinfo(rinfo, rinfo->bios_seg);
RTRACE("radeonfb: probed %s %dk videoram\n", (rinfo->ram_type), (rinfo->video_ram/1024));
+#if !defined(__powerpc__)
radeon_get_moninfo(rinfo);
+#else
+ switch (pdev->device) {
+ case PCI_DEVICE_ID_RADEON_LW:
+ case PCI_DEVICE_ID_RADEON_LY:
+ case PCI_DEVICE_ID_RADEON_LZ:
+ rinfo->dviDisp_type = MT_LCD;
+ break;
+ default:
+ radeon_get_moninfo(rinfo);
+ break;
+ }
+#endif
+
+ radeon_get_EDID(rinfo);
+
if ((rinfo->dviDisp_type == MT_DFP) || (rinfo->dviDisp_type == MT_LCD) ||
(rinfo->crtDisp_type == MT_DFP)) {
if (!radeon_get_dfpinfo(rinfo)) {
@@ -875,6 +963,9 @@
/* XXX turn off accel for now, blts aren't working right */
noaccel = 1;
+ /* currcon not yet configured, will be set by first switch */
+ rinfo->currcon = -1;
+
/* set all the vital stuff */
radeon_set_fbinfo (rinfo);
@@ -892,6 +983,8 @@
}
pci_set_drvdata(pdev, rinfo);
+ rinfo->next = board_list;
+ board_list = rinfo;
if (register_framebuffer ((struct fb_info *) rinfo) < 0) {
printk ("radeonfb: could not register framebuffer\n");
@@ -910,6 +1003,19 @@
radeon_engine_init (rinfo);
}
+#ifdef CONFIG_PMAC_BACKLIGHT
+ if (rinfo->dviDisp_type == MT_LCD)
+ register_backlight_controller(&radeon_backlight_controller,
+ rinfo, "ati");
+#endif
+
+#ifdef CONFIG_PMAC_PBOOK
+ if (rinfo->dviDisp_type == MT_LCD) {
+ rinfo->pm_reg = pci_find_capability(pdev, PCI_CAP_ID_PM);
+ pmu_register_sleep_notifier(&radeon_sleep_notifier);
+ }
+#endif
+
printk ("radeonfb: ATI %s %s %d MB\n", rinfo->name, rinfo->ram_type,
(rinfo->video_ram/(1024*1024)));
@@ -1054,7 +1160,7 @@
printk("radeonfb: ref_clk=%d, ref_div=%d, xclk=%d from BIOS\n",
rinfo->pll.ref_clk, rinfo->pll.ref_div, rinfo->pll.xclk);
} else {
-#if defined(__powerpc__)
+#ifdef CONFIG_ALL_PPC
if (radeon_read_OF(rinfo)) {
unsigned int tmp, Nx, M, ref_div, xclk;
@@ -1116,6 +1222,11 @@
{
unsigned int tmp;
+ if (force_dfp) {
+ rinfo->dviDisp_type = MT_DFP;
+ return;
+ }
+
tmp = INREG(RADEON_BIOS_4_SCRATCH);
if (rinfo->hasCRTC2) {
@@ -1155,74 +1266,251 @@
}
-static int radeon_get_dfpinfo (struct radeonfb_info *rinfo)
+
+static void radeon_get_EDID(struct radeonfb_info *rinfo)
{
- unsigned int tmp;
- unsigned short a, b;
+#ifdef CONFIG_ALL_PPC
+ if (!radeon_get_EDID_OF(rinfo))
+ RTRACE("radeonfb: could not retrieve EDID from OF\n");
+#else
+ /* XXX use other methods later */
+#endif
+}
- if (panel_yres) {
- rinfo->panel_yres = panel_yres;
- } else {
- tmp = INREG(FP_VERT_STRETCH);
- tmp &= 0x00fff000;
- rinfo->panel_yres = (unsigned short)(tmp >> 0x0c) + 1;
- }
- switch (rinfo->panel_yres) {
- case 480:
- rinfo->panel_xres = 640;
- break;
- case 600:
- rinfo->panel_xres = 800;
- break;
- case 786:
- rinfo->panel_xres = 1024;
- break;
- case 1024:
- rinfo->panel_xres = 1280;
- break;
- case 1050:
- rinfo->panel_xres = 1400;
- break;
- case 1200:
- rinfo->panel_xres = 1600;
- break;
- default:
- printk("radeonfb: Failed to detect DFP panel size\n");
- return 0;
+#ifdef CONFIG_ALL_PPC
+static int radeon_get_EDID_OF(struct radeonfb_info *rinfo)
+{
+ struct device_node *dp;
+ unsigned char *pedid = NULL;
+
+ dp = pci_device_to_OF_node(rinfo->pdev);
+ pedid = (unsigned char *) get_property(dp, "DFP,EDID", 0);
+ if (!pedid)
+ pedid = (unsigned char *) get_property(dp, "LCD,EDID", 0);
+ if (!pedid)
+ pedid = (unsigned char *) get_property(dp, "EDID", 0);
+
+ if (pedid) {
+ rinfo->EDID = pedid;
+ return 1;
+ } else
+ return 0;
+}
+#endif /* CONFIG_ALL_PPC */
+
+
+static int radeon_dfp_parse_EDID(struct radeonfb_info *rinfo)
+{
+ unsigned char *block = rinfo->EDID;
+
+ if (!block)
+ return 0;
+
+ /* jump to the detailed timing block section */
+ block += 54;
+
+ rinfo->clock = (block[0] + (block[1] << 8));
+ rinfo->panel_xres = (block[2] + ((block[4] & 0xf0) << 4));
+ rinfo->hblank = (block[3] + ((block[4] & 0x0f) << 8));
+ rinfo->panel_yres = (block[5] + ((block[7] & 0xf0) << 4));
+ rinfo->vblank = (block[6] + ((block[7] & 0x0f) << 8));
+ rinfo->hOver_plus = (block[8] + ((block[11] & 0xc0) << 2));
+ rinfo->hSync_width = (block[9] + ((block[11] & 0x30) << 4));
+ rinfo->vOver_plus = ((block[10] >> 4) + ((block[11] & 0x0c) << 2));
+ rinfo->vSync_width = ((block[10] & 0x0f) + ((block[11] & 0x03) << 4));
+ rinfo->interlaced = ((block[17] & 0x80) >> 7);
+ rinfo->synct = ((block[17] & 0x18) >> 3);
+ rinfo->misc = ((block[17] & 0x06) >> 1);
+ rinfo->hAct_high = rinfo->vAct_high = 0;
+ if (rinfo->synct == 3) {
+ if (rinfo->misc & 2)
+ rinfo->hAct_high = 1;
+ if (rinfo->misc & 1)
+ rinfo->vAct_high = 1;
}
- printk("radeonfb: detected DFP panel size: %dx%d\n",
+ printk("radeonfb: detected DFP panel size from EDID: %dx%d\n",
rinfo->panel_xres, rinfo->panel_yres);
- tmp = INREG(FP_CRTC_H_TOTAL_DISP);
- a = (tmp & FP_CRTC_H_TOTAL_MASK) + 4;
- b = (tmp & 0x01ff0000) >> FP_CRTC_H_DISP_SHIFT;
- rinfo->hblank = (a - b + 1) * 8;
-
- tmp = INREG(FP_H_SYNC_STRT_WID);
- rinfo->hOver_plus = (unsigned short) ((tmp & FP_H_SYNC_STRT_CHAR_MASK) >>
- FP_H_SYNC_STRT_CHAR_SHIFT) - b - 1;
- rinfo->hOver_plus *= 8;
- rinfo->hSync_width = (unsigned short) ((tmp & FP_H_SYNC_WID_MASK) >>
- FP_H_SYNC_WID_SHIFT);
- rinfo->hSync_width *= 8;
- tmp = INREG(FP_CRTC_V_TOTAL_DISP);
- a = (tmp & FP_CRTC_V_TOTAL_MASK) + 1;
- b = (tmp & FP_CRTC_V_DISP_MASK) >> FP_CRTC_V_DISP_SHIFT;
- rinfo->vblank = a - b /* + 24 */ ;
-
- tmp = INREG(FP_V_SYNC_STRT_WID);
- rinfo->vOver_plus = (unsigned short) (tmp & FP_V_SYNC_STRT_MASK)
- - b + 1;
- rinfo->vSync_width = (unsigned short) ((tmp & FP_V_SYNC_WID_MASK) >>
- FP_V_SYNC_WID_SHIFT);
+ rinfo->got_dfpinfo = 1;
return 1;
}
+static void radeon_update_default_var(struct radeonfb_info *rinfo)
+{
+ struct fb_var_screeninfo *var = &radeonfb_default_var;
+
+ var->xres = rinfo->panel_xres;
+ var->yres = rinfo->panel_yres;
+ var->xres_virtual = rinfo->panel_xres;
+ var->yres_virtual = rinfo->panel_yres;
+ var->xoffset = var->yoffset = 0;
+ var->bits_per_pixel = 8;
+ var->pixclock = 100000000 / rinfo->clock;
+ var->left_margin = (rinfo->hblank - rinfo->hOver_plus - rinfo->hSync_width);
+ var->right_margin = rinfo->hOver_plus;
+ var->upper_margin = (rinfo->vblank - rinfo->vOver_plus - rinfo->vSync_width);
+ var->lower_margin = rinfo->vOver_plus;
+ var->hsync_len = rinfo->hSync_width;
+ var->vsync_len = rinfo->vSync_width;
+ var->sync = 0;
+ if (rinfo->synct == 3) {
+ if (rinfo->hAct_high)
+ var->sync |= FB_SYNC_HOR_HIGH_ACT;
+ if (rinfo->vAct_high)
+ var->sync |= FB_SYNC_VERT_HIGH_ACT;
+ }
+
+ var->vmode = 0;
+ if (rinfo->interlaced)
+ var->vmode |= FB_VMODE_INTERLACED;
+
+ rinfo->use_default_var = 1;
+}
+
+
+static int radeon_get_dfpinfo_BIOS(struct radeonfb_info *rinfo)
+{
+ char *fpbiosstart, *tmp, *tmp0;
+ char stmp[30];
+ int i;
+
+ if (!rinfo->bios_seg)
+ return 0;
+
+ if (!(fpbiosstart = rinfo->bios_seg + readw(rinfo->bios_seg + 0x48))) {
+ printk("radeonfb: Failed to detect DFP panel info using BIOS\n");
+ return 0;
+ }
+
+ if (!(tmp = rinfo->bios_seg + readw(fpbiosstart + 0x40))) {
+ printk("radeonfb: Failed to detect DFP panel info using BIOS\n");
+ return 0;
+ }
+
+ for(i=0; i<24; i++)
+ stmp[i] = readb(tmp+i+1);
+ stmp[24] = 0;
+ printk("radeonfb: panel ID string: %s\n", stmp);
+ rinfo->panel_xres = readw(tmp + 25);
+ rinfo->panel_yres = readw(tmp + 27);
+ printk("radeonfb: detected DFP panel size from BIOS: %dx%d\n",
+ rinfo->panel_xres, rinfo->panel_yres);
+
+ for(i=0; i<20; i++) {
+ tmp0 = rinfo->bios_seg + readw(tmp+64+i*2);
+ if (tmp0 == 0)
+ break;
+ if ((readw(tmp0) == rinfo->panel_xres) &&
+ (readw(tmp0+2) == rinfo->panel_yres)) {
+ rinfo->hblank = (readw(tmp0+17) - readw(tmp0+19)) * 8;
+ rinfo->hOver_plus = ((readw(tmp0+21) - readw(tmp0+19) -1) * 8) & 0x7fff;
+ rinfo->hSync_width = readb(tmp0+23) * 8;
+ rinfo->vblank = readw(tmp0+24) - readw(tmp0+26);
+ rinfo->vOver_plus = (readw(tmp0+28) & 0x7ff) - readw(tmp0+26);
+ rinfo->vSync_width = (readw(tmp0+28) & 0xf800) >> 11;
+ rinfo->clock = readw(tmp0+9);
+
+ rinfo->got_dfpinfo = 1;
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+
+
+static int radeon_get_dfpinfo (struct radeonfb_info *rinfo)
+{
+ unsigned int tmp;
+ unsigned short a, b;
+
+ if (radeon_get_dfpinfo_BIOS(rinfo))
+ radeon_update_default_var(rinfo);
+
+ if (radeon_dfp_parse_EDID(rinfo))
+ radeon_update_default_var(rinfo);
+
+ if (!rinfo->got_dfpinfo) {
+ /*
+ * it seems all else has failed now and we
+ * resort to probing registers for our DFP info
+ */
+ if (panel_yres) {
+ rinfo->panel_yres = panel_yres;
+ } else {
+ tmp = INREG(FP_VERT_STRETCH);
+ tmp &= 0x00fff000;
+ rinfo->panel_yres = (unsigned short)(tmp >> 0x0c) + 1;
+ }
+
+ switch (rinfo->panel_yres) {
+ case 480:
+ rinfo->panel_xres = 640;
+ break;
+ case 600:
+ rinfo->panel_xres = 800;
+ break;
+ case 768:
#if defined(__powerpc__)
+ if (rinfo->dviDisp_type == MT_LCD)
+ rinfo->panel_xres = 1152;
+ else
+#endif
+ rinfo->panel_xres = 1024;
+ break;
+ case 1024:
+ rinfo->panel_xres = 1280;
+ break;
+ case 1050:
+ rinfo->panel_xres = 1400;
+ break;
+ case 1200:
+ rinfo->panel_xres = 1600;
+ break;
+ default:
+ printk("radeonfb: Failed to detect DFP panel size\n");
+ return 0;
+ }
+
+ printk("radeonfb: detected DFP panel size from registers: %dx%d\n",
+ rinfo->panel_xres, rinfo->panel_yres);
+
+ tmp = INREG(FP_CRTC_H_TOTAL_DISP);
+ a = (tmp & FP_CRTC_H_TOTAL_MASK) + 4;
+ b = (tmp & 0x01ff0000) >> FP_CRTC_H_DISP_SHIFT;
+ rinfo->hblank = (a - b + 1) * 8;
+
+ tmp = INREG(FP_H_SYNC_STRT_WID);
+ rinfo->hOver_plus = (unsigned short) ((tmp & FP_H_SYNC_STRT_CHAR_MASK) >>
+ FP_H_SYNC_STRT_CHAR_SHIFT) - b - 1;
+ rinfo->hOver_plus *= 8;
+ rinfo->hSync_width = (unsigned short) ((tmp & FP_H_SYNC_WID_MASK) >>
+ FP_H_SYNC_WID_SHIFT);
+ rinfo->hSync_width *= 8;
+ tmp = INREG(FP_CRTC_V_TOTAL_DISP);
+ a = (tmp & FP_CRTC_V_TOTAL_MASK) + 1;
+ b = (tmp & FP_CRTC_V_DISP_MASK) >> FP_CRTC_V_DISP_SHIFT;
+ rinfo->vblank = a - b /* + 24 */ ;
+
+ tmp = INREG(FP_V_SYNC_STRT_WID);
+ rinfo->vOver_plus = (unsigned short) (tmp & FP_V_SYNC_STRT_MASK)
+ - b + 1;
+ rinfo->vSync_width = (unsigned short) ((tmp & FP_V_SYNC_WID_MASK) >>
+ FP_V_SYNC_WID_SHIFT);
+
+ return 1;
+ }
+
+ return 1;
+}
+
+
+#ifdef CONFIG_ALL_PPC
static int radeon_read_OF (struct radeonfb_info *rinfo)
{
struct device_node *dp;
@@ -1255,7 +1543,7 @@
OUTREG(DSTCACHE_MODE, 0);
/* XXX */
- rinfo->pitch = ((rinfo->xres * (rinfo->depth / 8) + 0x3f)) >> 6;
+ rinfo->pitch = ((rinfo->xres * (rinfo->bpp / 8) + 0x3f)) >> 6;
radeon_fifo_wait (1);
temp = INREG(DEFAULT_PITCH_OFFSET);
@@ -1333,6 +1621,16 @@
disp = &rinfo->disp;
disp->var = radeonfb_default_var;
+#if defined(__powerpc__)
+ if (rinfo->dviDisp_type == MT_LCD) {
+ if (mac_vmode_to_var(VMODE_1152_768_60, CMODE_8, &disp->var))
+ disp->var = radeonfb_default_var;
+ }
+#endif
+
+ rinfo->depth = var_to_depth(&disp->var);
+ rinfo->bpp = disp->var.bits_per_pixel;
+
info->disp = disp;
radeon_set_dispsw (rinfo, disp);
@@ -1360,6 +1658,18 @@
NULL, 0, NULL, 8);
else
#endif
+#if defined(__powerpc__)
+ if (rinfo->dviDisp_type == MT_LCD) {
+ if (mac_vmode_to_var(VMODE_1152_768_60, CMODE_8, &rinfo->disp.var))
+ rinfo->disp.var = radeonfb_default_var;
+ }
+ else
+#endif
+ if (rinfo->use_default_var)
+ /* We will use the modified default far */
+ rinfo->disp.var = radeonfb_default_var;
+ else
+
fb_find_mode (&rinfo->disp.var, &rinfo->info, "640x480-8@60",
NULL, 0, NULL, 0);
@@ -1390,7 +1700,6 @@
disp->can_soft_blank = 1;
disp->inverse = 0;
- rinfo->depth = disp->var.bits_per_pixel;
switch (disp->var.bits_per_pixel) {
#ifdef FBCON_HAS_CFB8
case 8:
@@ -1443,7 +1752,7 @@
if (fb_display[con].cmap.len)
fb_set_cmap(&fb_display[con].cmap, 1, radeon_setcolreg, info);
else {
- int size = fb_display[con].var.bits_per_pixel == 8 ? 256 : 32;
+ int size = radeon_get_cmap_len(&fb_display[con].var);
fb_set_cmap(fb_default_cmap(size), 1, radeon_setcolreg, info);
}
}
@@ -1535,7 +1844,7 @@
fix->type_aux = disp->type_aux;
fix->visual = disp->visual;
- fix->xpanstep = 1;
+ fix->xpanstep = 8;
fix->ypanstep = 1;
fix->ywrapstep = 0;
@@ -1592,6 +1901,23 @@
memcpy (&v, var, sizeof (v));
switch (v.bits_per_pixel) {
+ case 0 ... 8:
+ v.bits_per_pixel = 8;
+ break;
+ case 9 ... 16:
+ v.bits_per_pixel = 16;
+ break;
+ case 17 ... 24:
+ v.bits_per_pixel = 24;
+ break;
+ case 25 ... 32:
+ v.bits_per_pixel = 32;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ switch (var_to_depth(&v)) {
#ifdef FBCON_HAS_CFB8
case 8:
nom = den = 1;
@@ -1604,6 +1930,17 @@
#endif
#ifdef FBCON_HAS_CFB16
+ case 15:
+ nom = 2;
+ den = 1;
+ disp->line_length = v.xres_virtual * 2;
+ disp->visual = FB_VISUAL_DIRECTCOLOR;
+ v.red.offset = 10;
+ v.green.offset = 5;
+ v.red.offset = 0;
+ v.red.length = v.green.length = v.blue.length = 5;
+ v.transp.offset = v.transp.length = 0;
+ break;
case 16:
nom = 2;
den = 1;
@@ -1785,7 +2122,7 @@
struct radeonfb_info *rinfo = (struct radeonfb_info *) info;
struct display *disp;
struct fb_cmap *cmap;
- int switchcon = 0;
+ int switchmode = 0;
disp = (con < 0) ? rinfo->info.disp : &fb_display[con];
@@ -1795,17 +2132,13 @@
fb_get_cmap (cmap, 1, radeon_getcolreg, info);
}
- if ((disp->var.xres != rinfo->xres) ||
- (disp->var.yres != rinfo->yres) ||
- (disp->var.pixclock != rinfo->pixclock) ||
- (disp->var.bits_per_pixel != rinfo->depth))
- switchcon = 1;
-
- if (switchcon) {
- rinfo->currcon = con;
- rinfo->currcon_display = disp;
- disp->var.activate = FB_ACTIVATE_NOW;
+ switchmode = (con != rinfo->currcon);
+
+ rinfo->currcon = con;
+ rinfo->currcon_display = disp;
+ disp->var.activate = FB_ACTIVATE_NOW;
+ if (switchmode) {
radeonfb_set_var (&disp->var, con, info);
radeon_set_dispsw (rinfo, disp);
do_install_cmap(con, info);
@@ -1837,11 +2170,20 @@
{
struct radeonfb_info *rinfo = (struct radeonfb_info *) info;
u32 val = INREG(CRTC_EXT_CNTL);
+ u32 val2 = INREG(LVDS_GEN_CNTL);
+
+#ifdef CONFIG_PMAC_BACKLIGHT
+ if (rinfo->dviDisp_type == MT_LCD && _machine == _MACH_Pmac) {
+ set_backlight_enable(!blank);
+ return;
+ }
+#endif
/* reset it */
val &= ~(CRTC_DISPLAY_DIS | CRTC_HSYNC_DIS |
CRTC_VSYNC_DIS);
-
+ val2 &= ~(LVDS_DISPLAY_DIS);
+
switch (blank) {
case VESA_NO_BLANKING:
break;
@@ -1854,25 +2196,33 @@
case VESA_POWERDOWN:
val |= (CRTC_DISPLAY_DIS | CRTC_VSYNC_DIS |
CRTC_HSYNC_DIS);
+ val2 |= (LVDS_DISPLAY_DIS);
break;
}
-
- OUTREG(CRTC_EXT_CNTL, val);
-}
+ switch (rinfo->dviDisp_type) {
+ case MT_LCD:
+ OUTREG(LVDS_GEN_CNTL, val2);
+ break;
+ case MT_CRT:
+ default:
+ OUTREG(CRTC_EXT_CNTL, val);
+ break;
+ }
+}
static int radeon_get_cmap_len (const struct fb_var_screeninfo *var)
{
- int rc = 16; /* reasonable default */
+ int rc = 256; /* reasonable default */
- switch (var->bits_per_pixel) {
- case 8:
- rc = 256;
- break;
- default:
+ switch (var_to_depth(var)) {
+ case 15:
rc = 32;
break;
+ case 16:
+ rc = 64;
+ break;
}
return rc;
@@ -1915,40 +2265,38 @@
rinfo->palette[regno].green = green;
rinfo->palette[regno].blue = blue;
- /* init gamma for hicolor */
- if ((rinfo->depth > 8) && (regno == 0)) {
- int i;
-
- for (i=0; i<255; i++) {
- OUTREG(PALETTE_INDEX, i);
- OUTREG(PALETTE_DATA, (i << 16) | (i << 8) | i);
- }
- }
-
/* default */
pindex = regno;
- /* XXX actually bpp, fixme */
- if (rinfo->depth == 16)
- pindex = regno * 8;
-
- if (rinfo->depth == 16) {
- OUTREG(PALETTE_INDEX, pindex/2);
- OUTREG(PALETTE_DATA, (rinfo->palette[regno/2].red << 16) |
- (green << 8) | (rinfo->palette[regno/2].blue));
- green = rinfo->palette[regno/2].green;
- }
-
- if ((rinfo->depth == 8) || (regno < 32)) {
- OUTREG(PALETTE_INDEX, pindex);
- OUTREG(PALETTE_DATA, (red << 16) | (green << 8) | blue);
- }
+ if (rinfo->bpp == 16) {
+ pindex = regno * 8;
+ if (rinfo->depth == 16 && regno > 63)
+ return 1;
+ if (rinfo->depth == 15 && regno > 31)
+ return 1;
-#if defined(FBCON_HAS_CFB16) || defined(FBCON_HAS_CFB32)
- if (regno < 32) {
+ /* For 565, the green component is mixed one order below */
+ if (rinfo->depth == 16) {
+ OUTREG(PALETTE_INDEX, pindex>>1);
+ OUTREG(PALETTE_DATA, (rinfo->palette[regno>>1].red << 16) |
+ (green << 8) | (rinfo->palette[regno>>1].blue));
+ green = rinfo->palette[regno<<1].green;
+ }
+ }
+
+ if (rinfo->depth != 16 || regno < 32) {
+ OUTREG(PALETTE_INDEX, pindex);
+ OUTREG(PALETTE_DATA, (red << 16) | (green << 8) | blue);
+ }
+
+ if (regno < 16) {
switch (rinfo->depth) {
#ifdef FBCON_HAS_CFB16
+ case 15:
+ rinfo->con_cmap.cfb16[regno] = (regno << 10) | (regno << 5) |
+ regno;
+ break;
case 16:
rinfo->con_cmap.cfb16[regno] = (regno << 11) | (regno << 5) |
regno;
@@ -1970,7 +2318,6 @@
#endif
}
}
-#endif
return 0;
}
@@ -2003,6 +2350,7 @@
save->lvds_gen_cntl = INREG(LVDS_GEN_CNTL);
save->lvds_pll_cntl = INREG(LVDS_PLL_CNTL);
save->tmds_crc = INREG(TMDS_CRC);
+ save->tmds_transmitter_cntl = INREG(TMDS_TRANSMITTER_CNTL);
}
@@ -2023,6 +2371,7 @@
int min_bits, format = 0;
int hsync_start, hsync_fudge, bytpp, hsync_wid, vsync_wid;
int primary_mon = PRIMARY_MONITOR(rinfo);
+ int depth = var_to_depth(mode);
rinfo->xres = mode->xres;
rinfo->yres = mode->yres;
@@ -2042,13 +2391,13 @@
if (rinfo->panel_yres < mode->yres)
rinfo->yres = mode->yres = rinfo->panel_yres;
- hTotal = mode->xres + rinfo->hblank + mode->left_margin;
- hSyncStart = mode->xres + rinfo->hOver_plus + mode->right_margin;
- hSyncEnd = hSyncStart + rinfo->hOver_plus + mode->hsync_len;
-
- vTotal = mode->yres + rinfo->vblank + mode->upper_margin;
- vSyncStart = mode->yres + rinfo->vOver_plus + mode->lower_margin;
- vSyncEnd = vSyncStart + rinfo->vSync_width + mode->vsync_len;
+ hTotal = mode->xres + rinfo->hblank;
+ hSyncStart = mode->xres + rinfo->hOver_plus;
+ hSyncEnd = hSyncStart + rinfo->hSync_width;
+
+ vTotal = mode->yres + rinfo->vblank;
+ vSyncStart = mode->yres + rinfo->vOver_plus;
+ vSyncEnd = vSyncStart + rinfo->vSync_width;
}
sync = mode->sync;
@@ -2066,7 +2415,7 @@
hsync_wid = 1;
else if (hsync_wid > 0x3f) /* max */
hsync_wid = 0x3f;
- vsync_wid = mode->vsync_len;
+
if (vsync_wid == 0)
vsync_wid = 1;
else if (vsync_wid > 0x1f) /* max */
@@ -2077,24 +2426,8 @@
cSync = mode->sync & FB_SYNC_COMP_HIGH_ACT ? (1 << 4) : 0;
- switch (mode->bits_per_pixel) {
- case 8:
- format = DST_8BPP;
- bytpp = 1;
- break;
- case 16:
- format = DST_16BPP;
- bytpp = 2;
- break;
- case 24:
- format = DST_24BPP;
- bytpp = 3;
- break;
- case 32:
- format = DST_32BPP;
- bytpp = 4;
- break;
- }
+ format = radeon_get_dstbpp(depth);
+ bytpp = mode->bits_per_pixel >> 3;
if ((primary_mon == MT_DFP) || (primary_mon == MT_LCD))
hsync_fudge = hsync_fudge_fp[format-1];
@@ -2118,7 +2451,7 @@
newmode.dac_cntl = /* INREG(DAC_CNTL) | */ DAC_MASK_ALL | DAC_VGA_ADR_EN |
DAC_8BIT_EN;
- newmode.crtc_h_total_disp = ((((hTotal / 8) - 1) & 0xffff) |
+ newmode.crtc_h_total_disp = ((((hTotal / 8) - 1) & 0x3ff) |
(((mode->xres / 8) - 1) << 16));
newmode.crtc_h_sync_strt_wid = ((hsync_start & 0x1fff) |
@@ -2158,6 +2491,7 @@
newmode.yres = mode->yres;
rinfo->bpp = mode->bits_per_pixel;
+ rinfo->depth = depth;
rinfo->hack_crtc_ext_cntl = newmode.crtc_ext_cntl;
rinfo->hack_crtc_v_sync_strt_wid = newmode.crtc_v_sync_strt_wid;
@@ -2234,50 +2568,38 @@
newmode.dda_on_off = (ron << 16) | roff;
if ((primary_mon == MT_DFP) || (primary_mon == MT_LCD)) {
- int hRatio, vRatio;
-
- if ((rinfo->panel_xres == 0) || (rinfo->panel_yres == 0)) {
- hRatio = vRatio = 1;
- } else {
- if (mode->xres > rinfo->panel_xres)
- mode->xres = rinfo->panel_xres;
- if (mode->yres > rinfo->panel_yres)
- mode->yres = rinfo->panel_yres;
-
- hRatio = mode->xres / rinfo->panel_xres;
- vRatio = mode->yres / rinfo->panel_yres;
- }
+ unsigned int hRatio, vRatio;
- if (hRatio == 1) {
- newmode.fp_horz_stretch =
- rinfo->init_state.fp_horz_stretch;
- newmode.fp_horz_stretch &= ~(HORZ_STRETCH_BLEND |
- HORZ_STRETCH_ENABLE);
- } else {
- newmode.fp_horz_stretch =
- ((((unsigned long)(hRatio * HORZ_STRETCH_RATIO_MAX +
- (int)0.5)) & HORZ_STRETCH_RATIO_MASK)) |
- (rinfo->init_state.fp_horz_stretch &
- (HORZ_PANEL_SIZE | HORZ_FP_LOOP_STRETCH |
- HORZ_AUTO_RATIO_INC));
+ if (mode->xres > rinfo->panel_xres)
+ mode->xres = rinfo->panel_xres;
+ if (mode->yres > rinfo->panel_yres)
+ mode->yres = rinfo->panel_yres;
+
+ newmode.fp_horz_stretch = (((rinfo->panel_xres / 8) - 1)
+ << HORZ_PANEL_SHIFT);
+ newmode.fp_vert_stretch = ((rinfo->panel_yres - 1)
+ << VERT_PANEL_SHIFT);
+
+ if (mode->xres != rinfo->panel_xres) {
+ hRatio = round_div(mode->xres * HORZ_STRETCH_RATIO_MAX,
+ rinfo->panel_xres);
+ newmode.fp_horz_stretch = (((((unsigned long)hRatio) & HORZ_STRETCH_RATIO_MASK)) |
+ (newmode.fp_horz_stretch &
+ (HORZ_PANEL_SIZE | HORZ_FP_LOOP_STRETCH |
+ HORZ_AUTO_RATIO_INC)));
newmode.fp_horz_stretch |= (HORZ_STRETCH_BLEND |
HORZ_STRETCH_ENABLE);
}
newmode.fp_horz_stretch &= ~HORZ_AUTO_RATIO;
- if (vRatio == 1) {
- newmode.fp_vert_stretch =
- rinfo->init_state.fp_vert_stretch;
- newmode.fp_vert_stretch &= ~(VERT_STRETCH_BLEND |
- VERT_STRETCH_ENABLE);
- } else {
- newmode.fp_vert_stretch =
- ((((unsigned long)(vRatio * VERT_STRETCH_RATIO_MAX +
- (int)0.5)) & VERT_STRETCH_RATIO_MASK)) |
- (rinfo->init_state.fp_vert_stretch &
- (VERT_PANEL_SIZE | VERT_STRETCH_RESERVED));
- newmode.fp_vert_stretch |= (VERT_STRETCH_BLEND |
- VERT_STRETCH_ENABLE);
+ if (mode->yres != rinfo->panel_yres) {
+ vRatio = round_div(mode->yres * VERT_STRETCH_RATIO_MAX,
+ rinfo->panel_yres);
+ newmode.fp_vert_stretch = (((((unsigned long)vRatio) & VERT_STRETCH_RATIO_MASK)) |
+ (newmode.fp_vert_stretch &
+ (VERT_PANEL_SIZE | VERT_STRETCH_RESERVED)));
+ newmode.fp_vert_stretch |= (VERT_STRETCH_BLEND |
+ VERT_STRETCH_ENABLE);
}
newmode.fp_vert_stretch &= ~VERT_AUTO_RATIO_EN;
@@ -2290,14 +2612,14 @@
FP_USE_SHADOW_EN |
FP_CRTC_USE_SHADOW_VEND |
FP_CRT_SYNC_ALT));
+
newmode.fp_gen_cntl |= (FP_CRTC_DONT_SHADOW_VPAR |
FP_CRTC_DONT_SHADOW_HEND);
newmode.lvds_gen_cntl = rinfo->init_state.lvds_gen_cntl;
newmode.lvds_pll_cntl = rinfo->init_state.lvds_pll_cntl;
newmode.tmds_crc = rinfo->init_state.tmds_crc;
-
- newmode.crtc_ext_cntl &= ~CRTC_CRT_ON;
+ newmode.tmds_transmitter_cntl = rinfo->init_state.tmds_transmitter_cntl;
if (primary_mon == MT_LCD) {
newmode.lvds_gen_cntl |= (LVDS_ON | LVDS_BLON);
@@ -2305,21 +2627,25 @@
} else {
/* DFP */
newmode.fp_gen_cntl |= (FP_FPON | FP_TMDS_EN);
+ newmode.tmds_transmitter_cntl = (TMDS_RAN_PAT_RST |
+ ICHCSEL) & ~(TMDS_PLLRST);
+ newmode.crtc_ext_cntl &= ~CRTC_CRT_ON;
}
- newmode.fp_crtc_h_total_disp =
- rinfo->init_state.fp_crtc_h_total_disp;
- newmode.fp_crtc_v_total_disp =
- rinfo->init_state.fp_crtc_v_total_disp;
- newmode.fp_h_sync_strt_wid =
- rinfo->init_state.fp_h_sync_strt_wid;
- newmode.fp_v_sync_strt_wid =
- rinfo->init_state.fp_v_sync_strt_wid;
+ newmode.fp_crtc_h_total_disp = newmode.crtc_h_total_disp;
+ newmode.fp_crtc_v_total_disp = newmode.crtc_v_total_disp;
+ newmode.fp_h_sync_strt_wid = newmode.crtc_h_sync_strt_wid;
+ newmode.fp_v_sync_strt_wid = newmode.crtc_v_sync_strt_wid;
}
/* do it! */
radeon_write_mode (rinfo, &newmode);
+#if defined(CONFIG_BOOTX_TEXT)
+ btext_update_display(rinfo->fb_base_phys, mode->xres, mode->yres,
+ rinfo->depth, rinfo->pitch*64);
+#endif
+
return;
}
@@ -2331,7 +2657,8 @@
int primary_mon = PRIMARY_MONITOR(rinfo);
/* blank screen */
- OUTREG8(CRTC_EXT_CNTL + 1, 4);
+ OUTREGP(CRTC_EXT_CNTL, CRTC_DISPLAY_DIS | CRTC_VSYNC_DIS | CRTC_HSYNC_DIS,
+ ~(CRTC_DISPLAY_DIS | CRTC_VSYNC_DIS | CRTC_HSYNC_DIS));
for (i=0; i<9; i++)
OUTREG(common_regs[i].reg, common_regs[i].val);
@@ -2347,16 +2674,6 @@
OUTREG(CRTC_OFFSET, 0);
OUTREG(CRTC_OFFSET_CNTL, 0);
OUTREG(CRTC_PITCH, mode->crtc_pitch);
-#if 1
- printk("CRTC_H_TOTAL_DISP = 0x%x, H_SYNC = 0x%x\n",
- mode->crtc_h_total_disp, mode->crtc_h_sync_strt_wid);
- printk("CRTC_V_TOTAL_DISP = 0x%x, V_SYNC = 0x%x\n",
- mode->crtc_v_total_disp, mode->crtc_v_sync_strt_wid);
- printk("PPLL_DIV_3 = 0x%x, PPLL_REF_DIV = 0x%x\n",
- mode->ppll_div_3, mode->ppll_ref_div);
- printk("DDA_CONFIG = 0x%x, DDA_ON_OFF = 0x%x\n",
- mode->dda_config, mode->dda_on_off);
-#endif
#if defined(__BIG_ENDIAN)
OUTREG(SURFACE_CNTL, mode->surface_cntl);
@@ -2396,27 +2713,31 @@
OUTREG(FP_CRTC_V_TOTAL_DISP, mode->fp_crtc_v_total_disp);
OUTREG(FP_H_SYNC_STRT_WID, mode->fp_h_sync_strt_wid);
OUTREG(FP_V_SYNC_STRT_WID, mode->fp_v_sync_strt_wid);
- OUTREG(TMDS_CRC, mode->tmds_crc);
OUTREG(FP_HORZ_STRETCH, mode->fp_horz_stretch);
OUTREG(FP_VERT_STRETCH, mode->fp_vert_stretch);
OUTREG(FP_GEN_CNTL, mode->fp_gen_cntl);
+ OUTREG(TMDS_CRC, mode->tmds_crc);
+ OUTREG(TMDS_TRANSMITTER_CNTL, mode->tmds_transmitter_cntl);
if (primary_mon == MT_LCD) {
unsigned int tmp = INREG(LVDS_GEN_CNTL);
+ mode->lvds_gen_cntl &= ~LVDS_STATE_MASK;
+ mode->lvds_gen_cntl |= (rinfo->init_state.lvds_gen_cntl & LVDS_STATE_MASK);
+
if ((tmp & (LVDS_ON | LVDS_BLON)) ==
- (mode->lvds_gen_cntl & (LVDS_ON | LVDS_BLON)))
- OUTREG(LVDS_GEN_CNTL, mode->lvds_gen_cntl);
- } else {
- /* DVI */
- if (mode->lvds_gen_cntl & (LVDS_ON | LVDS_BLON)) {
- udelay(1000);
+ (mode->lvds_gen_cntl & (LVDS_ON | LVDS_BLON))) {
OUTREG(LVDS_GEN_CNTL, mode->lvds_gen_cntl);
} else {
- OUTREG(LVDS_GEN_CNTL, mode->lvds_gen_cntl |
- LVDS_BLON);
- udelay(1000);
- OUTREG(LVDS_GEN_CNTL, mode->lvds_gen_cntl);
+ if (mode->lvds_gen_cntl & (LVDS_ON | LVDS_BLON)) {
+ udelay(1000);
+ OUTREG(LVDS_GEN_CNTL, mode->lvds_gen_cntl);
+ } else {
+ OUTREG(LVDS_GEN_CNTL, mode->lvds_gen_cntl |
+ LVDS_BLON);
+ udelay(1000);
+ OUTREG(LVDS_GEN_CNTL, mode->lvds_gen_cntl);
+ }
}
}
}
@@ -2428,6 +2749,204 @@
}
+#ifdef CONFIG_PMAC_BACKLIGHT
+
+static int backlight_conv[] = {
+ 0xff, 0xc0, 0xb5, 0xaa, 0x9f, 0x94, 0x89, 0x7e,
+ 0x73, 0x68, 0x5d, 0x52, 0x47, 0x3c, 0x31, 0x24
+};
+
+#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;
+ unsigned int lvds_gen_cntl = INREG(LVDS_GEN_CNTL);
+
+ lvds_gen_cntl |= (LVDS_BL_MOD_EN | LVDS_BLON);
+ if (on && (level > BACKLIGHT_OFF)) {
+ lvds_gen_cntl |= LVDS_DIGON;
+ if (!lvds_gen_cntl & LVDS_ON) {
+ lvds_gen_cntl &= ~LVDS_BLON;
+ OUTREG(LVDS_GEN_CNTL, lvds_gen_cntl);
+ (void)INREG(LVDS_GEN_CNTL);
+ mdelay(10);
+ lvds_gen_cntl |= LVDS_BLON;
+ OUTREG(LVDS_GEN_CNTL, lvds_gen_cntl);
+ }
+ lvds_gen_cntl &= ~LVDS_BL_MOD_LEVEL_MASK;
+ lvds_gen_cntl |= (backlight_conv[level] <<
+ LVDS_BL_MOD_LEVEL_SHIFT);
+ lvds_gen_cntl |= (LVDS_ON | LVDS_EN);
+ lvds_gen_cntl &= ~LVDS_DISPLAY_DIS;
+ } else {
+ lvds_gen_cntl &= ~LVDS_BL_MOD_LEVEL_MASK;
+ lvds_gen_cntl |= (backlight_conv[0] <<
+ LVDS_BL_MOD_LEVEL_SHIFT);
+ lvds_gen_cntl |= LVDS_DISPLAY_DIS;
+ OUTREG(LVDS_GEN_CNTL, lvds_gen_cntl);
+ udelay(10);
+ lvds_gen_cntl &= ~(LVDS_ON | LVDS_EN | LVDS_BLON | LVDS_DIGON);
+ }
+
+ OUTREG(LVDS_GEN_CNTL, lvds_gen_cntl);
+ 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 */
+
+
+#ifdef CONFIG_PMAC_PBOOK
+static void radeon_set_suspend(struct radeonfb_info *rinfo, int suspend)
+{
+ u16 pwr_cmd;
+
+ if (!rinfo->pm_reg)
+ return;
+
+ /* Set the chip into appropriate suspend mode (we use D2,
+ * D3 would require a compete re-initialization of the chip,
+ * including PCI config registers, clocks, AGP conf, ...)
+ */
+ if (suspend) {
+ /* Make sure CRTC2 is reset. Remove that the day
+ * we decide to actually use CRTC2 and replace it with
+ * real code for disabling the CRTC2 output during sleep.
+ */
+
+ pci_read_config_word(rinfo->pdev, rinfo->pm_reg+PCI_PM_CTRL,
+ &pwr_cmd);
+
+ /* Switch PCI power managment to D2 */
+ pci_write_config_word(rinfo->pdev, rinfo->pm_reg+PCI_PM_CTRL,
+ (pwr_cmd & ~PCI_PM_CTRL_STATE_MASK)
+ | 2);
+ pci_read_config_word(rinfo->pdev, rinfo->pm_reg+PCI_PM_CTRL,
+ &pwr_cmd);
+ } else {
+ /* Switch back PCI powermanagment to D0 */
+ mdelay(100);
+ pci_write_config_word(rinfo->pdev, rinfo->pm_reg+PCI_PM_CTRL, 0);
+ mdelay(100);
+ pci_read_config_word(rinfo->pdev, rinfo->pm_reg+PCI_PM_CTRL,
+ &pwr_cmd);
+ mdelay(100);
+ }
+}
+
+/*
+ * Save the contents of the framebuffer when we go to sleep,
+ * and restore it when we wake up again.
+ */
+
+int radeon_sleep_notify(struct pmu_sleep_notifier *self, int when)
+{
+ struct radeonfb_info *rinfo;
+
+ for (rinfo = board_list; rinfo != NULL; rinfo = rinfo->next) {
+ struct fb_fix_screeninfo fix;
+ int nb;
+
+ switch (rinfo->chipset) {
+ case PCI_DEVICE_ID_RADEON_LW:
+ case PCI_DEVICE_ID_RADEON_LY:
+ case PCI_DEVICE_ID_RADEON_LZ:
+ break;
+ default:
+ return PBOOK_SLEEP_REFUSE;
+ }
+
+ radeonfb_get_fix(&fix, fg_console, (struct fb_info *)rinfo);
+ nb = fb_display[fg_console].var.yres * fix.line_length;
+
+ switch (when) {
+ case PBOOK_SLEEP_REQUEST:
+#if 0
+ rinfo->save_framebuffer = vmalloc(nb);
+ if (rinfo->save_framebuffer == NULL)
+ return PBOOK_SLEEP_REFUSE;
+#endif
+ break;
+ case PBOOK_SLEEP_REJECT:
+#if 0
+ if (rinfo->save_framebuffer) {
+ vfree(rinfo->save_framebuffer);
+ rinfo->save_framebuffer = 0;
+ }
+#endif
+ break;
+ case PBOOK_SLEEP_NOW:
+ radeon_engine_idle();
+ radeon_engine_reset();
+ radeon_engine_idle();
+
+#if 0
+ /* Backup framebuffer content */
+ if (rinfo->save_framebuffer)
+ memcpy_fromio(rinfo->save_framebuffer,
+ (void *)rinfo->fb_base,
+ nb);
+#endif
+
+ /* Blank display and LCD */
+ radeonfb_blank(VESA_POWERDOWN+1,
+ (struct fb_info *)rinfo);
+
+ /* Sleep */
+ radeon_set_suspend(rinfo, 1);
+
+ break;
+ case PBOOK_WAKE:
+ /* Wakeup */
+ radeon_set_suspend(rinfo, 0);
+
+ radeon_engine_reset();
+ if (!noaccel) {
+ radeon_engine_init(rinfo);
+ radeon_engine_reset();
+ }
+
+#if 0
+ /* Restore framebuffer content */
+ if (rinfo->save_framebuffer) {
+ memcpy_toio((void *)rinfo->fb_base,
+ rinfo->save_framebuffer,
+ nb);
+ vfree(rinfo->save_framebuffer);
+ rinfo->save_framebuffer = 0;
+ }
+#endif
+
+ if (rinfo->currcon_display) {
+ radeonfb_set_var(&rinfo->currcon_display->var, rinfo->currcon,
+ (struct fb_info *) rinfo);
+ radeon_set_dispsw(rinfo, rinfo->currcon_display);
+ do_install_cmap(rinfo->currcon,
+ (struct fb_info *)rinfo);
+ }
+
+ radeonfb_blank(0, (struct fb_info *)rinfo);
+ break;
+ }
+ }
+
+ return PBOOK_SLEEP_OK;
+}
+
+#endif /* CONFIG_PMAC_PBOOK */
/*
* text console acceleration
@@ -2500,7 +3019,6 @@
OUTREG(DST_Y_X, (srcy << 16) | srcx);
OUTREG(DST_WIDTH_HEIGHT, (width << 16) | height);
}
-
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)