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
  ...
This commit is contained in:
Linus Torvalds 2006-06-19 18:53:20 -07:00
commit d90125bfe9
5 changed files with 413 additions and 211 deletions

View File

@ -743,7 +743,7 @@ config FB_I810_I2C
config FB_INTEL
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_INTEL
select FB_MODE_HELPERS

View File

@ -8,9 +8,9 @@
/*** Version/name ***/
#define INTELFB_VERSION "0.9.2"
#define INTELFB_VERSION "0.9.4"
#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 ***/
@ -52,11 +52,14 @@
#define PCI_DEVICE_ID_INTEL_865G 0x2572
#define PCI_DEVICE_ID_INTEL_915G 0x2582
#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 */
#define INTEL_REG_SIZE 0x80000
#define STRIDE_ALIGNMENT 16
#define STRIDE_ALIGNMENT_I9XX 64
#define PALETTE_8_ENTRIES 256
@ -125,7 +128,9 @@ enum intel_chips {
INTEL_855GME,
INTEL_865G,
INTEL_915G,
INTEL_915GM
INTEL_915GM,
INTEL_945G,
INTEL_945GM,
};
struct intelfb_hwstate {
@ -277,8 +282,13 @@ struct intelfb_info {
/* driver 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 ***/
extern int intelfb_var_to_depth(const struct fb_var_screeninfo *var);

View File

@ -1,11 +1,12 @@
/*
* intelfb
*
* Linux framebuffer driver for Intel(R) 830M/845G/852GM/855GM/865G/915G/915GM
* integrated graphics chips.
* Linux framebuffer driver for Intel(R) 830M/845G/852GM/855GM/865G/915G/915GM/
* 945G/945GM integrated graphics chips.
*
* Copyright © 2002, 2003 David Dawes <dawes@xfree86.org>
* 2004 Sylvain Meyer
* 2006 David Airlie
*
* This driver consists of two parts. The first part (intelfbdrv.c) provides
* the basic fbdev interfaces, is derived in part from the radeonfb and
@ -131,6 +132,7 @@
#include "intelfb.h"
#include "intelfbhw.h"
#include "../edid.h"
static void __devinit get_initial_mode(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 = {
{ 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_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, }
};
@ -261,7 +265,7 @@ MODULE_PARM_DESC(mode,
#ifndef MODULE
#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))
static __inline__ char *
@ -546,11 +550,11 @@ intelfb_pci_register(struct pci_dev *pdev, const struct pci_device_id *ent)
/* Set base addresses. */
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;
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.size = pci_resource_len(pdev, aperture_bar);
@ -584,8 +588,7 @@ intelfb_pci_register(struct pci_dev *pdev, const struct pci_device_id *ent)
/* Get the chipset info. */
dinfo->pci_chipset = pdev->device;
if (intelfbhw_get_chipset(pdev, &dinfo->name, &dinfo->chipset,
&dinfo->mobile)) {
if (intelfbhw_get_chipset(pdev, dinfo)) {
cleanup(dinfo);
return -ENODEV;
}
@ -1029,17 +1032,44 @@ intelfb_init_var(struct intelfb_info *dinfo)
sizeof(struct fb_var_screeninfo));
msrc = 5;
} else {
if (mode) {
msrc = fb_find_mode(var, dinfo->info, mode,
vesa_modes, VESA_MODEDB_SIZE,
NULL, 0);
if (msrc)
msrc |= 8;
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) {
printk("intelfb: Looking for mode in private "
"database\n");
msrc = fb_find_mode(var, dinfo->info, mode,
dinfo->info->monspecs.modedb,
dinfo->info->monspecs.modedb_len,
NULL, 0);
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) {
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)
}
/* 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))
dinfo->pitch = dinfo->initial_pitch;
@ -1162,16 +1195,33 @@ intelfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
struct fb_var_screeninfo v;
struct intelfb_info *dinfo;
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);
dinfo = GET_DINFO(info);
/* update the pitch */
if (intelfbhw_validate_mode(dinfo, var) != 0)
return -EINVAL;
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. */
if (v.bits_per_pixel <= 8) {
v.bits_per_pixel = 8;
@ -1467,7 +1517,7 @@ static int
intelfb_cursor(struct fb_info *info, struct fb_cursor *cursor)
{
struct intelfb_info *dinfo = GET_DINFO(info);
u32 physical;
#if VERBOSE > 0
DBG_MSG("intelfb_cursor\n");
#endif
@ -1478,7 +1528,10 @@ intelfb_cursor(struct fb_info *info, struct fb_cursor *cursor)
intelfbhw_cursor_hide(dinfo);
/* 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;
DBG_MSG("the cursor was killed - restore it !!\n");

View File

@ -40,68 +40,110 @@
#include "intelfb.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
intelfbhw_get_chipset(struct pci_dev *pdev, const char **name, int *chipset,
int *mobile)
intelfbhw_get_chipset(struct pci_dev *pdev, struct intelfb_info *dinfo)
{
u32 tmp;
if (!pdev || !name || !chipset || !mobile)
if (!pdev || !dinfo)
return 1;
switch (pdev->device) {
case PCI_DEVICE_ID_INTEL_830M:
*name = "Intel(R) 830M";
*chipset = INTEL_830M;
*mobile = 1;
dinfo->name = "Intel(R) 830M";
dinfo->chipset = INTEL_830M;
dinfo->mobile = 1;
dinfo->pll_index = PLLS_I8xx;
return 0;
case PCI_DEVICE_ID_INTEL_845G:
*name = "Intel(R) 845G";
*chipset = INTEL_845G;
*mobile = 0;
dinfo->name = "Intel(R) 845G";
dinfo->chipset = INTEL_845G;
dinfo->mobile = 0;
dinfo->pll_index = PLLS_I8xx;
return 0;
case PCI_DEVICE_ID_INTEL_85XGM:
tmp = 0;
*mobile = 1;
dinfo->mobile = 1;
dinfo->pll_index = PLLS_I8xx;
pci_read_config_dword(pdev, INTEL_85X_CAPID, &tmp);
switch ((tmp >> INTEL_85X_VARIANT_SHIFT) &
INTEL_85X_VARIANT_MASK) {
case INTEL_VAR_855GME:
*name = "Intel(R) 855GME";
*chipset = INTEL_855GME;
dinfo->name = "Intel(R) 855GME";
dinfo->chipset = INTEL_855GME;
return 0;
case INTEL_VAR_855GM:
*name = "Intel(R) 855GM";
*chipset = INTEL_855GM;
dinfo->name = "Intel(R) 855GM";
dinfo->chipset = INTEL_855GM;
return 0;
case INTEL_VAR_852GME:
*name = "Intel(R) 852GME";
*chipset = INTEL_852GME;
dinfo->name = "Intel(R) 852GME";
dinfo->chipset = INTEL_852GME;
return 0;
case INTEL_VAR_852GM:
*name = "Intel(R) 852GM";
*chipset = INTEL_852GM;
dinfo->name = "Intel(R) 852GM";
dinfo->chipset = INTEL_852GM;
return 0;
default:
*name = "Intel(R) 852GM/855GM";
*chipset = INTEL_85XGM;
dinfo->name = "Intel(R) 852GM/855GM";
dinfo->chipset = INTEL_85XGM;
return 0;
}
break;
case PCI_DEVICE_ID_INTEL_865G:
*name = "Intel(R) 865G";
*chipset = INTEL_865G;
*mobile = 0;
dinfo->name = "Intel(R) 865G";
dinfo->chipset = INTEL_865G;
dinfo->mobile = 0;
dinfo->pll_index = PLLS_I8xx;
return 0;
case PCI_DEVICE_ID_INTEL_915G:
*name = "Intel(R) 915G";
*chipset = INTEL_915G;
*mobile = 0;
dinfo->name = "Intel(R) 915G";
dinfo->chipset = INTEL_915G;
dinfo->mobile = 0;
dinfo->pll_index = PLLS_I9xx;
return 0;
case PCI_DEVICE_ID_INTEL_915GM:
*name = "Intel(R) 915GM";
*chipset = INTEL_915GM;
*mobile = 1;
dinfo->name = "Intel(R) 915GM";
dinfo->chipset = INTEL_915GM;
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;
default:
return 1;
@ -114,6 +156,7 @@ intelfbhw_get_memory(struct pci_dev *pdev, int *aperture_size,
{
struct pci_dev *bridge_dev;
u16 tmp;
int stolen_overhead;
if (!pdev || !aperture_size || !stolen_size)
return 1;
@ -128,21 +171,41 @@ intelfbhw_get_memory(struct pci_dev *pdev, int *aperture_size,
tmp = 0;
pci_read_config_word(bridge_dev, INTEL_GMCH_CTRL, &tmp);
switch (pdev->device) {
case PCI_DEVICE_ID_INTEL_830M:
case PCI_DEVICE_ID_INTEL_845G:
case PCI_DEVICE_ID_INTEL_915G:
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)
*aperture_size = MB(64);
else
*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) {
case INTEL_830_GMCH_GMS_STOLEN_512:
*stolen_size = KB(512) - KB(132);
*stolen_size = KB(512) - KB(stolen_overhead);
return 0;
case INTEL_830_GMCH_GMS_STOLEN_1024:
*stolen_size = MB(1) - KB(132);
*stolen_size = MB(1) - KB(stolen_overhead);
return 0;
case INTEL_830_GMCH_GMS_STOLEN_8192:
*stolen_size = MB(8) - KB(132);
*stolen_size = MB(8) - KB(stolen_overhead);
return 0;
case INTEL_830_GMCH_GMS_LOCAL:
ERR_MSG("only local memory found\n");
@ -157,28 +220,27 @@ intelfbhw_get_memory(struct pci_dev *pdev, int *aperture_size,
}
break;
default:
*aperture_size = MB(128);
switch (tmp & INTEL_855_GMCH_GMS_MASK) {
case INTEL_855_GMCH_GMS_STOLEN_1M:
*stolen_size = MB(1) - KB(132);
*stolen_size = MB(1) - KB(stolen_overhead);
return 0;
case INTEL_855_GMCH_GMS_STOLEN_4M:
*stolen_size = MB(4) - KB(132);
*stolen_size = MB(4) - KB(stolen_overhead);
return 0;
case INTEL_855_GMCH_GMS_STOLEN_8M:
*stolen_size = MB(8) - KB(132);
*stolen_size = MB(8) - KB(stolen_overhead);
return 0;
case INTEL_855_GMCH_GMS_STOLEN_16M:
*stolen_size = MB(16) - KB(132);
*stolen_size = MB(16) - KB(stolen_overhead);
return 0;
case INTEL_855_GMCH_GMS_STOLEN_32M:
*stolen_size = MB(32) - KB(132);
*stolen_size = MB(32) - KB(stolen_overhead);
return 0;
case INTEL_915G_GMCH_GMS_STOLEN_48M:
*stolen_size = MB(48) - KB(132);
*stolen_size = MB(48) - KB(stolen_overhead);
return 0;
case INTEL_915G_GMCH_GMS_STOLEN_64M:
*stolen_size = MB(64) - KB(132);
*stolen_size = MB(64) - KB(stolen_overhead);
return 0;
case INTEL_855_GMCH_GMS_DISABLED:
ERR_MSG("video memory is disabled\n");
@ -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
intelfbhw_print_hw_state(struct intelfb_info *dinfo, struct intelfb_hwstate *hw)
{
#if REGDUMP
int i, m1, m2, n, p1, p2;
int index = dinfo->pll_index;
DBG_MSG("intelfbhw_print_hw_state\n");
if (!hw || !dinfo)
@ -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;
m1 = (hw->vga0_divisor >> FP_M1_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;
else
p1 = (hw->vga_pd >> VGAPD_0_P1_SHIFT) & DPLL_P1_MASK;
p2 = (hw->vga_pd >> VGAPD_0_P2_SHIFT) & DPLL_P2_MASK;
intelfbhw_get_p1p2(dinfo, hw->vga_pd, &p1, &p2);
printk(" VGA0: (m1, m2, n, p1, p2) = (%d, %d, %d, %d, %d)\n",
m1, m2, n, p1, p2);
printk(" VGA0: clock is %d\n", CALC_VCLOCK(m1, m2, n, p1, p2));
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;
m1 = (hw->vga1_divisor >> FP_M1_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;
else
p1 = (hw->vga_pd >> VGAPD_1_P1_SHIFT) & DPLL_P1_MASK;
p2 = (hw->vga_pd >> VGAPD_1_P2_SHIFT) & DPLL_P2_MASK;
intelfbhw_get_p1p2(dinfo, hw->vga_pd, &p1, &p2);
printk(" VGA1: (m1, m2, n, p1, p2) = (%d, %d, %d, %d, %d)\n",
m1, m2, n, p1, p2);
printk(" VGA1: clock is %d\n", CALC_VCLOCK(m1, m2, n, p1, p2));
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_B: 0x%08x\n", hw->dpll_b);
@ -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;
m1 = (hw->fpa0 >> FP_M1_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;
else
p1 = (hw->dpll_a >> DPLL_P1_SHIFT) & DPLL_P1_MASK;
p2 = (hw->dpll_a >> DPLL_P2_SHIFT) & DPLL_P2_MASK;
intelfbhw_get_p1p2(dinfo, hw->dpll_a, &p1, &p2);
printk(" PLLA0: (m1, m2, n, p1, p2) = (%d, %d, %d, %d, %d)\n",
m1, m2, n, p1, p2);
printk(" PLLA0: clock is %d\n", CALC_VCLOCK(m1, m2, n, p1, p2));
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;
m1 = (hw->fpa1 >> FP_M1_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;
else
p1 = (hw->dpll_a >> DPLL_P1_SHIFT) & DPLL_P1_MASK;
p2 = (hw->dpll_a >> DPLL_P2_SHIFT) & DPLL_P2_MASK;
intelfbhw_get_p1p2(dinfo, hw->dpll_a, &p1, &p2);
printk(" PLLA1: (m1, m2, n, p1, p2) = (%d, %d, %d, %d, %d)\n",
m1, m2, n, p1, p2);
printk(" PLLA1: clock is %d\n", CALC_VCLOCK(m1, m2, n, p1, p2));
m1, m2, n, p1, p2);
printk(" PLLA1: clock is %d\n", calc_vclock(index, m1, m2, n, p1, p2, 0));
#if 0
printk(" PALETTE_A:\n");
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");
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
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)
}
for (i = 0; i < 3; i++) {
printk(" SWF3%d 0x%08x\n", i,
hw->swf3x[i]);
hw->swf3x[i]);
}
for (i = 0; i < 8; i++)
printk(" FENCE%d 0x%08x\n", i,
hw->fence[i]);
hw->fence[i]);
printk(" INSTPM 0x%08x\n", hw->instpm);
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)
#endif
}
/* Split the M parameter into M1 and M2. */
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 testm;
struct pll_min_max *pll = &plls[index];
m1 = (m - 2 - (MIN_M2 + MAX_M2) / 2) / 5 - 2;
if (m1 < MIN_M1)
m1 = MIN_M1;
if (m1 > MAX_M1)
m1 = MAX_M1;
m2 = m - 5 * (m1 + 2) - 2;
if (m2 < MIN_M2 || m2 > MAX_M2 || m2 >= m1) {
return 1;
} else {
*retm1 = (unsigned int)m1;
*retm2 = (unsigned int)m2;
return 0;
/* no point optimising too much - brute force m */
for (m1 = pll->min_m1; m1 < pll->max_m1 + 1; m1++) {
for (m2 = pll->min_m2; m2 < pll->max_m2 + 1; m2++) {
testm = (5 * (m1 + 2)) + (m2 + 2);
if (testm == m) {
*retm1 = (unsigned int)m1;
*retm2 = (unsigned int)m2;
return 0;
}
}
}
return 1;
}
/* Split the P parameter into P1 and P2. */
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;
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)
p2 = 1;
else
p2 = 0;
p1 = (p / (1 << (p2 + 1))) - 2;
if (p % 4 == 0 && p1 < MIN_P1) {
if (p % 4 == 0 && p1 < pll->min_p1) {
p2 = 0;
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;
} else {
*retp1 = (unsigned int)p1;
@ -741,14 +861,15 @@ splitp(unsigned int p, unsigned int *retp1, unsigned int *retp2)
}
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 m1, m2, n, p1, p2, n1;
u32 f_vco, p, p_best = 0, m, f_out;
u32 m1, m2, n, p1, p2, n1, testm;
u32 f_vco, p, p_best = 0, m, f_out = 0;
u32 err_max, err_target, err_best = 10000000;
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% */
err_max = 5 * clock / 1000;
@ -756,58 +877,56 @@ calc_pll_params(int clock, u32 *retm1, u32 *retm2, u32 *retn, u32 *retp1,
DBG_MSG("Clock is %d\n", clock);
div_max = MAX_VCO_FREQ / clock;
div_min = ROUND_UP_TO(MIN_VCO_FREQ, clock) / clock;
div_max = pll->max_vco / clock;
if (clock <= P_TRANSITION_CLOCK)
p_inc = 4;
else
p_inc = 2;
p_min = ROUND_UP_TO(div_min, p_inc);
p_inc = (clock <= pll->p_transition_clk) ? pll->p_inc_lo : pll->p_inc_hi;
p_min = p_inc;
p_max = ROUND_DOWN_TO(div_max, p_inc);
if (p_min < MIN_P)
p_min = 4;
if (p_max > MAX_P)
p_max = 128;
if (p_min < pll->min_p)
p_min = pll->min_p;
if (p_max > pll->max_p)
p_max = pll->max_p;
DBG_MSG("p range is %d-%d (%d)\n", p_min, p_max, p_inc);
p = p_min;
do {
if (splitp(p, &p1, &p2)) {
if (splitp(index, p, &p1, &p2)) {
WRN_MSG("cannot split p = %d\n", p);
p += p_inc;
continue;
}
n = MIN_N;
n = pll->min_n;
f_vco = clock * p;
do {
m = ROUND_UP_TO(f_vco * n, PLL_REFCLK) / PLL_REFCLK;
if (m < MIN_M)
m = MIN_M;
if (m > MAX_M)
m = MAX_M;
f_out = CALC_VCLOCK3(m, n, p);
if (splitm(m, &m1, &m2)) {
WRN_MSG("cannot split m = %d\n", m);
n++;
continue;
}
if (clock > f_out)
f_err = clock - f_out;
else
f_err = f_out - clock;
m = ROUND_UP_TO(f_vco * n, pll->ref_clk) / pll->ref_clk;
if (m < pll->min_m)
m = pll->min_m + 1;
if (m > pll->max_m)
m = pll->max_m - 1;
for (testm = m - 1; testm <= m; testm++) {
f_out = calc_vclock3(index, m, n, p);
if (splitm(index, testm, &m1, &m2)) {
WRN_MSG("cannot split m = %d\n", m);
n++;
continue;
}
if (clock > f_out)
f_err = clock - f_out;
else/* slightly bias the error for bigger clocks */
f_err = f_out - clock + 1;
if (f_err < err_best) {
m_best = m;
n_best = n;
p_best = p;
f_best = f_out;
err_best = f_err;
if (f_err < err_best) {
m_best = testm;
n_best = n;
p_best = p;
f_best = f_out;
err_best = f_err;
}
}
n++;
} while ((n <= MAX_N) && (f_out >= clock));
} while ((n <= pll->max_n) && (f_out >= clock));
p += p_inc;
} while ((p <= p_max));
@ -818,21 +937,22 @@ calc_pll_params(int clock, u32 *retm1, u32 *retm2, u32 *retn, u32 *retp1,
m = m_best;
n = n_best;
p = p_best;
splitm(m, &m1, &m2);
splitp(p, &p1, &p2);
splitm(index, m, &m1, &m2);
splitp(index, p, &p1, &p2);
n1 = n - 2;
DBG_MSG("m, n, p: %d (%d,%d), %d (%d), %d (%d,%d), "
"f: %d (%d), VCO: %d\n",
m, m1, m2, n, n1, p, p1, p2,
CALC_VCLOCK3(m, n, p), CALC_VCLOCK(m1, m2, n1, p1, p2),
CALC_VCLOCK3(m, n, p) * p);
calc_vclock3(index, m, n, p),
calc_vclock(index, m1, m2, n1, p1, p2, 0),
calc_vclock3(index, m, n, p) * p);
*retm1 = m1;
*retm2 = m2;
*retn = n1;
*retp1 = p1;
*retp2 = p2;
*retclock = CALC_VCLOCK(m1, m2, n1, p1, p2);
*retclock = calc_vclock(index, m1, m2, n1, p1, p2, 0);
return 0;
}
@ -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_pol, hsync_pol;
u32 *vs, *vb, *vt, *hs, *hb, *ht, *ss, *pipe_conf;
u32 stride_alignment;
DBG_MSG("intelfbhw_mode_to_hw\n");
@ -929,7 +1050,8 @@ intelfbhw_mode_to_hw(struct intelfb_info *dinfo, struct intelfb_hwstate *hw,
/* Desired clock in kHz */
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");
return 1;
}
@ -949,7 +1071,14 @@ intelfbhw_mode_to_hw(struct intelfb_info *dinfo, struct intelfb_hwstate *hw,
*dpll &= ~DPLL_P1_FORCE_DIV2;
*dpll &= ~((DPLL_P2_MASK << DPLL_P2_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) |
(m1 << FP_M1_DIVISOR_SHIFT) |
(m2 << FP_M2_DIVISOR_SHIFT);
@ -1054,7 +1183,7 @@ intelfbhw_mode_to_hw(struct intelfb_info *dinfo, struct intelfb_hwstate *hw,
*ss = (hactive << SRC_SIZE_HORIZ_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);
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,
hw->disp_a_base += dinfo->fb.offset << 12;
/* 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",
hw->disp_a_stride, STRIDE_ALIGNMENT);
hw->disp_a_stride, stride_alignment);
return 1;
}
@ -1087,6 +1218,7 @@ intelfbhw_program_mode(struct intelfb_info *dinfo,
u32 hsync_reg, htotal_reg, hblank_reg;
u32 vsync_reg, vtotal_reg, vblank_reg;
u32 src_size_reg;
u32 count, tmp_val[3];
/* Assume single pipe, display plane A, analog CRT. */
@ -1155,6 +1287,27 @@ intelfbhw_program_mode(struct intelfb_info *dinfo,
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. */
tmp = INREG(DSPACNTR);
tmp &= ~DISPPLANE_PLANE_ENABLE;
@ -1163,19 +1316,21 @@ intelfbhw_program_mode(struct intelfb_info *dinfo,
tmp &= ~DISPPLANE_PLANE_ENABLE;
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);
OUTREG(DVOB, INREG(DVOB) & ~PORT_ENABLE);
OUTREG(DVOC, INREG(DVOC) & ~PORT_ENABLE);
OUTREG(ADPA, INREG(ADPA) & ~ADPA_DAC_ENABLE);
/* Disable Sync */
tmp = INREG(ADPA);
tmp &= ~ADPA_DPMS_CONTROL_MASK;
tmp |= ADPA_DPMS_D3;
OUTREG(ADPA, tmp);
/* turn off pipe */
tmp = INREG(pipe_conf_reg);
tmp &= ~PIPECONF_ENABLE;
OUTREG(pipe_conf_reg, tmp);
/* do some funky magic - xyzzy */
OUTREG(0x61204, 0xabcd0000);
/* turn off PLL */
tmp = INREG(dpll_reg);
@ -1183,10 +1338,23 @@ intelfbhw_program_mode(struct intelfb_info *dinfo,
OUTREG(dpll_reg, tmp);
/* Set PLL parameters */
OUTREG(dpll_reg, *dpll & ~DPLL_VCO_ENABLE);
OUTREG(fp0_reg, *fp0);
OUTREG(fp1_reg, *fp1);
/* Enable PLL */
OUTREG(dpll_reg, *dpll);
/* Set DVOs B/C */
OUTREG(DVOB, hw->dvob);
OUTREG(DVOC, hw->dvoc);
/* undo funky magic */
OUTREG(0x61204, 0x00000000);
/* Set ADPA */
OUTREG(ADPA, INREG(ADPA) | ADPA_DAC_ENABLE);
OUTREG(ADPA, (hw->adpa & ~(ADPA_DPMS_CONTROL_MASK)) | ADPA_DPMS_D3);
/* Set pipe parameters */
OUTREG(hsync_reg, *hs);
OUTREG(hblank_reg, *hb);
@ -1196,18 +1364,6 @@ intelfbhw_program_mode(struct intelfb_info *dinfo,
OUTREG(vtotal_reg, *vt);
OUTREG(src_size_reg, *ss);
/* Set DVOs B/C */
OUTREG(DVOB, hw->dvob);
OUTREG(DVOC, hw->dvoc);
/* Set ADPA */
OUTREG(ADPA, (hw->adpa & ~(ADPA_DPMS_CONTROL_MASK)) | ADPA_DPMS_D3);
/* Enable PLL */
tmp = INREG(dpll_reg);
tmp |= DPLL_VCO_ENABLE;
OUTREG(dpll_reg, tmp);
/* Enable pipe */
OUTREG(pipe_conf_reg, *pipe_conf | PIPECONF_ENABLE);
@ -1231,7 +1387,7 @@ intelfbhw_program_mode(struct intelfb_info *dinfo,
OUTREG(DSPACNTR,
hw->disp_a_ctrl|DISPPLANE_PLANE_ENABLE);
mdelay(1);
}
}
}
OUTREG(DSPACNTR, hw->disp_a_ctrl & ~DISPPLANE_PLANE_ENABLE);
@ -1616,7 +1772,7 @@ intelfbhw_cursor_init(struct intelfb_info *dinfo)
DBG_MSG("intelfbhw_cursor_init\n");
#endif
if (dinfo->mobile) {
if (dinfo->mobile || IS_I9XX(dinfo)) {
if (!dinfo->cursor.physical)
return;
tmp = INREG(CURSOR_A_CONTROL);
@ -1649,7 +1805,7 @@ intelfbhw_cursor_hide(struct intelfb_info *dinfo)
#endif
dinfo->cursor_on = 0;
if (dinfo->mobile) {
if (dinfo->mobile || IS_I9XX(dinfo)) {
if (!dinfo->cursor.physical)
return;
tmp = INREG(CURSOR_A_CONTROL);
@ -1679,7 +1835,7 @@ intelfbhw_cursor_show(struct intelfb_info *dinfo)
if (dinfo->cursor_blanked)
return;
if (dinfo->mobile) {
if (dinfo->mobile || IS_I9XX(dinfo)) {
if (!dinfo->cursor.physical)
return;
tmp = INREG(CURSOR_A_CONTROL);
@ -1705,14 +1861,18 @@ intelfbhw_cursor_setpos(struct intelfb_info *dinfo, int x, int y)
#endif
/*
* Sets the position. The coordinates are assumed to already
* have any offset adjusted. Assume that the cursor is never
* Sets the position. The coordinates are assumed to already
* have any offset adjusted. Assume that the cursor is never
* completely off-screen, and that x, y are always >= 0.
*/
tmp = ((x & CURSOR_POS_MASK) << CURSOR_X_SHIFT) |
((y & CURSOR_POS_MASK) << CURSOR_Y_SHIFT);
OUTREG(CURSOR_A_POSITION, tmp);
if (IS_I9XX(dinfo)) {
OUTREG(CURSOR_A_BASEADDR, dinfo->cursor.physical);
}
}
void

View File

@ -133,6 +133,7 @@
#define DPLL_VGA_MODE_DISABLE (1 << 28)
#define DPLL_P2_MASK 1
#define DPLL_P2_SHIFT 23
#define DPLL_I9XX_P2_SHIFT 24
#define DPLL_P1_FORCE_DIV2 (1 << 21)
#define DPLL_P1_MASK 0x1f
#define DPLL_P1_SHIFT 16
@ -155,29 +156,8 @@
/* PLL parameters (these are for 852GM/855GM/865G, check earlier chips). */
/* Clock values are in units of kHz */
#define PLL_REFCLK 48000
#define MIN_VCO_FREQ 930000
#define MAX_VCO_FREQ 1400000
#define MIN_CLOCK 25000
#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 */
#define PIPE_A 0
@ -522,8 +502,7 @@
/* function protoypes */
extern int intelfbhw_get_chipset(struct pci_dev *pdev, const char **name,
int *chipset, int *mobile);
extern int intelfbhw_get_chipset(struct pci_dev *pdev, struct intelfb_info *dinfo);
extern int intelfbhw_get_memory(struct pci_dev *pdev, int *aperture_size,
int *stolen_size);
extern int intelfbhw_check_non_crt(struct intelfb_info *dinfo);