162306a36Sopenharmony_ci/* 262306a36Sopenharmony_ci * intelfb 362306a36Sopenharmony_ci * 462306a36Sopenharmony_ci * Linux framebuffer driver for Intel(R) 830M/845G/852GM/855GM/865G/915G/915GM/ 562306a36Sopenharmony_ci * 945G/945GM/945GME/965G/965GM integrated graphics chips. 662306a36Sopenharmony_ci * 762306a36Sopenharmony_ci * Copyright © 2002, 2003 David Dawes <dawes@xfree86.org> 862306a36Sopenharmony_ci * 2004 Sylvain Meyer 962306a36Sopenharmony_ci * 2006 David Airlie 1062306a36Sopenharmony_ci * 1162306a36Sopenharmony_ci * This driver consists of two parts. The first part (intelfbdrv.c) provides 1262306a36Sopenharmony_ci * the basic fbdev interfaces, is derived in part from the radeonfb and 1362306a36Sopenharmony_ci * vesafb drivers, and is covered by the GPL. The second part (intelfbhw.c) 1462306a36Sopenharmony_ci * provides the code to program the hardware. Most of it is derived from 1562306a36Sopenharmony_ci * the i810/i830 XFree86 driver. The HW-specific code is covered here 1662306a36Sopenharmony_ci * under a dual license (GPL and MIT/XFree86 license). 1762306a36Sopenharmony_ci * 1862306a36Sopenharmony_ci * Author: David Dawes 1962306a36Sopenharmony_ci * 2062306a36Sopenharmony_ci */ 2162306a36Sopenharmony_ci 2262306a36Sopenharmony_ci/* $DHD: intelfb/intelfbdrv.c,v 1.20 2003/06/27 15:17:40 dawes Exp $ */ 2362306a36Sopenharmony_ci 2462306a36Sopenharmony_ci/* 2562306a36Sopenharmony_ci * Changes: 2662306a36Sopenharmony_ci * 01/2003 - Initial driver (0.1.0), no mode switching, no acceleration. 2762306a36Sopenharmony_ci * This initial version is a basic core that works a lot like 2862306a36Sopenharmony_ci * the vesafb driver. It must be built-in to the kernel, 2962306a36Sopenharmony_ci * and the initial video mode must be set with vga=XXX at 3062306a36Sopenharmony_ci * boot time. (David Dawes) 3162306a36Sopenharmony_ci * 3262306a36Sopenharmony_ci * 01/2003 - Version 0.2.0: Mode switching added, colormap support 3362306a36Sopenharmony_ci * implemented, Y panning, and soft screen blanking implemented. 3462306a36Sopenharmony_ci * No acceleration yet. (David Dawes) 3562306a36Sopenharmony_ci * 3662306a36Sopenharmony_ci * 01/2003 - Version 0.3.0: fbcon acceleration support added. Module 3762306a36Sopenharmony_ci * option handling added. (David Dawes) 3862306a36Sopenharmony_ci * 3962306a36Sopenharmony_ci * 01/2003 - Version 0.4.0: fbcon HW cursor support added. (David Dawes) 4062306a36Sopenharmony_ci * 4162306a36Sopenharmony_ci * 01/2003 - Version 0.4.1: Add auto-generation of built-in modes. 4262306a36Sopenharmony_ci * (David Dawes) 4362306a36Sopenharmony_ci * 4462306a36Sopenharmony_ci * 02/2003 - Version 0.4.2: Add check for active non-CRT devices, and 4562306a36Sopenharmony_ci * mode validation checks. (David Dawes) 4662306a36Sopenharmony_ci * 4762306a36Sopenharmony_ci * 02/2003 - Version 0.4.3: Check when the VC is in graphics mode so that 4862306a36Sopenharmony_ci * acceleration is disabled while an XFree86 server is running. 4962306a36Sopenharmony_ci * (David Dawes) 5062306a36Sopenharmony_ci * 5162306a36Sopenharmony_ci * 02/2003 - Version 0.4.4: Monitor DPMS support. (David Dawes) 5262306a36Sopenharmony_ci * 5362306a36Sopenharmony_ci * 02/2003 - Version 0.4.5: Basic XFree86 + fbdev working. (David Dawes) 5462306a36Sopenharmony_ci * 5562306a36Sopenharmony_ci * 02/2003 - Version 0.5.0: Modify to work with the 2.5.32 kernel as well 5662306a36Sopenharmony_ci * as 2.4.x kernels. (David Dawes) 5762306a36Sopenharmony_ci * 5862306a36Sopenharmony_ci * 02/2003 - Version 0.6.0: Split out HW-specifics into a separate file. 5962306a36Sopenharmony_ci * (David Dawes) 6062306a36Sopenharmony_ci * 6162306a36Sopenharmony_ci * 02/2003 - Version 0.7.0: Test on 852GM/855GM. Acceleration and HW 6262306a36Sopenharmony_ci * cursor are disabled on this platform. (David Dawes) 6362306a36Sopenharmony_ci * 6462306a36Sopenharmony_ci * 02/2003 - Version 0.7.1: Test on 845G. Acceleration is disabled 6562306a36Sopenharmony_ci * on this platform. (David Dawes) 6662306a36Sopenharmony_ci * 6762306a36Sopenharmony_ci * 02/2003 - Version 0.7.2: Test on 830M. Acceleration and HW 6862306a36Sopenharmony_ci * cursor are disabled on this platform. (David Dawes) 6962306a36Sopenharmony_ci * 7062306a36Sopenharmony_ci * 02/2003 - Version 0.7.3: Fix 8-bit modes for mobile platforms 7162306a36Sopenharmony_ci * (David Dawes) 7262306a36Sopenharmony_ci * 7362306a36Sopenharmony_ci * 02/2003 - Version 0.7.4: Add checks for FB and FBCON_HAS_CFB* configured 7462306a36Sopenharmony_ci * in the kernel, and add mode bpp verification and default 7562306a36Sopenharmony_ci * bpp selection based on which FBCON_HAS_CFB* are configured. 7662306a36Sopenharmony_ci * (David Dawes) 7762306a36Sopenharmony_ci * 7862306a36Sopenharmony_ci * 02/2003 - Version 0.7.5: Add basic package/install scripts based on the 7962306a36Sopenharmony_ci * DRI packaging scripts. (David Dawes) 8062306a36Sopenharmony_ci * 8162306a36Sopenharmony_ci * 04/2003 - Version 0.7.6: Fix typo that affects builds with SMP-enabled 8262306a36Sopenharmony_ci * kernels. (David Dawes, reported by Anupam). 8362306a36Sopenharmony_ci * 8462306a36Sopenharmony_ci * 06/2003 - Version 0.7.7: 8562306a36Sopenharmony_ci * Fix Makefile.kernel build problem (Tsutomu Yasuda). 8662306a36Sopenharmony_ci * Fix mis-placed #endif (2.4.21 kernel). 8762306a36Sopenharmony_ci * 8862306a36Sopenharmony_ci * 09/2004 - Version 0.9.0 - by Sylvain Meyer 8962306a36Sopenharmony_ci * Port to linux 2.6 kernel fbdev 9062306a36Sopenharmony_ci * Fix HW accel and HW cursor on i845G 9162306a36Sopenharmony_ci * Use of agpgart for fb memory reservation 9262306a36Sopenharmony_ci * Add mtrr support 9362306a36Sopenharmony_ci * 9462306a36Sopenharmony_ci * 10/2004 - Version 0.9.1 9562306a36Sopenharmony_ci * Use module_param instead of old MODULE_PARM 9662306a36Sopenharmony_ci * Some cleanup 9762306a36Sopenharmony_ci * 9862306a36Sopenharmony_ci * 11/2004 - Version 0.9.2 9962306a36Sopenharmony_ci * Add vram option to reserve more memory than stolen by BIOS 10062306a36Sopenharmony_ci * Fix intelfbhw_pan_display typo 10162306a36Sopenharmony_ci * Add __initdata annotations 10262306a36Sopenharmony_ci * 10362306a36Sopenharmony_ci * 04/2008 - Version 0.9.5 10462306a36Sopenharmony_ci * Add support for 965G/965GM. (Maik Broemme <mbroemme@plusserver.de>) 10562306a36Sopenharmony_ci * 10662306a36Sopenharmony_ci * 08/2008 - Version 0.9.6 10762306a36Sopenharmony_ci * Add support for 945GME. (Phil Endecott <spam_from_intelfb@chezphil.org>) 10862306a36Sopenharmony_ci */ 10962306a36Sopenharmony_ci 11062306a36Sopenharmony_ci#include <linux/aperture.h> 11162306a36Sopenharmony_ci#include <linux/module.h> 11262306a36Sopenharmony_ci#include <linux/kernel.h> 11362306a36Sopenharmony_ci#include <linux/errno.h> 11462306a36Sopenharmony_ci#include <linux/string.h> 11562306a36Sopenharmony_ci#include <linux/mm.h> 11662306a36Sopenharmony_ci#include <linux/slab.h> 11762306a36Sopenharmony_ci#include <linux/delay.h> 11862306a36Sopenharmony_ci#include <linux/fb.h> 11962306a36Sopenharmony_ci#include <linux/ioport.h> 12062306a36Sopenharmony_ci#include <linux/init.h> 12162306a36Sopenharmony_ci#include <linux/pci.h> 12262306a36Sopenharmony_ci#include <linux/vmalloc.h> 12362306a36Sopenharmony_ci#include <linux/pagemap.h> 12462306a36Sopenharmony_ci#include <linux/screen_info.h> 12562306a36Sopenharmony_ci 12662306a36Sopenharmony_ci#include <asm/io.h> 12762306a36Sopenharmony_ci 12862306a36Sopenharmony_ci#include "intelfb.h" 12962306a36Sopenharmony_ci#include "intelfbhw.h" 13062306a36Sopenharmony_ci#include "../edid.h" 13162306a36Sopenharmony_ci 13262306a36Sopenharmony_cistatic void get_initial_mode(struct intelfb_info *dinfo); 13362306a36Sopenharmony_cistatic void update_dinfo(struct intelfb_info *dinfo, 13462306a36Sopenharmony_ci struct fb_var_screeninfo *var); 13562306a36Sopenharmony_cistatic int intelfb_open(struct fb_info *info, int user); 13662306a36Sopenharmony_cistatic int intelfb_release(struct fb_info *info, int user); 13762306a36Sopenharmony_cistatic int intelfb_check_var(struct fb_var_screeninfo *var, 13862306a36Sopenharmony_ci struct fb_info *info); 13962306a36Sopenharmony_cistatic int intelfb_set_par(struct fb_info *info); 14062306a36Sopenharmony_cistatic int intelfb_setcolreg(unsigned regno, unsigned red, unsigned green, 14162306a36Sopenharmony_ci unsigned blue, unsigned transp, 14262306a36Sopenharmony_ci struct fb_info *info); 14362306a36Sopenharmony_ci 14462306a36Sopenharmony_cistatic int intelfb_blank(int blank, struct fb_info *info); 14562306a36Sopenharmony_cistatic int intelfb_pan_display(struct fb_var_screeninfo *var, 14662306a36Sopenharmony_ci struct fb_info *info); 14762306a36Sopenharmony_ci 14862306a36Sopenharmony_cistatic void intelfb_fillrect(struct fb_info *info, 14962306a36Sopenharmony_ci const struct fb_fillrect *rect); 15062306a36Sopenharmony_cistatic void intelfb_copyarea(struct fb_info *info, 15162306a36Sopenharmony_ci const struct fb_copyarea *region); 15262306a36Sopenharmony_cistatic void intelfb_imageblit(struct fb_info *info, 15362306a36Sopenharmony_ci const struct fb_image *image); 15462306a36Sopenharmony_cistatic int intelfb_cursor(struct fb_info *info, 15562306a36Sopenharmony_ci struct fb_cursor *cursor); 15662306a36Sopenharmony_ci 15762306a36Sopenharmony_cistatic int intelfb_sync(struct fb_info *info); 15862306a36Sopenharmony_ci 15962306a36Sopenharmony_cistatic int intelfb_ioctl(struct fb_info *info, 16062306a36Sopenharmony_ci unsigned int cmd, unsigned long arg); 16162306a36Sopenharmony_ci 16262306a36Sopenharmony_cistatic int intelfb_pci_register(struct pci_dev *pdev, 16362306a36Sopenharmony_ci const struct pci_device_id *ent); 16462306a36Sopenharmony_cistatic void intelfb_pci_unregister(struct pci_dev *pdev); 16562306a36Sopenharmony_cistatic int intelfb_set_fbinfo(struct intelfb_info *dinfo); 16662306a36Sopenharmony_ci 16762306a36Sopenharmony_ci/* 16862306a36Sopenharmony_ci * Limiting the class to PCI_CLASS_DISPLAY_VGA prevents function 1 of the 16962306a36Sopenharmony_ci * mobile chipsets from being registered. 17062306a36Sopenharmony_ci */ 17162306a36Sopenharmony_ci#if DETECT_VGA_CLASS_ONLY 17262306a36Sopenharmony_ci#define INTELFB_CLASS_MASK ~0 << 8 17362306a36Sopenharmony_ci#else 17462306a36Sopenharmony_ci#define INTELFB_CLASS_MASK 0 17562306a36Sopenharmony_ci#endif 17662306a36Sopenharmony_ci 17762306a36Sopenharmony_cistatic const struct pci_device_id intelfb_pci_table[] = { 17862306a36Sopenharmony_ci { 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 }, 17962306a36Sopenharmony_ci { 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 }, 18062306a36Sopenharmony_ci { 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 }, 18162306a36Sopenharmony_ci { 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 }, 18262306a36Sopenharmony_ci { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_854, PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_DISPLAY_VGA << 8, INTELFB_CLASS_MASK, INTEL_854 }, 18362306a36Sopenharmony_ci { 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 }, 18462306a36Sopenharmony_ci { 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 }, 18562306a36Sopenharmony_ci { 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 }, 18662306a36Sopenharmony_ci { 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 }, 18762306a36Sopenharmony_ci { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_945GME, PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_DISPLAY_VGA << 8, INTELFB_CLASS_MASK, INTEL_945GME }, 18862306a36Sopenharmony_ci { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_965G, PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_DISPLAY_VGA << 8, INTELFB_CLASS_MASK, INTEL_965G }, 18962306a36Sopenharmony_ci { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_965GM, PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_DISPLAY_VGA << 8, INTELFB_CLASS_MASK, INTEL_965GM }, 19062306a36Sopenharmony_ci { 0, } 19162306a36Sopenharmony_ci}; 19262306a36Sopenharmony_ci 19362306a36Sopenharmony_ci/* Global data */ 19462306a36Sopenharmony_cistatic int num_registered = 0; 19562306a36Sopenharmony_ci 19662306a36Sopenharmony_ci/* fb ops */ 19762306a36Sopenharmony_cistatic const struct fb_ops intel_fb_ops = { 19862306a36Sopenharmony_ci .owner = THIS_MODULE, 19962306a36Sopenharmony_ci .fb_open = intelfb_open, 20062306a36Sopenharmony_ci .fb_release = intelfb_release, 20162306a36Sopenharmony_ci .fb_check_var = intelfb_check_var, 20262306a36Sopenharmony_ci .fb_set_par = intelfb_set_par, 20362306a36Sopenharmony_ci .fb_setcolreg = intelfb_setcolreg, 20462306a36Sopenharmony_ci .fb_blank = intelfb_blank, 20562306a36Sopenharmony_ci .fb_pan_display = intelfb_pan_display, 20662306a36Sopenharmony_ci .fb_fillrect = intelfb_fillrect, 20762306a36Sopenharmony_ci .fb_copyarea = intelfb_copyarea, 20862306a36Sopenharmony_ci .fb_imageblit = intelfb_imageblit, 20962306a36Sopenharmony_ci .fb_cursor = intelfb_cursor, 21062306a36Sopenharmony_ci .fb_sync = intelfb_sync, 21162306a36Sopenharmony_ci .fb_ioctl = intelfb_ioctl 21262306a36Sopenharmony_ci}; 21362306a36Sopenharmony_ci 21462306a36Sopenharmony_ci/* PCI driver module table */ 21562306a36Sopenharmony_cistatic struct pci_driver intelfb_driver = { 21662306a36Sopenharmony_ci .name = "intelfb", 21762306a36Sopenharmony_ci .id_table = intelfb_pci_table, 21862306a36Sopenharmony_ci .probe = intelfb_pci_register, 21962306a36Sopenharmony_ci .remove = intelfb_pci_unregister, 22062306a36Sopenharmony_ci}; 22162306a36Sopenharmony_ci 22262306a36Sopenharmony_ci/* Module description/parameters */ 22362306a36Sopenharmony_ciMODULE_AUTHOR("David Dawes <dawes@tungstengraphics.com>, " 22462306a36Sopenharmony_ci "Sylvain Meyer <sylvain.meyer@worldonline.fr>"); 22562306a36Sopenharmony_ciMODULE_DESCRIPTION("Framebuffer driver for Intel(R) " SUPPORTED_CHIPSETS 22662306a36Sopenharmony_ci " chipsets"); 22762306a36Sopenharmony_ciMODULE_LICENSE("Dual BSD/GPL"); 22862306a36Sopenharmony_ciMODULE_DEVICE_TABLE(pci, intelfb_pci_table); 22962306a36Sopenharmony_ci 23062306a36Sopenharmony_cistatic bool accel = 1; 23162306a36Sopenharmony_cistatic int vram = 4; 23262306a36Sopenharmony_cistatic bool hwcursor = 0; 23362306a36Sopenharmony_cistatic bool mtrr = 1; 23462306a36Sopenharmony_cistatic bool fixed = 0; 23562306a36Sopenharmony_cistatic bool noinit = 0; 23662306a36Sopenharmony_cistatic bool noregister = 0; 23762306a36Sopenharmony_cistatic bool probeonly = 0; 23862306a36Sopenharmony_cistatic bool idonly = 0; 23962306a36Sopenharmony_cistatic int bailearly = 0; 24062306a36Sopenharmony_cistatic int voffset = 48; 24162306a36Sopenharmony_cistatic char *mode = NULL; 24262306a36Sopenharmony_ci 24362306a36Sopenharmony_cimodule_param(accel, bool, S_IRUGO); 24462306a36Sopenharmony_ciMODULE_PARM_DESC(accel, "Enable hardware acceleration"); 24562306a36Sopenharmony_cimodule_param(vram, int, S_IRUGO); 24662306a36Sopenharmony_ciMODULE_PARM_DESC(vram, "System RAM to allocate to framebuffer in MiB"); 24762306a36Sopenharmony_cimodule_param(voffset, int, S_IRUGO); 24862306a36Sopenharmony_ciMODULE_PARM_DESC(voffset, "Offset of framebuffer in MiB"); 24962306a36Sopenharmony_cimodule_param(hwcursor, bool, S_IRUGO); 25062306a36Sopenharmony_ciMODULE_PARM_DESC(hwcursor, "Enable HW cursor"); 25162306a36Sopenharmony_cimodule_param(mtrr, bool, S_IRUGO); 25262306a36Sopenharmony_ciMODULE_PARM_DESC(mtrr, "Enable MTRR support"); 25362306a36Sopenharmony_cimodule_param(fixed, bool, S_IRUGO); 25462306a36Sopenharmony_ciMODULE_PARM_DESC(fixed, "Disable mode switching"); 25562306a36Sopenharmony_cimodule_param(noinit, bool, 0); 25662306a36Sopenharmony_ciMODULE_PARM_DESC(noinit, "Don't initialise graphics mode when loading"); 25762306a36Sopenharmony_cimodule_param(noregister, bool, 0); 25862306a36Sopenharmony_ciMODULE_PARM_DESC(noregister, "Don't register, just probe and exit (debug)"); 25962306a36Sopenharmony_cimodule_param(probeonly, bool, 0); 26062306a36Sopenharmony_ciMODULE_PARM_DESC(probeonly, "Do a minimal probe (debug)"); 26162306a36Sopenharmony_cimodule_param(idonly, bool, 0); 26262306a36Sopenharmony_ciMODULE_PARM_DESC(idonly, "Just identify without doing anything else (debug)"); 26362306a36Sopenharmony_cimodule_param(bailearly, int, 0); 26462306a36Sopenharmony_ciMODULE_PARM_DESC(bailearly, "Bail out early, depending on value (debug)"); 26562306a36Sopenharmony_cimodule_param(mode, charp, S_IRUGO); 26662306a36Sopenharmony_ciMODULE_PARM_DESC(mode, 26762306a36Sopenharmony_ci "Initial video mode \"<xres>x<yres>[-<depth>][@<refresh>]\""); 26862306a36Sopenharmony_ci 26962306a36Sopenharmony_ci#ifndef MODULE 27062306a36Sopenharmony_ci#define OPT_EQUAL(opt, name) (!strncmp(opt, name, strlen(name))) 27162306a36Sopenharmony_ci#define OPT_INTVAL(opt, name) simple_strtoul(opt + strlen(name) + 1, NULL, 0) 27262306a36Sopenharmony_ci#define OPT_STRVAL(opt, name) (opt + strlen(name)) 27362306a36Sopenharmony_ci 27462306a36Sopenharmony_cistatic __inline__ char * get_opt_string(const char *this_opt, const char *name) 27562306a36Sopenharmony_ci{ 27662306a36Sopenharmony_ci const char *p; 27762306a36Sopenharmony_ci int i; 27862306a36Sopenharmony_ci char *ret; 27962306a36Sopenharmony_ci 28062306a36Sopenharmony_ci p = OPT_STRVAL(this_opt, name); 28162306a36Sopenharmony_ci i = 0; 28262306a36Sopenharmony_ci while (p[i] && p[i] != ' ' && p[i] != ',') 28362306a36Sopenharmony_ci i++; 28462306a36Sopenharmony_ci ret = kmalloc(i + 1, GFP_KERNEL); 28562306a36Sopenharmony_ci if (ret) { 28662306a36Sopenharmony_ci strncpy(ret, p, i); 28762306a36Sopenharmony_ci ret[i] = '\0'; 28862306a36Sopenharmony_ci } 28962306a36Sopenharmony_ci return ret; 29062306a36Sopenharmony_ci} 29162306a36Sopenharmony_ci 29262306a36Sopenharmony_cistatic __inline__ int get_opt_int(const char *this_opt, const char *name, 29362306a36Sopenharmony_ci int *ret) 29462306a36Sopenharmony_ci{ 29562306a36Sopenharmony_ci if (!ret) 29662306a36Sopenharmony_ci return 0; 29762306a36Sopenharmony_ci 29862306a36Sopenharmony_ci if (!OPT_EQUAL(this_opt, name)) 29962306a36Sopenharmony_ci return 0; 30062306a36Sopenharmony_ci 30162306a36Sopenharmony_ci *ret = OPT_INTVAL(this_opt, name); 30262306a36Sopenharmony_ci return 1; 30362306a36Sopenharmony_ci} 30462306a36Sopenharmony_ci 30562306a36Sopenharmony_cistatic __inline__ int get_opt_bool(const char *this_opt, const char *name, 30662306a36Sopenharmony_ci bool *ret) 30762306a36Sopenharmony_ci{ 30862306a36Sopenharmony_ci if (!ret) 30962306a36Sopenharmony_ci return 0; 31062306a36Sopenharmony_ci 31162306a36Sopenharmony_ci if (OPT_EQUAL(this_opt, name)) { 31262306a36Sopenharmony_ci if (this_opt[strlen(name)] == '=') 31362306a36Sopenharmony_ci *ret = simple_strtoul(this_opt + strlen(name) + 1, 31462306a36Sopenharmony_ci NULL, 0); 31562306a36Sopenharmony_ci else 31662306a36Sopenharmony_ci *ret = 1; 31762306a36Sopenharmony_ci } else { 31862306a36Sopenharmony_ci if (OPT_EQUAL(this_opt, "no") && OPT_EQUAL(this_opt + 2, name)) 31962306a36Sopenharmony_ci *ret = 0; 32062306a36Sopenharmony_ci else 32162306a36Sopenharmony_ci return 0; 32262306a36Sopenharmony_ci } 32362306a36Sopenharmony_ci return 1; 32462306a36Sopenharmony_ci} 32562306a36Sopenharmony_ci 32662306a36Sopenharmony_cistatic int __init intelfb_setup(char *options) 32762306a36Sopenharmony_ci{ 32862306a36Sopenharmony_ci char *this_opt; 32962306a36Sopenharmony_ci 33062306a36Sopenharmony_ci DBG_MSG("intelfb_setup\n"); 33162306a36Sopenharmony_ci 33262306a36Sopenharmony_ci if (!options || !*options) { 33362306a36Sopenharmony_ci DBG_MSG("no options\n"); 33462306a36Sopenharmony_ci return 0; 33562306a36Sopenharmony_ci } else 33662306a36Sopenharmony_ci DBG_MSG("options: %s\n", options); 33762306a36Sopenharmony_ci 33862306a36Sopenharmony_ci /* 33962306a36Sopenharmony_ci * These are the built-in options analogous to the module parameters 34062306a36Sopenharmony_ci * defined above. 34162306a36Sopenharmony_ci * 34262306a36Sopenharmony_ci * The syntax is: 34362306a36Sopenharmony_ci * 34462306a36Sopenharmony_ci * video=intelfb:[mode][,<param>=<val>] ... 34562306a36Sopenharmony_ci * 34662306a36Sopenharmony_ci * e.g., 34762306a36Sopenharmony_ci * 34862306a36Sopenharmony_ci * video=intelfb:1024x768-16@75,accel=0 34962306a36Sopenharmony_ci */ 35062306a36Sopenharmony_ci 35162306a36Sopenharmony_ci while ((this_opt = strsep(&options, ","))) { 35262306a36Sopenharmony_ci if (!*this_opt) 35362306a36Sopenharmony_ci continue; 35462306a36Sopenharmony_ci if (get_opt_bool(this_opt, "accel", &accel)) 35562306a36Sopenharmony_ci ; 35662306a36Sopenharmony_ci else if (get_opt_int(this_opt, "vram", &vram)) 35762306a36Sopenharmony_ci ; 35862306a36Sopenharmony_ci else if (get_opt_bool(this_opt, "hwcursor", &hwcursor)) 35962306a36Sopenharmony_ci ; 36062306a36Sopenharmony_ci else if (get_opt_bool(this_opt, "mtrr", &mtrr)) 36162306a36Sopenharmony_ci ; 36262306a36Sopenharmony_ci else if (get_opt_bool(this_opt, "fixed", &fixed)) 36362306a36Sopenharmony_ci ; 36462306a36Sopenharmony_ci else if (get_opt_bool(this_opt, "init", &noinit)) 36562306a36Sopenharmony_ci noinit = !noinit; 36662306a36Sopenharmony_ci else if (OPT_EQUAL(this_opt, "mode=")) 36762306a36Sopenharmony_ci mode = get_opt_string(this_opt, "mode="); 36862306a36Sopenharmony_ci else 36962306a36Sopenharmony_ci mode = this_opt; 37062306a36Sopenharmony_ci } 37162306a36Sopenharmony_ci 37262306a36Sopenharmony_ci return 0; 37362306a36Sopenharmony_ci} 37462306a36Sopenharmony_ci 37562306a36Sopenharmony_ci#endif 37662306a36Sopenharmony_ci 37762306a36Sopenharmony_cistatic int __init intelfb_init(void) 37862306a36Sopenharmony_ci{ 37962306a36Sopenharmony_ci#ifndef MODULE 38062306a36Sopenharmony_ci char *option = NULL; 38162306a36Sopenharmony_ci#endif 38262306a36Sopenharmony_ci 38362306a36Sopenharmony_ci DBG_MSG("intelfb_init\n"); 38462306a36Sopenharmony_ci 38562306a36Sopenharmony_ci INF_MSG("Framebuffer driver for " 38662306a36Sopenharmony_ci "Intel(R) " SUPPORTED_CHIPSETS " chipsets\n"); 38762306a36Sopenharmony_ci INF_MSG("Version " INTELFB_VERSION "\n"); 38862306a36Sopenharmony_ci 38962306a36Sopenharmony_ci if (idonly) 39062306a36Sopenharmony_ci return -ENODEV; 39162306a36Sopenharmony_ci 39262306a36Sopenharmony_ci if (fb_modesetting_disabled("intelfb")) 39362306a36Sopenharmony_ci return -ENODEV; 39462306a36Sopenharmony_ci 39562306a36Sopenharmony_ci#ifndef MODULE 39662306a36Sopenharmony_ci if (fb_get_options("intelfb", &option)) 39762306a36Sopenharmony_ci return -ENODEV; 39862306a36Sopenharmony_ci intelfb_setup(option); 39962306a36Sopenharmony_ci#endif 40062306a36Sopenharmony_ci 40162306a36Sopenharmony_ci return pci_register_driver(&intelfb_driver); 40262306a36Sopenharmony_ci} 40362306a36Sopenharmony_ci 40462306a36Sopenharmony_cistatic void __exit intelfb_exit(void) 40562306a36Sopenharmony_ci{ 40662306a36Sopenharmony_ci DBG_MSG("intelfb_exit\n"); 40762306a36Sopenharmony_ci pci_unregister_driver(&intelfb_driver); 40862306a36Sopenharmony_ci} 40962306a36Sopenharmony_ci 41062306a36Sopenharmony_cimodule_init(intelfb_init); 41162306a36Sopenharmony_cimodule_exit(intelfb_exit); 41262306a36Sopenharmony_ci 41362306a36Sopenharmony_ci/*************************************************************** 41462306a36Sopenharmony_ci * driver init / cleanup * 41562306a36Sopenharmony_ci ***************************************************************/ 41662306a36Sopenharmony_ci 41762306a36Sopenharmony_cistatic void cleanup(struct intelfb_info *dinfo) 41862306a36Sopenharmony_ci{ 41962306a36Sopenharmony_ci DBG_MSG("cleanup\n"); 42062306a36Sopenharmony_ci 42162306a36Sopenharmony_ci if (!dinfo) 42262306a36Sopenharmony_ci return; 42362306a36Sopenharmony_ci 42462306a36Sopenharmony_ci intelfbhw_disable_irq(dinfo); 42562306a36Sopenharmony_ci 42662306a36Sopenharmony_ci fb_dealloc_cmap(&dinfo->info->cmap); 42762306a36Sopenharmony_ci kfree(dinfo->info->pixmap.addr); 42862306a36Sopenharmony_ci 42962306a36Sopenharmony_ci if (dinfo->registered) 43062306a36Sopenharmony_ci unregister_framebuffer(dinfo->info); 43162306a36Sopenharmony_ci 43262306a36Sopenharmony_ci arch_phys_wc_del(dinfo->wc_cookie); 43362306a36Sopenharmony_ci 43462306a36Sopenharmony_ci if (dinfo->fbmem_gart && dinfo->gtt_fb_mem) { 43562306a36Sopenharmony_ci agp_unbind_memory(dinfo->gtt_fb_mem); 43662306a36Sopenharmony_ci agp_free_memory(dinfo->gtt_fb_mem); 43762306a36Sopenharmony_ci } 43862306a36Sopenharmony_ci if (dinfo->gtt_cursor_mem) { 43962306a36Sopenharmony_ci agp_unbind_memory(dinfo->gtt_cursor_mem); 44062306a36Sopenharmony_ci agp_free_memory(dinfo->gtt_cursor_mem); 44162306a36Sopenharmony_ci } 44262306a36Sopenharmony_ci if (dinfo->gtt_ring_mem) { 44362306a36Sopenharmony_ci agp_unbind_memory(dinfo->gtt_ring_mem); 44462306a36Sopenharmony_ci agp_free_memory(dinfo->gtt_ring_mem); 44562306a36Sopenharmony_ci } 44662306a36Sopenharmony_ci 44762306a36Sopenharmony_ci#ifdef CONFIG_FB_INTEL_I2C 44862306a36Sopenharmony_ci /* un-register I2C bus */ 44962306a36Sopenharmony_ci intelfb_delete_i2c_busses(dinfo); 45062306a36Sopenharmony_ci#endif 45162306a36Sopenharmony_ci 45262306a36Sopenharmony_ci if (dinfo->mmio_base) 45362306a36Sopenharmony_ci iounmap((void __iomem *)dinfo->mmio_base); 45462306a36Sopenharmony_ci if (dinfo->aperture.virtual) 45562306a36Sopenharmony_ci iounmap((void __iomem *)dinfo->aperture.virtual); 45662306a36Sopenharmony_ci 45762306a36Sopenharmony_ci if (dinfo->flag & INTELFB_MMIO_ACQUIRED) 45862306a36Sopenharmony_ci release_mem_region(dinfo->mmio_base_phys, INTEL_REG_SIZE); 45962306a36Sopenharmony_ci if (dinfo->flag & INTELFB_FB_ACQUIRED) 46062306a36Sopenharmony_ci release_mem_region(dinfo->aperture.physical, 46162306a36Sopenharmony_ci dinfo->aperture.size); 46262306a36Sopenharmony_ci framebuffer_release(dinfo->info); 46362306a36Sopenharmony_ci} 46462306a36Sopenharmony_ci 46562306a36Sopenharmony_ci#define bailout(dinfo) do { \ 46662306a36Sopenharmony_ci DBG_MSG("bailout\n"); \ 46762306a36Sopenharmony_ci cleanup(dinfo); \ 46862306a36Sopenharmony_ci INF_MSG("Not going to register framebuffer, exiting...\n"); \ 46962306a36Sopenharmony_ci return -ENODEV; \ 47062306a36Sopenharmony_ci} while (0) 47162306a36Sopenharmony_ci 47262306a36Sopenharmony_ci 47362306a36Sopenharmony_cistatic int intelfb_pci_register(struct pci_dev *pdev, 47462306a36Sopenharmony_ci const struct pci_device_id *ent) 47562306a36Sopenharmony_ci{ 47662306a36Sopenharmony_ci struct fb_info *info; 47762306a36Sopenharmony_ci struct intelfb_info *dinfo; 47862306a36Sopenharmony_ci int i, err, dvo; 47962306a36Sopenharmony_ci int aperture_size, stolen_size = 0; 48062306a36Sopenharmony_ci struct agp_kern_info gtt_info; 48162306a36Sopenharmony_ci int agp_memtype; 48262306a36Sopenharmony_ci const char *s; 48362306a36Sopenharmony_ci struct agp_bridge_data *bridge; 48462306a36Sopenharmony_ci int aperture_bar = 0; 48562306a36Sopenharmony_ci int mmio_bar = 1; 48662306a36Sopenharmony_ci int offset; 48762306a36Sopenharmony_ci 48862306a36Sopenharmony_ci DBG_MSG("intelfb_pci_register\n"); 48962306a36Sopenharmony_ci 49062306a36Sopenharmony_ci err = aperture_remove_conflicting_pci_devices(pdev, "intelfb"); 49162306a36Sopenharmony_ci if (err) 49262306a36Sopenharmony_ci return err; 49362306a36Sopenharmony_ci 49462306a36Sopenharmony_ci num_registered++; 49562306a36Sopenharmony_ci if (num_registered != 1) { 49662306a36Sopenharmony_ci ERR_MSG("Attempted to register %d devices " 49762306a36Sopenharmony_ci "(should be only 1).\n", num_registered); 49862306a36Sopenharmony_ci return -ENODEV; 49962306a36Sopenharmony_ci } 50062306a36Sopenharmony_ci 50162306a36Sopenharmony_ci info = framebuffer_alloc(sizeof(struct intelfb_info), &pdev->dev); 50262306a36Sopenharmony_ci if (!info) 50362306a36Sopenharmony_ci return -ENOMEM; 50462306a36Sopenharmony_ci 50562306a36Sopenharmony_ci if (fb_alloc_cmap(&info->cmap, 256, 1) < 0) { 50662306a36Sopenharmony_ci ERR_MSG("Could not allocate cmap for intelfb_info.\n"); 50762306a36Sopenharmony_ci goto err_out_cmap; 50862306a36Sopenharmony_ci } 50962306a36Sopenharmony_ci 51062306a36Sopenharmony_ci dinfo = info->par; 51162306a36Sopenharmony_ci dinfo->info = info; 51262306a36Sopenharmony_ci dinfo->fbops = &intel_fb_ops; 51362306a36Sopenharmony_ci dinfo->pdev = pdev; 51462306a36Sopenharmony_ci 51562306a36Sopenharmony_ci /* Reserve pixmap space. */ 51662306a36Sopenharmony_ci info->pixmap.addr = kzalloc(64 * 1024, GFP_KERNEL); 51762306a36Sopenharmony_ci if (info->pixmap.addr == NULL) { 51862306a36Sopenharmony_ci ERR_MSG("Cannot reserve pixmap memory.\n"); 51962306a36Sopenharmony_ci goto err_out_pixmap; 52062306a36Sopenharmony_ci } 52162306a36Sopenharmony_ci 52262306a36Sopenharmony_ci /* set early this option because it could be changed by tv encoder 52362306a36Sopenharmony_ci driver */ 52462306a36Sopenharmony_ci dinfo->fixed_mode = fixed; 52562306a36Sopenharmony_ci 52662306a36Sopenharmony_ci /* Enable device. */ 52762306a36Sopenharmony_ci if ((err = pci_enable_device(pdev))) { 52862306a36Sopenharmony_ci ERR_MSG("Cannot enable device.\n"); 52962306a36Sopenharmony_ci cleanup(dinfo); 53062306a36Sopenharmony_ci return -ENODEV; 53162306a36Sopenharmony_ci } 53262306a36Sopenharmony_ci 53362306a36Sopenharmony_ci /* Set base addresses. */ 53462306a36Sopenharmony_ci if ((ent->device == PCI_DEVICE_ID_INTEL_915G) || 53562306a36Sopenharmony_ci (ent->device == PCI_DEVICE_ID_INTEL_915GM) || 53662306a36Sopenharmony_ci (ent->device == PCI_DEVICE_ID_INTEL_945G) || 53762306a36Sopenharmony_ci (ent->device == PCI_DEVICE_ID_INTEL_945GM) || 53862306a36Sopenharmony_ci (ent->device == PCI_DEVICE_ID_INTEL_945GME) || 53962306a36Sopenharmony_ci (ent->device == PCI_DEVICE_ID_INTEL_965G) || 54062306a36Sopenharmony_ci (ent->device == PCI_DEVICE_ID_INTEL_965GM)) { 54162306a36Sopenharmony_ci 54262306a36Sopenharmony_ci aperture_bar = 2; 54362306a36Sopenharmony_ci mmio_bar = 0; 54462306a36Sopenharmony_ci } 54562306a36Sopenharmony_ci dinfo->aperture.physical = pci_resource_start(pdev, aperture_bar); 54662306a36Sopenharmony_ci dinfo->aperture.size = pci_resource_len(pdev, aperture_bar); 54762306a36Sopenharmony_ci dinfo->mmio_base_phys = pci_resource_start(pdev, mmio_bar); 54862306a36Sopenharmony_ci DBG_MSG("fb aperture: 0x%llx/0x%llx, MMIO region: 0x%llx/0x%llx\n", 54962306a36Sopenharmony_ci (unsigned long long)pci_resource_start(pdev, aperture_bar), 55062306a36Sopenharmony_ci (unsigned long long)pci_resource_len(pdev, aperture_bar), 55162306a36Sopenharmony_ci (unsigned long long)pci_resource_start(pdev, mmio_bar), 55262306a36Sopenharmony_ci (unsigned long long)pci_resource_len(pdev, mmio_bar)); 55362306a36Sopenharmony_ci 55462306a36Sopenharmony_ci /* Reserve the fb and MMIO regions */ 55562306a36Sopenharmony_ci if (!request_mem_region(dinfo->aperture.physical, dinfo->aperture.size, 55662306a36Sopenharmony_ci INTELFB_MODULE_NAME)) { 55762306a36Sopenharmony_ci ERR_MSG("Cannot reserve FB region.\n"); 55862306a36Sopenharmony_ci cleanup(dinfo); 55962306a36Sopenharmony_ci return -ENODEV; 56062306a36Sopenharmony_ci } 56162306a36Sopenharmony_ci 56262306a36Sopenharmony_ci dinfo->flag |= INTELFB_FB_ACQUIRED; 56362306a36Sopenharmony_ci 56462306a36Sopenharmony_ci if (!request_mem_region(dinfo->mmio_base_phys, 56562306a36Sopenharmony_ci INTEL_REG_SIZE, 56662306a36Sopenharmony_ci INTELFB_MODULE_NAME)) { 56762306a36Sopenharmony_ci ERR_MSG("Cannot reserve MMIO region.\n"); 56862306a36Sopenharmony_ci cleanup(dinfo); 56962306a36Sopenharmony_ci return -ENODEV; 57062306a36Sopenharmony_ci } 57162306a36Sopenharmony_ci 57262306a36Sopenharmony_ci dinfo->flag |= INTELFB_MMIO_ACQUIRED; 57362306a36Sopenharmony_ci 57462306a36Sopenharmony_ci /* Get the chipset info. */ 57562306a36Sopenharmony_ci dinfo->pci_chipset = pdev->device; 57662306a36Sopenharmony_ci 57762306a36Sopenharmony_ci if (intelfbhw_get_chipset(pdev, dinfo)) { 57862306a36Sopenharmony_ci cleanup(dinfo); 57962306a36Sopenharmony_ci return -ENODEV; 58062306a36Sopenharmony_ci } 58162306a36Sopenharmony_ci 58262306a36Sopenharmony_ci if (intelfbhw_get_memory(pdev, &aperture_size, &stolen_size)) { 58362306a36Sopenharmony_ci cleanup(dinfo); 58462306a36Sopenharmony_ci return -ENODEV; 58562306a36Sopenharmony_ci } 58662306a36Sopenharmony_ci 58762306a36Sopenharmony_ci INF_MSG("%02x:%02x.%d: %s, aperture size %dMB, " 58862306a36Sopenharmony_ci "stolen memory %dkB\n", 58962306a36Sopenharmony_ci pdev->bus->number, PCI_SLOT(pdev->devfn), 59062306a36Sopenharmony_ci PCI_FUNC(pdev->devfn), dinfo->name, 59162306a36Sopenharmony_ci BtoMB(aperture_size), BtoKB(stolen_size)); 59262306a36Sopenharmony_ci 59362306a36Sopenharmony_ci /* Set these from the options. */ 59462306a36Sopenharmony_ci dinfo->accel = accel; 59562306a36Sopenharmony_ci dinfo->hwcursor = hwcursor; 59662306a36Sopenharmony_ci 59762306a36Sopenharmony_ci if (NOACCEL_CHIPSET(dinfo) && dinfo->accel == 1) { 59862306a36Sopenharmony_ci INF_MSG("Acceleration is not supported for the %s chipset.\n", 59962306a36Sopenharmony_ci dinfo->name); 60062306a36Sopenharmony_ci dinfo->accel = 0; 60162306a36Sopenharmony_ci } 60262306a36Sopenharmony_ci 60362306a36Sopenharmony_ci /* Framebuffer parameters - Use all the stolen memory if >= vram */ 60462306a36Sopenharmony_ci if (ROUND_UP_TO_PAGE(stolen_size) >= MB(vram)) { 60562306a36Sopenharmony_ci dinfo->fb.size = ROUND_UP_TO_PAGE(stolen_size); 60662306a36Sopenharmony_ci dinfo->fbmem_gart = 0; 60762306a36Sopenharmony_ci } else { 60862306a36Sopenharmony_ci dinfo->fb.size = MB(vram); 60962306a36Sopenharmony_ci dinfo->fbmem_gart = 1; 61062306a36Sopenharmony_ci } 61162306a36Sopenharmony_ci 61262306a36Sopenharmony_ci /* Allocate space for the ring buffer and HW cursor if enabled. */ 61362306a36Sopenharmony_ci if (dinfo->accel) { 61462306a36Sopenharmony_ci dinfo->ring.size = RINGBUFFER_SIZE; 61562306a36Sopenharmony_ci dinfo->ring_tail_mask = dinfo->ring.size - 1; 61662306a36Sopenharmony_ci } 61762306a36Sopenharmony_ci if (dinfo->hwcursor) 61862306a36Sopenharmony_ci dinfo->cursor.size = HW_CURSOR_SIZE; 61962306a36Sopenharmony_ci 62062306a36Sopenharmony_ci /* Use agpgart to manage the GATT */ 62162306a36Sopenharmony_ci if (!(bridge = agp_backend_acquire(pdev))) { 62262306a36Sopenharmony_ci ERR_MSG("cannot acquire agp\n"); 62362306a36Sopenharmony_ci cleanup(dinfo); 62462306a36Sopenharmony_ci return -ENODEV; 62562306a36Sopenharmony_ci } 62662306a36Sopenharmony_ci 62762306a36Sopenharmony_ci /* get the current gatt info */ 62862306a36Sopenharmony_ci if (agp_copy_info(bridge, >t_info)) { 62962306a36Sopenharmony_ci ERR_MSG("cannot get agp info\n"); 63062306a36Sopenharmony_ci agp_backend_release(bridge); 63162306a36Sopenharmony_ci cleanup(dinfo); 63262306a36Sopenharmony_ci return -ENODEV; 63362306a36Sopenharmony_ci } 63462306a36Sopenharmony_ci 63562306a36Sopenharmony_ci if (MB(voffset) < stolen_size) 63662306a36Sopenharmony_ci offset = (stolen_size >> 12); 63762306a36Sopenharmony_ci else 63862306a36Sopenharmony_ci offset = ROUND_UP_TO_PAGE(MB(voffset))/GTT_PAGE_SIZE; 63962306a36Sopenharmony_ci 64062306a36Sopenharmony_ci /* set the mem offsets - set them after the already used pages */ 64162306a36Sopenharmony_ci if (dinfo->accel) 64262306a36Sopenharmony_ci dinfo->ring.offset = offset + gtt_info.current_memory; 64362306a36Sopenharmony_ci if (dinfo->hwcursor) 64462306a36Sopenharmony_ci dinfo->cursor.offset = offset + 64562306a36Sopenharmony_ci + gtt_info.current_memory + (dinfo->ring.size >> 12); 64662306a36Sopenharmony_ci if (dinfo->fbmem_gart) 64762306a36Sopenharmony_ci dinfo->fb.offset = offset + 64862306a36Sopenharmony_ci + gtt_info.current_memory + (dinfo->ring.size >> 12) 64962306a36Sopenharmony_ci + (dinfo->cursor.size >> 12); 65062306a36Sopenharmony_ci 65162306a36Sopenharmony_ci /* Allocate memories (which aren't stolen) */ 65262306a36Sopenharmony_ci /* Map the fb and MMIO regions */ 65362306a36Sopenharmony_ci /* ioremap only up to the end of used aperture */ 65462306a36Sopenharmony_ci dinfo->aperture.virtual = (u8 __iomem *)ioremap_wc 65562306a36Sopenharmony_ci (dinfo->aperture.physical, ((offset + dinfo->fb.offset) << 12) 65662306a36Sopenharmony_ci + dinfo->fb.size); 65762306a36Sopenharmony_ci if (!dinfo->aperture.virtual) { 65862306a36Sopenharmony_ci ERR_MSG("Cannot remap FB region.\n"); 65962306a36Sopenharmony_ci agp_backend_release(bridge); 66062306a36Sopenharmony_ci cleanup(dinfo); 66162306a36Sopenharmony_ci return -ENODEV; 66262306a36Sopenharmony_ci } 66362306a36Sopenharmony_ci 66462306a36Sopenharmony_ci dinfo->mmio_base = 66562306a36Sopenharmony_ci (u8 __iomem *)ioremap(dinfo->mmio_base_phys, 66662306a36Sopenharmony_ci INTEL_REG_SIZE); 66762306a36Sopenharmony_ci if (!dinfo->mmio_base) { 66862306a36Sopenharmony_ci ERR_MSG("Cannot remap MMIO region.\n"); 66962306a36Sopenharmony_ci agp_backend_release(bridge); 67062306a36Sopenharmony_ci cleanup(dinfo); 67162306a36Sopenharmony_ci return -ENODEV; 67262306a36Sopenharmony_ci } 67362306a36Sopenharmony_ci 67462306a36Sopenharmony_ci if (dinfo->accel) { 67562306a36Sopenharmony_ci if (!(dinfo->gtt_ring_mem = 67662306a36Sopenharmony_ci agp_allocate_memory(bridge, dinfo->ring.size >> 12, 67762306a36Sopenharmony_ci AGP_NORMAL_MEMORY))) { 67862306a36Sopenharmony_ci ERR_MSG("cannot allocate ring buffer memory\n"); 67962306a36Sopenharmony_ci agp_backend_release(bridge); 68062306a36Sopenharmony_ci cleanup(dinfo); 68162306a36Sopenharmony_ci return -ENOMEM; 68262306a36Sopenharmony_ci } 68362306a36Sopenharmony_ci if (agp_bind_memory(dinfo->gtt_ring_mem, 68462306a36Sopenharmony_ci dinfo->ring.offset)) { 68562306a36Sopenharmony_ci ERR_MSG("cannot bind ring buffer memory\n"); 68662306a36Sopenharmony_ci agp_backend_release(bridge); 68762306a36Sopenharmony_ci cleanup(dinfo); 68862306a36Sopenharmony_ci return -EBUSY; 68962306a36Sopenharmony_ci } 69062306a36Sopenharmony_ci dinfo->ring.physical = dinfo->aperture.physical 69162306a36Sopenharmony_ci + (dinfo->ring.offset << 12); 69262306a36Sopenharmony_ci dinfo->ring.virtual = dinfo->aperture.virtual 69362306a36Sopenharmony_ci + (dinfo->ring.offset << 12); 69462306a36Sopenharmony_ci dinfo->ring_head = 0; 69562306a36Sopenharmony_ci } 69662306a36Sopenharmony_ci if (dinfo->hwcursor) { 69762306a36Sopenharmony_ci agp_memtype = dinfo->mobile ? AGP_PHYSICAL_MEMORY 69862306a36Sopenharmony_ci : AGP_NORMAL_MEMORY; 69962306a36Sopenharmony_ci if (!(dinfo->gtt_cursor_mem = 70062306a36Sopenharmony_ci agp_allocate_memory(bridge, dinfo->cursor.size >> 12, 70162306a36Sopenharmony_ci agp_memtype))) { 70262306a36Sopenharmony_ci ERR_MSG("cannot allocate cursor memory\n"); 70362306a36Sopenharmony_ci agp_backend_release(bridge); 70462306a36Sopenharmony_ci cleanup(dinfo); 70562306a36Sopenharmony_ci return -ENOMEM; 70662306a36Sopenharmony_ci } 70762306a36Sopenharmony_ci if (agp_bind_memory(dinfo->gtt_cursor_mem, 70862306a36Sopenharmony_ci dinfo->cursor.offset)) { 70962306a36Sopenharmony_ci ERR_MSG("cannot bind cursor memory\n"); 71062306a36Sopenharmony_ci agp_backend_release(bridge); 71162306a36Sopenharmony_ci cleanup(dinfo); 71262306a36Sopenharmony_ci return -EBUSY; 71362306a36Sopenharmony_ci } 71462306a36Sopenharmony_ci if (dinfo->mobile) 71562306a36Sopenharmony_ci dinfo->cursor.physical 71662306a36Sopenharmony_ci = dinfo->gtt_cursor_mem->physical; 71762306a36Sopenharmony_ci else 71862306a36Sopenharmony_ci dinfo->cursor.physical = dinfo->aperture.physical 71962306a36Sopenharmony_ci + (dinfo->cursor.offset << 12); 72062306a36Sopenharmony_ci dinfo->cursor.virtual = dinfo->aperture.virtual 72162306a36Sopenharmony_ci + (dinfo->cursor.offset << 12); 72262306a36Sopenharmony_ci } 72362306a36Sopenharmony_ci if (dinfo->fbmem_gart) { 72462306a36Sopenharmony_ci if (!(dinfo->gtt_fb_mem = 72562306a36Sopenharmony_ci agp_allocate_memory(bridge, dinfo->fb.size >> 12, 72662306a36Sopenharmony_ci AGP_NORMAL_MEMORY))) { 72762306a36Sopenharmony_ci WRN_MSG("cannot allocate framebuffer memory - use " 72862306a36Sopenharmony_ci "the stolen one\n"); 72962306a36Sopenharmony_ci dinfo->fbmem_gart = 0; 73062306a36Sopenharmony_ci } 73162306a36Sopenharmony_ci if (agp_bind_memory(dinfo->gtt_fb_mem, 73262306a36Sopenharmony_ci dinfo->fb.offset)) { 73362306a36Sopenharmony_ci WRN_MSG("cannot bind framebuffer memory - use " 73462306a36Sopenharmony_ci "the stolen one\n"); 73562306a36Sopenharmony_ci dinfo->fbmem_gart = 0; 73662306a36Sopenharmony_ci } 73762306a36Sopenharmony_ci } 73862306a36Sopenharmony_ci 73962306a36Sopenharmony_ci /* update framebuffer memory parameters */ 74062306a36Sopenharmony_ci if (!dinfo->fbmem_gart) 74162306a36Sopenharmony_ci dinfo->fb.offset = 0; /* starts at offset 0 */ 74262306a36Sopenharmony_ci dinfo->fb.physical = dinfo->aperture.physical 74362306a36Sopenharmony_ci + (dinfo->fb.offset << 12); 74462306a36Sopenharmony_ci dinfo->fb.virtual = dinfo->aperture.virtual + (dinfo->fb.offset << 12); 74562306a36Sopenharmony_ci dinfo->fb_start = dinfo->fb.offset << 12; 74662306a36Sopenharmony_ci 74762306a36Sopenharmony_ci /* release agpgart */ 74862306a36Sopenharmony_ci agp_backend_release(bridge); 74962306a36Sopenharmony_ci 75062306a36Sopenharmony_ci if (mtrr) 75162306a36Sopenharmony_ci dinfo->wc_cookie = arch_phys_wc_add(dinfo->aperture.physical, 75262306a36Sopenharmony_ci dinfo->aperture.size); 75362306a36Sopenharmony_ci 75462306a36Sopenharmony_ci DBG_MSG("fb: 0x%x(+ 0x%x)/0x%x (0x%p)\n", 75562306a36Sopenharmony_ci dinfo->fb.physical, dinfo->fb.offset, dinfo->fb.size, 75662306a36Sopenharmony_ci dinfo->fb.virtual); 75762306a36Sopenharmony_ci DBG_MSG("MMIO: 0x%x/0x%x (0x%p)\n", 75862306a36Sopenharmony_ci dinfo->mmio_base_phys, INTEL_REG_SIZE, 75962306a36Sopenharmony_ci dinfo->mmio_base); 76062306a36Sopenharmony_ci DBG_MSG("ring buffer: 0x%x/0x%x (0x%p)\n", 76162306a36Sopenharmony_ci dinfo->ring.physical, dinfo->ring.size, 76262306a36Sopenharmony_ci dinfo->ring.virtual); 76362306a36Sopenharmony_ci DBG_MSG("HW cursor: 0x%x/0x%x (0x%p) (offset 0x%x) (phys 0x%x)\n", 76462306a36Sopenharmony_ci dinfo->cursor.physical, dinfo->cursor.size, 76562306a36Sopenharmony_ci dinfo->cursor.virtual, dinfo->cursor.offset, 76662306a36Sopenharmony_ci dinfo->cursor.physical); 76762306a36Sopenharmony_ci 76862306a36Sopenharmony_ci DBG_MSG("options: vram = %d, accel = %d, hwcursor = %d, fixed = %d, " 76962306a36Sopenharmony_ci "noinit = %d\n", vram, accel, hwcursor, fixed, noinit); 77062306a36Sopenharmony_ci DBG_MSG("options: mode = \"%s\"\n", mode ? mode : ""); 77162306a36Sopenharmony_ci 77262306a36Sopenharmony_ci if (probeonly) 77362306a36Sopenharmony_ci bailout(dinfo); 77462306a36Sopenharmony_ci 77562306a36Sopenharmony_ci /* 77662306a36Sopenharmony_ci * Check if the LVDS port or any DVO ports are enabled. If so, 77762306a36Sopenharmony_ci * don't allow mode switching 77862306a36Sopenharmony_ci */ 77962306a36Sopenharmony_ci dvo = intelfbhw_check_non_crt(dinfo); 78062306a36Sopenharmony_ci if (dvo) { 78162306a36Sopenharmony_ci dinfo->fixed_mode = 1; 78262306a36Sopenharmony_ci WRN_MSG("Non-CRT device is enabled ( "); 78362306a36Sopenharmony_ci i = 0; 78462306a36Sopenharmony_ci while (dvo) { 78562306a36Sopenharmony_ci if (dvo & 1) { 78662306a36Sopenharmony_ci s = intelfbhw_dvo_to_string(1 << i); 78762306a36Sopenharmony_ci if (s) 78862306a36Sopenharmony_ci printk("%s ", s); 78962306a36Sopenharmony_ci } 79062306a36Sopenharmony_ci dvo >>= 1; 79162306a36Sopenharmony_ci ++i; 79262306a36Sopenharmony_ci } 79362306a36Sopenharmony_ci printk("). Disabling mode switching.\n"); 79462306a36Sopenharmony_ci } 79562306a36Sopenharmony_ci 79662306a36Sopenharmony_ci if (bailearly == 1) 79762306a36Sopenharmony_ci bailout(dinfo); 79862306a36Sopenharmony_ci 79962306a36Sopenharmony_ci if (FIXED_MODE(dinfo) && 80062306a36Sopenharmony_ci screen_info.orig_video_isVGA != VIDEO_TYPE_VLFB) { 80162306a36Sopenharmony_ci ERR_MSG("Video mode must be programmed at boot time.\n"); 80262306a36Sopenharmony_ci cleanup(dinfo); 80362306a36Sopenharmony_ci return -ENODEV; 80462306a36Sopenharmony_ci } 80562306a36Sopenharmony_ci 80662306a36Sopenharmony_ci if (bailearly == 2) 80762306a36Sopenharmony_ci bailout(dinfo); 80862306a36Sopenharmony_ci 80962306a36Sopenharmony_ci /* Initialise dinfo and related data. */ 81062306a36Sopenharmony_ci /* If an initial mode was programmed at boot time, get its details. */ 81162306a36Sopenharmony_ci if (screen_info.orig_video_isVGA == VIDEO_TYPE_VLFB) 81262306a36Sopenharmony_ci get_initial_mode(dinfo); 81362306a36Sopenharmony_ci 81462306a36Sopenharmony_ci if (bailearly == 3) 81562306a36Sopenharmony_ci bailout(dinfo); 81662306a36Sopenharmony_ci 81762306a36Sopenharmony_ci if (FIXED_MODE(dinfo)) /* remap fb address */ 81862306a36Sopenharmony_ci update_dinfo(dinfo, &dinfo->initial_var); 81962306a36Sopenharmony_ci 82062306a36Sopenharmony_ci if (bailearly == 4) 82162306a36Sopenharmony_ci bailout(dinfo); 82262306a36Sopenharmony_ci 82362306a36Sopenharmony_ci 82462306a36Sopenharmony_ci if (intelfb_set_fbinfo(dinfo)) { 82562306a36Sopenharmony_ci cleanup(dinfo); 82662306a36Sopenharmony_ci return -ENODEV; 82762306a36Sopenharmony_ci } 82862306a36Sopenharmony_ci 82962306a36Sopenharmony_ci if (bailearly == 5) 83062306a36Sopenharmony_ci bailout(dinfo); 83162306a36Sopenharmony_ci 83262306a36Sopenharmony_ci#ifdef CONFIG_FB_INTEL_I2C 83362306a36Sopenharmony_ci /* register I2C bus */ 83462306a36Sopenharmony_ci intelfb_create_i2c_busses(dinfo); 83562306a36Sopenharmony_ci#endif 83662306a36Sopenharmony_ci 83762306a36Sopenharmony_ci if (bailearly == 6) 83862306a36Sopenharmony_ci bailout(dinfo); 83962306a36Sopenharmony_ci 84062306a36Sopenharmony_ci pci_set_drvdata(pdev, dinfo); 84162306a36Sopenharmony_ci 84262306a36Sopenharmony_ci /* Save the initial register state. */ 84362306a36Sopenharmony_ci i = intelfbhw_read_hw_state(dinfo, &dinfo->save_state, 84462306a36Sopenharmony_ci bailearly > 6 ? bailearly - 6 : 0); 84562306a36Sopenharmony_ci if (i != 0) { 84662306a36Sopenharmony_ci DBG_MSG("intelfbhw_read_hw_state returned %d\n", i); 84762306a36Sopenharmony_ci bailout(dinfo); 84862306a36Sopenharmony_ci } 84962306a36Sopenharmony_ci 85062306a36Sopenharmony_ci intelfbhw_print_hw_state(dinfo, &dinfo->save_state); 85162306a36Sopenharmony_ci 85262306a36Sopenharmony_ci if (bailearly == 18) 85362306a36Sopenharmony_ci bailout(dinfo); 85462306a36Sopenharmony_ci 85562306a36Sopenharmony_ci /* read active pipe */ 85662306a36Sopenharmony_ci dinfo->pipe = intelfbhw_active_pipe(&dinfo->save_state); 85762306a36Sopenharmony_ci 85862306a36Sopenharmony_ci /* Cursor initialisation */ 85962306a36Sopenharmony_ci if (dinfo->hwcursor) { 86062306a36Sopenharmony_ci intelfbhw_cursor_init(dinfo); 86162306a36Sopenharmony_ci intelfbhw_cursor_reset(dinfo); 86262306a36Sopenharmony_ci } 86362306a36Sopenharmony_ci 86462306a36Sopenharmony_ci if (bailearly == 19) 86562306a36Sopenharmony_ci bailout(dinfo); 86662306a36Sopenharmony_ci 86762306a36Sopenharmony_ci /* 2d acceleration init */ 86862306a36Sopenharmony_ci if (dinfo->accel) 86962306a36Sopenharmony_ci intelfbhw_2d_start(dinfo); 87062306a36Sopenharmony_ci 87162306a36Sopenharmony_ci if (bailearly == 20) 87262306a36Sopenharmony_ci bailout(dinfo); 87362306a36Sopenharmony_ci 87462306a36Sopenharmony_ci if (noregister) 87562306a36Sopenharmony_ci bailout(dinfo); 87662306a36Sopenharmony_ci 87762306a36Sopenharmony_ci if (register_framebuffer(dinfo->info) < 0) { 87862306a36Sopenharmony_ci ERR_MSG("Cannot register framebuffer.\n"); 87962306a36Sopenharmony_ci cleanup(dinfo); 88062306a36Sopenharmony_ci return -ENODEV; 88162306a36Sopenharmony_ci } 88262306a36Sopenharmony_ci 88362306a36Sopenharmony_ci dinfo->registered = 1; 88462306a36Sopenharmony_ci dinfo->open = 0; 88562306a36Sopenharmony_ci 88662306a36Sopenharmony_ci init_waitqueue_head(&dinfo->vsync.wait); 88762306a36Sopenharmony_ci spin_lock_init(&dinfo->int_lock); 88862306a36Sopenharmony_ci dinfo->irq_flags = 0; 88962306a36Sopenharmony_ci dinfo->vsync.pan_display = 0; 89062306a36Sopenharmony_ci dinfo->vsync.pan_offset = 0; 89162306a36Sopenharmony_ci 89262306a36Sopenharmony_ci return 0; 89362306a36Sopenharmony_ci 89462306a36Sopenharmony_cierr_out_pixmap: 89562306a36Sopenharmony_ci fb_dealloc_cmap(&info->cmap); 89662306a36Sopenharmony_cierr_out_cmap: 89762306a36Sopenharmony_ci framebuffer_release(info); 89862306a36Sopenharmony_ci return -ENODEV; 89962306a36Sopenharmony_ci} 90062306a36Sopenharmony_ci 90162306a36Sopenharmony_cistatic void intelfb_pci_unregister(struct pci_dev *pdev) 90262306a36Sopenharmony_ci{ 90362306a36Sopenharmony_ci struct intelfb_info *dinfo = pci_get_drvdata(pdev); 90462306a36Sopenharmony_ci 90562306a36Sopenharmony_ci DBG_MSG("intelfb_pci_unregister\n"); 90662306a36Sopenharmony_ci 90762306a36Sopenharmony_ci if (!dinfo) 90862306a36Sopenharmony_ci return; 90962306a36Sopenharmony_ci 91062306a36Sopenharmony_ci cleanup(dinfo); 91162306a36Sopenharmony_ci} 91262306a36Sopenharmony_ci 91362306a36Sopenharmony_ci/*************************************************************** 91462306a36Sopenharmony_ci * helper functions * 91562306a36Sopenharmony_ci ***************************************************************/ 91662306a36Sopenharmony_ci 91762306a36Sopenharmony_ci__inline__ int intelfb_var_to_depth(const struct fb_var_screeninfo *var) 91862306a36Sopenharmony_ci{ 91962306a36Sopenharmony_ci DBG_MSG("intelfb_var_to_depth: bpp: %d, green.length is %d\n", 92062306a36Sopenharmony_ci var->bits_per_pixel, var->green.length); 92162306a36Sopenharmony_ci 92262306a36Sopenharmony_ci switch (var->bits_per_pixel) { 92362306a36Sopenharmony_ci case 16: 92462306a36Sopenharmony_ci return (var->green.length == 6) ? 16 : 15; 92562306a36Sopenharmony_ci case 32: 92662306a36Sopenharmony_ci return 24; 92762306a36Sopenharmony_ci default: 92862306a36Sopenharmony_ci return var->bits_per_pixel; 92962306a36Sopenharmony_ci } 93062306a36Sopenharmony_ci} 93162306a36Sopenharmony_ci 93262306a36Sopenharmony_ci 93362306a36Sopenharmony_cistatic __inline__ int var_to_refresh(const struct fb_var_screeninfo *var) 93462306a36Sopenharmony_ci{ 93562306a36Sopenharmony_ci int xtot = var->xres + var->left_margin + var->right_margin + 93662306a36Sopenharmony_ci var->hsync_len; 93762306a36Sopenharmony_ci int ytot = var->yres + var->upper_margin + var->lower_margin + 93862306a36Sopenharmony_ci var->vsync_len; 93962306a36Sopenharmony_ci 94062306a36Sopenharmony_ci return (1000000000 / var->pixclock * 1000 + 500) / xtot / ytot; 94162306a36Sopenharmony_ci} 94262306a36Sopenharmony_ci 94362306a36Sopenharmony_ci/*************************************************************** 94462306a36Sopenharmony_ci * Various initialisation functions * 94562306a36Sopenharmony_ci ***************************************************************/ 94662306a36Sopenharmony_ci 94762306a36Sopenharmony_cistatic void get_initial_mode(struct intelfb_info *dinfo) 94862306a36Sopenharmony_ci{ 94962306a36Sopenharmony_ci struct fb_var_screeninfo *var; 95062306a36Sopenharmony_ci int xtot, ytot; 95162306a36Sopenharmony_ci 95262306a36Sopenharmony_ci DBG_MSG("get_initial_mode\n"); 95362306a36Sopenharmony_ci 95462306a36Sopenharmony_ci dinfo->initial_vga = 1; 95562306a36Sopenharmony_ci dinfo->initial_fb_base = screen_info.lfb_base; 95662306a36Sopenharmony_ci dinfo->initial_video_ram = screen_info.lfb_size * KB(64); 95762306a36Sopenharmony_ci dinfo->initial_pitch = screen_info.lfb_linelength; 95862306a36Sopenharmony_ci 95962306a36Sopenharmony_ci var = &dinfo->initial_var; 96062306a36Sopenharmony_ci memset(var, 0, sizeof(*var)); 96162306a36Sopenharmony_ci var->xres = screen_info.lfb_width; 96262306a36Sopenharmony_ci var->yres = screen_info.lfb_height; 96362306a36Sopenharmony_ci var->bits_per_pixel = screen_info.lfb_depth; 96462306a36Sopenharmony_ci switch (screen_info.lfb_depth) { 96562306a36Sopenharmony_ci case 15: 96662306a36Sopenharmony_ci var->bits_per_pixel = 16; 96762306a36Sopenharmony_ci break; 96862306a36Sopenharmony_ci case 24: 96962306a36Sopenharmony_ci var->bits_per_pixel = 32; 97062306a36Sopenharmony_ci break; 97162306a36Sopenharmony_ci } 97262306a36Sopenharmony_ci 97362306a36Sopenharmony_ci DBG_MSG("Initial info: FB is 0x%x/0x%x (%d kByte)\n", 97462306a36Sopenharmony_ci dinfo->initial_fb_base, dinfo->initial_video_ram, 97562306a36Sopenharmony_ci BtoKB(dinfo->initial_video_ram)); 97662306a36Sopenharmony_ci 97762306a36Sopenharmony_ci DBG_MSG("Initial info: mode is %dx%d-%d (%d)\n", 97862306a36Sopenharmony_ci var->xres, var->yres, var->bits_per_pixel, 97962306a36Sopenharmony_ci dinfo->initial_pitch); 98062306a36Sopenharmony_ci 98162306a36Sopenharmony_ci /* Dummy timing values (assume 60Hz) */ 98262306a36Sopenharmony_ci var->left_margin = (var->xres / 8) & 0xf8; 98362306a36Sopenharmony_ci var->right_margin = 32; 98462306a36Sopenharmony_ci var->upper_margin = 16; 98562306a36Sopenharmony_ci var->lower_margin = 4; 98662306a36Sopenharmony_ci var->hsync_len = (var->xres / 8) & 0xf8; 98762306a36Sopenharmony_ci var->vsync_len = 4; 98862306a36Sopenharmony_ci 98962306a36Sopenharmony_ci xtot = var->xres + var->left_margin + 99062306a36Sopenharmony_ci var->right_margin + var->hsync_len; 99162306a36Sopenharmony_ci ytot = var->yres + var->upper_margin + 99262306a36Sopenharmony_ci var->lower_margin + var->vsync_len; 99362306a36Sopenharmony_ci var->pixclock = 10000000 / xtot * 1000 / ytot * 100 / 60; 99462306a36Sopenharmony_ci 99562306a36Sopenharmony_ci var->height = -1; 99662306a36Sopenharmony_ci var->width = -1; 99762306a36Sopenharmony_ci 99862306a36Sopenharmony_ci if (var->bits_per_pixel > 8) { 99962306a36Sopenharmony_ci var->red.offset = screen_info.red_pos; 100062306a36Sopenharmony_ci var->red.length = screen_info.red_size; 100162306a36Sopenharmony_ci var->green.offset = screen_info.green_pos; 100262306a36Sopenharmony_ci var->green.length = screen_info.green_size; 100362306a36Sopenharmony_ci var->blue.offset = screen_info.blue_pos; 100462306a36Sopenharmony_ci var->blue.length = screen_info.blue_size; 100562306a36Sopenharmony_ci var->transp.offset = screen_info.rsvd_pos; 100662306a36Sopenharmony_ci var->transp.length = screen_info.rsvd_size; 100762306a36Sopenharmony_ci } else { 100862306a36Sopenharmony_ci var->red.length = 8; 100962306a36Sopenharmony_ci var->green.length = 8; 101062306a36Sopenharmony_ci var->blue.length = 8; 101162306a36Sopenharmony_ci } 101262306a36Sopenharmony_ci} 101362306a36Sopenharmony_ci 101462306a36Sopenharmony_cistatic int intelfb_init_var(struct intelfb_info *dinfo) 101562306a36Sopenharmony_ci{ 101662306a36Sopenharmony_ci struct fb_var_screeninfo *var; 101762306a36Sopenharmony_ci int msrc = 0; 101862306a36Sopenharmony_ci 101962306a36Sopenharmony_ci DBG_MSG("intelfb_init_var\n"); 102062306a36Sopenharmony_ci 102162306a36Sopenharmony_ci var = &dinfo->info->var; 102262306a36Sopenharmony_ci if (FIXED_MODE(dinfo)) { 102362306a36Sopenharmony_ci memcpy(var, &dinfo->initial_var, 102462306a36Sopenharmony_ci sizeof(struct fb_var_screeninfo)); 102562306a36Sopenharmony_ci msrc = 5; 102662306a36Sopenharmony_ci } else { 102762306a36Sopenharmony_ci const u8 *edid_s = fb_firmware_edid(&dinfo->pdev->dev); 102862306a36Sopenharmony_ci u8 *edid_d = NULL; 102962306a36Sopenharmony_ci 103062306a36Sopenharmony_ci if (edid_s) { 103162306a36Sopenharmony_ci edid_d = kmemdup(edid_s, EDID_LENGTH, GFP_KERNEL); 103262306a36Sopenharmony_ci 103362306a36Sopenharmony_ci if (edid_d) { 103462306a36Sopenharmony_ci fb_edid_to_monspecs(edid_d, 103562306a36Sopenharmony_ci &dinfo->info->monspecs); 103662306a36Sopenharmony_ci kfree(edid_d); 103762306a36Sopenharmony_ci } 103862306a36Sopenharmony_ci } 103962306a36Sopenharmony_ci 104062306a36Sopenharmony_ci if (mode) { 104162306a36Sopenharmony_ci printk("intelfb: Looking for mode in private " 104262306a36Sopenharmony_ci "database\n"); 104362306a36Sopenharmony_ci msrc = fb_find_mode(var, dinfo->info, mode, 104462306a36Sopenharmony_ci dinfo->info->monspecs.modedb, 104562306a36Sopenharmony_ci dinfo->info->monspecs.modedb_len, 104662306a36Sopenharmony_ci NULL, 0); 104762306a36Sopenharmony_ci 104862306a36Sopenharmony_ci if (msrc && msrc > 1) { 104962306a36Sopenharmony_ci printk("intelfb: No mode in private database, " 105062306a36Sopenharmony_ci "intelfb: looking for mode in global " 105162306a36Sopenharmony_ci "database "); 105262306a36Sopenharmony_ci msrc = fb_find_mode(var, dinfo->info, mode, 105362306a36Sopenharmony_ci NULL, 0, NULL, 0); 105462306a36Sopenharmony_ci 105562306a36Sopenharmony_ci if (msrc) 105662306a36Sopenharmony_ci msrc |= 8; 105762306a36Sopenharmony_ci } 105862306a36Sopenharmony_ci 105962306a36Sopenharmony_ci } 106062306a36Sopenharmony_ci 106162306a36Sopenharmony_ci if (!msrc) 106262306a36Sopenharmony_ci msrc = fb_find_mode(var, dinfo->info, PREFERRED_MODE, 106362306a36Sopenharmony_ci NULL, 0, NULL, 0); 106462306a36Sopenharmony_ci } 106562306a36Sopenharmony_ci 106662306a36Sopenharmony_ci if (!msrc) { 106762306a36Sopenharmony_ci ERR_MSG("Cannot find a suitable video mode.\n"); 106862306a36Sopenharmony_ci return 1; 106962306a36Sopenharmony_ci } 107062306a36Sopenharmony_ci 107162306a36Sopenharmony_ci INF_MSG("Initial video mode is %dx%d-%d@%d.\n", var->xres, var->yres, 107262306a36Sopenharmony_ci var->bits_per_pixel, var_to_refresh(var)); 107362306a36Sopenharmony_ci 107462306a36Sopenharmony_ci DBG_MSG("Initial video mode is from %d.\n", msrc); 107562306a36Sopenharmony_ci 107662306a36Sopenharmony_ci#if ALLOCATE_FOR_PANNING 107762306a36Sopenharmony_ci /* Allow use of half of the video ram for panning */ 107862306a36Sopenharmony_ci var->xres_virtual = var->xres; 107962306a36Sopenharmony_ci var->yres_virtual = 108062306a36Sopenharmony_ci dinfo->fb.size / 2 / (var->bits_per_pixel * var->xres); 108162306a36Sopenharmony_ci if (var->yres_virtual < var->yres) 108262306a36Sopenharmony_ci var->yres_virtual = var->yres; 108362306a36Sopenharmony_ci#else 108462306a36Sopenharmony_ci var->yres_virtual = var->yres; 108562306a36Sopenharmony_ci#endif 108662306a36Sopenharmony_ci 108762306a36Sopenharmony_ci if (dinfo->accel) 108862306a36Sopenharmony_ci var->accel_flags |= FB_ACCELF_TEXT; 108962306a36Sopenharmony_ci else 109062306a36Sopenharmony_ci var->accel_flags &= ~FB_ACCELF_TEXT; 109162306a36Sopenharmony_ci 109262306a36Sopenharmony_ci return 0; 109362306a36Sopenharmony_ci} 109462306a36Sopenharmony_ci 109562306a36Sopenharmony_cistatic int intelfb_set_fbinfo(struct intelfb_info *dinfo) 109662306a36Sopenharmony_ci{ 109762306a36Sopenharmony_ci struct fb_info *info = dinfo->info; 109862306a36Sopenharmony_ci 109962306a36Sopenharmony_ci DBG_MSG("intelfb_set_fbinfo\n"); 110062306a36Sopenharmony_ci 110162306a36Sopenharmony_ci info->fbops = &intel_fb_ops; 110262306a36Sopenharmony_ci info->pseudo_palette = dinfo->pseudo_palette; 110362306a36Sopenharmony_ci 110462306a36Sopenharmony_ci info->pixmap.size = 64*1024; 110562306a36Sopenharmony_ci info->pixmap.buf_align = 8; 110662306a36Sopenharmony_ci info->pixmap.access_align = 32; 110762306a36Sopenharmony_ci info->pixmap.flags = FB_PIXMAP_SYSTEM; 110862306a36Sopenharmony_ci 110962306a36Sopenharmony_ci if (intelfb_init_var(dinfo)) 111062306a36Sopenharmony_ci return 1; 111162306a36Sopenharmony_ci 111262306a36Sopenharmony_ci info->pixmap.scan_align = 1; 111362306a36Sopenharmony_ci strcpy(info->fix.id, dinfo->name); 111462306a36Sopenharmony_ci info->fix.smem_start = dinfo->fb.physical; 111562306a36Sopenharmony_ci info->fix.smem_len = dinfo->fb.size; 111662306a36Sopenharmony_ci info->fix.type = FB_TYPE_PACKED_PIXELS; 111762306a36Sopenharmony_ci info->fix.type_aux = 0; 111862306a36Sopenharmony_ci info->fix.xpanstep = 8; 111962306a36Sopenharmony_ci info->fix.ypanstep = 1; 112062306a36Sopenharmony_ci info->fix.ywrapstep = 0; 112162306a36Sopenharmony_ci info->fix.mmio_start = dinfo->mmio_base_phys; 112262306a36Sopenharmony_ci info->fix.mmio_len = INTEL_REG_SIZE; 112362306a36Sopenharmony_ci info->fix.accel = FB_ACCEL_I830; 112462306a36Sopenharmony_ci update_dinfo(dinfo, &info->var); 112562306a36Sopenharmony_ci 112662306a36Sopenharmony_ci return 0; 112762306a36Sopenharmony_ci} 112862306a36Sopenharmony_ci 112962306a36Sopenharmony_ci/* Update dinfo to match the active video mode. */ 113062306a36Sopenharmony_cistatic void update_dinfo(struct intelfb_info *dinfo, 113162306a36Sopenharmony_ci struct fb_var_screeninfo *var) 113262306a36Sopenharmony_ci{ 113362306a36Sopenharmony_ci DBG_MSG("update_dinfo\n"); 113462306a36Sopenharmony_ci 113562306a36Sopenharmony_ci dinfo->bpp = var->bits_per_pixel; 113662306a36Sopenharmony_ci dinfo->depth = intelfb_var_to_depth(var); 113762306a36Sopenharmony_ci dinfo->xres = var->xres; 113862306a36Sopenharmony_ci dinfo->yres = var->xres; 113962306a36Sopenharmony_ci dinfo->pixclock = var->pixclock; 114062306a36Sopenharmony_ci 114162306a36Sopenharmony_ci dinfo->info->fix.visual = dinfo->visual; 114262306a36Sopenharmony_ci dinfo->info->fix.line_length = dinfo->pitch; 114362306a36Sopenharmony_ci 114462306a36Sopenharmony_ci switch (dinfo->bpp) { 114562306a36Sopenharmony_ci case 8: 114662306a36Sopenharmony_ci dinfo->visual = FB_VISUAL_PSEUDOCOLOR; 114762306a36Sopenharmony_ci dinfo->pitch = var->xres_virtual; 114862306a36Sopenharmony_ci break; 114962306a36Sopenharmony_ci case 16: 115062306a36Sopenharmony_ci dinfo->visual = FB_VISUAL_TRUECOLOR; 115162306a36Sopenharmony_ci dinfo->pitch = var->xres_virtual * 2; 115262306a36Sopenharmony_ci break; 115362306a36Sopenharmony_ci case 32: 115462306a36Sopenharmony_ci dinfo->visual = FB_VISUAL_TRUECOLOR; 115562306a36Sopenharmony_ci dinfo->pitch = var->xres_virtual * 4; 115662306a36Sopenharmony_ci break; 115762306a36Sopenharmony_ci } 115862306a36Sopenharmony_ci 115962306a36Sopenharmony_ci /* Make sure the line length is a aligned correctly. */ 116062306a36Sopenharmony_ci if (IS_I9XX(dinfo)) 116162306a36Sopenharmony_ci dinfo->pitch = ROUND_UP_TO(dinfo->pitch, STRIDE_ALIGNMENT_I9XX); 116262306a36Sopenharmony_ci else 116362306a36Sopenharmony_ci dinfo->pitch = ROUND_UP_TO(dinfo->pitch, STRIDE_ALIGNMENT); 116462306a36Sopenharmony_ci 116562306a36Sopenharmony_ci if (FIXED_MODE(dinfo)) 116662306a36Sopenharmony_ci dinfo->pitch = dinfo->initial_pitch; 116762306a36Sopenharmony_ci 116862306a36Sopenharmony_ci dinfo->info->screen_base = (char __iomem *)dinfo->fb.virtual; 116962306a36Sopenharmony_ci dinfo->info->fix.line_length = dinfo->pitch; 117062306a36Sopenharmony_ci dinfo->info->fix.visual = dinfo->visual; 117162306a36Sopenharmony_ci} 117262306a36Sopenharmony_ci 117362306a36Sopenharmony_ci/* fbops functions */ 117462306a36Sopenharmony_ci 117562306a36Sopenharmony_ci/*************************************************************** 117662306a36Sopenharmony_ci * fbdev interface * 117762306a36Sopenharmony_ci ***************************************************************/ 117862306a36Sopenharmony_ci 117962306a36Sopenharmony_cistatic int intelfb_open(struct fb_info *info, int user) 118062306a36Sopenharmony_ci{ 118162306a36Sopenharmony_ci struct intelfb_info *dinfo = GET_DINFO(info); 118262306a36Sopenharmony_ci 118362306a36Sopenharmony_ci if (user) 118462306a36Sopenharmony_ci dinfo->open++; 118562306a36Sopenharmony_ci 118662306a36Sopenharmony_ci return 0; 118762306a36Sopenharmony_ci} 118862306a36Sopenharmony_ci 118962306a36Sopenharmony_cistatic int intelfb_release(struct fb_info *info, int user) 119062306a36Sopenharmony_ci{ 119162306a36Sopenharmony_ci struct intelfb_info *dinfo = GET_DINFO(info); 119262306a36Sopenharmony_ci 119362306a36Sopenharmony_ci if (user) { 119462306a36Sopenharmony_ci dinfo->open--; 119562306a36Sopenharmony_ci msleep(1); 119662306a36Sopenharmony_ci if (!dinfo->open) 119762306a36Sopenharmony_ci intelfbhw_disable_irq(dinfo); 119862306a36Sopenharmony_ci } 119962306a36Sopenharmony_ci 120062306a36Sopenharmony_ci return 0; 120162306a36Sopenharmony_ci} 120262306a36Sopenharmony_ci 120362306a36Sopenharmony_cistatic int intelfb_check_var(struct fb_var_screeninfo *var, 120462306a36Sopenharmony_ci struct fb_info *info) 120562306a36Sopenharmony_ci{ 120662306a36Sopenharmony_ci int change_var = 0; 120762306a36Sopenharmony_ci struct fb_var_screeninfo v; 120862306a36Sopenharmony_ci struct intelfb_info *dinfo; 120962306a36Sopenharmony_ci static int first = 1; 121062306a36Sopenharmony_ci int i; 121162306a36Sopenharmony_ci /* Good pitches to allow tiling. Don't care about pitches < 1024. */ 121262306a36Sopenharmony_ci static const int pitches[] = { 121362306a36Sopenharmony_ci 128 * 8, 121462306a36Sopenharmony_ci 128 * 16, 121562306a36Sopenharmony_ci 128 * 32, 121662306a36Sopenharmony_ci 128 * 64, 121762306a36Sopenharmony_ci 0 121862306a36Sopenharmony_ci }; 121962306a36Sopenharmony_ci 122062306a36Sopenharmony_ci DBG_MSG("intelfb_check_var: accel_flags is %d\n", var->accel_flags); 122162306a36Sopenharmony_ci 122262306a36Sopenharmony_ci dinfo = GET_DINFO(info); 122362306a36Sopenharmony_ci 122462306a36Sopenharmony_ci if (!var->pixclock) 122562306a36Sopenharmony_ci return -EINVAL; 122662306a36Sopenharmony_ci 122762306a36Sopenharmony_ci /* update the pitch */ 122862306a36Sopenharmony_ci if (intelfbhw_validate_mode(dinfo, var) != 0) 122962306a36Sopenharmony_ci return -EINVAL; 123062306a36Sopenharmony_ci 123162306a36Sopenharmony_ci v = *var; 123262306a36Sopenharmony_ci 123362306a36Sopenharmony_ci for (i = 0; pitches[i] != 0; i++) { 123462306a36Sopenharmony_ci if (pitches[i] >= v.xres_virtual) { 123562306a36Sopenharmony_ci v.xres_virtual = pitches[i]; 123662306a36Sopenharmony_ci break; 123762306a36Sopenharmony_ci } 123862306a36Sopenharmony_ci } 123962306a36Sopenharmony_ci 124062306a36Sopenharmony_ci /* Check for a supported bpp. */ 124162306a36Sopenharmony_ci if (v.bits_per_pixel <= 8) 124262306a36Sopenharmony_ci v.bits_per_pixel = 8; 124362306a36Sopenharmony_ci else if (v.bits_per_pixel <= 16) { 124462306a36Sopenharmony_ci if (v.bits_per_pixel == 16) 124562306a36Sopenharmony_ci v.green.length = 6; 124662306a36Sopenharmony_ci v.bits_per_pixel = 16; 124762306a36Sopenharmony_ci } else if (v.bits_per_pixel <= 32) 124862306a36Sopenharmony_ci v.bits_per_pixel = 32; 124962306a36Sopenharmony_ci else 125062306a36Sopenharmony_ci return -EINVAL; 125162306a36Sopenharmony_ci 125262306a36Sopenharmony_ci change_var = ((info->var.xres != var->xres) || 125362306a36Sopenharmony_ci (info->var.yres != var->yres) || 125462306a36Sopenharmony_ci (info->var.xres_virtual != var->xres_virtual) || 125562306a36Sopenharmony_ci (info->var.yres_virtual != var->yres_virtual) || 125662306a36Sopenharmony_ci (info->var.bits_per_pixel != var->bits_per_pixel) || 125762306a36Sopenharmony_ci memcmp(&info->var.red, &var->red, sizeof(var->red)) || 125862306a36Sopenharmony_ci memcmp(&info->var.green, &var->green, 125962306a36Sopenharmony_ci sizeof(var->green)) || 126062306a36Sopenharmony_ci memcmp(&info->var.blue, &var->blue, sizeof(var->blue))); 126162306a36Sopenharmony_ci 126262306a36Sopenharmony_ci if (FIXED_MODE(dinfo) && 126362306a36Sopenharmony_ci (change_var || 126462306a36Sopenharmony_ci var->yres_virtual > dinfo->initial_var.yres_virtual || 126562306a36Sopenharmony_ci var->yres_virtual < dinfo->initial_var.yres || 126662306a36Sopenharmony_ci var->xoffset || var->nonstd)) { 126762306a36Sopenharmony_ci if (first) { 126862306a36Sopenharmony_ci ERR_MSG("Changing the video mode is not supported.\n"); 126962306a36Sopenharmony_ci first = 0; 127062306a36Sopenharmony_ci } 127162306a36Sopenharmony_ci return -EINVAL; 127262306a36Sopenharmony_ci } 127362306a36Sopenharmony_ci 127462306a36Sopenharmony_ci switch (intelfb_var_to_depth(&v)) { 127562306a36Sopenharmony_ci case 8: 127662306a36Sopenharmony_ci v.red.offset = v.green.offset = v.blue.offset = 0; 127762306a36Sopenharmony_ci v.red.length = v.green.length = v.blue.length = 8; 127862306a36Sopenharmony_ci v.transp.offset = v.transp.length = 0; 127962306a36Sopenharmony_ci break; 128062306a36Sopenharmony_ci case 15: 128162306a36Sopenharmony_ci v.red.offset = 10; 128262306a36Sopenharmony_ci v.green.offset = 5; 128362306a36Sopenharmony_ci v.blue.offset = 0; 128462306a36Sopenharmony_ci v.red.length = v.green.length = v.blue.length = 5; 128562306a36Sopenharmony_ci v.transp.offset = v.transp.length = 0; 128662306a36Sopenharmony_ci break; 128762306a36Sopenharmony_ci case 16: 128862306a36Sopenharmony_ci v.red.offset = 11; 128962306a36Sopenharmony_ci v.green.offset = 5; 129062306a36Sopenharmony_ci v.blue.offset = 0; 129162306a36Sopenharmony_ci v.red.length = 5; 129262306a36Sopenharmony_ci v.green.length = 6; 129362306a36Sopenharmony_ci v.blue.length = 5; 129462306a36Sopenharmony_ci v.transp.offset = v.transp.length = 0; 129562306a36Sopenharmony_ci break; 129662306a36Sopenharmony_ci case 24: 129762306a36Sopenharmony_ci v.red.offset = 16; 129862306a36Sopenharmony_ci v.green.offset = 8; 129962306a36Sopenharmony_ci v.blue.offset = 0; 130062306a36Sopenharmony_ci v.red.length = v.green.length = v.blue.length = 8; 130162306a36Sopenharmony_ci v.transp.offset = v.transp.length = 0; 130262306a36Sopenharmony_ci break; 130362306a36Sopenharmony_ci case 32: 130462306a36Sopenharmony_ci v.red.offset = 16; 130562306a36Sopenharmony_ci v.green.offset = 8; 130662306a36Sopenharmony_ci v.blue.offset = 0; 130762306a36Sopenharmony_ci v.red.length = v.green.length = v.blue.length = 8; 130862306a36Sopenharmony_ci v.transp.offset = 24; 130962306a36Sopenharmony_ci v.transp.length = 8; 131062306a36Sopenharmony_ci break; 131162306a36Sopenharmony_ci } 131262306a36Sopenharmony_ci 131362306a36Sopenharmony_ci if (v.xoffset > v.xres_virtual - v.xres) 131462306a36Sopenharmony_ci v.xoffset = v.xres_virtual - v.xres; 131562306a36Sopenharmony_ci if (v.yoffset > v.yres_virtual - v.yres) 131662306a36Sopenharmony_ci v.yoffset = v.yres_virtual - v.yres; 131762306a36Sopenharmony_ci 131862306a36Sopenharmony_ci v.red.msb_right = v.green.msb_right = v.blue.msb_right = 131962306a36Sopenharmony_ci v.transp.msb_right = 0; 132062306a36Sopenharmony_ci 132162306a36Sopenharmony_ci *var = v; 132262306a36Sopenharmony_ci 132362306a36Sopenharmony_ci return 0; 132462306a36Sopenharmony_ci} 132562306a36Sopenharmony_ci 132662306a36Sopenharmony_cistatic int intelfb_set_par(struct fb_info *info) 132762306a36Sopenharmony_ci{ 132862306a36Sopenharmony_ci struct intelfb_hwstate *hw; 132962306a36Sopenharmony_ci struct intelfb_info *dinfo = GET_DINFO(info); 133062306a36Sopenharmony_ci 133162306a36Sopenharmony_ci if (FIXED_MODE(dinfo)) { 133262306a36Sopenharmony_ci ERR_MSG("Changing the video mode is not supported.\n"); 133362306a36Sopenharmony_ci return -EINVAL; 133462306a36Sopenharmony_ci } 133562306a36Sopenharmony_ci 133662306a36Sopenharmony_ci hw = kmalloc(sizeof(*hw), GFP_ATOMIC); 133762306a36Sopenharmony_ci if (!hw) 133862306a36Sopenharmony_ci return -ENOMEM; 133962306a36Sopenharmony_ci 134062306a36Sopenharmony_ci DBG_MSG("intelfb_set_par (%dx%d-%d)\n", info->var.xres, 134162306a36Sopenharmony_ci info->var.yres, info->var.bits_per_pixel); 134262306a36Sopenharmony_ci 134362306a36Sopenharmony_ci /* 134462306a36Sopenharmony_ci * Disable VCO prior to timing register change. 134562306a36Sopenharmony_ci */ 134662306a36Sopenharmony_ci OUTREG(DPLL_A, INREG(DPLL_A) & ~DPLL_VCO_ENABLE); 134762306a36Sopenharmony_ci 134862306a36Sopenharmony_ci intelfb_blank(FB_BLANK_POWERDOWN, info); 134962306a36Sopenharmony_ci 135062306a36Sopenharmony_ci if (ACCEL(dinfo, info)) 135162306a36Sopenharmony_ci intelfbhw_2d_stop(dinfo); 135262306a36Sopenharmony_ci 135362306a36Sopenharmony_ci memcpy(hw, &dinfo->save_state, sizeof(*hw)); 135462306a36Sopenharmony_ci if (intelfbhw_mode_to_hw(dinfo, hw, &info->var)) 135562306a36Sopenharmony_ci goto invalid_mode; 135662306a36Sopenharmony_ci if (intelfbhw_program_mode(dinfo, hw, 0)) 135762306a36Sopenharmony_ci goto invalid_mode; 135862306a36Sopenharmony_ci 135962306a36Sopenharmony_ci#if REGDUMP > 0 136062306a36Sopenharmony_ci intelfbhw_read_hw_state(dinfo, hw, 0); 136162306a36Sopenharmony_ci intelfbhw_print_hw_state(dinfo, hw); 136262306a36Sopenharmony_ci#endif 136362306a36Sopenharmony_ci 136462306a36Sopenharmony_ci update_dinfo(dinfo, &info->var); 136562306a36Sopenharmony_ci 136662306a36Sopenharmony_ci if (ACCEL(dinfo, info)) 136762306a36Sopenharmony_ci intelfbhw_2d_start(dinfo); 136862306a36Sopenharmony_ci 136962306a36Sopenharmony_ci intelfb_pan_display(&info->var, info); 137062306a36Sopenharmony_ci 137162306a36Sopenharmony_ci intelfb_blank(FB_BLANK_UNBLANK, info); 137262306a36Sopenharmony_ci 137362306a36Sopenharmony_ci if (ACCEL(dinfo, info)) { 137462306a36Sopenharmony_ci info->flags = FBINFO_HWACCEL_YPAN | 137562306a36Sopenharmony_ci FBINFO_HWACCEL_COPYAREA | FBINFO_HWACCEL_FILLRECT | 137662306a36Sopenharmony_ci FBINFO_HWACCEL_IMAGEBLIT; 137762306a36Sopenharmony_ci } else 137862306a36Sopenharmony_ci info->flags = FBINFO_HWACCEL_YPAN; 137962306a36Sopenharmony_ci 138062306a36Sopenharmony_ci kfree(hw); 138162306a36Sopenharmony_ci return 0; 138262306a36Sopenharmony_ciinvalid_mode: 138362306a36Sopenharmony_ci kfree(hw); 138462306a36Sopenharmony_ci return -EINVAL; 138562306a36Sopenharmony_ci} 138662306a36Sopenharmony_ci 138762306a36Sopenharmony_cistatic int intelfb_setcolreg(unsigned regno, unsigned red, unsigned green, 138862306a36Sopenharmony_ci unsigned blue, unsigned transp, 138962306a36Sopenharmony_ci struct fb_info *info) 139062306a36Sopenharmony_ci{ 139162306a36Sopenharmony_ci struct intelfb_info *dinfo = GET_DINFO(info); 139262306a36Sopenharmony_ci 139362306a36Sopenharmony_ci#if VERBOSE > 0 139462306a36Sopenharmony_ci DBG_MSG("intelfb_setcolreg: regno %d, depth %d\n", regno, dinfo->depth); 139562306a36Sopenharmony_ci#endif 139662306a36Sopenharmony_ci 139762306a36Sopenharmony_ci if (regno > 255) 139862306a36Sopenharmony_ci return 1; 139962306a36Sopenharmony_ci 140062306a36Sopenharmony_ci if (dinfo->depth == 8) { 140162306a36Sopenharmony_ci red >>= 8; 140262306a36Sopenharmony_ci green >>= 8; 140362306a36Sopenharmony_ci blue >>= 8; 140462306a36Sopenharmony_ci 140562306a36Sopenharmony_ci intelfbhw_setcolreg(dinfo, regno, red, green, blue, 140662306a36Sopenharmony_ci transp); 140762306a36Sopenharmony_ci } 140862306a36Sopenharmony_ci 140962306a36Sopenharmony_ci if (regno < 16) { 141062306a36Sopenharmony_ci switch (dinfo->depth) { 141162306a36Sopenharmony_ci case 15: 141262306a36Sopenharmony_ci dinfo->pseudo_palette[regno] = ((red & 0xf800) >> 1) | 141362306a36Sopenharmony_ci ((green & 0xf800) >> 6) | 141462306a36Sopenharmony_ci ((blue & 0xf800) >> 11); 141562306a36Sopenharmony_ci break; 141662306a36Sopenharmony_ci case 16: 141762306a36Sopenharmony_ci dinfo->pseudo_palette[regno] = (red & 0xf800) | 141862306a36Sopenharmony_ci ((green & 0xfc00) >> 5) | 141962306a36Sopenharmony_ci ((blue & 0xf800) >> 11); 142062306a36Sopenharmony_ci break; 142162306a36Sopenharmony_ci case 24: 142262306a36Sopenharmony_ci dinfo->pseudo_palette[regno] = ((red & 0xff00) << 8) | 142362306a36Sopenharmony_ci (green & 0xff00) | 142462306a36Sopenharmony_ci ((blue & 0xff00) >> 8); 142562306a36Sopenharmony_ci break; 142662306a36Sopenharmony_ci } 142762306a36Sopenharmony_ci } 142862306a36Sopenharmony_ci 142962306a36Sopenharmony_ci return 0; 143062306a36Sopenharmony_ci} 143162306a36Sopenharmony_ci 143262306a36Sopenharmony_cistatic int intelfb_blank(int blank, struct fb_info *info) 143362306a36Sopenharmony_ci{ 143462306a36Sopenharmony_ci intelfbhw_do_blank(blank, info); 143562306a36Sopenharmony_ci return 0; 143662306a36Sopenharmony_ci} 143762306a36Sopenharmony_ci 143862306a36Sopenharmony_cistatic int intelfb_pan_display(struct fb_var_screeninfo *var, 143962306a36Sopenharmony_ci struct fb_info *info) 144062306a36Sopenharmony_ci{ 144162306a36Sopenharmony_ci intelfbhw_pan_display(var, info); 144262306a36Sopenharmony_ci return 0; 144362306a36Sopenharmony_ci} 144462306a36Sopenharmony_ci 144562306a36Sopenharmony_ci/* When/if we have our own ioctls. */ 144662306a36Sopenharmony_cistatic int intelfb_ioctl(struct fb_info *info, unsigned int cmd, 144762306a36Sopenharmony_ci unsigned long arg) 144862306a36Sopenharmony_ci{ 144962306a36Sopenharmony_ci int retval = 0; 145062306a36Sopenharmony_ci struct intelfb_info *dinfo = GET_DINFO(info); 145162306a36Sopenharmony_ci u32 pipe = 0; 145262306a36Sopenharmony_ci 145362306a36Sopenharmony_ci switch (cmd) { 145462306a36Sopenharmony_ci case FBIO_WAITFORVSYNC: 145562306a36Sopenharmony_ci if (get_user(pipe, (__u32 __user *)arg)) 145662306a36Sopenharmony_ci return -EFAULT; 145762306a36Sopenharmony_ci 145862306a36Sopenharmony_ci retval = intelfbhw_wait_for_vsync(dinfo, pipe); 145962306a36Sopenharmony_ci break; 146062306a36Sopenharmony_ci default: 146162306a36Sopenharmony_ci break; 146262306a36Sopenharmony_ci } 146362306a36Sopenharmony_ci 146462306a36Sopenharmony_ci return retval; 146562306a36Sopenharmony_ci} 146662306a36Sopenharmony_ci 146762306a36Sopenharmony_cistatic void intelfb_fillrect (struct fb_info *info, 146862306a36Sopenharmony_ci const struct fb_fillrect *rect) 146962306a36Sopenharmony_ci{ 147062306a36Sopenharmony_ci struct intelfb_info *dinfo = GET_DINFO(info); 147162306a36Sopenharmony_ci u32 rop, color; 147262306a36Sopenharmony_ci 147362306a36Sopenharmony_ci#if VERBOSE > 0 147462306a36Sopenharmony_ci DBG_MSG("intelfb_fillrect\n"); 147562306a36Sopenharmony_ci#endif 147662306a36Sopenharmony_ci 147762306a36Sopenharmony_ci if (!ACCEL(dinfo, info) || dinfo->depth == 4) { 147862306a36Sopenharmony_ci cfb_fillrect(info, rect); 147962306a36Sopenharmony_ci return; 148062306a36Sopenharmony_ci } 148162306a36Sopenharmony_ci 148262306a36Sopenharmony_ci if (rect->rop == ROP_COPY) 148362306a36Sopenharmony_ci rop = PAT_ROP_GXCOPY; 148462306a36Sopenharmony_ci else /* ROP_XOR */ 148562306a36Sopenharmony_ci rop = PAT_ROP_GXXOR; 148662306a36Sopenharmony_ci 148762306a36Sopenharmony_ci if (dinfo->depth != 8) 148862306a36Sopenharmony_ci color = dinfo->pseudo_palette[rect->color]; 148962306a36Sopenharmony_ci else 149062306a36Sopenharmony_ci color = rect->color; 149162306a36Sopenharmony_ci 149262306a36Sopenharmony_ci intelfbhw_do_fillrect(dinfo, rect->dx, rect->dy, 149362306a36Sopenharmony_ci rect->width, rect->height, color, 149462306a36Sopenharmony_ci dinfo->pitch, info->var.bits_per_pixel, 149562306a36Sopenharmony_ci rop); 149662306a36Sopenharmony_ci} 149762306a36Sopenharmony_ci 149862306a36Sopenharmony_cistatic void intelfb_copyarea(struct fb_info *info, 149962306a36Sopenharmony_ci const struct fb_copyarea *region) 150062306a36Sopenharmony_ci{ 150162306a36Sopenharmony_ci struct intelfb_info *dinfo = GET_DINFO(info); 150262306a36Sopenharmony_ci 150362306a36Sopenharmony_ci#if VERBOSE > 0 150462306a36Sopenharmony_ci DBG_MSG("intelfb_copyarea\n"); 150562306a36Sopenharmony_ci#endif 150662306a36Sopenharmony_ci 150762306a36Sopenharmony_ci if (!ACCEL(dinfo, info) || dinfo->depth == 4) { 150862306a36Sopenharmony_ci cfb_copyarea(info, region); 150962306a36Sopenharmony_ci return; 151062306a36Sopenharmony_ci } 151162306a36Sopenharmony_ci 151262306a36Sopenharmony_ci intelfbhw_do_bitblt(dinfo, region->sx, region->sy, region->dx, 151362306a36Sopenharmony_ci region->dy, region->width, region->height, 151462306a36Sopenharmony_ci dinfo->pitch, info->var.bits_per_pixel); 151562306a36Sopenharmony_ci} 151662306a36Sopenharmony_ci 151762306a36Sopenharmony_cistatic void intelfb_imageblit(struct fb_info *info, 151862306a36Sopenharmony_ci const struct fb_image *image) 151962306a36Sopenharmony_ci{ 152062306a36Sopenharmony_ci struct intelfb_info *dinfo = GET_DINFO(info); 152162306a36Sopenharmony_ci u32 fgcolor, bgcolor; 152262306a36Sopenharmony_ci 152362306a36Sopenharmony_ci#if VERBOSE > 0 152462306a36Sopenharmony_ci DBG_MSG("intelfb_imageblit\n"); 152562306a36Sopenharmony_ci#endif 152662306a36Sopenharmony_ci 152762306a36Sopenharmony_ci if (!ACCEL(dinfo, info) || dinfo->depth == 4 152862306a36Sopenharmony_ci || image->depth != 1) { 152962306a36Sopenharmony_ci cfb_imageblit(info, image); 153062306a36Sopenharmony_ci return; 153162306a36Sopenharmony_ci } 153262306a36Sopenharmony_ci 153362306a36Sopenharmony_ci if (dinfo->depth != 8) { 153462306a36Sopenharmony_ci fgcolor = dinfo->pseudo_palette[image->fg_color]; 153562306a36Sopenharmony_ci bgcolor = dinfo->pseudo_palette[image->bg_color]; 153662306a36Sopenharmony_ci } else { 153762306a36Sopenharmony_ci fgcolor = image->fg_color; 153862306a36Sopenharmony_ci bgcolor = image->bg_color; 153962306a36Sopenharmony_ci } 154062306a36Sopenharmony_ci 154162306a36Sopenharmony_ci if (!intelfbhw_do_drawglyph(dinfo, fgcolor, bgcolor, image->width, 154262306a36Sopenharmony_ci image->height, image->data, 154362306a36Sopenharmony_ci image->dx, image->dy, 154462306a36Sopenharmony_ci dinfo->pitch, info->var.bits_per_pixel)) { 154562306a36Sopenharmony_ci cfb_imageblit(info, image); 154662306a36Sopenharmony_ci return; 154762306a36Sopenharmony_ci } 154862306a36Sopenharmony_ci} 154962306a36Sopenharmony_ci 155062306a36Sopenharmony_cistatic int intelfb_cursor(struct fb_info *info, struct fb_cursor *cursor) 155162306a36Sopenharmony_ci{ 155262306a36Sopenharmony_ci struct intelfb_info *dinfo = GET_DINFO(info); 155362306a36Sopenharmony_ci u32 physical; 155462306a36Sopenharmony_ci#if VERBOSE > 0 155562306a36Sopenharmony_ci DBG_MSG("intelfb_cursor\n"); 155662306a36Sopenharmony_ci#endif 155762306a36Sopenharmony_ci 155862306a36Sopenharmony_ci if (!dinfo->hwcursor) 155962306a36Sopenharmony_ci return -ENODEV; 156062306a36Sopenharmony_ci 156162306a36Sopenharmony_ci intelfbhw_cursor_hide(dinfo); 156262306a36Sopenharmony_ci 156362306a36Sopenharmony_ci /* If XFree killed the cursor - restore it */ 156462306a36Sopenharmony_ci physical = (dinfo->mobile || IS_I9XX(dinfo)) ? dinfo->cursor.physical : 156562306a36Sopenharmony_ci (dinfo->cursor.offset << 12); 156662306a36Sopenharmony_ci 156762306a36Sopenharmony_ci if (INREG(CURSOR_A_BASEADDR) != physical) { 156862306a36Sopenharmony_ci u32 fg, bg; 156962306a36Sopenharmony_ci 157062306a36Sopenharmony_ci DBG_MSG("the cursor was killed - restore it !!\n"); 157162306a36Sopenharmony_ci DBG_MSG("size %d, %d pos %d, %d\n", 157262306a36Sopenharmony_ci cursor->image.width, cursor->image.height, 157362306a36Sopenharmony_ci cursor->image.dx, cursor->image.dy); 157462306a36Sopenharmony_ci 157562306a36Sopenharmony_ci intelfbhw_cursor_init(dinfo); 157662306a36Sopenharmony_ci intelfbhw_cursor_reset(dinfo); 157762306a36Sopenharmony_ci intelfbhw_cursor_setpos(dinfo, cursor->image.dx, 157862306a36Sopenharmony_ci cursor->image.dy); 157962306a36Sopenharmony_ci 158062306a36Sopenharmony_ci if (dinfo->depth != 8) { 158162306a36Sopenharmony_ci fg =dinfo->pseudo_palette[cursor->image.fg_color]; 158262306a36Sopenharmony_ci bg =dinfo->pseudo_palette[cursor->image.bg_color]; 158362306a36Sopenharmony_ci } else { 158462306a36Sopenharmony_ci fg = cursor->image.fg_color; 158562306a36Sopenharmony_ci bg = cursor->image.bg_color; 158662306a36Sopenharmony_ci } 158762306a36Sopenharmony_ci intelfbhw_cursor_setcolor(dinfo, bg, fg); 158862306a36Sopenharmony_ci intelfbhw_cursor_load(dinfo, cursor->image.width, 158962306a36Sopenharmony_ci cursor->image.height, 159062306a36Sopenharmony_ci dinfo->cursor_src); 159162306a36Sopenharmony_ci 159262306a36Sopenharmony_ci if (cursor->enable) 159362306a36Sopenharmony_ci intelfbhw_cursor_show(dinfo); 159462306a36Sopenharmony_ci return 0; 159562306a36Sopenharmony_ci } 159662306a36Sopenharmony_ci 159762306a36Sopenharmony_ci if (cursor->set & FB_CUR_SETPOS) { 159862306a36Sopenharmony_ci u32 dx, dy; 159962306a36Sopenharmony_ci 160062306a36Sopenharmony_ci dx = cursor->image.dx - info->var.xoffset; 160162306a36Sopenharmony_ci dy = cursor->image.dy - info->var.yoffset; 160262306a36Sopenharmony_ci 160362306a36Sopenharmony_ci intelfbhw_cursor_setpos(dinfo, dx, dy); 160462306a36Sopenharmony_ci } 160562306a36Sopenharmony_ci 160662306a36Sopenharmony_ci if (cursor->set & FB_CUR_SETSIZE) { 160762306a36Sopenharmony_ci if (cursor->image.width > 64 || cursor->image.height > 64) 160862306a36Sopenharmony_ci return -ENXIO; 160962306a36Sopenharmony_ci 161062306a36Sopenharmony_ci intelfbhw_cursor_reset(dinfo); 161162306a36Sopenharmony_ci } 161262306a36Sopenharmony_ci 161362306a36Sopenharmony_ci if (cursor->set & FB_CUR_SETCMAP) { 161462306a36Sopenharmony_ci u32 fg, bg; 161562306a36Sopenharmony_ci 161662306a36Sopenharmony_ci if (dinfo->depth != 8) { 161762306a36Sopenharmony_ci fg = dinfo->pseudo_palette[cursor->image.fg_color]; 161862306a36Sopenharmony_ci bg = dinfo->pseudo_palette[cursor->image.bg_color]; 161962306a36Sopenharmony_ci } else { 162062306a36Sopenharmony_ci fg = cursor->image.fg_color; 162162306a36Sopenharmony_ci bg = cursor->image.bg_color; 162262306a36Sopenharmony_ci } 162362306a36Sopenharmony_ci 162462306a36Sopenharmony_ci intelfbhw_cursor_setcolor(dinfo, bg, fg); 162562306a36Sopenharmony_ci } 162662306a36Sopenharmony_ci 162762306a36Sopenharmony_ci if (cursor->set & (FB_CUR_SETSHAPE | FB_CUR_SETIMAGE)) { 162862306a36Sopenharmony_ci u32 s_pitch = (ROUND_UP_TO(cursor->image.width, 8) / 8); 162962306a36Sopenharmony_ci u32 size = s_pitch * cursor->image.height; 163062306a36Sopenharmony_ci u8 *dat = (u8 *) cursor->image.data; 163162306a36Sopenharmony_ci u8 *msk = (u8 *) cursor->mask; 163262306a36Sopenharmony_ci u8 src[64]; 163362306a36Sopenharmony_ci u32 i; 163462306a36Sopenharmony_ci 163562306a36Sopenharmony_ci if (cursor->image.depth != 1) 163662306a36Sopenharmony_ci return -ENXIO; 163762306a36Sopenharmony_ci 163862306a36Sopenharmony_ci switch (cursor->rop) { 163962306a36Sopenharmony_ci case ROP_XOR: 164062306a36Sopenharmony_ci for (i = 0; i < size; i++) 164162306a36Sopenharmony_ci src[i] = dat[i] ^ msk[i]; 164262306a36Sopenharmony_ci break; 164362306a36Sopenharmony_ci case ROP_COPY: 164462306a36Sopenharmony_ci default: 164562306a36Sopenharmony_ci for (i = 0; i < size; i++) 164662306a36Sopenharmony_ci src[i] = dat[i] & msk[i]; 164762306a36Sopenharmony_ci break; 164862306a36Sopenharmony_ci } 164962306a36Sopenharmony_ci 165062306a36Sopenharmony_ci /* save the bitmap to restore it when XFree will 165162306a36Sopenharmony_ci make the cursor dirty */ 165262306a36Sopenharmony_ci memcpy(dinfo->cursor_src, src, size); 165362306a36Sopenharmony_ci 165462306a36Sopenharmony_ci intelfbhw_cursor_load(dinfo, cursor->image.width, 165562306a36Sopenharmony_ci cursor->image.height, src); 165662306a36Sopenharmony_ci } 165762306a36Sopenharmony_ci 165862306a36Sopenharmony_ci if (cursor->enable) 165962306a36Sopenharmony_ci intelfbhw_cursor_show(dinfo); 166062306a36Sopenharmony_ci 166162306a36Sopenharmony_ci return 0; 166262306a36Sopenharmony_ci} 166362306a36Sopenharmony_ci 166462306a36Sopenharmony_cistatic int intelfb_sync(struct fb_info *info) 166562306a36Sopenharmony_ci{ 166662306a36Sopenharmony_ci struct intelfb_info *dinfo = GET_DINFO(info); 166762306a36Sopenharmony_ci 166862306a36Sopenharmony_ci#if VERBOSE > 0 166962306a36Sopenharmony_ci DBG_MSG("intelfb_sync\n"); 167062306a36Sopenharmony_ci#endif 167162306a36Sopenharmony_ci 167262306a36Sopenharmony_ci if (dinfo->ring_lockup) 167362306a36Sopenharmony_ci return 0; 167462306a36Sopenharmony_ci 167562306a36Sopenharmony_ci intelfbhw_do_sync(dinfo); 167662306a36Sopenharmony_ci return 0; 167762306a36Sopenharmony_ci} 167862306a36Sopenharmony_ci 1679