Commit d90125bf authored by Linus Torvalds's avatar Linus Torvalds

Merge branch 'i915fb' of git://git.kernel.org/pub/scm/linux/kernel/git/airlied/intelfb-2.6

* 'i915fb' of git://git.kernel.org/pub/scm/linux/kernel/git/airlied/intelfb-2.6: (25 commits)
  intelfb: fixup clock calculation debugging.
  Removed hard coded EDID buffer size.
  intelfb: use regular modedb table instead of VESA
  intelfb: use firmware EDID for mode database
  Revert "intelfb driver -- use the regular modedb table instead of the VESA"
  intelfb: int option fix
  sync modesetting code with X.org
  intelfb: align with changes from my X driver.
  intelfb driver -- use the regular modedb table instead of the VESA
  Adds support for 256MB aperture on 945 chipsets to the intelfb driver
  intelfb -- uses stride alignment of 64 on the 9xx chipsets.
  intelfb: some cleanups for intelfbhw
  intelfb: fixup pitch calculation like X does
  intelfb: fixup p calculation
  This patch makes a needlessly global struct static.
  intelfb: add i945GM support
  intelfb: fixup whitespace..
  intelfb: add hw cursor support for i9xx
  intelfb: make i915 modeset
  intelfb: add support for i945G
  ...
