diff options
author | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 15:20:36 -0700 |
---|---|---|
committer | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 15:20:36 -0700 |
commit | 1da177e4c3f41524e886b7f1b8a0c1fc7321cac2 (patch) | |
tree | 0bba044c4ce775e45a88a51686b5d9f90697ea9d /drivers/video/intelfb |
Linux-2.6.12-rc2v2.6.12-rc2
Initial git repository build. I'm not bothering with the full history,
even though we have it. We can create a separate "historical" git
archive of that later if we want to, and in the meantime it's about
3.2GB when imported into git - space that would just make the early
git days unnecessarily complicated, when we don't have a lot of good
infrastructure for it.
Let it rip!
Diffstat (limited to 'drivers/video/intelfb')
-rw-r--r-- | drivers/video/intelfb/Makefile | 8 | ||||
-rw-r--r-- | drivers/video/intelfb/intelfb.h | 280 | ||||
-rw-r--r-- | drivers/video/intelfb/intelfbdrv.c | 1570 | ||||
-rw-r--r-- | drivers/video/intelfb/intelfbdrv.h | 68 | ||||
-rw-r--r-- | drivers/video/intelfb/intelfbhw.c | 1780 | ||||
-rw-r--r-- | drivers/video/intelfb/intelfbhw.h | 570 |
6 files changed, 4276 insertions, 0 deletions
diff --git a/drivers/video/intelfb/Makefile b/drivers/video/intelfb/Makefile new file mode 100644 index 00000000000..722d21d6e5c --- /dev/null +++ b/drivers/video/intelfb/Makefile @@ -0,0 +1,8 @@ +obj-$(CONFIG_FB_INTEL) += intelfb.o + +intelfb-objs := intelfbdrv.o intelfbhw.o + +ifdef CONFIG_FB_INTEL_DEBUG +#EXTRA_CFLAGS += -DDEBUG -DVERBOSE -DREGDUMP +EXTRA_CFLAGS += -DDEBUG -DREGDUMP +endif diff --git a/drivers/video/intelfb/intelfb.h b/drivers/video/intelfb/intelfb.h new file mode 100644 index 00000000000..6680ec9ba69 --- /dev/null +++ b/drivers/video/intelfb/intelfb.h @@ -0,0 +1,280 @@ +#ifndef _INTELFB_H +#define _INTELFB_H + +/* $DHD: intelfb/intelfb.h,v 1.40 2003/06/27 15:06:25 dawes Exp $ */ + +#include <linux/agp_backend.h> +#include <linux/fb.h> + + +/*** Version/name ***/ +#define INTELFB_VERSION "0.9.2" +#define INTELFB_MODULE_NAME "intelfb" +#define SUPPORTED_CHIPSETS "830M/845G/852GM/855GM/865G/915G" + + +/*** Debug/feature defines ***/ + +#ifndef DEBUG +#define DEBUG 0 +#endif + +#ifndef VERBOSE +#define VERBOSE 0 +#endif + +#ifndef REGDUMP +#define REGDUMP 0 +#endif + +#ifndef DETECT_VGA_CLASS_ONLY +#define DETECT_VGA_CLASS_ONLY 1 +#endif + +#ifndef ALLOCATE_FOR_PANNING +#define ALLOCATE_FOR_PANNING 1 +#endif + +#ifndef PREFERRED_MODE +#define PREFERRED_MODE "1024x768-32@70" +#endif + +/*** hw-related values ***/ + +/* PCI ids for supported devices */ +#define PCI_DEVICE_ID_INTEL_830M 0x3577 +#define PCI_DEVICE_ID_INTEL_845G 0x2562 +#define PCI_DEVICE_ID_INTEL_85XGM 0x3582 +#define PCI_DEVICE_ID_INTEL_865G 0x2572 +#define PCI_DEVICE_ID_INTEL_915G 0x2582 + +/* Size of MMIO region */ +#define INTEL_REG_SIZE 0x80000 + +#define STRIDE_ALIGNMENT 16 + +#define PALETTE_8_ENTRIES 256 + + +/*** Macros ***/ + +/* basic arithmetic */ +#define KB(x) ((x) * 1024) +#define MB(x) ((x) * 1024 * 1024) +#define BtoKB(x) ((x) / 1024) +#define BtoMB(x) ((x) / 1024 / 1024) + +#define GTT_PAGE_SIZE KB(4) + +#define ROUND_UP_TO(x, y) (((x) + (y) - 1) / (y) * (y)) +#define ROUND_DOWN_TO(x, y) ((x) / (y) * (y)) +#define ROUND_UP_TO_PAGE(x) ROUND_UP_TO((x), GTT_PAGE_SIZE) +#define ROUND_DOWN_TO_PAGE(x) ROUND_DOWN_TO((x), GTT_PAGE_SIZE) + +/* messages */ +#define PFX INTELFB_MODULE_NAME ": " + +#define ERR_MSG(fmt, args...) printk(KERN_ERR PFX fmt, ## args) +#define WRN_MSG(fmt, args...) printk(KERN_WARNING PFX fmt, ## args) +#define NOT_MSG(fmt, args...) printk(KERN_NOTICE PFX fmt, ## args) +#define INF_MSG(fmt, args...) printk(KERN_INFO PFX fmt, ## args) +#if DEBUG +#define DBG_MSG(fmt, args...) printk(KERN_DEBUG PFX fmt, ## args) +#else +#define DBG_MSG(fmt, args...) while (0) printk(fmt, ## args) +#endif + +/* get commonly used pointers */ +#define GET_DINFO(info) (info)->par + +/* misc macros */ +#define ACCEL(d, i) \ + ((d)->accel && !(d)->ring_lockup && \ + ((i)->var.accel_flags & FB_ACCELF_TEXT)) + +/*#define NOACCEL_CHIPSET(d) \ + ((d)->chipset != INTEL_865G)*/ +#define NOACCEL_CHIPSET(d) \ + (0) + +#define FIXED_MODE(d) ((d)->fixed_mode) + +/*** Driver paramters ***/ + +#define RINGBUFFER_SIZE KB(64) +#define HW_CURSOR_SIZE KB(4) + +/* Intel agpgart driver */ +#define AGP_PHYSICAL_MEMORY 2 + +/*** Data Types ***/ + +/* supported chipsets */ +enum intel_chips { + INTEL_830M, + INTEL_845G, + INTEL_85XGM, + INTEL_852GM, + INTEL_852GME, + INTEL_855GM, + INTEL_855GME, + INTEL_865G, + INTEL_915G +}; + +struct intelfb_hwstate { + u32 vga0_divisor; + u32 vga1_divisor; + u32 vga_pd; + u32 dpll_a; + u32 dpll_b; + u32 fpa0; + u32 fpa1; + u32 fpb0; + u32 fpb1; + u32 palette_a[PALETTE_8_ENTRIES]; + u32 palette_b[PALETTE_8_ENTRIES]; + u32 htotal_a; + u32 hblank_a; + u32 hsync_a; + u32 vtotal_a; + u32 vblank_a; + u32 vsync_a; + u32 src_size_a; + u32 bclrpat_a; + u32 htotal_b; + u32 hblank_b; + u32 hsync_b; + u32 vtotal_b; + u32 vblank_b; + u32 vsync_b; + u32 src_size_b; + u32 bclrpat_b; + u32 adpa; + u32 dvoa; + u32 dvob; + u32 dvoc; + u32 dvoa_srcdim; + u32 dvob_srcdim; + u32 dvoc_srcdim; + u32 lvds; + u32 pipe_a_conf; + u32 pipe_b_conf; + u32 disp_arb; + u32 cursor_a_control; + u32 cursor_b_control; + u32 cursor_a_base; + u32 cursor_b_base; + u32 cursor_size; + u32 disp_a_ctrl; + u32 disp_b_ctrl; + u32 disp_a_base; + u32 disp_b_base; + u32 cursor_a_palette[4]; + u32 cursor_b_palette[4]; + u32 disp_a_stride; + u32 disp_b_stride; + u32 vgacntrl; + u32 add_id; + u32 swf0x[7]; + u32 swf1x[7]; + u32 swf3x[3]; + u32 fence[8]; + u32 instpm; + u32 mem_mode; + u32 fw_blc_0; + u32 fw_blc_1; +}; + +struct intelfb_heap_data { + u32 physical; + u8 __iomem *virtual; + u32 offset; // in GATT pages + u32 size; // in bytes +}; + +struct intelfb_info { + struct fb_info *info; + struct fb_ops *fbops; + struct pci_dev *pdev; + + struct intelfb_hwstate save_state; + + /* agpgart structs */ + struct agp_memory *gtt_fb_mem; // use all stolen memory or vram + struct agp_memory *gtt_ring_mem; // ring buffer + struct agp_memory *gtt_cursor_mem; // hw cursor + + /* use a gart reserved fb mem */ + u8 fbmem_gart; + + /* mtrr support */ + u32 mtrr_reg; + u32 has_mtrr; + + /* heap data */ + struct intelfb_heap_data aperture; + struct intelfb_heap_data fb; + struct intelfb_heap_data ring; + struct intelfb_heap_data cursor; + + /* mmio regs */ + u32 mmio_base_phys; + u8 __iomem *mmio_base; + + /* fb start offset (in bytes) */ + u32 fb_start; + + /* ring buffer */ + u8 __iomem *ring_head; + u32 ring_tail; + u32 ring_tail_mask; + u32 ring_space; + u32 ring_lockup; + + /* palette */ + u32 pseudo_palette[17]; + struct { u8 red, green, blue, pad; } palette[256]; + + /* chip info */ + int pci_chipset; + int chipset; + const char *name; + int mobile; + + /* current mode */ + int bpp, depth; + u32 visual; + int xres, yres, pitch; + int pixclock; + + /* current pipe */ + int pipe; + + /* some flags */ + int accel; + int hwcursor; + int fixed_mode; + int ring_active; + + /* hw cursor */ + int cursor_on; + int cursor_blanked; + u8 cursor_src[64]; + + /* initial parameters */ + int initial_vga; + struct fb_var_screeninfo initial_var; + u32 initial_fb_base; + u32 initial_video_ram; + u32 initial_pitch; + + /* driver registered */ + int registered; +}; + +/*** function prototypes ***/ + +extern int intelfb_var_to_depth(const struct fb_var_screeninfo *var); + +#endif /* _INTELFB_H */ diff --git a/drivers/video/intelfb/intelfbdrv.c b/drivers/video/intelfb/intelfbdrv.c new file mode 100644 index 00000000000..6a05b700083 --- /dev/null +++ b/drivers/video/intelfb/intelfbdrv.c @@ -0,0 +1,1570 @@ +/* + * intelfb + * + * Linux framebuffer driver for Intel(R) 830M/845G/852GM/855GM/865G/915G + * integrated graphics chips. + * + * Copyright © 2002, 2003 David Dawes <dawes@xfree86.org> + * 2004 Sylvain Meyer + * + * This driver consists of two parts. The first part (intelfbdrv.c) provides + * the basic fbdev interfaces, is derived in part from the radeonfb and + * vesafb drivers, and is covered by the GPL. The second part (intelfbhw.c) + * provides the code to program the hardware. Most of it is derived from + * the i810/i830 XFree86 driver. The HW-specific code is covered here + * under a dual license (GPL and MIT/XFree86 license). + * + * Author: David Dawes + * + */ + +/* $DHD: intelfb/intelfbdrv.c,v 1.20 2003/06/27 15:17:40 dawes Exp $ */ + +/* + * Changes: + * 01/2003 - Initial driver (0.1.0), no mode switching, no acceleration. + * This initial version is a basic core that works a lot like + * the vesafb driver. It must be built-in to the kernel, + * and the initial video mode must be set with vga=XXX at + * boot time. (David Dawes) + * + * 01/2003 - Version 0.2.0: Mode switching added, colormap support + * implemented, Y panning, and soft screen blanking implemented. + * No acceleration yet. (David Dawes) + * + * 01/2003 - Version 0.3.0: fbcon acceleration support added. Module + * option handling added. (David Dawes) + * + * 01/2003 - Version 0.4.0: fbcon HW cursor support added. (David Dawes) + * + * 01/2003 - Version 0.4.1: Add auto-generation of built-in modes. + * (David Dawes) + * + * 02/2003 - Version 0.4.2: Add check for active non-CRT devices, and + * mode validation checks. (David Dawes) + * + * 02/2003 - Version 0.4.3: Check when the VC is in graphics mode so that + * acceleration is disabled while an XFree86 server is running. + * (David Dawes) + * + * 02/2003 - Version 0.4.4: Monitor DPMS support. (David Dawes) + * + * 02/2003 - Version 0.4.5: Basic XFree86 + fbdev working. (David Dawes) + * + * 02/2003 - Version 0.5.0: Modify to work with the 2.5.32 kernel as well + * as 2.4.x kernels. (David Dawes) + * + * 02/2003 - Version 0.6.0: Split out HW-specifics into a separate file. + * (David Dawes) + * + * 02/2003 - Version 0.7.0: Test on 852GM/855GM. Acceleration and HW + * cursor are disabled on this platform. (David Dawes) + * + * 02/2003 - Version 0.7.1: Test on 845G. Acceleration is disabled + * on this platform. (David Dawes) + * + * 02/2003 - Version 0.7.2: Test on 830M. Acceleration and HW + * cursor are disabled on this platform. (David Dawes) + * + * 02/2003 - Version 0.7.3: Fix 8-bit modes for mobile platforms + * (David Dawes) + * + * 02/2003 - Version 0.7.4: Add checks for FB and FBCON_HAS_CFB* configured + * in the kernel, and add mode bpp verification and default + * bpp selection based on which FBCON_HAS_CFB* are configured. + * (David Dawes) + * + * 02/2003 - Version 0.7.5: Add basic package/install scripts based on the + * DRI packaging scripts. (David Dawes) + * + * 04/2003 - Version 0.7.6: Fix typo that affects builds with SMP-enabled + * kernels. (David Dawes, reported by Anupam). + * + * 06/2003 - Version 0.7.7: + * Fix Makefile.kernel build problem (Tsutomu Yasuda). + * Fix mis-placed #endif (2.4.21 kernel). + * + * 09/2004 - Version 0.9.0 - by Sylvain Meyer + * Port to linux 2.6 kernel fbdev + * Fix HW accel and HW cursor on i845G + * Use of agpgart for fb memory reservation + * Add mtrr support + * + * 10/2004 - Version 0.9.1 + * Use module_param instead of old MODULE_PARM + * Some cleanup + * + * 11/2004 - Version 0.9.2 + * Add vram option to reserve more memory than stolen by BIOS + * Fix intelfbhw_pan_display typo + * Add __initdata annotations + * + * TODO: + * + * + * Wish List: + * + * + */ + +#include <linux/config.h> +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/errno.h> +#include <linux/string.h> +#include <linux/mm.h> +#include <linux/tty.h> +#include <linux/slab.h> +#include <linux/delay.h> +#include <linux/fb.h> +#include <linux/console.h> +#include <linux/selection.h> +#include <linux/ioport.h> +#include <linux/init.h> +#include <linux/pci.h> +#include <linux/vmalloc.h> +#include <linux/kd.h> +#include <linux/vt_kern.h> +#include <linux/pagemap.h> +#include <linux/version.h> + +#include <asm/io.h> + +#ifdef CONFIG_MTRR +#include <asm/mtrr.h> +#endif + +#include "intelfb.h" +#include "intelfbdrv.h" +#include "intelfbhw.h" + +/* + * Limiting the class to PCI_CLASS_DISPLAY_VGA prevents function 1 of the + * mobile chipsets from being registered. + */ +#if DETECT_VGA_CLASS_ONLY +#define INTELFB_CLASS_MASK ~0 << 8 +#else +#define INTELFB_CLASS_MASK 0 +#endif + +static struct pci_device_id intelfb_pci_table[] __devinitdata = { + { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_830M, PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_DISPLAY_VGA << 8, INTELFB_CLASS_MASK, INTEL_830M }, + { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_845G, PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_DISPLAY_VGA << 8, INTELFB_CLASS_MASK, INTEL_845G }, + { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_85XGM, PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_DISPLAY_VGA << 8, INTELFB_CLASS_MASK, INTEL_85XGM }, + { 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 }, + { 0, } +}; + +/* Global data */ +static int num_registered = 0; + +/* fb ops */ +static struct fb_ops intel_fb_ops = { + .owner = THIS_MODULE, + .fb_check_var = intelfb_check_var, + .fb_set_par = intelfb_set_par, + .fb_setcolreg = intelfb_setcolreg, + .fb_blank = intelfb_blank, + .fb_pan_display = intelfb_pan_display, + .fb_fillrect = intelfb_fillrect, + .fb_copyarea = intelfb_copyarea, + .fb_imageblit = intelfb_imageblit, + .fb_cursor = intelfb_cursor, + .fb_sync = intelfb_sync, + .fb_ioctl = intelfb_ioctl +}; + +/* PCI driver module table */ +static struct pci_driver intelfb_driver = { + .name = "Intel(R) " SUPPORTED_CHIPSETS " Framebuffer Driver", + .id_table = intelfb_pci_table, + .probe = intelfb_pci_register, + .remove = __devexit_p(intelfb_pci_unregister) +}; + +/* Module description/parameters */ +MODULE_AUTHOR("David Dawes <dawes@tungstengraphics.com>, " + "Sylvain Meyer <sylvain.meyer@worldonline.fr>"); +MODULE_DESCRIPTION( + "Framebuffer driver for Intel(R) " SUPPORTED_CHIPSETS " chipsets"); +MODULE_LICENSE("Dual BSD/GPL"); +MODULE_DEVICE_TABLE(pci, intelfb_pci_table); + +static int accel __initdata = 1; +static int vram __initdata = 4; +static int hwcursor __initdata = 1; +static int mtrr __initdata = 1; +static int fixed __initdata = 0; +static int noinit __initdata = 0; +static int noregister __initdata = 0; +static int probeonly __initdata = 0; +static int idonly __initdata = 0; +static int bailearly __initdata = 0; +static char *mode __initdata = NULL; + +module_param(accel, bool, S_IRUGO); +MODULE_PARM_DESC(accel, "Enable console acceleration"); +module_param(vram, int, S_IRUGO); +MODULE_PARM_DESC(vram, "System RAM to allocate to framebuffer in MiB"); +module_param(hwcursor, bool, S_IRUGO); +MODULE_PARM_DESC(hwcursor, "Enable HW cursor"); +module_param(mtrr, bool, S_IRUGO); +MODULE_PARM_DESC(mtrr, "Enable MTRR support"); +module_param(fixed, bool, S_IRUGO); +MODULE_PARM_DESC(fixed, "Disable mode switching"); +module_param(noinit, bool, 0); +MODULE_PARM_DESC(noinit, "Don't initialise graphics mode when loading"); +module_param(noregister, bool, 0); +MODULE_PARM_DESC(noregister, "Don't register, just probe and exit (debug)"); +module_param(probeonly, bool, 0); +MODULE_PARM_DESC(probeonly, "Do a minimal probe (debug)"); +module_param(idonly, bool, 0); +MODULE_PARM_DESC(idonly, "Just identify without doing anything else (debug)"); +module_param(bailearly, bool, 0); +MODULE_PARM_DESC(bailearly, "Bail out early, depending on value (debug)"); +module_param(mode, charp, S_IRUGO); +MODULE_PARM_DESC(mode, + "Initial video mode \"<xres>x<yres>[-<depth>][@<refresh>]\""); + +#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_STRVAL(opt, name) (opt + strlen(name)) + +static __inline__ char * +get_opt_string(const char *this_opt, const char *name) +{ + const char *p; + int i; + char *ret; + + p = OPT_STRVAL(this_opt, name); + i = 0; + while (p[i] && p[i] != ' ' && p[i] != ',') + i++; + ret = kmalloc(i + 1, GFP_KERNEL); + if (ret) { + strncpy(ret, p, i); + ret[i] = '\0'; + } + return ret; +} + +static __inline__ int +get_opt_int(const char *this_opt, const char *name, int *ret) +{ + if (!ret) + return 0; + + if (!OPT_EQUAL(this_opt, name)) + return 0; + + *ret = OPT_INTVAL(this_opt, name); + return 1; +} + +static __inline__ int +get_opt_bool(const char *this_opt, const char *name, int *ret) +{ + if (!ret) + return 0; + + if (OPT_EQUAL(this_opt, name)) { + if (this_opt[strlen(name)] == '=') + *ret = simple_strtoul(this_opt + strlen(name) + 1, + NULL, 0); + else + *ret = 1; + } else { + if (OPT_EQUAL(this_opt, "no") && OPT_EQUAL(this_opt + 2, name)) + *ret = 0; + else + return 0; + } + return 1; +} + +static int __init +intelfb_setup(char *options) +{ + char *this_opt; + + DBG_MSG("intelfb_setup\n"); + + if (!options || !*options) { + DBG_MSG("no options\n"); + return 0; + } else + DBG_MSG("options: %s\n", options); + + /* + * These are the built-in options analogous to the module parameters + * defined above. + * + * The syntax is: + * + * video=intelfb:[mode][,<param>=<val>] ... + * + * e.g., + * + * video=intelfb:1024x768-16@75,accel=0 + */ + + while ((this_opt = strsep(&options, ","))) { + if (!*this_opt) + continue; + if (get_opt_bool(this_opt, "accel", &accel)) + ; + else if (get_opt_int(this_opt, "vram", &vram)) + ; + else if (get_opt_bool(this_opt, "hwcursor", &hwcursor)) + ; + else if (get_opt_bool(this_opt, "mtrr", &mtrr)) + ; + else if (get_opt_bool(this_opt, "fixed", &fixed)) + ; + else if (get_opt_bool(this_opt, "init", &noinit)) + noinit = !noinit; + else if (OPT_EQUAL(this_opt, "mode=")) + mode = get_opt_string(this_opt, "mode="); + else + mode = this_opt; + } + + return 0; +} + +#endif + +static int __init +intelfb_init(void) +{ +#ifndef MODULE + char *option = NULL; +#endif + + DBG_MSG("intelfb_init\n"); + + INF_MSG("Framebuffer driver for " + "Intel(R) " SUPPORTED_CHIPSETS " chipsets\n"); + INF_MSG("Version " INTELFB_VERSION "\n"); + + if (idonly) + return -ENODEV; + +#ifndef MODULE + if (fb_get_options("intelfb", &option)) + return -ENODEV; + intelfb_setup(option); +#endif + + return pci_register_driver(&intelfb_driver); +} + +static void __exit +intelfb_exit(void) +{ + DBG_MSG("intelfb_exit\n"); + pci_unregister_driver(&intelfb_driver); +} + +module_init(intelfb_init); +module_exit(intelfb_exit); + +/*************************************************************** + * mtrr support functions * + ***************************************************************/ + +#ifdef CONFIG_MTRR +static inline void __devinit set_mtrr(struct intelfb_info *dinfo) +{ + dinfo->mtrr_reg = mtrr_add(dinfo->aperture.physical, + dinfo->aperture.size, MTRR_TYPE_WRCOMB, 1); + if (dinfo->mtrr_reg < 0) { + ERR_MSG("unable to set MTRR\n"); + return; + } + dinfo->has_mtrr = 1; +} +static inline void unset_mtrr(struct intelfb_info *dinfo) +{ + if (dinfo->has_mtrr) + mtrr_del(dinfo->mtrr_reg, dinfo->aperture.physical, + dinfo->aperture.size); +} +#else +#define set_mtrr(x) WRN_MSG("MTRR is disabled in the kernel\n") + +#define unset_mtrr(x) do { } while (0) +#endif /* CONFIG_MTRR */ + +/*************************************************************** + * driver init / cleanup * + ***************************************************************/ + +static void +cleanup(struct intelfb_info *dinfo) +{ + DBG_MSG("cleanup\n"); + + if (!dinfo) + return; + + fb_dealloc_cmap(&dinfo->info->cmap); + kfree(dinfo->info->pixmap.addr); + + if (dinfo->registered) + unregister_framebuffer(dinfo->info); + + unset_mtrr(dinfo); + + if (dinfo->fbmem_gart && dinfo->gtt_fb_mem) { + agp_unbind_memory(dinfo->gtt_fb_mem); + agp_free_memory(dinfo->gtt_fb_mem); + } + if (dinfo->gtt_cursor_mem) { + agp_unbind_memory(dinfo->gtt_cursor_mem); + agp_free_memory(dinfo->gtt_cursor_mem); + } + if (dinfo->gtt_ring_mem) { + agp_unbind_memory(dinfo->gtt_ring_mem); + agp_free_memory(dinfo->gtt_ring_mem); + } + + if (dinfo->mmio_base) + iounmap((void __iomem *)dinfo->mmio_base); + if (dinfo->aperture.virtual) + iounmap((void __iomem *)dinfo->aperture.virtual); + + if (dinfo->mmio_base_phys) + release_mem_region(dinfo->mmio_base_phys, INTEL_REG_SIZE); + if (dinfo->aperture.physical) + release_mem_region(dinfo->aperture.physical, + dinfo->aperture.size); + framebuffer_release(dinfo->info); +} + +#define bailout(dinfo) do { \ + DBG_MSG("bailout\n"); \ + cleanup(dinfo); \ + INF_MSG("Not going to register framebuffer, exiting...\n"); \ + return -ENODEV; \ +} while (0) + + +static int __devinit +intelfb_pci_register(struct pci_dev *pdev, const struct pci_device_id *ent) +{ + struct fb_info *info; + struct intelfb_info *dinfo; + int i, j, err, dvo; + int aperture_size, stolen_size; + struct agp_kern_info gtt_info; + int agp_memtype; + const char *s; + struct agp_bridge_data *bridge; + int aperture_bar = 0; + int mmio_bar = 1; + + DBG_MSG("intelfb_pci_register\n"); + + num_registered++; + if (num_registered != 1) { + ERR_MSG("Attempted to register %d devices " + "(should be only 1).\n", num_registered); + return -ENODEV; + } + + info = framebuffer_alloc(sizeof(struct intelfb_info), &pdev->dev); + if (!info) { + ERR_MSG("Could not allocate memory for intelfb_info.\n"); + return -ENODEV; + } + if (fb_alloc_cmap(&info->cmap, 256, 1) < 0) { + ERR_MSG("Could not allocate cmap for intelfb_info.\n"); + goto err_out_cmap; + return -ENODEV; + } + + dinfo = info->par; + dinfo->info = info; + dinfo->fbops = &intel_fb_ops; + dinfo->pdev = pdev; + + /* Reserve pixmap space. */ + info->pixmap.addr = kmalloc(64 * 1024, GFP_KERNEL); + if (info->pixmap.addr == NULL) { + ERR_MSG("Cannot reserve pixmap memory.\n"); + goto err_out_pixmap; + } + memset(info->pixmap.addr, 0, 64 * 1024); + + /* set early this option because it could be changed by tv encoder + driver */ + dinfo->fixed_mode = fixed; + + /* Enable device. */ + if ((err = pci_enable_device(pdev))) { + ERR_MSG("Cannot enable device.\n"); + cleanup(dinfo); + return -ENODEV; + } + + /* Set base addresses. */ + if (ent->device == PCI_DEVICE_ID_INTEL_915G) { + aperture_bar = 2; + mmio_bar = 0; + /* Disable HW cursor on 915G (not implemented yet) */ + hwcursor = 0; + } + dinfo->aperture.physical = pci_resource_start(pdev, aperture_bar); + dinfo->aperture.size = pci_resource_len(pdev, aperture_bar); + dinfo->mmio_base_phys = pci_resource_start(pdev, mmio_bar); + DBG_MSG("fb aperture: 0x%llx/0x%llx, MMIO region: 0x%llx/0x%llx\n", + (unsigned long long)pci_resource_start(pdev, aperture_bar), + (unsigned long long)pci_resource_len(pdev, aperture_bar), + (unsigned long long)pci_resource_start(pdev, mmio_bar), + (unsigned long long)pci_resource_len(pdev, mmio_bar)); + + /* Reserve the fb and MMIO regions */ + if (!request_mem_region(dinfo->aperture.physical, dinfo->aperture.size, + INTELFB_MODULE_NAME)) { + ERR_MSG("Cannot reserve FB region.\n"); + cleanup(dinfo); + return -ENODEV; + } + if (!request_mem_region(dinfo->mmio_base_phys, + INTEL_REG_SIZE, + INTELFB_MODULE_NAME)) { + ERR_MSG("Cannot reserve MMIO region.\n"); + cleanup(dinfo); + return -ENODEV; + } + + /* Map the fb and MMIO regions */ + dinfo->aperture.virtual = (u8 __iomem *)ioremap_nocache + (dinfo->aperture.physical, dinfo->aperture.size); + if (!dinfo->aperture.virtual) { + ERR_MSG("Cannot remap FB region.\n"); + cleanup(dinfo); + return -ENODEV; + } + dinfo->mmio_base = + (u8 __iomem *)ioremap_nocache(dinfo->mmio_base_phys, + INTEL_REG_SIZE); + if (!dinfo->mmio_base) { + ERR_MSG("Cannot remap MMIO region.\n"); + cleanup(dinfo); + return -ENODEV; + } + + /* Get the chipset info. */ + dinfo->pci_chipset = pdev->device; + + if (intelfbhw_get_chipset(pdev, &dinfo->name, &dinfo->chipset, + &dinfo->mobile)) { + cleanup(dinfo); + return -ENODEV; + } + + if (intelfbhw_get_memory(pdev, &aperture_size,&stolen_size)) { + cleanup(dinfo); + return -ENODEV; + } + + INF_MSG("%02x:%02x.%d: %s, aperture size %dMB, " + "stolen memory %dkB\n", + pdev->bus->number, PCI_SLOT(pdev->devfn), + PCI_FUNC(pdev->devfn), dinfo->name, + BtoMB(aperture_size), BtoKB(stolen_size)); + + /* Set these from the options. */ + dinfo->accel = accel; + dinfo->hwcursor = hwcursor; + + if (NOACCEL_CHIPSET(dinfo) && dinfo->accel == 1) { + INF_MSG("Acceleration is not supported for the %s chipset.\n", + dinfo->name); + dinfo->accel = 0; + } + + /* Framebuffer parameters - Use all the stolen memory if >= vram */ + if (ROUND_UP_TO_PAGE(stolen_size) >= MB(vram)) { + dinfo->fb.size = ROUND_UP_TO_PAGE(stolen_size); + dinfo->fbmem_gart = 0; + } else { + dinfo->fb.size = MB(vram); + dinfo->fbmem_gart = 1; + } + + /* Allocate space for the ring buffer and HW cursor if enabled. */ + if (dinfo->accel) { + dinfo->ring.size = RINGBUFFER_SIZE; + dinfo->ring_tail_mask = dinfo->ring.size - 1; + } + if (dinfo->hwcursor) { + dinfo->cursor.size = HW_CURSOR_SIZE; + } + + /* Use agpgart to manage the GATT */ + if (!(bridge = agp_backend_acquire(pdev))) { + ERR_MSG("cannot acquire agp\n"); + cleanup(dinfo); + return -ENODEV; + } + + /* get the current gatt info */ + if (agp_copy_info(bridge, >t_info)) { + ERR_MSG("cannot get agp info\n"); + agp_backend_release(bridge); + cleanup(dinfo); + return -ENODEV; + } + + /* set the mem offsets - set them after the already used pages */ + if (dinfo->accel) { + dinfo->ring.offset = (stolen_size >> 12) + + gtt_info.current_memory; + } + if (dinfo->hwcursor) { + dinfo->cursor.offset = (stolen_size >> 12) + + + gtt_info.current_memory + (dinfo->ring.size >> 12); + } + if (dinfo->fbmem_gart) { + dinfo->fb.offset = (stolen_size >> 12) + + + gtt_info.current_memory + (dinfo->ring.size >> 12) + + (dinfo->cursor.size >> 12); + } + + /* Allocate memories (which aren't stolen) */ + if (dinfo->accel) { + if (!(dinfo->gtt_ring_mem = + agp_allocate_memory(bridge, dinfo->ring.size >> 12, + AGP_NORMAL_MEMORY))) { + ERR_MSG("cannot allocate ring buffer memory\n"); + agp_backend_release(bridge); + cleanup(dinfo); + return -ENOMEM; + } + if (agp_bind_memory(dinfo->gtt_ring_mem, + dinfo->ring.offset)) { + ERR_MSG("cannot bind ring buffer memory\n"); + agp_backend_release(bridge); + cleanup(dinfo); + return -EBUSY; + } + dinfo->ring.physical = dinfo->aperture.physical + + (dinfo->ring.offset << 12); + dinfo->ring.virtual = dinfo->aperture.virtual + + (dinfo->ring.offset << 12); + dinfo->ring_head = dinfo->ring.virtual; + } + if (dinfo->hwcursor) { + agp_memtype = dinfo->mobile ? AGP_PHYSICAL_MEMORY + : AGP_NORMAL_MEMORY; + if (!(dinfo->gtt_cursor_mem = + agp_allocate_memory(bridge, dinfo->cursor.size >> 12, + agp_memtype))) { + ERR_MSG("cannot allocate cursor memory\n"); + agp_backend_release(bridge); + cleanup(dinfo); + return -ENOMEM; + } + if (agp_bind_memory(dinfo->gtt_cursor_mem, + dinfo->cursor.offset)) { + ERR_MSG("cannot bind cursor memory\n"); + agp_backend_release(bridge); + cleanup(dinfo); + return -EBUSY; + } + if (dinfo->mobile) + dinfo->cursor.physical + = dinfo->gtt_cursor_mem->physical; + else + dinfo->cursor.physical = dinfo->aperture.physical + + (dinfo->cursor.offset << 12); + dinfo->cursor.virtual = dinfo->aperture.virtual + + (dinfo->cursor.offset << 12); + } + if (dinfo->fbmem_gart) { + if (!(dinfo->gtt_fb_mem = + agp_allocate_memory(bridge, dinfo->fb.size >> 12, + AGP_NORMAL_MEMORY))) { + WRN_MSG("cannot allocate framebuffer memory - use " + "the stolen one\n"); + dinfo->fbmem_gart = 0; + } + if (agp_bind_memory(dinfo->gtt_fb_mem, + dinfo->fb.offset)) { + WRN_MSG("cannot bind framebuffer memory - use " + "the stolen one\n"); + dinfo->fbmem_gart = 0; + } + } + + /* update framebuffer memory parameters */ + if (!dinfo->fbmem_gart) + dinfo->fb.offset = 0; /* starts at offset 0 */ + dinfo->fb.physical = dinfo->aperture.physical + + (dinfo->fb.offset << 12); + dinfo->fb.virtual = dinfo->aperture.virtual + (dinfo->fb.offset << 12); + dinfo->fb_start = dinfo->fb.offset << 12; + + /* release agpgart */ + agp_backend_release(bridge); + + if (mtrr) + set_mtrr(dinfo); + + DBG_MSG("fb: 0x%x(+ 0x%x)/0x%x (0x%x)\n", + dinfo->fb.physical, dinfo->fb.offset, dinfo->fb.size, + (u32 __iomem ) dinfo->fb.virtual); + DBG_MSG("MMIO: 0x%x/0x%x (0x%x)\n", + dinfo->mmio_base_phys, INTEL_REG_SIZE, + (u32 __iomem) dinfo->mmio_base); + DBG_MSG("ring buffer: 0x%x/0x%x (0x%x)\n", + dinfo->ring.physical, dinfo->ring.size, + (u32 __iomem ) dinfo->ring.virtual); + DBG_MSG("HW cursor: 0x%x/0x%x (0x%x) (offset 0x%x) (phys 0x%x)\n", + dinfo->cursor.physical, dinfo->cursor.size, + (u32 __iomem ) dinfo->cursor.virtual, dinfo->cursor.offset, + dinfo->cursor.physical); + + DBG_MSG("options: vram = %d, accel = %d, hwcursor = %d, fixed = %d, " + "noinit = %d\n", vram, accel, hwcursor, fixed, noinit); + DBG_MSG("options: mode = \"%s\"\n", mode ? mode : ""); + + if (probeonly) + bailout(dinfo); + + /* + * Check if the LVDS port or any DVO ports are enabled. If so, + * don't allow mode switching + */ + dvo = intelfbhw_check_non_crt(dinfo); + if (dvo) { + dinfo->fixed_mode = 1; + WRN_MSG("Non-CRT device is enabled ( "); + i = 0; + while (dvo) { + if (dvo & 1) { + s = intelfbhw_dvo_to_string(1 << i); + if (s) + printk("%s ", s); + } + dvo >>= 1; + ++i; + } + printk("). Disabling mode switching.\n"); + } + + if (bailearly == 1) + bailout(dinfo); + + if (FIXED_MODE(dinfo) && ORIG_VIDEO_ISVGA != VIDEO_TYPE_VLFB) { + ERR_MSG("Video mode must be programmed at boot time.\n"); + cleanup(dinfo); + return -ENODEV; + } + + if (bailearly == 2) + bailout(dinfo); + + /* Initialise dinfo and related data. */ + /* If an initial mode was programmed at boot time, get its details. */ + if (ORIG_VIDEO_ISVGA == VIDEO_TYPE_VLFB) + get_initial_mode(dinfo); + + if (bailearly == 3) + bailout(dinfo); + + if (FIXED_MODE(dinfo)) { + /* remap fb address */ + update_dinfo(dinfo, &dinfo->initial_var); + } + + if (bailearly == 4) + bailout(dinfo); + + + if (intelfb_set_fbinfo(dinfo)) { + cleanup(dinfo); + return -ENODEV; + } + + if (bailearly == 5) + bailout(dinfo); + + for (i = 0; i < 16; i++) { + j = color_table[i]; + dinfo->palette[i].red = default_red[j]; + dinfo->palette[i].green = default_grn[j]; + dinfo->palette[i].blue = default_blu[j]; + } + + if (bailearly == 6) + bailout(dinfo); + + pci_set_drvdata(pdev, dinfo); + + /* Save the initial register state. */ + i = intelfbhw_read_hw_state(dinfo, &dinfo->save_state, + bailearly > 6 ? bailearly - 6 : 0); + if (i != 0) { + DBG_MSG("intelfbhw_read_hw_state returned %d\n", i); + bailout(dinfo); + } + + intelfbhw_print_hw_state(dinfo, &dinfo->save_state); + + if (bailearly == 18) + bailout(dinfo); + + /* Cursor initialisation */ + if (dinfo->hwcursor) { + intelfbhw_cursor_init(dinfo); |