162306a36Sopenharmony_ci /*-*- linux-c -*-
262306a36Sopenharmony_ci *  linux/drivers/video/i810_main.c -- Intel 810 frame buffer device
362306a36Sopenharmony_ci *
462306a36Sopenharmony_ci *      Copyright (C) 2001 Antonino Daplas<adaplas@pol.net>
562306a36Sopenharmony_ci *      All Rights Reserved
662306a36Sopenharmony_ci *
762306a36Sopenharmony_ci *      Contributors:
862306a36Sopenharmony_ci *         Michael Vogt <mvogt@acm.org> - added support for Intel 815 chipsets
962306a36Sopenharmony_ci *                                        and enabling the power-on state of
1062306a36Sopenharmony_ci *                                        external VGA connectors for
1162306a36Sopenharmony_ci *                                        secondary displays
1262306a36Sopenharmony_ci *
1362306a36Sopenharmony_ci *         Fredrik Andersson <krueger@shell.linux.se> - alpha testing of
1462306a36Sopenharmony_ci *                                        the VESA GTF
1562306a36Sopenharmony_ci *
1662306a36Sopenharmony_ci *         Brad Corrion <bcorrion@web-co.com> - alpha testing of customized
1762306a36Sopenharmony_ci *                                        timings support
1862306a36Sopenharmony_ci *
1962306a36Sopenharmony_ci *	The code framework is a modification of vfb.c by Geert Uytterhoeven.
2062306a36Sopenharmony_ci *      DotClock and PLL calculations are partly based on i810_driver.c
2162306a36Sopenharmony_ci *              in xfree86 v4.0.3 by Precision Insight.
2262306a36Sopenharmony_ci *      Watermark calculation and tables are based on i810_wmark.c
2362306a36Sopenharmony_ci *              in xfre86 v4.0.3 by Precision Insight.  Slight modifications
2462306a36Sopenharmony_ci *              only to allow for integer operations instead of floating point.
2562306a36Sopenharmony_ci *
2662306a36Sopenharmony_ci *  This file is subject to the terms and conditions of the GNU General Public
2762306a36Sopenharmony_ci *  License. See the file COPYING in the main directory of this archive for
2862306a36Sopenharmony_ci *  more details.
2962306a36Sopenharmony_ci */
3062306a36Sopenharmony_ci
3162306a36Sopenharmony_ci#include <linux/aperture.h>
3262306a36Sopenharmony_ci#include <linux/module.h>
3362306a36Sopenharmony_ci#include <linux/kernel.h>
3462306a36Sopenharmony_ci#include <linux/errno.h>
3562306a36Sopenharmony_ci#include <linux/string.h>
3662306a36Sopenharmony_ci#include <linux/mm.h>
3762306a36Sopenharmony_ci#include <linux/slab.h>
3862306a36Sopenharmony_ci#include <linux/fb.h>
3962306a36Sopenharmony_ci#include <linux/init.h>
4062306a36Sopenharmony_ci#include <linux/pci.h>
4162306a36Sopenharmony_ci#include <linux/pci_ids.h>
4262306a36Sopenharmony_ci#include <linux/resource.h>
4362306a36Sopenharmony_ci#include <linux/unistd.h>
4462306a36Sopenharmony_ci#include <linux/console.h>
4562306a36Sopenharmony_ci#include <linux/io.h>
4662306a36Sopenharmony_ci
4762306a36Sopenharmony_ci#include <asm/io.h>
4862306a36Sopenharmony_ci#include <asm/div64.h>
4962306a36Sopenharmony_ci#include <asm/page.h>
5062306a36Sopenharmony_ci
5162306a36Sopenharmony_ci#include "i810_regs.h"
5262306a36Sopenharmony_ci#include "i810.h"
5362306a36Sopenharmony_ci#include "i810_main.h"
5462306a36Sopenharmony_ci
5562306a36Sopenharmony_ci/*
5662306a36Sopenharmony_ci * voffset - framebuffer offset in MiB from aperture start address.  In order for
5762306a36Sopenharmony_ci * the driver to work with X, we must try to use memory holes left untouched by X. The
5862306a36Sopenharmony_ci * following table lists where X's different surfaces start at.
5962306a36Sopenharmony_ci *
6062306a36Sopenharmony_ci * ---------------------------------------------
6162306a36Sopenharmony_ci * :                :  64 MiB     : 32 MiB      :
6262306a36Sopenharmony_ci * ----------------------------------------------
6362306a36Sopenharmony_ci * : FrontBuffer    :   0         :  0          :
6462306a36Sopenharmony_ci * : DepthBuffer    :   48        :  16         :
6562306a36Sopenharmony_ci * : BackBuffer     :   56        :  24         :
6662306a36Sopenharmony_ci * ----------------------------------------------
6762306a36Sopenharmony_ci *
6862306a36Sopenharmony_ci * So for chipsets with 64 MiB Aperture sizes, 32 MiB for v_offset is okay, allowing up to
6962306a36Sopenharmony_ci * 15 + 1 MiB of Framebuffer memory.  For 32 MiB Aperture sizes, a v_offset of 8 MiB should
7062306a36Sopenharmony_ci * work, allowing 7 + 1 MiB of Framebuffer memory.
7162306a36Sopenharmony_ci * Note, the size of the hole may change depending on how much memory you allocate to X,
7262306a36Sopenharmony_ci * and how the memory is split up between these surfaces.
7362306a36Sopenharmony_ci *
7462306a36Sopenharmony_ci * Note: Anytime the DepthBuffer or FrontBuffer is overlapped, X would still run but with
7562306a36Sopenharmony_ci * DRI disabled.  But if the Frontbuffer is overlapped, X will fail to load.
7662306a36Sopenharmony_ci *
7762306a36Sopenharmony_ci * Experiment with v_offset to find out which works best for you.
7862306a36Sopenharmony_ci */
7962306a36Sopenharmony_cistatic u32 v_offset_default; /* For 32 MiB Aper size, 8 should be the default */
8062306a36Sopenharmony_cistatic u32 voffset;
8162306a36Sopenharmony_ci
8262306a36Sopenharmony_cistatic int i810fb_cursor(struct fb_info *info, struct fb_cursor *cursor);
8362306a36Sopenharmony_cistatic int i810fb_init_pci(struct pci_dev *dev,
8462306a36Sopenharmony_ci			   const struct pci_device_id *entry);
8562306a36Sopenharmony_cistatic void i810fb_remove_pci(struct pci_dev *dev);
8662306a36Sopenharmony_cistatic int i810fb_resume(struct pci_dev *dev);
8762306a36Sopenharmony_cistatic int i810fb_suspend(struct pci_dev *dev, pm_message_t state);
8862306a36Sopenharmony_ci
8962306a36Sopenharmony_ci/* Chipset Specific Functions */
9062306a36Sopenharmony_cistatic int i810fb_set_par    (struct fb_info *info);
9162306a36Sopenharmony_cistatic int i810fb_getcolreg  (u8 regno, u8 *red, u8 *green, u8 *blue,
9262306a36Sopenharmony_ci			      u8 *transp, struct fb_info *info);
9362306a36Sopenharmony_cistatic int i810fb_setcolreg  (unsigned regno, unsigned red, unsigned green, unsigned blue,
9462306a36Sopenharmony_ci			      unsigned transp, struct fb_info *info);
9562306a36Sopenharmony_cistatic int i810fb_pan_display(struct fb_var_screeninfo *var, struct fb_info *info);
9662306a36Sopenharmony_cistatic int i810fb_blank      (int blank_mode, struct fb_info *info);
9762306a36Sopenharmony_ci
9862306a36Sopenharmony_ci/* Initialization */
9962306a36Sopenharmony_cistatic void i810fb_release_resource       (struct fb_info *info, struct i810fb_par *par);
10062306a36Sopenharmony_ci
10162306a36Sopenharmony_ci/* PCI */
10262306a36Sopenharmony_cistatic const char * const i810_pci_list[] = {
10362306a36Sopenharmony_ci	"Intel(R) 810 Framebuffer Device"                                 ,
10462306a36Sopenharmony_ci	"Intel(R) 810-DC100 Framebuffer Device"                           ,
10562306a36Sopenharmony_ci	"Intel(R) 810E Framebuffer Device"                                ,
10662306a36Sopenharmony_ci	"Intel(R) 815 (Internal Graphics 100Mhz FSB) Framebuffer Device"  ,
10762306a36Sopenharmony_ci	"Intel(R) 815 (Internal Graphics only) Framebuffer Device"        ,
10862306a36Sopenharmony_ci	"Intel(R) 815 (Internal Graphics with AGP) Framebuffer Device"
10962306a36Sopenharmony_ci};
11062306a36Sopenharmony_ci
11162306a36Sopenharmony_cistatic const struct pci_device_id i810fb_pci_tbl[] = {
11262306a36Sopenharmony_ci	{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82810_IG1,
11362306a36Sopenharmony_ci	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
11462306a36Sopenharmony_ci	{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82810_IG3,
11562306a36Sopenharmony_ci	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 1  },
11662306a36Sopenharmony_ci	{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82810E_IG,
11762306a36Sopenharmony_ci	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 2 },
11862306a36Sopenharmony_ci	/* mvo: added i815 PCI-ID */
11962306a36Sopenharmony_ci	{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82815_100,
12062306a36Sopenharmony_ci	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 3 },
12162306a36Sopenharmony_ci	{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82815_NOAGP,
12262306a36Sopenharmony_ci	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 4 },
12362306a36Sopenharmony_ci	{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82815_CGC,
12462306a36Sopenharmony_ci	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 5 },
12562306a36Sopenharmony_ci	{ 0 },
12662306a36Sopenharmony_ci};
12762306a36Sopenharmony_ci
12862306a36Sopenharmony_cistatic struct pci_driver i810fb_driver = {
12962306a36Sopenharmony_ci	.name     =	"i810fb",
13062306a36Sopenharmony_ci	.id_table =	i810fb_pci_tbl,
13162306a36Sopenharmony_ci	.probe    =	i810fb_init_pci,
13262306a36Sopenharmony_ci	.remove   =	i810fb_remove_pci,
13362306a36Sopenharmony_ci	.suspend  =     i810fb_suspend,
13462306a36Sopenharmony_ci	.resume   =     i810fb_resume,
13562306a36Sopenharmony_ci};
13662306a36Sopenharmony_ci
13762306a36Sopenharmony_cistatic char *mode_option = NULL;
13862306a36Sopenharmony_cistatic int vram = 4;
13962306a36Sopenharmony_cistatic int bpp = 8;
14062306a36Sopenharmony_cistatic bool mtrr;
14162306a36Sopenharmony_cistatic bool accel;
14262306a36Sopenharmony_cistatic int hsync1;
14362306a36Sopenharmony_cistatic int hsync2;
14462306a36Sopenharmony_cistatic int vsync1;
14562306a36Sopenharmony_cistatic int vsync2;
14662306a36Sopenharmony_cistatic int xres;
14762306a36Sopenharmony_cistatic int yres;
14862306a36Sopenharmony_cistatic int vyres;
14962306a36Sopenharmony_cistatic bool sync;
15062306a36Sopenharmony_cistatic bool extvga;
15162306a36Sopenharmony_cistatic bool dcolor;
15262306a36Sopenharmony_cistatic bool ddc3;
15362306a36Sopenharmony_ci
15462306a36Sopenharmony_ci/*------------------------------------------------------------*/
15562306a36Sopenharmony_ci
15662306a36Sopenharmony_ci/**************************************************************
15762306a36Sopenharmony_ci *                Hardware Low Level Routines                 *
15862306a36Sopenharmony_ci **************************************************************/
15962306a36Sopenharmony_ci
16062306a36Sopenharmony_ci/**
16162306a36Sopenharmony_ci * i810_screen_off - turns off/on display
16262306a36Sopenharmony_ci * @mmio: address of register space
16362306a36Sopenharmony_ci * @mode: on or off
16462306a36Sopenharmony_ci *
16562306a36Sopenharmony_ci * DESCRIPTION:
16662306a36Sopenharmony_ci * Blanks/unblanks the display
16762306a36Sopenharmony_ci */
16862306a36Sopenharmony_cistatic void i810_screen_off(u8 __iomem *mmio, u8 mode)
16962306a36Sopenharmony_ci{
17062306a36Sopenharmony_ci	u32 count = WAIT_COUNT;
17162306a36Sopenharmony_ci	u8 val;
17262306a36Sopenharmony_ci
17362306a36Sopenharmony_ci	i810_writeb(SR_INDEX, mmio, SR01);
17462306a36Sopenharmony_ci	val = i810_readb(SR_DATA, mmio);
17562306a36Sopenharmony_ci	val = (mode == OFF) ? val | SCR_OFF :
17662306a36Sopenharmony_ci		val & ~SCR_OFF;
17762306a36Sopenharmony_ci
17862306a36Sopenharmony_ci	while((i810_readw(DISP_SL, mmio) & 0xFFF) && count--);
17962306a36Sopenharmony_ci	i810_writeb(SR_INDEX, mmio, SR01);
18062306a36Sopenharmony_ci	i810_writeb(SR_DATA, mmio, val);
18162306a36Sopenharmony_ci}
18262306a36Sopenharmony_ci
18362306a36Sopenharmony_ci/**
18462306a36Sopenharmony_ci * i810_dram_off - turns off/on dram refresh
18562306a36Sopenharmony_ci * @mmio: address of register space
18662306a36Sopenharmony_ci * @mode: on or off
18762306a36Sopenharmony_ci *
18862306a36Sopenharmony_ci * DESCRIPTION:
18962306a36Sopenharmony_ci * Turns off DRAM refresh.  Must be off for only 2 vsyncs
19062306a36Sopenharmony_ci * before data becomes corrupt
19162306a36Sopenharmony_ci */
19262306a36Sopenharmony_cistatic void i810_dram_off(u8 __iomem *mmio, u8 mode)
19362306a36Sopenharmony_ci{
19462306a36Sopenharmony_ci	u8 val;
19562306a36Sopenharmony_ci
19662306a36Sopenharmony_ci	val = i810_readb(DRAMCH, mmio);
19762306a36Sopenharmony_ci	val &= DRAM_OFF;
19862306a36Sopenharmony_ci	val = (mode == OFF) ? val : val | DRAM_ON;
19962306a36Sopenharmony_ci	i810_writeb(DRAMCH, mmio, val);
20062306a36Sopenharmony_ci}
20162306a36Sopenharmony_ci
20262306a36Sopenharmony_ci/**
20362306a36Sopenharmony_ci * i810_protect_regs - allows rw/ro mode of certain VGA registers
20462306a36Sopenharmony_ci * @mmio: address of register space
20562306a36Sopenharmony_ci * @mode: protect/unprotect
20662306a36Sopenharmony_ci *
20762306a36Sopenharmony_ci * DESCRIPTION:
20862306a36Sopenharmony_ci * The IBM VGA standard allows protection of certain VGA registers.
20962306a36Sopenharmony_ci * This will  protect or unprotect them.
21062306a36Sopenharmony_ci */
21162306a36Sopenharmony_cistatic void i810_protect_regs(u8 __iomem *mmio, int mode)
21262306a36Sopenharmony_ci{
21362306a36Sopenharmony_ci	u8 reg;
21462306a36Sopenharmony_ci
21562306a36Sopenharmony_ci	i810_writeb(CR_INDEX_CGA, mmio, CR11);
21662306a36Sopenharmony_ci	reg = i810_readb(CR_DATA_CGA, mmio);
21762306a36Sopenharmony_ci	reg = (mode == OFF) ? reg & ~0x80 :
21862306a36Sopenharmony_ci		reg | 0x80;
21962306a36Sopenharmony_ci
22062306a36Sopenharmony_ci	i810_writeb(CR_INDEX_CGA, mmio, CR11);
22162306a36Sopenharmony_ci	i810_writeb(CR_DATA_CGA, mmio, reg);
22262306a36Sopenharmony_ci}
22362306a36Sopenharmony_ci
22462306a36Sopenharmony_ci/**
22562306a36Sopenharmony_ci * i810_load_pll - loads values for the hardware PLL clock
22662306a36Sopenharmony_ci * @par: pointer to i810fb_par structure
22762306a36Sopenharmony_ci *
22862306a36Sopenharmony_ci * DESCRIPTION:
22962306a36Sopenharmony_ci * Loads the P, M, and N registers.
23062306a36Sopenharmony_ci */
23162306a36Sopenharmony_cistatic void i810_load_pll(struct i810fb_par *par)
23262306a36Sopenharmony_ci{
23362306a36Sopenharmony_ci	u32 tmp1, tmp2;
23462306a36Sopenharmony_ci	u8 __iomem *mmio = par->mmio_start_virtual;
23562306a36Sopenharmony_ci
23662306a36Sopenharmony_ci	tmp1 = par->regs.M | par->regs.N << 16;
23762306a36Sopenharmony_ci	tmp2 = i810_readl(DCLK_2D, mmio);
23862306a36Sopenharmony_ci	tmp2 &= ~MN_MASK;
23962306a36Sopenharmony_ci	i810_writel(DCLK_2D, mmio, tmp1 | tmp2);
24062306a36Sopenharmony_ci
24162306a36Sopenharmony_ci	tmp1 = par->regs.P;
24262306a36Sopenharmony_ci	tmp2 = i810_readl(DCLK_0DS, mmio);
24362306a36Sopenharmony_ci	tmp2 &= ~(P_OR << 16);
24462306a36Sopenharmony_ci	i810_writel(DCLK_0DS, mmio, (tmp1 << 16) | tmp2);
24562306a36Sopenharmony_ci
24662306a36Sopenharmony_ci	i810_writeb(MSR_WRITE, mmio, par->regs.msr | 0xC8 | 1);
24762306a36Sopenharmony_ci
24862306a36Sopenharmony_ci}
24962306a36Sopenharmony_ci
25062306a36Sopenharmony_ci/**
25162306a36Sopenharmony_ci * i810_load_vga - load standard VGA registers
25262306a36Sopenharmony_ci * @par: pointer to i810fb_par structure
25362306a36Sopenharmony_ci *
25462306a36Sopenharmony_ci * DESCRIPTION:
25562306a36Sopenharmony_ci * Load values to VGA registers
25662306a36Sopenharmony_ci */
25762306a36Sopenharmony_cistatic void i810_load_vga(struct i810fb_par *par)
25862306a36Sopenharmony_ci{
25962306a36Sopenharmony_ci	u8 __iomem *mmio = par->mmio_start_virtual;
26062306a36Sopenharmony_ci
26162306a36Sopenharmony_ci	/* interlace */
26262306a36Sopenharmony_ci	i810_writeb(CR_INDEX_CGA, mmio, CR70);
26362306a36Sopenharmony_ci	i810_writeb(CR_DATA_CGA, mmio, par->interlace);
26462306a36Sopenharmony_ci
26562306a36Sopenharmony_ci	i810_writeb(CR_INDEX_CGA, mmio, CR00);
26662306a36Sopenharmony_ci	i810_writeb(CR_DATA_CGA, mmio, par->regs.cr00);
26762306a36Sopenharmony_ci	i810_writeb(CR_INDEX_CGA, mmio, CR01);
26862306a36Sopenharmony_ci	i810_writeb(CR_DATA_CGA, mmio, par->regs.cr01);
26962306a36Sopenharmony_ci	i810_writeb(CR_INDEX_CGA, mmio, CR02);
27062306a36Sopenharmony_ci	i810_writeb(CR_DATA_CGA, mmio, par->regs.cr02);
27162306a36Sopenharmony_ci	i810_writeb(CR_INDEX_CGA, mmio, CR03);
27262306a36Sopenharmony_ci	i810_writeb(CR_DATA_CGA, mmio, par->regs.cr03);
27362306a36Sopenharmony_ci	i810_writeb(CR_INDEX_CGA, mmio, CR04);
27462306a36Sopenharmony_ci	i810_writeb(CR_DATA_CGA, mmio, par->regs.cr04);
27562306a36Sopenharmony_ci	i810_writeb(CR_INDEX_CGA, mmio, CR05);
27662306a36Sopenharmony_ci	i810_writeb(CR_DATA_CGA, mmio, par->regs.cr05);
27762306a36Sopenharmony_ci	i810_writeb(CR_INDEX_CGA, mmio, CR06);
27862306a36Sopenharmony_ci	i810_writeb(CR_DATA_CGA, mmio, par->regs.cr06);
27962306a36Sopenharmony_ci	i810_writeb(CR_INDEX_CGA, mmio, CR09);
28062306a36Sopenharmony_ci	i810_writeb(CR_DATA_CGA, mmio, par->regs.cr09);
28162306a36Sopenharmony_ci	i810_writeb(CR_INDEX_CGA, mmio, CR10);
28262306a36Sopenharmony_ci	i810_writeb(CR_DATA_CGA, mmio, par->regs.cr10);
28362306a36Sopenharmony_ci	i810_writeb(CR_INDEX_CGA, mmio, CR11);
28462306a36Sopenharmony_ci	i810_writeb(CR_DATA_CGA, mmio, par->regs.cr11);
28562306a36Sopenharmony_ci	i810_writeb(CR_INDEX_CGA, mmio, CR12);
28662306a36Sopenharmony_ci	i810_writeb(CR_DATA_CGA, mmio, par->regs.cr12);
28762306a36Sopenharmony_ci	i810_writeb(CR_INDEX_CGA, mmio, CR15);
28862306a36Sopenharmony_ci	i810_writeb(CR_DATA_CGA, mmio, par->regs.cr15);
28962306a36Sopenharmony_ci	i810_writeb(CR_INDEX_CGA, mmio, CR16);
29062306a36Sopenharmony_ci	i810_writeb(CR_DATA_CGA, mmio, par->regs.cr16);
29162306a36Sopenharmony_ci}
29262306a36Sopenharmony_ci
29362306a36Sopenharmony_ci/**
29462306a36Sopenharmony_ci * i810_load_vgax - load extended VGA registers
29562306a36Sopenharmony_ci * @par: pointer to i810fb_par structure
29662306a36Sopenharmony_ci *
29762306a36Sopenharmony_ci * DESCRIPTION:
29862306a36Sopenharmony_ci * Load values to extended VGA registers
29962306a36Sopenharmony_ci */
30062306a36Sopenharmony_cistatic void i810_load_vgax(struct i810fb_par *par)
30162306a36Sopenharmony_ci{
30262306a36Sopenharmony_ci	u8 __iomem *mmio = par->mmio_start_virtual;
30362306a36Sopenharmony_ci
30462306a36Sopenharmony_ci	i810_writeb(CR_INDEX_CGA, mmio, CR30);
30562306a36Sopenharmony_ci	i810_writeb(CR_DATA_CGA, mmio, par->regs.cr30);
30662306a36Sopenharmony_ci	i810_writeb(CR_INDEX_CGA, mmio, CR31);
30762306a36Sopenharmony_ci	i810_writeb(CR_DATA_CGA, mmio, par->regs.cr31);
30862306a36Sopenharmony_ci	i810_writeb(CR_INDEX_CGA, mmio, CR32);
30962306a36Sopenharmony_ci	i810_writeb(CR_DATA_CGA, mmio, par->regs.cr32);
31062306a36Sopenharmony_ci	i810_writeb(CR_INDEX_CGA, mmio, CR33);
31162306a36Sopenharmony_ci	i810_writeb(CR_DATA_CGA, mmio, par->regs.cr33);
31262306a36Sopenharmony_ci	i810_writeb(CR_INDEX_CGA, mmio, CR35);
31362306a36Sopenharmony_ci	i810_writeb(CR_DATA_CGA, mmio, par->regs.cr35);
31462306a36Sopenharmony_ci	i810_writeb(CR_INDEX_CGA, mmio, CR39);
31562306a36Sopenharmony_ci	i810_writeb(CR_DATA_CGA, mmio, par->regs.cr39);
31662306a36Sopenharmony_ci}
31762306a36Sopenharmony_ci
31862306a36Sopenharmony_ci/**
31962306a36Sopenharmony_ci * i810_load_2d - load grahics registers
32062306a36Sopenharmony_ci * @par: pointer to i810fb_par structure
32162306a36Sopenharmony_ci *
32262306a36Sopenharmony_ci * DESCRIPTION:
32362306a36Sopenharmony_ci * Load values to graphics registers
32462306a36Sopenharmony_ci */
32562306a36Sopenharmony_cistatic void i810_load_2d(struct i810fb_par *par)
32662306a36Sopenharmony_ci{
32762306a36Sopenharmony_ci	u32 tmp;
32862306a36Sopenharmony_ci	u8 tmp8;
32962306a36Sopenharmony_ci	u8 __iomem *mmio = par->mmio_start_virtual;
33062306a36Sopenharmony_ci
33162306a36Sopenharmony_ci  	i810_writel(FW_BLC, mmio, par->watermark);
33262306a36Sopenharmony_ci	tmp = i810_readl(PIXCONF, mmio);
33362306a36Sopenharmony_ci	tmp |= 1 | 1 << 20;
33462306a36Sopenharmony_ci	i810_writel(PIXCONF, mmio, tmp);
33562306a36Sopenharmony_ci
33662306a36Sopenharmony_ci	i810_writel(OVRACT, mmio, par->ovract);
33762306a36Sopenharmony_ci
33862306a36Sopenharmony_ci	i810_writeb(GR_INDEX, mmio, GR10);
33962306a36Sopenharmony_ci	tmp8 = i810_readb(GR_DATA, mmio);
34062306a36Sopenharmony_ci	tmp8 |= 2;
34162306a36Sopenharmony_ci	i810_writeb(GR_INDEX, mmio, GR10);
34262306a36Sopenharmony_ci	i810_writeb(GR_DATA, mmio, tmp8);
34362306a36Sopenharmony_ci}
34462306a36Sopenharmony_ci
34562306a36Sopenharmony_ci/**
34662306a36Sopenharmony_ci * i810_hires - enables high resolution mode
34762306a36Sopenharmony_ci * @mmio: address of register space
34862306a36Sopenharmony_ci */
34962306a36Sopenharmony_cistatic void i810_hires(u8 __iomem *mmio)
35062306a36Sopenharmony_ci{
35162306a36Sopenharmony_ci	u8 val;
35262306a36Sopenharmony_ci
35362306a36Sopenharmony_ci	i810_writeb(CR_INDEX_CGA, mmio, CR80);
35462306a36Sopenharmony_ci	val = i810_readb(CR_DATA_CGA, mmio);
35562306a36Sopenharmony_ci	i810_writeb(CR_INDEX_CGA, mmio, CR80);
35662306a36Sopenharmony_ci	i810_writeb(CR_DATA_CGA, mmio, val | 1);
35762306a36Sopenharmony_ci	/* Stop LCD displays from flickering */
35862306a36Sopenharmony_ci	i810_writel(MEM_MODE, mmio, i810_readl(MEM_MODE, mmio) | 4);
35962306a36Sopenharmony_ci}
36062306a36Sopenharmony_ci
36162306a36Sopenharmony_ci/**
36262306a36Sopenharmony_ci * i810_load_pitch - loads the characters per line of the display
36362306a36Sopenharmony_ci * @par: pointer to i810fb_par structure
36462306a36Sopenharmony_ci *
36562306a36Sopenharmony_ci * DESCRIPTION:
36662306a36Sopenharmony_ci * Loads the characters per line
36762306a36Sopenharmony_ci */
36862306a36Sopenharmony_cistatic void i810_load_pitch(struct i810fb_par *par)
36962306a36Sopenharmony_ci{
37062306a36Sopenharmony_ci	u32 tmp, pitch;
37162306a36Sopenharmony_ci	u8 val;
37262306a36Sopenharmony_ci	u8 __iomem *mmio = par->mmio_start_virtual;
37362306a36Sopenharmony_ci
37462306a36Sopenharmony_ci	pitch = par->pitch >> 3;
37562306a36Sopenharmony_ci	i810_writeb(SR_INDEX, mmio, SR01);
37662306a36Sopenharmony_ci	val = i810_readb(SR_DATA, mmio);
37762306a36Sopenharmony_ci	val &= 0xE0;
37862306a36Sopenharmony_ci	val |= 1 | 1 << 2;
37962306a36Sopenharmony_ci	i810_writeb(SR_INDEX, mmio, SR01);
38062306a36Sopenharmony_ci	i810_writeb(SR_DATA, mmio, val);
38162306a36Sopenharmony_ci
38262306a36Sopenharmony_ci	tmp = pitch & 0xFF;
38362306a36Sopenharmony_ci	i810_writeb(CR_INDEX_CGA, mmio, CR13);
38462306a36Sopenharmony_ci	i810_writeb(CR_DATA_CGA, mmio, (u8) tmp);
38562306a36Sopenharmony_ci
38662306a36Sopenharmony_ci	tmp = pitch >> 8;
38762306a36Sopenharmony_ci	i810_writeb(CR_INDEX_CGA, mmio, CR41);
38862306a36Sopenharmony_ci	val = i810_readb(CR_DATA_CGA, mmio) & ~0x0F;
38962306a36Sopenharmony_ci	i810_writeb(CR_INDEX_CGA, mmio, CR41);
39062306a36Sopenharmony_ci	i810_writeb(CR_DATA_CGA, mmio, (u8) tmp | val);
39162306a36Sopenharmony_ci}
39262306a36Sopenharmony_ci
39362306a36Sopenharmony_ci/**
39462306a36Sopenharmony_ci * i810_load_color - loads the color depth of the display
39562306a36Sopenharmony_ci * @par: pointer to i810fb_par structure
39662306a36Sopenharmony_ci *
39762306a36Sopenharmony_ci * DESCRIPTION:
39862306a36Sopenharmony_ci * Loads the color depth of the display and the graphics engine
39962306a36Sopenharmony_ci */
40062306a36Sopenharmony_cistatic void i810_load_color(struct i810fb_par *par)
40162306a36Sopenharmony_ci{
40262306a36Sopenharmony_ci	u8 __iomem *mmio = par->mmio_start_virtual;
40362306a36Sopenharmony_ci	u32 reg1;
40462306a36Sopenharmony_ci	u16 reg2;
40562306a36Sopenharmony_ci
40662306a36Sopenharmony_ci	reg1 = i810_readl(PIXCONF, mmio) & ~(0xF0000 | 1 << 27);
40762306a36Sopenharmony_ci	reg2 = i810_readw(BLTCNTL, mmio) & ~0x30;
40862306a36Sopenharmony_ci
40962306a36Sopenharmony_ci	reg1 |= 0x8000 | par->pixconf;
41062306a36Sopenharmony_ci	reg2 |= par->bltcntl;
41162306a36Sopenharmony_ci	i810_writel(PIXCONF, mmio, reg1);
41262306a36Sopenharmony_ci	i810_writew(BLTCNTL, mmio, reg2);
41362306a36Sopenharmony_ci}
41462306a36Sopenharmony_ci
41562306a36Sopenharmony_ci/**
41662306a36Sopenharmony_ci * i810_load_regs - loads all registers for the mode
41762306a36Sopenharmony_ci * @par: pointer to i810fb_par structure
41862306a36Sopenharmony_ci *
41962306a36Sopenharmony_ci * DESCRIPTION:
42062306a36Sopenharmony_ci * Loads registers
42162306a36Sopenharmony_ci */
42262306a36Sopenharmony_cistatic void i810_load_regs(struct i810fb_par *par)
42362306a36Sopenharmony_ci{
42462306a36Sopenharmony_ci	u8 __iomem *mmio = par->mmio_start_virtual;
42562306a36Sopenharmony_ci
42662306a36Sopenharmony_ci	i810_screen_off(mmio, OFF);
42762306a36Sopenharmony_ci	i810_protect_regs(mmio, OFF);
42862306a36Sopenharmony_ci	i810_dram_off(mmio, OFF);
42962306a36Sopenharmony_ci	i810_load_pll(par);
43062306a36Sopenharmony_ci	i810_load_vga(par);
43162306a36Sopenharmony_ci	i810_load_vgax(par);
43262306a36Sopenharmony_ci	i810_dram_off(mmio, ON);
43362306a36Sopenharmony_ci	i810_load_2d(par);
43462306a36Sopenharmony_ci	i810_hires(mmio);
43562306a36Sopenharmony_ci	i810_screen_off(mmio, ON);
43662306a36Sopenharmony_ci	i810_protect_regs(mmio, ON);
43762306a36Sopenharmony_ci	i810_load_color(par);
43862306a36Sopenharmony_ci	i810_load_pitch(par);
43962306a36Sopenharmony_ci}
44062306a36Sopenharmony_ci
44162306a36Sopenharmony_cistatic void i810_write_dac(u8 regno, u8 red, u8 green, u8 blue,
44262306a36Sopenharmony_ci			  u8 __iomem *mmio)
44362306a36Sopenharmony_ci{
44462306a36Sopenharmony_ci	i810_writeb(CLUT_INDEX_WRITE, mmio, regno);
44562306a36Sopenharmony_ci	i810_writeb(CLUT_DATA, mmio, red);
44662306a36Sopenharmony_ci	i810_writeb(CLUT_DATA, mmio, green);
44762306a36Sopenharmony_ci	i810_writeb(CLUT_DATA, mmio, blue);
44862306a36Sopenharmony_ci}
44962306a36Sopenharmony_ci
45062306a36Sopenharmony_cistatic void i810_read_dac(u8 regno, u8 *red, u8 *green, u8 *blue,
45162306a36Sopenharmony_ci			  u8 __iomem *mmio)
45262306a36Sopenharmony_ci{
45362306a36Sopenharmony_ci	i810_writeb(CLUT_INDEX_READ, mmio, regno);
45462306a36Sopenharmony_ci	*red = i810_readb(CLUT_DATA, mmio);
45562306a36Sopenharmony_ci	*green = i810_readb(CLUT_DATA, mmio);
45662306a36Sopenharmony_ci	*blue = i810_readb(CLUT_DATA, mmio);
45762306a36Sopenharmony_ci}
45862306a36Sopenharmony_ci
45962306a36Sopenharmony_ci/************************************************************
46062306a36Sopenharmony_ci *                   VGA State Restore                      *
46162306a36Sopenharmony_ci ************************************************************/
46262306a36Sopenharmony_cistatic void i810_restore_pll(struct i810fb_par *par)
46362306a36Sopenharmony_ci{
46462306a36Sopenharmony_ci	u32 tmp1, tmp2;
46562306a36Sopenharmony_ci	u8 __iomem *mmio = par->mmio_start_virtual;
46662306a36Sopenharmony_ci
46762306a36Sopenharmony_ci	tmp1 = par->hw_state.dclk_2d;
46862306a36Sopenharmony_ci	tmp2 = i810_readl(DCLK_2D, mmio);
46962306a36Sopenharmony_ci	tmp1 &= ~MN_MASK;
47062306a36Sopenharmony_ci	tmp2 &= MN_MASK;
47162306a36Sopenharmony_ci	i810_writel(DCLK_2D, mmio, tmp1 | tmp2);
47262306a36Sopenharmony_ci
47362306a36Sopenharmony_ci	tmp1 = par->hw_state.dclk_1d;
47462306a36Sopenharmony_ci	tmp2 = i810_readl(DCLK_1D, mmio);
47562306a36Sopenharmony_ci	tmp1 &= ~MN_MASK;
47662306a36Sopenharmony_ci	tmp2 &= MN_MASK;
47762306a36Sopenharmony_ci	i810_writel(DCLK_1D, mmio, tmp1 | tmp2);
47862306a36Sopenharmony_ci
47962306a36Sopenharmony_ci	i810_writel(DCLK_0DS, mmio, par->hw_state.dclk_0ds);
48062306a36Sopenharmony_ci}
48162306a36Sopenharmony_ci
48262306a36Sopenharmony_cistatic void i810_restore_dac(struct i810fb_par *par)
48362306a36Sopenharmony_ci{
48462306a36Sopenharmony_ci	u32 tmp1, tmp2;
48562306a36Sopenharmony_ci	u8 __iomem *mmio = par->mmio_start_virtual;
48662306a36Sopenharmony_ci
48762306a36Sopenharmony_ci	tmp1 = par->hw_state.pixconf;
48862306a36Sopenharmony_ci	tmp2 = i810_readl(PIXCONF, mmio);
48962306a36Sopenharmony_ci	tmp1 &= DAC_BIT;
49062306a36Sopenharmony_ci	tmp2 &= ~DAC_BIT;
49162306a36Sopenharmony_ci	i810_writel(PIXCONF, mmio, tmp1 | tmp2);
49262306a36Sopenharmony_ci}
49362306a36Sopenharmony_ci
49462306a36Sopenharmony_cistatic void i810_restore_vgax(struct i810fb_par *par)
49562306a36Sopenharmony_ci{
49662306a36Sopenharmony_ci	u8 i, j;
49762306a36Sopenharmony_ci	u8 __iomem *mmio = par->mmio_start_virtual;
49862306a36Sopenharmony_ci
49962306a36Sopenharmony_ci	for (i = 0; i < 4; i++) {
50062306a36Sopenharmony_ci		i810_writeb(CR_INDEX_CGA, mmio, CR30+i);
50162306a36Sopenharmony_ci		i810_writeb(CR_DATA_CGA, mmio, *(&(par->hw_state.cr30) + i));
50262306a36Sopenharmony_ci	}
50362306a36Sopenharmony_ci	i810_writeb(CR_INDEX_CGA, mmio, CR35);
50462306a36Sopenharmony_ci	i810_writeb(CR_DATA_CGA, mmio, par->hw_state.cr35);
50562306a36Sopenharmony_ci	i810_writeb(CR_INDEX_CGA, mmio, CR39);
50662306a36Sopenharmony_ci	i810_writeb(CR_DATA_CGA, mmio, par->hw_state.cr39);
50762306a36Sopenharmony_ci	i810_writeb(CR_INDEX_CGA, mmio, CR41);
50862306a36Sopenharmony_ci	i810_writeb(CR_DATA_CGA, mmio, par->hw_state.cr39);
50962306a36Sopenharmony_ci
51062306a36Sopenharmony_ci	/*restore interlace*/
51162306a36Sopenharmony_ci	i810_writeb(CR_INDEX_CGA, mmio, CR70);
51262306a36Sopenharmony_ci	i = par->hw_state.cr70;
51362306a36Sopenharmony_ci	i &= INTERLACE_BIT;
51462306a36Sopenharmony_ci	j = i810_readb(CR_DATA_CGA, mmio);
51562306a36Sopenharmony_ci	i810_writeb(CR_INDEX_CGA, mmio, CR70);
51662306a36Sopenharmony_ci	i810_writeb(CR_DATA_CGA, mmio, j | i);
51762306a36Sopenharmony_ci
51862306a36Sopenharmony_ci	i810_writeb(CR_INDEX_CGA, mmio, CR80);
51962306a36Sopenharmony_ci	i810_writeb(CR_DATA_CGA, mmio, par->hw_state.cr80);
52062306a36Sopenharmony_ci	i810_writeb(MSR_WRITE, mmio, par->hw_state.msr);
52162306a36Sopenharmony_ci	i810_writeb(SR_INDEX, mmio, SR01);
52262306a36Sopenharmony_ci	i = (par->hw_state.sr01) & ~0xE0 ;
52362306a36Sopenharmony_ci	j = i810_readb(SR_DATA, mmio) & 0xE0;
52462306a36Sopenharmony_ci	i810_writeb(SR_INDEX, mmio, SR01);
52562306a36Sopenharmony_ci	i810_writeb(SR_DATA, mmio, i | j);
52662306a36Sopenharmony_ci}
52762306a36Sopenharmony_ci
52862306a36Sopenharmony_cistatic void i810_restore_vga(struct i810fb_par *par)
52962306a36Sopenharmony_ci{
53062306a36Sopenharmony_ci	u8 i;
53162306a36Sopenharmony_ci	u8 __iomem *mmio = par->mmio_start_virtual;
53262306a36Sopenharmony_ci
53362306a36Sopenharmony_ci	for (i = 0; i < 10; i++) {
53462306a36Sopenharmony_ci		i810_writeb(CR_INDEX_CGA, mmio, CR00 + i);
53562306a36Sopenharmony_ci		i810_writeb(CR_DATA_CGA, mmio, *((&par->hw_state.cr00) + i));
53662306a36Sopenharmony_ci	}
53762306a36Sopenharmony_ci	for (i = 0; i < 8; i++) {
53862306a36Sopenharmony_ci		i810_writeb(CR_INDEX_CGA, mmio, CR10 + i);
53962306a36Sopenharmony_ci		i810_writeb(CR_DATA_CGA, mmio, *((&par->hw_state.cr10) + i));
54062306a36Sopenharmony_ci	}
54162306a36Sopenharmony_ci}
54262306a36Sopenharmony_ci
54362306a36Sopenharmony_cistatic void i810_restore_addr_map(struct i810fb_par *par)
54462306a36Sopenharmony_ci{
54562306a36Sopenharmony_ci	u8 tmp;
54662306a36Sopenharmony_ci	u8 __iomem *mmio = par->mmio_start_virtual;
54762306a36Sopenharmony_ci
54862306a36Sopenharmony_ci	i810_writeb(GR_INDEX, mmio, GR10);
54962306a36Sopenharmony_ci	tmp = i810_readb(GR_DATA, mmio);
55062306a36Sopenharmony_ci	tmp &= ADDR_MAP_MASK;
55162306a36Sopenharmony_ci	tmp |= par->hw_state.gr10;
55262306a36Sopenharmony_ci	i810_writeb(GR_INDEX, mmio, GR10);
55362306a36Sopenharmony_ci	i810_writeb(GR_DATA, mmio, tmp);
55462306a36Sopenharmony_ci}
55562306a36Sopenharmony_ci
55662306a36Sopenharmony_cistatic void i810_restore_2d(struct i810fb_par *par)
55762306a36Sopenharmony_ci{
55862306a36Sopenharmony_ci	u32 tmp_long;
55962306a36Sopenharmony_ci	u16 tmp_word;
56062306a36Sopenharmony_ci	u8 __iomem *mmio = par->mmio_start_virtual;
56162306a36Sopenharmony_ci
56262306a36Sopenharmony_ci	tmp_word = i810_readw(BLTCNTL, mmio);
56362306a36Sopenharmony_ci	tmp_word &= ~(3 << 4);
56462306a36Sopenharmony_ci	tmp_word |= par->hw_state.bltcntl;
56562306a36Sopenharmony_ci	i810_writew(BLTCNTL, mmio, tmp_word);
56662306a36Sopenharmony_ci
56762306a36Sopenharmony_ci	i810_dram_off(mmio, OFF);
56862306a36Sopenharmony_ci	i810_writel(PIXCONF, mmio, par->hw_state.pixconf);
56962306a36Sopenharmony_ci	i810_dram_off(mmio, ON);
57062306a36Sopenharmony_ci
57162306a36Sopenharmony_ci	tmp_word = i810_readw(HWSTAM, mmio);
57262306a36Sopenharmony_ci	tmp_word &= 3 << 13;
57362306a36Sopenharmony_ci	tmp_word |= par->hw_state.hwstam;
57462306a36Sopenharmony_ci	i810_writew(HWSTAM, mmio, tmp_word);
57562306a36Sopenharmony_ci
57662306a36Sopenharmony_ci	tmp_long = i810_readl(FW_BLC, mmio);
57762306a36Sopenharmony_ci	tmp_long &= FW_BLC_MASK;
57862306a36Sopenharmony_ci	tmp_long |= par->hw_state.fw_blc;
57962306a36Sopenharmony_ci	i810_writel(FW_BLC, mmio, tmp_long);
58062306a36Sopenharmony_ci
58162306a36Sopenharmony_ci	i810_writel(HWS_PGA, mmio, par->hw_state.hws_pga);
58262306a36Sopenharmony_ci	i810_writew(IER, mmio, par->hw_state.ier);
58362306a36Sopenharmony_ci	i810_writew(IMR, mmio, par->hw_state.imr);
58462306a36Sopenharmony_ci	i810_writel(DPLYSTAS, mmio, par->hw_state.dplystas);
58562306a36Sopenharmony_ci}
58662306a36Sopenharmony_ci
58762306a36Sopenharmony_cistatic void i810_restore_vga_state(struct i810fb_par *par)
58862306a36Sopenharmony_ci{
58962306a36Sopenharmony_ci	u8 __iomem *mmio = par->mmio_start_virtual;
59062306a36Sopenharmony_ci
59162306a36Sopenharmony_ci	i810_screen_off(mmio, OFF);
59262306a36Sopenharmony_ci	i810_protect_regs(mmio, OFF);
59362306a36Sopenharmony_ci	i810_dram_off(mmio, OFF);
59462306a36Sopenharmony_ci	i810_restore_pll(par);
59562306a36Sopenharmony_ci	i810_restore_dac(par);
59662306a36Sopenharmony_ci	i810_restore_vga(par);
59762306a36Sopenharmony_ci	i810_restore_vgax(par);
59862306a36Sopenharmony_ci	i810_restore_addr_map(par);
59962306a36Sopenharmony_ci	i810_dram_off(mmio, ON);
60062306a36Sopenharmony_ci	i810_restore_2d(par);
60162306a36Sopenharmony_ci	i810_screen_off(mmio, ON);
60262306a36Sopenharmony_ci	i810_protect_regs(mmio, ON);
60362306a36Sopenharmony_ci}
60462306a36Sopenharmony_ci
60562306a36Sopenharmony_ci/***********************************************************************
60662306a36Sopenharmony_ci *                         VGA State Save                              *
60762306a36Sopenharmony_ci ***********************************************************************/
60862306a36Sopenharmony_ci
60962306a36Sopenharmony_cistatic void i810_save_vgax(struct i810fb_par *par)
61062306a36Sopenharmony_ci{
61162306a36Sopenharmony_ci	u8 i;
61262306a36Sopenharmony_ci	u8 __iomem *mmio = par->mmio_start_virtual;
61362306a36Sopenharmony_ci
61462306a36Sopenharmony_ci	for (i = 0; i < 4; i++) {
61562306a36Sopenharmony_ci		i810_writeb(CR_INDEX_CGA, mmio, CR30 + i);
61662306a36Sopenharmony_ci		*(&(par->hw_state.cr30) + i) = i810_readb(CR_DATA_CGA, mmio);
61762306a36Sopenharmony_ci	}
61862306a36Sopenharmony_ci	i810_writeb(CR_INDEX_CGA, mmio, CR35);
61962306a36Sopenharmony_ci	par->hw_state.cr35 = i810_readb(CR_DATA_CGA, mmio);
62062306a36Sopenharmony_ci	i810_writeb(CR_INDEX_CGA, mmio, CR39);
62162306a36Sopenharmony_ci	par->hw_state.cr39 = i810_readb(CR_DATA_CGA, mmio);
62262306a36Sopenharmony_ci	i810_writeb(CR_INDEX_CGA, mmio, CR41);
62362306a36Sopenharmony_ci	par->hw_state.cr41 = i810_readb(CR_DATA_CGA, mmio);
62462306a36Sopenharmony_ci	i810_writeb(CR_INDEX_CGA, mmio, CR70);
62562306a36Sopenharmony_ci	par->hw_state.cr70 = i810_readb(CR_DATA_CGA, mmio);
62662306a36Sopenharmony_ci	par->hw_state.msr = i810_readb(MSR_READ, mmio);
62762306a36Sopenharmony_ci	i810_writeb(CR_INDEX_CGA, mmio, CR80);
62862306a36Sopenharmony_ci	par->hw_state.cr80 = i810_readb(CR_DATA_CGA, mmio);
62962306a36Sopenharmony_ci	i810_writeb(SR_INDEX, mmio, SR01);
63062306a36Sopenharmony_ci	par->hw_state.sr01 = i810_readb(SR_DATA, mmio);
63162306a36Sopenharmony_ci}
63262306a36Sopenharmony_ci
63362306a36Sopenharmony_cistatic void i810_save_vga(struct i810fb_par *par)
63462306a36Sopenharmony_ci{
63562306a36Sopenharmony_ci	u8 i;
63662306a36Sopenharmony_ci	u8 __iomem *mmio = par->mmio_start_virtual;
63762306a36Sopenharmony_ci
63862306a36Sopenharmony_ci	for (i = 0; i < 10; i++) {
63962306a36Sopenharmony_ci		i810_writeb(CR_INDEX_CGA, mmio, CR00 + i);
64062306a36Sopenharmony_ci		*((&par->hw_state.cr00) + i) = i810_readb(CR_DATA_CGA, mmio);
64162306a36Sopenharmony_ci	}
64262306a36Sopenharmony_ci	for (i = 0; i < 8; i++) {
64362306a36Sopenharmony_ci		i810_writeb(CR_INDEX_CGA, mmio, CR10 + i);
64462306a36Sopenharmony_ci		*((&par->hw_state.cr10) + i) = i810_readb(CR_DATA_CGA, mmio);
64562306a36Sopenharmony_ci	}
64662306a36Sopenharmony_ci}
64762306a36Sopenharmony_ci
64862306a36Sopenharmony_cistatic void i810_save_2d(struct i810fb_par *par)
64962306a36Sopenharmony_ci{
65062306a36Sopenharmony_ci	u8 __iomem *mmio = par->mmio_start_virtual;
65162306a36Sopenharmony_ci
65262306a36Sopenharmony_ci	par->hw_state.dclk_2d = i810_readl(DCLK_2D, mmio);
65362306a36Sopenharmony_ci	par->hw_state.dclk_1d = i810_readl(DCLK_1D, mmio);
65462306a36Sopenharmony_ci	par->hw_state.dclk_0ds = i810_readl(DCLK_0DS, mmio);
65562306a36Sopenharmony_ci	par->hw_state.pixconf = i810_readl(PIXCONF, mmio);
65662306a36Sopenharmony_ci	par->hw_state.fw_blc = i810_readl(FW_BLC, mmio);
65762306a36Sopenharmony_ci	par->hw_state.bltcntl = i810_readw(BLTCNTL, mmio);
65862306a36Sopenharmony_ci	par->hw_state.hwstam = i810_readw(HWSTAM, mmio);
65962306a36Sopenharmony_ci	par->hw_state.hws_pga = i810_readl(HWS_PGA, mmio);
66062306a36Sopenharmony_ci	par->hw_state.ier = i810_readw(IER, mmio);
66162306a36Sopenharmony_ci	par->hw_state.imr = i810_readw(IMR, mmio);
66262306a36Sopenharmony_ci	par->hw_state.dplystas = i810_readl(DPLYSTAS, mmio);
66362306a36Sopenharmony_ci}
66462306a36Sopenharmony_ci
66562306a36Sopenharmony_cistatic void i810_save_vga_state(struct i810fb_par *par)
66662306a36Sopenharmony_ci{
66762306a36Sopenharmony_ci	i810_save_vga(par);
66862306a36Sopenharmony_ci	i810_save_vgax(par);
66962306a36Sopenharmony_ci	i810_save_2d(par);
67062306a36Sopenharmony_ci}
67162306a36Sopenharmony_ci
67262306a36Sopenharmony_ci/************************************************************
67362306a36Sopenharmony_ci *                    Helpers                               *
67462306a36Sopenharmony_ci ************************************************************/
67562306a36Sopenharmony_ci/**
67662306a36Sopenharmony_ci * get_line_length - calculates buffer pitch in bytes
67762306a36Sopenharmony_ci * @par: pointer to i810fb_par structure
67862306a36Sopenharmony_ci * @xres_virtual: virtual resolution of the frame
67962306a36Sopenharmony_ci * @bpp: bits per pixel
68062306a36Sopenharmony_ci *
68162306a36Sopenharmony_ci * DESCRIPTION:
68262306a36Sopenharmony_ci * Calculates buffer pitch in bytes.
68362306a36Sopenharmony_ci */
68462306a36Sopenharmony_cistatic u32 get_line_length(struct i810fb_par *par, int xres_virtual, int bpp)
68562306a36Sopenharmony_ci{
68662306a36Sopenharmony_ci   	u32 length;
68762306a36Sopenharmony_ci
68862306a36Sopenharmony_ci	length = xres_virtual*bpp;
68962306a36Sopenharmony_ci	length = (length+31)&-32;
69062306a36Sopenharmony_ci	length >>= 3;
69162306a36Sopenharmony_ci	return length;
69262306a36Sopenharmony_ci}
69362306a36Sopenharmony_ci
69462306a36Sopenharmony_ci/**
69562306a36Sopenharmony_ci * i810_calc_dclk - calculates the P, M, and N values of a pixelclock value
69662306a36Sopenharmony_ci * @freq: target pixelclock in picoseconds
69762306a36Sopenharmony_ci * @m: where to write M register
69862306a36Sopenharmony_ci * @n: where to write N register
69962306a36Sopenharmony_ci * @p: where to write P register
70062306a36Sopenharmony_ci *
70162306a36Sopenharmony_ci * DESCRIPTION:
70262306a36Sopenharmony_ci * Based on the formula Freq_actual = (4*M*Freq_ref)/(N^P)
70362306a36Sopenharmony_ci * Repeatedly computes the Freq until the actual Freq is equal to
70462306a36Sopenharmony_ci * the target Freq or until the loop count is zero.  In the latter
70562306a36Sopenharmony_ci * case, the actual frequency nearest the target will be used.
70662306a36Sopenharmony_ci */
70762306a36Sopenharmony_cistatic void i810_calc_dclk(u32 freq, u32 *m, u32 *n, u32 *p)
70862306a36Sopenharmony_ci{
70962306a36Sopenharmony_ci	u32 m_reg, n_reg, p_divisor, n_target_max;
71062306a36Sopenharmony_ci	u32 m_target, n_target, p_target, n_best, m_best, mod;
71162306a36Sopenharmony_ci	u32 f_out, target_freq, diff = 0, mod_min, diff_min;
71262306a36Sopenharmony_ci
71362306a36Sopenharmony_ci	diff_min = mod_min = 0xFFFFFFFF;
71462306a36Sopenharmony_ci	n_best = m_best = m_target = f_out = 0;
71562306a36Sopenharmony_ci
71662306a36Sopenharmony_ci	target_freq =  freq;
71762306a36Sopenharmony_ci	n_target_max = 30;
71862306a36Sopenharmony_ci
71962306a36Sopenharmony_ci	/*
72062306a36Sopenharmony_ci	 * find P such that target freq is 16x reference freq (Hz).
72162306a36Sopenharmony_ci	 */
72262306a36Sopenharmony_ci	p_divisor = 1;
72362306a36Sopenharmony_ci	p_target = 0;
72462306a36Sopenharmony_ci	while(!((1000000 * p_divisor)/(16 * 24 * target_freq)) &&
72562306a36Sopenharmony_ci	      p_divisor <= 32) {
72662306a36Sopenharmony_ci		p_divisor <<= 1;
72762306a36Sopenharmony_ci		p_target++;
72862306a36Sopenharmony_ci	}
72962306a36Sopenharmony_ci
73062306a36Sopenharmony_ci	n_reg = m_reg = n_target = 3;
73162306a36Sopenharmony_ci	while (diff_min && mod_min && (n_target < n_target_max)) {
73262306a36Sopenharmony_ci		f_out = (p_divisor * n_reg * 1000000)/(4 * 24 * m_reg);
73362306a36Sopenharmony_ci		mod = (p_divisor * n_reg * 1000000) % (4 * 24 * m_reg);
73462306a36Sopenharmony_ci		m_target = m_reg;
73562306a36Sopenharmony_ci		n_target = n_reg;
73662306a36Sopenharmony_ci		if (f_out <= target_freq) {
73762306a36Sopenharmony_ci			n_reg++;
73862306a36Sopenharmony_ci			diff = target_freq - f_out;
73962306a36Sopenharmony_ci		} else {
74062306a36Sopenharmony_ci			m_reg++;
74162306a36Sopenharmony_ci			diff = f_out - target_freq;
74262306a36Sopenharmony_ci		}
74362306a36Sopenharmony_ci
74462306a36Sopenharmony_ci		if (diff_min > diff) {
74562306a36Sopenharmony_ci			diff_min = diff;
74662306a36Sopenharmony_ci			n_best = n_target;
74762306a36Sopenharmony_ci			m_best = m_target;
74862306a36Sopenharmony_ci		}
74962306a36Sopenharmony_ci
75062306a36Sopenharmony_ci		if (!diff && mod_min > mod) {
75162306a36Sopenharmony_ci			mod_min = mod;
75262306a36Sopenharmony_ci			n_best = n_target;
75362306a36Sopenharmony_ci			m_best = m_target;
75462306a36Sopenharmony_ci		}
75562306a36Sopenharmony_ci	}
75662306a36Sopenharmony_ci	if (m) *m = (m_best - 2) & 0x3FF;
75762306a36Sopenharmony_ci	if (n) *n = (n_best - 2) & 0x3FF;
75862306a36Sopenharmony_ci	if (p) *p = (p_target << 4);
75962306a36Sopenharmony_ci}
76062306a36Sopenharmony_ci
76162306a36Sopenharmony_ci/*************************************************************
76262306a36Sopenharmony_ci *                Hardware Cursor Routines                   *
76362306a36Sopenharmony_ci *************************************************************/
76462306a36Sopenharmony_ci
76562306a36Sopenharmony_ci/**
76662306a36Sopenharmony_ci * i810_enable_cursor - show or hide the hardware cursor
76762306a36Sopenharmony_ci * @mmio: address of register space
76862306a36Sopenharmony_ci * @mode: show (1) or hide (0)
76962306a36Sopenharmony_ci *
77062306a36Sopenharmony_ci * Description:
77162306a36Sopenharmony_ci * Shows or hides the hardware cursor
77262306a36Sopenharmony_ci */
77362306a36Sopenharmony_cistatic void i810_enable_cursor(u8 __iomem *mmio, int mode)
77462306a36Sopenharmony_ci{
77562306a36Sopenharmony_ci	u32 temp;
77662306a36Sopenharmony_ci
77762306a36Sopenharmony_ci	temp = i810_readl(PIXCONF, mmio);
77862306a36Sopenharmony_ci	temp = (mode == ON) ? temp | CURSOR_ENABLE_MASK :
77962306a36Sopenharmony_ci		temp & ~CURSOR_ENABLE_MASK;
78062306a36Sopenharmony_ci
78162306a36Sopenharmony_ci	i810_writel(PIXCONF, mmio, temp);
78262306a36Sopenharmony_ci}
78362306a36Sopenharmony_ci
78462306a36Sopenharmony_cistatic void i810_reset_cursor_image(struct i810fb_par *par)
78562306a36Sopenharmony_ci{
78662306a36Sopenharmony_ci	u8 __iomem *addr = par->cursor_heap.virtual;
78762306a36Sopenharmony_ci	int i, j;
78862306a36Sopenharmony_ci
78962306a36Sopenharmony_ci	for (i = 64; i--; ) {
79062306a36Sopenharmony_ci		for (j = 0; j < 8; j++) {
79162306a36Sopenharmony_ci			i810_writeb(j, addr, 0xff);
79262306a36Sopenharmony_ci			i810_writeb(j+8, addr, 0x00);
79362306a36Sopenharmony_ci		}
79462306a36Sopenharmony_ci		addr +=16;
79562306a36Sopenharmony_ci	}
79662306a36Sopenharmony_ci}
79762306a36Sopenharmony_ci
79862306a36Sopenharmony_cistatic void i810_load_cursor_image(int width, int height, u8 *data,
79962306a36Sopenharmony_ci				   struct i810fb_par *par)
80062306a36Sopenharmony_ci{
80162306a36Sopenharmony_ci	u8 __iomem *addr = par->cursor_heap.virtual;
80262306a36Sopenharmony_ci	int i, j, w = width/8;
80362306a36Sopenharmony_ci	int mod = width % 8, t_mask, d_mask;
80462306a36Sopenharmony_ci
80562306a36Sopenharmony_ci	t_mask = 0xff >> mod;
80662306a36Sopenharmony_ci	d_mask = ~(0xff >> mod);
80762306a36Sopenharmony_ci	for (i = height; i--; ) {
80862306a36Sopenharmony_ci		for (j = 0; j < w; j++) {
80962306a36Sopenharmony_ci			i810_writeb(j+0, addr, 0x00);
81062306a36Sopenharmony_ci			i810_writeb(j+8, addr, *data++);
81162306a36Sopenharmony_ci		}
81262306a36Sopenharmony_ci		if (mod) {
81362306a36Sopenharmony_ci			i810_writeb(j+0, addr, t_mask);
81462306a36Sopenharmony_ci			i810_writeb(j+8, addr, *data++ & d_mask);
81562306a36Sopenharmony_ci		}
81662306a36Sopenharmony_ci		addr += 16;
81762306a36Sopenharmony_ci	}
81862306a36Sopenharmony_ci}
81962306a36Sopenharmony_ci
82062306a36Sopenharmony_cistatic void i810_load_cursor_colors(int fg, int bg, struct fb_info *info)
82162306a36Sopenharmony_ci{
82262306a36Sopenharmony_ci	struct i810fb_par *par = info->par;
82362306a36Sopenharmony_ci	u8 __iomem *mmio = par->mmio_start_virtual;
82462306a36Sopenharmony_ci	u8 red, green, blue, trans, temp;
82562306a36Sopenharmony_ci
82662306a36Sopenharmony_ci	i810fb_getcolreg(bg, &red, &green, &blue, &trans, info);
82762306a36Sopenharmony_ci
82862306a36Sopenharmony_ci	temp = i810_readb(PIXCONF1, mmio);
82962306a36Sopenharmony_ci	i810_writeb(PIXCONF1, mmio, temp | EXTENDED_PALETTE);
83062306a36Sopenharmony_ci
83162306a36Sopenharmony_ci	i810_write_dac(4, red, green, blue, mmio);
83262306a36Sopenharmony_ci
83362306a36Sopenharmony_ci	i810_writeb(PIXCONF1, mmio, temp);
83462306a36Sopenharmony_ci
83562306a36Sopenharmony_ci	i810fb_getcolreg(fg, &red, &green, &blue, &trans, info);
83662306a36Sopenharmony_ci	temp = i810_readb(PIXCONF1, mmio);
83762306a36Sopenharmony_ci	i810_writeb(PIXCONF1, mmio, temp | EXTENDED_PALETTE);
83862306a36Sopenharmony_ci
83962306a36Sopenharmony_ci	i810_write_dac(5, red, green, blue, mmio);
84062306a36Sopenharmony_ci
84162306a36Sopenharmony_ci	i810_writeb(PIXCONF1, mmio, temp);
84262306a36Sopenharmony_ci}
84362306a36Sopenharmony_ci
84462306a36Sopenharmony_ci/**
84562306a36Sopenharmony_ci * i810_init_cursor - initializes the cursor
84662306a36Sopenharmony_ci * @par: pointer to i810fb_par structure
84762306a36Sopenharmony_ci *
84862306a36Sopenharmony_ci * DESCRIPTION:
84962306a36Sopenharmony_ci * Initializes the cursor registers
85062306a36Sopenharmony_ci */
85162306a36Sopenharmony_cistatic void i810_init_cursor(struct i810fb_par *par)
85262306a36Sopenharmony_ci{
85362306a36Sopenharmony_ci	u8 __iomem *mmio = par->mmio_start_virtual;
85462306a36Sopenharmony_ci
85562306a36Sopenharmony_ci	i810_enable_cursor(mmio, OFF);
85662306a36Sopenharmony_ci	i810_writel(CURBASE, mmio, par->cursor_heap.physical);
85762306a36Sopenharmony_ci	i810_writew(CURCNTR, mmio, COORD_ACTIVE | CURSOR_MODE_64_XOR);
85862306a36Sopenharmony_ci}
85962306a36Sopenharmony_ci
86062306a36Sopenharmony_ci/*********************************************************************
86162306a36Sopenharmony_ci *                    Framebuffer hook helpers                       *
86262306a36Sopenharmony_ci *********************************************************************/
86362306a36Sopenharmony_ci/**
86462306a36Sopenharmony_ci * i810_round_off -  Round off values to capability of hardware
86562306a36Sopenharmony_ci * @var: pointer to fb_var_screeninfo structure
86662306a36Sopenharmony_ci *
86762306a36Sopenharmony_ci * DESCRIPTION:
86862306a36Sopenharmony_ci * @var contains user-defined information for the mode to be set.
86962306a36Sopenharmony_ci * This will try modify those values to ones nearest the
87062306a36Sopenharmony_ci * capability of the hardware
87162306a36Sopenharmony_ci */
87262306a36Sopenharmony_cistatic void i810_round_off(struct fb_var_screeninfo *var)
87362306a36Sopenharmony_ci{
87462306a36Sopenharmony_ci	u32 xres, yres, vxres, vyres;
87562306a36Sopenharmony_ci
87662306a36Sopenharmony_ci	/*
87762306a36Sopenharmony_ci	 *  Presently supports only these configurations
87862306a36Sopenharmony_ci	 */
87962306a36Sopenharmony_ci
88062306a36Sopenharmony_ci	xres = var->xres;
88162306a36Sopenharmony_ci	yres = var->yres;
88262306a36Sopenharmony_ci	vxres = var->xres_virtual;
88362306a36Sopenharmony_ci	vyres = var->yres_virtual;
88462306a36Sopenharmony_ci
88562306a36Sopenharmony_ci	var->bits_per_pixel += 7;
88662306a36Sopenharmony_ci	var->bits_per_pixel &= ~7;
88762306a36Sopenharmony_ci
88862306a36Sopenharmony_ci	if (var->bits_per_pixel < 8)
88962306a36Sopenharmony_ci		var->bits_per_pixel = 8;
89062306a36Sopenharmony_ci	if (var->bits_per_pixel > 32)
89162306a36Sopenharmony_ci		var->bits_per_pixel = 32;
89262306a36Sopenharmony_ci
89362306a36Sopenharmony_ci	round_off_xres(&xres);
89462306a36Sopenharmony_ci	if (xres < 40)
89562306a36Sopenharmony_ci		xres = 40;
89662306a36Sopenharmony_ci	if (xres > 2048)
89762306a36Sopenharmony_ci		xres = 2048;
89862306a36Sopenharmony_ci	xres = (xres + 7) & ~7;
89962306a36Sopenharmony_ci
90062306a36Sopenharmony_ci	if (vxres < xres)
90162306a36Sopenharmony_ci		vxres = xres;
90262306a36Sopenharmony_ci
90362306a36Sopenharmony_ci	round_off_yres(&xres, &yres);
90462306a36Sopenharmony_ci	if (yres < 1)
90562306a36Sopenharmony_ci		yres = 1;
90662306a36Sopenharmony_ci	if (yres >= 2048)
90762306a36Sopenharmony_ci		yres = 2048;
90862306a36Sopenharmony_ci
90962306a36Sopenharmony_ci	if (vyres < yres)
91062306a36Sopenharmony_ci		vyres = yres;
91162306a36Sopenharmony_ci
91262306a36Sopenharmony_ci	if (var->bits_per_pixel == 32)
91362306a36Sopenharmony_ci		var->accel_flags = 0;
91462306a36Sopenharmony_ci
91562306a36Sopenharmony_ci	/* round of horizontal timings to nearest 8 pixels */
91662306a36Sopenharmony_ci	var->left_margin = (var->left_margin + 4) & ~7;
91762306a36Sopenharmony_ci	var->right_margin = (var->right_margin + 4) & ~7;
91862306a36Sopenharmony_ci	var->hsync_len = (var->hsync_len + 4) & ~7;
91962306a36Sopenharmony_ci
92062306a36Sopenharmony_ci	if (var->vmode & FB_VMODE_INTERLACED) {
92162306a36Sopenharmony_ci		if (!((yres + var->upper_margin + var->vsync_len +
92262306a36Sopenharmony_ci		       var->lower_margin) & 1))
92362306a36Sopenharmony_ci			var->upper_margin++;
92462306a36Sopenharmony_ci	}
92562306a36Sopenharmony_ci
92662306a36Sopenharmony_ci	var->xres = xres;
92762306a36Sopenharmony_ci	var->yres = yres;
92862306a36Sopenharmony_ci	var->xres_virtual = vxres;
92962306a36Sopenharmony_ci	var->yres_virtual = vyres;
93062306a36Sopenharmony_ci}
93162306a36Sopenharmony_ci
93262306a36Sopenharmony_ci/**
93362306a36Sopenharmony_ci * set_color_bitfields - sets rgba fields
93462306a36Sopenharmony_ci * @var: pointer to fb_var_screeninfo
93562306a36Sopenharmony_ci *
93662306a36Sopenharmony_ci * DESCRIPTION:
93762306a36Sopenharmony_ci * The length, offset and ordering  for each color field
93862306a36Sopenharmony_ci * (red, green, blue)  will be set as specified
93962306a36Sopenharmony_ci * by the hardware
94062306a36Sopenharmony_ci */
94162306a36Sopenharmony_cistatic void set_color_bitfields(struct fb_var_screeninfo *var)
94262306a36Sopenharmony_ci{
94362306a36Sopenharmony_ci	switch (var->bits_per_pixel) {
94462306a36Sopenharmony_ci	case 8:
94562306a36Sopenharmony_ci		var->red.offset = 0;
94662306a36Sopenharmony_ci		var->red.length = 8;
94762306a36Sopenharmony_ci		var->green.offset = 0;
94862306a36Sopenharmony_ci		var->green.length = 8;
94962306a36Sopenharmony_ci		var->blue.offset = 0;
95062306a36Sopenharmony_ci		var->blue.length = 8;
95162306a36Sopenharmony_ci		var->transp.offset = 0;
95262306a36Sopenharmony_ci		var->transp.length = 0;
95362306a36Sopenharmony_ci		break;
95462306a36Sopenharmony_ci	case 16:
95562306a36Sopenharmony_ci		var->green.length = (var->green.length == 5) ? 5 : 6;
95662306a36Sopenharmony_ci		var->red.length = 5;
95762306a36Sopenharmony_ci		var->blue.length = 5;
95862306a36Sopenharmony_ci		var->transp.length = 6 - var->green.length;
95962306a36Sopenharmony_ci		var->blue.offset = 0;
96062306a36Sopenharmony_ci		var->green.offset = 5;
96162306a36Sopenharmony_ci		var->red.offset = 5 + var->green.length;
96262306a36Sopenharmony_ci		var->transp.offset =  (5 + var->red.offset) & 15;
96362306a36Sopenharmony_ci		break;
96462306a36Sopenharmony_ci	case 24:	/* RGB 888   */
96562306a36Sopenharmony_ci	case 32:	/* RGBA 8888 */
96662306a36Sopenharmony_ci		var->red.offset = 16;
96762306a36Sopenharmony_ci		var->red.length = 8;
96862306a36Sopenharmony_ci		var->green.offset = 8;
96962306a36Sopenharmony_ci		var->green.length = 8;
97062306a36Sopenharmony_ci		var->blue.offset = 0;
97162306a36Sopenharmony_ci		var->blue.length = 8;
97262306a36Sopenharmony_ci		var->transp.length = var->bits_per_pixel - 24;
97362306a36Sopenharmony_ci		var->transp.offset = (var->transp.length) ? 24 : 0;
97462306a36Sopenharmony_ci		break;
97562306a36Sopenharmony_ci	}
97662306a36Sopenharmony_ci	var->red.msb_right = 0;
97762306a36Sopenharmony_ci	var->green.msb_right = 0;
97862306a36Sopenharmony_ci	var->blue.msb_right = 0;
97962306a36Sopenharmony_ci	var->transp.msb_right = 0;
98062306a36Sopenharmony_ci}
98162306a36Sopenharmony_ci
98262306a36Sopenharmony_ci/**
98362306a36Sopenharmony_ci * i810_check_params - check if contents in var are valid
98462306a36Sopenharmony_ci * @var: pointer to fb_var_screeninfo
98562306a36Sopenharmony_ci * @info: pointer to fb_info
98662306a36Sopenharmony_ci *
98762306a36Sopenharmony_ci * DESCRIPTION:
98862306a36Sopenharmony_ci * This will check if the framebuffer size is sufficient
98962306a36Sopenharmony_ci * for the current mode and if the user's monitor has the
99062306a36Sopenharmony_ci * required specifications to display the current mode.
99162306a36Sopenharmony_ci */
99262306a36Sopenharmony_cistatic int i810_check_params(struct fb_var_screeninfo *var,
99362306a36Sopenharmony_ci			     struct fb_info *info)
99462306a36Sopenharmony_ci{
99562306a36Sopenharmony_ci	struct i810fb_par *par = info->par;
99662306a36Sopenharmony_ci	int line_length, vidmem, mode_valid = 0, retval = 0;
99762306a36Sopenharmony_ci	u32 vyres = var->yres_virtual, vxres = var->xres_virtual;
99862306a36Sopenharmony_ci
99962306a36Sopenharmony_ci	/*
100062306a36Sopenharmony_ci	 *  Memory limit
100162306a36Sopenharmony_ci	 */
100262306a36Sopenharmony_ci	line_length = get_line_length(par, vxres, var->bits_per_pixel);
100362306a36Sopenharmony_ci	vidmem = line_length*vyres;
100462306a36Sopenharmony_ci
100562306a36Sopenharmony_ci	if (vidmem > par->fb.size) {
100662306a36Sopenharmony_ci		vyres = par->fb.size/line_length;
100762306a36Sopenharmony_ci		if (vyres < var->yres) {
100862306a36Sopenharmony_ci			vyres = info->var.yres;
100962306a36Sopenharmony_ci			vxres = par->fb.size/vyres;
101062306a36Sopenharmony_ci			vxres /= var->bits_per_pixel >> 3;
101162306a36Sopenharmony_ci			line_length = get_line_length(par, vxres,
101262306a36Sopenharmony_ci						      var->bits_per_pixel);
101362306a36Sopenharmony_ci			vidmem = line_length * info->var.yres;
101462306a36Sopenharmony_ci			if (vxres < var->xres) {
101562306a36Sopenharmony_ci				printk("i810fb: required video memory, "
101662306a36Sopenharmony_ci				       "%d bytes, for %dx%d-%d (virtual) "
101762306a36Sopenharmony_ci				       "is out of range\n",
101862306a36Sopenharmony_ci				       vidmem, vxres, vyres,
101962306a36Sopenharmony_ci				       var->bits_per_pixel);
102062306a36Sopenharmony_ci				return -ENOMEM;
102162306a36Sopenharmony_ci			}
102262306a36Sopenharmony_ci		}
102362306a36Sopenharmony_ci	}
102462306a36Sopenharmony_ci
102562306a36Sopenharmony_ci	var->xres_virtual = vxres;
102662306a36Sopenharmony_ci	var->yres_virtual = vyres;
102762306a36Sopenharmony_ci
102862306a36Sopenharmony_ci	/*
102962306a36Sopenharmony_ci	 * Monitor limit
103062306a36Sopenharmony_ci	 */
103162306a36Sopenharmony_ci	switch (var->bits_per_pixel) {
103262306a36Sopenharmony_ci	case 8:
103362306a36Sopenharmony_ci		info->monspecs.dclkmax = 234000000;
103462306a36Sopenharmony_ci		break;
103562306a36Sopenharmony_ci	case 16:
103662306a36Sopenharmony_ci		info->monspecs.dclkmax = 229000000;
103762306a36Sopenharmony_ci		break;
103862306a36Sopenharmony_ci	case 24:
103962306a36Sopenharmony_ci	case 32:
104062306a36Sopenharmony_ci		info->monspecs.dclkmax = 204000000;
104162306a36Sopenharmony_ci		break;
104262306a36Sopenharmony_ci	}
104362306a36Sopenharmony_ci
104462306a36Sopenharmony_ci	info->monspecs.dclkmin = 15000000;
104562306a36Sopenharmony_ci
104662306a36Sopenharmony_ci	if (!fb_validate_mode(var, info))
104762306a36Sopenharmony_ci		mode_valid = 1;
104862306a36Sopenharmony_ci
104962306a36Sopenharmony_ci#ifdef CONFIG_FB_I810_I2C
105062306a36Sopenharmony_ci	if (!mode_valid && info->monspecs.gtf &&
105162306a36Sopenharmony_ci	    !fb_get_mode(FB_MAXTIMINGS, 0, var, info))
105262306a36Sopenharmony_ci		mode_valid = 1;
105362306a36Sopenharmony_ci
105462306a36Sopenharmony_ci	if (!mode_valid && info->monspecs.modedb_len) {
105562306a36Sopenharmony_ci		const struct fb_videomode *mode;
105662306a36Sopenharmony_ci
105762306a36Sopenharmony_ci		mode = fb_find_best_mode(var, &info->modelist);
105862306a36Sopenharmony_ci		if (mode) {
105962306a36Sopenharmony_ci			fb_videomode_to_var(var, mode);
106062306a36Sopenharmony_ci			mode_valid = 1;
106162306a36Sopenharmony_ci		}
106262306a36Sopenharmony_ci	}
106362306a36Sopenharmony_ci#endif
106462306a36Sopenharmony_ci	if (!mode_valid && info->monspecs.modedb_len == 0) {
106562306a36Sopenharmony_ci		if (fb_get_mode(FB_MAXTIMINGS, 0, var, info)) {
106662306a36Sopenharmony_ci			int default_sync = (info->monspecs.hfmin-HFMIN)
106762306a36Sopenharmony_ci				|(info->monspecs.hfmax-HFMAX)
106862306a36Sopenharmony_ci				|(info->monspecs.vfmin-VFMIN)
106962306a36Sopenharmony_ci				|(info->monspecs.vfmax-VFMAX);
107062306a36Sopenharmony_ci			printk("i810fb: invalid video mode%s\n",
107162306a36Sopenharmony_ci			       default_sync ? "" : ". Specifying "
107262306a36Sopenharmony_ci			       "vsyncN/hsyncN parameters may help");
107362306a36Sopenharmony_ci			retval = -EINVAL;
107462306a36Sopenharmony_ci		}
107562306a36Sopenharmony_ci	}
107662306a36Sopenharmony_ci
107762306a36Sopenharmony_ci	return retval;
107862306a36Sopenharmony_ci}
107962306a36Sopenharmony_ci
108062306a36Sopenharmony_ci/**
108162306a36Sopenharmony_ci * encode_fix - fill up fb_fix_screeninfo structure
108262306a36Sopenharmony_ci * @fix: pointer to fb_fix_screeninfo
108362306a36Sopenharmony_ci * @info: pointer to fb_info
108462306a36Sopenharmony_ci *
108562306a36Sopenharmony_ci * DESCRIPTION:
108662306a36Sopenharmony_ci * This will set up parameters that are unmodifiable by the user.
108762306a36Sopenharmony_ci */
108862306a36Sopenharmony_cistatic int encode_fix(struct fb_fix_screeninfo *fix, struct fb_info *info)
108962306a36Sopenharmony_ci{
109062306a36Sopenharmony_ci	struct i810fb_par *par = info->par;
109162306a36Sopenharmony_ci
109262306a36Sopenharmony_ci    	memset(fix, 0, sizeof(struct fb_fix_screeninfo));
109362306a36Sopenharmony_ci
109462306a36Sopenharmony_ci    	strcpy(fix->id, "I810");
109562306a36Sopenharmony_ci	mutex_lock(&info->mm_lock);
109662306a36Sopenharmony_ci    	fix->smem_start = par->fb.physical;
109762306a36Sopenharmony_ci    	fix->smem_len = par->fb.size;
109862306a36Sopenharmony_ci	mutex_unlock(&info->mm_lock);
109962306a36Sopenharmony_ci    	fix->type = FB_TYPE_PACKED_PIXELS;
110062306a36Sopenharmony_ci    	fix->type_aux = 0;
110162306a36Sopenharmony_ci	fix->xpanstep = 8;
110262306a36Sopenharmony_ci	fix->ypanstep = 1;
110362306a36Sopenharmony_ci
110462306a36Sopenharmony_ci    	switch (info->var.bits_per_pixel) {
110562306a36Sopenharmony_ci	case 8:
110662306a36Sopenharmony_ci	    	fix->visual = FB_VISUAL_PSEUDOCOLOR;
110762306a36Sopenharmony_ci	    	break;
110862306a36Sopenharmony_ci	case 16:
110962306a36Sopenharmony_ci	case 24:
111062306a36Sopenharmony_ci	case 32:
111162306a36Sopenharmony_ci		if (info->var.nonstd)
111262306a36Sopenharmony_ci			fix->visual = FB_VISUAL_DIRECTCOLOR;
111362306a36Sopenharmony_ci		else
111462306a36Sopenharmony_ci			fix->visual = FB_VISUAL_TRUECOLOR;
111562306a36Sopenharmony_ci	    	break;
111662306a36Sopenharmony_ci	default:
111762306a36Sopenharmony_ci		return -EINVAL;
111862306a36Sopenharmony_ci	}
111962306a36Sopenharmony_ci    	fix->ywrapstep = 0;
112062306a36Sopenharmony_ci	fix->line_length = par->pitch;
112162306a36Sopenharmony_ci	fix->mmio_start = par->mmio_start_phys;
112262306a36Sopenharmony_ci	fix->mmio_len = MMIO_SIZE;
112362306a36Sopenharmony_ci	fix->accel = FB_ACCEL_I810;
112462306a36Sopenharmony_ci
112562306a36Sopenharmony_ci	return 0;
112662306a36Sopenharmony_ci}
112762306a36Sopenharmony_ci
112862306a36Sopenharmony_ci/**
112962306a36Sopenharmony_ci * decode_var - modify par according to contents of var
113062306a36Sopenharmony_ci * @var: pointer to fb_var_screeninfo
113162306a36Sopenharmony_ci * @par: pointer to i810fb_par
113262306a36Sopenharmony_ci *
113362306a36Sopenharmony_ci * DESCRIPTION:
113462306a36Sopenharmony_ci * Based on the contents of @var, @par will be dynamically filled up.
113562306a36Sopenharmony_ci * @par contains all information necessary to modify the hardware.
113662306a36Sopenharmony_ci*/
113762306a36Sopenharmony_cistatic void decode_var(const struct fb_var_screeninfo *var,
113862306a36Sopenharmony_ci		       struct i810fb_par *par)
113962306a36Sopenharmony_ci{
114062306a36Sopenharmony_ci	u32 xres, yres, vxres, vyres;
114162306a36Sopenharmony_ci
114262306a36Sopenharmony_ci	xres = var->xres;
114362306a36Sopenharmony_ci	yres = var->yres;
114462306a36Sopenharmony_ci	vxres = var->xres_virtual;
114562306a36Sopenharmony_ci	vyres = var->yres_virtual;
114662306a36Sopenharmony_ci
114762306a36Sopenharmony_ci	switch (var->bits_per_pixel) {
114862306a36Sopenharmony_ci	case 8:
114962306a36Sopenharmony_ci		par->pixconf = PIXCONF8;
115062306a36Sopenharmony_ci		par->bltcntl = 0;
115162306a36Sopenharmony_ci		par->depth = 1;
115262306a36Sopenharmony_ci		par->blit_bpp = BPP8;
115362306a36Sopenharmony_ci		break;
115462306a36Sopenharmony_ci	case 16:
115562306a36Sopenharmony_ci		if (var->green.length == 5)
115662306a36Sopenharmony_ci			par->pixconf = PIXCONF15;
115762306a36Sopenharmony_ci		else
115862306a36Sopenharmony_ci			par->pixconf = PIXCONF16;
115962306a36Sopenharmony_ci		par->bltcntl = 16;
116062306a36Sopenharmony_ci		par->depth = 2;
116162306a36Sopenharmony_ci		par->blit_bpp = BPP16;
116262306a36Sopenharmony_ci		break;
116362306a36Sopenharmony_ci	case 24:
116462306a36Sopenharmony_ci		par->pixconf = PIXCONF24;
116562306a36Sopenharmony_ci		par->bltcntl = 32;
116662306a36Sopenharmony_ci		par->depth = 3;
116762306a36Sopenharmony_ci		par->blit_bpp = BPP24;
116862306a36Sopenharmony_ci		break;
116962306a36Sopenharmony_ci	case 32:
117062306a36Sopenharmony_ci		par->pixconf = PIXCONF32;
117162306a36Sopenharmony_ci		par->bltcntl = 0;
117262306a36Sopenharmony_ci		par->depth = 4;
117362306a36Sopenharmony_ci		par->blit_bpp = 3 << 24;
117462306a36Sopenharmony_ci		break;
117562306a36Sopenharmony_ci	}
117662306a36Sopenharmony_ci	if (var->nonstd && var->bits_per_pixel != 8)
117762306a36Sopenharmony_ci		par->pixconf |= 1 << 27;
117862306a36Sopenharmony_ci
117962306a36Sopenharmony_ci	i810_calc_dclk(var->pixclock, &par->regs.M,
118062306a36Sopenharmony_ci		       &par->regs.N, &par->regs.P);
118162306a36Sopenharmony_ci	i810fb_encode_registers(var, par, xres, yres);
118262306a36Sopenharmony_ci
118362306a36Sopenharmony_ci	par->watermark = i810_get_watermark(var, par);
118462306a36Sopenharmony_ci	par->pitch = get_line_length(par, vxres, var->bits_per_pixel);
118562306a36Sopenharmony_ci}
118662306a36Sopenharmony_ci
118762306a36Sopenharmony_ci/**
118862306a36Sopenharmony_ci * i810fb_getcolreg - gets red, green and blue values of the hardware DAC
118962306a36Sopenharmony_ci * @regno: DAC index
119062306a36Sopenharmony_ci * @red: red
119162306a36Sopenharmony_ci * @green: green
119262306a36Sopenharmony_ci * @blue: blue
119362306a36Sopenharmony_ci * @transp: transparency (alpha)
119462306a36Sopenharmony_ci * @info: pointer to fb_info
119562306a36Sopenharmony_ci *
119662306a36Sopenharmony_ci * DESCRIPTION:
119762306a36Sopenharmony_ci * Gets the red, green and blue values of the hardware DAC as pointed by @regno
119862306a36Sopenharmony_ci * and writes them to @red, @green and @blue respectively
119962306a36Sopenharmony_ci */
120062306a36Sopenharmony_cistatic int i810fb_getcolreg(u8 regno, u8 *red, u8 *green, u8 *blue,
120162306a36Sopenharmony_ci			    u8 *transp, struct fb_info *info)
120262306a36Sopenharmony_ci{
120362306a36Sopenharmony_ci	struct i810fb_par *par = info->par;
120462306a36Sopenharmony_ci	u8 __iomem *mmio = par->mmio_start_virtual;
120562306a36Sopenharmony_ci	u8 temp;
120662306a36Sopenharmony_ci
120762306a36Sopenharmony_ci	if (info->fix.visual == FB_VISUAL_DIRECTCOLOR) {
120862306a36Sopenharmony_ci		if ((info->var.green.length == 5 && regno > 31) ||
120962306a36Sopenharmony_ci		    (info->var.green.length == 6 && regno > 63))
121062306a36Sopenharmony_ci			return 1;
121162306a36Sopenharmony_ci	}
121262306a36Sopenharmony_ci
121362306a36Sopenharmony_ci	temp = i810_readb(PIXCONF1, mmio);
121462306a36Sopenharmony_ci	i810_writeb(PIXCONF1, mmio, temp & ~EXTENDED_PALETTE);
121562306a36Sopenharmony_ci
121662306a36Sopenharmony_ci	if (info->fix.visual == FB_VISUAL_DIRECTCOLOR &&
121762306a36Sopenharmony_ci	    info->var.green.length == 5)
121862306a36Sopenharmony_ci		i810_read_dac(regno * 8, red, green, blue, mmio);
121962306a36Sopenharmony_ci
122062306a36Sopenharmony_ci	else if (info->fix.visual == FB_VISUAL_DIRECTCOLOR &&
122162306a36Sopenharmony_ci		 info->var.green.length == 6) {
122262306a36Sopenharmony_ci		u8 tmp;
122362306a36Sopenharmony_ci
122462306a36Sopenharmony_ci		i810_read_dac(regno * 8, red, &tmp, blue, mmio);
122562306a36Sopenharmony_ci		i810_read_dac(regno * 4, &tmp, green, &tmp, mmio);
122662306a36Sopenharmony_ci	}
122762306a36Sopenharmony_ci	else
122862306a36Sopenharmony_ci		i810_read_dac(regno, red, green, blue, mmio);
122962306a36Sopenharmony_ci
123062306a36Sopenharmony_ci    	*transp = 0;
123162306a36Sopenharmony_ci	i810_writeb(PIXCONF1, mmio, temp);
123262306a36Sopenharmony_ci
123362306a36Sopenharmony_ci    	return 0;
123462306a36Sopenharmony_ci}
123562306a36Sopenharmony_ci
123662306a36Sopenharmony_ci/******************************************************************
123762306a36Sopenharmony_ci *           Framebuffer device-specific hooks                    *
123862306a36Sopenharmony_ci ******************************************************************/
123962306a36Sopenharmony_ci
124062306a36Sopenharmony_cistatic int i810fb_open(struct fb_info *info, int user)
124162306a36Sopenharmony_ci{
124262306a36Sopenharmony_ci	struct i810fb_par *par = info->par;
124362306a36Sopenharmony_ci
124462306a36Sopenharmony_ci	mutex_lock(&par->open_lock);
124562306a36Sopenharmony_ci	if (par->use_count == 0) {
124662306a36Sopenharmony_ci		memset(&par->state, 0, sizeof(struct vgastate));
124762306a36Sopenharmony_ci		par->state.flags = VGA_SAVE_CMAP;
124862306a36Sopenharmony_ci		par->state.vgabase = par->mmio_start_virtual;
124962306a36Sopenharmony_ci		save_vga(&par->state);
125062306a36Sopenharmony_ci
125162306a36Sopenharmony_ci		i810_save_vga_state(par);
125262306a36Sopenharmony_ci	}
125362306a36Sopenharmony_ci
125462306a36Sopenharmony_ci	par->use_count++;
125562306a36Sopenharmony_ci	mutex_unlock(&par->open_lock);
125662306a36Sopenharmony_ci
125762306a36Sopenharmony_ci	return 0;
125862306a36Sopenharmony_ci}
125962306a36Sopenharmony_ci
126062306a36Sopenharmony_cistatic int i810fb_release(struct fb_info *info, int user)
126162306a36Sopenharmony_ci{
126262306a36Sopenharmony_ci	struct i810fb_par *par = info->par;
126362306a36Sopenharmony_ci
126462306a36Sopenharmony_ci	mutex_lock(&par->open_lock);
126562306a36Sopenharmony_ci	if (par->use_count == 0) {
126662306a36Sopenharmony_ci		mutex_unlock(&par->open_lock);
126762306a36Sopenharmony_ci		return -EINVAL;
126862306a36Sopenharmony_ci	}
126962306a36Sopenharmony_ci
127062306a36Sopenharmony_ci	if (par->use_count == 1) {
127162306a36Sopenharmony_ci		i810_restore_vga_state(par);
127262306a36Sopenharmony_ci		restore_vga(&par->state);
127362306a36Sopenharmony_ci	}
127462306a36Sopenharmony_ci
127562306a36Sopenharmony_ci	par->use_count--;
127662306a36Sopenharmony_ci	mutex_unlock(&par->open_lock);
127762306a36Sopenharmony_ci
127862306a36Sopenharmony_ci	return 0;
127962306a36Sopenharmony_ci}
128062306a36Sopenharmony_ci
128162306a36Sopenharmony_ci
128262306a36Sopenharmony_cistatic int i810fb_setcolreg(unsigned regno, unsigned red, unsigned green,
128362306a36Sopenharmony_ci			    unsigned blue, unsigned transp,
128462306a36Sopenharmony_ci			    struct fb_info *info)
128562306a36Sopenharmony_ci{
128662306a36Sopenharmony_ci	struct i810fb_par *par = info->par;
128762306a36Sopenharmony_ci	u8 __iomem *mmio = par->mmio_start_virtual;
128862306a36Sopenharmony_ci	u8 temp;
128962306a36Sopenharmony_ci	int i;
129062306a36Sopenharmony_ci
129162306a36Sopenharmony_ci 	if (regno > 255) return 1;
129262306a36Sopenharmony_ci
129362306a36Sopenharmony_ci	if (info->fix.visual == FB_VISUAL_DIRECTCOLOR) {
129462306a36Sopenharmony_ci		if ((info->var.green.length == 5 && regno > 31) ||
129562306a36Sopenharmony_ci		    (info->var.green.length == 6 && regno > 63))
129662306a36Sopenharmony_ci			return 1;
129762306a36Sopenharmony_ci	}
129862306a36Sopenharmony_ci
129962306a36Sopenharmony_ci	if (info->var.grayscale)
130062306a36Sopenharmony_ci		red = green = blue = (19595 * red + 38470 * green +
130162306a36Sopenharmony_ci				      7471 * blue) >> 16;
130262306a36Sopenharmony_ci
130362306a36Sopenharmony_ci	temp = i810_readb(PIXCONF1, mmio);
130462306a36Sopenharmony_ci	i810_writeb(PIXCONF1, mmio, temp & ~EXTENDED_PALETTE);
130562306a36Sopenharmony_ci
130662306a36Sopenharmony_ci	if (info->fix.visual == FB_VISUAL_DIRECTCOLOR &&
130762306a36Sopenharmony_ci	    info->var.green.length == 5) {
130862306a36Sopenharmony_ci		for (i = 0; i < 8; i++)
130962306a36Sopenharmony_ci			i810_write_dac((u8) (regno * 8) + i, (u8) red,
131062306a36Sopenharmony_ci				       (u8) green, (u8) blue, mmio);
131162306a36Sopenharmony_ci	} else if (info->fix.visual == FB_VISUAL_DIRECTCOLOR &&
131262306a36Sopenharmony_ci		 info->var.green.length == 6) {
131362306a36Sopenharmony_ci		u8 r, g, b;
131462306a36Sopenharmony_ci
131562306a36Sopenharmony_ci		if (regno < 32) {
131662306a36Sopenharmony_ci			for (i = 0; i < 8; i++)
131762306a36Sopenharmony_ci				i810_write_dac((u8) (regno * 8) + i,
131862306a36Sopenharmony_ci					       (u8) red, (u8) green,
131962306a36Sopenharmony_ci					       (u8) blue, mmio);
132062306a36Sopenharmony_ci		}
132162306a36Sopenharmony_ci		i810_read_dac((u8) (regno*4), &r, &g, &b, mmio);
132262306a36Sopenharmony_ci		for (i = 0; i < 4; i++)
132362306a36Sopenharmony_ci			i810_write_dac((u8) (regno*4) + i, r, (u8) green,
132462306a36Sopenharmony_ci				       b, mmio);
132562306a36Sopenharmony_ci	} else if (info->fix.visual == FB_VISUAL_PSEUDOCOLOR) {
132662306a36Sopenharmony_ci		i810_write_dac((u8) regno, (u8) red, (u8) green,
132762306a36Sopenharmony_ci			       (u8) blue, mmio);
132862306a36Sopenharmony_ci	}
132962306a36Sopenharmony_ci
133062306a36Sopenharmony_ci	i810_writeb(PIXCONF1, mmio, temp);
133162306a36Sopenharmony_ci
133262306a36Sopenharmony_ci	if (regno < 16) {
133362306a36Sopenharmony_ci		switch (info->var.bits_per_pixel) {
133462306a36Sopenharmony_ci		case 16:
133562306a36Sopenharmony_ci			if (info->fix.visual == FB_VISUAL_DIRECTCOLOR) {
133662306a36Sopenharmony_ci				if (info->var.green.length == 5)
133762306a36Sopenharmony_ci					((u32 *)info->pseudo_palette)[regno] =
133862306a36Sopenharmony_ci						(regno << 10) | (regno << 5) |
133962306a36Sopenharmony_ci						regno;
134062306a36Sopenharmony_ci				else
134162306a36Sopenharmony_ci					((u32 *)info->pseudo_palette)[regno] =
134262306a36Sopenharmony_ci						(regno << 11) | (regno << 5) |
134362306a36Sopenharmony_ci						regno;
134462306a36Sopenharmony_ci			} else {
134562306a36Sopenharmony_ci				if (info->var.green.length == 5) {
134662306a36Sopenharmony_ci					/* RGB 555 */
134762306a36Sopenharmony_ci					((u32 *)info->pseudo_palette)[regno] =
134862306a36Sopenharmony_ci						((red & 0xf800) >> 1) |
134962306a36Sopenharmony_ci						((green & 0xf800) >> 6) |
135062306a36Sopenharmony_ci						((blue & 0xf800) >> 11);
135162306a36Sopenharmony_ci				} else {
135262306a36Sopenharmony_ci					/* RGB 565 */
135362306a36Sopenharmony_ci					((u32 *)info->pseudo_palette)[regno] =
135462306a36Sopenharmony_ci						(red & 0xf800) |
135562306a36Sopenharmony_ci						((green & 0xf800) >> 5) |
135662306a36Sopenharmony_ci						((blue & 0xf800) >> 11);
135762306a36Sopenharmony_ci				}
135862306a36Sopenharmony_ci			}
135962306a36Sopenharmony_ci			break;
136062306a36Sopenharmony_ci		case 24:	/* RGB 888 */
136162306a36Sopenharmony_ci		case 32:	/* RGBA 8888 */
136262306a36Sopenharmony_ci			if (info->fix.visual == FB_VISUAL_DIRECTCOLOR)
136362306a36Sopenharmony_ci				((u32 *)info->pseudo_palette)[regno] =
136462306a36Sopenharmony_ci					(regno << 16) | (regno << 8) |
136562306a36Sopenharmony_ci					regno;
136662306a36Sopenharmony_ci			else
136762306a36Sopenharmony_ci				((u32 *)info->pseudo_palette)[regno] =
136862306a36Sopenharmony_ci					((red & 0xff00) << 8) |
136962306a36Sopenharmony_ci					(green & 0xff00) |
137062306a36Sopenharmony_ci					((blue & 0xff00) >> 8);
137162306a36Sopenharmony_ci			break;
137262306a36Sopenharmony_ci		}
137362306a36Sopenharmony_ci	}
137462306a36Sopenharmony_ci	return 0;
137562306a36Sopenharmony_ci}
137662306a36Sopenharmony_ci
137762306a36Sopenharmony_cistatic int i810fb_pan_display(struct fb_var_screeninfo *var,
137862306a36Sopenharmony_ci			      struct fb_info *info)
137962306a36Sopenharmony_ci{
138062306a36Sopenharmony_ci	struct i810fb_par *par = info->par;
138162306a36Sopenharmony_ci	u32 total;
138262306a36Sopenharmony_ci
138362306a36Sopenharmony_ci	total = var->xoffset * par->depth +
138462306a36Sopenharmony_ci		var->yoffset * info->fix.line_length;
138562306a36Sopenharmony_ci	i810fb_load_front(total, info);
138662306a36Sopenharmony_ci
138762306a36Sopenharmony_ci	return 0;
138862306a36Sopenharmony_ci}
138962306a36Sopenharmony_ci
139062306a36Sopenharmony_cistatic int i810fb_blank (int blank_mode, struct fb_info *info)
139162306a36Sopenharmony_ci{
139262306a36Sopenharmony_ci	struct i810fb_par *par = info->par;
139362306a36Sopenharmony_ci	u8 __iomem *mmio = par->mmio_start_virtual;
139462306a36Sopenharmony_ci	int mode = 0, pwr, scr_off = 0;
139562306a36Sopenharmony_ci
139662306a36Sopenharmony_ci	pwr = i810_readl(PWR_CLKC, mmio);
139762306a36Sopenharmony_ci
139862306a36Sopenharmony_ci	switch (blank_mode) {
139962306a36Sopenharmony_ci	case FB_BLANK_UNBLANK:
140062306a36Sopenharmony_ci		mode = POWERON;
140162306a36Sopenharmony_ci		pwr |= 1;
140262306a36Sopenharmony_ci		scr_off = ON;
140362306a36Sopenharmony_ci		break;
140462306a36Sopenharmony_ci	case FB_BLANK_NORMAL:
140562306a36Sopenharmony_ci		mode = POWERON;
140662306a36Sopenharmony_ci		pwr |= 1;
140762306a36Sopenharmony_ci		scr_off = OFF;
140862306a36Sopenharmony_ci		break;
140962306a36Sopenharmony_ci	case FB_BLANK_VSYNC_SUSPEND:
141062306a36Sopenharmony_ci		mode = STANDBY;
141162306a36Sopenharmony_ci		pwr |= 1;
141262306a36Sopenharmony_ci		scr_off = OFF;
141362306a36Sopenharmony_ci		break;
141462306a36Sopenharmony_ci	case FB_BLANK_HSYNC_SUSPEND:
141562306a36Sopenharmony_ci		mode = SUSPEND;
141662306a36Sopenharmony_ci		pwr |= 1;
141762306a36Sopenharmony_ci		scr_off = OFF;
141862306a36Sopenharmony_ci		break;
141962306a36Sopenharmony_ci	case FB_BLANK_POWERDOWN:
142062306a36Sopenharmony_ci		mode = POWERDOWN;
142162306a36Sopenharmony_ci		pwr &= ~1;
142262306a36Sopenharmony_ci		scr_off = OFF;
142362306a36Sopenharmony_ci		break;
142462306a36Sopenharmony_ci	default:
142562306a36Sopenharmony_ci		return -EINVAL;
142662306a36Sopenharmony_ci	}
142762306a36Sopenharmony_ci
142862306a36Sopenharmony_ci	i810_screen_off(mmio, scr_off);
142962306a36Sopenharmony_ci	i810_writel(HVSYNC, mmio, mode);
143062306a36Sopenharmony_ci	i810_writel(PWR_CLKC, mmio, pwr);
143162306a36Sopenharmony_ci
143262306a36Sopenharmony_ci	return 0;
143362306a36Sopenharmony_ci}
143462306a36Sopenharmony_ci
143562306a36Sopenharmony_cistatic int i810fb_set_par(struct fb_info *info)
143662306a36Sopenharmony_ci{
143762306a36Sopenharmony_ci	struct i810fb_par *par = info->par;
143862306a36Sopenharmony_ci
143962306a36Sopenharmony_ci	decode_var(&info->var, par);
144062306a36Sopenharmony_ci	i810_load_regs(par);
144162306a36Sopenharmony_ci	i810_init_cursor(par);
144262306a36Sopenharmony_ci	encode_fix(&info->fix, info);
144362306a36Sopenharmony_ci
144462306a36Sopenharmony_ci	if (info->var.accel_flags && !(par->dev_flags & LOCKUP)) {
144562306a36Sopenharmony_ci		info->flags = FBINFO_HWACCEL_YPAN |
144662306a36Sopenharmony_ci		FBINFO_HWACCEL_COPYAREA | FBINFO_HWACCEL_FILLRECT |
144762306a36Sopenharmony_ci		FBINFO_HWACCEL_IMAGEBLIT;
144862306a36Sopenharmony_ci		info->pixmap.scan_align = 2;
144962306a36Sopenharmony_ci	} else {
145062306a36Sopenharmony_ci		info->pixmap.scan_align = 1;
145162306a36Sopenharmony_ci		info->flags = FBINFO_HWACCEL_YPAN;
145262306a36Sopenharmony_ci	}
145362306a36Sopenharmony_ci	return 0;
145462306a36Sopenharmony_ci}
145562306a36Sopenharmony_ci
145662306a36Sopenharmony_cistatic int i810fb_check_var(struct fb_var_screeninfo *var,
145762306a36Sopenharmony_ci			    struct fb_info *info)
145862306a36Sopenharmony_ci{
145962306a36Sopenharmony_ci	int err;
146062306a36Sopenharmony_ci
146162306a36Sopenharmony_ci	if (IS_DVT) {
146262306a36Sopenharmony_ci		var->vmode &= ~FB_VMODE_MASK;
146362306a36Sopenharmony_ci		var->vmode |= FB_VMODE_NONINTERLACED;
146462306a36Sopenharmony_ci	}
146562306a36Sopenharmony_ci	if (var->vmode & FB_VMODE_DOUBLE) {
146662306a36Sopenharmony_ci		var->vmode &= ~FB_VMODE_MASK;
146762306a36Sopenharmony_ci		var->vmode |= FB_VMODE_NONINTERLACED;
146862306a36Sopenharmony_ci	}
146962306a36Sopenharmony_ci
147062306a36Sopenharmony_ci	i810_round_off(var);
147162306a36Sopenharmony_ci	if ((err = i810_check_params(var, info)))
147262306a36Sopenharmony_ci		return err;
147362306a36Sopenharmony_ci
147462306a36Sopenharmony_ci	i810fb_fill_var_timings(var);
147562306a36Sopenharmony_ci	set_color_bitfields(var);
147662306a36Sopenharmony_ci	return 0;
147762306a36Sopenharmony_ci}
147862306a36Sopenharmony_ci
147962306a36Sopenharmony_cistatic int i810fb_cursor(struct fb_info *info, struct fb_cursor *cursor)
148062306a36Sopenharmony_ci{
148162306a36Sopenharmony_ci	struct i810fb_par *par = info->par;
148262306a36Sopenharmony_ci	u8 __iomem *mmio = par->mmio_start_virtual;
148362306a36Sopenharmony_ci
148462306a36Sopenharmony_ci	if (par->dev_flags & LOCKUP)
148562306a36Sopenharmony_ci		return -ENXIO;
148662306a36Sopenharmony_ci
148762306a36Sopenharmony_ci	if (cursor->image.width > 64 || cursor->image.height > 64)
148862306a36Sopenharmony_ci		return -ENXIO;
148962306a36Sopenharmony_ci
149062306a36Sopenharmony_ci	if ((i810_readl(CURBASE, mmio) & 0xf) != par->cursor_heap.physical) {
149162306a36Sopenharmony_ci		i810_init_cursor(par);
149262306a36Sopenharmony_ci		cursor->set |= FB_CUR_SETALL;
149362306a36Sopenharmony_ci	}
149462306a36Sopenharmony_ci
149562306a36Sopenharmony_ci	i810_enable_cursor(mmio, OFF);
149662306a36Sopenharmony_ci
149762306a36Sopenharmony_ci	if (cursor->set & FB_CUR_SETPOS) {
149862306a36Sopenharmony_ci		u32 tmp;
149962306a36Sopenharmony_ci
150062306a36Sopenharmony_ci		tmp = (cursor->image.dx - info->var.xoffset) & 0xffff;
150162306a36Sopenharmony_ci		tmp |= (cursor->image.dy - info->var.yoffset) << 16;
150262306a36Sopenharmony_ci		i810_writel(CURPOS, mmio, tmp);
150362306a36Sopenharmony_ci	}
150462306a36Sopenharmony_ci
150562306a36Sopenharmony_ci	if (cursor->set & FB_CUR_SETSIZE)
150662306a36Sopenharmony_ci		i810_reset_cursor_image(par);
150762306a36Sopenharmony_ci
150862306a36Sopenharmony_ci	if (cursor->set & FB_CUR_SETCMAP)
150962306a36Sopenharmony_ci		i810_load_cursor_colors(cursor->image.fg_color,
151062306a36Sopenharmony_ci					cursor->image.bg_color,
151162306a36Sopenharmony_ci					info);
151262306a36Sopenharmony_ci
151362306a36Sopenharmony_ci	if (cursor->set & (FB_CUR_SETSHAPE | FB_CUR_SETIMAGE)) {
151462306a36Sopenharmony_ci		int size = ((cursor->image.width + 7) >> 3) *
151562306a36Sopenharmony_ci			cursor->image.height;
151662306a36Sopenharmony_ci		int i;
151762306a36Sopenharmony_ci		u8 *data = kmalloc(64 * 8, GFP_ATOMIC);
151862306a36Sopenharmony_ci
151962306a36Sopenharmony_ci		if (data == NULL)
152062306a36Sopenharmony_ci			return -ENOMEM;
152162306a36Sopenharmony_ci
152262306a36Sopenharmony_ci		switch (cursor->rop) {
152362306a36Sopenharmony_ci		case ROP_XOR:
152462306a36Sopenharmony_ci			for (i = 0; i < size; i++)
152562306a36Sopenharmony_ci				data[i] = cursor->image.data[i] ^ cursor->mask[i];
152662306a36Sopenharmony_ci			break;
152762306a36Sopenharmony_ci		case ROP_COPY:
152862306a36Sopenharmony_ci		default:
152962306a36Sopenharmony_ci			for (i = 0; i < size; i++)
153062306a36Sopenharmony_ci				data[i] = cursor->image.data[i] & cursor->mask[i];
153162306a36Sopenharmony_ci			break;
153262306a36Sopenharmony_ci		}
153362306a36Sopenharmony_ci
153462306a36Sopenharmony_ci		i810_load_cursor_image(cursor->image.width,
153562306a36Sopenharmony_ci				       cursor->image.height, data,
153662306a36Sopenharmony_ci				       par);
153762306a36Sopenharmony_ci		kfree(data);
153862306a36Sopenharmony_ci	}
153962306a36Sopenharmony_ci
154062306a36Sopenharmony_ci	if (cursor->enable)
154162306a36Sopenharmony_ci		i810_enable_cursor(mmio, ON);
154262306a36Sopenharmony_ci
154362306a36Sopenharmony_ci	return 0;
154462306a36Sopenharmony_ci}
154562306a36Sopenharmony_ci
154662306a36Sopenharmony_cistatic const struct fb_ops i810fb_ops = {
154762306a36Sopenharmony_ci	.owner =             THIS_MODULE,
154862306a36Sopenharmony_ci	.fb_open =           i810fb_open,
154962306a36Sopenharmony_ci	.fb_release =        i810fb_release,
155062306a36Sopenharmony_ci	.fb_check_var =      i810fb_check_var,
155162306a36Sopenharmony_ci	.fb_set_par =        i810fb_set_par,
155262306a36Sopenharmony_ci	.fb_setcolreg =      i810fb_setcolreg,
155362306a36Sopenharmony_ci	.fb_blank =          i810fb_blank,
155462306a36Sopenharmony_ci	.fb_pan_display =    i810fb_pan_display,
155562306a36Sopenharmony_ci	.fb_fillrect =       i810fb_fillrect,
155662306a36Sopenharmony_ci	.fb_copyarea =       i810fb_copyarea,
155762306a36Sopenharmony_ci	.fb_imageblit =      i810fb_imageblit,
155862306a36Sopenharmony_ci	.fb_cursor =         i810fb_cursor,
155962306a36Sopenharmony_ci	.fb_sync =           i810fb_sync,
156062306a36Sopenharmony_ci};
156162306a36Sopenharmony_ci
156262306a36Sopenharmony_ci/***********************************************************************
156362306a36Sopenharmony_ci *                         Power Management                            *
156462306a36Sopenharmony_ci ***********************************************************************/
156562306a36Sopenharmony_cistatic int i810fb_suspend(struct pci_dev *dev, pm_message_t mesg)
156662306a36Sopenharmony_ci{
156762306a36Sopenharmony_ci	struct fb_info *info = pci_get_drvdata(dev);
156862306a36Sopenharmony_ci	struct i810fb_par *par = info->par;
156962306a36Sopenharmony_ci
157062306a36Sopenharmony_ci	par->cur_state = mesg.event;
157162306a36Sopenharmony_ci
157262306a36Sopenharmony_ci	switch (mesg.event) {
157362306a36Sopenharmony_ci	case PM_EVENT_FREEZE:
157462306a36Sopenharmony_ci	case PM_EVENT_PRETHAW:
157562306a36Sopenharmony_ci		dev->dev.power.power_state = mesg;
157662306a36Sopenharmony_ci		return 0;
157762306a36Sopenharmony_ci	}
157862306a36Sopenharmony_ci
157962306a36Sopenharmony_ci	console_lock();
158062306a36Sopenharmony_ci	fb_set_suspend(info, 1);
158162306a36Sopenharmony_ci
158262306a36Sopenharmony_ci	if (info->fbops->fb_sync)
158362306a36Sopenharmony_ci		info->fbops->fb_sync(info);
158462306a36Sopenharmony_ci
158562306a36Sopenharmony_ci	i810fb_blank(FB_BLANK_POWERDOWN, info);
158662306a36Sopenharmony_ci	agp_unbind_memory(par->i810_gtt.i810_fb_memory);
158762306a36Sopenharmony_ci	agp_unbind_memory(par->i810_gtt.i810_cursor_memory);
158862306a36Sopenharmony_ci
158962306a36Sopenharmony_ci	pci_save_state(dev);
159062306a36Sopenharmony_ci	pci_disable_device(dev);
159162306a36Sopenharmony_ci	pci_set_power_state(dev, pci_choose_state(dev, mesg));
159262306a36Sopenharmony_ci	console_unlock();
159362306a36Sopenharmony_ci
159462306a36Sopenharmony_ci	return 0;
159562306a36Sopenharmony_ci}
159662306a36Sopenharmony_ci
159762306a36Sopenharmony_cistatic int i810fb_resume(struct pci_dev *dev)
159862306a36Sopenharmony_ci{
159962306a36Sopenharmony_ci	struct fb_info *info = pci_get_drvdata(dev);
160062306a36Sopenharmony_ci	struct i810fb_par *par = info->par;
160162306a36Sopenharmony_ci	int cur_state = par->cur_state;
160262306a36Sopenharmony_ci
160362306a36Sopenharmony_ci	par->cur_state = PM_EVENT_ON;
160462306a36Sopenharmony_ci
160562306a36Sopenharmony_ci	if (cur_state == PM_EVENT_FREEZE) {
160662306a36Sopenharmony_ci		pci_set_power_state(dev, PCI_D0);
160762306a36Sopenharmony_ci		return 0;
160862306a36Sopenharmony_ci	}
160962306a36Sopenharmony_ci
161062306a36Sopenharmony_ci	console_lock();
161162306a36Sopenharmony_ci	pci_set_power_state(dev, PCI_D0);
161262306a36Sopenharmony_ci	pci_restore_state(dev);
161362306a36Sopenharmony_ci
161462306a36Sopenharmony_ci	if (pci_enable_device(dev))
161562306a36Sopenharmony_ci		goto fail;
161662306a36Sopenharmony_ci
161762306a36Sopenharmony_ci	pci_set_master(dev);
161862306a36Sopenharmony_ci	agp_bind_memory(par->i810_gtt.i810_fb_memory,
161962306a36Sopenharmony_ci			par->fb.offset);
162062306a36Sopenharmony_ci	agp_bind_memory(par->i810_gtt.i810_cursor_memory,
162162306a36Sopenharmony_ci			par->cursor_heap.offset);
162262306a36Sopenharmony_ci	i810fb_set_par(info);
162362306a36Sopenharmony_ci	fb_set_suspend (info, 0);
162462306a36Sopenharmony_ci	info->fbops->fb_blank(VESA_NO_BLANKING, info);
162562306a36Sopenharmony_cifail:
162662306a36Sopenharmony_ci	console_unlock();
162762306a36Sopenharmony_ci	return 0;
162862306a36Sopenharmony_ci}
162962306a36Sopenharmony_ci/***********************************************************************
163062306a36Sopenharmony_ci *                  AGP resource allocation                            *
163162306a36Sopenharmony_ci ***********************************************************************/
163262306a36Sopenharmony_ci
163362306a36Sopenharmony_cistatic void i810_fix_pointers(struct i810fb_par *par)
163462306a36Sopenharmony_ci{
163562306a36Sopenharmony_ci      	par->fb.physical = par->aperture.physical+(par->fb.offset << 12);
163662306a36Sopenharmony_ci	par->fb.virtual = par->aperture.virtual+(par->fb.offset << 12);
163762306a36Sopenharmony_ci	par->iring.physical = par->aperture.physical +
163862306a36Sopenharmony_ci		(par->iring.offset << 12);
163962306a36Sopenharmony_ci	par->iring.virtual = par->aperture.virtual +
164062306a36Sopenharmony_ci		(par->iring.offset << 12);
164162306a36Sopenharmony_ci	par->cursor_heap.virtual = par->aperture.virtual+
164262306a36Sopenharmony_ci		(par->cursor_heap.offset << 12);
164362306a36Sopenharmony_ci}
164462306a36Sopenharmony_ci
164562306a36Sopenharmony_cistatic void i810_fix_offsets(struct i810fb_par *par)
164662306a36Sopenharmony_ci{
164762306a36Sopenharmony_ci	if (vram + 1 > par->aperture.size >> 20)
164862306a36Sopenharmony_ci		vram = (par->aperture.size >> 20) - 1;
164962306a36Sopenharmony_ci	if (v_offset_default > (par->aperture.size >> 20))
165062306a36Sopenharmony_ci		v_offset_default = (par->aperture.size >> 20);
165162306a36Sopenharmony_ci	if (vram + v_offset_default + 1 > par->aperture.size >> 20)
165262306a36Sopenharmony_ci		v_offset_default = (par->aperture.size >> 20) - (vram + 1);
165362306a36Sopenharmony_ci
165462306a36Sopenharmony_ci	par->fb.size = vram << 20;
165562306a36Sopenharmony_ci	par->fb.offset = v_offset_default << 20;
165662306a36Sopenharmony_ci	par->fb.offset >>= 12;
165762306a36Sopenharmony_ci
165862306a36Sopenharmony_ci	par->iring.offset = par->fb.offset + (par->fb.size >> 12);
165962306a36Sopenharmony_ci	par->iring.size = RINGBUFFER_SIZE;
166062306a36Sopenharmony_ci
166162306a36Sopenharmony_ci	par->cursor_heap.offset = par->iring.offset + (RINGBUFFER_SIZE >> 12);
166262306a36Sopenharmony_ci	par->cursor_heap.size = 4096;
166362306a36Sopenharmony_ci}
166462306a36Sopenharmony_ci
166562306a36Sopenharmony_cistatic int i810_alloc_agp_mem(struct fb_info *info)
166662306a36Sopenharmony_ci{
166762306a36Sopenharmony_ci	struct i810fb_par *par = info->par;
166862306a36Sopenharmony_ci	int size;
166962306a36Sopenharmony_ci	struct agp_bridge_data *bridge;
167062306a36Sopenharmony_ci
167162306a36Sopenharmony_ci	i810_fix_offsets(par);
167262306a36Sopenharmony_ci	size = par->fb.size + par->iring.size;
167362306a36Sopenharmony_ci
167462306a36Sopenharmony_ci	if (!(bridge = agp_backend_acquire(par->dev))) {
167562306a36Sopenharmony_ci		printk("i810fb_alloc_fbmem: cannot acquire agpgart\n");
167662306a36Sopenharmony_ci		return -ENODEV;
167762306a36Sopenharmony_ci	}
167862306a36Sopenharmony_ci	if (!(par->i810_gtt.i810_fb_memory =
167962306a36Sopenharmony_ci	      agp_allocate_memory(bridge, size >> 12, AGP_NORMAL_MEMORY))) {
168062306a36Sopenharmony_ci		printk("i810fb_alloc_fbmem: can't allocate framebuffer "
168162306a36Sopenharmony_ci		       "memory\n");
168262306a36Sopenharmony_ci		agp_backend_release(bridge);
168362306a36Sopenharmony_ci		return -ENOMEM;
168462306a36Sopenharmony_ci	}
168562306a36Sopenharmony_ci	if (agp_bind_memory(par->i810_gtt.i810_fb_memory,
168662306a36Sopenharmony_ci			    par->fb.offset)) {
168762306a36Sopenharmony_ci		printk("i810fb_alloc_fbmem: can't bind framebuffer memory\n");
168862306a36Sopenharmony_ci		agp_backend_release(bridge);
168962306a36Sopenharmony_ci		return -EBUSY;
169062306a36Sopenharmony_ci	}
169162306a36Sopenharmony_ci
169262306a36Sopenharmony_ci	if (!(par->i810_gtt.i810_cursor_memory =
169362306a36Sopenharmony_ci	      agp_allocate_memory(bridge, par->cursor_heap.size >> 12,
169462306a36Sopenharmony_ci				  AGP_PHYSICAL_MEMORY))) {
169562306a36Sopenharmony_ci		printk("i810fb_alloc_cursormem:  can't allocate "
169662306a36Sopenharmony_ci		       "cursor memory\n");
169762306a36Sopenharmony_ci		agp_backend_release(bridge);
169862306a36Sopenharmony_ci		return -ENOMEM;
169962306a36Sopenharmony_ci	}
170062306a36Sopenharmony_ci	if (agp_bind_memory(par->i810_gtt.i810_cursor_memory,
170162306a36Sopenharmony_ci			    par->cursor_heap.offset)) {
170262306a36Sopenharmony_ci		printk("i810fb_alloc_cursormem: cannot bind cursor memory\n");
170362306a36Sopenharmony_ci		agp_backend_release(bridge);
170462306a36Sopenharmony_ci		return -EBUSY;
170562306a36Sopenharmony_ci	}
170662306a36Sopenharmony_ci
170762306a36Sopenharmony_ci	par->cursor_heap.physical = par->i810_gtt.i810_cursor_memory->physical;
170862306a36Sopenharmony_ci
170962306a36Sopenharmony_ci	i810_fix_pointers(par);
171062306a36Sopenharmony_ci
171162306a36Sopenharmony_ci	agp_backend_release(bridge);
171262306a36Sopenharmony_ci
171362306a36Sopenharmony_ci	return 0;
171462306a36Sopenharmony_ci}
171562306a36Sopenharmony_ci
171662306a36Sopenharmony_ci/***************************************************************
171762306a36Sopenharmony_ci *                    Initialization                           *
171862306a36Sopenharmony_ci ***************************************************************/
171962306a36Sopenharmony_ci
172062306a36Sopenharmony_ci/**
172162306a36Sopenharmony_ci * i810_init_monspecs
172262306a36Sopenharmony_ci * @info: pointer to device specific info structure
172362306a36Sopenharmony_ci *
172462306a36Sopenharmony_ci * DESCRIPTION:
172562306a36Sopenharmony_ci * Sets the user monitor's horizontal and vertical
172662306a36Sopenharmony_ci * frequency limits
172762306a36Sopenharmony_ci */
172862306a36Sopenharmony_cistatic void i810_init_monspecs(struct fb_info *info)
172962306a36Sopenharmony_ci{
173062306a36Sopenharmony_ci	if (!hsync1)
173162306a36Sopenharmony_ci		hsync1 = HFMIN;
173262306a36Sopenharmony_ci	if (!hsync2)
173362306a36Sopenharmony_ci		hsync2 = HFMAX;
173462306a36Sopenharmony_ci	if (!info->monspecs.hfmax)
173562306a36Sopenharmony_ci		info->monspecs.hfmax = hsync2;
173662306a36Sopenharmony_ci	if (!info->monspecs.hfmin)
173762306a36Sopenharmony_ci		info->monspecs.hfmin = hsync1;
173862306a36Sopenharmony_ci	if (hsync2 < hsync1)
173962306a36Sopenharmony_ci		info->monspecs.hfmin = hsync2;
174062306a36Sopenharmony_ci
174162306a36Sopenharmony_ci	if (!vsync1)
174262306a36Sopenharmony_ci		vsync1 = VFMIN;
174362306a36Sopenharmony_ci	if (!vsync2)
174462306a36Sopenharmony_ci		vsync2 = VFMAX;
174562306a36Sopenharmony_ci	if (IS_DVT && vsync1 < 60)
174662306a36Sopenharmony_ci		vsync1 = 60;
174762306a36Sopenharmony_ci	if (!info->monspecs.vfmax)
174862306a36Sopenharmony_ci		info->monspecs.vfmax = vsync2;
174962306a36Sopenharmony_ci	if (!info->monspecs.vfmin)
175062306a36Sopenharmony_ci		info->monspecs.vfmin = vsync1;
175162306a36Sopenharmony_ci	if (vsync2 < vsync1)
175262306a36Sopenharmony_ci		info->monspecs.vfmin = vsync2;
175362306a36Sopenharmony_ci}
175462306a36Sopenharmony_ci
175562306a36Sopenharmony_ci/**
175662306a36Sopenharmony_ci * i810_init_defaults - initializes default values to use
175762306a36Sopenharmony_ci * @par: pointer to i810fb_par structure
175862306a36Sopenharmony_ci * @info: pointer to current fb_info structure
175962306a36Sopenharmony_ci */
176062306a36Sopenharmony_cistatic void i810_init_defaults(struct i810fb_par *par, struct fb_info *info)
176162306a36Sopenharmony_ci{
176262306a36Sopenharmony_ci	mutex_init(&par->open_lock);
176362306a36Sopenharmony_ci
176462306a36Sopenharmony_ci	if (voffset)
176562306a36Sopenharmony_ci		v_offset_default = voffset;
176662306a36Sopenharmony_ci	else if (par->aperture.size > 32 * 1024 * 1024)
176762306a36Sopenharmony_ci		v_offset_default = 16;
176862306a36Sopenharmony_ci	else
176962306a36Sopenharmony_ci		v_offset_default = 8;
177062306a36Sopenharmony_ci
177162306a36Sopenharmony_ci	if (!vram)
177262306a36Sopenharmony_ci		vram = 1;
177362306a36Sopenharmony_ci
177462306a36Sopenharmony_ci	if (accel)
177562306a36Sopenharmony_ci		par->dev_flags |= HAS_ACCELERATION;
177662306a36Sopenharmony_ci
177762306a36Sopenharmony_ci	if (sync)
177862306a36Sopenharmony_ci		par->dev_flags |= ALWAYS_SYNC;
177962306a36Sopenharmony_ci
178062306a36Sopenharmony_ci	par->ddc_num = (ddc3 ? 3 : 2);
178162306a36Sopenharmony_ci
178262306a36Sopenharmony_ci	if (bpp < 8)
178362306a36Sopenharmony_ci		bpp = 8;
178462306a36Sopenharmony_ci
178562306a36Sopenharmony_ci	par->i810fb_ops = i810fb_ops;
178662306a36Sopenharmony_ci
178762306a36Sopenharmony_ci	if (xres)
178862306a36Sopenharmony_ci		info->var.xres = xres;
178962306a36Sopenharmony_ci	else
179062306a36Sopenharmony_ci		info->var.xres = 640;
179162306a36Sopenharmony_ci
179262306a36Sopenharmony_ci	if (yres)
179362306a36Sopenharmony_ci		info->var.yres = yres;
179462306a36Sopenharmony_ci	else
179562306a36Sopenharmony_ci		info->var.yres = 480;
179662306a36Sopenharmony_ci
179762306a36Sopenharmony_ci	if (!vyres)
179862306a36Sopenharmony_ci		vyres = (vram << 20)/(info->var.xres*bpp >> 3);
179962306a36Sopenharmony_ci
180062306a36Sopenharmony_ci	info->var.yres_virtual = vyres;
180162306a36Sopenharmony_ci	info->var.bits_per_pixel = bpp;
180262306a36Sopenharmony_ci
180362306a36Sopenharmony_ci	if (dcolor)
180462306a36Sopenharmony_ci		info->var.nonstd = 1;
180562306a36Sopenharmony_ci
180662306a36Sopenharmony_ci	if (par->dev_flags & HAS_ACCELERATION)
180762306a36Sopenharmony_ci		info->var.accel_flags = 1;
180862306a36Sopenharmony_ci
180962306a36Sopenharmony_ci	i810_init_monspecs(info);
181062306a36Sopenharmony_ci}
181162306a36Sopenharmony_ci
181262306a36Sopenharmony_ci/**
181362306a36Sopenharmony_ci * i810_init_device - initialize device
181462306a36Sopenharmony_ci * @par: pointer to i810fb_par structure
181562306a36Sopenharmony_ci */
181662306a36Sopenharmony_cistatic void i810_init_device(struct i810fb_par *par)
181762306a36Sopenharmony_ci{
181862306a36Sopenharmony_ci	u8 reg;
181962306a36Sopenharmony_ci	u8 __iomem *mmio = par->mmio_start_virtual;
182062306a36Sopenharmony_ci
182162306a36Sopenharmony_ci	if (mtrr)
182262306a36Sopenharmony_ci		par->wc_cookie= arch_phys_wc_add((u32) par->aperture.physical,
182362306a36Sopenharmony_ci						 par->aperture.size);
182462306a36Sopenharmony_ci
182562306a36Sopenharmony_ci	i810_init_cursor(par);
182662306a36Sopenharmony_ci
182762306a36Sopenharmony_ci	/* mvo: enable external vga-connector (for laptops) */
182862306a36Sopenharmony_ci	if (extvga) {
182962306a36Sopenharmony_ci		i810_writel(HVSYNC, mmio, 0);
183062306a36Sopenharmony_ci		i810_writel(PWR_CLKC, mmio, 3);
183162306a36Sopenharmony_ci	}
183262306a36Sopenharmony_ci
183362306a36Sopenharmony_ci	pci_read_config_byte(par->dev, 0x50, &reg);
183462306a36Sopenharmony_ci	reg &= FREQ_MASK;
183562306a36Sopenharmony_ci	par->mem_freq = (reg) ? 133 : 100;
183662306a36Sopenharmony_ci
183762306a36Sopenharmony_ci}
183862306a36Sopenharmony_ci
183962306a36Sopenharmony_cistatic int i810_allocate_pci_resource(struct i810fb_par *par,
184062306a36Sopenharmony_ci				      const struct pci_device_id *entry)
184162306a36Sopenharmony_ci{
184262306a36Sopenharmony_ci	int err;
184362306a36Sopenharmony_ci
184462306a36Sopenharmony_ci	if ((err = pci_enable_device(par->dev))) {
184562306a36Sopenharmony_ci		printk("i810fb_init: cannot enable device\n");
184662306a36Sopenharmony_ci		return err;
184762306a36Sopenharmony_ci	}
184862306a36Sopenharmony_ci	par->res_flags |= PCI_DEVICE_ENABLED;
184962306a36Sopenharmony_ci
185062306a36Sopenharmony_ci	if (pci_resource_len(par->dev, 0) > 512 * 1024) {
185162306a36Sopenharmony_ci		par->aperture.physical = pci_resource_start(par->dev, 0);
185262306a36Sopenharmony_ci		par->aperture.size = pci_resource_len(par->dev, 0);
185362306a36Sopenharmony_ci		par->mmio_start_phys = pci_resource_start(par->dev, 1);
185462306a36Sopenharmony_ci	} else {
185562306a36Sopenharmony_ci		par->aperture.physical = pci_resource_start(par->dev, 1);
185662306a36Sopenharmony_ci		par->aperture.size = pci_resource_len(par->dev, 1);
185762306a36Sopenharmony_ci		par->mmio_start_phys = pci_resource_start(par->dev, 0);
185862306a36Sopenharmony_ci	}
185962306a36Sopenharmony_ci	if (!par->aperture.size) {
186062306a36Sopenharmony_ci		printk("i810fb_init: device is disabled\n");
186162306a36Sopenharmony_ci		return -ENOMEM;
186262306a36Sopenharmony_ci	}
186362306a36Sopenharmony_ci
186462306a36Sopenharmony_ci	if (!request_mem_region(par->aperture.physical,
186562306a36Sopenharmony_ci				par->aperture.size,
186662306a36Sopenharmony_ci				i810_pci_list[entry->driver_data])) {
186762306a36Sopenharmony_ci		printk("i810fb_init: cannot request framebuffer region\n");
186862306a36Sopenharmony_ci		return -ENODEV;
186962306a36Sopenharmony_ci	}
187062306a36Sopenharmony_ci	par->res_flags |= FRAMEBUFFER_REQ;
187162306a36Sopenharmony_ci
187262306a36Sopenharmony_ci	par->aperture.virtual = ioremap_wc(par->aperture.physical,
187362306a36Sopenharmony_ci					   par->aperture.size);
187462306a36Sopenharmony_ci	if (!par->aperture.virtual) {
187562306a36Sopenharmony_ci		printk("i810fb_init: cannot remap framebuffer region\n");
187662306a36Sopenharmony_ci		return -ENODEV;
187762306a36Sopenharmony_ci	}
187862306a36Sopenharmony_ci
187962306a36Sopenharmony_ci	if (!request_mem_region(par->mmio_start_phys,
188062306a36Sopenharmony_ci				MMIO_SIZE,
188162306a36Sopenharmony_ci				i810_pci_list[entry->driver_data])) {
188262306a36Sopenharmony_ci		printk("i810fb_init: cannot request mmio region\n");
188362306a36Sopenharmony_ci		return -ENODEV;
188462306a36Sopenharmony_ci	}
188562306a36Sopenharmony_ci	par->res_flags |= MMIO_REQ;
188662306a36Sopenharmony_ci
188762306a36Sopenharmony_ci	par->mmio_start_virtual = ioremap(par->mmio_start_phys,
188862306a36Sopenharmony_ci						  MMIO_SIZE);
188962306a36Sopenharmony_ci	if (!par->mmio_start_virtual) {
189062306a36Sopenharmony_ci		printk("i810fb_init: cannot remap mmio region\n");
189162306a36Sopenharmony_ci		return -ENODEV;
189262306a36Sopenharmony_ci	}
189362306a36Sopenharmony_ci
189462306a36Sopenharmony_ci	return 0;
189562306a36Sopenharmony_ci}
189662306a36Sopenharmony_ci
189762306a36Sopenharmony_cistatic void i810fb_find_init_mode(struct fb_info *info)
189862306a36Sopenharmony_ci{
189962306a36Sopenharmony_ci	struct fb_videomode mode;
190062306a36Sopenharmony_ci	struct fb_var_screeninfo var;
190162306a36Sopenharmony_ci	struct fb_monspecs *specs = &info->monspecs;
190262306a36Sopenharmony_ci	int found = 0;
190362306a36Sopenharmony_ci#ifdef CONFIG_FB_I810_I2C
190462306a36Sopenharmony_ci	int i;
190562306a36Sopenharmony_ci	int err = 1;
190662306a36Sopenharmony_ci	struct i810fb_par *par = info->par;
190762306a36Sopenharmony_ci#endif
190862306a36Sopenharmony_ci
190962306a36Sopenharmony_ci	INIT_LIST_HEAD(&info->modelist);
191062306a36Sopenharmony_ci	memset(&mode, 0, sizeof(struct fb_videomode));
191162306a36Sopenharmony_ci	var = info->var;
191262306a36Sopenharmony_ci#ifdef CONFIG_FB_I810_I2C
191362306a36Sopenharmony_ci	i810_create_i2c_busses(par);
191462306a36Sopenharmony_ci
191562306a36Sopenharmony_ci	for (i = 0; i < par->ddc_num + 1; i++) {
191662306a36Sopenharmony_ci		err = i810_probe_i2c_connector(info, &par->edid, i);
191762306a36Sopenharmony_ci		if (!err)
191862306a36Sopenharmony_ci			break;
191962306a36Sopenharmony_ci	}
192062306a36Sopenharmony_ci
192162306a36Sopenharmony_ci	if (!err)
192262306a36Sopenharmony_ci		printk("i810fb_init_pci: DDC probe successful\n");
192362306a36Sopenharmony_ci
192462306a36Sopenharmony_ci	fb_edid_to_monspecs(par->edid, specs);
192562306a36Sopenharmony_ci
192662306a36Sopenharmony_ci	if (specs->modedb == NULL)
192762306a36Sopenharmony_ci		printk("i810fb_init_pci: Unable to get Mode Database\n");
192862306a36Sopenharmony_ci
192962306a36Sopenharmony_ci	fb_videomode_to_modelist(specs->modedb, specs->modedb_len,
193062306a36Sopenharmony_ci				 &info->modelist);
193162306a36Sopenharmony_ci	if (specs->modedb != NULL) {
193262306a36Sopenharmony_ci		const struct fb_videomode *m;
193362306a36Sopenharmony_ci
193462306a36Sopenharmony_ci		if (xres && yres) {
193562306a36Sopenharmony_ci			if ((m = fb_find_best_mode(&var, &info->modelist))) {
193662306a36Sopenharmony_ci				mode = *m;
193762306a36Sopenharmony_ci				found  = 1;
193862306a36Sopenharmony_ci			}
193962306a36Sopenharmony_ci		}
194062306a36Sopenharmony_ci
194162306a36Sopenharmony_ci		if (!found) {
194262306a36Sopenharmony_ci			m = fb_find_best_display(&info->monspecs, &info->modelist);
194362306a36Sopenharmony_ci			mode = *m;
194462306a36Sopenharmony_ci			found = 1;
194562306a36Sopenharmony_ci		}
194662306a36Sopenharmony_ci
194762306a36Sopenharmony_ci		fb_videomode_to_var(&var, &mode);
194862306a36Sopenharmony_ci	}
194962306a36Sopenharmony_ci#endif
195062306a36Sopenharmony_ci	if (mode_option)
195162306a36Sopenharmony_ci		fb_find_mode(&var, info, mode_option, specs->modedb,
195262306a36Sopenharmony_ci			     specs->modedb_len, (found) ? &mode : NULL,
195362306a36Sopenharmony_ci			     info->var.bits_per_pixel);
195462306a36Sopenharmony_ci
195562306a36Sopenharmony_ci	info->var = var;
195662306a36Sopenharmony_ci	fb_destroy_modedb(specs->modedb);
195762306a36Sopenharmony_ci	specs->modedb = NULL;
195862306a36Sopenharmony_ci}
195962306a36Sopenharmony_ci
196062306a36Sopenharmony_ci#ifndef MODULE
196162306a36Sopenharmony_cistatic int i810fb_setup(char *options)
196262306a36Sopenharmony_ci{
196362306a36Sopenharmony_ci	char *this_opt, *suffix = NULL;
196462306a36Sopenharmony_ci
196562306a36Sopenharmony_ci	if (!options || !*options)
196662306a36Sopenharmony_ci		return 0;
196762306a36Sopenharmony_ci
196862306a36Sopenharmony_ci	while ((this_opt = strsep(&options, ",")) != NULL) {
196962306a36Sopenharmony_ci		if (!strncmp(this_opt, "mtrr", 4))
197062306a36Sopenharmony_ci			mtrr = true;
197162306a36Sopenharmony_ci		else if (!strncmp(this_opt, "accel", 5))
197262306a36Sopenharmony_ci			accel = true;
197362306a36Sopenharmony_ci		else if (!strncmp(this_opt, "extvga", 6))
197462306a36Sopenharmony_ci			extvga = true;
197562306a36Sopenharmony_ci		else if (!strncmp(this_opt, "sync", 4))
197662306a36Sopenharmony_ci			sync = true;
197762306a36Sopenharmony_ci		else if (!strncmp(this_opt, "vram:", 5))
197862306a36Sopenharmony_ci			vram = (simple_strtoul(this_opt+5, NULL, 0));
197962306a36Sopenharmony_ci		else if (!strncmp(this_opt, "voffset:", 8))
198062306a36Sopenharmony_ci			voffset = (simple_strtoul(this_opt+8, NULL, 0));
198162306a36Sopenharmony_ci		else if (!strncmp(this_opt, "xres:", 5))
198262306a36Sopenharmony_ci			xres = simple_strtoul(this_opt+5, NULL, 0);
198362306a36Sopenharmony_ci		else if (!strncmp(this_opt, "yres:", 5))
198462306a36Sopenharmony_ci			yres = simple_strtoul(this_opt+5, NULL, 0);
198562306a36Sopenharmony_ci		else if (!strncmp(this_opt, "vyres:", 6))
198662306a36Sopenharmony_ci			vyres = simple_strtoul(this_opt+6, NULL, 0);
198762306a36Sopenharmony_ci		else if (!strncmp(this_opt, "bpp:", 4))
198862306a36Sopenharmony_ci			bpp = simple_strtoul(this_opt+4, NULL, 0);
198962306a36Sopenharmony_ci		else if (!strncmp(this_opt, "hsync1:", 7)) {
199062306a36Sopenharmony_ci			hsync1 = simple_strtoul(this_opt+7, &suffix, 0);
199162306a36Sopenharmony_ci			if (strncmp(suffix, "H", 1))
199262306a36Sopenharmony_ci				hsync1 *= 1000;
199362306a36Sopenharmony_ci		} else if (!strncmp(this_opt, "hsync2:", 7)) {
199462306a36Sopenharmony_ci			hsync2 = simple_strtoul(this_opt+7, &suffix, 0);
199562306a36Sopenharmony_ci			if (strncmp(suffix, "H", 1))
199662306a36Sopenharmony_ci				hsync2 *= 1000;
199762306a36Sopenharmony_ci		} else if (!strncmp(this_opt, "vsync1:", 7))
199862306a36Sopenharmony_ci			vsync1 = simple_strtoul(this_opt+7, NULL, 0);
199962306a36Sopenharmony_ci		else if (!strncmp(this_opt, "vsync2:", 7))
200062306a36Sopenharmony_ci			vsync2 = simple_strtoul(this_opt+7, NULL, 0);
200162306a36Sopenharmony_ci		else if (!strncmp(this_opt, "dcolor", 6))
200262306a36Sopenharmony_ci			dcolor = true;
200362306a36Sopenharmony_ci		else if (!strncmp(this_opt, "ddc3", 4))
200462306a36Sopenharmony_ci			ddc3 = true;
200562306a36Sopenharmony_ci		else
200662306a36Sopenharmony_ci			mode_option = this_opt;
200762306a36Sopenharmony_ci	}
200862306a36Sopenharmony_ci	return 0;
200962306a36Sopenharmony_ci}
201062306a36Sopenharmony_ci#endif
201162306a36Sopenharmony_ci
201262306a36Sopenharmony_cistatic int i810fb_init_pci(struct pci_dev *dev,
201362306a36Sopenharmony_ci			   const struct pci_device_id *entry)
201462306a36Sopenharmony_ci{
201562306a36Sopenharmony_ci	struct fb_info    *info;
201662306a36Sopenharmony_ci	struct i810fb_par *par = NULL;
201762306a36Sopenharmony_ci	struct fb_videomode mode;
201862306a36Sopenharmony_ci	int err = -1, vfreq, hfreq, pixclock;
201962306a36Sopenharmony_ci
202062306a36Sopenharmony_ci	err = aperture_remove_conflicting_pci_devices(dev, "i810fb");
202162306a36Sopenharmony_ci	if (err)
202262306a36Sopenharmony_ci		return err;
202362306a36Sopenharmony_ci
202462306a36Sopenharmony_ci	info = framebuffer_alloc(sizeof(struct i810fb_par), &dev->dev);
202562306a36Sopenharmony_ci	if (!info)
202662306a36Sopenharmony_ci		return -ENOMEM;
202762306a36Sopenharmony_ci
202862306a36Sopenharmony_ci	par = info->par;
202962306a36Sopenharmony_ci	par->dev = dev;
203062306a36Sopenharmony_ci
203162306a36Sopenharmony_ci	if (!(info->pixmap.addr = kzalloc(8*1024, GFP_KERNEL))) {
203262306a36Sopenharmony_ci		i810fb_release_resource(info, par);
203362306a36Sopenharmony_ci		return -ENOMEM;
203462306a36Sopenharmony_ci	}
203562306a36Sopenharmony_ci	info->pixmap.size = 8*1024;
203662306a36Sopenharmony_ci	info->pixmap.buf_align = 8;
203762306a36Sopenharmony_ci	info->pixmap.access_align = 32;
203862306a36Sopenharmony_ci	info->pixmap.flags = FB_PIXMAP_SYSTEM;
203962306a36Sopenharmony_ci
204062306a36Sopenharmony_ci	if ((err = i810_allocate_pci_resource(par, entry))) {
204162306a36Sopenharmony_ci		i810fb_release_resource(info, par);
204262306a36Sopenharmony_ci		return err;
204362306a36Sopenharmony_ci	}
204462306a36Sopenharmony_ci
204562306a36Sopenharmony_ci	i810_init_defaults(par, info);
204662306a36Sopenharmony_ci
204762306a36Sopenharmony_ci	if ((err = i810_alloc_agp_mem(info))) {
204862306a36Sopenharmony_ci		i810fb_release_resource(info, par);
204962306a36Sopenharmony_ci		return err;
205062306a36Sopenharmony_ci	}
205162306a36Sopenharmony_ci
205262306a36Sopenharmony_ci	i810_init_device(par);
205362306a36Sopenharmony_ci
205462306a36Sopenharmony_ci	info->screen_base = par->fb.virtual;
205562306a36Sopenharmony_ci	info->fbops = &par->i810fb_ops;
205662306a36Sopenharmony_ci	info->pseudo_palette = par->pseudo_palette;
205762306a36Sopenharmony_ci	fb_alloc_cmap(&info->cmap, 256, 0);
205862306a36Sopenharmony_ci	i810fb_find_init_mode(info);
205962306a36Sopenharmony_ci
206062306a36Sopenharmony_ci	if ((err = info->fbops->fb_check_var(&info->var, info))) {
206162306a36Sopenharmony_ci		i810fb_release_resource(info, par);
206262306a36Sopenharmony_ci		return err;
206362306a36Sopenharmony_ci	}
206462306a36Sopenharmony_ci
206562306a36Sopenharmony_ci	fb_var_to_videomode(&mode, &info->var);
206662306a36Sopenharmony_ci	fb_add_videomode(&mode, &info->modelist);
206762306a36Sopenharmony_ci
206862306a36Sopenharmony_ci	i810fb_init_ringbuffer(info);
206962306a36Sopenharmony_ci	err = register_framebuffer(info);
207062306a36Sopenharmony_ci
207162306a36Sopenharmony_ci	if (err < 0) {
207262306a36Sopenharmony_ci    		i810fb_release_resource(info, par);
207362306a36Sopenharmony_ci		printk("i810fb_init: cannot register framebuffer device\n");
207462306a36Sopenharmony_ci    		return err;
207562306a36Sopenharmony_ci    	}
207662306a36Sopenharmony_ci
207762306a36Sopenharmony_ci	pci_set_drvdata(dev, info);
207862306a36Sopenharmony_ci	pixclock = 1000000000/(info->var.pixclock);
207962306a36Sopenharmony_ci	pixclock *= 1000;
208062306a36Sopenharmony_ci	hfreq = pixclock/(info->var.xres + info->var.left_margin +
208162306a36Sopenharmony_ci			  info->var.hsync_len + info->var.right_margin);
208262306a36Sopenharmony_ci	vfreq = hfreq/(info->var.yres + info->var.upper_margin +
208362306a36Sopenharmony_ci		       info->var.vsync_len + info->var.lower_margin);
208462306a36Sopenharmony_ci
208562306a36Sopenharmony_ci      	printk("I810FB: fb%d         : %s v%d.%d.%d%s\n"
208662306a36Sopenharmony_ci      	       "I810FB: Video RAM   : %dK\n"
208762306a36Sopenharmony_ci	       "I810FB: Monitor     : H: %d-%d KHz V: %d-%d Hz\n"
208862306a36Sopenharmony_ci	       "I810FB: Mode        : %dx%d-%dbpp@%dHz\n",
208962306a36Sopenharmony_ci	       info->node,
209062306a36Sopenharmony_ci	       i810_pci_list[entry->driver_data],
209162306a36Sopenharmony_ci	       VERSION_MAJOR, VERSION_MINOR, VERSION_TEENIE, BRANCH_VERSION,
209262306a36Sopenharmony_ci	       (int) par->fb.size>>10, info->monspecs.hfmin/1000,
209362306a36Sopenharmony_ci	       info->monspecs.hfmax/1000, info->monspecs.vfmin,
209462306a36Sopenharmony_ci	       info->monspecs.vfmax, info->var.xres,
209562306a36Sopenharmony_ci	       info->var.yres, info->var.bits_per_pixel, vfreq);
209662306a36Sopenharmony_ci	return 0;
209762306a36Sopenharmony_ci}
209862306a36Sopenharmony_ci
209962306a36Sopenharmony_ci/***************************************************************
210062306a36Sopenharmony_ci *                     De-initialization                        *
210162306a36Sopenharmony_ci ***************************************************************/
210262306a36Sopenharmony_ci
210362306a36Sopenharmony_cistatic void i810fb_release_resource(struct fb_info *info,
210462306a36Sopenharmony_ci				    struct i810fb_par *par)
210562306a36Sopenharmony_ci{
210662306a36Sopenharmony_ci	struct gtt_data *gtt = &par->i810_gtt;
210762306a36Sopenharmony_ci	arch_phys_wc_del(par->wc_cookie);
210862306a36Sopenharmony_ci
210962306a36Sopenharmony_ci	i810_delete_i2c_busses(par);
211062306a36Sopenharmony_ci
211162306a36Sopenharmony_ci	if (par->i810_gtt.i810_cursor_memory)
211262306a36Sopenharmony_ci		agp_free_memory(gtt->i810_cursor_memory);
211362306a36Sopenharmony_ci	if (par->i810_gtt.i810_fb_memory)
211462306a36Sopenharmony_ci		agp_free_memory(gtt->i810_fb_memory);
211562306a36Sopenharmony_ci
211662306a36Sopenharmony_ci	if (par->mmio_start_virtual)
211762306a36Sopenharmony_ci		iounmap(par->mmio_start_virtual);
211862306a36Sopenharmony_ci	if (par->aperture.virtual)
211962306a36Sopenharmony_ci		iounmap(par->aperture.virtual);
212062306a36Sopenharmony_ci	kfree(par->edid);
212162306a36Sopenharmony_ci	if (par->res_flags & FRAMEBUFFER_REQ)
212262306a36Sopenharmony_ci		release_mem_region(par->aperture.physical,
212362306a36Sopenharmony_ci				   par->aperture.size);
212462306a36Sopenharmony_ci	if (par->res_flags & MMIO_REQ)
212562306a36Sopenharmony_ci		release_mem_region(par->mmio_start_phys, MMIO_SIZE);
212662306a36Sopenharmony_ci
212762306a36Sopenharmony_ci	framebuffer_release(info);
212862306a36Sopenharmony_ci
212962306a36Sopenharmony_ci}
213062306a36Sopenharmony_ci
213162306a36Sopenharmony_cistatic void i810fb_remove_pci(struct pci_dev *dev)
213262306a36Sopenharmony_ci{
213362306a36Sopenharmony_ci	struct fb_info *info = pci_get_drvdata(dev);
213462306a36Sopenharmony_ci	struct i810fb_par *par = info->par;
213562306a36Sopenharmony_ci
213662306a36Sopenharmony_ci	unregister_framebuffer(info);
213762306a36Sopenharmony_ci	i810fb_release_resource(info, par);
213862306a36Sopenharmony_ci	printk("cleanup_module:  unloaded i810 framebuffer device\n");
213962306a36Sopenharmony_ci}
214062306a36Sopenharmony_ci
214162306a36Sopenharmony_ci#ifndef MODULE
214262306a36Sopenharmony_cistatic int i810fb_init(void)
214362306a36Sopenharmony_ci{
214462306a36Sopenharmony_ci	char *option = NULL;
214562306a36Sopenharmony_ci
214662306a36Sopenharmony_ci	if (fb_modesetting_disabled("i810fb"))
214762306a36Sopenharmony_ci		return -ENODEV;
214862306a36Sopenharmony_ci
214962306a36Sopenharmony_ci	if (fb_get_options("i810fb", &option))
215062306a36Sopenharmony_ci		return -ENODEV;
215162306a36Sopenharmony_ci	i810fb_setup(option);
215262306a36Sopenharmony_ci
215362306a36Sopenharmony_ci	return pci_register_driver(&i810fb_driver);
215462306a36Sopenharmony_ci}
215562306a36Sopenharmony_ci#endif
215662306a36Sopenharmony_ci
215762306a36Sopenharmony_ci/*********************************************************************
215862306a36Sopenharmony_ci *                          Modularization                           *
215962306a36Sopenharmony_ci *********************************************************************/
216062306a36Sopenharmony_ci
216162306a36Sopenharmony_ci#ifdef MODULE
216262306a36Sopenharmony_ci
216362306a36Sopenharmony_cistatic int i810fb_init(void)
216462306a36Sopenharmony_ci{
216562306a36Sopenharmony_ci	if (fb_modesetting_disabled("i810fb"))
216662306a36Sopenharmony_ci		return -ENODEV;
216762306a36Sopenharmony_ci
216862306a36Sopenharmony_ci	hsync1 *= 1000;
216962306a36Sopenharmony_ci	hsync2 *= 1000;
217062306a36Sopenharmony_ci
217162306a36Sopenharmony_ci	return pci_register_driver(&i810fb_driver);
217262306a36Sopenharmony_ci}
217362306a36Sopenharmony_ci
217462306a36Sopenharmony_cimodule_param(vram, int, 0);
217562306a36Sopenharmony_ciMODULE_PARM_DESC(vram, "System RAM to allocate to framebuffer in MiB"
217662306a36Sopenharmony_ci		 " (default=4)");
217762306a36Sopenharmony_cimodule_param(voffset, int, 0);
217862306a36Sopenharmony_ciMODULE_PARM_DESC(voffset, "at what offset to place start of framebuffer "
217962306a36Sopenharmony_ci                 "memory (0 to maximum aperture size), in MiB (default = 48)");
218062306a36Sopenharmony_cimodule_param(bpp, int, 0);
218162306a36Sopenharmony_ciMODULE_PARM_DESC(bpp, "Color depth for display in bits per pixel"
218262306a36Sopenharmony_ci		 " (default = 8)");
218362306a36Sopenharmony_cimodule_param(xres, int, 0);
218462306a36Sopenharmony_ciMODULE_PARM_DESC(xres, "Horizontal resolution in pixels (default = 640)");
218562306a36Sopenharmony_cimodule_param(yres, int, 0);
218662306a36Sopenharmony_ciMODULE_PARM_DESC(yres, "Vertical resolution in scanlines (default = 480)");
218762306a36Sopenharmony_cimodule_param(vyres,int, 0);
218862306a36Sopenharmony_ciMODULE_PARM_DESC(vyres, "Virtual vertical resolution in scanlines"
218962306a36Sopenharmony_ci		 " (default = 480)");
219062306a36Sopenharmony_cimodule_param(hsync1, int, 0);
219162306a36Sopenharmony_ciMODULE_PARM_DESC(hsync1, "Minimum horizontal frequency of monitor in KHz"
219262306a36Sopenharmony_ci		 " (default = 29)");
219362306a36Sopenharmony_cimodule_param(hsync2, int, 0);
219462306a36Sopenharmony_ciMODULE_PARM_DESC(hsync2, "Maximum horizontal frequency of monitor in KHz"
219562306a36Sopenharmony_ci		 " (default = 30)");
219662306a36Sopenharmony_cimodule_param(vsync1, int, 0);
219762306a36Sopenharmony_ciMODULE_PARM_DESC(vsync1, "Minimum vertical frequency of monitor in Hz"
219862306a36Sopenharmony_ci		 " (default = 50)");
219962306a36Sopenharmony_cimodule_param(vsync2, int, 0);
220062306a36Sopenharmony_ciMODULE_PARM_DESC(vsync2, "Maximum vertical frequency of monitor in Hz"
220162306a36Sopenharmony_ci		 " (default = 60)");
220262306a36Sopenharmony_cimodule_param(accel, bool, 0);
220362306a36Sopenharmony_ciMODULE_PARM_DESC(accel, "Use Acceleration (BLIT) engine (default = 0)");
220462306a36Sopenharmony_cimodule_param(mtrr, bool, 0);
220562306a36Sopenharmony_ciMODULE_PARM_DESC(mtrr, "Use MTRR (default = 0)");
220662306a36Sopenharmony_cimodule_param(extvga, bool, 0);
220762306a36Sopenharmony_ciMODULE_PARM_DESC(extvga, "Enable external VGA connector (default = 0)");
220862306a36Sopenharmony_cimodule_param(sync, bool, 0);
220962306a36Sopenharmony_ciMODULE_PARM_DESC(sync, "wait for accel engine to finish drawing"
221062306a36Sopenharmony_ci		 " (default = 0)");
221162306a36Sopenharmony_cimodule_param(dcolor, bool, 0);
221262306a36Sopenharmony_ciMODULE_PARM_DESC(dcolor, "use DirectColor visuals"
221362306a36Sopenharmony_ci		 " (default = 0 = TrueColor)");
221462306a36Sopenharmony_cimodule_param(ddc3, bool, 0);
221562306a36Sopenharmony_ciMODULE_PARM_DESC(ddc3, "Probe DDC bus 3 (default = 0 = no)");
221662306a36Sopenharmony_cimodule_param(mode_option, charp, 0);
221762306a36Sopenharmony_ciMODULE_PARM_DESC(mode_option, "Specify initial video mode");
221862306a36Sopenharmony_ci
221962306a36Sopenharmony_ciMODULE_AUTHOR("Tony A. Daplas");
222062306a36Sopenharmony_ciMODULE_DESCRIPTION("Framebuffer device for the Intel 810/815 and"
222162306a36Sopenharmony_ci		   " compatible cards");
222262306a36Sopenharmony_ciMODULE_LICENSE("GPL");
222362306a36Sopenharmony_ci
222462306a36Sopenharmony_cistatic void __exit i810fb_exit(void)
222562306a36Sopenharmony_ci{
222662306a36Sopenharmony_ci	pci_unregister_driver(&i810fb_driver);
222762306a36Sopenharmony_ci}
222862306a36Sopenharmony_cimodule_exit(i810fb_exit);
222962306a36Sopenharmony_ci
223062306a36Sopenharmony_ci#endif /* MODULE */
223162306a36Sopenharmony_ci
223262306a36Sopenharmony_cimodule_init(i810fb_init);
2233