GIT 51d797474f87b375819d084f7583a2864c5656c4 git+ssh://master.kernel.org/pub/scm/linux/kernel/git/airlied/intelfb-2.6#i915fb commit 51d797474f87b375819d084f7583a2864c5656c4 Author: Dave Airlie Date: Mon Apr 3 16:19:26 2006 +1000 intelfb: some cleanups for intelfbhw Signed-off-by: Dave Airlie commit 3587c50991b96fee2d26942f380e36e4f40fad71 Author: Dave Airlie Date: Mon Apr 3 14:46:55 2006 +1000 intelfb: fixup pitch calculation like X does Signed-off-by: Dave Airlie commit 3aff13cfb8810cc228e8fdcb92103ed0b11ee38e Author: Dave Airlie Date: Fri Mar 31 17:08:52 2006 +1000 intelfb: fixup p calculation This fixes up the p calculation of p1 and p2 for the i9xx chipsets. This seems to work a lot better for lower pixel clocks.. Signed-off-by: Dave Airlie commit 46f60b8e67e6fceede851dc69cdee2d7c0de27b9 Author: Dave Airlie Date: Fri Mar 24 12:31:14 2006 +1100 This patch makes a needlessly global struct static. Signed-off-by: Adrian Bunk Signed-off-by: Dave Airlie commit 9a90603f65dd5046ddcd586158abcad7784892b6 Author: Dave Airlie Date: Thu Mar 23 21:53:05 2006 +1100 intelfb: add i945GM support Untested i945GM support just add the framework. Signed-off-by: Dave Airlie commit 8b91b0b4f2d731b92f59bc82492769a09b4955a6 Author: Dave Airlie Date: Thu Mar 23 19:23:48 2006 +1100 intelfb: fixup whitespace.. repeat after me, I must not take code from X without reformatting... Signed-off-by: Dave Airlie commit 8bb91f6a2d1db8031bfbb367df075f041d0cdfe2 Author: Dave Airlie Date: Thu Mar 23 13:06:32 2006 +1100 intelfb: add hw cursor support for i9xx This adds hw cursor support for the i9xx chipsets. Signed-off-by: Dave Airlie commit 7679f4d69296de97a7f62458cc4d1c6c884dfcfb Author: Dave Airlie Date: Thu Mar 23 12:30:05 2006 +1100 intelfb: make i915 modeset This takes the modeset and pll code from my X driver. Signed-off-by: Dave Airlie commit 9639d5ec07a490134f05ac890506a367aaf8663b Author: Dave Airlie Date: Thu Mar 23 11:23:55 2006 +1100 intelfb: add support for i945G This just adds the defines and structure for i945G Signed-off-by: Dave Airlie commit 0c187addabbaf93512902442b4a90140a21b0ddc Author: Dave Airlie Date: Thu Mar 23 11:20:08 2006 +1100 intelfb: enable on x86_64 i945G chipsets supports 64-bit. Signed-off-by: Dave Airlie commit 16109b3f4c1f2635afd32eb6d49348590de2cb25 Author: Dave Airlie Date: Mon Mar 20 21:22:09 2006 +1100 intelfb: add p divisor increments for i9xx. Signed-off-by: Dave Airlie commit 8492f081e5552ff388068f612eae6f55f7210ed4 Author: Dave Airlie Date: Mon Mar 20 20:54:12 2006 +1100 intelfb: change splitm to be brute force The old splitm didn't always work use a brute force. Signed-off-by: Dave Airlie commit d024960cff5173bef6e83c01cf9cd2763c2c0ab0 Author: Dave Airlie Date: Mon Mar 20 20:26:45 2006 +1100 intelfb: add pll index to the intelfb structure Add the pll index into the information structure, change get_chipset to take only the info structure, use plls in correct places commit 7258b11d2e9a47d2b01620622579f22906960e1a Author: Dave Airlie Date: Mon Mar 20 20:02:24 2006 +1100 intelfb: prepare for i9xx support. This code just moves the PLL min/max calculations variables into a structure, it doesn't change or add any new functionality. Signed-off-by: Dave Airlie --- diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig index f87c017..190adce 100644 --- a/drivers/video/Kconfig +++ b/drivers/video/Kconfig @@ -741,7 +741,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 diff --git a/drivers/video/intelfb/intelfb.h b/drivers/video/intelfb/intelfb.h index da29d00..631a3a9 100644 --- a/drivers/video/intelfb/intelfb.h +++ b/drivers/video/intelfb/intelfb.h @@ -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,6 +52,8 @@ #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 @@ -125,7 +127,9 @@ enum intel_chips { INTEL_855GME, INTEL_865G, INTEL_915G, - INTEL_915GM + INTEL_915GM, + INTEL_945G, + INTEL_945GM, }; struct intelfb_hwstate { @@ -277,8 +281,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); diff --git a/drivers/video/intelfb/intelfbdrv.c b/drivers/video/intelfb/intelfbdrv.c index 995b47c..2aba6a4 100644 --- a/drivers/video/intelfb/intelfbdrv.c +++ b/drivers/video/intelfb/intelfbdrv.c @@ -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 * 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 @@ -182,6 +183,8 @@ static struct pci_device_id intelfb_pci_ { 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, } }; @@ -546,11 +549,11 @@ intelfb_pci_register(struct pci_dev *pde /* 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 +587,7 @@ intelfb_pci_register(struct pci_dev *pde /* 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; } @@ -1162,16 +1164,33 @@ intelfb_check_var(struct fb_var_screenin 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 +1486,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 +1497,10 @@ intelfb_cursor(struct fb_info *info, str 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"); diff --git a/drivers/video/intelfb/intelfbhw.c b/drivers/video/intelfb/intelfbhw.c index 624c4bc..05f0a3c 100644 --- a/drivers/video/intelfb/intelfbhw.c +++ b/drivers/video/intelfb/intelfbhw.c @@ -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; @@ -529,12 +571,40 @@ intelfbhw_read_hw_state(struct intelfb_i } +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) +{ + int p2_val; + switch(index) + { + case PLLS_I9xx: + if (p1 == 0) + return 0; + if (lvds) + p2_val = p2 ? 7 : 14; + else + p2_val = p2 ? 5 : 10; + return ((plls[index].ref_clk * (5 * (m1 + 2) + (m2 + 2)) / (n + 2) / + ((p1)) * (p2_val))); + case PLLS_I8xx: + default: + return ((plls[index].ref_clk * (5 * (m1 + 2) + (m2 + 2)) / (n + 2) / + ((p1+2) * (1 << (p2 + 1))))); + } +} + 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) @@ -551,10 +621,13 @@ intelfbhw_print_hw_state(struct intelfb_ 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; + 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; @@ -565,8 +638,8 @@ intelfbhw_print_hw_state(struct intelfb_ 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", - 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 +651,90 @@ intelfbhw_print_hw_state(struct intelfb_ 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; + + if (IS_I9XX(dinfo)) { + int tmpp1; + + if (hw->dpll_a & DPLL_P1_FORCE_DIV2) + p1 = 0; + else + p1 = (hw->dpll_a >> DPLL_P1_SHIFT) & 0xff; + + tmpp1 = p1; + + switch (tmpp1) + { + case 0x1: p1 = 1; break; + case 0x2: p1 = 2; break; + case 0x4: p1 = 3; break; + case 0x8: p1 = 4; break; + case 0x10: p1 = 5; break; + case 0x20: p1 = 6; break; + case 0x40: p1 = 7; break; + case 0x80: p1 = 8; break; + default: break; + } + + p2 = (hw->dpll_a >> DPLL_I9XX_P2_SHIFT) & DPLL_P2_MASK; + + } else { + 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; + } + 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; + + if (IS_I9XX(dinfo)) { + int tmpp1; + + if (hw->dpll_a & DPLL_P1_FORCE_DIV2) + p1 = 0; + else + p1 = (hw->dpll_a >> DPLL_P1_SHIFT) & 0xff; + + tmpp1 = p1; + + switch (tmpp1) { + case 0x1: p1 = 1; break; + case 0x2: p1 = 2; break; + case 0x4: p1 = 3; break; + case 0x8: p1 = 4; break; + case 0x10: p1 = 5; break; + case 0x20: p1 = 6; break; + case 0x40: p1 = 7; break; + case 0x80: p1 = 8; break; + default: break; + } + + p2 = (hw->dpll_a >> DPLL_I9XX_P2_SHIFT) & DPLL_P2_MASK; + + } else { + 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; + } 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 +809,11 @@ intelfbhw_print_hw_state(struct intelfb_ } 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,60 +824,77 @@ intelfbhw_print_hw_state(struct intelfb_ #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; - - 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; + int testm; + /* no point optimising too much - brute force m */ + for (m1 = plls[index].min_m1; m1 < plls[index].max_m1+1; m1++) { + for (m2 = plls[index].min_m2; m2 < plls[index].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; - if (p % 4 == 0) - p2 = 1; - else - p2 = 0; - p1 = (p / (1 << (p2 + 1))) - 2; - if (p % 4 == 0 && p1 < MIN_P1) { - p2 = 0; - p1 = (p / (1 << (p2 + 1))) - 2; - } - if (p1 < MIN_P1 || p1 > MAX_P1 || (p1 + 2) * (1 << (p2 + 1)) != p) { - return 1; - } else { + 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 (index == PLLS_I8xx) { + if (p % 4 == 0) + p2 = 1; + else + p2 = 0; + p1 = (p / (1 << (p2 + 1))) - 2; + if (p % 4 == 0 && p1 < plls[index].min_p1) { + p2 = 0; + p1 = (p / (1 << (p2 + 1))) - 2; + } + if (p1 < plls[index].min_p1 || + p1 > plls[index].max_p1 || + (p1 + 2) * (1 << (p2 + 1)) != p) { + return 1; + } else { + *retp1 = (unsigned int)p1; + *retp2 = (unsigned int)p2; + return 0; + } + } + return 1; } 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 +902,56 @@ calc_pll_params(int clock, u32 *retm1, u 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; - - if (f_err < err_best) { - m_best = m; - n_best = n; - p_best = p; - f_best = f_out; - err_best = f_err; + 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, m, &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; + } } 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 +962,22 @@ calc_pll_params(int clock, u32 *retm1, u 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; } @@ -929,7 +1074,8 @@ intelfbhw_mode_to_hw(struct intelfb_info /* 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 +1095,14 @@ intelfbhw_mode_to_hw(struct intelfb_info *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 +1207,7 @@ intelfbhw_mode_to_hw(struct intelfb_info *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 + @@ -1087,6 +1240,7 @@ intelfbhw_program_mode(struct intelfb_in 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 +1309,27 @@ intelfbhw_program_mode(struct intelfb_in 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,7 +1338,7 @@ intelfbhw_program_mode(struct intelfb_in 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); /* Disable Sync */ @@ -1172,10 +1347,8 @@ intelfbhw_program_mode(struct intelfb_in 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); @@ -1187,26 +1360,30 @@ intelfbhw_program_mode(struct intelfb_in OUTREG(fp0_reg, *fp0); OUTREG(fp1_reg, *fp1); - /* Set pipe parameters */ - OUTREG(hsync_reg, *hs); - 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); + /* Enable PLL */ + tmp = INREG(dpll_reg); + tmp |= DPLL_VCO_ENABLE; + OUTREG(dpll_reg, tmp); /* 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); - /* Enable PLL */ - tmp = INREG(dpll_reg); - tmp |= DPLL_VCO_ENABLE; - OUTREG(dpll_reg, tmp); + /* Set pipe parameters */ + OUTREG(hsync_reg, *hs); + 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); /* Enable pipe */ OUTREG(pipe_conf_reg, *pipe_conf | PIPECONF_ENABLE); @@ -1231,7 +1408,7 @@ intelfbhw_program_mode(struct intelfb_in OUTREG(DSPACNTR, hw->disp_a_ctrl|DISPPLANE_PLANE_ENABLE); mdelay(1); - } + } } OUTREG(DSPACNTR, hw->disp_a_ctrl & ~DISPPLANE_PLANE_ENABLE); @@ -1616,7 +1793,7 @@ intelfbhw_cursor_init(struct intelfb_inf 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 +1826,7 @@ intelfbhw_cursor_hide(struct intelfb_inf #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 +1856,7 @@ intelfbhw_cursor_show(struct intelfb_inf 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 +1882,18 @@ intelfbhw_cursor_setpos(struct intelfb_i #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 diff --git a/drivers/video/intelfb/intelfbhw.h b/drivers/video/intelfb/intelfbhw.h index ba19201..10acda0 100644 --- a/drivers/video/intelfb/intelfbhw.h +++ b/drivers/video/intelfb/intelfbhw.h @@ -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);