parents bfd189a8 2abac1db
...@@ -743,7 +743,7 @@ config FB_I810_I2C ...@@ -743,7 +743,7 @@ config FB_I810_I2C
config FB_INTEL config FB_INTEL
tristate "Intel 830M/845G/852GM/855GM/865G support (EXPERIMENTAL)" tristate "Intel 830M/845G/852GM/855GM/865G support (EXPERIMENTAL)"
depends on FB && EXPERIMENTAL && PCI && X86_32 depends on FB && EXPERIMENTAL && PCI && X86
select AGP select AGP
select AGP_INTEL select AGP_INTEL
select FB_MODE_HELPERS select FB_MODE_HELPERS
......
...@@ -8,9 +8,9 @@ ...@@ -8,9 +8,9 @@
/*** Version/name ***/ /*** Version/name ***/
#define INTELFB_VERSION "0.9.2" #define INTELFB_VERSION "0.9.4"
#define INTELFB_MODULE_NAME "intelfb" #define INTELFB_MODULE_NAME "intelfb"
#define SUPPORTED_CHIPSETS "830M/845G/852GM/855GM/865G/915G/915GM" #define SUPPORTED_CHIPSETS "830M/845G/852GM/855GM/865G/915G/915GM/945G/945GM"
/*** Debug/feature defines ***/ /*** Debug/feature defines ***/
...@@ -52,11 +52,14 @@ ...@@ -52,11 +52,14 @@
#define PCI_DEVICE_ID_INTEL_865G 0x2572 #define PCI_DEVICE_ID_INTEL_865G 0x2572
#define PCI_DEVICE_ID_INTEL_915G 0x2582 #define PCI_DEVICE_ID_INTEL_915G 0x2582
#define PCI_DEVICE_ID_INTEL_915GM 0x2592 #define PCI_DEVICE_ID_INTEL_915GM 0x2592
#define PCI_DEVICE_ID_INTEL_945G 0x2772
#define PCI_DEVICE_ID_INTEL_945GM 0x27A2
/* Size of MMIO region */ /* Size of MMIO region */
#define INTEL_REG_SIZE 0x80000 #define INTEL_REG_SIZE 0x80000
#define STRIDE_ALIGNMENT 16 #define STRIDE_ALIGNMENT 16
#define STRIDE_ALIGNMENT_I9XX 64
#define PALETTE_8_ENTRIES 256 #define PALETTE_8_ENTRIES 256
...@@ -125,7 +128,9 @@ enum intel_chips { ...@@ -125,7 +128,9 @@ enum intel_chips {
INTEL_855GME, INTEL_855GME,
INTEL_865G, INTEL_865G,
INTEL_915G, INTEL_915G,
INTEL_915GM INTEL_915GM,
INTEL_945G,
INTEL_945GM,
}; };
struct intelfb_hwstate { struct intelfb_hwstate {
...@@ -277,8 +282,13 @@ struct intelfb_info { ...@@ -277,8 +282,13 @@ struct intelfb_info {
/* driver registered */ /* driver registered */
int registered; int registered;
/* index into plls */
int pll_index;
}; };
#define IS_I9XX(dinfo) (((dinfo)->chipset == INTEL_915G)||(dinfo->chipset == INTEL_915GM)||((dinfo)->chipset == INTEL_945G)||(dinfo->chipset==INTEL_945GM))
/*** function prototypes ***/ /*** function prototypes ***/
extern int intelfb_var_to_depth(const struct fb_var_screeninfo *var); extern int intelfb_var_to_depth(const struct fb_var_screeninfo *var);
......
/* /*
* intelfb * intelfb
* *
* Linux framebuffer driver for Intel(R) 830M/845G/852GM/855GM/865G/915G/915GM * Linux framebuffer driver for Intel(R) 830M/845G/852GM/855GM/865G/915G/915GM/
* integrated graphics chips. * 945G/945GM integrated graphics chips.
* *
* Copyright 2002, 2003 David Dawes <dawes@xfree86.org> * Copyright 2002, 2003 David Dawes <dawes@xfree86.org>
* 2004 Sylvain Meyer * 2004 Sylvain Meyer
* 2006 David Airlie
* *
* This driver consists of two parts. The first part (intelfbdrv.c) provides * This driver consists of two parts. The first part (intelfbdrv.c) provides
* the basic fbdev interfaces, is derived in part from the radeonfb and * the basic fbdev interfaces, is derived in part from the radeonfb and
...@@ -131,6 +132,7 @@ ...@@ -131,6 +132,7 @@
#include "intelfb.h" #include "intelfb.h"
#include "intelfbhw.h" #include "intelfbhw.h"
#include "../edid.h"
static void __devinit get_initial_mode(struct intelfb_info *dinfo); static void __devinit get_initial_mode(struct intelfb_info *dinfo);
static void update_dinfo(struct intelfb_info *dinfo, static void update_dinfo(struct intelfb_info *dinfo,
...@@ -182,6 +184,8 @@ static struct pci_device_id intelfb_pci_table[] __devinitdata = { ...@@ -182,6 +184,8 @@ static struct pci_device_id intelfb_pci_table[] __devinitdata = {
{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_865G, PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_DISPLAY_VGA << 8, INTELFB_CLASS_MASK, INTEL_865G }, { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_865G, PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_DISPLAY_VGA << 8, INTELFB_CLASS_MASK, INTEL_865G },
{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_915G, PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_DISPLAY_VGA << 8, INTELFB_CLASS_MASK, INTEL_915G }, { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_915G, PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_DISPLAY_VGA << 8, INTELFB_CLASS_MASK, INTEL_915G },
{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_915GM, PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_DISPLAY_VGA << 8, INTELFB_CLASS_MASK, INTEL_915GM }, { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_915GM, PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_DISPLAY_VGA << 8, INTELFB_CLASS_MASK, INTEL_915GM },
{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_945G, PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_DISPLAY_VGA << 8, INTELFB_CLASS_MASK, INTEL_945G },
{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_945GM, PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_DISPLAY_VGA << 8, INTELFB_CLASS_MASK, INTEL_945GM },
{ 0, } { 0, }
}; };
...@@ -261,7 +265,7 @@ MODULE_PARM_DESC(mode, ...@@ -261,7 +265,7 @@ MODULE_PARM_DESC(mode,
#ifndef MODULE #ifndef MODULE
#define OPT_EQUAL(opt, name) (!strncmp(opt, name, strlen(name))) #define OPT_EQUAL(opt, name) (!strncmp(opt, name, strlen(name)))
#define OPT_INTVAL(opt, name) simple_strtoul(opt + strlen(name), NULL, 0) #define OPT_INTVAL(opt, name) simple_strtoul(opt + strlen(name) + 1, NULL, 0)
#define OPT_STRVAL(opt, name) (opt + strlen(name)) #define OPT_STRVAL(opt, name) (opt + strlen(name))
static __inline__ char * static __inline__ char *
...@@ -546,11 +550,11 @@ intelfb_pci_register(struct pci_dev *pdev, const struct pci_device_id *ent) ...@@ -546,11 +550,11 @@ intelfb_pci_register(struct pci_dev *pdev, const struct pci_device_id *ent)
/* Set base addresses. */ /* Set base addresses. */
if ((ent->device == PCI_DEVICE_ID_INTEL_915G) || if ((ent->device == PCI_DEVICE_ID_INTEL_915G) ||
(ent->device == PCI_DEVICE_ID_INTEL_915GM)) { (ent->device == PCI_DEVICE_ID_INTEL_915GM) ||
(ent->device == PCI_DEVICE_ID_INTEL_945G) ||
(ent->device == PCI_DEVICE_ID_INTEL_945GM)) {
aperture_bar = 2; aperture_bar = 2;
mmio_bar = 0; mmio_bar = 0;
/* Disable HW cursor on 915G/M (not implemented yet) */
hwcursor = 0;
} }
dinfo->aperture.physical = pci_resource_start(pdev, aperture_bar); dinfo->aperture.physical = pci_resource_start(pdev, aperture_bar);
dinfo->aperture.size = pci_resource_len(pdev, aperture_bar); dinfo->aperture.size = pci_resource_len(pdev, aperture_bar);
...@@ -584,8 +588,7 @@ intelfb_pci_register(struct pci_dev *pdev, const struct pci_device_id *ent) ...@@ -584,8 +588,7 @@ intelfb_pci_register(struct pci_dev *pdev, const struct pci_device_id *ent)
/* Get the chipset info. */ /* Get the chipset info. */
dinfo->pci_chipset = pdev->device; dinfo->pci_chipset = pdev->device;
if (intelfbhw_get_chipset(pdev, &dinfo->name, &dinfo->chipset, if (intelfbhw_get_chipset(pdev, dinfo)) {
&dinfo->mobile)) {
cleanup(dinfo); cleanup(dinfo);
return -ENODEV; return -ENODEV;
} }
...@@ -1029,17 +1032,44 @@ intelfb_init_var(struct intelfb_info *dinfo) ...@@ -1029,17 +1032,44 @@ intelfb_init_var(struct intelfb_info *dinfo)
sizeof(struct fb_var_screeninfo)); sizeof(struct fb_var_screeninfo));
msrc = 5; msrc = 5;
} else { } else {
const u8 *edid_s = fb_firmware_edid(&dinfo->pdev->dev);
u8 *edid_d = NULL;
if (edid_s) {
edid_d = kmalloc(EDID_LENGTH, GFP_KERNEL);
if (edid_d) {
memcpy(edid_d, edid_s, EDID_LENGTH);
fb_edid_to_monspecs(edid_d,
&dinfo->info->monspecs);
kfree(edid_d);
}
}
if (mode) { if (mode) {
printk("intelfb: Looking for mode in private "
"database\n");
msrc = fb_find_mode(var, dinfo->info, mode, msrc = fb_find_mode(var, dinfo->info, mode,
vesa_modes, VESA_MODEDB_SIZE, dinfo->info->monspecs.modedb,
dinfo->info->monspecs.modedb_len,
NULL, 0); NULL, 0);
if (msrc)
msrc |= 8; if (msrc && msrc > 1) {
printk("intelfb: No mode in private database, "
"intelfb: looking for mode in global "
"database ");
msrc = fb_find_mode(var, dinfo->info, mode,
NULL, 0, NULL, 0);
if (msrc)
msrc |= 8;
}
} }
if (!msrc) { if (!msrc) {
msrc = fb_find_mode(var, dinfo->info, PREFERRED_MODE, msrc = fb_find_mode(var, dinfo->info, PREFERRED_MODE,
vesa_modes, VESA_MODEDB_SIZE, NULL, 0, NULL, 0);
NULL, 0);
} }
} }
...@@ -1139,7 +1169,10 @@ update_dinfo(struct intelfb_info *dinfo, struct fb_var_screeninfo *var) ...@@ -1139,7 +1169,10 @@ update_dinfo(struct intelfb_info *dinfo, struct fb_var_screeninfo *var)
} }
/* Make sure the line length is a aligned correctly. */ /* Make sure the line length is a aligned correctly. */
dinfo->pitch = ROUND_UP_TO(dinfo->pitch, STRIDE_ALIGNMENT); if (IS_I9XX(dinfo))
dinfo->pitch = ROUND_UP_TO(dinfo->pitch, STRIDE_ALIGNMENT_I9XX);
else
dinfo->pitch = ROUND_UP_TO(dinfo->pitch, STRIDE_ALIGNMENT);
if (FIXED_MODE(dinfo)) if (FIXED_MODE(dinfo))
dinfo->pitch = dinfo->initial_pitch; dinfo->pitch = dinfo->initial_pitch;
...@@ -1162,16 +1195,33 @@ intelfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info) ...@@ -1162,16 +1195,33 @@ intelfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
struct fb_var_screeninfo v; struct fb_var_screeninfo v;
struct intelfb_info *dinfo; struct intelfb_info *dinfo;
static int first = 1; static int first = 1;
int i;
/* Good pitches to allow tiling. Don't care about pitches < 1024. */
static const int pitches[] = {
128 * 8,
128 * 16,
128 * 32,
128 * 64,
0
};
DBG_MSG("intelfb_check_var: accel_flags is %d\n", var->accel_flags); DBG_MSG("intelfb_check_var: accel_flags is %d\n", var->accel_flags);
dinfo = GET_DINFO(info); dinfo = GET_DINFO(info);
/* update the pitch */
if (intelfbhw_validate_mode(dinfo, var) != 0) if (intelfbhw_validate_mode(dinfo, var) != 0)
return -EINVAL; return -EINVAL;
v = *var; v = *var;
for (i = 0; pitches[i] != 0; i++) {
if (pitches[i] >= v.xres_virtual) {
v.xres_virtual = pitches[i];
break;
}
}
/* Check for a supported bpp. */ /* Check for a supported bpp. */
if (v.bits_per_pixel <= 8) { if (v.bits_per_pixel <= 8) {
v.bits_per_pixel = 8; v.bits_per_pixel = 8;
...@@ -1467,7 +1517,7 @@ static int ...@@ -1467,7 +1517,7 @@ static int
intelfb_cursor(struct fb_info *info, struct fb_cursor *cursor) intelfb_cursor(struct fb_info *info, struct fb_cursor *cursor)
{ {
struct intelfb_info *dinfo = GET_DINFO(info); struct intelfb_info *dinfo = GET_DINFO(info);
u32 physical;
#if VERBOSE > 0 #if VERBOSE > 0
DBG_MSG("intelfb_cursor\n"); DBG_MSG("intelfb_cursor\n");
#endif #endif
...@@ -1478,7 +1528,10 @@ intelfb_cursor(struct fb_info *info, struct fb_cursor *cursor) ...@@ -1478,7 +1528,10 @@ intelfb_cursor(struct fb_info *info, struct fb_cursor *cursor)
intelfbhw_cursor_hide(dinfo); intelfbhw_cursor_hide(dinfo);
/* If XFree killed the cursor - restore it */ /* If XFree killed the cursor - restore it */
if (INREG(CURSOR_A_BASEADDR) != dinfo->cursor.offset << 12) { physical = (dinfo->mobile || IS_I9XX(dinfo)) ? dinfo->cursor.physical :
(dinfo->cursor.offset << 12);
if (INREG(CURSOR_A_BASEADDR) != physical) {
u32 fg, bg; u32 fg, bg;
DBG_MSG("the cursor was killed - restore it !!\n"); DBG_MSG("the cursor was killed - restore it !!\n");
......
...@@ -40,68 +40,110 @@ ...@@ -40,68 +40,110 @@
#include "intelfb.h" #include "intelfb.h"
#include "intelfbhw.h" #include "intelfbhw.h"
struct pll_min_max {
int min_m, max_m, min_m1, max_m1;
int min_m2, max_m2, min_n, max_n;
int min_p, max_p, min_p1, max_p1;
int min_vco, max_vco, p_transition_clk, ref_clk;
int p_inc_lo, p_inc_hi;
};
#define PLLS_I8xx 0
#define PLLS_I9xx 1
#define PLLS_MAX 2
static struct pll_min_max plls[PLLS_MAX] = {
{ 108, 140, 18, 26,
6, 16, 3, 16,
4, 128, 0, 31,
930000, 1400000, 165000, 48000,
4, 2 }, //I8xx
{ 75, 120, 10, 20,
5, 9, 4, 7,
5, 80, 1, 8,
1400000, 2800000, 200000, 96000,
10, 5 } //I9xx
};
int int
intelfbhw_get_chipset(struct pci_dev *pdev, const char **name, int *chipset, intelfbhw_get_chipset(struct pci_dev *pdev, struct intelfb_info *dinfo)
int *mobile)
{ {
u32 tmp; u32 tmp;
if (!pdev || !dinfo)
if (!pdev || !name || !chipset || !mobile)
return 1; return 1;
switch (pdev->device) { switch (pdev->device) {
case PCI_DEVICE_ID_INTEL_830M: case PCI_DEVICE_ID_INTEL_830M:
*name = "Intel(R) 830M"; dinfo->name = "Intel(R) 830M";
*chipset = INTEL_830M; dinfo->chipset = INTEL_830M;
*mobile = 1; dinfo->mobile = 1;
dinfo->pll_index = PLLS_I8xx;
return 0; return 0;
case PCI_DEVICE_ID_INTEL_845G: case PCI_DEVICE_ID_INTEL_845G:
*name = "Intel(R) 845G"; dinfo->name = "Intel(R) 845G";
*chipset = INTEL_845G; dinfo->chipset = INTEL_845G;
*mobile = 0; dinfo->mobile = 0;
dinfo->pll_index = PLLS_I8xx;
return 0; return 0;
case PCI_DEVICE_ID_INTEL_85XGM: case PCI_DEVICE_ID_INTEL_85XGM:
tmp = 0; tmp = 0;
*mobile = 1; dinfo->mobile = 1;
dinfo->pll_index = PLLS_I8xx;
pci_read_config_dword(pdev, INTEL_85X_CAPID, &tmp); pci_read_config_dword(pdev, INTEL_85X_CAPID, &tmp);
switch ((tmp >> INTEL_85X_VARIANT_SHIFT) & switch ((tmp >> INTEL_85X_VARIANT_SHIFT) &
INTEL_85X_VARIANT_MASK) { INTEL_85X_VARIANT_MASK) {
case INTEL_VAR_855GME: case INTEL_VAR_855GME:
*name = "Intel(R) 855GME"; dinfo->name = "Intel(R) 855GME";
*chipset = INTEL_855GME; dinfo->chipset = INTEL_855GME;
return 0; return 0;
case INTEL_VAR_855GM: case INTEL_VAR_855GM:
*name = "Intel(R) 855GM"; dinfo->name = "Intel(R) 855GM";
*chipset = INTEL_855GM; dinfo->chipset = INTEL_855GM;
return 0; return 0;
case INTEL_VAR_852GME: case INTEL_VAR_852GME:
*name = "Intel(R) 852GME"; dinfo->name = "Intel(R) 852GME";
*chipset = INTEL_852GME; dinfo->chipset = INTEL_852GME;
return 0; return 0;
case INTEL_VAR_852GM: case INTEL_VAR_852GM:
*name = "Intel(R) 852GM"; dinfo->name = "Intel(R) 852GM";
*chipset = INTEL_852GM; dinfo->chipset = INTEL_852GM;
return 0; return 0;
default: default:
*name = "Intel(R) 852GM/855GM"; dinfo->name = "Intel(R) 852GM/855GM";
*chipset = INTEL_85XGM; dinfo->chipset = INTEL_85XGM;
return 0; return 0;
} }
break; break;
case PCI_DEVICE_ID_INTEL_865G: case PCI_DEVICE_ID_INTEL_865G:
*name = "Intel(R) 865G"; dinfo->name = "Intel(R) 865G";
*chipset = INTEL_865G; dinfo->chipset = INTEL_865G;
*mobile = 0; dinfo->mobile = 0;
dinfo->pll_index = PLLS_I8xx;
return 0; return 0;
case PCI_DEVICE_ID_INTEL_915G: case PCI_DEVICE_ID_INTEL_915G:
*name = "Intel(R) 915G"; dinfo->name = "Intel(R) 915G";
*chipset = INTEL_915G; dinfo->chipset = INTEL_915G;
*mobile = 0; dinfo->mobile = 0;
dinfo->pll_index = PLLS_I9xx;
return 0; return 0;
case PCI_DEVICE_ID_INTEL_915GM: case PCI_DEVICE_ID_INTEL_915GM:
*name = "Intel(R) 915GM"; dinfo->name = "Intel(R) 915GM";
*chipset = INTEL_915GM; dinfo->chipset = INTEL_915GM;
*mobile = 1; dinfo->mobile = 1;
dinfo->pll_index = PLLS_I9xx;
return 0;
case PCI_DEVICE_ID_INTEL_945G:
dinfo->name = "Intel(R) 945G";
dinfo->chipset = INTEL_945G;
dinfo->mobile = 0;
dinfo->pll_index = PLLS_I9xx;
return 0;
case PCI_DEVICE_ID_INTEL_945GM:
dinfo->name = "Intel(R) 945GM";
dinfo->chipset = INTEL_945GM;
dinfo->mobile = 1;
dinfo->pll_index = PLLS_I9xx;
return 0; return 0;
default: default:
return 1; return 1;
...@@ -114,6 +156,7 @@ intelfbhw_get_memory(struct pci_dev *pdev, int *aperture_size, ...@@ -114,6 +156,7 @@ intelfbhw_get_memory(struct pci_dev *pdev, int *aperture_size,
{ {
struct pci_dev *bridge_dev; struct pci_dev *bridge_dev;
u16 tmp; u16 tmp;
int stolen_overhead;
if (!pdev || !aperture_size || !stolen_size) if (!pdev || !aperture_size || !stolen_size)
return 1; return 1;
...@@ -128,21 +171,41 @@ intelfbhw_get_memory(struct pci_dev *pdev, int *aperture_size, ...@@ -128,21 +171,41 @@ intelfbhw_get_memory(struct pci_dev *pdev, int *aperture_size,
tmp = 0; tmp = 0;
pci_read_config_word(bridge_dev, INTEL_GMCH_CTRL, &tmp); pci_read_config_word(bridge_dev, INTEL_GMCH_CTRL, &tmp);
switch (pdev->device) { switch (pdev->device) {
case PCI_DEVICE_ID_INTEL_830M: case PCI_DEVICE_ID_INTEL_915G:
case PCI_DEVICE_ID_INTEL_845G: case PCI_DEVICE_ID_INTEL_915GM:
case PCI_DEVICE_ID_INTEL_945G:
case PCI_DEVICE_ID_INTEL_945GM:
/* 915 and 945 chipsets support a 256MB aperture.
Aperture size is determined by inspected the
base address of the aperture. */
if (pci_resource_start(pdev, 2) & 0x08000000)
*aperture_size = MB(128);
else
*aperture_size = MB(256);
break;
default:
if ((tmp & INTEL_GMCH_MEM_MASK) == INTEL_GMCH_MEM_64M) if ((tmp & INTEL_GMCH_MEM_MASK) == INTEL_GMCH_MEM_64M)
*aperture_size = MB(64); *aperture_size = MB(64);
else else
*aperture_size = MB(128); *aperture_size = MB(128);
break;
}
/* Stolen memory size is reduced by the GTT and the popup.
GTT is 1K per MB of aperture size, and popup is 4K. */
stolen_overhead = (*aperture_size / MB(1)) + 4;
switch(pdev->device) {
case PCI_DEVICE_ID_INTEL_830M:
case PCI_DEVICE_ID_INTEL_845G:
switch (tmp & INTEL_830_GMCH_GMS_MASK) { switch (tmp & INTEL_830_GMCH_GMS_MASK) {
case INTEL_830_GMCH_GMS_STOLEN_512: case INTEL_830_GMCH_GMS_STOLEN_512:
*stolen_size = KB(512) - KB(132); *stolen_size = KB(512) - KB(stolen_overhead);
return 0; return 0;
case INTEL_830_GMCH_GMS_STOLEN_1024: case INTEL_830_GMCH_GMS_STOLEN_1024:
*stolen_size = MB(1) - KB(132); *stolen_size = MB(1) - KB(stolen_overhead);
return 0; return 0;
case INTEL_830_GMCH_GMS_STOLEN_8192: case INTEL_830_GMCH_GMS_STOLEN_8192:
*stolen_size = MB(8) - KB(132); *stolen_size = MB(8) - KB(stolen_overhead);
return 0; return 0;
case INTEL_830_GMCH_GMS_LOCAL: case INTEL_830_GMCH_GMS_LOCAL:
ERR_MSG("only local memory found\n"); ERR_MSG("only local memory found\n");
...@@ -157,28 +220,27 @@ intelfbhw_get_memory(struct pci_dev *pdev, int *aperture_size, ...@@ -157,28 +220,27 @@ intelfbhw_get_memory(struct pci_dev *pdev, int *aperture_size,
} }
break; break;
default: default:
*aperture_size = MB(128);
switch (tmp & INTEL_855_GMCH_GMS_MASK) { switch (tmp & INTEL_855_GMCH_GMS_MASK) {
case INTEL_855_GMCH_GMS_STOLEN_1M: case INTEL_855_GMCH_GMS_STOLEN_1M:
*stolen_size = MB(1) - KB(132); *stolen_size = MB(1) - KB(stolen_overhead);
return 0; return 0;
case INTEL_855_GMCH_GMS_STOLEN_4M: case INTEL_855_GMCH_GMS_STOLEN_4M:
*stolen_size = MB(4) - KB(132); *stolen_size = MB(4) - KB(stolen_overhead);
return 0; return 0;
case INTEL_855_GMCH_GMS_STOLEN_8M: case INTEL_855_GMCH_GMS_STOLEN_8M:
*stolen_size = MB(8) - KB(132); *stolen_size = MB(8) - KB(stolen_overhead);
return 0; return 0;
case INTEL_855_GMCH_GMS_STOLEN_16M: case INTEL_855_GMCH_GMS_STOLEN_16M:
*stolen_size = MB(16) - KB(132); *stolen_size = MB(16) - KB(stolen_overhead);
return 0; return 0;
case INTEL_855_GMCH_GMS_STOLEN_32M: case INTEL_855_GMCH_GMS_STOLEN_32M:
*stolen_size = MB(32) - KB(132); *stolen_size = MB(32) - KB(stolen_overhead);
return 0; return 0;
case INTEL_915G_GMCH_GMS_STOLEN_48M: case INTEL_915G_GMCH_GMS_STOLEN_48M:
*stolen_size = MB(48) - KB(132); *stolen_size = MB(48) - KB(stolen_overhead);
return 0; return 0;
case INTEL_915G_GMCH_GMS_STOLEN_64M: case INTEL_915G_GMCH_GMS_STOLEN_64M:
*stolen_size = MB(64) - KB(132); *stolen_size = MB(64) - KB(stolen_overhead);
return 0; return 0;
case INTEL_855_GMCH_GMS_DISABLED: case INTEL_855_GMCH_GMS_DISABLED:
ERR_MSG("video memory is disabled\n"); ERR_MSG("video memory is disabled\n");
...@@ -529,12 +591,63 @@ intelfbhw_read_hw_state(struct intelfb_info *dinfo, struct intelfb_hwstate *hw, ...@@ -529,12 +591,63 @@ intelfbhw_read_hw_state(struct intelfb_info *dinfo, struct intelfb_hwstate *hw,
} }
static int calc_vclock3(int index, int m, int n, int p)
{
if (p == 0 || n == 0)
return 0;
return plls[index].ref_clk * m / n / p;
}
static int calc_vclock(int index, int m1, int m2, int n, int p1, int p2, int lvds)
{
struct pll_min_max *pll = &plls[index];
u32 m, vco, p;
m = (5 * (m1 + 2)) + (m2 + 2);
n += 2;
vco = pll->ref_clk * m / n;
if (index == PLLS_I8xx) {
p = ((p1 + 2) * (1 << (p2 + 1)));
} else {
p = ((p1) * (p2 ? 5 : 10));
}
return vco / p;
}
static void
intelfbhw_get_p1p2(struct intelfb_info *dinfo, int dpll, int *o_p1, int *o_p2)
{
int p1, p2;
if (IS_I9XX(dinfo)) {
if (dpll & DPLL_P1_FORCE_DIV2)
p1 = 1;
else
p1 = (dpll >> DPLL_P1_SHIFT) & 0xff;
p1 = ffs(p1);
p2 = (dpll >> DPLL_I9XX_P2_SHIFT) & DPLL_P2_MASK;
} else {
if (dpll & DPLL_P1_FORCE_DIV2)
p1 = 0;
else
p1 = (dpll >> DPLL_P1_SHIFT) & DPLL_P1_MASK;
p2 = (dpll >> DPLL_P2_SHIFT) & DPLL_P2_MASK;
}
*o_p1 = p1;
*o_p2 = p2;
}
void void
intelfbhw_print_hw_state(struct intelfb_info *dinfo, struct intelfb_hwstate *hw) intelfbhw_print_hw_state(struct intelfb_info *dinfo, struct intelfb_hwstate *hw)
{ {
#if REGDUMP #if REGDUMP
int i, m1, m2, n, p1, p2; int i, m1, m2, n, p1, p2;
int index = dinfo->pll_index;
DBG_MSG("intelfbhw_print_hw_state\n"); DBG_MSG("intelfbhw_print_hw_state\n");
if (!hw || !dinfo) if (!hw || !dinfo)
...@@ -547,26 +660,22 @@ intelfbhw_print_hw_state(struct intelfb_info *dinfo, struct intelfb_hwstate *hw) ...@@ -547,26 +660,22 @@ intelfbhw_print_hw_state(struct intelfb_info *dinfo, struct intelfb_hwstate *hw)
n = (hw->vga0_divisor >> FP_N_DIVISOR_SHIFT) & FP_DIVISOR_MASK; n = (hw->vga0_divisor >> FP_N_DIVISOR_SHIFT) & FP_DIVISOR_MASK;
m1 = (hw->vga0_divisor >> FP_M1_DIVISOR_SHIFT) & FP_DIVISOR_MASK; m1 = (hw->vga0_divisor >> FP_M1_DIVISOR_SHIFT) & FP_DIVISOR_MASK;
m2 = (hw->vga0_divisor >> FP_M2_DIVISOR_SHIFT) & FP_DIVISOR_MASK; m2 = (hw->vga0_divisor >> FP_M2_DIVISOR_SHIFT) & FP_DIVISOR_MASK;
if (hw->vga_pd & VGAPD_0_P1_FORCE_DIV2)
p1 = 0; intelfbhw_get_p1p2(dinfo, hw->vga_pd, &p1, &p2);
else
p1 = (hw->vga_pd >> VGAPD_0_P1_SHIFT) & DPLL_P1_MASK;
p2 = (hw->vga_pd >> VGAPD_0_P2_SHIFT) & DPLL_P2_MASK;
printk(" VGA0: (m1, m2, n, p1, p2) = (%d, %d, %d, %d, %d)\n", printk(" VGA0: (m1, m2, n, p1, p2) = (%d, %d, %d, %d, %d)\n",
m1, m2, n, p1, p2); m1, m2, n, p1, p2);
printk(" VGA0: clock is %d\n", CALC_VCLOCK(m1, m2, n, p1, p2)); printk(" VGA0: clock is %d\n",
calc_vclock(index, m1, m2, n, p1, p2, 0));
n = (hw->vga1_divisor >> FP_N_DIVISOR_SHIFT) & FP_DIVISOR_MASK; n = (hw->vga1_divisor >> FP_N_DIVISOR_SHIFT) & FP_DIVISOR_MASK;
m1 = (hw->vga1_divisor >> FP_M1_DIVISOR_SHIFT) & FP_DIVISOR_MASK; m1 = (hw->vga1_divisor >> FP_M1_DIVISOR_SHIFT) & FP_DIVISOR_MASK;
m2 = (hw->vga1_divisor >> FP_M2_DIVISOR_SHIFT) & FP_DIVISOR_MASK; m2 = (hw->vga1_divisor >> FP_M2_DIVISOR_SHIFT) & FP_DIVISOR_MASK;
if (hw->vga_pd & VGAPD_1_P1_FORCE_DIV2)
p1 = 0; intelfbhw_get_p1p2(dinfo, hw->vga_pd, &p1, &p2);
else
p1 = (hw->vga_pd >> VGAPD_1_P1_SHIFT) & DPLL_P1_MASK;
p2 = (hw->vga_pd >> VGAPD_1_P2_SHIFT) & DPLL_P2_MASK;
printk(" VGA1: (m1, m2, n, p1, p2) = (%d, %d, %d, %d, %d)\n", printk(" VGA1: (m1, m2, n, p1, p2) = (%d, %d, %d, %d, %d)\n",
m1, m2, n, p1, p2); m1, m2, n, p1, p2);
printk(" VGA1: clock is %d\n", CALC_VCLOCK(m1, m2, n, p1, p2)); printk(" VGA1: clock is %d\n", calc_vclock(index, m1, m2, n, p1, p2, 0));
printk(" DPLL_A: 0x%08x\n", hw->dpll_a); printk(" DPLL_A: 0x%08x\n", hw->dpll_a);
printk(" DPLL_B: 0x%08x\n", hw->dpll_b); printk(" DPLL_B: 0x%08x\n", hw->dpll_b);
...@@ -578,34 +687,30 @@ intelfbhw_print_hw_state(struct intelfb_info *dinfo, struct intelfb_hwstate *hw) ...@@ -578,34 +687,30 @@ intelfbhw_print_hw_state(struct intelfb_info *dinfo, struct intelfb_hwstate *hw)
n = (hw->fpa0 >> FP_N_DIVISOR_SHIFT) & FP_DIVISOR_MASK; n = (hw->fpa0 >> FP_N_DIVISOR_SHIFT) & FP_DIVISOR_MASK;
m1 = (hw->fpa0 >> FP_M1_DIVISOR_SHIFT) & FP_DIVISOR_MASK; m1 = (hw->fpa0 >> FP_M1_DIVISOR_SHIFT) & FP_DIVISOR_MASK;
m2 = (hw->fpa0 >> FP_M2_DIVISOR_SHIFT) & FP_DIVISOR_MASK; m2 = (hw->fpa0 >> FP_M2_DIVISOR_SHIFT) & FP_DIVISOR_MASK;
if (hw->dpll_a & DPLL_P1_FORCE_DIV2)
p1 = 0; intelfbhw_get_p1p2(dinfo, hw->dpll_a, &p1, &p2);
else
p1 = (hw->dpll_a >> DPLL_P1_SHIFT) & DPLL_P1_MASK;
p2 = (hw->dpll_a >> DPLL_P2_SHIFT) & DPLL_P2_MASK;
printk(" PLLA0: (m1, m2, n, p1, p2) = (%d, %d, %d, %d, %d)\n", printk(" PLLA0: (m1, m2, n, p1, p2) = (%d, %d, %d, %d, %d)\n",
m1, m2, n, p1, p2); m1, m2, n, p1, p2);
printk(" PLLA0: clock is %d\n", CALC_VCLOCK(m1, m2, n, p1, p2)); printk(" PLLA0: clock is %d\n", calc_vclock(index, m1, m2, n, p1, p2, 0));
n = (hw->fpa1 >> FP_N_DIVISOR_SHIFT) & FP_DIVISOR_MASK; n = (hw->fpa1 >> FP_N_DIVISOR_SHIFT) & FP_DIVISOR_MASK;
m1 = (hw->fpa1 >> FP_M1_DIVISOR_SHIFT) & FP_DIVISOR_MASK; m1 = (hw->fpa1 >> FP_M1_DIVISOR_SHIFT) & FP_DIVISOR_MASK;
m2 = (hw->fpa1 >> FP_M2_DIVISOR_SHIFT) & FP_DIVISOR_MASK; m2 = (hw->fpa1 >> FP_M2_DIVISOR_SHIFT) & FP_DIVISOR_MASK;
if (hw->dpll_a & DPLL_P1_FORCE_DIV2)
p1 = 0; intelfbhw_get_p1p2(dinfo, hw->dpll_a, &p1, &p2);
else
p1 = (hw->dpll_a >> DPLL_P1_SHIFT) & DPLL_P1_MASK;
p2 = (hw->dpll_a >> DPLL_P2_SHIFT) & DPLL_P2_MASK;
printk(" PLLA1: (m1, m2, n, p1, p2) = (%d, %d, %d, %d, %d)\n", printk(" PLLA1: (m1, m2, n, p1, p2) = (%d, %d, %d, %d, %d)\n",
m1, m2, n, p1, p2); m1, m2, n, p1, p2);
printk(" PLLA1: clock is %d\n", CALC_VCLOCK(m1, m2, n, p1, p2)); printk(" PLLA1: clock is %d\n", calc_vclock(index, m1, m2, n, p1, p2, 0));
#if 0 #if 0
printk(" PALETTE_A:\n"); printk(" PALETTE_A:\n");
for (i = 0; i < PALETTE_8_ENTRIES) for (i = 0; i < PALETTE_8_ENTRIES)
printk(" %3d: 0x%08x\n", i, hw->palette_a[i]; printk(" %3d: 0x%08x\n", i, hw->palette_a[i]);
printk(" PALETTE_B:\n"); printk(" PALETTE_B:\n");
for (i = 0; i < PALETTE_8_ENTRIES) for (i = 0; i < PALETTE_8_ENTRIES)
printk(" %3d: 0x%08x\n", i, hw->palette_b[i]; printk(" %3d: 0x%08x\n", i, hw->palette_b[i]);
#endif #endif
printk(" HTOTAL_A: 0x%08x\n", hw->htotal_a); printk(" HTOTAL_A: 0x%08x\n", hw->htotal_a);
...@@ -680,11 +785,11 @@ intelfbhw_print_hw_state(struct intelfb_info *dinfo, struct intelfb_hwstate *hw) ...@@ -680,11 +785,11 @@ intelfbhw_print_hw_state(struct intelfb_info *dinfo, struct intelfb_hwstate *hw)
} }
for (i = 0; i < 3; i++) { for (i = 0; i < 3; i++) {
printk(" SWF3%d 0x%08x\n", i, printk(" SWF3%d 0x%08x\n", i,
hw->swf3x[i]); hw->swf3x[i]);
} }
for (i = 0; i < 8; i++) for (i = 0; i < 8; i++)
printk(" FENCE%d 0x%08x\n", i, printk(" FENCE%d 0x%08x\n", i,
hw->fence[i]); hw->fence[i]);
printk(" INSTPM 0x%08x\n", hw->instpm); printk(" INSTPM 0x%08x\n", hw->instpm);
printk(" MEM_MODE 0x%08x\n", hw->mem_mode); printk(" MEM_MODE 0x%08x\n", hw->mem_mode);
...@@ -695,43 +800,58 @@ intelfbhw_print_hw_state(struct intelfb_info *dinfo, struct intelfb_hwstate *hw) ...@@ -695,43 +800,58 @@ intelfbhw_print_hw_state(struct intelfb_info *dinfo, struct intelfb_hwstate *hw)
#endif #endif
} }
/* Split the M parameter into M1 and M2. */ /* Split the M parameter into M1 and M2. */
static int static int
splitm(unsigned int m, unsigned int *retm1, unsigned int *retm2) splitm(int index, unsigned int m, unsigned int *retm1, unsigned int *retm2)
{ {
int m1, m2; int m1, m2;
int testm;
m1 = (m - 2 - (MIN_M2 + MAX_M2) / 2) / 5 - 2; struct pll_min_max *pll = &plls[index];
if (m1 < MIN_M1)
m1 = MIN_M1; /* no point optimising too much - brute force m */
if (m1 > MAX_M1) for (m1 = pll->min_m1; m1 < pll->max_m1 + 1; m1++) {
m1 = MAX_M1; for (m2 = pll->min_m2; m2 < pll->max_m2 + 1; m2++) {
m2 = m - 5 * (m1 + 2) - 2; testm = (5 * (m1 + 2)) + (m2 + 2);
if (m2 < MIN_M2 || m2 > MAX_M2 || m2 >= m1) { if (testm == m) {
return 1; *retm1 = (unsigned int)m1;
} else { *retm2 = (unsigned int)m2;
*retm1 = (unsigned int)m1; return 0;
*retm2 = (unsigned int)m2; }
return 0; }
} }
return 1;
} }
/* Split the P parameter into P1 and P2. */ /* Split the P parameter into P1 and P2. */
static int static int
splitp(unsigned int p, unsigned int *retp1, unsigned int *retp2) splitp(int index, unsigned int p, unsigned int *retp1, unsigned int *retp2)
{ {
int p1, p2; int p1, p2;
struct pll_min_max *pll = &plls[index];
if (index == PLLS_I9xx) {
p2 = (p % 10) ? 1 : 0;
p1 = p / (p2 ? 5 : 10);
*retp1 = (unsigned int)p1;
*retp2 = (unsigned int)p2;
return 0;
}
if (p % 4 == 0) if (p % 4 == 0)
p2 = 1; p2 = 1;
else else
p2 = 0; p2 = 0;
p1 = (p / (1 << (p2 + 1))) - 2; p1 = (p / (1 << (p2 + 1))) - 2;
if (p % 4 == 0 && p1 < MIN_P1) { if (p % 4 == 0 && p1 < pll->min_p1) {
p2 = 0; p2 = 0;
p1 = (p / (1 << (p2 + 1))) - 2; p1 = (p / (1 << (p2 + 1))) - 2;
} }
if (p1 < MIN_P1 || p1 > MAX_P1 || (p1 + 2) * (1 << (p2 + 1)) != p) { if (p1 < pll->min_p1 || p1 > pll->max_p1 ||
(p1 + 2) * (1 << (p2 + 1)) != p) {
return 1; return 1;
} else { } else {
*retp1 = (unsigned int)p1; *retp1 = (unsigned int)p1;
...@@ -741,14 +861,15 @@ splitp(unsigned int p, unsigned int *retp1, unsigned int *retp2) ...@@ -741,14 +861,15 @@ splitp(unsigned int p, unsigned int *retp1, unsigned int *retp2)
} }
static int static int
calc_pll_params(int clock, u32 *retm1, u32 *retm2, u32 *retn, u32 *retp1, calc_pll_params(int index, int clock, u32 *retm1, u32 *retm2, u32 *retn, u32 *retp1,
u32 *retp2, u32 *retclock) u32 *retp2, u32 *retclock)
{ {
u32 m1, m2, n, p1, p2, n1; u32 m1, m2, n, p1, p2, n1, testm;
u32 f_vco, p, p_best = 0, m, f_out; u32 f_vco, p, p_best = 0, m, f_out = 0;
u32 err_max, err_target, err_best = 10000000; u32 err_max, err_target, err_best = 10000000;
u32 n_best = 0, m_best = 0, f_best, f_err; u32 n_best = 0, m_best = 0, f_best, f_err;
u32 p_min, p_max, p_inc, div_min, div_max; u32 p_min, p_max, p_inc, div_max;
struct pll_min_max *pll = &plls[index];
/* Accept 0.5% difference, but aim for 0.1% */ /* Accept 0.5% difference, but aim for 0.1% */
err_max = 5 * clock / 1000; err_max = 5 * clock / 1000;
...@@ -756,58 +877,56 @@ calc_pll_params(int clock, u32 *retm1, u32 *retm2, u32 *retn, u32 *retp1, ...@@ -756,58 +877,56 @@ calc_pll_params(int clock, u32 *retm1, u32 *retm2, u32 *retn, u32 *retp1,
DBG_MSG("Clock is %d\n", clock); DBG_MSG("Clock is %d\n", clock);
div_max = MAX_VCO_FREQ / clock; div_max = pll->max_vco / clock;
div_min = ROUND_UP_TO(MIN_VCO_FREQ, clock) / clock;
if (clock <= P_TRANSITION_CLOCK) p_inc = (clock <= pll->p_transition_clk) ? pll->p_inc_lo : pll->p_inc_hi;
p_inc = 4; p_min = p_inc;
else
p_inc = 2;
p_min = ROUND_UP_TO(div_min, p_inc);
p_max = ROUND_DOWN_TO(div_max, p_inc); p_max = ROUND_DOWN_TO(div_max, p_inc);
if (p_min < MIN_P) if (p_min < pll->min_p)
p_min = 4; p_min = pll->min_p;
if (p_max > MAX_P) if (p_max > pll->max_p)
p_max = 128; p_max = pll->max_p;
DBG_MSG("p range is %d-%d (%d)\n", p_min, p_max, p_inc); DBG_MSG("p range is %d-%d (%d)\n", p_min, p_max, p_inc);
p = p_min; p = p_min;
do { do {
if (splitp(p, &p1, &p2)) { if (splitp(index, p, &p1, &p2)) {
WRN_MSG("cannot split p = %d\n", p); WRN_MSG("cannot split p = %d\n", p);
p += p_inc; p += p_inc;
continue; continue;
} }
n = MIN_N; n = pll->min_n;
f_vco = clock * p; f_vco = clock * p;
do { do {
m = ROUND_UP_TO(f_vco * n, PLL_REFCLK) / PLL_REFCLK; m = ROUND_UP_TO(f_vco * n, pll->ref_clk) / pll->ref_clk;
if (m < MIN_M) if (m < pll->min_m)
m = MIN_M; m = pll->min_m + 1;
if (m > MAX_M) if (m > pll->max_m)
m = MAX_M; m = pll->max_m - 1;
f_out = CALC_VCLOCK3(m, n, p); for (testm = m - 1; testm <= m; testm++) {
if (splitm(m, &m1, &m2)) { f_out = calc_vclock3(index, m, n, p);
WRN_MSG("cannot split m = %d\n", m); if (splitm(index, testm, &m1, &m2)) {
n++; WRN_MSG("cannot split m = %d\n", m);
continue; n++;
} continue;
if (clock > f_out) }
f_err = clock - f_out; if (clock > f_out)
else f_err = clock - f_out;
f_err = f_out - clock; else/* slightly bias the error for bigger clocks */
f_err = f_out - clock + 1;
if (f_err < err_best) {
m_best = m; if (f_err < err_best) {
n_best = n; m_best = testm;
p_best = p; n_best = n;
f_best = f_out; p_best = p;
err_best = f_err; f_best = f_out;
err_best = f_err;
}
} }
n++; n++;
} while ((n <= MAX_N) && (f_out >= clock)); } while ((n <= pll->max_n) && (f_out >= clock));
p += p_inc; p += p_inc;
} while ((p <= p_max)); } while ((p <= p_max));
...@@ -818,21 +937,22 @@ calc_pll_params(int clock, u32 *retm1, u32 *retm2, u32 *retn, u32 *retp1, ...@@ -818,21 +937,22 @@ calc_pll_params(int clock, u32 *retm1, u32 *retm2, u32 *retn, u32 *retp1,
m = m_best; m = m_best;
n = n_best; n = n_best;
p = p_best; p = p_best;
splitm(m, &m1, &m2); splitm(index, m, &m1, &m2);
splitp(p, &p1, &p2); splitp(index, p, &p1, &p2);
n1 = n - 2; n1 = n - 2;
DBG_MSG("m, n, p: %d (%d,%d), %d (%d), %d (%d,%d), " DBG_MSG("m, n, p: %d (%d,%d), %d (%d), %d (%d,%d), "
"f: %d (%d), VCO: %d\n", "f: %d (%d), VCO: %d\n",
m, m1, m2, n, n1, p, p1, p2, m, m1, m2, n, n1, p, p1, p2,
CALC_VCLOCK3(m, n, p), CALC_VCLOCK(m1, m2, n1, p1, p2), calc_vclock3(index, m, n, p),
CALC_VCLOCK3(m, n, p) * p); calc_vclock(index, m1, m2, n1, p1, p2, 0),
calc_vclock3(index, m, n, p) * p);
*retm1 = m1; *retm1 = m1;
*retm2 = m2; *retm2 = m2;
*retn = n1; *retn = n1;
*retp1 = p1; *retp1 = p1;
*retp2 = p2; *retp2 = p2;
*retclock = CALC_VCLOCK(m1, m2, n1, p1, p2); *retclock = calc_vclock(index, m1, m2, n1, p1, p2, 0);
return 0; return 0;
} }
...@@ -860,6 +980,7 @@ intelfbhw_mode_to_hw(struct intelfb_info *dinfo, struct intelfb_hwstate *hw, ...@@ -860,6 +980,7 @@ intelfbhw_mode_to_hw(struct intelfb_info *dinfo, struct intelfb_hwstate *hw,
u32 vsync_start, vsync_end, vblank_start, vblank_end, vtotal, vactive; u32 vsync_start, vsync_end, vblank_start, vblank_end, vtotal, vactive;
u32 vsync_pol, hsync_pol; u32 vsync_pol, hsync_pol;
u32 *vs, *vb, *vt, *hs, *hb, *ht, *ss, *pipe_conf; u32 *vs, *vb, *vt, *hs, *hb, *ht, *ss, *pipe_conf;
u32 stride_alignment;
DBG_MSG("intelfbhw_mode_to_hw\n"); DBG_MSG("intelfbhw_mode_to_hw\n");
...@@ -929,7 +1050,8 @@ intelfbhw_mode_to_hw(struct intelfb_info *dinfo, struct intelfb_hwstate *hw, ...@@ -929,7 +1050,8 @@ intelfbhw_mode_to_hw(struct intelfb_info *dinfo, struct intelfb_hwstate *hw,
/* Desired clock in kHz */ /* Desired clock in kHz */
clock_target = 1000000000 / var->pixclock; clock_target = 1000000000 / var->pixclock;
if (calc_pll_params(clock_target, &m1, &m2, &n, &p1, &p2, &clock)) { if (calc_pll_params(dinfo->pll_index, clock_target, &m1, &m2,
&n, &p1, &p2, &clock)) {
WRN_MSG("calc_pll_params failed\n"); WRN_MSG("calc_pll_params failed\n");
return 1; return 1;
} }
...@@ -949,7 +1071,14 @@ intelfbhw_mode_to_hw(struct intelfb_info *dinfo, struct intelfb_hwstate *hw, ...@@ -949,7 +1071,14 @@ intelfbhw_mode_to_hw(struct intelfb_info *dinfo, struct intelfb_hwstate *hw,
*dpll &= ~DPLL_P1_FORCE_DIV2; *dpll &= ~DPLL_P1_FORCE_DIV2;
*dpll &= ~((DPLL_P2_MASK << DPLL_P2_SHIFT) | *dpll &= ~((DPLL_P2_MASK << DPLL_P2_SHIFT) |
(DPLL_P1_MASK << DPLL_P1_SHIFT)); (DPLL_P1_MASK << DPLL_P1_SHIFT));
*dpll |= (p2 << DPLL_P2_SHIFT) | (p1 << DPLL_P1_SHIFT);
if (IS_I9XX(dinfo)) {
*dpll |= (p2 << DPLL_I9XX_P2_SHIFT);
*dpll |= (1 << (p1 - 1)) << DPLL_P1_SHIFT;
} else {
*dpll |= (p2 << DPLL_P2_SHIFT) | (p1 << DPLL_P1_SHIFT);
}
*fp0 = (n << FP_N_DIVISOR_SHIFT) | *fp0 = (n << FP_N_DIVISOR_SHIFT) |
(m1 << FP_M1_DIVISOR_SHIFT) | (m1 << FP_M1_DIVISOR_SHIFT) |
(m2 << FP_M2_DIVISOR_SHIFT); (m2 << FP_M2_DIVISOR_SHIFT);
...@@ -1054,7 +1183,7 @@ intelfbhw_mode_to_hw(struct intelfb_info *dinfo, struct intelfb_hwstate *hw, ...@@ -1054,7 +1183,7 @@ intelfbhw_mode_to_hw(struct intelfb_info *dinfo, struct intelfb_hwstate *hw,
*ss = (hactive << SRC_SIZE_HORIZ_SHIFT) | *ss = (hactive << SRC_SIZE_HORIZ_SHIFT) |
(vactive << SRC_SIZE_VERT_SHIFT); (vactive << SRC_SIZE_VERT_SHIFT);
hw->disp_a_stride = var->xres_virtual * var->bits_per_pixel / 8; hw->disp_a_stride = dinfo->pitch;
DBG_MSG("pitch is %d\n", hw->disp_a_stride); DBG_MSG("pitch is %d\n", hw->disp_a_stride);
hw->disp_a_base = hw->disp_a_stride * var->yoffset + hw->disp_a_base = hw->disp_a_stride * var->yoffset +
...@@ -1063,9 +1192,11 @@ intelfbhw_mode_to_hw(struct intelfb_info *dinfo, struct intelfb_hwstate *hw, ...@@ -1063,9 +1192,11 @@ intelfbhw_mode_to_hw(struct intelfb_info *dinfo, struct intelfb_hwstate *hw,
hw->disp_a_base += dinfo->fb.offset << 12; hw->disp_a_base += dinfo->fb.offset << 12;
/* Check stride alignment. */ /* Check stride alignment. */
if (hw->disp_a_stride % STRIDE_ALIGNMENT != 0) { stride_alignment = IS_I9XX(dinfo) ? STRIDE_ALIGNMENT_I9XX :
STRIDE_ALIGNMENT;
if (hw->disp_a_stride % stride_alignment != 0) {
WRN_MSG("display stride %d has bad alignment %d\n", WRN_MSG("display stride %d has bad alignment %d\n",
hw->disp_a_stride, STRIDE_ALIGNMENT); hw->disp_a_stride, stride_alignment);
return 1; return 1;
} }
...@@ -1087,6 +1218,7 @@ intelfbhw_program_mode(struct intelfb_info *dinfo, ...@@ -1087,6 +1218,7 @@ intelfbhw_program_mode(struct intelfb_info *dinfo,
u32 hsync_reg, htotal_reg, hblank_reg; u32 hsync_reg, htotal_reg, hblank_reg;
u32 vsync_reg, vtotal_reg, vblank_reg; u32 vsync_reg, vtotal_reg, vblank_reg;
u32 src_size_reg; u32 src_size_reg;
u32 count, tmp_val[3];
/* Assume single pipe, display plane A, analog CRT. */ /* Assume single pipe, display plane A, analog CRT. */
...@@ -1155,6 +1287,27 @@ intelfbhw_program_mode(struct intelfb_info *dinfo, ...@@ -1155,6 +1287,27 @@ intelfbhw_program_mode(struct intelfb_info *dinfo,
src_size_reg = SRC_SIZE_A; src_size_reg = SRC_SIZE_A;
} }
/* turn off pipe */
tmp = INREG(pipe_conf_reg);
tmp &= ~PIPECONF_ENABLE;
OUTREG(pipe_conf_reg, tmp);
count = 0;
do {
tmp_val[count%3] = INREG(0x70000);
if ((tmp_val[0] == tmp_val[1]) && (tmp_val[1]==tmp_val[2]))
break;
count++;
udelay(1);
if (count % 200 == 0) {
tmp = INREG(pipe_conf_reg);
tmp &= ~PIPECONF_ENABLE;
OUTREG(pipe_conf_reg, tmp);
}
} while(count < 2000);
OUTREG(ADPA, INREG(ADPA) & ~ADPA_DAC_ENABLE);
/* Disable planes A and B. */ /* Disable planes A and B. */
tmp = INREG(DSPACNTR); tmp = INREG(DSPACNTR);
tmp &= ~DISPPLANE_PLANE_ENABLE; tmp &= ~DISPPLANE_PLANE_ENABLE;
...@@ -1163,19 +1316,21 @@ intelfbhw_program_mode(struct intelfb_info *dinfo, ...@@ -1163,19 +1316,21 @@ intelfbhw_program_mode(struct intelfb_info *dinfo,
tmp &= ~DISPPLANE_PLANE_ENABLE; tmp &= ~DISPPLANE_PLANE_ENABLE;
OUTREG(DSPBCNTR, tmp); OUTREG(DSPBCNTR, tmp);
/* Wait for vblank. For now, just wait for a 50Hz cycle (20ms)) */ /* Wait for vblank. For now, just wait for a 50Hz cycle (20ms)) */
mdelay(20); mdelay(20);
OUTREG(DVOB, INREG(DVOB) & ~PORT_ENABLE);
OUTREG(DVOC, INREG(DVOC) & ~PORT_ENABLE);
OUTREG(ADPA, INREG(ADPA) & ~ADPA_DAC_ENABLE);
/* Disable Sync */ /* Disable Sync */
tmp = INREG(ADPA); tmp = INREG(ADPA);
tmp &= ~ADPA_DPMS_CONTROL_MASK; tmp &= ~ADPA_DPMS_CONTROL_MASK;
tmp |= ADPA_DPMS_D3; tmp |= ADPA_DPMS_D3;
OUTREG(ADPA, tmp); OUTREG(ADPA, tmp);
/* turn off pipe */ /* do some funky magic - xyzzy */
tmp = INREG(pipe_conf_reg); OUTREG(0x61204, 0xabcd0000);
tmp &= ~PIPECONF_ENABLE;
OUTREG(pipe_conf_reg, tmp);
/* turn off PLL */ /* turn off PLL */
tmp = INREG(dpll_reg); tmp = INREG(dpll_reg);
...@@ -1183,30 +1338,31 @@ intelfbhw_program_mode(struct intelfb_info *dinfo, ...@@ -1183,30 +1338,31 @@ intelfbhw_program_mode(struct intelfb_info *dinfo,
OUTREG(dpll_reg, tmp); OUTREG(dpll_reg, tmp);
/* Set PLL parameters */ /* Set PLL parameters */
OUTREG(dpll_reg, *dpll & ~DPLL_VCO_ENABLE);
OUTREG(fp0_reg, *fp0); OUTREG(fp0_reg, *fp0);
OUTREG(fp1_reg, *fp1); OUTREG(fp1_reg, *fp1);
/* Set pipe parameters */ /* Enable PLL */
OUTREG(hsync_reg, *hs); OUTREG(dpll_reg, *dpll);
OUTREG(hblank_reg, *hb);
OUTREG(htotal_reg, *ht);
OUTREG(vsync_reg, *vs);
OUTREG(vblank_reg, *vb);
OUTREG(vtotal_reg, *vt);
OUTREG(src_size_reg, *ss);
/* Set DVOs B/C */ /* Set DVOs B/C */
OUTREG(DVOB, hw->dvob); OUTREG(DVOB, hw->dvob);
OUTREG(DVOC, hw->dvoc); OUTREG(DVOC, hw->dvoc);
/* undo funky magic */
OUTREG(0x61204, 0x00000000);
/* Set ADPA */ /* Set ADPA */
OUTREG(ADPA, INREG(ADPA) | ADPA_DAC_ENABLE);
OUTREG(ADPA, (hw->adpa & ~(ADPA_DPMS_CONTROL_MASK)) | ADPA_DPMS_D3); OUTREG(ADPA, (hw->adpa & ~(ADPA_DPMS_CONTROL_MASK)) | ADPA_DPMS_D3);
/* Enable PLL */ /* Set pipe parameters */
tmp = INREG(dpll_reg); OUTREG(hsync_reg, *hs);
tmp |= DPLL_VCO_ENABLE; OUTREG(hblank_reg, *hb);
OUTREG(dpll_reg, tmp); OUTREG(htotal_reg, *ht);
OUTREG(vsync_reg, *vs);
OUTREG(vblank_reg, *vb);
OUTREG(vtotal_reg, *vt);
OUTREG(src_size_reg, *ss);
/* Enable pipe */ /* Enable pipe */
OUTREG(pipe_conf_reg, *pipe_conf | PIPECONF_ENABLE); OUTREG(pipe_conf_reg, *pipe_conf | PIPECONF_ENABLE);
...@@ -1231,7 +1387,7 @@ intelfbhw_program_mode(struct intelfb_info *dinfo, ...@@ -1231,7 +1387,7 @@ intelfbhw_program_mode(struct intelfb_info *dinfo,
OUTREG(DSPACNTR, OUTREG(DSPACNTR,
hw->disp_a_ctrl|DISPPLANE_PLANE_ENABLE); hw->disp_a_ctrl|DISPPLANE_PLANE_ENABLE);
mdelay(1); mdelay(1);
} }
} }
OUTREG(DSPACNTR, hw->disp_a_ctrl & ~DISPPLANE_PLANE_ENABLE); OUTREG(DSPACNTR, hw->disp_a_ctrl & ~DISPPLANE_PLANE_ENABLE);
...@@ -1616,7 +1772,7 @@ intelfbhw_cursor_init(struct intelfb_info *dinfo) ...@@ -1616,7 +1772,7 @@ intelfbhw_cursor_init(struct intelfb_info *dinfo)
DBG_MSG("intelfbhw_cursor_init\n"); DBG_MSG("intelfbhw_cursor_init\n");
#endif #endif
if (dinfo->mobile) { if (dinfo->mobile || IS_I9XX(dinfo)) {
if (!dinfo->cursor.physical) if (!dinfo->cursor.physical)
return; return;
tmp = INREG(CURSOR_A_CONTROL); tmp = INREG(CURSOR_A_CONTROL);
...@@ -1649,7 +1805,7 @@ intelfbhw_cursor_hide(struct intelfb_info *dinfo) ...@@ -1649,7 +1805,7 @@ intelfbhw_cursor_hide(struct intelfb_info *dinfo)
#endif #endif
dinfo->cursor_on = 0; dinfo->cursor_on = 0;
if (dinfo->mobile) { if (dinfo->mobile || IS_I9XX(dinfo)) {
if (!dinfo->cursor.physical) if (!dinfo->cursor.physical)
return; return;
tmp = INREG(CURSOR_A_CONTROL); tmp = INREG(CURSOR_A_CONTROL);
...@@ -1679,7 +1835,7 @@ intelfbhw_cursor_show(struct intelfb_info *dinfo) ...@@ -1679,7 +1835,7 @@ intelfbhw_cursor_show(struct intelfb_info *dinfo)
if (dinfo->cursor_blanked) if (dinfo->cursor_blanked)
return; return;
if (dinfo->mobile) { if (dinfo->mobile || IS_I9XX(dinfo)) {
if (!dinfo->cursor.physical) if (!dinfo->cursor.physical)
return; return;
tmp = INREG(CURSOR_A_CONTROL); tmp = INREG(CURSOR_A_CONTROL);
...@@ -1705,14 +1861,18 @@ intelfbhw_cursor_setpos(struct intelfb_info *dinfo, int x, int y) ...@@ -1705,14 +1861,18 @@ intelfbhw_cursor_setpos(struct intelfb_info *dinfo, int x, int y)
#endif #endif
/* /*
* Sets the position. The coordinates are assumed to already * Sets the position. The coordinates are assumed to already
* have any offset adjusted. Assume that the cursor is never * have any offset adjusted. Assume that the cursor is never
* completely off-screen, and that x, y are always >= 0. * completely off-screen, and that x, y are always >= 0.
*/ */
tmp = ((x & CURSOR_POS_MASK) << CURSOR_X_SHIFT) | tmp = ((x & CURSOR_POS_MASK) << CURSOR_X_SHIFT) |
((y & CURSOR_POS_MASK) << CURSOR_Y_SHIFT); ((y & CURSOR_POS_MASK) << CURSOR_Y_SHIFT);
OUTREG(CURSOR_A_POSITION, tmp); OUTREG(CURSOR_A_POSITION, tmp);
if (IS_I9XX(dinfo)) {
OUTREG(CURSOR_A_BASEADDR, dinfo->cursor.physical);
}
} }
void void
......
...@@ -133,6 +133,7 @@ ...@@ -133,6 +133,7 @@
#define DPLL_VGA_MODE_DISABLE (1 << 28) #define DPLL_VGA_MODE_DISABLE (1 << 28)
#define DPLL_P2_MASK 1 #define DPLL_P2_MASK 1
#define DPLL_P2_SHIFT 23 #define DPLL_P2_SHIFT 23
#define DPLL_I9XX_P2_SHIFT 24
#define DPLL_P1_FORCE_DIV2 (1 << 21) #define DPLL_P1_FORCE_DIV2 (1 << 21)
#define DPLL_P1_MASK 0x1f #define DPLL_P1_MASK 0x1f
#define DPLL_P1_SHIFT 16 #define DPLL_P1_SHIFT 16
...@@ -155,29 +156,8 @@ ...@@ -155,29 +156,8 @@
/* PLL parameters (these are for 852GM/855GM/865G, check earlier chips). */ /* PLL parameters (these are for 852GM/855GM/865G, check earlier chips). */
/* Clock values are in units of kHz */ /* Clock values are in units of kHz */
#define PLL_REFCLK 48000 #define PLL_REFCLK 48000
#define MIN_VCO_FREQ 930000
#define MAX_VCO_FREQ 1400000
#define MIN_CLOCK 25000 #define MIN_CLOCK 25000
#define MAX_CLOCK 350000 #define MAX_CLOCK 350000
#define P_TRANSITION_CLOCK 165000
#define MIN_M 108
#define MAX_M 140
#define MIN_M1 18
#define MAX_M1 26
#define MIN_M2 6
#define MAX_M2 16
#define MIN_P 4
#define MAX_P 128
#define MIN_P1 0
#define MAX_P1 31
#define MIN_N 3
#define MAX_N 16
#define CALC_VCLOCK(m1, m2, n, p1, p2) \
((PLL_REFCLK * (5 * ((m1) + 2) + ((m2) + 2)) / ((n) + 2)) / \
(((p1) + 2) * (1 << (p2 + 1))))
#define CALC_VCLOCK3(m, n, p) ((PLL_REFCLK * (m) / (n)) / (p))
/* Two pipes */ /* Two pipes */
#define PIPE_A 0 #define PIPE_A 0
...@@ -522,8 +502,7 @@ ...@@ -522,8 +502,7 @@
/* function protoypes */ /* function protoypes */
extern int intelfbhw_get_chipset(struct pci_dev *pdev, const char **name, extern int intelfbhw_get_chipset(struct pci_dev *pdev, struct intelfb_info *dinfo);
int *chipset, int *mobile);
extern int intelfbhw_get_memory(struct pci_dev *pdev, int *aperture_size, extern int intelfbhw_get_memory(struct pci_dev *pdev, int *aperture_size,
int *stolen_size); int *stolen_size);
extern int intelfbhw_check_non_crt(struct intelfb_info *dinfo); extern int intelfbhw_check_non_crt(struct intelfb_info *dinfo);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment