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, ®);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