/*
- * drivers/video/radeonfb.c
+ * drivers/video/aty/radeon_base.c
+ *
* framebuffer driver for ATI Radeon chipset video boards
*
* Copyright 2003 Ben. Herrenschmidt <benh@kernel.crashing.org>
#include <linux/tty.h>
#include <linux/slab.h>
#include <linux/delay.h>
+#include <linux/time.h>
#include <linux/fb.h>
#include <linux/ioport.h>
#include <linux/init.h>
#include <linux/pci.h>
#include <linux/vmalloc.h>
#include <linux/device.h>
-#include <linux/i2c.h>
#include <asm/io.h>
#include <asm/uaccess.h>
#ifdef CONFIG_PPC_OF
-#include <asm/prom.h>
#include <asm/pci-bridge.h>
#include "../macmodes.h"
/* Radeon VE/7000 */
CHIP_DEF(PCI_CHIP_RV100_QY, RV100, CHIP_HAS_CRTC2),
CHIP_DEF(PCI_CHIP_RV100_QZ, RV100, CHIP_HAS_CRTC2),
+ CHIP_DEF(PCI_CHIP_RN50, RV100, CHIP_HAS_CRTC2),
/* Radeon IGP320M (U1) */
CHIP_DEF(PCI_CHIP_RS100_4336, RS100, CHIP_HAS_CRTC2 | CHIP_IS_IGP | CHIP_IS_MOBILITY),
/* Radeon IGP320 (A3) */
CHIP_DEF(PCI_CHIP_RV250_Ig, RV250, CHIP_HAS_CRTC2),
/* Mobility 9100 IGP (U3) */
CHIP_DEF(PCI_CHIP_RS300_5835, RS300, CHIP_HAS_CRTC2 | CHIP_IS_IGP | CHIP_IS_MOBILITY),
+ CHIP_DEF(PCI_CHIP_RS350_7835, RS300, CHIP_HAS_CRTC2 | CHIP_IS_IGP | CHIP_IS_MOBILITY),
/* 9100 IGP (A5) */
CHIP_DEF(PCI_CHIP_RS300_5834, RS300, CHIP_HAS_CRTC2 | CHIP_IS_IGP),
+ CHIP_DEF(PCI_CHIP_RS350_7834, RS300, CHIP_HAS_CRTC2 | CHIP_IS_IGP),
/* Mobility 9200 (M9+) */
CHIP_DEF(PCI_CHIP_RV280_5C61, RV280, CHIP_HAS_CRTC2 | CHIP_IS_MOBILITY),
CHIP_DEF(PCI_CHIP_RV280_5C63, RV280, CHIP_HAS_CRTC2 | CHIP_IS_MOBILITY),
CHIP_DEF(PCI_CHIP_R350_NI, R350, CHIP_HAS_CRTC2),
CHIP_DEF(PCI_CHIP_R360_NJ, R350, CHIP_HAS_CRTC2),
CHIP_DEF(PCI_CHIP_R350_NK, R350, CHIP_HAS_CRTC2),
+ /* Newer stuff */
+ CHIP_DEF(PCI_CHIP_RV380_3E50, RV380, CHIP_HAS_CRTC2),
+ CHIP_DEF(PCI_CHIP_RV380_3E54, RV380, CHIP_HAS_CRTC2),
+ CHIP_DEF(PCI_CHIP_RV380_3150, RV380, CHIP_HAS_CRTC2 | CHIP_IS_MOBILITY),
+ CHIP_DEF(PCI_CHIP_RV380_3154, RV380, CHIP_HAS_CRTC2 | CHIP_IS_MOBILITY),
+ CHIP_DEF(PCI_CHIP_RV370_5B60, RV380, CHIP_HAS_CRTC2),
+ CHIP_DEF(PCI_CHIP_RV370_5B62, RV380, CHIP_HAS_CRTC2),
+ CHIP_DEF(PCI_CHIP_RV370_5B64, RV380, CHIP_HAS_CRTC2),
+ CHIP_DEF(PCI_CHIP_RV370_5B65, RV380, CHIP_HAS_CRTC2),
+ CHIP_DEF(PCI_CHIP_RV370_5460, RV380, CHIP_HAS_CRTC2 | CHIP_IS_MOBILITY),
+ CHIP_DEF(PCI_CHIP_RV370_5464, RV380, CHIP_HAS_CRTC2 | CHIP_IS_MOBILITY),
+ CHIP_DEF(PCI_CHIP_R420_JH, R420, CHIP_HAS_CRTC2),
+ CHIP_DEF(PCI_CHIP_R420_JI, R420, CHIP_HAS_CRTC2),
+ CHIP_DEF(PCI_CHIP_R420_JJ, R420, CHIP_HAS_CRTC2),
+ CHIP_DEF(PCI_CHIP_R420_JK, R420, CHIP_HAS_CRTC2),
+ CHIP_DEF(PCI_CHIP_R420_JL, R420, CHIP_HAS_CRTC2),
+ CHIP_DEF(PCI_CHIP_R420_JM, R420, CHIP_HAS_CRTC2),
+ CHIP_DEF(PCI_CHIP_R420_JN, R420, CHIP_HAS_CRTC2 | CHIP_IS_MOBILITY),
+ CHIP_DEF(PCI_CHIP_R420_JP, R420, CHIP_HAS_CRTC2),
+ CHIP_DEF(PCI_CHIP_R423_UH, R420, CHIP_HAS_CRTC2),
+ CHIP_DEF(PCI_CHIP_R423_UI, R420, CHIP_HAS_CRTC2),
+ CHIP_DEF(PCI_CHIP_R423_UJ, R420, CHIP_HAS_CRTC2),
+ CHIP_DEF(PCI_CHIP_R423_UK, R420, CHIP_HAS_CRTC2),
+ CHIP_DEF(PCI_CHIP_R423_UQ, R420, CHIP_HAS_CRTC2),
+ CHIP_DEF(PCI_CHIP_R423_UR, R420, CHIP_HAS_CRTC2),
+ CHIP_DEF(PCI_CHIP_R423_UT, R420, CHIP_HAS_CRTC2),
+ CHIP_DEF(PCI_CHIP_R423_5D57, R420, CHIP_HAS_CRTC2),
/* Original Radeon/7200 */
CHIP_DEF(PCI_CHIP_RADEON_QD, RADEON, 0),
CHIP_DEF(PCI_CHIP_RADEON_QE, RADEON, 0),
static char *mode_option;
static char *monitor_layout;
static int noaccel = 0;
+static int default_dynclk = -2;
static int nomodeset = 0;
static int ignore_edid = 0;
static int mirror = 0;
static int nomtrr = 0;
#endif
-int radeonfb_noaccel = 0;
-
/*
* prototypes
*/
#endif /* CONFIG_PPC_OF */
-static void __devexit radeon_unmap_ROM(struct radeonfb_info *rinfo, struct pci_dev *dev)
+static void radeon_unmap_ROM(struct radeonfb_info *rinfo, struct pci_dev *dev)
{
- // leave it disabled and unassigned
- struct resource *r = &dev->resource[PCI_ROM_RESOURCE];
-
if (!rinfo->bios_seg)
return;
- iounmap(rinfo->bios_seg);
-
- /* Release the ROM resource if we used it in the first place */
- if (r->parent && r->flags & PCI_ROM_ADDRESS_ENABLE) {
- release_resource(r);
- r->flags &= ~PCI_ROM_ADDRESS_ENABLE;
- r->end -= r->start;
- r->start = 0;
- }
- /* This will disable and set address to unassigned */
- pci_write_config_dword(dev, dev->rom_base_reg, 0);
+ pci_unmap_rom(dev, rinfo->bios_seg);
}
static int __devinit radeon_map_ROM(struct radeonfb_info *rinfo, struct pci_dev *dev)
{
- void *rom;
- struct resource *r;
+ void __iomem *rom;
u16 dptr;
u8 rom_type;
+ size_t rom_size;
/* If this is a primary card, there is a shadow copy of the
* ROM somewhere in the first meg. We will just ignore the copy
OUTREG(MPP_TB_CONFIG, temp);
temp = INREG(MPP_TB_CONFIG);
- /* no need to search for the ROM, just ask the card where it is. */
- r = &dev->resource[PCI_ROM_RESOURCE];
-
- /* assign the ROM an address if it doesn't have one */
- if (r->parent == NULL)
- pci_assign_resource(dev, PCI_ROM_RESOURCE);
-
- /* enable if needed */
- if (!(r->flags & PCI_ROM_ADDRESS_ENABLE)) {
- pci_write_config_dword(dev, dev->rom_base_reg,
- r->start | PCI_ROM_ADDRESS_ENABLE);
- r->flags |= PCI_ROM_ADDRESS_ENABLE;
- }
-
- rom = ioremap(r->start, r->end - r->start + 1);
+ rom = pci_map_rom(dev, &rom_size);
if (!rom) {
- printk(KERN_ERR "radeonfb: ROM failed to map\n");
+ printk(KERN_ERR "radeonfb (%s): ROM failed to map\n",
+ pci_name(rinfo->pdev));
return -ENOMEM;
}
/* Very simple test to make sure it appeared */
if (BIOS_IN16(0) != 0xaa55) {
- printk(KERN_ERR "radeonfb: Invalid ROM signature %x should be 0xaa55\n",
- BIOS_IN16(0));
+ printk(KERN_DEBUG "radeonfb (%s): Invalid ROM signature %x "
+ "should be 0xaa55\n",
+ pci_name(rinfo->pdev), BIOS_IN16(0));
goto failed;
}
/* Look for the PCI data to check the ROM type */
* } pci_data_t;
*/
if (BIOS_IN32(dptr) != (('R' << 24) | ('I' << 16) | ('C' << 8) | 'P')) {
- printk(KERN_WARNING "radeonfb: PCI DATA signature in ROM incorrect: %08x\n",
- BIOS_IN32(dptr));
+ printk(KERN_WARNING "radeonfb (%s): PCI DATA signature in ROM"
+ "incorrect: %08x\n", pci_name(rinfo->pdev), BIOS_IN32(dptr));
goto anyway;
}
rom_type = BIOS_IN8(dptr + 0x14);
return -ENXIO;
}
-#ifdef __i386__
+#ifdef CONFIG_X86
static int __devinit radeon_find_mem_vbios(struct radeonfb_info *rinfo)
{
/* I simplified this code as we used to miss the signatures in
* if we end up having conflicts
*/
u32 segstart;
- unsigned char *rom_base = NULL;
+ void __iomem *rom_base = NULL;
for(segstart=0x000c0000; segstart<0x000f0000; segstart+=0x00001000) {
- rom_base = (char *)ioremap(segstart, 0x10000);
+ rom_base = ioremap(segstart, 0x10000);
if (rom_base == NULL)
return -ENOMEM;
- if ((*rom_base == 0x55) && (((*(rom_base + 1)) & 0xff) == 0xaa))
+ if (readb(rom_base) == 0x55 && readb(rom_base + 1) == 0xaa)
break;
iounmap(rom_base);
rom_base = NULL;
return 0;
}
-#endif /* __i386__ */
+#endif
#ifdef CONFIG_PPC_OF
/*
*/
static int __devinit radeon_read_xtal_OF (struct radeonfb_info *rinfo)
{
- struct device_node *dp;
+ struct device_node *dp = rinfo->of_node;
u32 *val;
- dp = pci_device_to_OF_node(rinfo->pdev);
- if (dp == NULL) {
- printk(KERN_WARNING "radeonfb: Cannot match card to OF node !\n");
+ if (dp == NULL)
return -ENODEV;
- }
- val = (u32 *) get_property(dp, "ATY,RefCLK", 0);
+ val = (u32 *) get_property(dp, "ATY,RefCLK", NULL);
if (!val || !*val) {
printk(KERN_WARNING "radeonfb: No ATY,RefCLK property !\n");
return -EINVAL;
rinfo->pll.ref_clk = (*val) / 10;
- val = (u32 *) get_property(dp, "ATY,SCLK", 0);
+ val = (u32 *) get_property(dp, "ATY,SCLK", NULL);
if (val && *val)
rinfo->pll.sclk = (*val) / 10;
- val = (u32 *) get_property(dp, "ATY,MCLK", 0);
+ val = (u32 *) get_property(dp, "ATY,MCLK", NULL);
if (val && *val)
rinfo->pll.mclk = (*val) / 10;
*/
/* Flush PCI buffers ? */
- tmp = INREG(DEVICE_ID);
+ tmp = INREG16(DEVICE_ID);
local_irq_disable();
denom = 1;
break;
case 1:
- n = ((INPLL(X_MPLL_REF_FB_DIV) >> 16) & 0xff);
- m = (INPLL(X_MPLL_REF_FB_DIV) & 0xff);
+ n = ((INPLL(M_SPLL_REF_FB_DIV) >> 16) & 0xff);
+ m = (INPLL(M_SPLL_REF_FB_DIV) & 0xff);
num = 2*n;
denom = 2*m;
break;
case 2:
- n = ((INPLL(X_MPLL_REF_FB_DIV) >> 8) & 0xff);
- m = (INPLL(X_MPLL_REF_FB_DIV) & 0xff);
+ n = ((INPLL(M_SPLL_REF_FB_DIV) >> 8) & 0xff);
+ m = (INPLL(M_SPLL_REF_FB_DIV) & 0xff);
num = 2*n;
denom = 2*m;
break;
}
- OUTREG8(CLOCK_CNTL_INDEX, 1);
- ppll_div_sel = INREG8(CLOCK_CNTL_DATA + 1) & 0x3;
+ ppll_div_sel = INREG8(CLOCK_CNTL_INDEX + 1) & 0x3;
+ radeon_pll_errata_after_index(rinfo);
n = (INPLL(PPLL_DIV_0 + ppll_div_sel) & 0x7ff);
m = (INPLL(PPLL_REF_DIV) & 0x3ff);
return -1;
}
- tmp = INPLL(X_MPLL_REF_FB_DIV);
+ tmp = INPLL(M_SPLL_REF_FB_DIV);
ref_div = INPLL(PPLL_REF_DIV) & 0x3ff;
Ns = (tmp & 0xff0000) >> 16;
}
/*
- * Retreive PLL infos by different means (BIOS, Open Firmware, register probing...)
+ * Retrieve PLL infos by different means (BIOS, Open Firmware, register probing...)
*/
static void __devinit radeon_get_pllinfo(struct radeonfb_info *rinfo)
{
-#ifdef CONFIG_PPC_OF
- /*
- * Retreive PLL infos from Open Firmware first
- */
- if (!force_measure_pll && radeon_read_xtal_OF(rinfo) == 0) {
- printk(KERN_INFO "radeonfb: Retreived PLL infos from Open Firmware\n");
- rinfo->pll.ref_div = INPLL(PPLL_REF_DIV) & 0x3ff;
- /* FIXME: Max clock may be higher on newer chips */
- rinfo->pll.ppll_min = 12000;
- rinfo->pll.ppll_max = 35000;
- goto found;
- }
-#endif /* CONFIG_PPC_OF */
-
/*
- * Check out if we have an X86 which gave us some PLL informations
- * and if yes, retreive them
- */
- if (!force_measure_pll && rinfo->bios_seg) {
- u16 pll_info_block = BIOS_IN16(rinfo->fp_bios_start + 0x30);
-
- rinfo->pll.sclk = BIOS_IN16(pll_info_block + 0x08);
- rinfo->pll.mclk = BIOS_IN16(pll_info_block + 0x0a);
- rinfo->pll.ref_clk = BIOS_IN16(pll_info_block + 0x0e);
- rinfo->pll.ref_div = BIOS_IN16(pll_info_block + 0x10);
- rinfo->pll.ppll_min = BIOS_IN32(pll_info_block + 0x12);
- rinfo->pll.ppll_max = BIOS_IN32(pll_info_block + 0x16);
-
- printk(KERN_INFO "radeonfb: Retreived PLL infos from BIOS\n");
- goto found;
- }
-
- /*
- * We didn't get PLL parameters from either OF or BIOS, we try to
- * probe them
- */
- if (radeon_probe_pll_params(rinfo) == 0) {
- printk(KERN_INFO "radeonfb: Retreived PLL infos from registers\n");
- /* FIXME: Max clock may be higher on newer chips */
- rinfo->pll.ppll_min = 12000;
- rinfo->pll.ppll_max = 35000;
- goto found;
- }
-
- /*
- * Neither of the above worked, we have a few default values, though
- * that's mostly incomplete
+ * In the case nothing works, these are defaults; they are mostly
+ * incomplete, however. It does provide ppll_max and _min values
+ * even for most other methods, however.
*/
switch (rinfo->chipset) {
case PCI_DEVICE_ID_ATI_RADEON_QW:
rinfo->pll.ref_clk = 2700;
break;
}
- rinfo->pll.ref_div = INPLL(PPLL_REF_DIV) & 0x3ff;
+ rinfo->pll.ref_div = INPLL(PPLL_REF_DIV) & PPLL_REF_DIV_MASK;
+
+#ifdef CONFIG_PPC_OF
+ /*
+ * Retrieve PLL infos from Open Firmware first
+ */
+ if (!force_measure_pll && radeon_read_xtal_OF(rinfo) == 0) {
+ printk(KERN_INFO "radeonfb: Retrieved PLL infos from Open Firmware\n");
+ goto found;
+ }
+#endif /* CONFIG_PPC_OF */
+
+ /*
+ * Check out if we have an X86 which gave us some PLL informations
+ * and if yes, retrieve them
+ */
+ if (!force_measure_pll && rinfo->bios_seg) {
+ u16 pll_info_block = BIOS_IN16(rinfo->fp_bios_start + 0x30);
+
+ rinfo->pll.sclk = BIOS_IN16(pll_info_block + 0x08);
+ rinfo->pll.mclk = BIOS_IN16(pll_info_block + 0x0a);
+ rinfo->pll.ref_clk = BIOS_IN16(pll_info_block + 0x0e);
+ rinfo->pll.ref_div = BIOS_IN16(pll_info_block + 0x10);
+ rinfo->pll.ppll_min = BIOS_IN32(pll_info_block + 0x12);
+ rinfo->pll.ppll_max = BIOS_IN32(pll_info_block + 0x16);
+
+ printk(KERN_INFO "radeonfb: Retrieved PLL infos from BIOS\n");
+ goto found;
+ }
+
+ /*
+ * We didn't get PLL parameters from either OF or BIOS, we try to
+ * probe them
+ */
+ if (radeon_probe_pll_params(rinfo) == 0) {
+ printk(KERN_INFO "radeonfb: Retrieved PLL infos from registers\n");
+ goto found;
+ }
+
+ /*
+ * Fall back to already-set defaults...
+ */
printk(KERN_INFO "radeonfb: Used default PLL infos\n");
found:
/*
- * Some methods fail to retreive SCLK and MCLK values, we apply default
+ * Some methods fail to retrieve SCLK and MCLK values, we apply default
* settings in this case (200Mhz). If that really happne often, we could
* fetch from registers instead...
*/
rinfo->pll.ref_div,
rinfo->pll.mclk / 100, rinfo->pll.mclk % 100,
rinfo->pll.sclk / 100, rinfo->pll.sclk % 100);
+ printk("radeonfb: PLL min %d max %d\n", rinfo->pll.ppll_min, rinfo->pll.ppll_max);
}
static int radeonfb_check_var (struct fb_var_screeninfo *var, struct fb_info *info)
/* XXX I'm adjusting xres_virtual to the pitch, that may help XFree
* with some panels, though I don't quite like this solution
*/
- if (radeon_accel_disabled()) {
+ if (rinfo->info->flags & FBINFO_HWACCEL_DISABLED) {
v.xres_virtual = v.xres_virtual & ~7ul;
- v.accel_flags = 0;
} else {
pitch = ((v.xres_virtual * ((v.bits_per_pixel + 1) / 8) + 0x3f)
& ~(0x3f)) >> 6;
if (rinfo->asleep)
return 0;
+ radeon_fifo_wait(2);
OUTREG(CRTC_OFFSET, ((var->yoffset * var->xres_virtual + var->xoffset)
* var->bits_per_pixel / 8) & ~7);
return 0;
}
-static int radeonfb_ioctl (struct inode *inode, struct file *file, unsigned int cmd,
- unsigned long arg, struct fb_info *info)
+static int radeonfb_ioctl (struct fb_info *info, unsigned int cmd,
+ unsigned long arg)
{
struct radeonfb_info *rinfo = info->par;
unsigned int tmp;
if (!rinfo->is_mobility)
return -EINVAL;
- rc = get_user(value, (__u32*)arg);
+ rc = get_user(value, (__u32 __user *)arg);
if (rc)
return rc;
+ radeon_fifo_wait(2);
if (value & 0x01) {
tmp = INREG(LVDS_GEN_CNTL);
OUTREG(CRTC_EXT_CNTL, tmp);
- break;
+ return 0;
case FBIO_RADEON_GET_MIRROR:
if (!rinfo->is_mobility)
return -EINVAL;
if (CRTC_CRT_ON & tmp)
value |= 0x02;
- return put_user(value, (__u32*)arg);
+ return put_user(value, (__u32 __user *)arg);
default:
return -EINVAL;
}
}
-static int radeon_screen_blank (struct radeonfb_info *rinfo, int blank)
+int radeon_screen_blank(struct radeonfb_info *rinfo, int blank, int mode_switch)
{
- u32 val = INREG(CRTC_EXT_CNTL);
- u32 val2 = 0;
+ u32 val;
+ u32 tmp_pix_clks;
+ int unblank = 0;
- if (rinfo->mon1_type == MT_LCD)
- val2 = INREG(LVDS_GEN_CNTL) & ~LVDS_DISPLAY_DIS;
-
- /* reset it */
+ if (rinfo->lock_blank)
+ return 0;
+
+ radeon_engine_idle();
+
+ val = INREG(CRTC_EXT_CNTL);
val &= ~(CRTC_DISPLAY_DIS | CRTC_HSYNC_DIS |
CRTC_VSYNC_DIS);
-
switch (blank) {
- case VESA_NO_BLANKING:
- break;
- case VESA_VSYNC_SUSPEND:
- val |= (CRTC_DISPLAY_DIS | CRTC_VSYNC_DIS);
- break;
- case VESA_HSYNC_SUSPEND:
- val |= (CRTC_DISPLAY_DIS | CRTC_HSYNC_DIS);
- break;
- case VESA_POWERDOWN:
- val |= (CRTC_DISPLAY_DIS | CRTC_VSYNC_DIS |
- CRTC_HSYNC_DIS);
- val2 |= (LVDS_DISPLAY_DIS);
- break;
+ case FB_BLANK_VSYNC_SUSPEND:
+ val |= (CRTC_DISPLAY_DIS | CRTC_VSYNC_DIS);
+ break;
+ case FB_BLANK_HSYNC_SUSPEND:
+ val |= (CRTC_DISPLAY_DIS | CRTC_HSYNC_DIS);
+ break;
+ case FB_BLANK_POWERDOWN:
+ val |= (CRTC_DISPLAY_DIS | CRTC_VSYNC_DIS |
+ CRTC_HSYNC_DIS);
+ break;
+ case FB_BLANK_NORMAL:
+ val |= CRTC_DISPLAY_DIS;
+ break;
+ case FB_BLANK_UNBLANK:
+ default:
+ unblank = 1;
}
+ OUTREG(CRTC_EXT_CNTL, val);
+
switch (rinfo->mon1_type) {
- case MT_LCD:
- OUTREG(LVDS_GEN_CNTL, val2);
- break;
- case MT_CRT:
- default:
- OUTREG(CRTC_EXT_CNTL, val);
- break;
+ case MT_DFP:
+ if (unblank)
+ OUTREGP(FP_GEN_CNTL, (FP_FPON | FP_TMDS_EN),
+ ~(FP_FPON | FP_TMDS_EN));
+ else {
+ if (mode_switch || blank == FB_BLANK_NORMAL)
+ break;
+ OUTREGP(FP_GEN_CNTL, 0, ~(FP_FPON | FP_TMDS_EN));
+ }
+ break;
+ case MT_LCD:
+ del_timer_sync(&rinfo->lvds_timer);
+ val = INREG(LVDS_GEN_CNTL);
+ if (unblank) {
+ u32 target_val = (val & ~LVDS_DISPLAY_DIS) | LVDS_BLON | LVDS_ON
+ | LVDS_EN | (rinfo->init_state.lvds_gen_cntl
+ & (LVDS_DIGON | LVDS_BL_MOD_EN));
+ if ((val ^ target_val) == LVDS_DISPLAY_DIS)
+ OUTREG(LVDS_GEN_CNTL, target_val);
+ else if ((val ^ target_val) != 0) {
+ OUTREG(LVDS_GEN_CNTL, target_val
+ & ~(LVDS_ON | LVDS_BL_MOD_EN));
+ rinfo->init_state.lvds_gen_cntl &= ~LVDS_STATE_MASK;
+ rinfo->init_state.lvds_gen_cntl |=
+ target_val & LVDS_STATE_MASK;
+ if (mode_switch) {
+ radeon_msleep(rinfo->panel_info.pwr_delay);
+ OUTREG(LVDS_GEN_CNTL, target_val);
+ }
+ else {
+ rinfo->pending_lvds_gen_cntl = target_val;
+ mod_timer(&rinfo->lvds_timer,
+ jiffies +
+ msecs_to_jiffies(rinfo->panel_info.pwr_delay));
+ }
+ }
+ } else {
+ val |= LVDS_DISPLAY_DIS;
+ OUTREG(LVDS_GEN_CNTL, val);
+
+ /* We don't do a full switch-off on a simple mode switch */
+ if (mode_switch || blank == FB_BLANK_NORMAL)
+ break;
+
+ /* Asic bug, when turning off LVDS_ON, we have to make sure
+ * RADEON_PIXCLK_LVDS_ALWAYS_ON bit is off
+ */
+ tmp_pix_clks = INPLL(PIXCLKS_CNTL);
+ if (rinfo->is_mobility || rinfo->is_IGP)
+ OUTPLLP(PIXCLKS_CNTL, 0, ~PIXCLK_LVDS_ALWAYS_ONb);
+ val &= ~(LVDS_BL_MOD_EN);
+ OUTREG(LVDS_GEN_CNTL, val);
+ udelay(100);
+ val &= ~(LVDS_ON | LVDS_EN);
+ OUTREG(LVDS_GEN_CNTL, val);
+ val &= ~LVDS_DIGON;
+ rinfo->pending_lvds_gen_cntl = val;
+ mod_timer(&rinfo->lvds_timer,
+ jiffies +
+ msecs_to_jiffies(rinfo->panel_info.pwr_delay));
+ rinfo->init_state.lvds_gen_cntl &= ~LVDS_STATE_MASK;
+ rinfo->init_state.lvds_gen_cntl |= val & LVDS_STATE_MASK;
+ if (rinfo->is_mobility || rinfo->is_IGP)
+ OUTPLL(PIXCLKS_CNTL, tmp_pix_clks);
+ }
+ break;
+ case MT_CRT:
+ // todo: powerdown DAC
+ default:
+ break;
}
- return 0;
+ /* let fbcon do a soft blank for us */
+ return (blank == FB_BLANK_NORMAL) ? -EINVAL : 0;
}
-int radeonfb_blank (int blank, struct fb_info *info)
+static int radeonfb_blank (int blank, struct fb_info *info)
{
struct radeonfb_info *rinfo = info->par;
if (rinfo->asleep)
return 0;
-#ifdef CONFIG_PMAC_BACKLIGHT
- if (rinfo->mon1_type == MT_LCD && _machine == _MACH_Pmac && blank)
- set_backlight_enable(0);
-#endif
-
- radeon_screen_blank(rinfo, blank);
-
-#ifdef CONFIG_PMAC_BACKLIGHT
- if (rinfo->mon1_type == MT_LCD && _machine == _MACH_Pmac && !blank)
- set_backlight_enable(1);
-#endif
-
- return 0;
+ return radeon_screen_blank(rinfo, blank, 0);
}
-static int radeonfb_setcolreg (unsigned regno, unsigned red, unsigned green,
- unsigned blue, unsigned transp, struct fb_info *info)
+static int radeon_setcolreg (unsigned regno, unsigned red, unsigned green,
+ unsigned blue, unsigned transp,
+ struct radeonfb_info *rinfo)
{
- struct radeonfb_info *rinfo = info->par;
u32 pindex;
unsigned int i;
-
+
+
if (regno > 255)
return 1;
pindex = regno;
if (!rinfo->asleep) {
- u32 dac_cntl2, vclk_cntl = 0;
-
- if (rinfo->is_mobility) {
- vclk_cntl = INPLL(VCLK_ECP_CNTL);
- OUTPLL(VCLK_ECP_CNTL, vclk_cntl & ~PIXCLK_DAC_ALWAYS_ONb);
- }
-
- /* Make sure we are on first palette */
- if (rinfo->has_CRTC2) {
- dac_cntl2 = INREG(DAC_CNTL2);
- dac_cntl2 &= ~DAC2_PALETTE_ACCESS_CNTL;
- OUTREG(DAC_CNTL2, dac_cntl2);
- }
+ radeon_fifo_wait(9);
if (rinfo->bpp == 16) {
pindex = regno * 8;
if (rinfo->depth == 15 && regno > 31)
return 1;
- /* For 565, the green component is mixed one order below */
+ /* 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));
+ 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);
+ OUTREG(PALETTE_DATA, (red << 16) |
+ (green << 8) | blue);
}
- if (rinfo->is_mobility)
- OUTPLL(VCLK_ECP_CNTL, vclk_cntl);
}
if (regno < 16) {
- u32 *pal = info->pseudo_palette;
+ u32 *pal = rinfo->info->pseudo_palette;
switch (rinfo->depth) {
case 15:
pal[regno] = (regno << 10) | (regno << 5) | regno;
return 0;
}
+static int radeonfb_setcolreg (unsigned regno, unsigned red, unsigned green,
+ unsigned blue, unsigned transp,
+ struct fb_info *info)
+{
+ struct radeonfb_info *rinfo = info->par;
+ u32 dac_cntl2, vclk_cntl = 0;
+ int rc;
+
+ if (!rinfo->asleep) {
+ if (rinfo->is_mobility) {
+ vclk_cntl = INPLL(VCLK_ECP_CNTL);
+ OUTPLL(VCLK_ECP_CNTL,
+ vclk_cntl & ~PIXCLK_DAC_ALWAYS_ONb);
+ }
+
+ /* Make sure we are on first palette */
+ if (rinfo->has_CRTC2) {
+ dac_cntl2 = INREG(DAC_CNTL2);
+ dac_cntl2 &= ~DAC2_PALETTE_ACCESS_CNTL;
+ OUTREG(DAC_CNTL2, dac_cntl2);
+ }
+ }
+
+ rc = radeon_setcolreg (regno, red, green, blue, transp, rinfo);
-static void radeon_save_state (struct radeonfb_info *rinfo, struct radeon_regs *save)
+ if (!rinfo->asleep && rinfo->is_mobility)
+ OUTPLL(VCLK_ECP_CNTL, vclk_cntl);
+
+ return rc;
+}
+
+static int radeonfb_setcmap(struct fb_cmap *cmap, struct fb_info *info)
+{
+ struct radeonfb_info *rinfo = info->par;
+ u16 *red, *green, *blue, *transp;
+ u32 dac_cntl2, vclk_cntl = 0;
+ int i, start, rc = 0;
+
+ if (!rinfo->asleep) {
+ if (rinfo->is_mobility) {
+ vclk_cntl = INPLL(VCLK_ECP_CNTL);
+ OUTPLL(VCLK_ECP_CNTL,
+ vclk_cntl & ~PIXCLK_DAC_ALWAYS_ONb);
+ }
+
+ /* Make sure we are on first palette */
+ if (rinfo->has_CRTC2) {
+ dac_cntl2 = INREG(DAC_CNTL2);
+ dac_cntl2 &= ~DAC2_PALETTE_ACCESS_CNTL;
+ OUTREG(DAC_CNTL2, dac_cntl2);
+ }
+ }
+
+ red = cmap->red;
+ green = cmap->green;
+ blue = cmap->blue;
+ transp = cmap->transp;
+ start = cmap->start;
+
+ for (i = 0; i < cmap->len; i++) {
+ u_int hred, hgreen, hblue, htransp = 0xffff;
+
+ hred = *red++;
+ hgreen = *green++;
+ hblue = *blue++;
+ if (transp)
+ htransp = *transp++;
+ rc = radeon_setcolreg (start++, hred, hgreen, hblue, htransp,
+ rinfo);
+ if (rc)
+ break;
+ }
+
+ if (!rinfo->asleep && rinfo->is_mobility)
+ OUTPLL(VCLK_ECP_CNTL, vclk_cntl);
+
+ return rc;
+}
+
+static void radeon_save_state (struct radeonfb_info *rinfo,
+ struct radeon_regs *save)
{
/* CRTC regs */
save->crtc_gen_cntl = INREG(CRTC_GEN_CNTL);
save->fp_vert_stretch = INREG(FP_VERT_STRETCH);
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);
+ save->tmds_crc = INREG(TMDS_CRC);
+ save->tmds_transmitter_cntl = INREG(TMDS_TRANSMITTER_CNTL);
save->vclk_ecp_cntl = INPLL(VCLK_ECP_CNTL);
+
+ /* PLL regs */
+ save->clk_cntl_index = INREG(CLOCK_CNTL_INDEX) & ~0x3f;
+ radeon_pll_errata_after_index(rinfo);
+ save->ppll_div_3 = INPLL(PPLL_DIV_3);
+ save->ppll_ref_div = INPLL(PPLL_REF_DIV);
}
{
int i;
+ radeon_fifo_wait(20);
+
/* Workaround from XFree */
if (rinfo->is_mobility) {
- /* A temporal workaround for the occational blanking on certain laptop panels.
- This appears to related to the PLL divider registers (fail to lock?).
- It occurs even when all dividers are the same with their old settings.
- In this case we really don't need to fiddle with PLL registers.
- By doing this we can avoid the blanking problem with some panels.
- */
+ /* A temporal workaround for the occational blanking on certain laptop
+ * panels. This appears to related to the PLL divider registers
+ * (fail to lock?). It occurs even when all dividers are the same
+ * with their old settings. In this case we really don't need to
+ * fiddle with PLL registers. By doing this we can avoid the blanking
+ * problem with some panels.
+ */
if ((mode->ppll_ref_div == (INPLL(PPLL_REF_DIV) & PPLL_REF_DIV_MASK)) &&
(mode->ppll_div_3 == (INPLL(PPLL_DIV_3) &
(PPLL_POST3_DIV_MASK | PPLL_FB3_DIV_MASK)))) {
- /* We still have to force a switch to PPLL div 3 thanks to
+ /* We still have to force a switch to selected PPLL div thanks to
* an XFree86 driver bug which will switch it away in some cases
* even when using UseFDev */
- OUTREGP(CLOCK_CNTL_INDEX, PPLL_DIV_SEL_MASK, ~PPLL_DIV_SEL_MASK);
+ OUTREGP(CLOCK_CNTL_INDEX,
+ mode->clk_cntl_index & PPLL_DIV_SEL_MASK,
+ ~PPLL_DIV_SEL_MASK);
+ radeon_pll_errata_after_index(rinfo);
+ radeon_pll_errata_after_data(rinfo);
return;
}
}
PPLL_RESET | PPLL_ATOMIC_UPDATE_EN | PPLL_VGA_ATOMIC_UPDATE_EN,
~(PPLL_RESET | PPLL_ATOMIC_UPDATE_EN | PPLL_VGA_ATOMIC_UPDATE_EN));
- /* Switch to PPLL div 3 */
- OUTREGP(CLOCK_CNTL_INDEX, PPLL_DIV_SEL_MASK, ~PPLL_DIV_SEL_MASK);
+ /* Switch to selected PPLL divider */
+ OUTREGP(CLOCK_CNTL_INDEX,
+ mode->clk_cntl_index & PPLL_DIV_SEL_MASK,
+ ~PPLL_DIV_SEL_MASK);
+ radeon_pll_errata_after_index(rinfo);
+ radeon_pll_errata_after_data(rinfo);
/* Set PPLL ref. div */
if (rinfo->family == CHIP_FAMILY_R300 ||
~(PPLL_RESET | PPLL_SLEEP | PPLL_ATOMIC_UPDATE_EN | PPLL_VGA_ATOMIC_UPDATE_EN));
/* We may want some locking ... oh well */
- msleep(5);
+ radeon_msleep(5);
/* Switch back VCLK source to PPLL */
OUTPLLP(VCLK_ECP_CNTL, VCLK_SRC_SEL_PPLLCLK, ~VCLK_SRC_SEL_MASK);
{
struct radeonfb_info *rinfo = (struct radeonfb_info *)data;
+ radeon_engine_idle();
+
OUTREG(LVDS_GEN_CNTL, rinfo->pending_lvds_gen_cntl);
- if (rinfo->pending_pixclks_cntl) {
- OUTPLL(PIXCLKS_CNTL, rinfo->pending_pixclks_cntl);
- rinfo->pending_pixclks_cntl = 0;
- }
}
/*
* Apply a video mode. This will apply the whole register set, including
* the PLL registers, to the card
*/
-static void radeon_write_mode (struct radeonfb_info *rinfo,
- struct radeon_regs *mode)
+void radeon_write_mode (struct radeonfb_info *rinfo, struct radeon_regs *mode,
+ int regs_only)
{
int i;
int primary_mon = PRIMARY_MONITOR(rinfo);
if (nomodeset)
return;
- del_timer_sync(&rinfo->lvds_timer);
-
- radeon_screen_blank(rinfo, VESA_POWERDOWN);
+ if (!regs_only)
+ radeon_screen_blank(rinfo, FB_BLANK_NORMAL, 0);
+ radeon_fifo_wait(31);
for (i=0; i<10; i++)
OUTREG(common_regs[i].reg, common_regs[i].val);
radeon_write_pll_regs(rinfo, mode);
if ((primary_mon == MT_DFP) || (primary_mon == MT_LCD)) {
+ radeon_fifo_wait(10);
OUTREG(FP_CRTC_H_TOTAL_DISP, mode->fp_crtc_h_total_disp);
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_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);
-
- /* HACK: The backlight control code may have modified init_state.lvds_gen_cntl,
- * so we update ourselves
- */
- 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 {
- rinfo->pending_pixclks_cntl = INPLL(PIXCLKS_CNTL);
- if (rinfo->is_mobility || rinfo->is_IGP)
- OUTPLLP(PIXCLKS_CNTL, 0, ~PIXCLK_LVDS_ALWAYS_ONb);
- if (!(tmp & (LVDS_ON | LVDS_BLON)))
- OUTREG(LVDS_GEN_CNTL, mode->lvds_gen_cntl | LVDS_BLON);
- rinfo->pending_lvds_gen_cntl = mode->lvds_gen_cntl;
- mod_timer(&rinfo->lvds_timer,
- jiffies + MS_TO_HZ(rinfo->panel_info.pwr_delay));
- }
- }
}
- RTRACE("lvds_gen_cntl: %08x\n", INREG(LVDS_GEN_CNTL));
-
- radeon_screen_blank(rinfo, VESA_NO_BLANKING);
+ if (!regs_only)
+ radeon_screen_blank(rinfo, FB_BLANK_UNBLANK, 0);
+ radeon_fifo_wait(2);
OUTPLL(VCLK_ECP_CNTL, mode->vclk_ecp_cntl);
return;
* not sure which model starts having FP2_GEN_CNTL, I assume anything more
* recent than an r(v)100...
*/
-#if 0
+#if 1
/* XXX I had reports of flicker happening with the cinema display
* on TMDS1 that seem to be fixed if I also forbit odd dividers in
* this case. This could just be a bandwidth calculation issue, I
freq = rinfo->pll.ppll_max;
if (freq*12 < rinfo->pll.ppll_min)
freq = rinfo->pll.ppll_min / 12;
+ RTRACE("freq = %lu, PLL min = %u, PLL max = %u\n",
+ freq, rinfo->pll.ppll_min, rinfo->pll.ppll_max);
for (post_div = &post_divs[0]; post_div->divider; ++post_div) {
pll_output_freq = post_div->divider * freq;
break;
}
+ /* If we fall through the bottom, try the "default value"
+ given by the terminal post_div->bitvalue */
+ if ( !post_div->divider ) {
+ post_div = &post_divs[post_div->bitvalue];
+ pll_output_freq = post_div->divider * freq;
+ }
+ RTRACE("ref_div = %d, ref_clk = %d, output_freq = %d\n",
+ rinfo->pll.ref_div, rinfo->pll.ref_clk,
+ pll_output_freq);
+
+ /* If we fall through the bottom, try the "default value"
+ given by the terminal post_div->bitvalue */
+ if ( !post_div->divider ) {
+ post_div = &post_divs[post_div->bitvalue];
+ pll_output_freq = post_div->divider * freq;
+ }
+ RTRACE("ref_div = %d, ref_clk = %d, output_freq = %d\n",
+ rinfo->pll.ref_div, rinfo->pll.ref_clk,
+ pll_output_freq);
+
fb_div = round_div(rinfo->pll.ref_div*pll_output_freq,
rinfo->pll.ref_clk);
regs->ppll_ref_div = rinfo->pll.ref_div;
RTRACE("ppll_div_3 = 0x%x\n", regs->ppll_div_3);
}
-int radeonfb_set_par(struct fb_info *info)
+static int radeonfb_set_par(struct fb_info *info)
{
struct radeonfb_info *rinfo = info->par;
struct fb_var_screeninfo *mode = &info->var;
int hsync_start, hsync_fudge, bytpp, hsync_wid, vsync_wid;
int primary_mon = PRIMARY_MONITOR(rinfo);
int depth = var_to_depth(mode);
+ int use_rmx = 0;
newmode = kmalloc(sizeof(struct radeon_regs), GFP_KERNEL);
if (!newmode)
newmode->crtc_v_sync_strt_wid = (((vSyncStart - 1) & 0xfff) |
(vsync_wid << 16) | (v_sync_pol << 23));
- if (!radeon_accel_disabled()) {
+ if (!(info->flags & FBINFO_HWACCEL_DISABLED)) {
/* We first calculate the engine pitch */
rinfo->pitch = ((mode->xres_virtual * ((mode->bits_per_pixel + 1) / 8) + 0x3f)
& ~(0x3f)) >> 6;
RTRACE("pixclock = %lu\n", (unsigned long)pixClock);
RTRACE("freq = %lu\n", (unsigned long)freq);
+ /* We use PPLL_DIV_3 */
+ newmode->clk_cntl_index = 0x300;
+
+ /* Calculate PPLL value if necessary */
if (!nopllcalc)
radeon_calc_pll_regs(rinfo, newmode, freq);
HORZ_AUTO_RATIO_INC)));
newmode->fp_horz_stretch |= (HORZ_STRETCH_BLEND |
HORZ_STRETCH_ENABLE);
+ use_rmx = 1;
}
newmode->fp_horz_stretch &= ~HORZ_AUTO_RATIO;
(VERT_PANEL_SIZE | VERT_STRETCH_RESERVED)));
newmode->fp_vert_stretch |= (VERT_STRETCH_BLEND |
VERT_STRETCH_ENABLE);
+ use_rmx = 1;
}
newmode->fp_vert_stretch &= ~VERT_AUTO_RATIO_EN;
FP_CRT_SYNC_ALT));
newmode->fp_gen_cntl |= (FP_CRTC_DONT_SHADOW_VPAR |
- FP_CRTC_DONT_SHADOW_HEND);
+ FP_CRTC_DONT_SHADOW_HEND |
+ FP_PANEL_FORMAT);
+
+ if (IS_R300_VARIANT(rinfo) ||
+ (rinfo->family == CHIP_FAMILY_R200)) {
+ newmode->fp_gen_cntl &= ~R200_FP_SOURCE_SEL_MASK;
+ if (use_rmx)
+ newmode->fp_gen_cntl |= R200_FP_SOURCE_SEL_RMX;
+ else
+ newmode->fp_gen_cntl |= R200_FP_SOURCE_SEL_CRTC1;
+ } else
+ newmode->fp_gen_cntl |= FP_SEL_CRTC1;
newmode->lvds_gen_cntl = rinfo->init_state.lvds_gen_cntl;
newmode->lvds_pll_cntl = rinfo->init_state.lvds_pll_cntl;
} else {
/* DFP */
newmode->fp_gen_cntl |= (FP_FPON | FP_TMDS_EN);
- newmode->tmds_transmitter_cntl = (TMDS_RAN_PAT_RST | TMDS_ICHCSEL) &
- ~(TMDS_PLLRST);
+ newmode->tmds_transmitter_cntl &= ~(TMDS_PLLRST);
/* TMDS_PLL_EN bit is reversed on RV (and mobility) chips */
- if ((rinfo->family == CHIP_FAMILY_R300) ||
- (rinfo->family == CHIP_FAMILY_R350) ||
- (rinfo->family == CHIP_FAMILY_RV350) ||
+ if (IS_R300_VARIANT(rinfo) ||
(rinfo->family == CHIP_FAMILY_R200) || !rinfo->has_CRTC2)
newmode->tmds_transmitter_cntl &= ~TMDS_PLL_EN;
else
/* do it! */
if (!rinfo->asleep) {
- radeon_write_mode (rinfo, newmode);
+ memcpy(&rinfo->state, newmode, sizeof(*newmode));
+ radeon_write_mode (rinfo, newmode, 0);
/* (re)initialize the engine */
- if (!radeon_accel_disabled())
+ if (!(info->flags & FBINFO_HWACCEL_DISABLED))
radeonfb_engine_init (rinfo);
-
}
/* Update fix */
- if (!radeon_accel_disabled())
+ if (!(info->flags & FBINFO_HWACCEL_DISABLED))
info->fix.line_length = rinfo->pitch*64;
else
info->fix.line_length = mode->xres_virtual
}
-
-static ssize_t radeonfb_read(struct file *file, char *buf, size_t count, loff_t *ppos)
-{
- unsigned long p = *ppos;
- struct inode *inode = file->f_dentry->d_inode;
- int fbidx = iminor(inode);
- struct fb_info *info = registered_fb[fbidx];
- struct radeonfb_info *rinfo = info->par;
-
- if (p >= rinfo->mapped_vram)
- return 0;
- if (count >= rinfo->mapped_vram)
- count = rinfo->mapped_vram;
- if (count + p > rinfo->mapped_vram)
- count = rinfo->mapped_vram - p;
- radeonfb_sync(info);
- if (count) {
- char *base_addr;
-
- base_addr = info->screen_base;
- count -= copy_to_user(buf, base_addr+p, count);
- if (!count)
- return -EFAULT;
- *ppos += count;
- }
- return count;
-}
-
-static ssize_t radeonfb_write(struct file *file, const char *buf, size_t count,
- loff_t *ppos)
-{
- unsigned long p = *ppos;
- struct inode *inode = file->f_dentry->d_inode;
- int fbidx = iminor(inode);
- struct fb_info *info = registered_fb[fbidx];
- struct radeonfb_info *rinfo = info->par;
- int err;
-
- if (p > rinfo->mapped_vram)
- return -ENOSPC;
- if (count >= rinfo->mapped_vram)
- count = rinfo->mapped_vram;
- err = 0;
- if (count + p > rinfo->mapped_vram) {
- count = rinfo->mapped_vram - p;
- err = -ENOSPC;
- }
- radeonfb_sync(info);
- if (count) {
- char *base_addr;
-
- base_addr = info->screen_base;
- count -= copy_from_user(base_addr+p, buf, count);
- *ppos += count;
- err = -EFAULT;
- }
- if (count)
- return count;
- return err;
-}
-
-
static struct fb_ops radeonfb_ops = {
.owner = THIS_MODULE,
.fb_check_var = radeonfb_check_var,
.fb_set_par = radeonfb_set_par,
.fb_setcolreg = radeonfb_setcolreg,
+ .fb_setcmap = radeonfb_setcmap,
.fb_pan_display = radeonfb_pan_display,
.fb_blank = radeonfb_blank,
.fb_ioctl = radeonfb_ioctl,
.fb_fillrect = radeonfb_fillrect,
.fb_copyarea = radeonfb_copyarea,
.fb_imageblit = radeonfb_imageblit,
- .fb_read = radeonfb_read,
- .fb_write = radeonfb_write,
- .fb_cursor = soft_cursor,
};
{
struct fb_info *info = rinfo->info;
- info->currcon = -1;
info->par = rinfo;
info->pseudo_palette = rinfo->pseudo_palette;
- info->flags = FBINFO_FLAG_DEFAULT;
- info->fbops = &radeonfb_ops;
- info->screen_base = (char *)rinfo->fb_base;
-
+ info->flags = FBINFO_DEFAULT
+ | FBINFO_HWACCEL_COPYAREA
+ | FBINFO_HWACCEL_FILLRECT
+ | FBINFO_HWACCEL_XPAN
+ | FBINFO_HWACCEL_YPAN;
+ info->fbops = &radeonfb_ops;
+ info->screen_base = rinfo->fb_base;
+ info->screen_size = rinfo->mapped_vram;
/* Fill fix common fields */
strlcpy(info->fix.id, rinfo->name, sizeof(info->fix.id));
info->fix.smem_start = rinfo->fb_base_phys;
info->fix.type_aux = 0;
info->fix.mmio_start = rinfo->mmio_base_phys;
info->fix.mmio_len = RADEON_REGSIZE;
- if (radeon_accel_disabled())
- info->fix.accel = FB_ACCEL_NONE;
- else
- info->fix.accel = FB_ACCEL_ATI_RADEON;
+ info->fix.accel = FB_ACCEL_ATI_RADEON;
fb_alloc_cmap(&info->cmap, 256, 0);
- if (radeon_accel_disabled())
- info->var.accel_flags &= ~FB_ACCELF_TEXT;
- else
- info->var.accel_flags |= FB_ACCELF_TEXT;
+ if (noaccel)
+ info->flags |= FBINFO_HWACCEL_DISABLED;
return 0;
}
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);
- unsigned long tmpPixclksCntl = INPLL(PIXCLKS_CNTL);
+ u32 lvds_gen_cntl, tmpPixclksCntl;
int* conv_table;
if (rinfo->mon1_type != MT_LCD)
conv_table = backlight_conv_m6;
del_timer_sync(&rinfo->lvds_timer);
+ radeon_engine_idle();
- lvds_gen_cntl |= (LVDS_BL_MOD_EN | LVDS_BLON);
+ lvds_gen_cntl = INREG(LVDS_GEN_CNTL);
if (on && (level > BACKLIGHT_OFF)) {
- lvds_gen_cntl |= LVDS_DIGON;
- if (!(lvds_gen_cntl & LVDS_ON)) {
- lvds_gen_cntl &= ~LVDS_BLON;
+ 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);
- (void)INREG(LVDS_GEN_CNTL);
- mdelay(rinfo->panel_info.pwr_delay);/* OUCH !!! FIXME */
- lvds_gen_cntl |= LVDS_BLON;
+ 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);
}
- 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_EN);
- lvds_gen_cntl &= ~LVDS_DISPLAY_DIS;
+ 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_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 | LVDS_BLON;
+ 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);
- mdelay(rinfo->panel_info.pwr_delay);/* OUCH !!! FIXME */
- lvds_gen_cntl &= ~(LVDS_ON | LVDS_EN | LVDS_BLON | LVDS_DIGON);
+ 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);
}
-
- OUTREG(LVDS_GEN_CNTL, lvds_gen_cntl);
- 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);
#undef SET_MC_FB_FROM_APERTURE
static void fixup_memory_mappings(struct radeonfb_info *rinfo)
{
- u32 save_crtc_gen_cntl, save_crtc2_gen_cntl;
+ u32 save_crtc_gen_cntl, save_crtc2_gen_cntl = 0;
u32 save_crtc_ext_cntl;
u32 aper_base, aper_size;
u32 agp_base;
OUTREG(DISPLAY_BASE_ADDR, aper_base);
if (rinfo->has_CRTC2)
OUTREG(CRTC2_DISPLAY_BASE_ADDR, aper_base);
+ OUTREG(OV0_BASE_ADDR, aper_base);
#else
OUTREG(DISPLAY_BASE_ADDR, 0);
if (rinfo->has_CRTC2)
OUTREG(CRTC2_DISPLAY_BASE_ADDR, 0);
+ OUTREG(OV0_BASE_ADDR, 0);
#endif
mdelay(100);
#endif /* CONFIG_PPC_OF */
+static void radeon_identify_vram(struct radeonfb_info *rinfo)
+{
+ u32 tmp;
+
+ /* framebuffer size */
+ if ((rinfo->family == CHIP_FAMILY_RS100) ||
+ (rinfo->family == CHIP_FAMILY_RS200) ||
+ (rinfo->family == CHIP_FAMILY_RS300)) {
+ u32 tom = INREG(NB_TOM);
+ tmp = ((((tom >> 16) - (tom & 0xffff) + 1) << 6) * 1024);
+
+ radeon_fifo_wait(6);
+ OUTREG(MC_FB_LOCATION, tom);
+ OUTREG(DISPLAY_BASE_ADDR, (tom & 0xffff) << 16);
+ OUTREG(CRTC2_DISPLAY_BASE_ADDR, (tom & 0xffff) << 16);
+ OUTREG(OV0_BASE_ADDR, (tom & 0xffff) << 16);
+
+ /* This is supposed to fix the crtc2 noise problem. */
+ OUTREG(GRPH2_BUFFER_CNTL, INREG(GRPH2_BUFFER_CNTL) & ~0x7f0000);
+
+ if ((rinfo->family == CHIP_FAMILY_RS100) ||
+ (rinfo->family == CHIP_FAMILY_RS200)) {
+ /* This is to workaround the asic bug for RMX, some versions
+ of BIOS dosen't have this register initialized correctly.
+ */
+ OUTREGP(CRTC_MORE_CNTL, CRTC_H_CUTOFF_ACTIVE_EN,
+ ~CRTC_H_CUTOFF_ACTIVE_EN);
+ }
+ } else {
+ tmp = INREG(CONFIG_MEMSIZE);
+ }
+
+ /* mem size is bits [28:0], mask off the rest */
+ rinfo->video_ram = tmp & CONFIG_MEMSIZE_MASK;
+
+ /*
+ * Hack to get around some busted production M6's
+ * reporting no ram
+ */
+ if (rinfo->video_ram == 0) {
+ switch (rinfo->pdev->device) {
+ case PCI_CHIP_RADEON_LY:
+ case PCI_CHIP_RADEON_LZ:
+ rinfo->video_ram = 8192 * 1024;
+ break;
+ default:
+ break;
+ }
+ }
+
+
+ /*
+ * Now try to identify VRAM type
+ */
+ if (rinfo->is_IGP || (rinfo->family >= CHIP_FAMILY_R300) ||
+ (INREG(MEM_SDRAM_MODE_REG) & (1<<30)))
+ rinfo->vram_ddr = 1;
+ else
+ rinfo->vram_ddr = 0;
+
+ tmp = INREG(MEM_CNTL);
+ if (IS_R300_VARIANT(rinfo)) {
+ tmp &= R300_MEM_NUM_CHANNELS_MASK;
+ switch (tmp) {
+ case 0: rinfo->vram_width = 64; break;
+ case 1: rinfo->vram_width = 128; break;
+ case 2: rinfo->vram_width = 256; break;
+ default: rinfo->vram_width = 128; break;
+ }
+ } else if ((rinfo->family == CHIP_FAMILY_RV100) ||
+ (rinfo->family == CHIP_FAMILY_RS100) ||
+ (rinfo->family == CHIP_FAMILY_RS200)){
+ if (tmp & RV100_MEM_HALF_MODE)
+ rinfo->vram_width = 32;
+ else
+ rinfo->vram_width = 64;
+ } else {
+ if (tmp & MEM_NUM_CHANNELS_MASK)
+ rinfo->vram_width = 128;
+ else
+ rinfo->vram_width = 64;
+ }
+
+ /* This may not be correct, as some cards can have half of channel disabled
+ * ToDo: identify these cases
+ */
+
+ RTRACE("radeonfb (%s): Found %ldk of %s %d bits wide videoram\n",
+ pci_name(rinfo->pdev),
+ rinfo->video_ram / 1024,
+ rinfo->vram_ddr ? "DDR" : "SDRAM",
+ rinfo->vram_width);
+}
+
/*
* Sysfs
*/
{
struct fb_info *info;
struct radeonfb_info *rinfo;
- u32 tmp;
+ int ret;
RTRACE("radeonfb_pci_register BEGIN\n");
/* Enable device in PCI config */
- if (pci_enable_device(pdev) != 0) {
- printk(KERN_ERR "radeonfb: Cannot enable PCI device\n");
- return -ENODEV;
+ ret = pci_enable_device(pdev);
+ if (ret < 0) {
+ printk(KERN_ERR "radeonfb (%s): Cannot enable PCI device\n",
+ pci_name(pdev));
+ goto err_out;
}
info = framebuffer_alloc(sizeof(struct radeonfb_info), &pdev->dev);
if (!info) {
- printk (KERN_ERR "radeonfb: could not allocate memory\n");
- return -ENODEV;
+ printk (KERN_ERR "radeonfb (%s): could not allocate memory\n",
+ pci_name(pdev));
+ ret = -ENOMEM;
+ goto err_disable;
}
rinfo = info->par;
rinfo->info = info;
rinfo->has_CRTC2 = (ent->driver_data & CHIP_HAS_CRTC2) != 0;
rinfo->is_mobility = (ent->driver_data & CHIP_IS_MOBILITY) != 0;
rinfo->is_IGP = (ent->driver_data & CHIP_IS_IGP) != 0;
-
+
/* Set base addrs */
rinfo->fb_base_phys = pci_resource_start (pdev, 0);
rinfo->mmio_base_phys = pci_resource_start (pdev, 2);
/* request the mem regions */
- if (!request_mem_region (rinfo->fb_base_phys,
- pci_resource_len(pdev, 0), "radeonfb")) {
- printk (KERN_ERR "radeonfb: cannot reserve FB region\n");
- goto free_rinfo;
+ ret = pci_request_region(pdev, 0, "radeonfb framebuffer");
+ if (ret < 0) {
+ printk( KERN_ERR "radeonfb (%s): cannot request region 0.\n",
+ pci_name(rinfo->pdev));
+ goto err_release_fb;
}
- if (!request_mem_region (rinfo->mmio_base_phys,
- pci_resource_len(pdev, 2), "radeonfb")) {
- printk (KERN_ERR "radeonfb: cannot reserve MMIO region\n");
- goto release_fb;
+ ret = pci_request_region(pdev, 2, "radeonfb mmio");
+ if (ret < 0) {
+ printk( KERN_ERR "radeonfb (%s): cannot request region 2.\n",
+ pci_name(rinfo->pdev));
+ goto err_release_pci0;
}
/* map the regions */
- rinfo->mmio_base = (unsigned long) ioremap (rinfo->mmio_base_phys, RADEON_REGSIZE);
+ rinfo->mmio_base = ioremap(rinfo->mmio_base_phys, RADEON_REGSIZE);
if (!rinfo->mmio_base) {
- printk (KERN_ERR "radeonfb: cannot map MMIO\n");
- goto release_mmio;
+ printk(KERN_ERR "radeonfb (%s): cannot map MMIO\n",
+ pci_name(rinfo->pdev));
+ ret = -EIO;
+ goto err_release_pci2;
}
- /* On PPC, the firmware sets up a memory mapping that tends
- * to cause lockups when enabling the engine. We reconfigure
- * the card internal memory mappings properly
- */
-#ifdef CONFIG_PPC_OF
- fixup_memory_mappings(rinfo);
-#else
rinfo->fb_local_base = INREG(MC_FB_LOCATION) << 16;
-#endif /* CONFIG_PPC_OF */
- /* framebuffer size */
- if ((rinfo->family == CHIP_FAMILY_RS100) ||
- (rinfo->family == CHIP_FAMILY_RS200) ||
- (rinfo->family == CHIP_FAMILY_RS300)) {
- u32 tom = INREG(NB_TOM);
- tmp = ((((tom >> 16) - (tom & 0xffff) + 1) << 6) * 1024);
-
- OUTREG(MC_FB_LOCATION, tom);
- OUTREG(DISPLAY_BASE_ADDR, (tom & 0xffff) << 16);
- OUTREG(CRTC2_DISPLAY_BASE_ADDR, (tom & 0xffff) << 16);
- OUTREG(OV0_BASE_ADDR, (tom & 0xffff) << 16);
-
- /* This is supposed to fix the crtc2 noise problem. */
- OUTREG(GRPH2_BUFFER_CNTL, INREG(GRPH2_BUFFER_CNTL) & ~0x7f0000);
-
- if ((rinfo->family == CHIP_FAMILY_RS100) ||
- (rinfo->family == CHIP_FAMILY_RS200)) {
- /* This is to workaround the asic bug for RMX, some versions
- of BIOS dosen't have this register initialized correctly.
- */
- OUTREGP(CRTC_MORE_CNTL, CRTC_H_CUTOFF_ACTIVE_EN,
- ~CRTC_H_CUTOFF_ACTIVE_EN);
- }
- } else {
- tmp = INREG(CONFIG_MEMSIZE);
- }
+ /*
+ * Check for errata
+ */
+ rinfo->errata = 0;
+ if (rinfo->family == CHIP_FAMILY_R300 &&
+ (INREG(CONFIG_CNTL) & CFG_ATI_REV_ID_MASK)
+ == CFG_ATI_REV_A11)
+ rinfo->errata |= CHIP_ERRATA_R300_CG;
- /* mem size is bits [28:0], mask off the rest */
- rinfo->video_ram = tmp & CONFIG_MEMSIZE_MASK;
+ if (rinfo->family == CHIP_FAMILY_RV200 ||
+ rinfo->family == CHIP_FAMILY_RS200)
+ rinfo->errata |= CHIP_ERRATA_PLL_DUMMYREADS;
- /* ram type */
- tmp = INREG(MEM_SDRAM_MODE_REG);
- switch ((MEM_CFG_TYPE & tmp) >> 30) {
- case 0:
- /* SDR SGRAM (2:1) */
- strcpy(rinfo->ram_type, "SDR SGRAM");
- rinfo->ram.ml = 4;
- rinfo->ram.mb = 4;
- rinfo->ram.trcd = 1;
- rinfo->ram.trp = 2;
- rinfo->ram.twr = 1;
- rinfo->ram.cl = 2;
- rinfo->ram.loop_latency = 16;
- rinfo->ram.rloop = 16;
- break;
- case 1:
- /* DDR SGRAM */
- strcpy(rinfo->ram_type, "DDR SGRAM");
- rinfo->ram.ml = 4;
- rinfo->ram.mb = 4;
- rinfo->ram.trcd = 3;
- rinfo->ram.trp = 3;
- rinfo->ram.twr = 2;
- rinfo->ram.cl = 3;
- rinfo->ram.tr2w = 1;
- rinfo->ram.loop_latency = 16;
- rinfo->ram.rloop = 16;
- break;
- default:
- /* 64-bit SDR SGRAM */
- strcpy(rinfo->ram_type, "SDR SGRAM 64");
- rinfo->ram.ml = 4;
- rinfo->ram.mb = 8;
- rinfo->ram.trcd = 3;
- rinfo->ram.trp = 3;
- rinfo->ram.twr = 1;
- rinfo->ram.cl = 3;
- rinfo->ram.tr2w = 1;
- rinfo->ram.loop_latency = 17;
- rinfo->ram.rloop = 17;
- break;
- }
+ if (rinfo->family == CHIP_FAMILY_RV100 ||
+ rinfo->family == CHIP_FAMILY_RS100 ||
+ rinfo->family == CHIP_FAMILY_RS200)
+ rinfo->errata |= CHIP_ERRATA_PLL_DELAY;
- /*
- * Hack to get around some busted production M6's
- * reporting no ram
+#ifdef CONFIG_PPC_OF
+ /* On PPC, we obtain the OF device-node pointer to the firmware
+ * data for this chip
*/
- if (rinfo->video_ram == 0) {
- switch (pdev->device) {
- case PCI_CHIP_RADEON_LY:
- case PCI_CHIP_RADEON_LZ:
- rinfo->video_ram = 8192 * 1024;
- break;
- default:
- break;
- }
- }
-
- RTRACE("radeonfb: probed %s %ldk videoram\n", (rinfo->ram_type), (rinfo->video_ram/1024));
+ rinfo->of_node = pci_device_to_OF_node(pdev);
+ if (rinfo->of_node == NULL)
+ printk(KERN_WARNING "radeonfb (%s): Cannot match card to OF node !\n",
+ pci_name(rinfo->pdev));
- rinfo->mapped_vram = MAX_MAPPED_VRAM;
- if (rinfo->video_ram < rinfo->mapped_vram)
- rinfo->mapped_vram = rinfo->video_ram;
- for (;;) {
- rinfo->fb_base = (unsigned long) ioremap (rinfo->fb_base_phys,
- rinfo->mapped_vram);
- if (rinfo->fb_base == 0 && rinfo->mapped_vram > MIN_MAPPED_VRAM) {
- rinfo->mapped_vram /= 2;
- continue;
- }
- memset_io(rinfo->fb_base, 0, rinfo->mapped_vram);
- break;
- }
+ /* On PPC, the firmware sets up a memory mapping that tends
+ * to cause lockups when enabling the engine. We reconfigure
+ * the card internal memory mappings properly
+ */
+ fixup_memory_mappings(rinfo);
+#endif /* CONFIG_PPC_OF */
- if (!rinfo->fb_base) {
- printk (KERN_ERR "radeonfb: cannot map FB\n");
- goto unmap_rom;
- }
+ /* Get VRAM size and type */
+ radeon_identify_vram(rinfo);
- RTRACE("radeonfb: mapped %ldk videoram\n", rinfo->mapped_vram/1024);
+ rinfo->mapped_vram = min_t(unsigned long, MAX_MAPPED_VRAM, rinfo->video_ram);
+ do {
+ rinfo->fb_base = ioremap (rinfo->fb_base_phys,
+ rinfo->mapped_vram);
+ } while ( rinfo->fb_base == 0 &&
+ ((rinfo->mapped_vram /=2) >= MIN_MAPPED_VRAM) );
- /* Argh. Scary arch !!! */
-#ifdef CONFIG_PPC64
- rinfo->fb_base = IO_TOKEN_TO_ADDR(rinfo->fb_base);
-#endif
+ if (rinfo->fb_base == NULL) {
+ printk (KERN_ERR "radeonfb (%s): cannot map FB\n",
+ pci_name(rinfo->pdev));
+ ret = -EIO;
+ goto err_unmap_rom;
+ }
- /*
- * Check for required workaround for PLL accesses
- */
- rinfo->R300_cg_workaround = (rinfo->family == CHIP_FAMILY_R300 &&
- (INREG(CONFIG_CNTL) & CFG_ATI_REV_ID_MASK)
- == CFG_ATI_REV_A11);
+ RTRACE("radeonfb (%s): mapped %ldk videoram\n", pci_name(rinfo->pdev),
+ rinfo->mapped_vram/1024);
/*
- * Map the BIOS ROM if any and retreive PLL parameters from
- * either BIOS or Open Firmware
+ * Map the BIOS ROM if any and retrieve PLL parameters from
+ * the BIOS. We skip that on mobility chips as the real panel
+ * values we need aren't in the ROM but in the BIOS image in
+ * memory. This is definitely not the best meacnism though,
+ * we really need the arch code to tell us which is the "primary"
+ * video adapter to use the memory image (or better, the arch
+ * should provide us a copy of the BIOS image to shield us from
+ * archs who would store that elsewhere and/or could initialize
+ * more than one adapter during boot).
*/
- radeon_map_ROM(rinfo, pdev);
+ if (!rinfo->is_mobility)
+ radeon_map_ROM(rinfo, pdev);
/*
* On x86, the primary display on laptop may have it's BIOS
* ROM elsewhere, try to locate it at the legacy memory hole.
- * We probably need to make sure this is the primary dispay,
+ * We probably need to make sure this is the primary display,
* but that is difficult without some arch support.
*/
-#ifdef __i386__
+#ifdef CONFIG_X86
if (rinfo->bios_seg == NULL)
radeon_find_mem_vbios(rinfo);
-#endif /* __i386__ */
+#endif
+
+ /* If both above failed, try the BIOS ROM again for mobility
+ * chips
+ */
+ if (rinfo->bios_seg == NULL && rinfo->is_mobility)
+ radeon_map_ROM(rinfo, pdev);
/* Get informations about the board's PLL */
radeon_get_pllinfo(rinfo);
* so we can restore this upon __exit
*/
radeon_save_state (rinfo, &rinfo->init_state);
+ memcpy(&rinfo->state, &rinfo->init_state, sizeof(struct radeon_regs));
- pci_set_drvdata(pdev, info);
+ /* Setup Power Management capabilities */
+ if (default_dynclk < -1) {
+ /* -2 is special: means ON on mobility chips and do not
+ * change on others
+ */
+ radeonfb_pm_init(rinfo, rinfo->is_mobility ? 1 : -1);
+ } else
+ radeonfb_pm_init(rinfo, default_dynclk);
- /* Enable PM on mobility chips */
- if (rinfo->is_mobility) {
- /* Find PM registers in config space */
- rinfo->pm_reg = pci_find_capability(pdev, PCI_CAP_ID_PM);
- /* Enable dynamic PM of chip clocks */
- radeon_pm_enable_dynamic_mode(rinfo);
- printk("radeonfb: Power Management enabled for Mobility chipsets\n");
- }
+ pci_set_drvdata(pdev, info);
- if (register_framebuffer(info) < 0) {
- printk (KERN_ERR "radeonfb: could not register framebuffer\n");
- goto unmap_fb;
+ /* Register with fbdev layer */
+ ret = register_framebuffer(info);
+ if (ret < 0) {
+ printk (KERN_ERR "radeonfb (%s): could not register framebuffer\n",
+ pci_name(rinfo->pdev));
+ goto err_unmap_fb;
}
#ifdef CONFIG_MTRR
}
#endif
- printk ("radeonfb: %s %s %ld MB\n", rinfo->name, rinfo->ram_type,
- (rinfo->video_ram/(1024*1024)));
+ printk ("radeonfb (%s): %s\n", pci_name(rinfo->pdev), rinfo->name);
if (rinfo->bios_seg)
radeon_unmap_ROM(rinfo, pdev);
RTRACE("radeonfb_pci_register END\n");
return 0;
-unmap_fb:
- iounmap ((void*)rinfo->fb_base);
-unmap_rom:
- if (rinfo->mon1_EDID)
- kfree(rinfo->mon1_EDID);
- if (rinfo->mon2_EDID)
- kfree(rinfo->mon2_EDID);
+err_unmap_fb:
+ iounmap(rinfo->fb_base);
+err_unmap_rom:
+ kfree(rinfo->mon1_EDID);
+ kfree(rinfo->mon2_EDID);
if (rinfo->mon1_modedb)
fb_destroy_modedb(rinfo->mon1_modedb);
+ fb_dealloc_cmap(&info->cmap);
#ifdef CONFIG_FB_RADEON_I2C
radeon_delete_i2c_busses(rinfo);
#endif
if (rinfo->bios_seg)
radeon_unmap_ROM(rinfo, pdev);
- iounmap ((void*)rinfo->mmio_base);
-release_mmio:
- release_mem_region (rinfo->mmio_base_phys,
- pci_resource_len(pdev, 2));
-release_fb:
- release_mem_region (rinfo->fb_base_phys,
- pci_resource_len(pdev, 0));
-free_rinfo:
- framebuffer_release(info);
- return -ENODEV;
+ iounmap(rinfo->mmio_base);
+err_release_pci2:
+ pci_release_region(pdev, 2);
+err_release_pci0:
+ pci_release_region(pdev, 0);
+err_release_fb:
+ framebuffer_release(info);
+err_disable:
+ pci_disable_device(pdev);
+err_out:
+ return ret;
}
if (!rinfo)
return;
+ radeonfb_pm_exit(rinfo);
+
+ if (rinfo->mon1_EDID)
+ sysfs_remove_bin_file(&rinfo->pdev->dev.kobj, &edid1_attr);
+ if (rinfo->mon2_EDID)
+ sysfs_remove_bin_file(&rinfo->pdev->dev.kobj, &edid2_attr);
+
+#if 0
/* restore original state
*
- * Doesn't quite work yet, possibly because of the PPC hacking
- * I do on startup, disable for now. --BenH
+ * Doesn't quite work yet, I suspect if we come from a legacy
+ * VGA mode (or worse, text mode), we need to do some VGA black
+ * magic here that I know nothing about. --BenH
*/
- radeon_write_mode (rinfo, &rinfo->init_state);
-
+ radeon_write_mode (rinfo, &rinfo->init_state, 1);
+ #endif
+
del_timer_sync(&rinfo->lvds_timer);
#ifdef CONFIG_MTRR
unregister_framebuffer(info);
- iounmap ((void*)rinfo->mmio_base);
- iounmap ((void*)rinfo->fb_base);
+ iounmap(rinfo->mmio_base);
+ iounmap(rinfo->fb_base);
- release_mem_region (rinfo->mmio_base_phys,
- pci_resource_len(pdev, 2));
- release_mem_region (rinfo->fb_base_phys,
- pci_resource_len(pdev, 0));
+ pci_release_region(pdev, 2);
+ pci_release_region(pdev, 0);
- if (rinfo->mon1_EDID)
- kfree(rinfo->mon1_EDID);
- if (rinfo->mon2_EDID)
- kfree(rinfo->mon2_EDID);
+ kfree(rinfo->mon1_EDID);
+ kfree(rinfo->mon2_EDID);
if (rinfo->mon1_modedb)
fb_destroy_modedb(rinfo->mon1_modedb);
#ifdef CONFIG_FB_RADEON_I2C
radeon_delete_i2c_busses(rinfo);
#endif
+ fb_dealloc_cmap(&info->cmap);
framebuffer_release(info);
+ pci_disable_device(pdev);
}
#endif /* CONFIG_PM */
};
-
-int __init radeonfb_init (void)
-{
- radeonfb_noaccel = noaccel;
- return pci_module_init (&radeonfb_driver);
-}
-
-
-void __exit radeonfb_exit (void)
-{
- pci_unregister_driver (&radeonfb_driver);
-}
-
-int __init radeonfb_setup (char *options)
+#ifndef MODULE
+static int __init radeonfb_setup (char *options)
{
char *this_opt;
continue;
if (!strncmp(this_opt, "noaccel", 7)) {
- noaccel = radeonfb_noaccel = 1;
+ noaccel = 1;
} else if (!strncmp(this_opt, "mirror", 6)) {
mirror = 1;
} else if (!strncmp(this_opt, "force_dfp", 9)) {
}
return 0;
}
+#endif /* MODULE */
+
+static int __init radeonfb_init (void)
+{
+#ifndef MODULE
+ char *option = NULL;
+
+ if (fb_get_options("radeonfb", &option))
+ return -ENODEV;
+ radeonfb_setup(option);
+#endif
+ return pci_register_driver (&radeonfb_driver);
+}
+
+static void __exit radeonfb_exit (void)
+{
+ pci_unregister_driver (&radeonfb_driver);
+}
-#ifdef MODULE
module_init(radeonfb_init);
module_exit(radeonfb_exit);
-#endif
MODULE_AUTHOR("Ani Joshi");
MODULE_DESCRIPTION("framebuffer driver for ATI Radeon chipset");
MODULE_LICENSE("GPL");
module_param(noaccel, bool, 0);
+module_param(default_dynclk, int, 0);
+MODULE_PARM_DESC(default_dynclk, "int: -2=enable on mobility only,-1=do not change,0=off,1=on");
MODULE_PARM_DESC(noaccel, "bool: disable acceleration");
module_param(nomodeset, bool, 0);
MODULE_PARM_DESC(nomodeset, "bool: disable actual setting of video mode");