brintos

brintos / linux-shallow public Read only

0
0
Text · 58.5 KiB · d73a795 Raw
2235 lines · c
1 /*-*- linux-c -*-2 *  linux/drivers/video/i810_main.c -- Intel 810 frame buffer device3 *4 *      Copyright (C) 2001 Antonino Daplas<adaplas@pol.net>5 *      All Rights Reserved6 *7 *      Contributors:8 *         Michael Vogt <mvogt@acm.org> - added support for Intel 815 chipsets9 *                                        and enabling the power-on state of10 *                                        external VGA connectors for11 *                                        secondary displays12 *13 *         Fredrik Andersson <krueger@shell.linux.se> - alpha testing of14 *                                        the VESA GTF15 *16 *         Brad Corrion <bcorrion@web-co.com> - alpha testing of customized17 *                                        timings support18 *19 *	The code framework is a modification of vfb.c by Geert Uytterhoeven.20 *      DotClock and PLL calculations are partly based on i810_driver.c21 *              in xfree86 v4.0.3 by Precision Insight.22 *      Watermark calculation and tables are based on i810_wmark.c23 *              in xfre86 v4.0.3 by Precision Insight.  Slight modifications24 *              only to allow for integer operations instead of floating point.25 *26 *  This file is subject to the terms and conditions of the GNU General Public27 *  License. See the file COPYING in the main directory of this archive for28 *  more details.29 */30 31#include <linux/aperture.h>32#include <linux/module.h>33#include <linux/kernel.h>34#include <linux/errno.h>35#include <linux/string.h>36#include <linux/mm.h>37#include <linux/slab.h>38#include <linux/fb.h>39#include <linux/init.h>40#include <linux/pci.h>41#include <linux/pci_ids.h>42#include <linux/resource.h>43#include <linux/unistd.h>44#include <linux/console.h>45#include <linux/io.h>46 47#include <asm/io.h>48#include <asm/div64.h>49#include <asm/page.h>50 51#include "i810_regs.h"52#include "i810.h"53#include "i810_main.h"54 55/*56 * voffset - framebuffer offset in MiB from aperture start address.  In order for57 * the driver to work with X, we must try to use memory holes left untouched by X. The58 * following table lists where X's different surfaces start at.59 *60 * ---------------------------------------------61 * :                :  64 MiB     : 32 MiB      :62 * ----------------------------------------------63 * : FrontBuffer    :   0         :  0          :64 * : DepthBuffer    :   48        :  16         :65 * : BackBuffer     :   56        :  24         :66 * ----------------------------------------------67 *68 * So for chipsets with 64 MiB Aperture sizes, 32 MiB for v_offset is okay, allowing up to69 * 15 + 1 MiB of Framebuffer memory.  For 32 MiB Aperture sizes, a v_offset of 8 MiB should70 * work, allowing 7 + 1 MiB of Framebuffer memory.71 * Note, the size of the hole may change depending on how much memory you allocate to X,72 * and how the memory is split up between these surfaces.73 *74 * Note: Anytime the DepthBuffer or FrontBuffer is overlapped, X would still run but with75 * DRI disabled.  But if the Frontbuffer is overlapped, X will fail to load.76 *77 * Experiment with v_offset to find out which works best for you.78 */79static u32 v_offset_default; /* For 32 MiB Aper size, 8 should be the default */80static u32 voffset;81 82static int i810fb_cursor(struct fb_info *info, struct fb_cursor *cursor);83static int i810fb_init_pci(struct pci_dev *dev,84			   const struct pci_device_id *entry);85static void i810fb_remove_pci(struct pci_dev *dev);86static int i810fb_resume(struct pci_dev *dev);87static int i810fb_suspend(struct pci_dev *dev, pm_message_t state);88 89/* Chipset Specific Functions */90static int i810fb_set_par    (struct fb_info *info);91static int i810fb_getcolreg  (u8 regno, u8 *red, u8 *green, u8 *blue,92			      u8 *transp, struct fb_info *info);93static int i810fb_setcolreg  (unsigned regno, unsigned red, unsigned green, unsigned blue,94			      unsigned transp, struct fb_info *info);95static int i810fb_pan_display(struct fb_var_screeninfo *var, struct fb_info *info);96static int i810fb_blank      (int blank_mode, struct fb_info *info);97 98/* Initialization */99static void i810fb_release_resource       (struct fb_info *info, struct i810fb_par *par);100 101/* PCI */102static const char * const i810_pci_list[] = {103	"Intel(R) 810 Framebuffer Device"                                 ,104	"Intel(R) 810-DC100 Framebuffer Device"                           ,105	"Intel(R) 810E Framebuffer Device"                                ,106	"Intel(R) 815 (Internal Graphics 100Mhz FSB) Framebuffer Device"  ,107	"Intel(R) 815 (Internal Graphics only) Framebuffer Device"        ,108	"Intel(R) 815 (Internal Graphics with AGP) Framebuffer Device"109};110 111static const struct pci_device_id i810fb_pci_tbl[] = {112	{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82810_IG1,113	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },114	{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82810_IG3,115	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 1  },116	{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82810E_IG,117	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 2 },118	/* mvo: added i815 PCI-ID */119	{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82815_100,120	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 3 },121	{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82815_NOAGP,122	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 4 },123	{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82815_CGC,124	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 5 },125	{ 0 },126};127 128static struct pci_driver i810fb_driver = {129	.name     =	"i810fb",130	.id_table =	i810fb_pci_tbl,131	.probe    =	i810fb_init_pci,132	.remove   =	i810fb_remove_pci,133	.suspend  =     i810fb_suspend,134	.resume   =     i810fb_resume,135};136 137static char *mode_option = NULL;138static int vram = 4;139static int bpp = 8;140static bool mtrr;141static bool accel;142static int hsync1;143static int hsync2;144static int vsync1;145static int vsync2;146static int xres;147static int yres;148static int vyres;149static bool sync;150static bool extvga;151static bool dcolor;152static bool ddc3;153 154/*------------------------------------------------------------*/155 156/**************************************************************157 *                Hardware Low Level Routines                 *158 **************************************************************/159 160/**161 * i810_screen_off - turns off/on display162 * @mmio: address of register space163 * @mode: on or off164 *165 * DESCRIPTION:166 * Blanks/unblanks the display167 */168static void i810_screen_off(u8 __iomem *mmio, u8 mode)169{170	u32 count = WAIT_COUNT;171	u8 val;172 173	i810_writeb(SR_INDEX, mmio, SR01);174	val = i810_readb(SR_DATA, mmio);175	val = (mode == OFF) ? val | SCR_OFF :176		val & ~SCR_OFF;177 178	while((i810_readw(DISP_SL, mmio) & 0xFFF) && count--);179	i810_writeb(SR_INDEX, mmio, SR01);180	i810_writeb(SR_DATA, mmio, val);181}182 183/**184 * i810_dram_off - turns off/on dram refresh185 * @mmio: address of register space186 * @mode: on or off187 *188 * DESCRIPTION:189 * Turns off DRAM refresh.  Must be off for only 2 vsyncs190 * before data becomes corrupt191 */192static void i810_dram_off(u8 __iomem *mmio, u8 mode)193{194	u8 val;195 196	val = i810_readb(DRAMCH, mmio);197	val &= DRAM_OFF;198	val = (mode == OFF) ? val : val | DRAM_ON;199	i810_writeb(DRAMCH, mmio, val);200}201 202/**203 * i810_protect_regs - allows rw/ro mode of certain VGA registers204 * @mmio: address of register space205 * @mode: protect/unprotect206 *207 * DESCRIPTION:208 * The IBM VGA standard allows protection of certain VGA registers.209 * This will  protect or unprotect them.210 */211static void i810_protect_regs(u8 __iomem *mmio, int mode)212{213	u8 reg;214 215	i810_writeb(CR_INDEX_CGA, mmio, CR11);216	reg = i810_readb(CR_DATA_CGA, mmio);217	reg = (mode == OFF) ? reg & ~0x80 :218		reg | 0x80;219 220	i810_writeb(CR_INDEX_CGA, mmio, CR11);221	i810_writeb(CR_DATA_CGA, mmio, reg);222}223 224/**225 * i810_load_pll - loads values for the hardware PLL clock226 * @par: pointer to i810fb_par structure227 *228 * DESCRIPTION:229 * Loads the P, M, and N registers.230 */231static void i810_load_pll(struct i810fb_par *par)232{233	u32 tmp1, tmp2;234	u8 __iomem *mmio = par->mmio_start_virtual;235 236	tmp1 = par->regs.M | par->regs.N << 16;237	tmp2 = i810_readl(DCLK_2D, mmio);238	tmp2 &= ~MN_MASK;239	i810_writel(DCLK_2D, mmio, tmp1 | tmp2);240 241	tmp1 = par->regs.P;242	tmp2 = i810_readl(DCLK_0DS, mmio);243	tmp2 &= ~(P_OR << 16);244	i810_writel(DCLK_0DS, mmio, (tmp1 << 16) | tmp2);245 246	i810_writeb(MSR_WRITE, mmio, par->regs.msr | 0xC8 | 1);247 248}249 250/**251 * i810_load_vga - load standard VGA registers252 * @par: pointer to i810fb_par structure253 *254 * DESCRIPTION:255 * Load values to VGA registers256 */257static void i810_load_vga(struct i810fb_par *par)258{259	u8 __iomem *mmio = par->mmio_start_virtual;260 261	/* interlace */262	i810_writeb(CR_INDEX_CGA, mmio, CR70);263	i810_writeb(CR_DATA_CGA, mmio, par->interlace);264 265	i810_writeb(CR_INDEX_CGA, mmio, CR00);266	i810_writeb(CR_DATA_CGA, mmio, par->regs.cr00);267	i810_writeb(CR_INDEX_CGA, mmio, CR01);268	i810_writeb(CR_DATA_CGA, mmio, par->regs.cr01);269	i810_writeb(CR_INDEX_CGA, mmio, CR02);270	i810_writeb(CR_DATA_CGA, mmio, par->regs.cr02);271	i810_writeb(CR_INDEX_CGA, mmio, CR03);272	i810_writeb(CR_DATA_CGA, mmio, par->regs.cr03);273	i810_writeb(CR_INDEX_CGA, mmio, CR04);274	i810_writeb(CR_DATA_CGA, mmio, par->regs.cr04);275	i810_writeb(CR_INDEX_CGA, mmio, CR05);276	i810_writeb(CR_DATA_CGA, mmio, par->regs.cr05);277	i810_writeb(CR_INDEX_CGA, mmio, CR06);278	i810_writeb(CR_DATA_CGA, mmio, par->regs.cr06);279	i810_writeb(CR_INDEX_CGA, mmio, CR09);280	i810_writeb(CR_DATA_CGA, mmio, par->regs.cr09);281	i810_writeb(CR_INDEX_CGA, mmio, CR10);282	i810_writeb(CR_DATA_CGA, mmio, par->regs.cr10);283	i810_writeb(CR_INDEX_CGA, mmio, CR11);284	i810_writeb(CR_DATA_CGA, mmio, par->regs.cr11);285	i810_writeb(CR_INDEX_CGA, mmio, CR12);286	i810_writeb(CR_DATA_CGA, mmio, par->regs.cr12);287	i810_writeb(CR_INDEX_CGA, mmio, CR15);288	i810_writeb(CR_DATA_CGA, mmio, par->regs.cr15);289	i810_writeb(CR_INDEX_CGA, mmio, CR16);290	i810_writeb(CR_DATA_CGA, mmio, par->regs.cr16);291}292 293/**294 * i810_load_vgax - load extended VGA registers295 * @par: pointer to i810fb_par structure296 *297 * DESCRIPTION:298 * Load values to extended VGA registers299 */300static void i810_load_vgax(struct i810fb_par *par)301{302	u8 __iomem *mmio = par->mmio_start_virtual;303 304	i810_writeb(CR_INDEX_CGA, mmio, CR30);305	i810_writeb(CR_DATA_CGA, mmio, par->regs.cr30);306	i810_writeb(CR_INDEX_CGA, mmio, CR31);307	i810_writeb(CR_DATA_CGA, mmio, par->regs.cr31);308	i810_writeb(CR_INDEX_CGA, mmio, CR32);309	i810_writeb(CR_DATA_CGA, mmio, par->regs.cr32);310	i810_writeb(CR_INDEX_CGA, mmio, CR33);311	i810_writeb(CR_DATA_CGA, mmio, par->regs.cr33);312	i810_writeb(CR_INDEX_CGA, mmio, CR35);313	i810_writeb(CR_DATA_CGA, mmio, par->regs.cr35);314	i810_writeb(CR_INDEX_CGA, mmio, CR39);315	i810_writeb(CR_DATA_CGA, mmio, par->regs.cr39);316}317 318/**319 * i810_load_2d - load grahics registers320 * @par: pointer to i810fb_par structure321 *322 * DESCRIPTION:323 * Load values to graphics registers324 */325static void i810_load_2d(struct i810fb_par *par)326{327	u32 tmp;328	u8 tmp8;329	u8 __iomem *mmio = par->mmio_start_virtual;330 331  	i810_writel(FW_BLC, mmio, par->watermark);332	tmp = i810_readl(PIXCONF, mmio);333	tmp |= 1 | 1 << 20;334	i810_writel(PIXCONF, mmio, tmp);335 336	i810_writel(OVRACT, mmio, par->ovract);337 338	i810_writeb(GR_INDEX, mmio, GR10);339	tmp8 = i810_readb(GR_DATA, mmio);340	tmp8 |= 2;341	i810_writeb(GR_INDEX, mmio, GR10);342	i810_writeb(GR_DATA, mmio, tmp8);343}344 345/**346 * i810_hires - enables high resolution mode347 * @mmio: address of register space348 */349static void i810_hires(u8 __iomem *mmio)350{351	u8 val;352 353	i810_writeb(CR_INDEX_CGA, mmio, CR80);354	val = i810_readb(CR_DATA_CGA, mmio);355	i810_writeb(CR_INDEX_CGA, mmio, CR80);356	i810_writeb(CR_DATA_CGA, mmio, val | 1);357	/* Stop LCD displays from flickering */358	i810_writel(MEM_MODE, mmio, i810_readl(MEM_MODE, mmio) | 4);359}360 361/**362 * i810_load_pitch - loads the characters per line of the display363 * @par: pointer to i810fb_par structure364 *365 * DESCRIPTION:366 * Loads the characters per line367 */368static void i810_load_pitch(struct i810fb_par *par)369{370	u32 tmp, pitch;371	u8 val;372	u8 __iomem *mmio = par->mmio_start_virtual;373 374	pitch = par->pitch >> 3;375	i810_writeb(SR_INDEX, mmio, SR01);376	val = i810_readb(SR_DATA, mmio);377	val &= 0xE0;378	val |= 1 | 1 << 2;379	i810_writeb(SR_INDEX, mmio, SR01);380	i810_writeb(SR_DATA, mmio, val);381 382	tmp = pitch & 0xFF;383	i810_writeb(CR_INDEX_CGA, mmio, CR13);384	i810_writeb(CR_DATA_CGA, mmio, (u8) tmp);385 386	tmp = pitch >> 8;387	i810_writeb(CR_INDEX_CGA, mmio, CR41);388	val = i810_readb(CR_DATA_CGA, mmio) & ~0x0F;389	i810_writeb(CR_INDEX_CGA, mmio, CR41);390	i810_writeb(CR_DATA_CGA, mmio, (u8) tmp | val);391}392 393/**394 * i810_load_color - loads the color depth of the display395 * @par: pointer to i810fb_par structure396 *397 * DESCRIPTION:398 * Loads the color depth of the display and the graphics engine399 */400static void i810_load_color(struct i810fb_par *par)401{402	u8 __iomem *mmio = par->mmio_start_virtual;403	u32 reg1;404	u16 reg2;405 406	reg1 = i810_readl(PIXCONF, mmio) & ~(0xF0000 | 1 << 27);407	reg2 = i810_readw(BLTCNTL, mmio) & ~0x30;408 409	reg1 |= 0x8000 | par->pixconf;410	reg2 |= par->bltcntl;411	i810_writel(PIXCONF, mmio, reg1);412	i810_writew(BLTCNTL, mmio, reg2);413}414 415/**416 * i810_load_regs - loads all registers for the mode417 * @par: pointer to i810fb_par structure418 *419 * DESCRIPTION:420 * Loads registers421 */422static void i810_load_regs(struct i810fb_par *par)423{424	u8 __iomem *mmio = par->mmio_start_virtual;425 426	i810_screen_off(mmio, OFF);427	i810_protect_regs(mmio, OFF);428	i810_dram_off(mmio, OFF);429	i810_load_pll(par);430	i810_load_vga(par);431	i810_load_vgax(par);432	i810_dram_off(mmio, ON);433	i810_load_2d(par);434	i810_hires(mmio);435	i810_screen_off(mmio, ON);436	i810_protect_regs(mmio, ON);437	i810_load_color(par);438	i810_load_pitch(par);439}440 441static void i810_write_dac(u8 regno, u8 red, u8 green, u8 blue,442			  u8 __iomem *mmio)443{444	i810_writeb(CLUT_INDEX_WRITE, mmio, regno);445	i810_writeb(CLUT_DATA, mmio, red);446	i810_writeb(CLUT_DATA, mmio, green);447	i810_writeb(CLUT_DATA, mmio, blue);448}449 450static void i810_read_dac(u8 regno, u8 *red, u8 *green, u8 *blue,451			  u8 __iomem *mmio)452{453	i810_writeb(CLUT_INDEX_READ, mmio, regno);454	*red = i810_readb(CLUT_DATA, mmio);455	*green = i810_readb(CLUT_DATA, mmio);456	*blue = i810_readb(CLUT_DATA, mmio);457}458 459/************************************************************460 *                   VGA State Restore                      *461 ************************************************************/462static void i810_restore_pll(struct i810fb_par *par)463{464	u32 tmp1, tmp2;465	u8 __iomem *mmio = par->mmio_start_virtual;466 467	tmp1 = par->hw_state.dclk_2d;468	tmp2 = i810_readl(DCLK_2D, mmio);469	tmp1 &= ~MN_MASK;470	tmp2 &= MN_MASK;471	i810_writel(DCLK_2D, mmio, tmp1 | tmp2);472 473	tmp1 = par->hw_state.dclk_1d;474	tmp2 = i810_readl(DCLK_1D, mmio);475	tmp1 &= ~MN_MASK;476	tmp2 &= MN_MASK;477	i810_writel(DCLK_1D, mmio, tmp1 | tmp2);478 479	i810_writel(DCLK_0DS, mmio, par->hw_state.dclk_0ds);480}481 482static void i810_restore_dac(struct i810fb_par *par)483{484	u32 tmp1, tmp2;485	u8 __iomem *mmio = par->mmio_start_virtual;486 487	tmp1 = par->hw_state.pixconf;488	tmp2 = i810_readl(PIXCONF, mmio);489	tmp1 &= DAC_BIT;490	tmp2 &= ~DAC_BIT;491	i810_writel(PIXCONF, mmio, tmp1 | tmp2);492}493 494static void i810_restore_vgax(struct i810fb_par *par)495{496	u8 i, j;497	u8 __iomem *mmio = par->mmio_start_virtual;498 499	for (i = 0; i < 4; i++) {500		i810_writeb(CR_INDEX_CGA, mmio, CR30+i);501		i810_writeb(CR_DATA_CGA, mmio, *(&(par->hw_state.cr30) + i));502	}503	i810_writeb(CR_INDEX_CGA, mmio, CR35);504	i810_writeb(CR_DATA_CGA, mmio, par->hw_state.cr35);505	i810_writeb(CR_INDEX_CGA, mmio, CR39);506	i810_writeb(CR_DATA_CGA, mmio, par->hw_state.cr39);507	i810_writeb(CR_INDEX_CGA, mmio, CR41);508	i810_writeb(CR_DATA_CGA, mmio, par->hw_state.cr39);509 510	/*restore interlace*/511	i810_writeb(CR_INDEX_CGA, mmio, CR70);512	i = par->hw_state.cr70;513	i &= INTERLACE_BIT;514	j = i810_readb(CR_DATA_CGA, mmio);515	i810_writeb(CR_INDEX_CGA, mmio, CR70);516	i810_writeb(CR_DATA_CGA, mmio, j | i);517 518	i810_writeb(CR_INDEX_CGA, mmio, CR80);519	i810_writeb(CR_DATA_CGA, mmio, par->hw_state.cr80);520	i810_writeb(MSR_WRITE, mmio, par->hw_state.msr);521	i810_writeb(SR_INDEX, mmio, SR01);522	i = (par->hw_state.sr01) & ~0xE0 ;523	j = i810_readb(SR_DATA, mmio) & 0xE0;524	i810_writeb(SR_INDEX, mmio, SR01);525	i810_writeb(SR_DATA, mmio, i | j);526}527 528static void i810_restore_vga(struct i810fb_par *par)529{530	u8 i;531	u8 __iomem *mmio = par->mmio_start_virtual;532 533	for (i = 0; i < 10; i++) {534		i810_writeb(CR_INDEX_CGA, mmio, CR00 + i);535		i810_writeb(CR_DATA_CGA, mmio, *((&par->hw_state.cr00) + i));536	}537	for (i = 0; i < 8; i++) {538		i810_writeb(CR_INDEX_CGA, mmio, CR10 + i);539		i810_writeb(CR_DATA_CGA, mmio, *((&par->hw_state.cr10) + i));540	}541}542 543static void i810_restore_addr_map(struct i810fb_par *par)544{545	u8 tmp;546	u8 __iomem *mmio = par->mmio_start_virtual;547 548	i810_writeb(GR_INDEX, mmio, GR10);549	tmp = i810_readb(GR_DATA, mmio);550	tmp &= ADDR_MAP_MASK;551	tmp |= par->hw_state.gr10;552	i810_writeb(GR_INDEX, mmio, GR10);553	i810_writeb(GR_DATA, mmio, tmp);554}555 556static void i810_restore_2d(struct i810fb_par *par)557{558	u32 tmp_long;559	u16 tmp_word;560	u8 __iomem *mmio = par->mmio_start_virtual;561 562	tmp_word = i810_readw(BLTCNTL, mmio);563	tmp_word &= ~(3 << 4);564	tmp_word |= par->hw_state.bltcntl;565	i810_writew(BLTCNTL, mmio, tmp_word);566 567	i810_dram_off(mmio, OFF);568	i810_writel(PIXCONF, mmio, par->hw_state.pixconf);569	i810_dram_off(mmio, ON);570 571	tmp_word = i810_readw(HWSTAM, mmio);572	tmp_word &= 3 << 13;573	tmp_word |= par->hw_state.hwstam;574	i810_writew(HWSTAM, mmio, tmp_word);575 576	tmp_long = i810_readl(FW_BLC, mmio);577	tmp_long &= FW_BLC_MASK;578	tmp_long |= par->hw_state.fw_blc;579	i810_writel(FW_BLC, mmio, tmp_long);580 581	i810_writel(HWS_PGA, mmio, par->hw_state.hws_pga);582	i810_writew(IER, mmio, par->hw_state.ier);583	i810_writew(IMR, mmio, par->hw_state.imr);584	i810_writel(DPLYSTAS, mmio, par->hw_state.dplystas);585}586 587static void i810_restore_vga_state(struct i810fb_par *par)588{589	u8 __iomem *mmio = par->mmio_start_virtual;590 591	i810_screen_off(mmio, OFF);592	i810_protect_regs(mmio, OFF);593	i810_dram_off(mmio, OFF);594	i810_restore_pll(par);595	i810_restore_dac(par);596	i810_restore_vga(par);597	i810_restore_vgax(par);598	i810_restore_addr_map(par);599	i810_dram_off(mmio, ON);600	i810_restore_2d(par);601	i810_screen_off(mmio, ON);602	i810_protect_regs(mmio, ON);603}604 605/***********************************************************************606 *                         VGA State Save                              *607 ***********************************************************************/608 609static void i810_save_vgax(struct i810fb_par *par)610{611	u8 i;612	u8 __iomem *mmio = par->mmio_start_virtual;613 614	for (i = 0; i < 4; i++) {615		i810_writeb(CR_INDEX_CGA, mmio, CR30 + i);616		*(&(par->hw_state.cr30) + i) = i810_readb(CR_DATA_CGA, mmio);617	}618	i810_writeb(CR_INDEX_CGA, mmio, CR35);619	par->hw_state.cr35 = i810_readb(CR_DATA_CGA, mmio);620	i810_writeb(CR_INDEX_CGA, mmio, CR39);621	par->hw_state.cr39 = i810_readb(CR_DATA_CGA, mmio);622	i810_writeb(CR_INDEX_CGA, mmio, CR41);623	par->hw_state.cr41 = i810_readb(CR_DATA_CGA, mmio);624	i810_writeb(CR_INDEX_CGA, mmio, CR70);625	par->hw_state.cr70 = i810_readb(CR_DATA_CGA, mmio);626	par->hw_state.msr = i810_readb(MSR_READ, mmio);627	i810_writeb(CR_INDEX_CGA, mmio, CR80);628	par->hw_state.cr80 = i810_readb(CR_DATA_CGA, mmio);629	i810_writeb(SR_INDEX, mmio, SR01);630	par->hw_state.sr01 = i810_readb(SR_DATA, mmio);631}632 633static void i810_save_vga(struct i810fb_par *par)634{635	u8 i;636	u8 __iomem *mmio = par->mmio_start_virtual;637 638	for (i = 0; i < 10; i++) {639		i810_writeb(CR_INDEX_CGA, mmio, CR00 + i);640		*((&par->hw_state.cr00) + i) = i810_readb(CR_DATA_CGA, mmio);641	}642	for (i = 0; i < 8; i++) {643		i810_writeb(CR_INDEX_CGA, mmio, CR10 + i);644		*((&par->hw_state.cr10) + i) = i810_readb(CR_DATA_CGA, mmio);645	}646}647 648static void i810_save_2d(struct i810fb_par *par)649{650	u8 __iomem *mmio = par->mmio_start_virtual;651 652	par->hw_state.dclk_2d = i810_readl(DCLK_2D, mmio);653	par->hw_state.dclk_1d = i810_readl(DCLK_1D, mmio);654	par->hw_state.dclk_0ds = i810_readl(DCLK_0DS, mmio);655	par->hw_state.pixconf = i810_readl(PIXCONF, mmio);656	par->hw_state.fw_blc = i810_readl(FW_BLC, mmio);657	par->hw_state.bltcntl = i810_readw(BLTCNTL, mmio);658	par->hw_state.hwstam = i810_readw(HWSTAM, mmio);659	par->hw_state.hws_pga = i810_readl(HWS_PGA, mmio);660	par->hw_state.ier = i810_readw(IER, mmio);661	par->hw_state.imr = i810_readw(IMR, mmio);662	par->hw_state.dplystas = i810_readl(DPLYSTAS, mmio);663}664 665static void i810_save_vga_state(struct i810fb_par *par)666{667	i810_save_vga(par);668	i810_save_vgax(par);669	i810_save_2d(par);670}671 672/************************************************************673 *                    Helpers                               *674 ************************************************************/675/**676 * get_line_length - calculates buffer pitch in bytes677 * @par: pointer to i810fb_par structure678 * @xres_virtual: virtual resolution of the frame679 * @bpp: bits per pixel680 *681 * DESCRIPTION:682 * Calculates buffer pitch in bytes.683 */684static u32 get_line_length(struct i810fb_par *par, int xres_virtual, int bpp)685{686   	u32 length;687 688	length = xres_virtual*bpp;689	length = (length+31)&-32;690	length >>= 3;691	return length;692}693 694/**695 * i810_calc_dclk - calculates the P, M, and N values of a pixelclock value696 * @freq: target pixelclock in picoseconds697 * @m: where to write M register698 * @n: where to write N register699 * @p: where to write P register700 *701 * DESCRIPTION:702 * Based on the formula Freq_actual = (4*M*Freq_ref)/(N^P)703 * Repeatedly computes the Freq until the actual Freq is equal to704 * the target Freq or until the loop count is zero.  In the latter705 * case, the actual frequency nearest the target will be used.706 */707static void i810_calc_dclk(u32 freq, u32 *m, u32 *n, u32 *p)708{709	u32 m_reg, n_reg, p_divisor, n_target_max;710	u32 m_target, n_target, p_target, n_best, m_best, mod;711	u32 f_out, target_freq, diff = 0, mod_min, diff_min;712 713	diff_min = mod_min = 0xFFFFFFFF;714	n_best = m_best = m_target = f_out = 0;715 716	target_freq =  freq;717	n_target_max = 30;718 719	/*720	 * find P such that target freq is 16x reference freq (Hz).721	 */722	p_divisor = 1;723	p_target = 0;724	while(!((1000000 * p_divisor)/(16 * 24 * target_freq)) &&725	      p_divisor <= 32) {726		p_divisor <<= 1;727		p_target++;728	}729 730	n_reg = m_reg = n_target = 3;731	while (diff_min && mod_min && (n_target < n_target_max)) {732		f_out = (p_divisor * n_reg * 1000000)/(4 * 24 * m_reg);733		mod = (p_divisor * n_reg * 1000000) % (4 * 24 * m_reg);734		m_target = m_reg;735		n_target = n_reg;736		if (f_out <= target_freq) {737			n_reg++;738			diff = target_freq - f_out;739		} else {740			m_reg++;741			diff = f_out - target_freq;742		}743 744		if (diff_min > diff) {745			diff_min = diff;746			n_best = n_target;747			m_best = m_target;748		}749 750		if (!diff && mod_min > mod) {751			mod_min = mod;752			n_best = n_target;753			m_best = m_target;754		}755	}756	if (m) *m = (m_best - 2) & 0x3FF;757	if (n) *n = (n_best - 2) & 0x3FF;758	if (p) *p = (p_target << 4);759}760 761/*************************************************************762 *                Hardware Cursor Routines                   *763 *************************************************************/764 765/**766 * i810_enable_cursor - show or hide the hardware cursor767 * @mmio: address of register space768 * @mode: show (1) or hide (0)769 *770 * Description:771 * Shows or hides the hardware cursor772 */773static void i810_enable_cursor(u8 __iomem *mmio, int mode)774{775	u32 temp;776 777	temp = i810_readl(PIXCONF, mmio);778	temp = (mode == ON) ? temp | CURSOR_ENABLE_MASK :779		temp & ~CURSOR_ENABLE_MASK;780 781	i810_writel(PIXCONF, mmio, temp);782}783 784static void i810_reset_cursor_image(struct i810fb_par *par)785{786	u8 __iomem *addr = par->cursor_heap.virtual;787	int i, j;788 789	for (i = 64; i--; ) {790		for (j = 0; j < 8; j++) {791			i810_writeb(j, addr, 0xff);792			i810_writeb(j+8, addr, 0x00);793		}794		addr +=16;795	}796}797 798static void i810_load_cursor_image(int width, int height, u8 *data,799				   struct i810fb_par *par)800{801	u8 __iomem *addr = par->cursor_heap.virtual;802	int i, j, w = width/8;803	int mod = width % 8, t_mask, d_mask;804 805	t_mask = 0xff >> mod;806	d_mask = ~(0xff >> mod);807	for (i = height; i--; ) {808		for (j = 0; j < w; j++) {809			i810_writeb(j+0, addr, 0x00);810			i810_writeb(j+8, addr, *data++);811		}812		if (mod) {813			i810_writeb(j+0, addr, t_mask);814			i810_writeb(j+8, addr, *data++ & d_mask);815		}816		addr += 16;817	}818}819 820static void i810_load_cursor_colors(int fg, int bg, struct fb_info *info)821{822	struct i810fb_par *par = info->par;823	u8 __iomem *mmio = par->mmio_start_virtual;824	u8 red, green, blue, trans, temp;825 826	i810fb_getcolreg(bg, &red, &green, &blue, &trans, info);827 828	temp = i810_readb(PIXCONF1, mmio);829	i810_writeb(PIXCONF1, mmio, temp | EXTENDED_PALETTE);830 831	i810_write_dac(4, red, green, blue, mmio);832 833	i810_writeb(PIXCONF1, mmio, temp);834 835	i810fb_getcolreg(fg, &red, &green, &blue, &trans, info);836	temp = i810_readb(PIXCONF1, mmio);837	i810_writeb(PIXCONF1, mmio, temp | EXTENDED_PALETTE);838 839	i810_write_dac(5, red, green, blue, mmio);840 841	i810_writeb(PIXCONF1, mmio, temp);842}843 844/**845 * i810_init_cursor - initializes the cursor846 * @par: pointer to i810fb_par structure847 *848 * DESCRIPTION:849 * Initializes the cursor registers850 */851static void i810_init_cursor(struct i810fb_par *par)852{853	u8 __iomem *mmio = par->mmio_start_virtual;854 855	i810_enable_cursor(mmio, OFF);856	i810_writel(CURBASE, mmio, par->cursor_heap.physical);857	i810_writew(CURCNTR, mmio, COORD_ACTIVE | CURSOR_MODE_64_XOR);858}859 860/*********************************************************************861 *                    Framebuffer hook helpers                       *862 *********************************************************************/863/**864 * i810_round_off -  Round off values to capability of hardware865 * @var: pointer to fb_var_screeninfo structure866 *867 * DESCRIPTION:868 * @var contains user-defined information for the mode to be set.869 * This will try modify those values to ones nearest the870 * capability of the hardware871 */872static void i810_round_off(struct fb_var_screeninfo *var)873{874	u32 xres, yres, vxres, vyres;875 876	/*877	 *  Presently supports only these configurations878	 */879 880	xres = var->xres;881	yres = var->yres;882	vxres = var->xres_virtual;883	vyres = var->yres_virtual;884 885	var->bits_per_pixel += 7;886	var->bits_per_pixel &= ~7;887 888	if (var->bits_per_pixel < 8)889		var->bits_per_pixel = 8;890	if (var->bits_per_pixel > 32)891		var->bits_per_pixel = 32;892 893	round_off_xres(&xres);894	if (xres < 40)895		xres = 40;896	if (xres > 2048)897		xres = 2048;898	xres = (xres + 7) & ~7;899 900	if (vxres < xres)901		vxres = xres;902 903	round_off_yres(&xres, &yres);904	if (yres < 1)905		yres = 1;906	if (yres >= 2048)907		yres = 2048;908 909	if (vyres < yres)910		vyres = yres;911 912	if (var->bits_per_pixel == 32)913		var->accel_flags = 0;914 915	/* round of horizontal timings to nearest 8 pixels */916	var->left_margin = (var->left_margin + 4) & ~7;917	var->right_margin = (var->right_margin + 4) & ~7;918	var->hsync_len = (var->hsync_len + 4) & ~7;919 920	if (var->vmode & FB_VMODE_INTERLACED) {921		if (!((yres + var->upper_margin + var->vsync_len +922		       var->lower_margin) & 1))923			var->upper_margin++;924	}925 926	var->xres = xres;927	var->yres = yres;928	var->xres_virtual = vxres;929	var->yres_virtual = vyres;930}931 932/**933 * set_color_bitfields - sets rgba fields934 * @var: pointer to fb_var_screeninfo935 *936 * DESCRIPTION:937 * The length, offset and ordering  for each color field938 * (red, green, blue)  will be set as specified939 * by the hardware940 */941static void set_color_bitfields(struct fb_var_screeninfo *var)942{943	switch (var->bits_per_pixel) {944	case 8:945		var->red.offset = 0;946		var->red.length = 8;947		var->green.offset = 0;948		var->green.length = 8;949		var->blue.offset = 0;950		var->blue.length = 8;951		var->transp.offset = 0;952		var->transp.length = 0;953		break;954	case 16:955		var->green.length = (var->green.length == 5) ? 5 : 6;956		var->red.length = 5;957		var->blue.length = 5;958		var->transp.length = 6 - var->green.length;959		var->blue.offset = 0;960		var->green.offset = 5;961		var->red.offset = 5 + var->green.length;962		var->transp.offset =  (5 + var->red.offset) & 15;963		break;964	case 24:	/* RGB 888   */965	case 32:	/* RGBA 8888 */966		var->red.offset = 16;967		var->red.length = 8;968		var->green.offset = 8;969		var->green.length = 8;970		var->blue.offset = 0;971		var->blue.length = 8;972		var->transp.length = var->bits_per_pixel - 24;973		var->transp.offset = (var->transp.length) ? 24 : 0;974		break;975	}976	var->red.msb_right = 0;977	var->green.msb_right = 0;978	var->blue.msb_right = 0;979	var->transp.msb_right = 0;980}981 982/**983 * i810_check_params - check if contents in var are valid984 * @var: pointer to fb_var_screeninfo985 * @info: pointer to fb_info986 *987 * DESCRIPTION:988 * This will check if the framebuffer size is sufficient989 * for the current mode and if the user's monitor has the990 * required specifications to display the current mode.991 */992static int i810_check_params(struct fb_var_screeninfo *var,993			     struct fb_info *info)994{995	struct i810fb_par *par = info->par;996	int line_length, vidmem, mode_valid = 0, retval = 0;997	u32 vyres = var->yres_virtual, vxres = var->xres_virtual;998 999	/*1000	 *  Memory limit1001	 */1002	line_length = get_line_length(par, vxres, var->bits_per_pixel);1003	vidmem = line_length*vyres;1004 1005	if (vidmem > par->fb.size) {1006		vyres = par->fb.size/line_length;1007		if (vyres < var->yres) {1008			vyres = info->var.yres;1009			vxres = par->fb.size/vyres;1010			vxres /= var->bits_per_pixel >> 3;1011			line_length = get_line_length(par, vxres,1012						      var->bits_per_pixel);1013			vidmem = line_length * info->var.yres;1014			if (vxres < var->xres) {1015				printk("i810fb: required video memory, "1016				       "%d bytes, for %dx%d-%d (virtual) "1017				       "is out of range\n",1018				       vidmem, vxres, vyres,1019				       var->bits_per_pixel);1020				return -ENOMEM;1021			}1022		}1023	}1024 1025	var->xres_virtual = vxres;1026	var->yres_virtual = vyres;1027 1028	/*1029	 * Monitor limit1030	 */1031	switch (var->bits_per_pixel) {1032	case 8:1033		info->monspecs.dclkmax = 234000000;1034		break;1035	case 16:1036		info->monspecs.dclkmax = 229000000;1037		break;1038	case 24:1039	case 32:1040		info->monspecs.dclkmax = 204000000;1041		break;1042	}1043 1044	info->monspecs.dclkmin = 15000000;1045 1046	if (!fb_validate_mode(var, info))1047		mode_valid = 1;1048 1049#ifdef CONFIG_FB_I810_I2C1050	if (!mode_valid && info->monspecs.gtf &&1051	    !fb_get_mode(FB_MAXTIMINGS, 0, var, info))1052		mode_valid = 1;1053 1054	if (!mode_valid && info->monspecs.modedb_len) {1055		const struct fb_videomode *mode;1056 1057		mode = fb_find_best_mode(var, &info->modelist);1058		if (mode) {1059			fb_videomode_to_var(var, mode);1060			mode_valid = 1;1061		}1062	}1063#endif1064	if (!mode_valid && info->monspecs.modedb_len == 0) {1065		if (fb_get_mode(FB_MAXTIMINGS, 0, var, info)) {1066			int default_sync = (info->monspecs.hfmin-HFMIN)1067				|(info->monspecs.hfmax-HFMAX)1068				|(info->monspecs.vfmin-VFMIN)1069				|(info->monspecs.vfmax-VFMAX);1070			printk("i810fb: invalid video mode%s\n",1071			       default_sync ? "" : ". Specifying "1072			       "vsyncN/hsyncN parameters may help");1073			retval = -EINVAL;1074		}1075	}1076 1077	return retval;1078}1079 1080/**1081 * encode_fix - fill up fb_fix_screeninfo structure1082 * @fix: pointer to fb_fix_screeninfo1083 * @info: pointer to fb_info1084 *1085 * DESCRIPTION:1086 * This will set up parameters that are unmodifiable by the user.1087 */1088static int encode_fix(struct fb_fix_screeninfo *fix, struct fb_info *info)1089{1090	struct i810fb_par *par = info->par;1091 1092    	memset(fix, 0, sizeof(struct fb_fix_screeninfo));1093 1094    	strcpy(fix->id, "I810");1095	mutex_lock(&info->mm_lock);1096    	fix->smem_start = par->fb.physical;1097    	fix->smem_len = par->fb.size;1098	mutex_unlock(&info->mm_lock);1099    	fix->type = FB_TYPE_PACKED_PIXELS;1100    	fix->type_aux = 0;1101	fix->xpanstep = 8;1102	fix->ypanstep = 1;1103 1104    	switch (info->var.bits_per_pixel) {1105	case 8:1106	    	fix->visual = FB_VISUAL_PSEUDOCOLOR;1107	    	break;1108	case 16:1109	case 24:1110	case 32:1111		if (info->var.nonstd)1112			fix->visual = FB_VISUAL_DIRECTCOLOR;1113		else1114			fix->visual = FB_VISUAL_TRUECOLOR;1115	    	break;1116	default:1117		return -EINVAL;1118	}1119    	fix->ywrapstep = 0;1120	fix->line_length = par->pitch;1121	fix->mmio_start = par->mmio_start_phys;1122	fix->mmio_len = MMIO_SIZE;1123	fix->accel = FB_ACCEL_I810;1124 1125	return 0;1126}1127 1128/**1129 * decode_var - modify par according to contents of var1130 * @var: pointer to fb_var_screeninfo1131 * @par: pointer to i810fb_par1132 *1133 * DESCRIPTION:1134 * Based on the contents of @var, @par will be dynamically filled up.1135 * @par contains all information necessary to modify the hardware.1136*/1137static void decode_var(const struct fb_var_screeninfo *var,1138		       struct i810fb_par *par)1139{1140	u32 xres, yres, vxres, vyres;1141 1142	xres = var->xres;1143	yres = var->yres;1144	vxres = var->xres_virtual;1145	vyres = var->yres_virtual;1146 1147	switch (var->bits_per_pixel) {1148	case 8:1149		par->pixconf = PIXCONF8;1150		par->bltcntl = 0;1151		par->depth = 1;1152		par->blit_bpp = BPP8;1153		break;1154	case 16:1155		if (var->green.length == 5)1156			par->pixconf = PIXCONF15;1157		else1158			par->pixconf = PIXCONF16;1159		par->bltcntl = 16;1160		par->depth = 2;1161		par->blit_bpp = BPP16;1162		break;1163	case 24:1164		par->pixconf = PIXCONF24;1165		par->bltcntl = 32;1166		par->depth = 3;1167		par->blit_bpp = BPP24;1168		break;1169	case 32:1170		par->pixconf = PIXCONF32;1171		par->bltcntl = 0;1172		par->depth = 4;1173		par->blit_bpp = 3 << 24;1174		break;1175	}1176	if (var->nonstd && var->bits_per_pixel != 8)1177		par->pixconf |= 1 << 27;1178 1179	i810_calc_dclk(var->pixclock, &par->regs.M,1180		       &par->regs.N, &par->regs.P);1181	i810fb_encode_registers(var, par, xres, yres);1182 1183	par->watermark = i810_get_watermark(var, par);1184	par->pitch = get_line_length(par, vxres, var->bits_per_pixel);1185}1186 1187/**1188 * i810fb_getcolreg - gets red, green and blue values of the hardware DAC1189 * @regno: DAC index1190 * @red: red1191 * @green: green1192 * @blue: blue1193 * @transp: transparency (alpha)1194 * @info: pointer to fb_info1195 *1196 * DESCRIPTION:1197 * Gets the red, green and blue values of the hardware DAC as pointed by @regno1198 * and writes them to @red, @green and @blue respectively1199 */1200static int i810fb_getcolreg(u8 regno, u8 *red, u8 *green, u8 *blue,1201			    u8 *transp, struct fb_info *info)1202{1203	struct i810fb_par *par = info->par;1204	u8 __iomem *mmio = par->mmio_start_virtual;1205	u8 temp;1206 1207	if (info->fix.visual == FB_VISUAL_DIRECTCOLOR) {1208		if ((info->var.green.length == 5 && regno > 31) ||1209		    (info->var.green.length == 6 && regno > 63))1210			return 1;1211	}1212 1213	temp = i810_readb(PIXCONF1, mmio);1214	i810_writeb(PIXCONF1, mmio, temp & ~EXTENDED_PALETTE);1215 1216	if (info->fix.visual == FB_VISUAL_DIRECTCOLOR &&1217	    info->var.green.length == 5)1218		i810_read_dac(regno * 8, red, green, blue, mmio);1219 1220	else if (info->fix.visual == FB_VISUAL_DIRECTCOLOR &&1221		 info->var.green.length == 6) {1222		u8 tmp;1223 1224		i810_read_dac(regno * 8, red, &tmp, blue, mmio);1225		i810_read_dac(regno * 4, &tmp, green, &tmp, mmio);1226	}1227	else1228		i810_read_dac(regno, red, green, blue, mmio);1229 1230    	*transp = 0;1231	i810_writeb(PIXCONF1, mmio, temp);1232 1233    	return 0;1234}1235 1236/******************************************************************1237 *           Framebuffer device-specific hooks                    *1238 ******************************************************************/1239 1240static int i810fb_open(struct fb_info *info, int user)1241{1242	struct i810fb_par *par = info->par;1243 1244	mutex_lock(&par->open_lock);1245	if (par->use_count == 0) {1246		memset(&par->state, 0, sizeof(struct vgastate));1247		par->state.flags = VGA_SAVE_CMAP;1248		par->state.vgabase = par->mmio_start_virtual;1249		save_vga(&par->state);1250 1251		i810_save_vga_state(par);1252	}1253 1254	par->use_count++;1255	mutex_unlock(&par->open_lock);1256 1257	return 0;1258}1259 1260static int i810fb_release(struct fb_info *info, int user)1261{1262	struct i810fb_par *par = info->par;1263 1264	mutex_lock(&par->open_lock);1265	if (par->use_count == 0) {1266		mutex_unlock(&par->open_lock);1267		return -EINVAL;1268	}1269 1270	if (par->use_count == 1) {1271		i810_restore_vga_state(par);1272		restore_vga(&par->state);1273	}1274 1275	par->use_count--;1276	mutex_unlock(&par->open_lock);1277 1278	return 0;1279}1280 1281 1282static int i810fb_setcolreg(unsigned regno, unsigned red, unsigned green,1283			    unsigned blue, unsigned transp,1284			    struct fb_info *info)1285{1286	struct i810fb_par *par = info->par;1287	u8 __iomem *mmio = par->mmio_start_virtual;1288	u8 temp;1289	int i;1290 1291 	if (regno > 255) return 1;1292 1293	if (info->fix.visual == FB_VISUAL_DIRECTCOLOR) {1294		if ((info->var.green.length == 5 && regno > 31) ||1295		    (info->var.green.length == 6 && regno > 63))1296			return 1;1297	}1298 1299	if (info->var.grayscale)1300		red = green = blue = (19595 * red + 38470 * green +1301				      7471 * blue) >> 16;1302 1303	temp = i810_readb(PIXCONF1, mmio);1304	i810_writeb(PIXCONF1, mmio, temp & ~EXTENDED_PALETTE);1305 1306	if (info->fix.visual == FB_VISUAL_DIRECTCOLOR &&1307	    info->var.green.length == 5) {1308		for (i = 0; i < 8; i++)1309			i810_write_dac((u8) (regno * 8) + i, (u8) red,1310				       (u8) green, (u8) blue, mmio);1311	} else if (info->fix.visual == FB_VISUAL_DIRECTCOLOR &&1312		 info->var.green.length == 6) {1313		u8 r, g, b;1314 1315		if (regno < 32) {1316			for (i = 0; i < 8; i++)1317				i810_write_dac((u8) (regno * 8) + i,1318					       (u8) red, (u8) green,1319					       (u8) blue, mmio);1320		}1321		i810_read_dac((u8) (regno*4), &r, &g, &b, mmio);1322		for (i = 0; i < 4; i++)1323			i810_write_dac((u8) (regno*4) + i, r, (u8) green,1324				       b, mmio);1325	} else if (info->fix.visual == FB_VISUAL_PSEUDOCOLOR) {1326		i810_write_dac((u8) regno, (u8) red, (u8) green,1327			       (u8) blue, mmio);1328	}1329 1330	i810_writeb(PIXCONF1, mmio, temp);1331 1332	if (regno < 16) {1333		switch (info->var.bits_per_pixel) {1334		case 16:1335			if (info->fix.visual == FB_VISUAL_DIRECTCOLOR) {1336				if (info->var.green.length == 5)1337					((u32 *)info->pseudo_palette)[regno] =1338						(regno << 10) | (regno << 5) |1339						regno;1340				else1341					((u32 *)info->pseudo_palette)[regno] =1342						(regno << 11) | (regno << 5) |1343						regno;1344			} else {1345				if (info->var.green.length == 5) {1346					/* RGB 555 */1347					((u32 *)info->pseudo_palette)[regno] =1348						((red & 0xf800) >> 1) |1349						((green & 0xf800) >> 6) |1350						((blue & 0xf800) >> 11);1351				} else {1352					/* RGB 565 */1353					((u32 *)info->pseudo_palette)[regno] =1354						(red & 0xf800) |1355						((green & 0xf800) >> 5) |1356						((blue & 0xf800) >> 11);1357				}1358			}1359			break;1360		case 24:	/* RGB 888 */1361		case 32:	/* RGBA 8888 */1362			if (info->fix.visual == FB_VISUAL_DIRECTCOLOR)1363				((u32 *)info->pseudo_palette)[regno] =1364					(regno << 16) | (regno << 8) |1365					regno;1366			else1367				((u32 *)info->pseudo_palette)[regno] =1368					((red & 0xff00) << 8) |1369					(green & 0xff00) |1370					((blue & 0xff00) >> 8);1371			break;1372		}1373	}1374	return 0;1375}1376 1377static int i810fb_pan_display(struct fb_var_screeninfo *var,1378			      struct fb_info *info)1379{1380	struct i810fb_par *par = info->par;1381	u32 total;1382 1383	total = var->xoffset * par->depth +1384		var->yoffset * info->fix.line_length;1385	i810fb_load_front(total, info);1386 1387	return 0;1388}1389 1390static int i810fb_blank (int blank_mode, struct fb_info *info)1391{1392	struct i810fb_par *par = info->par;1393	u8 __iomem *mmio = par->mmio_start_virtual;1394	int mode = 0, pwr, scr_off = 0;1395 1396	pwr = i810_readl(PWR_CLKC, mmio);1397 1398	switch (blank_mode) {1399	case FB_BLANK_UNBLANK:1400		mode = POWERON;1401		pwr |= 1;1402		scr_off = ON;1403		break;1404	case FB_BLANK_NORMAL:1405		mode = POWERON;1406		pwr |= 1;1407		scr_off = OFF;1408		break;1409	case FB_BLANK_VSYNC_SUSPEND:1410		mode = STANDBY;1411		pwr |= 1;1412		scr_off = OFF;1413		break;1414	case FB_BLANK_HSYNC_SUSPEND:1415		mode = SUSPEND;1416		pwr |= 1;1417		scr_off = OFF;1418		break;1419	case FB_BLANK_POWERDOWN:1420		mode = POWERDOWN;1421		pwr &= ~1;1422		scr_off = OFF;1423		break;1424	default:1425		return -EINVAL;1426	}1427 1428	i810_screen_off(mmio, scr_off);1429	i810_writel(HVSYNC, mmio, mode);1430	i810_writel(PWR_CLKC, mmio, pwr);1431 1432	return 0;1433}1434 1435static int i810fb_set_par(struct fb_info *info)1436{1437	struct i810fb_par *par = info->par;1438 1439	decode_var(&info->var, par);1440	i810_load_regs(par);1441	i810_init_cursor(par);1442	encode_fix(&info->fix, info);1443 1444	if (info->var.accel_flags && !(par->dev_flags & LOCKUP)) {1445		info->flags = FBINFO_HWACCEL_YPAN |1446		FBINFO_HWACCEL_COPYAREA | FBINFO_HWACCEL_FILLRECT |1447		FBINFO_HWACCEL_IMAGEBLIT;1448		info->pixmap.scan_align = 2;1449	} else {1450		info->pixmap.scan_align = 1;1451		info->flags = FBINFO_HWACCEL_YPAN;1452	}1453	return 0;1454}1455 1456static int i810fb_check_var(struct fb_var_screeninfo *var,1457			    struct fb_info *info)1458{1459	int err;1460 1461	if (IS_DVT) {1462		var->vmode &= ~FB_VMODE_MASK;1463		var->vmode |= FB_VMODE_NONINTERLACED;1464	}1465	if (var->vmode & FB_VMODE_DOUBLE) {1466		var->vmode &= ~FB_VMODE_MASK;1467		var->vmode |= FB_VMODE_NONINTERLACED;1468	}1469 1470	i810_round_off(var);1471	if ((err = i810_check_params(var, info)))1472		return err;1473 1474	i810fb_fill_var_timings(var);1475	set_color_bitfields(var);1476	return 0;1477}1478 1479static int i810fb_cursor(struct fb_info *info, struct fb_cursor *cursor)1480{1481	struct i810fb_par *par = info->par;1482	u8 __iomem *mmio = par->mmio_start_virtual;1483 1484	if (par->dev_flags & LOCKUP)1485		return -ENXIO;1486 1487	if (cursor->image.width > 64 || cursor->image.height > 64)1488		return -ENXIO;1489 1490	if ((i810_readl(CURBASE, mmio) & 0xf) != par->cursor_heap.physical) {1491		i810_init_cursor(par);1492		cursor->set |= FB_CUR_SETALL;1493	}1494 1495	i810_enable_cursor(mmio, OFF);1496 1497	if (cursor->set & FB_CUR_SETPOS) {1498		u32 tmp;1499 1500		tmp = (cursor->image.dx - info->var.xoffset) & 0xffff;1501		tmp |= (cursor->image.dy - info->var.yoffset) << 16;1502		i810_writel(CURPOS, mmio, tmp);1503	}1504 1505	if (cursor->set & FB_CUR_SETSIZE)1506		i810_reset_cursor_image(par);1507 1508	if (cursor->set & FB_CUR_SETCMAP)1509		i810_load_cursor_colors(cursor->image.fg_color,1510					cursor->image.bg_color,1511					info);1512 1513	if (cursor->set & (FB_CUR_SETSHAPE | FB_CUR_SETIMAGE)) {1514		int size = ((cursor->image.width + 7) >> 3) *1515			cursor->image.height;1516		int i;1517		u8 *data = kmalloc(64 * 8, GFP_ATOMIC);1518 1519		if (data == NULL)1520			return -ENOMEM;1521 1522		switch (cursor->rop) {1523		case ROP_XOR:1524			for (i = 0; i < size; i++)1525				data[i] = cursor->image.data[i] ^ cursor->mask[i];1526			break;1527		case ROP_COPY:1528		default:1529			for (i = 0; i < size; i++)1530				data[i] = cursor->image.data[i] & cursor->mask[i];1531			break;1532		}1533 1534		i810_load_cursor_image(cursor->image.width,1535				       cursor->image.height, data,1536				       par);1537		kfree(data);1538	}1539 1540	if (cursor->enable)1541		i810_enable_cursor(mmio, ON);1542 1543	return 0;1544}1545 1546static const struct fb_ops i810fb_ops = {1547	.owner =             THIS_MODULE,1548	.fb_open =           i810fb_open,1549	.fb_release =        i810fb_release,1550	__FB_DEFAULT_IOMEM_OPS_RDWR,1551	.fb_check_var =      i810fb_check_var,1552	.fb_set_par =        i810fb_set_par,1553	.fb_setcolreg =      i810fb_setcolreg,1554	.fb_blank =          i810fb_blank,1555	.fb_pan_display =    i810fb_pan_display,1556	.fb_fillrect =       i810fb_fillrect,1557	.fb_copyarea =       i810fb_copyarea,1558	.fb_imageblit =      i810fb_imageblit,1559	.fb_cursor =         i810fb_cursor,1560	.fb_sync =           i810fb_sync,1561	__FB_DEFAULT_IOMEM_OPS_MMAP,1562};1563 1564/***********************************************************************1565 *                         Power Management                            *1566 ***********************************************************************/1567static int i810fb_suspend(struct pci_dev *dev, pm_message_t mesg)1568{1569	struct fb_info *info = pci_get_drvdata(dev);1570	struct i810fb_par *par = info->par;1571 1572	par->cur_state = mesg.event;1573 1574	switch (mesg.event) {1575	case PM_EVENT_FREEZE:1576	case PM_EVENT_PRETHAW:1577		dev->dev.power.power_state = mesg;1578		return 0;1579	}1580 1581	console_lock();1582	fb_set_suspend(info, 1);1583 1584	if (info->fbops->fb_sync)1585		info->fbops->fb_sync(info);1586 1587	i810fb_blank(FB_BLANK_POWERDOWN, info);1588	agp_unbind_memory(par->i810_gtt.i810_fb_memory);1589	agp_unbind_memory(par->i810_gtt.i810_cursor_memory);1590 1591	pci_save_state(dev);1592	pci_disable_device(dev);1593	pci_set_power_state(dev, pci_choose_state(dev, mesg));1594	console_unlock();1595 1596	return 0;1597}1598 1599static int i810fb_resume(struct pci_dev *dev)1600{1601	struct fb_info *info = pci_get_drvdata(dev);1602	struct i810fb_par *par = info->par;1603	int cur_state = par->cur_state;1604 1605	par->cur_state = PM_EVENT_ON;1606 1607	if (cur_state == PM_EVENT_FREEZE) {1608		pci_set_power_state(dev, PCI_D0);1609		return 0;1610	}1611 1612	console_lock();1613	pci_set_power_state(dev, PCI_D0);1614	pci_restore_state(dev);1615 1616	if (pci_enable_device(dev))1617		goto fail;1618 1619	pci_set_master(dev);1620	agp_bind_memory(par->i810_gtt.i810_fb_memory,1621			par->fb.offset);1622	agp_bind_memory(par->i810_gtt.i810_cursor_memory,1623			par->cursor_heap.offset);1624	i810fb_set_par(info);1625	fb_set_suspend (info, 0);1626	info->fbops->fb_blank(VESA_NO_BLANKING, info);1627fail:1628	console_unlock();1629	return 0;1630}1631/***********************************************************************1632 *                  AGP resource allocation                            *1633 ***********************************************************************/1634 1635static void i810_fix_pointers(struct i810fb_par *par)1636{1637      	par->fb.physical = par->aperture.physical+(par->fb.offset << 12);1638	par->fb.virtual = par->aperture.virtual+(par->fb.offset << 12);1639	par->iring.physical = par->aperture.physical +1640		(par->iring.offset << 12);1641	par->iring.virtual = par->aperture.virtual +1642		(par->iring.offset << 12);1643	par->cursor_heap.virtual = par->aperture.virtual+1644		(par->cursor_heap.offset << 12);1645}1646 1647static void i810_fix_offsets(struct i810fb_par *par)1648{1649	if (vram + 1 > par->aperture.size >> 20)1650		vram = (par->aperture.size >> 20) - 1;1651	if (v_offset_default > (par->aperture.size >> 20))1652		v_offset_default = (par->aperture.size >> 20);1653	if (vram + v_offset_default + 1 > par->aperture.size >> 20)1654		v_offset_default = (par->aperture.size >> 20) - (vram + 1);1655 1656	par->fb.size = vram << 20;1657	par->fb.offset = v_offset_default << 20;1658	par->fb.offset >>= 12;1659 1660	par->iring.offset = par->fb.offset + (par->fb.size >> 12);1661	par->iring.size = RINGBUFFER_SIZE;1662 1663	par->cursor_heap.offset = par->iring.offset + (RINGBUFFER_SIZE >> 12);1664	par->cursor_heap.size = 4096;1665}1666 1667static int i810_alloc_agp_mem(struct fb_info *info)1668{1669	struct i810fb_par *par = info->par;1670	int size;1671	struct agp_bridge_data *bridge;1672 1673	i810_fix_offsets(par);1674	size = par->fb.size + par->iring.size;1675 1676	if (!(bridge = agp_backend_acquire(par->dev))) {1677		printk("i810fb_alloc_fbmem: cannot acquire agpgart\n");1678		return -ENODEV;1679	}1680	if (!(par->i810_gtt.i810_fb_memory =1681	      agp_allocate_memory(bridge, size >> 12, AGP_NORMAL_MEMORY))) {1682		printk("i810fb_alloc_fbmem: can't allocate framebuffer "1683		       "memory\n");1684		agp_backend_release(bridge);1685		return -ENOMEM;1686	}1687	if (agp_bind_memory(par->i810_gtt.i810_fb_memory,1688			    par->fb.offset)) {1689		printk("i810fb_alloc_fbmem: can't bind framebuffer memory\n");1690		agp_backend_release(bridge);1691		return -EBUSY;1692	}1693 1694	if (!(par->i810_gtt.i810_cursor_memory =1695	      agp_allocate_memory(bridge, par->cursor_heap.size >> 12,1696				  AGP_PHYSICAL_MEMORY))) {1697		printk("i810fb_alloc_cursormem:  can't allocate "1698		       "cursor memory\n");1699		agp_backend_release(bridge);1700		return -ENOMEM;1701	}1702	if (agp_bind_memory(par->i810_gtt.i810_cursor_memory,1703			    par->cursor_heap.offset)) {1704		printk("i810fb_alloc_cursormem: cannot bind cursor memory\n");1705		agp_backend_release(bridge);1706		return -EBUSY;1707	}1708 1709	par->cursor_heap.physical = par->i810_gtt.i810_cursor_memory->physical;1710 1711	i810_fix_pointers(par);1712 1713	agp_backend_release(bridge);1714 1715	return 0;1716}1717 1718/***************************************************************1719 *                    Initialization                           *1720 ***************************************************************/1721 1722/**1723 * i810_init_monspecs1724 * @info: pointer to device specific info structure1725 *1726 * DESCRIPTION:1727 * Sets the user monitor's horizontal and vertical1728 * frequency limits1729 */1730static void i810_init_monspecs(struct fb_info *info)1731{1732	if (!hsync1)1733		hsync1 = HFMIN;1734	if (!hsync2)1735		hsync2 = HFMAX;1736	if (!info->monspecs.hfmax)1737		info->monspecs.hfmax = hsync2;1738	if (!info->monspecs.hfmin)1739		info->monspecs.hfmin = hsync1;1740	if (hsync2 < hsync1)1741		info->monspecs.hfmin = hsync2;1742 1743	if (!vsync1)1744		vsync1 = VFMIN;1745	if (!vsync2)1746		vsync2 = VFMAX;1747	if (IS_DVT && vsync1 < 60)1748		vsync1 = 60;1749	if (!info->monspecs.vfmax)1750		info->monspecs.vfmax = vsync2;1751	if (!info->monspecs.vfmin)1752		info->monspecs.vfmin = vsync1;1753	if (vsync2 < vsync1)1754		info->monspecs.vfmin = vsync2;1755}1756 1757/**1758 * i810_init_defaults - initializes default values to use1759 * @par: pointer to i810fb_par structure1760 * @info: pointer to current fb_info structure1761 */1762static void i810_init_defaults(struct i810fb_par *par, struct fb_info *info)1763{1764	mutex_init(&par->open_lock);1765 1766	if (voffset)1767		v_offset_default = voffset;1768	else if (par->aperture.size > 32 * 1024 * 1024)1769		v_offset_default = 16;1770	else1771		v_offset_default = 8;1772 1773	if (!vram)1774		vram = 1;1775 1776	if (accel)1777		par->dev_flags |= HAS_ACCELERATION;1778 1779	if (sync)1780		par->dev_flags |= ALWAYS_SYNC;1781 1782	par->ddc_num = (ddc3 ? 3 : 2);1783 1784	if (bpp < 8)1785		bpp = 8;1786 1787	par->i810fb_ops = i810fb_ops;1788 1789	if (xres)1790		info->var.xres = xres;1791	else1792		info->var.xres = 640;1793 1794	if (yres)1795		info->var.yres = yres;1796	else1797		info->var.yres = 480;1798 1799	if (!vyres)1800		vyres = (vram << 20)/(info->var.xres*bpp >> 3);1801 1802	info->var.yres_virtual = vyres;1803	info->var.bits_per_pixel = bpp;1804 1805	if (dcolor)1806		info->var.nonstd = 1;1807 1808	if (par->dev_flags & HAS_ACCELERATION)1809		info->var.accel_flags = 1;1810 1811	i810_init_monspecs(info);1812}1813 1814/**1815 * i810_init_device - initialize device1816 * @par: pointer to i810fb_par structure1817 */1818static void i810_init_device(struct i810fb_par *par)1819{1820	u8 reg;1821	u8 __iomem *mmio = par->mmio_start_virtual;1822 1823	if (mtrr)1824		par->wc_cookie= arch_phys_wc_add((u32) par->aperture.physical,1825						 par->aperture.size);1826 1827	i810_init_cursor(par);1828 1829	/* mvo: enable external vga-connector (for laptops) */1830	if (extvga) {1831		i810_writel(HVSYNC, mmio, 0);1832		i810_writel(PWR_CLKC, mmio, 3);1833	}1834 1835	pci_read_config_byte(par->dev, 0x50, &reg);1836	reg &= FREQ_MASK;1837	par->mem_freq = (reg) ? 133 : 100;1838 1839}1840 1841static int i810_allocate_pci_resource(struct i810fb_par *par,1842				      const struct pci_device_id *entry)1843{1844	int err;1845 1846	if ((err = pci_enable_device(par->dev))) {1847		printk("i810fb_init: cannot enable device\n");1848		return err;1849	}1850	par->res_flags |= PCI_DEVICE_ENABLED;1851 1852	if (pci_resource_len(par->dev, 0) > 512 * 1024) {1853		par->aperture.physical = pci_resource_start(par->dev, 0);1854		par->aperture.size = pci_resource_len(par->dev, 0);1855		par->mmio_start_phys = pci_resource_start(par->dev, 1);1856	} else {1857		par->aperture.physical = pci_resource_start(par->dev, 1);1858		par->aperture.size = pci_resource_len(par->dev, 1);1859		par->mmio_start_phys = pci_resource_start(par->dev, 0);1860	}1861	if (!par->aperture.size) {1862		printk("i810fb_init: device is disabled\n");1863		return -ENOMEM;1864	}1865 1866	if (!request_mem_region(par->aperture.physical,1867				par->aperture.size,1868				i810_pci_list[entry->driver_data])) {1869		printk("i810fb_init: cannot request framebuffer region\n");1870		return -ENODEV;1871	}1872	par->res_flags |= FRAMEBUFFER_REQ;1873 1874	par->aperture.virtual = ioremap_wc(par->aperture.physical,1875					   par->aperture.size);1876	if (!par->aperture.virtual) {1877		printk("i810fb_init: cannot remap framebuffer region\n");1878		return -ENODEV;1879	}1880 1881	if (!request_mem_region(par->mmio_start_phys,1882				MMIO_SIZE,1883				i810_pci_list[entry->driver_data])) {1884		printk("i810fb_init: cannot request mmio region\n");1885		return -ENODEV;1886	}1887	par->res_flags |= MMIO_REQ;1888 1889	par->mmio_start_virtual = ioremap(par->mmio_start_phys,1890						  MMIO_SIZE);1891	if (!par->mmio_start_virtual) {1892		printk("i810fb_init: cannot remap mmio region\n");1893		return -ENODEV;1894	}1895 1896	return 0;1897}1898 1899static void i810fb_find_init_mode(struct fb_info *info)1900{1901	struct fb_videomode mode;1902	struct fb_var_screeninfo var;1903	struct fb_monspecs *specs = &info->monspecs;1904	int found = 0;1905#ifdef CONFIG_FB_I810_I2C1906	int i;1907	int err = 1;1908	struct i810fb_par *par = info->par;1909#endif1910 1911	INIT_LIST_HEAD(&info->modelist);1912	memset(&mode, 0, sizeof(struct fb_videomode));1913	var = info->var;1914#ifdef CONFIG_FB_I810_I2C1915	i810_create_i2c_busses(par);1916 1917	for (i = 0; i < par->ddc_num + 1; i++) {1918		err = i810_probe_i2c_connector(info, &par->edid, i);1919		if (!err)1920			break;1921	}1922 1923	if (!err)1924		printk("i810fb_init_pci: DDC probe successful\n");1925 1926	fb_edid_to_monspecs(par->edid, specs);1927 1928	if (specs->modedb == NULL)1929		printk("i810fb_init_pci: Unable to get Mode Database\n");1930 1931	fb_videomode_to_modelist(specs->modedb, specs->modedb_len,1932				 &info->modelist);1933	if (specs->modedb != NULL) {1934		const struct fb_videomode *m;1935 1936		if (xres && yres) {1937			if ((m = fb_find_best_mode(&var, &info->modelist))) {1938				mode = *m;1939				found  = 1;1940			}1941		}1942 1943		if (!found) {1944			m = fb_find_best_display(&info->monspecs, &info->modelist);1945			mode = *m;1946			found = 1;1947		}1948 1949		fb_videomode_to_var(&var, &mode);1950	}1951#endif1952	if (mode_option)1953		fb_find_mode(&var, info, mode_option, specs->modedb,1954			     specs->modedb_len, (found) ? &mode : NULL,1955			     info->var.bits_per_pixel);1956 1957	info->var = var;1958	fb_destroy_modedb(specs->modedb);1959	specs->modedb = NULL;1960}1961 1962#ifndef MODULE1963static int i810fb_setup(char *options)1964{1965	char *this_opt, *suffix = NULL;1966 1967	if (!options || !*options)1968		return 0;1969 1970	while ((this_opt = strsep(&options, ",")) != NULL) {1971		if (!strncmp(this_opt, "mtrr", 4))1972			mtrr = true;1973		else if (!strncmp(this_opt, "accel", 5))1974			accel = true;1975		else if (!strncmp(this_opt, "extvga", 6))1976			extvga = true;1977		else if (!strncmp(this_opt, "sync", 4))1978			sync = true;1979		else if (!strncmp(this_opt, "vram:", 5))1980			vram = (simple_strtoul(this_opt+5, NULL, 0));1981		else if (!strncmp(this_opt, "voffset:", 8))1982			voffset = (simple_strtoul(this_opt+8, NULL, 0));1983		else if (!strncmp(this_opt, "xres:", 5))1984			xres = simple_strtoul(this_opt+5, NULL, 0);1985		else if (!strncmp(this_opt, "yres:", 5))1986			yres = simple_strtoul(this_opt+5, NULL, 0);1987		else if (!strncmp(this_opt, "vyres:", 6))1988			vyres = simple_strtoul(this_opt+6, NULL, 0);1989		else if (!strncmp(this_opt, "bpp:", 4))1990			bpp = simple_strtoul(this_opt+4, NULL, 0);1991		else if (!strncmp(this_opt, "hsync1:", 7)) {1992			hsync1 = simple_strtoul(this_opt+7, &suffix, 0);1993			if (strncmp(suffix, "H", 1))1994				hsync1 *= 1000;1995		} else if (!strncmp(this_opt, "hsync2:", 7)) {1996			hsync2 = simple_strtoul(this_opt+7, &suffix, 0);1997			if (strncmp(suffix, "H", 1))1998				hsync2 *= 1000;1999		} else if (!strncmp(this_opt, "vsync1:", 7))2000			vsync1 = simple_strtoul(this_opt+7, NULL, 0);2001		else if (!strncmp(this_opt, "vsync2:", 7))2002			vsync2 = simple_strtoul(this_opt+7, NULL, 0);2003		else if (!strncmp(this_opt, "dcolor", 6))2004			dcolor = true;2005		else if (!strncmp(this_opt, "ddc3", 4))2006			ddc3 = true;2007		else2008			mode_option = this_opt;2009	}2010	return 0;2011}2012#endif2013 2014static int i810fb_init_pci(struct pci_dev *dev,2015			   const struct pci_device_id *entry)2016{2017	struct fb_info    *info;2018	struct i810fb_par *par = NULL;2019	struct fb_videomode mode;2020	int err = -1, vfreq, hfreq, pixclock;2021 2022	err = aperture_remove_conflicting_pci_devices(dev, "i810fb");2023	if (err)2024		return err;2025 2026	info = framebuffer_alloc(sizeof(struct i810fb_par), &dev->dev);2027	if (!info)2028		return -ENOMEM;2029 2030	par = info->par;2031	par->dev = dev;2032 2033	if (!(info->pixmap.addr = kzalloc(8*1024, GFP_KERNEL))) {2034		i810fb_release_resource(info, par);2035		return -ENOMEM;2036	}2037	info->pixmap.size = 8*1024;2038	info->pixmap.buf_align = 8;2039	info->pixmap.access_align = 32;2040	info->pixmap.flags = FB_PIXMAP_SYSTEM;2041 2042	if ((err = i810_allocate_pci_resource(par, entry))) {2043		i810fb_release_resource(info, par);2044		return err;2045	}2046 2047	i810_init_defaults(par, info);2048 2049	if ((err = i810_alloc_agp_mem(info))) {2050		i810fb_release_resource(info, par);2051		return err;2052	}2053 2054	i810_init_device(par);2055 2056	info->screen_base = par->fb.virtual;2057	info->fbops = &par->i810fb_ops;2058	info->pseudo_palette = par->pseudo_palette;2059	fb_alloc_cmap(&info->cmap, 256, 0);2060	i810fb_find_init_mode(info);2061 2062	if ((err = info->fbops->fb_check_var(&info->var, info))) {2063		i810fb_release_resource(info, par);2064		return err;2065	}2066 2067	fb_var_to_videomode(&mode, &info->var);2068	fb_add_videomode(&mode, &info->modelist);2069 2070	i810fb_init_ringbuffer(info);2071	err = register_framebuffer(info);2072 2073	if (err < 0) {2074    		i810fb_release_resource(info, par);2075		printk("i810fb_init: cannot register framebuffer device\n");2076    		return err;2077    	}2078 2079	pci_set_drvdata(dev, info);2080	pixclock = 1000000000/(info->var.pixclock);2081	pixclock *= 1000;2082	hfreq = pixclock/(info->var.xres + info->var.left_margin +2083			  info->var.hsync_len + info->var.right_margin);2084	vfreq = hfreq/(info->var.yres + info->var.upper_margin +2085		       info->var.vsync_len + info->var.lower_margin);2086 2087      	printk("I810FB: fb%d         : %s v%d.%d.%d%s\n"2088      	       "I810FB: Video RAM   : %dK\n"2089	       "I810FB: Monitor     : H: %d-%d KHz V: %d-%d Hz\n"2090	       "I810FB: Mode        : %dx%d-%dbpp@%dHz\n",2091	       info->node,2092	       i810_pci_list[entry->driver_data],2093	       VERSION_MAJOR, VERSION_MINOR, VERSION_TEENIE, BRANCH_VERSION,2094	       (int) par->fb.size>>10, info->monspecs.hfmin/1000,2095	       info->monspecs.hfmax/1000, info->monspecs.vfmin,2096	       info->monspecs.vfmax, info->var.xres,2097	       info->var.yres, info->var.bits_per_pixel, vfreq);2098	return 0;2099}2100 2101/***************************************************************2102 *                     De-initialization                        *2103 ***************************************************************/2104 2105static void i810fb_release_resource(struct fb_info *info,2106				    struct i810fb_par *par)2107{2108	struct gtt_data *gtt = &par->i810_gtt;2109	arch_phys_wc_del(par->wc_cookie);2110 2111	i810_delete_i2c_busses(par);2112 2113	if (par->i810_gtt.i810_cursor_memory)2114		agp_free_memory(gtt->i810_cursor_memory);2115	if (par->i810_gtt.i810_fb_memory)2116		agp_free_memory(gtt->i810_fb_memory);2117 2118	if (par->mmio_start_virtual)2119		iounmap(par->mmio_start_virtual);2120	if (par->aperture.virtual)2121		iounmap(par->aperture.virtual);2122	kfree(par->edid);2123	if (par->res_flags & FRAMEBUFFER_REQ)2124		release_mem_region(par->aperture.physical,2125				   par->aperture.size);2126	if (par->res_flags & MMIO_REQ)2127		release_mem_region(par->mmio_start_phys, MMIO_SIZE);2128 2129	framebuffer_release(info);2130 2131}2132 2133static void i810fb_remove_pci(struct pci_dev *dev)2134{2135	struct fb_info *info = pci_get_drvdata(dev);2136	struct i810fb_par *par = info->par;2137 2138	unregister_framebuffer(info);2139	i810fb_release_resource(info, par);2140	printk("cleanup_module:  unloaded i810 framebuffer device\n");2141}2142 2143#ifndef MODULE2144static int i810fb_init(void)2145{2146	char *option = NULL;2147 2148	if (fb_modesetting_disabled("i810fb"))2149		return -ENODEV;2150 2151	if (fb_get_options("i810fb", &option))2152		return -ENODEV;2153	i810fb_setup(option);2154 2155	return pci_register_driver(&i810fb_driver);2156}2157#endif2158 2159/*********************************************************************2160 *                          Modularization                           *2161 *********************************************************************/2162 2163#ifdef MODULE2164 2165static int i810fb_init(void)2166{2167	if (fb_modesetting_disabled("i810fb"))2168		return -ENODEV;2169 2170	hsync1 *= 1000;2171	hsync2 *= 1000;2172 2173	return pci_register_driver(&i810fb_driver);2174}2175 2176module_param(vram, int, 0);2177MODULE_PARM_DESC(vram, "System RAM to allocate to framebuffer in MiB"2178		 " (default=4)");2179module_param(voffset, int, 0);2180MODULE_PARM_DESC(voffset, "at what offset to place start of framebuffer "2181                 "memory (0 to maximum aperture size), in MiB (default = 48)");2182module_param(bpp, int, 0);2183MODULE_PARM_DESC(bpp, "Color depth for display in bits per pixel"2184		 " (default = 8)");2185module_param(xres, int, 0);2186MODULE_PARM_DESC(xres, "Horizontal resolution in pixels (default = 640)");2187module_param(yres, int, 0);2188MODULE_PARM_DESC(yres, "Vertical resolution in scanlines (default = 480)");2189module_param(vyres,int, 0);2190MODULE_PARM_DESC(vyres, "Virtual vertical resolution in scanlines"2191		 " (default = 480)");2192module_param(hsync1, int, 0);2193MODULE_PARM_DESC(hsync1, "Minimum horizontal frequency of monitor in KHz"2194		 " (default = 29)");2195module_param(hsync2, int, 0);2196MODULE_PARM_DESC(hsync2, "Maximum horizontal frequency of monitor in KHz"2197		 " (default = 30)");2198module_param(vsync1, int, 0);2199MODULE_PARM_DESC(vsync1, "Minimum vertical frequency of monitor in Hz"2200		 " (default = 50)");2201module_param(vsync2, int, 0);2202MODULE_PARM_DESC(vsync2, "Maximum vertical frequency of monitor in Hz"2203		 " (default = 60)");2204module_param(accel, bool, 0);2205MODULE_PARM_DESC(accel, "Use Acceleration (BLIT) engine (default = 0)");2206module_param(mtrr, bool, 0);2207MODULE_PARM_DESC(mtrr, "Use MTRR (default = 0)");2208module_param(extvga, bool, 0);2209MODULE_PARM_DESC(extvga, "Enable external VGA connector (default = 0)");2210module_param(sync, bool, 0);2211MODULE_PARM_DESC(sync, "wait for accel engine to finish drawing"2212		 " (default = 0)");2213module_param(dcolor, bool, 0);2214MODULE_PARM_DESC(dcolor, "use DirectColor visuals"2215		 " (default = 0 = TrueColor)");2216module_param(ddc3, bool, 0);2217MODULE_PARM_DESC(ddc3, "Probe DDC bus 3 (default = 0 = no)");2218module_param(mode_option, charp, 0);2219MODULE_PARM_DESC(mode_option, "Specify initial video mode");2220 2221MODULE_AUTHOR("Tony A. Daplas");2222MODULE_DESCRIPTION("Framebuffer device for the Intel 810/815 and"2223		   " compatible cards");2224MODULE_LICENSE("GPL");2225 2226static void __exit i810fb_exit(void)2227{2228	pci_unregister_driver(&i810fb_driver);2229}2230module_exit(i810fb_exit);2231 2232#endif /* MODULE */2233 2234module_init(i810fb_init);2235