Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

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